From a488074b144e3eb3b21b1e8439fb36ce064ad6d2 Mon Sep 17 00:00:00 2001 From: William Joye Date: Fri, 22 Mar 2019 14:47:42 -0400 Subject: Squashed 'tkblt/' content from commit 85c4d08c git-subtree-dir: tkblt git-subtree-split: 85c4d08cdf668eb54a5ad0325270368c64f8909c --- .gitignore | 30 + LICENSE | 24 + Makefile.in | 466 ++ README.md | 28 + aclocal.m4 | 9 + configure | 10270 ++++++++++++++++++++++++++++++++++++++ configure.ac | 246 + doc/BLT.html | 74 + doc/BLT.n | 76 + doc/barchart.html | 1640 ++++++ doc/barchart.n | 2239 +++++++++ doc/graph.html | 1759 +++++++ doc/graph.n | 2408 +++++++++ doc/vector.html | 704 +++ doc/vector.n | 1134 +++++ generic/tkblt.decls | 92 + generic/tkbltChain.C | 194 + generic/tkbltChain.h | 91 + generic/tkbltConfig.C | 218 + generic/tkbltConfig.h | 43 + generic/tkbltDecls.h | 152 + generic/tkbltGrAxis.C | 1984 ++++++++ generic/tkbltGrAxis.h | 266 + generic/tkbltGrAxisOp.C | 674 +++ generic/tkbltGrAxisOp.h | 60 + generic/tkbltGrAxisOption.C | 264 + generic/tkbltGrAxisOption.h | 41 + generic/tkbltGrBind.C | 227 + generic/tkbltGrBind.h | 72 + generic/tkbltGrDef.h | 45 + generic/tkbltGrElem.C | 284 ++ generic/tkbltGrElem.h | 202 + generic/tkbltGrElemBar.C | 1315 +++++ generic/tkbltGrElemBar.h | 132 + generic/tkbltGrElemLine.C | 2405 +++++++++ generic/tkbltGrElemLine.h | 184 + generic/tkbltGrElemLineSpline.C | 1086 ++++ generic/tkbltGrElemOp.C | 652 +++ generic/tkbltGrElemOp.h | 41 + generic/tkbltGrElemOption.C | 396 ++ generic/tkbltGrElemOption.h | 41 + generic/tkbltGrHairs.C | 145 + generic/tkbltGrHairs.h | 78 + generic/tkbltGrHairsOp.C | 164 + generic/tkbltGrHairsOp.h | 42 + generic/tkbltGrLegd.C | 1070 ++++ generic/tkbltGrLegd.h | 178 + generic/tkbltGrLegdOp.C | 496 ++ generic/tkbltGrLegdOp.h | 40 + generic/tkbltGrMarker.C | 177 + generic/tkbltGrMarker.h | 103 + generic/tkbltGrMarkerLine.C | 298 ++ generic/tkbltGrMarkerLine.h | 82 + generic/tkbltGrMarkerOp.C | 495 ++ generic/tkbltGrMarkerOp.h | 39 + generic/tkbltGrMarkerOption.C | 209 + generic/tkbltGrMarkerOption.h | 39 + generic/tkbltGrMarkerPolygon.C | 298 ++ generic/tkbltGrMarkerPolygon.h | 84 + generic/tkbltGrMarkerText.C | 276 + generic/tkbltGrMarkerText.h | 82 + generic/tkbltGrMisc.C | 405 ++ generic/tkbltGrMisc.h | 138 + generic/tkbltGrPSOutput.C | 931 ++++ generic/tkbltGrPSOutput.h | 90 + generic/tkbltGrPen.C | 62 + generic/tkbltGrPen.h | 79 + generic/tkbltGrPenBar.C | 174 + generic/tkbltGrPenBar.h | 73 + generic/tkbltGrPenLine.C | 243 + generic/tkbltGrPenLine.h | 88 + generic/tkbltGrPenOp.C | 217 + generic/tkbltGrPenOp.h | 42 + generic/tkbltGrPenOption.C | 89 + generic/tkbltGrPostscript.C | 84 + generic/tkbltGrPostscript.h | 73 + generic/tkbltGrPostscriptOp.C | 183 + generic/tkbltGrPostscriptOp.h | 41 + generic/tkbltGrText.C | 233 + generic/tkbltGrText.h | 79 + generic/tkbltGrXAxisOp.C | 222 + generic/tkbltGrXAxisOp.h | 39 + generic/tkbltGraph.C | 1458 ++++++ generic/tkbltGraph.h | 256 + generic/tkbltGraphBar.C | 516 ++ generic/tkbltGraphBar.h | 119 + generic/tkbltGraphLine.C | 267 + generic/tkbltGraphLine.h | 76 + generic/tkbltGraphOp.C | 462 ++ generic/tkbltGraphOp.h | 44 + generic/tkbltGraphSup.C | 686 +++ generic/tkbltInt.C | 74 + generic/tkbltInt.h | 58 + generic/tkbltNsUtil.C | 129 + generic/tkbltNsUtil.h | 64 + generic/tkbltOp.C | 171 + generic/tkbltOp.h | 67 + generic/tkbltParse.C | 388 ++ generic/tkbltParse.h | 55 + generic/tkbltStubInit.c | 30 + generic/tkbltStubLib.C | 15 + generic/tkbltSwitch.C | 407 ++ generic/tkbltSwitch.h | 129 + generic/tkbltVecCmd.C | 1821 +++++++ generic/tkbltVecInt.h | 202 + generic/tkbltVecMath.C | 1612 ++++++ generic/tkbltVecOp.C | 56 + generic/tkbltVector.C | 1875 +++++++ generic/tkbltVector.h | 140 + library/graph.tcl | 554 ++ pkgIndex.tcl.in | 5 + tclconfig/ChangeLog | 1003 ++++ tclconfig/README.txt | 26 + tclconfig/install-sh | 528 ++ tclconfig/tcl.m4 | 4176 ++++++++++++++++ tests/all.tcl | 11 + tests/axis.tcl | 105 + tests/barelement.tcl | 97 + tests/bargraph.tcl | 80 + tests/barpen.tcl | 51 + tests/base.tcl | 142 + tests/crosshairs.tcl | 26 + tests/legend.tcl | 101 + tests/lineelement.tcl | 105 + tests/linegraph.tcl | 75 + tests/linemarker.tcl | 34 + tests/linepen.tcl | 55 + tests/marker.tcl | 33 + tests/markers.tcl | 4 + tests/polygonmarker.tcl | 30 + tests/ps.tcl | 29 + tests/test.tcl | 10 + tests/textmarker.tcl | 44 + tkbltConfig.sh.in | 45 + tools/genStubs.tcl | 1179 +++++ 135 files changed, 59973 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile.in create mode 100644 README.md create mode 100644 aclocal.m4 create mode 100755 configure create mode 100644 configure.ac create mode 100644 doc/BLT.html create mode 100644 doc/BLT.n create mode 100644 doc/barchart.html create mode 100644 doc/barchart.n create mode 100644 doc/graph.html create mode 100644 doc/graph.n create mode 100644 doc/vector.html create mode 100644 doc/vector.n create mode 100644 generic/tkblt.decls create mode 100644 generic/tkbltChain.C create mode 100644 generic/tkbltChain.h create mode 100644 generic/tkbltConfig.C create mode 100644 generic/tkbltConfig.h create mode 100644 generic/tkbltDecls.h create mode 100644 generic/tkbltGrAxis.C create mode 100644 generic/tkbltGrAxis.h create mode 100644 generic/tkbltGrAxisOp.C create mode 100644 generic/tkbltGrAxisOp.h create mode 100644 generic/tkbltGrAxisOption.C create mode 100644 generic/tkbltGrAxisOption.h create mode 100644 generic/tkbltGrBind.C create mode 100644 generic/tkbltGrBind.h create mode 100644 generic/tkbltGrDef.h create mode 100644 generic/tkbltGrElem.C create mode 100644 generic/tkbltGrElem.h create mode 100644 generic/tkbltGrElemBar.C create mode 100644 generic/tkbltGrElemBar.h create mode 100644 generic/tkbltGrElemLine.C create mode 100644 generic/tkbltGrElemLine.h create mode 100644 generic/tkbltGrElemLineSpline.C create mode 100644 generic/tkbltGrElemOp.C create mode 100644 generic/tkbltGrElemOp.h create mode 100644 generic/tkbltGrElemOption.C create mode 100644 generic/tkbltGrElemOption.h create mode 100644 generic/tkbltGrHairs.C create mode 100644 generic/tkbltGrHairs.h create mode 100644 generic/tkbltGrHairsOp.C create mode 100644 generic/tkbltGrHairsOp.h create mode 100644 generic/tkbltGrLegd.C create mode 100644 generic/tkbltGrLegd.h create mode 100644 generic/tkbltGrLegdOp.C create mode 100644 generic/tkbltGrLegdOp.h create mode 100644 generic/tkbltGrMarker.C create mode 100644 generic/tkbltGrMarker.h create mode 100644 generic/tkbltGrMarkerLine.C create mode 100644 generic/tkbltGrMarkerLine.h create mode 100644 generic/tkbltGrMarkerOp.C create mode 100644 generic/tkbltGrMarkerOp.h create mode 100644 generic/tkbltGrMarkerOption.C create mode 100644 generic/tkbltGrMarkerOption.h create mode 100644 generic/tkbltGrMarkerPolygon.C create mode 100644 generic/tkbltGrMarkerPolygon.h create mode 100644 generic/tkbltGrMarkerText.C create mode 100644 generic/tkbltGrMarkerText.h create mode 100644 generic/tkbltGrMisc.C create mode 100644 generic/tkbltGrMisc.h create mode 100644 generic/tkbltGrPSOutput.C create mode 100644 generic/tkbltGrPSOutput.h create mode 100644 generic/tkbltGrPen.C create mode 100644 generic/tkbltGrPen.h create mode 100644 generic/tkbltGrPenBar.C create mode 100644 generic/tkbltGrPenBar.h create mode 100644 generic/tkbltGrPenLine.C create mode 100644 generic/tkbltGrPenLine.h create mode 100644 generic/tkbltGrPenOp.C create mode 100644 generic/tkbltGrPenOp.h create mode 100644 generic/tkbltGrPenOption.C create mode 100644 generic/tkbltGrPostscript.C create mode 100644 generic/tkbltGrPostscript.h create mode 100644 generic/tkbltGrPostscriptOp.C create mode 100644 generic/tkbltGrPostscriptOp.h create mode 100644 generic/tkbltGrText.C create mode 100644 generic/tkbltGrText.h create mode 100644 generic/tkbltGrXAxisOp.C create mode 100644 generic/tkbltGrXAxisOp.h create mode 100644 generic/tkbltGraph.C create mode 100644 generic/tkbltGraph.h create mode 100644 generic/tkbltGraphBar.C create mode 100644 generic/tkbltGraphBar.h create mode 100644 generic/tkbltGraphLine.C create mode 100644 generic/tkbltGraphLine.h create mode 100644 generic/tkbltGraphOp.C create mode 100644 generic/tkbltGraphOp.h create mode 100644 generic/tkbltGraphSup.C create mode 100644 generic/tkbltInt.C create mode 100644 generic/tkbltInt.h create mode 100644 generic/tkbltNsUtil.C create mode 100644 generic/tkbltNsUtil.h create mode 100644 generic/tkbltOp.C create mode 100644 generic/tkbltOp.h create mode 100644 generic/tkbltParse.C create mode 100644 generic/tkbltParse.h create mode 100644 generic/tkbltStubInit.c create mode 100644 generic/tkbltStubLib.C create mode 100644 generic/tkbltSwitch.C create mode 100644 generic/tkbltSwitch.h create mode 100644 generic/tkbltVecCmd.C create mode 100644 generic/tkbltVecInt.h create mode 100644 generic/tkbltVecMath.C create mode 100644 generic/tkbltVecOp.C create mode 100644 generic/tkbltVector.C create mode 100644 generic/tkbltVector.h create mode 100644 library/graph.tcl create mode 100644 pkgIndex.tcl.in create mode 100644 tclconfig/ChangeLog create mode 100644 tclconfig/README.txt create mode 100755 tclconfig/install-sh create mode 100644 tclconfig/tcl.m4 create mode 100644 tests/all.tcl create mode 100644 tests/axis.tcl create mode 100644 tests/barelement.tcl create mode 100644 tests/bargraph.tcl create mode 100644 tests/barpen.tcl create mode 100644 tests/base.tcl create mode 100644 tests/crosshairs.tcl create mode 100644 tests/legend.tcl create mode 100644 tests/lineelement.tcl create mode 100644 tests/linegraph.tcl create mode 100644 tests/linemarker.tcl create mode 100644 tests/linepen.tcl create mode 100644 tests/marker.tcl create mode 100644 tests/markers.tcl create mode 100644 tests/polygonmarker.tcl create mode 100644 tests/ps.tcl create mode 100644 tests/test.tcl create mode 100644 tests/textmarker.tcl create mode 100755 tkbltConfig.sh.in create mode 100644 tools/genStubs.tcl diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c8694d4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +*~ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ffe507e --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +Smithsonian Astrophysical Observatory, Cambridge, MA, USA +This code has been modified under the terms listed below and is made +available under the same terms. + +Copyright 1991-2004 George A Howlett. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..d36c879 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,466 @@ +# Makefile.in -- +# +# This file is a Makefile for Sample TEA Extension. If it has the name +# "Makefile.in" then it is a template for a Makefile; to generate the +# actual Makefile, run "./configure", which is a configuration script +# generated by the "autoconf" program (constructs like "@foo@" will get +# replaced in the actual Makefile. +# +# Copyright (c) 1999 Scriptics Corporation. +# Copyright (c) 2002-2005 ActiveState Corporation. +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. + +#======================================================================== +# Add additional lines to handle any additional AC_SUBST cases that +# have been added in a customized configure script. +#======================================================================== + +#SAMPLE_NEW_VAR = @SAMPLE_NEW_VAR@ + +#======================================================================== +# Nothing of the variables below this line should 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_STUB_SOURCES = @PKG_STUB_SOURCES@ +PKG_STUB_OBJECTS = @PKG_STUB_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_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) +lib_BINARIES = $(PKG_LIB_FILE) $(PKG_STUB_LIB_FILE) +BINARIES = $(lib_BINARIES) + +SHELL = @SHELL@ + +srcdir = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +libdir = @libdir@ +includedir = @includedir@ +datarootdir = @datarootdir@ +datadir = @datadir@ +mandir = @mandir@ + +DESTDIR = + +PKG_DIR = $(PACKAGE_NAME)$(PACKAGE_VERSION) +pkgdatadir = $(datadir)/$(PKG_DIR) +pkglibdir = $(libdir)/$(PKG_DIR) +pkgincludedir = $(includedir)/$(PKG_DIR) + +top_builddir = @abs_top_builddir@ + +INSTALL_OPTIONS = +INSTALL = @INSTALL@ $(INSTALL_OPTIONS) +INSTALL_DATA_DIR = ${INSTALL} -d -m 755 +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_LIBRARY = ${INSTALL_DATA} + +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +CC = @CC@ +CFLAGS_DEFAULT = @CFLAGS_DEFAULT@ +CFLAGS_WARNING = @CFLAGS_WARNING@ +EXEEXT = @EXEEXT@ +LDFLAGS_DEFAULT = @LDFLAGS_DEFAULT@ +MAKE_LIB = @MAKE_LIB@ +MAKE_SHARED_LIB = @MAKE_SHARED_LIB@ +MAKE_STATIC_LIB = @MAKE_STATIC_LIB@ +MAKE_STUB_LIB = @MAKE_STUB_LIB@ +OBJEXT = @OBJEXT@ +RANLIB = @RANLIB@ +RANLIB_STUB = @RANLIB_STUB@ +SHLIB_CFLAGS = @SHLIB_CFLAGS@ +SHLIB_LD = @SHLIB_LD@ +SHLIB_LD_LIBS = @SHLIB_LD_LIBS@ +STLIB_LD = @STLIB_LD@ +#TCL_DEFS = @TCL_DEFS@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +#TK_BIN_DIR = @TK_BIN_DIR@ +#TK_SRC_DIR = @TK_SRC_DIR@ + +# Not used, but retained for reference of what libs Tcl required +#TCL_LIBS = @TCL_LIBS@ + +#======================================================================== +# TCLLIBPATH seeds the auto_path in Tcl's init.tcl so we can test our +# package without installing. The other environment variables allow us +# to test against an uninstalled Tcl. Add special env vars that you +# require for testing here (like TCLX_LIBRARY). +#======================================================================== + +EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR) +#EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR):$(TK_BIN_DIR) +TCLLIBPATH = $(top_builddir) +TCLSH_ENV = TCL_LIBRARY=`@CYGPATH@ $(TCL_SRC_DIR)/library` +PKG_ENV = @LD_LIBRARY_PATH_VAR@="$(EXTRA_PATH):$(@LD_LIBRARY_PATH_VAR@)" \ + PATH="$(EXTRA_PATH):$(PATH)" \ + TCLLIBPATH="$(TCLLIBPATH)" + +TCLSH_PROG = @TCLSH_PROG@ +TCLSH = $(TCLSH_ENV) $(PKG_ENV) $(TCLSH_PROG) + +#WISH_ENV = TK_LIBRARY=`@CYGPATH@ $(TK_SRC_DIR)/library` +#WISH_PROG = @WISH_PROG@ +#WISH = $(TCLSH_ENV) $(WISH_ENV) $(PKG_ENV) $(WISH_PROG) + +SHARED_BUILD = @SHARED_BUILD@ + +#INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ +INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ @TK_INCLUDES@ @TK_XINCLUDES@ + +PKG_CFLAGS = @PKG_CFLAGS@ + +# TCL_DEFS is not strictly need here, but if you remove it, then you +# must make sure that configure.ac checks for the necessary components +# that your library may use. TCL_DEFS can actually be a problem if +# you do not compile with a similar machine setup as the Tcl core was +# compiled with. +#DEFS = $(TCL_DEFS) @DEFS@ $(PKG_CFLAGS) +DEFS = @DEFS@ $(PKG_CFLAGS) + +# Move pkgIndex.tcl to 'BINARIES' var if it is generated in the Makefile +CONFIG_CLEAN_FILES = Makefile pkgIndex.tcl +CLEANFILES = @CLEANFILES@ + +CPPFLAGS = @CPPFLAGS@ +LIBS = @PKG_LIBS@ @LIBS@ +AR = @AR@ +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) \ + $(CFLAGS_DEFAULT) $(CFLAGS_WARNING) $(SHLIB_CFLAGS) $(CFLAGS) + +GDB = gdb +VALGRIND = valgrind +VALGRINDARGS = --tool=memcheck --num-callers=8 --leak-resolution=high \ + --leak-check=yes --show-reachable=yes -v + +.SUFFIXES: .c .C .$(OBJEXT) + +#======================================================================== +# Start of user-definable TARGETS section +#======================================================================== + +#======================================================================== +# TEA TARGETS. Please note that the "libraries:" target refers to platform +# independent files, and the "binaries:" target includes executable programs and +# platform-dependent libraries. Modify these targets so that they install +# the various pieces of your package. The make and install rules +# for the BINARIES that you specified above have already been done. +#======================================================================== + +all: binaries libraries doc + +#======================================================================== +# The binaries target builds executable programs, Windows .dll's, unix +# shared/static libraries, and any other platform-dependent files. +# The list of targets to build for "binaries:" is specified at the top +# of the Makefile, in the "BINARIES" variable. +#======================================================================== + +binaries: $(BINARIES) + +libraries: + +#======================================================================== +# Your doc target should differentiate from doc builds (by the developer) +# and doc installs (see install-doc), which just install the docs on the +# end user machine when building from source. +#======================================================================== + +doc: + @echo "If you have documentation to create, place the commands to" + @echo "build the docs in the 'doc:' target. For example:" + @echo " xml2nroff sample.xml > sample.n" + @echo " xml2html sample.xml > sample.html" + +install: all install-binaries install-libraries install-doc + +install-binaries: binaries install-lib-binaries install-bin-binaries + +#======================================================================== +# This rule installs platform-independent files, such as header files. +# The list=...; for p in $$list handles the empty list case x-platform. +#======================================================================== + +install-libraries: libraries + @$(INSTALL_DATA_DIR) $(DESTDIR)$(includedir) + @echo "Installing header files in $(DESTDIR)$(includedir)" + @list='$(PKG_HEADERS)'; for i in $$list; do \ + echo "Installing $(srcdir)/$$i" ; \ + $(INSTALL_DATA) $(srcdir)/$$i $(DESTDIR)$(includedir) ; \ + done; + +#======================================================================== +# Install documentation. Unix manpages should go in the $(mandir) +# directory. +#======================================================================== + +install-doc: doc + @$(INSTALL_DATA_DIR) $(DESTDIR)$(mandir)/mann + @echo "Installing documentation in $(DESTDIR)$(mandir)" + @list='$(srcdir)/doc/*.n'; for i in $$list; do \ + echo "Installing $$i"; \ + $(INSTALL_DATA) $$i $(DESTDIR)$(mandir)/mann ; \ + done + +test: binaries libraries + $(TCLSH) `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS) \ + -load "package ifneeded $(PACKAGE_NAME) $(PACKAGE_VERSION) \ + [list load `@CYGPATH@ $(PKG_LIB_FILE)` $(PACKAGE_NAME)]" + +genstubs: $(srcdir)/tools/genStubs.tcl $(srcdir)/src/tkblt.decls + @echo $(TCLSH) $(srcdir)/tools/genStubs.tcl $(srcdir)/src $(srcdir)/src/tkblt.decls + @$(TCLSH) $(srcdir)/tools/genStubs.tcl $(srcdir)/src $(srcdir)/src/tkblt.decls +shell: binaries libraries + @$(TCLSH) $(SCRIPT) + +gdb: + $(TCLSH_ENV) $(PKG_ENV) $(GDB) $(TCLSH_PROG) $(SCRIPT) + +gdb-test: binaries libraries + $(TCLSH_ENV) $(PKG_ENV) $(GDB) \ + --args $(TCLSH_PROG) `@CYGPATH@ $(srcdir)/tests/all.tcl` \ + $(TESTFLAGS) -singleproc 1 \ + -load "package ifneeded $(PACKAGE_NAME) $(PACKAGE_VERSION) \ + [list load `@CYGPATH@ $(PKG_LIB_FILE)` $(PACKAGE_NAME)]" + +valgrind: binaries libraries + $(TCLSH_ENV) $(PKG_ENV) $(VALGRIND) $(VALGRINDARGS) $(TCLSH_PROG) \ + `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS) + +valgrindshell: binaries libraries + $(TCLSH_ENV) $(PKG_ENV) $(VALGRIND) $(VALGRINDARGS) $(TCLSH_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) + +$(PKG_STUB_LIB_FILE): $(PKG_STUB_OBJECTS) + -rm -f $(PKG_STUB_LIB_FILE) + ${MAKE_STUB_LIB} + $(RANLIB_STUB) $(PKG_STUB_LIB_FILE) + +#======================================================================== +# We need to enumerate the list of .c to .o lines here. +# +# In the following lines, $(srcdir) refers to the toplevel directory +# containing your extension. If your sources are in a subdirectory, +# you will have to modify the paths to reflect this: +# +# sample.$(OBJEXT): $(srcdir)/generic/sample.c +# $(COMPILE) -c `@CYGPATH@ $(srcdir)/generic/sample.c` -o $@ +# +# Setting the VPATH variable to a list of paths will cause the makefile +# to look into these paths when resolving .c to .obj dependencies. +# As necessary, add $(srcdir):$(srcdir)/compat:.... +#======================================================================== + +VPATH = $(srcdir):$(srcdir)/generic:$(srcdir)/unix:$(srcdir)/win:$(srcdir)/macosx + +.c.@OBJEXT@: + $(COMPILE) -c `@CYGPATH@ $<` -o $@ + +.C.@OBJEXT@: + $(COMPILE) -c `@CYGPATH@ $<` -o $@ + +#======================================================================== +# Distribution creation +# You may need to tweak this target to make it work correctly. +#======================================================================== + +#COMPRESS = tar cvf $(PKG_DIR).tar $(PKG_DIR); compress $(PKG_DIR).tar +COMPRESS = tar zcvf $(PKG_DIR).tar.gz $(PKG_DIR) +DIST_ROOT = /tmp/dist +DIST_DIR = $(DIST_ROOT)/$(PKG_DIR) + +DIST_INSTALL_DATA = CPPROG='cp -p' $(INSTALL) -m 644 +DIST_INSTALL_SCRIPT = CPPROG='cp -p' $(INSTALL) -m 755 + +dist-clean: + rm -rf $(DIST_DIR) $(DIST_ROOT)/$(PKG_DIR).tar.* + +dist: dist-clean + $(INSTALL_DATA_DIR) $(DIST_DIR) + + # TEA files + $(DIST_INSTALL_DATA) $(srcdir)/Makefile.in \ + $(srcdir)/aclocal.m4 $(srcdir)/configure.ac \ + $(DIST_DIR)/ + $(DIST_INSTALL_SCRIPT) $(srcdir)/configure $(DIST_DIR)/ + + $(INSTALL_DATA_DIR) $(DIST_DIR)/tclconfig + $(DIST_INSTALL_DATA) $(srcdir)/tclconfig/README.txt \ + $(srcdir)/tclconfig/tcl.m4 $(srcdir)/tclconfig/install-sh \ + $(DIST_DIR)/tclconfig/ + + # Extension files + $(DIST_INSTALL_DATA) \ + $(srcdir)/ChangeLog \ + $(srcdir)/README.sha \ + $(srcdir)/license.terms \ + $(srcdir)/README \ + $(srcdir)/pkgIndex.tcl.in \ + $(DIST_DIR)/ + + list='demos doc generic library mac tests unix win'; \ + for p in $$list; do \ + if test -d $(srcdir)/$$p ; then \ + $(INSTALL_DATA_DIR) $(DIST_DIR)/$$p; \ + $(DIST_INSTALL_DATA) $(srcdir)/$$p/* $(DIST_DIR)/$$p/; \ + fi; \ + done + + (cd $(DIST_ROOT); $(COMPRESS);) + +#======================================================================== +# End of user-definable section +#======================================================================== + +#======================================================================== +# Don't modify the file to clean here. Instead, set the "CLEANFILES" +# variable in configure.ac +#======================================================================== + +clean: + -test -z "$(BINARIES)" || rm -f $(BINARIES) + -rm -f $(PKG_OBJECTS) *.$(OBJEXT) core *.core + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean: clean + -rm -f *.tab.c + -rm -f $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log config.status + +#======================================================================== +# Install binary object libraries. On Windows this includes both .dll and +# .lib files. Because the .lib files are not explicitly listed anywhere, +# we need to deduce their existence from the .dll file of the same name. +# Library files go into the lib directory. +# In addition, this will generate the pkgIndex.tcl +# file in the install location (assuming it can find a usable tclsh shell) +# +# You should not have to modify this target. +#======================================================================== + +install-lib-binaries: binaries + @$(INSTALL_DATA_DIR) $(DESTDIR)$(pkglibdir) + @list='$(lib_BINARIES)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_LIBRARY) $$p $(DESTDIR)$(pkglibdir)/$$p"; \ + $(INSTALL_LIBRARY) $$p $(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 + @if test "x$(SHARED_BUILD)" = "x1"; then \ + echo " Install pkgIndex.tcl $(DESTDIR)$(pkglibdir)"; \ + $(INSTALL_DATA) pkgIndex.tcl $(DESTDIR)$(pkglibdir); \ + fi + $(INSTALL_DATA) tkbltConfig.sh $(DESTDIR)$(libdir) + +#======================================================================== +# Install binary executables (e.g. .exe files and dependent .dll files) +# This is for files that must go in the bin directory (located next to +# wish and tclsh), like dependent .dll files on Windows. +# +# You should not have to modify this target, except to define bin_BINARIES +# above if necessary. +#======================================================================== + +install-bin-binaries: binaries + @$(INSTALL_DATA_DIR) $(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 + +.PHONY: all binaries clean depend distclean doc install libraries test +.PHONY: gdb gdb-test valgrind valgrindshell + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/README.md b/README.md new file mode 100644 index 0000000..c5a5b74 --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.1041783.svg)](https://doi.org/10.5281/zenodo.1041783) +# tkblt +Introduction to the TkBLT library + +TkBLT is a library of extensions to the Tk library. It adds new +commands and variables to the application's interpreter. + +TkBLT is a derived version of the BLT Toolkit by George A. Howlett, +for Tcl/Tk 8.5/8.6, is TEA compatible, with full support for MacOSX and +Windows, and is fully compatible with the Tk API. TkBLT is released +under the original BSD license. TkBLT includes only the Graph and +Barchart Tk widgets, and the Tcl Vector command. + +The following commands are added to the interpreter from the TkBLT library: + +Graph: A 2D plotting widget. Plots two variable data in a window with an optional +legend and annotations. It has of several components; coordinate axes, +crosshairs, a legend, and a collection of elements and tags. + +Barchart: A barchart widget. Plots two-variable data as rectangular bars in a +window. The x-coordinate values designate the position of the bar along +the x-axis, while the y-coordinate values designate the magnitude. +The barchart widget has of several components; coordinate axes, +crosshairs, a legend, and a collection of elements and tags. + +Vector: Creates a vector of floating point values. The vector's components +can be manipulated in three ways: through a Tcl array variable, a Tcl +command, or the C API. diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..0b05739 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,9 @@ +# +# Include the TEA standard macro set +# + +builtin(include,tclconfig/tcl.m4) + +# +# Add here whatever m4 macros you want to define for your package +# diff --git a/configure b/configure new file mode 100755 index 0000000..0a1414a --- /dev/null +++ b/configure @@ -0,0 +1,10270 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69 for tkblt 3.2. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='tkblt' +PACKAGE_TARNAME='tkblt' +PACKAGE_VERSION='3.2' +PACKAGE_STRING='tkblt 3.2' +PACKAGE_BUGREPORT='' +PACKAGE_URL='' + +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='LTLIBOBJS +LIBOBJS +PATCHLEVEL +MINOR_VERSION +MAJOR_VERSION +tkblt_STUB_LIB_PATH +tkblt_BUILD_STUB_LIB_PATH +tkblt_STUB_LIB_SPEC +tkblt_BUILD_STUB_LIB_SPEC +tkblt_LIB_SPEC +tkblt_BUILD_LIB_SPEC +WISH_PROG +TCLSH_PROG +VC_MANIFEST_EMBED_EXE +VC_MANIFEST_EMBED_DLL +RANLIB_STUB +MAKE_STUB_LIB +MAKE_STATIC_LIB +MAKE_SHARED_LIB +MAKE_LIB +TCL_DBGX +LDFLAGS_DEFAULT +CFLAGS_DEFAULT +LD_LIBRARY_PATH_VAR +SHLIB_CFLAGS +SHLIB_LD_LIBS +SHLIB_LD +STLIB_LD +CFLAGS_WARNING +CFLAGS_OPTIMIZE +CFLAGS_DEBUG +RC +CELIB_DIR +AR +STUBS_BUILD +SHARED_BUILD +TCL_THREADS +XMKMF +TK_XLIB_DIR_NATIVE +TK_TOP_DIR_NATIVE +TK_INCLUDES +TCL_TOP_DIR_NATIVE +TCL_INCLUDES +PKG_OBJECTS +PKG_SOURCES +EGREP +GREP +RANLIB +SET_MAKE +CPP +TK_XINCLUDES +TK_LIBS +TK_STUB_LIB_SPEC +TK_STUB_LIB_FLAG +TK_STUB_LIB_FILE +TK_LIB_SPEC +TK_LIB_FLAG +TK_LIB_FILE +TK_SRC_DIR +TK_BIN_DIR +TK_VERSION +TCL_SHLIB_LD_LIBS +TCL_LD_FLAGS +TCL_EXTRA_CFLAGS +TCL_DEFS +TCL_LIBS +CLEANFILES +OBJEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +TCL_STUB_LIB_SPEC +TCL_STUB_LIB_FLAG +TCL_STUB_LIB_FILE +TCL_LIB_SPEC +TCL_LIB_FLAG +TCL_LIB_FILE +TCL_SRC_DIR +TCL_BIN_DIR +TCL_PATCH_LEVEL +TCL_VERSION +INSTALL_LIBRARY +INSTALL_SCRIPT +INSTALL_PROGRAM +INSTALL_DATA +INSTALL_DATA_DIR +INSTALL +PKG_CFLAGS +PKG_LIBS +PKG_INCLUDES +PKG_HEADERS +PKG_TCL_SOURCES +PKG_STUB_OBJECTS +PKG_STUB_SOURCES +PKG_STUB_LIB_FILE +PKG_LIB_FILE +EXEEXT +CYGPATH +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +with_tcl +with_tk +with_tclinclude +with_tkinclude +with_x +enable_threads +enable_shared +enable_stubs +enable_64bit +enable_64bit_vis +enable_rpath +enable_wince +with_celib +enable_symbols +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP +XMKMF' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures tkblt 3.2 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/tkblt] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +X features: + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of tkblt 3.2:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-threads build with threads (default: on) + --enable-shared build and link with shared libraries (default: on) + --enable-stubs build and link with stub libraries. Always true for + shared builds (default: on) + --enable-64bit enable 64bit support (default: off) + --enable-64bit-vis enable 64bit Sparc VIS support (default: off) + --disable-rpath disable rpath support (default: on) + --enable-wince enable Win/CE support (where applicable) + --enable-symbols build with debugging symbols (default: off) + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-tcl directory containing tcl configuration + (tclConfig.sh) + --with-tk directory containing tk configuration (tkConfig.sh) + --with-tclinclude directory containing the public Tcl header files + --with-tkinclude directory containing the public Tk header files + --with-x use the X Window System + --with-celib=DIR use Windows/CE support library from DIR + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + XMKMF Path to xmkmf, Makefile generator for X Window System + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +tkblt configure 3.2 +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by tkblt $as_me 3.2, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +#-------------------------------------------------------------------- +# 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_VERSION="3.13" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking TEA configuration" >&5 +$as_echo_n "checking TEA configuration... " >&6; } + if test x"${PACKAGE_NAME}" = x ; then + as_fn_error $? " +The PACKAGE_NAME variable must be defined by your TEA configure.ac" "$LINENO" 5 + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok (TEA ${TEA_VERSION})" >&5 +$as_echo "ok (TEA ${TEA_VERSION})" >&6; } + + # If the user did not set CFLAGS, set it now to keep macros + # like AC_PROG_CC and AC_TRY_COMPILE from adding "-g -O2". + if test "${CFLAGS+set}" != "set" ; then + CFLAGS="" + fi + + case "`uname -s`" in + *win32*|*WIN32*|*MINGW32_*|*MINGW64_*) + # Extract the first word of "cygpath", so it can be a program name with args. +set dummy cygpath; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CYGPATH+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CYGPATH"; then + ac_cv_prog_CYGPATH="$CYGPATH" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CYGPATH="cygpath -m" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_CYGPATH" && ac_cv_prog_CYGPATH="echo" +fi +fi +CYGPATH=$ac_cv_prog_CYGPATH +if test -n "$CYGPATH"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CYGPATH" >&5 +$as_echo "$CYGPATH" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + EXEEXT=".exe" + TEA_PLATFORM="windows" + ;; + *CYGWIN_*) + EXEEXT=".exe" + # CYGPATH and TEA_PLATFORM are determined later in LOAD_TCLCONFIG + ;; + *) + CYGPATH=echo + # Maybe we are cross-compiling.... + case ${host_alias} in + *mingw32*) + EXEEXT=".exe" + TEA_PLATFORM="windows" + ;; + *) + EXEEXT="" + TEA_PLATFORM="unix" + ;; + esac + ;; + esac + + # Check if exec_prefix is set. If not use fall back to prefix. + # Note when adjusted, so that TEA_PREFIX can correct for this. + # This is needed for recursive configures, since autoconf propagates + # $prefix, but not $exec_prefix (doh!). + if test x$exec_prefix = xNONE ; then + exec_prefix_default=yes + exec_prefix=$prefix + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}" >&5 +$as_echo "$as_me: configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}" >&6;} + + + + + # This package name must be replaced statically for AC_SUBST to work + + # Substitute STUB_LIB_FILE in case package creates a stub library too. + + + # We AC_SUBST these here to ensure they are subst'ed, + # in case the user doesn't call TEA_ADD_... + + + + + + + + + # Configure the installer. + + INSTALL='$(SHELL) $(srcdir)/tclconfig/install-sh -c' + INSTALL_DATA_DIR='${INSTALL} -d -m 755' + INSTALL_DATA='${INSTALL} -m 644' + INSTALL_PROGRAM='${INSTALL} -m 755' + INSTALL_SCRIPT='${INSTALL} -m 755' + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking system version" >&5 +$as_echo_n "checking system version... " >&6; } +if ${tcl_cv_sys_version+:} false; then : + $as_echo_n "(cached) " >&6 +else + + # TEA specific: + if test "${TEA_PLATFORM}" = "windows" ; then + tcl_cv_sys_version=windows + else + tcl_cv_sys_version=`uname -s`-`uname -r` + if test "$?" -ne 0 ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: can't find uname command" >&5 +$as_echo "$as_me: WARNING: can't find uname command" >&2;} + tcl_cv_sys_version=unknown + else + if test "`uname -s`" = "AIX" ; then + tcl_cv_sys_version=AIX-`uname -v`.`uname -r` + fi + fi + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_sys_version" >&5 +$as_echo "$tcl_cv_sys_version" >&6; } + system=$tcl_cv_sys_version + + case $system in + HP-UX-*) INSTALL_LIBRARY='${INSTALL} -m 755' ;; + *) INSTALL_LIBRARY='${INSTALL} -m 644' ;; + esac + + + + + + + + + + +ac_aux_dir= +for ac_dir in tclconfig "$srcdir"/tclconfig; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in tclconfig \"$srcdir\"/tclconfig" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + + +#-------------------------------------------------------------------- +# Load the tclConfig.sh file +#-------------------------------------------------------------------- + + + + # + # Ok, lets find the tcl configuration + # First, look for one uninstalled. + # the alternative search directory is invoked by --with-tcl + # + + if test x"${no_tcl}" = x ; then + # we reset no_tcl in case something fails here + no_tcl=true + +# Check whether --with-tcl was given. +if test "${with_tcl+set}" = set; then : + withval=$with_tcl; with_tclconfig="${withval}" +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tcl configuration" >&5 +$as_echo_n "checking for Tcl configuration... " >&6; } + if ${ac_cv_c_tclconfig+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + # First check to see if --with-tcl was specified. + if test x"${with_tclconfig}" != x ; then + case "${with_tclconfig}" in + */tclConfig.sh ) + if test -f "${with_tclconfig}"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself" >&5 +$as_echo "$as_me: WARNING: --with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself" >&2;} + with_tclconfig="`echo "${with_tclconfig}" | sed 's!/tclConfig\.sh$!!'`" + fi ;; + esac + if test -f "${with_tclconfig}/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd "${with_tclconfig}"; pwd)`" + else + as_fn_error $? "${with_tclconfig} directory doesn't contain tclConfig.sh" "$LINENO" 5 + fi + fi + + # then check for a private Tcl installation + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in \ + ../tcl \ + `ls -dr ../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ + `ls -dr ../tcl[8-9].[0-9] 2>/dev/null` \ + `ls -dr ../tcl[8-9].[0-9]* 2>/dev/null` \ + ../../tcl \ + `ls -dr ../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ + `ls -dr ../../tcl[8-9].[0-9] 2>/dev/null` \ + `ls -dr ../../tcl[8-9].[0-9]* 2>/dev/null` \ + ../../../tcl \ + `ls -dr ../../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ + `ls -dr ../../../tcl[8-9].[0-9] 2>/dev/null` \ + `ls -dr ../../../tcl[8-9].[0-9]* 2>/dev/null` ; do + if test "${TEA_PLATFORM}" = "windows" \ + -a -f "$i/win/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/win; pwd)`" + break + fi + if test -f "$i/unix/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" + break + fi + done + fi + + # on Darwin, check in Framework installation locations + if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then + for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ + `ls -d /Library/Frameworks 2>/dev/null` \ + `ls -d /Network/Library/Frameworks 2>/dev/null` \ + `ls -d /System/Library/Frameworks 2>/dev/null` \ + `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Library/Frameworks/Tcl.framework 2>/dev/null` \ + `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Network/Library/Frameworks/Tcl.framework 2>/dev/null` \ + `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Tcl.framework 2>/dev/null` \ + ; do + if test -f "$i/Tcl.framework/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`" + break + fi + done + fi + + # TEA specific: on Windows, check in common installation locations + if test "${TEA_PLATFORM}" = "windows" \ + -a x"${ac_cv_c_tclconfig}" = x ; then + for i in `ls -d C:/Tcl/lib 2>/dev/null` \ + `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ + ; do + if test -f "$i/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i; pwd)`" + break + fi + done + fi + + # check in a few common install locations + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in `ls -d ${libdir} 2>/dev/null` \ + `ls -d ${exec_prefix}/lib 2>/dev/null` \ + `ls -d ${prefix}/lib 2>/dev/null` \ + `ls -d /usr/local/lib 2>/dev/null` \ + `ls -d /usr/contrib/lib 2>/dev/null` \ + `ls -d /usr/pkg/lib 2>/dev/null` \ + `ls -d /usr/lib 2>/dev/null` \ + `ls -d /usr/lib64 2>/dev/null` \ + `ls -d /usr/lib/tcl8.6 2>/dev/null` \ + `ls -d /usr/lib/tcl8.5 2>/dev/null` \ + `ls -d /usr/local/lib/tcl8.6 2>/dev/null` \ + `ls -d /usr/local/lib/tcl8.5 2>/dev/null` \ + `ls -d /usr/local/lib/tcl/tcl8.6 2>/dev/null` \ + `ls -d /usr/local/lib/tcl/tcl8.5 2>/dev/null` \ + ; do + if test -f "$i/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i; pwd)`" + break + fi + done + fi + + # check in a few other private locations + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in \ + ${srcdir}/../tcl \ + `ls -dr ${srcdir}/../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ + `ls -dr ${srcdir}/../tcl[8-9].[0-9] 2>/dev/null` \ + `ls -dr ${srcdir}/../tcl[8-9].[0-9]* 2>/dev/null` ; do + if test "${TEA_PLATFORM}" = "windows" \ + -a -f "$i/win/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/win; pwd)`" + break + fi + if test -f "$i/unix/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" + break + fi + done + fi + +fi + + + if test x"${ac_cv_c_tclconfig}" = x ; then + TCL_BIN_DIR="# no Tcl configs found" + as_fn_error $? "Can't find Tcl configuration definitions. Use --with-tcl to specify a directory containing tclConfig.sh" "$LINENO" 5 + else + no_tcl= + TCL_BIN_DIR="${ac_cv_c_tclconfig}" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: found ${TCL_BIN_DIR}/tclConfig.sh" >&5 +$as_echo "found ${TCL_BIN_DIR}/tclConfig.sh" >&6; } + fi + fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for existence of ${TCL_BIN_DIR}/tclConfig.sh" >&5 +$as_echo_n "checking for existence of ${TCL_BIN_DIR}/tclConfig.sh... " >&6; } + + if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: loading" >&5 +$as_echo "loading" >&6; } + . "${TCL_BIN_DIR}/tclConfig.sh" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: could not find ${TCL_BIN_DIR}/tclConfig.sh" >&5 +$as_echo "could not find ${TCL_BIN_DIR}/tclConfig.sh" >&6; } + fi + + # eval is required to do the TCL_DBGX substitution + eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" + eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" + + # If the TCL_BIN_DIR is the build directory (not the install directory), + # then set the common variable name to the value of the build variables. + # For example, the variable TCL_LIB_SPEC will be set to the value + # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC + # instead of TCL_BUILD_LIB_SPEC since it will work with both an + # installed and uninstalled version of Tcl. + if test -f "${TCL_BIN_DIR}/Makefile" ; then + TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}" + TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}" + TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}" + elif test "`uname -s`" = "Darwin"; then + # If Tcl was built as a framework, attempt to use the libraries + # from the framework at the given location so that linking works + # against Tcl.framework installed in an arbitrary location. + case ${TCL_DEFS} in + *TCL_FRAMEWORK*) + if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then + for i in "`cd "${TCL_BIN_DIR}"; pwd`" \ + "`cd "${TCL_BIN_DIR}"/../..; pwd`"; do + if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then + TCL_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TCL_LIB_FILE}" + break + fi + done + fi + if test -f "${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"; then + TCL_STUB_LIB_SPEC="-L`echo "${TCL_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TCL_STUB_LIB_FLAG}" + TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" + fi + ;; + esac + fi + + # eval is required to do the TCL_DBGX substitution + eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" + eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" + eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" + eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking platform" >&5 +$as_echo_n "checking platform... " >&6; } + hold_cc=$CC; CC="$TCL_CC" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + #ifdef _WIN32 + #error win32 + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + TEA_PLATFORM="unix" + CYGPATH=echo + +else + + TEA_PLATFORM="windows" + # Extract the first word of "cygpath", so it can be a program name with args. +set dummy cygpath; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CYGPATH+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CYGPATH"; then + ac_cv_prog_CYGPATH="$CYGPATH" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CYGPATH="cygpath -m" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_CYGPATH" && ac_cv_prog_CYGPATH="echo" +fi +fi +CYGPATH=$ac_cv_prog_CYGPATH +if test -n "$CYGPATH"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CYGPATH" >&5 +$as_echo "$CYGPATH" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CC=$hold_cc + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TEA_PLATFORM" >&5 +$as_echo "$TEA_PLATFORM" >&6; } + + # The BUILD_$pkg is to define the correct extern storage class + # handling when making this package + +cat >>confdefs.h <<_ACEOF +#define BUILD_${PACKAGE_NAME} /**/ +_ACEOF + + # Do this here as we have fully defined TEA_PLATFORM now + if test "${TEA_PLATFORM}" = "windows" ; then + EXEEXT=".exe" + CLEANFILES="$CLEANFILES *.lib *.dll *.pdb *.exp" + fi + + # TEA specific: + + + + + + + + +#-------------------------------------------------------------------- +# Load the tkConfig.sh file if necessary (Tk extension) +#-------------------------------------------------------------------- + + + # + # Ok, lets find the tk configuration + # First, look for one uninstalled. + # the alternative search directory is invoked by --with-tk + # + + if test x"${no_tk}" = x ; then + # we reset no_tk in case something fails here + no_tk=true + +# Check whether --with-tk was given. +if test "${with_tk+set}" = set; then : + withval=$with_tk; with_tkconfig="${withval}" +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tk configuration" >&5 +$as_echo_n "checking for Tk configuration... " >&6; } + if ${ac_cv_c_tkconfig+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + # First check to see if --with-tkconfig was specified. + if test x"${with_tkconfig}" != x ; then + case "${with_tkconfig}" in + */tkConfig.sh ) + if test -f "${with_tkconfig}"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself" >&5 +$as_echo "$as_me: WARNING: --with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself" >&2;} + with_tkconfig="`echo "${with_tkconfig}" | sed 's!/tkConfig\.sh$!!'`" + fi ;; + esac + if test -f "${with_tkconfig}/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd "${with_tkconfig}"; pwd)`" + else + as_fn_error $? "${with_tkconfig} directory doesn't contain tkConfig.sh" "$LINENO" 5 + fi + fi + + # then check for a private Tk library + if test x"${ac_cv_c_tkconfig}" = x ; then + for i in \ + ../tk \ + `ls -dr ../tk[8-9].[0-9].[0-9]* 2>/dev/null` \ + `ls -dr ../tk[8-9].[0-9] 2>/dev/null` \ + `ls -dr ../tk[8-9].[0-9]* 2>/dev/null` \ + ../../tk \ + `ls -dr ../../tk[8-9].[0-9].[0-9]* 2>/dev/null` \ + `ls -dr ../../tk[8-9].[0-9] 2>/dev/null` \ + `ls -dr ../../tk[8-9].[0-9]* 2>/dev/null` \ + ../../../tk \ + `ls -dr ../../../tk[8-9].[0-9].[0-9]* 2>/dev/null` \ + `ls -dr ../../../tk[8-9].[0-9] 2>/dev/null` \ + `ls -dr ../../../tk[8-9].[0-9]* 2>/dev/null` ; do + if test "${TEA_PLATFORM}" = "windows" \ + -a -f "$i/win/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/win; pwd)`" + break + fi + if test -f "$i/unix/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" + break + fi + done + fi + + # on Darwin, check in Framework installation locations + if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tkconfig}" = x ; then + for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ + `ls -d /Library/Frameworks 2>/dev/null` \ + `ls -d /Network/Library/Frameworks 2>/dev/null` \ + `ls -d /System/Library/Frameworks 2>/dev/null` \ + `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Library/Frameworks/Tcl.framework 2>/dev/null` \ + `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Network/Library/Frameworks/Tcl.framework 2>/dev/null` \ + `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Tcl.framework 2>/dev/null` \ + ; do + if test -f "$i/Tk.framework/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/Tk.framework; pwd)`" + break + fi + done + fi + + # check in a few common install locations + if test x"${ac_cv_c_tkconfig}" = x ; then + for i in `ls -d ${libdir} 2>/dev/null` \ + `ls -d ${exec_prefix}/lib 2>/dev/null` \ + `ls -d ${prefix}/lib 2>/dev/null` \ + `ls -d /usr/local/lib 2>/dev/null` \ + `ls -d /usr/contrib/lib 2>/dev/null` \ + `ls -d /usr/pkg/lib 2>/dev/null` \ + `ls -d /usr/lib 2>/dev/null` \ + `ls -d /usr/lib64 2>/dev/null` \ + `ls -d /usr/lib/tk8.6 2>/dev/null` \ + `ls -d /usr/lib/tk8.5 2>/dev/null` \ + `ls -d /usr/local/lib/tk8.6 2>/dev/null` \ + `ls -d /usr/local/lib/tk8.5 2>/dev/null` \ + `ls -d /usr/local/lib/tcl/tk8.6 2>/dev/null` \ + `ls -d /usr/local/lib/tcl/tk8.5 2>/dev/null` \ + ; do + if test -f "$i/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i; pwd)`" + break + fi + done + fi + + # TEA specific: on Windows, check in common installation locations + if test "${TEA_PLATFORM}" = "windows" \ + -a x"${ac_cv_c_tkconfig}" = x ; then + for i in `ls -d C:/Tcl/lib 2>/dev/null` \ + `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ + ; do + if test -f "$i/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i; pwd)`" + break + fi + done + fi + + # check in a few other private locations + if test x"${ac_cv_c_tkconfig}" = x ; then + for i in \ + ${srcdir}/../tk \ + `ls -dr ${srcdir}/../tk[8-9].[0-9].[0-9]* 2>/dev/null` \ + `ls -dr ${srcdir}/../tk[8-9].[0-9] 2>/dev/null` \ + `ls -dr ${srcdir}/../tk[8-9].[0-9]* 2>/dev/null` ; do + if test "${TEA_PLATFORM}" = "windows" \ + -a -f "$i/win/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/win; pwd)`" + break + fi + if test -f "$i/unix/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" + break + fi + done + fi + +fi + + + if test x"${ac_cv_c_tkconfig}" = x ; then + TK_BIN_DIR="# no Tk configs found" + as_fn_error $? "Can't find Tk configuration definitions. Use --with-tk to specify a directory containing tkConfig.sh" "$LINENO" 5 + else + no_tk= + TK_BIN_DIR="${ac_cv_c_tkconfig}" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: found ${TK_BIN_DIR}/tkConfig.sh" >&5 +$as_echo "found ${TK_BIN_DIR}/tkConfig.sh" >&6; } + fi + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for existence of ${TK_BIN_DIR}/tkConfig.sh" >&5 +$as_echo_n "checking for existence of ${TK_BIN_DIR}/tkConfig.sh... " >&6; } + + if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: loading" >&5 +$as_echo "loading" >&6; } + . "${TK_BIN_DIR}/tkConfig.sh" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: could not find ${TK_BIN_DIR}/tkConfig.sh" >&5 +$as_echo "could not find ${TK_BIN_DIR}/tkConfig.sh" >&6; } + fi + + # eval is required to do the TK_DBGX substitution + eval "TK_LIB_FILE=\"${TK_LIB_FILE}\"" + eval "TK_STUB_LIB_FILE=\"${TK_STUB_LIB_FILE}\"" + + # If the TK_BIN_DIR is the build directory (not the install directory), + # then set the common variable name to the value of the build variables. + # For example, the variable TK_LIB_SPEC will be set to the value + # of TK_BUILD_LIB_SPEC. An extension should make use of TK_LIB_SPEC + # instead of TK_BUILD_LIB_SPEC since it will work with both an + # installed and uninstalled version of Tcl. + if test -f "${TK_BIN_DIR}/Makefile" ; then + TK_LIB_SPEC="${TK_BUILD_LIB_SPEC}" + TK_STUB_LIB_SPEC="${TK_BUILD_STUB_LIB_SPEC}" + TK_STUB_LIB_PATH="${TK_BUILD_STUB_LIB_PATH}" + elif test "`uname -s`" = "Darwin"; then + # If Tk was built as a framework, attempt to use the libraries + # from the framework at the given location so that linking works + # against Tk.framework installed in an arbitrary location. + case ${TK_DEFS} in + *TK_FRAMEWORK*) + if test -f "${TK_BIN_DIR}/${TK_LIB_FILE}"; then + for i in "`cd "${TK_BIN_DIR}"; pwd`" \ + "`cd "${TK_BIN_DIR}"/../..; pwd`"; do + if test "`basename "$i"`" = "${TK_LIB_FILE}.framework"; then + TK_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TK_LIB_FILE}" + break + fi + done + fi + if test -f "${TK_BIN_DIR}/${TK_STUB_LIB_FILE}"; then + TK_STUB_LIB_SPEC="-L` echo "${TK_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TK_STUB_LIB_FLAG}" + TK_STUB_LIB_PATH="${TK_BIN_DIR}/${TK_STUB_LIB_FILE}" + fi + ;; + esac + fi + + # eval is required to do the TK_DBGX substitution + eval "TK_LIB_FLAG=\"${TK_LIB_FLAG}\"" + eval "TK_LIB_SPEC=\"${TK_LIB_SPEC}\"" + eval "TK_STUB_LIB_FLAG=\"${TK_STUB_LIB_FLAG}\"" + eval "TK_STUB_LIB_SPEC=\"${TK_STUB_LIB_SPEC}\"" + + # TEA specific: Ensure windowingsystem is defined + if test "${TEA_PLATFORM}" = "unix" ; then + case ${TK_DEFS} in + *MAC_OSX_TK*) + +$as_echo "#define MAC_OSX_TK 1" >>confdefs.h + + TEA_WINDOWINGSYSTEM="aqua" + ;; + *) + TEA_WINDOWINGSYSTEM="x11" + ;; + esac + elif test "${TEA_PLATFORM}" = "windows" ; then + TEA_WINDOWINGSYSTEM="win32" + fi + + + + + + + + + + + + + + # TEA specific: + + + + +#----------------------------------------------------------------------- +# Handle the --prefix=... option by defaulting to what Tcl gave. +# Must be called after TEA_LOAD_TCLCONFIG and before TEA_SETUP_COMPILER. +#----------------------------------------------------------------------- + + + if test "${prefix}" = "NONE"; then + prefix_default=yes + if test x"${TCL_PREFIX}" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: --prefix defaulting to TCL_PREFIX ${TCL_PREFIX}" >&5 +$as_echo "$as_me: --prefix defaulting to TCL_PREFIX ${TCL_PREFIX}" >&6;} + prefix=${TCL_PREFIX} + else + { $as_echo "$as_me:${as_lineno-$LINENO}: --prefix defaulting to /usr/local" >&5 +$as_echo "$as_me: --prefix defaulting to /usr/local" >&6;} + prefix=/usr/local + fi + fi + if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" \ + -o x"${exec_prefix_default}" = x"yes" ; then + if test x"${TCL_EXEC_PREFIX}" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: --exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}" >&5 +$as_echo "$as_me: --exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}" >&6;} + exec_prefix=${TCL_EXEC_PREFIX} + else + { $as_echo "$as_me:${as_lineno-$LINENO}: --exec-prefix defaulting to ${prefix}" >&5 +$as_echo "$as_me: --exec-prefix defaulting to ${prefix}" >&6;} + exec_prefix=$prefix + fi + fi + + +#----------------------------------------------------------------------- +# Standard compiler checks. +# This sets up CC by using the CC env var, or looks for gcc otherwise. +# This also calls AC_PROG_CC and a few others to create the basic setup +# necessary to compile executables. +#----------------------------------------------------------------------- + + + # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE) + # in this macro, they need to go into TEA_SETUP_COMPILER instead. + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + #-------------------------------------------------------------------- + # Checks to see if the make program sets the $MAKE variable. + #-------------------------------------------------------------------- + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + + + #-------------------------------------------------------------------- + # Find ranlib + #-------------------------------------------------------------------- + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + + + #-------------------------------------------------------------------- + # Determines the correct binary file extension (.o, .obj, .exe etc.) + #-------------------------------------------------------------------- + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + # Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here. + + + #------------------------------------------------------------------------ + # If we're using GCC, see if the compiler understands -pipe. If so, use it. + # It makes compiling go faster. (This is only a performance feature.) + #------------------------------------------------------------------------ + + if test -z "$no_pipe" -a -n "$GCC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the compiler understands -pipe" >&5 +$as_echo_n "checking if the compiler understands -pipe... " >&6; } +if ${tcl_cv_cc_pipe+:} false; then : + $as_echo_n "(cached) " >&6 +else + + hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + tcl_cv_cc_pipe=yes +else + tcl_cv_cc_pipe=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS=$hold_cflags +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_pipe" >&5 +$as_echo "$tcl_cv_cc_pipe" >&6; } + if test $tcl_cv_cc_pipe = yes; then + CFLAGS="$CFLAGS -pipe" + fi + fi + + #-------------------------------------------------------------------- + # Common compiler flag setup + #-------------------------------------------------------------------- + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 +$as_echo_n "checking whether byte ordering is bigendian... " >&6; } +if ${ac_cv_c_bigendian+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_c_bigendian=unknown + # See if we're dealing with a universal compiler. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifndef __APPLE_CC__ + not a universal capable compiler + #endif + typedef int dummy; + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # Check for potential -arch flags. It is not universal unless + # there are at least two -arch flags with different values. + ac_arch= + ac_prev= + for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do + if test -n "$ac_prev"; then + case $ac_word in + i?86 | x86_64 | ppc | ppc64) + if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then + ac_arch=$ac_word + else + ac_cv_c_bigendian=universal + break + fi + ;; + esac + ac_prev= + elif test "x$ac_word" = "x-arch"; then + ac_prev=arch + fi + done +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test $ac_cv_c_bigendian = unknown; then + # See if sys/param.h defines the BYTE_ORDER macro. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + +int +main () +{ +#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ + && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ + && LITTLE_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # It does; now see whether it defined to BIG_ENDIAN or not. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + +int +main () +{ +#if BYTE_ORDER != BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_bigendian=yes +else + ac_cv_c_bigendian=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + if test $ac_cv_c_bigendian = unknown; then + # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +int +main () +{ +#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # It does; now see whether it defined to _BIG_ENDIAN or not. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +int +main () +{ +#ifndef _BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_bigendian=yes +else + ac_cv_c_bigendian=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + if test $ac_cv_c_bigendian = unknown; then + # Compile a test program. + if test "$cross_compiling" = yes; then : + # Try to guess by grepping values from an object file. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +short int ascii_mm[] = + { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; + short int ascii_ii[] = + { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; + int use_ascii (int i) { + return ascii_mm[i] + ascii_ii[i]; + } + short int ebcdic_ii[] = + { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; + short int ebcdic_mm[] = + { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; + int use_ebcdic (int i) { + return ebcdic_mm[i] + ebcdic_ii[i]; + } + extern int foo; + +int +main () +{ +return use_ascii (foo) == use_ebcdic (foo); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then + ac_cv_c_bigendian=yes + fi + if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then + if test "$ac_cv_c_bigendian" = unknown; then + ac_cv_c_bigendian=no + else + # finding both strings is unlikely to happen, but who knows? + ac_cv_c_bigendian=unknown + fi + fi +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long int l; + char c[sizeof (long int)]; + } u; + u.l = 1; + return u.c[sizeof (long int) - 1] == 1; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_c_bigendian=no +else + ac_cv_c_bigendian=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 +$as_echo "$ac_cv_c_bigendian" >&6; } + case $ac_cv_c_bigendian in #( + yes) + $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h +;; #( + no) + ;; #( + universal) + +$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h + + ;; #( + *) + as_fn_error $? "unknown endianness + presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; + esac + + + +#----------------------------------------------------------------------- +# __CHANGE__ +# Specify the C source files to compile in TEA_ADD_SOURCES, +# public headers that need to be installed in TEA_ADD_HEADERS, +# stub library C source files to compile in TEA_ADD_STUB_SOURCES, +# and runtime Tcl library files in TEA_ADD_TCL_SOURCES. +# This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS +# and PKG_TCL_SOURCES. +#----------------------------------------------------------------------- + + + vars=" +tkbltChain.C +tkbltConfig.C +tkbltGrAxis.C +tkbltGrAxisOp.C +tkbltGrAxisOption.C +tkbltGrBind.C +tkbltGrElemOp.C +tkbltGrElemOption.C +tkbltGrElem.C +tkbltGrElemBar.C +tkbltGrElemLine.C +tkbltGrElemLineSpline.C +tkbltGrHairs.C +tkbltGrHairsOp.C +tkbltGrLegd.C +tkbltGrLegdOp.C +tkbltGrMarkerOp.C +tkbltGrMarkerOption.C +tkbltGrMarker.C +tkbltGrMarkerLine.C +tkbltGrMarkerPolygon.C +tkbltGrMarkerText.C +tkbltGrMisc.C +tkbltGrPenOp.C +tkbltGrPenOption.C +tkbltGrPen.C +tkbltGrPenBar.C +tkbltGrPenLine.C +tkbltGrPostscript.C +tkbltGrPostscriptOp.C +tkbltGrPSOutput.C +tkbltGrText.C +tkbltGrXAxisOp.C +tkbltGraph.C +tkbltGraphBar.C +tkbltGraphLine.C +tkbltGraphOp.C +tkbltGraphSup.C +tkbltInt.C +tkbltNsUtil.C +tkbltParse.C +tkbltOp.C +tkbltStubInit.c +tkbltStubLib.C +tkbltSwitch.C +tkbltVecCmd.C +tkbltVecOp.C +tkbltVecMath.C +tkbltVector.C +" + for i in $vars; do + case $i in + \$*) + # allow $-var names + PKG_SOURCES="$PKG_SOURCES $i" + PKG_OBJECTS="$PKG_OBJECTS $i" + ;; + *) + # check for existence - allows for generic/win/unix VPATH + # To add more dirs here (like 'src'), you have to update VPATH + # in Makefile.in as well + if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ + -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ + -a ! -f "${srcdir}/macosx/$i" \ + ; then + as_fn_error $? "could not find source file '$i'" "$LINENO" 5 + fi + PKG_SOURCES="$PKG_SOURCES $i" + # this assumes it is in a VPATH dir + i=`basename $i` + # handle user calling this before or after TEA_SETUP_COMPILER + if test x"${OBJEXT}" != x ; then + j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" + else + j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" + fi + PKG_OBJECTS="$PKG_OBJECTS $j" + ;; + esac + done + + + + + vars=" +generic/tkbltVector.h +generic/tkbltDecls.h +" + for i in $vars; do + # check for existence, be strict because it is installed + if test ! -f "${srcdir}/$i" ; then + as_fn_error $? "could not find header file '${srcdir}/$i'" "$LINENO" 5 + fi + PKG_HEADERS="$PKG_HEADERS $i" + done + + + + vars="" + for i in $vars; do + PKG_INCLUDES="$PKG_INCLUDES $i" + done + + + + vars="-lstdc++" + for i in $vars; do + if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then + # Convert foo.lib to -lfoo for GCC. No-op if not *.lib + i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` + fi + PKG_LIBS="$PKG_LIBS $i" + done + + +if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then + + PKG_CFLAGS="$PKG_CFLAGS -TP -EHsc -D_CRT_SECURE_NO_WARNINGS -D_USE_MATH_DEFINES" + + +fi + + vars="tkbltStubLib.C" + for i in $vars; do + # check for existence - allows for generic/win/unix VPATH + if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ + -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ + -a ! -f "${srcdir}/macosx/$i" \ + ; then + as_fn_error $? "could not find stub source file '$i'" "$LINENO" 5 + fi + PKG_STUB_SOURCES="$PKG_STUB_SOURCES $i" + # this assumes it is in a VPATH dir + i=`basename $i` + # handle user calling this before or after TEA_SETUP_COMPILER + if test x"${OBJEXT}" != x ; then + j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" + else + j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" + fi + PKG_STUB_OBJECTS="$PKG_STUB_OBJECTS $j" + done + + + + + vars="library/graph.tcl" + for i in $vars; do + # check for existence, be strict because it is installed + if test ! -f "${srcdir}/$i" ; then + as_fn_error $? "could not find tcl source file '${srcdir}/$i'" "$LINENO" 5 + fi + PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i" + done + + + +#-------------------------------------------------------------------- +# __CHANGE__ +# +# You can add more files to clean if your extension creates any extra +# files by extending CLEANFILES. +# Add pkgIndex.tcl if it is generated in the Makefile instead of ./configure +# and change Makefile.in to move it from CONFIG_CLEAN_FILES to BINARIES var. +# +# A few miscellaneous platform-specific items: +# TEA_ADD_* any platform specific compiler/build info here. +#-------------------------------------------------------------------- + +#CLEANFILES="$CLEANFILES pkgIndex.tcl" +if test "${TEA_PLATFORM}" = "windows" ; then + # Ensure no empty if clauses + : + #TEA_ADD_SOURCES([win/winFile.c]) + #TEA_ADD_INCLUDES([-I\"$(${CYGPATH} ${srcdir}/win)\"]) +else + # Ensure no empty else clauses + : + #TEA_ADD_SOURCES([unix/unixFile.c]) + #TEA_ADD_LIBS([-lsuperfly]) +fi + +#-------------------------------------------------------------------- +# __CHANGE__ +# Choose which headers you need. Extension authors should try very +# hard to only rely on the Tcl public header files. Internal headers +# contain private data structures and are subject to change without +# notice. +# This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG +#-------------------------------------------------------------------- + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tcl public headers" >&5 +$as_echo_n "checking for Tcl public headers... " >&6; } + + +# Check whether --with-tclinclude was given. +if test "${with_tclinclude+set}" = set; then : + withval=$with_tclinclude; with_tclinclude=${withval} +fi + + + if ${ac_cv_c_tclh+:} false; then : + $as_echo_n "(cached) " >&6 +else + + # Use the value from --with-tclinclude, if it was given + + if test x"${with_tclinclude}" != x ; then + if test -f "${with_tclinclude}/tcl.h" ; then + ac_cv_c_tclh=${with_tclinclude} + else + as_fn_error $? "${with_tclinclude} directory does not contain tcl.h" "$LINENO" 5 + fi + else + list="" + if test "`uname -s`" = "Darwin"; then + # If Tcl was built as a framework, attempt to use + # the framework's Headers directory + case ${TCL_DEFS} in + *TCL_FRAMEWORK*) + list="`ls -d ${TCL_BIN_DIR}/Headers 2>/dev/null`" + ;; + esac + fi + + # Look in the source dir only if Tcl is not installed, + # and in that situation, look there before installed locations. + if test -f "${TCL_BIN_DIR}/Makefile" ; then + list="$list `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`" + fi + + # Check order: pkg --prefix location, Tcl's --prefix location, + # relative to directory of tclConfig.sh. + + eval "temp_includedir=${includedir}" + list="$list \ + `ls -d ${temp_includedir} 2>/dev/null` \ + `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ + `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" + if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then + list="$list /usr/local/include /usr/include" + if test x"${TCL_INCLUDE_SPEC}" != x ; then + d=`echo "${TCL_INCLUDE_SPEC}" | sed -e 's/^-I//'` + list="$list `ls -d ${d} 2>/dev/null`" + fi + fi + for i in $list ; do + if test -f "$i/tcl.h" ; then + ac_cv_c_tclh=$i + break + fi + done + fi + +fi + + + # Print a message based on how we determined the include path + + if test x"${ac_cv_c_tclh}" = x ; then + as_fn_error $? "tcl.h not found. Please specify its location with --with-tclinclude" "$LINENO" 5 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${ac_cv_c_tclh}" >&5 +$as_echo "${ac_cv_c_tclh}" >&6; } + fi + + # Convert to a native path and substitute into the output files. + + INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}` + + TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" + + + + + # Allow for --with-tclinclude to take effect and define ${ac_cv_c_tclh} + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tcl private include files" >&5 +$as_echo_n "checking for Tcl private include files... " >&6; } + + TCL_SRC_DIR_NATIVE=`${CYGPATH} ${TCL_SRC_DIR}` + TCL_TOP_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}\" + + # Check to see if tclPort.h isn't already with the public headers + # Don't look for tclInt.h because that resides with tcl.h in the core + # sources, but the Port headers are in a different directory + if test "${TEA_PLATFORM}" = "windows" -a \ + -f "${ac_cv_c_tclh}/tclWinPort.h"; then + result="private headers found with public headers" + elif test "${TEA_PLATFORM}" = "unix" -a \ + -f "${ac_cv_c_tclh}/tclUnixPort.h"; then + result="private headers found with public headers" + else + TCL_GENERIC_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/generic\" + if test "${TEA_PLATFORM}" = "windows"; then + TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/win\" + else + TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/unix\" + fi + # Overwrite the previous TCL_INCLUDES as this should capture both + # public and private headers in the same set. + # We want to ensure these are substituted so as not to require + # any *_NATIVE vars be defined in the Makefile + TCL_INCLUDES="-I${TCL_GENERIC_DIR_NATIVE} -I${TCL_PLATFORM_DIR_NATIVE}" + if test "`uname -s`" = "Darwin"; then + # If Tcl was built as a framework, attempt to use + # the framework's Headers and PrivateHeaders directories + case ${TCL_DEFS} in + *TCL_FRAMEWORK*) + if test -d "${TCL_BIN_DIR}/Headers" -a \ + -d "${TCL_BIN_DIR}/PrivateHeaders"; then + TCL_INCLUDES="-I\"${TCL_BIN_DIR}/Headers\" -I\"${TCL_BIN_DIR}/PrivateHeaders\" ${TCL_INCLUDES}" + else + TCL_INCLUDES="${TCL_INCLUDES} ${TCL_INCLUDE_SPEC} `echo "${TCL_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" + fi + ;; + esac + result="Using ${TCL_INCLUDES}" + else + if test ! -f "${TCL_SRC_DIR}/generic/tclInt.h" ; then + as_fn_error $? "Cannot find private header tclInt.h in ${TCL_SRC_DIR}" "$LINENO" 5 + fi + result="Using srcdir found in tclConfig.sh: ${TCL_SRC_DIR}" + fi + fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${result}" >&5 +$as_echo "${result}" >&6; } + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tk public headers" >&5 +$as_echo_n "checking for Tk public headers... " >&6; } + + +# Check whether --with-tkinclude was given. +if test "${with_tkinclude+set}" = set; then : + withval=$with_tkinclude; with_tkinclude=${withval} +fi + + + if ${ac_cv_c_tkh+:} false; then : + $as_echo_n "(cached) " >&6 +else + + # Use the value from --with-tkinclude, if it was given + + if test x"${with_tkinclude}" != x ; then + if test -f "${with_tkinclude}/tk.h" ; then + ac_cv_c_tkh=${with_tkinclude} + else + as_fn_error $? "${with_tkinclude} directory does not contain tk.h" "$LINENO" 5 + fi + else + list="" + if test "`uname -s`" = "Darwin"; then + # If Tk was built as a framework, attempt to use + # the framework's Headers directory. + case ${TK_DEFS} in + *TK_FRAMEWORK*) + list="`ls -d ${TK_BIN_DIR}/Headers 2>/dev/null`" + ;; + esac + fi + + # Look in the source dir only if Tk is not installed, + # and in that situation, look there before installed locations. + if test -f "${TK_BIN_DIR}/Makefile" ; then + list="$list `ls -d ${TK_SRC_DIR}/generic 2>/dev/null`" + fi + + # Check order: pkg --prefix location, Tk's --prefix location, + # relative to directory of tkConfig.sh, Tcl's --prefix location, + # relative to directory of tclConfig.sh. + + eval "temp_includedir=${includedir}" + list="$list \ + `ls -d ${temp_includedir} 2>/dev/null` \ + `ls -d ${TK_PREFIX}/include 2>/dev/null` \ + `ls -d ${TK_BIN_DIR}/../include 2>/dev/null` \ + `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ + `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" + if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then + list="$list /usr/local/include /usr/include" + if test x"${TK_INCLUDE_SPEC}" != x ; then + d=`echo "${TK_INCLUDE_SPEC}" | sed -e 's/^-I//'` + list="$list `ls -d ${d} 2>/dev/null`" + fi + fi + for i in $list ; do + if test -f "$i/tk.h" ; then + ac_cv_c_tkh=$i + break + fi + done + fi + +fi + + + # Print a message based on how we determined the include path + + if test x"${ac_cv_c_tkh}" = x ; then + as_fn_error $? "tk.h not found. Please specify its location with --with-tkinclude" "$LINENO" 5 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${ac_cv_c_tkh}" >&5 +$as_echo "${ac_cv_c_tkh}" >&6; } + fi + + # Convert to a native path and substitute into the output files. + + INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tkh}` + + TK_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" + + + + if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then + # On Windows and Aqua, we need the X compat headers + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X11 header files" >&5 +$as_echo_n "checking for X11 header files... " >&6; } + if test ! -r "${INCLUDE_DIR_NATIVE}/X11/Xlib.h"; then + INCLUDE_DIR_NATIVE="`${CYGPATH} ${TK_SRC_DIR}/xlib`" + TK_XINCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${INCLUDE_DIR_NATIVE}" >&5 +$as_echo "${INCLUDE_DIR_NATIVE}" >&6; } + fi + + + # Allow for --with-tkinclude to take effect and define ${ac_cv_c_tkh} + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tk private include files" >&5 +$as_echo_n "checking for Tk private include files... " >&6; } + + TK_SRC_DIR_NATIVE=`${CYGPATH} ${TK_SRC_DIR}` + TK_TOP_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}\" + + # Check to see if tkPort.h isn't already with the public headers + # Don't look for tkInt.h because that resides with tk.h in the core + # sources, but the Port headers are in a different directory + if test "${TEA_PLATFORM}" = "windows" -a \ + -f "${ac_cv_c_tkh}/tkWinPort.h"; then + result="private headers found with public headers" + elif test "${TEA_PLATFORM}" = "unix" -a \ + -f "${ac_cv_c_tkh}/tkUnixPort.h"; then + result="private headers found with public headers" + else + TK_GENERIC_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/generic\" + TK_XLIB_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/xlib\" + if test "${TEA_PLATFORM}" = "windows"; then + TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/win\" + else + TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/unix\" + fi + # Overwrite the previous TK_INCLUDES as this should capture both + # public and private headers in the same set. + # We want to ensure these are substituted so as not to require + # any *_NATIVE vars be defined in the Makefile + TK_INCLUDES="-I${TK_GENERIC_DIR_NATIVE} -I${TK_PLATFORM_DIR_NATIVE}" + # Detect and add ttk subdir + if test -d "${TK_SRC_DIR}/generic/ttk"; then + TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/generic/ttk\"" + fi + if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then + TK_INCLUDES="${TK_INCLUDES} -I\"${TK_XLIB_DIR_NATIVE}\"" + fi + if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then + TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/macosx\"" + fi + if test "`uname -s`" = "Darwin"; then + # If Tk was built as a framework, attempt to use + # the framework's Headers and PrivateHeaders directories + case ${TK_DEFS} in + *TK_FRAMEWORK*) + if test -d "${TK_BIN_DIR}/Headers" -a \ + -d "${TK_BIN_DIR}/PrivateHeaders"; then + TK_INCLUDES="-I\"${TK_BIN_DIR}/Headers\" -I\"${TK_BIN_DIR}/PrivateHeaders\" ${TK_INCLUDES}" + else + TK_INCLUDES="${TK_INCLUDES} ${TK_INCLUDE_SPEC} `echo "${TK_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" + fi + ;; + esac + result="Using ${TK_INCLUDES}" + else + if test ! -f "${TK_SRC_DIR}/generic/tkInt.h" ; then + as_fn_error $? "Cannot find private header tkInt.h in ${TK_SRC_DIR}" "$LINENO" 5 + fi + result="Using srcdir found in tkConfig.sh: ${TK_SRC_DIR}" + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${result}" >&5 +$as_echo "${result}" >&6; } + + + if test "${TEA_WINDOWINGSYSTEM}" = "x11" ; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X" >&5 +$as_echo_n "checking for X... " >&6; } + + +# Check whether --with-x was given. +if test "${with_x+set}" = set; then : + withval=$with_x; +fi + +# $have_x is `yes', `no', `disabled', or empty when we do not yet know. +if test "x$with_x" = xno; then + # The user explicitly disabled X. + have_x=disabled +else + case $x_includes,$x_libraries in #( + *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5;; #( + *,NONE | NONE,*) if ${ac_cv_have_x+:} false; then : + $as_echo_n "(cached) " >&6 +else + # One or both of the vars are not set, and there is no cached value. +ac_x_includes=no ac_x_libraries=no +rm -f -r conftest.dir +if mkdir conftest.dir; then + cd conftest.dir + cat >Imakefile <<'_ACEOF' +incroot: + @echo incroot='${INCROOT}' +usrlibdir: + @echo usrlibdir='${USRLIBDIR}' +libdir: + @echo libdir='${LIBDIR}' +_ACEOF + if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then + # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. + for ac_var in incroot usrlibdir libdir; do + eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`" + done + # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. + for ac_extension in a so sl dylib la dll; do + if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" && + test -f "$ac_im_libdir/libX11.$ac_extension"; then + ac_im_usrlibdir=$ac_im_libdir; break + fi + done + # Screen out bogus values from the imake configuration. They are + # bogus both because they are the default anyway, and because + # using them would break gcc on systems where it needs fixed includes. + case $ac_im_incroot in + /usr/include) ac_x_includes= ;; + *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; + esac + case $ac_im_usrlibdir in + /usr/lib | /usr/lib64 | /lib | /lib64) ;; + *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; + esac + fi + cd .. + rm -f -r conftest.dir +fi + +# Standard set of common directories for X headers. +# Check X11 before X11Rn because it is often a symlink to the current release. +ac_x_header_dirs=' +/usr/X11/include +/usr/X11R7/include +/usr/X11R6/include +/usr/X11R5/include +/usr/X11R4/include + +/usr/include/X11 +/usr/include/X11R7 +/usr/include/X11R6 +/usr/include/X11R5 +/usr/include/X11R4 + +/usr/local/X11/include +/usr/local/X11R7/include +/usr/local/X11R6/include +/usr/local/X11R5/include +/usr/local/X11R4/include + +/usr/local/include/X11 +/usr/local/include/X11R7 +/usr/local/include/X11R6 +/usr/local/include/X11R5 +/usr/local/include/X11R4 + +/usr/X386/include +/usr/x386/include +/usr/XFree86/include/X11 + +/usr/include +/usr/local/include +/usr/unsupported/include +/usr/athena/include +/usr/local/x11r5/include +/usr/lpp/Xamples/include + +/usr/openwin/include +/usr/openwin/share/include' + +if test "$ac_x_includes" = no; then + # Guess where to find include files, by looking for Xlib.h. + # First, try using that file with no special directory specified. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # We can compile using X headers with no special include directory. +ac_x_includes= +else + for ac_dir in $ac_x_header_dirs; do + if test -r "$ac_dir/X11/Xlib.h"; then + ac_x_includes=$ac_dir + break + fi +done +fi +rm -f conftest.err conftest.i conftest.$ac_ext +fi # $ac_x_includes = no + +if test "$ac_x_libraries" = no; then + # Check for the libraries. + # See if we find them without any special options. + # Don't add to $LIBS permanently. + ac_save_LIBS=$LIBS + LIBS="-lX11 $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +XrmInitialize () + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + LIBS=$ac_save_LIBS +# We can link X programs with no special library path. +ac_x_libraries= +else + LIBS=$ac_save_LIBS +for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` +do + # Don't even attempt the hair of trying to link an X program! + for ac_extension in a so sl dylib la dll; do + if test -r "$ac_dir/libX11.$ac_extension"; then + ac_x_libraries=$ac_dir + break 2 + fi + done +done +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi # $ac_x_libraries = no + +case $ac_x_includes,$ac_x_libraries in #( + no,* | *,no | *\'*) + # Didn't find X, or a directory has "'" in its name. + ac_cv_have_x="have_x=no";; #( + *) + # Record where we found X for the cache. + ac_cv_have_x="have_x=yes\ + ac_x_includes='$ac_x_includes'\ + ac_x_libraries='$ac_x_libraries'" +esac +fi +;; #( + *) have_x=yes;; + esac + eval "$ac_cv_have_x" +fi # $with_x != no + +if test "$have_x" != yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5 +$as_echo "$have_x" >&6; } + no_x=yes +else + # If each of the values was on the command line, it overrides each guess. + test "x$x_includes" = xNONE && x_includes=$ac_x_includes + test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries + # Update the cache value to reflect the command line values. + ac_cv_have_x="have_x=yes\ + ac_x_includes='$x_includes'\ + ac_x_libraries='$x_libraries'" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5 +$as_echo "libraries $x_libraries, headers $x_includes" >&6; } +fi + + not_really_there="" + if test "$no_x" = ""; then + if test "$x_includes" = ""; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + not_really_there="yes" +fi +rm -f conftest.err conftest.i conftest.$ac_ext + else + if test ! -r $x_includes/X11/Xlib.h; then + not_really_there="yes" + fi + fi + fi + if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X11 header files" >&5 +$as_echo_n "checking for X11 header files... " >&6; } + found_xincludes="no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + found_xincludes="yes" +else + found_xincludes="no" +fi +rm -f conftest.err conftest.i conftest.$ac_ext + if test "$found_xincludes" = "no"; then + dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include" + for i in $dirs ; do + if test -r $i/X11/Xlib.h; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $i" >&5 +$as_echo "$i" >&6; } + XINCLUDES=" -I$i" + found_xincludes="yes" + break + fi + done + fi + else + if test "$x_includes" != ""; then + XINCLUDES="-I$x_includes" + found_xincludes="yes" + fi + fi + if test "$found_xincludes" = "no"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: couldn't find any!" >&5 +$as_echo "couldn't find any!" >&6; } + fi + + if test "$no_x" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X11 libraries" >&5 +$as_echo_n "checking for X11 libraries... " >&6; } + XLIBSW=nope + dirs="/usr/unsupported/lib /usr/local/lib /usr/X386/lib /usr/X11R6/lib /usr/X11R5/lib /usr/lib/X11R5 /usr/lib/X11R4 /usr/openwin/lib /usr/X11/lib /usr/sww/X11/lib" + for i in $dirs ; do + if test -r $i/libX11.a -o -r $i/libX11.so -o -r $i/libX11.sl -o -r $i/libX11.dylib; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $i" >&5 +$as_echo "$i" >&6; } + XLIBSW="-L$i -lX11" + x_libraries="$i" + break + fi + done + else + if test "$x_libraries" = ""; then + XLIBSW=-lX11 + else + XLIBSW="-L$x_libraries -lX11" + fi + fi + if test "$XLIBSW" = nope ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XCreateWindow in -lXwindow" >&5 +$as_echo_n "checking for XCreateWindow in -lXwindow... " >&6; } +if ${ac_cv_lib_Xwindow_XCreateWindow+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lXwindow $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char XCreateWindow (); +int +main () +{ +return XCreateWindow (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_Xwindow_XCreateWindow=yes +else + ac_cv_lib_Xwindow_XCreateWindow=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xwindow_XCreateWindow" >&5 +$as_echo "$ac_cv_lib_Xwindow_XCreateWindow" >&6; } +if test "x$ac_cv_lib_Xwindow_XCreateWindow" = xyes; then : + XLIBSW=-lXwindow +fi + + fi + if test "$XLIBSW" = nope ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: could not find any! Using -lX11." >&5 +$as_echo "could not find any! Using -lX11." >&6; } + XLIBSW=-lX11 + fi + # TEA specific: + if test x"${XLIBSW}" != x ; then + PKG_LIBS="${PKG_LIBS} ${XLIBSW}" + fi + + fi + + +#-------------------------------------------------------------------- +# Check whether --enable-threads or --disable-threads was given. +# This auto-enables if Tcl was compiled threaded. +#-------------------------------------------------------------------- + + + # Check whether --enable-threads was given. +if test "${enable_threads+set}" = set; then : + enableval=$enable_threads; tcl_ok=$enableval +else + tcl_ok=yes +fi + + + if test "${enable_threads+set}" = set; then + enableval="$enable_threads" + tcl_ok=$enableval + else + tcl_ok=yes + fi + + if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then + TCL_THREADS=1 + + if test "${TEA_PLATFORM}" != "windows" ; then + # We are always OK on Windows, so check what this platform wants: + + # USE_THREAD_ALLOC tells us to try the special thread-based + # allocator that significantly reduces lock contention + +$as_echo "#define USE_THREAD_ALLOC 1" >>confdefs.h + + +$as_echo "#define _REENTRANT 1" >>confdefs.h + + if test "`uname -s`" = "SunOS" ; then + +$as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h + + fi + +$as_echo "#define _THREAD_SAFE 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthread" >&5 +$as_echo_n "checking for pthread_mutex_init in -lpthread... " >&6; } +if ${ac_cv_lib_pthread_pthread_mutex_init+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthread $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_mutex_init (); +int +main () +{ +return pthread_mutex_init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_pthread_pthread_mutex_init=yes +else + ac_cv_lib_pthread_pthread_mutex_init=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_mutex_init" >&5 +$as_echo "$ac_cv_lib_pthread_pthread_mutex_init" >&6; } +if test "x$ac_cv_lib_pthread_pthread_mutex_init" = xyes; then : + tcl_ok=yes +else + tcl_ok=no +fi + + if test "$tcl_ok" = "no"; then + # Check a little harder for __pthread_mutex_init in the same + # library, as some systems hide it there until pthread.h is + # defined. We could alternatively do an AC_TRY_COMPILE with + # pthread.h, but that will work with libpthread really doesn't + # exist, like AIX 4.2. [Bug: 4359] + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __pthread_mutex_init in -lpthread" >&5 +$as_echo_n "checking for __pthread_mutex_init in -lpthread... " >&6; } +if ${ac_cv_lib_pthread___pthread_mutex_init+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthread $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char __pthread_mutex_init (); +int +main () +{ +return __pthread_mutex_init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_pthread___pthread_mutex_init=yes +else + ac_cv_lib_pthread___pthread_mutex_init=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread___pthread_mutex_init" >&5 +$as_echo "$ac_cv_lib_pthread___pthread_mutex_init" >&6; } +if test "x$ac_cv_lib_pthread___pthread_mutex_init" = xyes; then : + tcl_ok=yes +else + tcl_ok=no +fi + + fi + + if test "$tcl_ok" = "yes"; then + # The space is needed + THREADS_LIBS=" -lpthread" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthreads" >&5 +$as_echo_n "checking for pthread_mutex_init in -lpthreads... " >&6; } +if ${ac_cv_lib_pthreads_pthread_mutex_init+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthreads $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_mutex_init (); +int +main () +{ +return pthread_mutex_init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_pthreads_pthread_mutex_init=yes +else + ac_cv_lib_pthreads_pthread_mutex_init=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthreads_pthread_mutex_init" >&5 +$as_echo "$ac_cv_lib_pthreads_pthread_mutex_init" >&6; } +if test "x$ac_cv_lib_pthreads_pthread_mutex_init" = xyes; then : + tcl_ok=yes +else + tcl_ok=no +fi + + if test "$tcl_ok" = "yes"; then + # The space is needed + THREADS_LIBS=" -lpthreads" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lc" >&5 +$as_echo_n "checking for pthread_mutex_init in -lc... " >&6; } +if ${ac_cv_lib_c_pthread_mutex_init+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lc $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_mutex_init (); +int +main () +{ +return pthread_mutex_init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_c_pthread_mutex_init=yes +else + ac_cv_lib_c_pthread_mutex_init=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_pthread_mutex_init" >&5 +$as_echo "$ac_cv_lib_c_pthread_mutex_init" >&6; } +if test "x$ac_cv_lib_c_pthread_mutex_init" = xyes; then : + tcl_ok=yes +else + tcl_ok=no +fi + + if test "$tcl_ok" = "no"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lc_r" >&5 +$as_echo_n "checking for pthread_mutex_init in -lc_r... " >&6; } +if ${ac_cv_lib_c_r_pthread_mutex_init+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lc_r $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_mutex_init (); +int +main () +{ +return pthread_mutex_init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_c_r_pthread_mutex_init=yes +else + ac_cv_lib_c_r_pthread_mutex_init=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_mutex_init" >&5 +$as_echo "$ac_cv_lib_c_r_pthread_mutex_init" >&6; } +if test "x$ac_cv_lib_c_r_pthread_mutex_init" = xyes; then : + tcl_ok=yes +else + tcl_ok=no +fi + + if test "$tcl_ok" = "yes"; then + # The space is needed + THREADS_LIBS=" -pthread" + else + TCL_THREADS=0 + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Do not know how to find pthread lib on your system - thread support disabled" >&5 +$as_echo "$as_me: WARNING: Do not know how to find pthread lib on your system - thread support disabled" >&2;} + fi + fi + fi + fi + fi + else + TCL_THREADS=0 + fi + # Do checking message here to not mess up interleaved configure output + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for building with threads" >&5 +$as_echo_n "checking for building with threads... " >&6; } + if test "${TCL_THREADS}" = 1; then + +$as_echo "#define TCL_THREADS 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (default)" >&5 +$as_echo "yes (default)" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + # TCL_THREADS sanity checking. See if our request for building with + # threads is the same as the way Tcl was built. If not, warn the user. + case ${TCL_DEFS} in + *THREADS=1*) + if test "${TCL_THREADS}" = "0"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: + Building ${PACKAGE_NAME} without threads enabled, but building against Tcl + that IS thread-enabled. It is recommended to use --enable-threads." >&5 +$as_echo "$as_me: WARNING: + Building ${PACKAGE_NAME} without threads enabled, but building against Tcl + that IS thread-enabled. It is recommended to use --enable-threads." >&2;} + fi + ;; + esac + + + +#-------------------------------------------------------------------- +# The statement below defines a collection of symbols related to +# building as a shared library instead of a static library. +#-------------------------------------------------------------------- + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to build libraries" >&5 +$as_echo_n "checking how to build libraries... " >&6; } + # Check whether --enable-shared was given. +if test "${enable_shared+set}" = set; then : + enableval=$enable_shared; shared_ok=$enableval +else + shared_ok=yes +fi + + + if test "${enable_shared+set}" = set; then + enableval="$enable_shared" + shared_ok=$enableval + else + shared_ok=yes + fi + + # Check whether --enable-stubs was given. +if test "${enable_stubs+set}" = set; then : + enableval=$enable_stubs; stubs_ok=$enableval +else + stubs_ok=yes +fi + + + if test "${enable_stubs+set}" = set; then + enableval="$enable_stubs" + stubs_ok=$enableval + else + stubs_ok=yes + fi + + # Stubs are always enabled for shared builds + if test "$shared_ok" = "yes" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: shared" >&5 +$as_echo "shared" >&6; } + SHARED_BUILD=1 + STUBS_BUILD=1 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: static" >&5 +$as_echo "static" >&6; } + SHARED_BUILD=0 + +$as_echo "#define STATIC_BUILD 1" >>confdefs.h + + if test "$stubs_ok" = "yes" ; then + STUBS_BUILD=1 + else + STUBS_BUILD=0 + fi + fi + if test "${STUBS_BUILD}" = "1" ; then + +$as_echo "#define USE_TCL_STUBS 1" >>confdefs.h + + +$as_echo "#define USE_TCLOO_STUBS 1" >>confdefs.h + + if test "${TEA_WINDOWINGSYSTEM}" != ""; then + +$as_echo "#define USE_TK_STUBS 1" >>confdefs.h + + fi + fi + + + + + +#-------------------------------------------------------------------- +# This macro figures out what flags to use with the compiler/linker +# when building shared/static debug/optimized objects. This information +# can be taken from the tclConfig.sh file, but this figures it all out. +#-------------------------------------------------------------------- + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + + + + + # Step 0.a: Enable 64 bit support? + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if 64bit support is requested" >&5 +$as_echo_n "checking if 64bit support is requested... " >&6; } + # Check whether --enable-64bit was given. +if test "${enable_64bit+set}" = set; then : + enableval=$enable_64bit; do64bit=$enableval +else + do64bit=no +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $do64bit" >&5 +$as_echo "$do64bit" >&6; } + + # Step 0.b: Enable Solaris 64 bit VIS support? + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if 64bit Sparc VIS support is requested" >&5 +$as_echo_n "checking if 64bit Sparc VIS support is requested... " >&6; } + # Check whether --enable-64bit-vis was given. +if test "${enable_64bit_vis+set}" = set; then : + enableval=$enable_64bit_vis; do64bitVIS=$enableval +else + do64bitVIS=no +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $do64bitVIS" >&5 +$as_echo "$do64bitVIS" >&6; } + # Force 64bit on with VIS + if test "$do64bitVIS" = "yes"; then : + do64bit=yes +fi + + # Step 0.c: Check if visibility support is available. Do this here so + # that platform specific alternatives can be used below if this fails. + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler supports visibility \"hidden\"" >&5 +$as_echo_n "checking if compiler supports visibility \"hidden\"... " >&6; } +if ${tcl_cv_cc_visibility_hidden+:} false; then : + $as_echo_n "(cached) " >&6 +else + + hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + extern __attribute__((__visibility__("hidden"))) void f(void); + void f(void) {} +int +main () +{ +f(); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + tcl_cv_cc_visibility_hidden=yes +else + tcl_cv_cc_visibility_hidden=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS=$hold_cflags +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_visibility_hidden" >&5 +$as_echo "$tcl_cv_cc_visibility_hidden" >&6; } + if test $tcl_cv_cc_visibility_hidden = yes; then : + + +$as_echo "#define MODULE_SCOPE extern __attribute__((__visibility__(\"hidden\")))" >>confdefs.h + + +$as_echo "#define HAVE_HIDDEN 1" >>confdefs.h + + +fi + + # Step 0.d: Disable -rpath support? + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if rpath support is requested" >&5 +$as_echo_n "checking if rpath support is requested... " >&6; } + # Check whether --enable-rpath was given. +if test "${enable_rpath+set}" = set; then : + enableval=$enable_rpath; doRpath=$enableval +else + doRpath=yes +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $doRpath" >&5 +$as_echo "$doRpath" >&6; } + + # TEA specific: Cross-compiling options for Windows/CE builds? + + if test "${TEA_PLATFORM}" = windows; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if Windows/CE build is requested" >&5 +$as_echo_n "checking if Windows/CE build is requested... " >&6; } + # Check whether --enable-wince was given. +if test "${enable_wince+set}" = set; then : + enableval=$enable_wince; doWince=$enableval +else + doWince=no +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $doWince" >&5 +$as_echo "$doWince" >&6; } + +fi + + # Set the variable "system" to hold the name and version number + # for the system. + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking system version" >&5 +$as_echo_n "checking system version... " >&6; } +if ${tcl_cv_sys_version+:} false; then : + $as_echo_n "(cached) " >&6 +else + + # TEA specific: + if test "${TEA_PLATFORM}" = "windows" ; then + tcl_cv_sys_version=windows + else + tcl_cv_sys_version=`uname -s`-`uname -r` + if test "$?" -ne 0 ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: can't find uname command" >&5 +$as_echo "$as_me: WARNING: can't find uname command" >&2;} + tcl_cv_sys_version=unknown + else + if test "`uname -s`" = "AIX" ; then + tcl_cv_sys_version=AIX-`uname -v`.`uname -r` + fi + fi + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_sys_version" >&5 +$as_echo "$tcl_cv_sys_version" >&6; } + system=$tcl_cv_sys_version + + + # Require ranlib early so we can override it in special cases below. + + + + # Set configuration options based on system name and version. + # This is similar to Tcl's unix/tcl.m4 except that we've added a + # "windows" case and removed some core-only vars. + + do64bit_ok=no + # default to '{$LIBS}' and set to "" on per-platform necessary basis + SHLIB_LD_LIBS='${LIBS}' + # When ld needs options to work in 64-bit mode, put them in + # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load] + # is disabled by the user. [Bug 1016796] + LDFLAGS_ARCH="" + UNSHARED_LIB_SUFFIX="" + # TEA specific: use PACKAGE_VERSION instead of VERSION + TCL_TRIM_DOTS='`echo ${PACKAGE_VERSION} | tr -d .`' + ECHO_VERSION='`echo ${PACKAGE_VERSION}`' + TCL_LIB_VERSIONS_OK=ok + CFLAGS_DEBUG=-g + if test "$GCC" = yes; then : + + CFLAGS_OPTIMIZE=-O2 + CFLAGS_WARNING="-Wall" + +else + + CFLAGS_OPTIMIZE=-O + CFLAGS_WARNING="" + +fi + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_AR" = x; then + AR="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +else + AR="$ac_cv_prog_AR" +fi + + STLIB_LD='${AR} cr' + LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" + if test "x$SHLIB_VERSION" = x; then : + SHLIB_VERSION="" +else + SHLIB_VERSION=".$SHLIB_VERSION" +fi + case $system in + # TEA specific: + windows) + # This is a 2-stage check to make sure we have the 64-bit SDK + # We have to know where the SDK is installed. + # This magic is based on MS Platform SDK for Win2003 SP1 - hobbs + # MACHINE is IX86 for LINK, but this is used by the manifest, + # which requires x86|amd64|ia64. + MACHINE="X86" + if test "$do64bit" != "no" ; then + if test "x${MSSDK}x" = "xx" ; then + MSSDK="C:/Progra~1/Microsoft Platform SDK" + fi + MSSDK=`echo "$MSSDK" | sed -e 's!\\\!/!g'` + PATH64="" + case "$do64bit" in + amd64|x64|yes) + MACHINE="AMD64" ; # default to AMD64 64-bit build + PATH64="${MSSDK}/Bin/Win64/x86/AMD64" + ;; + ia64) + MACHINE="IA64" + PATH64="${MSSDK}/Bin/Win64" + ;; + esac + if test "$GCC" != "yes" -a ! -d "${PATH64}" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Could not find 64-bit $MACHINE SDK to enable 64bit mode" >&5 +$as_echo "$as_me: WARNING: Could not find 64-bit $MACHINE SDK to enable 64bit mode" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ensure latest Platform SDK is installed" >&5 +$as_echo "$as_me: WARNING: Ensure latest Platform SDK is installed" >&2;} + do64bit="no" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using 64-bit $MACHINE mode" >&5 +$as_echo " Using 64-bit $MACHINE mode" >&6; } + do64bit_ok="yes" + fi + fi + + if test "$doWince" != "no" ; then + if test "$do64bit" != "no" ; then + as_fn_error $? "Windows/CE and 64-bit builds incompatible" "$LINENO" 5 + fi + if test "$GCC" = "yes" ; then + as_fn_error $? "Windows/CE and GCC builds incompatible" "$LINENO" 5 + fi + + # First, look for one uninstalled. + # the alternative search directory is invoked by --with-celib + + if test x"${no_celib}" = x ; then + # we reset no_celib in case something fails here + no_celib=true + +# Check whether --with-celib was given. +if test "${with_celib+set}" = set; then : + withval=$with_celib; with_celibconfig=${withval} +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Windows/CE celib directory" >&5 +$as_echo_n "checking for Windows/CE celib directory... " >&6; } + if ${ac_cv_c_celibconfig+:} false; then : + $as_echo_n "(cached) " >&6 +else + + # First check to see if --with-celibconfig was specified. + if test x"${with_celibconfig}" != x ; then + if test -d "${with_celibconfig}/inc" ; then + ac_cv_c_celibconfig=`(cd ${with_celibconfig}; pwd)` + else + as_fn_error $? "${with_celibconfig} directory doesn't contain inc directory" "$LINENO" 5 + fi + fi + + # then check for a celib library + if test x"${ac_cv_c_celibconfig}" = x ; then + for i in \ + ../celib-palm-3.0 \ + ../celib \ + ../../celib-palm-3.0 \ + ../../celib \ + `ls -dr ../celib-*3.[0-9]* 2>/dev/null` \ + ${srcdir}/../celib-palm-3.0 \ + ${srcdir}/../celib \ + `ls -dr ${srcdir}/../celib-*3.[0-9]* 2>/dev/null` \ + ; do + if test -d "$i/inc" ; then + ac_cv_c_celibconfig=`(cd $i; pwd)` + break + fi + done + fi + +fi + + if test x"${ac_cv_c_celibconfig}" = x ; then + as_fn_error $? "Cannot find celib support library directory" "$LINENO" 5 + else + no_celib= + CELIB_DIR=${ac_cv_c_celibconfig} + CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: found $CELIB_DIR" >&5 +$as_echo "found $CELIB_DIR" >&6; } + fi + fi + + # Set defaults for common evc4/PPC2003 setup + # Currently Tcl requires 300+, possibly 420+ for sockets + CEVERSION=420; # could be 211 300 301 400 420 ... + TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ... + ARCH=ARM; # could be ARM MIPS X86EM ... + PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002" + if test "$doWince" != "yes"; then + # If !yes then the user specified something + # Reset ARCH to allow user to skip specifying it + ARCH= + eval `echo $doWince | awk -F, '{ \ + if (length($1)) { printf "CEVERSION=\"%s\"\n", $1; \ + if ($1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \ + if (length($2)) { printf "TARGETCPU=\"%s\"\n", toupper($2) }; \ + if (length($3)) { printf "ARCH=\"%s\"\n", toupper($3) }; \ + if (length($4)) { printf "PLATFORM=\"%s\"\n", $4 }; \ + }'` + if test "x${ARCH}" = "x" ; then + ARCH=$TARGETCPU; + fi + fi + OSVERSION=WCE$CEVERSION; + if test "x${WCEROOT}" = "x" ; then + WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0" + if test ! -d "${WCEROOT}" ; then + WCEROOT="C:/Program Files/Microsoft eMbedded Tools" + fi + fi + if test "x${SDKROOT}" = "x" ; then + SDKROOT="C:/Program Files/Windows CE Tools" + if test ! -d "${SDKROOT}" ; then + SDKROOT="C:/Windows CE Tools" + fi + fi + WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'` + SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'` + if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" \ + -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then + as_fn_error $? "could not find PocketPC SDK or target compiler to enable WinCE mode $CEVERSION,$TARGETCPU,$ARCH,$PLATFORM" "$LINENO" 5 + doWince="no" + else + # We could PATH_NOSPACE these, but that's not important, + # as long as we quote them when used. + CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include" + if test -d "${CEINCLUDE}/${TARGETCPU}" ; then + CEINCLUDE="${CEINCLUDE}/${TARGETCPU}" + fi + CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" + fi + fi + + if test "$GCC" != "yes" ; then + if test "${SHARED_BUILD}" = "0" ; then + runtime=-MT + else + runtime=-MD + fi + case "x`echo \${VisualStudioVersion}`" in + x1[4-9]*) + lflags="${lflags} -nodefaultlib:libucrt.lib" + + vars="ucrt.lib" + for i in $vars; do + if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then + # Convert foo.lib to -lfoo for GCC. No-op if not *.lib + i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` + fi + PKG_LIBS="$PKG_LIBS $i" + done + + + ;; + *) + ;; + esac + + if test "$do64bit" != "no" ; then + # All this magic is necessary for the Win64 SDK RC1 - hobbs + CC="\"${PATH64}/cl.exe\"" + CFLAGS="${CFLAGS} -I\"${MSSDK}/Include\" -I\"${MSSDK}/Include/crt\" -I\"${MSSDK}/Include/crt/sys\"" + RC="\"${MSSDK}/bin/rc.exe\"" + lflags="${lflags} -nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\"" + LINKBIN="\"${PATH64}/link.exe\"" + CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d" + CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" + # Avoid 'unresolved external symbol __security_cookie' + # errors, c.f. http://support.microsoft.com/?id=894573 + + vars="bufferoverflowU.lib" + for i in $vars; do + if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then + # Convert foo.lib to -lfoo for GCC. No-op if not *.lib + i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` + fi + PKG_LIBS="$PKG_LIBS $i" + done + + + elif test "$doWince" != "no" ; then + CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin" + if test "${TARGETCPU}" = "X86"; then + CC="\"${CEBINROOT}/cl.exe\"" + else + CC="\"${CEBINROOT}/cl${ARCH}.exe\"" + fi + CFLAGS="$CFLAGS -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\"" + RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\"" + arch=`echo ${ARCH} | awk '{print tolower($0)}'` + defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _WINDOWS" + if test "${SHARED_BUILD}" = "1" ; then + # Static CE builds require static celib as well + defs="${defs} _DLL" + fi + for i in $defs ; do + +cat >>confdefs.h <<_ACEOF +#define $i 1 +_ACEOF + + done + +cat >>confdefs.h <<_ACEOF +#define _WIN32_WCE $CEVERSION +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define UNDER_CE $CEVERSION +_ACEOF + + CFLAGS_DEBUG="-nologo -Zi -Od" + CFLAGS_OPTIMIZE="-nologo -Ox" + lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'` + lflags="${lflags} -MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo" + LINKBIN="\"${CEBINROOT}/link.exe\"" + + else + RC="rc" + lflags="${lflags} -nologo" + LINKBIN="link" + CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d" + CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" + fi + fi + + if test "$GCC" = "yes"; then + # mingw gcc mode + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}windres", so it can be a program name with args. +set dummy ${ac_tool_prefix}windres; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RC"; then + ac_cv_prog_RC="$RC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RC="${ac_tool_prefix}windres" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RC=$ac_cv_prog_RC +if test -n "$RC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RC" >&5 +$as_echo "$RC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RC"; then + ac_ct_RC=$RC + # Extract the first word of "windres", so it can be a program name with args. +set dummy windres; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RC"; then + ac_cv_prog_ac_ct_RC="$ac_ct_RC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RC="windres" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RC=$ac_cv_prog_ac_ct_RC +if test -n "$ac_ct_RC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RC" >&5 +$as_echo "$ac_ct_RC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RC" = x; then + RC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RC=$ac_ct_RC + fi +else + RC="$ac_cv_prog_RC" +fi + + CFLAGS_DEBUG="-g" + CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" + SHLIB_LD='${CC} -shared' + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' + LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" + LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cross-compile version of gcc" >&5 +$as_echo_n "checking for cross-compile version of gcc... " >&6; } +if ${ac_cv_cross+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #ifdef _WIN32 + #error cross-compiler + #endif + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_cross=yes +else + ac_cv_cross=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cross" >&5 +$as_echo "$ac_cv_cross" >&6; } + if test "$ac_cv_cross" = "yes"; then + case "$do64bit" in + amd64|x64|yes) + CC="x86_64-w64-mingw32-gcc" + LD="x86_64-w64-mingw32-ld" + AR="x86_64-w64-mingw32-ar" + RANLIB="x86_64-w64-mingw32-ranlib" + RC="x86_64-w64-mingw32-windres" + ;; + *) + CC="i686-w64-mingw32-gcc" + LD="i686-w64-mingw32-ld" + AR="i686-w64-mingw32-ar" + RANLIB="i686-w64-mingw32-ranlib" + RC="i686-w64-mingw32-windres" + ;; + esac + fi + + else + SHLIB_LD="${LINKBIN} -dll ${lflags}" + # link -lib only works when -lib is the first arg + STLIB_LD="${LINKBIN} -lib ${lflags}" + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.lib' + PATHTYPE=-w + # For information on what debugtype is most useful, see: + # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp + # and also + # http://msdn2.microsoft.com/en-us/library/y0zzbyt4%28VS.80%29.aspx + # This essentially turns it all on. + LDFLAGS_DEBUG="-debug -debugtype:cv" + LDFLAGS_OPTIMIZE="-release" + if test "$doWince" != "no" ; then + LDFLAGS_CONSOLE="-link ${lflags}" + LDFLAGS_WINDOW=${LDFLAGS_CONSOLE} + else + LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}" + LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}" + fi + fi + + SHLIB_SUFFIX=".dll" + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll' + + TCL_LIB_VERSIONS_OK=nodots + ;; + AIX-*) + if test "${TCL_THREADS}" = "1" -a "$GCC" != "yes"; then : + + # AIX requires the _r compiler when gcc isn't being used + case "${CC}" in + *_r|*_r\ *) + # ok ... + ;; + *) + # Make sure only first arg gets _r + CC=`echo "$CC" | sed -e 's/^\([^ ]*\)/\1_r/'` + ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using $CC for compiling with threads" >&5 +$as_echo "Using $CC for compiling with threads" >&6; } + +fi + LIBS="$LIBS -lc" + SHLIB_CFLAGS="" + SHLIB_SUFFIX=".so" + + LD_LIBRARY_PATH_VAR="LIBPATH" + + # Check to enable 64-bit flags for compiler/linker + if test "$do64bit" = yes; then : + + if test "$GCC" = yes; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC on $system" >&5 +$as_echo "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;} + +else + + do64bit_ok=yes + CFLAGS="$CFLAGS -q64" + LDFLAGS_ARCH="-q64" + RANLIB="${RANLIB} -X64" + AR="${AR} -X64" + SHLIB_LD_FLAGS="-b64" + +fi + +fi + + if test "`uname -m`" = ia64; then : + + # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC + SHLIB_LD="/usr/ccs/bin/ld -G -z text" + if test "$GCC" = yes; then : + + CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' + +else + + CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}' + +fi + LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' + +else + + if test "$GCC" = yes; then : + + SHLIB_LD='${CC} -shared -Wl,-bexpall' + +else + + SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bexpall -H512 -T512 -bnoentry" + LDFLAGS="$LDFLAGS -brtl" + +fi + SHLIB_LD="${SHLIB_LD} ${SHLIB_LD_FLAGS}" + CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + +fi + ;; + BeOS*) + SHLIB_CFLAGS="-fPIC" + SHLIB_LD='${CC} -nostart' + SHLIB_SUFFIX=".so" + + #----------------------------------------------------------- + # Check for inet_ntoa in -lbind, for BeOS (which also needs + # -lsocket, even if the network functions are in -lnet which + # is always linked to, for compatibility. + #----------------------------------------------------------- + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_ntoa in -lbind" >&5 +$as_echo_n "checking for inet_ntoa in -lbind... " >&6; } +if ${ac_cv_lib_bind_inet_ntoa+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lbind $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char inet_ntoa (); +int +main () +{ +return inet_ntoa (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_bind_inet_ntoa=yes +else + ac_cv_lib_bind_inet_ntoa=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bind_inet_ntoa" >&5 +$as_echo "$ac_cv_lib_bind_inet_ntoa" >&6; } +if test "x$ac_cv_lib_bind_inet_ntoa" = xyes; then : + LIBS="$LIBS -lbind -lsocket" +fi + + ;; + BSD/OS-4.*) + SHLIB_CFLAGS="-export-dynamic -fPIC" + SHLIB_LD='${CC} -shared' + SHLIB_SUFFIX=".so" + LDFLAGS="$LDFLAGS -export-dynamic" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + CYGWIN_*) + SHLIB_CFLAGS="" + SHLIB_LD='${CC} -shared' + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,--out-implib,\$@.a" + SHLIB_SUFFIX=".dll" + EXEEXT=".exe" + do64bit_ok=yes + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + Haiku*) + LDFLAGS="$LDFLAGS -Wl,--export-dynamic" + SHLIB_CFLAGS="-fPIC" + SHLIB_SUFFIX=".so" + SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS} -shared' + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_ntoa in -lnetwork" >&5 +$as_echo_n "checking for inet_ntoa in -lnetwork... " >&6; } +if ${ac_cv_lib_network_inet_ntoa+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnetwork $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char inet_ntoa (); +int +main () +{ +return inet_ntoa (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_network_inet_ntoa=yes +else + ac_cv_lib_network_inet_ntoa=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_network_inet_ntoa" >&5 +$as_echo "$ac_cv_lib_network_inet_ntoa" >&6; } +if test "x$ac_cv_lib_network_inet_ntoa" = xyes; then : + LIBS="$LIBS -lnetwork" +fi + + ;; + HP-UX-*.11.*) + # Use updated header definitions where possible + +$as_echo "#define _XOPEN_SOURCE_EXTENDED 1" >>confdefs.h + + # TEA specific: Needed by Tcl, but not most extensions + #AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?]) + #LIBS="$LIBS -lxnet" # Use the XOPEN network library + + if test "`uname -m`" = ia64; then : + + SHLIB_SUFFIX=".so" + # Use newer C++ library for C++ extensions + #if test "$GCC" != "yes" ; then + # CPPFLAGS="-AA" + #fi + +else + + SHLIB_SUFFIX=".sl" + +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 +$as_echo_n "checking for shl_load in -ldld... " >&6; } +if ${ac_cv_lib_dld_shl_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_shl_load=yes +else + ac_cv_lib_dld_shl_load=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 +$as_echo "$ac_cv_lib_dld_shl_load" >&6; } +if test "x$ac_cv_lib_dld_shl_load" = xyes; then : + tcl_ok=yes +else + tcl_ok=no +fi + + if test "$tcl_ok" = yes; then : + + LDFLAGS="$LDFLAGS -Wl,-E" + CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' + LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' + LD_LIBRARY_PATH_VAR="SHLIB_PATH" + +fi + if test "$GCC" = yes; then : + + SHLIB_LD='${CC} -shared' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + +else + + CFLAGS="$CFLAGS -z" + # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc + #CFLAGS="$CFLAGS +DAportable" + SHLIB_CFLAGS="+z" + SHLIB_LD="ld -b" + +fi + + # Check to enable 64-bit flags for compiler/linker + if test "$do64bit" = "yes"; then : + + if test "$GCC" = yes; then : + + case `${CC} -dumpmachine` in + hppa64*) + # 64-bit gcc in use. Fix flags for GNU ld. + do64bit_ok=yes + SHLIB_LD='${CC} -shared' + if test $doRpath = yes; then : + + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' +fi + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC on $system" >&5 +$as_echo "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;} + ;; + esac + +else + + do64bit_ok=yes + CFLAGS="$CFLAGS +DD64" + LDFLAGS_ARCH="+DD64" + +fi + +fi ;; + IRIX-6.*) + SHLIB_CFLAGS="" + SHLIB_LD="ld -n32 -shared -rdata_shared" + SHLIB_SUFFIX=".so" + if test $doRpath = yes; then : + + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' +fi + if test "$GCC" = yes; then : + + CFLAGS="$CFLAGS -mabi=n32" + LDFLAGS="$LDFLAGS -mabi=n32" + +else + + case $system in + IRIX-6.3) + # Use to build 6.2 compatible binaries on 6.3. + CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS" + ;; + *) + CFLAGS="$CFLAGS -n32" + ;; + esac + LDFLAGS="$LDFLAGS -n32" + +fi + ;; + IRIX64-6.*) + SHLIB_CFLAGS="" + SHLIB_LD="ld -n32 -shared -rdata_shared" + SHLIB_SUFFIX=".so" + if test $doRpath = yes; then : + + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' +fi + + # Check to enable 64-bit flags for compiler/linker + + if test "$do64bit" = yes; then : + + if test "$GCC" = yes; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported by gcc" >&5 +$as_echo "$as_me: WARNING: 64bit mode not supported by gcc" >&2;} + +else + + do64bit_ok=yes + SHLIB_LD="ld -64 -shared -rdata_shared" + CFLAGS="$CFLAGS -64" + LDFLAGS_ARCH="-64" + +fi + +fi + ;; + Linux*|GNU*|NetBSD-Debian) + SHLIB_CFLAGS="-fPIC" + SHLIB_SUFFIX=".so" + + # TEA specific: + CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" + + # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS + SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS_DEFAULT} -shared' + LDFLAGS="$LDFLAGS -Wl,--export-dynamic" + if test $doRpath = yes; then : + + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' +fi + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + if test "`uname -m`" = "alpha"; then : + CFLAGS="$CFLAGS -mieee" +fi + if test $do64bit = yes; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -m64 flag" >&5 +$as_echo_n "checking if compiler accepts -m64 flag... " >&6; } +if ${tcl_cv_cc_m64+:} false; then : + $as_echo_n "(cached) " >&6 +else + + hold_cflags=$CFLAGS + CFLAGS="$CFLAGS -m64" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + tcl_cv_cc_m64=yes +else + tcl_cv_cc_m64=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS=$hold_cflags +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_m64" >&5 +$as_echo "$tcl_cv_cc_m64" >&6; } + if test $tcl_cv_cc_m64 = yes; then : + + CFLAGS="$CFLAGS -m64" + do64bit_ok=yes + +fi + +fi + + # The combo of gcc + glibc has a bug related to inlining of + # functions like strtod(). The -fno-builtin flag should address + # this problem but it does not work. The -fno-inline flag is kind + # of overkill but it works. Disable inlining only when one of the + # files in compat/*.c is being linked in. + + if test x"${USE_COMPAT}" != x; then : + CFLAGS="$CFLAGS -fno-inline" +fi + ;; + Lynx*) + SHLIB_CFLAGS="-fPIC" + SHLIB_SUFFIX=".so" + CFLAGS_OPTIMIZE=-02 + SHLIB_LD='${CC} -shared' + LD_FLAGS="-Wl,--export-dynamic" + if test $doRpath = yes; then : + + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' +fi + ;; + OpenBSD-*) + arch=`arch -s` + case "$arch" in + alpha|sparc64) + SHLIB_CFLAGS="-fPIC" + ;; + *) + SHLIB_CFLAGS="-fpic" + ;; + esac + SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared' + SHLIB_SUFFIX=".so" + if test $doRpath = yes; then : + + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' +fi + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so${SHLIB_VERSION}' + LDFLAGS="-Wl,-export-dynamic" + CFLAGS_OPTIMIZE="-O2" + if test "${TCL_THREADS}" = "1"; then : + + # On OpenBSD: Compile with -pthread + # Don't link with -lpthread + LIBS=`echo $LIBS | sed s/-lpthread//` + CFLAGS="$CFLAGS -pthread" + +fi + # OpenBSD doesn't do version numbers with dots. + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' + TCL_LIB_VERSIONS_OK=nodots + ;; + NetBSD-*) + # NetBSD has ELF and can use 'cc -shared' to build shared libs + SHLIB_CFLAGS="-fPIC" + SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared' + SHLIB_SUFFIX=".so" + LDFLAGS="$LDFLAGS -export-dynamic" + if test $doRpath = yes; then : + + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' +fi + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + if test "${TCL_THREADS}" = "1"; then : + + # The -pthread needs to go in the CFLAGS, not LIBS + LIBS=`echo $LIBS | sed s/-pthread//` + CFLAGS="$CFLAGS -pthread" + LDFLAGS="$LDFLAGS -pthread" + +fi + ;; + DragonFly-*|FreeBSD-*) + # This configuration from FreeBSD Ports. + SHLIB_CFLAGS="-fPIC" + SHLIB_LD="${CC} -shared" + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,-soname,\$@" + SHLIB_SUFFIX=".so" + LDFLAGS="" + if test $doRpath = yes; then : + + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' +fi + if test "${TCL_THREADS}" = "1"; then : + + # The -pthread needs to go in the LDFLAGS, not LIBS + LIBS=`echo $LIBS | sed s/-pthread//` + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LDFLAGS="$LDFLAGS $PTHREAD_LIBS" +fi + case $system in + FreeBSD-3.*) + # Version numbers are dot-stripped by system policy. + TCL_TRIM_DOTS=`echo ${PACKAGE_VERSION} | tr -d .` + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1' + TCL_LIB_VERSIONS_OK=nodots + ;; + esac + ;; + Darwin-*) + CFLAGS_OPTIMIZE="-Os" + SHLIB_CFLAGS="-fno-common" + # To avoid discrepancies between what headers configure sees during + # preprocessing tests and compiling tests, move any -isysroot and + # -mmacosx-version-min flags from CFLAGS to CPPFLAGS: + CPPFLAGS="${CPPFLAGS} `echo " ${CFLAGS}" | \ + awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ + if ($i~/^(isysroot|mmacosx-version-min)/) print "-"$i}'`" + CFLAGS="`echo " ${CFLAGS}" | \ + awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ + if (!($i~/^(isysroot|mmacosx-version-min)/)) print "-"$i}'`" + if test $do64bit = yes; then : + + case `arch` in + ppc) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -arch ppc64 flag" >&5 +$as_echo_n "checking if compiler accepts -arch ppc64 flag... " >&6; } +if ${tcl_cv_cc_arch_ppc64+:} false; then : + $as_echo_n "(cached) " >&6 +else + + hold_cflags=$CFLAGS + CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + tcl_cv_cc_arch_ppc64=yes +else + tcl_cv_cc_arch_ppc64=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS=$hold_cflags +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_arch_ppc64" >&5 +$as_echo "$tcl_cv_cc_arch_ppc64" >&6; } + if test $tcl_cv_cc_arch_ppc64 = yes; then : + + CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" + do64bit_ok=yes + +fi;; + i386) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -arch x86_64 flag" >&5 +$as_echo_n "checking if compiler accepts -arch x86_64 flag... " >&6; } +if ${tcl_cv_cc_arch_x86_64+:} false; then : + $as_echo_n "(cached) " >&6 +else + + hold_cflags=$CFLAGS + CFLAGS="$CFLAGS -arch x86_64" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + tcl_cv_cc_arch_x86_64=yes +else + tcl_cv_cc_arch_x86_64=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS=$hold_cflags +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_arch_x86_64" >&5 +$as_echo "$tcl_cv_cc_arch_x86_64" >&6; } + if test $tcl_cv_cc_arch_x86_64 = yes; then : + + CFLAGS="$CFLAGS -arch x86_64" + do64bit_ok=yes + +fi;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Don't know how enable 64-bit on architecture \`arch\`" >&5 +$as_echo "$as_me: WARNING: Don't know how enable 64-bit on architecture \`arch\`" >&2;};; + esac + +else + + # Check for combined 32-bit and 64-bit fat build + if echo "$CFLAGS " |grep -E -q -- '-arch (ppc64|x86_64) ' \ + && echo "$CFLAGS " |grep -E -q -- '-arch (ppc|i386) '; then : + + fat_32_64=yes +fi + +fi + # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS + SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}' + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if ld accepts -single_module flag" >&5 +$as_echo_n "checking if ld accepts -single_module flag... " >&6; } +if ${tcl_cv_ld_single_module+:} false; then : + $as_echo_n "(cached) " >&6 +else + + hold_ldflags=$LDFLAGS + LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +int i; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + tcl_cv_ld_single_module=yes +else + tcl_cv_ld_single_module=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$hold_ldflags +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_ld_single_module" >&5 +$as_echo "$tcl_cv_ld_single_module" >&6; } + if test $tcl_cv_ld_single_module = yes; then : + + SHLIB_LD="${SHLIB_LD} -Wl,-single_module" + +fi + # TEA specific: link shlib with current and compatibility version flags + vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([0-9]\{1,5\}\)\(\(\.[0-9]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d` + SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}" + SHLIB_SUFFIX=".dylib" + # Don't use -prebind when building for Mac OS X 10.4 or later only: + if test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int($2)}'`" -lt 4 -a \ + "`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int($2)}'`" -lt 4; then : + + LDFLAGS="$LDFLAGS -prebind" +fi + LDFLAGS="$LDFLAGS -headerpad_max_install_names" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if ld accepts -search_paths_first flag" >&5 +$as_echo_n "checking if ld accepts -search_paths_first flag... " >&6; } +if ${tcl_cv_ld_search_paths_first+:} false; then : + $as_echo_n "(cached) " >&6 +else + + hold_ldflags=$LDFLAGS + LDFLAGS="$LDFLAGS -Wl,-search_paths_first" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +int i; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + tcl_cv_ld_search_paths_first=yes +else + tcl_cv_ld_search_paths_first=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$hold_ldflags +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_ld_search_paths_first" >&5 +$as_echo "$tcl_cv_ld_search_paths_first" >&6; } + if test $tcl_cv_ld_search_paths_first = yes; then : + + LDFLAGS="$LDFLAGS -Wl,-search_paths_first" + +fi + if test "$tcl_cv_cc_visibility_hidden" != yes; then : + + +$as_echo "#define MODULE_SCOPE __private_extern__" >>confdefs.h + + tcl_cv_cc_visibility_hidden=yes + +fi + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" + # TEA specific: for combined 32 & 64 bit fat builds of Tk + # extensions, verify that 64-bit build is possible. + if test "$fat_32_64" = yes && test -n "${TK_BIN_DIR}"; then : + + if test "${TEA_WINDOWINGSYSTEM}" = x11; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit X11" >&5 +$as_echo_n "checking for 64-bit X11... " >&6; } +if ${tcl_cv_lib_x11_64+:} false; then : + $as_echo_n "(cached) " >&6 +else + + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' + done + CPPFLAGS="$CPPFLAGS -I/usr/X11R6/include" + LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +XrmInitialize(); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + tcl_cv_lib_x11_64=yes +else + tcl_cv_lib_x11_64=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval $v'="$hold_'$v'"' + done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_lib_x11_64" >&5 +$as_echo "$tcl_cv_lib_x11_64" >&6; } + +fi + if test "${TEA_WINDOWINGSYSTEM}" = aqua; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit Tk" >&5 +$as_echo_n "checking for 64-bit Tk... " >&6; } +if ${tcl_cv_lib_tk_64+:} false; then : + $as_echo_n "(cached) " >&6 +else + + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' + done + CPPFLAGS="$CPPFLAGS -DUSE_TCL_STUBS=1 -DUSE_TK_STUBS=1 ${TCL_INCLUDES} ${TK_INCLUDES}" + LDFLAGS="$LDFLAGS ${TCL_STUB_LIB_SPEC} ${TK_STUB_LIB_SPEC}" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +Tk_InitStubs(NULL, "", 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + tcl_cv_lib_tk_64=yes +else + tcl_cv_lib_tk_64=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval $v'="$hold_'$v'"' + done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_lib_tk_64" >&5 +$as_echo "$tcl_cv_lib_tk_64" >&6; } + +fi + # remove 64-bit arch flags from CFLAGS et al. if configuration + # does not support 64-bit. + if test "$tcl_cv_lib_tk_64" = no -o "$tcl_cv_lib_x11_64" = no; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: Removing 64-bit architectures from compiler & linker flags" >&5 +$as_echo "$as_me: Removing 64-bit architectures from compiler & linker flags" >&6;} + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval $v'="`echo "$'$v' "|sed -e "s/-arch ppc64 / /g" -e "s/-arch x86_64 / /g"`"' + done +fi + +fi + ;; + OS/390-*) + CFLAGS_OPTIMIZE="" # Optimizer is buggy + +$as_echo "#define _OE_SOCKETS 1" >>confdefs.h + + ;; + OSF1-V*) + # Digital OSF/1 + SHLIB_CFLAGS="" + if test "$SHARED_BUILD" = 1; then : + + SHLIB_LD='ld -shared -expect_unresolved "*"' + +else + + SHLIB_LD='ld -non_shared -expect_unresolved "*"' + +fi + SHLIB_SUFFIX=".so" + if test $doRpath = yes; then : + + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' +fi + if test "$GCC" = yes; then : + CFLAGS="$CFLAGS -mieee" +else + + CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee" +fi + # see pthread_intro(3) for pthread support on osf1, k.furukawa + if test "${TCL_THREADS}" = 1; then : + + CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" + CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" + LIBS=`echo $LIBS | sed s/-lpthreads//` + if test "$GCC" = yes; then : + + LIBS="$LIBS -lpthread -lmach -lexc" + +else + + CFLAGS="$CFLAGS -pthread" + LDFLAGS="$LDFLAGS -pthread" + +fi + +fi + ;; + QNX-6*) + # QNX RTP + # This may work for all QNX, but it was only reported for v6. + SHLIB_CFLAGS="-fPIC" + SHLIB_LD="ld -Bshareable -x" + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + SCO_SV-3.2*) + if test "$GCC" = yes; then : + + SHLIB_CFLAGS="-fPIC -melf" + LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" + +else + + SHLIB_CFLAGS="-Kpic -belf" + LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" + +fi + SHLIB_LD="ld -G" + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + SunOS-5.[0-6]) + # Careful to not let 5.10+ fall into this case + + # Note: If _REENTRANT isn't defined, then Solaris + # won't define thread-safe library routines. + + +$as_echo "#define _REENTRANT 1" >>confdefs.h + + +$as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h + + + SHLIB_CFLAGS="-KPIC" + SHLIB_SUFFIX=".so" + if test "$GCC" = yes; then : + + SHLIB_LD='${CC} -shared' + CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + +else + + SHLIB_LD="/usr/ccs/bin/ld -G -z text" + CC_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + +fi + ;; + SunOS-5*) + # Note: If _REENTRANT isn't defined, then Solaris + # won't define thread-safe library routines. + + +$as_echo "#define _REENTRANT 1" >>confdefs.h + + +$as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h + + + SHLIB_CFLAGS="-KPIC" + + # Check to enable 64-bit flags for compiler/linker + if test "$do64bit" = yes; then : + + arch=`isainfo` + if test "$arch" = "sparcv9 sparc"; then : + + if test "$GCC" = yes; then : + + if test "`${CC} -dumpversion | awk -F. '{print $1}'`" -lt 3; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC < 3.2 on $system" >&5 +$as_echo "$as_me: WARNING: 64bit mode not supported with GCC < 3.2 on $system" >&2;} + +else + + do64bit_ok=yes + CFLAGS="$CFLAGS -m64 -mcpu=v9" + LDFLAGS="$LDFLAGS -m64 -mcpu=v9" + SHLIB_CFLAGS="-fPIC" + +fi + +else + + do64bit_ok=yes + if test "$do64bitVIS" = yes; then : + + CFLAGS="$CFLAGS -xarch=v9a" + LDFLAGS_ARCH="-xarch=v9a" + +else + + CFLAGS="$CFLAGS -xarch=v9" + LDFLAGS_ARCH="-xarch=v9" + +fi + # Solaris 64 uses this as well + #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" + +fi + +else + if test "$arch" = "amd64 i386"; then : + + if test "$GCC" = yes; then : + + case $system in + SunOS-5.1[1-9]*|SunOS-5.[2-9][0-9]*) + do64bit_ok=yes + CFLAGS="$CFLAGS -m64" + LDFLAGS="$LDFLAGS -m64";; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC on $system" >&5 +$as_echo "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;};; + esac + +else + + do64bit_ok=yes + case $system in + SunOS-5.1[1-9]*|SunOS-5.[2-9][0-9]*) + CFLAGS="$CFLAGS -m64" + LDFLAGS="$LDFLAGS -m64";; + *) + CFLAGS="$CFLAGS -xarch=amd64" + LDFLAGS="$LDFLAGS -xarch=amd64";; + esac + +fi + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported for $arch" >&5 +$as_echo "$as_me: WARNING: 64bit mode not supported for $arch" >&2;} +fi +fi + +fi + + SHLIB_SUFFIX=".so" + if test "$GCC" = yes; then : + + SHLIB_LD='${CC} -shared' + CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + if test "$do64bit_ok" = yes; then : + + if test "$arch" = "sparcv9 sparc"; then : + + # We need to specify -static-libgcc or we need to + # add the path to the sparv9 libgcc. + # JH: static-libgcc is necessary for core Tcl, but may + # not be necessary for extensions. + SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc" + # for finding sparcv9 libgcc, get the regular libgcc + # path, remove so name and append 'sparcv9' + #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..." + #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir" + +else + if test "$arch" = "amd64 i386"; then : + + # JH: static-libgcc is necessary for core Tcl, but may + # not be necessary for extensions. + SHLIB_LD="$SHLIB_LD -m64 -static-libgcc" + +fi +fi + +fi + +else + + case $system in + SunOS-5.[1-9][0-9]*) + # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS + SHLIB_LD='${CC} -G -z text ${LDFLAGS_DEFAULT}';; + *) + SHLIB_LD='/usr/ccs/bin/ld -G -z text';; + esac + CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' + +fi + ;; + UNIX_SV* | UnixWare-5*) + SHLIB_CFLAGS="-KPIC" + SHLIB_LD='${CC} -G' + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + # Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers + # that don't grok the -Bexport option. Test that it does. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld accepts -Bexport flag" >&5 +$as_echo_n "checking for ld accepts -Bexport flag... " >&6; } +if ${tcl_cv_ld_Bexport+:} false; then : + $as_echo_n "(cached) " >&6 +else + + hold_ldflags=$LDFLAGS + LDFLAGS="$LDFLAGS -Wl,-Bexport" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +int i; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + tcl_cv_ld_Bexport=yes +else + tcl_cv_ld_Bexport=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$hold_ldflags +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_ld_Bexport" >&5 +$as_echo "$tcl_cv_ld_Bexport" >&6; } + if test $tcl_cv_ld_Bexport = yes; then : + + LDFLAGS="$LDFLAGS -Wl,-Bexport" + +fi + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + esac + + if test "$do64bit" = yes -a "$do64bit_ok" = no; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit support being disabled -- don't know magic for this platform" >&5 +$as_echo "$as_me: WARNING: 64bit support being disabled -- don't know magic for this platform" >&2;} + +fi + + + + # Add in the arch flags late to ensure it wasn't removed. + # Not necessary in TEA, but this is aligned with core + LDFLAGS="$LDFLAGS $LDFLAGS_ARCH" + + # If we're running gcc, then change the C flags for compiling shared + # libraries to the right flags for gcc, instead of those for the + # standard manufacturer compiler. + + if test "$GCC" = yes; then : + + case $system in + AIX-*) ;; + BSD/OS*) ;; + CYGWIN_*|MINGW32_*|MINGW64_*) ;; + IRIX*) ;; + NetBSD-*|DragonFly-*|FreeBSD-*|OpenBSD-*) ;; + Darwin-*) ;; + SCO_SV-3.2*) ;; + windows) ;; + *) SHLIB_CFLAGS="-fPIC" ;; + esac +fi + + if test "$tcl_cv_cc_visibility_hidden" != yes; then : + + +$as_echo "#define MODULE_SCOPE extern" >>confdefs.h + + +fi + + if test "$SHARED_LIB_SUFFIX" = ""; then : + + # TEA specific: use PACKAGE_VERSION instead of VERSION + SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}' +fi + if test "$UNSHARED_LIB_SUFFIX" = ""; then : + + # TEA specific: use PACKAGE_VERSION instead of VERSION + UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a' +fi + + if test "${GCC}" = "yes" -a ${SHLIB_SUFFIX} = ".dll"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SEH support in compiler" >&5 +$as_echo_n "checking for SEH support in compiler... " >&6; } +if ${tcl_cv_seh+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + tcl_cv_seh=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN + + int main(int argc, char** argv) { + int a, b = 0; + __try { + a = 666 / b; + } + __except (EXCEPTION_EXECUTE_HANDLER) { + return 0; + } + return 1; + } + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + tcl_cv_seh=yes +else + tcl_cv_seh=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_seh" >&5 +$as_echo "$tcl_cv_seh" >&6; } + if test "$tcl_cv_seh" = "no" ; then + +$as_echo "#define HAVE_NO_SEH 1" >>confdefs.h + + fi + + # + # Check to see if the excpt.h include file provided contains the + # definition for EXCEPTION_DISPOSITION; if not, which is the case + # with Cygwin's version as of 2002-04-10, define it to be int, + # sufficient for getting the current code to work. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EXCEPTION_DISPOSITION support in include files" >&5 +$as_echo_n "checking for EXCEPTION_DISPOSITION support in include files... " >&6; } +if ${tcl_cv_eh_disposition+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +# define WIN32_LEAN_AND_MEAN +# include +# undef WIN32_LEAN_AND_MEAN + +int +main () +{ + + EXCEPTION_DISPOSITION x; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + tcl_cv_eh_disposition=yes +else + tcl_cv_eh_disposition=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_eh_disposition" >&5 +$as_echo "$tcl_cv_eh_disposition" >&6; } + if test "$tcl_cv_eh_disposition" = "no" ; then + +$as_echo "#define EXCEPTION_DISPOSITION int" >>confdefs.h + + fi + + # Check to see if winnt.h defines CHAR, SHORT, and LONG + # even if VOID has already been #defined. The win32api + # used by mingw and cygwin is known to do this. + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for winnt.h that ignores VOID define" >&5 +$as_echo_n "checking for winnt.h that ignores VOID define... " >&6; } +if ${tcl_cv_winnt_ignore_void+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define VOID void +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN + +int +main () +{ + + CHAR c; + SHORT s; + LONG l; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + tcl_cv_winnt_ignore_void=yes +else + tcl_cv_winnt_ignore_void=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_winnt_ignore_void" >&5 +$as_echo "$tcl_cv_winnt_ignore_void" >&6; } + if test "$tcl_cv_winnt_ignore_void" = "yes" ; then + +$as_echo "#define HAVE_WINNT_IGNORE_VOID 1" >>confdefs.h + + fi + fi + + # See if the compiler supports casting to a union type. + # This is used to stop gcc from printing a compiler + # warning when initializing a union member. + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cast to union support" >&5 +$as_echo_n "checking for cast to union support... " >&6; } +if ${tcl_cv_cast_to_union+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + union foo { int i; double d; }; + union foo f = (union foo) (int) 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + tcl_cv_cast_to_union=yes +else + tcl_cv_cast_to_union=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cast_to_union" >&5 +$as_echo "$tcl_cv_cast_to_union" >&6; } + if test "$tcl_cv_cast_to_union" = "yes"; then + +$as_echo "#define HAVE_CAST_TO_UNION 1" >>confdefs.h + + fi + + + + + + + + + + + + + + # These must be called after we do the basic CFLAGS checks and + # verify any possible 64-bit or similar switches are necessary + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for required early compiler flags" >&5 +$as_echo_n "checking for required early compiler flags... " >&6; } + tcl_flags="" + + if ${tcl_cv_flag__isoc99_source+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +char *p = (char *)strtoll; char *q = (char *)strtoull; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + tcl_cv_flag__isoc99_source=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _ISOC99_SOURCE 1 +#include +int +main () +{ +char *p = (char *)strtoll; char *q = (char *)strtoull; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + tcl_cv_flag__isoc99_source=yes +else + tcl_cv_flag__isoc99_source=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + if test "x${tcl_cv_flag__isoc99_source}" = "xyes" ; then + +$as_echo "#define _ISOC99_SOURCE 1" >>confdefs.h + + tcl_flags="$tcl_flags _ISOC99_SOURCE" + fi + + + if ${tcl_cv_flag__largefile64_source+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +struct stat64 buf; int i = stat64("/", &buf); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + tcl_cv_flag__largefile64_source=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _LARGEFILE64_SOURCE 1 +#include +int +main () +{ +struct stat64 buf; int i = stat64("/", &buf); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + tcl_cv_flag__largefile64_source=yes +else + tcl_cv_flag__largefile64_source=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + if test "x${tcl_cv_flag__largefile64_source}" = "xyes" ; then + +$as_echo "#define _LARGEFILE64_SOURCE 1" >>confdefs.h + + tcl_flags="$tcl_flags _LARGEFILE64_SOURCE" + fi + + + if ${tcl_cv_flag__largefile_source64+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +char *p = (char *)open64; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + tcl_cv_flag__largefile_source64=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _LARGEFILE_SOURCE64 1 +#include +int +main () +{ +char *p = (char *)open64; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + tcl_cv_flag__largefile_source64=yes +else + tcl_cv_flag__largefile_source64=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + if test "x${tcl_cv_flag__largefile_source64}" = "xyes" ; then + +$as_echo "#define _LARGEFILE_SOURCE64 1" >>confdefs.h + + tcl_flags="$tcl_flags _LARGEFILE_SOURCE64" + fi + + if test "x${tcl_flags}" = "x" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 +$as_echo "none" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${tcl_flags}" >&5 +$as_echo "${tcl_flags}" >&6; } + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit integer type" >&5 +$as_echo_n "checking for 64-bit integer type... " >&6; } + if ${tcl_cv_type_64bit+:} false; then : + $as_echo_n "(cached) " >&6 +else + + tcl_cv_type_64bit=none + # See if the compiler knows natively about __int64 + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +__int64 value = (__int64) 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + tcl_type_64bit=__int64 +else + tcl_type_64bit="long long" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + # See if we should use long anyway Note that we substitute in the + # type that is our current guess for a 64-bit type inside this check + # program, so it should be modified only carefully... + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +switch (0) { + case 1: case (sizeof(${tcl_type_64bit})==sizeof(long)): ; + } + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + tcl_cv_type_64bit=${tcl_type_64bit} +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + if test "${tcl_cv_type_64bit}" = none ; then + +$as_echo "#define TCL_WIDE_INT_IS_LONG 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: using long" >&5 +$as_echo "using long" >&6; } + elif test "${tcl_cv_type_64bit}" = "__int64" \ + -a "${TEA_PLATFORM}" = "windows" ; then + # TEA specific: We actually want to use the default tcl.h checks in + # this case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER* + { $as_echo "$as_me:${as_lineno-$LINENO}: result: using Tcl header defaults" >&5 +$as_echo "using Tcl header defaults" >&6; } + else + +cat >>confdefs.h <<_ACEOF +#define TCL_WIDE_INT_TYPE ${tcl_cv_type_64bit} +_ACEOF + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${tcl_cv_type_64bit}" >&5 +$as_echo "${tcl_cv_type_64bit}" >&6; } + + # Now check for auxiliary declarations + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct dirent64" >&5 +$as_echo_n "checking for struct dirent64... " >&6; } +if ${tcl_cv_struct_dirent64+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ +struct dirent64 p; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + tcl_cv_struct_dirent64=yes +else + tcl_cv_struct_dirent64=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_struct_dirent64" >&5 +$as_echo "$tcl_cv_struct_dirent64" >&6; } + if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then + +$as_echo "#define HAVE_STRUCT_DIRENT64 1" >>confdefs.h + + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct stat64" >&5 +$as_echo_n "checking for struct stat64... " >&6; } +if ${tcl_cv_struct_stat64+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +struct stat64 p; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + tcl_cv_struct_stat64=yes +else + tcl_cv_struct_stat64=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_struct_stat64" >&5 +$as_echo "$tcl_cv_struct_stat64" >&6; } + if test "x${tcl_cv_struct_stat64}" = "xyes" ; then + +$as_echo "#define HAVE_STRUCT_STAT64 1" >>confdefs.h + + fi + + for ac_func in open64 lseek64 +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for off64_t" >&5 +$as_echo_n "checking for off64_t... " >&6; } + if ${tcl_cv_type_off64_t+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +off64_t offset; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + tcl_cv_type_off64_t=yes +else + tcl_cv_type_off64_t=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + if test "x${tcl_cv_type_off64_t}" = "xyes" && \ + test "x${ac_cv_func_lseek64}" = "xyes" && \ + test "x${ac_cv_func_open64}" = "xyes" ; then + +$as_echo "#define HAVE_TYPE_OFF64_T 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + fi + + + +#-------------------------------------------------------------------- +# Set the default compiler switches based on the --enable-symbols option. +#-------------------------------------------------------------------- + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for build with symbols" >&5 +$as_echo_n "checking for build with symbols... " >&6; } + # Check whether --enable-symbols was given. +if test "${enable_symbols+set}" = set; then : + enableval=$enable_symbols; tcl_ok=$enableval +else + tcl_ok=no +fi + + DBGX="" + if test "$tcl_ok" = "no"; then + CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE} -DNDEBUG" + LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + else + CFLAGS_DEFAULT="${CFLAGS_DEBUG}" + LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}" + if test "$tcl_ok" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (standard debugging)" >&5 +$as_echo "yes (standard debugging)" >&6; } + fi + fi + # TEA specific: + if test "${TEA_PLATFORM}" != "windows" ; then + LDFLAGS_DEFAULT="${LDFLAGS}" + fi + + + + + if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then + +$as_echo "#define TCL_MEM_DEBUG 1" >>confdefs.h + + fi + + if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then + if test "$tcl_ok" = "all"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabled symbols mem debugging" >&5 +$as_echo "enabled symbols mem debugging" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabled $tcl_ok debugging" >&5 +$as_echo "enabled $tcl_ok debugging" >&6; } + fi + fi + + +#-------------------------------------------------------------------- +# This macro generates a line to use when building a library. It +# depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS, +# and TEA_LOAD_TCLCONFIG macros above. +#-------------------------------------------------------------------- + + + if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then + MAKE_STATIC_LIB="\${STLIB_LD} -out:\$@ \$(PKG_OBJECTS)" + MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LD_LIBS} \${LDFLAGS_DEFAULT} -out:\$@ \$(PKG_OBJECTS)" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#if defined(_MSC_VER) && _MSC_VER >= 1400 +print("manifest needed") +#endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "manifest needed" >/dev/null 2>&1; then : + + # Could do a CHECK_PROG for mt, but should always be with MSVC8+ + VC_MANIFEST_EMBED_DLL="if test -f \$@.manifest ; then mt.exe -nologo -manifest \$@.manifest -outputresource:\$@\;2 ; fi" + VC_MANIFEST_EMBED_EXE="if test -f \$@.manifest ; then mt.exe -nologo -manifest \$@.manifest -outputresource:\$@\;1 ; fi" + MAKE_SHARED_LIB="${MAKE_SHARED_LIB} ; ${VC_MANIFEST_EMBED_DLL}" + + CLEANFILES="$CLEANFILES *.manifest" + + +fi +rm -f conftest* + + MAKE_STUB_LIB="\${STLIB_LD} -nodefaultlib -out:\$@ \$(PKG_STUB_OBJECTS)" + else + MAKE_STATIC_LIB="\${STLIB_LD} \$@ \$(PKG_OBJECTS)" + MAKE_SHARED_LIB="\${SHLIB_LD} -o \$@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" + MAKE_STUB_LIB="\${STLIB_LD} \$@ \$(PKG_STUB_OBJECTS)" + fi + + if test "${SHARED_BUILD}" = "1" ; then + MAKE_LIB="${MAKE_SHARED_LIB} " + else + MAKE_LIB="${MAKE_STATIC_LIB} " + fi + + #-------------------------------------------------------------------- + # Shared libraries and static libraries have different names. + # Use the double eval to make sure any variables in the suffix is + # substituted. (@@@ Might not be necessary anymore) + #-------------------------------------------------------------------- + + if test "${TEA_PLATFORM}" = "windows" ; then + if test "${SHARED_BUILD}" = "1" ; then + # We force the unresolved linking of symbols that are really in + # the private libraries of Tcl and Tk. + if test x"${TK_BIN_DIR}" != x ; then + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\"" + fi + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\"" + if test "$GCC" = "yes"; then + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -static-libgcc" + fi + eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" + else + eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" + if test "$GCC" = "yes"; then + PKG_LIB_FILE=lib${PKG_LIB_FILE} + fi + fi + # Some packages build their own stubs libraries + eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" + if test "$GCC" = "yes"; then + PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE} + fi + # These aren't needed on Windows (either MSVC or gcc) + RANLIB=: + RANLIB_STUB=: + else + RANLIB_STUB="${RANLIB}" + if test "${SHARED_BUILD}" = "1" ; then + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}" + if test x"${TK_BIN_DIR}" != x ; then + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" + fi + eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" + RANLIB=: + else + eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" + fi + # Some packages build their own stubs libraries + eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" + fi + + # These are escaped so that only CFLAGS is picked up at configure time. + # The other values will be substituted at make time. + CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}" + if test "${SHARED_BUILD}" = "1" ; then + CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}" + fi + + + + + + + + + + +#-------------------------------------------------------------------- +# Determine the name of the tclsh and/or wish executables in the +# Tcl and Tk build directories or the location they were installed +# into. These paths are used to support running test cases only, +# the Makefile should not be making use of these paths to generate +# a pkgIndex.tcl file or anything else at extension build time. +#-------------------------------------------------------------------- + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tclsh" >&5 +$as_echo_n "checking for tclsh... " >&6; } + if test -f "${TCL_BIN_DIR}/Makefile" ; then + # tclConfig.sh is in Tcl build directory + if test "${TEA_PLATFORM}" = "windows"; then + if test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" ; then + TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" + elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}s${EXEEXT}" ; then + TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}s${EXEEXT}" + elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}t${EXEEXT}" ; then + TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}t${EXEEXT}" + elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}st${EXEEXT}" ; then + TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}st${EXEEXT}" + fi + else + TCLSH_PROG="${TCL_BIN_DIR}/tclsh" + fi + else + # tclConfig.sh is in install location + if test "${TEA_PLATFORM}" = "windows"; then + TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" + else + TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}${TCL_DBGX}" + fi + list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \ + `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \ + `ls -d ${TCL_PREFIX}/bin 2>/dev/null`" + for i in $list ; do + if test -f "$i/${TCLSH_PROG}" ; then + REAL_TCL_BIN_DIR="`cd "$i"; pwd`/" + break + fi + done + TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${TCLSH_PROG}" >&5 +$as_echo "${TCLSH_PROG}" >&6; } + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wish" >&5 +$as_echo_n "checking for wish... " >&6; } + if test -f "${TK_BIN_DIR}/Makefile" ; then + # tkConfig.sh is in Tk build directory + if test "${TEA_PLATFORM}" = "windows"; then + if test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" ; then + WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" + elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}s${EXEEXT}" ; then + WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}$s{EXEEXT}" + elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}t${EXEEXT}" ; then + WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}t${EXEEXT}" + elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}st${EXEEXT}" ; then + WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}st${EXEEXT}" + fi + else + WISH_PROG="${TK_BIN_DIR}/wish" + fi + else + # tkConfig.sh is in install location + if test "${TEA_PLATFORM}" = "windows"; then + WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" + else + WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}${TK_DBGX}" + fi + list="`ls -d ${TK_BIN_DIR}/../bin 2>/dev/null` \ + `ls -d ${TK_BIN_DIR}/.. 2>/dev/null` \ + `ls -d ${TK_PREFIX}/bin 2>/dev/null`" + for i in $list ; do + if test -f "$i/${WISH_PROG}" ; then + REAL_TK_BIN_DIR="`cd "$i"; pwd`/" + break + fi + done + WISH_PROG="${REAL_TK_BIN_DIR}${WISH_PROG}" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${WISH_PROG}" >&5 +$as_echo "${WISH_PROG}" >&6; } + + + +#-------------------------------------------------------------------- +# Setup a *Config.sh.in configuration file. +#-------------------------------------------------------------------- + + + #-------------------------------------------------------------------- + # These are for tkbltConfig.sh + #-------------------------------------------------------------------- + + # pkglibdir must be a fully qualified path and (not ${exec_prefix}/lib) + eval pkglibdir="${libdir}/tkblt${PACKAGE_VERSION}" + if test "${TCL_LIB_VERSIONS_OK}" = "ok"; then + eval tkblt_LIB_FLAG="-ltkblt${PACKAGE_VERSION}${DBGX}" + eval tkblt_STUB_LIB_FLAG="-ltkbltstub${PACKAGE_VERSION}${DBGX}" + else + eval tkblt_LIB_FLAG="-ltkblt`echo ${PACKAGE_VERSION} | tr -d .`${DBGX}" + eval tkblt_STUB_LIB_FLAG="-ltkbltstub`echo ${PACKAGE_VERSION} | tr -d .`${DBGX}" + fi + tkblt_BUILD_LIB_SPEC="-L`$CYGPATH $(pwd)` ${tkblt_LIB_FLAG}" + tkblt_LIB_SPEC="-L`$CYGPATH ${pkglibdir}` ${tkblt_LIB_FLAG}" + tkblt_BUILD_STUB_LIB_SPEC="-L`$CYGPATH $(pwd)` ${tkblt_STUB_LIB_FLAG}" + tkblt_STUB_LIB_SPEC="-L`$CYGPATH ${pkglibdir}` ${tkblt_STUB_LIB_FLAG}" + tkblt_BUILD_STUB_LIB_PATH="`$CYGPATH $(pwd)`/${PKG_STUB_LIB_FILE}" + tkblt_STUB_LIB_PATH="`$CYGPATH ${pkglibdir}`/${PKG_STUB_LIB_FILE}" + + + + + + + + + + + + +#AC_SUBST(SAMPLE_VAR) + +#-------------------------------------------------------------------- +# Specify files to substitute AC variables in. You may alternatively +# have a special pkgIndex.tcl.in or other files which require +# substituting the AC variables in. Include these here. +#-------------------------------------------------------------------- + +ac_config_files="$ac_config_files Makefile pkgIndex.tcl" + +ac_config_files="$ac_config_files tkbltConfig.sh" + + +#-------------------------------------------------------------------- +# Finally, substitute all of the various values into the files +# specified with AC_CONFIG_FILES. +#-------------------------------------------------------------------- + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +:mline +/\\$/{ + N + s,\\\n,, + b mline +} +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +CFLAGS="${CFLAGS} ${CPPFLAGS}"; CPPFLAGS="" + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by tkblt $as_me 3.2, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +tkblt config.status 3.2 +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h | --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "pkgIndex.tcl") CONFIG_FILES="$CONFIG_FILES pkgIndex.tcl" ;; + "tkbltConfig.sh") CONFIG_FILES="$CONFIG_FILES tkbltConfig.sh" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + + +eval set X " :F $CONFIG_FILES " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + + + + esac + +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..5bbfab0 --- /dev/null +++ b/configure.ac @@ -0,0 +1,246 @@ +#!/bin/bash -norc +dnl This file is an input file used by the GNU "autoconf" program to +dnl generate the file "configure", which is run during Tcl installation +dnl to configure the system for the local environment. + +#----------------------------------------------------------------------- +# Sample configure.ac 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. +# This will also define a special symbol for Windows (BUILD_ +# so that we create the export library with the dll. +#----------------------------------------------------------------------- + +AC_INIT([tkblt], [3.2]) + +#-------------------------------------------------------------------- +# 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() + +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 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([ +tkbltChain.C +tkbltConfig.C +tkbltGrAxis.C +tkbltGrAxisOp.C +tkbltGrAxisOption.C +tkbltGrBind.C +tkbltGrElemOp.C +tkbltGrElemOption.C +tkbltGrElem.C +tkbltGrElemBar.C +tkbltGrElemLine.C +tkbltGrElemLineSpline.C +tkbltGrHairs.C +tkbltGrHairsOp.C +tkbltGrLegd.C +tkbltGrLegdOp.C +tkbltGrMarkerOp.C +tkbltGrMarkerOption.C +tkbltGrMarker.C +tkbltGrMarkerLine.C +tkbltGrMarkerPolygon.C +tkbltGrMarkerText.C +tkbltGrMisc.C +tkbltGrPenOp.C +tkbltGrPenOption.C +tkbltGrPen.C +tkbltGrPenBar.C +tkbltGrPenLine.C +tkbltGrPostscript.C +tkbltGrPostscriptOp.C +tkbltGrPSOutput.C +tkbltGrText.C +tkbltGrXAxisOp.C +tkbltGraph.C +tkbltGraphBar.C +tkbltGraphLine.C +tkbltGraphOp.C +tkbltGraphSup.C +tkbltInt.C +tkbltNsUtil.C +tkbltParse.C +tkbltOp.C +tkbltStubInit.c +tkbltStubLib.C +tkbltSwitch.C +tkbltVecCmd.C +tkbltVecOp.C +tkbltVecMath.C +tkbltVector.C +]) +TEA_ADD_HEADERS([ +generic/tkbltVector.h +generic/tkbltDecls.h +]) +TEA_ADD_INCLUDES([]) +TEA_ADD_LIBS([-lstdc++]) +if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then +TEA_ADD_CFLAGS([-TP -EHsc -D_CRT_SECURE_NO_WARNINGS -D_USE_MATH_DEFINES]) +fi +TEA_ADD_STUB_SOURCES([tkbltStubLib.C]) +TEA_ADD_TCL_SOURCES([library/graph.tcl]) + +#-------------------------------------------------------------------- +# __CHANGE__ +# +# You can add more files to clean if your extension creates any extra +# files by extending CLEANFILES. +# Add pkgIndex.tcl if it is generated in the Makefile instead of ./configure +# and change Makefile.in to move it from CONFIG_CLEAN_FILES to BINARIES var. +# +# A few miscellaneous platform-specific items: +# TEA_ADD_* any platform specific compiler/build info here. +#-------------------------------------------------------------------- + +#CLEANFILES="$CLEANFILES pkgIndex.tcl" +if test "${TEA_PLATFORM}" = "windows" ; then + # Ensure no empty if clauses + : + #TEA_ADD_SOURCES([win/winFile.c]) + #TEA_ADD_INCLUDES([-I\"$(${CYGPATH} ${srcdir}/win)\"]) +else + # Ensure no empty else clauses + : + #TEA_ADD_SOURCES([unix/unixFile.c]) + #TEA_ADD_LIBS([-lsuperfly]) +fi + +#-------------------------------------------------------------------- +# __CHANGE__ +# Choose which headers you need. Extension authors should try very +# hard to only rely on the Tcl public header files. Internal headers +# contain private data structures and are subject to change without +# notice. +# This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG +#-------------------------------------------------------------------- + +TEA_PUBLIC_TCL_HEADERS +TEA_PRIVATE_TCL_HEADERS + +TEA_PUBLIC_TK_HEADERS +TEA_PRIVATE_TK_HEADERS +TEA_PATH_X + +#-------------------------------------------------------------------- +# Check whether --enable-threads or --disable-threads was given. +# This auto-enables if Tcl was compiled threaded. +#-------------------------------------------------------------------- + +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 + +#-------------------------------------------------------------------- +# 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 + +#-------------------------------------------------------------------- +# Determine the name of the tclsh and/or wish executables in the +# Tcl and Tk build directories or the location they were installed +# into. These paths are used to support running test cases only, +# the Makefile should not be making use of these paths to generate +# a pkgIndex.tcl file or anything else at extension build time. +#-------------------------------------------------------------------- + +TEA_PROG_TCLSH +TEA_PROG_WISH + +#-------------------------------------------------------------------- +# Setup a *Config.sh.in configuration file. +#-------------------------------------------------------------------- + +TEA_EXPORT_CONFIG([tkblt]) +#AC_SUBST(SAMPLE_VAR) + +#-------------------------------------------------------------------- +# Specify files to substitute AC variables in. You may alternatively +# have a special pkgIndex.tcl.in or other files which require +# substituting the AC variables in. Include these here. +#-------------------------------------------------------------------- + +AC_CONFIG_FILES([Makefile pkgIndex.tcl]) +AC_CONFIG_FILES([tkbltConfig.sh]) + +#-------------------------------------------------------------------- +# Finally, substitute all of the various values into the files +# specified with AC_CONFIG_FILES. +#-------------------------------------------------------------------- + +AC_OUTPUT() diff --git a/doc/BLT.html b/doc/BLT.html new file mode 100644 index 0000000..55e4e38 --- /dev/null +++ b/doc/BLT.html @@ -0,0 +1,74 @@ + + +
+
+
+
+

DESCRIPTION

+       BLT is a library of extensions to the Tk library.  It adds new commands
+       and variables to the application's interpreter.
+
+
+
+
+

COMMANDS

+       The following commands are  added  to  the  interpreter  from  the  BLT
+       library:
+
+       graph          A 2D plotting widget.  Plots two variable data in a win-
+                      dow with an optional legend and annotations.   It has of
+                      several  components; coordinate axes, crosshairs, a leg-
+                      end, and a collection of elements and tags.
+
+       barchart       A barchart widget.  Plots two-variable data as rectangu-
+                      lar bars in a window.  The x-coordinate values designate
+                      the position of the bar along the x-axis, while  the  y-
+                      coordinate values designate the magnitude.  The barchart
+                      widget  has  of  several  components;  coordinate  axes,
+                      crosshairs,  a  legend, and a collection of elements and
+                      tags.
+
+       vector         Creates a vector of floating point values.  The vector's
+                      components  can  be manipulated in three ways: through a
+                      Tcl array variable, a Tcl command, or the C API.
+
+
+
+

ADDING BLT TO YOUR APPLICATIONS

+       It's easy to add BLT to an existing Tk application.   BLT  requires  no
+       patches  or  edits  to the Tcl or Tk libraries.  To add BLT, simply add
+       the following code snippet to your application's tkAppInit.c file.
+
+       if (Tkblt_Init(interp) != TCL_OK) {
+
+           return TCL_ERROR;
+
+       }
+
+       Recompile and link with the tkblt library and that's it.
+
+       Alternately, you can dynamically load tkblt,  simply  by  invoking  the
+       command
+
+       % package require tkblt
+
+       from your Tcl script.
+
+
+
+

BUGS

+       Send bug reports, requests, suggestions, etc. to wjoye@cfa.harvard.edu
+
+
+
+

KEYWORDS

+       BLT
+
+
+
+
+Man(1) output converted with +man2html +
+ + diff --git a/doc/BLT.n b/doc/BLT.n new file mode 100644 index 0000000..6f63aa8 --- /dev/null +++ b/doc/BLT.n @@ -0,0 +1,76 @@ +'\" +'\" Smithsonian Astrophysical Observatory, Cambridge, MA, USA +'\" This code has been modified under the terms listed below and is made +'\" available under the same terms. +'\" +'\" Copyright 1991-1997 by Bell Labs Innovations for Lucent Technologies. +'\" +'\" Permission to use, copy, modify, and distribute this software and its +'\" documentation for any purpose and without fee is hereby granted, provided +'\" that the above copyright notice appear in all copies and that both that the +'\" copyright notice and warranty disclaimer appear in supporting documentation, +'\" and that the names of Lucent Technologies any of their entities not be used +'\" in advertising or publicity pertaining to distribution of the software +'\" without specific, written prior permission. +'\" +'\" Lucent Technologies disclaims all warranties with regard to this software, +'\" including all implied warranties of merchantability and fitness. In no event +'\" shall Lucent Technologies be liable for any special, indirect or +'\" consequential damages or any damages whatsoever resulting from loss of use, +'\" data or profits, whether in an action of contract, negligence or other +'\" tortuous action, arising out of or in connection with the use or performance +'\" of this software. +'\" +.TH intro n BLT_VERSION BLT "BLT Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +BLT \- Introduction to the BLT library +.BE +.SH DESCRIPTION +BLT is a library of extensions to the Tk library. It adds new +commands and variables to the application's interpreter. +.LP +.SH COMMANDS +The following commands are added to the interpreter from the BLT library: +.TP 15 +\fBgraph\fR +A 2D plotting widget. Plots two variable data in a window with an optional +legend and annotations. It has of several components; coordinate axes, +crosshairs, a legend, and a collection of elements and tags. +.TP 15 +\fBbarchart\fR +A barchart widget. Plots two-variable data as rectangular bars in a +window. The x-coordinate values designate the position of the bar along +the x-axis, while the y-coordinate values designate the magnitude. +The \fBbarchart\fR widget has of several components; coordinate axes, +crosshairs, a legend, and a collection of elements and tags. +.TP 15 +\fBvector\fR +Creates a vector of floating point values. The vector's components +can be manipulated in three ways: through a Tcl array variable, a Tcl +command, or the C API. +.SH ADDING BLT TO YOUR APPLICATIONS +It's easy to add BLT to an existing Tk application. BLT requires no +patches or edits to the Tcl or Tk libraries. To add BLT, simply add the +following code snippet to your application's tkAppInit.c file. +.PP +if (Tkblt_Init(interp) != TCL_OK) { +.PP + return TCL_ERROR; +.PP +} +.TP 15 +Recompile and link with the tkblt library and that's it. +.PP +Alternately, you can dynamically load tkblt, simply by invoking the +command +.PP +% package require tkblt +.PP +from your Tcl script. +.SH BUGS +Send bug reports, requests, suggestions, etc. to +wjoye@cfa.harvard.edu +.SH KEYWORDS +BLT diff --git a/doc/barchart.html b/doc/barchart.html new file mode 100644 index 0000000..7f04d25 --- /dev/null +++ b/doc/barchart.html @@ -0,0 +1,1640 @@ + + +
+
+
+
+

SYNOPSIS

+       barchart pathName ?option value?...
+
+
+
+

DESCRIPTION

+       The  barchart  command creates a bar chart for plotting two-dimensional
+       data (X-Y coordinates). A bar chart is a  graphic  means  of  comparing
+       numbers by displaying bars of lengths proportional to the y-coordinates
+       of the points they represented.  The bar chart  has  many  configurable
+       components: coordinate axes, elements, legend, grid lines, cross hairs,
+       etc.  They allow you to customize the look and feel of the graph.
+
+
+
+

INTRODUCTION

+       The barchart command creates a new window for plotting  two-dimensional
+       data  (X-Y coordinates), using bars of various lengths to represent the
+       data points.  The bars are drawn in a rectangular area displayed in the
+       center  of  the new window.  This is the plotting area.  The coordinate
+       axes are drawn in  the  margins  surrounding  the  plotting  area.   By
+       default,  the  legend  is drawn in the right margin.  The title is dis-
+       played in top margin.
+
+       A barchart widget has several configurable components: coordinate axes,
+       data elements, legend, grid, cross hairs, pens, postscript, and annota-
+       tion markers.  Each component can be queried or modified.
+
+       axis       Up to four coordinate axes (two X-coordinate and two Y-coor-
+                 dinate axes) can be displayed, but you can create and use any
+                 number of axes. Axes control what region of data is displayed
+                 and  how  the  data is scaled. Each axis consists of the axis
+                 line, title, major and minor ticks,  and  tick  labels.  Tick
+                 labels display the value at each major tick.
+
+       crosshairs
+                 Cross  hairs  are used to position the mouse pointer relative
+                 to the X and Y  coordinate  axes.  Two  perpendicular  lines,
+                 intersecting  at  the  current  location of the mouse, extend
+                 across the plotting area to the coordinate axes.
+
+       element   An element represents a set of data to be plotted.   It  con-
+                 tains  an  x  and  y  vector  of values representing the data
+                 points.  Each data point is displayed  as  a  bar  where  the
+                 length  of the bar is proportional to the ordinate (Y-coordi-
+                 nate) of the data point.  The appearance of the bar, such  as
+                 its color, stipple, or relief is configurable.
+
+                 A  special  case exists when two or more data points have the
+                 same abscissa (X-coordinate).  By default, the bars are over-
+                 layed,  one  on  top of the other.  The bars are drawn in the
+                 order of the element display list.  But you can also  config-
+                 ure  the bars to be displayed in two other ways.  They may be
+                 displayed as a stack, where each bar (with the same abscissa)
+                 is  stacked  on  the previous.  Or they can be drawn side-by-
+                 side as thin bars.  The width of each bar is  a  function  of
+
+       pen       Pens define attributes for elements.  Data elements use  pens
+                 to  specify how they should be drawn.  A data element may use
+                 many pens at once.  Here the particular pen used for  a  data
+                 point  is  determined  from each element's weight vector (see
+                 the element's -weight and -style options).
+
+       postscript
+                 The widget can generate encapsulated PostScript output.  This
+                 component has several options to configure how the PostScript
+                 is generated.
+
+
+
+

SYNTAX

+       barchart pathName ?option value?...  The barchart command creates a new
+       window  pathName and makes it into a barchart widget.  At the time this
+       command is invoked, there must not exist a window named  pathName,  but
+       pathName's  parent  must exist.  Additional options may be specified on
+       the command line or in the option database to configure aspects of  the
+       graph  such  as its colors and font.  See the configure operation below
+       for the exact details about what option and value pairs are valid.
+
+       If successful, barchart returns the path name of the widget.   It  also
+       creates  a  new Tcl command by the same name.  You can use this command
+       to invoke various operations that query or modify the graph.  The  gen-
+       eral form is: pathName operation ?arg?...  Both operation and its argu-
+       ments determine the exact behavior  of  the  command.   The  operations
+       available  for  the graph are described in the BARCHART OPERATIONS sec-
+       tion.
+
+       The command can also be used to access components of the graph.   path-
+       Name component operation ?arg?...  The operation, now located after the
+       name of the component, is the function to be performed on  that  compo-
+       nent. Each component has its own set of operations that manipulate that
+       component.  They will be described below in their own sections.
+
+
+
+

EXAMPLE

+       The barchart command creates a new bar  chart.   #  Create  a  new  bar
+       chart.   Plotting  area  is black.  barchart .b -plotbackground black A
+       new Tcl command .b is created.  This command can be used to  query  and
+       modify the bar chart.  For example, to change the title of the graph to
+       "My Plot", you use the new command  and  the  configure  operation.   #
+       Change  the title.  .b configure -title "My Plot" To add data elements,
+       you use the command and the element component.  # Create a new  element
+       named  "e1" .b element create e1 \      -xdata { 1 2 3 4 5 6 7 8 9 10 }
+       \       -ydata  {  26.18  50.46  72.85  93.31  111.86   128.47   143.14
+                 155.85  166.60  175.38  }  The  element's X-Y coordinates are
+       specified using lists of numbers.  Alternately, BLT  vectors  could  be
+       used to hold the X-Y coordinates.  # Create two vectors and add them to
+       the barchart.  vector xVector yVector xVector set { 1 2 3 4 5 6 7  8  9
+       10  } yVector set { 26.18 50.46 72.85 93.31 111.86 128.47 143.14 155.85
+            166.60 175.38 } n.b element create e1 -xdata xVector -ydata  yVec-
+       tor  The  advantage  of  using vectors is that when you modify one, the
+       sure we change the bar width  too.   .b  configure  -barwidth  0.2  The
+       height  of  each  bar is proportional to the ordinate (Y-coordinate) of
+       the data point.
+
+       If two or more data points have the same abscissa (X-coordinate value),
+       the  bars  representing those data points may be drawn in various ways.
+       The default is to overlay the bars, one  on  top  of  the  other.   The
+       ordering  is  determined  from  the  of  element  display list.  If the
+       stacked mode is selected (using the -barmode configuration option), the
+       bars  are stacked, each bar above the previous.  # Display the elements
+       as stacked.  .b configure -barmode  stacked  If  the  aligned  mode  is
+       selected,  the bars having the same x-coordinates are displayed side by
+       side.  The width of each bar is a fraction of its normal  width,  based
+       upon the number of bars with the same x-coordinate.  # Display the ele-
+       ments side-by-side.  .b configure -barmode aligned By default, the ele-
+       ment's  label in the legend will be also e1.  You can change the label,
+       or specify no legend entry, again using the element's configure  opera-
+       tion.   #  Don't  display  "e1" in the legend.  .b element configure e1
+       -label "" You can configure more than just  the  element's  label.   An
+       element  has many attributes such as stipple, foreground and background
+       colors, relief, etc.  .b element  configure  e1  -fg  red  -bg  pink  \
+            -stipple gray50 Four coordinate axes are automatically created: x,
+       x2, y, and y2.  And by default, elements are mapped onto the axes x and
+       y.   This  can be changed with the -mapx and -mapy options.  # Map "e1"
+       on the alternate y axis "y2".  .b element configure e1  -mapy  y2  Axes
+       can  be configured in many ways too.  For example, you change the scale
+       of the Y-axis from linear to log using the axis component.  # Y-axis is
+       log  scale.   .b  axis configure y -logscale yes One important way axes
+       are used is to zoom in on a particular data region.  Zooming is done by
+       simply specifying new axis limits using the -min and -max configuration
+       options.  .b axis configure x -min 1.0 -max 1.5  .b  axis  configure  y
+       -min  12.0 -max 55.15 To zoom interactively, you link theaxis configure
+       operations with some user interaction (such as pressing the mouse  but-
+       ton),  using  the  bind  command.   To convert between screen and graph
+       coordinates, use the invtransform operation.  # Click the button to set
+       a new minimum bind .b <ButtonPress-1> {
+           %W axis configure x -min [%W axis invtransform x %x]
+           %W  axis configure x -min [%W axis invtransform x %y] } By default,
+       the limits of the axis are determined from data values.  To reset  back
+       to  the  default  limits,  set  the  -min and -max options to the empty
+       value.  # Reset the axes to autoscale again.  .b axis configure x  -min
+       {}  -max  {} .b axis configure y -min {} -max {} By default, the legend
+       is drawn in the right margin.  You can change this or any  legend  con-
+       figuration  options using the legend component.  # Configure the legend
+       font, color, and relief .b  legend  configure  -position  left  -relief
+       raised  \       -font  fixed  -fg blue To prevent the legend from being
+       displayed, turn on the -hide option.  # Don't display the  legend.   .b
+       legend  configure  -hide yes The barchart has simple drawing procedures
+       called markers.  They can be used to highlight or annotate data in  the
+       graph.  The types of markers available are bitmaps, polygons, lines, or
+       windows.  Markers can be used, for example, to mark  or  brush  points.
+       For  example  there may be a line marker which indicates some low-water
+       chart into file "file.ps" .b postscript  output  file.ps  -maxpect  yes
+       -decorations  no  This generates a file file.ps containing the encapsu-
+       lated PostScript of the graph.  The option -maxpect says to  scale  the
+       plot  to  the  size  of  the page.  Turning off the -decorations option
+       denotes that no borders or color backgrounds should be drawn (i.e.  the
+       background of the margins, legend, and plotting area will be white).
+
+
+
+

SYNTAX

+       barchart pathName ?option value?...  The barchart command creates a new
+       window pathName and makes it into a barchart widget.  At the time  this
+       command  is  invoked, there must not exist a window named pathName, but
+       pathName's parent must exist.  Additional options may may be  specified
+       on  the  command line or in the option database to configure aspects of
+       the bar chart such as its colors and font.  See the configure operation
+       below  for  the  exact  details  as  to what option and value pairs are
+       valid.
+
+       If successful, barchart returns pathName. It also  creates  a  new  Tcl
+       command  pathName.   This  command may be used to invoke various opera-
+       tions to query or modify the bar chart.  It has the general form: path-
+       Name operation ?arg?...  Both operation and its arguments determine the
+       exact behavior of the command.  The operations available  for  the  bar
+       chart are described in the following section.
+
+
+
+

BARCHART OPERATIONS

+       pathName bar elemName ?option value?...
+              Creates  a  new  barchart element elemName.  It's an error if an
+              element elemName already exists.  See the  manual  for  barchart
+              for details about what option and value pairs are valid.
+
+       pathName cget option
+              Returns  the  current value of the configuration option given by
+              option.  Option may be any option described below for  the  con-
+              figure operation.
+
+       pathName configure ?option value?...
+              Queries  or modifies the configuration options of the graph.  If
+              option isn't specified, a list describing  the  current  options
+              for  pathName  is  returned.   If  option  is specified, but not
+              value, then a list describing option is  returned.   If  one  or
+              more  option  and value pairs are specified, then for each pair,
+              the option option is set to value.  The  following  options  are
+              valid.
+
+              -background color
+                     Sets  the background color. This includes the margins and
+                     legend, but not the plotting area.
+
+              -barmode mode
+                     Indicates  how  related  bar  elements  will  be   drawn.
+                     Related elements have data points with the same abscissas
+                     (X-coordinates). Mode indicates how those segments should
+
+              -barwidth value
+                     Specifies the width of the bars.  This value can be over-
+                     rided  by  the  individual elements using their -barwidth
+                     configuration option.  Value is the  width  in  terms  of
+                     graph-coordinates.  The default width is 1.0.
+
+              -borderwidth pixels
+                     Sets  the width of the 3-D border around the outside edge
+                     of the widget.  The -relief option determines if the bor-
+                     der is to be drawn.  The default is 2.
+
+              -bottommargin pixels
+                     Specifies  the  size of the margin below the X-coordinate
+                     axis.  If pixels is 0, the size of the margin is selected
+                     automatically.  The default is 0.
+
+              -bufferelements boolean
+                     Indicates  whether  an internal pixmap to buffer the dis-
+                     play of data elements should  be  used.   If  boolean  is
+                     true,  data  elements  are  drawn  to an internal pixmap.
+                     This option  is  especially  useful  when  the  graph  is
+                     redrawn  frequently while the remains data unchanged (for
+                     example, moving a marker across the plot).  See the SPEED
+                     TIPS section.  The default is 1.
+
+              -cursor cursor
+                     Specifies  the  widget's  cursor.   The default cursor is
+                     crosshair.
+
+              -font fontName
+                     Specifies the font of the graph  title.  The  default  is
+                     *-Helvetica-Bold-R-Normal-*-18-180-*.
+
+              -halo pixels
+                     Specifies  a  maximum distance to consider when searching
+                     for the closest data point  (see  the  element's  closest
+                     operation  below).   Data points further than pixels away
+                     are ignored.  The default is 0.5i.
+
+              -height pixels
+                     Specifies the requested height of widget.  The default is
+                     4i.
+
+              -invertxy boolean
+                     Indicates  whether the placement X-axis and Y-axis should
+                     be inverted.  If boolean is true, the X and  Y  axes  are
+                     swapped.  The default is 0.
+
+              -justify justify
+                     Specifies  how  the title should be justified.  This mat-
+                     ters only when the title contains more than one  line  of
+                     area.  The -plotrelief option determines if a  border  is
+                     drawn.  The default is 2.
+
+              -plotpadx pad
+                     Sets  the  amount  of padding to be added to the left and
+                     right sides of the plotting area.  Pad can be a  list  of
+                     one  or  two  screen distances.  If pad has two elements,
+                     the left side of the plotting area entry is padded by the
+                     first  distance and the right side by the second.  If pad
+                     is just one distance, both the left and right  sides  are
+                     padded evenly.  The default is 8.
+
+              -plotpady pad
+                     Sets  the  amount  of  padding to be added to the top and
+                     bottom of the plotting area.  Pad can be a list of one or
+                     two  screen  distances.  If pad has two elements, the top
+                     of the plotting area is padded by the first distance  and
+                     the  bottom  by the second.  If pad is just one distance,
+                     both the top and bottom are padded evenly.   The  default
+                     is 8.
+
+              -plotrelief relief
+                     Specifies  the  3-D effect for the plotting area.  Relief
+                     specifies how the interior of the  plotting  area  should
+                     appear relative to rest of the graph; for example, raised
+                     means the plot should appear to protrude from the  graph,
+                     relative  to  the  surface  of the graph.  The default is
+                     sunken.
+
+              -relief relief
+                     Specifies the 3-D effect for the barchart widget.  Relief
+                     specifies  how the graph should appear relative to widget
+                     it is packed into; for example, raised  means  the  graph
+                     should appear to protrude.  The default is flat.
+
+              -rightmargin pixels
+                     Sets  the  size  of  margin from the plotting area to the
+                     right edge of the window.   By  default,  the  legend  is
+                     drawn  in  this  margin.  If pixels is than 1, the margin
+                     size is selected automatically.
+
+              -takefocus focus
+                     Provides information used when moving the focus from win-
+                     dow  to  window  via  keyboard  traversal  (e.g., Tab and
+                     Shift-Tab).  If focus is 0, this means that  this  window
+                     should  be skipped entirely during keyboard traversal.  1
+                     means that the this  window  should  always  receive  the
+                     input  focus.   An  empty  value means that the traversal
+                     scripts make the decision whether to focus on the window.
+                     The default is "".
+
+              -tile image
+              -width pixels
+                     Specifies the requested width of the widget.  The default
+                     is 5i.
+
+       pathName crosshairs operation ?arg?
+              See the CROSSHAIRS COMPONENT section.
+
+       pathName element operation ?arg?...
+              See the ELEMENT COMPONENTS section.
+
+       pathName extents item
+              Returns  the  size of a particular item in the graph.  Item must
+              be  either  leftmargin,  rightmargin,  topmargin,  bottommargin,
+              plotwidth, or plotheight.
+
+       pathName grid operation ?arg?...
+              See the GRID COMPONENT section.
+
+       pathName invtransform winX winY
+              Performs  an  inverse  coordinate transformation, mapping window
+              coordinates back to graph-coordinates, using the standard X-axis
+              and  Y-axis.  Returns a list of containing the X-Y graph-coordi-
+              nates.
+
+       pathName inside x y
+              Returns 1 is the  designated  screen-coordinate  (x  and  y)  is
+              inside the plotting area and 0 otherwise.
+
+       pathName legend operation ?arg?...
+              See the LEGEND COMPONENT section.
+
+       pathName line operation arg...
+              The operation is the same as element.
+
+       pathName marker operation ?arg?...
+              See the MARKER COMPONENTS section.
+
+       pathName metafile ?fileName?
+              This  operation is for Window platforms only.  Creates a Windows
+              enhanced metafile of the barchart.  If present, fileName is  the
+              file name of the new metafile.  Otherwise, the metafile is auto-
+              matically added to the clipboard.
+
+       pathName postscript operation ?arg?...
+              See the POSTSCRIPT COMPONENT section.
+
+       pathName snap photoName
+              Takes a snapshot of the graph and stores  the  contents  in  the
+              photo  image  photoName.   PhotoName  is  the name of a Tk photo
+              image that must already exist.
+
+       pathName transform x y
+       A graph is composed of several components: coordinate axes,  data  ele-
+       ments,  legend,  grid, cross hairs, postscript, and annotation markers.
+       Instead of one big set of configuration  options  and  operations,  the
+       graph  is  partitioned,  where each component has its own configuration
+       options and operations that specifically control that aspect or part of
+       the graph.
+
+   AXIS COMPONENTS
+       Four  coordinate  axes are automatically created: two X-coordinate axes
+       (x and x2) and two Y-coordinate axes (y, and y2).  By default, the axis
+       x  is located in the bottom margin, y in the left margin, x2 in the top
+       margin, and y2 in the right margin.
+
+       An axis consists of the axis line, title, major and  minor  ticks,  and
+       tick  labels.   Major  ticks  are  drawn at uniform intervals along the
+       axis.  Each tick is labeled with its coordinate value.  Minor ticks are
+       drawn at uniform intervals within major ticks.
+
+       The  range  of  the axis controls what region of data is plotted.  Data
+       points outside the minimum and maximum limits of the axis are not plot-
+       ted.   By  default,  the minimum and maximum limits are determined from
+       the data, but you can reset either limit.
+
+       You can create and use several axes. To create an axis, invoke the axis
+       component  and  its create operation.  # Create a new axis called "tem-
+       perature" .b axis create temperature You map data elements to  an  axis
+       using the element's -mapy and -mapx configuration options. They specify
+       the coordinate axes an element is mapped onto.  # Now map the  tempera-
+       ture  data  to  this  axis.   .b element create "temp" -xdata $x -ydata
+       $tempData \
+           -mapy temperature While you can have many axes, only four axes  can
+       be  displayed  simultaneously.   They  are drawn in each of the margins
+       surrounding the plotting area.  The axes x and y are drawn in the  bot-
+       tom  and  left  margins.  The axes x2 and y2 are drawn in top and right
+       margins.  Only x and y are shown by default. Note  that  the  axes  can
+       have different scales.
+
+       To  display  a  different  axis, you invoke one of the following compo-
+       nents: xaxis, yaxis, x2axis, and y2axis.  The use operation  designates
+       the  axis to be drawn in the corresponding margin: xaxis in the bottom,
+       yaxis in the left, x2axis in the top, and y2axis in the right.  #  Dis-
+       play the axis temperature in the left margin.  .b yaxis use temperature
+
+       You can configure axes in many ways. The axis scale can  be  linear  or
+       logarithmic.   The  values  along  the  axis  can  either monotonically
+       increase or decrease.  If you need custom tick labels, you can  specify
+       a  Tcl procedure to format the label any way you wish.  You can control
+       how ticks are drawn, by changing the major tick interval or the  number
+       of minor ticks.  You can define non-uniform tick intervals, such as for
+       time-series plots.
+
+
+              -autorange range
+                     Sets the range of values for the axis to range.  The axis
+                     limits are automatically reset to display the most recent
+                     data points in this range.  If range is 0.0, the range is
+                     determined  from the limits of the data.  If -min or -max
+                     are specified, they override this option.  The default is
+                     0.0.
+
+              -color color
+                     Sets  the color of the axis and tick labels.  The default
+                     is black.
+
+              -command prefix
+                     Specifies a Tcl command to be invoked when formatting the
+                     axis  tick labels. Prefix is a string containing the name
+                     of a Tcl proc and any extra arguments for the  procedure.
+                     This  command is invoked for each major tick on the axis.
+                     Two additional arguments are passed to the procedure: the
+                     pathname  of the widget and the current the numeric value
+                     of the tick.  The procedure returns  the  formatted  tick
+                     label.   If  "" is returned, no label will appear next to
+                     the tick.  You can get the standard tick labels again  by
+                     setting prefix to "".  The default is "".
+
+                     Please  note that this procedure is invoked while the bar
+                     chart is redrawn.  You may query the widget's  configura-
+                     tion options.  But do not reset options, because this can
+                     have unexpected results.
+
+              -descending boolean
+                     Indicates whether the values along the axis are monotoni-
+                     cally  increasing or decreasing.  If boolean is true, the
+                     axis values will be decreasing.  The default is 0.
+
+              -hide boolean
+                     Indicates whether the axis is displayed.
+
+              -justify justify
+                     Specifies how the axis title should be  justified.   This
+                     matters  only  when the axis title contains more than one
+                     line of text. Justify must be  left,  right,  or  center.
+                     The default is center.
+
+              -limits formatStr
+                     Specifies a printf-like description to format the minimum
+                     and maximum limits of the axis.  The limits are displayed
+                     at  the  top/bottom  or  left/right sides of the plotting
+                     area.  FormatStr is a list of one or two format  descrip-
+                     tions.   If one description is supplied, both the minimum
+                     and maximum limits are formatted in  the  same  way.   If
+                     two,  the  first  designates  the  format for the minimum
+                     limit, the second for the maximum.  If  ""  is  given  as
+                     data points tightly, at the  outermost  data  points,  or
+                     loosely,  at  the outer tick intervals.  This is relevant
+                     only when the axis limit is automatically calculated.  If
+                     boolean  is true, the axis range is "loose".  The default
+                     is 0.
+
+              -majorticks majorList
+                     Specifies where to display major axis ticks.  You can use
+                     this  option  to  display ticks at non-uniform intervals.
+                     MajorList is a list of axis coordinates  designating  the
+                     location  of  major ticks.  No minor ticks are drawn.  If
+                     majorList is "", major ticks will be  automatically  com-
+                     puted. The default is "".
+
+              -max value
+                     Sets  the  maximum  limit  of  axisName.   Any data point
+                     greater than value is not displayed.  If value is "", the
+                     maximum limit is calculated using the largest data value.
+                     The default is "".
+
+              -min value
+                     Sets the minimum limit of axisName. Any data  point  less
+                     than value is not displayed.  If value is "", the minimum
+                     limit is calculated using the smallest data  value.   The
+                     default is "".
+
+              -minorticks minorList
+                     Specifies where to display minor axis ticks.  You can use
+                     this option to display minor ticks at non-uniform  inter-
+                     vals.  MinorList  is  a list of real values, ranging from
+                     0.0 to 1.0, designating the placement of  a  minor  tick.
+                     No minor ticks are drawn if the -majortick option is also
+                     set.  If minorList is "", minor ticks will  be  automati-
+                     cally computed. The default is "".
+
+              -rotate theta
+                     Specifies  the  how  many degrees to rotate the axis tick
+                     labels.  Theta is a real value representing the number of
+                     degrees  to  rotate  the tick labels.  The default is 0.0
+                     degrees.
+
+              -shiftby value
+                     Specifies how much to automatically shift  the  range  of
+                     the  axis.   When  the  new data exceeds the current axis
+                     maximum, the maximum is increased in increments of value.
+                     You  can  use this option to prevent the axis limits from
+                     being recomputed at each new time point. If value is 0.0,
+                     then no automatic shifting is down. The default is 0.0.
+
+              -showticks boolean
+                     Indicates  whether axis ticks should be drawn. If boolean
+                     is true, ticks are drawn.  If false, only the  axis  line
+
+              -tickfont fontName
+                     Specifies  the  font for axis tick labels. The default is
+                     *-Courier-Bold-R-Normal-*-100-*.
+
+              -ticklength pixels
+                     Sets the length of major and minor ticks (minor ticks are
+                     half  the  length of major ticks). If pixels is less than
+                     zero, the axis will be inverted with ticks drawn pointing
+                     towards the plot.  The default is 0.1i.
+
+              -title text
+                     Sets  the title of the axis. If text is "", no axis title
+                     will be displayed.
+
+              -titlecolor color
+                     Sets the color of the axis title. The default is black.
+
+              -titlefont fontName
+                     Specifies the font for axis title. The default is  *-Hel-
+                     vetica-Bold-R-Normal-*-14-140-*.
+
+              Axis configuration options may be also be set by the option com-
+              mand.  The resource class is Axis.  The resource names  are  the
+              names  of  the  axes  (such  as  x  or  x2).   option  add *Bar-
+              chart.Axis.Color  blue  option  add  *Barchart.x.LogScale   true
+              option add *Barchart.x2.LogScale false
+
+       pathName axis create axisName ?option value?...
+              Creates  a  new  axis by the name axisName.  No axis by the same
+              name can already exist. Option and value are described in  above
+              in the axis configure operation.
+
+       pathName axis delete ?axisName?...
+              Deletes  the  named axes. An axis is not really deleted until it
+              is not longer in use, so it's safe to delete axes mapped to ele-
+              ments.
+
+       pathName axis invtransform axisName value
+              Performs the inverse transformation, changing the screen-coordi-
+              nate value to a graph-coordinate, mapping the  value  mapped  to
+              axisName.  Returns the graph-coordinate.
+
+       pathName axis limits axisName
+              Returns  a  list of the minimum and maximum limits for axisName.
+              The order of the list is min max.
+
+       pathName axis names ?pattern?...
+              Returns a list of axes matching zero or more  patterns.   If  no
+              pattern argument is give, the names of all axes are returned.
+
+       pathName axis transform axisName value
+              Transforms  the  coordinate value to a screen-coordinate by map-
+
+       right Y-axis.
+
+       They implicitly control the axis that is currently using to that  loca-
+       tion.  By default, xaxis uses the x axis, yaxis uses y, x2axis uses x2,
+       and y2axis uses y2.  These components can be  more  convenient  to  use
+       than  always  determining  what axes are current being displayed by the
+       graph.
+
+       The following operations are available for axes.  They  mirror  exactly
+       the operations of the axis component.  The axis argument must be xaxis,
+       x2axis, yaxis, or y2axis.
+
+       pathName axis cget option
+
+       pathName axis configure ?option value?...
+
+       pathName axis invtransform value
+
+       pathName axis limits
+
+       pathName axis transform value
+
+       pathName axis use ?axisName?
+              Designates the axis axisName is to be displayed  at  this  loca-
+              tion.   AxisName  can not be already in use at another location.
+              This command returns the name of the axis currently  using  this
+              location.
+
+   CROSSHAIRS COMPONENT
+       Cross  hairs  consist  of  two intersecting lines (one vertical and one
+       horizontal) drawn completely across the plotting area.  They  are  used
+       to  position the mouse in relation to the coordinate axes.  Cross hairs
+       differ from line markers in that they are implemented using XOR drawing
+       primitives.  This means that they can be quickly drawn and erased with-
+       out redrawing the entire widget.
+
+       The following operations are available for cross hairs:
+
+       pathName crosshairs cget option
+              Returns the current  value  of  the  cross  hairs  configuration
+              option  given  by  option.   Option  may be any option described
+              below for the cross hairs configure operation.
+
+       pathName crosshairs configure ?option value?...
+              Queries or modifies  the  configuration  options  of  the  cross
+              hairs.   If  option  isn't  specified, a list describing all the
+              current options for the cross hairs is returned.  If  option  is
+              specified,  but  not  value,  then  a  list describing option is
+              returned.  If one or more option and value pairs are  specified,
+              then  for  each  pair,  the  cross hairs option option is set to
+              value.  The following options are available for cross hairs.
+
+              -linewidth pixels
+                     Set the width of the cross hair lines.  The default is 1.
+
+              -position pos
+                     Specifies  the  screen  position  where  the  cross hairs
+                     intersect.  Pos must be in the form "@x,y", where x and y
+                     are the window coordinates of the intersection.
+
+              Cross  hairs  configuration  options  may  be also be set by the
+              option command.  The resource name and class are crosshairs  and
+              Crosshairs       respectively.        option      add      *Bar-
+              chart.Crosshairs.LineWidth     2      option      add      *Bar-
+              chart.Crosshairs.Color     red
+
+       pathName crosshairs off
+              Turns off the cross hairs.
+
+       pathName crosshairs on
+              Turns on the display of the cross hairs.
+
+       pathName crosshairs toggle
+              Toggles  the  current state of the cross hairs, alternately map-
+              ping and unmapping the cross hairs.
+
+
+
+

ELEMENTS

+       A data element represents a set of data.  It contains x and  y  vectors
+       which  are  the coordinates of the data points.  Elements are displayed
+       as bars where the length of the bar is proportional to the ordinate  of
+       the data point.  Elements also control the appearance of the data, such
+       as the color, stipple, relief, etc.
+
+       When new data elements are created, they are automatically added  to  a
+       list  of  displayed elements.   The display list controls what elements
+       are drawn and in what order.
+
+       The following operations are available for elements.
+
+       pathName element activate elemName ?index?...
+              Specifies the data points of element elemName to be drawn  using
+              active  foreground  and background colors.  ElemName is the name
+              of the element and index is a number representing the  index  of
+              the  data  point. If no indices are present then all data points
+              become active.
+
+       pathName element bind tagName ?sequence?  ?command?
+              Associates command with tagName such  that  whenever  the  event
+              sequence  given by sequence occurs for an element with this tag,
+              command will be invoked.  The syntax is similar to the bind com-
+              mand except that it operates on graph elements, rather than wid-
+              gets. See the bind manual entry for complete details on sequence
+              and the substitutions performed on command before invoking it.
+
+
+       pathName element closest x y ?option value?... ?elemName?...
+              Finds  the data point representing the bar closest to the window
+              coordinates x and y in the element elemName.   ElemName  is  the
+              name  of  an  element, which must be currently displayed.  If no
+              elements  are  specified,  then  all  displayed   elements   are
+              searched.   It  returns  a key-value list containing the name of
+              the closest element, the index of its  closest  point,  and  the
+              graph-coordinates  of  the  point.  If  no data point within the
+              threshold distance can be found, "" is returned.  The  following
+              option-value pairs are available.
+
+              -halo pixels
+                     Specifies a threshold distance where selected data points
+                     are ignored.  Pixels is a valid screen distance, such  as
+                     2  or  1.2i.   If  this  option  isn't specified, then it
+                     defaults to the value of the barchart's -halo option.
+
+       pathName element configure elemName ?elemName... ?option value?...
+              Queries or modifies  the  configuration  options  for  elements.
+              Several  elements  can  be  modified at the same time. If option
+              isn't specified, a list describing all the current  options  for
+              elemName  is  returned.   If option is specified, but not value,
+              then a list describing the option option is returned.  If one or
+              more  option  and value pairs are specified, then for each pair,
+              the element option  option  is  set  to  value.   The  following
+              options are valid for elements.
+
+              -activepen penName
+                     Specifies  pen to use to draw active element.  If penName
+                     is "", no active elements will be drawn.  The default  is
+                     activeLine.
+
+              -bindtags tagList
+                     Specifies the binding tags for the element.  TagList is a
+                     list of binding tag names.  The tags and their order will
+                     determine  how events for elements.  Each tag in the list
+                     matching the current event sequence  will  have  its  Tcl
+                     command  executed.  Implicitly the name of the element is
+                     always the first tag in the list.  The default  value  is
+                     all.
+
+              -background color
+                     Sets  the  the  color of the border around each bar.  The
+                     default is white.
+
+              -barwidth value
+                     Specifies the width  the  bars  drawn  for  the  element.
+                     Value  is  the  width  in  X-coordinates.  If this option
+                     isn't specified, the width of each bar is  the  value  of
+                     the widget's -barwidth option.
+
+                     a list of numeric expressions representing the X-Y  coor-
+                     dinate pairs of each data point.
+
+              -foreground color
+                     Sets the color of the interior of the bars.
+
+              -hide boolean
+                     Indicates  whether the element is displayed.  The default
+                     is no.
+
+              -label text
+                     Sets the element's label in the legend.  If text  is  "",
+                     the  element  will  have  no  entry  in  the legend.  The
+                     default label is the element's name.
+
+              -mapx xAxis
+                     Selects the X-axis to  map  the  element's  X-coordinates
+                     onto.  XAxis must be the name of an axis.  The default is
+                     x.
+
+              -mapy yAxis
+                     Selects the Y-axis to  map  the  element's  Y-coordinates
+                     onto.   YAxis must be the name of an axis. The default is
+                     y.
+
+              -relief string
+                     Specifies the 3-D effect desired for bars.  Relief  indi-
+                     cates  how the interior of the bar should appear relative
+                     to the surface of the chart; for  example,  raised  means
+                     the bar should appear to protrude from the surface of the
+                     plotting area.  The default is raised.
+
+              -stipple bitmap
+                     Specifies a stipple pattern with which to draw the  bars.
+                     If  bitmap  is "", then the bar is drawn in a solid fash-
+                     ion.
+
+              -xdata xVector
+                     Specifies the x-coordinate vector of the  data.   XVector
+                     is  the name of a BLT vector or a list of numeric expres-
+                     sions.
+
+              -ydata yVector
+                     Specifies the y-coordinate vector of the  data.   YVector
+                     is  the name of a BLT vector or a list of numeric expres-
+                     sions.
+
+              Element configuration options may also be set by the option com-
+              mand.   The  resource names  in the option database are prefixed
+              by elem.  option add *Barchart.Element.background blue
+
+       pathName element create elemName ?option value?...
+
+       pathName element exists elemName
+              Returns  1  if an element elemName currently exists and 0 other-
+              wise.
+
+       pathName element names ?pattern?...
+              Returns the elements matching one or more pattern.  If  no  pat-
+              tern is given, the names of all elements is returned.
+
+       pathName element show ?nameList?
+              Queries  or modifies the element display list.  The element dis-
+              play list designates the  elements  drawn  and  in  what  order.
+              NameList is a list of elements to be displayed in the order they
+              are named.  If there is no nameList argument, the  current  dis-
+              play list is returned.
+
+       pathName element type elemName
+              Returns  the type of elemName.  If the element is a bar element,
+              the commands returns the  string  "bar",  otherwise  it  returns
+              "line".
+
+   GRID COMPONENT
+       Grid  lines extend from the major and minor ticks of each axis horizon-
+       tally or vertically across the plotting area.  The following operations
+       are available for grid lines.
+
+       pathName grid cget option
+              Returns  the current value of the grid line configuration option
+              given by option.  Option may be any option described  below  for
+              the grid configure operation.
+
+       pathName grid configure ?option value?...
+              Queries  or  modifies  the configuration options for grid lines.
+              If option isn't specified, a list  describing  all  the  current
+              grid  options for pathName is returned.  If option is specified,
+              but not value, then a list describing option  is  returned.   If
+              one  or more option and value pairs are specified, then for each
+              pair, the grid line option option is set to value.  The  follow-
+              ing options are valid for grid lines.
+
+              -color color
+                     Sets  the color of the grid lines.  The default is black.
+
+              -dashes dashList
+                     Sets the dash style of the grid lines. DashList is a list
+                     of  up  to  11  numbers  that  alternately  represent the
+                     lengths of the dashes and gaps on the grid  lines.   Each
+                     number must be between 1 and 255.  If dashList is "", the
+                     grid will be solid lines.
+
+              -hide boolean
+                     Indicates whether the grid should be drawn. If boolean is
+
+              -minor boolean
+                     Indicates  whether  the  grid  lines  should be drawn for
+                     minor ticks.  If boolean is true, the lines  will  appear
+                     at minor tick intervals.  The default is 1.
+
+              Grid  configuration  options  may also be set by the option com-
+              mand.  The resource name and class are  grid  and  Grid  respec-
+              tively.   option add *Barchart.grid.LineWidth 2 option add *Bar-
+              chart.Grid.Color     black
+
+       pathName grid off
+              Turns off the display the grid lines.
+
+       pathName grid on
+              Turns on the display the grid lines.
+
+       pathName grid toggle
+              Toggles the display of the grid.
+
+   LEGEND COMPONENT
+       The legend displays a list of the data elements.  Each  entry  consists
+       of the element's symbol and label.  The legend can appear in any margin
+       (the default location is in the right margin).  It can  also  be  posi-
+       tioned anywhere within the plotting area.
+
+       The following operations are valid for the legend.
+
+       pathName legend activate pattern...
+              Selects  legend entries to be drawn using the active legend col-
+              ors and relief.  All entries whose element names  match  pattern
+              are  selected.  To be selected, the element name must match only
+              one pattern.
+
+       pathName legend bind tagName ?sequence?  ?command?
+              Associates command with tagName such  that  whenever  the  event
+              sequence  given  by sequence occurs for a legend entry with this
+              tag, command will be invoked.  Implicitly the element  names  in
+              the  entry  are tags.  The syntax is similar to the bind command
+              except that it operates on legend entries, rather than  widgets.
+              See  the  bind manual entry for complete details on sequence and
+              the substitutions performed on command before invoking it.
+
+              If all arguments are specified then a new  binding  is  created,
+              replacing  any  existing  binding for the same sequence and tag-
+              Name.  If the first character of command is + then command  aug-
+              ments  an existing binding rather than replacing it.  If no com-
+              mand argument is provided then the command currently  associated
+              with  tagName  and  sequence (it's an error occurs if there's no
+              such binding) is returned.  If both  command  and  sequence  are
+              missing  then  a list of all the event sequences for which bind-
+              ings have been defined for tagName.
+
+              -activebackground color
+                     Sets the background color for active legend entries.  All
+                     legend  entries  marked  active  (see the legend activate
+                     operation) are drawn using this background color.
+
+              -activeborderwidth pixels
+                     Sets the width of the 3-D border around the outside  edge
+                     of the active legend entries.  The default is 2.
+
+              -activeforeground color
+                     Sets the foreground color for active legend entries.  All
+                     legend entries marked as active (see the legend  activate
+                     operation) are drawn using this foreground color.
+
+              -activerelief relief
+                     Specifies  the  3-D  effect  desired  for  active  legend
+                     entries.  Relief denotes how the interior  of  the  entry
+                     should appear relative to the legend; for example, raised
+                     means the entry should appear to protrude from  the  leg-
+                     end,  relative to the surface of the legend.  The default
+                     is flat.
+
+              -anchor anchor
+                     Tells how to position the legend relative  to  the  posi-
+                     tioning  point  for the legend.  This is dependent on the
+                     value of the -position option.  The default is center.
+
+                     left or right
+                                 The anchor describes how to position the leg-
+                                 end vertically.
+
+                     top or bottom
+                                 The anchor describes how to position the leg-
+                                 end horizontally.
+
+                     @x,y        The anchor specifies how to position the leg-
+                                 end  relative  to  the positioning point. For
+                                 example, if anchor is center then the  legend
+                                 is centered on the point; if anchor is n then
+                                 the legend will be drawn such  that  the  top
+                                 center  point of the rectangular region occu-
+                                 pied by the legend will be at the positioning
+                                 point.
+
+                     plotarea    The anchor specifies how to position the leg-
+                                 end relative to the plotting area. For  exam-
+                                 ple,  if  anchor is center then the legend is
+                                 centered in the plotting area; if  anchor  is
+                                 ne  then  the  legend will be drawn such that
+                                 occupies the upper right corner of the  plot-
+                                 ting area.
+
+                     of  the legend (if such border is being drawn; the relief
+                     option determines this).  The default is 2 pixels.
+
+              -font fontName
+                     FontName specifies a font to use when drawing the  labels
+                     of  each  element into the legend.  The default is *-Hel-
+                     vetica-Bold-R-Normal-*-12-120-*.
+
+              -foreground color
+                     Sets the foreground color of the text drawn for the  ele-
+                     ment's label.  The default is black.
+
+              -hide boolean
+                     Indicates  whether  the  legend  should  be displayed. If
+                     boolean is true,  the  legend  will  not  be  draw.   The
+                     default is no.
+
+              -ipadx pad
+                     Sets  the  amount  of internal padding to be added to the
+                     width of each legend entry.  Pad can be a list of one  or
+                     two  screen distances.  If pad has two elements, the left
+                     side of the legend entry is padded by the first  distance
+                     and  the  right  side  by the second.  If pad is just one
+                     distance, both  the  left  and  right  sides  are  padded
+                     evenly.  The default is 2.
+
+              -ipady pad
+                     Sets  an  amount  of  internal padding to be added to the
+                     height of each legend entry.  Pad can be a list of one or
+                     two  screen  distances.  If pad has two elements, the top
+                     of the entry is padded by the first distance and the bot-
+                     tom by the second.  If pad is just one distance, both the
+                     top and bottom of  the  entry  are  padded  evenly.   The
+                     default is 2.
+
+              -padx pad
+                     Sets  the  padding to the left and right exteriors of the
+                     legend.  Pad can be a list of  one  or  two  screen  dis-
+                     tances.   If  pad  has two elements, the left side of the
+                     legend is padded by the first distance and the right side
+                     by  the  second.   If pad has just one distance, both the
+                     left and right sides are padded evenly.  The  default  is
+                     4.
+
+              -pady pad
+                     Sets  the padding above and below the legend.  Pad can be
+                     a list of one or two screen distances.  If  pad  has  two
+                     elements,  the  area  above  the  legend is padded by the
+                     first distance and the area below by the second.  If  pad
+                     is  just  one distance, both the top and bottom areas are
+                     padded evenly.  The default is 0.
+
+                     drawn on top of any elements that  may  overlap  it.  The
+                     default is no.
+
+              -relief relief
+                     Specifies  the  3-D effect for the border around the leg-
+                     end.  Relief specifies how the  interior  of  the  legend
+                     should  appear  relative  to  the bar chart; for example,
+                     raised means the legend should appear  to  protrude  from
+                     the  bar chart, relative to the surface of the bar chart.
+                     The default is sunken.
+
+              Legend configuration options may also be set by the option  com-
+              mand.  The resource name and class are legend and Legend respec-
+              tively.  option add *Barchart.legend.Foreground blue option  add
+              *Barchart.Legend.Relief     raised
+
+       pathName legend deactivate pattern...
+              Selects  legend entries to be drawn using the normal legend col-
+              ors and relief.  All entries whose element names  match  pattern
+              are  selected.  To be selected, the element name must match only
+              one pattern.
+
+       pathName legend get pos
+              Returns the name of the element whose entry  is  at  the  screen
+              position  pos  in  the  legend.  Pos must be in the form "@x,y",
+              where x and y are window coordinates.  If the given  coordinates
+              do not lie over a legend entry, "" is returned.
+
+   PEN COMPONENTS
+       Pens  define  attributes  for  elements.  Pens mirror the configuration
+       options of data elements that pertain to  how  symbols  and  lines  are
+       drawn.  Data elements use pens to determine how they are drawn.  A data
+       element may use several pens at once.  In this case, the pen used for a
+       particular  data  point is determined from each element's weight vector
+       (see the element's -weight and -style options).
+
+       One pen, called activeBar, is automatically created.  It's used as  the
+       default  active  pen  for  elements.  So  you  can  change  the  active
+       attributes for all elements by simply reconfiguring this pen.   .g  pen
+       configure  "activeBar" -fg green -bg green4 You can create and use sev-
+       eral pens. To create a pen, invoke the pen  component  and  its  create
+       operation.   .g  pen  create myPen You map pens to a data element using
+       either the element's -pen or -activepen  options.   .g  element  create
+       "e1" -xdata $x -ydata $tempData \
+           -pen myPen An element can use several pens at once. This is done by
+       specifying the name of the pen in the element's  style  list  (see  the
+       -styles  option).   .g element configure "e1" -styles { myPen 2.0 3.0 }
+       This says that any data point with a weight between 2.0 and 3.0  is  to
+       be drawn using the pen myPen.  All other points are drawn with the ele-
+       ment's default attributes.
+
+       The following operations are available for pen components.
+              value.  The following options are valid for pens.
+
+              -background color
+                     Sets the the color of the border around  each  bar.   The
+                     default is white.
+
+              -borderwidth pixels
+                     Sets  the border width of the 3-D border drawn around the
+                     outside of each bar.  The -relief  option  determines  if
+                     such  a  border  is drawn.  Pixels must be a valid screen
+                     distance like 2 or 0.25i. The default is 2.
+
+              -foreground color
+                     Sets the color of the interior of the bars.
+
+              -relief string
+                     Specifies the 3-D effect desired for bars.  Relief  indi-
+                     cates  how the interior of the bar should appear relative
+                     to the surface of the chart; for  example,  raised  means
+                     the  bar  should  appear  to protrude from the bar chart,
+                     relative to  the  surface  of  the  plotting  area.   The
+                     default is raised.
+
+              -stipple bitmap
+                     Specifies  a stipple pattern with which to draw the bars.
+                     If bitmap is "", then the bar is drawn in a  solid  fash-
+                     ion.
+
+              -type elemType
+                     Specifies the type of element the pen is to be used with.
+                     This option should only be  employed  when  creating  the
+                     pen.   This is for those that wish to mix different types
+                     of elements (bars and lines)  on  the  same  graph.   The
+                     default type is "bar".
+
+              Pen  configuration options may be also be set by the option com-
+              mand.  The resource class is Pen.  The resource  names  are  the
+              names  of  the  pens.   option add *Barchart.Pen.Foreground
+              blue option add *Barchart.activeBar.foreground  green
+
+       pathName pen create penName ?option value?...
+              Creates a new pen by the name penName.  No pen by the same  name
+              can  already  exist.  Option and value are described in above in
+              the pen configure operation.
+
+       pathName pen delete ?penName?...
+              Deletes the named pens. A pen is not really deleted until it  is
+              not  longer  in  use, so it's safe to delete pens mapped to ele-
+              ments.
+
+       pathName pen names ?pattern?...
+              Returns a list of pens matching zero or more  patterns.   If  no
+              option.   Option may be any option described below for the post-
+              script configure operation.
+
+       pathName postscript configure ?option value?...
+              Queries or modifies the  configuration  options  for  PostScript
+              generation.   If  option  isn't specified, a list describing the
+              current postscript options for pathName is returned.  If  option
+              is  specified,  but  not value, then a list describing option is
+              returned.  If one or more option and value pairs are  specified,
+              then  for  each  pair,  the  postscript  option option is set to
+              value.  The following postscript options are available.
+
+              -center boolean
+                     Indicates whether the plot  should  be  centered  on  the
+                     PostScript  page.   If boolean is false, the plot will be
+                     placed in the upper left corner of the page.  The default
+                     is 1.
+
+              -colormap varName
+                     VarName  must be the name of a global array variable that
+                     specifies a color mapping from the X color name to  Post-
+                     Script.   Each  element  of varName must consist of Post-
+                     Script code to set a particular color value  (e.g.  ``1.0
+                     1.0  0.0  setrgbcolor'').  When generating color informa-
+                     tion in PostScript, the array variable varName is checked
+                     if  an element of the name as the color exists. If so, it
+                     uses its value as  the  PostScript  command  to  set  the
+                     color.  If this option hasn't been specified, or if there
+                     isn't an entry in varName for a given color, then it uses
+                     the red, green, and blue intensities from the X color.
+
+              -colormode mode
+                     Specifies  how to output color information.  Mode must be
+                     either color (for full color output), gray  (convert  all
+                     colors  to their gray-scale equivalents) or mono (convert
+                     foreground colors  to  black  and  background  colors  to
+                     white).  The default mode is color.
+
+              -fontmap varName
+                     VarName  must be the name of a global array variable that
+                     specifies a font mapping from the X font  name  to  Post-
+                     Script.   Each  element  of varName must consist of a Tcl
+                     list with one or two elements; the name and point size of
+                     a  PostScript  font.  When outputting PostScript commands
+                     for a particular font,  the  array  variable  varName  is
+                     checked  to  see  if  an  element  by  the specified font
+                     exists.  If there is  such  an  element,  then  the  font
+                     information  contained  in  that  element  is used in the
+                     PostScript output.  (If the point size  is  omitted  from
+                     the  list, the point size of the X font is used).  Other-
+                     wise the X font is examined in an attempt to  guess  what
+                     PostScript  font to use.  This works only for fonts whose
+                     widget's height.  The default is 0.
+
+              -landscape boolean
+                     If boolean is true, this specifies the printed area is to
+                     be  rotated 90 degrees.  In non-rotated output the X-axis
+                     of the printed area runs along the short dimension of the
+                     page  (``portrait''  orientation);  in rotated output the
+                     X-axis runs along the long dimension of the page (``land-
+                     scape'' orientation).  Defaults to 0.
+
+              -maxpect boolean
+                     Indicates  to  scale  the plot so that it fills the Post-
+                     Script page.  The aspect ratio of the barchart  is  still
+                     retained.  The default is 0.
+
+              -padx pad
+                     Sets  the  horizontal padding for the left and right page
+                     borders.  The borders are exterior to the plot.  Pad  can
+                     be a list of one or two screen distances.  If pad has two
+                     elements, the left border is padded by the first distance
+                     and  the right border by the second.  If pad has just one
+                     distance, both the left  and  right  borders  are  padded
+                     evenly.  The default is 1i.
+
+              -pady pad
+                     Sets  the  vertical  padding  for the top and bottom page
+                     borders. The borders are exterior to the plot.   Pad  can
+                     be a list of one or two screen distances.  If pad has two
+                     elements, the top border is padded by the first  distance
+                     and the bottom border by the second.  If pad has just one
+                     distance, both the top  and  bottom  borders  are  padded
+                     evenly.  The default is 1i.
+
+              -paperheight pixels
+                     Sets the height of the postscript page.  This can be used
+                     to select between different page sizes (letter, A4, etc).
+                     The default height is 11.0i.
+
+              -paperwidth pixels
+                     Sets  the width of the postscript page.  This can be used
+                     to select between different page sizes (letter, A4, etc).
+                     The default width is 8.5i.
+
+              -width pixels
+                     Sets  the  width  of  the plot.  This lets you generate a
+                     plot of a width different from that of  the  widget.   If
+                     pixels is 0, the width is the same as the widget's width.
+                     The default is 0.
+
+              Postscript configuration options may  be  also  be  set  by  the
+              option  command.  The resource name and class are postscript and
+              Postscript respectively.  option add  *Barchart.postscript.Deco-
+
+       with  a  particular  element, so that when the element is hidden or un-
+       hidden, so is the marker.  By  default,  markers  are  the  last  items
+       drawn,  so  that  data  elements  will  appear in behind them.  You can
+       change this by configuring the -under option.
+
+       Markers, in contrast to elements, don't affect the scaling of the coor-
+       dinate axes.  They can also have elastic coordinates (specified by -Inf
+       and Inf respectively) that translate into the minimum or maximum  limit
+       of  the axis.  For example, you can place a marker so it always remains
+       in the lower left corner of the plotting area, by using the coordinates
+       -Inf,-Inf.
+
+       The following operations are available for markers.
+
+       pathName marker after markerId ?afterId?
+              Changes the order of the markers, drawing the first marker after
+              the second.  If no second afterId  argument  is  specified,  the
+              marker  is  placed at the end of the display list.  This command
+              can be used to control how markers are displayed  since  markers
+              are drawn in the order of this display list.
+
+       pathName marker before markerId ?beforeId?
+              Changes  the  order  of  the  markers,  drawing the first marker
+              before the second.  If no second beforeId argument is specified,
+              the marker is placed at the beginning of the display list.  This
+              command can be used to control how markers are  displayed  since
+              markers are drawn in the order of this display list.
+
+       pathName marker bind tagName ?sequence?  ?command?
+              Associates  command  with  tagName  such that whenever the event
+              sequence given by sequence occurs for a marker  with  this  tag,
+              command will be invoked.  The syntax is similar to the bind com-
+              mand except that it operates on graph markers, rather than  wid-
+              gets. See the bind manual entry for complete details on sequence
+              and the substitutions performed on command before invoking it.
+
+              If all arguments are specified then a new  binding  is  created,
+              replacing  any  existing  binding for the same sequence and tag-
+              Name.  If the first character of command is + then command  aug-
+              ments  an existing binding rather than replacing it.  If no com-
+              mand argument is provided then the command currently  associated
+              with  tagName  and  sequence (it's an error occurs if there's no
+              such binding) is returned.  If both  command  and  sequence  are
+              missing  then  a list of all the event sequences for which bind-
+              ings have been defined for tagName.
+
+       pathName marker cget option
+              Returns the current value of  the  marker  configuration  option
+              given  by  option.   Option may be any option described below in
+              the configure operation.
+
+       pathName marker configure markerId ?option value?...
+                     determine  how  events for markers are handled.  Each tag
+                     in the list matching the current event sequence will have
+                     its  Tcl  command  executed.   Implicitly the name of the
+                     marker is always the first tag in the list.  The  default
+                     value is all.
+
+              -coords coordList
+                     Specifies  the coordinates of the marker.  CoordList is a
+                     list of graph-coordinates.   The  number  of  coordinates
+                     required  is  dependent  on  the  type  of marker.  Text,
+                     image, and window markers need only two  coordinates  (an
+                     X-Y  coordinate).   Bitmap markers can take either two or
+                     four coordinates (if four, they represent the corners  of
+                     the bitmap). Line markers need at least four coordinates,
+                     polygons at least six.  If coordList is  "",  the  marker
+                     will not be displayed.  The default is "".
+
+              -element elemName
+                     Links  the  marker with the element elemName.  The marker
+                     is drawn only if the element is also currently  displayed
+                     (see  the  element's show operation).  If elemName is "",
+                     the marker is always drawn.  The default is "".
+
+              -hide boolean
+                     Indicates whether the marker  is  drawn.  If  boolean  is
+                     true, the marker is not drawn.  The default is no.
+
+              -mapx xAxis
+                     Specifies  the  X-axis  to map the marker's X-coordinates
+                     onto.  XAxis must the name of an axis.  The default is x.
+
+              -mapy yAxis
+                     Specifies  the  Y-axis  to map the marker's Y-coordinates
+                     onto.  YAxis must the name of an axis.  The default is y.
+
+              -name markerId
+                     Changes  the  identifier  for the marker.  The identifier
+                     markerId can not already be used by another  marker.   If
+                     this   option  isn't  specified,  the  marker's  name  is
+                     uniquely generated.
+
+              -under boolean
+                     Indicates whether the marker is  drawn  below/above  data
+                     elements.   If  boolean  is  true, the marker is be drawn
+                     underneath the data elements.  Otherwise, the  marker  is
+                     drawn on top of the element.  The default is 0.
+
+              -xoffset pixels
+                     Specifies a screen distance to offset the marker horizon-
+                     tally.  Pixels is a valid screen distance, such as  2  or
+                     1.2i.  The default is 0.
+
+              Creates  a marker of the selected type. Type may be either text,
+              line, bitmap, image, polygon, or window.  This  command  returns
+              the  marker  identifier,  used  as  the markerId argument in the
+              other marker-related commands.  If the  -name  option  is  used,
+              this  overrides  the normal marker identifier.  If the name pro-
+              vided is already used for another marker, the  new  marker  will
+              replace the old.
+
+       pathName marker delete ?name?...
+              Removes  one  of  more markers.  The graph will automatically be
+              redrawn without the marker..
+
+       pathName marker exists markerId
+              Returns 1 if the marker markerId exists and 0 otherwise.
+
+       pathName marker names ?pattern?
+              Returns the names of all the markers that currently  exist.   If
+              pattern  is  supplied,  only  those markers whose names match it
+              will be returned.
+
+       pathName marker type markerId
+              Returns the type of the marker given by markerId, such  as  line
+              or  text.  If markerId is not a valid a marker identifier, "" is
+              returned.
+
+   BITMAP MARKERS
+       A bitmap marker displays a bitmap.  The size  of  the  bitmap  is  con-
+       trolled  by  the  number of coordinates specified.  If two coordinates,
+       they specify the position of the top-left corner of  the  bitmap.   The
+       bitmap  retains  its normal width and height.  If four coordinates, the
+       first and second pairs of coordinates represent the corners of the bit-
+       map.   The bitmap will be stretched or reduced as necessary to fit into
+       the bounding rectangle.
+
+       Bitmap markers are created with the marker's create  operation  in  the
+       form:  pathName  marker  create  bitmap ?option value?...  There may be
+       many option-value pairs, each sets  a  configuration  options  for  the
+       marker.   These  same  option-value pairs may be used with the marker's
+       configure operation.
+
+       The following options are specific to bitmap markers:
+
+       -background color
+              Same as the -fill option.
+
+       -bitmap bitmap
+              Specifies the bitmap to be displayed.   If  bitmap  is  "",  the
+              marker will not be displayed.  The default is "".
+
+       -fill color
+              Sets  the background color of the bitmap.  If color is the empty
+              string, no background will be transparent.   The  default  back-
+
+       -rotate theta
+              Sets  the rotation of the bitmap.  Theta is a real number repre-
+              senting the angle of rotation in degrees.  The marker  is  first
+              rotated  and  then placed according to its anchor position.  The
+              default rotation is 0.0.
+
+   IMAGE MARKERS
+       A image marker displays an image.  Image markers are created  with  the
+       marker's  create  operation  in  the form: pathName marker create image
+       ?option value?...  There may be many option-value pairs,  each  sets  a
+       configuration option for the marker.  These same option-value pairs may
+       be used with the marker's configure operation.
+
+       The following options are specific to image markers:
+
+       -anchor anchor
+              Anchor tells how to position the image relative to the position-
+              ing  point  for the image. For example, if anchor is center then
+              the image is centered on the point;  if anchor  is  n  then  the
+              image  will be drawn such that the top center point of the rect-
+              angular region occupied by the image will be at the  positioning
+              point.  This option defaults to center.
+
+       -image image
+              Specifies  the  image  to  be drawn.  If image is "", the marker
+              will not be drawn.  The default is "".
+
+   LINE MARKERS
+       A line marker displays one or more connected line segments.  Line mark-
+       ers  are  created  with marker's create operation in the form: pathName
+       marker create line ?option value?...  There may  be  many  option-value
+       pairs,  each  sets  a  configuration option for the marker.  These same
+       option-value pairs may be used with the marker's configure operation.
+
+       The following options are specific to line markers:
+
+       -dashes dashList
+              Sets the dash style of the line. DashList is a list of up to  11
+              numbers that alternately represent the lengths of the dashes and
+              gaps on the line.  Each number must be between 1  and  255.   If
+              dashList is "", the marker line will be solid.
+
+       -fill color
+              Sets  the background color of the line.  This color is used with
+              striped lines (see the -dashes option). If color  is  the  empty
+              string,  no  background color is drawn (the line will be dashed,
+              not striped).  The default background color is "".
+
+       -linewidth pixels
+              Sets the width of the lines.  The default width is 0.
+
+       in  the  form:  pathName marker create polygon ?option value?...  There
+       may be many option-value pairs, each sets a  configuration  option  for
+       the  marker.  These same option-value pairs may be used with the marker
+       configure command to change the marker's configuration.  The  following
+       options are supported for polygon markers:
+
+       -dashes dashList
+              Sets the dash style of the outline of the polygon. DashList is a
+              list of up to 11 numbers that alternately represent the  lengths
+              of  the  dashes  and  gaps  on the outline.  Each number must be
+              between 1 and 255. If dashList is "",  the  outline  will  be  a
+              solid line.
+
+       -fill color
+              Sets  the  fill  color of the polygon.  If color is "", then the
+              interior of the polygon is transparent.  The default is white.
+
+       -linewidth pixels
+              Sets the width of the outline of the polygon. If pixels is zero,
+              no outline is drawn. The default is 0.
+
+       -outline color
+              Sets the color of the outline of the polygon.  If the polygon is
+              stippled (see the -stipple option),  then  this  represents  the
+              foreground color of the stipple.  The default is black.
+
+       -stipple bitmap
+              Specifies  that the polygon should be drawn with a stippled pat-
+              tern rather than a solid color. Bitmap specifies a bitmap to use
+              as  the  stipple  pattern.  If bitmap is "", then the polygon is
+              filled with a solid color (if the -fill  option  is  set).   The
+              default is "".
+
+   TEXT MARKERS
+       A  text  marker displays a string of characters on one or more lines of
+       text.  Embedded newlines cause line breaks.  They may be used to  anno-
+       tate  regions  of  the graph.  Text markers are created with the create
+       operation in the form: pathName marker create  text  ?option  value?...
+       There  may be many option-value pairs, each sets a configuration option
+       for the text marker.  These same option-value pairs may  be  used  with
+       the marker's configure operation.
+
+       The following options are specific to text markers:
+
+       -anchor anchor
+              Anchor  tells how to position the text relative to the position-
+              ing point for the text. For example, if anchor  is  center  then
+              the  text is centered on the point; if anchor is n then the text
+              will be drawn such that the top center point of the  rectangular
+              region  occupied  by  the text will be at the positioning point.
+              This default is center.
+
+
+       -justify justify
+              Specifies  how  the text should be justified.  This matters only
+              when the marker contains more than one  line  of  text.  Justify
+              must be left, right, or center.  The default is center.
+
+       -outline color
+              Sets the color of the text. The default value is black.
+
+       -padx pad
+              Sets  the  padding  to the left and right exteriors of the text.
+              Pad can be a list of one or two screen distances.   If  pad  has
+              two  elements,  the left side of the text is padded by the first
+              distance and the right side by the second.  If pad has just  one
+              distance,  both the left and right sides are padded evenly.  The
+              default is 4.
+
+       -pady pad
+              Sets the padding above and below the text.  Pad can be a list of
+              one  or two screen distances.  If pad has two elements, the area
+              above the text is padded by the  first  distance  and  the  area
+              below  by the second.  If pad is just one distance, both the top
+              and bottom areas are padded evenly.  The default is 4.
+
+       -rotate theta
+              Specifies the number of degrees to rotate the text.  Theta is  a
+              real  number  representing the angle of rotation.  The marker is
+              first rotated along its center and is then  drawn  according  to
+              its anchor position. The default is 0.0.
+
+       -text text
+              Specifies  the  text  of  the marker.  The exact way the text is
+              displayed may be affected by other options such  as  -anchor  or
+              -rotate.
+
+   WINDOW MARKERS
+       A  window marker displays a widget at a given position.  Window markers
+       are created with the marker's create operation in  the  form:  pathName
+       marker  create window ?option value?...  There may be many option-value
+       pairs, each sets a configuration option for  the  marker.   These  same
+       option-value pairs may be used with the marker's configure command.
+
+       The following options are specific to window markers:
+
+       -anchor anchor
+              Anchor  tells  how  to position the widget relative to the posi-
+              tioning point for the widget. For example, if anchor  is  center
+              then  the  widget  is centered on the point; if anchor is n then
+              the widget will be displayed such that the top center  point  of
+              the  rectangular  region  occupied  by the widget will be at the
+              positioning point.  This option defaults to center.
+
+
+
+

GRAPH COMPONENT BINDINGS

+       Specific barchart components, such  as  elements,  markers  and  legend
+       entries,  can  have  a  command trigger when event occurs in them, much
+       like canvas items in Tk's canvas widget.  Not all event  sequences  are
+       valid.  The only binding events that may be specified are those related
+       to the mouse and keyboard (such as Enter, Leave,  ButtonPress,  Motion,
+       and KeyPress).
+
+       Only  one element or marker can be picked during an event.  This means,
+       that if the mouse is directly over both an element and a  marker,  only
+       the  uppermost  component  is  selected.   This  isn't  true for legend
+       entries.  Both a legend entry and an element (or marker)  binding  com-
+       mands will be invoked if both items are picked.
+
+       It is possible for multiple bindings to match a particular event.  This
+       could occur, for example, if one binding is associated with the element
+       name  and another is associated with one of the element's tags (see the
+       -bindtags option).  When this occurs, all of the matching bindings  are
+       invoked.   A binding associated with the element name is invoked first,
+       followed by one binding for each of the element's bindtags.   If  there
+       are  multiple  matching  bindings  for a single tag, then only the most
+       specific binding is invoked.  A continue command in  a  binding  script
+       terminates  that script, and a break command terminates that script and
+       skips any remaining scripts for the event, just as for  the  bind  com-
+       mand.
+
+       The  -bindtags  option for these components controls addition tag names
+       which can be matched.  Implicitly elements and markers always have tags
+       matching  their  names.   Setting  the  value  of  the -bindtags option
+       doesn't change this.
+
+
+
+

C LANGUAGE API

+       You can manipulate data elements from the C  language.   There  may  be
+       situations  where it is too expensive to translate the data values from
+       ASCII strings.  Or you might want to read data in a special  file  for-
+       mat.
+
+       Data  can manipulated from the C language using BLT vectors.  You spec-
+       ify the X-Y data coordinates of an element as  vectors  and  manipulate
+       the  vector  from  C.  The barchart will be redrawn automatically after
+       the vectors are updated.
+
+       From Tcl, create the vectors and configure the  element  to  use  them.
+       vector  X  Y  .g  element configure line1 -xdata X -ydata Y To set data
+       points from C, you pass the values  as  arrays  of  doubles  using  the
+       Blt_ResetVector call.  The vector is reset with the new data and at the
+       next idle point (when Tk re-enters its event loop), the graph  will  be
+       redrawn automatically.  #include <tcl.h> #include <blt.h>
+
+       register int i; Blt_Vector *xVec, *yVec; double x[50], y[50];
+
+       /*  Get  the  BLT  vectors  "X"  and "Y" (created above from Tcl) */ if
+       There may be cases where the bar chart needs to be drawn and updated as
+       quickly as possible.  If drawing speed becomes a big problem, here  are
+       a few tips to speed up displays.
+
+       o Try  to  minimize  the  number  of data points.  The more data points
+         looked at, the more work the bar chart must do.
+
+       o If your data is generated as floating point values, the time required
+         to  convert the data values to and from ASCII strings can be signifi-
+         cant, especially when there any many data points.  You can avoid  the
+         redundant  string-to-decimal  conversions using the C API to BLT vec-
+         tors.
+
+       o Don't stipple or dash the element.  Solid bars are much faster.
+
+       o If you update data elements frequently, try turning off the  widget's
+         -bufferelements  option.   When  the bar chart is first displayed, it
+         draws data elements into an internal pixmap.  The pixmap  acts  as  a
+         cache,  so that when the bar chart needs to be redrawn again, and the
+         data elements or coordinate axes haven't changed, the pixmap is  sim-
+         ply  copied  to  the  screen.  This is especially useful when you are
+         using markers to highlight points and regions on the bar chart.   But
+         if  the  bar chart is updated frequently, changing either the element
+         data or coordinate axes, the buffering becomes redundant.
+
+
+
+

LIMITATIONS

+       Auto-scale routines do not use requested min/max limits  as  boundaries
+       when the axis is logarithmically scaled.
+
+       The PostScript output generated for polygons with more than 1500 points
+       may exceed the limits of some printers (See PostScript Language  Refer-
+       ence  Manual,  page 568).  The work-around is to break the polygon into
+       separate pieces.
+
+
+
+

KEYWORDS

+       bar chart, widget
+
+
+
+BLT                               BLT_VERSION                      barchart(n)
+
+
+
+Man(1) output converted with +man2html +
+ + diff --git a/doc/barchart.n b/doc/barchart.n new file mode 100644 index 0000000..7a9dac8 --- /dev/null +++ b/doc/barchart.n @@ -0,0 +1,2239 @@ +'\" +'\" Smithsonian Astrophysical Observatory, Cambridge, MA, USA +'\" This code has been modified under the terms listed below and is made +'\" available under the same terms. +'\" +'\" Copyright 1991-1998 by Bell Labs Innovations for Lucent Technologies. +'\" +'\" Permission to use, copy, modify, and distribute this software and its +'\" documentation for any purpose and without fee is hereby granted, provided +'\" that the above copyright notice appear in all copies and that both that the +'\" copyright notice and warranty disclaimer appear in supporting documentation, +'\" and that the names of Lucent Technologies any of their entities not be used +'\" in advertising or publicity pertaining to distribution of the software +'\" without specific, written prior permission. +'\" +'\" Lucent Technologies disclaims all warranties with regard to this software, +'\" including all implied warranties of merchantability and fitness. In no event +'\" shall Lucent Technologies be liable for any special, indirect or +'\" consequential damages or any damages whatsoever resulting from loss of use, +'\" data or profits, whether in an action of contract, negligence or other +'\" tortuous action, arising out of or in connection with the use or performance +'\" of this software. +'\" +'\" Barchart widget created by Sani Nassif and George Howlett. +'\" +.TH barchart n BLT_VERSION BLT "BLT Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +barchart \- Bar chart for plotting X-Y coordinate data. +.SH SYNOPSIS +\fBbarchart\fI \fIpathName \fR?\fIoption value\fR?... +.BE +.SH DESCRIPTION +The \fBbarchart\fR command creates a bar chart for plotting +two-dimensional data (X-Y coordinates). A bar chart is a graphic means +of comparing numbers by displaying bars of lengths proportional to the +y-coordinates of the points they represented. The bar chart has many +configurable components: coordinate axes, elements, legend, grid +lines, cross hairs, etc. They allow you to customize the look and +feel of the graph. +.SH INTRODUCTION +The \fBbarchart\fR command creates a new window for plotting +two-dimensional data (X-Y coordinates), using bars of +various lengths to represent the data points. The bars are drawn in a +rectangular area displayed in the center of the new window. This is the +\fIplotting area\fR. The coordinate axes are drawn in +the margins surrounding the plotting area. By default, the legend is +drawn in the right margin. The title is displayed in top margin. +.PP +A \fBbarchart\fR widget has several configurable components: +coordinate axes, data elements, legend, grid, cross hairs, pens, +postscript, and annotation markers. Each component can be queried or +modified. +.TP 1i +\f(CWaxis\fR + +Up to four coordinate axes (two X\-coordinate and two Y\-coordinate +axes) can be displayed, but you can create and use any number of +axes. Axes control what region of data is displayed and how the data +is scaled. Each axis consists of the axis line, title, major and minor +ticks, and tick labels. Tick labels display the value at each major +tick. +.TP 1i +\f(CWcrosshairs\fR +Cross hairs are used to position the mouse pointer relative to the X +and Y coordinate axes. Two perpendicular lines, intersecting at the +current location of the mouse, extend across the plotting area to the +coordinate axes. +.TP 1i +\f(CWelement\fR +An element represents a set of data to be plotted. It contains an x +and y vector of values representing the data points. Each +data point is displayed as a bar where the length of the bar is +proportional to the ordinate (Y-coordinate) of the data point. +The appearance of the bar, such as its color, stipple, or relief +is configurable. +.sp +A special case exists when two or more data points have the same +abscissa (X-coordinate). By default, the bars are overlayed, one on +top of the other. The bars are drawn in the order of the element +display list. But you can also configure the bars to be displayed in +two other ways. They may be displayed as a stack, where each bar +(with the same abscissa) is stacked on the previous. Or they can be +drawn side-by-side as thin bars. The width of each bar is a function +of the number of data points with the same abscissa. +.TP 1i +\f(CWgrid\fR +Extends the major and minor ticks of the X\-axis and/or Y\-axis across the +plotting area. +.TP 1i +\f(CWlegend\fR +The legend displays the name and symbol of each data element. +The legend can be drawn in any margin or in the plotting area. +.TP 1i +\f(CWmarker\fR +Markers are used annotate or highlight areas of the graph. For +example, you could use a text marker to label a particular data +point. Markers come in various forms: text strings, bitmaps, connected +line segments, images, polygons, or embedded widgets. +.TP 1i +\f(CWpen\fR +Pens define attributes for elements. Data elements use pens to +specify how they should be drawn. A data element may use many pens at +once. Here the particular pen used for a data point is determined +from each element's weight vector (see the element's \fB\-weight\fR +and \fB\-style\fR options). +.TP 1i +\f(CWpostscript\fR +The widget can generate encapsulated PostScript output. This component +has several options to configure how the PostScript is generated. +.SH SYNTAX +.DS +\fBbarchart \fIpathName \fR?\fIoption value\fR?... +.DE +The \fBbarchart\fR command creates a new window \fIpathName\fR and makes +it into a \fBbarchart\fR widget. At the time this command is invoked, there +must not exist a window named \fIpathName\fR, but \fIpathName\fR's +parent must exist. Additional options may be specified on the +command line or in the option database to configure aspects of the +graph such as its colors and font. See the \fBconfigure\fR operation +below for the exact details about what \fIoption\fR and \fIvalue\fR +pairs are valid. +.PP +If successful, \fBbarchart\fR returns the path name of the widget. It +also creates a new Tcl command by the same name. You can use this +command to invoke various operations that query or modify the graph. +The general form is: +.DS +\fIpathName \fIoperation\fR \fR?\fIarg\fR?... +.DE +Both \fIoperation\fR and its arguments determine the exact behavior of +the command. The operations available for the graph are described in +the +.SB "BARCHART OPERATIONS" +section. +.PP +The command can also be used to access components of the graph. +.DS +\fIpathName component operation\fR ?\fIarg\fR?... +.DE +The operation, now located after the name of the component, is the +function to be performed on that component. Each component has its own +set of operations that manipulate that component. They will be +described below in their own sections. +.SH EXAMPLE +The \fBbarchart\fR command creates a new bar chart. +.CS +# Create a new bar chart. Plotting area is black. +barchart .b -plotbackground black +.CE +A new Tcl command \f(CW.b\fR is created. This command can be used +to query and modify the bar chart. For +example, to change the title of the graph to "My Plot", you use the +new command and the \fBconfigure\fR operation. +.CS +# Change the title. +\&.b configure -title "My Plot" +.CE +To add data elements, you use the command and the \fBelement\fR component. +.CS +# Create a new element named "e1" +\&.b element create e1 \\ + -xdata { 1 2 3 4 5 6 7 8 9 10 } \\ + -ydata { 26.18 50.46 72.85 93.31 111.86 128.47 143.14 + 155.85 166.60 175.38 } +.CE +The element's X-Y coordinates are specified using lists of +numbers. Alternately, BLT vectors could be used to hold the X-Y +coordinates. +.CS +# Create two vectors and add them to the barchart. +vector xVector yVector +xVector set { 1 2 3 4 5 6 7 8 9 10 } +yVector set { 26.18 50.46 72.85 93.31 111.86 128.47 143.14 155.85 + 166.60 175.38 } +\&n.b element create e1 -xdata xVector -ydata yVector +.CE +The advantage of using vectors is that when you modify one, the graph +is automatically redrawn to reflect the new values. +.CS +# Change the y coordinate of the first point. +set yVector(0) 25.18 +.CE +An element named \f(CWe1\fR is now created in \f(CW.b\fR. It +is automatically added to the display list of elements. You can +use this list to control in what order elements are displayed. +To query or reset the element display list, you use the element's +\fBshow\fR operation. +.CS +# Get the current display list +set elemList [.b element show] +# Remove the first element so it won't be displayed. +\&.b element show [lrange $elemList 0 end] +.CE +The element will be displayed by as many bars as there are data points +(in this case there are ten). The bars will be drawn centered at the +x-coordinate of the data point. All the bars will have the same +attributes (colors, stipple, etc). The width of each bar is by +default one unit. You can change this with using the \fB\-barwidth\fR +option. +.CS +# Change the scale of the x-coordinate data +xVector set { 0.2 0.4 0.6 0.8 1.0 1.2 1.4 1.6 1.8 2.0 } +# Make sure we change the bar width too. +\&.b configure -barwidth 0.2 +.CE +The height of each bar is proportional to the ordinate (Y-coordinate) +of the data point. +.PP +If two or more data points have the same abscissa (X-coordinate +value), the bars representing those data points may be drawn in +various ways. +The default is to overlay the bars, one on top of the other. +The ordering is determined from the of element display list. If +the stacked mode is selected (using the \fB\-barmode\fR configuration +option), the bars are stacked, each bar above the previous. +.CS +# Display the elements as stacked. +\&.b configure -barmode stacked +.CE +If the aligned mode is selected, the bars having the same +x-coordinates are displayed side by side. The width of each bar is a +fraction of its normal width, based upon the number of bars with the +same x-coordinate. +.CS +# Display the elements side-by-side. +\&.b configure -barmode aligned +.CE +By default, the element's label in the legend will be also +\f(CWe1\fR. You can change the label, or specify no legend entry, +again using the element's \fBconfigure\fR operation. +.CS +# Don't display "e1" in the legend. +\&.b element configure e1 -label "" +.CE +You can configure more than just the element's label. An element has +many attributes such as stipple, foreground and background colors, +relief, etc. +.CS +\&.b element configure e1 -fg red -bg pink \\ + -stipple gray50 +.CE +Four coordinate axes are automatically created: \f(CWx\fR, \f(CWx2\fR, +\f(CWy\fR, and \f(CWy2\fR. And by default, elements are mapped onto the +axes \f(CWx\fR and \f(CWy\fR. This can be changed with the \fB\-mapx\fR +and \fB\-mapy\fR options. +.CS +# Map "e1" on the alternate y axis "y2". +\&.b element configure e1 -mapy y2 +.CE +Axes can be configured in many ways too. For example, you change the +scale of the Y\-axis from linear to log using the \fBaxis\fR component. +.CS +# Y-axis is log scale. +\&.b axis configure y -logscale yes +.CE +One important way axes are used is to zoom in on a particular data +region. Zooming is done by simply specifying new axis limits using +the \fB\-min\fR and \fB\-max\fR configuration options. +.CS +\&.b axis configure x \-min 1.0 \-max 1.5 +\&.b axis configure y \-min 12.0 \-max 55.15 +.CE +To zoom interactively, you link the\fBaxis configure\fR operations with +some user interaction (such as pressing the mouse button), using the +\fBbind\fR command. To convert between screen and graph coordinates, +use the \fBinvtransform\fR operation. +.CS +# Click the button to set a new minimum +bind .b { + %W axis configure x \-min [%W axis invtransform x %x] + %W axis configure x \-min [%W axis invtransform x %y] +} +.CE +By default, the limits of the axis are determined from data values. +To reset back to the default limits, set the \fB\-min\fR and +\fB\-max\fR options to the empty value. +.CS +# Reset the axes to autoscale again. +\&.b axis configure x \-min {} \-max {} +\&.b axis configure y \-min {} \-max {} +.CE +By default, the legend is drawn in the right margin. You can +change this or any legend configuration options using the +\fBlegend\fR component. +.CS +# Configure the legend font, color, and relief +\&.b legend configure -position left -relief raised \\ + -font fixed -fg blue +.CE +To prevent the legend from being displayed, turn on the \fB\-hide\fR +option. +.CS +# Don't display the legend. +\&.b legend configure \-hide yes\fR +.CE +The \fBbarchart\fR has simple drawing procedures called markers. They can be +used to highlight or annotate data in the graph. The types of markers +available are bitmaps, polygons, lines, or windows. Markers can be +used, for example, to mark or brush points. For example there may be +a line marker which indicates some low-water value. Markers are created +using the \fBmarker\fR operation. +.CS +# Create a line represent the low water mark at 10.0 +\&.b marker create line -name "low_water" \\ + -coords { -Inf 10.0 Inf 10.0 } \\ + -dashes { 2 4 2 } -fg red -bg blue +.CE +This creates a line marker named \f(CWlow_water\fR. It will display a +horizontal line stretching across the plotting area at the +y-coordinate 10.0. The coordinates "-Inf" and "Inf" indicate the +relative minimum and maximum of the axis (in this case the x-axis). By +default, markers are drawn last, on top of the bars. You can change this +with the \fB\-under\fR option. +.CS +# Draw the marker before elements are drawn. +\&.b marker configure low_water -under yes +.CE +You can add cross hairs or grid lines using the \fBcrosshairs\fR and +\fBgrid\fR components. +.CS +# Display both cross hairs and grid lines. +\&.b crosshairs configure -hide no -color red +\&.b grid configure -hide no -dashes { 2 2 } +.CE +Finally, to get hardcopy of the graph, use the \fBpostscript\fR +component. +.CS +# Print the bar chart into file "file.ps" +\&.b postscript output file.ps -maxpect yes -decorations no +.CE +This generates a file \f(CWfile.ps\fR containing the encapsulated +PostScript of the graph. The option \fB\-maxpect\fR says to scale the +plot to the size of the page. Turning off the \fB\-decorations\fR +option denotes that no borders or color backgrounds should be +drawn (i.e. the background of the margins, legend, and plotting +area will be white). +.SH SYNTAX +.DS +\fBbarchart \fIpathName \fR?\fIoption value\fR?... +.DE +The \fBbarchart\fR command creates a new window \fIpathName\fR and makes +it into a barchart widget. At the time this command is invoked, there +must not exist a window named \fIpathName\fR, but \fIpathName\fR's +parent must exist. Additional options may may be specified on the +command line or in the option database to configure aspects of the +bar chart such as its colors and font. See the \fBconfigure\fR operation +below for the exact details as to what \fIoption\fR and \fIvalue\fR +pairs are valid. +.PP +If successful, \fBbarchart\fR returns \fIpathName\fR. It also creates a +new Tcl command \fIpathName\fR. This command may be used to invoke +various operations to query or modify the bar chart. It has the general +form: +.DS +\fIpathName \fIoperation\fR \fR?\fIarg\fR?... +.DE +Both \fIoperation\fR and its arguments determine the exact behavior of +the command. The operations available for the bar chart are described in +the following section. +.SH "BARCHART OPERATIONS" +.TP +\fIpathName \fBbar \fIelemName \fR?\fIoption value\fR?... +Creates a new barchart element \fIelemName\fR. It's an +error if an element \fIelemName\fR already exists. +See the manual for \fBbarchart\fR for details about +what \fIoption\fR and \fIvalue\fR pairs are valid. +.TP +\fIpathName \fBcget\fR \fIoption\fR +Returns the current value of the configuration option given by +\fIoption\fR. \fIOption\fR may be any option described +below for the \fBconfigure\fR operation. +.TP +\fIpathName \fBconfigure \fR?\fIoption value\fR?... +Queries or modifies the configuration options of the graph. If +\fIoption\fR isn't specified, a list describing the current +options for \fIpathName\fR is returned. If \fIoption\fR is specified, +but not \fIvalue\fR, then a list describing \fIoption\fR is returned. +If one or more \fIoption\fR and \fIvalue\fR pairs are specified, then +for each pair, the option \fIoption\fR is set to \fIvalue\fR. +The following options are valid. +.RS +.TP +\fB\-background \fIcolor\fR +Sets the background color. This includes the margins and +legend, but not the plotting area. +.TP +\fB\-barmode \fImode\fR +Indicates how related bar elements will be drawn. Related elements +have data points with the same abscissas (X-coordinates). \fIMode\fR +indicates how those segments should be drawn. \fIMode\fR can be +\f(CWinfront\fR, \f(CWaligned\fR, \f(CWoverlap\fR, or \f(CWstacked\fR. +The default mode is \f(CWinfront\fR. +.RS +.TP 1i +\f(CWinfront\fR +Each successive segment is drawn in front of the previous. +.TP 1i +\f(CWstacked\fR +Each successive segment is stacked vertically on top of the previous. +.TP 1i +\f(CWaligned\fR +Segments is displayed aligned from right-to-left. +.TP 1i +\f(CWoverlap\fR +Like \f(CWaligned\fR but segments slightly overlap each other. +.RE +.TP +\fB\-barwidth \fIvalue\fR +Specifies the width of the bars. This value can be overrided by the +individual elements using their \fB\-barwidth\fR configuration option. +\fIValue\fR is the width in terms of graph-coordinates. The +default width is \f(CW1.0\fR. +.TP +\fB\-borderwidth \fIpixels\fR +Sets the width of the 3\-D border around the outside edge of the widget. The +\fB\-relief\fR option determines if the border is to be drawn. The +default is \f(CW2\fR. +.TP +\fB\-bottommargin \fIpixels\fR +Specifies the size of the margin below the X\-coordinate axis. If +\fIpixels\fR is \f(CW0\fR, the size of the margin is selected automatically. +The default is \f(CW0\fR. +.TP +\fB\-bufferelements \fIboolean\fR +Indicates whether an internal pixmap to buffer the display of data +elements should be used. If \fIboolean\fR is true, data elements are +drawn to an internal pixmap. This option is especially useful when +the graph is redrawn frequently while the remains data unchanged (for +example, moving a marker across the plot). See the +.SB "SPEED TIPS" +section. +The default is \f(CW1\fR. +.TP +\fB\-cursor \fIcursor\fR +Specifies the widget's cursor. The default cursor is \f(CWcrosshair\fR. +.TP +\fB\-font \fIfontName\fR +Specifies the font of the graph title. The default is +\f(CW*-Helvetica-Bold-R-Normal-*-18-180-*\fR. +.TP +\fB\-halo \fIpixels\fR +Specifies a maximum distance to consider when searching for the +closest data point (see the element's \fBclosest\fR operation below). +Data points further than \fIpixels\fR away are ignored. The default is +\f(CW0.5i\fR. +.TP +\fB\-height \fIpixels\fR +Specifies the requested height of widget. The default is +\f(CW4i\fR. +.TP +\fB\-invertxy \fIboolean\fR +Indicates whether the placement X\-axis and Y\-axis should be inverted. If +\fIboolean\fR is true, the X and Y axes are swapped. The default is +\f(CW0\fR. +.TP +\fB\-justify \fIjustify\fR +Specifies how the title should be justified. This matters only when +the title contains more than one line of text. \fIJustify\fR must be +\f(CWleft\fR, \f(CWright\fR, or \f(CWcenter\fR. The default is +\f(CWcenter\fR. +.TP +\fB\-leftmargin \fIpixels\fR +Sets the size of the margin from the left edge of the window to +the Y\-coordinate axis. If \fIpixels\fR is \f(CW0\fR, the size is +calculated automatically. The default is \f(CW0\fR. +.TP +\fB\-plotbackground \fIcolor\fR +Specifies the background color of the plotting area. The default is +\f(CWwhite\fR. +.TP +\fB\-plotborderwidth \fIpixels\fR +Sets the width of the 3-D border around the plotting area. The +\fB\-plotrelief\fR option determines if a border is drawn. The +default is \f(CW2\fR. +.TP +\fB\-plotpadx \fIpad\fR +Sets the amount of padding to be added to the left and right sides of +the plotting area. \fIPad\fR can be a list of one or two screen +distances. If \fIpad\fR has two elements, the left side of the +plotting area entry is padded by the first distance and the right side +by the second. If \fIpad\fR is just one distance, both the left and +right sides are padded evenly. The default is \f(CW8\fR. +.TP +\fB\-plotpady \fIpad\fR +Sets the amount of padding to be added to the top and bottom of the +plotting area. \fIPad\fR can be a list of one or two screen +distances. If \fIpad\fR has two elements, the top of the plotting +area is padded by the first distance and the bottom by the second. If +\fIpad\fR is just one distance, both the top and bottom are padded +evenly. The default is \f(CW8\fR. +.TP +\fB\-plotrelief \fIrelief\fR +Specifies the 3-D effect for the plotting area. \fIRelief\fR +specifies how the interior of the plotting area should appear relative +to rest of the graph; for example, \f(CWraised\fR means the plot should +appear to protrude from the graph, relative to the surface of the +graph. The default is \f(CWsunken\fR. +.TP +\fB\-relief \fIrelief\fR +Specifies the 3-D effect for the barchart widget. \fIRelief\fR +specifies how the graph should appear relative to widget it is packed +into; for example, \f(CWraised\fR means the graph should +appear to protrude. The default is \f(CWflat\fR. +.TP +\fB\-rightmargin \fIpixels\fR +Sets the size of margin from the plotting area to the right edge of +the window. By default, the legend is drawn in this margin. If +\fIpixels\fR is than 1, the margin size is selected automatically. +.TP +\fB\-takefocus\fR \fIfocus\fR +Provides information used when moving the focus from window to window +via keyboard traversal (e.g., Tab and Shift-Tab). If \fIfocus\fR is +\f(CW0\fR, this means that this window should be skipped entirely during +keyboard traversal. \f(CW1\fR means that the this window should always +receive the input focus. An empty value means that the traversal +scripts make the decision whether to focus on the window. +The default is \f(CW""\fR. +.TP +\fB\-tile \fIimage\fR +Specifies a tiled background for the widget. If \fIimage\fR isn't +\f(CW""\fR, the background is tiled using \fIimage\fR. +Otherwise, the normal background color is drawn (see the +\fB\-background\fR option). \fIImage\fR must be an image created +using the Tk \fBimage\fR command. The default is \f(CW""\fR. +.TP +\fB\-title \fItext\fR +Sets the title to \fItext\fR. If \fItext\fR is \f(CW""\fR, +no title will be displayed. +.TP +\fB\-topmargin \fIpixels\fR +Specifies the size of the margin above the x2 axis. If \fIpixels\fR +is \f(CW0\fR, the margin size is calculated automatically. +.TP +\fB\-width \fIpixels\fR +Specifies the requested width of the widget. The default is +\f(CW5i\fR. +.RE +.TP +\fIpathName \fBcrosshairs \fIoperation \fR?\fIarg\fR? +See the +.SB "CROSSHAIRS COMPONENT" +section. +.TP +\fIpathName \fBelement \fIoperation \fR?\fIarg\fR?... +See the +.SB "ELEMENT COMPONENTS" +section. +.TP +\fIpathName \fBextents \fIitem\fR +Returns the size of a particular item in the graph. \fIItem\fR must +be either \f(CWleftmargin\fR, \f(CWrightmargin\fR, \f(CWtopmargin\fR, +\f(CWbottommargin\fR, \f(CWplotwidth\fR, or \f(CWplotheight\fR. +.TP +\fIpathName \fBgrid \fIoperation \fR?\fIarg\fR?... +See the +.SB "GRID COMPONENT" +section. +.TP +\fIpathName \fBinvtransform \fIwinX winY\fR +Performs an inverse coordinate transformation, mapping window +coordinates back to graph-coordinates, using the standard X\-axis and Y\-axis. +Returns a list of containing the X-Y graph-coordinates. +.TP +\fIpathName \fBinside \fIx y\fR +Returns \f(CW1\fR is the designated screen-coordinate (\fIx\fR and \fIy\fR) +is inside the plotting area and \f(CW0\fR otherwise. +.TP +\fIpathName \fBlegend \fIoperation \fR?\fIarg\fR?... +See the +.SB "LEGEND COMPONENT" +section. +.TP +\fIpathName \fBline\fB operation arg\fR... +The operation is the same as \fBelement\fR. +.TP +\fIpathName \fBmarker \fIoperation \fR?\fIarg\fR?... +See the +.SB "MARKER COMPONENTS" +section. +.TP +\fIpathName\fR \fBmetafile\fR ?\fIfileName\fR? +\fIThis operation is for Window platforms only\fR. +Creates a Windows enhanced metafile of the barchart. +If present, \fIfileName\fR is the file name of the new metafile. +Otherwise, the metafile is automatically added to the clipboard. +.TP +\fIpathName \fBpostscript \fIoperation \fR?\fIarg\fR?... +See the +.SB "POSTSCRIPT COMPONENT" +section. +.TP +\fIpathName \fBsnap \fIphotoName\fR +Takes a snapshot of the graph and stores the contents in the photo +image \fIphotoName\fR. \fIPhotoName\fR is the name of a Tk photo +image that must already exist. +.TP +\fIpathName \fBtransform \fIx y\fR +Performs a coordinate transformation, mapping graph-coordinates to +window coordinates, using the standard X\-axis and Y\-axis. +Returns a list containing the X\-Y screen-coordinates. +.TP +\fIpathName \fBxaxis \fIoperation\fR ?\fIarg\fR?... +.TP +\fIpathName \fBx2axis \fIoperation\fR ?\fIarg\fR?... +.TP +\fIpathName \fByaxis \fIoperation\fR ?\fIarg\fR?... +.TP +\fIpathName \fBy2axis \fIoperation\fR ?\fIarg\fR?... +See the +.SB "AXIS COMPONENTS" +section. +.SH "BARCHART COMPONENTS" +A graph is composed of several components: coordinate axes, data +elements, legend, grid, cross hairs, postscript, and annotation +markers. Instead of one big set of configuration options and +operations, the graph is partitioned, where each component has its own +configuration options and operations that specifically control that +aspect or part of the graph. +.SS "AXIS COMPONENTS" +Four coordinate axes are automatically created: two X\-coordinate axes +(\f(CWx\fR and \f(CWx2\fR) and two Y\-coordinate axes (\f(CWy\fR, and +\f(CWy2\fR). By default, the axis \f(CWx\fR is located in the bottom +margin, \f(CWy\fR in the left margin, \f(CWx2\fR in the top margin, and +\f(CWy2\fR in the right margin. +.PP +An axis consists of the axis line, title, major and minor ticks, and +tick labels. Major ticks are drawn at uniform intervals along the +axis. Each tick is labeled with its coordinate value. Minor ticks +are drawn at uniform intervals within major ticks. +.PP +The range of the axis controls what region of data is plotted. +Data points outside the minimum and maximum limits of the axis are +not plotted. By default, the minimum and maximum limits are +determined from the data, but you can reset either limit. +.PP +You can create and use several axes. To create an axis, invoke +the axis component and its create operation. +.CS +# Create a new axis called "temperature" +\&.b axis create temperature +.CE +You map data elements to an axis using the element's \-mapy and \-mapx +configuration options. They specify the coordinate axes an element +is mapped onto. +.CS +# Now map the temperature data to this axis. +\&.b element create "temp" \-xdata $x \-ydata $tempData \\ + \-mapy temperature +.CE +While you can have many axes, only four axes can be displayed +simultaneously. They are drawn in each of the margins surrounding +the plotting area. The axes \f(CWx\fR and \f(CWy\fR are drawn in the +bottom and left margins. The axes \f(CWx2\fR and \f(CWy2\fR are drawn in +top and right margins. Only \f(CWx\fR and \f(CWy\fR are shown by +default. Note that the axes can have different scales. +.PP +To display a different axis, you invoke one of the following +components: \fBxaxis\fR, \fByaxis\fR, \fBx2axis\fR, and \fBy2axis\fR. +The \fBuse\fR operation designates the axis to be drawn in the +corresponding margin: \fBxaxis\fR in the bottom, \fByaxis\fR in the left, +\fBx2axis\fR in the top, and \fBy2axis\fR in the right. +.CS +# Display the axis temperature in the left margin. +\&.b yaxis use temperature +.CE +.PP +You can configure axes in many ways. The axis scale can be linear or +logarithmic. The values along the axis can either monotonically +increase or decrease. If you need custom tick labels, you can specify +a Tcl procedure to format the label any way you wish. You can +control how ticks are drawn, by changing the major tick interval +or the number of minor ticks. You can define non-uniform tick intervals, +such as for time-series plots. +.PP +.TP +\fIpathName \fBaxis \fBcget \fIaxisName \fIoption\fR +Returns the current value of the option given by \fIoption\fR for +\fIaxisName\fR. \fIOption\fR may be any option described below +for the axis \fBconfigure\fR operation. +.TP +\fIpathName \fBaxis \fBconfigure \fIaxisName \fR?\fIaxisName\fR?... ?\fIoption value\fR?... +Queries or modifies the configuration options of \fIaxisName\fR. +Several axes can be changed. If \fIoption\fR isn't specified, a list +describing all the current options for \fIaxisName\fR is returned. If +\fIoption\fR is specified, but not \fIvalue\fR, then a list describing +\fIoption\fR is returned. If one or more \fIoption\fR and \fIvalue\fR +pairs are specified, then for each pair, the axis option \fIoption\fR +is set to \fIvalue\fR. The following options are valid for axes. +.RS +.TP +\fB\-autorange \fIrange\fR +Sets the range of values for the axis to \fIrange\fR. The axis limits +are automatically reset to display the most recent data points in this range. +If \fIrange\fR is 0.0, the range is +determined from the limits of the data. If \fB\-min\fR or \fB-max\fR +are specified, they override this option. The default is \f(CW0.0\fR. +.TP +\fB\-color \fIcolor\fR +Sets the color of the axis and tick labels. +The default is \f(CWblack\fR. +.TP +\fB\-command \fIprefix\fR +Specifies a Tcl command to be invoked when formatting the axis tick +labels. \fIPrefix\fR is a string containing the name of a Tcl proc and +any extra arguments for the procedure. This command is invoked for each +major tick on the axis. Two additional arguments are passed to the +procedure: the pathname of the widget and the current the numeric +value of the tick. The procedure returns the formatted tick label. If +\f(CW""\fR is returned, no label will appear next to the tick. You can +get the standard tick labels again by setting \fIprefix\fR to +\f(CW""\fR. The default is \f(CW""\fR. +.sp 1 +Please note that this procedure is invoked while the bar chart is redrawn. +You may query the widget's configuration options. But do not reset +options, because this can have unexpected results. +.TP +\fB\-descending \fIboolean\fR +Indicates whether the values along the axis are monotonically increasing or +decreasing. If \fIboolean\fR is true, the axis values will be +decreasing. The default is \f(CW0\fR. +.TP +\fB\-hide \fIboolean\fR +Indicates whether the axis is displayed. +.TP +\fB\-justify \fIjustify\fR +Specifies how the axis title should be justified. This matters only +when the axis title contains more than one line of text. \fIJustify\fR +must be \f(CWleft\fR, \f(CWright\fR, or \f(CWcenter\fR. The default is +\f(CWcenter\fR. +.TP +\fB\-limits \fIformatStr\fR +Specifies a printf-like description to format the minimum and maximum +limits of the axis. The limits are displayed at the top/bottom or +left/right sides of the plotting area. \fIFormatStr\fR is a list of +one or two format descriptions. If one description is supplied, both +the minimum and maximum limits are formatted in the same way. If two, +the first designates the format for the minimum limit, the second for +the maximum. If \f(CW""\fR is given as either description, then +the that limit will not be displayed. The default is \f(CW""\fR. +.TP +\fB\-linewidth \fIpixels\fR +Sets the width of the axis and tick lines. The default is \f(CW1\fR +pixel. +.TP +\fB\-logscale \fIboolean\fR +Indicates whether the scale of the axis is logarithmic or linear. If +\fIboolean\fR is true, the axis is logarithmic. The default scale is +linear. +.TP +\fB\-loose \fIboolean\fR +Indicates whether the limits of the axis should fit the data points tightly, +at the outermost data points, or loosely, at the outer tick intervals. +This is relevant only when the axis limit is automatically calculated. +If \fIboolean\fR is true, the axis range is "loose". +The default is \f(CW0\fR. +.TP +\fB\-majorticks \fImajorList\fR +Specifies where to display major axis ticks. You can use this option +to display ticks at non-uniform intervals. \fIMajorList\fR is a list +of axis coordinates designating the location of major ticks. No +minor ticks are drawn. If \fImajorList\fR is \f(CW""\fR, +major ticks will be automatically computed. The default is \f(CW""\fR. +.TP +\fB\-max \fIvalue\fR +Sets the maximum limit of \fIaxisName\fR. Any data point greater +than \fIvalue\fR is not displayed. If \fIvalue\fR is \f(CW""\fR, +the maximum limit is calculated using the largest data value. +The default is \f(CW""\fR. +.TP +\fB\-min \fIvalue\fR +Sets the minimum limit of \fIaxisName\fR. Any data point less than +\fIvalue\fR is not displayed. If \fIvalue\fR is \f(CW""\fR, +the minimum limit is calculated using the smallest data value. +The default is \f(CW""\fR. +.TP +\fB\-minorticks \fIminorList\fR +Specifies where to display minor axis ticks. You can use this option +to display minor ticks at non-uniform intervals. \fIMinorList\fR is a +list of real values, ranging from 0.0 to 1.0, designating the placement of +a minor tick. No minor ticks are drawn if the \fB\-majortick\fR +option is also set. If \fIminorList\fR is \f(CW""\fR, minor ticks will +be automatically computed. The default is \f(CW""\fR. +.TP +\fB\-rotate \fItheta\fR +Specifies the how many degrees to rotate the axis tick labels. +\fITheta\fR is a real value representing the number of degrees +to rotate the tick labels. The default is \f(CW0.0\fR degrees. +.TP +\fB\-shiftby \fIvalue\fR +Specifies how much to automatically shift the range of the axis. +When the new data exceeds the current axis maximum, the maximum +is increased in increments of \fIvalue\fR. You can use this +option to prevent the axis limits from being recomputed +at each new time point. If \fIvalue\fR is 0.0, then no automatic +shifting is down. The default is \f(CW0.0\fR. +.TP +\fB\-showticks \fIboolean\fR +Indicates whether axis ticks should be drawn. If \fIboolean\fR is +true, ticks are drawn. If false, only the +axis line is drawn. The default is \f(CW1\fR. +.TP +\fB\-stepsize \fIvalue\fR +Specifies the interval between major axis ticks. If \fIvalue\fR isn't +a valid interval (must be less than the axis range), +the request is ignored and the step size is automatically calculated. +.TP +\fB\-subdivisions \fInumber\fR +Indicates how many minor axis ticks are +to be drawn. For example, if \fInumber\fR is two, only one minor +tick is drawn. If \fInumber\fR is one, no minor ticks are +displayed. The default is \f(CW2\fR. +.TP +\fB\-tickfont \fIfontName\fR +Specifies the font for axis tick labels. The default is +\f(CW*-Courier-Bold-R-Normal-*-100-*\fR. +.TP +\fB\-ticklength \fIpixels\fR +Sets the length of major and minor ticks (minor ticks are half the +length of major ticks). If \fIpixels\fR is less than zero, the axis +will be inverted with ticks drawn pointing towards the plot. The +default is \f(CW0.1i\fR. +.TP +\fB\-title \fItext\fR +Sets the title of the axis. If \fItext\fR is +\f(CW""\fR, no axis title will be displayed. +.TP +\fB\-titlecolor \fIcolor\fR +Sets the color of the axis title. The default is \f(CWblack\fR. +.TP +\fB\-titlefont \fIfontName\fR +Specifies the font for axis title. The default is +\f(CW*-Helvetica-Bold-R-Normal-*-14-140-*\fR. +.PP +Axis configuration options may be also be set by the \fBoption\fR +command. The resource class is \f(CWAxis\fR. The resource names +are the names of the axes (such as \f(CWx\fR or \f(CWx2\fR). +.CS +option add *Barchart.Axis.Color blue +option add *Barchart.x.LogScale true +option add *Barchart.x2.LogScale false +.CE +.RE +.TP +\fIpathName \fBaxis \fBcreate \fIaxisName \fR?\fIoption value\fR?... +Creates a new axis by the name \fIaxisName\fR. No axis by the same +name can already exist. \fIOption\fR and \fIvalue\fR are described +in above in the axis \fBconfigure\fR operation. +.TP +\fIpathName \fBaxis \fBdelete \fR?\fIaxisName\fR?... +Deletes the named axes. An axis is not really +deleted until it is not longer in use, so it's safe to delete +axes mapped to elements. +.TP +\fIpathName \fBaxis invtransform \fIaxisName value\fR +Performs the inverse transformation, changing the screen-coordinate +\fIvalue\fR to a graph-coordinate, mapping the value mapped to +\fIaxisName\fR. Returns the graph-coordinate. +.TP +\fIpathName \fBaxis limits \fIaxisName\fR +Returns a list of the minimum and maximum limits for \fIaxisName\fR. The order +of the list is \f(CWmin max\fR. +.TP +\fIpathName \fBaxis names \fR?\fIpattern\fR?... +Returns a list of axes matching zero or more patterns. If no +\fIpattern\fR argument is give, the names of all axes are returned. +.TP +\fIpathName \fBaxis transform \fIaxisName value\fR +Transforms the coordinate \fIvalue\fR to a screen-coordinate by mapping +the it to \fIaxisName\fR. Returns the transformed screen-coordinate. +.PP +Only four axes can be displayed simultaneously. By default, they are +\f(CWx\fR, \f(CWy\fR, \f(CWx2\fR, and \f(CWy2\fR. You can swap in a different +axis with \fBuse\fR operation of the special axis components: +\fBxaxis\fR, \fBx2axis\fR, \fByaxis\fR, and \fBy2axis\fR. +.CS +\&.g create axis temp +\&.g create axis time +\&... +\&.g xaxis use temp +\&.g yaxis use time +.CE +Only the axes specified for use are displayed on the screen. +.PP +The \fBxaxis\fR, \fBx2axis\fR, \fByaxis\fR, and \fBy2axis\fR +components operate on an axis location rather than a specific axis +like the more general \fBaxis\fR component does. The \fBxaxis\fR +component manages the X-axis located in the bottom margin (whatever +axis that happens to be). Likewise, \fByaxis\fR uses the Y-axis in +the left margin, \fBx2axis\fR the top X-axis, and \fBy2axis\fR the +right Y-axis. +.PP +They implicitly control the axis that is currently using to that +location. By default, \fBxaxis\fR uses the \f(CWx\fR axis, \fByaxis\fR +uses \f(CWy\fR, \fBx2axis\fR uses \f(CWx2\fR, and \fBy2axis\fR uses +\f(CWy2\fR. These components can be more convenient to use than always +determining what axes are current being displayed by the graph. +.PP +The following operations are available for axes. They mirror exactly +the operations of the \fBaxis\fR component. The \fIaxis\fR argument +must be \fBxaxis\fR, \fBx2axis\fR, \fByaxis\fR, or \fBy2axis\fR. +.TP +\fIpathName \fIaxis \fBcget \fIoption\fR +.TP +\fIpathName \fIaxis \fBconfigure \fR?\fIoption value\fR?... +.TP +\fIpathName \fIaxis\fB invtransform \fIvalue\fR +.TP +\fIpathName \fIaxis \fBlimits\fR +.TP +\fIpathName \fIaxis\fB transform \fIvalue\fR +.TP +\fIpathName \fIaxis\fB use \fR?\fIaxisName\fR? +Designates the axis \fIaxisName\fR is to be displayed at this +location. \fIAxisName\fR can not be already in use at another location. +This command returns the name of the axis currently using this location. +.SS "CROSSHAIRS COMPONENT" +Cross hairs consist of two intersecting lines (one vertical and one horizontal) +drawn completely across the plotting area. They are used to position +the mouse in relation to the coordinate axes. Cross hairs differ from line +markers in that they are implemented using XOR drawing primitives. +This means that they can be quickly drawn and erased without redrawing +the entire widget. +.PP +The following operations are available for cross hairs: +.TP +\fIpathName \fBcrosshairs cget \fIoption\fR +Returns the current value of the cross hairs configuration option +given by \fIoption\fR. \fIOption\fR may be any option +described below for the cross hairs \fBconfigure\fR operation. +.TP +\fIpathName \fBcrosshairs configure \fR?\fIoption value\fR?... +Queries or modifies the configuration options of the cross hairs. If +\fIoption\fR isn't specified, a list describing all the current +options for the cross hairs is returned. If \fIoption\fR is specified, +but not \fIvalue\fR, then a list describing \fIoption\fR is returned. +If one or more \fIoption\fR and \fIvalue\fR pairs are specified, then +for each pair, the cross hairs option \fIoption\fR is set to +\fIvalue\fR. +The following options are available for cross hairs. +.RS +.TP +\fB\-color \fIcolor\fR +Sets the color of the cross hairs. The default is \f(CWblack\fR. +.TP +\fB\-dashes \fIdashList\fR +Sets the dash style of the cross hairs. \fIDashList\fR is a list of up +to 11 numbers that alternately represent the lengths of the dashes +and gaps on the cross hair lines. Each number must be between 1 and +255. If \fIdashList\fR is \f(CW""\fR, the cross hairs will be solid +lines. +.TP +\fB\-hide \fIboolean\fR +Indicates whether cross hairs are drawn. If \fIboolean\fR is true, +cross hairs are not drawn. The default is \f(CWyes\fR. +.TP +\fB\-linewidth \fIpixels\fR +Set the width of the cross hair lines. The default is \f(CW1\fR. +.TP +\fB\-position \fIpos\fR +Specifies the screen position where the cross hairs intersect. +\fIPos\fR must be in the form "\fI@x,y\fR", where \fIx\fR and \fIy\fR +are the window coordinates of the intersection. +.PP +Cross hairs configuration options may be also be set by the +\fBoption\fR command. The resource name and class are +\f(CWcrosshairs\fR and \f(CWCrosshairs\fR respectively. +.CS +option add *Barchart.Crosshairs.LineWidth 2 +option add *Barchart.Crosshairs.Color red +.CE +.RE +.TP +\fIpathName \fBcrosshairs off\fR +Turns off the cross hairs. +.TP +\fIpathName \fBcrosshairs on\fR +Turns on the display of the cross hairs. +.TP +\fIpathName \fBcrosshairs toggle\fR +Toggles the current state of the cross hairs, alternately mapping and +unmapping the cross hairs. +.SH "ELEMENTS" +A data element represents a set of data. It contains x and y vectors +which are the coordinates of the data points. Elements are displayed +as bars where the length of the bar is proportional to the ordinate of +the data point. Elements also control the appearance of the data, +such as the color, stipple, relief, etc. +.PP +When new data elements are created, they are automatically added to a +list of displayed elements. The display list controls what elements +are drawn and in what order. +.PP +The following operations are available for elements. +.TP +\fIpathName \fBelement activate \fIelemName \fR?\fIindex\fR?... +Specifies the data points of element \fIelemName\fR to be drawn +using active foreground and background colors. \fIElemName\fR is the +name of the element and \fIindex\fR is a number representing the index +of the data point. If no indices are present then all data points +become active. +.TP +\fIpathName \fBelement bind \fItagName\fR ?\fIsequence\fR? ?\fIcommand\fR? +Associates \fIcommand\fR with \fItagName\fR such that whenever the +event sequence given by \fIsequence\fR occurs for an element with this +tag, \fIcommand\fR will be invoked. The syntax is similar to the +\fBbind\fR command except that it operates on graph elements, rather +than widgets. See the \fBbind\fR manual entry for +complete details on \fIsequence\fR and the substitutions performed on +\fIcommand\fR before invoking it. +.sp +If all arguments are specified then a new binding is created, replacing +any existing binding for the same \fIsequence\fR and \fItagName\fR. +If the first character of \fIcommand\fR is \f(CW+\fR then \fIcommand\fR +augments an existing binding rather than replacing it. +If no \fIcommand\fR argument is provided then the command currently +associated with \fItagName\fR and \fIsequence\fR (it's an error occurs +if there's no such binding) is returned. If both \fIcommand\fR and +\fIsequence\fR are missing then a list of all the event sequences for +which bindings have been defined for \fItagName\fR. +.TP +\fIpathName \fBelement cget \fIelemName \fIoption\fR +Returns the current value of the element configuration option given by +\fIoption\fR. \fIOption\fR may be any of the options described below +for the element \fBconfigure\fR operation. +.TP +\fIpathName \fBelement closest \fIx y\fR ?\fIoption value\fR?... ?\fIelemName\fR?... +Finds the data point representing the bar closest to the window +coordinates \fIx\fR and \fIy\fR in the element \fIelemName\fR. +\fIElemName\fR is the name of an element, which must be currently displayed. +If no elements are specified, then all displayed elements are searched. It +returns a key-value list containing the name of the closest element, +the index of its closest point, and the graph-coordinates of the +point. If no data point within the threshold distance can be found, +\f(CW""\fR is returned. The following \fIoption\fR-\fIvalue\fR pairs +are available. +.RS +.TP +\fB\-halo \fIpixels\fR +Specifies a threshold distance where selected data points are ignored. +\fIPixels\fR is a valid screen distance, such as \f(CW2\fR or \f(CW1.2i\fR. +If this option isn't specified, then it defaults to the value of the +\fBbarchart\fR's \fB\-halo\fR option. +.RE +.TP +\fIpathName \fBelement configure \fIelemName \fR?\fIelemName\fR... ?\fIoption value\fR?... +Queries or modifies the configuration options for elements. Several +elements can be modified at the same time. If \fIoption\fR isn't +specified, a list describing all the current options for +\fIelemName\fR is returned. If \fIoption\fR is specified, but not +\fIvalue\fR, then a list describing the option \fIoption\fR is +returned. If one or more \fIoption\fR and \fIvalue\fR pairs are +specified, then for each pair, the element option \fIoption\fR is set +to \fIvalue\fR. The following options are valid for elements. +.RS +.TP +\fB\-activepen \fIpenName\fR +Specifies pen to use to draw active element. If \fIpenName\fR is +\f(CW""\fR, no active elements will be drawn. The default is +\f(CWactiveLine\fR. +.TP +\fB\-bindtags \fItagList\fR +Specifies the binding tags for the element. \fITagList\fR is a list +of binding tag names. The tags and their order will determine how +events for elements. Each tag in the list matching the current event +sequence will have its Tcl command executed. Implicitly the name of +the element is always the first tag in the list. The default value is +\f(CWall\fR. +.TP +\fB\-background \fIcolor\fR +Sets the the color of the border around each bar. The default is +\f(CWwhite\fR. +.TP +\fB\-barwidth \fIvalue\fR +Specifies the width the bars drawn for the element. \fIValue\fR is +the width in X-coordinates. If this option isn't +specified, the width of each bar is the value of the widget's +\fB\-barwidth\fR option. +.TP +\fB\-baseline \fIvalue\fR +Specifies the baseline of the bar segments. This affects how bars are +drawn since bars are drawn from their respective y-coordinate the +baseline. By default the baseline is \f(CW0.0\fR. +.TP +\fB\-borderwidth \fIpixels\fR +Sets the border width of the 3-D border drawn around the outside of +each bar. The \fB\-relief\fR option determines if such a border is +drawn. \fIPixels\fR must be a valid screen distance like \f(CW2\fR or +\f(CW0.25i\fR. The default is \f(CW2\fR. +.TP +\fB\-data \fIcoordList\fR +Specifies the X\-Y coordinates of the data. \fICoordList\fR is a +list of numeric expressions representing the X\-Y coordinate pairs +of each data point. +.TP +\fB\-foreground \fIcolor\fR +Sets the color of the interior of the bars. +.TP +\fB\-hide \fIboolean\fR +Indicates whether the element is displayed. The default is \f(CWno\fR. +.TP +\fB\-label \fItext\fR +Sets the element's label in the legend. If \fItext\fR +is \f(CW""\fR, the element will have no entry in the legend. +The default label is the element's name. +.TP +\fB\-mapx \fIxAxis\fR +Selects the X\-axis to map the element's X\-coordinates onto. +\fIXAxis\fR must be the name of an axis. The default is \f(CWx\fR. +.TP +\fB\-mapy \fIyAxis\fR +Selects the Y\-axis to map the element's Y\-coordinates onto. +\fIYAxis\fR must be the name of an axis. The default is \f(CWy\fR. +.TP +\fB\-relief \fIstring\fR +Specifies the 3-D effect desired for bars. \fIRelief\fR indicates how +the interior of the bar should appear relative to the surface of the +chart; for example, \f(CWraised\fR means the bar should appear to +protrude from the surface of the plotting area. The default is +\f(CWraised\fR. +.TP +\fB\-stipple \fIbitmap\fR +Specifies a stipple pattern with which to draw the bars. If +\fIbitmap\fR is \f(CW""\fR, then the bar is drawn in a solid fashion. +.TP +\fB\-xdata \fIxVector\fR +Specifies the x-coordinate vector of the data. +\fIXVector\fR is the name of a BLT vector or a +list of numeric expressions. +.TP +\fB\-ydata \fIyVector\fR +Specifies the y-coordinate vector of the data. +\fIYVector\fR is the name of a BLT vector or a list of +numeric expressions. +.PP +Element configuration options may also be set by the +\fBoption\fR command. The resource names in the option database +are prefixed by \f(CWelem\fR. +.CS +option add *Barchart.Element.background blue +.CE +.RE +.TP +\fIpathName \fBelement create \fIelemName\fR ?\fIoption value\fR?... +Creates a new element \fIelemName\fR. Element +names must be unique, so an element \fIelemName\fR may not already +exist. If additional arguments are present, they specify any of the +element options valid for element \fBconfigure\fR operation. +.TP +\fIpathName \fBelement deactivate \fIpattern\fR... +Deactivates all the elements matching \fIpattern\fR for the graph. +Elements whose names match any of the patterns given are redrawn +using their normal colors. +.TP +\fIpathName \fBelement delete\fR ?\fIpattern\fR?... +Deletes all the elements matching \fIpattern\fR for the graph. +Elements whose names match any of the patterns given are deleted. +The graph will be redrawn without the deleted elements. +.TP +\fIpathName \fBelement exists \fIelemName\fR +Returns \f(CW1\fR if an element \fIelemName\fR currently exists and +\f(CW0\fR otherwise. +.TP +\fIpathName \fBelement names \fR?\fIpattern\fR?... +Returns the elements matching one or more pattern. If no +\fIpattern\fR is given, the names of all elements is returned. +.TP +\fIpathName \fBelement show\fR ?\fInameList\fR? +Queries or modifies the element display list. The element display +list designates the elements drawn and in what +order. \fINameList\fR is a list of elements to be displayed in the +order they are named. If there is no \fInameList\fR argument, +the current display list is returned. +.TP +\fIpathName \fBelement type\fR \fIelemName\fR +Returns the type of \fIelemName\fR. +If the element is a bar element, the commands returns the string +\f(CW"bar"\fR, otherwise it returns \f(CW"line"\fR. +.CE +.SS "GRID COMPONENT" +Grid lines extend from the major and minor ticks of each axis +horizontally or vertically across the plotting area. The following +operations are available for grid lines. +.TP +\fIpathName \fBgrid cget \fIoption\fR +Returns the current value of the grid line configuration option given by +\fIoption\fR. \fIOption\fR may be any option described below +for the grid \fBconfigure\fR operation. +.TP +\fIpathName \fBgrid configure\fR ?\fIoption value\fR?... +Queries or modifies the configuration options for grid lines. If +\fIoption\fR isn't specified, a list describing all the current +grid options for \fIpathName\fR is returned. If \fIoption\fR is specified, +but not \fIvalue\fR, then a list describing \fIoption\fR is +returned. If one or more \fIoption\fR and \fIvalue\fR pairs are +specified, then for each pair, the grid line option \fIoption\fR is set to +\fIvalue\fR. The following options are valid for grid lines. +.RS +.TP +\fB\-color \fIcolor\fR +Sets the color of the grid lines. The default is \f(CWblack\fR. +.TP +\fB\-dashes \fIdashList\fR +Sets the dash style of the grid lines. \fIDashList\fR is a list of up +to 11 numbers that alternately represent the lengths of the dashes +and gaps on the grid lines. Each number must be between 1 and 255. +If \fIdashList\fR is \f(CW""\fR, the grid will be solid lines. +.TP +\fB\-hide \fIboolean\fR +Indicates whether the grid should be drawn. If \fIboolean\fR +is true, grid lines are not shown. The default is \f(CWyes\fR. +.TP +\fB\-linewidth \fIpixels\fR +Sets the width of grid lines. The default width is \f(CW1\fR. +.TP +\fB\-mapx \fIxAxis\fR +Specifies the X\-axis to display grid lines. \fIXAxis\fR +must be the name of an axis or \f(CW""\fR for no grid lines. +The default is \f(CW""\fR. +.TP +\fB\-mapy \fIyAxis\fR +Specifies the Y\-axis to display grid lines. \fIYAxis\fR +must be the name of an axis or \f(CW""\fR for no grid lines. +The default is \f(CWy\fR. +.TP +\fB\-minor \fIboolean\fR +Indicates whether the grid lines should be drawn for minor ticks. +If \fIboolean\fR is true, the lines will appear at +minor tick intervals. The default is \f(CW1\fR. +.PP +Grid configuration options may also be set by the +\fBoption\fR command. The resource name and class are \f(CWgrid\fR and +\f(CWGrid\fR respectively. +.CS +option add *Barchart.grid.LineWidth 2 +option add *Barchart.Grid.Color black +.CE +.RE +.TP +\fIpathName \fBgrid off\fR +Turns off the display the grid lines. +.TP +\fIpathName \fBgrid on\fR +Turns on the display the grid lines. +.TP +\fIpathName \fBgrid toggle\fR +Toggles the display of the grid. +.SS "LEGEND COMPONENT" +The legend displays a list of the data elements. Each entry consists +of the element's symbol and label. The legend can appear in any +margin (the default location is in the right margin). It +can also be positioned anywhere within the plotting area. +.PP +The following operations are valid for the legend. +.TP +\fIpathName \fBlegend activate \fIpattern\fR... +Selects legend entries to be drawn using the active legend colors and relief. +All entries whose element names match \fIpattern\fR are selected. To +be selected, the element name must match only one \fIpattern\fR. +.TP +\fIpathName \fBlegend bind \fItagName\fR ?\fIsequence\fR? ?\fIcommand\fR? +Associates \fIcommand\fR with \fItagName\fR such that whenever the +event sequence given by \fIsequence\fR occurs for a legend entry with this +tag, \fIcommand\fR will be invoked. Implicitly the element names +in the entry are tags. The syntax is similar to the +\fBbind\fR command except that it operates on legend entries, rather +than widgets. See the \fBbind\fR manual entry for +complete details on \fIsequence\fR and the substitutions performed on +\fIcommand\fR before invoking it. +.sp +If all arguments are specified then a new binding is created, replacing +any existing binding for the same \fIsequence\fR and \fItagName\fR. +If the first character of \fIcommand\fR is \f(CW+\fR then \fIcommand\fR +augments an existing binding rather than replacing it. +If no \fIcommand\fR argument is provided then the command currently +associated with \fItagName\fR and \fIsequence\fR (it's an error occurs +if there's no such binding) is returned. If both \fIcommand\fR and +\fIsequence\fR are missing then a list of all the event sequences for +which bindings have been defined for \fItagName\fR. +.TP +\fIpathName \fBlegend cget \fIoption\fR +Returns the current value of a legend configuration option. +\fIOption\fR may be any option described below in the +legend \fBconfigure\fR operation. +.TP +\fIpathName \fBlegend configure \fR?\fIoption value\fR?... +Queries or modifies the configuration options for the legend. If +\fIoption\fR isn't specified, a list describing the current +legend options for \fIpathName\fR is returned. If \fIoption\fR is +specified, but not \fIvalue\fR, then a list describing \fIoption\fR is +returned. If one or more \fIoption\fR and \fIvalue\fR pairs are +specified, then for each pair, the legend option \fIoption\fR is set +to \fIvalue\fR. The following options are valid for the legend. +.RS +.TP +\fB\-activebackground \fIcolor\fR +Sets the background color for active legend entries. All legend +entries marked active (see the legend \fBactivate\fR operation) are +drawn using this background color. +.TP +\fB\-activeborderwidth \fIpixels\fR +Sets the width of the 3-D border around the outside edge of the active legend +entries. The default is \f(CW2\fR. +.TP +\fB\-activeforeground \fIcolor\fR +Sets the foreground color for active legend entries. All legend +entries marked as active (see the legend \fBactivate\fR operation) are +drawn using this foreground color. +.TP +\fB\-activerelief \fIrelief\fR +Specifies the 3-D effect desired for active legend entries. +\fIRelief\fR denotes how the interior of the entry should appear +relative to the legend; for example, \f(CWraised\fR means the entry +should appear to protrude from the legend, relative to the surface of +the legend. The default is \f(CWflat\fR. +.TP +\fB\-anchor \fIanchor\fR +Tells how to position the legend relative to the positioning point for +the legend. This is dependent on the value of the \fB\-position\fR +option. The default is \f(CWcenter\fR. +.RS +.TP 1.25i +\f(CWleft\fR or \f(CWright\fR +The anchor describes how to position the legend vertically. +.TP +\f(CWtop\fR or \f(CWbottom\fR +The anchor describes how to position the legend horizontally. +.TP +\f(CW@x,y\fR +The anchor specifies how to position the legend relative to the +positioning point. For example, if \fIanchor\fR is \f(CWcenter\fR then +the legend is centered on the point; if \fIanchor\fR is \f(CWn\fR then +the legend will be drawn such that the top center point of the +rectangular region occupied by the legend will be at the positioning +point. +.TP +\f(CWplotarea\fR +The anchor specifies how to position the legend relative to the +plotting area. For example, if \fIanchor\fR is \f(CWcenter\fR then the +legend is centered in the plotting area; if \fIanchor\fR is \f(CWne\fR +then the legend will be drawn such that occupies the upper right +corner of the plotting area. +.RE +.TP +\fB\-background \fIcolor\fR +Sets the background color of the legend. If \fIcolor\fR is \f(CW""\fR, +the legend background with be transparent. +.TP +\fB\-bindtags \fItagList\fR +Specifies the binding tags for legend entries. \fITagList\fR is a list +of binding tag names. The tags and their order will determine how +events for legend entries. Each tag in the list matching the current +event sequence will have its Tcl command executed. The default value +is \f(CWall\fR. +.TP +\fB\-borderwidth \fIpixels\fR +Sets the width of the 3-D border around the outside edge of the legend (if +such border is being drawn; the \fBrelief\fR option determines this). +The default is \f(CW2\fR pixels. +.TP +\fB\-font \fIfontName\fR +\fIFontName\fR specifies a font to use when drawing the labels of each +element into the legend. The default is +\f(CW*-Helvetica-Bold-R-Normal-*-12-120-*\fR. +.TP +\fB\-foreground \fIcolor\fR +Sets the foreground color of the text drawn for the element's label. +The default is \f(CWblack\fR. +.TP +\fB\-hide \fIboolean\fR +Indicates whether the legend should be displayed. If \fIboolean\fR is +true, the legend will not be draw. The default is \f(CWno\fR. +.TP +\fB\-ipadx \fIpad\fR +Sets the amount of internal padding to be added to the width of each +legend entry. \fIPad\fR can be a list of one or two screen distances. If +\fIpad\fR has two elements, the left side of the legend entry is +padded by the first distance and the right side by the second. If +\fIpad\fR is just one distance, both the left and right sides are padded +evenly. The default is \f(CW2\fR. +.TP +\fB\-ipady \fIpad\fR +Sets an amount of internal padding to be added to the height of each +legend entry. \fIPad\fR can be a list of one or two screen distances. If +\fIpad\fR has two elements, the top of the entry is padded by the +first distance and the bottom by the second. If \fIpad\fR is just +one distance, both the top and bottom of the entry are padded evenly. +The default is \f(CW2\fR. +.TP +\fB\-padx \fIpad\fR +Sets the padding to the left and right exteriors of the legend. +\fIPad\fR can be a list of one or two screen distances. If \fIpad\fR +has two elements, the left side of the legend is padded by the first +distance and the right side by the second. If \fIpad\fR has just one +distance, both the left and right sides are padded evenly. The +default is \f(CW4\fR. +.TP +\fB\-pady \fIpad\fR +Sets the padding above and below the legend. \fIPad\fR can be a list +of one or two screen distances. If \fIpad\fR has two elements, the area above +the legend is padded by the first distance and the area below by the +second. If \fIpad\fR is just one distance, both the top and +bottom areas are padded evenly. The default is \f(CW0\fR. +.TP +\fB\-position \fIpos\fR +Specifies where the legend is drawn. The +\fB\-anchor\fR option also affects where the legend is positioned. If +\fIpos\fR is \f(CWleft\fR, \f(CWleft\fR, \f(CWtop\fR, or \f(CWbottom\fR, the +legend is drawn in the specified margin. If \fIpos\fR is +\f(CWplotarea\fR, then the legend is drawn inside the plotting area at a +particular anchor. If \fIpos\fR is in the form "\fI@x,y\fR", where +\fIx\fR and \fIy\fR are the window coordinates, the legend is drawn in +the plotting area at the specified coordinates. The default is +\f(CWright\fR. +.TP +\fB\-raised \fIboolean\fR +Indicates whether the legend is above or below the data elements. This +matters only if the legend is in the plotting area. If \fIboolean\fR +is true, the legend will be drawn on top of any elements that may +overlap it. The default is \f(CWno\fR. +.TP +\fB\-relief \fIrelief\fR +Specifies the 3-D effect for the border around the legend. +\fIRelief\fR specifies how the interior of the legend should appear +relative to the bar chart; for example, \f(CWraised\fR means the legend +should appear to protrude from the bar chart, relative to the surface of +the bar chart. The default is \f(CWsunken\fR. +.PP +Legend configuration options may also be set by the \fBoption\fR +command. The resource name and class are \f(CWlegend\fR and +\f(CWLegend\fR respectively. +.CS +option add *Barchart.legend.Foreground blue +option add *Barchart.Legend.Relief raised +.CE +.RE +.TP +\fIpathName \fBlegend deactivate \fIpattern\fR... +Selects legend entries to be drawn using the normal legend colors and +relief. All entries whose element names match \fIpattern\fR are +selected. To be selected, the element name must match only one +\fIpattern\fR. +.TP +\fIpathName \fBlegend get \fIpos\fR +Returns the name of the element whose entry is at the screen position +\fIpos\fR in the legend. \fIPos\fR must be in the form "\fI@x,y\fR", +where \fIx\fR and \fIy\fR are window coordinates. If the given +coordinates do not lie over a legend entry, \f(CW""\fR is returned. +.SS "PEN COMPONENTS" +Pens define attributes for elements. +Pens mirror the configuration options of data elements that pertain to +how symbols and lines are drawn. Data elements use pens to determine +how they are drawn. A data element may use several pens at once. In +this case, the pen used for a particular data point is determined from +each element's weight vector (see the element's \fB\-weight\fR and +\fB\-style\fR options). +.PP +One pen, called \f(CWactiveBar\fR, is automatically created. +It's used as the default active pen for elements. So you can change +the active attributes for all elements by simply reconfiguring this +pen. +.CS +\&.g pen configure "activeBar" -fg green -bg green4 +.CE +You can create and use several pens. To create a pen, invoke +the pen component and its create operation. +.CS +\&.g pen create myPen +.CE +You map pens to a data element using either the element's +\fB\-pen\fR or \fB\-activepen\fR options. +.CS +\&.g element create "e1" -xdata $x -ydata $tempData \\ + -pen myPen +.CE +An element can use several pens at once. This is done by specifying +the name of the pen in the element's style list (see the +\fB\-styles\fR option). +.CS +\&.g element configure "e1" -styles { myPen 2.0 3.0 } +.CE +This says that any data point with a weight between 2.0 and 3.0 +is to be drawn using the pen \f(CWmyPen\fR. All other points +are drawn with the element's default attributes. +.PP +The following operations are available for pen components. +.PP +.TP +\fIpathName \fBpen \fBcget \fIpenName \fIoption\fR +Returns the current value of the option given by \fIoption\fR for +\fIpenName\fR. \fIOption\fR may be any option described below +for the pen \fBconfigure\fR operation. +.TP +\fIpathName \fBpen \fBconfigure \fIpenName \fR?\fIpenName\fR... ?\fIoption value\fR?... +Queries or modifies the configuration options of +\fIpenName\fR. Several pens can be modified at once. If \fIoption\fR +isn't specified, a list describing the current options for +\fIpenName\fR is returned. If \fIoption\fR is specified, but not +\fIvalue\fR, then a list describing \fIoption\fR is returned. If one +or more \fIoption\fR and \fIvalue\fR pairs are specified, then for +each pair, the pen option \fIoption\fR is set to \fIvalue\fR. The +following options are valid for pens. +.RS +.TP +\fB\-background \fIcolor\fR +Sets the the color of the border around each bar. The default is +\f(CWwhite\fR. +.TP +\fB\-borderwidth \fIpixels\fR +Sets the border width of the 3-D border drawn around the outside of +each bar. The \fB\-relief\fR option determines if such a border is +drawn. \fIPixels\fR must be a valid screen distance like \f(CW2\fR or +\f(CW0.25i\fR. The default is \f(CW2\fR. +.TP +\fB\-foreground \fIcolor\fR +Sets the color of the interior of the bars. +.TP +\fB\-relief \fIstring\fR +Specifies the 3-D effect desired for bars. \fIRelief\fR indicates how +the interior of the bar should appear relative to the surface of the +chart; for example, \f(CWraised\fR means the bar should appear to +protrude from the bar chart, relative to the surface of the plotting +area. The default is \f(CWraised\fR. +.TP +\fB\-stipple \fIbitmap\fR +Specifies a stipple pattern with which to draw the bars. If +\fIbitmap\fR is \f(CW""\fR, then the bar is drawn in a solid fashion. +.TP +\fB\-type \fIelemType\fR +Specifies the type of element the pen is to be used with. +This option should only be employed when creating the pen. This +is for those that wish to mix different types of elements (bars and +lines) on the same graph. The default type is "bar". +.PP +Pen configuration options may be also be set by the \fBoption\fR +command. The resource class is \f(CWPen\fR. The resource names +are the names of the pens. +.CS +option add *Barchart.Pen.Foreground blue +option add *Barchart.activeBar.foreground green +.CE +.RE +.TP +\fIpathName \fBpen \fBcreate \fIpenName \fR?\fIoption value\fR?... +Creates a new pen by the name \fIpenName\fR. No pen by the same +name can already exist. \fIOption\fR and \fIvalue\fR are described +in above in the pen \fBconfigure\fR operation. +.TP +\fIpathName \fBpen \fBdelete \fR?\fIpenName\fR?... +Deletes the named pens. A pen is not really +deleted until it is not longer in use, so it's safe to delete +pens mapped to elements. +.TP +\fIpathName \fBpen names \fR?\fIpattern\fR?... +Returns a list of pens matching zero or more patterns. If no +\fIpattern\fR argument is give, the names of all pens are returned. +.SS "POSTSCRIPT COMPONENT" +The barchart can generate encapsulated PostScript output. There +are several configuration options you can specify to control how the +plot will be generated. You can change the page dimensions and +borders. The plot itself can be scaled, centered, or rotated to +landscape. The PostScript output can be written directly to a file or +returned through the interpreter. +.PP +The following postscript operations are available. +.TP +\fIpathName \fBpostscript cget \fIoption\fR +Returns the current value of the postscript option given by +\fIoption\fR. \fIOption\fR may be any option described +below for the postscript \fBconfigure\fR operation. +.TP +\fIpathName \fBpostscript configure \fR?\fIoption value\fR?... +Queries or modifies the configuration options for PostScript +generation. If \fIoption\fR isn't specified, a list describing +the current postscript options for \fIpathName\fR is returned. If +\fIoption\fR is specified, but not \fIvalue\fR, then a list describing +\fIoption\fR is returned. If one or more \fIoption\fR and \fIvalue\fR +pairs are specified, then for each pair, the postscript option +\fIoption\fR is set to \fIvalue\fR. The following postscript options +are available. +.RS +.TP +\fB\-center \fIboolean\fR +Indicates whether the plot should be centered on the PostScript page. If +\fIboolean\fR is false, the plot will be placed in the upper left +corner of the page. The default is \f(CW1\fR. +.TP +\fB\-colormap \fIvarName\fR +\fIVarName\fR must be the name of a global array variable that +specifies a color mapping from the X color name to PostScript. Each +element of \fIvarName\fR must consist of PostScript code to set a +particular color value (e.g. ``\f(CW1.0 1.0 0.0 setrgbcolor\fR''). When +generating color information in PostScript, the array variable \fIvarName\fR +is checked if an element of the name as the color exists. If so, it uses +its value as the PostScript +command to set the color. If this option hasn't been specified, or if +there isn't an entry in \fIvarName\fR for a given color, then it uses +the red, green, and blue intensities from the X color. +.TP +\fB\-colormode \fImode\fR +Specifies how to output color information. \fIMode\fR must be either +\f(CWcolor\fR (for full color output), \f(CWgray\fR (convert all colors to +their gray-scale equivalents) or \f(CWmono\fR (convert foreground colors +to black and background colors to white). The default mode is +\f(CWcolor\fR. +.TP +\fB\-fontmap \fIvarName\fR +\fIVarName\fR must be the name of a global array variable that +specifies a font mapping from the X font name to PostScript. Each +element of \fIvarName\fR must consist of a Tcl list with one or two +elements; the name and point size of a PostScript font. +When outputting PostScript commands for a particular font, the array +variable \fIvarName\fR is checked to see if an element by the +specified font exists. If there is such an element, then the font +information contained in that element is used in the PostScript +output. (If the point size is omitted from the list, the point size +of the X font is used). Otherwise the X font is examined in an +attempt to guess what PostScript font to use. This works only for +fonts whose foundry property is \fIAdobe\fR (such as Times, Helvetica, +Courier, etc.). If all of this fails then the font defaults to +\f(CWHelvetica-Bold\fR. +.TP +\fB\-decorations \fIboolean\fR +Indicates whether PostScript commands to generate color backgrounds and 3-D +borders will be output. If \fIboolean\fR is false, the graph will +background will be white and no 3-D borders will be generated. The +default is \f(CW1\fR. +.TP +\fB\-height \fIpixels\fR +Sets the height of the plot. This lets you print the bar chart with a +height different from the one drawn on the screen. If +\fIpixels\fR is 0, the height is the same as the widget's height. +The default is \f(CW0\fR. +.TP +\fB\-landscape \fIboolean\fR +If \fIboolean\fR is true, this specifies the printed area is to be +rotated 90 degrees. In non-rotated output the X\-axis of the printed +area runs along the short dimension of the page (``portrait'' +orientation); in rotated output the X\-axis runs along the long +dimension of the page (``landscape'' orientation). Defaults to +\f(CW0\fR. +.TP +\fB\-maxpect \fIboolean\fR +Indicates to scale the plot so that it fills the PostScript page. +The aspect ratio of the barchart is still retained. The default is +\f(CW0\fR. +.TP +\fB\-padx \fIpad\fR +Sets the horizontal padding for the left and right page borders. The +borders are exterior to the plot. \fIPad\fR can be a list of one or +two screen distances. If \fIpad\fR has two elements, the left border is padded +by the first distance and the right border by the second. If +\fIpad\fR has just one distance, both the left and right borders are +padded evenly. The default is \f(CW1i\fR. +.TP +\fB\-pady \fIpad\fR +Sets the vertical padding for the top and bottom page borders. The +borders are exterior to the plot. \fIPad\fR can be a list of one or +two screen distances. If \fIpad\fR has two elements, the top border is padded +by the first distance and the bottom border by the second. If +\fIpad\fR has just one distance, both the top and bottom borders are +padded evenly. The default is \f(CW1i\fR. +.TP +\fB\-paperheight \fIpixels\fR +Sets the height of the postscript page. This can be used to select +between different page sizes (letter, A4, etc). The default height is +\f(CW11.0i\fR. +.TP +\fB\-paperwidth \fIpixels\fR +Sets the width of the postscript page. This can be used to select +between different page sizes (letter, A4, etc). The default width is +\f(CW8.5i\fR. +.TP +\fB\-width \fIpixels\fR +Sets the width of the plot. This lets you generate a plot +of a width different from that of the widget. If \fIpixels\fR +is 0, the width is the same as the widget's width. The default is +\f(CW0\fR. +.PP +Postscript configuration options may be also be set by the +\fBoption\fR command. The resource name and class are +\f(CWpostscript\fR and \f(CWPostscript\fR respectively. +.CS +option add *Barchart.postscript.Decorations false +option add *Barchart.Postscript.Landscape true +.CE +.RE +.TP +\fIpathName \fBpostscript output \fR?\fIfileName\fR? ?\fIoption value\fR?... +Outputs a file of encapsulated PostScript. If a +\fIfileName\fR argument isn't present, the command returns the +PostScript. If any \fIoption-value\fR pairs are present, they set +configuration options controlling how the PostScript is generated. +\fIOption\fR and \fIvalue\fR can be anything accepted by the +postscript \fBconfigure\fR operation above. +.SS "MARKER COMPONENTS" +Markers are simple drawing procedures used to annotate or highlight +areas of the graph. Markers have various types: text strings, +bitmaps, images, connected lines, windows, or polygons. They can be +associated with a particular element, so that when the element is +hidden or un-hidden, so is the marker. By default, markers are the +last items drawn, so that data elements will appear in +behind them. You can change this by configuring the \fB\-under\fR +option. +.PP +Markers, in contrast to elements, don't affect the scaling of the +coordinate axes. They can also have \fIelastic\fR coordinates +(specified by \f(CW-Inf\fR and \f(CWInf\fR respectively) that translate +into the minimum or maximum limit of the axis. For example, you can +place a marker so it always remains in the lower left corner of the +plotting area, by using the coordinates \f(CW-Inf\fR,\f(CW-Inf\fR. +.PP +The following operations are available for markers. +.TP +\fIpathName \fBmarker after \fImarkerId\fR ?\fIafterId\fR? +Changes the order of the markers, drawing the first +marker after the second. If no second \fIafterId\fR argument is +specified, the marker is placed at the end of the display list. This +command can be used to control how markers are displayed since markers +are drawn in the order of this display list. +.TP +\fIpathName \fBmarker before \fImarkerId\fR ?\fIbeforeId\fR? +Changes the order of the markers, drawing the first +marker before the second. If no second \fIbeforeId\fR argument is +specified, the marker is placed at the beginning of the display list. +This command can be used to control how markers are displayed since +markers are drawn in the order of this display list. +.TP +\fIpathName \fBmarker bind \fItagName\fR ?\fIsequence\fR? ?\fIcommand\fR? +Associates \fIcommand\fR with \fItagName\fR such that whenever the +event sequence given by \fIsequence\fR occurs for a marker with this +tag, \fIcommand\fR will be invoked. The syntax is similar to the +\fBbind\fR command except that it operates on graph markers, rather +than widgets. See the \fBbind\fR manual entry for +complete details on \fIsequence\fR and the substitutions performed on +\fIcommand\fR before invoking it. +.sp +If all arguments are specified then a new binding is created, replacing +any existing binding for the same \fIsequence\fR and \fItagName\fR. +If the first character of \fIcommand\fR is \f(CW+\fR then \fIcommand\fR +augments an existing binding rather than replacing it. +If no \fIcommand\fR argument is provided then the command currently +associated with \fItagName\fR and \fIsequence\fR (it's an error occurs +if there's no such binding) is returned. If both \fIcommand\fR and +\fIsequence\fR are missing then a list of all the event sequences for +which bindings have been defined for \fItagName\fR. +.TP +\fIpathName \fBmarker cget \fIoption\fR +Returns the current value of the marker configuration option given by +\fIoption\fR. \fIOption\fR may be any option described +below in the \fBconfigure\fR operation. +.TP +\fIpathName \fBmarker configure \fImarkerId\fR ?\fIoption value\fR?... +Queries or modifies the configuration options for markers. If +\fIoption\fR isn't specified, a list describing the current +options for \fImarkerId\fR is returned. If \fIoption\fR is specified, +but not \fIvalue\fR, then a list describing \fIoption\fR is returned. +If one or more \fIoption\fR and \fIvalue\fR pairs are specified, then +for each pair, the marker option \fIoption\fR is set to \fIvalue\fR. +.sp +The following options are valid for all markers. +Each type of marker also has its own type-specific options. +They are described in the sections below. +.RS +.TP +\fB\-bindtags \fItagList\fR +Specifies the binding tags for the marker. \fITagList\fR is a list +of binding tag names. The tags and their order will determine how +events for markers are handled. Each tag in the list matching the +current event sequence will have its Tcl command executed. Implicitly +the name of the marker is always the first tag in the list. +The default value is \f(CWall\fR. +.TP +\fB\-coords \fIcoordList\fR +Specifies the coordinates of the marker. \fICoordList\fR is +a list of graph-coordinates. The number of coordinates required +is dependent on the type of marker. Text, image, and window markers +need only two coordinates (an X\-Y coordinate). Bitmap markers +can take either two or four coordinates (if four, they represent the +corners of the bitmap). Line markers +need at least four coordinates, polygons at least six. +If \fIcoordList\fR is \f(CW""\fR, the marker will not be displayed. +The default is \f(CW""\fR. +.TP +\fB\-element \fIelemName\fR +Links the marker with the element \fIelemName\fR. The marker is +drawn only if the element is also currently displayed (see the +element's \fBshow\fR operation). If \fIelemName\fR is \f(CW""\fR, the +marker is always drawn. The default is \f(CW""\fR. +.TP +\fB\-hide \fIboolean\fR +Indicates whether the marker is drawn. If \fIboolean\fR is true, +the marker is not drawn. The default is \f(CWno\fR. +.TP +\fB\-mapx \fIxAxis\fR +Specifies the X\-axis to map the marker's X\-coordinates onto. +\fIXAxis\fR must the name of an axis. The default is \f(CWx\fR. +.TP +\fB\-mapy \fIyAxis\fR +Specifies the Y\-axis to map the marker's Y\-coordinates onto. +\fIYAxis\fR must the name of an axis. The default is \f(CWy\fR. +.TP +\fB\-name \fImarkerId\fR +Changes the identifier for the marker. The identifier \fImarkerId\fR +can not already be used by another marker. If this option +isn't specified, the marker's name is uniquely generated. +.TP +\fB\-under \fIboolean\fR +Indicates whether the marker is drawn below/above data +elements. If \fIboolean\fR is true, the marker is be drawn +underneath the data elements. Otherwise, the marker is +drawn on top of the element. The default is \f(CW0\fR. +.TP +\fB\-xoffset \fIpixels\fR +Specifies a screen distance to offset the marker horizontally. +\fIPixels\fR is a valid screen distance, such as \f(CW2\fR or \f(CW1.2i\fR. +The default is \f(CW0\fR. +.TP +\fB\-yoffset \fIpixels\fR +Specifies a screen distance to offset the markers vertically. +\fIPixels\fR is a valid screen distance, such as \f(CW2\fR or \f(CW1.2i\fR. +The default is \f(CW0\fR. +.PP +Marker configuration options may also be set by the \fBoption\fR command. +The resource class is either \f(CWBitmapMarker\fR, \f(CWImageMarker\fR, +\f(CWLineMarker\fR, \f(CWPolygonMarker\fR, \f(CWTextMarker\fR, or \f(CWWindowMarker\fR, +depending on the type of marker. The resource name is the name of the +marker. +.CS +option add *Barchart.TextMarker.Foreground white +option add *Barchart.BitmapMarker.Foreground white +option add *Barchart.m1.Background blue +.CE +.RE +.TP +\fIpathName \fBmarker create \fItype\fR ?\fIoption value\fR?... +Creates a marker of the selected type. \fIType\fR may be either +\f(CWtext\fR, \f(CWline\fR, \f(CWbitmap\fR, \f(CWimage\fR, \f(CWpolygon\fR, or +\f(CWwindow\fR. This command returns the marker identifier, +used as the \fImarkerId\fR argument in the other marker-related +commands. If the \fB\-name\fR option is used, this overrides the +normal marker identifier. If the name provided is already used for +another marker, the new marker will replace the old. +.TP +\fIpathName \fBmarker delete\fR ?\fIname\fR?... +Removes one of more markers. The graph will automatically be redrawn +without the marker.\fR. +.TP +\fIpathName \fBmarker exists \fImarkerId\fR +Returns \f(CW1\fR if the marker \fImarkerId\fR exists and \f(CW0\fR +otherwise. +.TP +\fIpathName \fBmarker names\fR ?\fIpattern\fR? +Returns the names of all the markers that currently exist. If +\fIpattern\fR is supplied, only those markers whose names match it +will be returned. +.TP +\fIpathName \fBmarker type \fImarkerId\fR +Returns the type of the marker given by \fImarkerId\fR, such as +\f(CWline\fR or \f(CWtext\fR. If \fImarkerId\fR is not a valid a marker +identifier, \f(CW""\fR is returned. +.SS "BITMAP MARKERS" +A bitmap marker displays a bitmap. The size of the +bitmap is controlled by the number of coordinates specified. If two +coordinates, they specify the position of the top-left corner of the +bitmap. The bitmap retains its normal width and height. If four +coordinates, the first and second pairs of coordinates represent the +corners of the bitmap. The bitmap will be stretched or reduced as +necessary to fit into the bounding rectangle. +.PP +Bitmap markers are created with the marker's \fBcreate\fR operation in +the form: +.DS +\fIpathName \fBmarker create bitmap \fR?\fIoption value\fR?... +.DE +There may be many \fIoption\fR-\fIvalue\fR pairs, each +sets a configuration options for the marker. These +same \fIoption\fR\-\fIvalue\fR pairs may be used with the marker's +\fBconfigure\fR operation. +.PP +The following options are specific to bitmap markers: +.TP +\fB\-background \fIcolor\fR +Same as the \fB\-fill\fR option. +.TP +\fB\-bitmap \fIbitmap\fR +Specifies the bitmap to be displayed. If \fIbitmap\fR is \f(CW""\fR, +the marker will not be displayed. The default is \f(CW""\fR. +.TP +\fB\-fill \fIcolor\fR +Sets the background color of the bitmap. If \fIcolor\fR is the empty +string, no background will be transparent. The default background color is +\f(CW""\fR. +.TP +\fB\-foreground \fIcolor\fR +Same as the \fB\-outline\fR option. +.TP +\fB\-mask \fImask\fR +Specifies a mask for the bitmap to be displayed. This mask is a bitmap +itself, denoting the pixels that are transparent. If \fImask\fR is +\f(CW""\fR, all pixels of the bitmap will be drawn. The default is +\f(CW""\fR. +.TP +\fB\-outline \fIcolor\fR +Sets the foreground color of the bitmap. The default value is \f(CWblack\fR. +.TP +\fB\-rotate \fItheta\fR +Sets the rotation of the bitmap. \fITheta\fR is a real number +representing the angle of rotation in degrees. The marker is first +rotated and then placed according to its anchor position. The default +rotation is \f(CW0.0\fR. +.SS "IMAGE MARKERS" +A image marker displays an image. Image markers are +created with the marker's \fBcreate\fR operation in the form: +.DS +\fIpathName \fBmarker create image \fR?\fIoption value\fR?... +.DE +There may be many \fIoption\fR-\fIvalue\fR +pairs, each sets a configuration option +for the marker. These same \fIoption\fR\-\fIvalue\fR pairs may be +used with the marker's \fBconfigure\fR operation. +.PP +The following options are specific to image markers: +.TP +\fB\-anchor \fIanchor\fR +\fIAnchor\fR tells how to position the image relative to the +positioning point for the image. For example, if \fIanchor\fR +is \f(CWcenter\fR then the image is centered on the point; if +\fIanchor\fR is \f(CWn\fR then the image will be drawn such that +the top center point of the rectangular region occupied by the +image will be at the positioning point. +This option defaults to \f(CWcenter\fR. +.TP +\fB\-image \fIimage\fR +Specifies the image to be drawn. +If \fIimage\fR is \f(CW""\fR, the marker will not be +drawn. The default is \f(CW""\fR. +.SS "LINE MARKERS" +A line marker displays one or more connected line segments. +Line markers are created with marker's \fBcreate\fR operation in the form: +.DS +\fIpathName \fBmarker create line \fR?\fIoption value\fR?... +.DE +There may be many \fIoption\fR-\fIvalue\fR +pairs, each sets a configuration option +for the marker. These same \fIoption\fR-\fIvalue\fR pairs may be +used with the marker's \fBconfigure\fR operation. +.PP +The following options are specific to line markers: +.TP +\fB\-dashes \fIdashList\fR +Sets the dash style of the line. \fIDashList\fR is a list of up to 11 +numbers that alternately represent the lengths of the dashes and gaps +on the line. Each number must be between 1 and 255. If +\fIdashList\fR is \f(CW""\fR, the marker line will be solid. +.TP +\fB\-fill \fIcolor\fR +Sets the background color of the line. This color is used with +striped lines (see the \fB\-dashes\fR option). If \fIcolor\fR is +the empty string, no background color is drawn (the line will be +dashed, not striped). The default background color is \f(CW""\fR. +.TP +\fB\-linewidth \fIpixels\fR +Sets the width of the lines. +The default width is \f(CW0\fR. +.TP +\fB\-outline \fIcolor\fR +Sets the foreground color of the line. The default value is \f(CWblack\fR. +.TP +\fB\-stipple \fIbitmap\fR +Specifies a stipple pattern used to draw the line, rather than +a solid line. +\fIBitmap\fR specifies a bitmap to use as the stipple +pattern. If \fIbitmap\fR is \f(CW""\fR, then the +line is drawn in a solid fashion. The default is \f(CW""\fR. +.SS "POLYGON MARKERS" +A polygon marker displays a closed region described as two or more +connected line segments. It is assumed the first and +last points are connected. Polygon markers are created using the +marker \fBcreate\fR operation in the form: +.DS +\fIpathName \fBmarker create polygon \fR?\fIoption value\fR?... +.DE +There may be many \fIoption\fR-\fIvalue\fR +pairs, each sets a configuration option +for the marker. These same \fIoption\fR\-\fIvalue\fR pairs may be +used with the \fBmarker configure\fR command to change the marker's +configuration. +The following options are supported for polygon markers: +.TP +\fB\-dashes \fIdashList\fR +Sets the dash style of the outline of the polygon. \fIDashList\fR is a +list of up to 11 numbers that alternately represent the lengths of +the dashes and gaps on the outline. Each number must be between 1 and +255. If \fIdashList\fR is \f(CW""\fR, the outline will be a solid line. +.TP +\fB\-fill \fIcolor\fR +Sets the fill color of the polygon. If \fIcolor\fR is \f(CW""\fR, then +the interior of the polygon is transparent. +The default is \f(CWwhite\fR. +.TP +\fB\-linewidth \fIpixels\fR +Sets the width of the outline of the polygon. If \fIpixels\fR is zero, +no outline is drawn. The default is \f(CW0\fR. +.TP +\fB\-outline \fIcolor\fR +Sets the color of the outline of the polygon. If the polygon is +stippled (see the \fB\-stipple\fR option), then this represents the +foreground color of the stipple. The default is \f(CWblack\fR. +.TP +\fB\-stipple \fIbitmap\fR +Specifies that the polygon should be drawn with a stippled pattern +rather than a solid color. \fIBitmap\fR specifies a bitmap to use as +the stipple pattern. If \fIbitmap\fR is \f(CW""\fR, then the polygon is +filled with a solid color (if the \fB\-fill\fR option is set). The +default is \f(CW""\fR. +.SS "TEXT MARKERS" +A text marker displays a string of characters on one or more lines of +text. Embedded newlines cause line breaks. They may be used to +annotate regions of the graph. Text markers are created with the +\fBcreate\fR operation in the form: +.DS +\fIpathName \fBmarker create text \fR?\fIoption value\fR?... +.DE +There may be many \fIoption\fR-\fIvalue\fR pairs, +each sets a configuration option for the text marker. +These same \fIoption\fR\-\fIvalue\fR pairs may be used with the +marker's \fBconfigure\fR operation. +.PP +The following options are specific to text markers: +.TP +\fB\-anchor \fIanchor\fR +\fIAnchor\fR tells how to position the text relative to the +positioning point for the text. For example, if \fIanchor\fR is +\f(CWcenter\fR then the text is centered on the point; if +\fIanchor\fR is \f(CWn\fR then the text will be drawn such that the +top center point of the rectangular region occupied by the text will +be at the positioning point. This default is \f(CWcenter\fR. +.TP +\fB\-background \fIcolor\fR +Same as the \fB\-fill\fR option. +.TP +\fB\-font \fIfontName\fR +Specifies the font of the text. The default is +\f(CW*-Helvetica-Bold-R-Normal-*-120-*\fR. +.TP +\fB\-fill \fIcolor\fR +Sets the background color of the text. If \fIcolor\fR is the empty +string, no background will be transparent. The default background color is +\f(CW""\fR. +.TP +\fB\-foreground \fIcolor\fR +Same as the \fB\-outline\fR option. +.TP +\fB\-justify \fIjustify\fR +Specifies how the text should be justified. This matters only when +the marker contains more than one line of text. \fIJustify\fR must be +\f(CWleft\fR, \f(CWright\fR, or \f(CWcenter\fR. The default is +\f(CWcenter\fR. +.TP +\fB\-outline \fIcolor\fR +Sets the color of the text. The default value is \f(CWblack\fR. +.TP +\fB\-padx \fIpad\fR +Sets the padding to the left and right exteriors of the text. +\fIPad\fR can be a list of one or two screen distances. If \fIpad\fR +has two elements, the left side of the text is padded by the first +distance and the right side by the second. If \fIpad\fR has just one +distance, both the left and right sides are padded evenly. The +default is \f(CW4\fR. +.TP +\fB\-pady \fIpad\fR +Sets the padding above and below the text. \fIPad\fR can be a list of +one or two screen distances. If \fIpad\fR has two elements, the area above the +text is padded by the first distance and the area below by the second. +If \fIpad\fR is just one distance, both the top and bottom areas +are padded evenly. The default is \f(CW4\fR. +.TP +\fB\-rotate \fItheta\fR +Specifies the number of degrees to rotate the text. \fITheta\fR is a +real number representing the angle of rotation. The marker is first +rotated along its center and is then drawn according to its anchor +position. The default is \f(CW0.0\fR. +.TP +\fB\-text \fItext\fR +Specifies the text of the marker. The exact way the text is +displayed may be affected by other options such as \fB\-anchor\fR or +\fB\-rotate\fR. +.SS "WINDOW MARKERS" +A window marker displays a widget at a given position. +Window markers are created with the marker's \fBcreate\fR operation in +the form: +.DS +\fIpathName \fBmarker create window \fR?\fIoption value\fR?... +.DE +There may be many \fIoption\fR-\fIvalue\fR +pairs, each sets a configuration option +for the marker. These same \fIoption\fR\-\fIvalue\fR pairs may be +used with the marker's \fBconfigure\fR command. +.PP +The following options are specific to window markers: +.TP +\fB\-anchor \fIanchor\fR +\fIAnchor\fR tells how to position the widget relative to the +positioning point for the widget. For example, if \fIanchor\fR is +\f(CWcenter\fR then the widget is centered on the point; if \fIanchor\fR +is \f(CWn\fR then the widget will be displayed such that the top center +point of the rectangular region occupied by the widget will be at the +positioning point. This option defaults to \f(CWcenter\fR. +.TP +\fB\-height \fIpixels\fR +Specifies the height to assign to the marker's window. If this option +isn't specified, or if it is specified as \f(CW""\fR, then the window is +given whatever height the widget requests internally. +.TP +\fB\-width \fIpixels\fR +Specifies the width to assign to the marker's window. If this option +isn't specified, or if it is specified as \f(CW""\fR, then the window is +given whatever width the widget requests internally. +.TP +\fB\-window \fIpathName\fR +Specifies the widget to be managed by the barchart. \fIPathName\fR must +be a child of the \fBbarchart\fR widget. +.SH "GRAPH COMPONENT BINDINGS" +Specific barchart components, such as elements, markers and legend +entries, can have a command trigger when event occurs in them, much +like canvas items in Tk's canvas widget. Not all event sequences are +valid. The only binding events that may be specified are those +related to the mouse and keyboard (such as \fBEnter\fR, \fBLeave\fR, +\fBButtonPress\fR, \fBMotion\fR, and \fBKeyPress\fR). +.PP +Only one element or marker can be picked during an event. This means, +that if the mouse is directly over both an element and a marker, only +the uppermost component is selected. This isn't true for legend entries. +Both a legend entry and an element (or marker) binding commands +will be invoked if both items are picked. +.PP +It is possible for multiple bindings to match a particular event. +This could occur, for example, if one binding is associated with the +element name and another is associated with one of the element's tags +(see the \fB\-bindtags\fR option). When this occurs, all of the +matching bindings are invoked. A binding associated with the element +name is invoked first, followed by one binding for each of the element's +bindtags. If there are multiple matching bindings for a single tag, +then only the most specific binding is invoked. A continue command +in a binding script terminates that script, and a break command +terminates that script and skips any remaining scripts for the event, +just as for the bind command. +.PP +The \fB\-bindtags\fR option for these components controls addition +tag names which can be matched. Implicitly elements and markers +always have tags matching their names. Setting the value of +the \fB\-bindtags\fR option doesn't change this. +.SH "C LANGUAGE API" +You can manipulate data elements from the C language. There +may be situations where it is too expensive to translate the data +values from ASCII strings. Or you might want to read data in a +special file format. +.PP +Data can manipulated from the C language using BLT vectors. +You specify the X-Y data coordinates of an element as vectors and +manipulate the vector from C. The barchart will be redrawn automatically +after the vectors are updated. +.PP +From Tcl, create the vectors and configure the element to use them. +.CS +vector X Y +\&.g element configure line1 -xdata X -ydata Y +.CE +To set data points from C, you pass the values as arrays of doubles +using the \fBBlt_ResetVector\fR call. The vector is reset with the +new data and at the next idle point (when Tk re-enters its event +loop), the graph will be redrawn automatically. +.CS +#include +#include + +register int i; +Blt_Vector *xVec, *yVec; +double x[50], y[50]; + +/* Get the BLT vectors "X" and "Y" (created above from Tcl) */ +if ((Blt_GetVector(interp, "X", 50, &xVec) != TCL_OK) || + (Blt_GetVector(interp, "Y", 50, &yVec) != TCL_OK)) { + return TCL_ERROR; +} + +for (i = 0; i < 50; i++) { + x[i] = i * 0.02; + y[i] = sin(x[i]); +} + +/* Put the data into BLT vectors */ +if ((Blt_ResetVector(xVec, x, 50, 50, TCL_VOLATILE) != TCL_OK) || + (Blt_ResetVector(yVec, y, 50, 50, TCL_VOLATILE) != TCL_OK)) { + return TCL_ERROR; +} +.CE +See the \fBvector\fR manual page for more details. +.SH SPEED TIPS +There may be cases where the bar chart needs to be drawn and updated as +quickly as possible. If drawing speed becomes a big +problem, here are a few tips to speed up displays. +.TP 2 +\(bu +Try to minimize the number of data points. The more data points +looked at, the more work the bar chart must do. +.TP 2 +\(bu +If your data is generated as floating point values, the time required +to convert the data values to and from ASCII strings can be +significant, especially when there any many data points. You can +avoid the redundant string-to-decimal conversions using the C API to +BLT vectors. +.TP 2 +\(bu +Don't stipple or dash the element. Solid bars are much faster. +.TP 2 +\(bu +If you update data elements frequently, try turning off the +widget's \fB\-bufferelements\fR option. When the bar chart is first +displayed, it draws data elements into an internal pixmap. The pixmap +acts as a cache, so that when the bar chart needs to be redrawn again, and +the data elements or coordinate axes haven't changed, the pixmap is +simply copied to the screen. This is especially useful when you are +using markers to highlight points and regions on the bar chart. But if +the bar chart is updated frequently, changing either the element data or +coordinate axes, the buffering becomes redundant. +.SH LIMITATIONS +Auto-scale routines do not use requested min/max limits +as boundaries when the axis is logarithmically scaled. +.PP +The PostScript output generated for polygons with more than 1500 +points may exceed the limits of some printers (See PostScript Language +Reference Manual, page 568). The work-around is to break the polygon +into separate pieces. +.SH KEYWORDS +bar chart, widget diff --git a/doc/graph.html b/doc/graph.html new file mode 100644 index 0000000..70f1e6f --- /dev/null +++ b/doc/graph.html @@ -0,0 +1,1759 @@ + + +
+
+
+
+

SYNOPSIS

+       graph pathName ?option value?...
+
+
+
+

DESCRIPTION

+       The  graph  command  creates  a graph for plotting two-dimensional data
+       (X-Y coordinates). It  has  many  configurable  components:  coordinate
+       axes,  elements,  legend, grid lines, cross hairs, etc.  They allow you
+       to customize the look and feel of the graph.
+
+
+
+

INTRODUCTION

+       The graph command creates a new  window  for  plotting  two-dimensional
+       data  (X-Y coordinates).  Data points are plotted in a rectangular area
+       displayed in the center of the new window.  This is the plotting  area.
+       The  coordinate axes are drawn in the margins around the plotting area.
+       By default, the legend is displayed in the right margin.  The title  is
+       displayed in top margin.
+
+       The  graph  widget  is composed of several components: coordinate axes,
+       data elements, legend, grid, cross hairs, pens, postscript, and annota-
+       tion markers.
+
+       axis      The  graph has four standard axes (x, x2, y, and y2), but you
+                 can create and display any number of axes.  Axes control what
+                 region  of data is displayed and how the data is scaled. Each
+                 axis consists of the axis line, title, major and minor ticks,
+                 and tick labels.  Tick labels display the value at each major
+                 tick.
+
+       crosshairs
+                 Cross hairs are used to position the mouse  pointer  relative
+                 to  the  X  and  Y  coordinate axes. Two perpendicular lines,
+                 intersecting at the current location  of  the  mouse,  extend
+                 across the plotting area to the coordinate axes.
+
+       element   An  element  represents a set of data points. Elements can be
+                 plotted with a symbol at each data point and lines connecting
+                 the  points.  The appearance of the element, such as its sym-
+                 bol, line width, and color is configurable.
+
+       grid      Extends the major and minor ticks of the X-axis and/or Y-axis
+                 across the plotting area.
+
+       legend    The legend displays the name and symbol of each data element.
+                 The legend can be drawn in any  margin  or  in  the  plotting
+                 area.
+
+       marker    Markers  are  used  annotate or highlight areas of the graph.
+                 For example, you could use a polygon marker to fill  an  area
+                 under  a  curve,  or a text marker to label a particular data
+                 point. Markers come in various forms: text strings,  bitmaps,
+                 connected  line  segments, images, polygons, or embedded wid-
+                 gets.
+
+       graph  pathName ?option value?...  The graph command creates a new win-
+       dow pathName and makes it into a graph widget.  At the time  this  com-
+       mand  is  invoked,  there  must  not exist a window named pathName, but
+       pathName's parent must exist.  Additional options may be  specified  on
+       the  command line or in the option database to configure aspects of the
+       graph such as its colors and font.  See the configure  operation  below
+       for the exact details about what option and value pairs are valid.
+
+       If successful, graph returns the path name of the widget.  It also cre-
+       ates a new Tcl command by the same name.  You can use this  command  to
+       invoke  various operations that query or modify the graph.  The general
+       form is: pathName operation ?arg?...  Both operation and its  arguments
+       determine  the exact behavior of the command.  The operations available
+       for the graph are described in the GRAPH OPERATIONS section.
+
+       The command can also be used to access components of the graph.   path-
+       Name component operation ?arg?...  The operation, now located after the
+       name of the component, is the function to be performed on  that  compo-
+       nent. Each component has its own set of operations that manipulate that
+       component.  They will be described below in their own sections.
+
+
+
+

EXAMPLE

+       The graph command creates a new graph.  # Create a new graph.  Plotting
+       area  is black.  graph .g -plotbackground black A new Tcl command .g is
+       also created.  This command can be used to query and modify the  graph.
+       For example, to change the title of the graph to "My Plot", you use the
+       new command and the graph's configure operation.  # Change  the  title.
+       .g configure -title "My Plot" A graph has several components. To access
+       a particular component you use the component's name.  For  example,  to
+       add  data  elements, you use the new command and the element component.
+       # Create a  new  element  named  "line1"  .g  element  create  line1  \
+            -xdata { 0.2 0.4 0.6 0.8 1.0 1.2 1.4 1.6 1.8 2.0 } \      -ydata {
+       26.18 50.46 72.85 93.31 111.86 128.47  143.14            155.85  166.60
+       175.38  }  The  element's  X-Y coordinates are specified using lists of
+       numbers.  Alternately, BLT vectors could be used to hold the X-Y  coor-
+       dinates.   # Create two vectors and add them to the graph.  vector xVec
+       yVec xVec set { 0.2 0.4 0.6 0.8 1.0 1.2 1.4 1.6 1.8 2.0 }  yVec  set  {
+       26.18  50.46 72.85 93.31 111.86 128.47 143.14 155.85      166.60 175.38
+       } .g element create line1 -xdata xVec  -ydata  yVec  The  advantage  of
+       using  vectors  is that when you modify one, the graph is automatically
+       redrawn to reflect the new values.  # Change the y  coordinate  of  the
+       first  point.   set yVector(0) 25.18 An element named e1 is now created
+       in .b.  It is automatically added to the display list of elements.  You
+       can  use this list to control in what order elements are displayed.  To
+       query or reset the element display list, you  use  the  element's  show
+       operation.   #  Get  the  current display list set elemList [.b element
+       show] # Remove the first element so it won't be displayed.  .b  element
+       show  [lrange $elemList 0 end] The element will be displayed by as many
+       bars as there are data points (in this case there are ten).   The  bars
+       will  be drawn centered at the x-coordinate of the data point.  All the
+       bars will have the same attributes (colors, stipple, etc).   The  width
+       of each bar is by default one unit.  You can change this with using the
+       example, you change the scale of the Y-axis from linear  to  log  using
+       the  axis  component.   #  Y-axis  is  log  scale.  .g axis configure y
+       -logscale yes One important way axes are used is to zoom in on  a  par-
+       ticular  data  region.   Zooming  is done by simply specifying new axis
+       limits using the -min and -max configuration options.  .g axis  config-
+       ure  x  -min  1.0  -max 1.5 .g axis configure y -min 12.0 -max 55.15 To
+       zoom interactively, you link the axis configure  operations  with  some
+       user  interaction  (such  as pressing the mouse button), using the bind
+       command.  To convert between screen  and  graph  coordinates,  use  the
+       invtransform  operation.   # Click the button to set a new minimum bind
+       .g <ButtonPress-1> {
+           %W axis configure x -min [%W axis invtransform x %x]
+           %W axis configure x -min [%W axis invtransform x %y] } By  default,
+       the  limits of the axis are determined from data values.  To reset back
+       to the default limits, set the -min  and  -max  options  to  the  empty
+       value.   # Reset the axes to autoscale again.  .g axis configure x -min
+       {} -max {} .g axis configure y -min {} -max {} By default,  the  legend
+       is  drawn  in the right margin.  You can change this or any legend con-
+       figuration options using the legend component.  # Configure the  legend
+       font,  color,  and  relief  .g  legend configure -position left -relief
+       raised \      -font fixed -fg blue To prevent  the  legend  from  being
+       displayed,  turn  on the -hide option.  # Don't display the legend.  .g
+       legend configure -hide yes The graph widget has simple  drawing  proce-
+       dures  called  markers.  They can be used to highlight or annotate data
+       in the graph. The types of markers available are bitmaps, images, poly-
+       gons,  lines, or windows.  Markers can be used, for example, to mark or
+       brush points.  In this example, is a text marker that labels  the  data
+       first point.  Markers are created using the marker component.  # Create
+       a label for the first data point of "line1".   .g  marker  create  text
+       -name  first_marker  -coords { 0.2 26.18 } \      -text "start" -anchor
+       se  -xoffset  -10  -yoffset  -10  This  creates  a  text  marker  named
+       first_marker.  It will display the text "start" near the coordinates of
+       the first data point.  The -anchor, -xoffset, and -yoffset options  are
+       used  to display the marker above and to the left of the data point, so
+       that the data point isn't covered by the marker.  By  default,  markers
+       are  drawn  last,  on top of data.  You can change this with the -under
+       option.  # Draw the label before elements are drawn.  .g marker config-
+       ure first_marker -under yes You can add cross hairs or grid lines using
+       the crosshairs and grid components.  # Display  both  cross  hairs  and
+       grid  lines.   .g crosshairs configure -hide no -color red .g grid con-
+       figure -hide no -dashes { 2 2 } # Set up a binding  to  reposition  the
+       crosshairs.  bind .g <Motion> {
+           .g crosshairs configure -position @%x,%y } The crosshairs are repo-
+       sitioned as the mouse pointer is moved in the graph.  The  pointer  X-Y
+       coordinates define the center of the crosshairs.
+
+       Finally, to get hardcopy of the graph, use the postscript component.  #
+       Print the graph into file "file.ps" .g postscript output file.ps  -max-
+       pect  yes  -decorations no This generates a file file.ps containing the
+       encapsulated PostScript of the graph.   The  option  -maxpect  says  to
+       scale  the  plot to the size of the page.  Turning off the -decorations
+       option denotes that no borders or color  backgrounds  should  be  drawn
+              option.   Option  may be any option described below for the con-
+              figure operation.
+
+       pathName configure ?option value?...
+              Queries or modifies the configuration options of the graph.   If
+              option  isn't  specified,  a list describing the current options
+              for pathName is returned.   If  option  is  specified,  but  not
+              value,  then  a  list  describing option is returned.  If one or
+              more option and value pairs are specified, then for  each  pair,
+              the  option  option  is set to value.  The following options are
+              valid.
+
+              -aspect width/height
+                     Force a fixed aspect ratio of  width/height,  a  floating
+                     point number.
+
+              -background color
+                     Sets  the background color. This includes the margins and
+                     legend, but not the plotting area.
+
+              -borderwidth pixels
+                     Sets the width of the 3-D border around the outside  edge
+                     of the widget.  The -relief option determines if the bor-
+                     der is to be drawn.  The default is 2.
+
+              -bottommargin pixels
+                     If non-zero, overrides the computed size  of  the  margin
+                     extending  below  the X-coordinate axis.  If pixels is 0,
+                     the automatically computed size is used.  The default  is
+                     0.
+
+              -bufferelements boolean
+                     Indicates  whether  an internal pixmap to buffer the dis-
+                     play of data elements should  be  used.   If  boolean  is
+                     true,  data  elements  are  drawn  to an internal pixmap.
+                     This option  is  especially  useful  when  the  graph  is
+                     redrawn  frequently while the remains data unchanged (for
+                     example, moving a marker across the plot).  See the SPEED
+                     TIPS section.  The default is 1.
+
+              -cursor cursor
+                     Specifies  the  widget's  cursor.   The default cursor is
+                     crosshair.
+
+              -font fontName
+                     Specifies the font of the graph  title.  The  default  is
+                     *-Helvetica-Bold-R-Normal-*-18-180-*.
+
+              -halo pixels
+                     Specifies  a  maximum distance to consider when searching
+                     for the closest data point  (see  the  element's  closest
+                     operation  below).   Data points further than pixels away
+                     text.  Justify  must  be  left,  right,  or  center.  The
+                     default is center.
+
+              -leftmargin pixels
+                     If non-zero, overrides the computed size  of  the  margin
+                     extending from the left edge of the window to the Y-coor-
+                     dinate axis.  If pixels is 0, the automatically  computed
+                     size is used.  The default is 0.
+
+              -plotbackground color
+                     Specifies the background color of the plotting area.  The
+                     default is white.
+
+              -plotborderwidth pixels
+                     Sets the width of the  3-D  border  around  the  plotting
+                     area.   The  -plotrelief option determines if a border is
+                     drawn.  The default is 2.
+
+              -plotpadx pad
+                     Sets the amount of padding to be added to  the  left  and
+                     right  sides  of the plotting area.  Pad can be a list of
+                     one or two screen distances.  If pad  has  two  elements,
+                     the left side of the plotting area entry is padded by the
+                     first distance and the right side by the second.  If  pad
+                     is  just  one distance, both the left and right sides are
+                     padded evenly.  The default is 8.
+
+              -plotpady pad
+                     Sets the amount of padding to be added  to  the  top  and
+                     bottom of the plotting area.  Pad can be a list of one or
+                     two screen distances.  If pad has two elements,  the  top
+                     of  the plotting area is padded by the first distance and
+                     the bottom by the second.  If pad is just  one  distance,
+                     both  the  top and bottom are padded evenly.  The default
+                     is 8.
+
+              -plotrelief relief
+                     Specifies the 3-D effect for the plotting  area.   Relief
+                     specifies  how  the  interior of the plotting area should
+                     appear relative to rest of the graph; for example, raised
+                     means  the plot should appear to protrude from the graph,
+                     relative to the surface of the  graph.   The  default  is
+                     sunken.
+
+              -relief relief
+                     Specifies  the  3-D  effect for the graph widget.  Relief
+                     specifies how the graph should appear relative to  widget
+                     it  is  packed  into; for example, raised means the graph
+                     should appear to protrude.  The default is flat.
+
+              -rightmargin pixels
+                     If non-zero, overrides the computed size  of  the  margin
+
+              -tile image
+                     Specifies  a  tiled  background for the widget.  If image
+                     isn't "", the background is tiled  using  image.   Other-
+                     wise,  the  normal  background  color  is  drawn (see the
+                     -background option).  Image  must  be  an  image  created
+                     using the Tk image command.  The default is "".
+
+              -title text
+                     Sets  the  title to text. If text is "", no title will be
+                     displayed.
+
+              -topmargin pixels
+                     If non-zero, overrides the computed size  of  the  margin
+                     above  the  x2  axis.   If pixels is 0, the automatically
+                     computed size is used.  The default is 0.
+
+              -width pixels
+                     Specifies the requested width of the widget.  The default
+                     is 5i.
+
+       pathName crosshairs operation ?arg?
+              See the CROSSHAIRS COMPONENT section.
+
+       pathName element operation ?arg?...
+              See the ELEMENT COMPONENTS section.
+
+       pathName extents item
+              Returns  the  size of a particular item in the graph.  Item must
+              be  either  leftmargin,  rightmargin,  topmargin,  bottommargin,
+              plotwidth, or plotheight.
+
+       pathName grid operation ?arg?...
+              See the GRID COMPONENT section.
+
+       pathName invtransform winX winY
+              Performs  an  inverse  coordinate transformation, mapping window
+              coordinates back to graph coordinates, using the standard X-axis
+              and  Y-axis.  Returns a list of containing the X-Y graph coordi-
+              nates.
+
+       pathName inside x y
+              Returns 1 is the designated  screen  coordinate  (x  and  y)  is
+              inside the plotting area and 0 otherwise.
+
+       pathName legend operation ?arg?...
+              See the LEGEND COMPONENT section.
+
+       pathName line operation arg...
+              The operation is the same as element.
+
+       pathName marker operation ?arg?...
+                        photo  Saves a Tk photo image.  OutputName  represents
+                               the  name of a Tk photo image that must already
+                               have been created.
+
+                        wmf    Saves an Aldus Placeable Metafile.   OutputName
+                               represents  the  filename where the metafile is
+                               written.  If outputName is CLIPBOARD, then out-
+                               put  is  written  directly to the Windows clip-
+                               board.  This format  is  available  only  under
+                               Microsoft Windows.
+
+                        emf    Saves  an  Enhanced Metafile. OutputName repre-
+                               sents the filename where the metafile is  writ-
+                               ten.   If  outputName is CLIPBOARD, then output
+                               is written directly to the  Windows  clipboard.
+                               This  format  is available only under Microsoft
+                               Windows.
+
+              -height size
+                        Specifies the height of the graph.  Size is  a  screen
+                        distance.  The graph will be redrawn using this dimen-
+                        sion, rather than its current window height.
+
+              -width size
+                        Specifies the width of the graph.  Size  is  a  screen
+                        distance.  The graph will be redrawn using this dimen-
+                        sion, rather than its current window width.
+
+       pathName transform x y
+              Performs a coordinate transformation, mapping graph  coordinates
+              to  window  coordinates,  using  the standard X-axis and Y-axis.
+              Returns a list containing the X-Y screen coordinates.
+
+       pathName xaxis operation ?arg?...
+
+       pathName x2axis operation ?arg?...
+
+       pathName yaxis operation ?arg?...
+
+       pathName y2axis operation ?arg?...
+              See the AXIS COMPONENTS section.
+
+
+
+

GRAPH COMPONENTS

+       A graph is composed of several components: coordinate axes,  data  ele-
+       ments,  legend,  grid, cross hairs, postscript, and annotation markers.
+       Instead of one big set of configuration  options  and  operations,  the
+       graph  is  partitioned,  where each component has its own configuration
+       options and operations that specifically control that aspect or part of
+       the graph.
+
+   AXIS COMPONENTS
+       Four  coordinate  axes are automatically created: two X-coordinate axes
+       You can have several axes. To create an axis, invoke the axis component
+       and  its  create  operation.   # Create a new axis called "tempAxis" .g
+       axis create tempAxis You map data elements to an axis  using  the  ele-
+       ment's  -mapy and -mapx configuration options. They specify the coordi-
+       nate axes an element is mapped onto.  # Now map the  tempAxis  data  to
+       this  axis.   .g element create "e1" -xdata $x -ydata $y -mapy tempAxis
+       Any number of axes can be displayed simultaneously. They are  drawn  in
+       the  margins  surrounding  the plotting area.  The default axes x and y
+       are drawn in the bottom and left margins. The axes x2 and y2 are  drawn
+       in  top  and  right  margins.  By default, only x and y are shown. Note
+       that the axes can have different scales.
+
+       To display a different axis or more than one axis, you  invoke  one  of
+       the  following components: xaxis, yaxis, x2axis, and y2axis.  Each com-
+       ponent has a use operation that designates the axis  (or  axes)  to  be
+       drawn  in  that corresponding margin: xaxis in the bottom, yaxis in the
+       left, x2axis in the top, and y2axis in the right.  # Display  the  axis
+       tempAxis  in  the left margin.  .g yaxis use tempAxis The use operation
+       takes a list of axis names as its last argument.  This is the  list  of
+       axes to be drawn in this margin.
+
+       You  can  configure  axes in many ways. The axis scale can be linear or
+       logarithmic.  The  values  along  the  axis  can  either  monotonically
+       increase  or decrease.  If you need custom tick labels, you can specify
+       a Tcl procedure to format the label any way you wish.  You can  control
+       how  ticks are drawn, by changing the major tick interval or the number
+       of minor ticks.  You can define non-uniform tick intervals, such as for
+       time-series plots.
+
+
+       pathName axis bind tagName ?sequence?  ?command?
+              Associates  command  with  tagName  such that whenever the event
+              sequence given by sequence occurs for an  axis  with  this  tag,
+              command will be invoked.  The syntax is similar to the bind com-
+              mand except that it operates on graph axes, rather than widgets.
+              See  the  bind manual entry for complete details on sequence and
+              the substitutions performed on command before invoking it.
+
+              If all arguments are specified then a new  binding  is  created,
+              replacing  any  existing  binding for the same sequence and tag-
+              Name.  If the first character of command is + then command  aug-
+              ments  an existing binding rather than replacing it.  If no com-
+              mand argument is provided then the command currently  associated
+              with  tagName  and  sequence (it's an error occurs if there's no
+              such binding) is returned.  If both  command  and  sequence  are
+              missing  then  a list of all the event sequences for which bind-
+              ings have been defined for tagName.
+
+       pathName axis cget axisName option
+              Returns the current value of the  option  given  by  option  for
+              axisName.  Option may be any option described below for the axis
+              configure operation.
+                     the  list  matching  the current event sequence will have
+                     its Tcl command executed.  Implicitly  the  name  of  the
+                     element is always the first tag in the list.  The default
+                     value is all.
+
+              -color color
+                     Sets the color of the axis and tick labels.  The  default
+                     is black.
+
+              -descending boolean
+                     Indicates whether the values along the axis are monotoni-
+                     cally increasing or decreasing.  If boolean is true,  the
+                     axis values will be decreasing.  The default is 0.
+
+              -hide boolean
+                     Indicates  if  the axis is displayed. If boolean is false
+                     the axis will be displayed. Any  element  mapped  to  the
+                     axis is displayed regardless.  The default value is 0.
+
+              -justify justify
+                     Specifies  how  the axis title should be justified.  This
+                     matters only when the axis title contains more  than  one
+                     line  of  text.  Justify  must be left, right, or center.
+                     The default is center.
+
+              -limits formatStr
+                     Specifies a printf-like description to format the minimum
+                     and maximum limits of the axis.  The limits are displayed
+                     at the top/bottom or left/right  sides  of  the  plotting
+                     area.   FormatStr is a list of one or two format descrip-
+                     tions.  If one description is supplied, both the  minimum
+                     and  maximum  limits  are  formatted in the same way.  If
+                     two, the first designates  the  format  for  the  minimum
+                     limit,  the  second  for  the maximum.  If "" is given as
+                     either description, then the that limit will not be  dis-
+                     loosely, at the outer tick intervals.  If the axis  limit
+                     is  set  with  the -min or -max option, the axes are dis-
+                     played tightly.  If boolean is true, the  axis  range  is
+                     "loose".  The default is 0.
+
+              -majorticks majorList
+                     Specifies where to display major axis ticks.  You can use
+                     this option to display ticks  at  non-uniform  intervals.
+                     MajorList  is  a list of axis coordinates designating the
+                     location of major ticks.  No minor ticks are  drawn.   If
+                     majorList  is  "", major ticks will be automatically com-
+                     puted. The default is "".
+
+              -max value
+                     Sets the maximum  limit  of  axisName.   Any  data  point
+                     greater than value is not displayed.  If value is "", the
+                     maximum limit is calculated using the largest data value.
+                     The default is "".
+
+              -min value
+                     Sets  the  minimum limit of axisName. Any data point less
+                     than value is not displayed.  If value is "", the minimum
+                     limit  is  calculated using the smallest data value.  The
+                     default is "".
+
+              -minorticks minorList
+                     Specifies where to display minor axis ticks.  You can use
+                     this  option to display minor ticks at non-uniform inter-
+                     vals. MinorList is a list of real  values,  ranging  from
+                     0.0  to  1.0,  designating the placement of a minor tick.
+                     No minor ticks are drawn if the -majortick option is also
+                     set.   If  minorList is "", minor ticks will be automati-
+                     cally computed. The default is "".
+
+              -rotate theta
+                     Specifies the how many degrees to rotate  the  axis  tick
+                     labels.  Theta is a real value representing the number of
+                     degrees to rotate the tick labels.  The  default  is  0.0
+                     degrees.
+
+              -scrollcommand command
+                     Specify the prefix for a command used to communicate with
+                     scrollbars for this axis, such as .sbar set.
+
+              -scrollmax value
+                     Sets the maximum limit of the  axis  scroll  region.   If
+                     value  is  "",  the maximum limit is calculated using the
+                     largest data value.  The default is "".
+
+              -scrollmin value
+                     Sets the minimum limit of axis scroll region.   If  value
+                     is "", the minimum limit is calculated using the smallest
+                     Indicates how many minor axis ticks are to be drawn.  For
+                     example, if number is two, only one minor tick is  drawn.
+                     If  number  is  one,  no  minor ticks are displayed.  The
+                     default is 2.
+
+              -tickfont fontName
+                     Specifies the font for axis tick labels. The  default  is
+                     *-Courier-Bold-R-Normal-*-100-*.
+
+              -tickformat formatStr
+                     Specifies a printf-like description to format teh axis
+                     tick labels.  You can get the standard tick labels again by
+                     setting formatStr to "".  The default is "".
+
+              -tickformatcommand, -command prefix
+                     Specifies a Tcl command to be invoked when formatting the
+                     axis tick labels. Prefix is a string containing the  name
+                     of  a Tcl proc and any extra arguments for the procedure.
+                     This command is invoked for each major tick on the  axis.
+                     Two additional arguments are passed to the procedure: the
+                     pathname of the widget and the current the numeric  value
+                     of  the  tick.   The procedure returns the formatted tick
+                     label.  If "" is returned, no label will appear  next  to
+                     the  tick.  You can get the standard tick labels again by
+                     setting prefix to "".  The default is "".
+
+                     The numeric value for the tick might change when using the
+                     -logscale and -tickformat options.
+
+                     Please note that this  procedure  is  invoked  while  the
+                     graph  is  redrawn.  You may query configuration options.
+                     But  do  not  them,  because  this  can  have  unexpected
+                     results.
+
+              -ticklength pixels
+                     Sets the length of major and minor ticks (minor ticks are
+                     half the length of major ticks). If pixels is  less  than
+                     zero, the axis will be inverted with ticks drawn pointing
+                     towards the plot.  The default is 0.1i.
+
+              -title text
+                     Sets the title of the axis. If text is "", no axis  title
+                     will be displayed.
+
+              -titlealternate boolean
+                     Indicates  to  display  the  axis  title in its alternate
+                     location.  Normally the axis title is centered along  the
+                     axis.   This  option  places the axis either to the right
+                     (horizontal axes) or above (vertical axes) the axis.  The
+                     default is 0.
+
+              -titlecolor color
+                     Sets the color of the axis title. The default is black.
+
+              -titlefont fontName
+                     Specifies  the font for axis title. The default is *-Hel-
+                     vetica-Bold-R-Normal-*-14-140-*.
+
+              Axis configuration options may be also be set by the option com-
+              mand.   The  resource class is Axis.  The resource names are the
+              names  of  the  axes  (such   as   x   or   x2).    option   add
+              *Graph.Axis.Color    blue  option  add  *Graph.x.LogScale   true
+              option add *Graph.x2.LogScale false
+
+       pathName axis create axisName ?option value?...
+              Creates a new axis by the name axisName.  No axis  by  the  same
+              name  can already exist. Option and value are described in above
+              in the axis configure operation.
+
+       pathName axis delete ?axisName?...
+              Deletes the named axes. An axis is not really deleted  until  it
+              is not longer in use, so it's safe to delete axes mapped to ele-
+              ments.
+
+       pathName axis invtransform axisName value
+              Performs the inverse transformation, changing the screen coordi-
+              nate  value  to  a graph coordinate, mapping the value mapped to
+
+       pathName axis view axisName
+              Change the viewable area of this axis. Use as an argument  to  a
+              scrollbar's "-command".
+
+       The  default  axes are x, y, x2, and y2.  But you can display more than
+       four axes simultaneously.  You can also swap in a different  axis  with
+       use operation of the special axis components: xaxis, x2axis, yaxis, and
+       y2axis.  .g create axis temp .g create axis time ...  .g xaxis use temp
+       .g  yaxis use time Only the axes specified for use are displayed on the
+       screen.
+
+       The xaxis, x2axis, yaxis, and y2axis  components  operate  on  an  axis
+       location  rather than a specific axis like the more general axis compo-
+       nent does.  They implicitly control the axis that is currently using to
+       that location.  By default, xaxis uses the x axis, yaxis uses y, x2axis
+       uses x2, and y2axis uses y2.  When more than one axis is displayed in a
+       margin, it represents the first axis displayed.
+
+       The  following  operations  are available for axes. They mirror exactly
+       the operations of the axis component.  The axis argument must be xaxis,
+       x2axis,  yaxis,  or y2axis.  This feature is deprecated since more than
+       one axis can now be used a margin.  You  should  only  use  the  xaxis,
+       x2axis,  yaxis,  and y2axis components with the use operation.  For all
+       other operations, use the general axis component instead.
+
+       pathName axis cget option
+
+       pathName axis configure ?option value?...
+
+       pathName axis invtransform value
+
+       pathName axis limits
+
+       pathName axis transform value
+
+       pathName axis use ?axisName?
+              Designates the axis axisName is to be displayed  at  this  loca-
+              tion.   AxisName  can not be already in use at another location.
+              This command returns the name of the axis currently  using  this
+              location.
+
+   CROSSHAIRS COMPONENT
+       Cross  hairs  consist  of  two intersecting lines (one vertical and one
+       horizontal) drawn completely across the plotting area.  They  are  used
+       to  position the mouse in relation to the coordinate axes.  Cross hairs
+       differ from line markers in that they are implemented using XOR drawing
+       primitives.  This means that they can be quickly drawn and erased with-
+       out redrawing the entire graph.
+
+       The following operations are available for cross hairs:
+
+              -color color
+                     Sets the color of the cross hairs.  The default is black.
+
+              -dashes dashList
+                     Sets  the  dash  style  of the cross hairs. DashList is a
+                     list of up to 11 numbers that alternately  represent  the
+                     lengths  of  the dashes and gaps on the cross hair lines.
+                     Each number must be between 1 and 255.   If  dashList  is
+                     "", the cross hairs will be solid lines.
+
+              -hide boolean
+                     Indicates  whether  cross  hairs are drawn. If boolean is
+                     true, cross hairs are not drawn.  The default is yes.
+
+              -linewidth pixels
+                     Set the width of the cross hair lines.  The default is 1.
+
+              -position pos
+                     Specifies  the  screen  position  where  the  cross hairs
+                     intersect.  Pos must be in the form "@x,y", where x and y
+                     are the window coordinates of the intersection.
+
+              Cross  hairs  configuration  options  may  be also be set by the
+              option command.  The resource name and class are crosshairs  and
+              Crosshairs respectively.  option add *Graph.Crosshairs.LineWidth
+              2 option add *Graph.Crosshairs.Color     red
+
+       pathName crosshairs off
+              Turns off the cross hairs.
+
+       pathName crosshairs on
+              Turns on the display of the cross hairs.
+
+       pathName crosshairs toggle
+              Toggles the current state of the cross hairs,  alternately  map-
+              ping and unmapping the cross hairs.
+
+   ELEMENT COMPONENTS
+       A  data  element represents a set of data.  It contains x and y vectors
+       containing the coordinates of the data points.  Elements  can  be  dis-
+       played  with  a  symbol  at  each  data  point and lines connecting the
+       points.  Elements also control the appearance of the data, such as  the
+       symbol type, line width, color etc.
+
+       When  new  data elements are created, they are automatically added to a
+       list of displayed elements.   The display list controls  what  elements
+       are drawn and in what order.
+
+       The following operations are available for elements.
+
+       pathName element activate elemName ?index?...
+              Specifies  the data points of element elemName to be drawn using
+              replacing  any  existing  binding for the same sequence and tag-
+              Name.  If the first character of command is + then command  aug-
+              ments  an existing binding rather than replacing it.  If no com-
+              mand argument is provided then the command currently  associated
+              with  tagName  and  sequence (it's an error occurs if there's no
+              such binding) is returned.  If both  command  and  sequence  are
+              missing  then  a list of all the event sequences for which bind-
+              ings have been defined for tagName.
+
+       pathName element cget elemName option
+              Returns the current value of the  element  configuration  option
+              given  by  option.   Option  may be any of the options described
+              below for the element configure operation.
+
+       pathName element closest x y ?option value?... ?elemName?...
+              Searches for the data point closest to the window coordinates  x
+              and  y.  By default, all elements are searched.  Hidden elements
+              (see the -hide option is false) are ignored.  You can limit  the
+              search  by  specifying  only the elements you want to be consid-
+              ered.  ElemName must be the name of an element that can  not  be
+              hidden.   It returns a key-value list containing the name of the
+              closest element, the index of the closest data  point,  and  the
+              graph-coordinates  of  the  point.  Returns "", if no data point
+              within the  threshold  distance  can  be  found.  The  following
+              option-value pairs are available.
+
+              -along direction
+                     Search for the closest element using the following crite-
+                     ria:
+
+                     x      Find closest element vertically from the given  X-
+                            coordinate.
+
+                     y      Find  the  closest  element  horizontally from the
+                            given Y-coordinate.
+
+                     both   Find the  closest  element  for  the  given  point
+                            (using both the X and Y coordinates).
+
+              -halo pixels
+                     Specifies a threshold distance where selected data points
+                     are ignored.  Pixels is a valid screen distance, such  as
+                     2  or  1.2i.   If  this  option  isn't specified, then it
+                     defaults to the value of the graph's -halo option.
+
+              -interpolate string
+                     Indicates whether to consider projections that lie  along
+                     the  line  segments connecting data points when searching
+                     for the closest point.  The default value is 0. The  val-
+                     ues for string are described below.
+
+                     no          Search only for the closest data point.
+
+              -activepen penName
+                     Specifies pen to use to draw active element.  If  penName
+                     is  "", no active elements will be drawn.  The default is
+                     activeLine.
+
+              -areabackground color
+                     Specifies the background color  of  the  area  under  the
+                     curve.  The  background area color is drawn only for bit-
+                     maps (see the -areapattern option).  If color is "",  the
+                     background is transparent.  The default is black.
+
+              -areaforeground color
+                     Specifies  the  foreground  color  of  the area under the
+                     curve.  The default is black.
+
+              -areapattern pattern
+                     Specifies how to fill the area under the curve.   Pattern
+                     may  be  the  name  of  a  Tk  bitmap,  solid, or "".  If
+                     "solid", then the area under the curve is drawn with  the
+                     color  designated  by  the  -areaforeground option.  If a
+                     bitmap, then the bitmap  is  stippled  across  the  area.
+                     Here  the  bitmap colors are controlled by the -areafore-
+                     ground and -areabackground options.  If pattern is "", no
+                     filled area is drawn.  The default is "".
+
+              -areatile image
+                     Specifies  the  name of a Tk image to be used to tile the
+                     area under the curve.  This option supersedes the -areap-
+                     attern option.  Image must be a photo image.  If image is
+                     "", no tiling is performed.  The default is "".
+
+              -bindtags tagList
+                     Specifies the binding tags for the element.  TagList is a
+                     list of binding tag names.  The tags and their order will
+                     determine how events are handled for elements.  Each  tag
+                     in the list matching the current event sequence will have
+                     its Tcl command executed.  Implicitly  the  name  of  the
+                     element is always the first tag in the list.  The default
+                     value is all.
+
+              -color color
+                     Sets the color of the traces connecting the data  points.
+
+              -dashes dashList
+                     Sets  the  dash style of element line. DashList is a list
+                     of up  to  11  numbers  that  alternately  represent  the
+                     lengths of the dashes and gaps on the element line.  Each
+                     number must be between 1 and 255.  If dashList is "", the
+                     lines will be solid.
+
+              -data coordList
+                     Specifies  the X-Y coordinates of the data.  CoordList is
+                     Sets  the  element's label in the legend.  If text is "",
+                     the element will  have  no  entry  in  the  legend.   The
+                     default label is the element's name.
+
+              -linewidth pixels
+                     Sets  the  width  of  the  connecting  lines between data
+                     points.  If pixels is 0,  no  connecting  lines  will  be
+                     drawn between symbols.  The default is 0.
+
+              -mapx xAxis
+                     Selects  the  X-axis  to  map the element's X-coordinates
+                     onto.  XAxis must be the name of an axis.  The default is
+                     x.
+
+              -mapy yAxis
+                     Selects  the  Y-axis  to  map the element's Y-coordinates
+                     onto.  YAxis must be the name of an axis. The default  is
+                     y.
+
+              -offdash color
+                     Sets the color of the stripes when traces are dashed (see
+                     the -dashes option).  If color is "", then the "off" pix-
+                     els  will represent gaps instead of stripes.  If color is
+                     defcolor, then the color will be the same as  the  -color
+                     option.  The default is defcolor.
+
+              -outline color
+                     Sets  the  color  or  the outline around each symbol.  If
+                     color is "", then no outline is drawn. If color  is  def-
+                     color,  then  the  color  will  be the same as the -color
+                     option.  The default is defcolor.
+
+              -pen penname
+                     Set the pen to use for this element.
+
+              -outlinewidth pixels
+                     Sets the width of the outline bordering each symbol.   If
+                     pixels  is 0, no outline will be drawn. The default is 1.
+
+              -pixels pixels
+                     Sets the size of symbols.  If pixels  is  0,  no  symbols
+                     will be drawn.  The default is 0.125i.
+
+              -scalesymbols boolean
+                     If  boolean  is  true,  the size of the symbols drawn for
+                     elemName will change with scale of the X-axis and Y-axis.
+                     At the time this option is set, the current ranges of the
+                     axes are saved as the normalized scales (i.e scale factor
+                     is  1.0)  and the element is drawn at its designated size
+                     (see the -pixels option).   As  the  scale  of  the  axes
+                     change,  the  symbol  will  be  scaled  according  to the
+                     smaller of the X-axis and Y-axis scales.  If  boolean  is
+                     dratic spline is used.  The default is linear.
+
+              -styles styleList
+                     Specifies what pen to use based on the range  of  weights
+                     given.  StyleList is a list of style specifications. Each
+                     style specification, in turn, is a list consisting  of  a
+                     pen  name,  and  optionally  a minimum and maximum range.
+                     Data points whose weight (see the -weight  option)  falls
+                     in  this  range, are drawn with this pen.  If no range is
+                     specified it defaults to the index  of  the  pen  in  the
+                     list.   Note  that  this  affects only symbol attributes.
+                     Line attributes, such as line  width,  dashes,  etc.  are
+                     ignored.
+
+              -symbol symbol
+                     Specifies  the  symbol  for  data  points.  Symbol can be
+                     either  square,  circle,  diamond,  plus,  cross,  splus,
+                     scross,  triangle,  ""  (where  no symbol is drawn), or a
+                     bitmap.  Bitmaps are specified as "source ?mask?",  where
+                     source  is  the  name of the bitmap, and mask is the bit-
+                     map's optional mask.  The default is circle.
+
+              -trace direction
+                     Indicates whether connecting lines  between  data  points
+                     (whose  X-coordinate  values  are  either  increasing  or
+                     decreasing) are drawn.   Direction  must  be  increasing,
+                     decreasing,  or  both.   For  example,  if  direction  is
+                     increasing, connecting lines will be drawn  only  between
+                     those data points where X-coordinate values are monotoni-
+                     cally increasing.  If direction is both, connecting lines
+                     will  be  draw  between  all data points.  The default is
+                     both.
+
+              -weights wVec
+                     Specifies the weights  of  the  individual  data  points.
+                     This,  with the list pen styles (see the -styles option),
+                     controls how data points are drawn.  WVec is the name  of
+                     a  BLT vector or a list of numeric expressions represent-
+                     ing the weights for each data point.
+
+              -xdata xVec
+                     Specifies the X-coordinates of the  data.   XVec  is  the
+                     name of a BLT vector or a list of numeric expressions.
+
+              -ydata yVec
+                     Specifies  the  Y-coordinates  of  the data.  YVec is the
+                     name of a BLT vector or a list of numeric expressions.
+
+              Element configuration options may also be set by the option com-
+              mand.   The  resource class is Element. The resource name is the
+              name of the  element.   option  add  *Graph.Element.symbol  line
+              option add *Graph.e1.symbol line
+
+       pathName element exists elemName
+              Returns  1  if an element elemName currently exists and 0 other-
+              wise.
+
+       pathName element names ?pattern?...
+              Returns the elements matching one or more pattern.  If  no  pat-
+              tern is given, the names of all elements is returned.
+
+       pathName element show ?nameList?
+              Queries  or modifies the element display list.  The element dis-
+              play list designates the  elements  drawn  and  in  what  order.
+              NameList is a list of elements to be displayed in the order they
+              are named.  If there is no nameList argument, the  current  dis-
+              play list is returned.
+
+       pathName element type elemName
+              Returns  the type of elemName.  If the element is a bar element,
+              the commands returns the  string  "bar",  otherwise  it  returns
+              "line".
+
+   GRID COMPONENT
+       Grid  lines extend from the major and minor ticks of each axis horizon-
+       tally or vertically across the plotting area.  The following operations
+       are available for grid lines.
+
+       pathName grid cget option
+              Returns  the current value of the grid line configuration option
+              given by option.  Option may be any option described  below  for
+              the grid configure operation.
+
+       pathName grid configure ?option value?...
+              Queries  or  modifies  the configuration options for grid lines.
+              If option isn't specified, a list  describing  all  the  current
+              grid  options for pathName is returned.  If option is specified,
+              but not value, then a list describing option  is  returned.   If
+              one  or more option and value pairs are specified, then for each
+              pair, the grid line option option is set to value.  The  follow-
+              ing options are valid for grid lines.
+
+              -color color
+                     Sets  the color of the grid lines.  The default is black.
+
+              -dashes dashList
+                     Sets the dash style of the grid lines. DashList is a list
+                     of  up  to  11  numbers  that  alternately  represent the
+                     lengths of the dashes and gaps on the grid  lines.   Each
+                     number must be between 1 and 255.  If dashList is "", the
+                     grid will be solid lines.
+
+              -hide boolean
+                     Indicates whether the grid should be drawn. If boolean is
+
+              -minor boolean
+                     Indicates  whether  the  grid  lines  should be drawn for
+                     minor ticks.  If boolean is true, the lines  will  appear
+                     at minor tick intervals.  The default is 1.
+
+              Grid  configuration  options  may also be set by the option com-
+              mand.  The resource name and class are  grid  and  Grid  respec-
+              tively.    option   add   *Graph.grid.LineWidth   2  option  add
+              *Graph.Grid.Color     black
+
+       pathName grid off
+              Turns off the display the grid lines.
+
+       pathName grid on
+              Turns on the display the grid lines.
+
+       pathName grid toggle
+              Toggles the display of the grid.
+
+   LEGEND COMPONENT
+       The legend displays a list of the data elements.  Each  entry  consists
+       of the element's symbol and label.  The legend can appear in any margin
+       (the default location is in the right margin).  It can  also  be  posi-
+       tioned anywhere within the plotting area.
+
+       The following operations are valid for the legend.
+
+       pathName legend activate pattern...
+              Selects  legend entries to be drawn using the active legend col-
+              ors and relief.  All entries whose element names  match  pattern
+              are  selected.  To be selected, the element name must match only
+              one pattern.
+
+       pathName legend bind tagName ?sequence?  ?command?
+              Associates command with tagName such  that  whenever  the  event
+              sequence  given  by sequence occurs for a legend entry with this
+              tag, command will be invoked.  Implicitly the element  names  in
+              the  entry  are tags.  The syntax is similar to the bind command
+              except that it operates on legend entries, rather than  widgets.
+              See  the  bind manual entry for complete details on sequence and
+              the substitutions performed on command before invoking it.
+
+              If all arguments are specified then a new  binding  is  created,
+              replacing  any  existing  binding for the same sequence and tag-
+              Name.  If the first character of command is + then command  aug-
+              ments  an existing binding rather than replacing it.  If no com-
+              mand argument is provided then the command currently  associated
+              with  tagName  and  sequence (it's an error occurs if there's no
+              such binding) is returned.  If both  command  and  sequence  are
+              missing  then  a list of all the event sequences for which bind-
+              ings have been defined for tagName.
+
+              -activebackground color
+                     Sets the background color for active legend entries.  All
+                     legend  entries  marked  active  (see the legend activate
+                     operation) are drawn using this background color.
+
+              -activeborderwidth pixels
+                     Sets the width of the 3-D border around the outside  edge
+                     of the active legend entries.  The default is 2.
+
+              -activeforeground color
+                     Sets the foreground color for active legend entries.  All
+                     legend entries marked as active (see the legend  activate
+                     operation) are drawn using this foreground color.
+
+              -activerelief relief
+                     Specifies  the  3-D  effect  desired  for  active  legend
+                     entries.  Relief denotes how the interior  of  the  entry
+                     should appear relative to the legend; for example, raised
+                     means the entry should appear to protrude from  the  leg-
+                     end,  relative to the surface of the legend.  The default
+                     is flat.
+
+              -anchor anchor
+                     Tells how to position the legend relative  to  the  posi-
+                     tioning  point  for the legend.  This is dependent on the
+                     value of the -position option.  The default is center.
+
+                     left or right
+                                 The anchor describes how to position the leg-
+                                 end vertically.
+
+                     top or bottom
+                                 The anchor describes how to position the leg-
+                                 end horizontally.
+
+                     @x,y        The anchor specifies how to position the leg-
+                                 end  relative  to  the positioning point. For
+                                 example, if anchor is center then the  legend
+                                 is centered on the point; if anchor is n then
+                                 the legend will be drawn such  that  the  top
+                                 center  point of the rectangular region occu-
+                                 pied by the legend will be at the positioning
+                                 point.
+
+                     plotarea    The anchor specifies how to position the leg-
+                                 end relative to the plotting area. For  exam-
+                                 ple,  if  anchor is center then the legend is
+                                 centered in the plotting area; if  anchor  is
+                                 ne  then  the  legend will be drawn such that
+                                 occupies the upper right corner of the  plot-
+                                 ting area.
+
+                     Sets  the width of the 3-D border around the outside edge
+                     of the legend (if such border is being drawn; the  relief
+                     option determines this).  The default is 2 pixels.
+
+              -font fontName
+                     FontName  specifies a font to use when drawing the labels
+                     of each element into the legend.  The default  is  *-Hel-
+                     vetica-Bold-R-Normal-*-12-120-*.
+
+              -foreground color
+                     Sets  the foreground color of the text drawn for the ele-
+                     ment's label.  The default is black.
+
+              -hide boolean
+                     Indicates whether the  legend  should  be  displayed.  If
+                     boolean  is  true,  the  legend  will  not  be draw.  The
+                     default is no.
+
+              -ipadx pad
+                     Sets the amount of internal padding to be  added  to  the
+                     width  of each legend entry.  Pad can be a list of one or
+                     two screen distances.  If pad has two elements, the  left
+                     side  of the legend entry is padded by the first distance
+                     and the right side by the second.  If  pad  is  just  one
+                     distance,  both  the  left  and  right  sides  are padded
+                     evenly.  The default is 2.
+
+              -ipady pad
+                     Sets an amount of internal padding to  be  added  to  the
+                     height of each legend entry.  Pad can be a list of one or
+                     two screen distances.  If pad has two elements,  the  top
+                     of the entry is padded by the first distance and the bot-
+                     tom by the second.  If pad is just one distance, both the
+                     top  and  bottom  of  the  entry  are padded evenly.  The
+                     default is 2.
+
+              -padx pad
+                     Sets the padding to the left and right exteriors  of  the
+                     legend.   Pad  can  be  a  list of one or two screen dis-
+                     tances.  If pad has two elements, the left  side  of  the
+                     legend is padded by the first distance and the right side
+                     by the second.  If pad has just one  distance,  both  the
+                     left  and  right sides are padded evenly.  The default is
+                     4.
+
+              -pady pad
+                     Sets the padding above and below the legend.  Pad can  be
+                     a  list  of  one or two screen distances.  If pad has two
+                     elements, the area above the  legend  is  padded  by  the
+                     first  distance and the area below by the second.  If pad
+                     is just one distance, both the top and bottom  areas  are
+                     padded evenly.  The default is 0.
+                     plotting area.  If boolean is true, the  legend  will  be
+                     drawn  on  top  of  any elements that may overlap it. The
+                     default is no.
+
+              -relief relief
+                     Specifies the 3-D effect for the border around  the  leg-
+                     end.   Relief  specifies  how  the interior of the legend
+                     should appear relative to the graph; for example,  raised
+                     means  the  legend  should  appear  to  protrude from the
+                     graph, relative to the surface of the graph.  The default
+                     is sunken.
+
+              Legend  configuration options may also be set by the option com-
+              mand.  The resource name and class are legend and Legend respec-
+              tively.   option  add  *Graph.legend.Foreground  blue option add
+              *Graph.Legend.Relief     raised
+
+       pathName legend deactivate pattern...
+              Selects legend entries to be drawn using the normal legend  col-
+              ors  and  relief.  All entries whose element names match pattern
+              are selected.  To be selected, the element name must match  only
+              one pattern.
+
+       pathName legend get pos
+              Returns  the  name  of  the element whose entry is at the screen
+              position pos in the legend.  Pos must be  in  the  form  "@x,y",
+              where  x and y are window coordinates.  If the given coordinates
+              do not lie over a legend entry, "" is returned.
+
+   PEN COMPONENTS
+       Pens define attributes (both symbol and line style) for elements.  Pens
+       mirror  the  configuration options of data elements that pertain to how
+       symbols and lines are drawn.  Data elements use pens to  determine  how
+       they  are drawn.  A data element may use several pens at once.  In this
+       case, the pen used for a particular data point is determined from  each
+       element's weight vector (see the element's -weight and -style options).
+
+       One pen, called activeLine, is automatically created.  It's used as the
+       default  active  pen  for  elements.  So  you  can  change  the  active
+       attributes for all elements by simply reconfiguring this pen.   .g  pen
+       configure  "activeLine"  -color  green  You  can create and use several
+       pens. To create a pen, invoke the pen component and its  create  opera-
+       tion.   .g pen create myPen You map pens to a data element using either
+       the element's -pen or -activepen options.  .g  element  create  "line1"
+       -xdata $x -ydata $tempData \
+           -pen myPen An element can use several pens at once. This is done by
+       specifying the name of the pen in the element's  style  list  (see  the
+       -styles  option).  .g element configure "line1" -styles { myPen 2.0 3.0
+       } This says that any data point with a weight between 2.0 and 3.0 is to
+       be drawn using the pen myPen.  All other points are drawn with the ele-
+       ment's default attributes.
+
+              specified,  then  for each pair, the pen option option is set to
+              value.  The following options are valid for pens.
+
+              -color color
+                     Sets the color of the traces connecting the data  points.
+
+              -dashes dashList
+                     Sets  the  dash style of element line. DashList is a list
+                     of up  to  11  numbers  that  alternately  represent  the
+                     lengths of the dashes and gaps on the element line.  Each
+                     number must be between 1 and 255.  If dashList is "", the
+                     lines will be solid.
+
+              -fill color
+                     Sets the interior color of symbols.  If color is "", then
+                     the interior of the symbol is transparent.  If  color  is
+                     defcolor,  then  the color will be the same as the -color
+                     option.  The default is defcolor.
+
+              -linewidth pixels
+                     Sets the width  of  the  connecting  lines  between  data
+                     points.   If  pixels  is  0,  no connecting lines will be
+                     drawn between symbols.  The default is 0.
+
+              -offdash color
+                     Sets the color of the stripes when traces are dashed (see
+                     the -dashes option).  If color is "", then the "off" pix-
+                     els will represent gaps instead of stripes.  If color  is
+                     defcolor,  then  the color will be the same as the -color
+                     option.  The default is defcolor.
+
+              -outline color
+                     Sets the color or the outline  around  each  symbol.   If
+                     color  is  "", then no outline is drawn. If color is def-
+                     color, then the color will be  the  same  as  the  -color
+                     option.  The default is defcolor.
+
+              -outlinewidth pixels
+                     Sets  the width of the outline bordering each symbol.  If
+                     pixels is 0, no outline will be drawn. The default is  1.
+
+              -pixels pixels
+                     Sets  the  size  of  symbols.  If pixels is 0, no symbols
+                     will be drawn.  The default is 0.125i.
+
+              -symbol symbol
+                     Specifies the symbol for  data  points.   Symbol  can  be
+                     either  square,  circle,  diamond,  plus,  cross,  splus,
+                     scross, triangle, "" (where no symbol  is  drawn),  or  a
+                     bitmap.   Bitmaps are specified as "source ?mask?", where
+                     source is the name of the bitmap, and mask  is  the  bit-
+                     map's optional mask.  The default is circle.
+
+              Creates a new pen by the name penName.  No pen by the same  name
+              can  already  exist.  Option and value are described in above in
+              the pen configure operation.
+
+       pathName pen delete ?penName?...
+              Deletes the named pens. A pen is not really deleted until it  is
+              not  longer  in  use, so it's safe to delete pens mapped to ele-
+              ments.
+
+       pathName pen names ?pattern?...
+              Returns a list of pens matching zero or more  patterns.   If  no
+              pattern argument is give, the names of all pens are returned.
+
+   POSTSCRIPT COMPONENT
+       The  graph can generate encapsulated PostScript output.  There are sev-
+       eral configuration options you can specify to control how the plot will
+       be  generated.   You  can  change the page dimensions and borders.  The
+       plot itself can be scaled, centered,  or  rotated  to  landscape.   The
+       PostScript output can be written directly to a file or returned through
+       the interpreter.
+
+       The following postscript operations are available.
+
+       pathName postscript cget option
+              Returns the current value of  the  postscript  option  given  by
+              option.   Option may be any option described below for the post-
+              script configure operation.
+
+       pathName postscript configure ?option value?...
+              Queries or modifies the  configuration  options  for  PostScript
+              generation.   If  option  isn't specified, a list describing the
+              current postscript options for pathName is returned.  If  option
+              is  specified,  but  not value, then a list describing option is
+              returned.  If one or more option and value pairs are  specified,
+              then  for  each  pair,  the  postscript  option option is set to
+              value.  The following postscript options are available.
+
+              -center boolean
+                     Indicates whether the plot  should  be  centered  on  the
+                     PostScript  page.   If boolean is false, the plot will be
+                     placed in the upper left corner of the page.  The default
+                     is 1.
+
+              -colormap varName
+                     VarName  must be the name of a global array variable that
+                     specifies a color mapping from the X color name to  Post-
+                     Script.   Each  element  of varName must consist of Post-
+                     Script code to set a particular color value  (e.g.  ``1.0
+                     1.0  0.0  setrgbcolor'').  When generating color informa-
+                     tion in PostScript, the array variable varName is checked
+                     if  an element of the name as the color exists. If so, it
+                     uses its value as  the  PostScript  command  to  set  the
+                     Script.   Each  element  of varName must consist of a Tcl
+                     list with one or two elements; the name and point size of
+                     a  PostScript  font.  When outputting PostScript commands
+                     for a particular font,  the  array  variable  varName  is
+                     checked  to  see  if  an  element  by  the specified font
+                     exists.  If there is  such  an  element,  then  the  font
+                     information  contained  in  that  element  is used in the
+                     PostScript output.  (If the point size  is  omitted  from
+                     the  list, the point size of the X font is used).  Other-
+                     wise the X font is examined in an attempt to  guess  what
+                     PostScript  font to use.  This works only for fonts whose
+                     foundry property is  Adobe  (such  as  Times,  Helvetica,
+                     Courier,  etc.).   If  all  of  this  fails then the font
+                     defaults to Helvetica-Bold.
+
+              -decorations boolean
+                     Indicates whether PostScript commands to  generate  color
+                     backgrounds  and  3-D borders will be output.  If boolean
+                     is false, the background will be white and no 3-D borders
+                     will be generated. The default is 1.
+
+              -height pixels
+                     Sets  the  height  of  the plot.  This lets you print the
+                     graph with a height different from the one drawn  on  the
+                     screen.   If  pixels  is 0, the height is the same as the
+                     widget's height.  The default is 0.
+
+              -landscape boolean
+                     If boolean is true, this specifies the printed area is to
+                     be  rotated 90 degrees.  In non-rotated output the X-axis
+                     of the printed area runs along the short dimension of the
+                     page  (``portrait''  orientation);  in rotated output the
+                     X-axis runs along the long dimension of the page (``land-
+                     scape'' orientation).  Defaults to 0.
+
+              -maxpect boolean
+                     Indicates  to  scale  the plot so that it fills the Post-
+                     Script page.  The aspect ratio  of  the  graph  is  still
+                     retained.  The default is 0.
+
+              -padx pad
+                     Sets  the  horizontal padding for the left and right page
+                     borders.  The borders are exterior to the plot.  Pad  can
+                     be a list of one or two screen distances.  If pad has two
+                     elements, the left border is padded by the first distance
+                     and  the right border by the second.  If pad has just one
+                     distance, both the left  and  right  borders  are  padded
+                     evenly.  The default is 1i.
+
+              -pady pad
+                     Sets  the  vertical  padding  for the top and bottom page
+                     borders. The borders are exterior to the plot.   Pad  can
+                     The default width is 8.5i.
+
+              -width pixels
+                     Sets  the  width  of  the plot.  This lets you generate a
+                     plot of a width different from that of  the  widget.   If
+                     pixels is 0, the width is the same as the widget's width.
+                     The default is 0.
+
+              Postscript configuration options may  be  also  be  set  by  the
+              option  command.  The resource name and class are postscript and
+              Postscript respectively.  option  add  *Graph.postscript.Decora-
+              tions false option add *Graph.Postscript.Landscape   true
+
+       pathName postscript output ?fileName? ?option value?...
+              Outputs  a file of encapsulated PostScript.  If a fileName argu-
+              ment isn't present, the command returns the PostScript.  If  any
+              option-value  pairs  are present, they set configuration options
+              controlling how the PostScript is generated.  Option  and  value
+              can  be  anything accepted by the postscript configure operation
+              above.
+
+   MARKER COMPONENTS
+       Markers are simple drawing procedures used  to  annotate  or  highlight
+       areas of the graph.  Markers have various types: text strings, bitmaps,
+       images, connected lines, windows, or polygons.  They can be  associated
+       with  a  particular  element, so that when the element is hidden or un-
+       hidden, so is the marker.  By  default,  markers  are  the  last  items
+       drawn,  so  that  data  elements  will  appear in behind them.  You can
+       change this by configuring the -under option.
+
+       Markers, in contrast to elements, don't affect the scaling of the coor-
+       dinate axes.  They can also have elastic coordinates (specified by -Inf
+       and Inf respectively) that translate into the minimum or maximum  limit
+       of  the axis.  For example, you can place a marker so it always remains
+       in the lower left corner of the plotting area, by using the coordinates
+       -Inf,-Inf.
+
+       The following operations are available for markers.
+
+       pathName marker after markerId ?afterId?
+              Changes the order of the markers, drawing the first marker after
+              the second.  If no second afterId  argument  is  specified,  the
+              marker  is  placed at the end of the display list.  This command
+              can be used to control how markers are displayed  since  markers
+              are drawn in the order of this display list.
+
+       pathName marker before markerId ?beforeId?
+              Changes  the  order  of  the  markers,  drawing the first marker
+              before the second.  If no second beforeId argument is specified,
+              the marker is placed at the beginning of the display list.  This
+              command can be used to control how markers are  displayed  since
+              markers are drawn in the order of this display list.
+              with  tagName  and  sequence (it's an error occurs if there's no
+              such binding) is returned.  If both  command  and  sequence  are
+              missing  then  a list of all the event sequences for which bind-
+              ings have been defined for tagName.
+
+       pathName marker cget option
+              Returns the current value of  the  marker  configuration  option
+              given  by  option.   Option may be any option described below in
+              the configure operation.
+
+       pathName marker configure markerId ?option value?...
+              Queries or modifies the configuration options for  markers.   If
+              option  isn't  specified,  a list describing the current options
+              for markerId is returned.   If  option  is  specified,  but  not
+              value,  then  a  list  describing option is returned.  If one or
+              more option and value pairs are specified, then for  each  pair,
+              the marker option option is set to value.
+
+              The  following  options are valid for all markers.  Each type of
+              marker  also  has  its  own  type-specific  options.   They  are
+              described in the sections below.
+
+              -bindtags tagList
+                     Specifies  the binding tags for the marker.  TagList is a
+                     list of binding tag names.  The tags and their order will
+                     determine  how  events for markers are handled.  Each tag
+                     in the list matching the current event sequence will have
+                     its  Tcl  command  executed.   Implicitly the name of the
+                     marker is always the first tag in the list.  The  default
+                     value is all.
+
+              -coords coordList
+                     Specifies  the coordinates of the marker.  CoordList is a
+                     list of graph coordinates.   The  number  of  coordinates
+                     required  is  dependent  on  the  type  of marker.  Text,
+                     image, and window markers need only two  coordinates  (an
+                     X-Y  coordinate).   Bitmap markers can take either two or
+                     four coordinates (if four, they represent the corners  of
+                     the bitmap). Line markers need at least four coordinates,
+                     polygons at least six.  If coordList is  "",  the  marker
+                     will not be displayed.  The default is "".
+
+              -element elemName
+                     Links  the  marker with the element elemName.  The marker
+                     is drawn only if the element is also currently  displayed
+                     (see  the  element's show operation).  If elemName is "",
+                     the marker is always drawn.  The default is "".
+
+              -hide boolean
+                     Indicates whether the marker  is  drawn.  If  boolean  is
+                     true, the marker is not drawn.  The default is no.
+
+              -under boolean
+                     Indicates whether the marker is  drawn  below/above  data
+                     elements.   If  boolean  is  true, the marker is be drawn
+                     underneath the data element symbols  and  lines.   Other-
+                     wise,  the  marker  is  drawn on top of the element.  The
+                     default is 0.
+
+              -xoffset pixels
+                     Specifies a screen distance to offset the marker horizon-
+                     tally.   Pixels  is a valid screen distance, such as 2 or
+                     1.2i.  The default is 0.
+
+              -yoffset pixels
+                     Specifies a screen distance to offset the markers  verti-
+                     cally.   Pixels  is a valid screen distance, such as 2 or
+                     1.2i.  The default is 0.
+
+              Marker configuration options may also be set by the option  com-
+              mand.   The resource class is either BitmapMarker,  ImageMarker,
+              LineMarker, PolygonMarker, TextMarker, or WindowMarker,  depend-
+              ing on the type of marker.  The resource name is the name of the
+              marker.  option add  *Graph.TextMarker.Foreground  white  option
+              add     *Graph.BitmapMarker.Foreground    white    option    add
+              *Graph.m1.Background     blue
+
+       pathName marker create type ?option value?...
+              Creates a marker of the selected type. Type may be either  text,
+              line,  bitmap,  image, polygon, or window.  This command returns
+              the marker identifier, used as  the  markerId  argument  in  the
+              other  marker-related  commands.   If  the -name option is used,
+              this overrides the normal marker identifier.  If the  name  pro-
+              vided  is  already  used for another marker, the new marker will
+              replace the old.
+
+       pathName marker delete ?name?...
+              Removes one of more markers.  The graph  will  automatically  be
+              redrawn without the marker..
+
+       pathName marker exists markerId
+              Returns 1 if the marker markerId exists and 0 otherwise.
+
+       pathName marker names ?pattern?
+              Returns  the  names of all the markers that currently exist.  If
+              pattern is supplied, only those markers  whose  names  match  it
+              will be returned.
+
+       pathName marker type markerId
+              Returns  the  type of the marker given by markerId, such as line
+              or text.  If markerId is not a valid a marker identifier, ""  is
+              returned.
+
+   BITMAP MARKERS
+       The following options are specific to bitmap markers:
+
+       -background color
+              Same as the -fill option.
+
+       -bitmap bitmap
+              Specifies  the  bitmap  to  be  displayed.  If bitmap is "", the
+              marker will not be displayed.  The default is "".
+
+       -fill color
+              Sets the background color of the bitmap.  If color is the  empty
+              string,  no  background  will be transparent.  The default back-
+              ground color is "".
+
+       -foreground color
+              Same as the -outline option.
+
+       -mask mask
+              Specifies a mask for the bitmap to be displayed. This mask is  a
+              bitmap  itself,  denoting  the  pixels that are transparent.  If
+              mask is "", all pixels of the bitmap will be drawn.  The default
+              is "".
+
+       -outline color
+              Sets  the  foreground  color of the bitmap. The default value is
+              black.
+
+       -rotate theta
+              Sets the rotation of the bitmap.  Theta is a real number  repre-
+              senting  the  angle of rotation in degrees.  The marker is first
+              rotated and then placed according to its anchor  position.   The
+              default rotation is 0.0.
+
+   IMAGE MARKERS
+       A  image  marker displays an image.  Image markers are created with the
+       marker's create operation in the form:  pathName  marker  create  image
+       ?option  value?...   There  may be many option-value pairs, each sets a
+       configuration option for the marker.  These same option-value pairs may
+       be used with the marker's configure operation.
+
+       The following options are specific to image markers:
+
+       -anchor anchor
+              Anchor tells how to position the image relative to the position-
+              ing point for the image. For example, if anchor is  center  then
+              the  image  is  centered  on the point;  if anchor is n then the
+              image will be drawn such that the top center point of the  rect-
+              angular  region occupied by the image will be at the positioning
+              point.  This option defaults to center.
+
+       -image image
+              Specifies the image to be drawn.  If image  is  "",  the  marker
+              gaps  on  the  line.  Each number must be between 1 and 255.  If
+              dashList is "", the marker line will be solid.
+
+       -fill color
+              Sets the background color of the line.  This color is used  with
+              striped  lines  (see the -fdashes option). If color is the empty
+              string, no background color is drawn (the line will  be  dashed,
+              not striped).  The default background color is "".
+
+       -linewidth pixels
+              Sets the width of the lines.  The default width is 0.
+
+       -outline color
+              Sets  the  foreground  color  of  the line. The default value is
+              black.
+
+       -stipple bitmap
+              Specifies a stipple pattern used to draw the line, rather than a
+              solid  line.   Bitmap  specifies  a bitmap to use as the stipple
+              pattern.  If bitmap is "", then the line is  drawn  in  a  solid
+              fashion. The default is "".
+
+   POLYGON MARKERS
+       A polygon marker displays a closed region described as two or more con-
+       nected line segments.  It is assumed the first and last points are con-
+       nected.   Polygon markers are created using the marker create operation
+       in the form: pathName marker create polygon  ?option  value?...   There
+       may  be  many  option-value pairs, each sets a configuration option for
+       the marker.  These same option-value pairs may be used with the  marker
+       configure  command to change the marker's configuration.  The following
+       options are supported for polygon markers:
+
+       -dashes dashList
+              Sets the dash style of the outline of the polygon. DashList is a
+              list  of up to 11 numbers that alternately represent the lengths
+              of the dashes and gaps on the  outline.   Each  number  must  be
+              between  1  and  255.  If  dashList is "", the outline will be a
+              solid line.
+
+       -fill color
+              Sets the fill color of the polygon.  If color is  "",  then  the
+              interior of the polygon is transparent.  The default is white.
+
+       -linewidth pixels
+              Sets the width of the outline of the polygon. If pixels is zero,
+              no outline is drawn. The default is 0.
+
+       -outline color
+              Sets the color of the outline of the polygon.  If the polygon is
+              stippled  (see  the  -stipple  option), then this represents the
+              foreground color of the stipple.  The default is black.
+
+       the marker's configure operation.
+
+       The following options are specific to text markers:
+
+       -anchor anchor
+              Anchor tells how to position the text relative to the  position-
+              ing  point  for  the text. For example, if anchor is center then
+              the text is centered on the point; if anchor is n then the  text
+              will  be drawn such that the top center point of the rectangular
+              region occupied by the text will be at  the  positioning  point.
+              This default is center.
+
+       -background color
+              Same as the -fill option.
+
+       -font fontName
+              Specifies  the  font  of  the text.  The default is *-Helvetica-
+              Bold-R-Normal-*-120-*.
+
+       -fill color
+              Sets the background color of the text.  If color  is  the  empty
+              string,  no  background  will be transparent.  The default back-
+              ground color is "".
+
+       -foreground color
+              Same as the -outline option.
+
+       -justify justify
+              Specifies how the text should be justified.  This  matters  only
+              when  the  marker  contains  more than one line of text. Justify
+              must be left, right, or center.  The default is center.
+
+       -outline color
+              Sets the color of the text. The default value is black.
+
+       -padx pad
+              Sets the padding to the left and right exteriors  of  the  text.
+              Pad  can  be  a list of one or two screen distances.  If pad has
+              two elements, the left side of the text is padded by  the  first
+              distance  and the right side by the second.  If pad has just one
+              distance, both the left and right sides are padded evenly.   The
+              default is 4.
+
+       -pady pad
+              Sets the padding above and below the text.  Pad can be a list of
+              one or two screen distances.  If pad has two elements, the  area
+              above  the  text  is  padded  by the first distance and the area
+              below by the second.  If pad is just one distance, both the  top
+              and bottom areas are padded evenly.  The default is 4.
+
+       -rotate theta
+              Specifies  the number of degrees to rotate the text.  Theta is a
+
+       option-value pairs may be used with the marker's configure command.
+
+       The following options are specific to window markers:
+
+       -anchor anchor
+              Anchor tells how to position the widget relative  to  the  posi-
+              tioning  point  for the widget. For example, if anchor is center
+              then the widget is centered on the point; if anchor  is  n  then
+              the  widget  will be displayed such that the top center point of
+              the rectangular region occupied by the widget  will  be  at  the
+              positioning point.  This option defaults to center.
+
+       -height pixels
+              Specifies  the height to assign to the marker's window.  If this
+              option isn't specified, or if it is specified as  "",  then  the
+              window  is given whatever height the widget requests internally.
+
+       -width pixels
+              Specifies the width to assign to the marker's window.   If  this
+              option  isn't  specified,  or if it is specified as "", then the
+              window is given whatever width the widget requests internally.
+
+       -window pathName
+              Specifies the widget to be managed by the graph.  PathName  must
+              be a child of the graph widget.
+
+
+
+

GRAPH COMPONENT BINDINGS

+       Specific  graph  components,  such  as  elements,  markers  and  legend
+       entries, can have a command trigger when event  occurs  in  them,  much
+       like  canvas  items in Tk's canvas widget.  Not all event sequences are
+       valid.  The only binding events that may be specified are those related
+       to  the  mouse and keyboard (such as Enter, Leave, ButtonPress, Motion,
+       and KeyPress).
+
+       Only one element or marker can be picked during an event.  This  means,
+       that  if  the mouse is directly over both an element and a marker, only
+       the uppermost component  is  selected.   This  isn't  true  for  legend
+       entries.   Both  a legend entry and an element (or marker) binding com-
+       mands will be invoked if both items are picked.
+
+       It is possible for multiple bindings to match a particular event.  This
+       could occur, for example, if one binding is associated with the element
+       name and another is associated with one of the element's tags (see  the
+       -bindtags  option).  When this occurs, all of the matching bindings are
+       invoked.  A binding associated with the element name is invoked  first,
+       followed  by  one binding for each of the element's bindtags.  If there
+       are multiple matching bindings for a single tag,  then  only  the  most
+       specific  binding  is  invoked.  A continue command in a binding script
+       terminates that script, and a break command terminates that script  and
+       skips  any  remaining  scripts for the event, just as for the bind com-
+       mand.
+
+       vectors are updated.
+
+       From  Tcl,  create  the  vectors and configure the element to use them.
+       vector X Y .g element configure line1 -xdata X -ydata  Y  To  set  data
+       points  from  C,  you  pass  the  values as arrays of doubles using the
+       Blt_ResetVector call.  The vector is reset with the new data and at the
+       next  idle  point (when Tk re-enters its event loop), the graph will be
+       redrawn automatically.  #include <tcl.h> #include <blt.h>
+
+       register int i; Blt_Vector *xVec, *yVec; double x[50], y[50];
+
+       /* Get the BLT vectors "X" and "Y"  (created  above  from  Tcl)  */  if
+       ((Blt_GetVector(interp, "X", &xVec) != TCL_OK) ||
+           (Blt_GetVector(interp, "Y", &yVec) != TCL_OK)) {
+           return TCL_ERROR; }
+
+       for (i = 0; i < 50; i++) {
+           x[i] = i * 0.02;
+           y[i] = sin(x[i]); }
+
+       /*  Put  the data into BLT vectors */ if ((Blt_ResetVector(xVec, x, 50,
+       50, TCL_VOLATILE) != TCL_OK) ||
+           (Blt_ResetVector(yVec, y, 50, 50, TCL_VOLATILE) != TCL_OK)) {
+          return TCL_ERROR; } See the vector manual page for more details.
+
+
+
+

SPEED TIPS

+       There may be cases where the graph needs to be  drawn  and  updated  as
+       quickly  as possible.  If drawing speed becomes a big problem, here are
+       a few tips to speed up displays.
+
+       o Try to minimize the number of data points.  The more data points  the
+         looked at, the more work the graph must do.
+
+       o If your data is generated as floating point values, the time required
+         to convert the data values to and from ASCII strings can be  signifi-
+         cant,  especially when there any many data points.  You can avoid the
+         redundant string-to-decimal conversions using the C API to  BLT  vec-
+         tors.
+
+       o Data  elements  without  symbols  are drawn faster than with symbols.
+         Set the data element's -symbol option to none.  If you need  to  draw
+         symbols, try using the simple symbols such as splus and scross.
+
+       o Don't stipple or dash the element.  Solid lines are much faster.
+
+       o If  you update data elements frequently, try turning off the widget's
+         -bufferelements option.  When the graph is first displayed, it  draws
+         data  elements  into an internal pixmap.  The pixmap acts as a cache,
+         so that when the graph needs to be redrawn again, and the  data  ele-
+         ments or coordinate axes haven't changed, the pixmap is simply copied
+         to the screen.  This is especially useful when you are using  markers
+         to  highlight  points  and regions on the graph.  But if the graph is
+
+
+
+BLT                               BLT_VERSION                         graph(n)
+
+
+
+Man(1) output converted with +man2html +
+ + diff --git a/doc/graph.n b/doc/graph.n new file mode 100644 index 0000000..fbbbb9b --- /dev/null +++ b/doc/graph.n @@ -0,0 +1,2408 @@ +'\" +'\" Smithsonian Astrophysical Observatory, Cambridge, MA, USA +'\" This code has been modified under the terms listed below and is made +'\" available under the same terms. +'\" +'\" Copyright 1991-1998 by Bell Labs Innovations for Lucent Technologies. +'\" +'\" Permission to use, copy, modify, and distribute this software and its +'\" documentation for any purpose and without fee is hereby granted, provided +'\" that the above copyright notice appear in all copies and that both that the +'\" copyright notice and warranty disclaimer appear in supporting documentation, +'\" and that the names of Lucent Technologies any of their entities not be used +'\" in advertising or publicity pertaining to distribution of the software +'\" without specific, written prior permission. +'\" +'\" Lucent Technologies disclaims all warranties with regard to this software, +'\" including all implied warranties of merchantability and fitness. In no event +'\" shall Lucent Technologies be liable for any special, indirect or +'\" consequential damages or any damages whatsoever resulting from loss of use, +'\" data or profits, whether in an action of contract, negligence or other +'\" tortuous action, arising out of or in connection with the use or performance +'\" of this software. +'\" +'\" Graph widget created by Sani Nassif and George Howlett. +'\" +.TH graph n BLT_VERSION BLT "BLT Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +graph \- 2D graph for plotting X\-Y coordinate data. +.SH SYNOPSIS +\fBgraph\fI \fIpathName \fR?\fIoption value\fR?... +.BE +.SH DESCRIPTION +The \fBgraph\fR command creates a graph for plotting +two-dimensional data (X\-Y coordinates). It has many configurable +components: coordinate axes, elements, legend, grid lines, cross +hairs, etc. They allow you to customize the look and feel of the +graph. +.SH INTRODUCTION +The \fBgraph\fR command creates a new window for plotting +two-dimensional data (X\-Y coordinates). Data points are plotted in a +rectangular area displayed in the center of the new window. This is the +\fIplotting area\fR. The coordinate axes are drawn in the +margins around the plotting area. By default, the legend is displayed +in the right margin. The title is displayed in top margin. +.PP +The \fBgraph\fR widget is composed of several components: coordinate +axes, data elements, legend, grid, cross hairs, pens, postscript, and +annotation markers. +.TP 1i +\f(CWaxis\fR +The graph has four standard axes (\f(CWx\fR, \f(CWx2\fR, +\f(CWy\fR, and \f(CWy2\fR), but you can create and display any number +of axes. Axes control what region of data is +displayed and how the data is scaled. Each axis consists of the axis +line, title, major and minor ticks, and tick labels. Tick labels +display the value at each major tick. +.TP 1i +\f(CWcrosshairs\fR +Cross hairs are used to position the mouse pointer relative to the X +and Y coordinate axes. Two perpendicular lines, intersecting at the +current location of the mouse, extend across the plotting area to the +coordinate axes. +.TP 1i +\f(CWelement\fR +An element represents a set of data points. Elements can be plotted +with a symbol at each data point and lines connecting the points. +The appearance of the element, such as its symbol, line width, and +color is configurable. +.TP 1i +\f(CWgrid\fR +Extends the major and minor ticks of the X\-axis and/or Y\-axis across the +plotting area. +.TP 1i +\f(CWlegend\fR +The legend displays the name and symbol of each data element. +The legend can be drawn in any margin or in the plotting area. +.TP 1i +\f(CWmarker\fR +Markers are used annotate or highlight areas of the graph. For +example, you could use a polygon marker to fill an area under a +curve, or a text marker to label a particular data point. Markers +come in various forms: text strings, bitmaps, connected line +segments, images, polygons, or embedded widgets. +.TP 1i +\f(CWpen\fR +Pens define attributes (both symbol and line style) for elements. +Data elements use pens to specify how they should be drawn. A data +element may use many pens at once. Here, the particular pen +used for a data point is determined from each element's weight +vector (see the element's \fB\-weight\fR and \fB\-style\fR options). +.TP 1i +\f(CWpostscript\fR +The widget can generate encapsulated PostScript output. This component +has several options to configure how the PostScript is generated. +.SH SYNTAX +.DS +\fBgraph \fIpathName \fR?\fIoption value\fR?... +.DE +The \fBgraph\fR command creates a new window \fIpathName\fR and makes +it into a \fBgraph\fR widget. At the time this command is invoked, there +must not exist a window named \fIpathName\fR, but \fIpathName\fR's +parent must exist. Additional options may be specified on the +command line or in the option database to configure aspects of the +graph such as its colors and font. See the \fBconfigure\fR operation +below for the exact details about what \fIoption\fR and \fIvalue\fR +pairs are valid. +.PP +If successful, \fBgraph\fR returns the path name of the widget. It +also creates a new Tcl command by the same name. You can use this +command to invoke various operations that query or modify the graph. +The general form is: +.DS +\fIpathName \fIoperation\fR \fR?\fIarg\fR?... +.DE +Both \fIoperation\fR and its arguments determine the exact behavior of +the command. The operations available for the graph are described in +the +.SB "GRAPH OPERATIONS" +section. +.PP +The command can also be used to access components of the graph. +.DS +\fIpathName component operation\fR ?\fIarg\fR?... +.DE +The operation, now located after the name of the component, is the +function to be performed on that component. Each component has its own +set of operations that manipulate that component. They will be +described below in their own sections. +.SH EXAMPLE +The \fBgraph\fR command creates a new graph. +.CS +# Create a new graph. Plotting area is black. +graph .g \-plotbackground black +.CE +A new Tcl command \f(CW.g\fR is also created. This command can be used +to query and modify the graph. For example, to change the title of +the graph to "My Plot", you use the new command and the graph's +\fBconfigure\fR operation. +.CS +# Change the title. +\&.g configure \-title "My Plot" +.CE +A graph has several components. To access a particular component you +use the component's name. For example, to add data elements, you use +the new command and the \fBelement\fR component. +.CS +# Create a new element named "line1" +\&.g element create line1 \\ + \-xdata { 0.2 0.4 0.6 0.8 1.0 1.2 1.4 1.6 1.8 2.0 } \\ + \-ydata { 26.18 50.46 72.85 93.31 111.86 128.47 143.14 + 155.85 166.60 175.38 } +.CE +The element's X-Y coordinates are specified using lists of +numbers. Alternately, BLT vectors could be used to hold the X\-Y +coordinates. +.CS +# Create two vectors and add them to the graph. +vector xVec yVec +xVec set { 0.2 0.4 0.6 0.8 1.0 1.2 1.4 1.6 1.8 2.0 } +yVec set { 26.18 50.46 72.85 93.31 111.86 128.47 143.14 155.85 + 166.60 175.38 } +\&.g element create line1 \-xdata xVec \-ydata yVec +.CE +The advantage of using vectors is that when you modify one, the graph +is automatically redrawn to reflect the new values. +.CS +# Change the y coordinate of the first point. +set yVector(0) 25.18 +.CE +An element named \f(CWe1\fR is now created in \f(CW.b\fR. It +is automatically added to the display list of elements. You can +use this list to control in what order elements are displayed. +To query or reset the element display list, you use the element's +\fBshow\fR operation. +.CS +# Get the current display list +set elemList [.b element show] +# Remove the first element so it won't be displayed. +\&.b element show [lrange $elemList 0 end] +.CE +The element will be displayed by as many bars as there are data points +(in this case there are ten). The bars will be drawn centered at the +x-coordinate of the data point. All the bars will have the same +attributes (colors, stipple, etc). The width of each bar is by +default one unit. You can change this with using the \fB\-barwidth\fR +option. +.CS +# Change the X\-Y coordinates of the first point. +set xVec(0) 0.18 +set yVec(0) 25.18 +.CE +An element named \f(CWline1\fR is now created in \f(CW.g\fR. By +default, the element's label in the legend will be also \f(CWline1\fR. +You can change the label, or specify no legend entry, again using the +element's \fBconfigure\fR operation. +.CS +# Don't display "line1" in the legend. +\&.g element configure line1 \-label "" +.CE +You can configure more than just the element's label. An element has +many attributes such as symbol type and size, dashed or solid lines, +colors, line width, etc. +.CS +\&.g element configure line1 \-symbol square \-color red \\ + \-dashes { 2 4 2 } \-linewidth 2 \-pixels 2c +.CE +Four coordinate axes are automatically created: \f(CWx\fR, \f(CWx2\fR, +\f(CWy\fR, and \f(CWy2\fR. And by default, elements are mapped onto the +axes \f(CWx\fR and \f(CWy\fR. This can be changed with the \fB\-mapx\fR +and \fB\-mapy\fR options. +.CS +# Map "line1" on the alternate Y\-axis "y2". +\&.g element configure line1 \-mapy y2 +.CE +Axes can be configured in many ways too. For example, you change the +scale of the Y\-axis from linear to log using the \fBaxis\fR component. +.CS +# Y\-axis is log scale. +\&.g axis configure y \-logscale yes +.CE +One important way axes are used is to zoom in on a particular data +region. Zooming is done by simply specifying new axis limits using +the \fB\-min\fR and \fB\-max\fR configuration options. +.CS +\&.g axis configure x \-min 1.0 \-max 1.5 +\&.g axis configure y \-min 12.0 \-max 55.15 +.CE +To zoom interactively, you link the \fBaxis configure\fR operations with +some user interaction (such as pressing the mouse button), using the +\fBbind\fR command. To convert between screen and graph coordinates, +use the \fBinvtransform\fR operation. +.CS +# Click the button to set a new minimum +bind .g { + %W axis configure x \-min [%W axis invtransform x %x] + %W axis configure x \-min [%W axis invtransform x %y] +} +.CE +By default, the limits of the axis are determined from data values. +To reset back to the default limits, set the \fB\-min\fR and +\fB\-max\fR options to the empty value. +.CS +# Reset the axes to autoscale again. +\&.g axis configure x \-min {} \-max {} +\&.g axis configure y \-min {} \-max {} +.CE +By default, the legend is drawn in the right margin. You can +change this or any legend configuration options using the +\fBlegend\fR component. +.CS +# Configure the legend font, color, and relief +\&.g legend configure \-position left \-relief raised \\ + \-font fixed \-fg blue +.CE +To prevent the legend from being displayed, turn on the \fB\-hide\fR +option. +.CS +# Don't display the legend. +\&.g legend configure \-hide yes\fR +.CE +The \fBgraph\fR widget has simple drawing procedures called markers. +They can be used to highlight or annotate data in the graph. The types +of markers available are bitmaps, images, polygons, lines, or windows. +Markers can be used, for example, to mark or brush points. In this +example, is a text marker that labels the data first point. Markers +are created using the \fBmarker\fR component. +.CS +# Create a label for the first data point of "line1". +\&.g marker create text \-name first_marker \-coords { 0.2 26.18 } \\ + \-text "start" \-anchor se \-xoffset -10 \-yoffset -10 +.CE +This creates a text marker named \f(CWfirst_marker\fR. It will display +the text "start" near the coordinates of the first data point. The +\fB\-anchor\fR, \fB\-xoffset\fR, and \fB\-yoffset\fR options are used +to display the marker above and to the left of the data point, so that +the data point isn't covered by the marker. By default, +markers are drawn last, on top of data. You can change this with the +\fB\-under\fR option. +.CS +# Draw the label before elements are drawn. +\&.g marker configure first_marker \-under yes +.CE +You can add cross hairs or grid lines using the \fBcrosshairs\fR and +\fBgrid\fR components. +.CS +# Display both cross hairs and grid lines. +\&.g crosshairs configure \-hide no \-color red +\&.g grid configure \-hide no \-dashes { 2 2 } +# Set up a binding to reposition the crosshairs. +bind .g { + .g crosshairs configure -position @%x,%y +} +.CE +The crosshairs are repositioned as the mouse pointer is moved +in the graph. The pointer X-Y coordinates define the center +of the crosshairs. +.PP +Finally, to get hardcopy of the graph, use the \fBpostscript\fR +component. +.CS +# Print the graph into file "file.ps" +\&.g postscript output file.ps \-maxpect yes \-decorations no +.CE +This generates a file \f(CWfile.ps\fR containing the encapsulated +PostScript of the graph. The option \fB\-maxpect\fR says to scale the +plot to the size of the page. Turning off the \fB\-decorations\fR +option denotes that no borders or color backgrounds should be +drawn (i.e. the background of the margins, legend, and plotting +area will be white). +.SH "GRAPH OPERATIONS" +.TP +\fIpathName \fBaxis \fIoperation \fR?\fIarg\fR?... +See the +.SB "AXIS COMPONENTS" +section. +.TP +\fIpathName \fBbar \fIelemName \fR?\fIoption value\fR?... +Creates a new barchart element \fIelemName\fR. It's an +error if an element \fIelemName\fR already exists. +See the manual for \fBbarchart\fR for details about +what \fIoption\fR and \fIvalue\fR pairs are valid. +.TP +\fIpathName \fBcget\fR \fIoption\fR +Returns the current value of the configuration option given by +\fIoption\fR. \fIOption\fR may be any option described +below for the \fBconfigure\fR operation. +.TP +\fIpathName \fBconfigure \fR?\fIoption value\fR?... +Queries or modifies the configuration options of the graph. If +\fIoption\fR isn't specified, a list describing the current +options for \fIpathName\fR is returned. If \fIoption\fR is specified, +but not \fIvalue\fR, then a list describing \fIoption\fR is returned. +If one or more \fIoption\fR and \fIvalue\fR pairs are specified, then +for each pair, the option \fIoption\fR is set to \fIvalue\fR. +The following options are valid. +.RS +.TP +\fB\-aspect \fIwidth/height\fR +Force a fixed aspect ratio of \fIwidth/height\fR, a floating point number. +.TP +\fB\-background \fIcolor\fR +Sets the background color. This includes the margins and +legend, but not the plotting area. +.TP +\fB\-borderwidth \fIpixels\fR +Sets the width of the 3\-D border around the outside edge of the widget. The +\fB\-relief\fR option determines if the border is to be drawn. The +default is \f(CW2\fR. +.TP +\fB\-bottommargin \fIpixels\fR +If non-zero, overrides the computed size of the margin extending +below the X\-coordinate axis. +If \fIpixels\fR is \f(CW0\fR, the automatically computed size is used. +The default is \f(CW0\fR. +.TP +\fB\-bufferelements \fIboolean\fR +Indicates whether an internal pixmap to buffer the display of data +elements should be used. If \fIboolean\fR is true, data elements are +drawn to an internal pixmap. This option is especially useful when +the graph is redrawn frequently while the remains data unchanged (for +example, moving a marker across the plot). See the +.SB "SPEED TIPS" +section. +The default is \f(CW1\fR. +.TP +\fB\-cursor \fIcursor\fR +Specifies the widget's cursor. The default cursor is \f(CWcrosshair\fR. +.TP +\fB\-font \fIfontName\fR +Specifies the font of the graph title. The default is +\f(CW*-Helvetica-Bold-R-Normal-*-18-180-*\fR. +.TP +\fB\-halo \fIpixels\fR +Specifies a maximum distance to consider when searching for the +closest data point (see the element's \fBclosest\fR operation below). +Data points further than \fIpixels\fR away are ignored. The default is +\f(CW0.5i\fR. +.TP +\fB\-height \fIpixels\fR +Specifies the requested height of widget. The default is +\f(CW4i\fR. +.TP +\fB\-invertxy \fIboolean\fR +Indicates whether the placement X\-axis and Y\-axis should be inverted. If +\fIboolean\fR is true, the X and Y axes are swapped. The default is +\f(CW0\fR. +.TP +\fB\-justify \fIjustify\fR +Specifies how the title should be justified. This matters only when +the title contains more than one line of text. \fIJustify\fR must be +\f(CWleft\fR, \f(CWright\fR, or \f(CWcenter\fR. The default is +\f(CWcenter\fR. +.TP +\fB\-leftmargin \fIpixels\fR +If non-zero, overrides the computed size of the margin extending +from the left edge of the window to the Y\-coordinate axis. +If \fIpixels\fR is \f(CW0\fR, the automatically computed size is used. +The default is \f(CW0\fR. +.TP +\fB\-plotbackground \fIcolor\fR +Specifies the background color of the plotting area. The default is +\f(CWwhite\fR. +.TP +\fB\-plotborderwidth \fIpixels\fR +Sets the width of the 3-D border around the plotting area. The +\fB\-plotrelief\fR option determines if a border is drawn. The +default is \f(CW2\fR. +.TP +\fB\-plotpadx \fIpad\fR +Sets the amount of padding to be added to the left and right sides of +the plotting area. \fIPad\fR can be a list of one or two screen +distances. If \fIpad\fR has two elements, the left side of the +plotting area entry is padded by the first distance and the right side +by the second. If \fIpad\fR is just one distance, both the left and +right sides are padded evenly. The default is \f(CW8\fR. +.TP +\fB\-plotpady \fIpad\fR +Sets the amount of padding to be added to the top and bottom of the +plotting area. \fIPad\fR can be a list of one or two screen +distances. If \fIpad\fR has two elements, the top of the plotting +area is padded by the first distance and the bottom by the second. If +\fIpad\fR is just one distance, both the top and bottom are padded +evenly. The default is \f(CW8\fR. +.TP +\fB\-plotrelief \fIrelief\fR +Specifies the 3-D effect for the plotting area. \fIRelief\fR +specifies how the interior of the plotting area should appear relative +to rest of the graph; for example, \f(CWraised\fR means the plot should +appear to protrude from the graph, relative to the surface of the +graph. The default is \f(CWsunken\fR. +.TP +\fB\-relief \fIrelief\fR +Specifies the 3-D effect for the graph widget. \fIRelief\fR +specifies how the graph should appear relative to widget it is packed +into; for example, \f(CWraised\fR means the graph should +appear to protrude. The default is \f(CWflat\fR. +.TP +\fB\-rightmargin \fIpixels\fR +If non-zero, overrides the computed size of the margin extending +from the plotting area to the right edge of +the window. By default, the legend is drawn in this margin. +If \fIpixels\fR is \f(CW0\fR, the automatically computed size is used. +The default is \f(CW0\fR. +.TP +\fB\-takefocus\fR \fIfocus\fR +Provides information used when moving the focus from window to window +via keyboard traversal (e.g., Tab and Shift-Tab). If \fIfocus\fR is +\f(CW0\fR, this means that this window should be skipped entirely during +keyboard traversal. \f(CW1\fR means that the this window should always +receive the input focus. An empty value means that the traversal +scripts make the decision whether to focus on the window. +The default is \f(CW""\fR. +.TP +\fB\-tile \fIimage\fR +Specifies a tiled background for the widget. If \fIimage\fR isn't +\f(CW""\fR, the background is tiled using \fIimage\fR. +Otherwise, the normal background color is drawn (see the +\fB\-background\fR option). \fIImage\fR must be an image created +using the Tk \fBimage\fR command. The default is \f(CW""\fR. +.TP +\fB\-title \fItext\fR +Sets the title to \fItext\fR. If \fItext\fR is \f(CW""\fR, +no title will be displayed. +.TP +\fB\-topmargin \fIpixels\fR +If non-zero, overrides the computed size of the margin above the x2 +axis. If \fIpixels\fR is \f(CW0\fR, the automatically computed size +is used. The default is \f(CW0\fR. +.TP +\fB\-width \fIpixels\fR +Specifies the requested width of the widget. The default is +\f(CW5i\fR. +.RE +.TP +\fIpathName \fBcrosshairs \fIoperation \fR?\fIarg\fR? +See the +.SB "CROSSHAIRS COMPONENT" +section. +.TP +\fIpathName \fBelement \fIoperation \fR?\fIarg\fR?... +See the +.SB "ELEMENT COMPONENTS" +section. +.TP +\fIpathName \fBextents \fIitem\fR +Returns the size of a particular item in the graph. \fIItem\fR must +be either \f(CWleftmargin\fR, \f(CWrightmargin\fR, \f(CWtopmargin\fR, +\f(CWbottommargin\fR, \f(CWplotwidth\fR, or \f(CWplotheight\fR. +.TP +\fIpathName \fBgrid \fIoperation \fR?\fIarg\fR?... +See the +.SB "GRID COMPONENT" +section. +.TP +\fIpathName \fBinvtransform \fIwinX winY\fR +Performs an inverse coordinate transformation, mapping window +coordinates back to graph coordinates, using the standard X\-axis and Y\-axis. +Returns a list of containing the X-Y graph coordinates. +.TP +\fIpathName \fBinside \fIx y\fR +Returns \f(CW1\fR is the designated screen coordinate (\fIx\fR and \fIy\fR) +is inside the plotting area and \f(CW0\fR otherwise. +.TP +\fIpathName \fBlegend \fIoperation \fR?\fIarg\fR?... +See the +.SB "LEGEND COMPONENT" +section. +.TP +\fIpathName \fBline\fB operation arg\fR... +The operation is the same as \fBelement\fR. +.TP +\fIpathName \fBmarker \fIoperation \fR?\fIarg\fR?... +See the +.SB "MARKER COMPONENTS" +section. +.TP +\fIpathName \fBpostscript \fIoperation \fR?\fIarg\fR?... +See the +.SB "POSTSCRIPT COMPONENT" +section. +.TP +\fIpathName \fBsnap \fR?\fIswitches\fR? \fIoutputName\fR +Takes a snapshot of the graph, saving the output in \fIoutputName\fR. +The following switches are available. +.RS +.TP 1i +\fB\-format\fR \fIformat\fR +Specifies how the snapshot is output. \fIFormat\fR may be one of +the following listed below. The default is \f(CWphoto\fR. +.RS +.TP +\f(CWphoto\fR +Saves a Tk photo image. \fIOutputName\fR represents the name of a +Tk photo image that must already have been created. +.TP +\f(CWwmf\fR +Saves an Aldus Placeable Metafile. \fIOutputName\fR represents the +filename where the metafile is written. If \fIoutputName\fR is +\f(CWCLIPBOARD\fR, then output is written directly to the Windows +clipboard. This format is available only under Microsoft Windows. +.TP +\f(CWemf\fR +Saves an Enhanced Metafile. \fIOutputName\fR represents the filename +where the metafile is written. If \fIoutputName\fR is +\f(CWCLIPBOARD\fR, then output is written directly to the Windows +clipboard. This format is available only under Microsoft Windows. +.RE +.TP 1i +\fB\-height\fR \fIsize\fR +Specifies the height of the graph. \fISize\fR is a screen distance. +The graph will be redrawn using this dimension, rather than its +current window height. +.TP 1i +\fB\-width\fR \fIsize\fR +Specifies the width of the graph. \fISize\fR is a screen distance. +The graph will be redrawn using this dimension, rather than its +current window width. +.RE +.TP +\fIpathName \fBtransform \fIx y\fR +Performs a coordinate transformation, mapping graph coordinates to +window coordinates, using the standard X\-axis and Y\-axis. +Returns a list containing the X\-Y screen coordinates. +.TP +\fIpathName \fBxaxis \fIoperation\fR ?\fIarg\fR?... +.TP +\fIpathName \fBx2axis \fIoperation\fR ?\fIarg\fR?... +.TP +\fIpathName \fByaxis \fIoperation\fR ?\fIarg\fR?... +.TP +\fIpathName \fBy2axis \fIoperation\fR ?\fIarg\fR?... +See the +.SB "AXIS COMPONENTS" +section. +.SH "GRAPH COMPONENTS" +A graph is composed of several components: coordinate axes, data +elements, legend, grid, cross hairs, postscript, and annotation +markers. Instead of one big set of configuration options and +operations, the graph is partitioned, where each component has its own +configuration options and operations that specifically control that +aspect or part of the graph. +.SS "AXIS COMPONENTS" +Four coordinate axes are automatically created: two X\-coordinate axes +(\f(CWx\fR and \f(CWx2\fR) and two Y\-coordinate axes (\f(CWy\fR, and +\f(CWy2\fR). By default, the axis \f(CWx\fR is located in the bottom +margin, \f(CWy\fR in the left margin, \f(CWx2\fR in the top margin, and +\f(CWy2\fR in the right margin. +.PP +An axis consists of the axis line, title, major and minor ticks, and +tick labels. Major ticks are drawn at uniform intervals along the +axis. Each tick is labeled with its coordinate value. Minor ticks +are drawn at uniform intervals within major ticks. +.PP +The range of the axis controls what region of data is plotted. +Data points outside the minimum and maximum limits of the axis are +not plotted. By default, the minimum and maximum limits are +determined from the data, but you can reset either limit. +.PP +You can have several axes. To create an axis, invoke +the axis component and its create operation. +.CS +# Create a new axis called "tempAxis" +\&.g axis create tempAxis +.CE +You map data elements to an axis using the element's \-mapy and \-mapx +configuration options. They specify the coordinate axes an element +is mapped onto. +.CS +# Now map the tempAxis data to this axis. +\&.g element create "e1" \-xdata $x \-ydata $y \-mapy tempAxis +.CE +Any number of axes can be displayed simultaneously. They are drawn in +the margins surrounding the plotting area. The default axes \f(CWx\fR +and \f(CWy\fR are drawn in the bottom and left margins. The axes +\f(CWx2\fR and \f(CWy2\fR are drawn in top and right margins. By +default, only \f(CWx\fR and \f(CWy\fR are shown. Note that the axes +can have different scales. +.PP +To display a different axis or more than one axis, you invoke one of +the following components: \fBxaxis\fR, \fByaxis\fR, \fBx2axis\fR, and +\fBy2axis\fR. Each component has a \fBuse\fR operation that +designates the axis (or axes) to be drawn in that corresponding +margin: \fBxaxis\fR in the bottom, \fByaxis\fR in the left, +\fBx2axis\fR in the top, and \fBy2axis\fR in the right. +.CS +# Display the axis tempAxis in the left margin. +\&.g yaxis use tempAxis +.CE +The \fBuse\fR operation takes a list of axis names as its last +argument. This is the list of axes to be drawn in this margin. +.PP +You can configure axes in many ways. The axis scale can be linear or +logarithmic. The values along the axis can either monotonically +increase or decrease. If you need custom tick labels, you can specify +a Tcl procedure to format the label any way you wish. You can control +how ticks are drawn, by changing the major tick interval or the number +of minor ticks. You can define non-uniform tick intervals, such as +for time-series plots. +.PP +.TP +\fIpathName \fBaxis bind \fItagName\fR ?\fIsequence\fR? ?\fIcommand\fR? +Associates \fIcommand\fR with \fItagName\fR such that whenever the +event sequence given by \fIsequence\fR occurs for an axis with this +tag, \fIcommand\fR will be invoked. The syntax is similar to the +\fBbind\fR command except that it operates on graph axes, rather +than widgets. See the \fBbind\fR manual entry for +complete details on \fIsequence\fR and the substitutions performed on +\fIcommand\fR before invoking it. +.sp +If all arguments are specified then a new binding is created, replacing +any existing binding for the same \fIsequence\fR and \fItagName\fR. +If the first character of \fIcommand\fR is \f(CW+\fR then \fIcommand\fR +augments an existing binding rather than replacing it. +If no \fIcommand\fR argument is provided then the command currently +associated with \fItagName\fR and \fIsequence\fR (it's an error occurs +if there's no such binding) is returned. If both \fIcommand\fR and +\fIsequence\fR are missing then a list of all the event sequences for +which bindings have been defined for \fItagName\fR. +.TP +\fIpathName \fBaxis \fBcget \fIaxisName \fIoption\fR +Returns the current value of the option given by \fIoption\fR for +\fIaxisName\fR. \fIOption\fR may be any option described below +for the axis \fBconfigure\fR operation. +.TP +\fIpathName \fBaxis \fBconfigure \fIaxisName \fR?\fIaxisName\fR?... ?\fIoption value\fR?... +Queries or modifies the configuration options of \fIaxisName\fR. +Several axes can be changed. If \fIoption\fR isn't specified, a list +describing all the current options for \fIaxisName\fR is returned. If +\fIoption\fR is specified, but not \fIvalue\fR, then a list describing +\fIoption\fR is returned. If one or more \fIoption\fR and \fIvalue\fR +pairs are specified, then for each pair, the axis option \fIoption\fR +is set to \fIvalue\fR. The following options are valid for axes. +.RS +.TP +\fB\-bindtags \fItagList\fR +Specifies the binding tags for the axis. \fITagList\fR is a list +of binding tag names. The tags and their order will determine how +events for axes are handled. Each tag in the list matching the current event +sequence will have its Tcl command executed. Implicitly the name of +the element is always the first tag in the list. The default value is +\f(CWall\fR. +.TP +\fB\-color \fIcolor\fR +Sets the color of the axis and tick labels. +The default is \f(CWblack\fR. +.TP +\fB\-descending \fIboolean\fR +Indicates whether the values along the axis are monotonically increasing or +decreasing. If \fIboolean\fR is true, the axis values will be +decreasing. The default is \f(CW0\fR. +.TP +\fB\-hide \fIboolean\fR +Indicates if the axis is displayed. If \fIboolean\fR is false the axis +will be displayed. Any element mapped to the axis is displayed regardless. +The default value is \f(CW0\fR. +.TP +\fB\-justify \fIjustify\fR +Specifies how the axis title should be justified. This matters only +when the axis title contains more than one line of text. \fIJustify\fR +must be \f(CWleft\fR, \f(CWright\fR, or \f(CWcenter\fR. The default is +\f(CWcenter\fR. +.TP +\fB\-limits \fIformatStr\fR +Specifies a printf-like description to format the minimum and maximum +limits of the axis. The limits are displayed at the top/bottom or +left/right sides of the plotting area. \fIFormatStr\fR is a list of +one or two format descriptions. If one description is supplied, both +the minimum and maximum limits are formatted in the same way. If two, +the first designates the format for the minimum limit, the second for +the maximum. If \f(CW""\fR is given as either description, then +the that limit will not be displayed. The default is \f(CW""\fR. +.TP +\fB\-linewidth \fIpixels\fR +Sets the width of the axis and tick lines. The default is \f(CW1\fR +pixel. +.TP +\fB\-logscale \fIboolean\fR +Indicates whether the scale of the axis is logarithmic or linear. If +\fIboolean\fR is true, the axis is logarithmic. The default scale is +linear. +.TP +\fB\-loose \fIboolean\fR +Indicates whether the limits of the axis should fit the data points tightly, +at the outermost data points, or loosely, at the outer tick intervals. +If the axis limit is set with the -min or -max option, the axes are +displayed tightly. +If \fIboolean\fR is true, the axis range is "loose". +The default is \f(CW0\fR. +.TP +\fB\-majorticks \fImajorList\fR +Specifies where to display major axis ticks. You can use this option +to display ticks at non-uniform intervals. \fIMajorList\fR is a list +of axis coordinates designating the location of major ticks. No +minor ticks are drawn. If \fImajorList\fR is \f(CW""\fR, +major ticks will be automatically computed. The default is \f(CW""\fR. +.TP +\fB\-max \fIvalue\fR +Sets the maximum limit of \fIaxisName\fR. Any data point greater +than \fIvalue\fR is not displayed. If \fIvalue\fR is \f(CW""\fR, +the maximum limit is calculated using the largest data value. +The default is \f(CW""\fR. +.TP +\fB\-min \fIvalue\fR +Sets the minimum limit of \fIaxisName\fR. Any data point less than +\fIvalue\fR is not displayed. If \fIvalue\fR is \f(CW""\fR, +the minimum limit is calculated using the smallest data value. +The default is \f(CW""\fR. +.TP +\fB\-minorticks \fIminorList\fR +Specifies where to display minor axis ticks. You can use this option +to display minor ticks at non-uniform intervals. \fIMinorList\fR is a +list of real values, ranging from 0.0 to 1.0, designating the placement of +a minor tick. No minor ticks are drawn if the \fB\-majortick\fR +option is also set. If \fIminorList\fR is \f(CW""\fR, minor ticks will +be automatically computed. The default is \f(CW""\fR. +.TP +\fB\-rotate \fItheta\fR +Specifies the how many degrees to rotate the axis tick labels. +\fITheta\fR is a real value representing the number of degrees +to rotate the tick labels. The default is \f(CW0.0\fR degrees. +.TP +\fB\-scrollcommand \fIcommand\fR +Specify the prefix for a command used to communicate with scrollbars +for this axis, such as \fI.sbar set\fP. +.TP +\fB\-scrollmax \fIvalue\fR +Sets the maximum limit of the axis scroll region. If \fIvalue\fR is +\f(CW""\fR, the maximum limit is calculated using the largest data +value. The default is \f(CW""\fR. +.TP +\fB\-scrollmin \fIvalue\fR +Sets the minimum limit of axis scroll region. If \fIvalue\fR is +\f(CW""\fR, the minimum limit is calculated using the smallest data +value. The default is \f(CW""\fR. +.TP +\fB\-showticks \fIboolean\fR +Indicates whether axis ticks should be drawn. If \fIboolean\fR is +true, ticks are drawn. If false, only the +axis line is drawn. The default is \f(CW1\fR. +.TP +\fB\-stepsize \fIvalue\fR +Specifies the interval between major axis ticks. If \fIvalue\fR isn't +a valid interval (must be less than the axis range), +the request is ignored and the step size is automatically calculated. +.TP +\fB\-subdivisions \fInumber\fR +Indicates how many minor axis ticks are +to be drawn. For example, if \fInumber\fR is two, only one minor +tick is drawn. If \fInumber\fR is one, no minor ticks are +displayed. The default is \f(CW2\fR. +.TP +\fB\-tickfont \fIfontName\fR +Specifies the font for axis tick labels. The default is +\f(CW*-Courier-Bold-R-Normal-*-100-*\fR. +.TP +\fB\-tickformat\fR \fIformatStr\fR +Specifies a printf-like description to format teh axis +tick labels. You can get the standard tick labels again by +setting \fIformatStr\fR to \f(CW""\fR. The default is \f(CW""\fR. +.TP +\fB\-tickformatcommand\fR, \fB\-command \fIprefix\fR +Specifies a Tcl command to be invoked when formatting the axis tick +labels. \fIPrefix\fR is a string containing the name of a Tcl proc and +any extra arguments for the procedure. This command is invoked for each +major tick on the axis. Two additional arguments are passed to the +procedure: the pathname of the widget and the current the numeric +value of the tick. The procedure returns the formatted tick label. If +\f(CW""\fR is returned, no label will appear next to the tick. You can +get the standard tick labels again by setting \fIprefix\fR to +\f(CW""\fR. The default is \f(CW""\fR. +.sp 1 +The numeric value for the tick might change when using the +\fB\-logscale\fR and \fB\-tickformat\fR options. +.sp 1 +Please note that this procedure is invoked while the graph is redrawn. +You may query configuration options. But do not them, because this +can have unexpected results. +.TP +\fB\-ticklength \fIpixels\fR +Sets the length of major and minor ticks (minor ticks are half the +length of major ticks). If \fIpixels\fR is less than zero, the axis +will be inverted with ticks drawn pointing towards the plot. The +default is \f(CW0.1i\fR. +.TP +\fB\-title \fItext\fR +Sets the title of the axis. If \fItext\fR is +\f(CW""\fR, no axis title will be displayed. +.TP +\fB\-titlealternate \fIboolean\fR +Indicates to display the axis title in its alternate location. +Normally the axis title is centered along the axis. This option +places the axis either to the right (horizontal axes) or above +(vertical axes) the axis. The default is \f(CW0\fR. +.TP +\fB\-titlecolor \fIcolor\fR +Sets the color of the axis title. The default is \f(CWblack\fR. +.TP +\fB\-titlefont \fIfontName\fR +Specifies the font for axis title. The default is +\f(CW*-Helvetica-Bold-R-Normal-*-14-140-*\fR. +.PP +Axis configuration options may be also be set by the \fBoption\fR +command. The resource class is \f(CWAxis\fR. The resource names +are the names of the axes (such as \f(CWx\fR or \f(CWx2\fR). +.CS +option add *Graph.Axis.Color blue +option add *Graph.x.LogScale true +option add *Graph.x2.LogScale false +.CE +.RE +.TP +\fIpathName \fBaxis \fBcreate \fIaxisName \fR?\fIoption value\fR?... +Creates a new axis by the name \fIaxisName\fR. No axis by the same +name can already exist. \fIOption\fR and \fIvalue\fR are described +in above in the axis \fBconfigure\fR operation. +.TP +\fIpathName \fBaxis \fBdelete \fR?\fIaxisName\fR?... +Deletes the named axes. An axis is not really +deleted until it is not longer in use, so it's safe to delete +axes mapped to elements. +.TP +\fIpathName \fBaxis invtransform \fIaxisName value\fR +Performs the inverse transformation, changing the screen coordinate +\fIvalue\fR to a graph coordinate, mapping the value mapped to +\fIaxisName\fR. Returns the graph coordinate. +.TP +\fIpathName \fBaxis limits \fIaxisName\fR +Returns a list of the minimum and maximum limits for \fIaxisName\fR. The order +of the list is \f(CWmin max\fR. +.TP +\fIpathName \fBaxis names \fR?\fIpattern\fR?... +Returns a list of axes matching zero or more patterns. If no +\fIpattern\fR argument is give, the names of all axes are returned. +.TP +\fIpathName \fBaxis transform \fIaxisName value\fR +Transforms the coordinate \fIvalue\fR to a screen coordinate by mapping +the it to \fIaxisName\fR. Returns the transformed screen coordinate. +.TP +\fIpathName \fBaxis view \fIaxisName\fR +Change the viewable area of this axis. Use as an argument to a scrollbar's "\fI\-command\fR". +.PP +The default axes are \f(CWx\fR, \f(CWy\fR, \f(CWx2\fR, and \f(CWy2\fR. +But you can display more than four axes simultaneously. You can also +swap in a different axis with \fBuse\fR operation of the special axis +components: \fBxaxis\fR, \fBx2axis\fR, \fByaxis\fR, and \fBy2axis\fR. +.CS +\&.g create axis temp +\&.g create axis time +\&... +\&.g xaxis use temp +\&.g yaxis use time +.CE +Only the axes specified for use are displayed on the screen. +.PP +The \fBxaxis\fR, \fBx2axis\fR, \fByaxis\fR, and \fBy2axis\fR +components operate on an axis location rather than a specific axis +like the more general \fBaxis\fR component does. They implicitly +control the axis that is currently using to that location. By +default, \fBxaxis\fR uses the \f(CWx\fR axis, \fByaxis\fR uses +\f(CWy\fR, \fBx2axis\fR uses \f(CWx2\fR, and \fBy2axis\fR uses +\f(CWy2\fR. When more than one axis is displayed in a margin, it +represents the first axis displayed. +.PP +The following operations are available for axes. They mirror exactly +the operations of the \fBaxis\fR component. The \fIaxis\fR argument +must be \fBxaxis\fR, \fBx2axis\fR, \fByaxis\fR, or \fBy2axis\fR. This +feature is deprecated since more than one axis can now be used a +margin. You should only use the \fBxaxis\fR, \fBx2axis\fR, +\fByaxis\fR, and \fBy2axis\fR components with the \fBuse\fR operation. +For all other operations, use the general \fBaxis\fR component +instead. +.TP +\fIpathName \fIaxis \fBcget \fIoption\fR +.TP +\fIpathName \fIaxis \fBconfigure \fR?\fIoption value\fR?... +.TP +\fIpathName \fIaxis\fB invtransform \fIvalue\fR +.TP +\fIpathName \fIaxis \fBlimits\fR +.TP +\fIpathName \fIaxis\fB transform \fIvalue\fR +.TP +\fIpathName \fIaxis\fB use \fR?\fIaxisName\fR? +Designates the axis \fIaxisName\fR is to be displayed at this +location. \fIAxisName\fR can not be already in use at another location. +This command returns the name of the axis currently using this location. +.SS "CROSSHAIRS COMPONENT" +Cross hairs consist of two intersecting lines (one vertical and one horizontal) +drawn completely across the plotting area. They are used to position +the mouse in relation to the coordinate axes. Cross hairs differ from line +markers in that they are implemented using XOR drawing primitives. +This means that they can be quickly drawn and erased without redrawing +the entire graph. +.PP +The following operations are available for cross hairs: +.TP +\fIpathName \fBcrosshairs cget \fIoption\fR +Returns the current value of the cross hairs configuration option +given by \fIoption\fR. \fIOption\fR may be any option +described below for the cross hairs \fBconfigure\fR operation. +.TP +\fIpathName \fBcrosshairs configure \fR?\fIoption value\fR?... +Queries or modifies the configuration options of the cross hairs. If +\fIoption\fR isn't specified, a list describing all the current +options for the cross hairs is returned. If \fIoption\fR is specified, +but not \fIvalue\fR, then a list describing \fIoption\fR is returned. +If one or more \fIoption\fR and \fIvalue\fR pairs are specified, then +for each pair, the cross hairs option \fIoption\fR is set to +\fIvalue\fR. +The following options are available for cross hairs. +.RS +.TP +\fB\-color \fIcolor\fR +Sets the color of the cross hairs. The default is \f(CWblack\fR. +.TP +\fB\-dashes \fIdashList\fR +Sets the dash style of the cross hairs. \fIDashList\fR is a list of up +to 11 numbers that alternately represent the lengths of the dashes +and gaps on the cross hair lines. Each number must be between 1 and +255. If \fIdashList\fR is \f(CW""\fR, the cross hairs will be solid +lines. +.TP +\fB\-hide \fIboolean\fR +Indicates whether cross hairs are drawn. If \fIboolean\fR is true, +cross hairs are not drawn. The default is \f(CWyes\fR. +.TP +\fB\-linewidth \fIpixels\fR +Set the width of the cross hair lines. The default is \f(CW1\fR. +.TP +\fB\-position \fIpos\fR +Specifies the screen position where the cross hairs intersect. +\fIPos\fR must be in the form "\fI@x,y\fR", where \fIx\fR and \fIy\fR +are the window coordinates of the intersection. +.PP +Cross hairs configuration options may be also be set by the +\fBoption\fR command. The resource name and class are +\f(CWcrosshairs\fR and \f(CWCrosshairs\fR respectively. +.CS +option add *Graph.Crosshairs.LineWidth 2 +option add *Graph.Crosshairs.Color red +.CE +.RE +.TP +\fIpathName \fBcrosshairs off\fR +Turns off the cross hairs. +.TP +\fIpathName \fBcrosshairs on\fR +Turns on the display of the cross hairs. +.TP +\fIpathName \fBcrosshairs toggle\fR +Toggles the current state of the cross hairs, alternately mapping and +unmapping the cross hairs. +.SS "ELEMENT COMPONENTS" +A data element represents a set of data. It contains x and y vectors +containing the coordinates of the data points. Elements can be +displayed with a symbol at each data point and lines connecting the +points. Elements also control the appearance of the data, such as the +symbol type, line width, color etc. +.PP +When new data elements are created, they are automatically added to a +list of displayed elements. The display list controls what elements +are drawn and in what order. +.PP +The following operations are available for elements. +.TP +\fIpathName \fBelement activate \fIelemName \fR?\fIindex\fR?... +Specifies the data points of element \fIelemName\fR to be drawn +using active foreground and background colors. \fIElemName\fR is the +name of the element and \fIindex\fR is a number representing the index +of the data point. If no indices are present then all data points +become active. +.TP +\fIpathName \fBelement bind \fItagName\fR ?\fIsequence\fR? ?\fIcommand\fR? +Associates \fIcommand\fR with \fItagName\fR such that whenever the +event sequence given by \fIsequence\fR occurs for an element with this +tag, \fIcommand\fR will be invoked. The syntax is similar to the +\fBbind\fR command except that it operates on graph elements, rather +than widgets. See the \fBbind\fR manual entry for +complete details on \fIsequence\fR and the substitutions performed on +\fIcommand\fR before invoking it. +.sp +If all arguments are specified then a new binding is created, replacing +any existing binding for the same \fIsequence\fR and \fItagName\fR. +If the first character of \fIcommand\fR is \f(CW+\fR then \fIcommand\fR +augments an existing binding rather than replacing it. +If no \fIcommand\fR argument is provided then the command currently +associated with \fItagName\fR and \fIsequence\fR (it's an error occurs +if there's no such binding) is returned. If both \fIcommand\fR and +\fIsequence\fR are missing then a list of all the event sequences for +which bindings have been defined for \fItagName\fR. +.TP +\fIpathName \fBelement cget \fIelemName \fIoption\fR +Returns the current value of the element configuration option given by +\fIoption\fR. \fIOption\fR may be any of the options described below +for the element \fBconfigure\fR operation. +.TP +\fIpathName \fBelement closest \fIx y\fR ?\fIoption value\fR?... ?\fIelemName\fR?... +Searches for the data point closest to the window coordinates \fIx\fR +and \fIy\fR. By default, all elements are searched. Hidden elements +(see the \fB\-hide\fR option is false) are ignored. You can limit the +search by specifying only the elements you want to be considered. +\fIElemName\fR must be the name of an element that can not be hidden. +It returns a key-value list containing the name of the closest element, +the index of the closest data point, and the graph-coordinates of the point. +Returns \f(CW""\fR, if no data point within the threshold distance +can be found. The following +\fIoption\fR\-\fIvalue\fR pairs are available. +.RS +.TP +\fB\-along \fIdirection\fR +Search for the closest element using the following criteria: +.RS +.TP +\f(CWx\fR +Find closest element vertically from the given X-coordinate. +.TP +\f(CWy\fR +Find the closest element horizontally from the given Y-coordinate. +.TP +\f(CWboth\fR +Find the closest element for the given point (using both the X and Y +coordinates). +.RE +.TP +\fB\-halo \fIpixels\fR +Specifies a threshold distance where selected data points are ignored. +\fIPixels\fR is a valid screen distance, such as \f(CW2\fR or \f(CW1.2i\fR. +If this option isn't specified, then it defaults to the value of the +graph's \fB\-halo\fR option. +.TP +\fB\-interpolate \fIstring\fR +Indicates whether to consider projections that lie along the line segments +connecting data points when searching for the closest point. +The default value is \f(CW0\fR. The values for \fIstring\fR are +described below. +.RS +.TP 1.25i +\f(CWno\fR +Search only for the closest data point. +.TP +\f(CWyes\fR +Search includes projections that lie along the +line segments connecting the data points. +.RE +.RE +.TP +\fIpathName \fBelement configure \fIelemName \fR?\fIelemName\fR... ?\fIoption value\fR?... +Queries or modifies the configuration options for elements. Several +elements can be modified at the same time. If \fIoption\fR isn't +specified, a list describing all the current options for +\fIelemName\fR is returned. If \fIoption\fR is specified, but not +\fIvalue\fR, then a list describing the option \fIoption\fR is +returned. If one or more \fIoption\fR and \fIvalue\fR pairs are +specified, then for each pair, the element option \fIoption\fR is set +to \fIvalue\fR. The following options are valid for elements. +.RS +.TP +\fB\-activepen \fIpenName\fR +Specifies pen to use to draw active element. If \fIpenName\fR is +\f(CW""\fR, no active elements will be drawn. The default is +\f(CWactiveLine\fR. +.TP +\fB\-areabackground \fIcolor\fR +Specifies the background color of the area under the curve. The +background area color is drawn only for bitmaps (see the +\fB\-areapattern\fR option). If \fIcolor\fR is \f(CW""\fR, the +background is transparent. The default is \f(CWblack\fR. +.TP +\fB\-areaforeground \fIcolor\fR +Specifies the foreground color of the area under the curve. +The default is \f(CWblack\fR. +.TP +\fB\-areapattern \fIpattern\fR +Specifies how to fill the area under the curve. \fIPattern\fR may be +the name of a Tk bitmap, \f(CWsolid\fR, or \f(CW""\fR. If "solid", +then the area under the curve is drawn with the color designated by +the \fB\-areaforeground\fR option. If a bitmap, then the bitmap is +stippled across the area. Here the bitmap colors are controlled by the +\fB\-areaforeground\fR and \fB\-areabackground\fR options. If +\fIpattern\fR is \f(CW""\fR, no filled area is drawn. The default is +\f(CW""\fR. +.TP +\fB\-areatile \fIimage\fR +Specifies the name of a Tk image to be used to tile the area under the +curve. This option supersedes the \fB\-areapattern\fR option. +\fIImage\fR must be a photo image. If \fIimage\fR is \f(CW""\fR, no +tiling is performed. The default is \f(CW""\fR. +.TP +\fB\-bindtags \fItagList\fR +Specifies the binding tags for the element. \fITagList\fR is a list +of binding tag names. The tags and their order will determine how +events are handled for elements. Each tag in the list matching the +current event +sequence will have its Tcl command executed. Implicitly the name of +the element is always the first tag in the list. The default value is +\f(CWall\fR. +.TP +\fB\-color \fIcolor\fR +Sets the color of the traces connecting the data points. +.TP +\fB\-dashes \fIdashList\fR +Sets the dash style of element line. \fIDashList\fR is a list of up to +11 numbers that alternately represent the lengths of the dashes and +gaps on the element line. Each number must be between 1 and 255. If +\fIdashList\fR is \f(CW""\fR, the lines will be solid. +.TP +\fB\-data \fIcoordList\fR +Specifies the X\-Y coordinates of the data. \fICoordList\fR is a +list of numeric expressions representing the X\-Y coordinate pairs +of each data point. +.TP +\fB\-fill \fIcolor\fR +Sets the interior color of symbols. If \fIcolor\fR is \f(CW""\fR, then +the interior of the symbol is transparent. If \fIcolor\fR is +\f(CWdefcolor\fR, then the color will be the same as the \fB\-color\fR +option. The default is \f(CWdefcolor\fR. +.TP +\fB\-hide \fIboolean\fR +Indicates whether the element is displayed. +The default is \f(CWno\fR. +.TP +\fB\-label \fItext\fR +Sets the element's label in the legend. If \fItext\fR +is \f(CW""\fR, the element will have no entry in the legend. +The default label is the element's name. +.TP +\fB\-linewidth \fIpixels\fR +Sets the width of the connecting lines between data points. If +\fIpixels\fR is \f(CW0\fR, no connecting lines will be drawn between +symbols. The default is \f(CW0\fR. +.TP +\fB\-mapx \fIxAxis\fR +Selects the X\-axis to map the element's X\-coordinates onto. +\fIXAxis\fR must be the name of an axis. The default is \f(CWx\fR. +.TP +\fB\-mapy \fIyAxis\fR +Selects the Y\-axis to map the element's Y\-coordinates onto. +\fIYAxis\fR must be the name of an axis. The default is \f(CWy\fR. +.TP +\fB\-offdash \fIcolor\fR +Sets the color of the stripes when traces are dashed (see the +\fB\-dashes\fR option). If \fIcolor\fR is \f(CW""\fR, then the "off" +pixels will represent gaps instead of stripes. If \fIcolor\fR is +\f(CWdefcolor\fR, then the color will be the same as the \fB\-color\fR +option. The default is \f(CWdefcolor\fR. +.TP +\fB\-outline \fIcolor\fR +Sets the color or the outline around each symbol. If \fIcolor\fR is +\f(CW""\fR, then no outline is drawn. If \fIcolor\fR is \f(CWdefcolor\fR, +then the color will be the same as the \fB\-color\fR option. The +default is \f(CWdefcolor\fR. +.TP +\fB\-pen \fIpenname\fR +Set the pen to use for this element. +.TP +\fB\-outlinewidth \fIpixels\fR +Sets the width of the outline bordering each symbol. If \fIpixels\fR +is \f(CW0\fR, no outline will be drawn. The default is \f(CW1\fR. +.TP +\fB\-pixels \fIpixels\fR +Sets the size of symbols. If \fIpixels\fR is \f(CW0\fR, no symbols will +be drawn. The default is \f(CW0.125i\fR. +.TP +\fB\-scalesymbols \fIboolean\fR +If \fIboolean\fR is true, the size of the symbols +drawn for \fIelemName\fR will change with scale of the X\-axis and Y\-axis. +At the time this option is set, the current ranges of the axes are +saved as the normalized scales (i.e scale factor is 1.0) and the +element is drawn at its designated size (see the \fB\-pixels\fR +option). As the scale of the axes change, the symbol will be scaled +according to the smaller of the X\-axis and Y\-axis scales. If \fIboolean\fR +is false, the element's symbols are drawn at the designated size, +regardless of axis scales. The default is \f(CW0\fR. +.TP +\fB\-smooth \fIsmooth\fR +Specifies how connecting line segments are drawn between data points. +\fISmooth\fR can be either \f(CWlinear\fR, \f(CWstep\fR, \f(CWnatural\fR, or +\f(CWquadratic\fR. If \fIsmooth\fR is \f(CWlinear\fR, a single line +segment is drawn, connecting both data points. When \fIsmooth\fR is +\f(CWstep\fR, two line segments are drawn. The first is a horizontal +line segment that steps the next X\-coordinate. The second is a +vertical line, moving to the next Y\-coordinate. Both \fInatural\fR and +\fIquadratic\fR generate multiple segments between data points. If +\fInatural\fR, the segments are generated using a cubic spline. If +\fIquadratic\fR, a quadratic spline is used. The default is +\fIlinear\fR. +.TP +\fB\-styles \fIstyleList\fR +Specifies what pen to use based on the range of weights given. +\fIStyleList\fR is a list of style specifications. Each style +specification, in turn, is a list consisting of a pen name, and +optionally a minimum and maximum range. Data points whose weight (see +the \fB\-weight\fR option) falls in this range, are drawn with this +pen. If no range is specified it defaults to the index of the pen in +the list. Note that this affects only symbol attributes. Line +attributes, such as line width, dashes, etc. are ignored. +.TP +\fB\-symbol \fIsymbol\fR +Specifies the symbol for data points. \fISymbol\fR can be either +\f(CWsquare\fR, \f(CWcircle\fR, \f(CWdiamond\fR, \f(CWplus\fR, \f(CWcross\fR, +\f(CWsplus\fR, \f(CWscross\fR, \f(CWtriangle\fR, \f(CW""\fR (where no symbol +is drawn), or a bitmap. Bitmaps are specified as "\fIsource\fR +?\fImask\fR?", where \fIsource\fR is the name of the bitmap, and +\fImask\fR is the bitmap's optional mask. The default is +\f(CWcircle\fR. +.TP +\fB\-trace \fIdirection\fR +Indicates whether connecting lines between data points (whose +X\-coordinate values are either increasing or decreasing) are drawn. +\fIDirection\fR +must be \f(CWincreasing\fR, \f(CWdecreasing\fR, or \f(CWboth\fR. For +example, if \fIdirection\fR is \f(CWincreasing\fR, connecting lines will +be drawn only between those data points where X\-coordinate values are +monotonically increasing. If \fIdirection\fR is \f(CWboth\fR, +connecting lines will be draw between all data points. The default is +\f(CWboth\fR. +.TP +\fB\-weights \fIwVec\fR +Specifies the weights of the individual data points. This, +with the list pen styles (see the \fB\-styles\fR option), +controls how data points are drawn. \fIWVec\fR is the name of a BLT +vector or a list of numeric expressions representing the weights for +each data point. +.TP +\fB\-xdata \fIxVec\fR +Specifies the X\-coordinates of the data. \fIXVec\fR is the name of +a BLT vector or a list of numeric expressions. +.TP +\fB\-ydata \fIyVec\fR +Specifies the Y\-coordinates of the data. \fIYVec\fR is the name of +a BLT vector or a list of numeric expressions. +.PP +Element configuration options may also be set by the \fBoption\fR +command. The resource class is \f(CWElement\fR. The resource name is +the name of the element. +.CS +option add *Graph.Element.symbol line +option add *Graph.e1.symbol line +.CE +.RE +.TP +\fIpathName \fBelement create \fIelemName\fR ?\fIoption value\fR?... +Creates a new element \fIelemName\fR. It's an error is +an element \fIelemName\fR already exists. If +additional arguments are present, they specify options valid for +the element \fBconfigure\fR operation. +.TP +\fIpathName \fBelement deactivate \fIelemName\fR ?\fIelemName\fR?... +Deactivates all the elements matching \fIpattern\fR. +Elements whose names match any of the patterns given are redrawn using +their normal colors. +.TP +\fIpathName \fBelement delete\fR ?\fIelemName\fR?... +Deletes all the named elements. The graph is automatically redrawn. +.TP +\fIpathName \fBelement exists \fIelemName\fR +Returns \f(CW1\fR if an element \fIelemName\fR currently exists and +\f(CW0\fR otherwise. +.TP +\fIpathName \fBelement names \fR?\fIpattern\fR?... +Returns the elements matching one or more pattern. If no +\fIpattern\fR is given, the names of all elements is returned. +.TP +\fIpathName \fBelement show\fR ?\fInameList\fR? +Queries or modifies the element display list. The element display +list designates the elements drawn and in what +order. \fINameList\fR is a list of elements to be displayed in the +order they are named. If there is no \fInameList\fR argument, +the current display list is returned. +.TP +\fIpathName \fBelement type\fR \fIelemName\fR +Returns the type of \fIelemName\fR. +If the element is a bar element, the commands returns the string +\f(CW"bar"\fR, otherwise it returns \f(CW"line"\fR. +.CE +.SS "GRID COMPONENT" +Grid lines extend from the major and minor ticks of each axis +horizontally or vertically across the plotting area. The following +operations are available for grid lines. +.TP +\fIpathName \fBgrid cget \fIoption\fR +Returns the current value of the grid line configuration option given by +\fIoption\fR. \fIOption\fR may be any option described below +for the grid \fBconfigure\fR operation. +.TP +\fIpathName \fBgrid configure\fR ?\fIoption value\fR?... +Queries or modifies the configuration options for grid lines. If +\fIoption\fR isn't specified, a list describing all the current +grid options for \fIpathName\fR is returned. If \fIoption\fR is specified, +but not \fIvalue\fR, then a list describing \fIoption\fR is +returned. If one or more \fIoption\fR and \fIvalue\fR pairs are +specified, then for each pair, the grid line option \fIoption\fR is set to +\fIvalue\fR. The following options are valid for grid lines. +.RS +.TP +\fB\-color \fIcolor\fR +Sets the color of the grid lines. The default is \f(CWblack\fR. +.TP +\fB\-dashes \fIdashList\fR +Sets the dash style of the grid lines. \fIDashList\fR is a list of up +to 11 numbers that alternately represent the lengths of the dashes +and gaps on the grid lines. Each number must be between 1 and 255. +If \fIdashList\fR is \f(CW""\fR, the grid will be solid lines. +.TP +\fB\-hide \fIboolean\fR +Indicates whether the grid should be drawn. If \fIboolean\fR +is true, grid lines are not shown. The default is \f(CWyes\fR. +.TP +\fB\-linewidth \fIpixels\fR +Sets the width of grid lines. The default width is \f(CW1\fR. +.TP +\fB\-mapx \fIxAxis\fR +Specifies the X\-axis to display grid lines. \fIXAxis\fR +must be the name of an axis or \f(CW""\fR for no grid lines. +The default is \f(CW""\fR. +.TP +\fB\-mapy \fIyAxis\fR +Specifies the Y\-axis to display grid lines. \fIYAxis\fR +must be the name of an axis or \f(CW""\fR for no grid lines. +The default is \f(CWy\fR. +.TP +\fB\-minor \fIboolean\fR +Indicates whether the grid lines should be drawn for minor ticks. +If \fIboolean\fR is true, the lines will appear at +minor tick intervals. The default is \f(CW1\fR. +.PP +Grid configuration options may also be set by the +\fBoption\fR command. The resource name and class are \f(CWgrid\fR and +\f(CWGrid\fR respectively. +.CS +option add *Graph.grid.LineWidth 2 +option add *Graph.Grid.Color black +.CE +.RE +.TP +\fIpathName \fBgrid off\fR +Turns off the display the grid lines. +.TP +\fIpathName \fBgrid on\fR +Turns on the display the grid lines. +.TP +\fIpathName \fBgrid toggle\fR +Toggles the display of the grid. +.SS "LEGEND COMPONENT" +The legend displays a list of the data elements. Each entry consists +of the element's symbol and label. The legend can appear in any +margin (the default location is in the right margin). It +can also be positioned anywhere within the plotting area. +.PP +The following operations are valid for the legend. +.TP +\fIpathName \fBlegend activate \fIpattern\fR... +Selects legend entries to be drawn using the active legend colors and relief. +All entries whose element names match \fIpattern\fR are selected. To +be selected, the element name must match only one \fIpattern\fR. +.TP +\fIpathName \fBlegend bind \fItagName\fR ?\fIsequence\fR? ?\fIcommand\fR? +Associates \fIcommand\fR with \fItagName\fR such that whenever the +event sequence given by \fIsequence\fR occurs for a legend entry with this +tag, \fIcommand\fR will be invoked. Implicitly the element names +in the entry are tags. The syntax is similar to the +\fBbind\fR command except that it operates on legend entries, rather +than widgets. See the \fBbind\fR manual entry for +complete details on \fIsequence\fR and the substitutions performed on +\fIcommand\fR before invoking it. +.sp +If all arguments are specified then a new binding is created, replacing +any existing binding for the same \fIsequence\fR and \fItagName\fR. +If the first character of \fIcommand\fR is \f(CW+\fR then \fIcommand\fR +augments an existing binding rather than replacing it. +If no \fIcommand\fR argument is provided then the command currently +associated with \fItagName\fR and \fIsequence\fR (it's an error occurs +if there's no such binding) is returned. If both \fIcommand\fR and +\fIsequence\fR are missing then a list of all the event sequences for +which bindings have been defined for \fItagName\fR. +.TP +\fIpathName \fBlegend cget \fIoption\fR +Returns the current value of a legend configuration option. +\fIOption\fR may be any option described below in the +legend \fBconfigure\fR operation. +.TP +\fIpathName \fBlegend configure \fR?\fIoption value\fR?... +Queries or modifies the configuration options for the legend. If +\fIoption\fR isn't specified, a list describing the current +legend options for \fIpathName\fR is returned. If \fIoption\fR is +specified, but not \fIvalue\fR, then a list describing \fIoption\fR is +returned. If one or more \fIoption\fR and \fIvalue\fR pairs are +specified, then for each pair, the legend option \fIoption\fR is set +to \fIvalue\fR. The following options are valid for the legend. +.RS +.TP +\fB\-activebackground \fIcolor\fR +Sets the background color for active legend entries. All legend +entries marked active (see the legend \fBactivate\fR operation) are +drawn using this background color. +.TP +\fB\-activeborderwidth \fIpixels\fR +Sets the width of the 3-D border around the outside edge of the active legend +entries. The default is \f(CW2\fR. +.TP +\fB\-activeforeground \fIcolor\fR +Sets the foreground color for active legend entries. All legend +entries marked as active (see the legend \fBactivate\fR operation) are +drawn using this foreground color. +.TP +\fB\-activerelief \fIrelief\fR +Specifies the 3-D effect desired for active legend entries. +\fIRelief\fR denotes how the interior of the entry should appear +relative to the legend; for example, \f(CWraised\fR means the entry +should appear to protrude from the legend, relative to the surface of +the legend. The default is \f(CWflat\fR. +.TP +\fB\-anchor \fIanchor\fR +Tells how to position the legend relative to the positioning point for +the legend. This is dependent on the value of the \fB\-position\fR +option. The default is \f(CWcenter\fR. +.RS +.TP 1.25i +\f(CWleft\fR or \f(CWright\fR +The anchor describes how to position the legend vertically. +.TP +\f(CWtop\fR or \f(CWbottom\fR +The anchor describes how to position the legend horizontally. +.TP +\f(CW@x,y\fR +The anchor specifies how to position the legend relative to the +positioning point. For example, if \fIanchor\fR is \f(CWcenter\fR then +the legend is centered on the point; if \fIanchor\fR is \f(CWn\fR then +the legend will be drawn such that the top center point of the +rectangular region occupied by the legend will be at the positioning +point. +.TP +\f(CWplotarea\fR +The anchor specifies how to position the legend relative to the +plotting area. For example, if \fIanchor\fR is \f(CWcenter\fR then the +legend is centered in the plotting area; if \fIanchor\fR is \f(CWne\fR +then the legend will be drawn such that occupies the upper right +corner of the plotting area. +.RE +.TP +\fB\-background \fIcolor\fR +Sets the background color of the legend. If \fIcolor\fR is \f(CW""\fR, +the legend background with be transparent. +.TP +\fB\-bindtags \fItagList\fR +Specifies the binding tags for legend entries. \fITagList\fR is a list +of binding tag names. The tags and their order will determine how +events are handled for legend entries. Each tag in the list matching +the current event sequence will have its Tcl command executed. The +default value is \f(CWall\fR. +.TP +\fB\-borderwidth \fIpixels\fR +Sets the width of the 3-D border around the outside edge of the legend (if +such border is being drawn; the \fBrelief\fR option determines this). +The default is \f(CW2\fR pixels. +.TP +\fB\-font \fIfontName\fR +\fIFontName\fR specifies a font to use when drawing the labels of each +element into the legend. The default is +\f(CW*-Helvetica-Bold-R-Normal-*-12-120-*\fR. +.TP +\fB\-foreground \fIcolor\fR +Sets the foreground color of the text drawn for the element's label. +The default is \f(CWblack\fR. +.TP +\fB\-hide \fIboolean\fR +Indicates whether the legend should be displayed. If \fIboolean\fR is +true, the legend will not be draw. The default is \f(CWno\fR. +.TP +\fB\-ipadx \fIpad\fR +Sets the amount of internal padding to be added to the width of each +legend entry. \fIPad\fR can be a list of one or two screen distances. If +\fIpad\fR has two elements, the left side of the legend entry is +padded by the first distance and the right side by the second. If +\fIpad\fR is just one distance, both the left and right sides are padded +evenly. The default is \f(CW2\fR. +.TP +\fB\-ipady \fIpad\fR +Sets an amount of internal padding to be added to the height of each +legend entry. \fIPad\fR can be a list of one or two screen distances. If +\fIpad\fR has two elements, the top of the entry is padded by the +first distance and the bottom by the second. If \fIpad\fR is just +one distance, both the top and bottom of the entry are padded evenly. +The default is \f(CW2\fR. +.TP +\fB\-padx \fIpad\fR +Sets the padding to the left and right exteriors of the legend. +\fIPad\fR can be a list of one or two screen distances. If \fIpad\fR +has two elements, the left side of the legend is padded by the first +distance and the right side by the second. If \fIpad\fR has just one +distance, both the left and right sides are padded evenly. The +default is \f(CW4\fR. +.TP +\fB\-pady \fIpad\fR +Sets the padding above and below the legend. \fIPad\fR can be a list +of one or two screen distances. If \fIpad\fR has two elements, the area above +the legend is padded by the first distance and the area below by the +second. If \fIpad\fR is just one distance, both the top and +bottom areas are padded evenly. The default is \f(CW0\fR. +.TP +\fB\-position \fIpos\fR +Specifies where the legend is drawn. The +\fB\-anchor\fR option also affects where the legend is positioned. If +\fIpos\fR is \f(CWleft\fR, \f(CWleft\fR, \f(CWtop\fR, or \f(CWbottom\fR, the +legend is drawn in the specified margin. If \fIpos\fR is +\f(CWplotarea\fR, then the legend is drawn inside the plotting area at a +particular anchor. If \fIpos\fR is in the form "\fI@x,y\fR", where +\fIx\fR and \fIy\fR are the window coordinates, the legend is drawn in +the plotting area at the specified coordinates. The default is +\f(CWright\fR. +.TP +\fB\-raised \fIboolean\fR +Indicates whether the legend is above or below the data elements. This +matters only if the legend is in the plotting area. If \fIboolean\fR +is true, the legend will be drawn on top of any elements that may +overlap it. The default is \f(CWno\fR. +.TP +\fB\-relief \fIrelief\fR +Specifies the 3-D effect for the border around the legend. +\fIRelief\fR specifies how the interior of the legend should appear +relative to the graph; for example, \f(CWraised\fR means the legend +should appear to protrude from the graph, relative to the surface of +the graph. The default is \f(CWsunken\fR. +.PP +Legend configuration options may also be set by the \fBoption\fR +command. The resource name and class are \f(CWlegend\fR and +\f(CWLegend\fR respectively. +.CS +option add *Graph.legend.Foreground blue +option add *Graph.Legend.Relief raised +.CE +.RE +.TP +\fIpathName \fBlegend deactivate \fIpattern\fR... +Selects legend entries to be drawn using the normal legend colors and +relief. All entries whose element names match \fIpattern\fR are +selected. To be selected, the element name must match only one +\fIpattern\fR. +.TP +\fIpathName \fBlegend get \fIpos\fR +Returns the name of the element whose entry is at the screen position +\fIpos\fR in the legend. \fIPos\fR must be in the form "\fI@x,y\fR", +where \fIx\fR and \fIy\fR are window coordinates. If the given +coordinates do not lie over a legend entry, \f(CW""\fR is returned. +.SS "PEN COMPONENTS" +Pens define attributes (both symbol and line style) for elements. +Pens mirror the configuration options of data elements that pertain to +how symbols and lines are drawn. Data elements use pens to determine +how they are drawn. A data element may use several pens at once. In +this case, the pen used for a particular data point is determined from +each element's weight vector (see the element's \fB\-weight\fR and +\fB\-style\fR options). +.PP +One pen, called \f(CWactiveLine\fR, is automatically created. +It's used as the default active pen for elements. So you can change +the active attributes for all elements by simply reconfiguring this +pen. +.CS +\&.g pen configure "activeLine" -color green +.CE +You can create and use several pens. To create a pen, invoke +the pen component and its create operation. +.CS +\&.g pen create myPen +.CE +You map pens to a data element using either the element's +\fB\-pen\fR or \fB\-activepen\fR options. +.CS +\&.g element create "line1" -xdata $x -ydata $tempData \\ + -pen myPen +.CE +An element can use several pens at once. This is done by specifying +the name of the pen in the element's style list (see the +\fB\-styles\fR option). +.CS +\&.g element configure "line1" -styles { myPen 2.0 3.0 } +.CE +This says that any data point with a weight between 2.0 and 3.0 +is to be drawn using the pen \f(CWmyPen\fR. All other points +are drawn with the element's default attributes. +.PP +The following operations are available for pen components. +.PP +.TP +\fIpathName \fBpen \fBcget \fIpenName \fIoption\fR +Returns the current value of the option given by \fIoption\fR for +\fIpenName\fR. \fIOption\fR may be any option described below +for the pen \fBconfigure\fR operation. +.TP +\fIpathName \fBpen \fBconfigure \fIpenName \fR?\fIpenName\fR... ?\fIoption value\fR?... +Queries or modifies the configuration options of +\fIpenName\fR. Several pens can be modified at once. If \fIoption\fR +isn't specified, a list describing the current options for +\fIpenName\fR is returned. If \fIoption\fR is specified, but not +\fIvalue\fR, then a list describing \fIoption\fR is returned. If one +or more \fIoption\fR and \fIvalue\fR pairs are specified, then for +each pair, the pen option \fIoption\fR is set to \fIvalue\fR. The +following options are valid for pens. +.RS +.TP +\fB\-color \fIcolor\fR +Sets the color of the traces connecting the data points. +.TP +\fB\-dashes \fIdashList\fR +Sets the dash style of element line. \fIDashList\fR is a list of up to +11 numbers that alternately represent the lengths of the dashes and +gaps on the element line. Each number must be between 1 and 255. If +\fIdashList\fR is \f(CW""\fR, the lines will be solid. +.TP +\fB\-fill \fIcolor\fR +Sets the interior color of symbols. If \fIcolor\fR is \f(CW""\fR, then +the interior of the symbol is transparent. If \fIcolor\fR is +\f(CWdefcolor\fR, then the color will be the same as the \fB\-color\fR +option. The default is \f(CWdefcolor\fR. +.TP +\fB\-linewidth \fIpixels\fR +Sets the width of the connecting lines between data points. If +\fIpixels\fR is \f(CW0\fR, no connecting lines will be drawn between +symbols. The default is \f(CW0\fR. +.TP +\fB\-offdash \fIcolor\fR +Sets the color of the stripes when traces are dashed (see the +\fB\-dashes\fR option). If \fIcolor\fR is \f(CW""\fR, then the "off" +pixels will represent gaps instead of stripes. If \fIcolor\fR is +\f(CWdefcolor\fR, then the color will be the same as the \fB\-color\fR +option. The default is \f(CWdefcolor\fR. +.TP +\fB\-outline \fIcolor\fR +Sets the color or the outline around each symbol. If \fIcolor\fR is +\f(CW""\fR, then no outline is drawn. If \fIcolor\fR is \f(CWdefcolor\fR, +then the color will be the same as the \fB\-color\fR option. The +default is \f(CWdefcolor\fR. +.TP +\fB\-outlinewidth \fIpixels\fR +Sets the width of the outline bordering each symbol. If \fIpixels\fR +is \f(CW0\fR, no outline will be drawn. The default is \f(CW1\fR. +.TP +\fB\-pixels \fIpixels\fR +Sets the size of symbols. If \fIpixels\fR is \f(CW0\fR, no symbols will +be drawn. The default is \f(CW0.125i\fR. +.TP +\fB\-symbol \fIsymbol\fR +Specifies the symbol for data points. \fISymbol\fR can be either +\f(CWsquare\fR, \f(CWcircle\fR, \f(CWdiamond\fR, \f(CWplus\fR, \f(CWcross\fR, +\f(CWsplus\fR, \f(CWscross\fR, \f(CWtriangle\fR, \f(CW""\fR (where no symbol +is drawn), or a bitmap. Bitmaps are specified as "\fIsource\fR +?\fImask\fR?", where \fIsource\fR is the name of the bitmap, and +\fImask\fR is the bitmap's optional mask. The default is +\f(CWcircle\fR. +.TP +\fB\-type \fIelemType\fR +Specifies the type of element the pen is to be used with. +This option should only be employed when creating the pen. This +is for those that wish to mix different types of elements (bars and +lines) on the same graph. The default type is "line". +.PP +Pen configuration options may be also be set by the \fBoption\fR +command. The resource class is \f(CWPen\fR. The resource names +are the names of the pens. +.CS +option add *Graph.Pen.Color blue +option add *Graph.activeLine.color green +.CE +.RE +.TP +\fIpathName \fBpen \fBcreate \fIpenName \fR?\fIoption value\fR?... +Creates a new pen by the name \fIpenName\fR. No pen by the same +name can already exist. \fIOption\fR and \fIvalue\fR are described +in above in the pen \fBconfigure\fR operation. +.TP +\fIpathName \fBpen \fBdelete \fR?\fIpenName\fR?... +Deletes the named pens. A pen is not really +deleted until it is not longer in use, so it's safe to delete +pens mapped to elements. +.TP +\fIpathName \fBpen names \fR?\fIpattern\fR?... +Returns a list of pens matching zero or more patterns. If no +\fIpattern\fR argument is give, the names of all pens are returned. +.SS "POSTSCRIPT COMPONENT" +The graph can generate encapsulated PostScript output. There +are several configuration options you can specify to control how the +plot will be generated. You can change the page dimensions and +borders. The plot itself can be scaled, centered, or rotated to +landscape. The PostScript output can be written directly to a file or +returned through the interpreter. +.PP +The following postscript operations are available. +.TP +\fIpathName \fBpostscript cget \fIoption\fR +Returns the current value of the postscript option given by +\fIoption\fR. \fIOption\fR may be any option described +below for the postscript \fBconfigure\fR operation. +.TP +\fIpathName \fBpostscript configure \fR?\fIoption value\fR?... +Queries or modifies the configuration options for PostScript +generation. If \fIoption\fR isn't specified, a list describing +the current postscript options for \fIpathName\fR is returned. If +\fIoption\fR is specified, but not \fIvalue\fR, then a list describing +\fIoption\fR is returned. If one or more \fIoption\fR and \fIvalue\fR +pairs are specified, then for each pair, the postscript option +\fIoption\fR is set to \fIvalue\fR. The following postscript options +are available. +.RS +.TP +\fB\-center \fIboolean\fR +Indicates whether the plot should be centered on the PostScript page. If +\fIboolean\fR is false, the plot will be placed in the upper left +corner of the page. The default is \f(CW1\fR. +.TP +\fB\-colormap \fIvarName\fR +\fIVarName\fR must be the name of a global array variable that +specifies a color mapping from the X color name to PostScript. Each +element of \fIvarName\fR must consist of PostScript code to set a +particular color value (e.g. ``\f(CW1.0 1.0 0.0 setrgbcolor\fR''). When +generating color information in PostScript, the array variable \fIvarName\fR +is checked if an element of the name as the color exists. If so, it uses +its value as the PostScript +command to set the color. If this option hasn't been specified, or if +there isn't an entry in \fIvarName\fR for a given color, then it uses +the red, green, and blue intensities from the X color. +.TP +\fB\-colormode \fImode\fR +Specifies how to output color information. \fIMode\fR must be either +\f(CWcolor\fR (for full color output), \f(CWgray\fR (convert all colors to +their gray-scale equivalents) or \f(CWmono\fR (convert foreground colors +to black and background colors to white). The default mode is +\f(CWcolor\fR. +.TP +\fB\-fontmap \fIvarName\fR +\fIVarName\fR must be the name of a global array variable that +specifies a font mapping from the X font name to PostScript. Each +element of \fIvarName\fR must consist of a Tcl list with one or two +elements; the name and point size of a PostScript font. +When outputting PostScript commands for a particular font, the array +variable \fIvarName\fR is checked to see if an element by the +specified font exists. If there is such an element, then the font +information contained in that element is used in the PostScript +output. (If the point size is omitted from the list, the point size +of the X font is used). Otherwise the X font is examined in an +attempt to guess what PostScript font to use. This works only for +fonts whose foundry property is \fIAdobe\fR (such as Times, Helvetica, +Courier, etc.). If all of this fails then the font defaults to +\f(CWHelvetica-Bold\fR. +.TP +\fB\-decorations \fIboolean\fR +Indicates whether PostScript commands to generate color backgrounds and 3-D +borders will be output. If \fIboolean\fR is false, the background will be +white and no 3-D borders will be generated. The +default is \f(CW1\fR. +.TP +\fB\-height \fIpixels\fR +Sets the height of the plot. This lets you print the graph with a +height different from the one drawn on the screen. If +\fIpixels\fR is 0, the height is the same as the widget's height. +The default is \f(CW0\fR. +.TP +\fB\-landscape \fIboolean\fR +If \fIboolean\fR is true, this specifies the printed area is to be +rotated 90 degrees. In non-rotated output the X\-axis of the printed +area runs along the short dimension of the page (``portrait'' +orientation); in rotated output the X\-axis runs along the long +dimension of the page (``landscape'' orientation). Defaults to +\f(CW0\fR. +.TP +\fB\-maxpect \fIboolean\fR +Indicates to scale the plot so that it fills the PostScript page. +The aspect ratio of the graph is still retained. The default is +\f(CW0\fR. +.TP +\fB\-padx \fIpad\fR +Sets the horizontal padding for the left and right page borders. The +borders are exterior to the plot. \fIPad\fR can be a list of one or +two screen distances. If \fIpad\fR has two elements, the left border is padded +by the first distance and the right border by the second. If +\fIpad\fR has just one distance, both the left and right borders are +padded evenly. The default is \f(CW1i\fR. +.TP +\fB\-pady \fIpad\fR +Sets the vertical padding for the top and bottom page borders. The +borders are exterior to the plot. \fIPad\fR can be a list of one or +two screen distances. If \fIpad\fR has two elements, the top border is padded +by the first distance and the bottom border by the second. If +\fIpad\fR has just one distance, both the top and bottom borders are +padded evenly. The default is \f(CW1i\fR. +.TP +\fB\-paperheight \fIpixels\fR +Sets the height of the postscript page. This can be used to select +between different page sizes (letter, A4, etc). The default height is +\f(CW11.0i\fR. +.TP +\fB\-paperwidth \fIpixels\fR +Sets the width of the postscript page. This can be used to select +between different page sizes (letter, A4, etc). The default width is +\f(CW8.5i\fR. +.TP +\fB\-width \fIpixels\fR +Sets the width of the plot. This lets you generate a plot +of a width different from that of the widget. If \fIpixels\fR +is 0, the width is the same as the widget's width. The default is +\f(CW0\fR. +.PP +Postscript configuration options may be also be set by the +\fBoption\fR command. The resource name and class are +\f(CWpostscript\fR and \f(CWPostscript\fR respectively. +.CS +option add *Graph.postscript.Decorations false +option add *Graph.Postscript.Landscape true +.CE +.RE +.TP +\fIpathName \fBpostscript output \fR?\fIfileName\fR? ?\fIoption value\fR?... +Outputs a file of encapsulated PostScript. If a +\fIfileName\fR argument isn't present, the command returns the +PostScript. If any \fIoption-value\fR pairs are present, they set +configuration options controlling how the PostScript is generated. +\fIOption\fR and \fIvalue\fR can be anything accepted by the +postscript \fBconfigure\fR operation above. +.SS "MARKER COMPONENTS" +Markers are simple drawing procedures used to annotate or highlight +areas of the graph. Markers have various types: text strings, +bitmaps, images, connected lines, windows, or polygons. They can be +associated with a particular element, so that when the element is +hidden or un-hidden, so is the marker. By default, markers are the +last items drawn, so that data elements will appear in +behind them. You can change this by configuring the \fB\-under\fR +option. +.PP +Markers, in contrast to elements, don't affect the scaling of the +coordinate axes. They can also have \fIelastic\fR coordinates +(specified by \f(CW-Inf\fR and \f(CWInf\fR respectively) that translate +into the minimum or maximum limit of the axis. For example, you can +place a marker so it always remains in the lower left corner of the +plotting area, by using the coordinates \f(CW-Inf\fR,\f(CW-Inf\fR. +.PP +The following operations are available for markers. +.TP +\fIpathName \fBmarker after \fImarkerId\fR ?\fIafterId\fR? +Changes the order of the markers, drawing the first +marker after the second. If no second \fIafterId\fR argument is +specified, the marker is placed at the end of the display list. This +command can be used to control how markers are displayed since markers +are drawn in the order of this display list. +.TP +\fIpathName \fBmarker before \fImarkerId\fR ?\fIbeforeId\fR? +Changes the order of the markers, drawing the first +marker before the second. If no second \fIbeforeId\fR argument is +specified, the marker is placed at the beginning of the display list. +This command can be used to control how markers are displayed since +markers are drawn in the order of this display list. +.TP +\fIpathName \fBmarker bind \fItagName\fR ?\fIsequence\fR? ?\fIcommand\fR? +Associates \fIcommand\fR with \fItagName\fR such that whenever the +event sequence given by \fIsequence\fR occurs for a marker with this +tag, \fIcommand\fR will be invoked. The syntax is similar to the +\fBbind\fR command except that it operates on graph markers, rather +than widgets. See the \fBbind\fR manual entry for +complete details on \fIsequence\fR and the substitutions performed on +\fIcommand\fR before invoking it. +.sp +If all arguments are specified then a new binding is created, replacing +any existing binding for the same \fIsequence\fR and \fItagName\fR. +If the first character of \fIcommand\fR is \f(CW+\fR then \fIcommand\fR +augments an existing binding rather than replacing it. +If no \fIcommand\fR argument is provided then the command currently +associated with \fItagName\fR and \fIsequence\fR (it's an error occurs +if there's no such binding) is returned. If both \fIcommand\fR and +\fIsequence\fR are missing then a list of all the event sequences for +which bindings have been defined for \fItagName\fR. +.TP +\fIpathName \fBmarker cget \fIoption\fR +Returns the current value of the marker configuration option given by +\fIoption\fR. \fIOption\fR may be any option described +below in the \fBconfigure\fR operation. +.TP +\fIpathName \fBmarker configure \fImarkerId\fR ?\fIoption value\fR?... +Queries or modifies the configuration options for markers. If +\fIoption\fR isn't specified, a list describing the current +options for \fImarkerId\fR is returned. If \fIoption\fR is specified, +but not \fIvalue\fR, then a list describing \fIoption\fR is returned. +If one or more \fIoption\fR and \fIvalue\fR pairs are specified, then +for each pair, the marker option \fIoption\fR is set to \fIvalue\fR. +.sp +The following options are valid for all markers. +Each type of marker also has its own type-specific options. +They are described in the sections below. +.RS +.TP +\fB\-bindtags \fItagList\fR +Specifies the binding tags for the marker. \fITagList\fR is a list +of binding tag names. The tags and their order will determine how +events for markers are handled. Each tag in the list matching the +current event sequence will have its Tcl command executed. Implicitly +the name of the marker is always the first tag in the list. +The default value is \f(CWall\fR. +.TP +\fB\-coords \fIcoordList\fR +Specifies the coordinates of the marker. \fICoordList\fR is +a list of graph coordinates. The number of coordinates required +is dependent on the type of marker. Text, image, and window markers +need only two coordinates (an X\-Y coordinate). Bitmap markers +can take either two or four coordinates (if four, they represent the +corners of the bitmap). Line markers +need at least four coordinates, polygons at least six. +If \fIcoordList\fR is \f(CW""\fR, the marker will not be displayed. +The default is \f(CW""\fR. +.TP +\fB\-element \fIelemName\fR +Links the marker with the element \fIelemName\fR. The marker is +drawn only if the element is also currently displayed (see the +element's \fBshow\fR operation). If \fIelemName\fR is \f(CW""\fR, the +marker is always drawn. The default is \f(CW""\fR. +.TP +\fB\-hide \fIboolean\fR +Indicates whether the marker is drawn. If \fIboolean\fR is true, +the marker is not drawn. The default is \f(CWno\fR. +.TP +\fB\-mapx \fIxAxis\fR +Specifies the X\-axis to map the marker's X\-coordinates onto. +\fIXAxis\fR must the name of an axis. The default is \f(CWx\fR. +.TP +\fB\-mapy \fIyAxis\fR +Specifies the Y\-axis to map the marker's Y\-coordinates onto. +\fIYAxis\fR must the name of an axis. The default is \f(CWy\fR. +.TP +\fB\-name \fImarkerId\fR +Changes the identifier for the marker. The identifier \fImarkerId\fR +can not already be used by another marker. If this option +isn't specified, the marker's name is uniquely generated. +.TP +\fB\-under \fIboolean\fR +Indicates whether the marker is drawn below/above data +elements. If \fIboolean\fR is true, the marker is be drawn +underneath the data element symbols and lines. Otherwise, the marker is +drawn on top of the element. The default is \f(CW0\fR. +.TP +\fB\-xoffset \fIpixels\fR +Specifies a screen distance to offset the marker horizontally. +\fIPixels\fR is a valid screen distance, such as \f(CW2\fR or \f(CW1.2i\fR. +The default is \f(CW0\fR. +.TP +\fB\-yoffset \fIpixels\fR +Specifies a screen distance to offset the markers vertically. +\fIPixels\fR is a valid screen distance, such as \f(CW2\fR or \f(CW1.2i\fR. +The default is \f(CW0\fR. +.PP +Marker configuration options may also be set by the \fBoption\fR command. +The resource class is either \f(CWBitmapMarker\fR, \f(CWImageMarker\fR, +\f(CWLineMarker\fR, \f(CWPolygonMarker\fR, \f(CWTextMarker\fR, or \f(CWWindowMarker\fR, +depending on the type of marker. The resource name is the name of the +marker. +.CS +option add *Graph.TextMarker.Foreground white +option add *Graph.BitmapMarker.Foreground white +option add *Graph.m1.Background blue +.CE +.RE +.TP +\fIpathName \fBmarker create \fItype\fR ?\fIoption value\fR?... +Creates a marker of the selected type. \fIType\fR may be either +\f(CWtext\fR, \f(CWline\fR, \f(CWbitmap\fR, \f(CWimage\fR, \f(CWpolygon\fR, or +\f(CWwindow\fR. This command returns the marker identifier, +used as the \fImarkerId\fR argument in the other marker-related +commands. If the \fB\-name\fR option is used, this overrides the +normal marker identifier. If the name provided is already used for +another marker, the new marker will replace the old. +.TP +\fIpathName \fBmarker delete\fR ?\fIname\fR?... +Removes one of more markers. The graph will automatically be redrawn +without the marker.\fR. +.TP +\fIpathName \fBmarker exists \fImarkerId\fR +Returns \f(CW1\fR if the marker \fImarkerId\fR exists and \f(CW0\fR +otherwise. +.TP +\fIpathName \fBmarker names\fR ?\fIpattern\fR? +Returns the names of all the markers that currently exist. If +\fIpattern\fR is supplied, only those markers whose names match it +will be returned. +.TP +\fIpathName \fBmarker type \fImarkerId\fR +Returns the type of the marker given by \fImarkerId\fR, such as +\f(CWline\fR or \f(CWtext\fR. If \fImarkerId\fR is not a valid a marker +identifier, \f(CW""\fR is returned. +.SS "BITMAP MARKERS" +A bitmap marker displays a bitmap. The size of the +bitmap is controlled by the number of coordinates specified. If two +coordinates, they specify the position of the top-left corner of the +bitmap. The bitmap retains its normal width and height. If four +coordinates, the first and second pairs of coordinates represent the +corners of the bitmap. The bitmap will be stretched or reduced as +necessary to fit into the bounding rectangle. +.PP +Bitmap markers are created with the marker's \fBcreate\fR operation in +the form: +.DS +\fIpathName \fBmarker create bitmap \fR?\fIoption value\fR?... +.DE +There may be many \fIoption\fR-\fIvalue\fR pairs, each +sets a configuration options for the marker. These +same \fIoption\fR\-\fIvalue\fR pairs may be used with the marker's +\fBconfigure\fR operation. +.PP +The following options are specific to bitmap markers: +.TP +\fB\-background \fIcolor\fR +Same as the \fB\-fill\fR option. +.TP +\fB\-bitmap \fIbitmap\fR +Specifies the bitmap to be displayed. If \fIbitmap\fR is \f(CW""\fR, +the marker will not be displayed. The default is \f(CW""\fR. +.TP +\fB\-fill \fIcolor\fR +Sets the background color of the bitmap. If \fIcolor\fR is the empty +string, no background will be transparent. The default background color is +\f(CW""\fR. +.TP +\fB\-foreground \fIcolor\fR +Same as the \fB\-outline\fR option. +.TP +\fB\-mask \fImask\fR +Specifies a mask for the bitmap to be displayed. This mask is a bitmap +itself, denoting the pixels that are transparent. If \fImask\fR is +\f(CW""\fR, all pixels of the bitmap will be drawn. The default is +\f(CW""\fR. +.TP +\fB\-outline \fIcolor\fR +Sets the foreground color of the bitmap. The default value is \f(CWblack\fR. +.TP +\fB\-rotate \fItheta\fR +Sets the rotation of the bitmap. \fITheta\fR is a real number +representing the angle of rotation in degrees. The marker is first +rotated and then placed according to its anchor position. The default +rotation is \f(CW0.0\fR. +.SS "IMAGE MARKERS" +A image marker displays an image. Image markers are +created with the marker's \fBcreate\fR operation in the form: +.DS +\fIpathName \fBmarker create image \fR?\fIoption value\fR?... +.DE +There may be many \fIoption\fR-\fIvalue\fR +pairs, each sets a configuration option +for the marker. These same \fIoption\fR\-\fIvalue\fR pairs may be +used with the marker's \fBconfigure\fR operation. +.PP +The following options are specific to image markers: +.TP +\fB\-anchor \fIanchor\fR +\fIAnchor\fR tells how to position the image relative to the +positioning point for the image. For example, if \fIanchor\fR +is \f(CWcenter\fR then the image is centered on the point; if +\fIanchor\fR is \f(CWn\fR then the image will be drawn such that +the top center point of the rectangular region occupied by the +image will be at the positioning point. +This option defaults to \f(CWcenter\fR. +.TP +\fB\-image \fIimage\fR +Specifies the image to be drawn. +If \fIimage\fR is \f(CW""\fR, the marker will not be +drawn. The default is \f(CW""\fR. +.SS "LINE MARKERS" +A line marker displays one or more connected line segments. +Line markers are created with marker's \fBcreate\fR operation in the form: +.DS +\fIpathName \fBmarker create line \fR?\fIoption value\fR?... +.DE +There may be many \fIoption\fR-\fIvalue\fR +pairs, each sets a configuration option +for the marker. These same \fIoption\fR-\fIvalue\fR pairs may be +used with the marker's \fBconfigure\fR operation. +.PP +The following options are specific to line markers: +.TP +\fB\-dashes \fIdashList\fR +Sets the dash style of the line. \fIDashList\fR is a list of up to 11 +numbers that alternately represent the lengths of the dashes and gaps +on the line. Each number must be between 1 and 255. If +\fIdashList\fR is \f(CW""\fR, the marker line will be solid. +.TP +\fB\-fill \fIcolor\fR +Sets the background color of the line. This color is used with +striped lines (see the \fB\-fdashes\fR option). If \fIcolor\fR is +the empty string, no background color is drawn (the line will be +dashed, not striped). The default background color is \f(CW""\fR. +.TP +\fB\-linewidth \fIpixels\fR +Sets the width of the lines. +The default width is \f(CW0\fR. +.TP +\fB\-outline \fIcolor\fR +Sets the foreground color of the line. The default value is \f(CWblack\fR. +.TP +\fB\-stipple \fIbitmap\fR +Specifies a stipple pattern used to draw the line, rather than +a solid line. +\fIBitmap\fR specifies a bitmap to use as the stipple +pattern. If \fIbitmap\fR is \f(CW""\fR, then the +line is drawn in a solid fashion. The default is \f(CW""\fR. +.SS "POLYGON MARKERS" +A polygon marker displays a closed region described as two or more +connected line segments. It is assumed the first and +last points are connected. Polygon markers are created using the +marker \fBcreate\fR operation in the form: +.DS +\fIpathName \fBmarker create polygon \fR?\fIoption value\fR?... +.DE +There may be many \fIoption\fR-\fIvalue\fR +pairs, each sets a configuration option +for the marker. These same \fIoption\fR\-\fIvalue\fR pairs may be +used with the \fBmarker configure\fR command to change the marker's +configuration. +The following options are supported for polygon markers: +.TP +\fB\-dashes \fIdashList\fR +Sets the dash style of the outline of the polygon. \fIDashList\fR is a +list of up to 11 numbers that alternately represent the lengths of +the dashes and gaps on the outline. Each number must be between 1 and +255. If \fIdashList\fR is \f(CW""\fR, the outline will be a solid line. +.TP +\fB\-fill \fIcolor\fR +Sets the fill color of the polygon. If \fIcolor\fR is \f(CW""\fR, then +the interior of the polygon is transparent. +The default is \f(CWwhite\fR. +.TP +\fB\-linewidth \fIpixels\fR +Sets the width of the outline of the polygon. If \fIpixels\fR is zero, +no outline is drawn. The default is \f(CW0\fR. +.TP +\fB\-outline \fIcolor\fR +Sets the color of the outline of the polygon. If the polygon is +stippled (see the \fB\-stipple\fR option), then this represents the +foreground color of the stipple. The default is \f(CWblack\fR. +.TP +\fB\-stipple \fIbitmap\fR +Specifies that the polygon should be drawn with a stippled pattern +rather than a solid color. \fIBitmap\fR specifies a bitmap to use as +the stipple pattern. If \fIbitmap\fR is \f(CW""\fR, then the polygon is +filled with a solid color (if the \fB\-fill\fR option is set). The +default is \f(CW""\fR. +.SS "TEXT MARKERS" +A text marker displays a string of characters on one or more lines of +text. Embedded newlines cause line breaks. They may be used to +annotate regions of the graph. Text markers are created with the +\fBcreate\fR operation in the form: +.DS +\fIpathName \fBmarker create text \fR?\fIoption value\fR?... +.DE +There may be many \fIoption\fR-\fIvalue\fR pairs, +each sets a configuration option for the text marker. +These same \fIoption\fR\-\fIvalue\fR pairs may be used with the +marker's \fBconfigure\fR operation. +.PP +The following options are specific to text markers: +.TP +\fB\-anchor \fIanchor\fR +\fIAnchor\fR tells how to position the text relative to the +positioning point for the text. For example, if \fIanchor\fR is +\f(CWcenter\fR then the text is centered on the point; if +\fIanchor\fR is \f(CWn\fR then the text will be drawn such that the +top center point of the rectangular region occupied by the text will +be at the positioning point. This default is \f(CWcenter\fR. +.TP +\fB\-background \fIcolor\fR +Same as the \fB\-fill\fR option. +.TP +\fB\-font \fIfontName\fR +Specifies the font of the text. The default is +\f(CW*-Helvetica-Bold-R-Normal-*-120-*\fR. +.TP +\fB\-fill \fIcolor\fR +Sets the background color of the text. If \fIcolor\fR is the empty +string, no background will be transparent. The default background color is +\f(CW""\fR. +.TP +\fB\-foreground \fIcolor\fR +Same as the \fB\-outline\fR option. +.TP +\fB\-justify \fIjustify\fR +Specifies how the text should be justified. This matters only when +the marker contains more than one line of text. \fIJustify\fR must be +\f(CWleft\fR, \f(CWright\fR, or \f(CWcenter\fR. The default is +\f(CWcenter\fR. +.TP +\fB\-outline \fIcolor\fR +Sets the color of the text. The default value is \f(CWblack\fR. +.TP +\fB\-padx \fIpad\fR +Sets the padding to the left and right exteriors of the text. +\fIPad\fR can be a list of one or two screen distances. If \fIpad\fR +has two elements, the left side of the text is padded by the first +distance and the right side by the second. If \fIpad\fR has just one +distance, both the left and right sides are padded evenly. The +default is \f(CW4\fR. +.TP +\fB\-pady \fIpad\fR +Sets the padding above and below the text. \fIPad\fR can be a list of +one or two screen distances. If \fIpad\fR has two elements, the area above the +text is padded by the first distance and the area below by the second. +If \fIpad\fR is just one distance, both the top and bottom areas +are padded evenly. The default is \f(CW4\fR. +.TP +\fB\-rotate \fItheta\fR +Specifies the number of degrees to rotate the text. \fITheta\fR is a +real number representing the angle of rotation. The marker is first +rotated along its center and is then drawn according to its anchor +position. The default is \f(CW0.0\fR. +.TP +\fB\-text \fItext\fR +Specifies the text of the marker. The exact way the text is +displayed may be affected by other options such as \fB\-anchor\fR or +\fB\-rotate\fR. +.SS "WINDOW MARKERS" +A window marker displays a widget at a given position. +Window markers are created with the marker's \fBcreate\fR operation in +the form: +.DS +\fIpathName \fBmarker create window \fR?\fIoption value\fR?... +.DE +There may be many \fIoption\fR-\fIvalue\fR +pairs, each sets a configuration option +for the marker. These same \fIoption\fR\-\fIvalue\fR pairs may be +used with the marker's \fBconfigure\fR command. +.PP +The following options are specific to window markers: +.TP +\fB\-anchor \fIanchor\fR +\fIAnchor\fR tells how to position the widget relative to the +positioning point for the widget. For example, if \fIanchor\fR is +\f(CWcenter\fR then the widget is centered on the point; if \fIanchor\fR +is \f(CWn\fR then the widget will be displayed such that the top center +point of the rectangular region occupied by the widget will be at the +positioning point. This option defaults to \f(CWcenter\fR. +.TP +\fB\-height \fIpixels\fR +Specifies the height to assign to the marker's window. If this option +isn't specified, or if it is specified as \f(CW""\fR, then the window is +given whatever height the widget requests internally. +.TP +\fB\-width \fIpixels\fR +Specifies the width to assign to the marker's window. If this option +isn't specified, or if it is specified as \f(CW""\fR, then the window is +given whatever width the widget requests internally. +.TP +\fB\-window \fIpathName\fR +Specifies the widget to be managed by the graph. \fIPathName\fR must +be a child of the \fBgraph\fR widget. +.SH "GRAPH COMPONENT BINDINGS" +Specific graph components, such as elements, markers and legend +entries, can have a command trigger when event occurs in them, much +like canvas items in Tk's canvas widget. Not all event sequences are +valid. The only binding events that may be specified are those +related to the mouse and keyboard (such as \fBEnter\fR, \fBLeave\fR, +\fBButtonPress\fR, \fBMotion\fR, and \fBKeyPress\fR). +.PP +Only one element or marker can be picked during an event. This means, +that if the mouse is directly over both an element and a marker, only +the uppermost component is selected. This isn't true for legend entries. +Both a legend entry and an element (or marker) binding commands +will be invoked if both items are picked. +.PP +It is possible for multiple bindings to match a particular event. +This could occur, for example, if one binding is associated with the +element name and another is associated with one of the element's tags +(see the \fB\-bindtags\fR option). When this occurs, all of the +matching bindings are invoked. A binding associated with the element +name is invoked first, followed by one binding for each of the element's +bindtags. If there are multiple matching bindings for a single tag, +then only the most specific binding is invoked. A continue command +in a binding script terminates that script, and a break command +terminates that script and skips any remaining scripts for the event, +just as for the bind command. +.PP +The \fB\-bindtags\fR option for these components controls addition +tag names which can be matched. Implicitly elements and markers +always have tags matching their names. Setting the value of +the \fB\-bindtags\fR option doesn't change this. +.SH "C LANGUAGE API" +You can manipulate data elements from the C language. There +may be situations where it is too expensive to translate the data +values from ASCII strings. Or you might want to read data in a +special file format. +.PP +Data can manipulated from the C language using BLT vectors. +You specify the X-Y data coordinates of an element as vectors and +manipulate the vector from C. The graph will be redrawn automatically +after the vectors are updated. +.PP +From Tcl, create the vectors and configure the element to use them. +.CS +vector X Y +\&.g element configure line1 -xdata X -ydata Y +.CE +To set data points from C, you pass the values as arrays of doubles +using the \fBBlt_ResetVector\fR call. The vector is reset with the +new data and at the next idle point (when Tk re-enters its event +loop), the graph will be redrawn automatically. +.CS +#include +#include + +register int i; +Blt_Vector *xVec, *yVec; +double x[50], y[50]; + +/* Get the BLT vectors "X" and "Y" (created above from Tcl) */ +if ((Blt_GetVector(interp, "X", &xVec) != TCL_OK) || + (Blt_GetVector(interp, "Y", &yVec) != TCL_OK)) { + return TCL_ERROR; +} + +for (i = 0; i < 50; i++) { + x[i] = i * 0.02; + y[i] = sin(x[i]); +} + +/* Put the data into BLT vectors */ +if ((Blt_ResetVector(xVec, x, 50, 50, TCL_VOLATILE) != TCL_OK) || + (Blt_ResetVector(yVec, y, 50, 50, TCL_VOLATILE) != TCL_OK)) { + return TCL_ERROR; +} +.CE +See the \fBvector\fR manual page for more details. +.SH SPEED TIPS +There may be cases where the graph needs to be drawn and updated as +quickly as possible. If drawing speed becomes a big +problem, here are a few tips to speed up displays. +.TP 2 +\(bu +Try to minimize the number of data points. The more data points +the looked at, the more work the graph must do. +.TP 2 +\(bu +If your data is generated as floating point values, the time required +to convert the data values to and from ASCII strings can be +significant, especially when there any many data points. You can +avoid the redundant string-to-decimal conversions using the C API to +BLT vectors. +.TP 2 +\(bu +Data elements without symbols are drawn faster than with symbols. +Set the data element's \fB\-symbol\fR option to \f(CWnone\fR. If you need to +draw symbols, try using the simple symbols such as \f(CWsplus\fR and +\f(CWscross\fR. +.TP 2 +\(bu +Don't stipple or dash the element. Solid lines are much faster. +.TP 2 +\(bu +If you update data elements frequently, try turning off the +widget's \fB\-bufferelements\fR option. When the graph is first +displayed, it draws data elements into an internal pixmap. The pixmap +acts as a cache, so that when the graph needs to be redrawn again, and +the data elements or coordinate axes haven't changed, the pixmap is +simply copied to the screen. This is especially useful when you are +using markers to highlight points and regions on the graph. But if +the graph is updated frequently, changing either the element data or +coordinate axes, the buffering becomes redundant. +.SH LIMITATIONS +Auto-scale routines do not use requested min/max limits as boundaries +when the axis is logarithmically scaled. +.PP +The PostScript output generated for polygons with more than 1500 +points may exceed the limits of some printers (See PostScript Language +Reference Manual, page 568). The work-around is to break the polygon +into separate pieces. +.SH KEYWORDS +graph, widget diff --git a/doc/vector.html b/doc/vector.html new file mode 100644 index 0000000..ef097c6 --- /dev/null +++ b/doc/vector.html @@ -0,0 +1,704 @@ + + +
+
+
+
+

SYNOPSIS

+       blt::vector create vecName ?vecName...? ?switches?
+
+       blt::vector destroy vecName ?vecName...?
+
+       blt::vector expr expression
+
+       blt::vector names ?pattern...?
+
+
+
+

DESCRIPTION

+       The vector command creates an array of floating point values.  The vec-
+       tor's components can be manipulated in three ways: through a Tcl  array
+       variable, a Tcl command, or the C API.
+
+
+
+

INTRODUCTION

+       A vector is an ordered set of real numbers.  The components of a vector
+       are indexed by integers.
+
+       Vectors are common data structures for many applications.  For example,
+       a  graph  may  use  two vectors to represent the X-Y coordinates of the
+       data plotted.  The graph will automatically be redrawn when the vectors
+       are  updated or changed. By using vectors, you can separate data analy-
+       sis from the graph widget.  This makes it easier, for example,  to  add
+       data  transformations, such as splines.  It's possible to plot the same
+       data to in multiple graphs, where each graph presents a different  view
+       or scale of the data.
+
+       You  could  try to use Tcl's associative arrays as vectors.  Tcl arrays
+       are easy to use.  You can access individual elements randomly by speci-
+       fying  the  index,  or  the set the entire array by providing a list of
+       index and value pairs for each element.  The disadvantages of  associa-
+       tive  arrays  as  vectors  lie in the fact they are implemented as hash
+       tables.
+
+       o There's no implied ordering to the associative arrays.  If  you  used
+         vectors  for  plotting, you would want to insure the second component
+         comes after the first, an so on.  This isn't  possible  since  arrays
+         are actually hash tables.  For example, you can't get a range of val-
+         ues between two indices.  Nor can you sort an array.
+
+       o Arrays consume lots of memory when the  number  of  elements  becomes
+         large  (tens of thousands).  This is because each element's index and
+         value are stored as strings in the hash table.
+
+       o The C programming interface is unwieldy.  Normally with vectors,  you
+         would  like to view the Tcl array as you do a C array, as an array of
+         floats or doubles.  But with hash tables, you must convert  both  the
+         index  and  value to and from decimal strings, just to access an ele-
+         ment in the array.  This makes it cumbersome to perform operations on
+         the array as a whole.
+
+       The  vector  command  tries to overcome these disadvantages while still
+       0.0.  In addition, both a Tcl command and array variable, both named y,
+       are created.  You can use either the command or variable  to  query  or
+       modify components of the vector.  # Set the first value.  set y(0) 9.25
+       puts "y has [y length] components" The array y can be used to  read  or
+       set individual components of the vector.  Vector components are indexed
+       from zero.  The array index must be a number less than  the  number  of
+       components.  For example, it's an error if you try to set the 51st ele-
+       ment of y.  # This is an error. The vector only has 50 components.  set
+       y(50) 0.02 You can also specify a range of indices using a colon (:) to
+       separate the first and last indices of the range.  # Set the first  six
+       components  of y set y(0:5) 25.2 If you don't include an index, then it
+       will default to the first and/or last component of the vector.  # Print
+       out  all  the  components  of y puts "y = $y(:)" There are special non-
+       numeric indices.  The index end, specifies the last  component  of  the
+       vector.  It's an error to use this index if the vector is empty (length
+       is zero).  The index ++end can be used to extend the vector by one com-
+       ponent  and initialize it to a specific value.  You can't read from the
+       array using this index, though.  # Extend the vector by one  component.
+       set  y(++end)  0.02  The  other  special indices are min and max.  They
+       return the current smallest and largest components of  the  vector.   #
+       Print the bounds of the vector puts "min=$y(min) max=$y(max)" To delete
+       components from a vector, simply unset the corresponding array element.
+       In the following example, the first component of y is deleted.  All the
+       remaining components of y will be moved down by one index as the length
+       of  the  vector  is reduced by one.  # Delete the first component unset
+       y(0) puts "new first element is $y(0)" The  vector's  Tcl  command  can
+       also  be  used to query or set the vector.  # Create and set the compo-
+       nents of a new vector blt::vector create x x set { 0.02 0.04 0.06  0.08
+       0.10 0.12 0.14 0.16 0.18 0.20 } Here we've created a vector x without a
+       initial length specification.  In this case, the length is  zero.   The
+       set  operation  resets  the vector, extending it and setting values for
+       each new component.
+
+       There are several operations for vectors.  The  range  operation  lists
+       the  components of a vector between two indices.  # List the components
+       puts "x = [x range 0 end]" You can search for a particular value  using
+       the  search  operation.  It returns a list of indices of the components
+       with the same value.  If no component has the same  value,  it  returns
+       "".   #  Find  the index of the biggest component set indices [x search
+       $x(max)] Other operations copy,  append,  or  sort  vectors.   You  can
+       append  vectors  or  new values onto an existing vector with the append
+       operation.  # Append assorted vectors and values to x x append x2 x3  {
+       2.3  4.5  }  x4 The sort operation sorts the vector.  If any additional
+       vectors are specified, they are rearranged in the  same  order  as  the
+       vector.   For example, you could use it to sort data points represented
+       by x and y vectors.  # Sort the data points x sort y The  vector  x  is
+       sorted  while  the  components of y are rearranged so that the original
+       x,y coordinate pairs are retained.
+
+       The expr operation lets you perform arithmetic on vectors.  The  result
+       is stored in the vector.  # Add the two vectors and a scalar x expr { x
+       + y } x expr { x * 2 } When a vector is modified, resized, or  deleted,
+       Vectors are created using the vector create operation.  Th create oper-
+       ation can be invoked in one of three forms:
+
+       blt::vector create vecName
+              This  creates a new vector vecName which initially has no compo-
+              nents.
+
+       blt::vector create vecName(size)
+              This second form creates a new vector which  will  contain  size
+              number  of  components.  The components will be indexed starting
+              from zero (0). The default value for the components is 0.0.
+
+       blt::vector create vecName(first:last)
+              The last form creates a new  vector  of  indexed  first  through
+              last.   First and last can be any integer value so long as first
+              is less than last.
+
+       Vector names must start with a letter and consist of  letters,  digits,
+       or  underscores.   #  Error:  must start with letter blt::vector create
+       1abc You can automatically generate vector names using the "#auto" vec-
+       tor  name.   The  create  operation will generate a unique vector name.
+       set vec [blt::vector create #auto] puts "$vec has [$vec length]  compo-
+       nents"
+
+   VECTOR INDICES
+       Vectors  are indexed by integers.  You can access the individual vector
+       components via its array variable or Tcl command.   The  string  repre-
+       senting  the index can be an integer, a numeric expression, a range, or
+       a special keyword.
+
+       The index must lie within the current range of the vector, otherwise an
+       an  error  message  is  returned.  Normally the indices of a vector are
+       start from 0.  But you can use the offset operation to  change  a  vec-
+       tor's  indices  on-the-fly.   puts  $vecName(0)  vecName offset -5 puts
+       $vecName(-5) You can also use  numeric  expressions  as  indices.   The
+       result  of  the expression must be an integer value.  set n 21 set vec-
+       Name($n+3) 50.2 The following special non-numeric  indices  are  avail-
+       able:  min,  max, end, and ++end.  puts "min = $vecName($min)" set vec-
+       Name(end) -1.2 The indices min and max will return the minimum and max-
+       imum values of the vector.  The index end returns the value of the last
+       component in the vector.  The index ++end is used to append  new  value
+       onto  the vector.  It automatically extends the vector by one component
+       and sets its value.  # Append an new component  to  the  end  set  vec-
+       Name(++end)  3.2 A range of indices can be indicated by a colon (:).  #
+       Set the first six components to 1.0 set vecName(0:5) 1.0 If no index is
+       supplied the first or last component is assumed.  # Print the values of
+       all the components puts $vecName(:)
+
+
+
+

VECTOR OPERATIONS

+       blt::vector create vecName?(size)?... ?switches?
+              The create operation creates a new vector vecName.  Both  a  Tcl
+              command  and  array variable vecName are also created.  The name
+                     then  no  variable  will be mapped.  You can always map a
+                     variable back to the vector using the  vector's  variable
+                     operation.
+
+              -command cmdName
+                     Maps  a  Tcl  command  to  the  vector. The vector can be
+                     accessed using cmdName and one  of  the  vector  instance
+                     operations.   A  Tcl  command by that name cannot already
+                     exist.  If cmdName is the empty string, no  command  map-
+                     ping will be made.
+
+              -watchunset boolean
+                     Indicates  that  the  vector  should automatically delete
+                     itself if the variable  associated  with  the  vector  is
+                     unset.  By default, the vector will not be deleted.  This
+                     is different from  previous  releases.   Set  boolean  to
+                     "true" to get the old behavior.
+
+       blt::vector destroy vecName ?vecName...?
+              Deletes  one  or  more  vectors.  Both the Tcl command and array
+              variable are removed also.
+
+       blt::vector expr expression
+              All binary operators take vectors  as  operands  (remember  that
+              numbers are treated as one-component vectors).  The exact action
+              of binary operators depends upon the length of the second  oper-
+              and.   If  the  second operand has only one component, then each
+              element of the first vector operand is computed by  that  value.
+              For  example,  the  expression "x * 2" multiples all elements of
+              the vector x by 2.  If the second operand has more than one com-
+              ponent,  both  operands  must  be the same length.  Each pair of
+              corresponding elements are computed.  So "x + y"  adds  the  the
+              first components of x and y together, the second, and so on.
+
+              The  valid  operators  are  listed  below, grouped in decreasing
+              order of precedence:
+
+              -  !                Unary minus  and  logical  NOT.   The  unary
+                                  minus  flips  the  sign of each component in
+                                  the  vector.   The  logical   not   operator
+                                  returns  a vector of whose values are 0.0 or
+                                  1.0.  For each  non-zero  component  1.0  is
+                                  returned, 0.0 otherwise.
+
+              ^                   Exponentiation.
+
+              *  /  %             Multiply, divide, remainder.
+
+              +  -                Add and subtract.
+
+              <<  >>              Left and right shift.  Circularly shifts the
+                                  values of the vector (not implemented  yet).
+
+              &&                  Logical AND.  Produces a 1  result  if  both
+                                  operands are non-zero, 0 otherwise.
+
+              ||                  Logical OR.  Produces a 0 result if both op-
+                                  erands are zero, 1 otherwise.
+
+              x?y:z               If-then-else, as  in  C.   (Not  implemented
+                                  yet).
+
+              See  the  C  manual  for more details on the results produced by
+              each operator.  All of the binary operators group  left-to-right
+              within the same precedence level.
+
+              Several  mathematical functions are supported for vectors.  Each
+              of the following functions invokes the math library function  of
+              the  same name; see the manual entries for the library functions
+              for details on what they do.  The operation is  applied  to  all
+              elements     of    the    vector    returning    the    results.
+              acos    cos     hypot   sinh        asin    cosh    log     sqrt
+              atan    exp     log10   tan ceil    floor   sin     tanh
+
+              Additional functions are:
+
+              abs       Returns the absolute value of each component.
+
+              random    Returns a vector of non-negative values uniformly dis-
+                        tributed between [0.0, 1.0) using drand48.   The  seed
+                        comes from the internal clock of the machine or may be
+                        set manual with the srandom function.
+
+              round     Rounds each component of the vector.
+
+              srandom   Initializes the random number generator using srand48.
+                        The high order 32-bits are set using the integral por-
+                        tion of the first vector component. All  other  compo-
+                        nents  are  ignored.  The low order 16-bits are set to
+                        an arbitrary value.
+
+              The following functions return a single value.
+
+              adev      Returns the average deviation (defined as the  sum  of
+                        the  absolute values of the differences between compo-
+                        nent and the mean, divided by the length of  the  vec-
+                        tor).
+
+              kurtosis  Returns  the  degree  of peakedness (fourth moment) of
+                        the vector.
+
+              length    Returns the number of components in the vector.
+
+              max       Returns the vector's maximum value.
+
+
+              skew      Returns  the skewness (or third moment) of the vector.
+                        This characterizes the degree of asymmetry of the vec-
+                        tor about the mean.
+
+              sum       Returns the sum of the components.
+
+              var       Returns  the  variance  of  the vector. The sum of the
+                        squared differences between  each  component  and  the
+                        mean  is computed.  The variance is the sum divided by
+                        the length of the vector minus 1.
+
+              The last set returns a vector of the same length  as  the  argu-
+              ment.
+
+              norm      Scales  the  values  of the vector to lie in the range
+                        [0.0..1.0].
+
+              sort      Returns the  vector  components  sorted  in  ascending
+                        order.
+
+       vector names ?pattern?
+
+
+
+

INSTANCE OPERATIONS

+       You  can  also use the vector's Tcl command to query or modify it.  The
+       general form is vecName operation  ?arg?...   Both  operation  and  its
+       arguments  determine the exact behavior of the command.  The operations
+       available for vectors are listed below.
+
+       vecName append item ?item?...
+              Appends the component values from item to vecName.  Item can  be
+              either the name of a vector or a list of numeric values.
+
+       vecName binread channel ?length? ?switches?
+              Reads  binary  values  from  a  Tcl  channel.  Values are either
+              appended to the end of the vector or placed  at  a  given  index
+              (using  the  -at  option), overwriting existing values.  Data is
+              read until EOF is found on the channel or a specified number  of
+              values  length  are  read (note that this is not necessarily the
+              same as the number of bytes). The following  switches  are  sup-
+              ported:
+
+              -swap  Swap  bytes  and  words.   The default endian is the host
+                     machine.
+
+              -at index
+                     New values will start at vector index index.   This  will
+                     overwrite any current values.
+
+              -format format
+                     Specifies  the  format of the data.  Format can be one of
+                     the following: "i1", "i2", "i4", "i8", "u1,  "u2",  "u4",
+
+              This is useful when the vector is large.
+
+       vecName delete index ?index?...
+              Deletes the indexth component from the vector vecName.  Index is
+              the  index  of  the  element to be deleted.  This is the same as
+              unsetting the array variable element index.  The vector is  com-
+              pacted after all the indices have been deleted.
+
+       vecName dup destName
+              Copies  vecName  to destName. DestName is the name of a destina-
+              tion vector.  If a vector destName already exists, it  is  over-
+              written  with the components of vecName.  Otherwise a new vector
+              is created.
+
+       vecName expr expression
+              Computes the expression and resets  the  values  of  the  vector
+              accordingly.    Both  scalar  and  vector  math  operations  are
+              allowed.  All values in expressions are either real  numbers  or
+              names of vectors.  All numbers are treated as one component vec-
+              tors.
+
+       vecName length ?newSize?
+              Queries or resets the number of components in vecName.   NewSize
+              is  a  number specifying the new size of the vector.  If newSize
+              is smaller than the current size of vecName,  vecName  is  trun-
+              cated.   If  newSize  is greater, the vector is extended and the
+              new components are initialized to 0.0.  If no  newSize  argument
+              is present, the current length of the vector is returned.
+
+       vecName merge srcName ?srcName?...
+              Merges  the  named  vectors into a single vector.  The resulting
+              vector is formed by merging the components of each source vector
+              one index at a time.
+
+       vecName notify keyword
+              Controls  how vector clients are notified of changes to the vec-
+              tor.  The exact behavior is determined by keyword.
+
+              always Indicates that clients are  to  be  notified  immediately
+                     whenever the vector is updated.
+
+              never  Indicates that no clients are to be notified.
+
+              whenidle
+                     Indicates  that  clients  are  to be notified at the next
+                     idle point whenever the vector is updated.
+
+              now    If any client notifications is  currently  pending,  they
+                     are notified immediately.
+
+              cancel Cancels  pending  notifications of clients using the vec-
+                     tor.
+
+              density number of new components, whose values are  evenly  dis-
+              tributed between the original components values.  This is useful
+              for generating abscissas to be interpolated along a spline.
+
+       vecName range firstIndex ?lastIndex?...
+              Returns a list of numeric values representing the vector  compo-
+              nents  between  two  indices.  Both firstIndex and lastIndex are
+              indices representing the range of components to be returned.  If
+              lastIndex  is less than firstIndex, the components are listed in
+              reverse order.
+
+       vecName search value ?value?
+              Searches for a value or range of values among the components  of
+              vecName.   If  one value argument is given, a list of indices of
+              the components which equal value is returned.  If a second value
+              is  also  provided, then the indices of all components which lie
+              within the range of the two values are returned.  If  no  compo-
+              nents are found, then "" is returned.
+
+       vecName set item
+              Resets  the components of the vector to item. Item can be either
+              a list of numeric expressions or another vector.
+
+       vecName seq start ?finish? ?step?
+              Generates a sequence of values starting with  the  value  start.
+              Finish  indicates  the  terminating  value of the sequence.  The
+              vector is automatically resized to contain  just  the  sequence.
+              If three arguments are present, step designates the interval.
+
+              With  only two arguments (no finish argument), the sequence will
+              continue until the vector is filled.   With  one  argument,  the
+              interval defaults to 1.0.
+
+       vecName sort ?-reverse? ?argName?...
+              Sorts  the  vector vecName in increasing order.  If the -reverse
+              flag is present, the vector is sorted in decreasing  order.   If
+              other  arguments argName are present, they are the names of vec-
+              tors which will be rearranged in the  same  manner  as  vecName.
+              Each  vector  must be the same length as vecName.  You could use
+              this to sort the x vector of a graph, while still retaining  the
+              same x,y coordinate pairs in a y vector.
+
+       vecName variable varName
+              Maps  a  Tcl  variable to the vector, creating another means for
+              accessing the vector.  The variable varName can't already exist.
+              This overrides any current variable mapping the vector may have.
+
+
+
+

C LANGUAGE API

+       You can create, modify, and destroy vectors from C code, using  library
+       routines.   You  need to include the header file blt.h. It contains the
+       definition of the structure Blt_Vector, which  represents  the  vector.
+       It appears below.  typedef struct {
+       Blt_CreateVector
+
+         Synopsis: int Blt_CreateVector (interp, vecName, length, vecPtrPtr)
+                      Tcl_Interp  *interp; char *vecName; int length; Blt_Vec-
+                      tor **vecPtrPtr;
+
+         Description:
+                   Creates a new vector  vecName  with  a  length  of  length.
+                   Blt_CreateVector  creates  both a new Tcl command and array
+                   variable vecName.  Neither a  command  nor  variable  named
+                   vecName  can  already  exist.   A  pointer to the vector is
+                   placed into vecPtrPtr.
+
+         Results:  Returns TCL_OK if the vector is successfully  created.   If
+                   length  is  negative,  a  Tcl  variable  or command vecName
+                   already exists, or memory cannot be allocated for the  vec-
+                   tor,  then  TCL_ERROR  is  returned and interp->result will
+                   contain an error message.
+
+
+       Blt_DeleteVectorByName
+
+         Synopsis: int Blt_DeleteVectorByName (interp, vecName)
+                      Tcl_Interp *interp; char *vecName;
+
+         Description:
+                   Removes the vector vecName.  VecName is the name of a  vec-
+                   tor  which  must  already  exist.  Both the Tcl command and
+                   array variable vecName are destroyed.  All clients  of  the
+                   vector  will  be  notified  immediately that the vector has
+                   been destroyed.
+
+         Results:  Returns TCL_OK if the vector is successfully  deleted.   If
+                   vecName  is  not  the  name  a  vector,  then  TCL_ERROR is
+                   returned and interp->result will contain an error  message.
+
+
+       Blt_DeleteVector
+
+         Synopsis: int Blt_DeleteVector (vecPtr)
+                      Blt_Vector *vecPtr;
+
+         Description:
+                   Removes  the  vector  pointed  to  by  vecPtr.  VecPtr is a
+                   pointer to a vector,  typically  set  by  Blt_GetVector  or
+                   Blt_CreateVector.   Both the Tcl command and array variable
+                   of the vector are destroyed.  All  clients  of  the  vector
+                   will  be  notified  immediately  that  the  vector has been
+                   destroyed.
+
+         Results:  Returns TCL_OK if the vector is successfully  deleted.   If
+                   vecName  is  not  the  name  a  vector,  then  TCL_ERROR is
+
+         Results:  Returns TCL_OK if the vector is successfully retrieved.  If
+                   vecName  is  not  the  name  of a vector, then TCL_ERROR is
+                   returned and interp->result will contain an error  message.
+
+
+       Blt_ResetVector
+
+
+         Synopsis: int  Blt_ResetVector  (vecPtr,  dataArr,         numValues,
+                   arraySize, freeProc)
+                      Blt_Vector *vecPtr; double *dataArr; int *numValues; int
+                      *arraySize; Tcl_FreeProc *freeProc;
+
+         Description:
+                   Resets  the  components of the vector pointed to by vecPtr.
+                   Calling Blt_ResetVector will trigger the vector to dispatch
+                   notifications  to its clients. DataArr is the array of dou-
+                   bles which represents the vector  data.  NumValues  is  the
+                   number  of  elements  in the array. ArraySize is the actual
+                   size of the array (the array may be bigger than the  number
+                   of values stored in it). FreeProc indicates how the storage
+                   for the vector component array (dataArr) was allocated.  It
+                   is used to determine how to reallocate memory when the vec-
+                   tor is resized  or  destroyed.   It  must  be  TCL_DYNAMIC,
+                   TCL_STATIC,  TCL_VOLATILE,  or  a  pointer to a function to
+                   free the memory allocated for the vector array. If freeProc
+                   is  TCL_VOLATILE,  it indicates that dataArr must be copied
+                   and saved.  If freeProc is TCL_DYNAMIC, it  indicates  that
+                   dataArr  was dynamically allocated and that Tcl should free
+                   dataArr if necessary.  Static indicates that nothing should
+                   be done to release storage for dataArr.
+
+         Results:  Returns  TCL_OK  if the vector is successfully resized.  If
+                   newSize is negative, a vector vecName does  not  exist,  or
+                   memory  cannot  be allocated for the vector, then TCL_ERROR
+                   is returned and interp->result will contain an  error  mes-
+                   sage.
+
+
+       Blt_ResizeVector
+
+         Synopsis: int Blt_ResizeVector (vecPtr, newSize)
+                      Blt_Vector *vecPtr; int newSize;
+
+         Description:
+                   Resets  the  length  of  the vector pointed to by vecPtr to
+                   newSize.  If newSize is smaller than the  current  size  of
+                   the  vector,  it  is truncated.  If newSize is greater, the
+                   vector is extended and the new components  are  initialized
+                   to 0.0.  Calling Blt_ResetVector will trigger the vector to
+                   dispatch notifications.
+
+            Results:  Returns 1 if a vector vecName exists and 0 otherwise.
+
+
+         If  your  application  needs to be notified when a vector changes, it
+         can allocate a unique client identifier for itself.  Using this iden-
+         tifier,  you  can  then  register a call-back to be made whenever the
+         vector is updated or destroyed.  By default, the call-backs are  made
+         at the next idle point.  This can be changed to occur at the time the
+         vector is modified.  An application can allocate more than one  iden-
+         tifier  for any vector.  When the client application is done with the
+         vector, it should free the identifier.
+
+         The call-back routine must of the following type.
+
+                typedef void (Blt_VectorChangedProc) (Tcl_Interp *interp,
+                   ClientData clientData, Blt_VectorNotify notify);
+
+         ClientData is passed to this routine whenever it is called.  You  can
+         use  this  to pass information to the call-back.  The notify argument
+         indicates whether the vector has been updated of destroyed. It is  an
+         enumerated type.
+
+                typedef enum {
+                    BLT_VECTOR_NOTIFY_UPDATE=1,
+                    BLT_VECTOR_NOTIFY_DESTROY=2 } Blt_VectorNotify;
+
+
+         Blt_AllocVectorId
+
+            Synopsis: Blt_VectorId Blt_AllocVectorId (interp, vecName)
+                        Tcl_Interp *interp; char *vecName;
+
+            Description:
+                      Allocates  an client identifier for with the vector vec-
+                      Name.  This identifier can be used to  specify  a  call-
+                      back  which  is  triggered when the vector is updated or
+                      destroyed.
+
+            Results:  Returns a client identifier if successful.   If  vecName
+                      is  not  the name of a vector, then NULL is returned and
+                      interp->result will contain an error message.
+
+
+         Blt_GetVectorById
+
+            Synopsis: int Blt_GetVector (interp, clientId, vecPtrPtr)
+                        Tcl_Interp *interp; Blt_VectorId clientId;  Blt_Vector
+                        **vecPtrPtr;
+
+            Description:
+                      Retrieves  the  vector  used by clientId.  ClientId is a
+                      valid   vector   client    identifier    allocated    by
+                      Specifies  a call-back routine to be called whenever the
+                      vector associated with clientId is updated  or  deleted.
+                      Proc  is  a  pointer to call-back routine and must be of
+                      the type Blt_VectorChangedProc.  ClientData  is  a  one-
+                      word  value  to  be  passed  to  the  routine when it is
+                      invoked. If proc is NULL, then the client is  not  noti-
+                      fied.
+
+            Results:  The  designated call-back procedure will be invoked when
+                      the vector is updated or destroyed.
+
+
+         Blt_FreeVectorId
+
+            Synopsis: void Blt_FreeVectorId (clientId);
+                        Blt_VectorId clientId;
+
+            Description:
+                      Frees the client identifier.  Memory allocated  for  the
+                      identifier  is  released.   The client will no longer be
+                      notified when the vector is modified.
+
+            Results:  The designated call-back procedure will be no longer  be
+                      invoked when the vector is updated or destroyed.
+
+
+         Blt_NameOfVectorId
+
+            Synopsis: char *Blt_NameOfVectorId (clientId);
+                        Blt_VectorId clientId;
+
+            Description:
+                      Retrieves  the  name  of  the vector associated with the
+                      client identifier clientId.
+
+            Results:  Returns the name of the vector associated with clientId.
+                      If  clientId is not an identifier or the vector has been
+                      destroyed, NULL is returned.
+
+
+         Blt_InstallIndexProc
+
+            Synopsis: void Blt_InstallIndexProc (indexName, procPtr)
+                        char *indexName; Blt_VectorIndexProc *procPtr;
+
+            Description:
+                      Registers a function to be called to retrieved the index
+                      indexName from the vector's array variable.
+
+                      typedef double Blt_VectorIndexProc(Vector *vecPtr);
+
+                      The  function  will  be  passed a pointer to the vector.
+
+       reset  shortly.  The  vector  is updated when lt_ResetVector is called.
+       Blt_ResetVector makes the changes visible  to  the  Tcl  interface  and
+       other vector clients (such as a graph widget).
+
+       #include  <tcl.h>  #include  <blt.h>         Blt_Vector *vecPtr; double
+       *newArr; FILE *f; struct stat statBuf; int numBytes, numValues;
+
+       f = fopen("binary.dat", "r"); fstat(fileno(f),  &statBuf);  numBytes  =
+       (int)statBuf.st_size;
+
+       /*  Allocate an array big enough to hold all the data */ newArr = (dou-
+       ble  *)malloc(numBytes);  numValues  =   numBytes   /   sizeof(double);
+       fread((void *)newArr, numValues, sizeof(double), f); fclose(f);
+
+       if (Blt_VectorExists(interp, "data"))  {
+           if   (Blt_GetVector(interp,   "data",   &vecPtr)   !=   TCL_OK)   {
+               return TCL_ERROR;
+           } } else {
+          if  (Blt_CreateVector(interp,  "data",  0,  &vecPtr)  !=  TCL_OK)  {
+               return TCL_ERROR;
+          } } /*
+        * Reset the vector. Clients will be notified when Tk is idle.
+        * TCL_DYNAMIC tells the vector to free the memory allocated
+        * if it needs to reallocate or destroy the vector.
+        */   if   (Blt_ResetVector(vecPtr,   newArr,   numValues,   numValues,
+               TCL_DYNAMIC) != TCL_OK) {
+           return TCL_ERROR; }
+
+
+
+

INCOMPATIBILITIES

+       In previous versions, if the array variable isn't global (i.e. local to
+       a Tcl procedure), the vector is automatically destroyed when the proce-
+       dure returns.  proc doit {} {
+           # Temporary vector x
+           vector x(10)
+           set x(9) 2.0
+             ...  }
+
+       This has changed.  Variables are not automatically destroyed when their
+       variable  is  unset.   You  can restore the old behavior by setting the
+       "-watchunset" switch.
+
+
+
+

KEYWORDS

+       vector, graph, widget
+
+
+
+BLT                               BLT_VERSION                   blt::vector(n)
+
+
+
+Man(1) output converted with +man2html +
+ + diff --git a/doc/vector.n b/doc/vector.n new file mode 100644 index 0000000..fa8bb7e --- /dev/null +++ b/doc/vector.n @@ -0,0 +1,1134 @@ +'\" +'\" Smithsonian Astrophysical Observatory, Cambridge, MA, USA +'\" This code has been modified under the terms listed below and is made +'\" available under the same terms. +'\" +'\" Copyright 1991-1997 by Lucent Technologies, Inc. +'\" +'\" Permission to use, copy, modify, and distribute this software and its +'\" documentation for any purpose and without fee is hereby granted, provided +'\" that the above copyright notice appear in all copies and that both that the +'\" copyright notice and warranty disclaimer appear in supporting documentation, +'\" and that the names of Lucent Technologies any of their entities not be used +'\" in advertising or publicity pertaining to distribution of the software +'\" without specific, written prior permission. +'\" +'\" Lucent Technologies disclaims all warranties with regard to this software, +'\" including all implied warranties of merchantability and fitness. In no event +'\" shall Lucent Technologies be liable for any special, indirect or +'\" consequential damages or any damages whatsoever resulting from loss of use, +'\" data or profits, whether in an action of contract, negligence or other +'\" tortuous action, arising out of or in connection with the use or performance +'\" of this software. +'\" +'\" Vector command created by George Howlett. +'\" +.TH blt::vector n BLT_VERSION BLT "BLT Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +\fBvector\fR \- Vector data type for Tcl +.SH SYNOPSIS +\fBblt::vector create \fIvecName \fR?\fIvecName\fR...? ?\fIswitches\fR? +.sp +\fBblt::vector destroy \fIvecName \fR?\fIvecName\fR...? +.sp +\fBblt::vector expr \fIexpression\fR +.sp +\fBblt::vector names \fR?\fIpattern\fR...? +.BE +.SH DESCRIPTION +The \fBvector\fR command creates an array of floating point +values. The vector's components can be manipulated in three ways: +through a Tcl array variable, a Tcl command, or the C API. +.SH INTRODUCTION +A vector is an ordered set of real numbers. The components of a +vector are indexed by integers. +.PP +Vectors are common data structures for many applications. For +example, a graph may use two vectors to represent the X-Y +coordinates of the data plotted. The graph will automatically +be redrawn when the vectors are updated or changed. By using vectors, +you can separate +data analysis from the graph widget. This makes it easier, for +example, to add data transformations, such as splines. It's possible +to plot the same data to in multiple graphs, where each graph presents +a different view or scale of the data. +.PP +You could try to use Tcl's associative arrays as vectors. Tcl arrays +are easy to use. You can access individual elements randomly by +specifying the index, or the set the entire array by providing a list +of index and value pairs for each element. The disadvantages of +associative arrays as vectors lie in the fact they are implemented as +hash tables. +.TP 2 +\(bu +There's no implied ordering to the associative arrays. If you used +vectors for plotting, you would want to insure the second component +comes after the first, an so on. This isn't possible since arrays +are actually hash tables. For example, you can't get a range of +values between two indices. Nor can you sort an array. +.TP 2 +\(bu +Arrays consume lots of memory when the number of elements becomes +large (tens of thousands). This is because each element's index and +value are stored as strings in the hash table. +.TP 2 +\(bu +The C programming interface is unwieldy. Normally with vectors, you +would like to view the Tcl array as you do a C array, as an array of +floats or doubles. But with hash tables, you must convert both the +index and value to and from decimal strings, just to access +an element in the array. This makes it cumbersome to perform operations on +the array as a whole. +.PP +The \fBvector\fR command tries to overcome these disadvantages while +still retaining the ease of use of Tcl arrays. The \fBvector\fR +command creates both a new Tcl command and associate array which are +linked to the vector components. You can randomly access vector +components though the elements of array. Not have all indices are +generated for the array, so printing the array (using the \fBparray\fR +procedure) does not print out all the component values. You can use +the Tcl command to access the array as a whole. You can copy, append, +or sort vector using its command. If you need greater performance, or +customized behavior, you can write your own C code to manage vectors. +.SH EXAMPLE +You create vectors using the \fBvector\fR command and its \fBcreate\fR +operation. +.CS +# Create a new vector. +blt::vector create y(50) +.CE +This creates a new vector named \f(CWy\fR. It has fifty components, by +default, initialized to \f(CW0.0\fR. In addition, both a Tcl command +and array variable, both named \f(CWy\fR, are created. You can use +either the command or variable to query or modify components of the +vector. +.CS +# Set the first value. +set y(0) 9.25 +puts "y has [y length] components" +.CE +The array \f(CWy\fR can be used to read or set individual components of +the vector. Vector components are indexed from zero. The array index +must be a number less than the number of components. For example, +it's an error if you try to set the 51st element of \f(CWy\fR. +.CS +# This is an error. The vector only has 50 components. +set y(50) 0.02 +.CE +You can also specify a range of indices using a colon (:) to separate +the first and last indices of the range. +.CS +# Set the first six components of y +set y(0:5) 25.2 +.CE +If you don't include an index, then it will default to the first +and/or last component of the vector. +.CS +# Print out all the components of y +puts "y = $y(:)" +.CE +There are special non-numeric indices. The index \f(CWend\fR, specifies +the last component of the vector. It's an error to use this index if +the vector is empty (length is zero). The index \f(CW++end\fR can be +used to extend the vector by one component and initialize it to a specific +value. You can't read from the array using this index, though. +.CS +# Extend the vector by one component. +set y(++end) 0.02 +.CE +The other special indices are \f(CWmin\fR and \f(CWmax\fR. They return the +current smallest and largest components of the vector. +.CS +# Print the bounds of the vector +puts "min=$y(min) max=$y(max)" +.CE +To delete components from a vector, simply unset the corresponding +array element. In the following example, the first component of +\f(CWy\fR is deleted. All the remaining components of \f(CWy\fR will be +moved down by one index as the length of the vector is reduced by +one. +.CS +# Delete the first component +unset y(0) +puts "new first element is $y(0)" +.CE +The vector's Tcl command can also be used to query or set the vector. +.CS +# Create and set the components of a new vector +blt::vector create x +x set { 0.02 0.04 0.06 0.08 0.10 0.12 0.14 0.16 0.18 0.20 } +.CE +Here we've created a vector \f(CWx\fR without a initial length specification. +In this case, the length is zero. The \fBset\fR operation resets the vector, +extending it and setting values for each new component. +.PP +There are several operations for vectors. The \fBrange\fR operation +lists the components of a vector between two indices. +.CS +# List the components +puts "x = [x range 0 end]" +.CE +You can search for a particular value using the \fBsearch\fR +operation. It returns a list of indices of the components with the +same value. If no component has the same value, it returns \f(CW""\fR. +.CS +# Find the index of the biggest component +set indices [x search $x(max)] +.CE +Other operations copy, append, or sort vectors. You can append +vectors or new values onto an existing vector with the \fBappend\fR +operation. +.CS +# Append assorted vectors and values to x +x append x2 x3 { 2.3 4.5 } x4 +.CE +The \fBsort\fR operation sorts the vector. If any additional vectors +are specified, they are rearranged in the same order as the vector. +For example, you could use it to sort data points represented by x and +y vectors. +.CS +# Sort the data points +x sort y +.CE +The vector \f(CWx\fR is sorted while the components of \f(CWy\fR are +rearranged so that the original x,y coordinate pairs are retained. +.PP +The \fBexpr\fR operation lets you perform arithmetic on vectors. +The result is stored in the vector. +.CS +# Add the two vectors and a scalar +x expr { x + y } +x expr { x * 2 } +.CE +When a vector is modified, resized, or deleted, it may trigger +call-backs to notify the clients of the vector. For example, when a +vector used in the \fBgraph\fR widget is updated, the vector +automatically notifies the widget that it has changed. The graph can +then redrawn itself at the next idle point. By default, the +notification occurs when Tk is next idle. This way you can modify the +vector many times without incurring the penalty of the graph redrawing +itself for each change. You can change this behavior using the +\fBnotify\fR operation. +.CS +# Make vector x notify after every change +x notify always + ... +# Never notify +x notify never + ... +# Force notification now +x notify now +.CE +To delete a vector, use the \fBvector delete\fR command. +Both the vector and its corresponding Tcl command are destroyed. +.CS +# Remove vector x +blt::vector destroy x +.CE +.SH SYNTAX +Vectors are created using the \fBvector create\fR operation. +Th \fBcreate\fR operation can be invoked in one of three forms: +.TP +\fBblt::vector create \fIvecName\fR +This creates a new vector \fIvecName\fR which initially has no components. +.TP +\fBblt::vector create \fIvecName\fR(\fIsize\fR) +This second form creates a new vector which will contain \fIsize\fR +number of components. The components will be indexed starting from +zero (0). The default value for the components is \f(CW0.0\fR. +.TP +\fBblt::vector create \fIvecName\fR(\fIfirst\fR:\fIlast\fR) +The last form creates a new vector of indexed \fIfirst\fR through +\fIlast\fR. \fIFirst\fR and \fIlast\fR can be any integer value +so long as \fIfirst\fR is less than \fIlast\fR. +.PP +Vector names must start with a letter and consist of letters, digits, +or underscores. +.CS +# Error: must start with letter +blt::vector create 1abc +.CE +You can automatically generate vector names using the +"\f(CW#auto\fR" vector name. The \fBcreate\fR operation will generate a +unique vector name. +.CS +set vec [blt::vector create #auto] +puts "$vec has [$vec length] components" +.CE +.SS VECTOR INDICES +Vectors are indexed by integers. You can access the individual vector +components via its array variable or Tcl command. The string +representing the index can be an integer, a numeric expression, a +range, or a special keyword. +.PP +The index must lie within the current range of the vector, otherwise +an an error message is returned. Normally the indices of a vector +are start from 0. But you can use the \fBoffset\fR operation to +change a vector's indices on-the-fly. +.CS +puts $vecName(0) +vecName offset -5 +puts $vecName(-5) +.CE +You can also use numeric expressions as indices. The result +of the expression must be an integer value. +.CS +set n 21 +set vecName($n+3) 50.2 +.CE +The following special non-numeric indices are available: \f(CWmin\fR, \f(CWmax\fR, \f(CWend\fR, and +\f(CW++end\fR. +.CS +puts "min = $vecName($min)" +set vecName(end) -1.2 +.CE +The indices \f(CWmin\fR and \f(CWmax\fR will return the minimum and maximum +values of the vector. The index \f(CWend\fR returns the value of the +last component in the vector. The index \f(CW++end\fR is used to append +new value onto the vector. It automatically extends the vector by +one component and sets its value. +.CS +# Append an new component to the end +set vecName(++end) 3.2 +.CE +A range of indices can be indicated by a colon (:). +.CS +# Set the first six components to 1.0 +set vecName(0:5) 1.0 +.CE +If no index is supplied the first or last component is assumed. +.CS +# Print the values of all the components +puts $vecName(:) +.CE +.SH VECTOR OPERATIONS +.TP +\fBblt::vector create \fIvecName\fR?(\fIsize\fR)?... \fR?\fIswitches\fR? +The \fBcreate\fR operation creates a new vector \fIvecName\fR. Both a +Tcl command and array variable \fIvecName\fR are also created. The +name \fIvecName\fR must be unique, so another Tcl command or array +variable can not already exist in that scope. You can access the +components of the vector using its variable. If you change a value in +the array, or unset an array element, the vector is updated to reflect +the changes. When the variable \fIvecName\fR is unset, the vector and +its Tcl command are also destroyed. +.sp +The vector has optional switches that affect how the vector is created. They +are as follows: +.RS +.TP +\fB\-variable \fIvarName\fR +Specifies the name of a Tcl variable to be mapped to the vector. If +the variable already exists, it is first deleted, then recreated. +If \fIvarName\fR is the empty string, then no variable will be mapped. +You can always map a variable back to the vector using the vector's +\fBvariable\fR operation. +.TP +\fB\-command \fIcmdName\fR +Maps a Tcl command to the vector. The vector can be accessed using +\fIcmdName\fR and one of the vector instance operations. +A Tcl command by that name cannot already exist. +If \fIcmdName\fR is the empty string, no command mapping +will be made. +.TP +\fB\-watchunset \fIboolean\fR +Indicates that the vector should automatically delete itself if +the variable associated with the vector is unset. By default, +the vector will not be deleted. This is different from previous +releases. Set \fIboolean\fR to "true" to get the old behavior. +.RE +.TP +\fBblt::vector destroy \fIvecName\fR \fR?\fIvecName...\fR? +Deletes one or more vectors. Both the Tcl command and array variable +are removed also. +.TP +\fBblt::vector expr \fIexpression\fR +.RS +All binary operators take vectors as operands (remember that numbers +are treated as one-component vectors). The exact action of binary +operators depends upon the length of the second operand. If the +second operand has only one component, then each element of the first +vector operand is computed by that value. For example, the expression +"x * 2" multiples all elements of the vector x by 2. If the second +operand has more than one component, both operands must be the same +length. Each pair of corresponding elements are computed. So "x + y" +adds the the first components of x and y together, the second, and so on. +.sp +The valid operators are listed below, grouped in decreasing order +of precedence: +.TP 20 +\fB\-\0\0!\fR +Unary minus and logical NOT. The unary minus flips the sign of each +component in the vector. The logical not operator returns a vector of +whose values are 0.0 or 1.0. For each non-zero component 1.0 is returned, +0.0 otherwise. +.TP 20 +\fB^\fR +Exponentiation. +.TP 20 +\fB*\0\0/\0\0%\fR +Multiply, divide, remainder. +.TP 20 +\fB+\0\0\-\fR +Add and subtract. +.TP 20 +\fB<<\0\0>>\fR +Left and right shift. Circularly shifts the values of the vector +(not implemented yet). +.TP 20 +\fB<\0\0>\0\0<=\0\0>=\fR +Boolean less, greater, less than or equal, and greater than or equal. +Each operator returns a vector of ones and zeros. If the condition is true, +1.0 is the component value, 0.0 otherwise. +.TP 20 +\fB==\0\0!=\fR +Boolean equal and not equal. +Each operator returns a vector of ones and zeros. If the condition is true, +1.0 is the component value, 0.0 otherwise. +.TP 20 +\fB|\fR +Bit-wise OR. (Not implemented). +.TP 20 +\fB&&\fR +Logical AND. Produces a 1 result if both operands are non-zero, 0 otherwise. +.TP 20 +\fB||\fR +Logical OR. Produces a 0 result if both operands are zero, 1 otherwise. +.TP 20 +\fIx\fB?\fIy\fB:\fIz\fR +If-then-else, as in C. (Not implemented yet). +.LP +See the C manual for more details on the results produced by each +operator. All of the binary operators group left-to-right within the +same precedence level. +.sp +Several mathematical functions are supported for vectors. Each of +the following functions invokes the math library function of the same name; +see the manual entries for the library functions for details on what +they do. The operation is applied to all elements of the vector +returning the results. +.CS +.ta 2c 4c 6c +\fBacos\fR \fBcos\fR \fBhypot\fR \fBsinh\fR +\fBasin\fR \fBcosh\fR \fBlog\fR \fBsqrt\fR +\fBatan\fR \fBexp\fR \fBlog10\fR \fBtan\fR +\fBceil\fR \fBfloor\fR \fBsin\fR \fBtanh\fR +.sp +.CE +Additional functions are: +.TP 1i +\fBabs\fR +Returns the absolute value of each component. +.TP 1i +\fBrandom\fR +Returns a vector of non-negative values uniformly distributed +between [0.0, 1.0) using \fIdrand48\fR. +The seed comes from the internal clock of the machine or may be +set manual with the srandom function. +.TP 1i +\fBround\fR +Rounds each component of the vector. +.TP 1i +\fBsrandom\fR +Initializes the random number generator using \fIsrand48\fR. +The high order 32-bits are set using the integral portion of the first +vector component. All other components are ignored. The low order 16-bits +are set to an arbitrary value. +.PP +The following functions return a single value. +.TP 1i +\fBadev\fR +Returns the average deviation (defined as the sum of the absolute values +of the differences between component and the mean, divided by the length +of the vector). +.TP 1i +\fBkurtosis\fR +Returns the degree of peakedness (fourth moment) of the vector. +.TP 1i +\fBlength\fR +Returns the number of components in the vector. +.TP 1i +\fBmax\fR +Returns the vector's maximum value. +.TP 1i +\fBmean\fR +Returns the mean value of the vector. +.TP 1i +\fBmedian\fR +Returns the median of the vector. +.TP 1i +\fBmin\fR +Returns the vector's minimum value. +.TP 1i +\fBq1\fR +Returns the first quartile of the vector. +.TP 1i +\fBq3\fR +Returns the third quartile of the vector. +.TP 1i +\fBprod\fR +Returns the product of the components. +.TP 1i +\fBsdev\fR +Returns the standard deviation (defined as the square root of the variance) +of the vector. +.TP 1i +\fBskew\fR +Returns the skewness (or third moment) of the vector. This characterizes +the degree of asymmetry of the vector about the mean. +.TP 1i +\fBsum\fR +Returns the sum of the components. +.TP 1i +\fBvar\fR +Returns the variance of the vector. The sum of the squared differences +between each component and the mean is computed. The variance is +the sum divided by the length of the vector minus 1. +.PP +The last set returns a vector of the same length as the argument. +.TP 1i +\fBnorm\fR +Scales the values of the vector to lie in the range [0.0..1.0]. +.TP 1i +\fBsort\fR +Returns the vector components sorted in ascending order. +.RE +.TP +\fBvector names \fR?\fIpattern\fR? +.SH INSTANCE OPERATIONS +You can also use the vector's Tcl command to query or modify it. The +general form is +.DS +\fIvecName \fIoperation\fR \fR?\fIarg\fR?... +.DE +Both \fIoperation\fR and its arguments determine the exact behavior of +the command. The operations available for vectors are listed below. +.TP +\fIvecName \fBappend\fR \fIitem\fR ?\fIitem\fR?... +Appends the component values from \fIitem\fR to \fIvecName\fR. +\fIItem\fR can be either the name of a vector or a list of numeric +values. +.TP +\fIvecName \fBbinread\fR \fIchannel\fR ?\fIlength\fR? ?\fIswitches\fR? +Reads binary values from a Tcl channel. Values are either appended +to the end of the vector or placed at a given index (using the +\fB\-at\fR option), overwriting existing values. Data is read until EOF +is found on the channel or a specified number of values \fIlength\fR +are read (note that this is not necessarily the same as the number of +bytes). The following switches are supported: +.RS +.TP +\fB\-swap\fR +Swap bytes and words. The default endian is the host machine. +.TP +\fB\-at \fIindex\fR +New values will start at vector index \fIindex\fR. This will +overwrite any current values. +.TP +\fB\-format\fR \fIformat\fR +Specifies the format of the data. \fIFormat\fR can be one of the +following: "i1", "i2", "i4", "i8", "u1, "u2", "u4", "u8", "r4", +"r8", or "r16". The number indicates the number of bytes +required for each value. The letter indicates the type: "i" for signed, +"u" for unsigned, "r" or real. The default format is "r16". +.RE +.TP +\fIvecName \fBclear\fR +Clears the element indices from the array variable associated with +\fIvecName\fR. This doesn't affect the components of the vector. By +default, the number of entries in the Tcl array doesn't match the +number of components in the vector. This is because its too expensive +to maintain decimal strings for both the index and value for each +component. Instead, the index and value are saved only when you read +or write an element with a new index. This command removes the index +and value strings from the array. This is useful when the vector is +large. +.TP +\fIvecName \fBdelete\fR \fIindex\fR ?\fIindex\fR?... +Deletes the \fIindex\fRth component from the vector \fIvecName\fR. +\fIIndex\fR is the index of the element to be deleted. This is the +same as unsetting the array variable element \fIindex\fR. The vector +is compacted after all the indices have been deleted. +.TP +\fIvecName \fBdup\fR \fIdestName\fR +Copies \fIvecName\fR to \fIdestName\fR. \fIDestName\fR is the name of a +destination vector. If a vector \fIdestName\fR already exists, it is +overwritten with the components of \fIvecName\fR. Otherwise a +new vector is created. +.TP +\fIvecName \fBexpr\fR \fIexpression\fR +Computes the expression and resets the values of the vector accordingly. +Both scalar and vector math operations are allowed. All values in +expressions are either real numbers or names of vectors. All numbers +are treated as one component vectors. +.TP +\fIvecName \fBlength\fR ?\fInewSize\fR? +Queries or resets the number of components in \fIvecName\fR. +\fINewSize\fR is a number specifying the new size of the vector. If +\fInewSize\fR is smaller than the current size of \fIvecName\fR, +\fIvecName\fR is truncated. If \fInewSize\fR is greater, the vector +is extended and the new components are initialized to \f(CW0.0\fR. If +no \fInewSize\fR argument is present, the current length of the vector +is returned. +.TP +\fIvecName \fBmerge\fR \fIsrcName\fR ?\fIsrcName\fR?... +Merges the named vectors into a single vector. The resulting +vector is formed by merging the components of each source vector +one index at a time. +.TP +\fIvecName \fBnotify\fR \fIkeyword\fR +Controls how vector clients are notified of changes to the vector. +The exact behavior is determined by \fIkeyword\fR. +.RS +.TP 0.75i +\f(CWalways\fR +Indicates that clients are to be notified immediately whenever the +vector is updated. +.TP +\f(CWnever\fR +Indicates that no clients are to be notified. +.TP +\f(CWwhenidle\fR +Indicates that clients are to be notified at the next idle point +whenever the vector is updated. +.TP +\f(CWnow\fR +If any client notifications is currently pending, they are notified +immediately. +.TP +\f(CWcancel\fR +Cancels pending notifications of clients using the vector. +.TP +\f(CWpending\fR +Returns \f(CW1\fR if a client notification is pending, and \f(CW0\fR otherwise. +.RE +.TP +\fIvecName \fBoffset\fR ?\fIvalue\fR? +Shifts the indices of the vector by the amount specified by \fIvalue\fR. +\fIValue\fR is an integer number. If no \fIvalue\fR argument is +given, the current offset is returned. +.TP +\fIvecName \fBpopulate\fR \fIdestName\fR ?\fIdensity\fR? +Creates a vector \fIdestName\fR which is a superset of \fIvecName\fR. +\fIDestName\fR will include all the components of \fIvecName\fR, in +addition the interval between each of the original components will +contain a \fIdensity\fR number of new components, whose values are +evenly distributed between the original components values. This is +useful for generating abscissas to be interpolated along a spline. +.TP +\fIvecName \fBrange\fR \fIfirstIndex\fR ?\fIlastIndex\fR?... +Returns a list of numeric values representing the vector components +between two indices. Both \fIfirstIndex\fR and \fIlastIndex\fR are +indices representing the range of components to be returned. If +\fIlastIndex\fR is less than \fIfirstIndex\fR, the components are +listed in reverse order. +.TP +\fIvecName \fBsearch\fR \fIvalue\fR ?\fIvalue\fR? +Searches for a value or range of values among the components of +\fIvecName\fR. If one \fIvalue\fR argument is given, a list of +indices of the components which equal \fIvalue\fR is returned. If a +second \fIvalue\fR is also provided, then the indices of all +components which lie within the range of the two values are returned. +If no components are found, then \f(CW""\fR is returned. +.TP +\fIvecName \fBset\fR \fIitem\fR +Resets the components of the vector to \fIitem\fR. \fIItem\fR can +be either a list of numeric expressions or another vector. +.TP +\fIvecName \fBseq\fR \fIstart\fR ?\fIfinish\fR? ?\fIstep\fR? +Generates a sequence of values starting with the value \fIstart\fR. +\fIFinish\fR indicates the terminating value of the sequence. +The vector is automatically resized to contain just the sequence. +If three arguments are present, \fIstep\fR designates the interval. +.sp +With only two arguments (no \fIfinish\fR argument), the sequence will +continue until the vector is filled. With one argument, the interval +defaults to 1.0. +.TP +\fIvecName \fBsort\fR ?\fB-reverse\fR? ?\fIargName\fR?... +Sorts the vector \fIvecName\fR in increasing order. If the +\fB-reverse\fR flag is present, the vector is sorted in decreasing +order. If other arguments \fIargName\fR are present, they are the +names of vectors which will be rearranged in the same manner as +\fIvecName\fR. Each vector must be the same length as \fIvecName\fR. +You could use this to sort the x vector of a graph, while still +retaining the same x,y coordinate pairs in a y vector. +.TP +\fIvecName \fBvariable\fR \fIvarName\fR +Maps a Tcl variable to the vector, creating another means for +accessing the vector. The variable \fIvarName\fR can't already +exist. This overrides any current variable mapping the vector +may have. +.RE +.SH C LANGUAGE API +You can create, modify, and destroy vectors from C code, using +library routines. +You need to include the header file \f(CWblt.h\fR. It contains the +definition of the structure \fBBlt_Vector\fR, which represents the +vector. It appears below. +.CS +\fRtypedef struct { + double *\fIvalueArr\fR; + int \fInumValues\fR; + int \fIarraySize\fR; + double \fImin\fR, \fImax\fR; +} \fBBlt_Vector\fR; +.CE +The field \fIvalueArr\fR points to memory holding the vector +components. The components are stored in a double precision array, +whose size size is represented by \fIarraySize\fR. \fINumValues\fR is +the length of vector. The size of the array is always equal to or +larger than the length of the vector. \fIMin\fR and \fImax\fR are +minimum and maximum component values. +.SH LIBRARY ROUTINES +The following routines are available from C to manage vectors. +Vectors are identified by the vector name. +.PP +\fBBlt_CreateVector\fR +.RS .25i +.TP 1i +Synopsis: +.CS +int \fBBlt_CreateVector\fR (\fIinterp\fR, \fIvecName\fR, \fIlength\fR, \fIvecPtrPtr\fR) +.RS 1.25i +Tcl_Interp *\fIinterp\fR; +char *\fIvecName\fR; +int \fIlength\fR; +Blt_Vector **\fIvecPtrPtr\fR; +.RE +.CE +.TP +Description: +Creates a new vector \fIvecName\fR\fR with a length of \fIlength\fR. +\fBBlt_CreateVector\fR creates both a new Tcl command and array +variable \fIvecName\fR. Neither a command nor variable named +\fIvecName\fR can already exist. A pointer to the vector is +placed into \fIvecPtrPtr\fR. +.TP +Results: +Returns \f(CWTCL_OK\fR if the vector is successfully created. If +\fIlength\fR is negative, a Tcl variable or command \fIvecName\fR +already exists, or memory cannot be allocated for the vector, then +\f(CWTCL_ERROR\fR is returned and \fIinterp->result\fR will contain an +error message. +.RE +.sp +.PP +\fBBlt_DeleteVectorByName\fR +.RS .25i +.TP 1i +Synopsis: +.CS +int \fBBlt_DeleteVectorByName\fR (\fIinterp\fR, \fIvecName\fR) +.RS 1.25i +Tcl_Interp *\fIinterp\fR; +char *\fIvecName\fR; +.RE +.CE +.TP 1i +Description: +Removes the vector \fIvecName\fR. \fIVecName\fR is the name of a vector +which must already exist. Both the Tcl command and array variable +\fIvecName\fR are destroyed. All clients of the vector will be notified +immediately that the vector has been destroyed. +.TP +Results: +Returns \f(CWTCL_OK\fR if the vector is successfully deleted. If +\fIvecName\fR is not the name a vector, then \f(CWTCL_ERROR\fR is returned +and \fIinterp->result\fR will contain an error message. +.RE +.sp +.PP +\fBBlt_DeleteVector\fR +.RS .25i +.TP 1i +Synopsis: +.CS +int \fBBlt_DeleteVector\fR (\fIvecPtr\fR) +.RS 1.25i +Blt_Vector *\fIvecPtr\fR; +.RE +.CE +.TP 1i +Description: +Removes the vector pointed to by \fIvecPtr\fR. \fIVecPtr\fR is a +pointer to a vector, typically set by \fBBlt_GetVector\fR or +\fBBlt_CreateVector\fR. Both the Tcl command and array variable of +the vector are destroyed. All clients of the vector will be notified +immediately that the vector has been destroyed. +.TP +Results: +Returns \f(CWTCL_OK\fR if the vector is successfully deleted. If +\fIvecName\fR is not the name a vector, then \f(CWTCL_ERROR\fR is returned +and \fIinterp->result\fR will contain an error message. +.RE +.sp +.PP +\fBBlt_GetVector\fR +.RS .25i +.TP 1i +Synopsis: +.CS +int \fBBlt_GetVector\fR (\fIinterp\fR, \fIvecName\fR, \fIvecPtrPtr\fR) +.RS 1.25i +Tcl_Interp *\fIinterp\fR; +char *\fIvecName\fR; +Blt_Vector **\fIvecPtrPtr\fR; +.RE +.CE +.TP 1i +Description: +Retrieves the vector \fIvecName\fR. \fIVecName\fR is the name of a +vector which must already exist. \fIVecPtrPtr\fR will point be set to +the address of the vector. +.TP +Results: +Returns \f(CWTCL_OK\fR if the vector is successfully retrieved. If +\fIvecName\fR is not the name of a vector, then \f(CWTCL_ERROR\fR is +returned and \fIinterp->result\fR will contain an error message. +.RE +.sp +.PP +\fBBlt_ResetVector\fR +.PP +.RS .25i +.TP 1i +Synopsis: +.CS +int \fBBlt_ResetVector\fR (\fIvecPtr\fR, \fIdataArr\fR, + \fInumValues\fR, \fIarraySize\fR, \fIfreeProc\fR) +.RS 1.25i +Blt_Vector *\fIvecPtr\fR; +double *\fIdataArr\fR; +int *\fInumValues\fR; +int *\fIarraySize\fR; +Tcl_FreeProc *\fIfreeProc\fR; +.RE +.CE +.TP +Description: +Resets the components of the vector pointed to by \fIvecPtr\fR. +Calling \fBBlt_ResetVector\fR will trigger the vector to dispatch +notifications to its clients. \fIDataArr\fR is the array of doubles +which represents the vector data. \fINumValues\fR is the number of +elements in the array. \fIArraySize\fR is the actual size of the array +(the array may be bigger than the number of values stored in +it). \fIFreeProc\fP indicates how the storage for the vector component +array (\fIdataArr\fR) was allocated. It is used to determine how to +reallocate memory when the vector is resized or destroyed. It must be +\f(CWTCL_DYNAMIC\fR, \f(CWTCL_STATIC\fR, \f(CWTCL_VOLATILE\fR, or a pointer +to a function to free the memory allocated for the vector array. If +\fIfreeProc\fR is \f(CWTCL_VOLATILE\fR, it indicates that \fIdataArr\fR +must be copied and saved. If \fIfreeProc\fR is \f(CWTCL_DYNAMIC\fR, it +indicates that \fIdataArr\fR was dynamically allocated and that Tcl +should free \fIdataArr\fR if necessary. \f(CWStatic\fR indicates that +nothing should be done to release storage for \fIdataArr\fR. +.TP +Results: +Returns \f(CWTCL_OK\fR if the vector is successfully resized. If +\fInewSize\fR is negative, a vector \fIvecName\fR does not exist, or +memory cannot be allocated for the vector, then \f(CWTCL_ERROR\fR is +returned and \fIinterp->result\fR will contain an error message. +.RE +.sp +.PP +\fBBlt_ResizeVector\fR +.RS .25i +.TP 1i +Synopsis: +.CS +int \fBBlt_ResizeVector\fR (\fIvecPtr\fR, \fInewSize\fR) +.RS 1.25i +Blt_Vector *\fIvecPtr\fR; +int \fInewSize\fR; +.RE +.CE +.TP +Description: +Resets the length of the vector pointed to by \fIvecPtr\fR to +\fInewSize\fR. If \fInewSize\fR is smaller than the current size of +the vector, it is truncated. If \fInewSize\fR is greater, the vector +is extended and the new components are initialized to \f(CW0.0\fR. +Calling \fBBlt_ResetVector\fR will trigger the vector to dispatch +notifications. +.TP +Results: +Returns \f(CWTCL_OK\fR if the vector is successfully resized. If +\fInewSize\fR is negative or memory can not be allocated for the vector, +then \f(CWTCL_ERROR\fR is returned and \fIinterp->result\fR will contain +an error message. +.sp +.PP +\fBBlt_VectorExists\fR +.RS .25i +.TP 1i +Synopsis: +.CS +int \fBBlt_VectorExists\fR (\fIinterp\fR, \fIvecName\fR) +.RS 1.25i +Tcl_Interp *\fIinterp\fR; +char *\fIvecName\fR; +.RE +.CE +.TP +Description: +Indicates if a vector named \fIvecName\fR exists in \fIinterp\fR. +.TP +Results: +Returns \f(CW1\fR if a vector \fIvecName\fR exists and \f(CW0\fR otherwise. +.RE +.sp +.PP +If your application needs to be notified when a vector changes, it can +allocate a unique \fIclient identifier\fR for itself. Using this +identifier, you can then register a call-back to be made whenever the +vector is updated or destroyed. By default, the call-backs are made at +the next idle point. This can be changed to occur at the time the +vector is modified. An application can allocate more than one +identifier for any vector. When the client application is done with +the vector, it should free the identifier. +.PP +The call-back routine must of the following type. +.CS +.RS +.sp +typedef void (\fBBlt_VectorChangedProc\fR) (Tcl_Interp *\fIinterp\fR, +.RS .25i +ClientData \fIclientData\fR, Blt_VectorNotify \fInotify\fR); +.RE +.sp +.RE +.CE +.fi +\fIClientData\fR is passed to this routine whenever it is called. You +can use this to pass information to the call-back. The \fInotify\fR +argument indicates whether the vector has been updated of destroyed. It +is an enumerated type. +.CS +.RS +.sp +typedef enum { + \f(CWBLT_VECTOR_NOTIFY_UPDATE\fR=1, + \f(CWBLT_VECTOR_NOTIFY_DESTROY\fR=2 +} \fBBlt_VectorNotify\fR; +.sp +.RE +.CE +.PP +\fBBlt_AllocVectorId\fR +.RS .25i +.TP 1i +Synopsis: +.CS +Blt_VectorId \fBBlt_AllocVectorId\fR (\fIinterp\fR, \fIvecName\fR) +.RS 1.25i +Tcl_Interp *\fIinterp\fR; +char *\fIvecName\fR; +.RE +.CE +.TP +Description: +Allocates an client identifier for with the vector \fIvecName\fR. +This identifier can be used to specify a call-back which is triggered +when the vector is updated or destroyed. +.TP +Results: +Returns a client identifier if successful. If \fIvecName\fR is not +the name of a vector, then \f(CWNULL\fR is returned and +\fIinterp->result\fR will contain an error message. +.RE +.sp +.PP +\fBBlt_GetVectorById\fR +.RS .25i +.TP 1i +Synopsis: +.CS +int \fBBlt_GetVector\fR (\fIinterp\fR, \fIclientId\fR, \fIvecPtrPtr\fR) +.RS 1.25i +Tcl_Interp *\fIinterp\fR; +Blt_VectorId \fIclientId\fR; +Blt_Vector **\fIvecPtrPtr\fR; +.RE +.CE +.TP 1i +Description: +Retrieves the vector used by \fIclientId\fR. \fIClientId\fR is a valid +vector client identifier allocated by \fBBlt_AllocVectorId\fR. +\fIVecPtrPtr\fR will point be set to the address of the vector. +.TP +Results: +Returns \f(CWTCL_OK\fR if the vector is successfully retrieved. +.RE +.sp +.PP +\fBBlt_SetVectorChangedProc\fR +.RS .25i +.TP 1i +Synopsis: +.CS +void \fBBlt_SetVectorChangedProc\fR (\fIclientId\fR, \fIproc\fR, \fIclientData\fR); +.RS 1.25i +Blt_VectorId \fIclientId\fR; +Blt_VectorChangedProc *\fIproc\fR; +ClientData *\fIclientData\fR; +.RE +.CE +.TP +Description: +Specifies a call-back routine to be called whenever the vector +associated with \fIclientId\fR is updated or deleted. \fIProc\fR is a +pointer to call-back routine and must be of the type +\fBBlt_VectorChangedProc\fR. \fIClientData\fR is a one-word value to +be passed to the routine when it is invoked. If \fIproc\fR is +\f(CWNULL\fR, then the client is not notified. +.TP +Results: +The designated call-back procedure will be invoked when the vector is +updated or destroyed. +.RE +.sp +.PP +\fBBlt_FreeVectorId\fR +.RS .25i +.TP 1i +Synopsis: +.CS +void \fBBlt_FreeVectorId\fR (\fIclientId\fR); +.RS 1.25i +Blt_VectorId \fIclientId\fR; +.RE +.CE +.TP +Description: +Frees the client identifier. Memory allocated for the identifier +is released. The client will no longer be notified when the +vector is modified. +.TP +Results: +The designated call-back procedure will be no longer be invoked when +the vector is updated or destroyed. +.RE +.sp +.PP +\fBBlt_NameOfVectorId\fR +.RS .25i +.TP 1i +Synopsis: +.CS +char *\fBBlt_NameOfVectorId\fR (\fIclientId\fR); +.RS 1.25i +Blt_VectorId \fIclientId\fR; +.RE +.CE +.TP +Description: +Retrieves the name of the vector associated with the client identifier +\fIclientId\fR. +.TP +Results: +Returns the name of the vector associated with \fIclientId\fR. If +\fIclientId\fR is not an identifier or the vector has been destroyed, +\f(CWNULL\fR is returned. +.RE +.sp +.PP +\fBBlt_InstallIndexProc\fR +.RS .25i +.TP 1i +Synopsis: +.CS +void \fBBlt_InstallIndexProc\fR (\fIindexName\fR, \fIprocPtr\fR) +.RS 1.25i +char *\fIindexName\fR; +Blt_VectorIndexProc *\fIprocPtr\fR; +.RE +.CE +.TP +Description: +Registers a function to be called to retrieved the index \fIindexName\fR +from the vector's array variable. +.sp +typedef double Blt_VectorIndexProc(Vector *vecPtr); +.sp +The function will be passed a pointer to the vector. The function must +return a double representing the value at the index. +.TP +Results: +The new index is installed into the vector. +.RE +.RE +.SH C API EXAMPLE +The following example opens a file of binary data and stores it in an +array of doubles. The array size is computed from the size of the +file. If the vector "data" exists, calling \fBBlt_VectorExists\fR, +\fBBlt_GetVector\fR is called to get the pointer to the vector. +Otherwise the routine \fBBlt_CreateVector\fR is called to create a new +vector and returns a pointer to it. Just like the Tcl interface, both +a new Tcl command and array variable are created when a new vector is +created. It doesn't make any difference what the initial size of the +vector is since it will be reset shortly. The vector is updated when +\fBlt_ResetVector\fR is called. Blt_ResetVector makes the changes +visible to the Tcl interface and other vector clients (such as a graph +widget). +.sp +.CS +#include +#include +... +Blt_Vector *vecPtr; +double *newArr; +FILE *f; +struct stat statBuf; +int numBytes, numValues; + +f = fopen("binary.dat", "r"); +fstat(fileno(f), &statBuf); +numBytes = (int)statBuf.st_size; + +/* Allocate an array big enough to hold all the data */ +newArr = (double *)malloc(numBytes); +numValues = numBytes / sizeof(double); +fread((void *)newArr, numValues, sizeof(double), f); +fclose(f); + +if (Blt_VectorExists(interp, "data")) { + if (Blt_GetVector(interp, "data", &vecPtr) != TCL_OK) { + return TCL_ERROR; + } +} else { + if (Blt_CreateVector(interp, "data", 0, &vecPtr) != TCL_OK) { + return TCL_ERROR; + } +} +/* + * Reset the vector. Clients will be notified when Tk is idle. + * TCL_DYNAMIC tells the vector to free the memory allocated + * if it needs to reallocate or destroy the vector. + */ +if (Blt_ResetVector(vecPtr, newArr, numValues, numValues, + TCL_DYNAMIC) != TCL_OK) { + return TCL_ERROR; +} +.CE +.SH "INCOMPATIBILITIES" +In previous versions, if the array variable isn't global +(i.e. local to a Tcl procedure), the vector is automatically +destroyed when the procedure returns. +.CS +proc doit {} { + # Temporary vector x + vector x(10) + set x(9) 2.0 + ... +} +.CE +.PP +This has changed. Variables are not automatically destroyed when +their variable is unset. You can restore the old behavior by +setting the "-watchunset" switch. +.CE +.SH KEYWORDS +vector, graph, widget diff --git a/generic/tkblt.decls b/generic/tkblt.decls new file mode 100644 index 0000000..b4b5c67 --- /dev/null +++ b/generic/tkblt.decls @@ -0,0 +1,92 @@ +library tkblt +interface tkblt + +declare 0 generic { + int Blt_CreateVector(Tcl_Interp* interp, const char *vecName, + int size, Blt_Vector** vecPtrPtr) +} + +declare 1 generic { + int Blt_CreateVector2(Tcl_Interp* interp, const char *vecName, + const char *cmdName, const char *varName, + int initialSize, Blt_Vector **vecPtrPtr) +} + +declare 2 generic { + int Blt_DeleteVectorByName(Tcl_Interp* interp, const char *vecName) +} + +declare 3 generic { + int Blt_DeleteVector(Blt_Vector *vecPtr) +} + +declare 4 generic { + int Blt_GetVector(Tcl_Interp* interp, const char *vecName, + Blt_Vector **vecPtrPtr) +} + +declare 5 generic { + int Blt_GetVectorFromObj(Tcl_Interp* interp, Tcl_Obj *objPtr, + Blt_Vector **vecPtrPtr) +} + +declare 6 generic { + int Blt_ResetVector(Blt_Vector *vecPtr, double *dataArr, int n, + int arraySize, Tcl_FreeProc *freeProc) +} + +declare 7 generic { + int Blt_ResizeVector(Blt_Vector *vecPtr, int n) +} + +declare 8 generic { + int Blt_VectorExists(Tcl_Interp* interp, const char *vecName) +} + +declare 9 generic { + int Blt_VectorExists2(Tcl_Interp* interp, const char *vecName) +} + +declare 10 generic { + Blt_VectorId Blt_AllocVectorId(Tcl_Interp* interp, const char *vecName) +} + +declare 11 generic { + int Blt_GetVectorById(Tcl_Interp* interp, Blt_VectorId clientId, + Blt_Vector **vecPtrPtr) +} + +declare 12 generic { + void Blt_SetVectorChangedProc(Blt_VectorId clientId, + Blt_VectorChangedProc *proc, + ClientData clientData) +} + +declare 13 generic { + void Blt_FreeVectorId(Blt_VectorId clientId) +} + +declare 14 generic { + const char *Blt_NameOfVectorId(Blt_VectorId clientId) +} + +declare 15 generic { + const char *Blt_NameOfVector(Blt_Vector *vecPtr) +} + +declare 16 generic { + int Blt_ExprVector(Tcl_Interp* interp, char *expr, Blt_Vector *vecPtr) +} + +declare 17 generic { + void Blt_InstallIndexProc(Tcl_Interp* interp, const char *indexName, + Blt_VectorIndexProc * procPtr) +} + +declare 18 generic { + double Blt_VecMin(Blt_Vector *vPtr) +} + +declare 19 generic { + double Blt_VecMax(Blt_Vector *vPtr) +} diff --git a/generic/tkbltChain.C b/generic/tkbltChain.C new file mode 100644 index 0000000..dbd317c --- /dev/null +++ b/generic/tkbltChain.C @@ -0,0 +1,194 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1991-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "tkbltChain.h" + +using namespace Blt; + +// ChainLink + +ChainLink::ChainLink(void* clientData) +{ + prev_ =NULL; + next_ =NULL; + manage_ =0; + clientData_ = clientData; +} + +ChainLink::ChainLink(size_t ss) +{ + prev_ =NULL; + next_ =NULL; + manage_ =1; + clientData_ = (void*)calloc(1,ss); +} + +ChainLink::~ChainLink() +{ + if (manage_ && clientData_) + free(clientData_); +} + +// Chain + +Chain::Chain() +{ + head_ =NULL; + tail_ =NULL; + nLinks_ =0; +} + +Chain::~Chain() +{ + ChainLink* linkPtr = head_; + while (linkPtr) { + ChainLink* oldPtr =linkPtr; + linkPtr = linkPtr->next_; + delete oldPtr; + } +} + +void Chain::reset() +{ + ChainLink* linkPtr = head_; + while (linkPtr) { + ChainLink* oldPtr = linkPtr; + linkPtr = linkPtr->next_; + delete oldPtr; + } + head_ =NULL; + tail_ =NULL; + nLinks_ =0; +} + +void Chain::linkAfter(ChainLink* linkPtr, ChainLink* afterPtr) +{ + if (!head_) { + head_ = linkPtr; + tail_ = linkPtr; + } + else { + if (!afterPtr) { + linkPtr->next_ = NULL; + linkPtr->prev_ = tail_; + tail_->next_ = linkPtr; + tail_ = linkPtr; + } + else { + linkPtr->next_ = afterPtr->next_; + linkPtr->prev_ = afterPtr; + if (afterPtr == tail_) + tail_ = linkPtr; + else + afterPtr->next_->prev_ = linkPtr; + afterPtr->next_ = linkPtr; + } + } + + nLinks_++; +} + +void Chain::linkBefore(ChainLink* linkPtr, ChainLink* beforePtr) +{ + if (!head_) { + head_ = linkPtr; + tail_ = linkPtr; + } + else { + if (beforePtr == NULL) { + linkPtr->next_ = head_; + linkPtr->prev_ = NULL; + head_->prev_ = linkPtr; + head_ = linkPtr; + } + else { + linkPtr->prev_ = beforePtr->prev_; + linkPtr->next_ = beforePtr; + if (beforePtr == head_) + head_ = linkPtr; + else + beforePtr->prev_->next_ = linkPtr; + beforePtr->prev_ = linkPtr; + } + } + + nLinks_++; +} + +void Chain::unlinkLink(ChainLink* linkPtr) +{ + // Indicates if the link is actually remove from the chain + int unlinked; + + unlinked = 0; + if (head_ == linkPtr) { + head_ = linkPtr->next_; + unlinked = 1; + } + if (tail_ == linkPtr) { + tail_ = linkPtr->prev_; + unlinked = 1; + } + if (linkPtr->next_) { + linkPtr->next_->prev_ = linkPtr->prev_; + unlinked = 1; + } + if (linkPtr->prev_) { + linkPtr->prev_->next_ = linkPtr->next_; + unlinked = 1; + } + if (unlinked) + nLinks_--; + + linkPtr->prev_ =NULL; + linkPtr->next_ =NULL; +} + +void Chain::deleteLink(ChainLink* link) +{ + unlinkLink(link); + delete link; + link = NULL; +} + +ChainLink* Chain::append(void* clientData) +{ + ChainLink* link = new ChainLink(clientData); + linkAfter(link, NULL); + return link; +} + +ChainLink* Chain::prepend(void* clientData) +{ + ChainLink* link = new ChainLink(clientData); + linkBefore(link, NULL); + return link; +} diff --git a/generic/tkbltChain.h b/generic/tkbltChain.h new file mode 100644 index 0000000..6e254f9 --- /dev/null +++ b/generic/tkbltChain.h @@ -0,0 +1,91 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef _BLT_CHAIN_H +#define _BLT_CHAIN_H + +#define Chain_GetLength(c) (((c) == NULL) ? 0 : (c)->nLinks()) +#define Chain_FirstLink(c) (((c) == NULL) ? NULL : (c)->head()) +#define Chain_LastLink(c) (((c) == NULL) ? NULL : (c)->tail()) + +#define Chain_PrevLink(l) ((l)->prev()) +#define Chain_NextLink(l) ((l)->next()) +#define Chain_GetValue(l) ((l)->clientData()) + +namespace Blt { + + class Chain; + + class ChainLink { + friend class Chain; + + protected: + ChainLink* prev_; + ChainLink* next_; + int manage_; + void* clientData_; + + public: + ChainLink(void*); + ChainLink(size_t); + virtual ~ChainLink(); + + ChainLink* prev() {return prev_;} + ChainLink* next() {return next_;} + void* clientData() {return clientData_;} + void setClientData(void* d) {clientData_ =d;} + }; + + class Chain { + protected: + ChainLink* head_; + ChainLink* tail_; + long nLinks_; + + public: + Chain(); + virtual ~Chain(); + + ChainLink* head() {return head_;} + ChainLink* tail() {return tail_;} + long nLinks() {return nLinks_;} + + void reset(); + void linkAfter(ChainLink* link, ChainLink* after); + void linkBefore(ChainLink* link, ChainLink* before); + void unlinkLink(ChainLink* linkPtr); + void deleteLink(ChainLink* link); + ChainLink* append(void* clientData); + ChainLink* prepend(void* clientData); + }; +}; + +#endif diff --git a/generic/tkbltConfig.C b/generic/tkbltConfig.C new file mode 100644 index 0000000..82fea4e --- /dev/null +++ b/generic/tkbltConfig.C @@ -0,0 +1,218 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright (c) 1990-1994 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. + * + * Copyright 2003-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#include "tkbltConfig.h" +#include "tkbltGrMisc.h" + +using namespace Blt; + +void RestoreProc(ClientData clientData, Tk_Window tkwin, + char *ptr, char *savePtr) +{ + *(double*)ptr = *(double*)savePtr; +} + +// Fill +const char* fillObjOption[] = {"none", "x", "y", "both", NULL}; + +// Dashes +static Tk_CustomOptionSetProc DashesSetProc; +static Tk_CustomOptionGetProc DashesGetProc; +Tk_ObjCustomOption dashesObjOption = + { + "dashes", DashesSetProc, DashesGetProc, NULL, NULL, NULL + }; + +static int DashesSetProc(ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, Tcl_Obj** objPtr, char* widgRec, + int offset, char* save, int flags) +{ + Dashes* dashesPtr = (Dashes*)(widgRec + offset); + + int length; + const char* string = Tcl_GetStringFromObj(*objPtr, &length); + if (!string || !string[0]) { + dashesPtr->values[0] = 0; + return TCL_OK; + } + + if (!strncmp(string, "dot", length)) { + dashesPtr->values[0] = 1; + dashesPtr->values[1] = 0; + } + else if (!strncmp(string, "dash", length)) { + dashesPtr->values[0] = 5; + dashesPtr->values[1] = 2; + dashesPtr->values[2] = 0; + } + else if (!strncmp(string, "dashdot", length)) { + dashesPtr->values[0] = 2; + dashesPtr->values[1] = 4; + dashesPtr->values[2] = 2; + dashesPtr->values[3] = 0; + } + else if (!strncmp(string, "dashdotdot", length)) { + dashesPtr->values[0] = 2; + dashesPtr->values[1] = 4; + dashesPtr->values[2] = 2; + dashesPtr->values[3] = 2; + dashesPtr->values[4] = 0; + } + else { + int objc; + Tcl_Obj** objv; + if (Tcl_ListObjGetElements(interp, *objPtr, &objc, &objv) != TCL_OK) + return TCL_ERROR; + + // This is the postscript limit + if (objc > 11) { + Tcl_AppendResult(interp, "too many values in dash list \"", + string, "\"", (char *)NULL); + return TCL_ERROR; + } + + int ii; + for (ii=0; ii 255)) { + Tcl_AppendResult(interp, "dash value \"", + Tcl_GetString(objv[ii]), "\" is out of range", + (char *)NULL); + return TCL_ERROR; + } + dashesPtr->values[ii] = (unsigned char)value; + } + + // Make sure the array ends with a NULL byte + dashesPtr->values[ii] = 0; + } + + return TCL_OK; +}; + +static Tcl_Obj* DashesGetProc(ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset) +{ + Dashes* dashesPtr = (Dashes*)(widgRec + offset); + + // count how many + int cnt =0; + while (dashesPtr->values[cnt]) + cnt++; + + if (!cnt) + return Tcl_NewListObj(0, (Tcl_Obj**)NULL); + + Tcl_Obj** ll = new Tcl_Obj*[cnt]; + for (int ii=0; iivalues[ii]); + Tcl_Obj* listObjPtr = Tcl_NewListObj(cnt, ll); + delete [] ll; + + return listObjPtr; +}; + +// List +static Tk_CustomOptionSetProc ListSetProc; +static Tk_CustomOptionGetProc ListGetProc; +static Tk_CustomOptionFreeProc ListFreeProc; +Tk_ObjCustomOption listObjOption = + { + "list", ListSetProc, ListGetProc, RestoreProc, ListFreeProc, NULL + }; + +static int ListSetProc(ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, Tcl_Obj** objPtr, char* widgRec, + int offset, char* savePtr, int flags) +{ + const char*** listPtr = (const char***)(widgRec + offset); + *(double*)savePtr = *(double*)listPtr; + + if (!listPtr) + return TCL_OK; + + const char** argv; + int argc; + if (Tcl_SplitList(interp, Tcl_GetString(*objPtr), &argc, &argv) != TCL_OK) + return TCL_ERROR; + + *listPtr = argv; + + return TCL_OK; +}; + +static Tcl_Obj* ListGetProc(ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset) +{ + const char*** listPtr = (const char***)(widgRec + offset); + + if (!listPtr || !(*listPtr)) + return Tcl_NewListObj(0, NULL); + + // count how many + int cnt=0; + for (const char** pp=*listPtr; *pp; pp++,cnt++) {} + if (!cnt) + return Tcl_NewListObj(0, NULL); + + Tcl_Obj** ll = new Tcl_Obj*[cnt]; + for (int ii=0; ii + +extern const char* fillObjOption[]; +extern Tk_ObjCustomOption dashesObjOption; +extern Tk_ObjCustomOption listObjOption; +extern Tk_CustomOptionRestoreProc RestoreProc; + +#endif diff --git a/generic/tkbltDecls.h b/generic/tkbltDecls.h new file mode 100644 index 0000000..4d7c679 --- /dev/null +++ b/generic/tkbltDecls.h @@ -0,0 +1,152 @@ +/* !BEGIN!: Do not edit below this line. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Exported function declarations: + */ + +/* 0 */ +TKBLT_STORAGE_CLASS int Blt_CreateVector(Tcl_Interp*interp, + const char *vecName, int size, + Blt_Vector**vecPtrPtr); +/* 1 */ +TKBLT_STORAGE_CLASS int Blt_CreateVector2(Tcl_Interp*interp, + const char *vecName, const char *cmdName, + const char *varName, int initialSize, + Blt_Vector **vecPtrPtr); +/* 2 */ +TKBLT_STORAGE_CLASS int Blt_DeleteVectorByName(Tcl_Interp*interp, + const char *vecName); +/* 3 */ +TKBLT_STORAGE_CLASS int Blt_DeleteVector(Blt_Vector *vecPtr); +/* 4 */ +TKBLT_STORAGE_CLASS int Blt_GetVector(Tcl_Interp*interp, const char *vecName, + Blt_Vector **vecPtrPtr); +/* 5 */ +TKBLT_STORAGE_CLASS int Blt_GetVectorFromObj(Tcl_Interp*interp, + Tcl_Obj *objPtr, Blt_Vector **vecPtrPtr); +/* 6 */ +TKBLT_STORAGE_CLASS int Blt_ResetVector(Blt_Vector *vecPtr, double *dataArr, + int n, int arraySize, Tcl_FreeProc *freeProc); +/* 7 */ +TKBLT_STORAGE_CLASS int Blt_ResizeVector(Blt_Vector *vecPtr, int n); +/* 8 */ +TKBLT_STORAGE_CLASS int Blt_VectorExists(Tcl_Interp*interp, + const char *vecName); +/* 9 */ +TKBLT_STORAGE_CLASS int Blt_VectorExists2(Tcl_Interp*interp, + const char *vecName); +/* 10 */ +TKBLT_STORAGE_CLASS Blt_VectorId Blt_AllocVectorId(Tcl_Interp*interp, + const char *vecName); +/* 11 */ +TKBLT_STORAGE_CLASS int Blt_GetVectorById(Tcl_Interp*interp, + Blt_VectorId clientId, + Blt_Vector **vecPtrPtr); +/* 12 */ +TKBLT_STORAGE_CLASS void Blt_SetVectorChangedProc(Blt_VectorId clientId, + Blt_VectorChangedProc *proc, + ClientData clientData); +/* 13 */ +TKBLT_STORAGE_CLASS void Blt_FreeVectorId(Blt_VectorId clientId); +/* 14 */ +TKBLT_STORAGE_CLASS const char * Blt_NameOfVectorId(Blt_VectorId clientId); +/* 15 */ +TKBLT_STORAGE_CLASS const char * Blt_NameOfVector(Blt_Vector *vecPtr); +/* 16 */ +TKBLT_STORAGE_CLASS int Blt_ExprVector(Tcl_Interp*interp, char *expr, + Blt_Vector *vecPtr); +/* 17 */ +TKBLT_STORAGE_CLASS void Blt_InstallIndexProc(Tcl_Interp*interp, + const char *indexName, + Blt_VectorIndexProc *procPtr); +/* 18 */ +TKBLT_STORAGE_CLASS double Blt_VecMin(Blt_Vector *vPtr); +/* 19 */ +TKBLT_STORAGE_CLASS double Blt_VecMax(Blt_Vector *vPtr); + +typedef struct TkbltStubs { + int magic; + void *hooks; + + int (*blt_CreateVector) (Tcl_Interp*interp, const char *vecName, int size, Blt_Vector**vecPtrPtr); /* 0 */ + int (*blt_CreateVector2) (Tcl_Interp*interp, const char *vecName, const char *cmdName, const char *varName, int initialSize, Blt_Vector **vecPtrPtr); /* 1 */ + int (*blt_DeleteVectorByName) (Tcl_Interp*interp, const char *vecName); /* 2 */ + int (*blt_DeleteVector) (Blt_Vector *vecPtr); /* 3 */ + int (*blt_GetVector) (Tcl_Interp*interp, const char *vecName, Blt_Vector **vecPtrPtr); /* 4 */ + int (*blt_GetVectorFromObj) (Tcl_Interp*interp, Tcl_Obj *objPtr, Blt_Vector **vecPtrPtr); /* 5 */ + int (*blt_ResetVector) (Blt_Vector *vecPtr, double *dataArr, int n, int arraySize, Tcl_FreeProc *freeProc); /* 6 */ + int (*blt_ResizeVector) (Blt_Vector *vecPtr, int n); /* 7 */ + int (*blt_VectorExists) (Tcl_Interp*interp, const char *vecName); /* 8 */ + int (*blt_VectorExists2) (Tcl_Interp*interp, const char *vecName); /* 9 */ + Blt_VectorId (*blt_AllocVectorId) (Tcl_Interp*interp, const char *vecName); /* 10 */ + int (*blt_GetVectorById) (Tcl_Interp*interp, Blt_VectorId clientId, Blt_Vector **vecPtrPtr); /* 11 */ + void (*blt_SetVectorChangedProc) (Blt_VectorId clientId, Blt_VectorChangedProc *proc, ClientData clientData); /* 12 */ + void (*blt_FreeVectorId) (Blt_VectorId clientId); /* 13 */ + const char * (*blt_NameOfVectorId) (Blt_VectorId clientId); /* 14 */ + const char * (*blt_NameOfVector) (Blt_Vector *vecPtr); /* 15 */ + int (*blt_ExprVector) (Tcl_Interp*interp, char *expr, Blt_Vector *vecPtr); /* 16 */ + void (*blt_InstallIndexProc) (Tcl_Interp*interp, const char *indexName, Blt_VectorIndexProc *procPtr); /* 17 */ + double (*blt_VecMin) (Blt_Vector *vPtr); /* 18 */ + double (*blt_VecMax) (Blt_Vector *vPtr); /* 19 */ +} TkbltStubs; + +extern const TkbltStubs *tkbltStubsPtr; + +#ifdef __cplusplus +} +#endif + +#if defined(USE_TKBLT_STUBS) + +/* + * Inline function declarations: + */ + +#define Blt_CreateVector \ + (tkbltStubsPtr->blt_CreateVector) /* 0 */ +#define Blt_CreateVector2 \ + (tkbltStubsPtr->blt_CreateVector2) /* 1 */ +#define Blt_DeleteVectorByName \ + (tkbltStubsPtr->blt_DeleteVectorByName) /* 2 */ +#define Blt_DeleteVector \ + (tkbltStubsPtr->blt_DeleteVector) /* 3 */ +#define Blt_GetVector \ + (tkbltStubsPtr->blt_GetVector) /* 4 */ +#define Blt_GetVectorFromObj \ + (tkbltStubsPtr->blt_GetVectorFromObj) /* 5 */ +#define Blt_ResetVector \ + (tkbltStubsPtr->blt_ResetVector) /* 6 */ +#define Blt_ResizeVector \ + (tkbltStubsPtr->blt_ResizeVector) /* 7 */ +#define Blt_VectorExists \ + (tkbltStubsPtr->blt_VectorExists) /* 8 */ +#define Blt_VectorExists2 \ + (tkbltStubsPtr->blt_VectorExists2) /* 9 */ +#define Blt_AllocVectorId \ + (tkbltStubsPtr->blt_AllocVectorId) /* 10 */ +#define Blt_GetVectorById \ + (tkbltStubsPtr->blt_GetVectorById) /* 11 */ +#define Blt_SetVectorChangedProc \ + (tkbltStubsPtr->blt_SetVectorChangedProc) /* 12 */ +#define Blt_FreeVectorId \ + (tkbltStubsPtr->blt_FreeVectorId) /* 13 */ +#define Blt_NameOfVectorId \ + (tkbltStubsPtr->blt_NameOfVectorId) /* 14 */ +#define Blt_NameOfVector \ + (tkbltStubsPtr->blt_NameOfVector) /* 15 */ +#define Blt_ExprVector \ + (tkbltStubsPtr->blt_ExprVector) /* 16 */ +#define Blt_InstallIndexProc \ + (tkbltStubsPtr->blt_InstallIndexProc) /* 17 */ +#define Blt_VecMin \ + (tkbltStubsPtr->blt_VecMin) /* 18 */ +#define Blt_VecMax \ + (tkbltStubsPtr->blt_VecMax) /* 19 */ + +#endif /* defined(USE_TKBLT_STUBS) */ + +/* !END!: Do not edit above this line. */ diff --git a/generic/tkbltGrAxis.C b/generic/tkbltGrAxis.C new file mode 100644 index 0000000..be3e995 --- /dev/null +++ b/generic/tkbltGrAxis.C @@ -0,0 +1,1984 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include + +#include "tkbltGraph.h" +#include "tkbltGrBind.h" +#include "tkbltGrAxis.h" +#include "tkbltGrAxisOption.h" +#include "tkbltGrPostscript.h" +#include "tkbltGrMisc.h" +#include "tkbltGrDef.h" +#include "tkbltConfig.h" +#include "tkbltGrPSOutput.h" +#include "tkbltInt.h" + +using namespace Blt; + +#define AXIS_PAD_TITLE 2 +#define EXP10(x) (pow(10.0,(x))) + +AxisName Blt::axisNames[] = { + { "x", CID_AXIS_X }, + { "y", CID_AXIS_Y }, + { "x2", CID_AXIS_X }, + { "y2", CID_AXIS_Y } +} ; + +// Defs + +extern double AdjustViewport(double offset, double windowSize); + +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_COLOR, "-activeforeground", "activeForeground", "ActiveForeground", + STD_ACTIVE_FOREGROUND, -1, Tk_Offset(AxisOptions, activeFgColor), + 0, NULL, CACHE}, + {TK_OPTION_RELIEF, "-activerelief", "activeRelief", "Relief", + "flat", -1, Tk_Offset(AxisOptions, activeRelief), 0, NULL, CACHE}, + {TK_OPTION_DOUBLE, "-autorange", "autoRange", "AutoRange", + "0", -1, Tk_Offset(AxisOptions, windowSize), 0, NULL, RESET}, + {TK_OPTION_BORDER, "-background", "background", "Background", + NULL, -1, Tk_Offset(AxisOptions, normalBg), TK_OPTION_NULL_OK, NULL, CACHE}, + {TK_OPTION_SYNONYM, "-bg", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-background", 0}, + {TK_OPTION_CUSTOM, "-bindtags", "bindTags", "BindTags", + "all", -1, Tk_Offset(AxisOptions, tags), + TK_OPTION_NULL_OK, &listObjOption, 0}, + {TK_OPTION_SYNONYM, "-bd", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-borderwidth", 0}, + {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", + STD_BORDERWIDTH, -1, Tk_Offset(AxisOptions, borderWidth), 0, NULL, LAYOUT}, + {TK_OPTION_BOOLEAN, "-checklimits", "checkLimits", "CheckLimits", + "no", -1, Tk_Offset(AxisOptions, checkLimits), 0, NULL, RESET}, + {TK_OPTION_COLOR, "-color", "color", "Color", + STD_NORMAL_FOREGROUND, -1, Tk_Offset(AxisOptions, tickColor), + 0, NULL, CACHE}, + {TK_OPTION_SYNONYM, "-command", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-tickformatcommand", 0}, + {TK_OPTION_BOOLEAN, "-descending", "descending", "Descending", + "no", -1, Tk_Offset(AxisOptions, descending), 0, NULL, RESET}, + {TK_OPTION_BOOLEAN, "-exterior", "exterior", "exterior", + "yes", -1, Tk_Offset(AxisOptions, exterior), 0, NULL, LAYOUT}, + {TK_OPTION_SYNONYM, "-fg", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-color", 0}, + {TK_OPTION_SYNONYM, "-foreground", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-color", 0}, + {TK_OPTION_BOOLEAN, "-grid", "grid", "Grid", + "yes", -1, Tk_Offset(AxisOptions, showGrid), 0, NULL, CACHE}, + {TK_OPTION_COLOR, "-gridcolor", "gridColor", "GridColor", + "gray64", -1, Tk_Offset(AxisOptions, major.color), 0, NULL, CACHE}, + {TK_OPTION_CUSTOM, "-griddashes", "gridDashes", "GridDashes", + "dot", -1, Tk_Offset(AxisOptions, major.dashes), + TK_OPTION_NULL_OK, &dashesObjOption, CACHE}, + {TK_OPTION_PIXELS, "-gridlinewidth", "gridLineWidth", "GridLineWidth", + "1", -1, Tk_Offset(AxisOptions, major.lineWidth), 0, NULL, CACHE}, + {TK_OPTION_BOOLEAN, "-gridminor", "gridMinor", "GridMinor", + "yes", -1, Tk_Offset(AxisOptions, showGridMinor), 0, NULL, CACHE}, + {TK_OPTION_COLOR, "-gridminorcolor", "gridMinorColor", "GridMinorColor", + "gray64", -1, Tk_Offset(AxisOptions, minor.color), 0, NULL, CACHE}, + {TK_OPTION_CUSTOM, "-gridminordashes", "gridMinorDashes", "GridMinorDashes", + "dot", -1, Tk_Offset(AxisOptions, minor.dashes), + TK_OPTION_NULL_OK, &dashesObjOption, CACHE}, + {TK_OPTION_PIXELS, "-gridminorlinewidth", "gridMinorLineWidth", + "GridMinorLineWidth", + "1", -1, Tk_Offset(AxisOptions, minor.lineWidth), 0, NULL, CACHE}, + {TK_OPTION_BOOLEAN, "-hide", "hide", "Hide", + "no", -1, Tk_Offset(AxisOptions, hide), 0, NULL, LAYOUT}, + {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify", + "c", -1, Tk_Offset(AxisOptions, titleJustify), 0, NULL, LAYOUT}, + {TK_OPTION_BOOLEAN, "-labeloffset", "labelOffset", "LabelOffset", + "no", -1, Tk_Offset(AxisOptions, labelOffset), 0, NULL, LAYOUT}, + {TK_OPTION_COLOR, "-limitscolor", "limitsColor", "LimitsColor", + STD_NORMAL_FOREGROUND, -1, Tk_Offset(AxisOptions, limitsTextStyle.color), + 0, NULL, CACHE}, + {TK_OPTION_FONT, "-limitsfont", "limitsFont", "LimitsFont", + STD_FONT_SMALL, -1, Tk_Offset(AxisOptions, limitsTextStyle.font), + 0, NULL, LAYOUT}, + {TK_OPTION_STRING, "-limitsformat", "limitsFormat", "LimitsFormat", + NULL, -1, Tk_Offset(AxisOptions, limitsFormat), + TK_OPTION_NULL_OK, NULL, LAYOUT}, + {TK_OPTION_PIXELS, "-linewidth", "lineWidth", "LineWidth", + "1", -1, Tk_Offset(AxisOptions, lineWidth), 0, NULL, LAYOUT}, + {TK_OPTION_BOOLEAN, "-logscale", "logScale", "LogScale", + "no", -1, Tk_Offset(AxisOptions, logScale), 0, NULL, RESET}, + {TK_OPTION_BOOLEAN, "-loosemin", "looseMin", "LooseMin", + "no", -1, Tk_Offset(AxisOptions, looseMin), 0, NULL, RESET}, + {TK_OPTION_BOOLEAN, "-loosemax", "looseMax", "LooseMax", + "no", -1, Tk_Offset(AxisOptions, looseMax), 0, NULL, RESET}, + {TK_OPTION_CUSTOM, "-majorticks", "majorTicks", "MajorTicks", + NULL, -1, Tk_Offset(AxisOptions, t1UPtr), + TK_OPTION_NULL_OK, &ticksObjOption, RESET}, + {TK_OPTION_CUSTOM, "-max", "max", "Max", + NULL, -1, Tk_Offset(AxisOptions, reqMax), + TK_OPTION_NULL_OK, &limitObjOption, RESET}, + {TK_OPTION_CUSTOM, "-min", "min", "Min", + NULL, -1, Tk_Offset(AxisOptions, reqMin), + TK_OPTION_NULL_OK, &limitObjOption, RESET}, + {TK_OPTION_CUSTOM, "-minorticks", "minorTicks", "MinorTicks", + NULL, -1, Tk_Offset(AxisOptions, t2UPtr), + TK_OPTION_NULL_OK, &ticksObjOption, RESET}, + {TK_OPTION_RELIEF, "-relief", "relief", "Relief", + "flat", -1, Tk_Offset(AxisOptions, relief), 0, NULL, CACHE}, + {TK_OPTION_DOUBLE, "-rotate", "rotate", "Rotate", + "0", -1, Tk_Offset(AxisOptions, tickAngle), 0, NULL, LAYOUT}, + {TK_OPTION_CUSTOM, "-scrollcommand", "scrollCommand", "ScrollCommand", + NULL, -1, Tk_Offset(AxisOptions, scrollCmdObjPtr), + TK_OPTION_NULL_OK, &objectObjOption, 0}, + {TK_OPTION_PIXELS, "-scrollincrement", "scrollIncrement", "ScrollIncrement", + "10", -1, Tk_Offset(AxisOptions, scrollUnits), 0, NULL, 0}, + {TK_OPTION_CUSTOM, "-scrollmax", "scrollMax", "ScrollMax", + NULL, -1, Tk_Offset(AxisOptions, reqScrollMax), + TK_OPTION_NULL_OK, &limitObjOption, 0}, + {TK_OPTION_CUSTOM, "-scrollmin", "scrollMin", "ScrollMin", + NULL, -1, Tk_Offset(AxisOptions, reqScrollMin), + TK_OPTION_NULL_OK, &limitObjOption, 0}, + {TK_OPTION_DOUBLE, "-shiftby", "shiftBy", "ShiftBy", + "0", -1, Tk_Offset(AxisOptions, shiftBy), 0, NULL, RESET}, + {TK_OPTION_BOOLEAN, "-showticks", "showTicks", "ShowTicks", + "yes", -1, Tk_Offset(AxisOptions, showTicks), 0, NULL, LAYOUT}, + {TK_OPTION_DOUBLE, "-stepsize", "stepSize", "StepSize", + "0", -1, Tk_Offset(AxisOptions, reqStep), 0, NULL, RESET}, + {TK_OPTION_INT, "-subdivisions", "subdivisions", "Subdivisions", + "2", -1, Tk_Offset(AxisOptions, reqNumMinorTicks), 0, NULL, RESET}, + {TK_OPTION_ANCHOR, "-tickanchor", "tickAnchor", "Anchor", + "c", -1, Tk_Offset(AxisOptions, reqTickAnchor), 0, NULL, LAYOUT}, + {TK_OPTION_FONT, "-tickfont", "tickFont", "Font", + STD_FONT_SMALL, -1, Tk_Offset(AxisOptions, tickFont), 0, NULL, LAYOUT}, + {TK_OPTION_PIXELS, "-ticklength", "tickLength", "TickLength", + "8", -1, Tk_Offset(AxisOptions, tickLength), 0, NULL, LAYOUT}, + {TK_OPTION_INT, "-tickdefault", "tickDefault", "TickDefault", + "4", -1, Tk_Offset(AxisOptions, reqNumMajorTicks), 0, NULL, RESET}, + {TK_OPTION_STRING, "-tickformat", "tickFormat", "TickFormat", + NULL, -1, Tk_Offset(AxisOptions, tickFormat), TK_OPTION_NULL_OK, NULL, 0}, + {TK_OPTION_STRING, "-tickformatcommand", "tickformatcommand", "TickFormatCommand", + NULL, -1, Tk_Offset(AxisOptions, tickFormatCmd), TK_OPTION_NULL_OK, NULL, 0}, + {TK_OPTION_STRING, "-title", "title", "Title", + NULL, -1, Tk_Offset(AxisOptions, title), TK_OPTION_NULL_OK, NULL, LAYOUT}, + {TK_OPTION_BOOLEAN, "-titlealternate", "titleAlternate", "TitleAlternate", + "no", -1, Tk_Offset(AxisOptions, titleAlternate), 0, NULL, LAYOUT}, + {TK_OPTION_COLOR, "-titlecolor", "titleColor", "TitleColor", + STD_NORMAL_FOREGROUND, -1, Tk_Offset(AxisOptions, titleColor), + 0, NULL, CACHE}, + {TK_OPTION_FONT, "-titlefont", "titleFont", "TitleFont", + STD_FONT_NORMAL, -1, Tk_Offset(AxisOptions, titleFont), 0, NULL, LAYOUT}, + {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, -1, 0, 0, 0} +}; + +TickLabel::TickLabel(char* str) +{ + anchorPos.x = DBL_MAX; + anchorPos.y = DBL_MAX; + width =0; + height =0; + string = dupstr(str); +} + +TickLabel::~TickLabel() +{ + delete [] string; +} + +Ticks::Ticks(int cnt) +{ + nTicks =cnt; + values = new double[cnt]; +} + +Ticks::~Ticks() +{ + delete [] values; +} + +Axis::Axis(Graph* graphPtr, const char* name, int margin, Tcl_HashEntry* hPtr) +{ + ops_ = (AxisOptions*)calloc(1, sizeof(AxisOptions)); + AxisOptions* ops = (AxisOptions*)ops_; + + graphPtr_ = graphPtr; + classId_ = CID_NONE; + name_ = dupstr(name); + className_ = dupstr("none"); + + hashPtr_ = hPtr; + refCount_ =0; + use_ =0; + active_ =0; + + link =NULL; + chain =NULL; + + titlePos_.x =0; + titlePos_.y =0; + titleWidth_ =0; + titleHeight_ =0; + min_ =0; + max_ =0; + scrollMin_ =0; + scrollMax_ =0; + valueRange_.min =0; + valueRange_.max =0; + valueRange_.range =0; + valueRange_.scale =0; + axisRange_.min =0; + axisRange_.max =0; + axisRange_.range =0; + axisRange_.scale =0; + prevMin_ =0; + prevMax_ =0; + t1Ptr_ =NULL; + t2Ptr_ =NULL; + minorSweep_.initial =0; + minorSweep_.step =0; + minorSweep_.nSteps =0; + majorSweep_.initial =0; + majorSweep_.step =0; + majorSweep_.nSteps =0; + + margin_ = margin; + segments_ =NULL; + nSegments_ =0; + tickLabels_ = new Chain(); + left_ =0; + right_ =0; + top_ =0; + bottom_ =0; + width_ =0; + height_ =0; + maxTickWidth_ =0; + maxTickHeight_ =0; + tickAnchor_ = TK_ANCHOR_N; + tickGC_ =NULL; + activeTickGC_ =NULL; + titleAngle_ =0; + titleAnchor_ = TK_ANCHOR_N; + screenScale_ =0; + screenMin_ =0; + screenRange_ =0; + + ops->reqMin =NAN; + ops->reqMax =NAN; + ops->reqScrollMin =NAN; + ops->reqScrollMax =NAN; + + ops->limitsTextStyle.anchor =TK_ANCHOR_NW; + ops->limitsTextStyle.color =NULL; + ops->limitsTextStyle.font =NULL; + ops->limitsTextStyle.angle =0; + ops->limitsTextStyle.justify =TK_JUSTIFY_LEFT; + + optionTable_ = Tk_CreateOptionTable(graphPtr_->interp_, optionSpecs); +} + +Axis::~Axis() +{ + AxisOptions* ops = (AxisOptions*)ops_; + + graphPtr_->bindTable_->deleteBindings(this); + + if (link) + chain->deleteLink(link); + + if (hashPtr_) + Tcl_DeleteHashEntry(hashPtr_); + + delete [] name_; + delete [] className_; + + if (tickGC_) + Tk_FreeGC(graphPtr_->display_, tickGC_); + + if (activeTickGC_) + Tk_FreeGC(graphPtr_->display_, activeTickGC_); + + delete [] ops->major.segments; + if (ops->major.gc) + graphPtr_->freePrivateGC(ops->major.gc); + + delete [] ops->minor.segments; + if (ops->minor.gc) + graphPtr_->freePrivateGC(ops->minor.gc); + + delete t1Ptr_; + delete t2Ptr_; + + freeTickLabels(); + + delete tickLabels_; + + delete [] segments_; + + Tk_FreeConfigOptions((char*)ops_, optionTable_, graphPtr_->tkwin_); + free(ops_); +} + +int Axis::configure() +{ + AxisOptions* ops = (AxisOptions*)ops_; + + // Check the requested axis limits. Can't allow -min to be greater than + // -max. Do this regardless of -checklimits option. We want to always + // detect when the user has zoomed in beyond the precision of the data + + if (((!isnan(ops->reqMin)) && (!isnan(ops->reqMax))) && + (ops->reqMin >= ops->reqMax)) { + ostringstream str; + str << "impossible axis limits (-min " << ops->reqMin + << " >= -max " << ops->reqMax << ") for \"" + << name_ << "\"" << ends; + Tcl_AppendResult(graphPtr_->interp_, str.str().c_str(), NULL); + return TCL_ERROR; + } + + scrollMin_ = ops->reqScrollMin; + scrollMax_ = ops->reqScrollMax; + if (ops->logScale) { + if (ops->checkLimits) { + // Check that the logscale limits are positive. + if ((!isnan(ops->reqMin)) && (ops->reqMin <= 0.0)) { + ostringstream str; + str << "bad logscale -min limit \"" << ops->reqMin + << "\" for axis \"" << name_ << "\"" << ends; + Tcl_AppendResult(graphPtr_->interp_, str.str().c_str(), NULL); + return TCL_ERROR; + } + } + if ((!isnan(scrollMin_)) && (scrollMin_ <= 0.0)) + scrollMin_ = NAN; + + if ((!isnan(scrollMax_)) && (scrollMax_ <= 0.0)) + scrollMax_ = NAN; + } + + double angle = fmod(ops->tickAngle, 360.0); + if (angle < 0.0) + angle += 360.0; + + ops->tickAngle = angle; + resetTextStyles(); + + titleWidth_ = titleHeight_ = 0; + if (ops->title) { + int w, h; + graphPtr_->getTextExtents(ops->titleFont, ops->title, -1, &w, &h); + titleWidth_ = (unsigned int)w; + titleHeight_ = (unsigned int)h; + } + + return TCL_OK; +} + +void Axis::map(int offset, int margin) +{ + if (isHorizontal()) { + screenMin_ = graphPtr_->hOffset_; + width_ = graphPtr_->right_ - graphPtr_->left_; + screenRange_ = graphPtr_->hRange_; + } + else { + screenMin_ = graphPtr_->vOffset_; + height_ = graphPtr_->bottom_ - graphPtr_->top_; + screenRange_ = graphPtr_->vRange_; + } + screenScale_ = 1.0 / screenRange_; + + AxisInfo info; + offsets(margin, offset, &info); + makeSegments(&info); +} + +void Axis::mapStacked(int count, int margin) +{ + AxisOptions* ops = (AxisOptions*)ops_; + GraphOptions* gops = (GraphOptions*)graphPtr_->ops_; + + if (Chain_GetLength(gops->margins[margin_].axes) > 1 + || ops->reqNumMajorTicks <= 0) + ops->reqNumMajorTicks = 4; + + unsigned int slice; + if (isHorizontal()) { + slice = graphPtr_->hRange_ / Chain_GetLength(gops->margins[margin].axes); + screenMin_ = graphPtr_->hOffset_; + width_ = slice; + } + else { + slice = graphPtr_->vRange_ / Chain_GetLength(gops->margins[margin].axes); + screenMin_ = graphPtr_->vOffset_; + height_ = slice; + } + + int w, h; + graphPtr_->getTextExtents(ops->tickFont, "0", 1, &w, &h); + screenMin_ += (slice * count) + 2 + h / 2; + screenRange_ = slice - 2 * 2 - h; + screenScale_ = 1.0 / screenRange_; + + AxisInfo info; + offsets(margin, 0, &info); + makeSegments(&info); +} + +void Axis::mapGridlines() +{ + AxisOptions* ops = (AxisOptions*)ops_; + + Ticks* t1Ptr = t1Ptr_; + if (!t1Ptr) + t1Ptr = generateTicks(&majorSweep_); + + Ticks* t2Ptr = t2Ptr_; + if (!t2Ptr) + t2Ptr = generateTicks(&minorSweep_); + + int needed = t1Ptr->nTicks; + if (ops->showGridMinor) + needed += (t1Ptr->nTicks * t2Ptr->nTicks); + + if (needed == 0) { + if (t1Ptr != t1Ptr_) + delete t1Ptr; + if (t2Ptr != t2Ptr_) + delete t2Ptr; + + return; + } + + needed = t1Ptr->nTicks; + if (needed != ops->major.nAllocated) { + delete [] ops->major.segments; + ops->major.segments = new Segment2d[needed]; + ops->major.nAllocated = needed; + } + needed = (t1Ptr->nTicks * t2Ptr->nTicks); + if (needed != ops->minor.nAllocated) { + delete [] ops->minor.segments; + ops->minor.segments = new Segment2d[needed]; + ops->minor.nAllocated = needed; + } + + Segment2d* s1 = ops->major.segments; + Segment2d* s2 = ops->minor.segments; + for (int ii=0; iinTicks; ii++) { + double value = t1Ptr->values[ii]; + if (ops->showGridMinor) { + for (int jj=0; jjnTicks; jj++) { + double subValue = value + (majorSweep_.step * t2Ptr->values[jj]); + if (inRange(subValue, &axisRange_)) { + makeGridLine(subValue, s2); + s2++; + } + } + } + if (inRange(value, &axisRange_)) { + makeGridLine(value, s1); + s1++; + } + } + + if (t1Ptr != t1Ptr_) + delete t1Ptr; + if (t2Ptr != t2Ptr_) + delete t2Ptr; + + ops->major.nUsed = s1 - ops->major.segments; + ops->minor.nUsed = s2 - ops->minor.segments; +} + +void Axis::draw(Drawable drawable) +{ + AxisOptions* ops = (AxisOptions*)ops_; + + if (ops->hide || !use_) + return; + + if (ops->normalBg) { + int relief = active_ ? ops->activeRelief : ops->relief; + Tk_Fill3DRectangle(graphPtr_->tkwin_, drawable, ops->normalBg, + left_, top_, right_ - left_, bottom_ - top_, + ops->borderWidth, relief); + } + + if (ops->title) { + TextStyle ts(graphPtr_); + TextStyleOptions* tops = (TextStyleOptions*)ts.ops(); + + tops->angle = titleAngle_; + tops->font = ops->titleFont; + tops->anchor = titleAnchor_; + tops->color = active_ ? ops->activeFgColor : ops->titleColor; + tops->justify = ops->titleJustify; + + ts.xPad_ = 1; + ts.yPad_ = 0; + ts.drawText(drawable, ops->title, titlePos_.x, titlePos_.y); + } + + if (ops->scrollCmdObjPtr) { + double worldMin = valueRange_.min; + double worldMax = valueRange_.max; + if (!isnan(scrollMin_)) + worldMin = scrollMin_; + if (!isnan(scrollMax_)) + worldMax = scrollMax_; + + double viewMin = min_; + double viewMax = max_; + if (viewMin < worldMin) + viewMin = worldMin; + if (viewMax > worldMax) + viewMax = worldMax; + + if (ops->logScale) { + worldMin = log10(worldMin); + worldMax = log10(worldMax); + viewMin = log10(viewMin); + viewMax = log10(viewMax); + } + + double worldWidth = worldMax - worldMin; + double viewWidth = viewMax - viewMin; + int isHoriz = isHorizontal(); + + double fract; + if (isHoriz != ops->descending) + fract = (viewMin - worldMin) / worldWidth; + else + fract = (worldMax - viewMax) / worldWidth; + + fract = AdjustViewport(fract, viewWidth / worldWidth); + + if (isHoriz != ops->descending) { + viewMin = (fract * worldWidth); + min_ = viewMin + worldMin; + max_ = min_ + viewWidth; + viewMax = viewMin + viewWidth; + if (ops->logScale) { + min_ = EXP10(min_); + max_ = EXP10(max_); + } + updateScrollbar(graphPtr_->interp_, ops->scrollCmdObjPtr, + (int)viewMin, (int)viewMax, (int)worldWidth); + } + else { + viewMax = (fract * worldWidth); + max_ = worldMax - viewMax; + min_ = max_ - viewWidth; + viewMin = viewMax + viewWidth; + if (ops->logScale) { + min_ = EXP10(min_); + max_ = EXP10(max_); + } + updateScrollbar(graphPtr_->interp_, ops->scrollCmdObjPtr, + (int)viewMax, (int)viewMin, (int)worldWidth); + } + } + + if (ops->showTicks) { + TextStyle ts(graphPtr_); + TextStyleOptions* tops = (TextStyleOptions*)ts.ops(); + + tops->angle = ops->tickAngle; + tops->font = ops->tickFont; + tops->anchor = tickAnchor_; + tops->color = active_ ? ops->activeFgColor : ops->tickColor; + + ts.xPad_ = 2; + ts.yPad_ = 0; + + for (ChainLink* link = Chain_FirstLink(tickLabels_); link; + link = Chain_NextLink(link)) { + TickLabel* labelPtr = (TickLabel*)Chain_GetValue(link); + ts.drawText(drawable, labelPtr->string, labelPtr->anchorPos.x, + labelPtr->anchorPos.y); + } + } + + if ((nSegments_ > 0) && (ops->lineWidth > 0)) { + GC gc = active_ ? activeTickGC_ : tickGC_; + graphPtr_->drawSegments(drawable, gc, segments_, nSegments_); + } +} + +void Axis::drawGrids(Drawable drawable) +{ + AxisOptions* ops = (AxisOptions*)ops_; + + if (ops->hide || !ops->showGrid || !use_) + return; + + graphPtr_->drawSegments(drawable, ops->major.gc, + ops->major.segments, ops->major.nUsed); + + if (ops->showGridMinor) + graphPtr_->drawSegments(drawable, ops->minor.gc, + ops->minor.segments, ops->minor.nUsed); +} + +void Axis::drawLimits(Drawable drawable) +{ + AxisOptions* ops = (AxisOptions*)ops_; + GraphOptions* gops = (GraphOptions*)graphPtr_->ops_; + + if (!ops->limitsFormat) + return; + + int vMin = graphPtr_->left_ + gops->xPad + 2; + int vMax = vMin; + int hMin = graphPtr_->bottom_ - gops->yPad - 2; + int hMax = hMin; + + const int spacing =8; + int isHoriz = isHorizontal(); + char* minPtr =NULL; + char* maxPtr =NULL; + char minString[200]; + char maxString[200]; + const char* fmt = ops->limitsFormat; + if (fmt && *fmt) { + minPtr = minString; + snprintf(minString, 200, fmt, axisRange_.min); + + maxPtr = maxString; + snprintf(maxString, 200, fmt, axisRange_.max); + } + if (ops->descending) { + char *tmp = minPtr; + minPtr = maxPtr; + maxPtr = tmp; + } + + TextStyle ts(graphPtr_, &ops->limitsTextStyle); + if (maxPtr) { + if (isHoriz) { + ops->limitsTextStyle.angle = 90.0; + ops->limitsTextStyle.anchor = TK_ANCHOR_SE; + + int ww, hh; + ts.drawTextBBox(drawable, maxPtr, graphPtr_->right_, hMax, &ww, &hh); + hMax -= (hh + spacing); + } + else { + ops->limitsTextStyle.angle = 0.0; + ops->limitsTextStyle.anchor = TK_ANCHOR_NW; + + int ww, hh; + ts.drawTextBBox(drawable, maxPtr, vMax, graphPtr_->top_, &ww, &hh); + vMax += (ww + spacing); + } + } + if (minPtr) { + ops->limitsTextStyle.anchor = TK_ANCHOR_SW; + + if (isHoriz) { + ops->limitsTextStyle.angle = 90.0; + + int ww, hh; + ts.drawTextBBox(drawable, minPtr, graphPtr_->left_, hMin, &ww, &hh); + hMin -= (hh + spacing); + } + else { + ops->limitsTextStyle.angle = 0.0; + + int ww, hh; + ts.drawTextBBox(drawable, minPtr, vMin, graphPtr_->bottom_, &ww, &hh); + vMin += (ww + spacing); + } + } +} + +void Axis::setClass(ClassId classId) +{ + delete [] className_; + + classId_ = classId; + switch (classId) { + case CID_NONE: + className_ = dupstr("none"); + break; + case CID_AXIS_X: + className_ = dupstr("XAxis"); + break; + case CID_AXIS_Y: + className_ = dupstr("YAxis"); + break; + default: + className_ = NULL; + break; + } +} + +void Axis::logScale(double min, double max) +{ + AxisOptions* ops = (AxisOptions*)ops_; + + double range; + double tickMin, tickMax; + double majorStep, minorStep; + int nMajor, nMinor; + + nMajor = nMinor = 0; + majorStep = minorStep = 0.0; + tickMin = tickMax = NAN; + if (min < max) { + min = (min != 0.0) ? log10(fabs(min)) : 0.0; + max = (max != 0.0) ? log10(fabs(max)) : 1.0; + + tickMin = floor(min); + tickMax = ceil(max); + range = tickMax - tickMin; + + if (range > 10) { + // There are too many decades to display a major tick at every + // decade. Instead, treat the axis as a linear scale + range = niceNum(range, 0); + majorStep = niceNum(range / ops->reqNumMajorTicks, 1); + tickMin = floor(tickMin/majorStep)*majorStep; + tickMax = ceil(tickMax/majorStep)*majorStep; + nMajor = (int)((tickMax - tickMin) / majorStep) + 1; + minorStep = EXP10(floor(log10(majorStep))); + if (minorStep == majorStep) { + nMinor = 4; + minorStep = 0.2; + } + else + nMinor = (int)(majorStep/minorStep) - 1; + } + else { + if (tickMin == tickMax) + tickMax++; + majorStep = 1.0; + nMajor = (int)(tickMax - tickMin + 1); /* FIXME: Check this. */ + + minorStep = 0.0; /* This is a special hack to pass + * information to the GenerateTicks + * routine. An interval of 0.0 tells 1) + * this is a minor sweep and 2) the axis + * is log scale. */ + nMinor = 10; + } + if (!ops->looseMin || (ops->looseMin && !isnan(ops->reqMin))) { + tickMin = min; + nMajor++; + } + if (!ops->looseMax || (ops->looseMax && !isnan(ops->reqMax))) { + tickMax = max; + } + } + majorSweep_.step = majorStep; + majorSweep_.initial = floor(tickMin); + majorSweep_.nSteps = nMajor; + minorSweep_.initial = minorSweep_.step = minorStep; + minorSweep_.nSteps = nMinor; + + setRange(&axisRange_, tickMin, tickMax); +} + +void Axis::linearScale(double min, double max) +{ + AxisOptions* ops = (AxisOptions*)ops_; + + unsigned int nTicks = 0; + double step = 1.0; + double axisMin =NAN; + double axisMax =NAN; + double tickMin =NAN; + double tickMax =NAN; + + if (min < max) { + double range = max - min; + if (ops->reqStep > 0.0) { + step = ops->reqStep; + while ((2 * step) >= range && step >= (2 * DBL_EPSILON)) { + step *= 0.5; + } + } + else { + range = niceNum(range, 0); + step = niceNum(range / ops->reqNumMajorTicks, 1); + } + if (step >= DBL_EPSILON) { + axisMin = tickMin = floor(min / step) * step + 0.0; + axisMax = tickMax = ceil(max / step) * step + 0.0; + nTicks = (int)((tickMax-tickMin) / step) + 1; + } else { + /* + * A zero step can result from having a too small range, such that + * the floating point can no longer represent fractions of it (think + * subnormals). In such a case, let's just have two steps: the + * minimum and the maximum. + */ + axisMin = tickMin = min; + axisMax = tickMax = min + DBL_EPSILON; + step = DBL_EPSILON; + nTicks = 2; + } + } + majorSweep_.step = step; + majorSweep_.initial = tickMin; + majorSweep_.nSteps = nTicks; + + /* + * The limits of the axis are either the range of the data ("tight") or at + * the next outer tick interval ("loose"). The looseness or tightness has + * to do with how the axis fits the range of data values. This option is + * overridden when the user sets an axis limit (by either -min or -max + * option). The axis limit is always at the selected limit (otherwise we + * assume that user would have picked a different number). + */ + if (!ops->looseMin || (ops->looseMin && !isnan(ops->reqMin))) + axisMin = min; + + if (!ops->looseMax || (ops->looseMax && !isnan(ops->reqMax))) + axisMax = max; + + setRange(&axisRange_, axisMin, axisMax); + + if (ops->reqNumMinorTicks > 0) { + nTicks = ops->reqNumMinorTicks - 1; + step = 1.0 / (nTicks + 1); + } + else { + nTicks = 0; + step = 0.5; + } + minorSweep_.initial = minorSweep_.step = step; + minorSweep_.nSteps = nTicks; +} + +void Axis::setRange(AxisRange *rangePtr, double min, double max) +{ + rangePtr->min = min; + rangePtr->max = max; + rangePtr->range = max - min; + if (fabs(rangePtr->range) < DBL_EPSILON) { + rangePtr->range = DBL_EPSILON; + } + rangePtr->scale = 1.0 / rangePtr->range; +} + +void Axis::fixRange() +{ + AxisOptions* ops = (AxisOptions*)ops_; + + // When auto-scaling, the axis limits are the bounds of the element data. + // If no data exists, set arbitrary limits (wrt to log/linear scale). + double min = valueRange_.min; + double max = valueRange_.max; + + // Check the requested axis limits. Can't allow -min to be greater + // than -max, or have undefined log scale limits. */ + if (((!isnan(ops->reqMin)) && (!isnan(ops->reqMax))) && + (ops->reqMin >= ops->reqMax)) { + ops->reqMin = ops->reqMax = NAN; + } + if (ops->reqMin < -DBL_MAX) { + ops->reqMin = -DBL_MAX; + } + if (ops->reqMax > DBL_MAX) { + ops->reqMax = DBL_MAX; + } + if (ops->logScale) { + if ((!isnan(ops->reqMin)) && (ops->reqMin <= 0.0)) + ops->reqMin = NAN; + + if ((!isnan(ops->reqMax)) && (ops->reqMax <= 0.0)) + ops->reqMax = NAN; + } + + if (min == DBL_MAX) { + if (!isnan(ops->reqMin)) + min = ops->reqMin; + else + min = (ops->logScale) ? 0.001 : 0.0; + } + if (max == -DBL_MAX) { + if (!isnan(ops->reqMax)) + max = ops->reqMax; + else + max = 1.0; + } + if (min >= max) { + + // There is no range of data (i.e. min is not less than max), so + // manufacture one. + if (min == 0.0) + min = 0.0, max = 1.0; + else + max = min + (fabs(min) * 0.1); + } + setRange(&valueRange_, min, max); + + // The axis limits are either the current data range or overridden by the + // values selected by the user with the -min or -max options. + min_ = min; + max_ = max; + if (!isnan(ops->reqMin)) + min_ = ops->reqMin; + + if (!isnan(ops->reqMax)) + max_ = ops->reqMax; + + if (max_ < min_) { + // If the limits still don't make sense, it's because one limit + // configuration option (-min or -max) was set and the other default + // (based upon the data) is too small or large. Remedy this by making + // up a new min or max from the user-defined limit. + if (isnan(ops->reqMin)) + min_ = max_ - (fabs(max_) * 0.1); + + if (isnan(ops->reqMax)) + max_ = min_ + (fabs(max_) * 0.1); + } + + // If a window size is defined, handle auto ranging by shifting the axis + // limits. + if ((ops->windowSize > 0.0) && + (isnan(ops->reqMin)) && (isnan(ops->reqMax))) { + if (ops->shiftBy < 0.0) + ops->shiftBy = 0.0; + + max = min_ + ops->windowSize; + if (max_ >= max) { + if (ops->shiftBy > 0.0) + max = ceil(max_/ops->shiftBy)*ops->shiftBy; + min_ = max - ops->windowSize; + } + max_ = max; + } + if ((max_ != prevMax_) || + (min_ != prevMin_)) { + /* and save the previous minimum and maximum values */ + prevMin_ = min_; + prevMax_ = max_; + } +} + +// Reference: Paul Heckbert, "Nice Numbers for Graph Labels", +// Graphics Gems, pp 61-63. +double Axis::niceNum(double x, int round) +{ + double expt; /* Exponent of x */ + double frac; /* Fractional part of x */ + double nice; /* Nice, rounded fraction */ + + expt = floor(log10(x)); + frac = x / EXP10(expt); /* between 1 and 10 */ + if (round) { + if (frac < 1.5) { + nice = 1.0; + } else if (frac < 3.0) { + nice = 2.0; + } else if (frac < 7.0) { + nice = 5.0; + } else { + nice = 10.0; + } + } else { + if (frac <= 1.0) { + nice = 1.0; + } else if (frac <= 2.0) { + nice = 2.0; + } else if (frac <= 5.0) { + nice = 5.0; + } else { + nice = 10.0; + } + } + return nice * EXP10(expt); +} + +int Axis::inRange(double x, AxisRange *rangePtr) +{ + if (rangePtr->range < DBL_EPSILON) + return (fabs(rangePtr->max - x) >= DBL_EPSILON); + else { + double norm; + + norm = (x - rangePtr->min) * rangePtr->scale; + return ((norm >= -DBL_EPSILON) && ((norm - 1.0) < DBL_EPSILON)); + } +} + +int Axis::isHorizontal() +{ + GraphOptions* gops = (GraphOptions*)graphPtr_->ops_; + return ((classId_ == CID_AXIS_Y) == gops->inverted); +} + +void Axis::freeTickLabels() +{ + Chain* chain = tickLabels_; + for (ChainLink* link = Chain_FirstLink(chain); link; + link = Chain_NextLink(link)) { + TickLabel* labelPtr = (TickLabel*)Chain_GetValue(link); + delete labelPtr; + } + chain->reset(); +} + +TickLabel* Axis::makeLabel(double value) +{ +#define TICK_LABEL_SIZE 200 + + AxisOptions* ops = (AxisOptions*)ops_; + + char string[TICK_LABEL_SIZE + 1]; + + // zero out any extremely small numbers + if (value-DBL_EPSILON) + value =0; + + if (ops->tickFormat && *ops->tickFormat) { + snprintf(string, TICK_LABEL_SIZE, ops->tickFormat, value); + } else if (ops->logScale) { + snprintf(string, TICK_LABEL_SIZE, "1E%d", int(value)); + } else { + snprintf(string, TICK_LABEL_SIZE, "%.15G", value); + } + + if (ops->tickFormatCmd) { + Tcl_Interp* interp = graphPtr_->interp_; + Tk_Window tkwin = graphPtr_->tkwin_; + + // A TCL proc was designated to format tick labels. Append the path + // name of the widget and the default tick label as arguments when + // invoking it. Copy and save the new label from interp->result. + Tcl_ResetResult(interp); + if (Tcl_VarEval(interp, ops->tickFormatCmd, " ", Tk_PathName(tkwin), + " ", string, NULL) != TCL_OK) { + Tcl_BackgroundError(interp); + } + else { + // The proc could return a string of any length, so arbitrarily + // limit it to what will fit in the return string. + strncpy(string, Tcl_GetStringResult(interp), TICK_LABEL_SIZE); + string[TICK_LABEL_SIZE] = '\0'; + + Tcl_ResetResult(interp); /* Clear the interpreter's result. */ + } + } + + TickLabel* labelPtr = new TickLabel(string); + + return labelPtr; +} + +double Axis::invHMap(double x) +{ + AxisOptions* ops = (AxisOptions*)ops_; + double value; + + x = (double)(x - screenMin_) * screenScale_; + if (ops->descending) { + x = 1.0 - x; + } + value = (x * axisRange_.range) + axisRange_.min; + if (ops->logScale) { + value = EXP10(value); + } + return value; +} + +double Axis::invVMap(double y) +{ + AxisOptions* ops = (AxisOptions*)ops_; + double value; + + y = (double)(y - screenMin_) * screenScale_; + if (ops->descending) { + y = 1.0 - y; + } + value = ((1.0 - y) * axisRange_.range) + axisRange_.min; + if (ops->logScale) { + value = EXP10(value); + } + return value; +} + +double Axis::hMap(double x) +{ + AxisOptions* ops = (AxisOptions*)ops_; + if (ops->logScale) { + x = log10(fabs(x)); + } + /* Map graph coordinate to normalized coordinates [0..1] */ + x = (x - axisRange_.min) * axisRange_.scale; + if (ops->descending) { + x = 1.0 - x; + } + return (x * screenRange_ + screenMin_); +} + +double Axis::vMap(double y) +{ + AxisOptions* ops = (AxisOptions*)ops_; + if (ops->logScale) { + y = log10(fabs(y)); + } + /* Map graph coordinate to normalized coordinates [0..1] */ + y = (y - axisRange_.min) * axisRange_.scale; + if (ops->descending) { + y = 1.0 - y; + } + return ((1.0 - y) * screenRange_ + screenMin_); +} + +void Axis::getDataLimits(double min, double max) +{ + if (valueRange_.min > min) + valueRange_.min = min; + + if (valueRange_.max < max) + valueRange_.max = max; +} + +void Axis::resetTextStyles() +{ + AxisOptions* ops = (AxisOptions*)ops_; + + XGCValues gcValues; + unsigned long gcMask; + gcMask = (GCForeground | GCLineWidth | GCCapStyle); + gcValues.foreground = ops->tickColor->pixel; + gcValues.font = Tk_FontId(ops->tickFont); + gcValues.line_width = ops->lineWidth; + gcValues.cap_style = CapProjecting; + + GC newGC = Tk_GetGC(graphPtr_->tkwin_, gcMask, &gcValues); + if (tickGC_) + Tk_FreeGC(graphPtr_->display_, tickGC_); + tickGC_ = newGC; + + // Assuming settings from above GC + gcValues.foreground = ops->activeFgColor->pixel; + newGC = Tk_GetGC(graphPtr_->tkwin_, gcMask, &gcValues); + if (activeTickGC_) + Tk_FreeGC(graphPtr_->display_, activeTickGC_); + activeTickGC_ = newGC; + + gcValues.background = gcValues.foreground = ops->major.color->pixel; + gcValues.line_width = ops->major.lineWidth; + gcMask = (GCForeground | GCBackground | GCLineWidth); + if (LineIsDashed(ops->major.dashes)) { + gcValues.line_style = LineOnOffDash; + gcMask |= GCLineStyle; + } + newGC = graphPtr_->getPrivateGC(gcMask, &gcValues); + if (LineIsDashed(ops->major.dashes)) + graphPtr_->setDashes(newGC, &ops->major.dashes); + + if (ops->major.gc) + graphPtr_->freePrivateGC(ops->major.gc); + + ops->major.gc = newGC; + + gcValues.background = gcValues.foreground = ops->minor.color->pixel; + gcValues.line_width = ops->minor.lineWidth; + gcMask = (GCForeground | GCBackground | GCLineWidth); + if (LineIsDashed(ops->minor.dashes)) { + gcValues.line_style = LineOnOffDash; + gcMask |= GCLineStyle; + } + newGC = graphPtr_->getPrivateGC(gcMask, &gcValues); + if (LineIsDashed(ops->minor.dashes)) + graphPtr_->setDashes(newGC, &ops->minor.dashes); + + if (ops->minor.gc) + graphPtr_->freePrivateGC(ops->minor.gc); + + ops->minor.gc = newGC; +} + +void Axis::makeLine(int line, Segment2d *sp) +{ + AxisOptions* ops = (AxisOptions*)ops_; + + double min = axisRange_.min; + double max = axisRange_.max; + if (ops->logScale) { + min = EXP10(min); + max = EXP10(max); + } + if (isHorizontal()) { + sp->p.x = hMap(min); + sp->q.x = hMap(max); + sp->p.y = sp->q.y = line; + } + else { + sp->q.x = sp->p.x = line; + sp->p.y = vMap(min); + sp->q.y = vMap(max); + } +} + +void Axis::offsets(int margin, int offset, AxisInfo *infoPtr) +{ + AxisOptions* ops = (AxisOptions*)ops_; + GraphOptions* gops = (GraphOptions*)graphPtr_->ops_; + + int axisLine =0; + int t1 =0; + int t2 =0; + int labelOffset =AXIS_PAD_TITLE; + int tickLabel =0; + + float titleAngle[4] = {0.0, 90.0, 0.0, 270.0}; + titleAngle_ = titleAngle[margin]; + Margin *marginPtr = gops->margins + margin; + + if (ops->lineWidth > 0) { + if (ops->showTicks) { + t1 = ops->tickLength; + t2 = (t1 * 10) / 15; + } + labelOffset = t1 + AXIS_PAD_TITLE; + if (ops->exterior) + labelOffset += ops->lineWidth; + } + + int axisPad =0; + + // Adjust offset for the interior border width and the line width */ + // fixme + int pad = 0; + // int pad = 1; + // if (graphPtr_->plotBW > 0) + // pad += graphPtr_->plotBW + 1; + + // Pre-calculate the x-coordinate positions of the axis, tick labels, and + // the individual major and minor ticks. + int inset = pad + ops->lineWidth / 2; + + switch (margin) { + case MARGIN_TOP: + { + int mark = graphPtr_->top_ - offset - pad; + tickAnchor_ = TK_ANCHOR_S; + left_ = screenMin_ - inset - 2; + right_ = screenMin_ + screenRange_ + inset - 1; + if (gops->stackAxes) + top_ = mark - marginPtr->axesOffset; + else + top_ = mark - height_; + bottom_ = mark; + + axisLine = bottom_; + if (ops->exterior) { + axisLine -= gops->plotBW + axisPad + ops->lineWidth / 2; + tickLabel = axisLine - 2; + if (ops->lineWidth > 0) + tickLabel -= ops->tickLength; + } + else { + if (gops->plotRelief == TK_RELIEF_SOLID) + axisLine--; + + axisLine -= axisPad + ops->lineWidth / 2; + tickLabel = graphPtr_->top_ - gops->plotBW - 2; + } + + int x, y; + if (ops->titleAlternate) { + x = graphPtr_->right_ + AXIS_PAD_TITLE; + y = mark - (height_ / 2); + titleAnchor_ = TK_ANCHOR_W; + } + else { + x = (right_ + left_) / 2; + if (gops->stackAxes) + y = mark - marginPtr->axesOffset + AXIS_PAD_TITLE; + else + y = mark - height_ + AXIS_PAD_TITLE; + + titleAnchor_ = TK_ANCHOR_N; + } + titlePos_.x = x; + titlePos_.y = y; + } + break; + + case MARGIN_BOTTOM: + { + /* + * ----------- bottom + plot borderwidth + * mark -------------------------------------------- + * ===================== axisLine (linewidth) + * tick + * title + * + * ===================== axisLine (linewidth) + * ----------- bottom + plot borderwidth + * mark -------------------------------------------- + * tick + * title + */ + int mark = graphPtr_->bottom_ + offset; + double fangle = fmod(ops->tickAngle, 90.0); + if (fangle == 0.0) + tickAnchor_ = TK_ANCHOR_N; + else { + int quadrant = (int)(ops->tickAngle / 90.0); + if ((quadrant == 0) || (quadrant == 2)) + tickAnchor_ = TK_ANCHOR_NE; + else + tickAnchor_ = TK_ANCHOR_NW; + } + + left_ = screenMin_ - inset - 2; + right_ = screenMin_ + screenRange_ + inset - 1; + top_ = mark + labelOffset - t1; + if (gops->stackAxes) + bottom_ = mark + marginPtr->axesOffset - 1; + else + bottom_ = mark + height_ - 1; + + axisLine = top_; + if (gops->plotRelief == TK_RELIEF_SOLID) + axisLine++; + + if (ops->exterior) { + axisLine += gops->plotBW + axisPad + ops->lineWidth / 2; + tickLabel = axisLine + 2; + if (ops->lineWidth > 0) + tickLabel += ops->tickLength; + } + else { + axisLine -= axisPad + ops->lineWidth / 2; + tickLabel = graphPtr_->bottom_ + gops->plotBW + 2; + } + + int x, y; + if (ops->titleAlternate) { + x = graphPtr_->right_ + AXIS_PAD_TITLE; + y = mark + (height_ / 2); + titleAnchor_ = TK_ANCHOR_W; + } + else { + x = (right_ + left_) / 2; + if (gops->stackAxes) + y = mark + marginPtr->axesOffset - AXIS_PAD_TITLE; + else + y = mark + height_ - AXIS_PAD_TITLE; + titleAnchor_ = TK_ANCHOR_S; + } + titlePos_.x = x; + titlePos_.y = y; + } + break; + + case MARGIN_LEFT: + { + /* + * mark + * | : + * | : + * | : + * | : + * | : + * axisLine + */ + /* + * Exterior axis + * + plotarea right + * |A|B|C|D|E|F|G|H + * |right + * A = plot pad + * B = plot border width + * C = axis pad + * D = axis line + * E = tick length + * F = tick label + * G = graph border width + * H = highlight thickness + */ + /* + * Interior axis + * + plotarea right + * |A|B|C|D|E|F|G|H + * |right + * A = plot pad + * B = tick length + * C = axis line width + * D = axis pad + * E = plot border width + * F = tick label + * G = graph border width + * H = highlight thickness + */ + int mark = graphPtr_->left_ - offset; + tickAnchor_ = TK_ANCHOR_E; + if (gops->stackAxes) + left_ = mark - marginPtr->axesOffset; + else + left_ = mark - width_; + right_ = mark - 3; + top_ = screenMin_ - inset - 2; + bottom_ = screenMin_ + screenRange_ + inset - 1; + + axisLine = right_; + if (ops->exterior) { + axisLine -= gops->plotBW + axisPad + ops->lineWidth / 2; + tickLabel = axisLine - 2; + if (ops->lineWidth > 0) + tickLabel -= ops->tickLength; + } + else { + if (gops->plotRelief == TK_RELIEF_SOLID) + axisLine--; + axisLine += axisPad + ops->lineWidth / 2; + tickLabel = graphPtr_->left_ - gops->plotBW - 2; + } + + int x, y; + if (ops->titleAlternate) { + x = mark - (width_ / 2); + y = graphPtr_->top_ - AXIS_PAD_TITLE; + titleAnchor_ = TK_ANCHOR_SW; + } + else { + if (gops->stackAxes) + x = mark - marginPtr->axesOffset; + else + x = mark - width_ + AXIS_PAD_TITLE; + y = (bottom_ + top_) / 2; + titleAnchor_ = TK_ANCHOR_W; + } + titlePos_.x = x; + titlePos_.y = y; + } + break; + + case MARGIN_RIGHT: + { + int mark = graphPtr_->right_ + offset + pad; + tickAnchor_ = TK_ANCHOR_W; + left_ = mark; + if (gops->stackAxes) + right_ = mark + marginPtr->axesOffset - 1; + else + right_ = mark + width_ - 1; + + top_ = screenMin_ - inset - 2; + bottom_ = screenMin_ + screenRange_ + inset -1; + + axisLine = left_; + if (gops->plotRelief == TK_RELIEF_SOLID) + axisLine++; + + if (ops->exterior) { + axisLine += gops->plotBW + axisPad + ops->lineWidth / 2; + tickLabel = axisLine + 2; + if (ops->lineWidth > 0) + tickLabel += ops->tickLength; + } + else { + axisLine -= axisPad + ops->lineWidth / 2; + tickLabel = graphPtr_->right_ + gops->plotBW + 2; + } + + int x, y; + if (ops->titleAlternate) { + x = mark + (width_ / 2); + y = graphPtr_->top_ - AXIS_PAD_TITLE; + titleAnchor_ = TK_ANCHOR_SE; + } + else { + if (gops->stackAxes) + x = mark + marginPtr->axesOffset - AXIS_PAD_TITLE; + else + x = mark + width_ - AXIS_PAD_TITLE; + + y = (bottom_ + top_) / 2; + titleAnchor_ = TK_ANCHOR_E; + } + titlePos_.x = x; + titlePos_.y = y; + } + break; + + case MARGIN_NONE: + axisLine = 0; + break; + } + + if ((margin == MARGIN_LEFT) || (margin == MARGIN_TOP)) { + t1 = -t1; + t2 = -t2; + labelOffset = -labelOffset; + } + + infoPtr->axis = axisLine; + infoPtr->t1 = axisLine + t1; + infoPtr->t2 = axisLine + t2; + if (tickLabel > 0) + infoPtr->label = tickLabel; + else + infoPtr->label = axisLine + labelOffset; + + if (!ops->exterior) { + infoPtr->t1 = axisLine - t1; + infoPtr->t2 = axisLine - t2; + } +} + +void Axis::makeTick(double value, int tick, int line, Segment2d *sp) +{ + AxisOptions* ops = (AxisOptions*)ops_; + + if (ops->logScale) + value = EXP10(value); + + if (isHorizontal()) { + sp->p.x = hMap(value); + sp->p.y = line; + sp->q.x = sp->p.x; + sp->q.y = tick; + } + else { + sp->p.x = line; + sp->p.y = vMap(value); + sp->q.x = tick; + sp->q.y = sp->p.y; + } +} + +void Axis::makeSegments(AxisInfo *infoPtr) +{ + AxisOptions* ops = (AxisOptions*)ops_; + + delete [] segments_; + segments_ = NULL; + + Ticks* t1Ptr = ops->t1UPtr ? ops->t1UPtr : t1Ptr_; + Ticks* t2Ptr = ops->t2UPtr ? ops->t2UPtr : t2Ptr_; + + int nMajorTicks= t1Ptr ? t1Ptr->nTicks : 0; + int nMinorTicks= t2Ptr ? t2Ptr->nTicks : 0; + + int arraySize = 1 + (nMajorTicks * (nMinorTicks + 1)); + Segment2d* segments = new Segment2d[arraySize]; + Segment2d* sp = segments; + if (ops->lineWidth > 0) { + makeLine(infoPtr->axis, sp); + sp++; + } + + if (ops->showTicks) { + int isHoriz = isHorizontal(); + for (int ii=0; iivalues[ii]; + /* Minor ticks */ + for (int jj=0; jjvalues[jj]); + if (inRange(t2, &axisRange_)) { + makeTick(t2, infoPtr->t2, infoPtr->axis, sp); + sp++; + } + } + if (!inRange(t1, &axisRange_)) + continue; + + /* Major tick */ + makeTick(t1, infoPtr->t1, infoPtr->axis, sp); + sp++; + } + + ChainLink* link = Chain_FirstLink(tickLabels_); + double labelPos = (double)infoPtr->label; + + for (int ii=0; ii< nMajorTicks; ii++) { + double t1 = t1Ptr->values[ii]; + if (ops->labelOffset) + t1 += majorSweep_.step * 0.5; + + if (!inRange(t1, &axisRange_)) + continue; + + TickLabel* labelPtr = (TickLabel*)Chain_GetValue(link); + link = Chain_NextLink(link); + Segment2d seg; + makeTick(t1, infoPtr->t1, infoPtr->axis, &seg); + // Save tick label X-Y position + if (isHoriz) { + labelPtr->anchorPos.x = seg.p.x; + labelPtr->anchorPos.y = labelPos; + } + else { + labelPtr->anchorPos.x = labelPos; + labelPtr->anchorPos.y = seg.p.y; + } + } + } + segments_ = segments; + nSegments_ = sp - segments; +} + +Ticks* Axis::generateTicks(TickSweep *sweepPtr) +{ + Ticks* ticksPtr = new Ticks(sweepPtr->nSteps); + + if (sweepPtr->step == 0.0) { + // Hack: A zero step indicates to use log values + // Precomputed log10 values [1..10] + static double logTable[] = { + 0.0, + 0.301029995663981, + 0.477121254719662, + 0.602059991327962, + 0.698970004336019, + 0.778151250383644, + 0.845098040014257, + 0.903089986991944, + 0.954242509439325, + 1.0 + }; + for (int ii=0; iinSteps; ii++) + ticksPtr->values[ii] = logTable[ii]; + } + else { + double value = sweepPtr->initial; + for (int ii=0; iinSteps; ii++) { + value = (value/sweepPtr->step)*sweepPtr->step; + ticksPtr->values[ii] = value; + value += sweepPtr->step; + } + } + + return ticksPtr; +} + +void Axis::makeGridLine(double value, Segment2d *sp) +{ + AxisOptions* ops = (AxisOptions*)ops_; + + if (ops->logScale) + value = EXP10(value); + + if (isHorizontal()) { + sp->p.x = hMap(value); + sp->p.y = graphPtr_->top_; + sp->q.x = sp->p.x; + sp->q.y = graphPtr_->bottom_; + } + else { + sp->p.x = graphPtr_->left_; + sp->p.y = vMap(value); + sp->q.x = graphPtr_->right_; + sp->q.y = sp->p.y; + } +} + +void Axis::print(PSOutput* psPtr) +{ + AxisOptions* ops = (AxisOptions*)ops_; + PostscriptOptions* pops = (PostscriptOptions*)graphPtr_->postscript_->ops_; + + if (ops->hide || !use_) + return; + + psPtr->format("%% Axis \"%s\"\n", name_); + if (pops->decorations) { + if (ops->normalBg) { + int relief = active_ ? ops->activeRelief : ops->relief; + psPtr->fill3DRectangle(ops->normalBg, left_, top_, + right_-left_, bottom_-top_, + ops->borderWidth, relief); + } + } + else { + psPtr->setClearBackground(); + psPtr->fillRectangle(left_, top_, right_-left_, bottom_-top_); + } + + if (ops->title) { + TextStyle ts(graphPtr_); + TextStyleOptions* tops = (TextStyleOptions*)ts.ops(); + + tops->angle = titleAngle_; + tops->font = ops->titleFont; + tops->anchor = titleAnchor_; + tops->color = active_ ? ops->activeFgColor : ops->titleColor; + tops->justify = ops->titleJustify; + + ts.xPad_ = 1; + ts.yPad_ = 0; + ts.printText(psPtr, ops->title, titlePos_.x, titlePos_.y); + } + + if (ops->showTicks) { + TextStyle ts(graphPtr_); + TextStyleOptions* tops = (TextStyleOptions*)ts.ops(); + + tops->angle = ops->tickAngle; + tops->font = ops->tickFont; + tops->anchor = tickAnchor_; + tops->color = active_ ? ops->activeFgColor : ops->tickColor; + + ts.xPad_ = 2; + ts.yPad_ = 0; + + for (ChainLink* link = Chain_FirstLink(tickLabels_); link; + link = Chain_NextLink(link)) { + TickLabel *labelPtr = (TickLabel*)Chain_GetValue(link); + ts.printText(psPtr, labelPtr->string, labelPtr->anchorPos.x, + labelPtr->anchorPos.y); + } + } + + if ((nSegments_ > 0) && (ops->lineWidth > 0)) { + psPtr->setLineAttributes(active_ ? ops->activeFgColor : ops->tickColor, + ops->lineWidth, (Dashes*)NULL, CapButt, JoinMiter); + psPtr->printSegments(segments_, nSegments_); + } +} + +void Axis::printGrids(PSOutput* psPtr) +{ + AxisOptions* ops = (AxisOptions*)ops_; + + if (ops->hide || !ops->showGrid || !use_) + return; + + psPtr->format("%% Axis %s: grid line attributes\n", name_); + psPtr->setLineAttributes(ops->major.color, ops->major.lineWidth, + &ops->major.dashes, CapButt, JoinMiter); + psPtr->format("%% Axis %s: major grid line segments\n", name_); + psPtr->printSegments(ops->major.segments, ops->major.nUsed); + + if (ops->showGridMinor) { + psPtr->setLineAttributes(ops->minor.color, ops->minor.lineWidth, + &ops->minor.dashes, CapButt, JoinMiter); + psPtr->format("%% Axis %s: minor grid line segments\n", name_); + psPtr->printSegments(ops->minor.segments, ops->minor.nUsed); + } +} + +void Axis::printLimits(PSOutput* psPtr) +{ + AxisOptions* ops = (AxisOptions*)ops_; + GraphOptions* gops = (GraphOptions*)graphPtr_->ops_; + + if (!ops->limitsFormat) + return; + + double vMin = graphPtr_->left_ + gops->xPad + 2; + double vMax = vMin; + double hMin = graphPtr_->bottom_ - gops->yPad - 2; + double hMax = hMin; + + const int spacing =8; + int isHoriz = isHorizontal(); + char* minPtr =NULL; + char* maxPtr =NULL; + char minString[200]; + char maxString[200]; + const char* fmt = ops->limitsFormat; + if (fmt && *fmt) { + minPtr = minString; + snprintf(minString, 200, fmt, axisRange_.min); + + maxPtr = maxString; + snprintf(maxString, 200, fmt, axisRange_.max); + } + if (ops->descending) { + char *tmp = minPtr; + minPtr = maxPtr; + maxPtr = tmp; + } + + int textWidth, textHeight; + TextStyle ts(graphPtr_, &ops->limitsTextStyle); + if (maxPtr) { + graphPtr_->getTextExtents(ops->tickFont, maxPtr, -1, + &textWidth, &textHeight); + if ((textWidth > 0) && (textHeight > 0)) { + if (isHoriz) { + ops->limitsTextStyle.angle = 90.0; + ops->limitsTextStyle.anchor = TK_ANCHOR_SE; + + ts.printText(psPtr, maxPtr, graphPtr_->right_, (int)hMax); + hMax -= (textWidth + spacing); + } + else { + ops->limitsTextStyle.angle = 0.0; + ops->limitsTextStyle.anchor = TK_ANCHOR_NW; + + ts.printText(psPtr, maxPtr, (int)vMax, graphPtr_->top_); + vMax += (textWidth + spacing); + } + } + } + + if (minPtr) { + graphPtr_->getTextExtents(ops->tickFont, minPtr, -1, + &textWidth, &textHeight); + if ((textWidth > 0) && (textHeight > 0)) { + ops->limitsTextStyle.anchor = TK_ANCHOR_SW; + + if (isHoriz) { + ops->limitsTextStyle.angle = 90.0; + + ts.printText(psPtr, minPtr, graphPtr_->left_, (int)hMin); + hMin -= (textWidth + spacing); + } + else { + ops->limitsTextStyle.angle = 0.0; + + ts.printText(psPtr, minPtr, (int)vMin, graphPtr_->bottom_); + vMin += (textWidth + spacing); + } + } + } +} + +void Axis::updateScrollbar(Tcl_Interp* interp, Tcl_Obj *scrollCmdObjPtr, + int first, int last, int width) +{ + double firstFract =0.0; + double lastFract = 1.0; + if (width > 0) { + firstFract = (double)first / (double)width; + lastFract = (double)last / (double)width; + } + Tcl_Obj *cmdObjPtr = Tcl_DuplicateObj(scrollCmdObjPtr); + Tcl_ListObjAppendElement(interp, cmdObjPtr, Tcl_NewDoubleObj(firstFract)); + Tcl_ListObjAppendElement(interp, cmdObjPtr, Tcl_NewDoubleObj(lastFract)); + Tcl_IncrRefCount(cmdObjPtr); + if (Tcl_EvalObjEx(interp, cmdObjPtr, TCL_EVAL_GLOBAL) != TCL_OK) { + Tcl_BackgroundError(interp); + } + Tcl_DecrRefCount(cmdObjPtr); +} + +void Axis::getGeometry() +{ + AxisOptions* ops = (AxisOptions*)ops_; + GraphOptions* gops = (GraphOptions*)graphPtr_->ops_; + + freeTickLabels(); + + // Leave room for axis baseline and padding + unsigned int y =0; + if (ops->exterior && (gops->plotRelief != TK_RELIEF_SOLID)) + y += ops->lineWidth + 2; + + maxTickHeight_ = maxTickWidth_ = 0; + + if (t1Ptr_) + delete t1Ptr_; + t1Ptr_ = generateTicks(&majorSweep_); + + if (t2Ptr_) + delete t2Ptr_; + t2Ptr_ = generateTicks(&minorSweep_); + + if (ops->showTicks) { + Ticks* t1Ptr = ops->t1UPtr ? ops->t1UPtr : t1Ptr_; + + int nTicks =0; + if (t1Ptr) + nTicks = t1Ptr->nTicks; + + unsigned int nLabels =0; + for (int ii=0; iivalues[ii]; + double x2 = t1Ptr->values[ii]; + if (ops->labelOffset) + x2 += majorSweep_.step * 0.5; + + if (!inRange(x2, &axisRange_)) + continue; + + TickLabel* labelPtr = makeLabel(x); + tickLabels_->append(labelPtr); + nLabels++; + + // Get the dimensions of each tick label. Remember tick labels + // can be multi-lined and/or rotated. + int lw, lh; + graphPtr_->getTextExtents(ops->tickFont, labelPtr->string, -1, &lw, &lh); + labelPtr->width = lw; + labelPtr->height = lh; + + if (ops->tickAngle != 0.0) { + // Rotated label width and height + double rlw, rlh; + graphPtr_->getBoundingBox(lw, lh, ops->tickAngle, &rlw, &rlh, NULL); + lw = (int)rlw; + lh = (int)rlh; + } + if (maxTickWidth_ < int(lw)) + maxTickWidth_ = lw; + + if (maxTickHeight_ < int(lh)) + maxTickHeight_ = lh; + } + + unsigned int pad =0; + if (ops->exterior) { + // Because the axis cap style is "CapProjecting", we need to + // account for an extra 1.5 linewidth at the end of each line + pad = ((ops->lineWidth * 12) / 8); + } + if (isHorizontal()) + y += maxTickHeight_ + pad; + else { + y += maxTickWidth_ + pad; + if (maxTickWidth_ > 0) + // Pad either size of label. + y += 5; + } + y += 2 * AXIS_PAD_TITLE; + if ((ops->lineWidth > 0) && ops->exterior) + // Distance from axis line to tick label. + y += ops->tickLength; + + } // showTicks + + if (ops->title) { + if (ops->titleAlternate) { + if (y < titleHeight_) + y = titleHeight_; + } + else + y += titleHeight_ + AXIS_PAD_TITLE; + } + + // Correct for orientation of the axis + if (isHorizontal()) + height_ = y; + else + width_ = y; +} + diff --git a/generic/tkbltGrAxis.h b/generic/tkbltGrAxis.h new file mode 100644 index 0000000..d459e8c --- /dev/null +++ b/generic/tkbltGrAxis.h @@ -0,0 +1,266 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___BltGrAxis_h__ +#define ___BltGrAxis_h__ + +#include + +#include "tkbltChain.h" + +#include "tkbltGrMisc.h" +#include "tkbltGrText.h" +#include "tkbltGrPSOutput.h" + +namespace Blt { + class Graph; + class Postscript; + + typedef struct { + int axis; + int t1; + int t2; + int label; + } AxisInfo; + + typedef struct { + const char* name; + ClassId classId; + } AxisName; + + extern AxisName axisNames[]; + + typedef struct { + Dashes dashes; + int lineWidth; + XColor* color; + GC gc; + Segment2d *segments; + int nUsed; + int nAllocated; + } Grid; + + typedef struct { + double min; + double max; + double range; + double scale; + } AxisRange; + + class TickLabel { + public: + Point2d anchorPos; + unsigned int width; + unsigned int height; + char* string; + + public: + TickLabel(char*); + virtual ~TickLabel(); + }; + + class Ticks { + public: + int nTicks; + double* values; + + public: + Ticks(int); + virtual ~Ticks(); + }; + + typedef struct { + double initial; + double step; + int nSteps; + } TickSweep; + + typedef struct { + const char** tags; + int checkLimits; + int exterior; + int showGrid; + int showGridMinor; + int hide; + int showTicks; + + double windowSize; + const char *tickFormatCmd; + int descending; + int labelOffset; + TextStyleOptions limitsTextStyle; + const char *limitsFormat; + int lineWidth; + int logScale; + int looseMin; + int looseMax; + Ticks* t1UPtr; + Ticks* t2UPtr; + double reqMin; + double reqMax; + Tcl_Obj *scrollCmdObjPtr; + int scrollUnits; + double reqScrollMin; + double reqScrollMax; + double shiftBy; + double reqStep; + int reqNumMajorTicks; + int reqNumMinorTicks; + int tickLength; + const char *title; + int titleAlternate; + + XColor* activeFgColor; + int activeRelief; + Tk_3DBorder normalBg; + int borderWidth; + XColor* tickColor; + Grid major; + Grid minor; + Tk_Justify titleJustify; + int relief; + double tickAngle; + Tk_Anchor reqTickAnchor; + Tk_Font tickFont; + Tk_Font titleFont; + XColor* titleColor; + + const char *tickFormat; + } AxisOptions; + + class Axis { + protected: + Tk_OptionTable optionTable_; + void* ops_; + + public: + Graph* graphPtr_; + ClassId classId_; + const char* name_; + const char* className_; + + Tcl_HashEntry* hashPtr_; + int refCount_; + int use_; + int active_; + + ChainLink* link; + Chain* chain; + + Point2d titlePos_; + unsigned int titleWidth_; + unsigned int titleHeight_; + double min_; + double max_; + double scrollMin_; + double scrollMax_; + AxisRange valueRange_; + AxisRange axisRange_; + double prevMin_; + double prevMax_; + Ticks* t1Ptr_; + Ticks* t2Ptr_; + TickSweep minorSweep_; + TickSweep majorSweep_; + + int margin_; + Segment2d *segments_; + int nSegments_; + Chain* tickLabels_; + int left_; + int right_; + int top_; + int bottom_; + int width_; + int height_; + int maxTickWidth_; + int maxTickHeight_; + Tk_Anchor tickAnchor_; + GC tickGC_; + GC activeTickGC_; + double titleAngle_; + Tk_Anchor titleAnchor_; + double screenScale_; + int screenMin_; + int screenRange_; + + protected: + double niceNum(double, int); + void setRange(AxisRange*, double, double); + void makeGridLine(double, Segment2d*); + void makeSegments(AxisInfo*); + void resetTextStyles(); + void makeLine(int, Segment2d*); + void makeTick(double, int, int, Segment2d*); + void offsets(int, int, AxisInfo*); + void updateScrollbar(Tcl_Interp*, Tcl_Obj*, int, int, int); + + public: + Axis(Graph*, const char*, int, Tcl_HashEntry*); + virtual ~Axis(); + + Tk_OptionTable optionTable() {return optionTable_;} + void* ops() {return ops_;} + ClassId classId() {return classId_;} + const char* className() {return className_;} + + int configure(); + void map(int, int); + void draw(Drawable); + void drawGrids(Drawable); + void drawLimits(Drawable); + void print(PSOutput*); + void printGrids(PSOutput*); + void printLimits(PSOutput*); + + void mapStacked(int, int); + void mapGridlines(); + void setClass(ClassId); + void logScale(double, double); + void linearScale(double, double); + void fixRange(); + int isHorizontal(); + void freeTickLabels(); + TickLabel* makeLabel(double); + void getDataLimits(double, double); + Ticks* generateTicks(TickSweep*); + int inRange(double, AxisRange*); + void getGeometry(); + + double invHMap(double x); + double invVMap(double y); + double hMap(double x); + double vMap(double y); + }; +}; + +#endif diff --git a/generic/tkbltGrAxisOp.C b/generic/tkbltGrAxisOp.C new file mode 100644 index 0000000..fb3277e --- /dev/null +++ b/generic/tkbltGrAxisOp.C @@ -0,0 +1,674 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include + +#include "tkbltGrBind.h" +#include "tkbltGraph.h" +#include "tkbltGrAxis.h" +#include "tkbltGrAxisOp.h" +#include "tkbltGrMisc.h" +#include "tkbltInt.h" + +using namespace Blt; + +#define EXP10(x) (pow(10.0,(x))) + +static int GetAxisScrollInfo(Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[], + double *offsetPtr, double windowSize, + double scrollUnits, double scale); + +static double Clamp(double x) +{ + return (x < 0.0) ? 0.0 : (x > 1.0) ? 1.0 : x; +} + +int Blt::AxisObjConfigure(Axis* axisPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = axisPtr->graphPtr_; + Tk_SavedOptions savedOptions; + int mask =0; + int error; + Tcl_Obj* errorResult; + + for (error=0; error<=1; error++) { + if (!error) { + if (Tk_SetOptions(interp, (char*)axisPtr->ops(), axisPtr->optionTable(), + objc, objv, graphPtr->tkwin_, &savedOptions, &mask) + != TCL_OK) + continue; + } + else { + errorResult = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); + } + + if (axisPtr->configure() != TCL_OK) + return TCL_ERROR; + + graphPtr->flags |= mask; + graphPtr->eventuallyRedraw(); + + break; + } + + if (!error) { + Tk_FreeSavedOptions(&savedOptions); + return TCL_OK; + } + else { + Tcl_SetObjResult(interp, errorResult); + Tcl_DecrRefCount(errorResult); + return TCL_ERROR; + } +} + +static int CgetOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc!=5) { + Tcl_WrongNumArgs(interp, 3, objv, "axisId option"); + return TCL_ERROR; + } + + Axis* axisPtr; + if (graphPtr->getAxis(objv[3], &axisPtr) != TCL_OK) + return TCL_ERROR; + + return AxisCgetOp(axisPtr, interp, objc-1, objv+1); +} + +static int ConfigureOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc<4) { + Tcl_WrongNumArgs(interp, 3, objv, "axisId ?option value?..."); + return TCL_ERROR; + } + + Axis* axisPtr; + if (graphPtr->getAxis(objv[3], &axisPtr) != TCL_OK) + return TCL_ERROR; + + return AxisConfigureOp(axisPtr, interp, objc-1, objv+1); +} + +static int ActivateOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc!=4) { + Tcl_WrongNumArgs(interp, 3, objv, "axisId"); + return TCL_ERROR; + } + + Axis* axisPtr; + if (graphPtr->getAxis(objv[3], &axisPtr) != TCL_OK) + return TCL_ERROR; + + return AxisActivateOp(axisPtr, interp, objc, objv); +} + +static int BindOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc == 3) { + Tcl_Obj *listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + Tcl_HashSearch iter; + for (Tcl_HashEntry* hPtr=Tcl_FirstHashEntry(&graphPtr->axes_.tagTable, &iter); hPtr; hPtr = Tcl_NextHashEntry(&iter)) { + char* tagName = (char*)Tcl_GetHashKey(&graphPtr->axes_.tagTable, hPtr); + Tcl_Obj* objPtr = Tcl_NewStringObj(tagName, -1); + Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); + } + + Tcl_SetObjResult(interp, listObjPtr); + return TCL_OK; + } + else + return graphPtr->bindTable_->configure(graphPtr->axisTag(Tcl_GetString(objv[3])), objc-4, objv+4); +} + +static int CreateOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc!=4) { + Tcl_WrongNumArgs(interp, 3, objv, "axisId"); + return TCL_ERROR; + } + + if (graphPtr->createAxis(objc, objv) != TCL_OK) + return TCL_ERROR; + Tcl_SetObjResult(interp, objv[3]); + + return TCL_OK; +} + +static int DeleteOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc!=4) { + Tcl_WrongNumArgs(interp, 3, objv, "axisId"); + return TCL_ERROR; + } + + Axis* axisPtr; + if (graphPtr->getAxis(objv[3], &axisPtr) != TCL_OK) + return TCL_ERROR; + + if (axisPtr->refCount_ == 0) + delete axisPtr; + + graphPtr->flags |= RESET; + graphPtr->eventuallyRedraw(); + + return TCL_OK; +} + +static int InvTransformOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc!=5) { + Tcl_WrongNumArgs(interp, 3, objv, "axisId scoord"); + return TCL_ERROR; + } + + Axis* axisPtr; + if (graphPtr->getAxis(objv[3], &axisPtr) != TCL_OK) + return TCL_ERROR; + + return AxisInvTransformOp(axisPtr, interp, objc-1, objv+1); +} + +static int LimitsOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc!=4) { + Tcl_WrongNumArgs(interp, 3, objv, "axisId"); + return TCL_ERROR; + } + + Axis* axisPtr; + if (graphPtr->getAxis(objv[3], &axisPtr) != TCL_OK) + return TCL_ERROR; + + return AxisLimitsOp(axisPtr, interp, objc-1, objv+1); +} + +static int MarginOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc!=4) { + Tcl_WrongNumArgs(interp, 3, objv, "axisId"); + return TCL_ERROR; + } + + Axis* axisPtr; + if (graphPtr->getAxis(objv[3], &axisPtr) != TCL_OK) + return TCL_ERROR; + + return AxisMarginOp(axisPtr, interp, objc-1, objv+1); +} + +static int NamesOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + Tcl_Obj *listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + if (objc<3) { + Tcl_WrongNumArgs(interp, 3, objv, "?pattern...?"); + return TCL_ERROR; + } + if (objc == 3) { + Tcl_HashSearch cursor; + for (Tcl_HashEntry *hPtr = Tcl_FirstHashEntry(&graphPtr->axes_.table, &cursor); hPtr; hPtr = Tcl_NextHashEntry(&cursor)) { + Axis* axisPtr = (Axis*)Tcl_GetHashValue(hPtr); + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj(axisPtr->name_, -1)); + } + } + else { + Tcl_HashSearch cursor; + for (Tcl_HashEntry *hPtr = Tcl_FirstHashEntry(&graphPtr->axes_.table, &cursor); hPtr; hPtr = Tcl_NextHashEntry(&cursor)) { + Axis* axisPtr = (Axis*)Tcl_GetHashValue(hPtr); + for (int ii=3; iiname_, pattern)) { + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewStringObj(axisPtr->name_, -1)); + break; + } + } + } + } + Tcl_SetObjResult(interp, listObjPtr); + + return TCL_OK; +} + +static int TransformOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc!=5) { + Tcl_WrongNumArgs(interp, 3, objv, "axisId coord"); + return TCL_ERROR; + } + + Axis* axisPtr; + if (graphPtr->getAxis(objv[3], &axisPtr) != TCL_OK) + return TCL_ERROR; + + return AxisTransformOp(axisPtr, interp, objc-1, objv+1); +} + +static int TypeOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc!=4) { + Tcl_WrongNumArgs(interp, 3, objv, "axisId"); + return TCL_ERROR; + } + + Axis* axisPtr; + if (graphPtr->getAxis(objv[3], &axisPtr) != TCL_OK) + return TCL_ERROR; + + return AxisTypeOp(axisPtr, interp, objc-1, objv+1); +} + +static int ViewOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc!=4) { + Tcl_WrongNumArgs(interp, 3, objv, "axisId"); + return TCL_ERROR; + } + + Axis* axisPtr; + if (graphPtr->getAxis(objv[3], &axisPtr) != TCL_OK) + return TCL_ERROR; + + return AxisViewOp(axisPtr, interp, objc-1, objv+1); +} + +const Ensemble Blt::axisEnsemble[] = { + {"activate", ActivateOp, 0}, + {"bind", BindOp, 0}, + {"cget", CgetOp,0 }, + {"configure", ConfigureOp,0 }, + {"create", CreateOp, 0}, + {"deactivate", ActivateOp, 0}, + {"delete", DeleteOp, 0}, + {"invtransform", InvTransformOp, 0}, + {"limits", LimitsOp, 0}, + {"margin", MarginOp, 0}, + {"names", NamesOp, 0}, + {"transform", TransformOp, 0}, + {"type", TypeOp, 0}, + {"view", ViewOp, 0}, + { 0,0,0 } +}; + +// Support + +double AdjustViewport(double offset, double windowSize) +{ + // Canvas-style scrolling allows the world to be scrolled within the window. + if (windowSize > 1.0) { + if (windowSize < (1.0 - offset)) + offset = 1.0 - windowSize; + + if (offset > 0.0) + offset = 0.0; + } + else { + if ((offset + windowSize) > 1.0) + offset = 1.0 - windowSize; + + if (offset < 0.0) + offset = 0.0; + } + return offset; +} + +static int GetAxisScrollInfo(Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[], + double *offsetPtr, double windowSize, + double scrollUnits, double scale) +{ + const char *string; + char c; + double offset; + int length; + + offset = *offsetPtr; + string = Tcl_GetStringFromObj(objv[0], &length); + c = string[0]; + scrollUnits *= scale; + if ((c == 's') && (strncmp(string, "scroll", length) == 0)) { + int count; + double fract; + + /* Scroll number unit/page */ + if (Tcl_GetIntFromObj(interp, objv[1], &count) != TCL_OK) + return TCL_ERROR; + + string = Tcl_GetStringFromObj(objv[2], &length); + c = string[0]; + if ((c == 'u') && (strncmp(string, "units", length) == 0)) + fract = count * scrollUnits; + else if ((c == 'p') && (strncmp(string, "pages", length) == 0)) + /* A page is 90% of the view-able window. */ + fract = (int)(count * windowSize * 0.9 + 0.5); + else if ((c == 'p') && (strncmp(string, "pixels", length) == 0)) + fract = count * scale; + else { + Tcl_AppendResult(interp, "unknown \"scroll\" units \"", string, + "\"", NULL); + return TCL_ERROR; + } + offset += fract; + } + else if ((c == 'm') && (strncmp(string, "moveto", length) == 0)) { + double fract; + + /* moveto fraction */ + if (Tcl_GetDoubleFromObj(interp, objv[1], &fract) != TCL_OK) { + return TCL_ERROR; + } + offset = fract; + } + else { + int count; + double fract; + + /* Treat like "scroll units" */ + if (Tcl_GetIntFromObj(interp, objv[0], &count) != TCL_OK) { + return TCL_ERROR; + } + fract = (double)count * scrollUnits; + offset += fract; + /* CHECK THIS: return TCL_OK; */ + } + *offsetPtr = AdjustViewport(offset, windowSize); + return TCL_OK; +} + +// Common Ops + +int AxisCgetOp(Axis* axisPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = axisPtr->graphPtr_; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "cget option"); + return TCL_ERROR; + } + + Tcl_Obj* objPtr = Tk_GetOptionValue(interp, (char*)axisPtr->ops(), + axisPtr->optionTable(), + objv[3], graphPtr->tkwin_); + if (!objPtr) + return TCL_ERROR; + else + Tcl_SetObjResult(interp, objPtr); + return TCL_OK; +} + +int AxisConfigureOp(Axis* axisPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = axisPtr->graphPtr_; + + if (objc <= 4) { + Tcl_Obj* objPtr = Tk_GetOptionInfo(interp, (char*)axisPtr->ops(), + axisPtr->optionTable(), + (objc == 4) ? objv[3] : NULL, + graphPtr->tkwin_); + if (!objPtr) + return TCL_ERROR; + else + Tcl_SetObjResult(interp, objPtr); + return TCL_OK; + } + else + return AxisObjConfigure(axisPtr, interp, objc-3, objv+3); +} + +int AxisActivateOp(Axis* axisPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + AxisOptions* ops = (AxisOptions*)axisPtr->ops(); + Graph* graphPtr = axisPtr->graphPtr_; + const char *string; + + string = Tcl_GetString(objv[2]); + axisPtr->active_ = (string[0] == 'a') ? 1 : 0; + + if (!ops->hide && axisPtr->use_) { + graphPtr->flags |= RESET; + graphPtr->eventuallyRedraw(); + } + + return TCL_OK; +} + +int AxisInvTransformOp(Axis* axisPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = axisPtr->graphPtr_; + + if (graphPtr->flags & RESET) + graphPtr->resetAxes(); + + int sy; + if (Tcl_GetIntFromObj(interp, objv[3], &sy) != TCL_OK) + return TCL_ERROR; + + // Is the axis vertical or horizontal? + // Check the site where the axis was positioned. If the axis is + // virtual, all we have to go on is how it was mapped to an + // element (using either -mapx or -mapy options). + double y = axisPtr->isHorizontal() ? + axisPtr->invHMap(sy) : axisPtr->invVMap(sy); + + Tcl_SetDoubleObj(Tcl_GetObjResult(interp), y); + return TCL_OK; +} + +int AxisLimitsOp(Axis* axisPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + AxisOptions* ops = (AxisOptions*)axisPtr->ops(); + Graph* graphPtr = axisPtr->graphPtr_; + + if (graphPtr->flags & RESET) + graphPtr->resetAxes(); + + double min, max; + if (ops->logScale) { + min = EXP10(axisPtr->axisRange_.min); + max = EXP10(axisPtr->axisRange_.max); + } + else { + min = axisPtr->axisRange_.min; + max = axisPtr->axisRange_.max; + } + + Tcl_Obj *listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(min)); + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(max)); + + Tcl_SetObjResult(interp, listObjPtr); + return TCL_OK; +} + +int AxisMarginOp(Axis* axisPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + const char *marginName = ""; + if (axisPtr->use_) + marginName = axisNames[axisPtr->margin_].name; + + Tcl_SetStringObj(Tcl_GetObjResult(interp), marginName, -1); + return TCL_OK; +} + +int AxisTransformOp(Axis* axisPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = axisPtr->graphPtr_; + + if (graphPtr->flags & RESET) + graphPtr->resetAxes(); + + double x; + if (Tcl_GetDoubleFromObj(interp, objv[3], &x) != TCL_OK) + return TCL_ERROR; + + if (axisPtr->isHorizontal()) + x = axisPtr->hMap(x); + else + x = axisPtr->vMap(x); + + Tcl_SetIntObj(Tcl_GetObjResult(interp), (int)x); + return TCL_OK; +} + +int AxisTypeOp(Axis* axisPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + const char* typeName = ""; + if (axisPtr->use_) { + switch (axisPtr->classId_) { + case CID_AXIS_X: + typeName = "x"; + break; + case CID_AXIS_Y: + typeName = "y"; + break; + } + } + + Tcl_SetStringObj(Tcl_GetObjResult(interp), typeName, -1); + return TCL_OK; +} + +int AxisViewOp(Axis* axisPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + AxisOptions* ops = (AxisOptions*)axisPtr->ops(); + Graph* graphPtr = axisPtr->graphPtr_; + double worldMin = axisPtr->valueRange_.min; + double worldMax = axisPtr->valueRange_.max; + /* Override data dimensions with user-selected limits. */ + if (!isnan(axisPtr->scrollMin_)) + worldMin = axisPtr->scrollMin_; + + if (!isnan(axisPtr->scrollMax_)) + worldMax = axisPtr->scrollMax_; + + double viewMin = axisPtr->min_; + double viewMax = axisPtr->max_; + /* Bound the view within scroll region. */ + if (viewMin < worldMin) + viewMin = worldMin; + + if (viewMax > worldMax) + viewMax = worldMax; + + if (ops->logScale) { + worldMin = log10(worldMin); + worldMax = log10(worldMax); + viewMin = log10(viewMin); + viewMax = log10(viewMax); + } + double worldWidth = worldMax - worldMin; + double viewWidth = viewMax - viewMin; + + /* Unlike horizontal axes, vertical axis values run opposite of the + * scrollbar first/last values. So instead of pushing the axis minimum + * around, we move the maximum instead. */ + double axisOffset; + double axisScale; + if (axisPtr->isHorizontal() != ops->descending) { + axisOffset = viewMin - worldMin; + axisScale = graphPtr->hScale_; + } else { + axisOffset = worldMax - viewMax; + axisScale = graphPtr->vScale_; + } + if (objc == 4) { + double first = Clamp(axisOffset / worldWidth); + double last = Clamp((axisOffset + viewWidth) / worldWidth); + Tcl_Obj *listObjPtr = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(first)); + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(last)); + Tcl_SetObjResult(interp, listObjPtr); + return TCL_OK; + } + double fract = axisOffset / worldWidth; + if (GetAxisScrollInfo(interp, objc, objv, &fract, viewWidth / worldWidth, + ops->scrollUnits, axisScale) != TCL_OK) + return TCL_ERROR; + + if (axisPtr->isHorizontal() != ops->descending) { + ops->reqMin = (fract * worldWidth) + worldMin; + ops->reqMax = ops->reqMin + viewWidth; + } + else { + ops->reqMax = worldMax - (fract * worldWidth); + ops->reqMin = ops->reqMax - viewWidth; + } + if (ops->logScale) { + ops->reqMin = EXP10(ops->reqMin); + ops->reqMax = EXP10(ops->reqMax); + } + + graphPtr->flags |= RESET; + graphPtr->eventuallyRedraw(); + + return TCL_OK; +} + diff --git a/generic/tkbltGrAxisOp.h b/generic/tkbltGrAxisOp.h new file mode 100644 index 0000000..777aea7 --- /dev/null +++ b/generic/tkbltGrAxisOp.h @@ -0,0 +1,60 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGrAxisOp_h__ +#define __BltGrAxisOp_h__ + +#include "tkbltGraph.h" + +namespace Blt { + extern const Ensemble axisEnsemble[]; + extern int AxisObjConfigure(Blt::Axis* axisPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]); +}; + +extern int AxisCgetOp(Blt::Axis* axisPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]); +extern int AxisConfigureOp(Blt::Axis* axisPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]); +extern int AxisActivateOp(Blt::Axis* axisPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]); +extern int AxisInvTransformOp(Blt::Axis* axisPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]); +extern int AxisLimitsOp(Blt::Axis* axisPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]); +extern int AxisMarginOp(Blt::Axis* axisPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]); +extern int AxisTransformOp(Blt::Axis* axisPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]); +extern int AxisTypeOp(Blt::Axis* axisPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]); +extern int AxisViewOp(Blt::Axis* axisPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]); + +#endif diff --git a/generic/tkbltGrAxisOption.C b/generic/tkbltGrAxisOption.C new file mode 100644 index 0000000..6f91d99 --- /dev/null +++ b/generic/tkbltGrAxisOption.C @@ -0,0 +1,264 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include + +#include "tkbltGraph.h" +#include "tkbltGrAxis.h" +#include "tkbltGrAxisOption.h" +#include "tkbltConfig.h" +#include "tkbltInt.h" + +using namespace Blt; + +static Tk_CustomOptionSetProc AxisSetProc; +static Tk_CustomOptionGetProc AxisGetProc; +static Tk_CustomOptionFreeProc AxisFreeProc; +Tk_ObjCustomOption xAxisObjOption = + { + "xaxis", AxisSetProc, AxisGetProc, RestoreProc, AxisFreeProc, + (ClientData)CID_AXIS_X + }; +Tk_ObjCustomOption yAxisObjOption = + { + "yaxis", AxisSetProc, AxisGetProc, RestoreProc, AxisFreeProc, + (ClientData)CID_AXIS_Y + }; + +static int AxisSetProc(ClientData clientData, Tcl_Interp* interp, + Tk_Window tkwin, Tcl_Obj** objPtr, char* widgRec, + int offset, char* savePtr, int flags) +{ + Axis** axisPtrPtr = (Axis**)(widgRec + offset); + *(double*)savePtr = *(double*)axisPtrPtr; + + if (!axisPtrPtr) + return TCL_OK; + + Graph* graphPtr = getGraphFromWindowData(tkwin); +#ifdef _WIN64 + ClassId classId = (ClassId)((long long)clientData); +#else + ClassId classId = (ClassId)((long)clientData); +#endif + + Axis *axisPtr; + if (graphPtr->getAxis(*objPtr, &axisPtr) != TCL_OK) + return TCL_ERROR; + + if (classId != CID_NONE) { + // Set the axis type on the first use of it. + if ((axisPtr->refCount_ == 0) || (axisPtr->classId_ == CID_NONE)) + axisPtr->setClass(classId); + + else if (axisPtr->classId_ != classId) { + Tcl_AppendResult(interp, "axis \"", Tcl_GetString(*objPtr), + "\" is already in use on an opposite ", + axisPtr->className_, "-axis", + NULL); + return TCL_ERROR; + } + axisPtr->refCount_++; + } + + *axisPtrPtr = axisPtr; + return TCL_OK; +}; + +static Tcl_Obj* AxisGetProc(ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset) +{ + Axis* axisPtr = *(Axis**)(widgRec + offset); + if (!axisPtr) + return Tcl_NewStringObj("", -1); + + return Tcl_NewStringObj(axisPtr->name_, -1); +}; + +static void AxisFreeProc(ClientData clientData, Tk_Window tkwin, char *ptr) +{ + Axis* axisPtr = *(Axis**)ptr; + if (axisPtr) { + axisPtr->refCount_--; + if (axisPtr->refCount_ == 0) + delete axisPtr; + } +} + +static Tk_CustomOptionSetProc LimitSetProc; +static Tk_CustomOptionGetProc LimitGetProc; +Tk_ObjCustomOption limitObjOption = + { + "limit", LimitSetProc, LimitGetProc, NULL, NULL, NULL + }; + +static int LimitSetProc(ClientData clientData, Tcl_Interp* interp, + Tk_Window tkwin, Tcl_Obj** objPtr, char* widgRec, + int offset, char* save, int flags) +{ + double* limitPtr = (double*)(widgRec + offset); + const char* string = Tcl_GetString(*objPtr); + if (!string || !string[0]) { + *limitPtr = NAN; + return TCL_OK; + } + + if (Tcl_GetDoubleFromObj(interp, *objPtr, limitPtr) != TCL_OK) + return TCL_ERROR; + + return TCL_OK; +} + +static Tcl_Obj* LimitGetProc(ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset) +{ + double limit = *(double*)(widgRec + offset); + Tcl_Obj* objPtr; + + if (!isnan(limit)) + objPtr = Tcl_NewDoubleObj(limit); + else + objPtr = Tcl_NewStringObj("", -1); + + return objPtr; +} + +static Tk_CustomOptionSetProc TicksSetProc; +static Tk_CustomOptionGetProc TicksGetProc; +static Tk_CustomOptionFreeProc TicksFreeProc; +Tk_ObjCustomOption ticksObjOption = + { + "ticks", TicksSetProc, TicksGetProc, RestoreProc, TicksFreeProc, NULL + }; + +static int TicksSetProc(ClientData clientData, Tcl_Interp* interp, + Tk_Window tkwin, Tcl_Obj** objPtr, char* widgRec, + int offset, char* savePtr, int flags) +{ + Ticks** ticksPtrPtr = (Ticks**)(widgRec + offset); + *(double*)savePtr = *(double*)ticksPtrPtr; + + if (!ticksPtrPtr) + return TCL_OK; + + int objc; + Tcl_Obj** objv; + if (Tcl_ListObjGetElements(interp, *objPtr, &objc, &objv) != TCL_OK) + return TCL_ERROR; + + Ticks* ticksPtr = NULL; + if (objc > 0) { + ticksPtr = new Ticks(objc); + for (int ii=0; iivalues[ii] = value; + } + ticksPtr->nTicks = objc; + } + + *ticksPtrPtr = ticksPtr; + + return TCL_OK; +} + +static Tcl_Obj* TicksGetProc(ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset) +{ + Ticks* ticksPtr = *(Ticks**)(widgRec + offset); + + if (!ticksPtr) + return Tcl_NewListObj(0, NULL); + + int cnt = ticksPtr->nTicks; + Tcl_Obj** ll = new Tcl_Obj*[cnt]; + for (int ii = 0; iivalues[ii]); + + Tcl_Obj* listObjPtr = Tcl_NewListObj(cnt, ll); + delete [] ll; + + return listObjPtr; +} + +static void TicksFreeProc(ClientData clientData, Tk_Window tkwin, + char *ptr) +{ + Ticks* ticksPtr = *(Ticks**)ptr; + delete ticksPtr; +} + +static Tk_CustomOptionSetProc ObjectSetProc; +static Tk_CustomOptionGetProc ObjectGetProc; +static Tk_CustomOptionFreeProc ObjectFreeProc; +Tk_ObjCustomOption objectObjOption = + { + "object", ObjectSetProc, ObjectGetProc, RestoreProc, ObjectFreeProc, NULL, + }; + +static int ObjectSetProc(ClientData clientData, Tcl_Interp* interp, + Tk_Window tkwin, Tcl_Obj** objPtr, char* widgRec, + int offset, char* savePtr, int flags) +{ + Tcl_Obj** objectPtrPtr = (Tcl_Obj**)(widgRec + offset); + *(double*)savePtr = *(double*)objectPtrPtr; + + if (!objectPtrPtr) + return TCL_OK; + + Tcl_IncrRefCount(*objPtr); + *objectPtrPtr = *objPtr; + + return TCL_OK; +} + +static Tcl_Obj* ObjectGetProc(ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset) +{ + Tcl_Obj** objectPtrPtr = (Tcl_Obj**)(widgRec + offset); + + if (!objectPtrPtr) + return Tcl_NewObj(); + + return *objectPtrPtr; +} + +static void ObjectFreeProc(ClientData clientData, Tk_Window tkwin, + char *ptr) +{ + Tcl_Obj* objectPtr = *(Tcl_Obj**)ptr; + if (objectPtr) + Tcl_DecrRefCount(objectPtr); +} + diff --git a/generic/tkbltGrAxisOption.h b/generic/tkbltGrAxisOption.h new file mode 100644 index 0000000..4efa8ee --- /dev/null +++ b/generic/tkbltGrAxisOption.h @@ -0,0 +1,41 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGrAxisOption_h__ +#define __BltGrAxisOption_h__ + +#include + +extern Tk_ObjCustomOption xAxisObjOption; +extern Tk_ObjCustomOption yAxisObjOption; +extern Tk_ObjCustomOption limitObjOption; +extern Tk_ObjCustomOption ticksObjOption; +extern Tk_ObjCustomOption objectObjOption; + +#endif diff --git a/generic/tkbltGrBind.C b/generic/tkbltGrBind.C new file mode 100644 index 0000000..3e7e81e --- /dev/null +++ b/generic/tkbltGrBind.C @@ -0,0 +1,227 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1998 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include +#include +#include +using namespace std; + +#include "tkbltGrBind.h" +#include "tkbltGraph.h" +#include "tkbltGrLegd.h" + +using namespace Blt; + +static Tk_EventProc BindProc; + +BindTable::BindTable(Graph* graphPtr, Pick* pickPtr) +{ + graphPtr_ = graphPtr; + pickPtr_ = pickPtr; + grab_ =0; + table_ = Tk_CreateBindingTable(graphPtr->interp_); + currentItem_ =NULL; + currentContext_ =CID_NONE; + newItem_ =NULL; + newContext_ =CID_NONE; + focusItem_ =NULL; + focusContext_ =CID_NONE; + // pickEvent =NULL; + state_ =0; + + unsigned int mask = (KeyPressMask | KeyReleaseMask | ButtonPressMask | + ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | + PointerMotionMask); + Tk_CreateEventHandler(graphPtr->tkwin_, mask, BindProc, this); +} + +BindTable::~BindTable() +{ + Tk_DeleteBindingTable(table_); + unsigned int mask = (KeyPressMask | KeyReleaseMask | ButtonPressMask | + ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | + PointerMotionMask); + Tk_DeleteEventHandler(graphPtr_->tkwin_, mask, BindProc, this); +} + +int BindTable::configure(ClientData item, int objc, Tcl_Obj* const objv[]) +{ + if (objc == 0) { + Tk_GetAllBindings(graphPtr_->interp_, table_, item); + return TCL_OK; + } + + const char *string = Tcl_GetString(objv[0]); + if (objc == 1) { + const char* command = + Tk_GetBinding(graphPtr_->interp_, table_, item, string); + if (!command) { + Tcl_ResetResult(graphPtr_->interp_); + Tcl_AppendResult(graphPtr_->interp_, "invalid binding event \"", + string, "\"", NULL); + return TCL_ERROR; + } + Tcl_SetStringObj(Tcl_GetObjResult(graphPtr_->interp_), command, -1); + return TCL_OK; + } + + const char* seq = string; + const char* command = Tcl_GetString(objv[1]); + if (command[0] == '\0') + return Tk_DeleteBinding(graphPtr_->interp_, table_, item, seq); + + unsigned long mask; + if (command[0] == '+') + mask = Tk_CreateBinding(graphPtr_->interp_, table_, + item, seq, command+1, 1); + else + mask = Tk_CreateBinding(graphPtr_->interp_, table_, + item, seq, command, 0); + if (!mask) + return TCL_ERROR; + + if (mask & (unsigned) ~(ButtonMotionMask|Button1MotionMask + |Button2MotionMask|Button3MotionMask|Button4MotionMask + |Button5MotionMask|ButtonPressMask|ButtonReleaseMask + |EnterWindowMask|LeaveWindowMask|KeyPressMask + |KeyReleaseMask|PointerMotionMask|VirtualEventMask)) { + Tk_DeleteBinding(graphPtr_->interp_, table_, item, seq); + Tcl_ResetResult(graphPtr_->interp_); + Tcl_AppendResult(graphPtr_->interp_, "requested illegal events; ", + "only key, button, motion, enter, leave, and virtual ", + "events may be used", (char *)NULL); + return TCL_ERROR; + } + + return TCL_OK; +} + +void BindTable::deleteBindings(ClientData object) +{ + Tk_DeleteAllBindings(table_, object); + + if (currentItem_ == object) { + currentItem_ =NULL; + currentContext_ =CID_NONE; + } + + if (newItem_ == object) { + newItem_ =NULL; + newContext_ =CID_NONE; + } + + if (focusItem_ == object) { + focusItem_ =NULL; + focusContext_ =CID_NONE; + } +} + +void BindTable::doEvent(XEvent* eventPtr) +{ + ClientData item = currentItem_; + ClassId classId = currentContext_; + + if ((eventPtr->type == KeyPress) || (eventPtr->type == KeyRelease)) { + item = focusItem_; + classId = focusContext_; + } + if (!item) + return; + + int nTags; + const char** tagArray = graphPtr_->getTags(item, classId, &nTags); + Tk_BindEvent(table_, eventPtr, graphPtr_->tkwin_, nTags, (void**)tagArray); + + delete [] tagArray; +} + +void BindTable::pickItem(XEvent* eventPtr) +{ + int buttonDown = state_ + & (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask); + + // A LeaveNotify event automatically means that there's no current item, + if (eventPtr->type != LeaveNotify) { + int x = eventPtr->xcrossing.x; + int y = eventPtr->xcrossing.y; + newItem_ = pickPtr_->pickEntry(x, y, &newContext_); + } + else { + newItem_ =NULL; + newContext_ = CID_NONE; + } + + // Nothing to do: the current item hasn't changed. + if ((newItem_ == currentItem_) && !grab_) + return; + + if (!buttonDown) + grab_ =0; + + if ((newItem_ != currentItem_) && buttonDown) { + grab_ =1; + return; + } + + grab_ =0; + currentItem_ = newItem_; + currentContext_ = newContext_; +} + +static void BindProc(ClientData clientData, XEvent* eventPtr) +{ + BindTable* bindPtr = (BindTable*)clientData; + Tcl_Preserve(bindPtr->graphPtr_); + + switch (eventPtr->type) { + case ButtonPress: + case ButtonRelease: + bindPtr->state_ = eventPtr->xbutton.state; + break; + case EnterNotify: + case LeaveNotify: + bindPtr->state_ = eventPtr->xcrossing.state; + break; + case MotionNotify: + bindPtr->state_ = eventPtr->xmotion.state; + break; + case KeyPress: + case KeyRelease: + bindPtr->state_ = eventPtr->xkey.state; + break; + } + + bindPtr->pickItem(eventPtr); + bindPtr->doEvent(eventPtr); + + Tcl_Release(bindPtr->graphPtr_); +} + diff --git a/generic/tkbltGrBind.h b/generic/tkbltGrBind.h new file mode 100644 index 0000000..7947210 --- /dev/null +++ b/generic/tkbltGrBind.h @@ -0,0 +1,72 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1998-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGrBind_h__ +#define __BltGrBind_h__ + +#include + +#include "tkbltGrMisc.h" + +namespace Blt { + class Graph; + class Pick; + + class BindTable { + protected: + Tk_BindingTable table_; + unsigned int grab_; + ClientData newItem_; + ClassId newContext_; + Pick* pickPtr_; + + public: + Graph* graphPtr_; + ClientData currentItem_; + ClassId currentContext_; + ClientData focusItem_; + ClassId focusContext_; + int state_; + XEvent pickEvent_; + + public: + BindTable(Graph*, Pick*); + virtual ~BindTable(); + + int configure(ClientData, int, Tcl_Obj *const []); + void deleteBindings(ClientData object); + void doEvent(XEvent*); + void pickItem(XEvent*); + + ClientData currentItem() {return currentItem_;} + }; +}; + + +#endif diff --git a/generic/tkbltGrDef.h b/generic/tkbltGrDef.h new file mode 100644 index 0000000..d73836a --- /dev/null +++ b/generic/tkbltGrDef.h @@ -0,0 +1,45 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGrDef_h__ +#define __BltGrDef_h__ + +#define STD_NORMAL_BACKGROUND "gray85" +#define STD_NORMAL_FOREGROUND "black" +#define STD_ACTIVE_BACKGROUND "gray90" +#define STD_ACTIVE_FOREGROUND "black" + +#define STD_FONT_LARGE "helvetica 16 normal roman" +#define STD_FONT_MEDIUM "helvetica 14 normal roman" +#define STD_FONT_NORMAL "helvetica 12 normal roman" +#define STD_FONT_SMALL "helvetica 10 normal roman" + +#define STD_BORDERWIDTH "2" + +#endif diff --git a/generic/tkbltGrElem.C b/generic/tkbltGrElem.C new file mode 100644 index 0000000..faf1b72 --- /dev/null +++ b/generic/tkbltGrElem.C @@ -0,0 +1,284 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include + +#include "tkbltGraph.h" +#include "tkbltGrBind.h" +#include "tkbltGrElem.h" +#include "tkbltGrPen.h" +#include "tkbltInt.h" + +using namespace Blt; + +// Class ElemValues + +ElemValues::ElemValues() +{ + values_ =NULL; + nValues_ =0; + min_ =0; + max_ =0; +} + +ElemValues::~ElemValues() +{ + delete [] values_; +} + +void ElemValues::reset() +{ + delete [] values_; + values_ =NULL; + nValues_ =0; + min_ =0; + max_ =0; +} + +ElemValuesSource::ElemValuesSource(int nn) : ElemValues() +{ + nValues_ = nn; + values_ = new double[nn]; +} + +ElemValuesSource::ElemValuesSource(int nn, double* vv) : ElemValues() +{ + nValues_ = nn; + values_ = vv; +} + +ElemValuesSource::~ElemValuesSource() +{ +} + +void ElemValuesSource::findRange() +{ + if (nValues_<1 || !values_) + return; + + min_ = DBL_MAX; + max_ = -DBL_MAX; + for (int ii=0; ii max_) + max_ = values_[ii]; + } + } +} + +ElemValuesVector::ElemValuesVector(Element* ptr, const char* vecName) + : ElemValues() +{ + elemPtr_ = ptr; + Graph* graphPtr = elemPtr_->graphPtr_; + source_ = Blt_AllocVectorId(graphPtr->interp_, vecName); +} + +ElemValuesVector::~ElemValuesVector() +{ + freeSource(); +} + +int ElemValuesVector::getVector() +{ + Graph* graphPtr = elemPtr_->graphPtr_; + + Blt_Vector *vecPtr; + if (Blt_GetVectorById(graphPtr->interp_, source_, &vecPtr) != TCL_OK) + return TCL_ERROR; + + if (fetchValues(vecPtr) != TCL_OK) { + freeSource(); + return TCL_ERROR; + } + + Blt_SetVectorChangedProc(source_, VectorChangedProc, this); + return TCL_OK; +} + +int ElemValuesVector::fetchValues(Blt_Vector* vector) +{ + Graph* graphPtr = elemPtr_->graphPtr_; + + delete [] values_; + values_ = NULL; + nValues_ = 0; + min_ =0; + max_ =0; + + int ss = Blt_VecLength(vector); + if (!ss) + return TCL_OK; + + double* array = new double[ss]; + if (!array) { + Tcl_AppendResult(graphPtr->interp_, "can't allocate new vector", NULL); + return TCL_ERROR; + } + + memcpy(array, Blt_VecData(vector), ss*sizeof(double)); + values_ = array; + nValues_ = Blt_VecLength(vector); + min_ = Blt_VecMin(vector); + max_ = Blt_VecMax(vector); + + return TCL_OK; +} + +void ElemValuesVector::freeSource() +{ + if (source_) { + Blt_SetVectorChangedProc(source_, NULL, NULL); + Blt_FreeVectorId(source_); + source_ = NULL; + } +} + +// Class Element + +Element::Element(Graph* graphPtr, const char* name, Tcl_HashEntry* hPtr) +{ + graphPtr_ = graphPtr; + name_ = dupstr(name); + optionTable_ =NULL; + ops_ =NULL; + hashPtr_ = hPtr; + + row_ =0; + col_ =0; + activeIndices_ =NULL; + nActiveIndices_ =0; + xRange_ =0; + yRange_ =0; + active_ =0; + labelActive_ =0; + + link =NULL; +} + +Element::~Element() +{ + graphPtr_->bindTable_->deleteBindings(this); + + if (link) + graphPtr_->elements_.displayList->deleteLink(link); + + if (hashPtr_) + Tcl_DeleteHashEntry(hashPtr_); + + delete [] name_; + + delete [] activeIndices_; + + Tk_FreeConfigOptions((char*)ops_, optionTable_, graphPtr_->tkwin_); + free(ops_); +} + +double Element::FindElemValuesMinimum(ElemValues* valuesPtr, double minLimit) +{ + double min = DBL_MAX; + if (!valuesPtr) + return min; + + for (int ii=0; iinValues(); ii++) { + double x = valuesPtr->values_[ii]; + // What do you do about negative values when using log + // scale values seems like a grey area. Mirror. + if (x < 0.0) + x = -x; + if ((x > minLimit) && (min > x)) + min = x; + } + if (min == DBL_MAX) + min = minLimit; + + return min; +} + +PenStyle** Element::StyleMap() +{ + ElementOptions* ops = (ElementOptions*)ops_; + + int nPoints = NUMBEROFPOINTS(ops); + int nWeights = MIN(ops->w ? ops->w->nValues() : 0, nPoints); + double* w = ops->w ? ops->w->values_ : NULL; + ChainLink* link = Chain_FirstLink(ops->stylePalette); + PenStyle* stylePtr = (PenStyle*)Chain_GetValue(link); + + // Create a style mapping array (data point index to style), + // initialized to the default style. + PenStyle** dataToStyle = new PenStyle*[nPoints]; + for (int ii=0; iistylePalette); link; + link=Chain_PrevLink(link)) { + stylePtr = (PenStyle*)Chain_GetValue(link); + + if (stylePtr->weight.range > 0.0) { + double norm = (w[ii] - stylePtr->weight.min) / stylePtr->weight.range; + if (((norm - 1.0) <= DBL_EPSILON) && + (((1.0 - norm) - 1.0) <= DBL_EPSILON)) { + dataToStyle[ii] = stylePtr; + break; + } + } + } + } + + return dataToStyle; +} + +void Element::freeStylePalette(Chain* stylePalette) +{ + // Skip the first slot. It contains the built-in "normal" pen of the element + ChainLink* link = Chain_FirstLink(stylePalette); + if (link) { + ChainLink* next; + for (link=Chain_NextLink(link); link; link=next) { + next = Chain_NextLink(link); + PenStyle *stylePtr = (PenStyle*)Chain_GetValue(link); + Pen* penPtr = stylePtr->penPtr; + if (penPtr) { + penPtr->refCount_--; + if (penPtr->refCount_ == 0) + delete penPtr; + } + stylePalette->deleteLink(link); + } + } +} + diff --git a/generic/tkbltGrElem.h b/generic/tkbltGrElem.h new file mode 100644 index 0000000..8904df0 --- /dev/null +++ b/generic/tkbltGrElem.h @@ -0,0 +1,202 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGrElem_h__ +#define __BltGrElem_h__ + +#include + +#include "tkbltVector.h" +#include "tkbltChain.h" + +#include "tkbltGrMisc.h" +#include "tkbltGrPen.h" +#include "tkbltGrPSOutput.h" + +#define SHOW_NONE 0 +#define SHOW_X 1 +#define SHOW_Y 2 +#define SHOW_BOTH 3 + +#define NUMBEROFPOINTS(e) MIN( (e)->coords.x ? (e)->coords.x->nValues() : 0, \ + (e)->coords.y ? (e)->coords.y->nValues() : 0 ) +#define NORMALPEN(e) ((((e)->normalPenPtr == NULL) ? \ + (e)->builtinPenPtr : (e)->normalPenPtr)) + +namespace Blt { + class Axis; + class Element; + class Pen; + class Postscript; + + class ElemValues { + protected: + double min_; + double max_; + int nValues_; + + public: + double* values_; + + public: + ElemValues(); + virtual ~ElemValues(); + + void reset(); + int nValues() {return nValues_;} + double min() {return min_;} + double max() {return max_;} + }; + + class ElemValuesSource : public ElemValues + { + public: + ElemValuesSource(int); + ElemValuesSource(int, double*); + ~ElemValuesSource(); + + void findRange(); + }; + + class ElemValuesVector : public ElemValues + { + public: + Element* elemPtr_; + Blt_VectorId source_; + + public: + ElemValuesVector(Element*, const char*); + ~ElemValuesVector(); + + int getVector(); + int fetchValues(Blt_Vector*); + void freeSource(); + }; + + typedef struct { + Segment2d *segments; + int *map; + int length; + } GraphSegments; + + typedef struct { + ElemValuesSource* x; + ElemValuesSource* y; + } ElemCoords; + + typedef struct { + double min; + double max; + double range; + } Weight; + + typedef struct { + Weight weight; + Pen* penPtr; + } PenStyle; + + typedef struct { + Element* elemPtr; + const char* label; + const char** tags; + Axis* xAxis; + Axis* yAxis; + ElemCoords coords; + ElemValues* w; + ElemValues* xError; + ElemValues* yError; + ElemValues* xHigh; + ElemValues* xLow; + ElemValues* yHigh; + ElemValues* yLow; + int hide; + int legendRelief; + Chain* stylePalette; + Pen* builtinPenPtr; + Pen* activePenPtr; + Pen* normalPenPtr; + PenOptions builtinPen; + } ElementOptions; + + class Element { + protected: + Tk_OptionTable optionTable_; + void* ops_; + + double xRange_; + double yRange_; + + public: + Graph* graphPtr_; + const char* name_; + Tcl_HashEntry* hashPtr_; + unsigned row_; + unsigned col_; + int nActiveIndices_; + int* activeIndices_; + int active_; + int labelActive_; + + ChainLink* link; + + protected: + double FindElemValuesMinimum(ElemValues*, double); + PenStyle** StyleMap(); + + public: + Element(Graph*, const char*, Tcl_HashEntry*); + virtual ~Element(); + + virtual int configure() =0; + virtual void map() =0; + virtual void extents(Region2d*) =0; + virtual void draw(Drawable) =0; + virtual void drawActive(Drawable) =0; + virtual void drawSymbol(Drawable, int, int, int) =0; + virtual void closest() =0; + virtual void print(PSOutput*) =0; + virtual void printActive(PSOutput*) =0; + virtual void printSymbol(PSOutput*, double, double, int) =0; + + virtual ClassId classId() =0; + virtual const char* className() =0; + virtual const char* typeName() =0; + + void freeStylePalette (Chain*); + + Tk_OptionTable optionTable() {return optionTable_;} + void* ops() {return ops_;} + }; +}; + +extern void VectorChangedProc(Tcl_Interp* interp, ClientData clientData, + Blt_VectorNotify notify); + + +#endif diff --git a/generic/tkbltGrElemBar.C b/generic/tkbltGrElemBar.C new file mode 100644 index 0000000..6698760 --- /dev/null +++ b/generic/tkbltGrElemBar.C @@ -0,0 +1,1315 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include + +#include "tkbltGraphBar.h" +#include "tkbltGrElemBar.h" +#include "tkbltGrElemOption.h" +#include "tkbltGrAxis.h" +#include "tkbltGrMisc.h" +#include "tkbltGrDef.h" +#include "tkbltConfig.h" +#include "tkbltGrPSOutput.h" +#include "tkbltInt.h" + +using namespace Blt; + +#define CLAMP(x,l,h) ((x) = (((x)<(l))? (l) : ((x)>(h)) ? (h) : (x))) +#define MIN3(a,b,c) (((a)<(b))?(((a)<(c))?(a):(c)):(((b)<(c))?(b):(c))) + +#define PointInRectangle(r,x0,y0) \ + (((x0) <= (int)((r)->x + (r)->width - 1)) && ((x0) >= (int)(r)->x) && \ + ((y0) <= (int)((r)->y + (r)->height - 1)) && ((y0) >= (int)(r)->y)) + +// OptionSpecs + +static Tk_ObjCustomOption styleObjOption = + { + "style", StyleSetProc, StyleGetProc, StyleRestoreProc, StyleFreeProc, + (ClientData)sizeof(BarStyle) + }; + +extern Tk_ObjCustomOption penObjOption; +extern Tk_ObjCustomOption pairsObjOption; +extern Tk_ObjCustomOption valuesObjOption; +extern Tk_ObjCustomOption xAxisObjOption; +extern Tk_ObjCustomOption yAxisObjOption; + +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_CUSTOM, "-activepen", "activePen", "ActivePen", + "active", -1, Tk_Offset(BarElementOptions, activePenPtr), + TK_OPTION_NULL_OK, &penObjOption, LAYOUT}, + {TK_OPTION_SYNONYM, "-background", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-color", 0}, + {TK_OPTION_DOUBLE, "-barwidth", "barWidth", "BarWidth", + "0", -1, Tk_Offset(BarElementOptions, barWidth), 0, NULL, LAYOUT}, + {TK_OPTION_SYNONYM, "-bd", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-borderwidth", 0}, + {TK_OPTION_SYNONYM, "-bg", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-color", 0}, + {TK_OPTION_CUSTOM, "-bindtags", "bindTags", "BindTags", + "all", -1, Tk_Offset(BarElementOptions, tags), + TK_OPTION_NULL_OK, &listObjOption, 0}, + {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", + STD_BORDERWIDTH, -1, Tk_Offset(BarElementOptions, builtinPen.borderWidth), + 0, NULL, CACHE}, + {TK_OPTION_BORDER, "-color", "color", "color", + STD_NORMAL_FOREGROUND, -1, Tk_Offset(BarElementOptions, builtinPen.fill), + 0, NULL, CACHE}, + {TK_OPTION_CUSTOM, "-data", "data", "Data", + NULL, -1, Tk_Offset(BarElementOptions, coords), + TK_OPTION_NULL_OK, &pairsObjOption, RESET}, + {TK_OPTION_COLOR, "-errorbarcolor", "errorBarColor", "ErrorBarColor", + NULL, -1, Tk_Offset(BarElementOptions, builtinPen.errorBarColor), + TK_OPTION_NULL_OK, NULL, CACHE}, + {TK_OPTION_PIXELS,"-errorbarwidth", "errorBarWidth", "ErrorBarWidth", + "1", -1, Tk_Offset(BarElementOptions, builtinPen.errorBarLineWidth), + 0, NULL, CACHE}, + {TK_OPTION_PIXELS, "-errorbarcap", "errorBarCap", "ErrorBarCap", + "0", -1, Tk_Offset(BarElementOptions, builtinPen.errorBarCapWidth), + 0, NULL, LAYOUT}, + {TK_OPTION_SYNONYM, "-fg", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-outline", 0}, + {TK_OPTION_SYNONYM, "-fill", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-color", 0}, + {TK_OPTION_SYNONYM, "-foreground", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-outline", 0}, + {TK_OPTION_BOOLEAN, "-hide", "hide", "Hide", + "no", -1, Tk_Offset(BarElementOptions, hide), 0, NULL, LAYOUT}, + {TK_OPTION_STRING, "-label", "label", "Label", + NULL, -1, Tk_Offset(BarElementOptions, label), + TK_OPTION_NULL_OK, NULL, LAYOUT}, + {TK_OPTION_RELIEF, "-legendrelief", "legendRelief", "LegendRelief", + "flat", -1, Tk_Offset(BarElementOptions, legendRelief), 0, NULL, LAYOUT}, + {TK_OPTION_CUSTOM, "-mapx", "mapX", "MapX", + "x", -1, Tk_Offset(BarElementOptions, xAxis), 0, &xAxisObjOption, RESET}, + {TK_OPTION_CUSTOM, "-mapy", "mapY", "MapY", + "y", -1, Tk_Offset(BarElementOptions, yAxis), 0, &yAxisObjOption, RESET}, + {TK_OPTION_COLOR, "-outline", "outline", "Outline", + NULL, -1, Tk_Offset(BarElementOptions, builtinPen.outlineColor), + TK_OPTION_NULL_OK, NULL, CACHE}, + {TK_OPTION_CUSTOM, "-pen", "pen", "Pen", + NULL, -1, Tk_Offset(BarElementOptions, normalPenPtr), + TK_OPTION_NULL_OK, &penObjOption, LAYOUT}, + {TK_OPTION_RELIEF, "-relief", "relief", "Relief", + "raised", -1, Tk_Offset(BarElementOptions, builtinPen.relief), + 0, NULL, LAYOUT}, + {TK_OPTION_STRING_TABLE, "-showerrorbars", "showErrorBars", "ShowErrorBars", + "both", -1, Tk_Offset(BarElementOptions, builtinPen.errorBarShow), + 0, &fillObjOption, LAYOUT}, + {TK_OPTION_STRING_TABLE, "-showvalues", "showValues", "ShowValues", + "none", -1, Tk_Offset(BarElementOptions, builtinPen.valueShow), + 0, &fillObjOption, CACHE}, + {TK_OPTION_STRING, "-stack", "stack", "Stack", + NULL, -1, Tk_Offset(BarElementOptions, groupName), + TK_OPTION_NULL_OK, NULL, RESET}, + {TK_OPTION_CUSTOM, "-styles", "styles", "Styles", + "", -1, Tk_Offset(BarElementOptions, stylePalette), + 0, &styleObjOption, RESET}, + {TK_OPTION_ANCHOR, "-valueanchor", "valueAnchor", "ValueAnchor", + "s", -1, Tk_Offset(BarElementOptions, builtinPen.valueStyle.anchor), + 0, NULL, CACHE}, + {TK_OPTION_COLOR, "-valuecolor", "valueColor", "ValueColor", + STD_NORMAL_FOREGROUND, -1, + Tk_Offset(BarElementOptions,builtinPen.valueStyle.color), 0, NULL, CACHE}, + {TK_OPTION_FONT, "-valuefont", "valueFont", "ValueFont", + STD_FONT_SMALL, -1, Tk_Offset(BarElementOptions, builtinPen.valueStyle.font), + 0, NULL, CACHE}, + {TK_OPTION_STRING, "-valueformat", "valueFormat", "ValueFormat", + "%g", -1, Tk_Offset(BarElementOptions, builtinPen.valueFormat), + TK_OPTION_NULL_OK, NULL, CACHE}, + {TK_OPTION_DOUBLE, "-valuerotate", "valueRotate", "ValueRotate", + "0", -1, Tk_Offset(BarElementOptions, builtinPen.valueStyle.angle), + 0, NULL, CACHE}, + {TK_OPTION_CUSTOM, "-weights", "weights", "Weights", + NULL, -1, Tk_Offset(BarElementOptions, w), + TK_OPTION_NULL_OK, &valuesObjOption, RESET}, + {TK_OPTION_SYNONYM, "-x", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-xdata", 0}, + {TK_OPTION_CUSTOM, "-xdata", "xData", "XData", + NULL, -1, Tk_Offset(BarElementOptions, coords.x), + TK_OPTION_NULL_OK, &valuesObjOption, RESET}, + {TK_OPTION_CUSTOM, "-xerror", "xError", "XError", + NULL, -1, Tk_Offset(BarElementOptions, xError), + TK_OPTION_NULL_OK, &valuesObjOption, RESET}, + {TK_OPTION_CUSTOM, "-xhigh", "xHigh", "XHigh", + NULL, -1, Tk_Offset(BarElementOptions, xHigh), + TK_OPTION_NULL_OK, &valuesObjOption, RESET}, + {TK_OPTION_CUSTOM, "-xlow", "xLow", "XLow", + NULL, -1, Tk_Offset(BarElementOptions, xLow), + TK_OPTION_NULL_OK, &valuesObjOption, RESET}, + {TK_OPTION_SYNONYM, "-y", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-ydata", 0}, + {TK_OPTION_CUSTOM, "-ydata", "yData", "YData", + NULL, -1, Tk_Offset(BarElementOptions, coords.y), + TK_OPTION_NULL_OK, &valuesObjOption, RESET}, + {TK_OPTION_CUSTOM, "-yerror", "yError", "YError", + NULL, -1, Tk_Offset(BarElementOptions, yError), + TK_OPTION_NULL_OK, &valuesObjOption, RESET}, + {TK_OPTION_CUSTOM, "-yhigh", "yHigh", "YHigh", + NULL, -1, Tk_Offset(BarElementOptions, yHigh), + TK_OPTION_NULL_OK, &valuesObjOption, RESET}, + {TK_OPTION_CUSTOM, "-ylow", "yLow", "YLow", + NULL, -1, Tk_Offset(BarElementOptions, yLow), + TK_OPTION_NULL_OK, &valuesObjOption, RESET}, + {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, -1, 0, 0, 0} +}; + +BarElement::BarElement(Graph* graphPtr, const char* name, Tcl_HashEntry* hPtr) + : Element(graphPtr, name, hPtr) +{ + barToData_ =NULL; + bars_ =NULL; + activeToData_ =NULL; + activeRects_ =NULL; + nBars_ =0; + nActive_ =0; + + xeb_.segments =NULL; + xeb_.map =NULL; + xeb_.length =0; + yeb_.segments =NULL; + yeb_.map =NULL; + yeb_.length =0; + + ops_ = (BarElementOptions*)calloc(1, sizeof(BarElementOptions)); + BarElementOptions* ops = (BarElementOptions*)ops_; + ops->elemPtr = (Element*)this; + + builtinPenPtr = new BarPen(graphPtr_, "builtin", &ops->builtinPen); + ops->builtinPenPtr = builtinPenPtr; + + optionTable_ = Tk_CreateOptionTable(graphPtr->interp_, optionSpecs); + + ops->stylePalette = new Chain(); + + // this is an option and will be freed via Tk_FreeConfigOptions + // By default an element's name and label are the same + ops->label = Tcl_Alloc(strlen(name)+1); + if (name) + strcpy((char*)ops->label,(char*)name); + + Tk_InitOptions(graphPtr_->interp_, (char*)&(ops->builtinPen), + builtinPenPtr->optionTable(), graphPtr->tkwin_); +} + +BarElement::~BarElement() +{ + BarElementOptions* ops = (BarElementOptions*)ops_; + + delete builtinPenPtr; + + reset(); + + if (ops->stylePalette) { + freeStylePalette(ops->stylePalette); + delete ops->stylePalette; + } +} + +int BarElement::configure() +{ + BarElementOptions* ops = (BarElementOptions*)ops_; + + if (builtinPenPtr->configure() != TCL_OK) + return TCL_ERROR; + + // Point to the static normal pen if no external pens have been selected. + ChainLink* link = Chain_FirstLink(ops->stylePalette); + if (!link) { + link = new ChainLink(sizeof(BarStyle)); + ops->stylePalette->linkAfter(link, NULL); + } + BarStyle* stylePtr = (BarStyle*)Chain_GetValue(link); + stylePtr->penPtr = NORMALPEN(ops); + + return TCL_OK; +} + +void BarElement::map() +{ + BarGraph* barGraphPtr_ = (BarGraph*)graphPtr_; + BarElementOptions* ops = (BarElementOptions*)ops_; + BarGraphOptions* gops = (BarGraphOptions*)graphPtr_->ops_; + + if (!link) + return; + + reset(); + if (!ops->coords.x || !ops->coords.y || + !ops->coords.x->nValues() || !ops->coords.y->nValues()) + return; + int nPoints = NUMBEROFPOINTS(ops); + + double barWidth = (ops->barWidth > 0.0) ? ops->barWidth : gops->barWidth; + AxisOptions* axisyops = (AxisOptions*)ops->yAxis->ops(); + double baseline = (axisyops->logScale) ? 0.0 : gops->baseline; + double barOffset = barWidth * 0.5; + + // Create an array of bars representing the screen coordinates of all the + // segments in the bar. + Rectangle* bars = new Rectangle[nPoints]; + int* barToData = new int[nPoints]; + + double* x = ops->coords.x->values_; + double* y = ops->coords.y->values_; + int count = 0; + + int ii; + Rectangle* rp; + for (rp=bars, ii=0; ii ops->xAxis->axisRange_.max) || + ((x[ii] + barWidth) < ops->xAxis->axisRange_.min)) + continue; + + c1.x = x[ii] - barOffset; + c1.y = y[ii]; + c2.x = c1.x + barWidth; + c2.y = baseline; + + // If the mode is "aligned" or "stacked" we need to adjust the x or y + // coordinates of the two corners. + if ((barGraphPtr_->nBarGroups_ > 0) && + ((BarGraph::BarMode)gops->barMode != BarGraph::INFRONT) && + (!gops->stackAxes)) { + + BarSetKey key; + key.value =x[ii]; + key.xAxis =ops->xAxis; + key.yAxis =NULL; + Tcl_HashEntry* hPtr = + Tcl_FindHashEntry(&barGraphPtr_->setTable_, (char*)&key); + + if (hPtr) { + Tcl_HashTable *tablePtr = (Tcl_HashTable*)Tcl_GetHashValue(hPtr); + const char *name = (ops->groupName) ? ops->groupName:ops->yAxis->name_; + Tcl_HashEntry* hPtr2 = Tcl_FindHashEntry(tablePtr, name); + if (hPtr2) { + BarGroup* groupPtr = (BarGroup*)Tcl_GetHashValue(hPtr2); + double slice = barWidth / (double)barGraphPtr_->maxBarSetSize_; + double offset = (slice * groupPtr->index); + if (barGraphPtr_->maxBarSetSize_ > 1) { + offset += slice * 0.05; + slice *= 0.90; + } + + switch ((BarGraph::BarMode)gops->barMode) { + case BarGraph::STACKED: + groupPtr->count++; + c2.y = groupPtr->lastY; + c1.y += c2.y; + groupPtr->lastY = c1.y; + c1.x += offset; + c2.x = c1.x + slice; + break; + + case BarGraph::ALIGNED: + slice /= groupPtr->nSegments; + c1.x += offset + (slice * groupPtr->count); + c2.x = c1.x + slice; + groupPtr->count++; + break; + + case BarGraph::OVERLAP: + { + slice /= (groupPtr->nSegments + 1); + double width = slice + slice; + groupPtr->count++; + c1.x += offset + + (slice * (groupPtr->nSegments - groupPtr->count)); + c2.x = c1.x + width; + } + break; + + case BarGraph::INFRONT: + break; + } + } + } + } + + int invertBar = 0; + if (c1.y < c2.y) { + // Handle negative bar values by swapping ordinates + double temp = c1.y; + c1.y = c2.y; + c2.y = temp; + invertBar = 1; + } + + // Get the two corners of the bar segment and compute the rectangle + double ybot = c2.y; + c1 = graphPtr_->map2D(c1.x, c1.y, ops->xAxis, ops->yAxis); + c2 = graphPtr_->map2D(c2.x, c2.y, ops->xAxis, ops->yAxis); + if ((ybot == 0.0) && (axisyops->logScale)) + c2.y = graphPtr_->bottom_; + + if (c2.y < c1.y) { + double t = c1.y; + c1.y = c2.y; + c2.y = t; + } + + if (c2.x < c1.x) { + double t = c1.x; + c1.x = c2.x; + c2.x = t; + } + + if ((c1.x > graphPtr_->right_) || (c2.x < graphPtr_->left_) || + (c1.y > graphPtr_->bottom_) || (c2.y < graphPtr_->top_)) + continue; + + // Bound the bars horizontally by the width of the graph window + // Bound the bars vertically by the position of the axis. + double right =0; + double left =0; + double top =0; + double bottom =0; + if (gops->stackAxes) { + top = ops->yAxis->screenMin_; + bottom = ops->yAxis->screenMin_ + ops->yAxis->screenRange_; + left = graphPtr_->left_; + right = graphPtr_->right_; + } + else { + bottom = right = 10000; + // Shouldn't really have a call to Tk_Width or Tk_Height in + // mapping routine. We only want to clamp the bar segment to the + // size of the window if we're actually mapped onscreen + if (Tk_Height(graphPtr_->tkwin_) > 1) + bottom = Tk_Height(graphPtr_->tkwin_); + if (Tk_Width(graphPtr_->tkwin_) > 1) + right = Tk_Width(graphPtr_->tkwin_); + } + + CLAMP(c1.y, top, bottom); + CLAMP(c2.y, top, bottom); + CLAMP(c1.x, left, right); + CLAMP(c2.x, left, right); + double dx = fabs(c1.x - c2.x); + double dy = fabs(c1.y - c2.y); + if ((dx == 0) || (dy == 0)) + continue; + + int height = (int)dy; + int width = (int)dx; + if (invertBar) + rp->y = (int)MIN(c1.y, c2.y); + else + rp->y = (int)(MAX(c1.y, c2.y)) - height; + + rp->x = (int)MIN(c1.x, c2.x); + + rp->width = width + 1; + rp->width |= 0x1; + if (rp->width < 1) + rp->width = 1; + + rp->height = height + 1; + if (rp->height < 1) + rp->height = 1; + + // Save the data index corresponding to the rectangle + barToData[count] = ii; + count++; + rp++; + } + nBars_ = count; + bars_ = bars; + barToData_ = barToData; + if (nActiveIndices_ > 0) + mapActive(); + + int size = 20; + if (count > 0) + size = bars->width; + + // Set the symbol size of all the pen styles + for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link; + link = Chain_NextLink(link)) { + BarStyle *stylePtr = (BarStyle*)Chain_GetValue(link); + BarPen* penPtr = stylePtr->penPtr; + BarPenOptions* pops = (BarPenOptions*)penPtr->ops(); + stylePtr->symbolSize = size; + stylePtr->errorBarCapWidth = pops->errorBarCapWidth; + } + + BarStyle** dataToStyle = (BarStyle**)StyleMap(); + if (((ops->yHigh && ops->yHigh->nValues() > 0) && + (ops->yLow && ops->yLow->nValues() > 0)) || + ((ops->xHigh && ops->xHigh->nValues() > 0) && + (ops->xLow && ops->xLow->nValues() > 0)) || + (ops->xError && ops->xError->nValues() > 0) || + (ops->yError && ops->yError->nValues() > 0)) { + mapErrorBars(dataToStyle); + } + + mergePens(dataToStyle); + delete [] dataToStyle; +} + +void BarElement::extents(Region2d *regPtr) +{ + BarGraph* barGraphPtr_ = (BarGraph*)graphPtr_; + BarElementOptions* ops = (BarElementOptions*)ops_; + BarGraphOptions* gops = (BarGraphOptions*)graphPtr_->ops_; + + regPtr->top = regPtr->left = DBL_MAX; + regPtr->bottom = regPtr->right = -DBL_MAX; + + if (!ops->coords.x || !ops->coords.y || + !ops->coords.x->nValues() || !ops->coords.y->nValues()) + return; + + int nPoints = NUMBEROFPOINTS(ops); + + double middle = 0.5; + regPtr->left = ops->coords.x->min() - middle; + regPtr->right = ops->coords.x->max() + middle; + + regPtr->top = ops->coords.y->min(); + regPtr->bottom = ops->coords.y->max(); + if (regPtr->bottom < gops->baseline) + regPtr->bottom = gops->baseline; + + // Handle stacked bar elements specially. + // If element is stacked, the sum of its ordinates may be outside the + // minimum/maximum limits of the element's data points. + if (((BarGraph::BarMode)gops->barMode == BarGraph::STACKED) && + (barGraphPtr_->nBarGroups_ > 0)) + checkStacks(ops->xAxis, ops->yAxis, ®Ptr->top, ®Ptr->bottom); + + // Warning: You get what you deserve if the x-axis is logScale + AxisOptions* axisxops = (AxisOptions*)ops->xAxis->ops(); + AxisOptions* axisyops = (AxisOptions*)ops->yAxis->ops(); + if (axisxops->logScale) + regPtr->left = FindElemValuesMinimum(ops->coords.x, DBL_MIN) + middle; + + // Fix y-min limits for barchart + if (axisyops->logScale) { + if ((regPtr->top <= 0.0) || (regPtr->top > 1.0)) + regPtr->top = 1.0; + } + else { + if (regPtr->top > 0.0) + regPtr->top = 0.0; + } + + // Correct the extents for error bars if they exist + if (ops->xError && (ops->xError->nValues() > 0)) { + nPoints = MIN(ops->xError->nValues(), nPoints); + for (int ii=0; iicoords.x->values_[ii] + ops->xError->values_[ii]; + if (x > regPtr->right) + regPtr->right = x; + + x = ops->coords.x->values_[ii] - ops->xError->values_[ii]; + if (axisxops->logScale) { + // Mirror negative values, instead of ignoring them + if (x < 0.0) + x = -x; + + if ((x > DBL_MIN) && (x < regPtr->left)) + regPtr->left = x; + + } + else if (x < regPtr->left) + regPtr->left = x; + } + } + else { + if ((ops->xHigh) && + (ops->xHigh->nValues() > 0) && + (ops->xHigh->max() > regPtr->right)) + regPtr->right = ops->xHigh->max(); + + if (ops->xLow && (ops->xLow->nValues() > 0)) { + double left; + if ((ops->xLow->min() <= 0.0) && (axisxops->logScale)) + left = FindElemValuesMinimum(ops->xLow, DBL_MIN); + else + left = ops->xLow->min(); + + if (left < regPtr->left) + regPtr->left = left; + } + } + + if (ops->yError && (ops->yError->nValues() > 0)) { + nPoints = MIN(ops->yError->nValues(), nPoints); + + for (int ii=0; iicoords.y->values_[ii] + ops->yError->values_[ii]; + if (y > regPtr->bottom) + regPtr->bottom = y; + + y = ops->coords.y->values_[ii] - ops->yError->values_[ii]; + if (axisyops->logScale) { + // Mirror negative values, instead of ignoring them + if (y < 0.0) + y = -y; + + if ((y > DBL_MIN) && (y < regPtr->left)) + regPtr->top = y; + + } + else if (y < regPtr->top) + regPtr->top = y; + } + } + else { + if ((ops->yHigh) && + (ops->yHigh->nValues() > 0) && + (ops->yHigh->max() > regPtr->bottom)) + regPtr->bottom = ops->yHigh->max(); + + if (ops->yLow && ops->yLow->nValues() > 0) { + double top; + if ((ops->yLow->min() <= 0.0) && + (axisyops->logScale)) + top = FindElemValuesMinimum(ops->yLow, DBL_MIN); + else + top = ops->yLow->min(); + + if (top < regPtr->top) + regPtr->top = top; + } + } +} + +void BarElement::closest() +{ + BarElementOptions* ops = (BarElementOptions*)ops_; + BarGraphOptions* gops = (BarGraphOptions*)graphPtr_->ops_; + + ClosestSearch* searchPtr = &gops->search; + double minDist = searchPtr->dist; + int imin = 0; + + int ii; + Rectangle* bp; + for (bp=bars_, ii=0; iix, searchPtr->y)) { + imin = barToData_[ii]; + minDist = 0.0; + break; + } + double left = bp->x; + double top = bp->y; + double right = (double)(bp->x + bp->width); + double bottom = (double)(bp->y + bp->height); + + Point2d outline[5]; + outline[4].x = outline[3].x = outline[0].x = left; + outline[4].y = outline[1].y = outline[0].y = top; + outline[2].x = outline[1].x = right; + outline[3].y = outline[2].y = bottom; + + Point2d *pp, *pend; + for (pp=outline, pend=outline+4; ppx, searchPtr->y, pp, pp + 1); + if (t.x > right) + t.x = right; + else if (t.x < left) + t.x = left; + + if (t.y > bottom) + t.y = bottom; + else if (t.y < top) + t.y = top; + + double dist = hypot((t.x - searchPtr->x), (t.y - searchPtr->y)); + if (dist < minDist) { + minDist = dist; + imin = barToData_[ii]; + } + } + } + if (minDist < searchPtr->dist) { + searchPtr->elemPtr = (Element*)this; + searchPtr->dist = minDist; + searchPtr->index = imin; + searchPtr->point.x = + ops->coords.x ? (double)ops->coords.x->values_[imin] : 0; + searchPtr->point.y = + ops->coords.y ? (double)ops->coords.y->values_[imin] : 0; + } +} + +void BarElement::draw(Drawable drawable) +{ + BarElementOptions* ops = (BarElementOptions*)ops_; + + if (ops->hide) + return; + + int count = 0; + for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link; + link = Chain_NextLink(link)) { + + BarStyle* stylePtr = (BarStyle*)Chain_GetValue(link); + BarPen* penPtr = (BarPen*)stylePtr->penPtr; + BarPenOptions* pops = (BarPenOptions*)penPtr->ops(); + + if (stylePtr->nBars > 0) + drawSegments(drawable, penPtr, stylePtr->bars, stylePtr->nBars); + + if ((stylePtr->xeb.length > 0) && (pops->errorBarShow & SHOW_X)) + graphPtr_->drawSegments(drawable, penPtr->errorBarGC_, + stylePtr->xeb.segments, stylePtr->xeb.length); + + if ((stylePtr->yeb.length > 0) && (pops->errorBarShow & SHOW_Y)) + graphPtr_->drawSegments(drawable, penPtr->errorBarGC_, + stylePtr->yeb.segments, stylePtr->yeb.length); + + if (pops->valueShow != SHOW_NONE) + drawValues(drawable, penPtr, stylePtr->bars, stylePtr->nBars, + barToData_ + count); + + count += stylePtr->nBars; + } +} + +void BarElement::drawActive(Drawable drawable) +{ + BarElementOptions* ops = (BarElementOptions*)ops_; + + if (ops->hide || !active_) + return; + + BarPen* penPtr = (BarPen*)ops->activePenPtr; + if (!penPtr) + return; + BarPenOptions* pops = (BarPenOptions*)penPtr->ops(); + + if (nActiveIndices_ > 0) { + mapActive(); + + drawSegments(drawable, penPtr, activeRects_, nActive_); + if (pops->valueShow != SHOW_NONE) + drawValues(drawable, penPtr, activeRects_, nActive_, activeToData_); + } + else if (nActiveIndices_ < 0) { + drawSegments(drawable, penPtr, bars_, nBars_); + if (pops->valueShow != SHOW_NONE) + drawValues(drawable, penPtr, bars_, nBars_, barToData_); + } +} + +void BarElement::drawSymbol(Drawable drawable, int x, int y, int size) +{ + BarElementOptions* ops = (BarElementOptions*)ops_; + + BarPen* penPtr = NORMALPEN(ops); + BarPenOptions* pops = (BarPenOptions*)penPtr->ops(); + + int radius = (size / 2); + size--; + + x -= radius; + y -= radius; + + Tk_Fill3DRectangle(graphPtr_->tkwin_, drawable, + pops->fill, x, y, size, size, + pops->borderWidth, pops->relief); + + if (pops->outlineColor) + XDrawRectangle(graphPtr_->display_, drawable, penPtr->outlineGC_, + x, y, size, size); +} + +void BarElement::print(PSOutput* psPtr) +{ + BarElementOptions* ops = (BarElementOptions*)ops_; + + if (ops->hide) + return; + + psPtr->format("\n%% Element \"%s\"\n\n", name_); + + int count = 0; + for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link; + link = Chain_NextLink(link)) { + + BarStyle *stylePtr = (BarStyle*)Chain_GetValue(link); + BarPen* penPtr = (BarPen*)stylePtr->penPtr; + BarPenOptions* pops = (BarPenOptions*)penPtr->ops(); + + if (stylePtr->nBars > 0) + printSegments(psPtr, penPtr, stylePtr->bars, stylePtr->nBars); + + XColor* colorPtr = pops->errorBarColor; + if (!colorPtr) + colorPtr = pops->outlineColor; + if (!colorPtr) + colorPtr = Tk_3DBorderColor(pops->fill); + + if ((stylePtr->xeb.length > 0) && (pops->errorBarShow & SHOW_X)) { + psPtr->setLineAttributes(colorPtr, pops->errorBarLineWidth, + NULL, CapButt, JoinMiter); + psPtr->printSegments(stylePtr->xeb.segments, stylePtr->xeb.length); + } + + if ((stylePtr->yeb.length > 0) && (pops->errorBarShow & SHOW_Y)) { + psPtr->setLineAttributes(colorPtr, pops->errorBarLineWidth, + NULL, CapButt, JoinMiter); + psPtr->printSegments(stylePtr->yeb.segments, stylePtr->yeb.length); + } + + if (pops->valueShow != SHOW_NONE) + printValues(psPtr, penPtr, stylePtr->bars, stylePtr->nBars, + barToData_ + count); + + count += stylePtr->nBars; + } +} + +void BarElement::printActive(PSOutput* psPtr) +{ + BarElementOptions* ops = (BarElementOptions*)ops_; + + if (ops->hide || !active_) + return; + + BarPen* penPtr = (BarPen*)ops->activePenPtr; + if (!penPtr) + return; + BarPenOptions* pops = (BarPenOptions*)penPtr->ops(); + + psPtr->format("\n%% Active Element \"%s\"\n\n", name_); + + if (nActiveIndices_ > 0) { + mapActive(); + + printSegments(psPtr, penPtr, activeRects_, nActive_); + if (pops->valueShow != SHOW_NONE) + printValues(psPtr, penPtr, activeRects_, nActive_,activeToData_); + } + else if (nActiveIndices_ < 0) { + printSegments(psPtr, penPtr, bars_, nBars_); + if (pops->valueShow != SHOW_NONE) + printValues(psPtr, penPtr, bars_, nBars_, barToData_); + } +} + +void BarElement::printSymbol(PSOutput* psPtr, double x, double y, int size) +{ + BarElementOptions* ops = (BarElementOptions*)ops_; + + BarPen* penPtr = NORMALPEN(ops); + BarPenOptions* pops = (BarPenOptions*)penPtr->ops(); + + x -= size/2.; + y -= size/2.; + + psPtr->fill3DRectangle(pops->fill, x, y, size, size, + pops->borderWidth, pops->relief); + + if (pops->outlineColor) { + psPtr->setForeground(pops->outlineColor); + psPtr->printRectangle(x, y, size, size); + } +} + +// Support + +void BarElement::ResetStylePalette(Chain* stylePalette) +{ + for (ChainLink* link = Chain_FirstLink(stylePalette); link; + link = Chain_NextLink(link)) { + BarStyle *stylePtr = (BarStyle*)Chain_GetValue(link); + stylePtr->xeb.length = 0; + stylePtr->yeb.length = 0; + stylePtr->nBars = 0; + } +} + +void BarElement::checkStacks(Axis* xAxis, Axis* yAxis, + double* minPtr, double* maxPtr) +{ + BarGraph* barGraphPtr_ = (BarGraph*)graphPtr_; + BarGraphOptions* gops = (BarGraphOptions*)graphPtr_->ops_; + if (((BarGraph::BarMode)gops->barMode != BarGraph::STACKED) || + barGraphPtr_->nBarGroups_ == 0) + return; + + for (BarGroup *gp = barGraphPtr_->barGroups_, + *gend = gp + barGraphPtr_->nBarGroups_; gp < gend; gp++) { + if ((gp->xAxis == xAxis) && (gp->yAxis == yAxis)) { + + // Check if any of the y-values (because of stacking) are greater + // than the current limits of the graph. + if (gp->sum < 0.0) { + if (*minPtr > gp->sum) + *minPtr = gp->sum; + } + else { + if (*maxPtr < gp->sum) + *maxPtr = gp->sum; + } + } + } +} + +void BarElement::mergePens(BarStyle** dataToStyle) +{ + BarElementOptions* ops = (BarElementOptions*)ops_; + + if (Chain_GetLength(ops->stylePalette) < 2) { + ChainLink* link = Chain_FirstLink(ops->stylePalette); + BarStyle *stylePtr = (BarStyle*)Chain_GetValue(link); + stylePtr->nBars = nBars_; + stylePtr->bars = bars_; + stylePtr->symbolSize = bars_->width / 2; + stylePtr->xeb.length = xeb_.length; + stylePtr->xeb.segments = xeb_.segments; + stylePtr->yeb.length = yeb_.length; + stylePtr->yeb.segments = yeb_.segments; + return; + } + + // We have more than one style. Group bar segments of like pen styles together + if (nBars_ > 0) { + Rectangle* bars = new Rectangle[nBars_]; + int* barToData = new int[nBars_]; + Rectangle* bp = bars; + int* ip = barToData; + for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link; + link = Chain_NextLink(link)) { + BarStyle *stylePtr = (BarStyle*)Chain_GetValue(link); + stylePtr->symbolSize = bp->width / 2; + stylePtr->bars = bp; + for (int ii=0; iinBars = bp - stylePtr->bars; + } + delete [] bars_; + bars_ = bars; + delete [] barToData_; + barToData_ = barToData; + } + + if (xeb_.length > 0) { + Segment2d* bars = new Segment2d[xeb_.length]; + Segment2d *sp = bars; + int* map = new int[xeb_.length]; + int* ip = map; + for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link; + link = Chain_NextLink(link)) { + BarStyle *stylePtr = (BarStyle*)Chain_GetValue(link); + stylePtr->xeb.segments = sp; + for (int ii=0; iixeb.length = sp - stylePtr->xeb.segments; + } + delete [] xeb_.segments; + xeb_.segments = bars; + delete [] xeb_.map; + xeb_.map = map; + } + + if (yeb_.length > 0) { + Segment2d* bars = new Segment2d[yeb_.length]; + Segment2d* sp = bars; + int* map = new int[yeb_.length]; + int* ip = map; + for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link; + link = Chain_NextLink(link)) { + BarStyle *stylePtr = (BarStyle*)Chain_GetValue(link); + stylePtr->yeb.segments = sp; + for (int ii=0; iiyeb.length = sp - stylePtr->yeb.segments; + } + delete [] yeb_.segments; + yeb_.segments = bars; + delete [] yeb_.map; + yeb_.map = map; + } +} + +void BarElement::mapActive() +{ + delete [] activeRects_; + activeRects_ = NULL; + + delete [] activeToData_; + activeToData_ = NULL; + + nActive_ = 0; + + if (nActiveIndices_ > 0) { + Rectangle* activeRects = new Rectangle[nActiveIndices_]; + int* activeToData = new int[nActiveIndices_]; + int count = 0; + for (int ii=0; iistylePalette); + + delete [] activeRects_; + activeRects_ = NULL; + delete [] activeToData_; + activeToData_ = NULL; + + delete [] xeb_.segments; + xeb_.segments = NULL; + delete [] xeb_.map; + xeb_.map = NULL; + xeb_.length = 0; + + delete [] yeb_.segments; + yeb_.segments = NULL; + delete [] yeb_.map; + yeb_.map = NULL; + yeb_.length = 0; + + delete [] bars_; + bars_ = NULL; + delete [] barToData_; + barToData_ = NULL; + + nActive_ = 0; + nBars_ = 0; +} + +void BarElement::mapErrorBars(BarStyle **dataToStyle) +{ + BarElementOptions* ops = (BarElementOptions*)ops_; + + Region2d reg; + graphPtr_->extents(®); + + int nPoints = NUMBEROFPOINTS(ops); + int nn =0; + if (ops->coords.x && ops->coords.y) { + if (ops->xError && (ops->xError->nValues() > 0)) + nn = MIN(ops->xError->nValues(), nPoints); + else + if (ops->xHigh && ops->xLow) + nn = MIN3(ops->xHigh->nValues(), ops->xLow->nValues(), nPoints); + } + + if (nn) { + Segment2d* bars = new Segment2d[nn * 3]; + Segment2d* segPtr = bars; + int* map = new int[nn * 3]; + int* indexPtr = map; + + for (int ii=0; iicoords.x->values_[ii]; + double y = ops->coords.y->values_[ii]; + BarStyle* stylePtr = dataToStyle[ii]; + + if ((isfinite(x)) && (isfinite(y))) { + double high, low; + if (ops->xError->nValues() > 0) { + high = x + ops->xError->values_[ii]; + low = x - ops->xError->values_[ii]; + } + else { + high = ops->xHigh ? ops->xHigh->values_[ii] : 0; + low = ops->xLow ? ops->xLow->values_[ii] : 0; + } + if ((isfinite(high)) && (isfinite(low))) { + Point2d p = graphPtr_->map2D(high, y, ops->xAxis, ops->yAxis); + Point2d q = graphPtr_->map2D(low, y, ops->xAxis, ops->yAxis); + segPtr->p = p; + segPtr->q = q; + if (lineRectClip(®, &segPtr->p, &segPtr->q)) { + segPtr++; + *indexPtr++ = ii; + } + // Left cap + segPtr->p.x = p.x; + segPtr->q.x = p.x; + segPtr->p.y = p.y - stylePtr->errorBarCapWidth; + segPtr->q.y = p.y + stylePtr->errorBarCapWidth; + if (lineRectClip(®, &segPtr->p, &segPtr->q)) { + segPtr++; + *indexPtr++ = ii; + } + // Right cap + segPtr->p.x = q.x; + segPtr->q.x = q.x; + segPtr->p.y = q.y - stylePtr->errorBarCapWidth; + segPtr->q.y = q.y + stylePtr->errorBarCapWidth; + if (lineRectClip(®, &segPtr->p, &segPtr->q)) { + segPtr++; + *indexPtr++ = ii; + } + } + } + } + xeb_.segments = bars; + xeb_.length = segPtr - bars; + xeb_.map = map; + } + + nn =0; + if (ops->coords.x && ops->coords.y) { + if (ops->yError && (ops->yError->nValues() > 0)) + nn = MIN(ops->yError->nValues(), nPoints); + else + if (ops->yHigh && ops->yLow) + nn = MIN3(ops->yHigh->nValues(), ops->yLow->nValues(), nPoints); + } + + if (nn) { + Segment2d* bars = new Segment2d[nn * 3]; + Segment2d* segPtr = bars; + int* map = new int[nn * 3]; + int* indexPtr = map; + + for (int ii=0; iicoords.x->values_[ii]; + double y = ops->coords.y->values_[ii]; + BarStyle *stylePtr = dataToStyle[ii]; + + if ((isfinite(x)) && (isfinite(y))) { + double high, low; + if (ops->yError->nValues() > 0) { + high = y + ops->yError->values_[ii]; + low = y - ops->yError->values_[ii]; + } + else { + high = ops->yHigh->values_[ii]; + low = ops->yLow->values_[ii]; + } + if ((isfinite(high)) && (isfinite(low))) { + Point2d p = graphPtr_->map2D(x, high, ops->xAxis, ops->yAxis); + Point2d q = graphPtr_->map2D(x, low, ops->xAxis, ops->yAxis); + segPtr->p = p; + segPtr->q = q; + if (lineRectClip(®, &segPtr->p, &segPtr->q)) { + segPtr++; + *indexPtr++ = ii; + } + // Top cap + segPtr->p.y = p.y; + segPtr->q.y = p.y; + segPtr->p.x = p.x - stylePtr->errorBarCapWidth; + segPtr->q.x = p.x + stylePtr->errorBarCapWidth; + if (lineRectClip(®, &segPtr->p, &segPtr->q)) { + segPtr++; + *indexPtr++ = ii; + } + // Bottom cap + segPtr->p.y = q.y; + segPtr->q.y = q.y; + segPtr->p.x = q.x - stylePtr->errorBarCapWidth; + segPtr->q.x = q.x + stylePtr->errorBarCapWidth; + if (lineRectClip(®, &segPtr->p, &segPtr->q)) { + segPtr++; + *indexPtr++ = ii; + } + } + } + } + yeb_.segments = bars; + yeb_.length = segPtr - bars; + yeb_.map = map; + } +} + +void BarElement::drawSegments(Drawable drawable, BarPen* penPtr, + Rectangle *bars, int nBars) +{ + BarPenOptions* pops = (BarPenOptions*)penPtr->ops(); + for (Rectangle *rp = bars, *rend = rp + nBars; rp < rend; rp++) { + if ((rp->width < 1) || (rp->height < 1)) + continue; + + Tk_Fill3DRectangle(graphPtr_->tkwin_, drawable, + pops->fill, rp->x, rp->y, rp->width, rp->height, + pops->borderWidth, pops->relief); + + if (pops->outlineColor) + XDrawRectangle(graphPtr_->display_, drawable, penPtr->outlineGC_, + rp->x, rp->y, rp->width, rp->height); + } +} + +void BarElement::drawValues(Drawable drawable, BarPen* penPtr, + Rectangle *bars, int nBars, int *barToData) +{ + BarElementOptions* ops = (BarElementOptions*)ops_; + BarPenOptions* pops = (BarPenOptions*)penPtr->ops(); + BarGraphOptions* gops = (BarGraphOptions*)graphPtr_->ops_; + + const char *fmt = pops->valueFormat; + if (!fmt) + fmt = "%g"; + TextStyle ts(graphPtr_, &pops->valueStyle); + + int count = 0; + for (Rectangle *rp = bars, *rend = rp + nBars; rp < rend; rp++) { + Point2d anchorPos; + char string[TCL_DOUBLE_SPACE * 2 + 2]; + + double x = ops->coords.x->values_[barToData[count]]; + double y = ops->coords.y->values_[barToData[count]]; + + count++; + if (pops->valueShow == SHOW_X) + snprintf(string, TCL_DOUBLE_SPACE, fmt, x); + else if (pops->valueShow == SHOW_Y) + snprintf(string, TCL_DOUBLE_SPACE, fmt, y); + else if (pops->valueShow == SHOW_BOTH) { + snprintf(string, TCL_DOUBLE_SPACE, fmt, x); + strcat(string, ","); + snprintf(string + strlen(string), TCL_DOUBLE_SPACE, fmt, y); + } + + if (gops->inverted) { + anchorPos.y = rp->y + rp->height * 0.5; + anchorPos.x = rp->x + rp->width; + if (x < gops->baseline) + anchorPos.x -= rp->width; + } + else { + anchorPos.x = rp->x + rp->width * 0.5; + anchorPos.y = rp->y; + if (y < gops->baseline) + anchorPos.y += rp->height; + } + + ts.drawText(drawable, string, anchorPos.x, anchorPos.y); + } +} + +void BarElement::printSegments(PSOutput* psPtr, BarPen* penPtr, + Rectangle *bars, int nBars) +{ + BarPenOptions* pops = (BarPenOptions*)penPtr->ops(); + for (Rectangle *rp = bars, *rend = rp + nBars; rp < rend; rp++) { + if ((rp->width < 1) || (rp->height < 1)) + continue; + + psPtr->fill3DRectangle(pops->fill, (double)rp->x, (double)rp->y, + (int)rp->width, (int)rp->height, + pops->borderWidth, pops->relief); + + if (pops->outlineColor) { + psPtr->setForeground(pops->outlineColor); + psPtr->printRectangle((double)rp->x, (double)rp->y, + (int)rp->width, (int)rp->height); + } + } +} + +void BarElement::printValues(PSOutput* psPtr, BarPen* penPtr, + Rectangle *bars, int nBars, int *barToData) +{ + BarPenOptions* pops = (BarPenOptions*)penPtr->ops(); + BarElementOptions* ops = (BarElementOptions*)ops_; + BarGraphOptions* gops = (BarGraphOptions*)graphPtr_->ops_; + + int count = 0; + const char* fmt = pops->valueFormat; + if (!fmt) + fmt = "%g"; + TextStyle ts(graphPtr_, &pops->valueStyle); + + for (Rectangle *rp = bars, *rend = rp + nBars; rp < rend; rp++) { + double x = ops->coords.x->values_[barToData[count]]; + double y = ops->coords.y->values_[barToData[count]]; + + count++; + char string[TCL_DOUBLE_SPACE * 2 + 2]; + if (pops->valueShow == SHOW_X) + snprintf(string, TCL_DOUBLE_SPACE, fmt, x); + else if (pops->valueShow == SHOW_Y) + snprintf(string, TCL_DOUBLE_SPACE, fmt, y); + else if (pops->valueShow == SHOW_BOTH) { + snprintf(string, TCL_DOUBLE_SPACE, fmt, x); + strcat(string, ","); + snprintf(string + strlen(string), TCL_DOUBLE_SPACE, fmt, y); + } + + Point2d anchorPos; + if (gops->inverted) { + anchorPos.y = rp->y + rp->height * 0.5; + anchorPos.x = rp->x + rp->width; + if (x < gops->baseline) + anchorPos.x -= rp->width; + } + else { + anchorPos.x = rp->x + rp->width * 0.5; + anchorPos.y = rp->y; + if (y < gops->baseline) + anchorPos.y += rp->height; + } + + ts.printText(psPtr, string, anchorPos.x, anchorPos.y); + } +} + diff --git a/generic/tkbltGrElemBar.h b/generic/tkbltGrElemBar.h new file mode 100644 index 0000000..8b48114 --- /dev/null +++ b/generic/tkbltGrElemBar.h @@ -0,0 +1,132 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGrElemBar_h__ +#define __BltGrElemBar_h__ + +#include + +#include + +#include "tkbltGrElem.h" +#include "tkbltGrPenBar.h" + +namespace Blt { + + typedef struct { + float x1; + float y1; + float x2; + float y2; + } BarRegion; + + typedef struct { + Weight weight; + BarPen* penPtr; + Rectangle* bars; + int nBars; + GraphSegments xeb; + GraphSegments yeb; + int symbolSize; + int errorBarCapWidth; + } BarStyle; + + typedef struct { + Element* elemPtr; + const char *label; + char** tags; + Axis* xAxis; + Axis* yAxis; + ElemCoords coords; + ElemValues* w; + ElemValues* xError; + ElemValues* yError; + ElemValues* xHigh; + ElemValues* xLow; + ElemValues* yHigh; + ElemValues* yLow; + int hide; + int legendRelief; + Chain* stylePalette; + BarPen* builtinPenPtr; + BarPen* activePenPtr; + BarPen* normalPenPtr; + BarPenOptions builtinPen; + + // derived + double barWidth; + const char *groupName; + } BarElementOptions; + + class BarElement : public Element { + protected: + BarPen* builtinPenPtr; + int* barToData_; + Rectangle* bars_; + int* activeToData_; + Rectangle* activeRects_; + int nBars_; + int nActive_; + GraphSegments xeb_; + GraphSegments yeb_; + + protected: + void ResetStylePalette(Chain*); + void checkStacks(Axis*, Axis*, double*, double*); + void mergePens(BarStyle**); + void mapActive(); + void reset(); + void mapErrorBars(BarStyle**); + void drawSegments(Drawable, BarPen*, Rectangle*, int); + void drawValues(Drawable, BarPen*, Rectangle*, int, int*); + void printSegments(PSOutput*, BarPen*, Rectangle*, int); + void printValues(PSOutput*, BarPen*, Rectangle*, int, int*); + + public: + BarElement(Graph*, const char*, Tcl_HashEntry*); + virtual ~BarElement(); + + ClassId classId() {return CID_ELEM_BAR;} + const char* className() {return "BarElement";} + const char* typeName() {return "bar";} + + int configure(); + void map(); + void extents(Region2d*); + void closest(); + void draw(Drawable); + void drawActive(Drawable); + void drawSymbol(Drawable, int, int, int); + void print(PSOutput*); + void printActive(PSOutput*); + void printSymbol(PSOutput*, double, double, int); + }; +}; + +#endif diff --git a/generic/tkbltGrElemLine.C b/generic/tkbltGrElemLine.C new file mode 100644 index 0000000..f8ec8f7 --- /dev/null +++ b/generic/tkbltGrElemLine.C @@ -0,0 +1,2405 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright (c) 1993 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include + +#include "tkbltGraph.h" +#include "tkbltGrElemLine.h" +#include "tkbltGrElemOption.h" +#include "tkbltGrAxis.h" +#include "tkbltGrMisc.h" +#include "tkbltGrDef.h" +#include "tkbltConfig.h" +#include "tkbltGrPSOutput.h" +#include "tkbltInt.h" + +using namespace Blt; + +#define SEARCH_X 0 +#define SEARCH_Y 1 +#define SEARCH_BOTH 2 + +#define SEARCH_POINTS 0 // closest data point. +#define SEARCH_TRACES 1 // closest point on trace. +#define SEARCH_AUTO 2 // traces if linewidth is > 0 and more than one + +#define MIN3(a,b,c) (((a)<(b))?(((a)<(c))?(a):(c)):(((b)<(c))?(b):(c))) +#define PointInRegion(e,x,y) (((x) <= (e)->right) && ((x) >= (e)->left) && ((y) <= (e)->bottom) && ((y) >= (e)->top)) + +#define BROKEN_TRACE(dir,last,next) (((dir == INCREASING)&&(next < last)) || ((dir == DECREASING)&&(next > last))) +#define DRAW_SYMBOL() (symbolInterval_==0||(symbolCounter_%symbolInterval_)==0) + +static const char* symbolMacros[] = + {"Li", "Sq", "Ci", "Di", "Pl", "Cr", "Sp", "Sc", "Tr", "Ar", "Bm", NULL}; + +// OptionSpecs + +static const char* smoothObjOption[] = + {"linear", "step", "cubic", "quadratic", "catrom", NULL}; + +static const char* penDirObjOption[] = + {"increasing", "decreasing", "both", NULL}; + +static Tk_ObjCustomOption styleObjOption = + { + "styles", StyleSetProc, StyleGetProc, StyleRestoreProc, StyleFreeProc, + (ClientData)sizeof(LineStyle) + }; + +extern Tk_ObjCustomOption penObjOption; +extern Tk_ObjCustomOption pairsObjOption; +extern Tk_ObjCustomOption valuesObjOption; +extern Tk_ObjCustomOption xAxisObjOption; +extern Tk_ObjCustomOption yAxisObjOption; + +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_CUSTOM, "-activepen", "activePen", "ActivePen", + "active", -1, Tk_Offset(LineElementOptions, activePenPtr), + TK_OPTION_NULL_OK, &penObjOption, LAYOUT}, + {TK_OPTION_BORDER, "-areabackground", "areaBackground", "AreaBackground", + NULL, -1, Tk_Offset(LineElementOptions, fillBg), + TK_OPTION_NULL_OK, NULL, LAYOUT}, + {TK_OPTION_CUSTOM, "-bindtags", "bindTags", "BindTags", + "all", -1, Tk_Offset(LineElementOptions, tags), + TK_OPTION_NULL_OK, &listObjOption, 0}, + {TK_OPTION_COLOR, "-color", "color", "Color", + STD_NORMAL_FOREGROUND, -1, + Tk_Offset(LineElementOptions, builtinPen.traceColor), 0, NULL, CACHE}, + {TK_OPTION_CUSTOM, "-dashes", "dashes", "Dashes", + NULL, -1, Tk_Offset(LineElementOptions, builtinPen.traceDashes), + TK_OPTION_NULL_OK, &dashesObjOption, CACHE}, + {TK_OPTION_CUSTOM, "-data", "data", "Data", + NULL, -1, Tk_Offset(LineElementOptions, coords), + TK_OPTION_NULL_OK, &pairsObjOption, RESET}, + {TK_OPTION_COLOR, "-errorbarcolor", "errorBarColor", "ErrorBarColor", + NULL, -1, Tk_Offset(LineElementOptions, builtinPen.errorBarColor), + TK_OPTION_NULL_OK, NULL, CACHE}, + {TK_OPTION_PIXELS,"-errorbarwidth", "errorBarWidth", "ErrorBarWidth", + "1", -1, Tk_Offset(LineElementOptions, builtinPen.errorBarLineWidth), + 0, NULL, CACHE}, + {TK_OPTION_PIXELS, "-errorbarcap", "errorBarCap", "ErrorBarCap", + "0", -1, Tk_Offset(LineElementOptions, builtinPen.errorBarCapWidth), + 0, NULL, LAYOUT}, + {TK_OPTION_COLOR, "-fill", "fill", "Fill", + NULL, -1, Tk_Offset(LineElementOptions, builtinPen.symbol.fillColor), + TK_OPTION_NULL_OK, NULL, CACHE}, + {TK_OPTION_BOOLEAN, "-hide", "hide", "Hide", + "no", -1, Tk_Offset(LineElementOptions, hide), 0, NULL, LAYOUT}, + {TK_OPTION_STRING, "-label", "label", "Label", + NULL, -1, Tk_Offset(LineElementOptions, label), + TK_OPTION_NULL_OK | TK_OPTION_DONT_SET_DEFAULT, NULL, LAYOUT}, + {TK_OPTION_RELIEF, "-legendrelief", "legendRelief", "LegendRelief", + "flat", -1, Tk_Offset(LineElementOptions, legendRelief), 0, NULL, LAYOUT}, + {TK_OPTION_PIXELS, "-linewidth", "lineWidth", "LineWidth", + "1", -1, Tk_Offset(LineElementOptions, builtinPen.traceWidth), + 0, NULL, CACHE}, + {TK_OPTION_CUSTOM, "-mapx", "mapX", "MapX", + "x", -1, Tk_Offset(LineElementOptions, xAxis), 0, &xAxisObjOption, RESET}, + {TK_OPTION_CUSTOM, "-mapy", "mapY", "MapY", + "y", -1, Tk_Offset(LineElementOptions, yAxis), 0, &yAxisObjOption, RESET}, + {TK_OPTION_INT, "-maxsymbols", "maxSymbols", "MaxSymbols", + "0", -1, Tk_Offset(LineElementOptions, reqMaxSymbols), 0, NULL, CACHE}, + {TK_OPTION_COLOR, "-offdash", "offDash", "OffDash", + NULL, -1, Tk_Offset(LineElementOptions, builtinPen.traceOffColor), + TK_OPTION_NULL_OK, NULL, CACHE}, + {TK_OPTION_COLOR, "-outline", "outline", "Outline", + NULL, -1, Tk_Offset(LineElementOptions, builtinPen.symbol.outlineColor), + TK_OPTION_NULL_OK, NULL, CACHE}, + {TK_OPTION_PIXELS, "-outlinewidth", "outlineWidth", "OutlineWidth", + "1", -1, Tk_Offset(LineElementOptions, builtinPen.symbol.outlineWidth), + 0, NULL, CACHE}, + {TK_OPTION_CUSTOM, "-pen", "pen", "Pen", + NULL, -1, Tk_Offset(LineElementOptions, normalPenPtr), + TK_OPTION_NULL_OK, &penObjOption, LAYOUT}, + {TK_OPTION_PIXELS, "-pixels", "pixels", "Pixels", + "0.1i", -1, Tk_Offset(LineElementOptions, builtinPen.symbol.size), + 0, NULL, LAYOUT}, + {TK_OPTION_DOUBLE, "-reduce", "reduce", "Reduce", + "0", -1, Tk_Offset(LineElementOptions, rTolerance), 0, NULL, RESET}, + {TK_OPTION_BOOLEAN, "-scalesymbols", "scaleSymbols", "ScaleSymbols", + "yes", -1, Tk_Offset(LineElementOptions, scaleSymbols), 0, NULL, LAYOUT}, + {TK_OPTION_STRING_TABLE, "-showerrorbars", "showErrorBars", "ShowErrorBars", + "both", -1, Tk_Offset(LineElementOptions, builtinPen.errorBarShow), + 0, &fillObjOption, LAYOUT}, + {TK_OPTION_STRING_TABLE, "-showvalues", "showValues", "ShowValues", + "none", -1, Tk_Offset(LineElementOptions, builtinPen.valueShow), + 0, &fillObjOption, CACHE}, + {TK_OPTION_STRING_TABLE, "-smooth", "smooth", "Smooth", + "linear", -1, Tk_Offset(LineElementOptions, reqSmooth), + 0, &smoothObjOption, LAYOUT}, + {TK_OPTION_CUSTOM, "-styles", "styles", "Styles", + "", -1, Tk_Offset(LineElementOptions, stylePalette), + 0, &styleObjOption, RESET}, + {TK_OPTION_STRING_TABLE, "-symbol", "symbol", "Symbol", + "none", -1, Tk_Offset(LineElementOptions, builtinPen.symbol), + 0, &symbolObjOption, CACHE}, + {TK_OPTION_STRING_TABLE, "-trace", "trace", "Trace", + "both", -1, Tk_Offset(LineElementOptions, penDir), + 0, &penDirObjOption, RESET}, + {TK_OPTION_ANCHOR, "-valueanchor", "valueAnchor", "ValueAnchor", + "s", -1, Tk_Offset(LineElementOptions, builtinPen.valueStyle.anchor), + 0, NULL, CACHE}, + {TK_OPTION_COLOR, "-valuecolor", "valueColor", "ValueColor", + STD_NORMAL_FOREGROUND,-1, + Tk_Offset(LineElementOptions, builtinPen.valueStyle.color), + 0, NULL, CACHE}, + {TK_OPTION_FONT, "-valuefont", "valueFont", "ValueFont", + STD_FONT_SMALL, -1, + Tk_Offset(LineElementOptions, builtinPen.valueStyle.font), + 0, NULL, CACHE}, + {TK_OPTION_STRING, "-valueformat", "valueFormat", "ValueFormat", + "%g", -1, Tk_Offset(LineElementOptions, builtinPen.valueFormat), + TK_OPTION_NULL_OK, NULL, CACHE}, + {TK_OPTION_DOUBLE, "-valuerotate", "valueRotate", "ValueRotate", + "0", -1, Tk_Offset(LineElementOptions, builtinPen.valueStyle.angle), + 0, NULL, CACHE}, + {TK_OPTION_CUSTOM, "-weights", "weights", "Weights", + NULL, -1, Tk_Offset(LineElementOptions, w), + TK_OPTION_NULL_OK, &valuesObjOption, RESET}, + {TK_OPTION_SYNONYM, "-x", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-xdata", 0}, + {TK_OPTION_CUSTOM, "-xdata", "xData", "XData", + NULL, -1, Tk_Offset(LineElementOptions, coords.x), + TK_OPTION_NULL_OK, &valuesObjOption, RESET}, + {TK_OPTION_CUSTOM, "-xerror", "xError", "XError", + NULL, -1, Tk_Offset(LineElementOptions, xError), + TK_OPTION_NULL_OK, &valuesObjOption, RESET}, + {TK_OPTION_CUSTOM, "-xhigh", "xHigh", "XHigh", + NULL, -1, Tk_Offset(LineElementOptions, xHigh), + TK_OPTION_NULL_OK, &valuesObjOption, RESET}, + {TK_OPTION_CUSTOM, "-xlow", "xLow", "XLow", + NULL, -1, Tk_Offset(LineElementOptions, xLow), + TK_OPTION_NULL_OK, &valuesObjOption, RESET}, + {TK_OPTION_SYNONYM, "-y", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-ydata", 0}, + {TK_OPTION_CUSTOM, "-ydata", "yData", "YData", + NULL, -1, Tk_Offset(LineElementOptions, coords.y), + TK_OPTION_NULL_OK, &valuesObjOption, RESET}, + {TK_OPTION_CUSTOM, "-yerror", "yError", "YError", + NULL, -1, Tk_Offset(LineElementOptions, yError), + TK_OPTION_NULL_OK, &valuesObjOption, RESET}, + {TK_OPTION_CUSTOM, "-yhigh", "yHigh", "YHigh", + NULL, -1, Tk_Offset(LineElementOptions, yHigh), + TK_OPTION_NULL_OK, &valuesObjOption, RESET}, + {TK_OPTION_CUSTOM, "-ylow", "yLow", "YLow", + NULL, -1, Tk_Offset(LineElementOptions, yLow), + TK_OPTION_NULL_OK, &valuesObjOption, RESET}, + {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, -1, 0, 0, 0} +}; + +LineElement::LineElement(Graph* graphPtr, const char* name, Tcl_HashEntry* hPtr) + : Element(graphPtr, name, hPtr) +{ + smooth_ = LINEAR; + fillPts_ =NULL; + nFillPts_ = 0; + + symbolPts_.points =NULL; + symbolPts_.length =0; + symbolPts_.map =NULL; + activePts_.points =NULL; + activePts_.length =0; + activePts_.map =NULL; + + xeb_.segments =NULL; + xeb_.map =NULL; + xeb_.length =0; + yeb_.segments =NULL; + yeb_.map =NULL; + yeb_.length =0; + + symbolInterval_ =0; + symbolCounter_ =0; + traces_ =NULL; + + ops_ = (LineElementOptions*)calloc(1, sizeof(LineElementOptions)); + LineElementOptions* ops = (LineElementOptions*)ops_; + ops->elemPtr = (Element*)this; + + builtinPenPtr = new LinePen(graphPtr, "builtin", &ops->builtinPen); + ops->builtinPenPtr = builtinPenPtr; + + optionTable_ = Tk_CreateOptionTable(graphPtr->interp_, optionSpecs); + + ops->stylePalette = new Chain(); + // this is an option and will be freed via Tk_FreeConfigOptions + // By default an element's name and label are the same + ops->label = Tcl_Alloc(strlen(name)+1); + if (name) + strcpy((char*)ops->label,(char*)name); + + Tk_InitOptions(graphPtr->interp_, (char*)&(ops->builtinPen), + builtinPenPtr->optionTable(), graphPtr->tkwin_); +} + +LineElement::~LineElement() +{ + LineElementOptions* ops = (LineElementOptions*)ops_; + + delete builtinPenPtr; + + reset(); + + if (ops->stylePalette) { + freeStylePalette(ops->stylePalette); + delete ops->stylePalette; + } + + delete [] fillPts_; +} + +int LineElement::configure() +{ + LineElementOptions* ops = (LineElementOptions*)ops_; + + if (builtinPenPtr->configure() != TCL_OK) + return TCL_ERROR; + + // Point to the static normal/active pens if no external pens have been + // selected. + ChainLink* link = Chain_FirstLink(ops->stylePalette); + if (!link) { + link = new ChainLink(sizeof(LineStyle)); + ops->stylePalette->linkAfter(link, NULL); + } + LineStyle* stylePtr = (LineStyle*)Chain_GetValue(link); + stylePtr->penPtr = NORMALPEN(ops); + + return TCL_OK; +} + +void LineElement::map() +{ + LineElementOptions* ops = (LineElementOptions*)ops_; + + if (!link) + return; + + reset(); + if (!ops->coords.x || !ops->coords.y || + !ops->coords.x->nValues() || !ops->coords.y->nValues()) + return; + + MapInfo mi; + getScreenPoints(&mi); + mapSymbols(&mi); + + if (nActiveIndices_ > 0) + mapActiveSymbols(); + + // Map connecting line segments if they are to be displayed. + smooth_ = (Smoothing)ops->reqSmooth; + if ((mi.nScreenPts > 1) && (ops->builtinPen.traceWidth > 0)) { + // Do smoothing if necessary. This can extend the coordinate array, + // so both mi.points and mi.nPoints may change. + switch (smooth_) { + case STEP: + generateSteps(&mi); + break; + + case CUBIC: + case QUADRATIC: + // Can't interpolate with less than three points + if (mi.nScreenPts < 3) + smooth_ = LINEAR; + else + generateSpline(&mi); + break; + + case CATROM: + // Can't interpolate with less than three points + if (mi.nScreenPts < 3) + smooth_ = LINEAR; + else + generateParametricSpline(&mi); + break; + + default: + break; + } + if (ops->rTolerance > 0.0) + reducePoints(&mi, ops->rTolerance); + + if (ops->fillBg) + mapFillArea(&mi); + + mapTraces(&mi); + } + delete [] mi.screenPts; + delete [] mi.map; + + // Set the symbol size of all the pen styles + for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link; + link = Chain_NextLink(link)) { + LineStyle* stylePtr = (LineStyle*)Chain_GetValue(link); + LinePen* penPtr = (LinePen *)stylePtr->penPtr; + LinePenOptions* penOps = (LinePenOptions*)penPtr->ops(); + int size = scaleSymbol(penOps->symbol.size); + stylePtr->symbolSize = size; + stylePtr->errorBarCapWidth = penOps->errorBarCapWidth; + } + + LineStyle** styleMap = (LineStyle**)StyleMap(); + if (((ops->yHigh && ops->yHigh->nValues() > 0) && + (ops->yLow && ops->yLow->nValues() > 0)) || + ((ops->xHigh && ops->xHigh->nValues() > 0) && + (ops->xLow && ops->xLow->nValues() > 0)) || + (ops->xError && ops->xError->nValues() > 0) || + (ops->yError && ops->yError->nValues() > 0)) { + mapErrorBars(styleMap); + } + + mergePens(styleMap); + delete [] styleMap; +} + +void LineElement::extents(Region2d *extsPtr) +{ + LineElementOptions* ops = (LineElementOptions*)ops_; + + extsPtr->top = extsPtr->left = DBL_MAX; + extsPtr->bottom = extsPtr->right = -DBL_MAX; + + if (!ops->coords.x || !ops->coords.y || + !ops->coords.x->nValues() || !ops->coords.y->nValues()) + return; + int np = NUMBEROFPOINTS(ops); + + extsPtr->right = ops->coords.x->max(); + AxisOptions* axisxops = (AxisOptions*)ops->xAxis->ops(); + if ((ops->coords.x->min() <= 0.0) && (axisxops->logScale)) + extsPtr->left = FindElemValuesMinimum(ops->coords.x, DBL_MIN); + else + extsPtr->left = ops->coords.x->min(); + + extsPtr->bottom = ops->coords.y->max(); + AxisOptions* axisyops = (AxisOptions*)ops->yAxis->ops(); + if ((ops->coords.y->min() <= 0.0) && (axisyops->logScale)) + extsPtr->top = FindElemValuesMinimum(ops->coords.y, DBL_MIN); + else + extsPtr->top = ops->coords.y->min(); + + // Correct the data limits for error bars + if (ops->xError && ops->xError->nValues() > 0) { + np = MIN(ops->xError->nValues(), np); + for (int ii=0; iicoords.x->values_[ii] + ops->xError->values_[ii]; + if (x > extsPtr->right) + extsPtr->right = x; + + x = ops->coords.x->values_[ii] - ops->xError->values_[ii]; + AxisOptions* axisxops = (AxisOptions*)ops->xAxis->ops(); + if (axisxops->logScale) { + // Mirror negative values, instead of ignoring them + if (x < 0.0) + x = -x; + if ((x > DBL_MIN) && (x < extsPtr->left)) + extsPtr->left = x; + } + else if (x < extsPtr->left) + extsPtr->left = x; + } + } + else { + if (ops->xHigh && + (ops->xHigh->nValues() > 0) && + (ops->xHigh->max() > extsPtr->right)) { + extsPtr->right = ops->xHigh->max(); + } + if (ops->xLow && ops->xLow->nValues() > 0) { + double left; + if ((ops->xLow->min() <= 0.0) && (axisxops->logScale)) + left = FindElemValuesMinimum(ops->xLow, DBL_MIN); + else + left = ops->xLow->min(); + + if (left < extsPtr->left) + extsPtr->left = left; + } + } + + if (ops->yError && ops->yError->nValues() > 0) { + np = MIN(ops->yError->nValues(), np); + for (int ii=0; iicoords.y->values_[ii] + ops->yError->values_[ii]; + if (y > extsPtr->bottom) + extsPtr->bottom = y; + + y = ops->coords.y->values_[ii] - ops->yError->values_[ii]; + AxisOptions* axisyops = (AxisOptions*)ops->yAxis->ops(); + if (axisyops->logScale) { + // Mirror negative values, instead of ignoring them + if (y < 0.0) + y = -y; + if ((y > DBL_MIN) && (y < extsPtr->left)) + extsPtr->top = y; + } + else if (y < extsPtr->top) + extsPtr->top = y; + } + } + else { + if (ops->yHigh && (ops->yHigh->nValues() > 0) && + (ops->yHigh->max() > extsPtr->bottom)) + extsPtr->bottom = ops->yHigh->max(); + + if (ops->yLow && ops->yLow->nValues() > 0) { + double top; + if ((ops->yLow->min() <= 0.0) && (axisyops->logScale)) + top = FindElemValuesMinimum(ops->yLow, DBL_MIN); + else + top = ops->yLow->min(); + + if (top < extsPtr->top) + extsPtr->top = top; + } + } +} + +void LineElement::closest() +{ + LineElementOptions* ops = (LineElementOptions*)ops_; + GraphOptions* gops = (GraphOptions*)graphPtr_->ops_; + + ClosestSearch* searchPtr = &gops->search; + int mode = searchPtr->mode; + if (mode == SEARCH_AUTO) { + LinePen* penPtr = NORMALPEN(ops); + LinePenOptions* penOps = (LinePenOptions*)penPtr->ops(); + mode = SEARCH_POINTS; + if ((NUMBEROFPOINTS(ops) > 1) && (penOps->traceWidth > 0)) + mode = SEARCH_TRACES; + } + if (mode == SEARCH_POINTS) + closestPoint(searchPtr); + else { + int found = closestTrace(); + if ((!found) && (searchPtr->along != SEARCH_BOTH)) + closestPoint(searchPtr); + } +} + +void LineElement::draw(Drawable drawable) +{ + LineElementOptions* ops = (LineElementOptions*)ops_; + LinePen* penPtr = NORMALPEN(ops); + LinePenOptions* penOps = (LinePenOptions*)penPtr->ops(); + + if (ops->hide) + return; + + // Fill area under the curve + if (ops->fillBg && fillPts_) { + XPoint*points = new XPoint[nFillPts_]; + + unsigned int count =0; + for (Point2d *pp = fillPts_, *endp = pp + nFillPts_; pp < endp; pp++) { + points[count].x = (short)pp->x; + points[count].y = (short)pp->y; + count++; + } + Tk_Fill3DPolygon(graphPtr_->tkwin_, drawable, ops->fillBg, points, + nFillPts_, 0, TK_RELIEF_FLAT); + delete [] points; + } + + // Error bars + for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link; + link = Chain_NextLink(link)) { + LineStyle* stylePtr = (LineStyle*)Chain_GetValue(link); + LinePen* penPtr = (LinePen *)stylePtr->penPtr; + LinePenOptions* penOps = (LinePenOptions*)penPtr->ops(); + + if ((stylePtr->xeb.length > 0) && (penOps->errorBarShow & SHOW_X)) + graphPtr_->drawSegments(drawable, penPtr->errorBarGC_, + stylePtr->xeb.segments, stylePtr->xeb.length); + + if ((stylePtr->yeb.length > 0) && (penOps->errorBarShow & SHOW_Y)) + graphPtr_->drawSegments(drawable, penPtr->errorBarGC_, + stylePtr->yeb.segments, stylePtr->yeb.length); + } + + // traces + if ((Chain_GetLength(traces_) > 0) && (penOps->traceWidth > 0)) + drawTraces(drawable, penPtr); + + // Symbols, values + if (ops->reqMaxSymbols > 0) { + int total = 0; + for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link; + link = Chain_NextLink(link)) { + LineStyle *stylePtr = (LineStyle*)Chain_GetValue(link); + total += stylePtr->symbolPts.length; + } + symbolInterval_ = total / ops->reqMaxSymbols; + symbolCounter_ = 0; + } + + unsigned int count =0; + for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link; + link = Chain_NextLink(link)) { + LineStyle* stylePtr = (LineStyle*)Chain_GetValue(link); + LinePen* penPtr = (LinePen *)stylePtr->penPtr; + LinePenOptions* penOps = (LinePenOptions*)penPtr->ops(); + + if ((stylePtr->symbolPts.length > 0) && + (penOps->symbol.type != SYMBOL_NONE)) + drawSymbols(drawable, penPtr, stylePtr->symbolSize, + stylePtr->symbolPts.length, stylePtr->symbolPts.points); + + if (penOps->valueShow != SHOW_NONE) + drawValues(drawable, penPtr, stylePtr->symbolPts.length, + stylePtr->symbolPts.points, symbolPts_.map + count); + + count += stylePtr->symbolPts.length; + } + + symbolInterval_ = 0; + symbolCounter_ = 0; +} + +void LineElement::drawActive(Drawable drawable) +{ + LineElementOptions* ops = (LineElementOptions*)ops_; + LinePen* penPtr = (LinePen*)ops->activePenPtr; + if (!penPtr) + return; + LinePenOptions* penOps = (LinePenOptions*)penPtr->ops(); + + if (ops->hide || !active_) + return; + + int symbolSize = scaleSymbol(penOps->symbol.size); + + if (nActiveIndices_ > 0) { + mapActiveSymbols(); + + if (penOps->symbol.type != SYMBOL_NONE) + drawSymbols(drawable, penPtr, symbolSize, activePts_.length, + activePts_.points); + if (penOps->valueShow != SHOW_NONE) + drawValues(drawable, penPtr, activePts_.length, activePts_.points, + activePts_.map); + } + else if (nActiveIndices_ < 0) { + if ((Chain_GetLength(traces_) > 0) && (penOps->traceWidth > 0)) + drawTraces(drawable, penPtr); + + if (penOps->symbol.type != SYMBOL_NONE) + drawSymbols(drawable, penPtr, symbolSize, symbolPts_.length, + symbolPts_.points); + + if (penOps->valueShow != SHOW_NONE) { + drawValues(drawable, penPtr, symbolPts_.length, symbolPts_.points, + symbolPts_.map); + } + } +} + +void LineElement::drawSymbol(Drawable drawable, int x, int y, int size) +{ + LineElementOptions* ops = (LineElementOptions*)ops_; + + LinePen* penPtr = NORMALPEN(ops); + LinePenOptions* penOps = (LinePenOptions*)penPtr->ops(); + + if (penOps->traceWidth > 0) { + // Draw an extra line offset by one pixel from the previous to give a + // thicker appearance. This is only for the legend entry. This routine + // is never called for drawing the actual line segments. + XDrawLine(graphPtr_->display_, drawable, penPtr->traceGC_, x - size, y, + x + size, y); + XDrawLine(graphPtr_->display_, drawable, penPtr->traceGC_, x - size, y + 1, + x + size, y + 1); + } + if (penOps->symbol.type != SYMBOL_NONE) { + Point2d point; + point.x = x; + point.y = y; + drawSymbols(drawable, penPtr, size, 1, &point); + } +} + +void LineElement::print(PSOutput* psPtr) +{ + LineElementOptions* ops = (LineElementOptions*)ops_; + LinePen* penPtr = NORMALPEN(ops); + LinePenOptions* penOps = (LinePenOptions*)penPtr->ops(); + + if (ops->hide) + return; + + psPtr->format("\n%% Element \"%s\"\n\n", name_); + + // Draw fill area + if (ops->fillBg && fillPts_) { + psPtr->append("% start fill area\n"); + psPtr->setBackground(ops->fillBg); + psPtr->printPolyline(fillPts_, nFillPts_); + psPtr->append("gsave fill grestore\n"); + psPtr->append("% end fill area\n"); + } + + // traces + if ((Chain_GetLength(traces_) > 0) && (penOps->traceWidth > 0)) + printTraces(psPtr, penPtr); + + // Symbols, error bars, values + if (ops->reqMaxSymbols > 0) { + int total = 0; + for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link; + link = Chain_NextLink(link)) { + LineStyle *stylePtr = (LineStyle*)Chain_GetValue(link); + total += stylePtr->symbolPts.length; + } + symbolInterval_ = total / ops->reqMaxSymbols; + symbolCounter_ = 0; + } + + unsigned int count =0; + for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link; + link = Chain_NextLink(link)) { + LineStyle *stylePtr = (LineStyle*)Chain_GetValue(link); + LinePen* penPtr = (LinePen *)stylePtr->penPtr; + LinePenOptions* penOps = (LinePenOptions*)penPtr->ops(); + XColor* colorPtr = penOps->errorBarColor; + if (!colorPtr) + colorPtr = penOps->traceColor; + + if ((stylePtr->xeb.length > 0) && (penOps->errorBarShow & SHOW_X)) { + psPtr->setLineAttributes(colorPtr, penOps->errorBarLineWidth, + NULL, CapButt, JoinMiter); + psPtr->printSegments(stylePtr->xeb.segments, stylePtr->xeb.length); + } + + if ((stylePtr->yeb.length > 0) && (penOps->errorBarShow & SHOW_Y)) { + psPtr->setLineAttributes(colorPtr, penOps->errorBarLineWidth, + NULL, CapButt, JoinMiter); + psPtr->printSegments(stylePtr->yeb.segments, stylePtr->yeb.length); + } + + if ((stylePtr->symbolPts.length > 0) && + (penOps->symbol.type != SYMBOL_NONE)) + printSymbols(psPtr, penPtr, stylePtr->symbolSize, + stylePtr->symbolPts.length, stylePtr->symbolPts.points); + + if (penOps->valueShow != SHOW_NONE) + printValues(psPtr, penPtr, stylePtr->symbolPts.length, + stylePtr->symbolPts.points, symbolPts_.map + count); + + count += stylePtr->symbolPts.length; + } + + symbolInterval_ = 0; + symbolCounter_ = 0; +} + +void LineElement::printActive(PSOutput* psPtr) +{ + LineElementOptions* ops = (LineElementOptions*)ops_; + LinePen* penPtr = (LinePen *)ops->activePenPtr; + if (!penPtr) + return; + LinePenOptions* penOps = (LinePenOptions*)penPtr->ops(); + + if (ops->hide || !active_) + return; + + psPtr->format("\n%% Active Element \"%s\"\n\n", name_); + + int symbolSize = scaleSymbol(penOps->symbol.size); + if (nActiveIndices_ > 0) { + mapActiveSymbols(); + + if (penOps->symbol.type != SYMBOL_NONE) + printSymbols(psPtr, penPtr, symbolSize, activePts_.length, + activePts_.points); + + if (penOps->valueShow != SHOW_NONE) + printValues(psPtr, penPtr, activePts_.length, activePts_.points, + activePts_.map); + } + else if (nActiveIndices_ < 0) { + if ((Chain_GetLength(traces_) > 0) && (penOps->traceWidth > 0)) + printTraces(psPtr, (LinePen*)penPtr); + + if (penOps->symbol.type != SYMBOL_NONE) + printSymbols(psPtr, penPtr, symbolSize, symbolPts_.length, + symbolPts_.points); + if (penOps->valueShow != SHOW_NONE) { + printValues(psPtr, penPtr, symbolPts_.length, symbolPts_.points, + symbolPts_.map); + } + } +} + +void LineElement::printSymbol(PSOutput* psPtr, double x, double y, int size) +{ + LineElementOptions* ops = (LineElementOptions*)ops_; + + LinePen* penPtr = NORMALPEN(ops); + LinePenOptions* penOps = (LinePenOptions*)penPtr->ops(); + + if (penOps->traceWidth > 0) { + // Draw an extra line offset by one pixel from the previous to give a + // thicker appearance. This is only for the legend entry. This routine + // is never called for drawing the actual line segments. + psPtr->setLineAttributes(penOps->traceColor, penOps->traceWidth, + &penOps->traceDashes, CapButt, JoinMiter); + psPtr->format("%g %g %d Li\n", x, y, size + size); + } + + if (penOps->symbol.type != SYMBOL_NONE) { + Point2d point; + point.x = x; + point.y = y; + printSymbols(psPtr, penPtr, size, 1, &point); + } +} + +// Support + +double LineElement::distanceToLine(int x, int y, Point2d *p, Point2d *q, + Point2d *t) +{ + double right, left, top, bottom; + + *t = getProjection(x, y, p, q); + if (p->x > q->x) + right = p->x, left = q->x; + else + left = p->x, right = q->x; + + if (p->y > q->y) + bottom = p->y, top = q->y; + else + top = p->y, bottom = q->y; + + if (t->x > right) + t->x = right; + else if (t->x < left) + t->x = left; + + if (t->y > bottom) + t->y = bottom; + else if (t->y < top) + t->y = top; + + return hypot((t->x - x), (t->y - y)); +} + +double LineElement::distanceToX(int x, int y, Point2d *p, Point2d *q, + Point2d *t) +{ + double dx, dy; + double d; + + if (p->x > q->x) { + if ((x > p->x) || (x < q->x)) { + return DBL_MAX; /* X-coordinate outside line segment. */ + } + } else { + if ((x > q->x) || (x < p->x)) { + return DBL_MAX; /* X-coordinate outside line segment. */ + } + } + dx = p->x - q->x; + dy = p->y - q->y; + t->x = (double)x; + if (fabs(dx) < DBL_EPSILON) { + double d1, d2; + /* + * Same X-coordinate indicates a vertical line. Pick the closest end + * point. + */ + d1 = p->y - y; + d2 = q->y - y; + if (fabs(d1) < fabs(d2)) { + t->y = p->y, d = d1; + } else { + t->y = q->y, d = d2; + } + } + else if (fabs(dy) < DBL_EPSILON) { + /* Horizontal line. */ + t->y = p->y, d = p->y - y; + } + else { + double m = dy / dx; + double b = p->y - (m * p->x); + t->y = (x * m) + b; + d = y - t->y; + } + + return fabs(d); +} + +double LineElement::distanceToY(int x, int y, Point2d *p, Point2d *q, + Point2d *t) +{ + double dx, dy; + double d; + + if (p->y > q->y) { + if ((y > p->y) || (y < q->y)) { + return DBL_MAX; + } + } + else { + if ((y > q->y) || (y < p->y)) { + return DBL_MAX; + } + } + dx = p->x - q->x; + dy = p->y - q->y; + t->y = y; + if (fabs(dy) < DBL_EPSILON) { + double d1, d2; + + /* Save Y-coordinate indicates an horizontal line. Pick the closest end + * point. */ + d1 = p->x - x; + d2 = q->x - x; + if (fabs(d1) < fabs(d2)) { + t->x = p->x, d = d1; + } + else { + t->x = q->x, d = d2; + } + } + else if (fabs(dx) < DBL_EPSILON) { + /* Vertical line. */ + t->x = p->x, d = p->x - x; + } + else { + double m = dy / dx; + double b = p->y - (m * p->x); + t->x = (y - b) / m; + d = x - t->x; + } + + return fabs(d); +} + +int LineElement::scaleSymbol(int normalSize) +{ + LineElementOptions* ops = (LineElementOptions*)ops_; + + double scale = 1.0; + if (ops->scaleSymbols) { + double xRange = (ops->xAxis->max_ - ops->xAxis->min_); + double yRange = (ops->yAxis->max_ - ops->yAxis->min_); + // Save the ranges as a baseline for future scaling + if (!xRange_ || !yRange_) { + xRange_ = xRange; + yRange_ = yRange; + } + else { + // Scale the symbol by the smallest change in the X or Y axes + double xScale = xRange_ / xRange; + double yScale = yRange_ / yRange; + scale = MIN(xScale, yScale); + } + } + int newSize = (int)(normalSize * scale); + + int maxSize = MIN(graphPtr_->hRange_, graphPtr_->vRange_); + if (newSize > maxSize) + newSize = maxSize; + + // Make the symbol size odd so that its center is a single pixel. + newSize |= 0x01; + + return newSize; +} + +void LineElement::getScreenPoints(MapInfo* mapPtr) +{ + LineElementOptions* ops = (LineElementOptions*)ops_; + GraphOptions* gops = (GraphOptions*)graphPtr_->ops_; + + if (!ops->coords.x || !ops->coords.y) { + mapPtr->screenPts = NULL; + mapPtr->nScreenPts = 0; + mapPtr->map = NULL; + } + + int np = NUMBEROFPOINTS(ops); + double* x = ops->coords.x->values_; + double* y = ops->coords.y->values_; + Point2d* points = new Point2d[np]; + int* map = new int[np]; + + int count = 0; + if (gops->inverted) { + for (int ii=0; iiyAxis->hMap(y[ii]); + points[count].y = ops->xAxis->vMap(x[ii]); + map[count] = ii; + count++; + } + } + } + else { + for (int ii=0; ii< np; ii++) { + if ((isfinite(x[ii])) && (isfinite(y[ii]))) { + points[count].x = ops->xAxis->hMap(x[ii]); + points[count].y = ops->yAxis->vMap(y[ii]); + map[count] = ii; + count++; + } + } + } + mapPtr->screenPts = points; + mapPtr->nScreenPts = count; + mapPtr->map = map; +} + +void LineElement::reducePoints(MapInfo *mapPtr, double tolerance) +{ + int* simple = new int[mapPtr->nScreenPts]; + int* map = new int[mapPtr->nScreenPts]; + Point2d* screenPts = new Point2d[mapPtr->nScreenPts]; + int np = simplify(mapPtr->screenPts, 0, mapPtr->nScreenPts - 1, + tolerance, simple); + for (int ii=0; iiscreenPts[kk]; + map[ii] = mapPtr->map[kk]; + } + delete [] simple; + + delete [] mapPtr->screenPts; + mapPtr->screenPts = screenPts; + delete [] mapPtr->map; + mapPtr->map = map; + mapPtr->nScreenPts = np; +} + +// Douglas-Peucker line simplification algorithm +int LineElement::simplify(Point2d *inputPts, int low, int high, + double tolerance, int *indices) +{ +#define StackPush(a) s++, stack[s] = (a) +#define StackPop(a) (a) = stack[s], s-- +#define StackEmpty() (s < 0) +#define StackTop() stack[s] + int split = -1; + double dist2, tolerance2; + int s = -1; /* Points to top stack item. */ + + int* stack = new int[high - low + 1]; + StackPush(high); + int count = 0; + indices[count++] = 0; + tolerance2 = tolerance * tolerance; + while (!StackEmpty()) { + dist2 = findSplit(inputPts, low, StackTop(), &split); + if (dist2 > tolerance2) + StackPush(split); + else { + indices[count++] = StackTop(); + StackPop(low); + } + } + delete [] stack; + return count; +} + +double LineElement::findSplit(Point2d *points, int i, int j, int *split) +{ + double maxDist2 = -1.0; + if ((i + 1) < j) { + double a = points[i].y - points[j].y; + double b = points[j].x - points[i].x; + double c = (points[i].x * points[j].y) - (points[i].y * points[j].x); + for (int kk = (i + 1); kk < j; kk++) { + double dist2 = (points[kk].x * a) + (points[kk].y * b) + c; + if (dist2 < 0.0) + dist2 = -dist2; + + // Track the maximum. + if (dist2 > maxDist2) { + maxDist2 = dist2; + *split = kk; + } + } + // Correction for segment length---should be redone if can == 0 + maxDist2 *= maxDist2 / (a * a + b * b); + } + return maxDist2; +} + +void LineElement::generateSteps(MapInfo *mapPtr) +{ + int newSize = ((mapPtr->nScreenPts - 1) * 2) + 1; + Point2d* screenPts = new Point2d[newSize]; + int* map = new int[newSize]; + screenPts[0] = mapPtr->screenPts[0]; + map[0] = 0; + + int count = 1; + for (int i = 1; i < mapPtr->nScreenPts; i++) { + screenPts[count + 1] = mapPtr->screenPts[i]; + + // Hold last y-coordinate, use new x-coordinate + screenPts[count].x = screenPts[count + 1].x; + screenPts[count].y = screenPts[count - 1].y; + + // Use the same style for both the hold and the step points + map[count] = map[count + 1] = mapPtr->map[i]; + count += 2; + } + delete [] mapPtr->map; + mapPtr->map = map; + delete [] mapPtr->screenPts; + mapPtr->screenPts = screenPts; + mapPtr->nScreenPts = newSize; +} + +void LineElement::generateSpline(MapInfo *mapPtr) +{ + int nOrigPts = mapPtr->nScreenPts; + Point2d* origPts = mapPtr->screenPts; + + // check points are not monotonically increasing + for (int ii=0, jj=1; jj (double)graphPtr_->right_)) || + ((origPts[mapPtr->nScreenPts - 1].x < (double)graphPtr_->left_))) + return; + + // The spline is computed in screen coordinates instead of data points so + // that we can select the abscissas of the interpolated points from each + // pixel horizontally across the plotting area. + int extra = (graphPtr_->right_ - graphPtr_->left_) + 1; + if (extra < 1) + return; + + int niPts = nOrigPts + extra + 1; + Point2d* iPts = new Point2d[niPts]; + int* map = new int[niPts]; + + // Populate the x2 array with both the original X-coordinates and extra + // X-coordinates for each horizontal pixel that the line segment contains + int count = 0; + for (int ii=0, jj=1; jjmap[ii]; + count++; + + // Is any part of the interval (line segment) in the plotting area? + if ((origPts[jj].x >= (double)graphPtr_->left_) || + (origPts[ii].x <= (double)graphPtr_->right_)) { + double x = origPts[ii].x + 1.0; + + /* + * Since the line segment may be partially clipped on the left or + * right side, the points to interpolate are always interior to + * the plotting area. + * + * left right + * x1----|---------------------------|---x2 + * + * Pick the max of the starting X-coordinate and the left edge and + * the min of the last X-coordinate and the right edge. + */ + x = MAX(x, (double)graphPtr_->left_); + double last = MIN(origPts[jj].x, (double)graphPtr_->right_); + + // Add the extra x-coordinates to the interval + while (x < last) { + map[count] = mapPtr->map[ii]; + iPts[count++].x = x; + x++; + } + } + } + niPts = count; + int result = 0; + if (smooth_ == CUBIC) + result = naturalSpline(origPts, nOrigPts, iPts, niPts); + else if (smooth_ == QUADRATIC) + result = quadraticSpline(origPts, nOrigPts, iPts, niPts); + + // The spline interpolation failed. We will fall back to the current + // coordinates and do no smoothing (standard line segments) + if (!result) { + smooth_ = LINEAR; + delete [] iPts; + delete [] map; + } + else { + delete [] mapPtr->map; + mapPtr->map = map; + delete [] mapPtr->screenPts; + mapPtr->screenPts = iPts; + mapPtr->nScreenPts = niPts; + } +} + +void LineElement::generateParametricSpline(MapInfo *mapPtr) +{ + int nOrigPts = mapPtr->nScreenPts; + Point2d *origPts = mapPtr->screenPts; + + Region2d exts; + graphPtr_->extents(&exts); + + /* + * Populate the x2 array with both the original X-coordinates and extra + * X-coordinates for each horizontal pixel that the line segment contains. + */ + int count = 1; + for (int i = 0, j = 1; j < nOrigPts; i++, j++) { + Point2d p = origPts[i]; + Point2d q = origPts[j]; + count++; + if (lineRectClip(&exts, &p, &q)) + count += (int)(hypot(q.x - p.x, q.y - p.y) * 0.5); + } + int niPts = count; + Point2d *iPts = new Point2d[niPts]; + int* map = new int[niPts]; + + /* + * FIXME: This is just plain wrong. The spline should be computed + * and evaluated in separate steps. This will mean breaking + * up this routine since the catrom coefficients can be + * independently computed for original data point. This + * also handles the problem of allocating enough points + * since evaluation is independent of the number of points + * to be evalualted. The interpolated + * line segments should be clipped, not the original segments. + */ + count = 0; + int i,j; + for (i = 0, j = 1; j < nOrigPts; i++, j++) { + Point2d p = origPts[i]; + Point2d q = origPts[j]; + + double d = hypot(q.x - p.x, q.y - p.y); + /* Add the original x-coordinate */ + iPts[count].x = (double)i; + iPts[count].y = 0.0; + + /* Include the starting offset of the point in the offset array */ + map[count] = mapPtr->map[i]; + count++; + + /* Is any part of the interval (line segment) in the plotting + * area? */ + + if (lineRectClip(&exts, &p, &q)) { + double dp, dq; + + /* Distance of original point to p. */ + dp = hypot(p.x - origPts[i].x, p.y - origPts[i].y); + /* Distance of original point to q. */ + dq = hypot(q.x - origPts[i].x, q.y - origPts[i].y); + dp += 2.0; + while(dp <= dq) { + /* Point is indicated by its interval and parameter t. */ + iPts[count].x = (double)i; + iPts[count].y = dp / d; + map[count] = mapPtr->map[i]; + count++; + dp += 2.0; + } + } + } + iPts[count].x = (double)i; + iPts[count].y = 0.0; + map[count] = mapPtr->map[i]; + count++; + niPts = count; + int result = 0; + if (smooth_ == CUBIC) + result = naturalParametricSpline(origPts, nOrigPts, &exts, 0, iPts, niPts); + else if (smooth_ == CATROM) + result = catromParametricSpline(origPts, nOrigPts, iPts, niPts); + + // The spline interpolation failed. We will fall back to the current + // coordinates and do no smoothing (standard line segments) + if (!result) { + smooth_ = LINEAR; + delete [] iPts; + delete [] map; + } + else { + delete [] mapPtr->map; + mapPtr->map = map; + delete [] mapPtr->screenPts; + mapPtr->screenPts = iPts; + mapPtr->nScreenPts = niPts; + } +} + +void LineElement::mapSymbols(MapInfo *mapPtr) +{ + Point2d* points = new Point2d[mapPtr->nScreenPts]; + int *map = new int[mapPtr->nScreenPts]; + + Region2d exts; + graphPtr_->extents(&exts); + + Point2d *pp; + int count = 0; + int i; + for (pp=mapPtr->screenPts, i=0; inScreenPts; i++, pp++) { + if (PointInRegion(&exts, pp->x, pp->y)) { + points[count].x = pp->x; + points[count].y = pp->y; + map[count] = mapPtr->map[i]; + count++; + } + } + symbolPts_.points = points; + symbolPts_.length = count; + symbolPts_.map = map; +} + +void LineElement::mapActiveSymbols() +{ + LineElementOptions* ops = (LineElementOptions*)ops_; + + delete [] activePts_.points; + activePts_.points = NULL; + delete [] activePts_.map; + activePts_.map = NULL; + + Region2d exts; + graphPtr_->extents(&exts); + + Point2d *points = new Point2d[nActiveIndices_]; + int* map = new int[nActiveIndices_]; + int np = NUMBEROFPOINTS(ops); + int count = 0; + if (ops->coords.x && ops->coords.y) { + for (int ii=0; ii= np) + continue; + + double x = ops->coords.x->values_[iPoint]; + double y = ops->coords.y->values_[iPoint]; + points[count] = graphPtr_->map2D(x, y, ops->xAxis, ops->yAxis); + map[count] = iPoint; + if (PointInRegion(&exts, points[count].x, points[count].y)) { + count++; + } + } + } + + if (count > 0) { + activePts_.points = points; + activePts_.map = map; + } + else { + delete [] points; + delete [] map; + } + activePts_.length = count; +} + +void LineElement::mergePens(LineStyle **styleMap) +{ + LineElementOptions* ops = (LineElementOptions*)ops_; + + if (Chain_GetLength(ops->stylePalette) < 2) { + ChainLink* link = Chain_FirstLink(ops->stylePalette); + LineStyle *stylePtr = (LineStyle*)Chain_GetValue(link); + stylePtr->symbolPts.length = symbolPts_.length; + stylePtr->symbolPts.points = symbolPts_.points; + stylePtr->xeb.length = xeb_.length; + stylePtr->xeb.segments = xeb_.segments; + stylePtr->yeb.length = yeb_.length; + stylePtr->yeb.segments = yeb_.segments; + return; + } + + if (symbolPts_.length > 0) { + Point2d* points = new Point2d[symbolPts_.length]; + int* map = new int[symbolPts_.length]; + Point2d *pp = points; + int* ip = map; + for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link; + link = Chain_NextLink(link)) { + LineStyle *stylePtr = (LineStyle*)Chain_GetValue(link); + stylePtr->symbolPts.points = pp; + for (int ii=0; iisymbolPts.length = pp - stylePtr->symbolPts.points; + } + delete [] symbolPts_.points; + symbolPts_.points = points; + delete [] symbolPts_.map; + symbolPts_.map = map; + } + + if (xeb_.length > 0) { + Segment2d* segments = new Segment2d[xeb_.length]; + Segment2d *sp = segments; + int* map = new int[xeb_.length]; + int* ip = map; + for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link; + link = Chain_NextLink(link)) { + LineStyle *stylePtr = (LineStyle*)Chain_GetValue(link); + stylePtr->xeb.segments = sp; + for (int ii=0; iixeb.length = sp - stylePtr->xeb.segments; + } + delete [] xeb_.segments; + xeb_.segments = segments; + delete [] xeb_.map; + xeb_.map = map; + } + + if (yeb_.length > 0) { + Segment2d* segments = new Segment2d[yeb_.length]; + Segment2d* sp = segments; + int* map = new int [yeb_.length]; + int* ip = map; + for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link; + link = Chain_NextLink(link)) { + LineStyle *stylePtr = (LineStyle*)Chain_GetValue(link); + stylePtr->yeb.segments = sp; + for (int ii=0; iiyeb.length = sp - stylePtr->yeb.segments; + } + delete [] yeb_.segments; + yeb_.segments = segments; + delete [] yeb_.map; + yeb_.map = map; + } +} + +void LineElement::saveTrace(int start, int length, MapInfo* mapPtr) +{ + bltTrace* tracePtr = new bltTrace; + Point2d* screenPts = new Point2d[length]; + int* map = new int[length]; + + // Copy the screen coordinates of the trace into the point array + if (mapPtr->map) { + for (int ii=0, jj=start; iiscreenPts[jj].x; + screenPts[ii].y = mapPtr->screenPts[jj].y; + map[ii] = mapPtr->map[jj]; + } + } + else { + for (int ii=0, jj=start; iiscreenPts[jj].x; + screenPts[ii].y = mapPtr->screenPts[jj].y; + map[ii] = jj; + } + } + tracePtr->screenPts.length = length; + tracePtr->screenPts.points = screenPts; + tracePtr->screenPts.map = map; + tracePtr->start = start; + if (traces_ == NULL) + traces_ = new Chain(); + + traces_->append(tracePtr); +} + +void LineElement::freeTraces() +{ + for (ChainLink* link = Chain_FirstLink(traces_); link; + link = Chain_NextLink(link)) { + bltTrace* tracePtr = (bltTrace*)Chain_GetValue(link); + delete [] tracePtr->screenPts.map; + delete [] tracePtr->screenPts.points; + delete tracePtr; + } + delete traces_; + traces_ = NULL; +} + +void LineElement::mapTraces(MapInfo *mapPtr) +{ + LineElementOptions* ops = (LineElementOptions*)ops_; + + Region2d exts; + graphPtr_->extents(&exts); + + int count = 1; + Point2d* p = mapPtr->screenPts; + Point2d* q = p + 1; + + int start; + int ii; + for (ii=1; iinScreenPts; ii++, p++, q++) { + // Save the coordinates of the last point before clipping. + Point2d originalq = *q; + int broken = BROKEN_TRACE(ops->penDir, p->x, q->x); + LineRectClipResult clipresult = lineRectClip(&exts, p, q); + + if (broken || clipresult == CLIP_OUTSIDE) { + // The last line segment is either totally clipped by the plotting + // area or the x-direction is wrong, breaking the trace. Either + // way, save information about the last trace (if one exists), + // discarding the current line segment + if (count > 1) { + start = ii - count; + saveTrace(start, count, mapPtr); + count = 1; + } + } + else { + // Add the point to the trace + count++; + + // If the last point is clipped, this means that the trace is + // broken after this point. Restore the original coordinate + // (before clipping) after saving the trace. + if (clipresult & CLIP_Q) { + start = ii - (count - 1); + saveTrace(start, count, mapPtr); + mapPtr->screenPts[ii] = originalq; + count = 1; + } + } + } + if (count > 1) { + start = ii - count; + saveTrace(start, count, mapPtr); + } +} + +void LineElement::mapFillArea(MapInfo *mapPtr) +{ + LineElementOptions* ops = (LineElementOptions*)ops_; + GraphOptions* gops = (GraphOptions*)graphPtr_->ops_; + + if (fillPts_) { + delete [] fillPts_; + fillPts_ = NULL; + nFillPts_ = 0; + } + if (mapPtr->nScreenPts < 3) + return; + + int np = mapPtr->nScreenPts + 3; + Region2d exts; + graphPtr_->extents(&exts); + + Point2d* origPts = new Point2d[np]; + if (gops->inverted) { + int i; + double minX = (double)ops->yAxis->screenMin_; + for (i = 0; i < mapPtr->nScreenPts; i++) { + origPts[i].x = mapPtr->screenPts[i].x + 1; + origPts[i].y = mapPtr->screenPts[i].y; + if (origPts[i].x < minX) { + minX = origPts[i].x; + } + } + // Add edges to make the polygon fill to the bottom of plotting window + origPts[i].x = minX; + origPts[i].y = origPts[i - 1].y; + i++; + origPts[i].x = minX; + origPts[i].y = origPts[0].y; + i++; + origPts[i] = origPts[0]; + } + else { + int i; + double maxY = (double)ops->yAxis->bottom_; + for (i = 0; i < mapPtr->nScreenPts; i++) { + origPts[i].x = mapPtr->screenPts[i].x + 1; + origPts[i].y = mapPtr->screenPts[i].y; + if (origPts[i].y > maxY) { + maxY = origPts[i].y; + } + } + // Add edges to extend the fill polygon to the bottom of plotting window + origPts[i].x = origPts[i - 1].x; + origPts[i].y = maxY; + i++; + origPts[i].x = origPts[0].x; + origPts[i].y = maxY; + i++; + origPts[i] = origPts[0]; + } + + Point2d *clipPts = new Point2d[np * 3]; + np = polyRectClip(&exts, origPts, np - 1, clipPts); + + delete [] origPts; + if (np < 3) + delete [] clipPts; + else { + fillPts_ = clipPts; + nFillPts_ = np; + } +} + +void LineElement::reset() +{ + LineElementOptions* ops = (LineElementOptions*)ops_; + + freeTraces(); + + for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link; + link = Chain_NextLink(link)) { + LineStyle *stylePtr = (LineStyle*)Chain_GetValue(link); + stylePtr->symbolPts.length = 0; + stylePtr->xeb.length = 0; + stylePtr->yeb.length = 0; + } + + delete [] symbolPts_.points; + symbolPts_.points = NULL; + + delete [] symbolPts_.map; + symbolPts_.map = NULL; + symbolPts_.length = 0; + + delete [] activePts_.points; + activePts_.points = NULL; + activePts_.length = 0; + + delete [] activePts_.map; + activePts_.map = NULL; + + delete [] xeb_.segments; + xeb_.segments = NULL; + delete [] xeb_.map; + xeb_.map = NULL; + xeb_.length = 0; + + delete [] yeb_.segments; + yeb_.segments = NULL; + delete [] yeb_.map; + yeb_.map = NULL; + yeb_.length = 0; +} + +void LineElement::mapErrorBars(LineStyle **styleMap) +{ + LineElementOptions* ops = (LineElementOptions*)ops_; + + Region2d exts; + graphPtr_->extents(&exts); + + int nn =0; + int np = NUMBEROFPOINTS(ops); + if (ops->coords.x && ops->coords.y) { + if (ops->xError && (ops->xError->nValues() > 0)) + nn = MIN(ops->xError->nValues(), np); + else + if (ops->xHigh && ops->xLow) + nn = MIN3(ops->xHigh->nValues(), ops->xLow->nValues(), np); + } + + if (nn) { + Segment2d* errorBars = new Segment2d[nn * 3]; + Segment2d* segPtr = errorBars; + int* errorToData = new int[nn * 3]; + int* indexPtr = errorToData; + + for (int ii=0; iicoords.x->values_[ii]; + double y = ops->coords.y->values_[ii]; + LineStyle* stylePtr = styleMap[ii]; + + if ((isfinite(x)) && (isfinite(y))) { + double high; + double low; + if (ops->xError && ops->xError->nValues() > 0) { + high = x + ops->xError->values_[ii]; + low = x - ops->xError->values_[ii]; + } + else { + high = ops->xHigh ? ops->xHigh->values_[ii] : 0; + low = ops->xLow ? ops->xLow->values_[ii] : 0; + } + + if ((isfinite(high)) && (isfinite(low))) { + Point2d p = graphPtr_->map2D(high, y, ops->xAxis, ops->yAxis); + Point2d q = graphPtr_->map2D(low, y, ops->xAxis, ops->yAxis); + segPtr->p = p; + segPtr->q = q; + if (lineRectClip(&exts, &segPtr->p, &segPtr->q)) { + segPtr++; + *indexPtr++ = ii; + } + // Left cap + segPtr->p.x = p.x; + segPtr->q.x = p.x; + segPtr->p.y = p.y - stylePtr->errorBarCapWidth; + segPtr->q.y = p.y + stylePtr->errorBarCapWidth; + if (lineRectClip(&exts, &segPtr->p, &segPtr->q)) { + segPtr++; + *indexPtr++ = ii; + } + // Right cap + segPtr->p.x = q.x; + segPtr->q.x = q.x; + segPtr->p.y = q.y - stylePtr->errorBarCapWidth; + segPtr->q.y = q.y + stylePtr->errorBarCapWidth; + if (lineRectClip(&exts, &segPtr->p, &segPtr->q)) { + segPtr++; + *indexPtr++ = ii; + } + } + } + } + xeb_.segments = errorBars; + xeb_.length = segPtr - errorBars; + xeb_.map = errorToData; + } + + nn =0; + if (ops->coords.x && ops->coords.y) { + if (ops->yError && (ops->yError->nValues() > 0)) + nn = MIN(ops->yError->nValues(), np); + else + if (ops->yHigh && ops->yLow) + nn = MIN3(ops->yHigh->nValues(), ops->yLow->nValues(), np); + } + + if (nn) { + Segment2d* errorBars = new Segment2d[nn * 3]; + Segment2d* segPtr = errorBars; + int* errorToData = new int[nn * 3]; + int* indexPtr = errorToData; + + for (int ii=0; iicoords.x->values_[ii]; + double y = ops->coords.y->values_[ii]; + LineStyle* stylePtr = styleMap[ii]; + + if ((isfinite(x)) && (isfinite(y))) { + double high; + double low; + if (ops->yError && ops->yError->nValues() > 0) { + high = y + ops->yError->values_[ii]; + low = y - ops->yError->values_[ii]; + } + else { + high = ops->yHigh->values_[ii]; + low = ops->yLow->values_[ii]; + } + + if ((isfinite(high)) && (isfinite(low))) { + Point2d p = graphPtr_->map2D(x, high, ops->xAxis, ops->yAxis); + Point2d q = graphPtr_->map2D(x, low, ops->xAxis, ops->yAxis); + segPtr->p = p; + segPtr->q = q; + if (lineRectClip(&exts, &segPtr->p, &segPtr->q)) { + segPtr++; + *indexPtr++ = ii; + } + // Top cap + segPtr->p.y = p.y; + segPtr->q.y = p.y; + segPtr->p.x = p.x - stylePtr->errorBarCapWidth; + segPtr->q.x = p.x + stylePtr->errorBarCapWidth; + if (lineRectClip(&exts, &segPtr->p, &segPtr->q)) { + segPtr++; + *indexPtr++ = ii; + } + // Bottom cap + segPtr->p.y = q.y; + segPtr->q.y = q.y; + segPtr->p.x = q.x - stylePtr->errorBarCapWidth; + segPtr->q.x = q.x + stylePtr->errorBarCapWidth; + if (lineRectClip(&exts, &segPtr->p, &segPtr->q)) { + segPtr++; + *indexPtr++ = ii; + } + } + } + } + yeb_.segments = errorBars; + yeb_.length = segPtr - errorBars; + yeb_.map = errorToData; + } +} + +int LineElement::closestTrace() +{ + LineElementOptions* ops = (LineElementOptions*)ops_; + GraphOptions* gops = (GraphOptions*)graphPtr_->ops_; + ClosestSearch* searchPtr = &gops->search; + + Point2d closest; + + int iClose = -1; + double dMin = searchPtr->dist; + closest.x = closest.y = 0; + for (ChainLink *link=Chain_FirstLink(traces_); link; + link = Chain_NextLink(link)) { + bltTrace *tracePtr = (bltTrace*)Chain_GetValue(link); + for (Point2d *p=tracePtr->screenPts.points, + *pend=p + (tracePtr->screenPts.length - 1); palong == SEARCH_X) + d = distanceToX(searchPtr->x, searchPtr->y, p, p + 1, &b); + else if (searchPtr->along == SEARCH_Y) + d = distanceToY(searchPtr->x, searchPtr->y, p, p + 1, &b); + else + d = distanceToLine(searchPtr->x, searchPtr->y, p, p + 1, &b); + + if (d < dMin) { + closest = b; + iClose = tracePtr->screenPts.map[p-tracePtr->screenPts.points]; + dMin = d; + } + } + } + if (dMin < searchPtr->dist) { + searchPtr->dist = dMin; + searchPtr->elemPtr = (Element*)this; + searchPtr->index = iClose; + searchPtr->point = graphPtr_->invMap2D(closest.x, closest.y, + ops->xAxis, ops->yAxis); + return 1; + } + + return 0; +} + +void LineElement::closestPoint(ClosestSearch *searchPtr) +{ + LineElementOptions* ops = (LineElementOptions*)ops_; + + double dMin = searchPtr->dist; + int iClose = 0; + + // Instead of testing each data point in graph coordinates, look at the + // array of mapped screen coordinates. The advantages are + // 1) only examine points that are visible (unclipped), and + // 2) the computed distance is already in screen coordinates. + int count =0; + for (Point2d *pp = symbolPts_.points; count < symbolPts_.length; + count++, pp++) { + double dx = (double)abs(searchPtr->x - pp->x); + double dy = (double)abs(searchPtr->y - pp->y); + double d; + if (searchPtr->along == SEARCH_BOTH) + d = hypot(dx, dy); + else if (searchPtr->along == SEARCH_X) + d = dx; + else if (searchPtr->along == SEARCH_Y) + d = dy; + else + continue; + + if (d < dMin) { + iClose = symbolPts_.map[count]; + dMin = d; + } + } + if (dMin < searchPtr->dist) { + searchPtr->elemPtr = (Element*)this; + searchPtr->dist = dMin; + searchPtr->index = iClose; + searchPtr->point.x = ops->coords.x->values_[iClose]; + searchPtr->point.y = ops->coords.y->values_[iClose]; + } +} + +void LineElement::drawCircle(Display *display, Drawable drawable, + LinePen* penPtr, + int nSymbolPts, Point2d *symbolPts, int radius) +{ + LinePenOptions* penOps = (LinePenOptions*)penPtr->ops(); + + int count = 0; + int s = radius + radius; + XArc* arcs = new XArc[nSymbolPts]; + XArc *ap = arcs; + for (Point2d *pp=symbolPts, *pend=pp+nSymbolPts; ppx = (short)(pp->x - radius); + ap->y = (short)(pp->y - radius); + ap->width = (short)s; + ap->height = (short)s; + ap->angle1 = 0; + ap->angle2 = 23040; + ap++; + count++; + } + symbolCounter_++; + } + + for (XArc *ap=arcs, *aend=ap+count; apsymbol.fillGC) + XFillArc(display, drawable, penOps->symbol.fillGC, + ap->x, ap->y, ap->width, ap->height, ap->angle1, ap->angle2); + + if (penOps->symbol.outlineWidth > 0) + XDrawArc(display, drawable, penOps->symbol.outlineGC, + ap->x, ap->y, ap->width, ap->height, ap->angle1, ap->angle2); + } + + delete [] arcs; +} + +void LineElement::drawSquare(Display *display, Drawable drawable, + LinePen* penPtr, + int nSymbolPts, Point2d *symbolPts, int r) +{ + LinePenOptions* penOps = (LinePenOptions*)penPtr->ops(); + + int s = r + r; + int count =0; + Rectangle* rectangles = new Rectangle[nSymbolPts]; + Rectangle* rp=rectangles; + for (Point2d *pp=symbolPts, *pend=pp+nSymbolPts; ppx = (int)pp->x - r; + rp->y = (int)pp->y - r; + rp->width = s; + rp->height = s; + rp++; + count++; + } + symbolCounter_++; + } + + for (Rectangle *rp=rectangles, *rend=rp+count; rpsymbol.fillGC) + XFillRectangle(display, drawable, penOps->symbol.fillGC, + rp->x, rp->y, rp->width, rp->height); + + if (penOps->symbol.outlineWidth > 0) + XDrawRectangle(display, drawable, penOps->symbol.outlineGC, + rp->x, rp->y, rp->width, rp->height); + } + + delete [] rectangles; +} + +void LineElement::drawSCross(Display* display, Drawable drawable, + LinePen* penPtr, + int nSymbolPts, Point2d* symbolPts, int r2) +{ + LinePenOptions* penOps = (LinePenOptions*)penPtr->ops(); + + Point pattern[4]; + if (penOps->symbol.type == SYMBOL_SCROSS) { + r2 = (int)(r2 * M_SQRT1_2); + pattern[3].y = pattern[2].x = pattern[0].x = pattern[0].y = -r2; + pattern[3].x = pattern[2].y = pattern[1].y = pattern[1].x = r2; + } + else { + pattern[0].y = pattern[1].y = pattern[2].x = pattern[3].x = 0; + pattern[0].x = pattern[2].y = -r2; + pattern[1].x = pattern[3].y = r2; + } + + for (Point2d *pp=symbolPts, *endp=pp+nSymbolPts; ppx; + int rndy = (int)pp->y; + XDrawLine(graphPtr_->display_, drawable, penOps->symbol.outlineGC, + pattern[0].x + rndx, pattern[0].y + rndy, + pattern[1].x + rndx, pattern[1].y + rndy); + XDrawLine(graphPtr_->display_, drawable, penOps->symbol.outlineGC, + pattern[2].x + rndx, pattern[2].y + rndy, + pattern[3].x + rndx, pattern[3].y + rndy); + } + } +} + +void LineElement::drawCross(Display *display, Drawable drawable, + LinePen* penPtr, + int nSymbolPts, Point2d *symbolPts, int r2) +{ + LinePenOptions* penOps = (LinePenOptions*)penPtr->ops(); + + /* + * 2 3 The plus/cross symbol is a closed polygon + * of 12 points. The diagram to the left + * 0,12 1 4 5 represents the positions of the points + * x,y which are computed below. The extra + * 11 10 7 6 (thirteenth) point connects the first and + * last points. + * 9 8 + */ + int d = (r2 / 3); + Point pattern[13]; + pattern[0].x = pattern[11].x = pattern[12].x = -r2; + pattern[2].x = pattern[1].x = pattern[10].x = pattern[9].x = -d; + pattern[3].x = pattern[4].x = pattern[7].x = pattern[8].x = d; + pattern[5].x = pattern[6].x = r2; + pattern[2].y = pattern[3].y = -r2; + pattern[0].y = pattern[1].y = pattern[4].y = pattern[5].y = + pattern[12].y = -d; + pattern[11].y = pattern[10].y = pattern[7].y = pattern[6].y = d; + pattern[9].y = pattern[8].y = r2; + + if (penOps->symbol.type == SYMBOL_CROSS) { + // For the cross symbol, rotate the points by 45 degrees + for (int ii=0; ii<12; ii++) { + double dx = (double)pattern[ii].x * M_SQRT1_2; + double dy = (double)pattern[ii].y * M_SQRT1_2; + pattern[ii].x = (int)(dx - dy); + pattern[ii].y = (int)(dx + dy); + } + pattern[12] = pattern[0]; + } + + int count = 0; + XPoint* polygon = new XPoint[nSymbolPts*13]; + XPoint* xpp = polygon; + for (Point2d *pp = symbolPts, *endp = pp + nSymbolPts; pp < endp; pp++) { + if (DRAW_SYMBOL()) { + int rndx = (int)pp->x; + int rndy = (int)pp->y; + for (int ii=0; ii<13; ii++) { + xpp->x = (short)(pattern[ii].x + rndx); + xpp->y = (short)(pattern[ii].y + rndy); + xpp++; + } + count++; + } + symbolCounter_++; + } + + if (penOps->symbol.fillGC) { + XPoint* xpp = polygon; + for (int ii=0; iidisplay_, drawable, + penOps->symbol.fillGC, xpp, 13, Complex, + CoordModeOrigin); + } + + if (penOps->symbol.outlineWidth > 0) { + XPoint*xpp = polygon; + for (int ii=0; iidisplay_, drawable, + penOps->symbol.outlineGC, xpp, 13, CoordModeOrigin); + } + + delete [] polygon; +} + +void LineElement::drawDiamond(Display *display, Drawable drawable, + LinePen* penPtr, + int nSymbolPts, Point2d *symbolPts, int r1) +{ + LinePenOptions* penOps = (LinePenOptions*)penPtr->ops(); + + /* + * The plus symbol is a closed polygon + * 1 of 4 points. The diagram to the left + * represents the positions of the points + * 0,4 x,y 2 which are computed below. The extra + * (fifth) point connects the first and + * 3 last points. + */ + Point pattern[5]; + pattern[1].y = pattern[0].x = -r1; + pattern[2].y = pattern[3].x = pattern[0].y = pattern[1].x = 0; + pattern[3].y = pattern[2].x = r1; + pattern[4] = pattern[0]; + + int count = 0; + XPoint* polygon = new XPoint[nSymbolPts*5]; + XPoint* xpp = polygon; + for (Point2d *pp = symbolPts, *endp = pp + nSymbolPts; pp < endp; pp++) { + if (DRAW_SYMBOL()) { + int rndx = (int)pp->x; + int rndy = (int)pp->y; + for (int ii=0; ii<5; ii++) { + xpp->x = (short)(pattern[ii].x + rndx); + xpp->y = (short)(pattern[ii].y + rndy); + xpp++; + } + count++; + } + symbolCounter_++; + } + + if (penOps->symbol.fillGC) { + XPoint* xpp = polygon; + for (int ii=0; iidisplay_, drawable, + penOps->symbol.fillGC, xpp, 5, Convex, CoordModeOrigin); + } + + if (penOps->symbol.outlineWidth > 0) { + XPoint* xpp = polygon; + for (int ii=0; iidisplay_, drawable, + penOps->symbol.outlineGC, xpp, 5, CoordModeOrigin); + } + + delete [] polygon; +} + +#define B_RATIO 1.3467736870885982 +#define TAN30 0.57735026918962573 +#define COS30 0.86602540378443871 +void LineElement::drawArrow(Display *display, Drawable drawable, + LinePen* penPtr, + int nSymbolPts, Point2d *symbolPts, int size) +{ + LinePenOptions* penOps = (LinePenOptions*)penPtr->ops(); + + double b = size * B_RATIO * 0.7 * 0.5; + short b2 = (short)b; + short h2 = (short)(TAN30 * b); + short h1 = (short)(b / COS30); + /* + * The triangle symbol is a closed polygon + * 0,3 of 3 points. The diagram to the left + * represents the positions of the points + * x,y which are computed below. The extra + * (fourth) point connects the first and + * 2 1 last points. + */ + + Point pattern[4]; + if (penOps->symbol.type == SYMBOL_ARROW) { + pattern[3].x = pattern[0].x = 0; + pattern[3].y = pattern[0].y = h1; + pattern[1].x = b2; + pattern[2].y = pattern[1].y = -h2; + pattern[2].x = -b2; + } else { + pattern[3].x = pattern[0].x = 0; + pattern[3].y = pattern[0].y = -h1; + pattern[1].x = b2; + pattern[2].y = pattern[1].y = h2; + pattern[2].x = -b2; + } + + int count = 0; + XPoint* polygon = new XPoint[nSymbolPts*4]; + XPoint* xpp = polygon; + for (Point2d *pp = symbolPts, *endp = pp + nSymbolPts; pp < endp; pp++) { + if (DRAW_SYMBOL()) { + int rndx = (int)pp->x; + int rndy = (int)pp->y; + for (int ii=0; ii<4; ii++) { + xpp->x = (short)(pattern[ii].x + rndx); + xpp->y = (short)(pattern[ii].y + rndy); + xpp++; + } + count++; + } + symbolCounter_++; + } + + if (penOps->symbol.fillGC) { + XPoint* xpp = polygon; + for (int ii=0; iidisplay_, drawable, + penOps->symbol.fillGC, xpp, 4, Convex, CoordModeOrigin); + } + + if (penOps->symbol.outlineWidth > 0) { + XPoint* xpp = polygon; + for (int ii=0; iidisplay_, drawable, + penOps->symbol.outlineGC, xpp, 4, CoordModeOrigin); + } + + delete [] polygon; +} + +#define S_RATIO 0.886226925452758 +void LineElement::drawSymbols(Drawable drawable, LinePen* penPtr, int size, + int nSymbolPts, Point2d* symbolPts) +{ + LinePenOptions* penOps = (LinePenOptions*)penPtr->ops(); + + if (size < 3) { + if (penOps->symbol.fillGC) { + for (Point2d *pp = symbolPts, *endp = pp + nSymbolPts; pp < endp; pp++) + XDrawLine(graphPtr_->display_, drawable, penOps->symbol.fillGC, + (int)pp->x, (int)pp->y, (int)pp->x+1, (int)pp->y+1); + } + return; + } + + int r1 = (int)ceil(size * 0.5); + int r2 = (int)ceil(size * S_RATIO * 0.5); + + switch (penOps->symbol.type) { + case SYMBOL_NONE: + break; + case SYMBOL_SQUARE: + drawSquare(graphPtr_->display_, drawable, penPtr, nSymbolPts,symbolPts,r2); + break; + case SYMBOL_CIRCLE: + drawCircle(graphPtr_->display_, drawable, penPtr, nSymbolPts,symbolPts,r1); + break; + case SYMBOL_SPLUS: + case SYMBOL_SCROSS: + drawSCross(graphPtr_->display_, drawable, penPtr, nSymbolPts,symbolPts,r2); + break; + case SYMBOL_PLUS: + case SYMBOL_CROSS: + drawCross(graphPtr_->display_, drawable, penPtr, nSymbolPts,symbolPts,r2); + break; + case SYMBOL_DIAMOND: + drawDiamond(graphPtr_->display_, drawable, penPtr, nSymbolPts,symbolPts,r1); + break; + case SYMBOL_TRIANGLE: + case SYMBOL_ARROW: + drawArrow(graphPtr_->display_, drawable, penPtr, nSymbolPts,symbolPts,size); + break; + } +} + +void LineElement::drawTraces(Drawable drawable, LinePen* penPtr) +{ + for (ChainLink* link = Chain_FirstLink(traces_); link; + link = Chain_NextLink(link)) { + bltTrace* tracePtr = (bltTrace*)Chain_GetValue(link); + + int count = tracePtr->screenPts.length; + XPoint* points = new XPoint[count]; + XPoint*xpp = points; + for (int ii=0; iix = (short)tracePtr->screenPts.points[ii].x; + xpp->y = (short)tracePtr->screenPts.points[ii].y; + } + XDrawLines(graphPtr_->display_, drawable, penPtr->traceGC_, points, + count, CoordModeOrigin); + delete [] points; + } +} + +void LineElement::drawValues(Drawable drawable, LinePen* penPtr, + int length, Point2d *points, int *map) +{ + LineElementOptions* ops = (LineElementOptions*)ops_; + LinePenOptions* pops = (LinePenOptions*)penPtr->ops(); + + char string[TCL_DOUBLE_SPACE * 2 + 2]; + const char* fmt = pops->valueFormat; + if (fmt == NULL) + fmt = "%g"; + TextStyle ts(graphPtr_, &pops->valueStyle); + + double* xval = ops->coords.x->values_; + double* yval = ops->coords.y->values_; + int count = 0; + + for (Point2d *pp = points, *endp = points + length; pp < endp; pp++) { + double x = xval[map[count]]; + double y = yval[map[count]]; + count++; + if (pops->valueShow == SHOW_X) + snprintf(string, TCL_DOUBLE_SPACE, fmt, x); + else if (pops->valueShow == SHOW_Y) + snprintf(string, TCL_DOUBLE_SPACE, fmt, y); + else if (pops->valueShow == SHOW_BOTH) { + snprintf(string, TCL_DOUBLE_SPACE, fmt, x); + strcat(string, ","); + snprintf(string + strlen(string), TCL_DOUBLE_SPACE, fmt, y); + } + + ts.drawText(drawable, string, pp->x, pp->y); + } +} + +void LineElement::printSymbols(PSOutput* psPtr, LinePen* penPtr, int size, + int nSymbolPts, Point2d *symbolPts) +{ + LinePenOptions* pops = (LinePenOptions*)penPtr->ops(); + + double symbolSize; + + // Set line and foreground attributes + XColor* fillColor = pops->symbol.fillColor; + if (!fillColor) + fillColor = pops->traceColor; + + XColor* outlineColor = pops->symbol.outlineColor; + if (!outlineColor) + outlineColor = pops->traceColor; + + if (pops->symbol.type == SYMBOL_NONE) + psPtr->setLineAttributes(pops->traceColor, pops->traceWidth + 2, + &pops->traceDashes, CapButt, JoinMiter); + else { + psPtr->setLineWidth(pops->symbol.outlineWidth); + psPtr->setDashes(NULL); + } + + // build DrawSymbolProc + psPtr->append("\n/DrawSymbolProc {\n"); + switch (pops->symbol.type) { + case SYMBOL_NONE: + break; + default: + psPtr->append(" "); + psPtr->setBackground(fillColor); + psPtr->append(" gsave fill grestore\n"); + + if (pops->symbol.outlineWidth > 0) { + psPtr->append(" "); + psPtr->setForeground(outlineColor); + psPtr->append(" stroke\n"); + } + break; + } + psPtr->append("} def\n\n"); + + // set size + symbolSize = (double)size; + switch (pops->symbol.type) { + case SYMBOL_SQUARE: + case SYMBOL_CROSS: + case SYMBOL_PLUS: + case SYMBOL_SCROSS: + case SYMBOL_SPLUS: + symbolSize = (double)size * S_RATIO; + break; + case SYMBOL_TRIANGLE: + case SYMBOL_ARROW: + symbolSize = (double)size * 0.7; + break; + case SYMBOL_DIAMOND: + symbolSize = (double)size * M_SQRT1_2; + break; + + default: + break; + } + + int count =0; + for (Point2d *pp=symbolPts, *endp=symbolPts + nSymbolPts; pp < endp; pp++) { + if (DRAW_SYMBOL()) { + psPtr->format("%g %g %g %s\n", pp->x, pp->y, symbolSize, + symbolMacros[pops->symbol.type]); + count++; + } + symbolCounter_++; + } +} + +void LineElement::setLineAttributes(PSOutput* psPtr, LinePen* penPtr) +{ + LinePenOptions* pops = (LinePenOptions*)penPtr->ops(); + + psPtr->setLineAttributes(pops->traceColor, pops->traceWidth, + &pops->traceDashes, CapButt, JoinMiter); + + if ((LineIsDashed(pops->traceDashes)) && + (pops->traceOffColor)) { + psPtr->append("/DashesProc {\n gsave\n "); + psPtr->setBackground(pops->traceOffColor); + psPtr->append(" "); + psPtr->setDashes(NULL); + psPtr->append("stroke\n grestore\n} def\n"); + } else { + psPtr->append("/DashesProc {} def\n"); + } +} + +void LineElement::printTraces(PSOutput* psPtr, LinePen* penPtr) +{ + setLineAttributes(psPtr, penPtr); + for (ChainLink* link = Chain_FirstLink(traces_); link; + link = Chain_NextLink(link)) { + bltTrace *tracePtr = (bltTrace*)Chain_GetValue(link); + if (tracePtr->screenPts.length > 0) { + psPtr->append("% start trace\n"); + psPtr->printMaxPolyline(tracePtr->screenPts.points, + tracePtr->screenPts.length); + psPtr->append("% end trace\n"); + } + } +} + +void LineElement::printValues(PSOutput* psPtr, LinePen* penPtr, + int nSymbolPts, Point2d *symbolPts, + int *pointToData) +{ + LineElementOptions* ops = (LineElementOptions*)ops_; + LinePenOptions* pops = (LinePenOptions*)penPtr->ops(); + + const char* fmt = pops->valueFormat; + if (fmt == NULL) + fmt = "%g"; + TextStyle ts(graphPtr_, &pops->valueStyle); + + int count = 0; + for (Point2d *pp=symbolPts, *endp=symbolPts + nSymbolPts; pp < endp; pp++) { + double x = ops->coords.x->values_[pointToData[count]]; + double y = ops->coords.y->values_[pointToData[count]]; + count++; + + char string[TCL_DOUBLE_SPACE * 2 + 2]; + if (pops->valueShow == SHOW_X) + snprintf(string, TCL_DOUBLE_SPACE, fmt, x); + else if (pops->valueShow == SHOW_Y) + snprintf(string, TCL_DOUBLE_SPACE, fmt, y); + else if (pops->valueShow == SHOW_BOTH) { + snprintf(string, TCL_DOUBLE_SPACE, fmt, x); + strcat(string, ","); + snprintf(string + strlen(string), TCL_DOUBLE_SPACE, fmt, y); + } + + ts.printText(psPtr, string, pp->x, pp->y); + } +} + + diff --git a/generic/tkbltGrElemLine.h b/generic/tkbltGrElemLine.h new file mode 100644 index 0000000..f937615 --- /dev/null +++ b/generic/tkbltGrElemLine.h @@ -0,0 +1,184 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGrElemLine_h__ +#define __BltGrElemLine_h__ + +#include + +#include "tkbltGraph.h" +#include "tkbltGrElem.h" +#include "tkbltGrPenLine.h" + +namespace Blt { + + typedef struct { + Point2d *screenPts; + int nScreenPts; + int *styleMap; + int *map; + } MapInfo; + + typedef struct { + Point2d *points; + int length; + int *map; + } GraphPoints; + + typedef struct { + int start; + GraphPoints screenPts; + } bltTrace; + + typedef struct { + Weight weight; + LinePen* penPtr; + GraphPoints symbolPts; + GraphSegments xeb; + GraphSegments yeb; + int symbolSize; + int errorBarCapWidth; + } LineStyle; + + typedef struct { + Element* elemPtr; + const char* label; + char** tags; + Axis* xAxis; + Axis* yAxis; + ElemCoords coords; + ElemValues* w; + ElemValues* xError; + ElemValues* yError; + ElemValues* xHigh; + ElemValues* xLow; + ElemValues* yHigh; + ElemValues* yLow; + int hide; + int legendRelief; + Chain* stylePalette; + LinePen *builtinPenPtr; + LinePen *activePenPtr; + LinePen *normalPenPtr; + LinePenOptions builtinPen; + + // derived + Tk_3DBorder fillBg; + int reqMaxSymbols; + double rTolerance; + int scaleSymbols; + int reqSmooth; + int penDir; + } LineElementOptions; + + class LineElement : public Element { + public: + enum PenDirection {INCREASING, DECREASING, BOTH_DIRECTIONS}; + enum Smoothing {LINEAR, STEP, CUBIC, QUADRATIC, CATROM}; + + protected: + LinePen* builtinPenPtr; + Smoothing smooth_; + Point2d *fillPts_; + int nFillPts_; + GraphPoints symbolPts_; + GraphPoints activePts_; + GraphSegments xeb_; + GraphSegments yeb_; + int symbolInterval_; + int symbolCounter_; + Chain* traces_; + + void drawCircle(Display*, Drawable, LinePen*, int, Point2d*, int); + void drawSquare(Display*, Drawable, LinePen*, int, Point2d*, int); + void drawSCross(Display*, Drawable, LinePen*, int, Point2d*, int); + void drawCross(Display*, Drawable, LinePen*, int, Point2d*, int); + void drawDiamond(Display*, Drawable, LinePen*, int, Point2d*, int); + void drawArrow(Display*, Drawable, LinePen*, int, Point2d*, int); + + protected: + int scaleSymbol(int); + void getScreenPoints(MapInfo*); + void reducePoints(MapInfo*, double); + void generateSteps(MapInfo*); + void generateSpline(MapInfo*); + void generateParametricSpline(MapInfo*); + void mapSymbols(MapInfo*); + void mapActiveSymbols(); + void mergePens(LineStyle**); + int outCode(Region2d*, Point2d*); + int clipSegment(Region2d*, int, int, Point2d*, Point2d*); + void saveTrace(int, int, MapInfo*); + void freeTraces(); + void mapTraces(MapInfo*); + void mapFillArea(MapInfo*); + void mapErrorBars(LineStyle**); + void reset(); + int closestTrace(); + void closestPoint(ClosestSearch*); + void drawSymbols(Drawable, LinePen*, int, int, Point2d*); + void drawTraces(Drawable, LinePen*); + void drawValues(Drawable, LinePen*, int, Point2d*, int*); + void setLineAttributes(PSOutput*, LinePen*); + void printTraces(PSOutput*, LinePen*); + void printValues(PSOutput*, LinePen*, int, Point2d*, int*); + void printSymbols(PSOutput*, LinePen*, int, int, Point2d*); + double distanceToLine(int, int, Point2d*, Point2d*, Point2d*); + double distanceToX(int, int, Point2d*, Point2d*, Point2d*); + double distanceToY(int, int, Point2d*, Point2d*, Point2d*); + int simplify(Point2d*, int, int, double, int*); + double findSplit(Point2d*, int, int, int*); + + int naturalSpline(Point2d*, int, Point2d*, int); + int quadraticSpline(Point2d*, int, Point2d*, int); + int naturalParametricSpline(Point2d*, int, Region2d*, int, Point2d*, int); + int catromParametricSpline(Point2d*, int, Point2d*, int); + + public: + LineElement(Graph*, const char*, Tcl_HashEntry*); + virtual ~LineElement(); + + ClassId classId() {return CID_ELEM_LINE;} + const char* className() {return "LineElement";} + const char* typeName() {return "line";} + + int configure(); + void map(); + void extents(Region2d*); + void closest(); + void draw(Drawable); + void drawActive(Drawable); + void drawSymbol(Drawable, int, int, int); + void print(PSOutput*); + void printActive(PSOutput*); + void printSymbol(PSOutput*, double, double, int); + }; +}; + +#endif diff --git a/generic/tkbltGrElemLineSpline.C b/generic/tkbltGrElemLineSpline.C new file mode 100644 index 0000000..9224d53 --- /dev/null +++ b/generic/tkbltGrElemLineSpline.C @@ -0,0 +1,1086 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 2009 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include +#include +#include + +#include + +#include "tkbltGrElemLine.h" + +using namespace Blt; + +typedef double TriDiagonalMatrix[3]; +typedef struct { + double b, c, d; +} Cubic2D; + +typedef struct { + double b, c, d, e, f; +} Quint2D; + +// Quadratic spline parameters +#define E1 param[0] +#define E2 param[1] +#define V1 param[2] +#define V2 param[3] +#define W1 param[4] +#define W2 param[5] +#define Z1 param[6] +#define Z2 param[7] +#define Y1 param[8] +#define Y2 param[9] + +/* + *--------------------------------------------------------------------------- + * + * Search -- + * + * Conducts a binary search for a value. This routine is called + * only if key is between x(0) and x(len - 1). + * + * Results: + * Returns the index of the largest value in xtab for which + * x[i] < key. + * + *--------------------------------------------------------------------------- + */ +static int Search(Point2d points[], int nPoints, double key, int *foundPtr) +{ + int low = 0; + int high = nPoints - 1; + + while (high >= low) { + int mid = (high + low) / 2; + if (key > points[mid].x) + low = mid + 1; + else if (key < points[mid].x) + high = mid - 1; + else { + *foundPtr = 1; + return mid; + } + } + *foundPtr = 0; + return low; +} + +/* + *--------------------------------------------------------------------------- + * + * QuadChoose -- + * + * Determines the case needed for the computation of the parame- + * ters of the quadratic spline. + * + * Results: + * Returns a case number (1-4) which controls how the parameters + * of the quadratic spline are evaluated. + * + *--------------------------------------------------------------------------- + */ +static int QuadChoose(Point2d* p, Point2d* q, double m1, double m2, + double epsilon) +{ + // Calculate the slope of the line joining P and Q + double slope = (q->y - p->y) / (q->x - p->x); + + if (slope != 0.0) { + double prod1 = slope * m1; + double prod2 = slope * m2; + + // Find the absolute values of the slopes slope, m1, and m2 + double mref = fabs(slope); + double mref1 = fabs(m1); + double mref2 = fabs(m2); + + // If the relative deviation of m1 or m2 from slope is less than + // epsilon, then choose case 2 or case 3. + double relerr = epsilon * mref; + if ((fabs(slope - m1) > relerr) && (fabs(slope - m2) > relerr) && + (prod1 >= 0.0) && (prod2 >= 0.0)) { + double prod = (mref - mref1) * (mref - mref2); + if (prod < 0.0) { + // l1, the line through (x1,y1) with slope m1, and l2, + // the line through (x2,y2) with slope m2, intersect + // at a point whose abscissa is between x1 and x2. + // The abscissa becomes a knot of the spline. + return 1; + } + if (mref1 > (mref * 2.0)) { + if (mref2 <= ((2.0 - epsilon) * mref)) + return 3; + } + else if (mref2 <= (mref * 2.0)) { + // Both l1 and l2 cross the line through + // (x1+x2)/2.0,y1 and (x1+x2)/2.0,y2, which is the + // midline of the rectangle formed by P and Q or both + // m1 and m2 have signs different than the sign of + // slope, or one of m1 and m2 has opposite sign from + // slope and l1 and l2 intersect to the left of x1 or + // to the right of x2. The point (x1+x2)/2. is a knot + // of the spline. + return 2; + } + else if (mref1 <= ((2.0 - epsilon) * mref)) { + // In cases 3 and 4, sign(m1)=sign(m2)=sign(slope). + // Either l1 or l2 crosses the midline, but not both. + // Choose case 4 if mref1 is greater than + // (2.-epsilon)*mref; otherwise, choose case 3. + return 3; + } + // If neither l1 nor l2 crosses the midline, the spline + // requires two knots between x1 and x2. + return 4; + } + else { + // The sign of at least one of the slopes m1 or m2 does not + // agree with the sign of *slope*. + if ((prod1 < 0.0) && (prod2 < 0.0)) { + return 2; + } + else if (prod1 < 0.0) { + if (mref2 > ((epsilon + 1.0) * mref)) + return 1; + else + return 2; + } + else if (mref1 > ((epsilon + 1.0) * mref)) + return 1; + else + return 2; + } + } + else if ((m1 * m2) >= 0.0) + return 2; + else + return 1; +} + +/* + *--------------------------------------------------------------------------- + * Computes the knots and other parameters of the spline on the + * interval PQ. + * On input-- + * P and Q are the coordinates of the points of interpolation. + * m1 is the slope at P. + * m2 is the slope at Q. + * ncase controls the number and location of the knots. + * On output-- + * + * (v1,v2),(w1,w2),(z1,z2), and (e1,e2) are the coordinates of + * the knots and other parameters of the spline on P. + * (e1,e2) and Q are used only if ncase=4. + *--------------------------------------------------------------------------- + */ +static void QuadCases(Point2d* p, Point2d* q, double m1, double m2, + double param[], int which) +{ + if ((which == 3) || (which == 4)) { + double c1 = p->x + (q->y - p->y) / m1; + double d1 = q->x + (p->y - q->y) / m2; + double h1 = c1 * 2.0 - p->x; + double j1 = d1 * 2.0 - q->x; + double mbar1 = (q->y - p->y) / (h1 - p->x); + double mbar2 = (p->y - q->y) / (j1 - q->x); + + if (which == 4) { + // Case 4 + Y1 = (p->x + c1) / 2.0; + V1 = (p->x + Y1) / 2.0; + V2 = m1 * (V1 - p->x) + p->y; + Z1 = (d1 + q->x) / 2.0; + W1 = (q->x + Z1) / 2.0; + W2 = m2 * (W1 - q->x) + q->y; + double mbar3 = (W2 - V2) / (W1 - V1); + Y2 = mbar3 * (Y1 - V1) + V2; + Z2 = mbar3 * (Z1 - V1) + V2; + E1 = (Y1 + Z1) / 2.0; + E2 = mbar3 * (E1 - V1) + V2; + } + else { + // Case 3 + double k1 = (p->y - q->y + q->x * mbar2 - p->x * mbar1) / (mbar2 - mbar1); + if (fabs(m1) > fabs(m2)) { + Z1 = (k1 + p->x) / 2.0; + } else { + Z1 = (k1 + q->x) / 2.0; + } + V1 = (p->x + Z1) / 2.0; + V2 = p->y + m1 * (V1 - p->x); + W1 = (q->x + Z1) / 2.0; + W2 = q->y + m2 * (W1 - q->x); + Z2 = V2 + (W2 - V2) / (W1 - V1) * (Z1 - V1); + } + } + else if (which == 2) { + // Case 2 + Z1 = (p->x + q->x) / 2.0; + V1 = (p->x + Z1) / 2.0; + V2 = p->y + m1 * (V1 - p->x); + W1 = (Z1 + q->x) / 2.0; + W2 = q->y + m2 * (W1 - q->x); + Z2 = (V2 + W2) / 2.0; + } + else { + // Case 1 + Z1 = (p->y - q->y + m2 * q->x - m1 * p->x) / (m2 - m1); + double ztwo = p->y + m1 * (Z1 - p->x); + V1 = (p->x + Z1) / 2.0; + V2 = (p->y + ztwo) / 2.0; + W1 = (Z1 + q->x) / 2.0; + W2 = (ztwo + q->y) / 2.0; + Z2 = V2 + (W2 - V2) / (W1 - V1) * (Z1 - V1); + } +} + +static int QuadSelect(Point2d* p, Point2d* q, double m1, double m2, + double epsilon, double param[]) +{ + int ncase = QuadChoose(p, q, m1, m2, epsilon); + QuadCases(p, q, m1, m2, param, ncase); + return ncase; +} + +static double QuadGetImage(double p1, double p2, double p3, double x1, + double x2, double x3) +{ + double A = x1 - x2; + double B = x2 - x3; + double C = x1 - x3; + + double y = (p1 * (A * A) + p2 * 2.0 * B * A + p3 * (B * B)) / (C * C); + return y; +} + +/* + *--------------------------------------------------------------------------- + * Finds the image of a point in x. + * On input + * x Contains the value at which the spline is evaluated. + * leftX, leftY + * Coordinates of the left-hand data point used in the + * evaluation of x values. + * rightX, rightY + * Coordinates of the right-hand data point used in the + * evaluation of x values. + * Z1, Z2, Y1, Y2, E2, W2, V2 + * Parameters of the spline. + * ncase Controls the evaluation of the spline by indicating + * whether one or two knots were placed in the interval + * (xtabs,xtabs1). + *--------------------------------------------------------------------------- + */ +static void QuadSpline(Point2d* intp, Point2d* left, Point2d* right, + double param[], int ncase) + +{ + double y; + + if (ncase == 4) { + // Case 4: More than one knot was placed in the interval. + // Determine the location of data point relative to the 1st knot. + if (Y1 > intp->x) + y = QuadGetImage(left->y, V2, Y2, Y1, intp->x, left->x); + else if (Y1 < intp->x) { + // Determine the location of the data point relative to the 2nd knot. + if (Z1 > intp->x) + y = QuadGetImage(Y2, E2, Z2, Z1, intp->x, Y1); + else if (Z1 < intp->x) + y = QuadGetImage(Z2, W2, right->y, right->x, intp->x, Z1); + else + y = Z2; + } + else + y = Y2; + } + else { + // Cases 1, 2, or 3: + // Determine the location of the data point relative to the knot. + if (Z1 < intp->x) + y = QuadGetImage(Z2, W2, right->y, right->x, intp->x, Z1); + else if (Z1 > intp->x) + y = QuadGetImage(left->y, V2, Z2, Z1, intp->x, left->x); + else + y = Z2; + } + + intp->y = y; +} + +/* + *--------------------------------------------------------------------------- + * Calculates the derivative at each of the data points. The + * slopes computed will insure that an osculatory quadratic + * spline will have one additional knot between two adjacent + * points of interpolation. Convexity and monotonicity are + * preserved wherever these conditions are compatible with the + * data. + *--------------------------------------------------------------------------- + */ +static void QuadSlopes(Point2d *points, double *m, int nPoints) +{ + double m1s =0; + double m2s =0; + double m1 =0; + double m2 =0; + int i, n, l; + for (l = 0, i = 1, n = 2; i < (nPoints - 1); l++, i++, n++) { + // Calculate the slopes of the two lines joining three + // consecutive data points. + double ydif1 = points[i].y - points[l].y; + double ydif2 = points[n].y - points[i].y; + m1 = ydif1 / (points[i].x - points[l].x); + m2 = ydif2 / (points[n].x - points[i].x); + if (i == 1) { + // Save slopes of starting point + m1s = m1; + m2s = m2; + } + // If one of the preceding slopes is zero or if they have opposite + // sign, assign the value zero to the derivative at the middle point. + if ((m1 == 0.0) || (m2 == 0.0) || ((m1 * m2) <= 0.0)) + m[i] = 0.0; + else if (fabs(m1) > fabs(m2)) { + // Calculate the slope by extending the line with slope m1. + double xbar = ydif2 / m1 + points[i].x; + double xhat = (xbar + points[n].x) / 2.0; + m[i] = ydif2 / (xhat - points[i].x); + } + else { + // Calculate the slope by extending the line with slope m2. + double xbar = -ydif1 / m2 + points[i].x; + double xhat = (points[l].x + xbar) / 2.0; + m[i] = ydif1 / (points[i].x - xhat); + } + } + + // Calculate the slope at the last point, x(n). + i = nPoints - 2; + n = nPoints - 1; + if ((m1 * m2) < 0.0) + m[n] = m2 * 2.0; + else { + double xmid = (points[i].x + points[n].x) / 2.0; + double yxmid = m[i] * (xmid - points[i].x) + points[i].y; + m[n] = (points[n].y - yxmid) / (points[n].x - xmid); + if ((m[n] * m2) < 0.0) + m[n] = 0.0; + } + + // Calculate the slope at the first point, x(0). + if ((m1s * m2s) < 0.0) + m[0] = m1s * 2.0; + else { + double xmid = (points[0].x + points[1].x) / 2.0; + double yxmid = m[1] * (xmid - points[1].x) + points[1].y; + m[0] = (yxmid - points[0].y) / (xmid - points[0].x); + if ((m[0] * m1s) < 0.0) + m[0] = 0.0; + } +} + +/* + *--------------------------------------------------------------------------- + * + * QuadEval -- + * + * QuadEval controls the evaluation of an osculatory quadratic + * spline. The user may provide his own slopes at the points of + * interpolation or use the subroutine 'QuadSlopes' to calculate + * slopes which are consistent with the shape of the data. + * + * ON INPUT-- + * intpPts must be a nondecreasing vector of points at which the + * spline will be evaluated. + * origPts contains the abscissas of the data points to be + * interpolated. xtab must be increasing. + * y contains the ordinates of the data points to be + * interpolated. + * m contains the slope of the spline at each point of + * interpolation. + * nPoints number of data points (dimension of xtab and y). + * numEval is the number of points of evaluation (dimension of + * xval and yval). + * epsilon is a relative error tolerance used in subroutine + * 'QuadChoose' to distinguish the situation m(i) or + * m(i+1) is relatively close to the slope or twice + * the slope of the linear segment between xtab(i) and + * xtab(i+1). If this situation occurs, roundoff may + * cause a change in convexity or monotonicity of the + * resulting spline and a change in the case number + * provided by 'QuadChoose'. If epsilon is not equal to zero, + * then epsilon should be greater than or equal to machine + * epsilon. + * ON OUTPUT-- + * yval contains the images of the points in xval. + * err is one of the following error codes: + * 0 - QuadEval ran normally. + * 1 - xval(i) is less than xtab(1) for at least one + * i or xval(i) is greater than xtab(num) for at + * least one i. QuadEval will extrapolate to provide + * function values for these abscissas. + * 2 - xval(i+1) < xval(i) for some i. + * + * + * QuadEval calls the following subroutines or functions: + * Search + * QuadCases + * QuadChoose + * QuadSpline + *--------------------------------------------------------------------------- + */ +static int QuadEval(Point2d origPts[], int nOrigPts, Point2d intpPts[], + int nIntpPts, double *m, double epsilon) +{ + double param[10]; + + // Initialize indices and set error result + int error = 0; + int l = nOrigPts - 1; + int p = l - 1; + int ncase = 1; + + // Determine if abscissas of new vector are non-decreasing. + for (int jj=1; jj= origPts[0].x) + break; + } + // Determine if any of the points in xval are GREATER than the + // abscissa of the l data point. + int end; + for (end = nIntpPts - 1; end >= 0; end--) { + if (intpPts[end].x <= origPts[l].x) + break; + } + + if (start > 0) { + // Set error value to indicate that extrapolation has occurred + error = 1; + + // Calculate the images of points of evaluation whose abscissas + // are less than the abscissa of the first data point. + ncase = QuadSelect(origPts, origPts + 1, m[0], m[1], epsilon, param); + for (int jj=0; jj<(start - 1); jj++) + QuadSpline(intpPts + jj, origPts, origPts + 1, param, ncase); + if (nIntpPts == 1) + return error; + } + int ii; + int nn; + if ((nIntpPts == 1) && (end != (nIntpPts - 1))) + goto noExtrapolation; + + // Search locates the interval in which the first in-range + // point of evaluation lies. + int found; + ii = Search(origPts, nOrigPts, intpPts[start].x, &found); + + nn = ii + 1; + if (nn >= nOrigPts) { + nn = nOrigPts - 1; + ii = nOrigPts - 2; + } + /* + * If the first in-range point of evaluation is equal to one + * of the data points, assign the appropriate value from y. + * Continue until a point of evaluation is found which is not + * equal to a data point. + */ + if (found) { + do { + intpPts[start].y = origPts[ii].y; + start++; + if (start >= nIntpPts) { + return error; + } + } while (intpPts[start - 1].x == intpPts[start].x); + + for (;;) { + if (intpPts[start].x < origPts[nn].x) { + break; /* Break out of for-loop */ + } + if (intpPts[start].x == origPts[nn].x) { + do { + intpPts[start].y = origPts[nn].y; + start++; + if (start >= nIntpPts) { + return error; + } + } while (intpPts[start].x == intpPts[start - 1].x); + } + ii++; + nn++; + } + } + /* + * Calculate the images of all the points which lie within + * range of the data. + */ + if ((ii > 0) || (error != 1)) + ncase = QuadSelect(origPts+ii, origPts+nn, m[ii], m[nn], epsilon, param); + + for (int jj=start; jj<=end; jj++) { + // If xx(j) - x(n) is negative, do not recalculate + // the parameters for this section of the spline since + // they are already known. + if (intpPts[jj].x == origPts[nn].x) { + intpPts[jj].y = origPts[nn].y; + continue; + } + else if (intpPts[jj].x > origPts[nn].x) { + double delta; + + // Determine that the routine is in the correct part of the spline + do { + ii++; + nn++; + delta = intpPts[jj].x - origPts[nn].x; + } while (delta > 0.0); + + if (delta < 0.0) + ncase = QuadSelect(origPts+ii, origPts+nn, m[ii], m[nn], + epsilon, param); + else if (delta == 0.0) { + intpPts[jj].y = origPts[nn].y; + continue; + } + } + QuadSpline(intpPts+jj, origPts+ii, origPts+nn, param, ncase); + } + + if (end == (nIntpPts - 1)) + return error; + + if ((nn == l) && (intpPts[end].x != origPts[l].x)) + goto noExtrapolation; + + // Set error value to indicate that extrapolation has occurred + error = 1; + ncase = QuadSelect(origPts + p, origPts + l, m[p], m[l], epsilon, param); + + noExtrapolation: + // Calculate the images of the points of evaluation whose + // abscissas are greater than the abscissa of the last data point. + for (int jj=(end + 1); jj 1) { + return 0; + } + return 1; +} + +/* + *--------------------------------------------------------------------------- + * Reference: + * Numerical Analysis, R. Burden, J. Faires and A. Reynolds. + * Prindle, Weber & Schmidt 1981 pp 112 + *--------------------------------------------------------------------------- + */ +int LineElement::naturalSpline(Point2d *origPts, int nOrigPts, + Point2d *intpPts, int nIntpPts) +{ + Point2d *ip, *iend; + double x, dy, alpha; + int isKnot; + int i, j, n; + + double* dx = new double[nOrigPts]; + /* Calculate vector of differences */ + for (i = 0, j = 1; j < nOrigPts; i++, j++) { + dx[i] = origPts[j].x - origPts[i].x; + if (dx[i] < 0.0) { + return 0; + } + } + n = nOrigPts - 1; /* Number of intervals. */ + TriDiagonalMatrix* A = new TriDiagonalMatrix[nOrigPts]; + if (!A) { + delete [] dx; + return 0; + } + /* Vectors to solve the tridiagonal matrix */ + A[0][0] = A[n][0] = 1.0; + A[0][1] = A[n][1] = 0.0; + A[0][2] = A[n][2] = 0.0; + + /* Calculate the intermediate results */ + for (i = 0, j = 1; j < n; j++, i++) { + alpha = 3.0 * ((origPts[j + 1].y / dx[j]) - (origPts[j].y / dx[i]) - + (origPts[j].y / dx[j]) + (origPts[i].y / dx[i])); + A[j][0] = 2 * (dx[j] + dx[i]) - dx[i] * A[i][1]; + A[j][1] = dx[j] / A[j][0]; + A[j][2] = (alpha - dx[i] * A[i][2]) / A[j][0]; + } + + Cubic2D* eq = new Cubic2D[nOrigPts]; + if (!eq) { + delete [] A; + delete [] dx; + return 0; + } + eq[0].c = eq[n].c = 0.0; + for (j = n, i = n - 1; i >= 0; i--, j--) { + eq[i].c = A[i][2] - A[i][1] * eq[j].c; + dy = origPts[i+1].y - origPts[i].y; + eq[i].b = (dy) / dx[i] - dx[i] * (eq[j].c + 2.0 * eq[i].c) / 3.0; + eq[i].d = (eq[j].c - eq[i].c) / (3.0 * dx[i]); + } + delete [] A; + delete [] dx; + + /* Now calculate the new values */ + for (ip = intpPts, iend = ip + nIntpPts; ip < iend; ip++) { + ip->y = 0.0; + x = ip->x; + + /* Is it outside the interval? */ + if ((x < origPts[0].x) || (x > origPts[n].x)) { + continue; + } + /* Search for the interval containing x in the point array */ + i = Search(origPts, nOrigPts, x, &isKnot); + if (isKnot) { + ip->y = origPts[i].y; + } else { + i--; + x -= origPts[i].x; + ip->y = origPts[i].y + x * (eq[i].b + x * (eq[i].c + x * eq[i].d)); + } + } + delete [] eq; + return 1; +} + +typedef struct { + double t; /* Arc length of interval. */ + double x; /* 2nd derivative of X with respect to T */ + double y; /* 2nd derivative of Y with respect to T */ +} CubicSpline; + +/* + * The following two procedures solve the special linear system which arise + * in cubic spline interpolation. If x is assumed cyclic ( x[i]=x[n+i] ) the + * equations can be written as (i=0,1,...,n-1): + * m[i][0] * x[i-1] + m[i][1] * x[i] + m[i][2] * x[i+1] = b[i] . + * In matrix notation one gets A * x = b, where the matrix A is tridiagonal + * with additional elements in the upper right and lower left position: + * A[i][0] = A_{i,i-1} for i=1,2,...,n-1 and m[0][0] = A_{0,n-1} , + * A[i][1] = A_{i, i } for i=0,1,...,n-1 + * A[i][2] = A_{i,i+1} for i=0,1,...,n-2 and m[n-1][2] = A_{n-1,0}. + * A should be symmetric (A[i+1][0] == A[i][2]) and positive definite. + * The size of the system is given in n (n>=1). + * + * In the first procedure the Cholesky decomposition A = C^T * D * C + * (C is upper triangle with unit diagonal, D is diagonal) is calculated. + * Return TRUE if decomposition exist. + */ +static int SolveCubic1(TriDiagonalMatrix A[], int n) +{ + int i; + double m_ij, m_n, m_nn, d; + + if (n < 1) { + return 0; /* Dimension should be at least 1 */ + } + d = A[0][1]; /* D_{0,0} = A_{0,0} */ + if (d <= 0.0) { + return 0; /* A (or D) should be positive definite */ + } + m_n = A[0][0]; /* A_{0,n-1} */ + m_nn = A[n - 1][1]; /* A_{n-1,n-1} */ + for (i = 0; i < n - 2; i++) { + m_ij = A[i][2]; /* A_{i,1} */ + A[i][2] = m_ij / d; /* C_{i,i+1} */ + A[i][0] = m_n / d; /* C_{i,n-1} */ + m_nn -= A[i][0] * m_n; /* to get C_{n-1,n-1} */ + m_n = -A[i][2] * m_n; /* to get C_{i+1,n-1} */ + d = A[i + 1][1] - A[i][2] * m_ij; /* D_{i+1,i+1} */ + if (d <= 0.0) { + return 0; /* Elements of D should be positive */ + } + A[i + 1][1] = d; + } + if (n >= 2) { /* Complete last column */ + m_n += A[n - 2][2]; /* add A_{n-2,n-1} */ + A[n - 2][0] = m_n / d; /* C_{n-2,n-1} */ + A[n - 1][1] = d = m_nn - A[n - 2][0] * m_n; /* D_{n-1,n-1} */ + if (d <= 0.0) { + return 0; + } + } + return 1; +} + +/* + * The second procedure solves the linear system, with the Cholesky + * decomposition calculated above (in m[][]) and the right side b given + * in x[]. The solution x overwrites the right side in x[]. + */ +static void SolveCubic2(TriDiagonalMatrix A[], CubicSpline spline[], + int nIntervals) +{ + int n = nIntervals - 2; + int m = nIntervals - 1; + + // Division by transpose of C : b = C^{-T} * b + double x = spline[m].x; + double y = spline[m].y; + for (int ii=0; ii= 0) { + // C_{n-2,n-1} * x_{n-1} + spline[m].x = x - A[n][0] * spline[n].x; + spline[m].y = y - A[n][0] * spline[n].y; + } + // Division by D: b = D^{-1} * b + for (int ii=0; ii= 0) { + // C_{n-2,n-1} * x_{n-1} + spline[n].x -= A[n][0] * x; + spline[n].y -= A[n][0] * y; + } + for (int ii=(n - 1); ii>=0; ii--) { + // C_{i,i+1} * x_{i+1} + C_{i,n-1} * x_{n-1} + spline[ii].x -= A[ii][2] * spline[ii + 1].x + A[ii][0] * x; + spline[ii].y -= A[ii][2] * spline[ii + 1].y + A[ii][0] * y; + } +} + +/* + * Find second derivatives (x''(t_i),y''(t_i)) of cubic spline interpolation + * through list of points (x_i,y_i). The parameter t is calculated as the + * length of the linear stroke. The number of points must be at least 3. + * Note: For CLOSED_CONTOURs the first and last point must be equal. + */ +static CubicSpline* CubicSlopes(Point2d points[], int nPoints, + int isClosed, double unitX, double unitY) +{ + CubicSpline *s1, *s2; + int n, i; + double norm, dx, dy; + + CubicSpline* spline = new CubicSpline[nPoints]; + if (!spline) + return NULL; + + TriDiagonalMatrix *A = new TriDiagonalMatrix[nPoints]; + if (!A) { + delete [] spline; + return NULL; + } + /* + * Calculate first differences in (dxdt2[i], y[i]) and interval lengths + * in dist[i]: + */ + s1 = spline; + for (i = 0; i < nPoints - 1; i++) { + s1->x = points[i+1].x - points[i].x; + s1->y = points[i+1].y - points[i].y; + + /* + * The Norm of a linear stroke is calculated in "normal coordinates" + * and used as interval length: + */ + dx = s1->x / unitX; + dy = s1->y / unitY; + s1->t = sqrt(dx * dx + dy * dy); + + s1->x /= s1->t; /* first difference, with unit norm: */ + s1->y /= s1->t; /* || (dxdt2[i], y[i]) || = 1 */ + s1++; + } + + /* + * Setup linear System: Ax = b + */ + n = nPoints - 2; /* Without first and last point */ + if (isClosed) { + /* First and last points must be equal for CLOSED_CONTOURs */ + spline[nPoints - 1].t = spline[0].t; + spline[nPoints - 1].x = spline[0].x; + spline[nPoints - 1].y = spline[0].y; + n++; /* Add last point (= first point) */ + } + s1 = spline, s2 = s1 + 1; + for (i = 0; i < n; i++) { + /* Matrix A, mainly tridiagonal with cyclic second index + ("j = j+n mod n") + */ + A[i][0] = s1->t; /* Off-diagonal element A_{i,i-1} */ + A[i][1] = 2.0 * (s1->t + s2->t); /* A_{i,i} */ + A[i][2] = s2->t; /* Off-diagonal element A_{i,i+1} */ + + /* Right side b_x and b_y */ + s1->x = (s2->x - s1->x) * 6.0; + s1->y = (s2->y - s1->y) * 6.0; + + /* + * If the linear stroke shows a cusp of more than 90 degree, + * the right side is reduced to avoid oscillations in the + * spline: + */ + /* + * The Norm of a linear stroke is calculated in "normal coordinates" + * and used as interval length: + */ + dx = s1->x / unitX; + dy = s1->y / unitY; + norm = sqrt(dx * dx + dy * dy) / 8.5; + if (norm > 1.0) { + /* The first derivative will not be continuous */ + s1->x /= norm; + s1->y /= norm; + } + s1++, s2++; + } + + if (!isClosed) { + /* Third derivative is set to zero at both ends */ + A[0][1] += A[0][0]; /* A_{0,0} */ + A[0][0] = 0.0; /* A_{0,n-1} */ + A[n-1][1] += A[n-1][2]; /* A_{n-1,n-1} */ + A[n-1][2] = 0.0; /* A_{n-1,0} */ + } + /* Solve linear systems for dxdt2[] and y[] */ + + if (SolveCubic1(A, n)) { /* Cholesky decomposition */ + SolveCubic2(A, spline, n); /* A * dxdt2 = b_x */ + } + else { /* Should not happen, but who knows ... */ + delete [] A; + delete [] spline; + return NULL; + } + /* Shift all second derivatives one place right and update the ends. */ + s2 = spline + n, s1 = s2 - 1; + for (/* empty */; s2 > spline; s2--, s1--) { + s2->x = s1->x; + s2->y = s1->y; + } + if (isClosed) { + spline[0].x = spline[n].x; + spline[0].y = spline[n].y; + } else { + /* Third derivative is 0.0 for the first and last interval. */ + spline[0].x = spline[1].x; + spline[0].y = spline[1].y; + spline[n + 1].x = spline[n].x; + spline[n + 1].y = spline[n].y; + } + delete [] A; + return spline; +} + +// Calculate interpolated values of the spline function (defined via p_cntr +// and the second derivatives dxdt2[] and dydt2[]). The number of tabulated +// values is n. On an equidistant grid n_intpol values are calculated. +static int CubicEval(Point2d *origPts, int nOrigPts, Point2d *intpPts, + int nIntpPts, CubicSpline *spline) +{ + double t, tSkip; + Point2d q; + int count; + + /* Sum the lengths of all the segments (intervals). */ + double tMax = 0.0; + for (int ii=0; iiright - extsPtr->left; + double unitY = extsPtr->bottom - extsPtr->top; + if (unitX < FLT_EPSILON) + unitX = FLT_EPSILON; + if (unitY < FLT_EPSILON) + unitY = FLT_EPSILON; + + /* Calculate parameters for cubic spline: + * t = arc length of interval. + * dxdt2 = second derivatives of x with respect to t, + * dydt2 = second derivatives of y with respect to t, + */ + CubicSpline* spline = CubicSlopes(origPts, nOrigPts, isClosed, unitX, unitY); + if (spline == NULL) + return 0; + + int result= CubicEval(origPts, nOrigPts, intpPts, nIntpPts, spline); + + delete [] spline; + return result; +} + +static void CatromCoeffs(Point2d* p, Point2d* a, Point2d* b, + Point2d* c, Point2d* d) +{ + a->x = -p[0].x + 3.0 * p[1].x - 3.0 * p[2].x + p[3].x; + b->x = 2.0 * p[0].x - 5.0 * p[1].x + 4.0 * p[2].x - p[3].x; + c->x = -p[0].x + p[2].x; + d->x = 2.0 * p[1].x; + a->y = -p[0].y + 3.0 * p[1].y - 3.0 * p[2].y + p[3].y; + b->y = 2.0 * p[0].y - 5.0 * p[1].y + 4.0 * p[2].y - p[3].y; + c->y = -p[0].y + p[2].y; + d->y = 2.0 * p[1].y; +} + +int LineElement::catromParametricSpline(Point2d* points, int nPoints, + Point2d* intpPts, int nIntpPts) +{ + // The spline is computed in screen coordinates instead of data points so + // that we can select the abscissas of the interpolated points from each + // pixel horizontally across the plotting area. + + Point2d* origPts = new Point2d[nPoints + 4]; + memcpy(origPts + 1, points, sizeof(Point2d) * nPoints); + + origPts[0] = origPts[1]; + origPts[nPoints + 2] = origPts[nPoints + 1] = origPts[nPoints]; + + for (int ii=0; ii + +#include "tkbltGrBind.h" +#include "tkbltGraph.h" +#include "tkbltGrAxis.h" +#include "tkbltGrElem.h" +#include "tkbltGrElemOp.h" +#include "tkbltGrElemBar.h" +#include "tkbltGrElemLine.h" +#include "tkbltGrLegd.h" + +using namespace Blt; + +static int GetIndex(Tcl_Interp* interp, Element* elemPtr, + Tcl_Obj *objPtr, int *indexPtr); +static Tcl_Obj *DisplayListObj(Graph* graphPtr); + +int Blt::ElementObjConfigure(Element* elemPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = elemPtr->graphPtr_; + Tk_SavedOptions savedOptions; + int mask =0; + int error; + Tcl_Obj* errorResult; + + for (error=0; error<=1; error++) { + if (!error) { + if (Tk_SetOptions(interp, (char*)elemPtr->ops(), elemPtr->optionTable(), + objc, objv, graphPtr->tkwin_, &savedOptions, &mask) + != TCL_OK) + continue; + } + else { + errorResult = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); + } + + if (elemPtr->configure() != TCL_OK) + return TCL_ERROR; + graphPtr->flags |= mask; + graphPtr->eventuallyRedraw(); + + break; + } + + if (!error) { + Tk_FreeSavedOptions(&savedOptions); + return TCL_OK; + } + else { + Tcl_SetObjResult(interp, errorResult); + Tcl_DecrRefCount(errorResult); + return TCL_ERROR; + } +} + +static int CgetOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc!=5) { + Tcl_WrongNumArgs(interp, 3, objv, "elemId option"); + return TCL_ERROR; + } + + Element* elemPtr; + if (graphPtr->getElement(objv[3], &elemPtr) != TCL_OK) + return TCL_ERROR; + + Tcl_Obj* objPtr = Tk_GetOptionValue(interp, + (char*)elemPtr->ops(), + elemPtr->optionTable(), + objv[4], graphPtr->tkwin_); + if (objPtr == NULL) + return TCL_ERROR; + else + Tcl_SetObjResult(interp, objPtr); + return TCL_OK; +} + +static int ConfigureOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc<4) { + Tcl_WrongNumArgs(interp, 3, objv, "elemId ?option value...?"); + return TCL_ERROR; + } + + Element* elemPtr; + if (graphPtr->getElement(objv[3], &elemPtr) != TCL_OK) + return TCL_ERROR; + + if (objc <= 5) { + Tcl_Obj* objPtr = Tk_GetOptionInfo(interp, (char*)elemPtr->ops(), + elemPtr->optionTable(), + (objc == 5) ? objv[4] : NULL, + graphPtr->tkwin_); + if (objPtr == NULL) + return TCL_ERROR; + else + Tcl_SetObjResult(interp, objPtr); + return TCL_OK; + } + else + return ElementObjConfigure(elemPtr, interp, objc-4, objv+4); +} + +static int ActivateOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + + if (objc<3) { + Tcl_WrongNumArgs(interp, 3, objv, "?elemId? ?index...?"); + return TCL_ERROR; + } + + // List all the currently active elements + if (objc == 3) { + Tcl_Obj *listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + + Tcl_HashSearch iter; + for (Tcl_HashEntry* hPtr = Tcl_FirstHashEntry(&graphPtr->elements_.table, &iter); hPtr; hPtr = Tcl_NextHashEntry(&iter)) { + Element* elemPtr = (Element*)Tcl_GetHashValue(hPtr); + if (elemPtr->active_) + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewStringObj(elemPtr->name_, -1)); + } + + Tcl_SetObjResult(interp, listObjPtr); + return TCL_OK; + } + + Element* elemPtr; + if (graphPtr->getElement(objv[3], &elemPtr) != TCL_OK) + return TCL_ERROR; + + int* indices = NULL; + int nIndices = -1; + if (objc > 4) { + nIndices = objc - 4; + indices = new int[nIndices]; + + int* activePtr = indices; + for (int ii=4; iiactiveIndices_; + elemPtr->activeIndices_ = indices; + elemPtr->nActiveIndices_ = nIndices; + + elemPtr->active_ = 1; + + graphPtr->flags |= RESET; + graphPtr->eventuallyRedraw(); + + return TCL_OK; +} + +static int BindOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc == 3) { + Tcl_Obj *listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + + Tcl_HashSearch iter; + for (Tcl_HashEntry* hPtr=Tcl_FirstHashEntry(&graphPtr->elements_.tagTable, &iter); hPtr; hPtr = Tcl_NextHashEntry(&iter)) { + char* tagName = + (char*)Tcl_GetHashKey(&graphPtr->elements_.tagTable, hPtr); + Tcl_ListObjAppendElement(interp, listObjPtr,Tcl_NewStringObj(tagName,-1)); + } + + Tcl_SetObjResult(interp, listObjPtr); + return TCL_OK; + } + + return graphPtr->bindTable_->configure(graphPtr->elementTag(Tcl_GetString(objv[3])), objc - 4, objv + 4); +} + +static int ClosestOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc<5) { + Tcl_WrongNumArgs(interp, 3, objv, "x y ?elemName?..."); + return TCL_ERROR; + } + + GraphOptions* gops = (GraphOptions*)graphPtr->ops_; + ClosestSearch* searchPtr = &gops->search; + + if (graphPtr->flags & RESET) + graphPtr->resetAxes(); + + int x; + if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK) { + Tcl_AppendResult(interp, ": bad window x-coordinate", NULL); + return TCL_ERROR; + } + int y; + if (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK) { + Tcl_AppendResult(interp, ": bad window y-coordinate", NULL); + return TCL_ERROR; + } + + searchPtr->x = x; + searchPtr->y = y; + searchPtr->index = -1; + searchPtr->dist = (double)(searchPtr->halo + 1); + + if (objc>5) { + for (int ii=5; iigetElement(objv[ii], &elemPtr) != TCL_OK) + return TCL_ERROR; + + ElementOptions* eops = (ElementOptions*)elemPtr->ops(); + if (!eops->hide) + elemPtr->closest(); + } + } + else { + // Find the closest point from the set of displayed elements, + // searching the display list from back to front. That way if + // the points from two different elements overlay each other + // exactly, the last one picked will be the topmost. + for (ChainLink* link = Chain_LastLink(graphPtr->elements_.displayList); + link; link = Chain_PrevLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + ElementOptions* eops = (ElementOptions*)elemPtr->ops(); + if (!eops->hide) + elemPtr->closest(); + } + } + + if (searchPtr->dist < (double)searchPtr->halo) { + Tcl_Obj* listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj("name", -1)); + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj(searchPtr->elemPtr->name_, -1)); + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj("index", -1)); + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewIntObj(searchPtr->index)); + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj("x", -1)); + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(searchPtr->point.x)); + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj("y", -1)); + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(searchPtr->point.y)); + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj("dist", -1)); + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(searchPtr->dist)); + Tcl_SetObjResult(interp, listObjPtr); + } + + return TCL_OK; +} + +static int CreateOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + + // may vary in length + // if (objc!=4) { + // Tcl_WrongNumArgs(interp, 3, objv, "elemId"); + // return TCL_ERROR; + // } + if (objc<4) { + Tcl_WrongNumArgs(interp, 3, objv, "elemId..."); + return TCL_ERROR; + } + + if (graphPtr->createElement(objc, objv) != TCL_OK) + return TCL_ERROR; + Tcl_SetObjResult(interp, objv[3]); + + graphPtr->flags |= RESET; + graphPtr->eventuallyRedraw(); + + return TCL_OK; +} + +static int DeactivateOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + if (objc<4) { + Tcl_WrongNumArgs(interp, 3, objv, "elemId..."); + return TCL_ERROR; + } + Graph* graphPtr = (Graph*)clientData; + for (int ii=3; iigetElement(objv[ii], &elemPtr) != TCL_OK) + return TCL_ERROR; + + delete [] elemPtr->activeIndices_; + elemPtr->activeIndices_ = NULL; + elemPtr->nActiveIndices_ = 0; + elemPtr->active_ = 0; + } + + graphPtr->flags |= RESET; + graphPtr->eventuallyRedraw(); + + return TCL_OK; +} + +static int DeleteOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + if (objc<4) { + Tcl_WrongNumArgs(interp, 3, objv, "elemId..."); + return TCL_ERROR; + } + Graph* graphPtr = (Graph*)clientData; + for (int ii=3; iigetElement(objv[ii], &elemPtr) != TCL_OK) + return TCL_ERROR; + graphPtr->legend_->removeElement(elemPtr); + delete elemPtr; + } + + graphPtr->flags |= RESET; + graphPtr->eventuallyRedraw(); + + return TCL_OK; +} + +static int ExistsOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + + if (objc!=4) { + Tcl_WrongNumArgs(interp, 3, objv, "elemId"); + return TCL_ERROR; + } + + Tcl_HashEntry *hPtr = + Tcl_FindHashEntry(&graphPtr->elements_.table, Tcl_GetString(objv[3])); + Tcl_SetBooleanObj(Tcl_GetObjResult(interp), (hPtr != NULL)); + return TCL_OK; +} + +static int LowerOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + + if (objc<4) { + Tcl_WrongNumArgs(interp, 3, objv, "elemId..."); + return TCL_ERROR; + } + + // Move the links of lowered elements out of the display list into + // a temporary list + Chain* chain = new Chain(); + + for (int ii=3; iigetElement(objv[ii], &elemPtr) != TCL_OK) + return TCL_ERROR; + + // look for duplicates + int ok=1; + for (ChainLink* link = Chain_FirstLink(chain); + link; link = Chain_NextLink(link)) { + Element* ptr = (Element*)Chain_GetValue(link); + if (ptr == elemPtr) { + ok=0; + break; + } + } + + if (ok && elemPtr->link) { + graphPtr->elements_.displayList->unlinkLink(elemPtr->link); + chain->linkAfter(elemPtr->link, NULL); + } + } + + // Append the links to end of the display list + ChainLink *next; + for (ChainLink *link = Chain_FirstLink(chain); link; link = next) { + next = Chain_NextLink(link); + chain->unlinkLink(link); + graphPtr->elements_.displayList->linkAfter(link, NULL); + } + delete chain; + + graphPtr->flags |= CACHE; + graphPtr->eventuallyRedraw(); + + Tcl_SetObjResult(interp, DisplayListObj(graphPtr)); + return TCL_OK; +} + +static int NamesOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + + if (objc<3) { + Tcl_WrongNumArgs(interp, 3, objv, "?pattern...?"); + return TCL_ERROR; + } + + Tcl_Obj *listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + if (objc == 3) { + Tcl_HashSearch iter; + for (Tcl_HashEntry *hPtr = Tcl_FirstHashEntry(&graphPtr->elements_.table, &iter); hPtr != NULL; hPtr = Tcl_NextHashEntry(&iter)) { + Element* elemPtr = (Element*)Tcl_GetHashValue(hPtr); + Tcl_Obj *objPtr = Tcl_NewStringObj(elemPtr->name_, -1); + Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); + } + } + else { + Tcl_HashSearch iter; + for (Tcl_HashEntry *hPtr = Tcl_FirstHashEntry(&graphPtr->elements_.table, &iter); hPtr != NULL; hPtr = Tcl_NextHashEntry(&iter)) { + Element* elemPtr = (Element*)Tcl_GetHashValue(hPtr); + + for (int ii=3; iiname_,Tcl_GetString(objv[ii]))) { + Tcl_Obj *objPtr = Tcl_NewStringObj(elemPtr->name_, -1); + Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); + break; + } + } + } + } + + Tcl_SetObjResult(interp, listObjPtr); + return TCL_OK; +} + +static int RaiseOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + + if (objc<4) { + Tcl_WrongNumArgs(interp, 3, objv, "elemId..."); + return TCL_ERROR; + } + + Chain* chain = new Chain(); + for (int ii=3; iigetElement(objv[ii], &elemPtr) != TCL_OK) + return TCL_ERROR; + + // look for duplicates + int ok=1; + for (ChainLink* link = Chain_FirstLink(chain); + link; link = Chain_NextLink(link)) { + Element* ptr = (Element*)Chain_GetValue(link); + if (ptr == elemPtr) { + ok=0; + break; + } + } + + if (ok && elemPtr->link) { + graphPtr->elements_.displayList->unlinkLink(elemPtr->link); + chain->linkAfter(elemPtr->link, NULL); + } + } + + // Prepend the links to beginning of the display list in reverse order + ChainLink *prev; + for (ChainLink *link = Chain_LastLink(chain); link; link = prev) { + prev = Chain_PrevLink(link); + chain->unlinkLink(link); + graphPtr->elements_.displayList->linkBefore(link, NULL); + } + delete chain; + + graphPtr->flags |= CACHE; + graphPtr->eventuallyRedraw(); + + Tcl_SetObjResult(interp, DisplayListObj(graphPtr)); + return TCL_OK; +} + +static int ShowOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + // may vary in length + if (objc<3) { + // if (objc!=3 || objc!=4) { + Tcl_WrongNumArgs(interp, 3, objv, "?nameList?"); + return TCL_ERROR; + } + + if (objc == 3) { + Tcl_SetObjResult(interp, DisplayListObj(graphPtr)); + return TCL_OK; + } + + int elemObjc; + Tcl_Obj** elemObjv; + if (Tcl_ListObjGetElements(interp, objv[3], &elemObjc, &elemObjv) != TCL_OK) + return TCL_ERROR; + + // Collect the named elements into a list + Chain* chain = new Chain(); + for (int ii=0; iigetElement(elemObjv[ii], &elemPtr) != TCL_OK) { + delete chain; + return TCL_ERROR; + } + + // look for duplicates + int ok=1; + for (ChainLink* link = Chain_FirstLink(chain); + link; link = Chain_NextLink(link)) { + Element* ptr = (Element*)Chain_GetValue(link); + if (ptr == elemPtr) { + ok=0; + break; + } + } + + if (ok) + chain->append(elemPtr); + } + + // Clear the links from the currently displayed elements + for (ChainLink* link = Chain_FirstLink(graphPtr->elements_.displayList); + link; link = Chain_NextLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + elemPtr->link = NULL; + } + delete graphPtr->elements_.displayList; + graphPtr->elements_.displayList = chain; + + // Set links on all the displayed elements + for (ChainLink* link = Chain_FirstLink(chain); link; + link = Chain_NextLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + elemPtr->link = link; + } + + graphPtr->flags |= RESET; + graphPtr->eventuallyRedraw(); + + Tcl_SetObjResult(interp, DisplayListObj(graphPtr)); + return TCL_OK; +} + +static int TypeOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + + if (objc!=4) { + Tcl_WrongNumArgs(interp, 3, objv, "elemId"); + return TCL_ERROR; + } + + Element* elemPtr; + if (graphPtr->getElement(objv[3], &elemPtr) != TCL_OK) + return TCL_ERROR; + + Tcl_SetStringObj(Tcl_GetObjResult(interp), elemPtr->typeName(), -1); + return TCL_OK; +} + +const Ensemble Blt::elementEnsemble[] = { + {"activate", ActivateOp, 0}, + {"bind", BindOp, 0}, + {"cget", CgetOp, 0}, + {"closest", ClosestOp, 0}, + {"configure", ConfigureOp, 0}, + {"create", CreateOp, 0}, + {"deactivate", DeactivateOp, 0}, + {"delete", DeleteOp, 0}, + {"exists", ExistsOp, 0}, + {"lower", LowerOp, 0}, + {"names", NamesOp, 0}, + {"raise", RaiseOp, 0}, + {"show", ShowOp, 0}, + {"type", TypeOp, 0}, + { 0,0,0 } +}; + +// Support + +static Tcl_Obj *DisplayListObj(Graph* graphPtr) +{ + Tcl_Obj *listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + + for (ChainLink* link = Chain_FirstLink(graphPtr->elements_.displayList); + link; link = Chain_NextLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + Tcl_Obj *objPtr = Tcl_NewStringObj(elemPtr->name_, -1); + Tcl_ListObjAppendElement(graphPtr->interp_, listObjPtr, objPtr); + } + + return listObjPtr; +} + +static int GetIndex(Tcl_Interp* interp, Element* elemPtr, + Tcl_Obj *objPtr, int *indexPtr) +{ + ElementOptions* ops = (ElementOptions*)elemPtr->ops(); + + char *string = Tcl_GetString(objPtr); + if ((*string == 'e') && (strcmp("end", string) == 0)) + *indexPtr = NUMBEROFPOINTS(ops); + else if (Tcl_GetIntFromObj(interp, objPtr, indexPtr) != TCL_OK) + return TCL_ERROR; + + return TCL_OK; +} + + diff --git a/generic/tkbltGrElemOp.h b/generic/tkbltGrElemOp.h new file mode 100644 index 0000000..b596b11 --- /dev/null +++ b/generic/tkbltGrElemOp.h @@ -0,0 +1,41 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGrElemOp_h__ +#define __BltGrElemOp_h__ + +#include "tkbltGraph.h" + +namespace Blt { + extern const Ensemble elementEnsemble[]; + extern int ElementObjConfigure(Blt::Element* elemPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]); +}; + +#endif diff --git a/generic/tkbltGrElemOption.C b/generic/tkbltGrElemOption.C new file mode 100644 index 0000000..a0a67e6 --- /dev/null +++ b/generic/tkbltGrElemOption.C @@ -0,0 +1,396 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include + +#include "tkbltChain.h" + +#include "tkbltGraph.h" +#include "tkbltGrElem.h" +#include "tkbltGrElemOption.h" +#include "tkbltGrPen.h" +#include "tkbltConfig.h" + +using namespace Blt; + +#define SETRANGE(l) ((l).range = ((l).max > (l).min) ? ((l).max - (l).min) : DBL_EPSILON) +#define SETWEIGHT(l, lo, hi) ((l).min = (lo), (l).max = (hi), SETRANGE(l)) + +// Defs + +static int GetPenStyleFromObj(Tcl_Interp* interp, Graph* graphPtr, + Tcl_Obj *objPtr, ClassId classId, + PenStyle *stylePtr); +static int ParseValues(Tcl_Interp* interp, Tcl_Obj *objPtr, int *nValuesPtr, + double **arrayPtr); + +// OptionSpecs + +static Tk_CustomOptionSetProc ValuesSetProc; +static Tk_CustomOptionGetProc ValuesGetProc; +static Tk_CustomOptionFreeProc ValuesFreeProc; +Tk_ObjCustomOption valuesObjOption = + { + "values", ValuesSetProc, ValuesGetProc, RestoreProc, ValuesFreeProc, NULL + }; + +static int ValuesSetProc(ClientData clientData, Tcl_Interp* interp, + Tk_Window tkwin, Tcl_Obj** objPtr, char* widgRec, + int offset, char* savePtr, int flags) +{ + ElemValues** valuesPtrPtr = (ElemValues**)(widgRec + offset); + *(double*)savePtr = *(double*)valuesPtrPtr; + ElementOptions* ops = (ElementOptions*)widgRec; + Element* elemPtr = ops->elemPtr; + + if (!valuesPtrPtr) + return TCL_OK; + + Tcl_Obj** objv; + int objc; + if (Tcl_ListObjGetElements(interp, *objPtr, &objc, &objv) != TCL_OK) + return TCL_ERROR; + + if (objc == 0) { + *valuesPtrPtr = NULL; + return TCL_OK; + } + + const char *string = Tcl_GetString(objv[0]); + if (objc == 1) { + if (Blt_VectorExists2(interp, string)) { + ElemValuesVector* valuesPtr = new ElemValuesVector(elemPtr, string); + if (valuesPtr->getVector() != TCL_OK) { + delete valuesPtr; + return TCL_ERROR; + } + *valuesPtrPtr = valuesPtr; + } + else + return TCL_ERROR; + } + else { + double* values; + int nValues; + if (ParseValues(interp, *objPtr, &nValues, &values) != TCL_OK) + return TCL_ERROR; + ElemValuesSource* valuesPtr = new ElemValuesSource(nValues, values); + valuesPtr->findRange(); + *valuesPtrPtr = valuesPtr; + } + + return TCL_OK; +} + +static Tcl_Obj* ValuesGetProc(ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset) +{ + ElemValues* valuesPtr = *(ElemValues**)(widgRec + offset); + + if (!valuesPtr) + return Tcl_NewStringObj("", -1); + + int cnt = valuesPtr->nValues(); + if (!cnt) + return Tcl_NewListObj(0, (Tcl_Obj**)NULL); + + Tcl_Obj** ll = new Tcl_Obj*[cnt]; + for (int ii=0; iivalues_[ii]); + Tcl_Obj* listObjPtr = Tcl_NewListObj(cnt, ll); + delete [] ll; + + return listObjPtr; +} + +static void ValuesFreeProc(ClientData clientData, Tk_Window tkwin, char *ptr) +{ + ElemValues* valuesPtr = *(ElemValues**)ptr; + delete valuesPtr; +} + +static Tk_CustomOptionSetProc PairsSetProc; +static Tk_CustomOptionGetProc PairsGetProc; +static Tk_CustomOptionRestoreProc PairsRestoreProc; +static Tk_CustomOptionFreeProc PairsFreeProc; +Tk_ObjCustomOption pairsObjOption = + { + "pairs", PairsSetProc, PairsGetProc, PairsRestoreProc, PairsFreeProc, NULL + }; + +static int PairsSetProc(ClientData clientData, Tcl_Interp* interp, + Tk_Window tkwin, Tcl_Obj** objPtr, char* widgRec, + int offset, char* savePtr, int flags) +{ + ElemCoords* coordsPtr = (ElemCoords*)(widgRec + offset); + *(double*)savePtr = (double)NULL; + + double* values; + int nValues; + if (ParseValues(interp, *objPtr, &nValues, &values) != TCL_OK) + return TCL_ERROR; + + if (nValues == 0) + return TCL_OK; + + if (nValues & 1) { + Tcl_AppendResult(interp, "odd number of data points", NULL); + delete [] values; + return TCL_ERROR; + } + + nValues /= 2; + delete coordsPtr->x; + coordsPtr->x = new ElemValuesSource(nValues); + + delete coordsPtr->y; + coordsPtr->y = new ElemValuesSource(nValues); + + int ii=0; + for (double* p = values; iix->values_[ii] = *p++; + coordsPtr->y->values_[ii] = *p++; + } + delete [] values; + + coordsPtr->x->findRange(); + coordsPtr->y->findRange(); + + return TCL_OK; +}; + +static Tcl_Obj* PairsGetProc(ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset) +{ + ElemCoords* coordsPtr = (ElemCoords*)(widgRec + offset); + + if (!coordsPtr || + !coordsPtr->x || !coordsPtr->y || + !coordsPtr->x->nValues() || !coordsPtr->y->nValues()) + return Tcl_NewListObj(0, (Tcl_Obj**)NULL); + + int cnt = MIN(coordsPtr->x->nValues(), coordsPtr->y->nValues()); + Tcl_Obj** ll = new Tcl_Obj*[2*cnt]; + for (int ii=0, jj=0; iix->values_[ii]); + ll[jj++] = Tcl_NewDoubleObj(coordsPtr->y->values_[ii]); + } + Tcl_Obj* listObjPtr = Tcl_NewListObj(2*cnt, ll); + delete [] ll; + + return listObjPtr; +}; + +static void PairsRestoreProc(ClientData clientData, Tk_Window tkwin, + char *ptr, char *savePtr) +{ + // do nothing +} + +static void PairsFreeProc(ClientData clientData, Tk_Window tkwin, char *ptr) +{ + // do nothing +} + +int StyleSetProc(ClientData clientData, Tcl_Interp* interp, + Tk_Window tkwin, Tcl_Obj** objPtr, char* widgRec, + int offset, char* save, int flags) +{ + Chain* stylePalette = *(Chain**)(widgRec + offset); + ElementOptions* ops = (ElementOptions*)(widgRec); + Element* elemPtr = ops->elemPtr; + size_t size = (size_t)clientData; + + int objc; + Tcl_Obj** objv; + if (Tcl_ListObjGetElements(interp, *objPtr, &objc, &objv) != TCL_OK) + return TCL_ERROR; + + // Reserve the first entry for the "normal" pen. We'll set the style later + elemPtr->freeStylePalette(stylePalette); + ChainLink* link = Chain_FirstLink(stylePalette); + if (!link) { + link = new ChainLink(size); + stylePalette->linkAfter(link, NULL); + } + + PenStyle* stylePtr = (PenStyle*)Chain_GetValue(link); + stylePtr->penPtr = NORMALPEN(ops); + for (int ii = 0; iiweight.min = (double)ii; + stylePtr->weight.max = (double)ii + 1.0; + stylePtr->weight.range = 1.0; + if (GetPenStyleFromObj(interp, elemPtr->graphPtr_, objv[ii], + elemPtr->classId(), + (PenStyle*)stylePtr) != TCL_OK) { + elemPtr->freeStylePalette(stylePalette); + return TCL_ERROR; + } + stylePalette->linkAfter(link, NULL); + } + + return TCL_OK; +} + +Tcl_Obj* StyleGetProc(ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset) +{ + Chain* stylePalette = *(Chain**)(widgRec + offset); + + // count how many + int cnt =0; + for (ChainLink* link = Chain_FirstLink(stylePalette); link; + link = Chain_NextLink(link), cnt++) {} + if (!cnt) + return Tcl_NewListObj(0, (Tcl_Obj**)NULL); + + Tcl_Obj** ll = new Tcl_Obj*[3*cnt]; + int ii=0; + for (ChainLink* link = Chain_FirstLink(stylePalette); link; + link = Chain_NextLink(link)) { + PenStyle *stylePtr = (PenStyle*)Chain_GetValue(link); + ll[ii++] = Tcl_NewStringObj(stylePtr->penPtr->name_, -1); + ll[ii++] = Tcl_NewDoubleObj(stylePtr->weight.min); + ll[ii++] = Tcl_NewDoubleObj(stylePtr->weight.max); + } + Tcl_Obj *listObjPtr = Tcl_NewListObj(3*cnt,ll); + delete [] ll; + + return listObjPtr; +} + +void StyleRestoreProc(ClientData clientData, Tk_Window tkwin, + char *ptr, char *savePtr) +{ + // do nothing +} + +void StyleFreeProc(ClientData clientData, Tk_Window tkwin, char *ptr) +{ + // do nothing +} + +// Support + +static int GetPenStyleFromObj(Tcl_Interp* interp, Graph* graphPtr, + Tcl_Obj *objPtr, ClassId classId, + PenStyle *stylePtr) +{ + int objc; + Tcl_Obj **objv; + if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) + return TCL_ERROR; + + if ((objc != 1) && (objc != 3)) { + Tcl_AppendResult(interp, "bad style entry \"", + Tcl_GetString(objPtr), + "\": should be \"penName\" or \"penName min max\"", + NULL); + return TCL_ERROR; + } + + Pen* penPtr; + if (graphPtr->getPen(objv[0], &penPtr) != TCL_OK) + return TCL_ERROR; + + if (objc == 3) { + double min, max; + if ((Tcl_GetDoubleFromObj(interp, objv[1], &min) != TCL_OK) || + (Tcl_GetDoubleFromObj(interp, objv[2], &max) != TCL_OK)) + return TCL_ERROR; + + SETWEIGHT(stylePtr->weight, min, max); + } + + penPtr->refCount_++; + stylePtr->penPtr = penPtr; + return TCL_OK; +} + +void VectorChangedProc(Tcl_Interp* interp, ClientData clientData, + Blt_VectorNotify notify) +{ + ElemValuesVector* valuesPtr = (ElemValuesVector*)clientData; + if (!valuesPtr) + return; + + if (notify == BLT_VECTOR_NOTIFY_DESTROY) { + valuesPtr->freeSource(); + valuesPtr->reset(); + } + else { + Blt_Vector* vector; + Blt_GetVectorById(interp, valuesPtr->source_, &vector); + if (valuesPtr->fetchValues(vector) != TCL_OK) + return; + } + + Element* elemPtr = valuesPtr->elemPtr_; + Graph* graphPtr = elemPtr->graphPtr_; + + graphPtr->flags |= RESET; + graphPtr->eventuallyRedraw(); +} + +static int ParseValues(Tcl_Interp* interp, Tcl_Obj *objPtr, int *nValuesPtr, + double **arrayPtr) +{ + int objc; + Tcl_Obj **objv; + if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) + return TCL_ERROR; + + *arrayPtr = NULL; + *nValuesPtr = 0; + if (objc > 0) { + double* array = new double[objc]; + if (!array) { + Tcl_AppendResult(interp, "can't allocate new vector", NULL); + return TCL_ERROR; + } + + int i=0; + for (double* p = array; i < objc; i++, p++) { + if (Tcl_GetDoubleFromObj(interp, objv[i], p) != TCL_OK) { + delete [] array; + return TCL_ERROR; + } + } + *arrayPtr = array; + *nValuesPtr = objc; + } + + return TCL_OK; +} diff --git a/generic/tkbltGrElemOption.h b/generic/tkbltGrElemOption.h new file mode 100644 index 0000000..4312691 --- /dev/null +++ b/generic/tkbltGrElemOption.h @@ -0,0 +1,41 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGrElemOption_h__ +#define __BltGrElemOption_h__ + +#include + +extern const char* fillObjOption[]; +extern Tk_CustomOptionSetProc StyleSetProc; +extern Tk_CustomOptionGetProc StyleGetProc; +extern Tk_CustomOptionRestoreProc StyleRestoreProc; +extern Tk_CustomOptionFreeProc StyleFreeProc; + +#endif diff --git a/generic/tkbltGrHairs.C b/generic/tkbltGrHairs.C new file mode 100644 index 0000000..d7ea3d2 --- /dev/null +++ b/generic/tkbltGrHairs.C @@ -0,0 +1,145 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "tkbltGraph.h" +#include "tkbltGrHairs.h" +#include "tkbltConfig.h" + +using namespace Blt; + +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_COLOR, "-color", "color", "Color", + "green", -1, Tk_Offset(CrosshairsOptions, colorPtr), 0, NULL, 0}, + {TK_OPTION_CUSTOM, "-dashes", "dashes", "Dashes", + NULL, -1, Tk_Offset(CrosshairsOptions, dashes), + TK_OPTION_NULL_OK, &dashesObjOption, 0}, + {TK_OPTION_PIXELS, "-linewidth", "lineWidth", "Linewidth", + "1", -1, Tk_Offset(CrosshairsOptions, lineWidth), 0, NULL, 0}, + {TK_OPTION_PIXELS, "-x", "x", "X", + "0", -1, Tk_Offset(CrosshairsOptions, x), 0, NULL, 0}, + {TK_OPTION_PIXELS, "-y", "y", "Y", + "0", -1, Tk_Offset(CrosshairsOptions, y), 0, NULL, 0}, + {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, -1, 0, 0, 0} +}; + +Crosshairs::Crosshairs(Graph* graphPtr) +{ + ops_ = (CrosshairsOptions*)calloc(1, sizeof(CrosshairsOptions)); + + graphPtr_ = graphPtr; + visible_ =0; + gc_ =NULL; + + optionTable_ = Tk_CreateOptionTable(graphPtr->interp_, optionSpecs); + Tk_InitOptions(graphPtr->interp_, (char*)ops_, optionTable_, + graphPtr->tkwin_); +} + +Crosshairs::~Crosshairs() +{ + if (gc_) + graphPtr_->freePrivateGC(gc_); + + Tk_FreeConfigOptions((char*)ops_, optionTable_, graphPtr_->tkwin_); + free(ops_); +} + +// Configure + +int Crosshairs::configure() +{ + CrosshairsOptions* ops = (CrosshairsOptions*)ops_; + + XGCValues gcValues; + gcValues.foreground = ops->colorPtr->pixel; + gcValues.line_width = ops->lineWidth; + unsigned long gcMask = (GCForeground | GCLineWidth); + if (LineIsDashed(ops->dashes)) { + gcValues.line_style = LineOnOffDash; + gcMask |= GCLineStyle; + } + GC newGC = graphPtr_->getPrivateGC(gcMask, &gcValues); + if (LineIsDashed(ops->dashes)) + graphPtr_->setDashes(newGC, &ops->dashes); + + if (gc_) + graphPtr_->freePrivateGC(gc_); + gc_ = newGC; + + // Are the new coordinates on the graph? + map(); + + return TCL_OK; +} + +void Crosshairs::map() +{ + CrosshairsOptions* ops = (CrosshairsOptions*)ops_; + + segArr_[0].x = ops->x; + segArr_[1].x = ops->x; + segArr_[0].y = graphPtr_->bottom_; + segArr_[1].y = graphPtr_->top_; + segArr_[2].y = ops->y; + segArr_[3].y = ops->y; + segArr_[2].x = graphPtr_->left_; + segArr_[3].x = graphPtr_->right_; +} + +void Crosshairs::on() +{ + visible_ =1; +} + +void Crosshairs::off() +{ + visible_ =0; +} + +void Crosshairs::draw(Drawable drawable) +{ + CrosshairsOptions* ops = (CrosshairsOptions*)ops_; + + if (visible_ && Tk_IsMapped(graphPtr_->tkwin_)) { + if (ops->x <= graphPtr_->right_ && + ops->x >= graphPtr_->left_ && + ops->y <= graphPtr_->bottom_ && + ops->y >= graphPtr_->top_) { + XDrawLine(graphPtr_->display_, drawable, gc_, + segArr_[0].x, segArr_[0].y, segArr_[1].x, segArr_[1].y); + XDrawLine(graphPtr_->display_, drawable, gc_, + segArr_[2].x, segArr_[2].y, segArr_[3].x, segArr_[3].y); + } + } +} diff --git a/generic/tkbltGrHairs.h b/generic/tkbltGrHairs.h new file mode 100644 index 0000000..a86d0c6 --- /dev/null +++ b/generic/tkbltGrHairs.h @@ -0,0 +1,78 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGrHairs_h__ +#define __BltGrHairs_h__ + +#include + +#include "tkbltGrMisc.h" + +namespace Blt { + class Graph; + + typedef struct { + XColor* colorPtr; + Dashes dashes; + int lineWidth; + int x; + int y; + } CrosshairsOptions; + + class Crosshairs { + protected: + Graph* graphPtr_; + Tk_OptionTable optionTable_; + void* ops_; + + int visible_; + GC gc_; + Point segArr_[4]; + + public: + Crosshairs(Graph*); + virtual ~Crosshairs(); + + int configure(); + void map(); + void draw(Drawable); + + void on(); + void off(); + int isOn() {return visible_;} + + Tk_OptionTable optionTable() {return optionTable_;} + void* ops() {return ops_;} + }; +}; + +#endif diff --git a/generic/tkbltGrHairsOp.C b/generic/tkbltGrHairsOp.C new file mode 100644 index 0000000..57650ce --- /dev/null +++ b/generic/tkbltGrHairsOp.C @@ -0,0 +1,164 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "tkbltGraph.h" +#include "tkbltGrHairs.h" +#include "tkbltGrHairsOp.h" + +using namespace Blt; + +static int CrosshairsObjConfigure(Graph* graphPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Crosshairs* chPtr = graphPtr->crosshairs_; + Tk_SavedOptions savedOptions; + int mask =0; + int error; + Tcl_Obj* errorResult; + + for (error=0; error<=1; error++) { + if (!error) { + if (Tk_SetOptions(interp, (char*)chPtr->ops(), chPtr->optionTable(), + objc, objv, graphPtr->tkwin_, &savedOptions, &mask) + != TCL_OK) + continue; + } + else { + errorResult = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); + } + + if (chPtr->configure() != TCL_OK) + return TCL_ERROR; + graphPtr->flags |= mask; + graphPtr->eventuallyRedraw(); + + break; + } + + if (!error) { + Tk_FreeSavedOptions(&savedOptions); + return TCL_OK; + } + else { + Tcl_SetObjResult(interp, errorResult); + Tcl_DecrRefCount(errorResult); + return TCL_ERROR; + } +} + +static int CgetOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "cget option"); + return TCL_ERROR; + } + + Crosshairs* chPtr = graphPtr->crosshairs_; + Tcl_Obj* objPtr = Tk_GetOptionValue(interp, + (char*)chPtr->ops(), + chPtr->optionTable(), + objv[3], graphPtr->tkwin_); + if (objPtr == NULL) + return TCL_ERROR; + else + Tcl_SetObjResult(interp, objPtr); + return TCL_OK; +} + +static int ConfigureOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + Crosshairs* chPtr = graphPtr->crosshairs_; + if (objc <= 4) { + Tcl_Obj* objPtr = Tk_GetOptionInfo(interp, (char*)chPtr->ops(), + chPtr->optionTable(), + (objc == 4) ? objv[3] : NULL, + graphPtr->tkwin_); + if (objPtr == NULL) + return TCL_ERROR; + else + Tcl_SetObjResult(interp, objPtr); + return TCL_OK; + } + else + return CrosshairsObjConfigure(graphPtr, interp, objc-3, objv+3); +} + +static int OnOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + Crosshairs *chPtr = graphPtr->crosshairs_; + + chPtr->on(); + + return TCL_OK; +} + +static int OffOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + Crosshairs *chPtr = graphPtr->crosshairs_; + + chPtr->off(); + + return TCL_OK; +} + +static int ToggleOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + Crosshairs *chPtr = graphPtr->crosshairs_; + + if (chPtr->isOn()) + chPtr->off(); + else + chPtr->on(); + + return TCL_OK; +} + +const Ensemble Blt::crosshairsEnsemble[] = { + {"cget", CgetOp, 0}, + {"configure", ConfigureOp, 0}, + {"off", OffOp, 0}, + {"on", OnOp, 0}, + {"toggle", ToggleOp, 0}, + { 0,0,0 } +}; diff --git a/generic/tkbltGrHairsOp.h b/generic/tkbltGrHairsOp.h new file mode 100644 index 0000000..3f3d009 --- /dev/null +++ b/generic/tkbltGrHairsOp.h @@ -0,0 +1,42 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGrHairsOp_h__ +#define __BltGrHairsOp_h__ + +#include "tkbltGraph.h" + +namespace Blt { + extern const Ensemble crosshairsEnsemble[]; +}; + +#endif diff --git a/generic/tkbltGrLegd.C b/generic/tkbltGrLegd.C new file mode 100644 index 0000000..b8822f1 --- /dev/null +++ b/generic/tkbltGrLegd.C @@ -0,0 +1,1070 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#include "tkbltGrBind.h" +#include "tkbltGraph.h" +#include "tkbltGrLegd.h" +#include "tkbltGrElem.h" +#include "tkbltGrPostscript.h" +#include "tkbltGrMisc.h" +#include "tkbltGrDef.h" +#include "tkbltConfig.h" +#include "tkbltGrPSOutput.h" + +using namespace Blt; + +static void SelectCmdProc(ClientData); +static Tk_SelectionProc SelectionProc; + +// OptionSpecs + +static const char* selectmodeObjOption[] = { + "single", "multiple", NULL +}; +static const char* positionObjOption[] = { + "rightmargin", "leftmargin", "topmargin", "bottommargin", + "plotarea", "xy", NULL +}; + +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_BORDER, "-activebackground", "activeBackground", + "ActiveBackground", + STD_ACTIVE_BACKGROUND, -1, Tk_Offset(LegendOptions, activeBg), + 0, NULL, CACHE}, + {TK_OPTION_PIXELS, "-activeborderwidth", "activeBorderWidth", + "ActiveBorderWidth", + STD_BORDERWIDTH, -1, Tk_Offset(LegendOptions, entryBW), 0, NULL, LAYOUT}, + {TK_OPTION_COLOR, "-activeforeground", "activeForeground", "ActiveForeground", + STD_ACTIVE_FOREGROUND, -1, Tk_Offset(LegendOptions, activeFgColor), + 0, NULL, CACHE}, + {TK_OPTION_RELIEF, "-activerelief", "activeRelief", "ActiveRelief", + "flat", -1, Tk_Offset(LegendOptions, activeRelief), 0, NULL, LAYOUT}, + {TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor", + "n", -1, Tk_Offset(LegendOptions, anchor), 0, NULL, LAYOUT}, + {TK_OPTION_SYNONYM, "-bg", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-background", 0}, + {TK_OPTION_BORDER, "-background", "background", "Background", + NULL, -1, Tk_Offset(LegendOptions, normalBg), + TK_OPTION_NULL_OK, NULL, CACHE}, + {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", + STD_BORDERWIDTH, -1, Tk_Offset(LegendOptions, borderWidth), + 0, NULL, LAYOUT}, + {TK_OPTION_SYNONYM, "-bd", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-borderwidth", 0}, + {TK_OPTION_INT, "-columns", "columns", "columns", + "0", -1, Tk_Offset(LegendOptions, reqColumns), 0, NULL, LAYOUT}, + {TK_OPTION_BOOLEAN, "-exportselection", "exportSelection", "ExportSelection", + "no", -1, Tk_Offset(LegendOptions, exportSelection), 0, NULL, LAYOUT}, + {TK_OPTION_CUSTOM, "-focusdashes", "focusDashes", "FocusDashes", + "dot", -1, Tk_Offset(LegendOptions, focusDashes), + TK_OPTION_NULL_OK, &dashesObjOption, CACHE}, + {TK_OPTION_COLOR, "-focusforeground", "focusForeground", "FocusForeground", + STD_ACTIVE_FOREGROUND, -1, Tk_Offset(LegendOptions, focusColor), + 0, NULL, CACHE}, + {TK_OPTION_FONT, "-font", "font", "Font", + STD_FONT_SMALL, -1, Tk_Offset(LegendOptions, style.font), 0, NULL, LAYOUT}, + {TK_OPTION_SYNONYM, "-fg", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-foreground", 0}, + {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground", + STD_NORMAL_FOREGROUND, -1, Tk_Offset(LegendOptions, fgColor), + 0, NULL, CACHE}, + {TK_OPTION_BOOLEAN, "-hide", "hide", "Hide", + "no", -1, Tk_Offset(LegendOptions, hide), 0, NULL, LAYOUT}, + {TK_OPTION_PIXELS, "-ipadx", "iPadX", "Pad", + "1", -1, Tk_Offset(LegendOptions, ixPad), 0, NULL, LAYOUT}, + {TK_OPTION_PIXELS, "-ipady", "iPadY", "Pad", + "1", -1, Tk_Offset(LegendOptions, iyPad), 0, NULL, LAYOUT}, + {TK_OPTION_BORDER, "-nofocusselectbackground", "noFocusSelectBackground", + "NoFocusSelectBackground", + STD_ACTIVE_BACKGROUND, -1, Tk_Offset(LegendOptions, selOutFocusBg), + 0, NULL, CACHE}, + {TK_OPTION_COLOR, "-nofocusselectforeground", "noFocusSelectForeground", + "NoFocusSelectForeground", + STD_ACTIVE_FOREGROUND, -1, Tk_Offset(LegendOptions, selOutFocusFgColor), + 0, NULL, CACHE}, + {TK_OPTION_PIXELS, "-padx", "padX", "Pad", + "1", -1, Tk_Offset(LegendOptions, xPad), 0, NULL, LAYOUT}, + {TK_OPTION_PIXELS, "-pady", "padY", "Pad", + "1", -1, Tk_Offset(LegendOptions, yPad), 0, NULL, LAYOUT}, + {TK_OPTION_STRING_TABLE, "-position", "position", "Position", + "rightmargin", -1, Tk_Offset(LegendOptions, position), + 0, &positionObjOption, LAYOUT}, + {TK_OPTION_BOOLEAN, "-raised", "raised", "Raised", + "no", -1, Tk_Offset(LegendOptions, raised), 0, NULL, LAYOUT}, + {TK_OPTION_RELIEF, "-relief", "relief", "Relief", + "flat", -1, Tk_Offset(LegendOptions, relief), 0, NULL, LAYOUT}, + {TK_OPTION_INT, "-rows", "rows", "rows", + "0", -1, Tk_Offset(LegendOptions, reqRows), 0, NULL, LAYOUT}, + {TK_OPTION_BORDER, "-selectbackground", "selectBackground", + "SelectBackground", + STD_ACTIVE_BACKGROUND, -1, Tk_Offset(LegendOptions, selInFocusBg), + 0, NULL, LAYOUT}, + {TK_OPTION_PIXELS, "-selectborderwidth", "selectBorderWidth", + "SelectBorderWidth", + "1", -1, Tk_Offset(LegendOptions, selBW), 0, NULL, LAYOUT}, + {TK_OPTION_STRING, "-selectcommand", "selectCommand", "SelectCommand", + NULL, -1, Tk_Offset(LegendOptions, selectCmd), TK_OPTION_NULL_OK, NULL, 0}, + {TK_OPTION_COLOR, "-selectforeground", "selectForeground", "SelectForeground", + STD_ACTIVE_FOREGROUND, -1, Tk_Offset(LegendOptions, selInFocusFgColor), + 0, NULL, CACHE}, + {TK_OPTION_STRING_TABLE, "-selectmode", "selectMode", "SelectMode", + "multiple", -1, Tk_Offset(LegendOptions, selectMode), + 0, &selectmodeObjOption, 0}, + {TK_OPTION_RELIEF, "-selectrelief", "selectRelief", "SelectRelief", + "flat", -1, Tk_Offset(LegendOptions, selRelief), 0, NULL, LAYOUT}, + {TK_OPTION_STRING, "-title", "title", "Title", + NULL, -1, Tk_Offset(LegendOptions, title), TK_OPTION_NULL_OK, NULL, LAYOUT}, + {TK_OPTION_COLOR, "-titlecolor", "titleColor", "TitleColor", + STD_NORMAL_FOREGROUND, -1, Tk_Offset(LegendOptions, titleStyle.color), + 0, NULL, CACHE}, + {TK_OPTION_FONT, "-titlefont", "titleFont", "TitleFont", + STD_FONT_SMALL, -1, Tk_Offset(LegendOptions, titleStyle.font), + 0, NULL, LAYOUT}, + {TK_OPTION_PIXELS, "-x", "x", "X", + "0", -1, Tk_Offset(LegendOptions, xReq), 0, NULL, LAYOUT}, + {TK_OPTION_PIXELS, "-y", "y", "Y", + "0", -1, Tk_Offset(LegendOptions, yReq), 0, NULL, LAYOUT}, + {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, -1, 0, 0, 0} +}; + +Legend::Legend(Graph* graphPtr) +{ + ops_ = (void*)calloc(1, sizeof(LegendOptions)); + LegendOptions* ops = (LegendOptions*)ops_; + + graphPtr_ = graphPtr; + flags =0; + nEntries_ =0; + nColumns_ =0; + nRows_ =0; + width_ =0; + height_ =0; + entryWidth_ =0; + entryHeight_ =0; + x_ =0; + y_ =0; + bindTable_ =NULL; + focusGC_ =NULL; + focusPtr_ =NULL; + selAnchorPtr_ =NULL; + selMarkPtr_ =NULL; + selected_ = new Chain(); + titleWidth_ =0; + titleHeight_ =0; + + ops->style.anchor =TK_ANCHOR_NW; + ops->style.color =NULL; + ops->style.font =NULL; + ops->style.angle =0; + ops->style.justify =TK_JUSTIFY_LEFT; + + ops->titleStyle.anchor =TK_ANCHOR_NW; + ops->titleStyle.color =NULL; + ops->titleStyle.font =NULL; + ops->titleStyle.angle =0; + ops->titleStyle.justify =TK_JUSTIFY_LEFT; + + bindTable_ = new BindTable(graphPtr, this); + + Tcl_InitHashTable(&selectTable_, TCL_ONE_WORD_KEYS); + + Tk_CreateSelHandler(graphPtr_->tkwin_, XA_PRIMARY, XA_STRING, + SelectionProc, this, XA_STRING); + + optionTable_ =Tk_CreateOptionTable(graphPtr->interp_, optionSpecs); + Tk_InitOptions(graphPtr->interp_, (char*)ops_, optionTable_, graphPtr->tkwin_); +} + +Legend::~Legend() +{ + // LegendOptions* ops = (LegendOptions*)ops_; + + delete bindTable_; + + if (focusGC_) + graphPtr_->freePrivateGC(focusGC_); + + if (graphPtr_->tkwin_) + Tk_DeleteSelHandler(graphPtr_->tkwin_, XA_PRIMARY, XA_STRING); + + delete selected_; + + Tk_FreeConfigOptions((char*)ops_, optionTable_, graphPtr_->tkwin_); + free(ops_); +} + +int Legend::configure() +{ + LegendOptions* ops = (LegendOptions*)ops_; + + // GC for active label, Dashed outline + unsigned long gcMask = GCForeground | GCLineStyle; + XGCValues gcValues; + gcValues.foreground = ops->focusColor->pixel; + gcValues.line_style = (LineIsDashed(ops->focusDashes)) + ? LineOnOffDash : LineSolid; + GC newGC = graphPtr_->getPrivateGC(gcMask, &gcValues); + if (LineIsDashed(ops->focusDashes)) { + ops->focusDashes.offset = 2; + graphPtr_->setDashes(newGC, &ops->focusDashes); + } + if (focusGC_) + graphPtr_->freePrivateGC(focusGC_); + + focusGC_ = newGC; + + return TCL_OK; +} + +void Legend::map(int plotWidth, int plotHeight) +{ + LegendOptions* ops = (LegendOptions*)ops_; + + entryWidth_ =0; + entryHeight_ = 0; + nRows_ =0; + nColumns_ =0; + nEntries_ =0; + height_ =0; + width_ = 0; + + TextStyle tts(graphPtr_, &ops->titleStyle); + tts.getExtents(ops->title, &titleWidth_, &titleHeight_); + + // Count the number of legend entries and determine the widest and tallest + // label. The number of entries would normally be the number of elements, + // but elements can have no legend entry (-label ""). + int nEntries =0; + int maxWidth =0; + int maxHeight =0; + TextStyle ts(graphPtr_, &ops->style); + for (ChainLink* link = Chain_FirstLink(graphPtr_->elements_.displayList); + link; link = Chain_NextLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + ElementOptions* elemOps = (ElementOptions*)elemPtr->ops(); + + if (!elemOps->label) + continue; + + int w, h; + ts.getExtents(elemOps->label, &w, &h); + if (maxWidth < (int)w) + maxWidth = w; + + if (maxHeight < (int)h) + maxHeight = h; + + nEntries++; + } + if (nEntries == 0) + return; + + Tk_FontMetrics fontMetrics; + Tk_GetFontMetrics(ops->style.font, &fontMetrics); + int symbolWidth = 2 * fontMetrics.ascent; + + maxWidth += 2 * ops->entryBW + 2*ops->ixPad + + + symbolWidth + 3 * 2; + + maxHeight += 2 * ops->entryBW + 2*ops->iyPad; + + maxWidth |= 0x01; + maxHeight |= 0x01; + + int lw = plotWidth - 2 * ops->borderWidth - 2*ops->xPad; + int lh = plotHeight - 2 * ops->borderWidth - 2*ops->yPad; + + /* + * The number of rows and columns is computed as one of the following: + * + * both options set User defined. + * -rows Compute columns from rows. + * -columns Compute rows from columns. + * neither set Compute rows and columns from + * size of plot. + */ + int nRows =0; + int nColumns =0; + if (ops->reqRows > 0) { + nRows = MIN(ops->reqRows, nEntries); + if (ops->reqColumns > 0) + nColumns = MIN(ops->reqColumns, nEntries); + else + nColumns = ((nEntries - 1) / nRows) + 1; /* Only -rows. */ + } + else if (ops->reqColumns > 0) { /* Only -columns. */ + nColumns = MIN(ops->reqColumns, nEntries); + nRows = ((nEntries - 1) / nColumns) + 1; + } + else { + // Compute # of rows and columns from the legend size + nRows = lh / maxHeight; + nColumns = lw / maxWidth; + if (nRows < 1) { + nRows = nEntries; + } + if (nColumns < 1) { + nColumns = nEntries; + } + if (nRows > nEntries) { + nRows = nEntries; + } + switch ((Position)ops->position) { + case TOP: + case BOTTOM: + nRows = ((nEntries - 1) / nColumns) + 1; + break; + case LEFT: + case RIGHT: + default: + nColumns = ((nEntries - 1) / nRows) + 1; + break; + } + } + if (nColumns < 1) + nColumns = 1; + + if (nRows < 1) + nRows = 1; + + lh = (nRows * maxHeight); + if (titleHeight_ > 0) + lh += titleHeight_ + ops->yPad; + + lw = nColumns * maxWidth; + if (lw < (int)(titleWidth_)) + lw = titleWidth_; + + width_ = lw + 2 * ops->borderWidth + 2*ops->xPad; + height_ = lh + 2 * ops->borderWidth + 2*ops->yPad; + nRows_ = nRows; + nColumns_ = nColumns; + nEntries_ = nEntries; + entryHeight_ = maxHeight; + entryWidth_ = maxWidth; + + int row =0; + int col =0; + int count =0; + for (ChainLink* link = Chain_FirstLink(graphPtr_->elements_.displayList); + link; link = Chain_NextLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + count++; + elemPtr->row_ = row; + elemPtr->col_ = col; + row++; + if ((count % nRows) == 0) { + col++; + row = 0; + } + } +} + +void Legend::draw(Drawable drawable) +{ + LegendOptions* ops = (LegendOptions*)ops_; + GraphOptions* gops = (GraphOptions*)graphPtr_->ops_; + + if ((ops->hide) || (nEntries_ == 0)) + return; + + setOrigin(); + Tk_Window tkwin = graphPtr_->tkwin_; + int w = width_; + int h = height_; + + Pixmap pixmap = Tk_GetPixmap(graphPtr_->display_, Tk_WindowId(tkwin), w, h, + Tk_Depth(tkwin)); + + if (ops->normalBg) + Tk_Fill3DRectangle(tkwin, pixmap, ops->normalBg, 0, 0, + w, h, 0, TK_RELIEF_FLAT); + else { + switch ((Position)ops->position) { + case TOP: + case BOTTOM: + case RIGHT: + case LEFT: + Tk_Fill3DRectangle(tkwin, pixmap, gops->normalBg, 0, 0, + w, h, 0, TK_RELIEF_FLAT); + break; + case PLOT: + case XY: + // Legend background is transparent and is positioned over the the + // plot area. Either copy the part of the background from the backing + // store pixmap or (if no backing store exists) just fill it with the + // background color of the plot. + if (graphPtr_->cache_ != None) + XCopyArea(graphPtr_->display_, graphPtr_->cache_, pixmap, + graphPtr_->drawGC_, x_, y_, w, h, 0, 0); + else + Tk_Fill3DRectangle(tkwin, pixmap, gops->plotBg, 0, 0, + w, h, TK_RELIEF_FLAT, 0); + break; + }; + } + + Tk_FontMetrics fontMetrics; + Tk_GetFontMetrics(ops->style.font, &fontMetrics); + + int symbolSize = fontMetrics.ascent; + int xMid = symbolSize + 1 + ops->entryBW; + int yMid = (symbolSize / 2) + 1 + ops->entryBW; + int xLabel = 2 * symbolSize + ops->entryBW + ops->ixPad + 2 * 2; + int ySymbol = yMid + ops->iyPad; + int xSymbol = xMid + 2; + + int x = ops->xPad + ops->borderWidth; + int y = ops->yPad + ops->borderWidth; + + TextStyle tts(graphPtr_, &ops->titleStyle); + tts.drawText(pixmap, ops->title, x, y); + if (titleHeight_ > 0) + y += titleHeight_ + ops->yPad; + + int count = 0; + int yStart = y; + TextStyle ts(graphPtr_, &ops->style); + + for (ChainLink* link = Chain_FirstLink(graphPtr_->elements_.displayList); + link; link = Chain_NextLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + ElementOptions* elemOps = (ElementOptions*)elemPtr->ops(); + if (!elemOps->label) + continue; + + int isSelected = entryIsSelected(elemPtr); + if (elemPtr->labelActive_) + Tk_Fill3DRectangle(tkwin, pixmap, ops->activeBg, + x, y, entryWidth_, entryHeight_, + ops->entryBW, ops->activeRelief); + else if (isSelected) { + XColor* fg = (flags & FOCUS) ? + ops->selInFocusFgColor : ops->selOutFocusFgColor; + Tk_3DBorder bg = (flags & FOCUS) ? + ops->selInFocusBg : ops->selOutFocusBg; + ops->style.color = fg; + Tk_Fill3DRectangle(tkwin, pixmap, bg, x, y, + entryWidth_, entryHeight_, + ops->selBW, ops->selRelief); + } + else { + ops->style.color = ops->fgColor; + if (elemOps->legendRelief != TK_RELIEF_FLAT) + Tk_Fill3DRectangle(tkwin, pixmap, gops->normalBg, + x, y, entryWidth_, + entryHeight_, ops->entryBW, + elemOps->legendRelief); + } + elemPtr->drawSymbol(pixmap, x + xSymbol, y + ySymbol, symbolSize); + + ts.drawText(pixmap, elemOps->label, x+xLabel, y+ops->entryBW+ops->iyPad); + count++; + + if (focusPtr_ == elemPtr) { + if (isSelected) { + XColor* color = (flags & FOCUS) ? + ops->selInFocusFgColor : ops->selOutFocusFgColor; + XSetForeground(graphPtr_->display_, focusGC_, color->pixel); + } + XDrawRectangle(graphPtr_->display_, pixmap, focusGC_, + x + 1, y + 1, entryWidth_ - 3, + entryHeight_ - 3); + if (isSelected) + XSetForeground(graphPtr_->display_, focusGC_, ops->focusColor->pixel); + } + + // Check when to move to the next column + if ((count % nRows_) > 0) + y += entryHeight_; + else { + x += entryWidth_; + y = yStart; + } + } + + Tk_3DBorder bg = ops->normalBg; + if (!bg) + bg = gops->normalBg; + + Tk_Draw3DRectangle(tkwin, pixmap, bg, 0, 0, w, h, + ops->borderWidth, ops->relief); + XCopyArea(graphPtr_->display_, pixmap, drawable, graphPtr_->drawGC_, + 0, 0, w, h, x_, y_); + + Tk_FreePixmap(graphPtr_->display_, pixmap); +} + +void Legend::print(PSOutput* psPtr) +{ + LegendOptions* ops = (LegendOptions*)ops_; + GraphOptions* gops = (GraphOptions*)graphPtr_->ops_; + PostscriptOptions* pops = (PostscriptOptions*)graphPtr_->postscript_->ops_; + + if ((ops->hide) || (nEntries_ == 0)) + return; + + setOrigin(); + + double x = x_; + double y = y_; + int width = width_ - 2*ops->xPad; + int height = height_ - 2*ops->yPad; + + psPtr->append("% Legend\n"); + if (pops->decorations) { + if (ops->normalBg) + psPtr->fill3DRectangle(ops->normalBg, x, y, width, height, + ops->borderWidth, ops->relief); + else + psPtr->print3DRectangle(gops->normalBg, x, y, width, height, + ops->borderWidth, ops->relief); + + } + else { + psPtr->setClearBackground(); + psPtr->fillRectangle(x, y, width, height); + } + + Tk_FontMetrics fontMetrics; + Tk_GetFontMetrics(ops->style.font, &fontMetrics); + int symbolSize = fontMetrics.ascent; + int xMid = symbolSize + 1 + ops->entryBW; + int yMid = (symbolSize / 2) + 1 + ops->entryBW; + int xLabel = 2 * symbolSize + ops->entryBW + ops->ixPad + 5; + int xSymbol = xMid + ops->ixPad; + int ySymbol = yMid + ops->iyPad; + + x += ops->borderWidth; + y += ops->borderWidth; + TextStyle tts(graphPtr_, &ops->titleStyle); + tts.printText(psPtr, ops->title, x, y); + if (titleHeight_ > 0) + y += titleHeight_ + ops->yPad; + + int count = 0; + double yStart = y; + TextStyle ts(graphPtr_, &ops->style); + + for (ChainLink* link = Chain_FirstLink(graphPtr_->elements_.displayList); + link; link = Chain_NextLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + ElementOptions* elemOps = (ElementOptions*)elemPtr->ops(); + + if (!elemOps->label) + continue; + + if (elemPtr->labelActive_) { + ops->style.color = ops->activeFgColor; + psPtr->fill3DRectangle(ops->activeBg, x, y, entryWidth_, + entryHeight_, ops->entryBW, + ops->activeRelief); + } + else { + ops->style.color = ops->fgColor; + if (elemOps->legendRelief != TK_RELIEF_FLAT) + psPtr->print3DRectangle(gops->normalBg, x, y, entryWidth_, entryHeight_, + ops->entryBW, elemOps->legendRelief); + } + elemPtr->printSymbol(psPtr, x + xSymbol, y + ySymbol, symbolSize); + ts.printText(psPtr, elemOps->label, x + xLabel, + y + ops->entryBW + ops->iyPad); + count++; + + if ((count % nRows_) > 0) + y += entryHeight_; + else { + x += entryWidth_; + y = yStart; + } + } +} + +void Legend::removeElement(Element* elemPtr) +{ + bindTable_->deleteBindings(elemPtr); +} + +void Legend::eventuallyInvokeSelectCmd() +{ + if ((flags & SELECT_PENDING) == 0) { + flags |= SELECT_PENDING; + Tcl_DoWhenIdle(SelectCmdProc, this); + } +} + +void Legend::setOrigin() +{ + LegendOptions* ops = (LegendOptions*)ops_; + GraphOptions* gops = (GraphOptions*)graphPtr_->ops_; + + int x =0; + int y =0; + int w =0; + int h =0; + switch ((Position)ops->position) { + case RIGHT: + w = gops->rightMargin.width - gops->rightMargin.axesOffset; + h = graphPtr_->bottom_ - graphPtr_->top_; + x = graphPtr_->right_ + gops->rightMargin.axesOffset; + y = graphPtr_->top_; + break; + + case LEFT: + w = gops->leftMargin.width - gops->leftMargin.axesOffset; + h = graphPtr_->bottom_ - graphPtr_->top_; + x = graphPtr_->inset_; + y = graphPtr_->top_; + break; + + case TOP: + w = graphPtr_->right_ - graphPtr_->left_; + h = gops->topMargin.height - gops->topMargin.axesOffset; + if (gops->title) + h -= graphPtr_->titleHeight_; + + x = graphPtr_->left_; + y = graphPtr_->inset_; + if (gops->title) + y += graphPtr_->titleHeight_; + break; + + case BOTTOM: + w = graphPtr_->right_ - graphPtr_->left_; + h = gops->bottomMargin.height - gops->bottomMargin.axesOffset; + x = graphPtr_->left_; + y = graphPtr_->bottom_ + gops->bottomMargin.axesOffset; + break; + + case PLOT: + w = graphPtr_->right_ - graphPtr_->left_; + h = graphPtr_->bottom_ - graphPtr_->top_; + x = graphPtr_->left_; + y = graphPtr_->top_; + break; + + case XY: + w = width_; + h = height_; + x = ops->xReq; + y = ops->yReq; + if (x < 0) + x += graphPtr_->width_; + + if (y < 0) + y += graphPtr_->height_; + break; + } + + switch (ops->anchor) { + case TK_ANCHOR_NW: + break; + case TK_ANCHOR_W: + if (h > height_) + y += (h - height_) / 2; + break; + case TK_ANCHOR_SW: + if (h > height_) + y += (h - height_); + break; + case TK_ANCHOR_N: + if (w > width_) + x += (w - width_) / 2; + break; + case TK_ANCHOR_CENTER: + if (h > height_) + y += (h - height_) / 2; + + if (w > width_) + x += (w - width_) / 2; + break; + case TK_ANCHOR_S: + if (w > width_) + x += (w - width_) / 2; + + if (h > height_) + y += (h - height_); + break; + case TK_ANCHOR_NE: + if (w > width_) + x += w - width_; + break; + case TK_ANCHOR_E: + if (w > width_) + x += w - width_; + + if (h > height_) + y += (h - height_) / 2; + break; + case TK_ANCHOR_SE: + if (w > width_) { + x += w - width_; + } + if (h > height_) { + y += (h - height_); + } + break; + } + + x_ = x + ops->xPad; + y_ = y + ops->yPad; +} + +void Legend::selectEntry(Element* elemPtr) +{ + switch (flags & SELECT_TOGGLE) { + case SELECT_CLEAR: + deselectElement(elemPtr); + break; + case SELECT_SET: + selectElement(elemPtr); + break; + case SELECT_TOGGLE: + Tcl_HashEntry* hPtr = Tcl_FindHashEntry(&selectTable_, (char*)elemPtr); + if (hPtr) + deselectElement(elemPtr); + else + selectElement(elemPtr); + break; + } +} + +void Legend::selectElement(Element* elemPtr) +{ + int isNew; + Tcl_HashEntry* hPtr = + Tcl_CreateHashEntry(&selectTable_, (char*)elemPtr, &isNew); + if (isNew) { + ChainLink* link = selected_->append(elemPtr); + Tcl_SetHashValue(hPtr, link); + } +} + +void Legend::deselectElement(Element* elemPtr) +{ + Tcl_HashEntry* hPtr = Tcl_FindHashEntry(&selectTable_, (char*)elemPtr); + if (hPtr) { + ChainLink* link = (ChainLink*)Tcl_GetHashValue(hPtr); + selected_->deleteLink(link); + Tcl_DeleteHashEntry(hPtr); + } +} + + +int Legend::selectRange(Element *fromPtr, Element *toPtr) +{ + int isBefore=0; + for (ChainLink* linkPtr = fromPtr->link; linkPtr; linkPtr = linkPtr->next()) + if (linkPtr == toPtr->link) + isBefore =1; + + if (isBefore) { + for (ChainLink* link = fromPtr->link; link; link = Chain_NextLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + selectEntry(elemPtr); + if (link == toPtr->link) + break; + } + } + else { + for (ChainLink* link = fromPtr->link; link; link = Chain_PrevLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + selectEntry(elemPtr); + if (link == toPtr->link) + break; + } + } + + return TCL_OK; +} + +void Legend::clearSelection() +{ + LegendOptions* ops = (LegendOptions*)ops_; + + Tcl_DeleteHashTable(&selectTable_); + Tcl_InitHashTable(&selectTable_, TCL_ONE_WORD_KEYS); + selected_->reset(); + + if (ops->selectCmd) + eventuallyInvokeSelectCmd(); +} + +int Legend::entryIsSelected(Element* elemPtr) +{ + Tcl_HashEntry* hPtr = Tcl_FindHashEntry(&selectTable_, (char*)elemPtr); + return (hPtr != NULL); +} + +int Legend::getElementFromObj(Tcl_Obj* objPtr, Element** elemPtrPtr) +{ + const char *string = Tcl_GetString(objPtr); + Element* elemPtr = NULL; + + if (!strcmp(string, "anchor")) + elemPtr = selAnchorPtr_; + else if (!strcmp(string, "current")) + elemPtr = (Element*)bindTable_->currentItem(); + else if (!strcmp(string, "first")) + elemPtr = getFirstElement(); + else if (!strcmp(string, "focus")) + elemPtr = focusPtr_; + else if (!strcmp(string, "last")) + elemPtr = getLastElement(); + else if (!strcmp(string, "end")) + elemPtr = getLastElement(); + else if (!strcmp(string, "next.row")) + elemPtr = getNextRow(focusPtr_); + else if (!strcmp(string, "next.column")) + elemPtr = getNextColumn(focusPtr_); + else if (!strcmp(string, "previous.row")) + elemPtr = getPreviousRow(focusPtr_); + else if (!strcmp(string, "previous.column")) + elemPtr = getPreviousColumn(focusPtr_); + else if (string[0] == '@') { + int x, y; + if (graphPtr_->getXY(string, &x, &y) != TCL_OK) + return TCL_ERROR; + + ClassId classId; + elemPtr = (Element*)pickEntry(x, y, &classId); + } + else { + if (graphPtr_->getElement(objPtr, &elemPtr) != TCL_OK) + return TCL_ERROR; + + if (!elemPtr->link) { + Tcl_AppendResult(graphPtr_->interp_, "bad legend index \"", string, "\"", + (char *)NULL); + return TCL_ERROR; + } + ElementOptions* elemOps = (ElementOptions*)elemPtr->ops(); + if (!elemOps->label) + elemPtr = NULL; + } + + *elemPtrPtr = elemPtr; + return TCL_OK; +} + +Element* Legend::getNextRow(Element* focusPtr) +{ + unsigned col = focusPtr->col_; + unsigned row = focusPtr->row_ + 1; + for (ChainLink* link = focusPtr->link; link; link = Chain_NextLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + ElementOptions* elemOps = (ElementOptions*)elemPtr->ops(); + + if (!elemOps->label) + continue; + + if ((elemPtr->col_ == col) && (elemPtr->row_ == row)) + return elemPtr; + } + return NULL; +} + +Element* Legend::getNextColumn(Element* focusPtr) +{ + unsigned col = focusPtr->col_ + 1; + unsigned row = focusPtr->row_; + for (ChainLink* link = focusPtr->link; link; link = Chain_NextLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + ElementOptions* elemOps = (ElementOptions*)elemPtr->ops(); + + if (!elemOps->label) + continue; + + if ((elemPtr->col_ == col) && (elemPtr->row_ == row)) + return elemPtr; + } + return NULL; +} + +Element* Legend::getPreviousRow(Element* focusPtr) +{ + unsigned col = focusPtr->col_; + unsigned row = focusPtr->row_ - 1; + for (ChainLink* link = focusPtr->link; link; link = Chain_PrevLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + ElementOptions* elemOps = (ElementOptions*)elemPtr->ops(); + + if (!elemOps->label) + continue; + + if ((elemPtr->col_ == col) && (elemPtr->row_ == row)) + return elemPtr; + } + return NULL; +} + +Element* Legend::getPreviousColumn(Element* focusPtr) +{ + unsigned col = focusPtr->col_ - 1; + unsigned row = focusPtr->row_; + for (ChainLink* link = focusPtr->link; link; link = Chain_PrevLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + ElementOptions* elemOps = (ElementOptions*)elemPtr->ops(); + + if (!elemOps->label) + continue; + + if ((elemPtr->col_ == col) && (elemPtr->row_ == row)) + return elemPtr; + } + return NULL; +} + +Element* Legend::getFirstElement() +{ + for (ChainLink* link = Chain_FirstLink(graphPtr_->elements_.displayList); + link; link = Chain_NextLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + ElementOptions* elemOps = (ElementOptions*)elemPtr->ops(); + if (elemOps->label) + return elemPtr; + } + return NULL; +} + +Element* Legend::getLastElement() +{ + for (ChainLink* link = Chain_LastLink(graphPtr_->elements_.displayList); + link; link = Chain_PrevLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + ElementOptions* elemOps = (ElementOptions*)elemPtr->ops(); + if (elemOps->label) + return elemPtr; + } + return NULL; +} + +ClientData Legend::pickEntry(int xx, int yy, ClassId* classIdPtr) +{ + LegendOptions* ops = (LegendOptions*)ops_; + + int ww = width_; + int hh = height_; + + if (titleHeight_ > 0) + yy -= titleHeight_ + ops->yPad; + + xx -= x_ + ops->borderWidth; + yy -= y_ + ops->borderWidth; + ww -= 2 * ops->borderWidth + 2*ops->xPad; + hh -= 2 * ops->borderWidth + 2*ops->yPad; + + // In the bounding box? if so, compute the index + if (xx >= 0 && xx < ww && yy >= 0 && yy < hh) { + int row = yy / entryHeight_; + int column = xx / entryWidth_; + int nn = (column * nRows_) + row; + + // Legend entries are stored in bottom-to-top + if (nn < nEntries_) { + int count = 0; + for (ChainLink* link = Chain_FirstLink(graphPtr_->elements_.displayList); + link; link = Chain_NextLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + ElementOptions* elemOps = (ElementOptions*)elemPtr->ops(); + if (elemOps->label) { + if (count == nn) { + *classIdPtr = elemPtr->classId(); + return elemPtr; + } + count++; + } + } + } + } + + return NULL; +} + +// Support + +static int SelectionProc(ClientData clientData, int offset, char *buffer, + int maxBytes) +{ + Legend* legendPtr = (Legend*)clientData; + Graph* graphPtr = legendPtr->graphPtr_; + LegendOptions* ops = (LegendOptions*)legendPtr->ops(); + + if ((ops->exportSelection) == 0) + return -1; + + // Retrieve the names of the selected entries + Tcl_DString dString; + Tcl_DStringInit(&dString); + if (legendPtr->flags & SELECT_SORTED) { + for (ChainLink* link=Chain_FirstLink(legendPtr->selected_); + link; link = Chain_NextLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + Tcl_DStringAppend(&dString, elemPtr->name_, -1); + Tcl_DStringAppend(&dString, "\n", -1); + } + } + else { + for (ChainLink* link=Chain_FirstLink(graphPtr->elements_.displayList); + link; link = Chain_NextLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + if (legendPtr->entryIsSelected(elemPtr)) { + Tcl_DStringAppend(&dString, elemPtr->name_, -1); + Tcl_DStringAppend(&dString, "\n", -1); + } + } + } + + int nBytes = Tcl_DStringLength(&dString) - offset; + strncpy(buffer, Tcl_DStringValue(&dString) + offset, maxBytes); + Tcl_DStringFree(&dString); + buffer[maxBytes] = '\0'; + return MIN(nBytes, maxBytes); +} + +static void SelectCmdProc(ClientData clientData) +{ + Legend* legendPtr = (Legend*)clientData; + LegendOptions* ops = (LegendOptions*)legendPtr->ops(); + + Tcl_Preserve(legendPtr); + legendPtr->flags &= ~SELECT_PENDING; + if (ops->selectCmd) { + Tcl_Interp* interp = legendPtr->graphPtr_->interp_; + if (Tcl_GlobalEval(interp, ops->selectCmd) != TCL_OK) + Tcl_BackgroundError(interp); + } + Tcl_Release(legendPtr); +} + + + diff --git a/generic/tkbltGrLegd.h b/generic/tkbltGrLegd.h new file mode 100644 index 0000000..66ffbc1 --- /dev/null +++ b/generic/tkbltGrLegd.h @@ -0,0 +1,178 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGrLegend_h__ +#define __BltGrLegend_h__ + +#include + +#include "tkbltGrMisc.h" +#include "tkbltGrText.h" + +namespace Blt { + class Graph; + class Pick; + class Element; + + /* + * Selection related flags: + * SELECT_PENDING A "selection" command idle task is pending. + * SELECT_CLEAR Clear selection flag of entry. + * SELECT_SET Set selection flag of entry. + * SELECT_TOGGLE Toggle selection flag of entry. + * Mask of selection set/clear/toggle flags. + * SELECT_SORTED Indicates if the entries in the selection + * should be sorted or displayed in the order + * they were selected. + */ + +#define SELECT_CLEAR (1<<24) +#define SELECT_PENDING (1<<25) +#define SELECT_SET (1<<26) +#define SELECT_SORTED (1<<27) +#define SELECT_TOGGLE (SELECT_SET | SELECT_CLEAR) + + typedef enum { + SELECT_MODE_SINGLE, SELECT_MODE_MULTIPLE + } SelectMode; + + typedef struct { + Tk_3DBorder activeBg; + XColor* activeFgColor; + int activeRelief; + Tk_3DBorder normalBg; + XColor* fgColor; + Tk_Anchor anchor; + int borderWidth; + int reqColumns; + int exportSelection; + Dashes focusDashes; + XColor* focusColor; + TextStyleOptions style; + int hide; + int ixPad; + int iyPad; + int xPad; + int yPad; + int raised; + int relief; + int reqRows; + int entryBW; + int selBW; + int xReq; + int yReq; + int position; + const char *selectCmd; + Tk_3DBorder selOutFocusBg; + Tk_3DBorder selInFocusBg; + XColor* selOutFocusFgColor; + XColor* selInFocusFgColor; + SelectMode selectMode; + int selRelief; + const char *title; + TextStyleOptions titleStyle; + } LegendOptions; + + class Legend : public Pick { + public: + enum Position {RIGHT, LEFT, TOP, BOTTOM, PLOT, XY}; + + protected: + Tk_OptionTable optionTable_; + void* ops_; + + GC focusGC_; + Tcl_HashTable selectTable_; + + public: + Graph* graphPtr_; + unsigned int flags; + + int width_; + int height_; + int x_; + int y_; + + int nEntries_; + int nColumns_; + int nRows_; + int entryWidth_; + int entryHeight_; + BindTable* bindTable_; + Element* focusPtr_; + Element* selAnchorPtr_; + Element* selMarkPtr_; + Chain* selected_; + int titleWidth_; + int titleHeight_; + + protected: + void setOrigin(); + Element* getNextRow(Element*); + Element* getNextColumn(Element*); + Element* getPreviousRow(Element*); + Element* getPreviousColumn(Element*); + Element* getFirstElement(); + Element* getLastElement(); + + public: + Legend(Graph*); + virtual ~Legend(); + + int configure(); + void map(int, int); + void draw(Drawable drawable); + void print(PSOutput* ps); + void eventuallyInvokeSelectCmd(); + + void removeElement(Element*); + int getElementFromObj(Tcl_Obj*, Element**); + + void selectEntry(Element*); + void selectElement(Element*); + void deselectElement(Element*); + int selectRange(Element*, Element*); + void clearSelection(); + int entryIsSelected(Element*); + + void* ops() {return ops_;} + Tk_OptionTable optionTable() {return optionTable_;} + + Position position() {return (Position)((LegendOptions*)ops_)->position;} + int isRaised() {return ((LegendOptions*)ops_)->raised;} + int isHidden() {return ((LegendOptions*)ops_)->hide;} + + ClientData pickEntry(int, int, ClassId*); + }; +}; + +#endif diff --git a/generic/tkbltGrLegdOp.C b/generic/tkbltGrLegdOp.C new file mode 100644 index 0000000..139d2f1 --- /dev/null +++ b/generic/tkbltGrLegdOp.C @@ -0,0 +1,496 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#include "tkbltGrBind.h" +#include "tkbltGraph.h" +#include "tkbltGrLegd.h" +#include "tkbltGrLegdOp.h" +#include "tkbltGrElem.h" + +using namespace Blt; + +static Tk_LostSelProc LostSelectionProc; + +static int LegendObjConfigure(Graph* graphPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Legend* legendPtr = graphPtr->legend_; + Tk_SavedOptions savedOptions; + int mask =0; + int error; + Tcl_Obj* errorResult; + + for (error=0; error<=1; error++) { + if (!error) { + if (Tk_SetOptions(interp, (char*)legendPtr->ops(), + legendPtr->optionTable(), + objc, objv, graphPtr->tkwin_, &savedOptions, &mask) + != TCL_OK) + continue; + } + else { + errorResult = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); + } + + if (legendPtr->configure() != TCL_OK) + return TCL_ERROR; + graphPtr->flags |= mask; + graphPtr->eventuallyRedraw(); + + break; + } + + if (!error) { + Tk_FreeSavedOptions(&savedOptions); + return TCL_OK; + } + else { + Tcl_SetObjResult(interp, errorResult); + Tcl_DecrRefCount(errorResult); + return TCL_ERROR; + } +} + +static int CgetOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "cget option"); + return TCL_ERROR; + } + + Legend* legendPtr = graphPtr->legend_; + Tcl_Obj* objPtr = Tk_GetOptionValue(interp, + (char*)legendPtr->ops(), + legendPtr->optionTable(), + objv[3], graphPtr->tkwin_); + if (objPtr == NULL) + return TCL_ERROR; + else + Tcl_SetObjResult(interp, objPtr); + return TCL_OK; +} + +static int ConfigureOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + Legend* legendPtr = graphPtr->legend_; + if (objc <= 4) { + Tcl_Obj* objPtr = Tk_GetOptionInfo(interp, (char*)legendPtr->ops(), + legendPtr->optionTable(), + (objc == 4) ? objv[3] : NULL, + graphPtr->tkwin_); + if (objPtr == NULL) + return TCL_ERROR; + else + Tcl_SetObjResult(interp, objPtr); + return TCL_OK; + } + else + return LegendObjConfigure(graphPtr, interp, objc-3, objv+3); +} + +static int ActivateOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + Legend* legendPtr = graphPtr->legend_; + LegendOptions* ops = (LegendOptions*)legendPtr->ops(); + + const char *string = Tcl_GetString(objv[2]); + int active = (string[0] == 'a') ? 1 : 0; + int redraw = 0; + for (int ii=3; iielements_.displayList); + link; link = Chain_NextLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + if (Tcl_StringMatch(elemPtr->name_, pattern)) { + if (active) { + if (!elemPtr->labelActive_) { + elemPtr->labelActive_ =1; + redraw = 1; + } + } + else { + if (elemPtr->labelActive_) { + elemPtr->labelActive_ =0; + redraw = 1; + } + } + } + } + } + + if (redraw && !ops->hide) { + graphPtr->flags |= LAYOUT; + graphPtr->eventuallyRedraw(); + } + + // List active elements in stacking order + Tcl_Obj *listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + for (ChainLink* link = Chain_FirstLink(graphPtr->elements_.displayList); + link; link = Chain_NextLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + if (elemPtr->labelActive_) { + Tcl_Obj *objPtr = Tcl_NewStringObj(elemPtr->name_, -1); + Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); + } + } + Tcl_SetObjResult(interp, listObjPtr); + + return TCL_OK; +} + +static int BindOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + + if (objc == 3) { + Tcl_Obj* listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + Tcl_HashSearch iter; + for (Tcl_HashEntry* hPtr=Tcl_FirstHashEntry(&graphPtr->elements_.tagTable, &iter); hPtr; hPtr = Tcl_NextHashEntry(&iter)) { + char* tagName = + (char*)Tcl_GetHashKey(&graphPtr->elements_.tagTable, hPtr); + Tcl_Obj *objPtr = Tcl_NewStringObj(tagName, -1); + Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); + } + + Tcl_SetObjResult(interp, listObjPtr); + return TCL_OK; + } + + return graphPtr->legend_->bindTable_->configure(graphPtr->elementTag(Tcl_GetString(objv[3])), objc - 4, objv + 4); +} + +static int CurselectionOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + Legend* legendPtr = graphPtr->legend_; + Tcl_Obj *listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + if (legendPtr->flags & SELECT_SORTED) { + for (ChainLink* link = Chain_FirstLink(legendPtr->selected_); link; + link = Chain_NextLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + Tcl_Obj *objPtr = Tcl_NewStringObj(elemPtr->name_, -1); + Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); + } + } + else { + // List of selected entries is in stacking order + for (ChainLink* link = Chain_FirstLink(graphPtr->elements_.displayList); + link; link = Chain_NextLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + + if (legendPtr->entryIsSelected(elemPtr)) { + Tcl_Obj *objPtr = Tcl_NewStringObj(elemPtr->name_, -1); + Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); + } + } + } + Tcl_SetObjResult(interp, listObjPtr); + return TCL_OK; +} + +static int FocusOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + Legend* legendPtr = graphPtr->legend_; + + legendPtr->focusPtr_ = NULL; + if (objc == 4) { + Element* elemPtr; + if (legendPtr->getElementFromObj(objv[3], &elemPtr) != TCL_OK) + return TCL_ERROR; + + if (elemPtr) { + legendPtr->focusPtr_ = elemPtr; + + legendPtr->bindTable_->focusItem_ = (ClientData)elemPtr; + legendPtr->bindTable_->focusContext_ = elemPtr->classId(); + } + } + + graphPtr->flags |= CACHE; + graphPtr->eventuallyRedraw(); + + if (legendPtr->focusPtr_) + Tcl_SetStringObj(Tcl_GetObjResult(interp),legendPtr->focusPtr_->name_,-1); + + return TCL_OK; +} + +static int GetOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc<3) + return TCL_ERROR; + + Legend* legendPtr = graphPtr->legend_; + LegendOptions* ops = (LegendOptions*)legendPtr->ops(); + + if (((ops->hide) == 0) && (legendPtr->nEntries_ > 0)) { + Element* elemPtr; + + if (legendPtr->getElementFromObj(objv[3], &elemPtr) != TCL_OK) + return TCL_ERROR; + + if (elemPtr) + Tcl_SetStringObj(Tcl_GetObjResult(interp), elemPtr->name_, -1); + } + return TCL_OK; +} + +const Ensemble Blt::legendEnsemble[] = { + {"activate", ActivateOp, 0}, + {"bind", BindOp, 0}, + {"cget", CgetOp, 0}, + {"configure", ConfigureOp, 0}, + {"curselection", CurselectionOp, 0}, + {"deactivate", ActivateOp, 0}, + {"focus", FocusOp, 0}, + {"get", GetOp, 0}, + {"selection", 0, selectionEnsemble}, + { 0,0,0 } +}; + +// Selection Ops + +static int SelectionAnchorOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + Legend* legendPtr = graphPtr->legend_; + Element* elemPtr; + + if (legendPtr->getElementFromObj(objv[4], &elemPtr) != TCL_OK) + return TCL_ERROR; + + // Set both the anchor and the mark. Indicates that a single entry + // is selected + legendPtr->selAnchorPtr_ = elemPtr; + legendPtr->selMarkPtr_ = NULL; + if (elemPtr) + Tcl_SetStringObj(Tcl_GetObjResult(interp), elemPtr->name_, -1); + + graphPtr->flags |= CACHE; + graphPtr->eventuallyRedraw(); + + return TCL_OK; +} + +static int SelectionClearallOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + Legend* legendPtr = graphPtr->legend_; + legendPtr->clearSelection(); + + graphPtr->flags |= CACHE; + graphPtr->eventuallyRedraw(); + + return TCL_OK; +} + +static int SelectionIncludesOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + Legend* legendPtr = graphPtr->legend_; + Element* elemPtr; + if (legendPtr->getElementFromObj(objv[4], &elemPtr) != TCL_OK) + return TCL_ERROR; + + int boo = legendPtr->entryIsSelected(elemPtr); + Tcl_SetBooleanObj(Tcl_GetObjResult(interp), boo); + return TCL_OK; +} + +static int SelectionMarkOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + Legend* legendPtr = graphPtr->legend_; + LegendOptions* ops = (LegendOptions*)legendPtr->ops(); + Element* elemPtr; + + if (legendPtr->getElementFromObj(objv[4], &elemPtr) != TCL_OK) + return TCL_ERROR; + + if (legendPtr->selAnchorPtr_ == NULL) { + Tcl_AppendResult(interp, "selection anchor must be set first", NULL); + return TCL_ERROR; + } + + if (legendPtr->selMarkPtr_ != elemPtr) { + // Deselect entry from the list all the way back to the anchor + ChainLink *link, *next; + for (link = Chain_LastLink(legendPtr->selected_); link; link = next) { + next = Chain_PrevLink(link); + Element *selectPtr = (Element*)Chain_GetValue(link); + if (selectPtr == legendPtr->selAnchorPtr_) + break; + + legendPtr->deselectElement(selectPtr); + } + + legendPtr->flags &= ~SELECT_TOGGLE; + legendPtr->flags |= SELECT_SET; + legendPtr->selectRange(legendPtr->selAnchorPtr_, elemPtr); + Tcl_SetStringObj(Tcl_GetObjResult(interp), elemPtr->name_, -1); + legendPtr->selMarkPtr_ = elemPtr; + + if (ops->selectCmd) + legendPtr->eventuallyInvokeSelectCmd(); + + graphPtr->flags |= CACHE; + graphPtr->eventuallyRedraw(); + } + return TCL_OK; +} + +static int SelectionPresentOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + Legend* legendPtr = graphPtr->legend_; + int boo = (Chain_GetLength(legendPtr->selected_) > 0); + Tcl_SetBooleanObj(Tcl_GetObjResult(interp), boo); + return TCL_OK; +} + +static int SelectionSetOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + Legend* legendPtr = graphPtr->legend_; + LegendOptions* ops = (LegendOptions*)legendPtr->ops(); + + legendPtr->flags &= ~SELECT_TOGGLE; + const char* string = Tcl_GetString(objv[3]); + switch (string[0]) { + case 's': + legendPtr->flags |= SELECT_SET; + break; + case 'c': + legendPtr->flags |= SELECT_CLEAR; + break; + case 't': + legendPtr->flags |= SELECT_TOGGLE; + break; + } + + Element *firstPtr; + if (legendPtr->getElementFromObj(objv[4], &firstPtr) != TCL_OK) + return TCL_ERROR; + ElementOptions* eops = (ElementOptions*)firstPtr->ops(); + + if ((eops->hide) && ((legendPtr->flags & SELECT_CLEAR)==0)) { + Tcl_AppendResult(interp, "can't select hidden node \"", + Tcl_GetString(objv[4]), "\"", (char *)NULL); + return TCL_ERROR; + } + + Element* lastPtr = firstPtr; + if (objc > 5) { + if (legendPtr->getElementFromObj(objv[5], &lastPtr) != TCL_OK) + return TCL_ERROR; + ElementOptions* eops = (ElementOptions*)firstPtr->ops(); + + if (eops->hide && ((legendPtr->flags & SELECT_CLEAR) == 0)) { + Tcl_AppendResult(interp, "can't select hidden node \"", + Tcl_GetString(objv[5]), "\"", (char *)NULL); + return TCL_ERROR; + } + } + + if (firstPtr == lastPtr) + legendPtr->selectEntry(firstPtr); + else + legendPtr->selectRange(firstPtr, lastPtr); + + // Set both the anchor and the mark. Indicates that a single entry is + // selected + if (legendPtr->selAnchorPtr_ == NULL) + legendPtr->selAnchorPtr_ = firstPtr; + + if (ops->exportSelection) + Tk_OwnSelection(graphPtr->tkwin_, XA_PRIMARY, LostSelectionProc, legendPtr); + + if (ops->selectCmd) + legendPtr->eventuallyInvokeSelectCmd(); + + graphPtr->flags |= CACHE; + graphPtr->eventuallyRedraw(); + + return TCL_OK; +} + +const Ensemble Blt::selectionEnsemble[] = { + {"anchor", SelectionAnchorOp, 0}, + {"clear", SelectionSetOp, 0}, + {"clearall", SelectionClearallOp, 0}, + {"includes", SelectionIncludesOp, 0}, + {"mark", SelectionMarkOp, 0}, + {"present", SelectionPresentOp, 0}, + {"set", SelectionSetOp, 0}, + {"toggle", SelectionSetOp, 0}, + { 0,0,0 } +}; + +// Support + +static void LostSelectionProc(ClientData clientData) +{ + Legend* legendPtr = (Legend*)clientData; + LegendOptions* ops = (LegendOptions*)legendPtr->ops(); + Graph* graphPtr = legendPtr->graphPtr_; + + if (ops->exportSelection) + legendPtr->clearSelection(); + + graphPtr->flags |= CACHE; + graphPtr->eventuallyRedraw(); +} + + + + diff --git a/generic/tkbltGrLegdOp.h b/generic/tkbltGrLegdOp.h new file mode 100644 index 0000000..6369a2b --- /dev/null +++ b/generic/tkbltGrLegdOp.h @@ -0,0 +1,40 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGrLegdOp_h__ +#define __BltGrLegdOp_h__ + +#include "tkbltGraph.h" + +namespace Blt { + extern const Ensemble legendEnsemble[]; + extern const Ensemble selectionEnsemble[]; +}; + +#endif diff --git a/generic/tkbltGrMarker.C b/generic/tkbltGrMarker.C new file mode 100644 index 0000000..6f701f8 --- /dev/null +++ b/generic/tkbltGrMarker.C @@ -0,0 +1,177 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#include + +#include "tkbltGraph.h" +#include "tkbltGrBind.h" +#include "tkbltGrMarker.h" +#include "tkbltGrAxis.h" +#include "tkbltGrMisc.h" + +using namespace Blt; + +Marker::Marker(Graph* graphPtr, const char* name, Tcl_HashEntry* hPtr) +{ + optionTable_ =NULL; + ops_ =NULL; + + graphPtr_ =graphPtr; + name_ = dupstr(name); + hashPtr_ = hPtr; + link =NULL; + flags =0; + clipped_ =0; +} + +Marker::~Marker() +{ + graphPtr_->bindTable_->deleteBindings(this); + + if (link) + graphPtr_->markers_.displayList->deleteLink(link); + + if (hashPtr_) + Tcl_DeleteHashEntry(hashPtr_); + + delete [] name_; + + Tk_FreeConfigOptions((char*)ops_, optionTable_, graphPtr_->tkwin_); + free(ops_); +} + +double Marker::HMap(Axis *axisPtr, double x) +{ + AxisOptions* ops = (AxisOptions*)axisPtr->ops(); + + if (x == DBL_MAX) + x = 1.0; + else if (x == -DBL_MAX) + x = 0.0; + else { + if (ops->logScale) { + if (x > 0.0) + x = log10(x); + else if (x < 0.0) + x = 0.0; + } + x = (x - axisPtr->axisRange_.min) * axisPtr->axisRange_.scale; + } + if (ops->descending) + x = 1.0 - x; + + // Horizontal transformation + return (x * axisPtr->screenRange_ + axisPtr->screenMin_); +} + +double Marker::VMap(Axis *axisPtr, double y) +{ + AxisOptions* ops = (AxisOptions*)axisPtr->ops(); + + if (y == DBL_MAX) + y = 1.0; + else if (y == -DBL_MAX) + y = 0.0; + else { + if (ops->logScale) { + if (y > 0.0) + y = log10(y); + else if (y < 0.0) + y = 0.0; + } + y = (y - axisPtr->axisRange_.min) * axisPtr->axisRange_.scale; + } + if (ops->descending) + y = 1.0 - y; + + // Vertical transformation + return (((1.0 - y) * axisPtr->screenRange_) + axisPtr->screenMin_); +} + +Point2d Marker::mapPoint(Point2d* pointPtr, Axis* xAxis, Axis* yAxis) +{ + GraphOptions* gops = (GraphOptions*)graphPtr_->ops_; + Point2d result; + if (gops->inverted) { + result.x = HMap(yAxis, pointPtr->y); + result.y = VMap(xAxis, pointPtr->x); + } + else { + result.x = HMap(xAxis, pointPtr->x); + result.y = VMap(yAxis, pointPtr->y); + } + + return result; +} + +int Marker::boxesDontOverlap(Graph* graphPtr_, Region2d *extsPtr) +{ + return (((double)graphPtr_->right_ < extsPtr->left) || + ((double)graphPtr_->bottom_ < extsPtr->top) || + (extsPtr->right < (double)graphPtr_->left_) || + (extsPtr->bottom < (double)graphPtr_->top_)); +} + +int Marker::regionInPolygon(Region2d *regionPtr, Point2d *points, int nPoints, + int enclosed) +{ + if (enclosed) { + // All points of the polygon must be inside the rectangle. + for (Point2d *pp = points, *pend = pp + nPoints; pp < pend; pp++) { + if ((pp->x < regionPtr->left) || (pp->x > regionPtr->right) || + (pp->y < regionPtr->top) || (pp->y > regionPtr->bottom)) { + return 0; /* One point is exterior. */ + } + } + return 1; + } + else { + // If any segment of the polygon clips the bounding region, the + // polygon overlaps the rectangle. + points[nPoints] = points[0]; + for (Point2d *pp = points, *pend = pp + nPoints; pp < pend; pp++) { + Point2d p = *pp; + Point2d q = *(pp + 1); + if (lineRectClip(regionPtr, &p, &q)) + return 1; + } + + // Otherwise the polygon and rectangle are either disjoint or + // enclosed. Check if one corner of the rectangle is inside the polygon. + Point2d r; + r.x = regionPtr->left; + r.y = regionPtr->top; + + return pointInPolygon(&r, points, nPoints); + } +} + diff --git a/generic/tkbltGrMarker.h b/generic/tkbltGrMarker.h new file mode 100644 index 0000000..573357d --- /dev/null +++ b/generic/tkbltGrMarker.h @@ -0,0 +1,103 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGrMarker_h__ +#define __BltGrMarker_h__ + +#include + +#include "tkbltChain.h" + +#include "tkbltGrMisc.h" +#include "tkbltGrPSOutput.h" + +namespace Blt { + class Graph; + class Postscript; + class Axis; + + typedef struct { + Point2d* points; + int num; + } Coords; + + typedef struct { + const char** tags; + Coords* worldPts; + const char* elemName; + Axis* xAxis; + Axis* yAxis; + int hide; + int drawUnder; + int xOffset; + int yOffset; + } MarkerOptions; + + class Marker { + protected: + Tk_OptionTable optionTable_; + void* ops_; + + public: + Graph* graphPtr_; + const char *name_; + Tcl_HashEntry* hashPtr_; + ChainLink* link; + unsigned int flags; + int clipped_; + + protected: + double HMap(Axis*, double); + double VMap(Axis*, double); + Point2d mapPoint(Point2d*, Axis*, Axis*); + int boxesDontOverlap(Graph*, Region2d*); + int regionInPolygon(Region2d *extsPtr, Point2d *points, + int nPoints, int enclosed); + + public: + Marker(Graph*, const char*, Tcl_HashEntry*); + virtual ~Marker(); + + virtual int configure() =0; + virtual void draw(Drawable) =0; + virtual void map() =0; + virtual int pointIn(Point2d*) =0; + virtual int regionIn(Region2d*, int) =0; + virtual void print(PSOutput*) =0; + + virtual ClassId classId() =0; + virtual const char* className() =0; + virtual const char* typeName() =0; + + Tk_OptionTable optionTable() {return optionTable_;} + void* ops() {return ops_;} + }; +}; + +#endif diff --git a/generic/tkbltGrMarkerLine.C b/generic/tkbltGrMarkerLine.C new file mode 100644 index 0000000..82c9ab8 --- /dev/null +++ b/generic/tkbltGrMarkerLine.C @@ -0,0 +1,298 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#include + +#include "tkbltGraph.h" +#include "tkbltGrMarkerLine.h" +#include "tkbltGrMarkerOption.h" +#include "tkbltGrMisc.h" +#include "tkbltGrDef.h" +#include "tkbltConfig.h" +#include "tkbltGrPSOutput.h" + +using namespace Blt; + +#define BOUND(x, lo, hi) (((x) > (hi)) ? (hi) : ((x) < (lo)) ? (lo) : (x)) + +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_CUSTOM, "-bindtags", "bindTags", "BindTags", + "Line all", -1, Tk_Offset(LineMarkerOptions, tags), + TK_OPTION_NULL_OK, &listObjOption, 0}, + {TK_OPTION_CUSTOM, "-cap", "cap", "Cap", + "butt", -1, Tk_Offset(LineMarkerOptions, capStyle), + 0, &capStyleObjOption, 0}, + {TK_OPTION_CUSTOM, "-coords", "coords", "Coords", + NULL, -1, Tk_Offset(LineMarkerOptions, worldPts), + TK_OPTION_NULL_OK, &coordsObjOption, 0}, + {TK_OPTION_CUSTOM, "-dashes", "dashes", "Dashes", + NULL, -1, Tk_Offset(LineMarkerOptions, dashes), + TK_OPTION_NULL_OK, &dashesObjOption, 0}, + {TK_OPTION_PIXELS, "-dashoffset", "dashOffset", "DashOffset", + "0", -1, Tk_Offset(LineMarkerOptions, dashes.offset), 0, NULL, 0}, + {TK_OPTION_STRING, "-element", "element", "Element", + NULL, -1, Tk_Offset(LineMarkerOptions, elemName), + TK_OPTION_NULL_OK, NULL, 0}, + {TK_OPTION_COLOR, "-fill", "fill", "Fill", + NULL, -1, Tk_Offset(LineMarkerOptions, fillColor), + TK_OPTION_NULL_OK, NULL, 0}, + {TK_OPTION_CUSTOM, "-join", "join", "Join", + "miter", -1, Tk_Offset(LineMarkerOptions, joinStyle), + 0, &joinStyleObjOption, 0}, + {TK_OPTION_PIXELS, "-linewidth", "lineWidth", "LineWidth", + "1", -1, Tk_Offset(LineMarkerOptions, lineWidth), 0, NULL, 0}, + {TK_OPTION_BOOLEAN, "-hide", "hide", "Hide", + "no", -1, Tk_Offset(LineMarkerOptions, hide), 0, NULL, 0}, + {TK_OPTION_CUSTOM, "-mapx", "mapX", "MapX", + "x", -1, Tk_Offset(LineMarkerOptions, xAxis), 0, &xAxisObjOption, 0}, + {TK_OPTION_CUSTOM, "-mapy", "mapY", "MapY", + "y", -1, Tk_Offset(LineMarkerOptions, yAxis), 0, &yAxisObjOption, 0}, + {TK_OPTION_COLOR, "-outline", "outline", "Outline", + STD_NORMAL_FOREGROUND, -1, Tk_Offset(LineMarkerOptions, outlineColor), + TK_OPTION_NULL_OK, NULL, 0}, + {TK_OPTION_BOOLEAN, "-under", "under", "Under", + "no", -1, Tk_Offset(LineMarkerOptions, drawUnder), 0, NULL, CACHE}, + {TK_OPTION_PIXELS, "-xoffset", "xOffset", "XOffset", + "0", -1, Tk_Offset(LineMarkerOptions, xOffset), 0, NULL, 0}, + {TK_OPTION_PIXELS, "-yoffset", "yOffset", "YOffset", + "0", -1, Tk_Offset(LineMarkerOptions, yOffset), 0, NULL, 0}, + {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, -1, 0, 0, 0} +}; + +LineMarker::LineMarker(Graph* graphPtr, const char* name, Tcl_HashEntry* hPtr) + : Marker(graphPtr, name, hPtr) +{ + ops_ = (LineMarkerOptions*)calloc(1, sizeof(LineMarkerOptions)); + optionTable_ = Tk_CreateOptionTable(graphPtr->interp_, optionSpecs); + + gc_ =NULL; + segments_ =NULL; + nSegments_ =0; +} + +LineMarker::~LineMarker() +{ + if (gc_) + graphPtr_->freePrivateGC(gc_); + delete [] segments_; +} + +int LineMarker::configure() +{ + LineMarkerOptions* ops = (LineMarkerOptions*)ops_; + + unsigned long gcMask = (GCLineWidth | GCLineStyle | GCCapStyle | GCJoinStyle); + XGCValues gcValues; + if (ops->outlineColor) { + gcMask |= GCForeground; + gcValues.foreground = ops->outlineColor->pixel; + } + if (ops->fillColor) { + gcMask |= GCBackground; + gcValues.background = ops->fillColor->pixel; + } + gcValues.cap_style = ops->capStyle; + gcValues.join_style = ops->joinStyle; + gcValues.line_width = ops->lineWidth; + gcValues.line_style = LineSolid; + if (LineIsDashed(ops->dashes)) { + gcValues.line_style = + (gcMask & GCBackground) ? LineDoubleDash : LineOnOffDash; + } + + GC newGC = graphPtr_->getPrivateGC(gcMask, &gcValues); + if (gc_) + graphPtr_->freePrivateGC(gc_); + + if (LineIsDashed(ops->dashes)) + graphPtr_->setDashes(newGC, &ops->dashes); + gc_ = newGC; + + return TCL_OK; +} + +void LineMarker::draw(Drawable drawable) +{ + if (nSegments_ > 0) + graphPtr_->drawSegments(drawable, gc_, segments_, nSegments_); +} + +void LineMarker::map() +{ + LineMarkerOptions* ops = (LineMarkerOptions*)ops_; + + delete [] segments_; + segments_ = NULL; + nSegments_ = 0; + + if (!ops->worldPts || (ops->worldPts->num < 2)) + return; + + Region2d extents; + graphPtr_->extents(&extents); + + // Allow twice the number of world coordinates. The line will represented + // as series of line segments, not one continous polyline. This is + // because clipping against the plot area may chop the line into several + // disconnected segments. + + Segment2d* segments = new Segment2d[ops->worldPts->num]; + Point2d* srcPtr = ops->worldPts->points; + Point2d p = mapPoint(srcPtr, ops->xAxis, ops->yAxis); + p.x += ops->xOffset; + p.y += ops->yOffset; + + Segment2d* segPtr = segments; + Point2d* pend; + for (srcPtr++, pend = ops->worldPts->points + ops->worldPts->num; + srcPtr < pend; srcPtr++) { + Point2d next = mapPoint(srcPtr, ops->xAxis, ops->yAxis); + next.x += ops->xOffset; + next.y += ops->yOffset; + Point2d q = next; + + if (lineRectClip(&extents, &p, &q)) { + segPtr->p = p; + segPtr->q = q; + segPtr++; + } + p = next; + } + nSegments_ = segPtr - segments; + segments_ = segments; + clipped_ = (nSegments_ == 0); +} + +int LineMarker::pointIn(Point2d *samplePtr) +{ + GraphOptions* gops = (GraphOptions*)graphPtr_->ops_; + return pointInSegments(samplePtr, segments_, nSegments_, + (double)gops->search.halo); +} + +int LineMarker::pointInSegments(Point2d* samplePtr, Segment2d* segments, + int nSegments, double halo) +{ + double minDist = DBL_MAX; + for (Segment2d *sp = segments, *send = sp + nSegments; sp < send; sp++) { + Point2d t = getProjection((int)samplePtr->x, (int)samplePtr->y, + &sp->p, &sp->q); + double right; + double left; + if (sp->p.x > sp->q.x) { + right = sp->p.x; + left = sp->q.x; + } + else { + right = sp->q.x; + left = sp->p.x; + } + + double top; + double bottom; + if (sp->p.y > sp->q.y) { + bottom = sp->p.y; + top = sp->q.y; + } + else { + bottom = sp->q.y; + top = sp->p.y; + } + + Point2d p; + p.x = BOUND(t.x, left, right); + p.y = BOUND(t.y, top, bottom); + + double dist = hypot(p.x - samplePtr->x, p.y - samplePtr->y); + if (dist < minDist) + minDist = dist; + } + + return (minDist < halo); +} + +int LineMarker::regionIn(Region2d *extsPtr, int enclosed) +{ + LineMarkerOptions* ops = (LineMarkerOptions*)ops_; + + if (!ops->worldPts || ops->worldPts->num < 2) + return 0; + + if (enclosed) { + for (Point2d *pp = ops->worldPts->points, *pend = pp + ops->worldPts->num; + pp < pend; pp++) { + Point2d p = mapPoint(pp, ops->xAxis, ops->yAxis); + if ((p.x < extsPtr->left) && (p.x > extsPtr->right) && + (p.y < extsPtr->top) && (p.y > extsPtr->bottom)) { + return 0; + } + } + return 1; + } + else { + int count = 0; + for (Point2d *pp=ops->worldPts->points, *pend=pp+(ops->worldPts->num - 1); + pp < pend; pp++) { + Point2d p = mapPoint(pp, ops->xAxis, ops->yAxis); + Point2d q = mapPoint(pp + 1, ops->xAxis, ops->yAxis); + if (lineRectClip(extsPtr, &p, &q)) + count++; + } + return (count > 0); /* At least 1 segment passes through + * region. */ + } +} + +void LineMarker::print(PSOutput* psPtr) +{ + LineMarkerOptions* ops = (LineMarkerOptions*)ops_; + + if (nSegments_ > 0) { + psPtr->setLineAttributes(ops->outlineColor, ops->lineWidth, + &ops->dashes, ops->capStyle, ops->joinStyle); + if ((LineIsDashed(ops->dashes)) && (ops->fillColor)) { + psPtr->append("/DashesProc {\n gsave\n "); + psPtr->setBackground(ops->fillColor); + psPtr->append(" "); + psPtr->setDashes(NULL); + psPtr->append("stroke\n"); + psPtr->append("grestore\n"); + psPtr->append("} def\n"); + } + else + psPtr->append("/DashesProc {} def\n"); + + psPtr->printSegments(segments_, nSegments_); + } +} + + diff --git a/generic/tkbltGrMarkerLine.h b/generic/tkbltGrMarkerLine.h new file mode 100644 index 0000000..3191951 --- /dev/null +++ b/generic/tkbltGrMarkerLine.h @@ -0,0 +1,82 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGrMarkerLine_h__ +#define __BltGrMarkerLine_h__ + +#include "tkbltGrMarker.h" + +namespace Blt { + + typedef struct { + const char** tags; + Coords* worldPts; + const char* elemName; + Axis* xAxis; + Axis* yAxis; + int hide; + int drawUnder; + int xOffset; + int yOffset; + + int capStyle; + Dashes dashes; + XColor* fillColor; + int joinStyle; + int lineWidth; + XColor* outlineColor; + } LineMarkerOptions; + + class LineMarker : public Marker { + protected: + GC gc_; + Segment2d* segments_; + int nSegments_; + + protected: + int configure(); + void draw(Drawable); + void map(); + int pointIn(Point2d*); + int regionIn(Region2d*, int); + void print(PSOutput*); + int pointInSegments(Point2d *samplePtr, Segment2d *segments, + int nSegments, double halo); + + public: + LineMarker(Graph*, const char*, Tcl_HashEntry*); + virtual ~LineMarker(); + + ClassId classId() {return CID_MARKER_LINE;} + const char* className() {return "LineMarker";} + const char* typeName() {return "line";} + }; +}; + +#endif diff --git a/generic/tkbltGrMarkerOp.C b/generic/tkbltGrMarkerOp.C new file mode 100644 index 0000000..0865556 --- /dev/null +++ b/generic/tkbltGrMarkerOp.C @@ -0,0 +1,495 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "tkbltGrBind.h" +#include "tkbltGraph.h" +#include "tkbltGrElem.h" +#include "tkbltGrMarkerOp.h" +#include "tkbltGrMarker.h" +#include "tkbltGrMarkerLine.h" +#include "tkbltGrMarkerPolygon.h" +#include "tkbltGrMarkerText.h" + +using namespace Blt; + +static int GetMarkerFromObj(Tcl_Interp* interp, Graph* graphPtr, + Tcl_Obj* objPtr, Marker** markerPtrPtr); + +#define FIND_ENCLOSED (1<<0) +#define FIND_OVERLAPPING (1<<1) + +static int MarkerObjConfigure( Graph* graphPtr,Marker* markerPtr, + Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Tk_SavedOptions savedOptions; + int mask =0; + int error; + Tcl_Obj* errorResult; + + for (error=0; error<=1; error++) { + if (!error) { + if (Tk_SetOptions(interp, (char*)markerPtr->ops(), + markerPtr->optionTable(), + objc, objv, graphPtr->tkwin_, &savedOptions, &mask) + != TCL_OK) + continue; + } + else { + errorResult = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); + } + + markerPtr->flags |= MAP_ITEM; + if (markerPtr->configure() != TCL_OK) + return TCL_ERROR; + + MarkerOptions* ops = (MarkerOptions*)markerPtr->ops(); + if (ops->drawUnder) + graphPtr->flags |= CACHE; + graphPtr->flags |= mask; + graphPtr->eventuallyRedraw(); + + break; + } + + if (!error) { + Tk_FreeSavedOptions(&savedOptions); + return TCL_OK; + } + else { + Tcl_SetObjResult(interp, errorResult); + Tcl_DecrRefCount(errorResult); + return TCL_ERROR; + } +} + +static int CreateMarker(Graph* graphPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + int offset = 5; + const char* name =NULL; + ostringstream str; + if (objc == 4) { + offset = 4; + str << "marker" << graphPtr->nextMarkerId_++ << ends; + name = dupstr(str.str().c_str()); + } + else { + name = dupstr(Tcl_GetString(objv[4])); + if (name[0] == '-') { + delete [] name; + offset = 4; + str << "marker" << graphPtr->nextMarkerId_++ << ends; + name = dupstr(str.str().c_str()); + } + } + + int isNew; + Tcl_HashEntry* hPtr = + Tcl_CreateHashEntry(&graphPtr->markers_.table, name, &isNew); + if (!isNew) { + Tcl_AppendResult(graphPtr->interp_, "marker \"", name, + "\" already exists in \"", Tcl_GetString(objv[0]), + "\"", NULL); + delete [] name; + return TCL_ERROR; + } + + const char* type = Tcl_GetString(objv[3]); + Marker* markerPtr; + if (!strcmp(type, "line")) + markerPtr = new LineMarker(graphPtr, name, hPtr); + else if (!strcmp(type, "polygon")) + markerPtr = new PolygonMarker(graphPtr, name, hPtr); + else if (!strcmp(type, "text")) + markerPtr = new TextMarker(graphPtr, name, hPtr); + else { + Tcl_DeleteHashEntry(hPtr); + delete [] name; + Tcl_AppendResult(interp, "unknown marker type ", type, NULL); + return TCL_ERROR; + } + + Tcl_SetHashValue(hPtr, markerPtr); + + if ((Tk_InitOptions(graphPtr->interp_, (char*)markerPtr->ops(), markerPtr->optionTable(), graphPtr->tkwin_) != TCL_OK) || (MarkerObjConfigure(graphPtr, markerPtr, interp, objc-offset, objv+offset) != TCL_OK)) { + delete markerPtr; + delete [] name; + return TCL_ERROR; + } + + // Unlike elements, new markers are drawn on top of old markers + markerPtr->link = graphPtr->markers_.displayList->prepend(markerPtr); + + Tcl_SetStringObj(Tcl_GetObjResult(interp), name, -1); + + delete [] name; + return TCL_OK; +} + +static int CgetOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc!=5) { + Tcl_WrongNumArgs(interp, 3, objv, "markerId option"); + return TCL_ERROR; + } + + Marker* markerPtr; + if (GetMarkerFromObj(interp, graphPtr, objv[3], &markerPtr) != TCL_OK) + return TCL_ERROR; + + Tcl_Obj* objPtr = Tk_GetOptionValue(interp, + (char*)markerPtr->ops(), + markerPtr->optionTable(), + objv[4], graphPtr->tkwin_); + if (objPtr == NULL) + return TCL_ERROR; + else + Tcl_SetObjResult(interp, objPtr); + return TCL_OK; +} + +static int ConfigureOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc<4) { + Tcl_WrongNumArgs(interp, 3, objv, "markerId ?option value...?"); + return TCL_ERROR; + } + + Marker* markerPtr; + if (GetMarkerFromObj(interp, graphPtr, objv[3], &markerPtr) != TCL_OK) + return TCL_ERROR; + + if (objc <= 5) { + Tcl_Obj* objPtr = Tk_GetOptionInfo(interp, (char*)markerPtr->ops(), + markerPtr->optionTable(), + (objc == 5) ? objv[4] : NULL, + graphPtr->tkwin_); + if (objPtr == NULL) + return TCL_ERROR; + else + Tcl_SetObjResult(interp, objPtr); + return TCL_OK; + } + else + return MarkerObjConfigure(graphPtr, markerPtr, interp, objc-4, objv+4); +} + +static int BindOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc == 3) { + Tcl_Obj *listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + Tcl_HashSearch iter; + for (Tcl_HashEntry* hp = + Tcl_FirstHashEntry(&graphPtr->markers_.tagTable, &iter); + hp; hp = Tcl_NextHashEntry(&iter)) { + + const char* tag = + (const char*)Tcl_GetHashKey(&graphPtr->markers_.tagTable, hp); + Tcl_Obj* objPtr = Tcl_NewStringObj(tag, -1); + Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); + } + Tcl_SetObjResult(interp, listObjPtr); + return TCL_OK; + } else if (objc >= 4) { + return graphPtr->bindTable_->configure(graphPtr->markerTag(Tcl_GetString(objv[3])), objc - 4, objv + 4); + } else { + Tcl_WrongNumArgs(interp, 3, objv, "markerId ?tag? ?sequence? ?command?"); + return TCL_ERROR; + } +} + +static int CreateOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc<4) { + Tcl_WrongNumArgs(interp, 2, objv, "markerId ?type? ?option value...?"); + return TCL_ERROR; + } + if (CreateMarker(graphPtr, interp, objc, objv) != TCL_OK) + return TCL_ERROR; + // set in CreateMarker + // Tcl_SetObjResult(interp, objv[3]); + + graphPtr->flags |= CACHE; + graphPtr->eventuallyRedraw(); + + return TCL_OK; +} + +static int DeleteOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + + if (objc<4) { + Tcl_WrongNumArgs(interp, 2, objv, "markerId..."); + return TCL_ERROR; + } + + int res = TCL_OK; + + for (int ii=3; iimarkers_.table, string); + if (!hPtr) { + if (res == TCL_OK) { + Tcl_AppendResult(interp, "can't find markers in \"", + Tk_PathName(graphPtr->tkwin_), "\":", NULL); + } + Tcl_AppendResult(interp, " ", Tcl_GetString(objv[ii]), NULL); + res = TCL_ERROR; + } else { + markerPtr = (Marker*)Tcl_GetHashValue(hPtr); + delete markerPtr; + } + } + + graphPtr->flags |= CACHE; + graphPtr->eventuallyRedraw(); + + return res; +} + +static int ExistsOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc!=4) { + Tcl_WrongNumArgs(interp, 3, objv, "markerId"); + return TCL_ERROR; + } + + Tcl_HashEntry* hPtr = + Tcl_FindHashEntry(&graphPtr->markers_.table, Tcl_GetString(objv[3])); + Tcl_SetBooleanObj(Tcl_GetObjResult(interp), (hPtr != NULL)); + + return TCL_OK; +} + +static int FindOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc!=8) { + Tcl_WrongNumArgs(interp, 3, objv, "searchtype left top right bottom"); + return TCL_ERROR; + } + + const char* string = Tcl_GetString(objv[3]); + int mode; + if (strcmp(string, "enclosed") == 0) + mode = FIND_ENCLOSED; + else if (strcmp(string, "overlapping") == 0) + mode = FIND_OVERLAPPING; + else { + Tcl_AppendResult(interp, "bad search type \"", string, + ": should be \"enclosed\", or \"overlapping\"", + NULL); + return TCL_ERROR; + } + + int left, right, top, bottom; + if ((Tcl_GetIntFromObj(interp, objv[4], &left) != TCL_OK) || + (Tcl_GetIntFromObj(interp, objv[5], &top) != TCL_OK) || + (Tcl_GetIntFromObj(interp, objv[6], &right) != TCL_OK) || + (Tcl_GetIntFromObj(interp, objv[7], &bottom) != TCL_OK)) { + return TCL_ERROR; + } + + Region2d extents; + if (left < right) { + extents.left = (double)left; + extents.right = (double)right; + } + else { + extents.left = (double)right; + extents.right = (double)left; + } + if (top < bottom) { + extents.top = (double)top; + extents.bottom = (double)bottom; + } + else { + extents.top = (double)bottom; + extents.bottom = (double)top; + } + + int enclosed = (mode == FIND_ENCLOSED); + for (ChainLink* link = Chain_FirstLink(graphPtr->markers_.displayList); + link; link = Chain_NextLink(link)) { + Marker* markerPtr = (Marker*)Chain_GetValue(link); + MarkerOptions* ops = (MarkerOptions*)markerPtr->ops(); + if (ops->hide) + continue; + + if (graphPtr->isElementHidden(markerPtr)) + continue; + + if (markerPtr->regionIn(&extents, enclosed)) { + Tcl_Obj* objPtr = Tcl_GetObjResult(interp); + Tcl_SetStringObj(objPtr, markerPtr->name_, -1); + return TCL_OK; + } + } + + Tcl_SetStringObj(Tcl_GetObjResult(interp), "", -1); + return TCL_OK; +} + +static int NamesOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + Tcl_Obj* listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + if (objc == 3) { + for (ChainLink* link=Chain_FirstLink(graphPtr->markers_.displayList); + link; link = Chain_NextLink(link)) { + Marker* markerPtr = (Marker*)Chain_GetValue(link); + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewStringObj(markerPtr->name_, -1)); + } + } + else { + for (ChainLink* link=Chain_FirstLink(graphPtr->markers_.displayList); + link; link = Chain_NextLink(link)) { + Marker* markerPtr = (Marker*)Chain_GetValue(link); + for (int ii = 3; iiname_, pattern)) { + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewStringObj(markerPtr->name_, -1)); + break; + } + } + } + } + + Tcl_SetObjResult(interp, listObjPtr); + return TCL_OK; +} + +static int RelinkOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc!=4 && objc!=5) { + Tcl_WrongNumArgs(interp, 3, objv, "markerId ?placeId?"); + return TCL_ERROR; + } + + Marker* markerPtr; + if (GetMarkerFromObj(interp, graphPtr, objv[3], &markerPtr) != TCL_OK) + return TCL_ERROR; + + Marker* placePtr =NULL; + if (objc == 5) + if (GetMarkerFromObj(interp, graphPtr, objv[4], &placePtr) != TCL_OK) + return TCL_ERROR; + + ChainLink* link = markerPtr->link; + graphPtr->markers_.displayList->unlinkLink(markerPtr->link); + + ChainLink* place = placePtr ? placePtr->link : NULL; + + const char* string = Tcl_GetString(objv[2]); + if (string[0] == 'l') + graphPtr->markers_.displayList->linkAfter(link, place); + else + graphPtr->markers_.displayList->linkBefore(link, place); + + graphPtr->flags |= CACHE; + graphPtr->eventuallyRedraw(); + + return TCL_OK; +} + +static int TypeOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc!=4) { + Tcl_WrongNumArgs(interp, 3, objv, "markerId"); + return TCL_ERROR; + } + + Marker* markerPtr; + if (GetMarkerFromObj(interp, graphPtr, objv[3], &markerPtr) != TCL_OK) + return TCL_ERROR; + + Tcl_SetStringObj(Tcl_GetObjResult(interp), markerPtr->typeName(), -1); + return TCL_OK; +} + +const Ensemble Blt::markerEnsemble[] = { + {"bind", BindOp, 0}, + {"cget", CgetOp, 0}, + {"configure", ConfigureOp, 0}, + {"create", CreateOp, 0}, + {"delete", DeleteOp, 0}, + {"exists", ExistsOp, 0}, + {"find", FindOp, 0}, + {"lower", RelinkOp, 0}, + {"names", NamesOp, 0}, + {"raise", RelinkOp, 0}, + {"type", TypeOp, 0}, + { 0,0,0 } +}; + +// Support + +static int GetMarkerFromObj(Tcl_Interp* interp, Graph* graphPtr, + Tcl_Obj *objPtr, Marker** markerPtrPtr) +{ + const char* string = Tcl_GetString(objPtr); + Tcl_HashEntry* hPtr = Tcl_FindHashEntry(&graphPtr->markers_.table, string); + if (hPtr) { + *markerPtrPtr = (Marker*)Tcl_GetHashValue(hPtr); + return TCL_OK; + } + if (interp) { + Tcl_AppendResult(interp, "can't find marker \"", string, + "\" in \"", Tk_PathName(graphPtr->tkwin_), "\"", NULL); + } + + return TCL_ERROR; +} + diff --git a/generic/tkbltGrMarkerOp.h b/generic/tkbltGrMarkerOp.h new file mode 100644 index 0000000..6f7c16f --- /dev/null +++ b/generic/tkbltGrMarkerOp.h @@ -0,0 +1,39 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __Blt_GrMarkerOp_h__ +#define __Blt_GrMarkerOp_h__ + +#include "tkbltGraph.h" + +namespace Blt { + extern const Ensemble markerEnsemble[]; +}; + +#endif diff --git a/generic/tkbltGrMarkerOption.C b/generic/tkbltGrMarkerOption.C new file mode 100644 index 0000000..6b13fd9 --- /dev/null +++ b/generic/tkbltGrMarkerOption.C @@ -0,0 +1,209 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include "tkbltGrMarker.h" +#include "tkbltGrMarkerOption.h" +#include "tkbltConfig.h" + +using namespace Blt; + +static Tcl_Obj* PrintCoordinate(double x); +static int GetCoordinate(Tcl_Interp* interp, Tcl_Obj *objPtr, double *valuePtr); + +static Tk_CustomOptionSetProc CoordsSetProc; +static Tk_CustomOptionGetProc CoordsGetProc; +static Tk_CustomOptionFreeProc CoordsFreeProc; +Tk_ObjCustomOption coordsObjOption = + { + "coords", CoordsSetProc, CoordsGetProc, RestoreProc, CoordsFreeProc, NULL + }; + +static int CoordsSetProc(ClientData clientData, Tcl_Interp* interp, + Tk_Window tkwin, Tcl_Obj** objPtr, char* widgRec, + int offset, char* savePtr, int flags) +{ + Coords** coordsPtrPtr = (Coords**)(widgRec + offset); + *(double*)savePtr = *(double*)coordsPtrPtr; + + if (!coordsPtrPtr) + return TCL_OK; + + int objc; + Tcl_Obj** objv; + if (Tcl_ListObjGetElements(interp, *objPtr, &objc, &objv) != TCL_OK) + return TCL_ERROR; + + if (objc == 0) { + *coordsPtrPtr = NULL; + return TCL_OK; + } + + if (objc & 1) { + Tcl_AppendResult(interp, "odd number of marker coordinates specified",NULL); + return TCL_ERROR; + } + + Coords* coordsPtr = new Coords; + coordsPtr->num = objc/2; + coordsPtr->points = new Point2d[coordsPtr->num]; + + Point2d* pp = coordsPtr->points; + for (int ii=0; iix = x; + pp->y = y; + pp++; + } + + *coordsPtrPtr = coordsPtr; + return TCL_OK; +} + +static Tcl_Obj* CoordsGetProc(ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset) +{ + Coords* coordsPtr = *(Coords**)(widgRec + offset); + + if (!coordsPtr) + return Tcl_NewListObj(0, NULL); + + int cnt = coordsPtr->num*2; + Tcl_Obj** ll = new Tcl_Obj*[cnt]; + + Point2d* pp = coordsPtr->points; + for (int ii=0; iix); + ll[ii++] = PrintCoordinate(pp->y); + } + + Tcl_Obj* listObjPtr = Tcl_NewListObj(cnt, ll); + delete [] ll; + return listObjPtr; +} + +static void CoordsFreeProc(ClientData clientData, Tk_Window tkwin, + char *ptr) +{ + Coords* coordsPtr = *(Coords**)ptr; + if (coordsPtr) { + delete [] coordsPtr->points; + delete coordsPtr; + } +} + +static Tk_CustomOptionSetProc CapStyleSetProc; +static Tk_CustomOptionGetProc CapStyleGetProc; +Tk_ObjCustomOption capStyleObjOption = + { + "capStyle", CapStyleSetProc, CapStyleGetProc, NULL, NULL, NULL + }; + +static int CapStyleSetProc(ClientData clientData, Tcl_Interp* interp, + Tk_Window tkwin, Tcl_Obj** objPtr, char* widgRec, + int offset, char* save, int flags) +{ + int* ptr = (int*)(widgRec + offset); + + Tk_Uid uid = Tk_GetUid(Tcl_GetString(*objPtr)); + int cap; + if (Tk_GetCapStyle(interp, uid, &cap) != TCL_OK) + return TCL_ERROR; + *ptr = cap; + + return TCL_OK; +} + +static Tcl_Obj* CapStyleGetProc(ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset) +{ + int* ptr = (int*)(widgRec + offset); + return Tcl_NewStringObj(Tk_NameOfCapStyle(*ptr), -1); +} + +static Tk_CustomOptionSetProc JoinStyleSetProc; +static Tk_CustomOptionGetProc JoinStyleGetProc; +Tk_ObjCustomOption joinStyleObjOption = + { + "joinStyle", JoinStyleSetProc, JoinStyleGetProc, NULL, NULL, NULL + }; + +static int JoinStyleSetProc(ClientData clientData, Tcl_Interp* interp, + Tk_Window tkwin, Tcl_Obj** objPtr, char* widgRec, + int offset, char* save, int flags) +{ + int* ptr = (int*)(widgRec + offset); + + Tk_Uid uid = Tk_GetUid(Tcl_GetString(*objPtr)); + int join; + if (Tk_GetJoinStyle(interp, uid, &join) != TCL_OK) + return TCL_ERROR; + *ptr = join; + + return TCL_OK; +} + +static Tcl_Obj* JoinStyleGetProc(ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset) +{ + int* ptr = (int*)(widgRec + offset); + return Tcl_NewStringObj(Tk_NameOfJoinStyle(*ptr), -1); +} + +static Tcl_Obj* PrintCoordinate(double x) +{ + if (x == DBL_MAX) + return Tcl_NewStringObj("+Inf", -1); + else if (x == -DBL_MAX) + return Tcl_NewStringObj("-Inf", -1); + else + return Tcl_NewDoubleObj(x); +} + +static int GetCoordinate(Tcl_Interp* interp, Tcl_Obj *objPtr, double *valuePtr) +{ + const char* expr = Tcl_GetString(objPtr); + char c = expr[0]; + if ((c == 'I') && (strcmp(expr, "Inf") == 0)) + *valuePtr = DBL_MAX; /* Elastic upper bound */ + else if ((c == '-') && (expr[1] == 'I') && (strcmp(expr, "-Inf") == 0)) + *valuePtr = -DBL_MAX; /* Elastic lower bound */ + else if ((c == '+') && (expr[1] == 'I') && (strcmp(expr, "+Inf") == 0)) + *valuePtr = DBL_MAX; /* Elastic upper bound */ + else if (Tcl_GetDoubleFromObj(interp, objPtr, valuePtr) != TCL_OK) + return TCL_ERROR; + + return TCL_OK; +} diff --git a/generic/tkbltGrMarkerOption.h b/generic/tkbltGrMarkerOption.h new file mode 100644 index 0000000..143810e --- /dev/null +++ b/generic/tkbltGrMarkerOption.h @@ -0,0 +1,39 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __Blt_GrMarkerOption_h__ +#define __Blt_GrMarkerOption_h__ + +extern Tk_ObjCustomOption coordsObjOption; +extern Tk_ObjCustomOption capStyleObjOption; +extern Tk_ObjCustomOption joinStyleObjOption; +extern Tk_ObjCustomOption xAxisObjOption; +extern Tk_ObjCustomOption yAxisObjOption; + +#endif diff --git a/generic/tkbltGrMarkerPolygon.C b/generic/tkbltGrMarkerPolygon.C new file mode 100644 index 0000000..383d0e8 --- /dev/null +++ b/generic/tkbltGrMarkerPolygon.C @@ -0,0 +1,298 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "tkbltGraph.h" +#include "tkbltGrMarkerPolygon.h" +#include "tkbltGrMarkerOption.h" +#include "tkbltGrMisc.h" +#include "tkbltGrDef.h" +#include "tkbltConfig.h" +#include "tkbltGrPSOutput.h" + +using namespace Blt; + +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_CUSTOM, "-bindtags", "bindTags", "BindTags", + "Polygon all", -1, Tk_Offset(PolygonMarkerOptions, tags), + TK_OPTION_NULL_OK, &listObjOption, 0}, + {TK_OPTION_CUSTOM, "-cap", "cap", "Cap", + "butt", -1, Tk_Offset(PolygonMarkerOptions, capStyle), + 0, &capStyleObjOption, 0}, + {TK_OPTION_CUSTOM, "-coords", "coords", "Coords", + NULL, -1, Tk_Offset(PolygonMarkerOptions, worldPts), + TK_OPTION_NULL_OK, &coordsObjOption, 0}, + {TK_OPTION_CUSTOM, "-dashes", "dashes", "Dashes", + NULL, -1, Tk_Offset(PolygonMarkerOptions, dashes), + TK_OPTION_NULL_OK, &dashesObjOption, 0}, + {TK_OPTION_STRING, "-element", "element", "Element", + NULL, -1, Tk_Offset(PolygonMarkerOptions, elemName), + TK_OPTION_NULL_OK, NULL, 0}, + {TK_OPTION_COLOR, "-fill", "fill", "Fill", + NULL, -1, Tk_Offset(PolygonMarkerOptions, fill), + TK_OPTION_NULL_OK, NULL, 0}, + {TK_OPTION_CUSTOM, "-join", "join", "Join", + "miter", -1, Tk_Offset(PolygonMarkerOptions, joinStyle), + 0, &joinStyleObjOption, 0}, + {TK_OPTION_PIXELS, "-linewidth", "lineWidth", "LineWidth", + "1", -1, Tk_Offset(PolygonMarkerOptions, lineWidth), 0, NULL, 0}, + {TK_OPTION_BOOLEAN, "-hide", "hide", "Hide", + "no", -1, Tk_Offset(PolygonMarkerOptions, hide), 0, NULL, 0}, + {TK_OPTION_CUSTOM, "-mapx", "mapX", "MapX", + "x", -1, Tk_Offset(PolygonMarkerOptions, xAxis), 0, &xAxisObjOption, 0}, + {TK_OPTION_CUSTOM, "-mapy", "mapY", "MapY", + "y", -1, Tk_Offset(PolygonMarkerOptions, yAxis), 0, &yAxisObjOption, 0}, + {TK_OPTION_COLOR, "-outline", "outline", "Outline", + STD_NORMAL_FOREGROUND, -1, Tk_Offset(PolygonMarkerOptions, outline), + TK_OPTION_NULL_OK, NULL, 0}, + {TK_OPTION_BOOLEAN, "-under", "under", "Under", + "no", -1, Tk_Offset(PolygonMarkerOptions, drawUnder), 0, NULL, CACHE}, + {TK_OPTION_PIXELS, "-xoffset", "xOffset", "XOffset", + "0", -1, Tk_Offset(PolygonMarkerOptions, xOffset), 0, NULL, 0}, + {TK_OPTION_PIXELS, "-yoffset", "yOffset", "YOffset", + "0", -1, Tk_Offset(PolygonMarkerOptions, yOffset), 0, NULL, 0}, + {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, -1, 0, 0, 0} +}; + +PolygonMarker::PolygonMarker(Graph* graphPtr, const char* name, + Tcl_HashEntry* hPtr) + : Marker(graphPtr, name, hPtr) +{ + ops_ = (PolygonMarkerOptions*)calloc(1, sizeof(PolygonMarkerOptions)); + optionTable_ = Tk_CreateOptionTable(graphPtr->interp_, optionSpecs); + + screenPts_ =NULL; + outlineGC_ =NULL; + fillGC_ =NULL; + fillPts_ =NULL; + nFillPts_ =0; + outlinePts_ =NULL; + nOutlinePts_ =0; +} + +PolygonMarker::~PolygonMarker() +{ + if (fillGC_) + Tk_FreeGC(graphPtr_->display_, fillGC_); + if (outlineGC_) + graphPtr_->freePrivateGC(outlineGC_); + delete [] fillPts_; + delete [] outlinePts_; + delete [] screenPts_; +} + +int PolygonMarker::configure() +{ + PolygonMarkerOptions* ops = (PolygonMarkerOptions*)ops_; + + // outlineGC + unsigned long gcMask = (GCLineWidth | GCLineStyle); + XGCValues gcValues; + if (ops->outline) { + gcMask |= GCForeground; + gcValues.foreground = ops->outline->pixel; + } + gcMask |= (GCCapStyle | GCJoinStyle); + gcValues.cap_style = ops->capStyle; + gcValues.join_style = ops->joinStyle; + gcValues.line_style = LineSolid; + gcValues.dash_offset = 0; + gcValues.line_width = ops->lineWidth; + if (LineIsDashed(ops->dashes)) + gcValues.line_style = LineOnOffDash; + + GC newGC = graphPtr_->getPrivateGC(gcMask, &gcValues); + if (LineIsDashed(ops->dashes)) + graphPtr_->setDashes(newGC, &ops->dashes); + if (outlineGC_) + graphPtr_->freePrivateGC(outlineGC_); + outlineGC_ = newGC; + + // fillGC + gcMask = 0; + if (ops->fill) { + gcMask |= GCForeground; + gcValues.foreground = ops->fill->pixel; + } + newGC = Tk_GetGC(graphPtr_->tkwin_, gcMask, &gcValues); + if (fillGC_) + Tk_FreeGC(graphPtr_->display_, fillGC_); + fillGC_ = newGC; + + return TCL_OK; +} + +void PolygonMarker::draw(Drawable drawable) +{ + PolygonMarkerOptions* ops = (PolygonMarkerOptions*)ops_; + + // fill region + if ((nFillPts_ > 0) && (ops->fill)) { + XPoint* points = new XPoint[nFillPts_]; + if (!points) + return; + + XPoint* dp = points; + for (Point2d *sp = fillPts_, *send = sp + nFillPts_; sp < send; sp++) { + dp->x = (short)sp->x; + dp->y = (short)sp->y; + dp++; + } + + XFillPolygon(graphPtr_->display_, drawable, fillGC_, points, + nFillPts_, Complex, CoordModeOrigin); + delete [] points; + } + + // outline + if ((nOutlinePts_ > 0) && (ops->lineWidth > 0) && (ops->outline)) + graphPtr_->drawSegments(drawable, outlineGC_, outlinePts_, nOutlinePts_); +} + +void PolygonMarker::map() +{ + PolygonMarkerOptions* ops = (PolygonMarkerOptions*)ops_; + + if (outlinePts_) { + delete [] outlinePts_; + outlinePts_ = NULL; + nOutlinePts_ = 0; + } + + if (fillPts_) { + delete [] fillPts_; + fillPts_ = NULL; + nFillPts_ = 0; + } + + if (screenPts_) { + delete [] screenPts_; + screenPts_ = NULL; + } + + if (!ops->worldPts || ops->worldPts->num < 3) + return; + + // Allocate and fill a temporary array to hold the screen coordinates of + // the polygon. + + int nScreenPts = ops->worldPts->num + 1; + Point2d* screenPts = new Point2d[nScreenPts + 1]; + { + Point2d* dp = screenPts; + for (Point2d *sp = ops->worldPts->points, *send = sp + ops->worldPts->num; + sp < send; sp++) { + *dp = mapPoint(sp, ops->xAxis, ops->yAxis); + dp->x += ops->xOffset; + dp->y += ops->yOffset; + dp++; + } + *dp = screenPts[0]; + } + Region2d extents; + graphPtr_->extents(&extents); + + clipped_ = 1; + if (ops->fill) { + Point2d* lfillPts = new Point2d[nScreenPts * 3]; + int n = polyRectClip(&extents, screenPts, ops->worldPts->num,lfillPts); + if (n < 3) + delete [] lfillPts; + else { + nFillPts_ = n; + fillPts_ = lfillPts; + clipped_ = 0; + } + } + if ((ops->outline) && (ops->lineWidth > 0)) { + // Generate line segments representing the polygon outline. The + // resulting outline may or may not be closed from viewport clipping. + Segment2d* outlinePts = new Segment2d[nScreenPts]; + if (!outlinePts) + return; + + // Note that this assumes that the point array contains an extra point + // that closes the polygon. + Segment2d* segPtr = outlinePts; + for (Point2d *sp=screenPts, *send=sp+(nScreenPts - 1); sp < send; sp++) { + segPtr->p = sp[0]; + segPtr->q = sp[1]; + if (lineRectClip(&extents, &segPtr->p, &segPtr->q)) { + segPtr++; + } + } + nOutlinePts_ = segPtr - outlinePts; + outlinePts_ = outlinePts; + if (nOutlinePts_ > 0) + clipped_ = 0; + } + + screenPts_ = screenPts; +} + +int PolygonMarker::pointIn(Point2d *samplePtr) +{ + PolygonMarkerOptions* ops = (PolygonMarkerOptions*)ops_; + + if (ops->worldPts && (ops->worldPts->num >= 3) && screenPts_) + return pointInPolygon(samplePtr, screenPts_, ops->worldPts->num + 1); + + return 0; +} + +int PolygonMarker::regionIn(Region2d *extsPtr, int enclosed) +{ + PolygonMarkerOptions* ops = (PolygonMarkerOptions*)ops_; + + if (ops->worldPts && (ops->worldPts->num >= 3) && screenPts_) + return regionInPolygon(extsPtr, screenPts_, ops->worldPts->num, enclosed); + + return 0; +} + +void PolygonMarker::print(PSOutput* psPtr) +{ + PolygonMarkerOptions* ops = (PolygonMarkerOptions*)ops_; + + if (ops->fill) { + psPtr->printPolyline(fillPts_, nFillPts_); + psPtr->setForeground(ops->fill); + psPtr->append("fill\n"); + } + + if ((ops->lineWidth > 0) && (ops->outline)) { + psPtr->setLineAttributes(ops->outline, ops->lineWidth, &ops->dashes, + ops->capStyle, ops->joinStyle); + psPtr->append("/DashesProc {} def\n"); + + psPtr->printSegments(outlinePts_, nOutlinePts_); + } +} + diff --git a/generic/tkbltGrMarkerPolygon.h b/generic/tkbltGrMarkerPolygon.h new file mode 100644 index 0000000..8eb2216 --- /dev/null +++ b/generic/tkbltGrMarkerPolygon.h @@ -0,0 +1,84 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGrMarkerPolygon_h__ +#define __BltGrMarkerPolygon_h__ + +#include "tkbltGrMarker.h" + +namespace Blt { + + typedef struct { + const char** tags; + Coords* worldPts; + const char* elemName; + Axis* xAxis; + Axis* yAxis; + int hide; + int drawUnder; + int xOffset; + int yOffset; + + int capStyle; + Dashes dashes; + XColor* fill; + int joinStyle; + int lineWidth; + XColor* outline; + } PolygonMarkerOptions; + + class PolygonMarker : public Marker { + protected: + Point2d *screenPts_; + GC outlineGC_; + GC fillGC_; + Point2d *fillPts_; + int nFillPts_; + Segment2d *outlinePts_; + int nOutlinePts_; + + protected: + int configure(); + void draw(Drawable); + void map(); + int pointIn(Point2d*); + int regionIn(Region2d*, int); + void print(PSOutput*); + + public: + PolygonMarker(Graph*, const char*, Tcl_HashEntry*); + virtual ~PolygonMarker(); + + ClassId classId() {return CID_MARKER_POLYGON;} + const char* className() {return "PolygonMarker";} + const char* typeName() {return "polygon";} + }; +}; + +#endif diff --git a/generic/tkbltGrMarkerText.C b/generic/tkbltGrMarkerText.C new file mode 100644 index 0000000..9c4da2a --- /dev/null +++ b/generic/tkbltGrMarkerText.C @@ -0,0 +1,276 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include + +#include "tkbltGraph.h" +#include "tkbltGrMarkerText.h" +#include "tkbltGrMarkerOption.h" +#include "tkbltGrMisc.h" +#include "tkbltGrDef.h" +#include "tkbltConfig.h" +#include "tkbltGrPSOutput.h" + +using namespace Blt; + +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor", + "center", -1, Tk_Offset(TextMarkerOptions, anchor), 0, NULL, 0}, + {TK_OPTION_COLOR, "-background", "background", "Background", + NULL, -1, Tk_Offset(TextMarkerOptions, fillColor), + TK_OPTION_NULL_OK, NULL, 0}, + {TK_OPTION_SYNONYM, "-bg", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-background", 0}, + {TK_OPTION_CUSTOM, "-bindtags", "bindTags", "BindTags", + "Text all", -1, Tk_Offset(TextMarkerOptions, tags), + TK_OPTION_NULL_OK, &listObjOption, 0}, + {TK_OPTION_CUSTOM, "-coords", "coords", "Coords", + NULL, -1, Tk_Offset(TextMarkerOptions, worldPts), + TK_OPTION_NULL_OK, &coordsObjOption, 0}, + {TK_OPTION_STRING, "-element", "element", "Element", + NULL, -1, Tk_Offset(TextMarkerOptions, elemName), + TK_OPTION_NULL_OK, NULL, 0}, + {TK_OPTION_SYNONYM, "-fg", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-foreground", 0}, + {TK_OPTION_SYNONYM, "-fill", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-background", 0}, + {TK_OPTION_FONT, "-font", "font", "Font", + STD_FONT_NORMAL, -1, Tk_Offset(TextMarkerOptions, style.font), 0, NULL, 0}, + {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground", + STD_NORMAL_FOREGROUND, -1, Tk_Offset(TextMarkerOptions, style.color), + 0, NULL, 0}, + {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify", + "left", -1, Tk_Offset(TextMarkerOptions, style.justify), 0, NULL, 0}, + {TK_OPTION_BOOLEAN, "-hide", "hide", "Hide", + "no", -1, Tk_Offset(TextMarkerOptions, hide), 0, NULL, 0}, + {TK_OPTION_CUSTOM, "-mapx", "mapX", "MapX", + "x", -1, Tk_Offset(TextMarkerOptions, xAxis), 0, &xAxisObjOption, 0}, + {TK_OPTION_CUSTOM, "-mapy", "mapY", "MapY", + "y", -1, Tk_Offset(TextMarkerOptions, yAxis), 0, &yAxisObjOption, 0}, + {TK_OPTION_SYNONYM, "-outline", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-foreground", 0}, + {TK_OPTION_DOUBLE, "-rotate", "rotate", "Rotate", + "0", -1, Tk_Offset(TextMarkerOptions, style.angle), 0, NULL, 0}, + {TK_OPTION_STRING, "-text", "text", "Text", + NULL, -1, Tk_Offset(TextMarkerOptions, string), TK_OPTION_NULL_OK, NULL, 0}, + {TK_OPTION_BOOLEAN, "-under", "under", "Under", + "no", -1, Tk_Offset(TextMarkerOptions, drawUnder), 0, NULL, CACHE}, + {TK_OPTION_PIXELS, "-xoffset", "xOffset", "XOffset", + "0", -1, Tk_Offset(TextMarkerOptions, xOffset), 0, NULL, 0}, + {TK_OPTION_PIXELS, "-yoffset", "yOffset", "YOffset", + "0", -1, Tk_Offset(TextMarkerOptions, yOffset), 0, NULL, 0}, + {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, -1, 0, 0, 0} +}; + +TextMarker::TextMarker(Graph* graphPtr, const char* name, Tcl_HashEntry* hPtr) + : Marker(graphPtr, name, hPtr) +{ + ops_ = (TextMarkerOptions*)calloc(1, sizeof(TextMarkerOptions)); + TextMarkerOptions* ops = (TextMarkerOptions*)ops_; + + ops->style.anchor =TK_ANCHOR_NW; + ops->style.color =NULL; + ops->style.font =NULL; + ops->style.angle =0; + ops->style.justify =TK_JUSTIFY_LEFT; + + anchorPt_.x =0; + anchorPt_.y =0; + width_ =0; + height_ =0; + fillGC_ =NULL; + + optionTable_ = Tk_CreateOptionTable(graphPtr->interp_, optionSpecs); +} + +TextMarker::~TextMarker() +{ +} + +int TextMarker::configure() +{ + TextMarkerOptions* ops = (TextMarkerOptions*)ops_; + + ops->style.angle = (float)fmod(ops->style.angle, 360.0); + if (ops->style.angle < 0.0) + ops->style.angle += 360.0; + + GC newGC = NULL; + XGCValues gcValues; + unsigned long gcMask; + if (ops->fillColor) { + gcMask = GCForeground; + gcValues.foreground = ops->fillColor->pixel; + newGC = Tk_GetGC(graphPtr_->tkwin_, gcMask, &gcValues); + } + if (fillGC_) + Tk_FreeGC(graphPtr_->display_, fillGC_); + fillGC_ = newGC; + + return TCL_OK; +} + +void TextMarker::draw(Drawable drawable) +{ + TextMarkerOptions* ops = (TextMarkerOptions*)ops_; + + if (!ops->string) + return; + + if (fillGC_) { + XPoint points[4]; + for (int ii=0; ii<4; ii++) { + points[ii].x = (short)(outline_[ii].x + anchorPt_.x); + points[ii].y = (short)(outline_[ii].y + anchorPt_.y); + } + XFillPolygon(graphPtr_->display_, drawable, fillGC_, points, 4, + Convex, CoordModeOrigin); + } + + TextStyle ts(graphPtr_, &ops->style); + ts.drawText(drawable, ops->string, anchorPt_.x, anchorPt_.y); +} + +void TextMarker::map() +{ + TextMarkerOptions* ops = (TextMarkerOptions*)ops_; + + if (!ops->string) + return; + + if (!ops->worldPts || (ops->worldPts->num < 1)) + return; + + width_ =0; + height_ =0; + + int w, h; + TextStyle ts(graphPtr_, &ops->style); + ts.getExtents(ops->string, &w, &h); + + double rw; + double rh; + graphPtr_->getBoundingBox(w, h, ops->style.angle, &rw, &rh, outline_); + width_ = (int)rw; + height_ = (int)rh; + for (int ii=0; ii<4; ii++) { + outline_[ii].x += rw * 0.5; + outline_[ii].y += rh * 0.5; + } + outline_[4].x = outline_[0].x; + outline_[4].y = outline_[0].y; + + Point2d anchorPtr = mapPoint(ops->worldPts->points, ops->xAxis, ops->yAxis); + anchorPtr = graphPtr_->anchorPoint(anchorPtr.x, anchorPtr.y, + width_, height_, ops->anchor); + anchorPtr.x += ops->xOffset; + anchorPtr.y += ops->yOffset; + + Region2d extents; + extents.left = anchorPtr.x; + extents.top = anchorPtr.y; + extents.right = anchorPtr.x + width_ - 1; + extents.bottom = anchorPtr.y + height_ - 1; + clipped_ = boxesDontOverlap(graphPtr_, &extents); + + anchorPt_ = anchorPtr; +} + +int TextMarker::pointIn(Point2d *samplePtr) +{ + TextMarkerOptions* ops = (TextMarkerOptions*)ops_; + + if (!ops->string) + return 0; + + if (ops->style.angle != 0.0) { + Point2d points[5]; + + // Figure out the bounding polygon (isolateral) for the text and see + // if the point is inside of it. + for (int ii=0; ii<5; ii++) { + points[ii].x = outline_[ii].x + anchorPt_.x; + points[ii].y = outline_[ii].y + anchorPt_.y; + } + return pointInPolygon(samplePtr, points, 5); + } + + return ((samplePtr->x >= anchorPt_.x) && + (samplePtr->x < (anchorPt_.x + width_)) && + (samplePtr->y >= anchorPt_.y) && + (samplePtr->y < (anchorPt_.y + height_))); +} + +int TextMarker::regionIn(Region2d *extsPtr, int enclosed) +{ + TextMarkerOptions* ops = (TextMarkerOptions*)ops_; + + if (ops->style.angle != 0.0) { + Point2d points[5]; + for (int ii=0; ii<4; ii++) { + points[ii].x = outline_[ii].x + anchorPt_.x; + points[ii].y = outline_[ii].y + anchorPt_.y; + } + return regionInPolygon(extsPtr, points, 4, enclosed); + } + + if (enclosed) + return ((anchorPt_.x >= extsPtr->left) && + (anchorPt_.y >= extsPtr->top) && + ((anchorPt_.x + width_) <= extsPtr->right) && + ((anchorPt_.y + height_) <= extsPtr->bottom)); + + return !((anchorPt_.x >= extsPtr->right) || + (anchorPt_.y >= extsPtr->bottom) || + ((anchorPt_.x + width_) <= extsPtr->left) || + ((anchorPt_.y + height_) <= extsPtr->top)); +} + +void TextMarker::print(PSOutput* psPtr) +{ + TextMarkerOptions* ops = (TextMarkerOptions*)ops_; + + if (!ops->string) + return; + + if (fillGC_) { + Point2d points[4]; + for (int ii=0; ii<4; ii++) { + points[ii].x = outline_[ii].x + anchorPt_.x; + points[ii].y = outline_[ii].y + anchorPt_.y; + } + psPtr->setBackground(ops->fillColor); + psPtr->fillPolygon(points, 4); + } + + TextStyle ts(graphPtr_, &ops->style); + ts.printText(psPtr, ops->string, anchorPt_.x, anchorPt_.y); +} diff --git a/generic/tkbltGrMarkerText.h b/generic/tkbltGrMarkerText.h new file mode 100644 index 0000000..99dc814 --- /dev/null +++ b/generic/tkbltGrMarkerText.h @@ -0,0 +1,82 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGrMarkerText_h__ +#define __BltGrMarkerText_h__ + +#include + +#include "tkbltGrMarker.h" + +namespace Blt { + + typedef struct { + const char** tags; + Coords* worldPts; + const char* elemName; + Axis* xAxis; + Axis* yAxis; + int hide; + int drawUnder; + int xOffset; + int yOffset; + + Tk_Anchor anchor; + XColor* fillColor; + TextStyleOptions style; + const char* string; + } TextMarkerOptions; + + class TextMarker : public Marker { + protected: + Point2d anchorPt_; + int width_; + int height_; + GC fillGC_; + Point2d outline_[5]; + + protected: + int configure(); + void draw(Drawable); + void map(); + int pointIn(Point2d*); + int regionIn(Region2d*, int); + void print(PSOutput*); + + public: + TextMarker(Graph*, const char*, Tcl_HashEntry*); + virtual ~TextMarker(); + + ClassId classId() {return CID_MARKER_TEXT;} + const char* className() {return "TextMarker";} + const char* typeName() {return "text";} + }; +}; + +#endif diff --git a/generic/tkbltGrMisc.C b/generic/tkbltGrMisc.C new file mode 100644 index 0000000..aaafcfd --- /dev/null +++ b/generic/tkbltGrMisc.C @@ -0,0 +1,405 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include + +#include +#include + +#include "tkbltGraph.h" +#include "tkbltGrMisc.h" +#include "tkbltInt.h" + +using namespace Blt; + +char* Blt::dupstr(const char* str) +{ + char* copy =NULL; + if (str) { + copy=new char[strlen(str)+1]; + strcpy(copy,str); + } + + return copy; +} + +int Blt::pointInPolygon(Point2d *s, Point2d *points, int nPoints) +{ + int count = 0; + for (Point2d *p=points, *q=p+1, *qend=p + nPoints; q < qend; p++, q++) { + if (((p->y <= s->y) && (s->y < q->y)) || + ((q->y <= s->y) && (s->y < p->y))) { + double b; + + b = (q->x - p->x) * (s->y - p->y) / (q->y - p->y) + p->x; + if (s->x < b) { + count++; /* Count the number of intersections. */ + } + } + } + return (count & 0x01); +} + +/* + *--------------------------------------------------------------------------- + * Clips a rectangle in one direction where some of the coordinates are + * infinite. + *--------------------------------------------------------------------------- + */ +static LineRectClipResult ClipInfinity (double *pa, double *pb, double *qa, double *qb, double region_min, double region_max) +{ + int finitepa = isfinite(*pa); + int finiteqa = isfinite(*qa); + + if (!finitepa) { + if (finiteqa) { + if (*pa > 0) { // +Inf + *pa = region_max; + } else if (*pa < 0) { // -Inf + *pa = region_min; + } else { // NaN + return CLIP_OUTSIDE; + } + // *qa is finite, simplify to zero slope at *pb. + *pb = *qb; + return CLIP_P; + } else { // Both infinite. + int positivepa = *pa > 0; + int positiveqa = *qa > 0; + + if (positivepa < positiveqa) { // (p,q) ~ (-Inf,Inf) + *pa = region_min; + *qa = region_max; + } else if (positivepa > positiveqa) { // (p,q) ~ (Inf,-Inf) + *pa = region_max; + *qa = region_min; + } else { // (Inf,Inf), (-Inf,-Inf) or NaN. + return CLIP_OUTSIDE; + } + // At opposite infinities; simplify to zero slope in the middle. + *pb = *qb = (*pb + *qb) / 2.0; + return CLIP_P | CLIP_Q; + } + } else if (!finiteqa) { + // *pa is finite. + if (*qa > 0) { // +Inf + *qa = region_max; + } else if (*qa < 0) { // -Inf + *qa = region_min; + } else { // NaN + return CLIP_OUTSIDE; + } + // *pa is finite, simplify to zero slope at *qb. + *qb = *pb; + return CLIP_Q; + } + return CLIP_OUTSIDE; +} + + +static int ClipTest (double ds, double dr, double *t1, double *t2) +{ + double t; + + if (ds < 0.0) { + t = dr / ds; + if (t > *t2) { + return 0; /* Line is outside clipping edge */ + } + if (t > *t1) { + *t1 = t; + } + } else if (ds > 0.0) { + t = dr / ds; + if (t < *t1) { + return 0; /* Line is outside clipping edge */ + } + if (t < *t2) { + *t2 = t; + } + } else { + /* d = 0, so line is parallel to this clipping edge */ + if (dr < 0.0) { /* Line is outside clipping edge */ + return 0; + } + } + return 1; +} + +/* + *--------------------------------------------------------------------------- + * Clips the given line segment to a rectangular region. The coordinates + * of the clipped line segment are returned. The original coordinates + * are overwritten. + * + * The return value indicates whether the line was completely outside of + * the region, returning CLIP_OUTSIDE; or at least partly inside, returning + * CLIP_INSIDE. In the latter case, the result might be or'ed with CLIP_P + * if p coordinates were clipped, or CLIP_Q if q coordinates were. + * + * Reference: + * Liang, Y-D., and B. Barsky, A new concept and method for + * Line Clipping, ACM, TOG,3(1), 1984, pp.1-22. + *--------------------------------------------------------------------------- + */ +LineRectClipResult Blt::lineRectClip(Region2d* regionPtr, Point2d *p, Point2d *q) +{ + double t1, t2; + double dx, dy; + LineRectClipResult res = CLIP_OUTSIDE; + + res |= ClipInfinity(&p->x, &p->y, &q->x, &q->y, regionPtr->bottom, regionPtr->top); + + t1 = 0.0, t2 = 1.0; + dx = q->x - p->x; + if ((ClipTest (-dx, p->x - regionPtr->left, &t1, &t2)) && + (ClipTest (dx, regionPtr->right - p->x, &t1, &t2))) { + res |= ClipInfinity(&p->y, &p->x, &q->y, &q->x, regionPtr->top, regionPtr->bottom); + + dy = q->y - p->y; + if ((ClipTest (-dy, p->y - regionPtr->top, &t1, &t2)) && + (ClipTest (dy, regionPtr->bottom - p->y, &t1, &t2))) { + if (t2 < 1.0) { + q->x = p->x + t2 * dx; + q->y = p->y + t2 * dy; + res |= CLIP_Q; + } + if (t1 > 0.0) { + p->x += t1 * dx; + p->y += t1 * dy; + res |= CLIP_P; + } + return res | CLIP_INSIDE; + } + } + return CLIP_OUTSIDE; +} + +/* + *--------------------------------------------------------------------------- + * Clips the given polygon to a rectangular region. The resulting + * polygon is returned. Note that the resulting polyon may be complex, + * connected by zero width/height segments. The drawing routine (such as + * XFillPolygon) will not draw a connecting segment. + * + * Reference: + * Liang Y. D. and Brian A. Barsky, "Analysis and Algorithm for + * Polygon Clipping", Communications of ACM, Vol. 26, + * p.868-877, 1983 + *--------------------------------------------------------------------------- + */ +#define AddVertex(vx, vy) r->x=(vx), r->y=(vy), r++, count++ +#define LastVertex(vx, vy) r->x=(vx), r->y=(vy), count++ + +int Blt::polyRectClip(Region2d *regionPtr, Point2d *points, int nPoints, + Point2d *clipPts) +{ + Point2d* r = clipPts; + // Counts # of vertices in output polygon. + int count = 0; + + points[nPoints] = points[0]; + for (Point2d *p=points, *q=p+1, *pend=p+nPoints; px - p->x; /* X-direction */ + dy = q->y - p->y; /* Y-direction */ + + if (fabs(dx) < FLT_EPSILON) + dx = (p->x > regionPtr->left) ? -FLT_EPSILON : FLT_EPSILON ; + + if (fabs(dy) < FLT_EPSILON) + dy = (p->y > regionPtr->top) ? -FLT_EPSILON : FLT_EPSILON ; + + if (dx > 0.0) { /* Left */ + xin = regionPtr->left; + xout = regionPtr->right + 1.0; + } + else { /* Right */ + xin = regionPtr->right + 1.0; + xout = regionPtr->left; + } + if (dy > 0.0) { /* Top */ + yin = regionPtr->top; + yout = regionPtr->bottom + 1.0; + } + else { /* Bottom */ + yin = regionPtr->bottom + 1.0; + yout = regionPtr->top; + } + + tinx = (xin - p->x) / dx; + tiny = (yin - p->y) / dy; + + if (tinx < tiny) { /* Hits x first */ + tin1 = tinx; + tin2 = tiny; + } + else { /* Hits y first */ + tin1 = tiny; + tin2 = tinx; + } + + if (tin1 <= 1.0) { + if (tin1 > 0.0) { + AddVertex(xin, yin); + } + if (tin2 <= 1.0) { + double toutx = (xout - p->x) / dx; + double touty = (yout - p->y) / dy; + double tout1 = MIN(toutx, touty); + + if ((tin2 > 0.0) || (tout1 > 0.0)) { + if (tin2 <= tout1) { + if (tin2 > 0.0) { + if (tinx > tiny) { + AddVertex(xin, p->y + tinx * dy); + } else { + AddVertex(p->x + tiny * dx, yin); + } + } + if (tout1 < 1.0) { + if (toutx < touty) { + AddVertex(xout, p->y + toutx * dy); + } else { + AddVertex(p->x + touty * dx, yout); + } + } else { + AddVertex(q->x, q->y); + } + } else { + if (tinx > tiny) { + AddVertex(xin, yout); + } else { + AddVertex(xout, yin); + } + + } + } + } + } + } + if (count > 0) { + LastVertex(clipPts[0].x, clipPts[0].y); + } + return count; +} + +/* + *--------------------------------------------------------------------------- + * Computes the projection of a point on a line. The line (given by two + * points), is assumed the be infinite. + * + * Compute the slope (angle) of the line and rotate it 90 degrees. Using + * the slope-intercept method (we know the second line from the sample + * test point and the computed slope), then find the intersection of both + * lines. This will be the projection of the sample point on the first + * line. + *--------------------------------------------------------------------------- + */ +Point2d Blt::getProjection(int x, int y, Point2d *p, Point2d *q) +{ + double dx = p->x - q->x; + double dy = p->y - q->y; + + /* Test for horizontal and vertical lines */ + Point2d t; + if (fabs(dx) < DBL_EPSILON) { + t.x = p->x; + t.y = (double)y; + } + else if (fabs(dy) < DBL_EPSILON) { + t.x = (double)x; + t.y = p->y; + } + else { + /* Compute the slope and intercept of PQ. */ + double m1 = (dy / dx); + double b1 = p->y - (p->x * m1); + + /* + * Compute the slope and intercept of a second line segment: one that + * intersects through sample X-Y coordinate with a slope perpendicular + * to original line. + */ + + /* Find midpoint of PQ. */ + double midX = (p->x + q->x) * 0.5; + double midY = (p->y + q->y) * 0.5; + + /* Rotate the line 90 degrees */ + double ax = midX - (0.5 * dy); + double ay = midY - (0.5 * -dx); + double bx = midX + (0.5 * dy); + double by = midY + (0.5 * -dx); + + double m2 = (ay - by) / (ax - bx); + double b2 = y - (x * m2); + + /* + * Given the equations of two lines which contain the same point, + * + * y = m1 * x + b1 + * y = m2 * x + b2 + * + * solve for the intersection. + * + * x = (b2 - b1) / (m1 - m2) + * y = m1 * x + b1 + * + */ + + t.x = (b2 - b1) / (m1 - m2); + t.y = m1 * t.x + b1; + } + + return t; +} + +Graph* Blt::getGraphFromWindowData(Tk_Window tkwin) +{ + while (tkwin) { + TkWindow* winPtr = (TkWindow*)tkwin; + if (winPtr->instanceData != NULL) { + Graph* graphPtr = (Graph*)winPtr->instanceData; + if (graphPtr) + return graphPtr; + } + tkwin = Tk_Parent(tkwin); + } + return NULL; +} + diff --git a/generic/tkbltGrMisc.h b/generic/tkbltGrMisc.h new file mode 100644 index 0000000..5c16dce --- /dev/null +++ b/generic/tkbltGrMisc.h @@ -0,0 +1,138 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGrMisc_h__ +#define __BltGrMisc_h__ + +#include +#include +#include +using namespace std; + +#include + +#ifndef MIN +# define MIN(x,y) ((x)<(y)?(x):(y)) +#endif + +#ifndef MAX +# define MAX(x,y) ((x)>(y)?(x):(y)) +#endif + +#define GRAPH_DELETED (1<<1) +#define REDRAW_PENDING (1<<2) +#define FOCUS (1<<3) + +#define MAP_ITEM (1<<4) + +#define RESET (1<<5) +#define LAYOUT (1<<6) +#define MAP_MARKERS (1<<7) +#define CACHE (1<<8) + +#define MARGIN_NONE -1 +#define MARGIN_BOTTOM 0 /* x */ +#define MARGIN_LEFT 1 /* y */ +#define MARGIN_TOP 2 /* x2 */ +#define MARGIN_RIGHT 3 /* y2 */ + +#define LineIsDashed(d) ((d).values[0] != 0) + +namespace Blt { + class Graph; + + typedef struct { + int x, y; + } Point; + + typedef struct { + int x, y; + unsigned width, height; + } Rectangle; + + typedef struct { + double x; + double y; + } Point2d; + + typedef struct { + Point2d p; + Point2d q; + } Segment2d; + + typedef struct { + double left; + double right; + double top; + double bottom; + } Region2d; + + typedef enum { + CID_NONE, CID_AXIS_X, CID_AXIS_Y, CID_ELEM_BAR, CID_ELEM_LINE, + CID_MARKER_BITMAP, CID_MARKER_IMAGE, CID_MARKER_LINE, CID_MARKER_POLYGON, + CID_MARKER_TEXT + } ClassId; + + typedef struct { + unsigned char values[12]; + int offset; + } Dashes; + + typedef enum { + CLIP_OUTSIDE = 0, + CLIP_INSIDE = 1 << 0, + CLIP_P = 1 << 1, + CLIP_Q = 1 << 2 + } LineRectClipResult; + + inline LineRectClipResult operator|(LineRectClipResult a, LineRectClipResult b) { + return static_cast(static_cast(a) | static_cast(b)); + } + + inline LineRectClipResult operator&(LineRectClipResult a, LineRectClipResult b) { + return static_cast(static_cast(a) & static_cast(b)); + } + + inline LineRectClipResult & operator|=(LineRectClipResult & rhs, LineRectClipResult v) { + rhs = rhs | v; + return rhs; + } + + extern char* dupstr(const char*); + extern Graph* getGraphFromWindowData(Tk_Window tkwin); + + extern int pointInPolygon(Point2d *samplePtr, Point2d *screenPts, + int nScreenPts); + extern int polyRectClip(Region2d *extsPtr, Point2d *inputPts, + int nInputPts, Point2d *outputPts); + extern LineRectClipResult lineRectClip(Region2d *regionPtr, Point2d *p, Point2d *q); + extern Point2d getProjection (int x, int y, Point2d *p, Point2d *q); +}; + +#endif diff --git a/generic/tkbltGrPSOutput.C b/generic/tkbltGrPSOutput.C new file mode 100644 index 0000000..01a3101 --- /dev/null +++ b/generic/tkbltGrPSOutput.C @@ -0,0 +1,931 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1991-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include +#include +#include + +#include + +#include "tk.h" + +// copied from tk3d.h + +typedef struct TkBorder { + Screen *screen; /* Screen on which the border will be used. */ + Visual *visual; /* Visual for all windows and pixmaps using + * the border. */ + int depth; /* Number of bits per pixel of drawables where + * the border will be used. */ + Colormap colormap; /* Colormap out of which pixels are + * allocated. */ + int resourceRefCount; /* Number of active uses of this color (each + * active use corresponds to a call to + * Tk_Alloc3DBorderFromObj or Tk_Get3DBorder). + * If this count is 0, then this structure is + * no longer valid and it isn't present in + * borderTable: it is being kept around only + * because there are objects referring to it. + * The structure is freed when objRefCount and + * resourceRefCount are both 0. */ + int objRefCount; /* The number of Tcl objects that reference + * this structure. */ + XColor *bgColorPtr; /* Background color (intensity between + * lightColorPtr and darkColorPtr). */ + XColor *darkColorPtr; /* Color for darker areas (must free when + * deleting structure). NULL means shadows + * haven't been allocated yet.*/ + XColor *lightColorPtr; /* Color used for lighter areas of border + * (must free this when deleting structure). + * NULL means shadows haven't been allocated + * yet. */ + Pixmap shadow; /* Stipple pattern to use for drawing shadows + * areas. Used for displays with <= 64 colors + * or where colormap has filled up. */ + GC bgGC; /* Used (if necessary) to draw areas in the + * background color. */ + GC darkGC; /* Used to draw darker parts of the border. + * None means the shadow colors haven't been + * allocated yet.*/ + GC lightGC; /* Used to draw lighter parts of the border. + * None means the shadow colors haven't been + * allocated yet. */ + Tcl_HashEntry *hashPtr; /* Entry in borderTable (needed in order to + * delete structure). */ + struct TkBorder *nextPtr; /* Points to the next TkBorder structure with + * the same color name. Borders with the same + * name but different screens or colormaps are + * chained together off a single entry in + * borderTable. */ +} TkBorder; + +#include "tkbltGraph.h" +#include "tkbltGrPostscript.h" +#include "tkbltGrPSOutput.h" + +using namespace Blt; + +PSOutput::PSOutput(Graph* graphPtr) +{ + graphPtr_ = graphPtr; + + Tcl_DStringInit(&dString_); +} + +PSOutput::~PSOutput() +{ + Tcl_DStringFree(&dString_); +} + +void PSOutput::printPolyline(Point2d* screenPts, int nScreenPts) +{ + Point2d* pp = screenPts; + append("newpath\n"); + format(" %g %g moveto\n", pp->x, pp->y); + + Point2d* pend; + for (pp++, pend = screenPts + nScreenPts; pp < pend; pp++) + format(" %g %g lineto\n", pp->x, pp->y); +} + +void PSOutput::printMaxPolyline(Point2d* points, int nPoints) +{ + if (nPoints <= 0) + return; + + for (int nLeft = nPoints; nLeft > 0; nLeft -= 1500) { + int length = MIN(1500, nLeft); + printPolyline(points, length); + append("DashesProc stroke\n"); + points += length; + } +} + +void PSOutput::printSegments(Segment2d* segments, int nSegments) +{ + append("newpath\n"); + + for (Segment2d *sp = segments, *send = sp + nSegments; sp < send; sp++) { + format(" %g %g moveto %g %g lineto\n", sp->p.x, sp->p.y, sp->q.x, sp->q.y); + append("DashesProc stroke\n"); + } +} + +void PSOutput::computeBBox(int width, int height) +{ + Postscript* setupPtr = graphPtr_->postscript_; + PostscriptOptions* pops = (PostscriptOptions*)setupPtr->ops_; + + // scale from points to pica + double pica = 25.4 / 72 * + WidthOfScreen(Tk_Screen(graphPtr_->tkwin_)) / + WidthMMOfScreen(Tk_Screen(graphPtr_->tkwin_)); + + double hBorder = 2*pops->xPad/pica; + double vBorder = 2*pops->yPad/pica; + int hSize = !pops->landscape ? width : height; + int vSize = !pops->landscape ? height : width; + + // If the paper size wasn't specified, set it to the graph size plus the + // paper border. + double paperWidth = pops->reqPaperWidth > 0 ? pops->reqPaperWidth/pica : + hSize + hBorder; + double paperHeight = pops->reqPaperHeight > 0 ? pops->reqPaperHeight/pica : + vSize + vBorder; + + // Scale the plot size if it's bigger than the paper + double hScale = (hSize+hBorder)>paperWidth ? (paperWidth-hBorder)/hSize + : 1.0; + double vScale = (vSize+vBorder)>paperHeight ? (paperHeight-vBorder)/vSize + : 1.0; + + double scale = MIN(hScale, vScale); + if (scale != 1.0) { + hSize = (int)(hSize*scale + 0.5); + vSize = (int)(vSize*scale + 0.5); + } + + int x = (int)((paperWidth > hSize) && pops->center ? + (paperWidth - hSize) / 2 : pops->xPad/pica); + int y = (int)((paperHeight > vSize) && pops->center ? + (paperHeight - vSize) / 2 : pops->yPad/pica); + + setupPtr->left = x; + setupPtr->bottom = y; + setupPtr->right = x + hSize - 1; + setupPtr->top = y + vSize - 1; + setupPtr->scale = scale; + setupPtr->paperHeight = (int)paperHeight; + setupPtr->paperWidth = (int)paperWidth; +} + +const char* PSOutput::getValue(int* lengthPtr) +{ + *lengthPtr = strlen(Tcl_DStringValue(&dString_)); + return Tcl_DStringValue(&dString_); +} + +void PSOutput::append(const char* string) +{ + Tcl_DStringAppend(&dString_, string, -1); +} + +void PSOutput::format(const char* fmt, ...) +{ + va_list argList; + + va_start(argList, fmt); + vsnprintf(scratchArr_, POSTSCRIPT_BUFSIZ, fmt, argList); + va_end(argList); + Tcl_DStringAppend(&dString_, scratchArr_, -1); +} + +void PSOutput::setLineWidth(int lineWidth) +{ + if (lineWidth < 1) + lineWidth = 1; + format("%d setlinewidth\n", lineWidth); +} + +void PSOutput::printRectangle(double x, double y, int width, int height) +{ + append("newpath\n"); + format(" %g %g moveto\n", x, y); + format(" %d %d rlineto\n", width, 0); + format(" %d %d rlineto\n", 0, height); + format(" %d %d rlineto\n", -width, 0); + append("closepath\n"); + append("stroke\n"); +} + +void PSOutput::fillRectangle(double x, double y, int width, int height) +{ + append("newpath\n"); + format(" %g %g moveto\n", x, y); + format(" %d %d rlineto\n", width, 0); + format(" %d %d rlineto\n", 0, height); + format(" %d %d rlineto\n", -width, 0); + append("closepath\n"); + append("fill\n"); +} + +void PSOutput::fillRectangles(Rectangle* rectangles, int nRectangles) +{ + for (Rectangle *rp = rectangles, *rend = rp + nRectangles; rp < rend; rp++) + fillRectangle((double)rp->x, (double)rp->y, (int)rp->width,(int)rp->height); +} + +void PSOutput::setBackground(XColor* colorPtr) +{ + PostscriptOptions* pops = (PostscriptOptions*)graphPtr_->postscript_->ops_; + printXColor(colorPtr); + append(" setrgbcolor\n"); + if (pops->greyscale) + append(" currentgray setgray\n"); +} + +void PSOutput::setForeground(XColor* colorPtr) +{ + PostscriptOptions* pops = (PostscriptOptions*)graphPtr_->postscript_->ops_; + printXColor(colorPtr); + append(" setrgbcolor\n"); + if (pops->greyscale) + append(" currentgray setgray\n"); +} + +void PSOutput::setBackground(Tk_3DBorder border) +{ + TkBorder* borderPtr = (TkBorder*)border; + setBackground(borderPtr->bgColorPtr); +} + +void PSOutput::setFont(Tk_Font font) +{ + Tcl_DString psdstr; + Tcl_DStringInit(&psdstr); + int psSize = Tk_PostscriptFontName(font, &psdstr); + format("%d /%s SetFont\n", psSize, Tcl_DStringValue(&psdstr)); + Tcl_DStringFree(&psdstr); +} + +void PSOutput::setLineAttributes(XColor* colorPtr,int lineWidth, + Dashes* dashesPtr, int capStyle, + int joinStyle) +{ + setJoinStyle(joinStyle); + setCapStyle(capStyle); + setForeground(colorPtr); + setLineWidth(lineWidth); + setDashes(dashesPtr); + append("/DashesProc {} def\n"); +} + +void PSOutput::fill3DRectangle(Tk_3DBorder border, double x, double y, + int width, int height, int borderWidth, + int relief) +{ + TkBorder* borderPtr = (TkBorder*)border; + + setBackground(borderPtr->bgColorPtr); + fillRectangle(x, y, width, height); + print3DRectangle(border, x, y, width, height, borderWidth, relief); +} + +void PSOutput::setClearBackground() +{ + append("1 1 1 setrgbcolor\n"); +} + +void PSOutput::setDashes(Dashes* dashesPtr) +{ + + append("[ "); + if (dashesPtr) { + for (unsigned char* vp = dashesPtr->values; *vp != 0; vp++) + format(" %d", *vp); + } + append("] 0 setdash\n"); +} + +void PSOutput::fillPolygon(Point2d *screenPts, int nScreenPts) +{ + printPolygon(screenPts, nScreenPts); + append("fill\n"); +} + +void PSOutput::setJoinStyle(int joinStyle) +{ + // miter = 0, round = 1, bevel = 2 + format("%d setlinejoin\n", joinStyle); +} + +void PSOutput::setCapStyle(int capStyle) +{ + // X11:not last = 0, butt = 1, round = 2, projecting = 3 + // PS: butt = 0, round = 1, projecting = 2 + if (capStyle > 0) + capStyle--; + + format("%d setlinecap\n", capStyle); +} + +void PSOutput::printPolygon(Point2d *screenPts, int nScreenPts) +{ + Point2d* pp = screenPts; + append("newpath\n"); + format(" %g %g moveto\n", pp->x, pp->y); + + Point2d* pend; + for (pp++, pend = screenPts + nScreenPts; pp < pend; pp++) + format(" %g %g lineto\n", pp->x, pp->y); + + format(" %g %g lineto\n", screenPts[0].x, screenPts[0].y); + append("closepath\n"); +} + +void PSOutput::print3DRectangle(Tk_3DBorder border, double x, double y, + int width, int height, int borderWidth, + int relief) +{ + int twiceWidth = (borderWidth * 2); + if ((width < twiceWidth) || (height < twiceWidth)) + return; + + TkBorder* borderPtr = (TkBorder*)border; + + // Handle grooves and ridges with recursive calls + if ((relief == TK_RELIEF_GROOVE) || (relief == TK_RELIEF_RIDGE)) { + int halfWidth = borderWidth / 2; + int insideOffset = borderWidth - halfWidth; + print3DRectangle(border, (double)x, (double)y, width, height, halfWidth, + (relief == TK_RELIEF_GROOVE) ? + TK_RELIEF_SUNKEN : TK_RELIEF_RAISED); + print3DRectangle(border, (double)(x + insideOffset), + (double)(y + insideOffset), width - insideOffset * 2, + height - insideOffset * 2, halfWidth, + (relief == TK_RELIEF_GROOVE) ? + TK_RELIEF_RAISED : TK_RELIEF_SUNKEN); + return; + } + + XColor* lightPtr = borderPtr->lightColorPtr; + XColor* darkPtr = borderPtr->darkColorPtr; + XColor light; + if (!lightPtr) { + light.red = 0x00; + light.blue = 0x00; + light.green = 0x00; + lightPtr = &light; + } + XColor dark; + if (!darkPtr) { + dark.red = 0x00; + dark.blue = 0x00; + dark.green = 0x00; + darkPtr = &dark; + } + + XColor* topPtr, *bottomPtr; + if (relief == TK_RELIEF_RAISED) { + topPtr = lightPtr; + bottomPtr = darkPtr; + } + else if (relief == TK_RELIEF_SUNKEN) { + topPtr = darkPtr; + bottomPtr = lightPtr; + } + else if (relief == TK_RELIEF_SOLID) { + topPtr = lightPtr; + bottomPtr = lightPtr; + } + else { + topPtr = borderPtr->bgColorPtr; + bottomPtr = borderPtr->bgColorPtr; + } + + setBackground(bottomPtr); + fillRectangle(x, y + height - borderWidth, width, borderWidth); + fillRectangle(x + width - borderWidth, y, borderWidth, height); + + Point2d points[7]; + points[0].x = points[1].x = points[6].x = x; + points[0].y = points[6].y = y + height; + points[1].y = points[2].y = y; + points[2].x = x + width; + points[3].x = x + width - borderWidth; + points[3].y = points[4].y = y + borderWidth; + points[4].x = points[5].x = x + borderWidth; + points[5].y = y + height - borderWidth; + if (relief != TK_RELIEF_FLAT) + setBackground(topPtr); + + fillPolygon(points, 7); +} + +void PSOutput::printXColor(XColor* colorPtr) +{ + format("%g %g %g", + ((double)(colorPtr->red >> 8) / 255.0), + ((double)(colorPtr->green >> 8) / 255.0), + ((double)(colorPtr->blue >> 8) / 255.0)); +} + +int PSOutput::preamble(const char* fileName) +{ + Postscript* setupPtr = graphPtr_->postscript_; + PostscriptOptions* ops = (PostscriptOptions*)setupPtr->ops_; + + if (!fileName) + fileName = Tk_PathName(graphPtr_->tkwin_); + + // Comments + append("%!PS-Adobe-3.0 EPSF-3.0\n"); + + // The "BoundingBox" comment is required for EPS files. The box + // coordinates are integers, so we need round away from the center of the + // box. + format("%%%%BoundingBox: %d %d %d %d\n", + setupPtr->left, setupPtr->paperHeight - setupPtr->top, + setupPtr->right, setupPtr->paperHeight - setupPtr->bottom); + + append("%%Pages: 0\n"); + + format("%%%%Creator: (%s %s %s)\n", PACKAGE_NAME, PACKAGE_VERSION, + Tk_Class(graphPtr_->tkwin_)); + + time_t ticks = time((time_t *) NULL); + char date[200]; + strcpy(date, ctime(&ticks)); + char* newline = date + strlen(date) - 1; + if (*newline == '\n') + *newline = '\0'; + + format("%%%%CreationDate: (%s)\n", date); + format("%%%%Title: (%s)\n", fileName); + append("%%DocumentData: Clean7Bit\n"); + if (ops->landscape) + append("%%Orientation: Landscape\n"); + else + append("%%Orientation: Portrait\n"); + + append("%%DocumentNeededResources: font Helvetica Courier\n"); + addComments(ops->comments); + append("%%EndComments\n\n"); + + // Prolog + prolog(); + + // Setup + append("%%BeginSetup\n"); + append("gsave\n"); + append("1 setlinewidth\n"); + append("1 setlinejoin\n"); + append("0 setlinecap\n"); + append("[] 0 setdash\n"); + append("0 0 0 setrgbcolor\n"); + + if (ops->footer) { + const char* who = getenv("LOGNAME"); + if (!who) + who = "???"; + + append("8 /Helvetica SetFont\n"); + append("10 30 moveto\n"); + format("(Date: %s) show\n", date); + append("10 20 moveto\n"); + format("(File: %s) show\n", fileName); + append("10 10 moveto\n"); + format("(Created by: %s@%s) show\n", who, Tcl_GetHostName()); + append("0 0 moveto\n"); + } + + // Set the conversion from postscript to X11 coordinates. Scale pica to + // pixels and flip the y-axis (the origin is the upperleft corner). + // Papersize is in pixels. Translate the new origin *after* changing the scale + append("% Transform coordinate system to use X11 coordinates\n"); + append("% 1. Flip y-axis over by reversing the scale,\n"); + append("% 2. Translate the origin to the other side of the page,\n"); + append("% making the origin the upper left corner\n"); + append("1 -1 scale\n"); + format("0 %d translate\n", -setupPtr->paperHeight); + + // Set Origin + format("%% Set origin\n%d %d translate\n\n", setupPtr->left,setupPtr->bottom); + if (ops->landscape) + format("%% Landscape orientation\n0 %g translate\n-90 rotate\n", + ((double)graphPtr_->width_ * setupPtr->scale)); + + append("\n%%EndSetup\n\n"); + + return TCL_OK; +} + +void PSOutput::addComments(const char** comments) +{ + if (!comments) + return; + + for (const char** pp = comments; *pp; pp+=2) { + if (*(pp+1) == NULL) + break; + format("%% %s: %s\n", *pp, *(pp+1)); + } +} + +unsigned char PSOutput::reverseBits(unsigned char byte) +{ + byte = ((byte >> 1) & 0x55) | ((byte << 1) & 0xaa); + byte = ((byte >> 2) & 0x33) | ((byte << 2) & 0xcc); + byte = ((byte >> 4) & 0x0f) | ((byte << 4) & 0xf0); + return byte; +} + +void PSOutput::byteToHex(unsigned char byte, char* string) +{ + static char hexDigits[] = "0123456789ABCDEF"; + + string[0] = hexDigits[byte >> 4]; + string[1] = hexDigits[byte & 0x0F]; +} + +void PSOutput::prolog() +{ + append( +"%%BeginProlog\n" +"%\n" +"% PostScript prolog file of the BLT graph widget.\n" +"%\n" +"% Copyright 1989-1992 Regents of the University of California.\n" +"% Permission to use, copy, modify, and distribute this\n" +"% software and its documentation for any purpose and without\n" +"% fee is hereby granted, provided that the above copyright\n" +"% notice appear in all copies. The University of California\n" +"% makes no representations about the suitability of this\n" +"% software for any purpose. It is provided 'as is' without\n" +"% express or implied warranty.\n" +"%\n" +"% Copyright 1991-1997 Bell Labs Innovations for Lucent Technologies.\n" +"%\n" +"% Permission to use, copy, modify, and distribute this software and its\n" +"% documentation for any purpose and without fee is hereby granted, provided\n" +"% that the above copyright notice appear in all copies and that both that the\n" +"% copyright notice and warranty disclaimer appear in supporting documentation,\n" +"% and that the names of Lucent Technologies any of their entities not be used\n" +"% in advertising or publicity pertaining to distribution of the software\n" +"% without specific, written prior permission.\n" +"%\n" +"% Lucent Technologies disclaims all warranties with regard to this software,\n" +"% including all implied warranties of merchantability and fitness. In no event\n" +"% shall Lucent Technologies be liable for any special, indirect or\n" +"% consequential damages or any damages whatsoever resulting from loss of use,\n" +"% data or profits, whether in an action of contract, negligence or other\n" +"% tortuous action, arising out of or in connection with the use or performance\n" +"% of this software.\n" +"%\n" +"\n" +"200 dict begin\n" +"\n" +"/BaseRatio 1.3467736870885982 def % Ratio triangle base / symbol size\n" +"/DrawSymbolProc 0 def % Routine to draw symbol outline/fill\n" +"/DashesProc 0 def % Dashes routine (line segments)\n" +"\n" +"% Define the array ISOLatin1Encoding (which specifies how characters are \n" +"% encoded for ISO-8859-1 fonts), if it isn't already present (Postscript \n" +"% level 2 is supposed to define it, but level 1 doesn't). \n" +"\n" +"systemdict /ISOLatin1Encoding known not { \n" +" /ISOLatin1Encoding [ \n" +" /space /space /space /space /space /space /space /space \n" +" /space /space /space /space /space /space /space /space \n" +" /space /space /space /space /space /space /space /space \n" +" /space /space /space /space /space /space /space /space \n" +" /space /exclam /quotedbl /numbersign /dollar /percent /ampersand \n" +" /quoteright \n" +" /parenleft /parenright /asterisk /plus /comma /minus /period /slash \n" +" /zero /one /two /three /four /five /six /seven \n" +" /eight /nine /colon /semicolon /less /equal /greater /question \n" +" /at /A /B /C /D /E /F /G \n" +" /H /I /J /K /L /M /N /O \n" +" /P /Q /R /S /T /U /V /W \n" +" /X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore \n" +" /quoteleft /a /b /c /d /e /f /g \n" +" /h /i /j /k /l /m /n /o \n" +" /p /q /r /s /t /u /v /w \n" +" /x /y /z /braceleft /bar /braceright /asciitilde /space \n" +" /space /space /space /space /space /space /space /space \n" +" /space /space /space /space /space /space /space /space \n" +" /dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent \n" +" /dieresis /space /ring /cedilla /space /hungarumlaut /ogonek /caron \n" +" /space /exclamdown /cent /sterling /currency /yen /brokenbar /section \n" +" /dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen \n" +" /registered /macron \n" +" /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph \n" +" /periodcentered \n" +" /cedillar /onesuperior /ordmasculine /guillemotright /onequarter \n" +" /onehalf /threequarters /questiondown \n" +" /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla \n" +" /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex \n" +" /Idieresis \n" +" /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply \n" +" /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn \n" +" /germandbls \n" +" /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla \n" +" /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex \n" +" /idieresis \n" +" /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide \n" +" /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn \n" +" /ydieresis \n" +" ] def \n" +"} if \n" +"\n" +"% font ISOEncode font \n" +"% This procedure changes the encoding of a font from the default \n" +"% Postscript encoding to ISOLatin1. It is typically invoked just \n" +"% before invoking 'setfont'. The body of this procedure comes from \n" +"% Section 5.6.1 of the Postscript book. \n" +"\n" +"/ISOEncode { \n" +" dup length dict\n" +" begin \n" +" {1 index /FID ne {def} {pop pop} ifelse} forall \n" +" /Encoding ISOLatin1Encoding def \n" +" currentdict \n" +" end \n" +"\n" +" % I'm not sure why it's necessary to use 'definefont' on this new \n" +" % font, but it seems to be important; just use the name 'Temporary' \n" +" % for the font. \n" +"\n" +" /Temporary exch definefont \n" +"} bind def \n" +"\n" +"/Stroke {\n" +" gsave\n" +" stroke\n" +" grestore\n" +"} def\n" +"\n" +"/Fill {\n" +" gsave\n" +" fill\n" +" grestore\n" +"} def\n" +"\n" +"/SetFont { \n" +" % Stack: pointSize fontName\n" +" findfont exch scalefont ISOEncode setfont\n" +"} def\n" +"\n" +"/Box {\n" +" % Stack: x y width height\n" +" newpath\n" +" exch 4 2 roll moveto\n" +" dup 0 rlineto\n" +" exch 0 exch rlineto\n" +" neg 0 rlineto\n" +" closepath\n" +"} def\n" +"\n" +"/LS { % Stack: x1 y1 x2 y2\n" +" newpath \n" +" 4 2 roll moveto \n" +" lineto \n" +" closepath\n" +" stroke\n" +"} def\n" +"\n" +"/baselineSampler ( TXygqPZ) def\n" +"% Put an extra-tall character in; done this way to avoid encoding trouble\n" +"baselineSampler 0 196 put\n" +"\n" +"/cstringshow {\n" +" {\n" +" dup type /stringtype eq\n" +" { show } { glyphshow }\n" +" ifelse\n" +" } forall\n" +"} bind def\n" +"\n" +"/cstringwidth {\n" +" 0 exch 0 exch\n" +" {\n" +" dup type /stringtype eq\n" +" { stringwidth } {\n" +" currentfont /Encoding get exch 1 exch put (\001)\n" +" stringwidth\n" +" }\n" +" ifelse\n" +" exch 3 1 roll add 3 1 roll add exch\n" +" } forall\n" +"} bind def\n" +"\n" +"/DrawText {\n" +" gsave\n" +" /justify exch def\n" +" /yoffset exch def\n" +" /xoffset exch def\n" +" /strings exch def\n" +" % Compute the baseline offset and the actual font height.\n" +" 0 0 moveto baselineSampler false charpath\n" +" pathbbox dup /baseline exch def\n" +" exch pop exch sub /height exch def pop\n" +" newpath\n" +" % overall width\n" +" /ww 0 def\n" +" strings {\n" +" cstringwidth pop\n" +" dup ww gt {/ww exch def} {pop} ifelse\n" +" newpath\n" +" } forall\n" +" % overall height\n" +" /hh 0 def\n" +" strings length height mul /hh exch def\n" +" newpath\n" +" % Translate to x,y\n" +" translate\n" +" % Translate to offset\n" +" ww xoffset mul hh yoffset mul translate\n" +" % rotate\n" +" ww 2 div hh 2 div translate\n" +" neg rotate\n" +" ww -2 div hh -2 div translate\n" +" % Translate to justify and baseline\n" +" justify ww mul baseline translate\n" +" % For each line, justify and display\n" +" strings {\n" +" dup cstringwidth pop\n" +" justify neg mul 0 moveto\n" +" gsave\n" +" 1 -1 scale\n" +" cstringshow\n" +" grestore\n" +" 0 height translate\n" +" } forall\n" +" grestore\n" +"} bind def \n" +"\n" +"% Symbols:\n" +"\n" +"% Skinny-cross\n" +"/Sc {\n" +" % Stack: x y symbolSize\n" +" gsave\n" +" 3 -2 roll translate 45 rotate\n" +" 0 0 3 -1 roll Sp\n" +" grestore\n" +"} def\n" +"\n" +"% Skinny-plus\n" +"/Sp {\n" +" % Stack: x y symbolSize\n" +" gsave\n" +" 3 -2 roll translate\n" +" 2 div\n" +" dup 2 copy\n" +" newpath \n" +" neg 0 \n" +" moveto 0 \n" +" lineto\n" +" DrawSymbolProc\n" +" newpath \n" +" neg 0 \n" +" exch moveto 0 \n" +" exch lineto\n" +" DrawSymbolProc\n" +" grestore\n" +"} def\n" +"\n" +"% Cross\n" +"/Cr {\n" +" % Stack: x y symbolSize\n" +" gsave\n" +" 3 -2 roll translate 45 rotate\n" +" 0 0 3 -1 roll Pl\n" +" grestore\n" +"} def\n" +"\n" +"% Plus\n" +"/Pl {\n" +" % Stack: x y symbolSize\n" +" gsave\n" +" 3 -2 roll translate\n" +" dup 2 div\n" +" exch 6 div\n" +"\n" +" %\n" +" % 2 3 The plus/cross symbol is a\n" +" % closed polygon of 12 points.\n" +" % 0 1 4 5 The diagram to the left\n" +" % x,y represents the positions of\n" +" % 11 10 7 6 the points which are computed\n" +" % below.\n" +" % 9 8\n" +" %\n" +"\n" +" newpath\n" +" 2 copy exch neg exch neg moveto \n" +" dup neg dup lineto\n" +" 2 copy neg exch neg lineto\n" +" 2 copy exch neg lineto\n" +" dup dup neg lineto \n" +" 2 copy neg lineto 2 copy lineto\n" +" dup dup lineto \n" +" 2 copy exch lineto \n" +" 2 copy neg exch lineto\n" +" dup dup neg exch lineto \n" +" exch neg exch lineto\n" +" closepath\n" +" DrawSymbolProc\n" +" grestore\n" +"} def\n" +"\n" +"% Circle\n" +"/Ci {\n" +" % Stack: x y symbolSize\n" +" gsave\n" +" 3 copy pop moveto \n" +" newpath\n" +" 2 div 0 360 arc\n" +" closepath \n" +" DrawSymbolProc\n" +" grestore\n" +"} def\n" +"\n" +"% Square\n" +"/Sq {\n" +" % Stack: x y symbolSize\n" +" gsave\n" +" dup dup 2 div dup\n" +" 6 -1 roll exch sub exch\n" +" 5 -1 roll exch sub 4 -2 roll Box\n" +" DrawSymbolProc\n" +" grestore\n" +"} def\n" +"\n" +"% Line\n" +"/Li {\n" +" % Stack: x y symbolSize\n" +" gsave\n" +" 3 1 roll exch 3 -1 roll 2 div 3 copy\n" +" newpath\n" +" sub exch moveto \n" +" add exch lineto\n" +" closepath\n" +" stroke\n" +" grestore\n" +"} def\n" +"\n" +"% Diamond\n" +"/Di {\n" +" % Stack: x y symbolSize\n" +" gsave\n" +" 3 1 roll translate 45 rotate 0 0 3 -1 roll Sq\n" +" grestore\n" +"} def\n" +" \n" +"% Triangle\n" +"/Tr {\n" +" % Stack: x y symbolSize\n" +" gsave\n" +" 3 -2 roll translate\n" +" BaseRatio mul 0.5 mul % Calculate 1/2 base\n" +" dup 0 exch 30 cos mul % h1 = height above center point\n" +" neg % b2 0 -h1\n" +" newpath \n" +" moveto % point 1; b2\n" +" dup 30 sin 30 cos div mul % h2 = height below center point\n" +" 2 copy lineto % point 2; b2 h2\n" +" exch neg exch lineto % \n" +" closepath\n" +" DrawSymbolProc\n" +" grestore\n" +"} def\n" +"\n" +"% Arrow\n" +"/Ar {\n" +" % Stack: x y symbolSize\n" +" gsave\n" +" 3 -2 roll translate\n" +" BaseRatio mul 0.5 mul % Calculate 1/2 base\n" +" dup 0 exch 30 cos mul % h1 = height above center point\n" +" % b2 0 h1\n" +" newpath moveto % point 1; b2\n" +" dup 30 sin 30 cos div mul % h2 = height below center point\n" +" neg % -h2 b2\n" +" 2 copy lineto % point 2; b2 h2\n" +" exch neg exch lineto % \n" +" closepath\n" +" DrawSymbolProc\n" +" grestore\n" +"} def\n" +"\n" +"%%EndProlog\n" +); +} diff --git a/generic/tkbltGrPSOutput.h b/generic/tkbltGrPSOutput.h new file mode 100644 index 0000000..04bb2fd --- /dev/null +++ b/generic/tkbltGrPSOutput.h @@ -0,0 +1,90 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __Blt_GrPSOutput_h__ +#define __Blt_GrPSOutput_h__ + +#include + +#define POSTSCRIPT_BUFSIZ ((BUFSIZ*2)-1) + +namespace Blt { + class Graph; + class Postscript; + + class PSOutput { + protected: + Graph* graphPtr_; + Tcl_DString dString_; + char scratchArr_[POSTSCRIPT_BUFSIZ+1]; + + protected: + void addComments(const char**); + void printXColor(XColor*); + unsigned char reverseBits(unsigned char); + void byteToHex(unsigned char, char*); + void setJoinStyle(int); + void setCapStyle(int); + void prolog(); + + public: + PSOutput(Graph*); + virtual ~PSOutput(); + + void printPolyline(Point2d*, int); + void printMaxPolyline(Point2d*, int); + void printSegments(Segment2d*, int); + void printRectangle(double, double, int, int); + void printPolygon(Point2d*, int); + void print3DRectangle(Tk_3DBorder, double, double, int, int, int, int); + + void fillRectangle(double, double, int, int); + void fillRectangles(Rectangle*, int); + void fill3DRectangle(Tk_3DBorder, double, double, int, int, int, int); + void fillPolygon(Point2d*, int); + + void setFont(Tk_Font); + void setLineWidth(int); + void setBackground(XColor*); + void setForeground(XColor*); + void setBackground(Tk_3DBorder); + void setLineAttributes(XColor*,int, Dashes*, int, int); + void setClearBackground(); + void setDashes(Dashes*); + + int preamble(const char*); + void computeBBox(int, int); + const char* getValue(int*); + void append(const char*); + void format(const char*, ...); + void varAppend(const char*, ...); + }; +}; + +#endif diff --git a/generic/tkbltGrPen.C b/generic/tkbltGrPen.C new file mode 100644 index 0000000..71e5fe9 --- /dev/null +++ b/generic/tkbltGrPen.C @@ -0,0 +1,62 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "tkbltGrPen.h" +#include "tkbltGraph.h" + +using namespace Blt; + +Pen::Pen(Graph* graphPtr, const char* name, Tcl_HashEntry* hPtr) +{ + optionTable_ = NULL; + ops_ = NULL; + graphPtr_ = graphPtr; + name_ = dupstr(name); + hashPtr_ = hPtr; + refCount_ =0; + flags =0; + manageOptions_ =0; +} + +Pen::~Pen() +{ + delete [] name_; + + if (hashPtr_) + Tcl_DeleteHashEntry(hashPtr_); + + // PenOptions* ops = (PenOptions*)ops_; + + Tk_FreeConfigOptions((char*)ops_, optionTable_, graphPtr_->tkwin_); + + if (manageOptions_) + free(ops_); +} diff --git a/generic/tkbltGrPen.h b/generic/tkbltGrPen.h new file mode 100644 index 0000000..003e8dd --- /dev/null +++ b/generic/tkbltGrPen.h @@ -0,0 +1,79 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGrPen_h__ +#define __BltGrPen_h__ + +#include + +#include "tkbltGrText.h" + +namespace Blt { + class Graph; + + typedef struct { + int errorBarShow; + int errorBarLineWidth; + int errorBarCapWidth; + XColor* errorBarColor; + int valueShow; + const char* valueFormat; + TextStyleOptions valueStyle; + } PenOptions; + + class Pen { + protected: + Tk_OptionTable optionTable_; + void* ops_; + + public: + Graph* graphPtr_; + const char *name_; + Tcl_HashEntry *hashPtr_; + int refCount_; + unsigned int flags; + int manageOptions_; + + public: + Pen(); + Pen(Graph*, const char*, Tcl_HashEntry*); + virtual ~Pen(); + + virtual ClassId classId() =0; + virtual const char* className() =0; + virtual const char* typeName() =0; + + Tk_OptionTable optionTable() {return optionTable_;} + void* ops() {return ops_;} + + virtual int configure() =0; + }; +}; + +#endif diff --git a/generic/tkbltGrPenBar.C b/generic/tkbltGrPenBar.C new file mode 100644 index 0000000..8f6e59a --- /dev/null +++ b/generic/tkbltGrPenBar.C @@ -0,0 +1,174 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "tkbltGrPenBar.h" +#include "tkbltGraph.h" +#include "tkbltGrDef.h" +#include "tkbltConfig.h" + +using namespace Blt; + +static Tk_OptionSpec barPenOptionSpecs[] = { + {TK_OPTION_SYNONYM, "-background", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-color", 0}, + {TK_OPTION_SYNONYM, "-bd", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-borderwidth", 0}, + {TK_OPTION_SYNONYM, "-bg", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-color", 0}, + {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", + STD_BORDERWIDTH, -1, Tk_Offset(BarPenOptions, borderWidth), 0, NULL, CACHE}, + {TK_OPTION_BORDER, "-color", "color", "Color", + STD_NORMAL_FOREGROUND, -1, Tk_Offset(BarPenOptions, fill), 0, NULL, CACHE}, + {TK_OPTION_COLOR, "-errorbarcolor", "errorBarColor", "ErrorBarColor", + NULL, -1, Tk_Offset(BarPenOptions, errorBarColor), + TK_OPTION_NULL_OK, NULL, CACHE}, + {TK_OPTION_PIXELS, "-errorbarwidth", "errorBarWidth","ErrorBarWidth", + "1", -1, Tk_Offset(BarPenOptions, errorBarLineWidth), 0, NULL, CACHE}, + {TK_OPTION_PIXELS, "-errorbarcap", "errorBarCap", "ErrorBarCap", + "0", -1, Tk_Offset(BarPenOptions, errorBarCapWidth), 0, NULL, LAYOUT}, + {TK_OPTION_SYNONYM, "-fg", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-outline", 0}, + {TK_OPTION_SYNONYM, "-fill", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-color", 0}, + {TK_OPTION_SYNONYM, "-foreground", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-outline", 0}, + {TK_OPTION_COLOR, "-outline", "outline", "Outline", + NULL, -1, Tk_Offset(BarPenOptions, outlineColor), + TK_OPTION_NULL_OK, NULL, CACHE}, + {TK_OPTION_RELIEF, "-relief", "relief", "Relief", + "raised", -1, Tk_Offset(BarPenOptions, relief), 0, NULL, LAYOUT}, + {TK_OPTION_STRING_TABLE, "-showerrorbars", "showErrorBars", "ShowErrorBars", + "both", -1, Tk_Offset(BarPenOptions, errorBarShow), + 0, &fillObjOption, LAYOUT}, + {TK_OPTION_STRING_TABLE, "-showvalues", "showValues", "ShowValues", + "none", -1, Tk_Offset(BarPenOptions, valueShow), 0, &fillObjOption, CACHE}, + {TK_OPTION_ANCHOR, "-valueanchor", "valueAnchor", "ValueAnchor", + "s", -1, Tk_Offset(BarPenOptions, valueStyle.anchor), 0, NULL, CACHE}, + {TK_OPTION_COLOR, "-valuecolor", "valueColor", "ValueColor", + STD_NORMAL_FOREGROUND, -1, Tk_Offset(BarPenOptions, valueStyle.color), + 0, NULL, CACHE}, + {TK_OPTION_FONT, "-valuefont", "valueFont", "ValueFont", + STD_FONT_SMALL, -1, Tk_Offset(BarPenOptions, valueStyle.font), + 0, NULL, CACHE}, + {TK_OPTION_STRING, "-valueformat", "valueFormat", "ValueFormat", + "%g", -1, Tk_Offset(BarPenOptions, valueFormat), + TK_OPTION_NULL_OK, NULL, CACHE}, + {TK_OPTION_DOUBLE, "-valuerotate", "valueRotate", "ValueRotate", + "0", -1, Tk_Offset(BarPenOptions, valueStyle.angle), 0, NULL, CACHE}, + {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, -1, 0, 0, 0} +}; + +BarPen::BarPen(Graph* graphPtr, const char* name, Tcl_HashEntry* hPtr) + : Pen(graphPtr, name, hPtr) +{ + ops_ = calloc(1, sizeof(BarPenOptions)); + BarPenOptions* ops = (BarPenOptions*)ops_; + manageOptions_ =1; + + outlineGC_ =NULL; + errorBarGC_ =NULL; + + ops->valueStyle.anchor =TK_ANCHOR_NW; + ops->valueStyle.color =NULL; + ops->valueStyle.font =NULL; + ops->valueStyle.angle =0; + ops->valueStyle.justify =TK_JUSTIFY_LEFT; + + optionTable_ = Tk_CreateOptionTable(graphPtr_->interp_, barPenOptionSpecs); +} + +BarPen::BarPen(Graph* graphPtr, const char* name, void* options) + : Pen(graphPtr, name, NULL) +{ + ops_ = options; + BarPenOptions* ops = (BarPenOptions*)ops_; + manageOptions_ =0; + + outlineGC_ =NULL; + errorBarGC_ =NULL; + + ops->valueStyle.anchor =TK_ANCHOR_NW; + ops->valueStyle.color =NULL; + ops->valueStyle.font =NULL; + ops->valueStyle.angle =0; + ops->valueStyle.justify =TK_JUSTIFY_LEFT; + + optionTable_ = Tk_CreateOptionTable(graphPtr_->interp_, barPenOptionSpecs); +} + +BarPen::~BarPen() +{ + if (outlineGC_) + Tk_FreeGC(graphPtr_->display_, outlineGC_); + if (errorBarGC_) + Tk_FreeGC(graphPtr_->display_, errorBarGC_); +} + +int BarPen::configure() +{ + BarPenOptions* ops = (BarPenOptions*)ops_; + + // outlineGC + { + unsigned long gcMask = GCForeground | GCLineWidth; + XGCValues gcValues; + gcValues.line_width = ops->borderWidth; + if (ops->outlineColor) + gcValues.foreground = ops->outlineColor->pixel; + else if (ops->fill) + gcValues.foreground = Tk_3DBorderColor(ops->fill)->pixel; + GC newGC = Tk_GetGC(graphPtr_->tkwin_, gcMask, &gcValues); + if (outlineGC_) + Tk_FreeGC(graphPtr_->display_, outlineGC_); + outlineGC_ = newGC; + } + + // errorBarGC + { + unsigned long gcMask = GCForeground | GCLineWidth; + XGCValues gcValues; + if (ops->errorBarColor) + gcValues.foreground = ops->errorBarColor->pixel; + else if (ops->outlineColor) + gcValues.foreground = ops->outlineColor->pixel; + else if (ops->fill) + gcValues.foreground = Tk_3DBorderColor(ops->fill)->pixel; + + gcValues.line_width = ops->errorBarLineWidth; + GC newGC = Tk_GetGC(graphPtr_->tkwin_, gcMask, &gcValues); + if (errorBarGC_) + Tk_FreeGC(graphPtr_->display_, errorBarGC_); + errorBarGC_ = newGC; + } + + return TCL_OK; +} + diff --git a/generic/tkbltGrPenBar.h b/generic/tkbltGrPenBar.h new file mode 100644 index 0000000..f39db94 --- /dev/null +++ b/generic/tkbltGrPenBar.h @@ -0,0 +1,73 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGrPenBar_h__ +#define __BltGrPenBar_h__ + +#include + +#include "tkbltGrPen.h" + +namespace Blt { + + typedef struct { + int errorBarShow; + int errorBarLineWidth; + int errorBarCapWidth; + XColor* errorBarColor; + int valueShow; + const char *valueFormat; + TextStyleOptions valueStyle; + + XColor* outlineColor; + Tk_3DBorder fill; + int borderWidth; + int relief; + } BarPenOptions; + + class BarPen : public Pen { + public: + GC fillGC_; + GC outlineGC_; + GC errorBarGC_; + + public: + BarPen(Graph*, const char*, Tcl_HashEntry*); + BarPen(Graph*, const char*, void*); + virtual ~BarPen(); + + ClassId classId() {return CID_ELEM_BAR;} + const char* className() {return "BarElement";} + const char* typeName() {return "bar";} + + int configure(); + }; +}; + +#endif diff --git a/generic/tkbltGrPenLine.C b/generic/tkbltGrPenLine.C new file mode 100644 index 0000000..5f15ce8 --- /dev/null +++ b/generic/tkbltGrPenLine.C @@ -0,0 +1,243 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#include "tkbltGrPenLine.h" +#include "tkbltGraph.h" +#include "tkbltGrMisc.h" +#include "tkbltGrDef.h" +#include "tkbltConfig.h" + +using namespace Blt; + +const char* symbolObjOption[] = + {"none", "square", "circle", "diamond", "plus", "cross", "splus", "scross", "triangle", "arrow", NULL}; + +// Defs + +static Tk_OptionSpec linePenOptionSpecs[] = { + {TK_OPTION_COLOR, "-color", "color", "Color", + STD_NORMAL_FOREGROUND, -1, Tk_Offset(LinePenOptions, traceColor), + 0, NULL, CACHE}, + {TK_OPTION_CUSTOM, "-dashes", "dashes", "Dashes", + NULL, -1, Tk_Offset(LinePenOptions, traceDashes), + TK_OPTION_NULL_OK, &dashesObjOption, CACHE}, + {TK_OPTION_COLOR, "-errorbarcolor", "errorBarColor", "ErrorBarColor", + NULL, -1, Tk_Offset(LinePenOptions, errorBarColor), + TK_OPTION_NULL_OK, NULL, CACHE}, + {TK_OPTION_PIXELS, "-errorbarwidth", "errorBarWidth", "ErrorBarWidth", + "1", -1, Tk_Offset(LinePenOptions, errorBarLineWidth), 0, NULL, CACHE}, + {TK_OPTION_PIXELS, "-errorbarcap", "errorBarCap", "ErrorBarCap", + "0", -1, Tk_Offset(LinePenOptions, errorBarCapWidth), 0, NULL, LAYOUT}, + {TK_OPTION_COLOR, "-fill", "fill", "Fill", + NULL, -1, Tk_Offset(LinePenOptions, symbol.fillColor), + TK_OPTION_NULL_OK, NULL, CACHE}, + {TK_OPTION_PIXELS, "-linewidth", "lineWidth", "LineWidth", + "1", -1, Tk_Offset(LinePenOptions, traceWidth), 0, NULL, CACHE}, + {TK_OPTION_COLOR, "-offdash", "offDash", "OffDash", + NULL, -1, Tk_Offset(LinePenOptions, traceOffColor), + TK_OPTION_NULL_OK, NULL, CACHE}, + {TK_OPTION_COLOR, "-outline", "outline", "Outline", + NULL, -1, Tk_Offset(LinePenOptions, symbol.outlineColor), + TK_OPTION_NULL_OK, NULL, CACHE}, + {TK_OPTION_PIXELS, "-outlinewidth", "outlineWidth", "OutlineWidth", + "1", -1, Tk_Offset(LinePenOptions, symbol.outlineWidth), 0, NULL, CACHE}, + {TK_OPTION_PIXELS, "-pixels", "pixels", "Pixels", + "0.1i", -1, Tk_Offset(LinePenOptions, symbol.size), 0, NULL, LAYOUT}, + {TK_OPTION_STRING_TABLE, "-showerrorbars", "showErrorBars", "ShowErrorBars", + "both", -1, Tk_Offset(LinePenOptions, errorBarShow), + 0, &fillObjOption, LAYOUT}, + {TK_OPTION_STRING_TABLE, "-showvalues", "showValues", "ShowValues", + "none", -1, Tk_Offset(LinePenOptions, valueShow), 0, &fillObjOption, CACHE}, + {TK_OPTION_STRING_TABLE, "-symbol", "symbol", "Symbol", + "none", -1, Tk_Offset(LinePenOptions, symbol), 0, &symbolObjOption, CACHE}, + {TK_OPTION_ANCHOR, "-valueanchor", "valueAnchor", "ValueAnchor", + "s", -1, Tk_Offset(LinePenOptions, valueStyle.anchor), 0, NULL, CACHE}, + {TK_OPTION_COLOR, "-valuecolor", "valueColor", "ValueColor", + STD_NORMAL_FOREGROUND, -1, Tk_Offset(LinePenOptions, valueStyle.color), + 0, NULL, CACHE}, + {TK_OPTION_FONT, "-valuefont", "valueFont", "ValueFont", + STD_FONT_SMALL, -1, Tk_Offset(LinePenOptions, valueStyle.font), + 0, NULL, CACHE}, + {TK_OPTION_STRING, "-valueformat", "valueFormat", "ValueFormat", + "%g", -1, Tk_Offset(LinePenOptions, valueFormat), + TK_OPTION_NULL_OK, NULL, CACHE}, + {TK_OPTION_DOUBLE, "-valuerotate", "valueRotate", "ValueRotate", + "0", -1, Tk_Offset(LinePenOptions, valueStyle.angle), 0, NULL, CACHE}, + {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, -1, 0, 0, 0} +}; + +LinePen::LinePen(Graph* graphPtr, const char* name, Tcl_HashEntry* hPtr) + : Pen(graphPtr, name, hPtr) +{ + ops_ = calloc(1, sizeof(LinePenOptions)); + LinePenOptions* ops = (LinePenOptions*)ops_; + manageOptions_ =1; + + traceGC_ =NULL; + errorBarGC_ =NULL; + + ops->symbol.type = SYMBOL_NONE; + + ops->valueStyle.anchor =TK_ANCHOR_NW; + ops->valueStyle.color =NULL; + ops->valueStyle.font =NULL; + ops->valueStyle.angle =0; + ops->valueStyle.justify =TK_JUSTIFY_LEFT; + + optionTable_ = Tk_CreateOptionTable(graphPtr_->interp_, linePenOptionSpecs); +} + +LinePen::LinePen(Graph* graphPtr, const char* name, void* options) + : Pen(graphPtr, name, NULL) +{ + ops_ = options; + LinePenOptions* ops = (LinePenOptions*)ops_; + manageOptions_ =0; + + traceGC_ =NULL; + errorBarGC_ =NULL; + + ops->symbol.type = SYMBOL_NONE; + + ops->valueStyle.anchor =TK_ANCHOR_NW; + ops->valueStyle.color =NULL; + ops->valueStyle.font =NULL; + ops->valueStyle.angle =0; + ops->valueStyle.justify =TK_JUSTIFY_LEFT; + + optionTable_ = Tk_CreateOptionTable(graphPtr_->interp_, linePenOptionSpecs); +} + +LinePen::~LinePen() +{ + LinePenOptions* ops = (LinePenOptions*)ops_; + + if (errorBarGC_) + Tk_FreeGC(graphPtr_->display_, errorBarGC_); + + if (traceGC_) + graphPtr_->freePrivateGC(traceGC_); + + if (ops->symbol.outlineGC) + Tk_FreeGC(graphPtr_->display_, ops->symbol.outlineGC); + + if (ops->symbol.fillGC) + Tk_FreeGC(graphPtr_->display_, ops->symbol.fillGC); +} + +int LinePen::configure() +{ + LinePenOptions* ops = (LinePenOptions*)ops_; + + // symbol outline + { + unsigned long gcMask = (GCLineWidth | GCForeground); + XColor* colorPtr = ops->symbol.outlineColor; + if (!colorPtr) + colorPtr = ops->traceColor; + XGCValues gcValues; + gcValues.foreground = colorPtr->pixel; + gcValues.line_width = ops->symbol.outlineWidth; + GC newGC = Tk_GetGC(graphPtr_->tkwin_, gcMask, &gcValues); + if (ops->symbol.outlineGC) + Tk_FreeGC(graphPtr_->display_, ops->symbol.outlineGC); + ops->symbol.outlineGC = newGC; + } + + // symbol fill + { + unsigned long gcMask = (GCLineWidth | GCForeground); + XColor* colorPtr = ops->symbol.fillColor; + if (!colorPtr) + colorPtr = ops->traceColor; + GC newGC = NULL; + XGCValues gcValues; + if (colorPtr) { + gcValues.foreground = colorPtr->pixel; + newGC = Tk_GetGC(graphPtr_->tkwin_, gcMask, &gcValues); + } + if (ops->symbol.fillGC) + Tk_FreeGC(graphPtr_->display_, ops->symbol.fillGC); + ops->symbol.fillGC = newGC; + } + + // trace + { + unsigned long gcMask = + (GCLineWidth | GCForeground | GCLineStyle | GCCapStyle | GCJoinStyle); + XGCValues gcValues; + gcValues.cap_style = CapButt; + gcValues.join_style = JoinRound; + gcValues.line_style = LineSolid; + gcValues.line_width = ops->traceWidth; + + gcValues.foreground = ops->traceColor->pixel; + XColor* colorPtr = ops->traceOffColor; + if (colorPtr) { + gcMask |= GCBackground; + gcValues.background = colorPtr->pixel; + } + if (LineIsDashed(ops->traceDashes)) { + gcValues.line_width = ops->traceWidth; + gcValues.line_style = !colorPtr ? LineOnOffDash : LineDoubleDash; + } + GC newGC = graphPtr_->getPrivateGC(gcMask, &gcValues); + if (traceGC_) + graphPtr_->freePrivateGC(traceGC_); + + if (LineIsDashed(ops->traceDashes)) { + ops->traceDashes.offset = ops->traceDashes.values[0] / 2; + graphPtr_->setDashes(newGC, &ops->traceDashes); + } + traceGC_ = newGC; + } + + // errorbar + { + unsigned long gcMask = (GCLineWidth | GCForeground); + XColor* colorPtr = ops->errorBarColor; + if (!colorPtr) + colorPtr = ops->traceColor; + XGCValues gcValues; + gcValues.line_width = ops->errorBarLineWidth; + gcValues.foreground = colorPtr->pixel; + GC newGC = Tk_GetGC(graphPtr_->tkwin_, gcMask, &gcValues); + if (errorBarGC_) { + Tk_FreeGC(graphPtr_->display_, errorBarGC_); + } + errorBarGC_ = newGC; + } + + return TCL_OK; +} + + diff --git a/generic/tkbltGrPenLine.h b/generic/tkbltGrPenLine.h new file mode 100644 index 0000000..63eeeb8 --- /dev/null +++ b/generic/tkbltGrPenLine.h @@ -0,0 +1,88 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGrPenLine_h__ +#define __BltGrPenLine_h__ + +#include "tkbltGrPen.h" + +namespace Blt { + + typedef enum { + SYMBOL_NONE, SYMBOL_SQUARE, SYMBOL_CIRCLE, SYMBOL_DIAMOND, SYMBOL_PLUS, + SYMBOL_CROSS, SYMBOL_SPLUS, SYMBOL_SCROSS, SYMBOL_TRIANGLE, SYMBOL_ARROW + } SymbolType; + + typedef struct { + SymbolType type; + int size; + XColor* outlineColor; + int outlineWidth; + GC outlineGC; + XColor* fillColor; + GC fillGC; + } Symbol; + + typedef struct { + int errorBarShow; + int errorBarLineWidth; + int errorBarCapWidth; + XColor* errorBarColor; + int valueShow; + const char* valueFormat; + TextStyleOptions valueStyle; + + Symbol symbol; + int traceWidth; + Dashes traceDashes; + XColor* traceColor; + XColor* traceOffColor; + } LinePenOptions; + + class LinePen : public Pen { + public: + GC traceGC_; + GC errorBarGC_; + + public: + LinePen(Graph*, const char*, Tcl_HashEntry*); + LinePen(Graph*, const char*, void*); + virtual ~LinePen(); + + ClassId classId() {return CID_ELEM_LINE;} + const char* className() {return "LineElement";} + const char* typeName() {return "line";} + + int configure(); + }; +}; + +extern const char* symbolObjOption[]; + +#endif diff --git a/generic/tkbltGrPenOp.C b/generic/tkbltGrPenOp.C new file mode 100644 index 0000000..8c5669d --- /dev/null +++ b/generic/tkbltGrPenOp.C @@ -0,0 +1,217 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1996-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "tkbltGraph.h" +#include "tkbltGrPen.h" +#include "tkbltGrPenOp.h" +#include "tkbltGrPenLine.h" +#include "tkbltGrPenBar.h" + +using namespace Blt; + +int Blt::PenObjConfigure(Graph* graphPtr, Pen* penPtr, + Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Tk_SavedOptions savedOptions; + int mask =0; + int error; + Tcl_Obj* errorResult; + + for (error=0; error<=1; error++) { + if (!error) { + if (Tk_SetOptions(interp, (char*)penPtr->ops(), penPtr->optionTable(), + objc, objv, graphPtr->tkwin_, &savedOptions, &mask) + != TCL_OK) + continue; + } + else { + errorResult = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); + } + + if (penPtr->configure() != TCL_OK) + return TCL_ERROR; + graphPtr->flags |= mask; + graphPtr->eventuallyRedraw(); + + break; + } + + if (!error) { + Tk_FreeSavedOptions(&savedOptions); + return TCL_OK; + } + else { + Tcl_SetObjResult(interp, errorResult); + Tcl_DecrRefCount(errorResult); + return TCL_ERROR; + } +} + +static int CgetOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc != 5) { + Tcl_WrongNumArgs(interp, 3, objv, "cget option"); + return TCL_ERROR; + } + + Pen* penPtr; + if (graphPtr->getPen(objv[3], &penPtr) != TCL_OK) + return TCL_ERROR; + + Tcl_Obj* objPtr = Tk_GetOptionValue(interp, + (char*)penPtr->ops(), + penPtr->optionTable(), + objv[4], graphPtr->tkwin_); + if (objPtr == NULL) + return TCL_ERROR; + else + Tcl_SetObjResult(interp, objPtr); + return TCL_OK; +} + +static int ConfigureOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc<4) + return TCL_ERROR; + + Pen* penPtr; + if (graphPtr->getPen(objv[3], &penPtr) != TCL_OK) + return TCL_ERROR; + + if (objc <= 5) { + Tcl_Obj* objPtr = Tk_GetOptionInfo(interp, (char*)penPtr->ops(), + penPtr->optionTable(), + (objc == 5) ? objv[4] : NULL, + graphPtr->tkwin_); + if (objPtr == NULL) + return TCL_ERROR; + else + Tcl_SetObjResult(interp, objPtr); + return TCL_OK; + } + else + return PenObjConfigure(graphPtr, penPtr, interp, objc-4, objv+4); +} + +static int CreateOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc<4) + return TCL_ERROR; + + if (graphPtr->createPen(Tcl_GetString(objv[3]), objc, objv) != TCL_OK) + return TCL_ERROR; + Tcl_SetObjResult(interp, objv[3]); + + return TCL_OK; +} + +static int DeleteOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc<4) + return TCL_ERROR; + + Pen* penPtr; + if (graphPtr->getPen(objv[3], &penPtr) != TCL_OK) + return TCL_ERROR; + + if (penPtr->refCount_ == 0) + delete penPtr; + + return TCL_OK; +} + +static int NamesOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + Tcl_Obj *listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + if (objc == 3) { + Tcl_HashSearch iter; + for (Tcl_HashEntry *hPtr=Tcl_FirstHashEntry(&graphPtr->penTable_, &iter); + hPtr; hPtr=Tcl_NextHashEntry(&iter)) { + Pen* penPtr = (Pen*)Tcl_GetHashValue(hPtr); + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewStringObj(penPtr->name_, -1)); + } + } + else { + Tcl_HashSearch iter; + for (Tcl_HashEntry *hPtr=Tcl_FirstHashEntry(&graphPtr->penTable_, &iter); + hPtr; hPtr=Tcl_NextHashEntry(&iter)) { + Pen* penPtr = (Pen*)Tcl_GetHashValue(hPtr); + for (int ii=3; iiname_, pattern)) { + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewStringObj(penPtr->name_, -1)); + break; + } + } + } + } + Tcl_SetObjResult(interp, listObjPtr); + return TCL_OK; +} + +static int TypeOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc<4) + return TCL_ERROR; + + Pen* penPtr; + if (graphPtr->getPen(objv[3], &penPtr) != TCL_OK) + return TCL_ERROR; + + Tcl_SetStringObj(Tcl_GetObjResult(interp), penPtr->typeName(), -1); + return TCL_OK; +} + +const Ensemble Blt::penEnsemble[] = { + {"cget", CgetOp, 0}, + {"configure", ConfigureOp, 0}, + {"create", CreateOp, 0}, + {"delete", DeleteOp, 0}, + {"names", NamesOp, 0}, + {"type", TypeOp, 0}, + { 0,0,0 } +}; + diff --git a/generic/tkbltGrPenOp.h b/generic/tkbltGrPenOp.h new file mode 100644 index 0000000..5dab592 --- /dev/null +++ b/generic/tkbltGrPenOp.h @@ -0,0 +1,42 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGrPenOp_h__ +#define __BltGrPenOp_h__ + +#include "tkbltGraph.h" + +namespace Blt { + extern const Ensemble penEnsemble[]; + extern int PenObjConfigure(Blt::Graph* graphPtr, Blt::Pen* penPtr, + Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]); +}; + +#endif diff --git a/generic/tkbltGrPenOption.C b/generic/tkbltGrPenOption.C new file mode 100644 index 0000000..b1da1b6 --- /dev/null +++ b/generic/tkbltGrPenOption.C @@ -0,0 +1,89 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1996-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "tkbltGraph.h" +#include "tkbltGrPen.h" +#include "tkbltConfig.h" + +using namespace Blt; + +static Tk_CustomOptionSetProc PenSetProc; +static Tk_CustomOptionGetProc PenGetProc; +static Tk_CustomOptionFreeProc PenFreeProc; +Tk_ObjCustomOption penObjOption = + { + "pen", PenSetProc, PenGetProc, RestoreProc, PenFreeProc, NULL + }; + +static int PenSetProc(ClientData clientData, Tcl_Interp* interp, + Tk_Window tkwin, Tcl_Obj** objPtr, char* widgRec, + int offset, char* savePtr, int flags) +{ + Pen** penPtrPtr = (Pen**)(widgRec + offset); + *(double*)savePtr = *(double*)penPtrPtr; + + if (!penPtrPtr) + return TCL_OK; + + const char* string = Tcl_GetString(*objPtr); + if (!string || !string[0]) { + *penPtrPtr = NULL; + return TCL_OK; + } + + Graph* graphPtr = getGraphFromWindowData(tkwin); + Pen* penPtr; + if (graphPtr->getPen(*objPtr, &penPtr) != TCL_OK) + return TCL_ERROR; + + penPtr->refCount_++; + *penPtrPtr = penPtr; + + return TCL_OK; +}; + +static Tcl_Obj* PenGetProc(ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset) +{ + Pen* penPtr = *(Pen**)(widgRec + offset); + if (!penPtr) + return Tcl_NewStringObj("", -1); + + return Tcl_NewStringObj(penPtr->name_, -1); +}; + +static void PenFreeProc(ClientData clientData, Tk_Window tkwin, char *ptr) +{ + Pen* penPtr = *(Pen**)ptr; + if (penPtr) + if (penPtr->refCount_ > 0) + penPtr->refCount_--; +} + + diff --git a/generic/tkbltGrPostscript.C b/generic/tkbltGrPostscript.C new file mode 100644 index 0000000..4bbf504 --- /dev/null +++ b/generic/tkbltGrPostscript.C @@ -0,0 +1,84 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1991-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "tkbltGraph.h" +#include "tkbltGrPostscript.h" +#include "tkbltConfig.h" + +using namespace Blt; + +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_BOOLEAN, "-center", "center", "Center", + "yes", -1, Tk_Offset(PostscriptOptions, center), 0, NULL, 0}, + {TK_OPTION_CUSTOM, "-comments", "comments", "Comments", + NULL, -1, Tk_Offset(PostscriptOptions, comments), + TK_OPTION_NULL_OK, &listObjOption, 0}, + {TK_OPTION_BOOLEAN, "-decorations", "decorations", "Decorations", + "yes", -1, Tk_Offset(PostscriptOptions, decorations), 0, NULL, 0}, + {TK_OPTION_BOOLEAN, "-footer", "footer", "Footer", + "no", -1, Tk_Offset(PostscriptOptions, footer), 0, NULL, 0}, + {TK_OPTION_BOOLEAN, "-greyscale", "greyscale", "Greyscale", + "no", -1, Tk_Offset(PostscriptOptions, greyscale), 0, NULL, 0}, + {TK_OPTION_PIXELS, "-height", "height", "Height", + "0", -1, Tk_Offset(PostscriptOptions, reqHeight), 0, NULL, 0}, + {TK_OPTION_BOOLEAN, "-landscape", "landscape", "Landscape", + "no", -1, Tk_Offset(PostscriptOptions, landscape), 0, NULL, 0}, + {TK_OPTION_INT, "-level", "level", "Level", + "2", -1, Tk_Offset(PostscriptOptions, level), 0, NULL, 0}, + {TK_OPTION_PIXELS, "-padx", "padX", "PadX", + "1.0i", -1, Tk_Offset(PostscriptOptions, xPad), 0, NULL, 0}, + {TK_OPTION_PIXELS, "-pady", "padY", "PadY", + "1.0i", -1, Tk_Offset(PostscriptOptions, yPad), 0, NULL, 0}, + {TK_OPTION_PIXELS, "-paperheight", "paperHeight", "PaperHeight", + "11.0i", -1, Tk_Offset(PostscriptOptions, reqPaperHeight), 0, NULL, 0}, + {TK_OPTION_PIXELS, "-paperwidth", "paperWidth", "PaperWidth", + "8.5i", -1, Tk_Offset(PostscriptOptions, reqPaperWidth), 0, NULL, 0}, + {TK_OPTION_PIXELS, "-width", "width", "Width", + "0", -1, Tk_Offset(PostscriptOptions, reqWidth), 0, NULL, 0}, + {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, -1, 0, 0, 0} +}; + +Postscript::Postscript(Graph* graphPtr) +{ + ops_ = (PostscriptOptions*)calloc(1, sizeof(PostscriptOptions)); + graphPtr_ = graphPtr; + + optionTable_ =Tk_CreateOptionTable(graphPtr_->interp_, optionSpecs); + Tk_InitOptions(graphPtr_->interp_, (char*)ops_, optionTable_, + graphPtr_->tkwin_); +} + +Postscript::~Postscript() +{ + Tk_FreeConfigOptions((char*)ops_, optionTable_, graphPtr_->tkwin_); + free(ops_); +} + diff --git a/generic/tkbltGrPostscript.h b/generic/tkbltGrPostscript.h new file mode 100644 index 0000000..a0c35a1 --- /dev/null +++ b/generic/tkbltGrPostscript.h @@ -0,0 +1,73 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1991-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGrPostscript_h__ +#define __BltGrPostscript_h__ + +#include + +namespace Blt { + + typedef struct { + int center; + const char **comments; + int decorations; + int footer; + int greyscale; + int landscape; + int level; + int xPad; + int yPad; + int reqPaperWidth; + int reqPaperHeight; + int reqWidth; + int reqHeight; + } PostscriptOptions; + + class Postscript { + public: + Tk_OptionTable optionTable_; + void* ops_; + Graph* graphPtr_; + + int left; + int bottom; + int right; + int top; + double scale; + int paperHeight; + int paperWidth; + + public: + Postscript(Graph*); + virtual ~Postscript(); + }; +}; + +#endif diff --git a/generic/tkbltGrPostscriptOp.C b/generic/tkbltGrPostscriptOp.C new file mode 100644 index 0000000..931feb9 --- /dev/null +++ b/generic/tkbltGrPostscriptOp.C @@ -0,0 +1,183 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1991-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "tkbltGraph.h" +#include "tkbltGrPostscript.h" +#include "tkbltGrPostscriptOp.h" +#include "tkbltGrPSOutput.h" + +using namespace Blt; + +int Blt::PostscriptObjConfigure(Graph* graphPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Postscript* setupPtr = graphPtr->postscript_; + Tk_SavedOptions savedOptions; + int mask =0; + int error; + Tcl_Obj* errorResult; + + for (error=0; error<=1; error++) { + if (!error) { + if (Tk_SetOptions(interp, (char*)setupPtr->ops_, setupPtr->optionTable_, + objc, objv, graphPtr->tkwin_, &savedOptions, &mask) + != TCL_OK) + continue; + } + else { + errorResult = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); + } + + break; + } + + if (!error) { + Tk_FreeSavedOptions(&savedOptions); + return TCL_OK; + } + else { + Tcl_SetObjResult(interp, errorResult); + Tcl_DecrRefCount(errorResult); + return TCL_ERROR; + } +} + +static int CgetOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "cget option"); + return TCL_ERROR; + } + + Postscript *setupPtr = graphPtr->postscript_; + Tcl_Obj* objPtr = Tk_GetOptionValue(interp, + (char*)setupPtr->ops_, + setupPtr->optionTable_, + objv[3], graphPtr->tkwin_); + if (objPtr == NULL) + return TCL_ERROR; + else + Tcl_SetObjResult(interp, objPtr); + return TCL_OK; +} + +static int ConfigureOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + Postscript* setupPtr = graphPtr->postscript_; + if (objc <= 4) { + Tcl_Obj* objPtr = Tk_GetOptionInfo(interp, (char*)setupPtr->ops_, + setupPtr->optionTable_, + (objc == 4) ? objv[3] : NULL, + graphPtr->tkwin_); + if (objPtr == NULL) + return TCL_ERROR; + else + Tcl_SetObjResult(interp, objPtr); + return TCL_OK; + } + else + return PostscriptObjConfigure(graphPtr, interp, objc-3, objv+3); +} + +static int OutputOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + + const char *fileName = NULL; + Tcl_Channel channel = NULL; + if (objc > 3) { + fileName = Tcl_GetString(objv[3]); + if (fileName[0] != '-') { + // First argument is the file name + objv++, objc--; + + channel = Tcl_OpenFileChannel(interp, fileName, "w", 0666); + if (!channel) + return TCL_ERROR; + + if (Tcl_SetChannelOption(interp, channel, "-translation", "binary") + != TCL_OK) + return TCL_ERROR; + } + } + + PSOutput* psPtr = new PSOutput(graphPtr); + + if (PostscriptObjConfigure(graphPtr, interp, objc-3, objv+3) != TCL_OK) { + if (channel) + Tcl_Close(interp, channel); + delete psPtr; + return TCL_ERROR; + } + + if (graphPtr->print(fileName, psPtr) != TCL_OK) { + if (channel) + Tcl_Close(interp, channel); + delete psPtr; + return TCL_ERROR; + } + + int length; + const char* buffer = psPtr->getValue(&length); + if (channel) { + int nBytes = Tcl_Write(channel, buffer, length); + if (nBytes < 0) { + Tcl_AppendResult(interp, "error writing file \"", fileName, "\": ", + Tcl_PosixError(interp), (char *)NULL); + if (channel) + Tcl_Close(interp, channel); + delete psPtr; + return TCL_ERROR; + } + Tcl_Close(interp, channel); + } + else + Tcl_SetStringObj(Tcl_GetObjResult(interp), buffer, length); + + delete psPtr; + + return TCL_OK; +} + +const Ensemble Blt::postscriptEnsemble[] = { + {"cget", CgetOp, 0}, + {"configure", ConfigureOp, 0}, + {"output", OutputOp, 0}, + { 0,0,0 } +}; diff --git a/generic/tkbltGrPostscriptOp.h b/generic/tkbltGrPostscriptOp.h new file mode 100644 index 0000000..9a81266 --- /dev/null +++ b/generic/tkbltGrPostscriptOp.h @@ -0,0 +1,41 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1991-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGrPostscriptOp_h__ +#define __BltGrPostscriptOp_h__ + +#include "tkbltGraph.h" + +namespace Blt { + extern const Ensemble postscriptEnsemble[]; + extern int PostscriptObjConfigure(Blt::Graph* graphPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]); +}; + +#endif diff --git a/generic/tkbltGrText.C b/generic/tkbltGrText.C new file mode 100644 index 0000000..0b4e3e3 --- /dev/null +++ b/generic/tkbltGrText.C @@ -0,0 +1,233 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include +#include + +#include "tkbltGrText.h" +#include "tkbltGraph.h" +#include "tkbltGrPSOutput.h" + +using namespace Blt; + +TextStyle::TextStyle(Graph* graphPtr) +{ + ops_ = (TextStyleOptions*)calloc(1, sizeof(TextStyleOptions)); + TextStyleOptions* ops = (TextStyleOptions*)ops_; + graphPtr_ = graphPtr; + manageOptions_ = 1; + + ops->anchor =TK_ANCHOR_NW; + ops->color =NULL; + ops->font =NULL; + ops->angle =0; + ops->justify =TK_JUSTIFY_LEFT; + + xPad_ = 0; + yPad_ = 0; + gc_ = NULL; +} + +TextStyle::TextStyle(Graph* graphPtr, TextStyleOptions* ops) +{ + ops_ = (TextStyleOptions*)ops; + graphPtr_ = graphPtr; + manageOptions_ = 0; + + xPad_ = 0; + yPad_ = 0; + gc_ = NULL; +} + +TextStyle::~TextStyle() +{ + // TextStyleOptions* ops = (TextStyleOptions*)ops_; + + if (gc_) + Tk_FreeGC(graphPtr_->display_, gc_); + + if (manageOptions_) + free(ops_); +} + +void TextStyle::drawText(Drawable drawable, const char *text, double x, double y) { + drawText(drawable, text, (int)x, (int)y); +} + +void TextStyle::drawText(Drawable drawable, const char *text, int x, int y) +{ + drawTextBBox(drawable, text, x, y, NULL, NULL); +} + +void TextStyle::drawTextBBox(Drawable drawable, const char *text, + int x, int y, int* ww, int* hh) +{ + TextStyleOptions* ops = (TextStyleOptions*)ops_; + + if (!text || !(*text)) + return; + + if (!gc_) + resetStyle(); + + int w1, h1; + Tk_TextLayout layout = Tk_ComputeTextLayout(ops->font, text, -1, -1, + ops->justify, 0, &w1, &h1); + Point2d rr = rotateText(x, y, w1, h1); +#if (TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 6) + TkDrawAngledTextLayout(graphPtr_->display_, drawable, gc_, layout, + (int)rr.x, (int)rr.y, ops->angle, 0, -1); +#else + Tk_DrawTextLayout(graphPtr_->display_, drawable, gc_, layout, + (int)rr.x, (int)rr.y, 0, -1); +#endif + Tk_FreeTextLayout(layout); + + if (ww && hh) { + double angle = fmod(ops->angle, 360.0); + if (angle < 0.0) + angle += 360.0; + + if (angle != 0.0) { + double rotWidth, rotHeight; + graphPtr_->getBoundingBox(w1, h1, angle, &rotWidth, &rotHeight, NULL); + w1 = (int)rotWidth; + h1 = (int)rotHeight; + } + + *ww = w1; + *hh = h1; + } +} + +void TextStyle::printText(PSOutput* psPtr, const char *text, int x, int y) +{ + TextStyleOptions* ops = (TextStyleOptions*)ops_; + + if (!text || !(*text)) + return; + + int w1, h1; + Tk_TextLayout layout = Tk_ComputeTextLayout(ops->font, text, -1, -1, + ops->justify, 0, &w1, &h1); + + int xx =0; + int yy =0; + switch (ops->anchor) { + case TK_ANCHOR_NW: xx = 0; yy = 0; break; + case TK_ANCHOR_N: xx = 1; yy = 0; break; + case TK_ANCHOR_NE: xx = 2; yy = 0; break; + case TK_ANCHOR_E: xx = 2; yy = 1; break; + case TK_ANCHOR_SE: xx = 2; yy = 2; break; + case TK_ANCHOR_S: xx = 1; yy = 2; break; + case TK_ANCHOR_SW: xx = 0; yy = 2; break; + case TK_ANCHOR_W: xx = 0; yy = 1; break; + case TK_ANCHOR_CENTER: xx = 1; yy = 1; break; + } + + const char* justify =NULL; + switch (ops->justify) { + case TK_JUSTIFY_LEFT: justify = "0"; break; + case TK_JUSTIFY_CENTER: justify = "0.5"; break; + case TK_JUSTIFY_RIGHT: justify = "1"; break; + } + + psPtr->setFont(ops->font); + psPtr->setForeground(ops->color); + + psPtr->format("%g %d %d [\n", ops->angle, x, y); + Tcl_ResetResult(graphPtr_->interp_); + Tk_TextLayoutToPostscript(graphPtr_->interp_, layout); + psPtr->append(Tcl_GetStringResult(graphPtr_->interp_)); + Tcl_ResetResult(graphPtr_->interp_); + psPtr->format("] %g %g %s DrawText\n", xx/-2.0, yy/-2.0, justify); +} + +void TextStyle::printText(PSOutput* psPtr, const char *text, double x, double y) { + return printText(psPtr, text, (int)x, (int)y); +} + +void TextStyle::resetStyle() +{ + TextStyleOptions* ops = (TextStyleOptions*)ops_; + + unsigned long gcMask; + gcMask = GCFont; + + XGCValues gcValues; + gcValues.font = Tk_FontId(ops->font); + if (ops->color) { + gcMask |= GCForeground; + gcValues.foreground = ops->color->pixel; + } + GC newGC = Tk_GetGC(graphPtr_->tkwin_, gcMask, &gcValues); + if (gc_) + Tk_FreeGC(graphPtr_->display_, gc_); + + gc_ = newGC; +} + +Point2d TextStyle::rotateText(int x, int y, int w1, int h1) +{ + TextStyleOptions* ops = (TextStyleOptions*)ops_; + + // Matrix t0 = Translate(-x,-y); + // Matrix t1 = Translate(-w1/2,-h1/2); + // Matrix rr = Rotate(angle); + // Matrix t2 = Translate(w2/2,h2/2); + // Matrix t3 = Translate(x,y); + + double angle = ops->angle; + double ccos = cos(M_PI*angle/180.); + double ssin = sin(M_PI*angle/180.); + double w2, h2; + graphPtr_->getBoundingBox(w1, h1, angle, &w2, &h2, NULL); + + double x1 = x+w1/2.; + double y1 = y+h1/2.; + double x2 = w2/2.+x; + double y2 = h2/2.+y; + + double rx = x*ccos + y*ssin + (-x1*ccos -y1*ssin +x2); + double ry = -x*ssin + y*ccos + ( x1*ssin -y1*ccos +y2); + + return graphPtr_->anchorPoint(rx, ry, w2, h2, ops->anchor); +} + +void TextStyle::getExtents(const char *text, int* ww, int* hh) +{ + TextStyleOptions* ops = (TextStyleOptions*)ops_; + + int w, h; + graphPtr_->getTextExtents(ops->font, text, -1, &w, &h); + *ww = w + 2*xPad_; + *hh = h + 2*yPad_; +} diff --git a/generic/tkbltGrText.h b/generic/tkbltGrText.h new file mode 100644 index 0000000..4593b33 --- /dev/null +++ b/generic/tkbltGrText.h @@ -0,0 +1,79 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltText_h__ +#define __BltText_h__ + +#include + +#include "tkbltGrMisc.h" + +namespace Blt { + class Graph; + class PSOutput; + + typedef struct { + Tk_Anchor anchor; + XColor* color; + Tk_Font font; + double angle; + Tk_Justify justify; + } TextStyleOptions; + + class TextStyle { + protected: + Graph* graphPtr_; + void* ops_; + GC gc_; + int manageOptions_; + + public: + int xPad_; + int yPad_; + + protected: + void resetStyle(); + Point2d rotateText(int, int, int, int); + + public: + TextStyle(Graph*); + TextStyle(Graph*, TextStyleOptions*); + virtual ~TextStyle(); + + void* ops() {return ops_;} + void drawText(Drawable, const char*, int, int); + void drawText(Drawable, const char*, double, double); + void drawTextBBox(Drawable, const char*, int, int, int*, int*); + void printText(PSOutput*, const char*, int, int); + void printText(PSOutput*, const char*, double, double); + void getExtents(const char*, int*, int*); + }; +}; + +#endif diff --git a/generic/tkbltGrXAxisOp.C b/generic/tkbltGrXAxisOp.C new file mode 100644 index 0000000..ac788ff --- /dev/null +++ b/generic/tkbltGrXAxisOp.C @@ -0,0 +1,222 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "tkbltGraph.h" +#include "tkbltGrBind.h" +#include "tkbltGrXAxisOp.h" +#include "tkbltGrAxis.h" +#include "tkbltGrAxisOp.h" + +using namespace Blt; + +static Axis* GetAxisFromCmd(ClientData clientData, Tcl_Obj* obj) +{ + Graph* graphPtr = (Graph*)clientData; + GraphOptions* ops = (GraphOptions*)graphPtr->ops_; + + int margin; + const char* name = Tcl_GetString(obj); + if (!strcmp(name,"xaxis")) + margin = (ops->inverted) ? MARGIN_LEFT : MARGIN_BOTTOM; + else if (!strcmp(name,"yaxis")) + margin = (ops->inverted) ? MARGIN_BOTTOM : MARGIN_LEFT; + else if (!strcmp(name,"x2axis")) + margin = (ops->inverted) ? MARGIN_RIGHT : MARGIN_TOP; + else if (!strcmp(name,"y2axis")) + margin = (ops->inverted) ? MARGIN_TOP : MARGIN_RIGHT; + else + return NULL; + + ChainLink* link = Chain_FirstLink(ops->margins[margin].axes); + return (Axis*)Chain_GetValue(link); +} + +static int CgetOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Axis* axisPtr = GetAxisFromCmd(clientData, objv[1]); + return AxisCgetOp(axisPtr, interp, objc, objv); +} + +static int ConfigureOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Axis* axisPtr = GetAxisFromCmd(clientData, objv[1]); + return AxisConfigureOp(axisPtr, interp, objc, objv); +} + +static int ActivateOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Axis* axisPtr = GetAxisFromCmd(clientData, objv[1]); + return AxisActivateOp(axisPtr, interp, objc, objv); +} + +static int BindOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + Axis* axisPtr = GetAxisFromCmd(clientData, objv[1]); + return graphPtr->bindTable_->configure(graphPtr->axisTag(axisPtr->name_), objc-3, objv+3); +} + +static int InvTransformOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Axis* axisPtr = GetAxisFromCmd(clientData, objv[1]); + return AxisInvTransformOp(axisPtr, interp, objc, objv); +} + +static int LimitsOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Axis* axisPtr = GetAxisFromCmd(clientData, objv[1]); + return AxisLimitsOp(axisPtr, interp, objc, objv); +} + +static int TransformOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Axis* axisPtr = GetAxisFromCmd(clientData, objv[1]); + return AxisTransformOp(axisPtr, interp, objc, objv); +} + +static int UseOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + GraphOptions* ops = (GraphOptions*)graphPtr->ops_; + + int margin; + ClassId classId; + const char* name = Tcl_GetString(objv[1]); + if (!strcmp(name,"xaxis")) { + classId = CID_AXIS_X; + margin = (ops->inverted) ? MARGIN_LEFT : MARGIN_BOTTOM; + } + else if (!strcmp(name,"yaxis")) { + classId = CID_AXIS_Y; + margin = (ops->inverted) ? MARGIN_BOTTOM : MARGIN_LEFT; + } + else if (!strcmp(name,"x2axis")) { + classId = CID_AXIS_X; + margin = (ops->inverted) ? MARGIN_RIGHT : MARGIN_TOP; + } + else if (!strcmp(name,"y2axis")) { + classId = CID_AXIS_Y; + margin = (ops->inverted) ? MARGIN_TOP : MARGIN_RIGHT; + } + else + return TCL_ERROR; + + Chain* chain = ops->margins[margin].axes; + + if (objc == 3) { + Tcl_Obj* listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + for (ChainLink* link = Chain_FirstLink(chain); link; + link = Chain_NextLink(link)) { + Axis* axisPtr = (Axis*)Chain_GetValue(link); + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewStringObj(axisPtr->name_, -1)); + } + Tcl_SetObjResult(interp, listObjPtr); + return TCL_OK; + } + + int axisObjc; + Tcl_Obj **axisObjv; + if (Tcl_ListObjGetElements(interp, objv[3], &axisObjc, &axisObjv) != TCL_OK) + return TCL_ERROR; + + for (ChainLink* link = Chain_FirstLink(chain); link; + link = Chain_NextLink(link)) { + Axis* axisPtr = (Axis*)Chain_GetValue(link); + axisPtr->link = NULL; + axisPtr->use_ =0; + axisPtr->margin_ = MARGIN_NONE; + // Clear the axis type if it's not currently used + if (axisPtr->refCount_ == 0) + axisPtr->setClass(CID_NONE); + } + + chain->reset(); + for (int ii=0; iigetAxis(axisObjv[ii], &axisPtr) != TCL_OK) + return TCL_ERROR; + + if (axisPtr->classId_ == CID_NONE) + axisPtr->setClass(classId); + else if (axisPtr->classId_ != classId) { + Tcl_AppendResult(interp, "wrong type axis \"", + axisPtr->name_, "\": can't use ", + axisPtr->className_, " type axis.", NULL); + return TCL_ERROR; + } + if (axisPtr->link) { + // Move the axis from the old margin's "use" list to the new + axisPtr->chain->unlinkLink(axisPtr->link); + chain->linkAfter(axisPtr->link, NULL); + } + else + axisPtr->link = chain->append(axisPtr); + + axisPtr->chain = chain; + axisPtr->use_ =1; + axisPtr->margin_ = margin; + } + + graphPtr->flags |= RESET; + graphPtr->eventuallyRedraw(); + + return TCL_OK; +} + +static int ViewOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Axis* axisPtr = GetAxisFromCmd(clientData, objv[1]); + return AxisViewOp(axisPtr, interp, objc, objv); +} + +const Ensemble Blt::xaxisEnsemble[] = { + {"activate", ActivateOp, 0}, + {"bind", BindOp, 0}, + {"cget", CgetOp, 0}, + {"configure", ConfigureOp, 0}, + {"deactivate", ActivateOp, 0}, + {"invtransform", InvTransformOp, 0}, + {"limits", LimitsOp, 0}, + {"transform", TransformOp, 0}, + {"use", UseOp, 0}, + {"view", ViewOp, 0}, + { 0,0,0 } +}; diff --git a/generic/tkbltGrXAxisOp.h b/generic/tkbltGrXAxisOp.h new file mode 100644 index 0000000..b813c83 --- /dev/null +++ b/generic/tkbltGrXAxisOp.h @@ -0,0 +1,39 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGrXAxisOp_h__ +#define __BltGrXAxisOp_h__ + +#include "tkbltGraph.h" + +namespace Blt { + extern const Ensemble xaxisEnsemble[]; +}; + +#endif diff --git a/generic/tkbltGraph.C b/generic/tkbltGraph.C new file mode 100644 index 0000000..f1453dc --- /dev/null +++ b/generic/tkbltGraph.C @@ -0,0 +1,1458 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1991-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#include + +#include "tkbltGraph.h" +#include "tkbltGraphOp.h" + +#include "tkbltGrBind.h" +#include "tkbltGrAxis.h" +#include "tkbltGrAxisOp.h" +#include "tkbltGrXAxisOp.h" +#include "tkbltGrPen.h" +#include "tkbltGrPenBar.h" +#include "tkbltGrPenLine.h" +#include "tkbltGrElem.h" +#include "tkbltGrElemBar.h" +#include "tkbltGrElemLine.h" +#include "tkbltGrMarker.h" +#include "tkbltGrLegd.h" +#include "tkbltGrHairs.h" +#include "tkbltGrDef.h" +#include "tkbltGrPostscript.h" +#include "tkbltGrPSOutput.h" +#include "tkbltInt.h" + +using namespace Blt; + +#define MARKER_ABOVE 0 +#define MARKER_UNDER 1 + +// OptionSpecs + +Graph::Graph(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + valid_ =1; + interp_ = interp; + tkwin_ = Tk_CreateWindowFromPath(interp_, Tk_MainWindow(interp_), + Tcl_GetString(objv[1]), NULL); + if (!tkwin_) { + valid_ =0; + return; + } + display_ = Tk_Display(tkwin_); + ((TkWindow*)tkwin_)->instanceData = this; + + cmdToken_ = Tcl_CreateObjCommand(interp_, Tk_PathName(tkwin_), + GraphInstCmdProc, this, + GraphInstCmdDeleteProc); + + flags = RESET; + nextMarkerId_ = 1; + + inset_ =0; + titleX_ =0; + titleY_ =0; + titleWidth_ =0; + titleHeight_ =0; + width_ =0; + height_ =0; + left_ =0; + right_ =0; + top_ =0; + bottom_ =0; + focusPtr_ =NULL; + halo_ =0; + drawGC_ =NULL; + vRange_ =0; + hRange_ =0; + vOffset_ =0; + hOffset_ =0; + vScale_ =0; + hScale_ =0; + cache_ =None; + cacheWidth_ =0; + cacheHeight_ =0; + + Tcl_InitHashTable(&axes_.table, TCL_STRING_KEYS); + Tcl_InitHashTable(&axes_.tagTable, TCL_STRING_KEYS); + Tcl_InitHashTable(&elements_.table, TCL_STRING_KEYS); + Tcl_InitHashTable(&elements_.tagTable, TCL_STRING_KEYS); + Tcl_InitHashTable(&markers_.table, TCL_STRING_KEYS); + Tcl_InitHashTable(&markers_.tagTable, TCL_STRING_KEYS); + Tcl_InitHashTable(&penTable_, TCL_STRING_KEYS); + + axes_.displayList = new Chain(); + elements_.displayList = new Chain(); + markers_.displayList = new Chain(); + bindTable_ = new BindTable(this, this); + + // Keep a hold of the associated tkwin until we destroy the graph, + // otherwise Tk might free it while we still need it. + Tcl_Preserve(tkwin_); + + Tk_CreateEventHandler(tkwin_, + ExposureMask|StructureNotifyMask|FocusChangeMask, + GraphEventProc, this); +} + +Graph::~Graph() +{ + // GraphOptions* ops = (GraphOptions*)ops_; + + destroyMarkers(); + destroyElements(); // must come before legend and others + + delete crosshairs_; + delete legend_; + delete postscript_; + + destroyAxes(); + destroyPens(); + + delete bindTable_; + + if (drawGC_) + Tk_FreeGC(display_, drawGC_); + + if (cache_ != None) + Tk_FreePixmap(display_, cache_); + + Tk_FreeConfigOptions((char*)ops_, optionTable_, tkwin_); + Tcl_Release(tkwin_); + tkwin_ = NULL; + + free (ops_); +} + +int Graph::configure() +{ + GraphOptions* ops = (GraphOptions*)ops_; + + inset_ = ops->borderWidth + ops->highlightWidth; + if ((ops->reqHeight != Tk_ReqHeight(tkwin_)) || + (ops->reqWidth != Tk_ReqWidth(tkwin_))) + Tk_GeometryRequest(tkwin_, ops->reqWidth, ops->reqHeight); + + Tk_SetInternalBorder(tkwin_, ops->borderWidth); + XColor* colorPtr = Tk_3DBorderColor(ops->normalBg); + + titleWidth_ =0; + titleHeight_ =0; + if (ops->title != NULL) { + int w, h; + TextStyle ts(this, &ops->titleTextStyle); + ts.getExtents(ops->title, &w, &h); + titleHeight_ = h; + } + + // Create GCs for interior and exterior regions, and a background GC for + // clearing the margins with XFillRectangle + // Margin + XGCValues gcValues; + gcValues.foreground = ops->titleTextStyle.color->pixel; + gcValues.background = colorPtr->pixel; + unsigned long gcMask = (GCForeground | GCBackground); + GC newGC = Tk_GetGC(tkwin_, gcMask, &gcValues); + if (drawGC_ != NULL) + Tk_FreeGC(display_, drawGC_); + drawGC_ = newGC; + + // If the -inverted option changed, we need to readjust the pointers + // to the axes and recompute the their scales. + adjustAxes(); + + // Free the pixmap if we're not buffering the display of elements anymore. + if (cache_ != None) { + Tk_FreePixmap(display_, cache_); + cache_ = None; + } + + return TCL_OK; +} + +void Graph::map() +{ + if (flags & RESET) { + resetAxes(); + flags &= ~RESET; + flags |= LAYOUT; + } + + if (flags & LAYOUT) { + layoutGraph(); + crosshairs_->map(); + mapAxes(); + mapElements(); + flags &= ~LAYOUT; + flags |= MAP_MARKERS | CACHE; + } + + mapMarkers(); +} + +void Graph::draw() +{ + GraphOptions* ops = (GraphOptions*)ops_; + + flags &= ~REDRAW_PENDING; + if ((flags & GRAPH_DELETED) || !Tk_IsMapped(tkwin_)) + return; + + // Don't bother computing the layout until the size of the window is + // something reasonable. + if ((Tk_Width(tkwin_) <= 1) || (Tk_Height(tkwin_) <= 1)) + return; + + width_ = Tk_Width(tkwin_); + height_ = Tk_Height(tkwin_); + + map(); + + // Create a pixmap the size of the window for double buffering + Pixmap drawable = Tk_GetPixmap(display_, Tk_WindowId(tkwin_), + width_, height_, Tk_Depth(tkwin_)); + + if (cache_ == None || cacheWidth_ != width_ || cacheHeight_ != height_) { + if (cache_ != None) + Tk_FreePixmap(display_, cache_); + cache_ = Tk_GetPixmap(display_, Tk_WindowId(tkwin_), width_, height_, + Tk_Depth(tkwin_)); + cacheWidth_ = width_; + cacheHeight_ = height_; + flags |= CACHE; + } + + // Update cache if needed + if (flags & CACHE) { + drawMargins(cache_); + + switch (legend_->position()) { + case Legend::TOP: + case Legend::BOTTOM: + case Legend::RIGHT: + case Legend::LEFT: + legend_->draw(cache_); + break; + default: + break; + } + + // Draw the background of the plotting area with 3D border + Tk_Fill3DRectangle(tkwin_, cache_, ops->plotBg, + left_-ops->plotBW, + top_-ops->plotBW, + right_-left_+1+2*ops->plotBW, + bottom_-top_+1+2*ops->plotBW, + ops->plotBW, ops->plotRelief); + + drawAxesGrids(cache_); + drawAxes(cache_); + drawAxesLimits(cache_); + + if (!legend_->isRaised()) { + switch (legend_->position()) { + case Legend::PLOT: + case Legend::XY: + legend_->draw(cache_); + break; + default: + break; + } + } + + drawMarkers(cache_, MARKER_UNDER); + drawElements(cache_); + drawActiveElements(cache_); + + if (legend_->isRaised()) { + switch (legend_->position()) { + case Legend::PLOT: + case Legend::XY: + legend_->draw(cache_); + break; + default: + break; + } + } + + flags &= ~CACHE; + } + + XCopyArea(display_, cache_, drawable, drawGC_, 0, 0, Tk_Width(tkwin_), + Tk_Height(tkwin_), 0, 0); + + drawMarkers(drawable, MARKER_ABOVE); + + // Draw 3D border just inside of the focus highlight ring + if ((ops->borderWidth > 0) && (ops->relief != TK_RELIEF_FLAT)) + Tk_Draw3DRectangle(tkwin_, drawable, ops->normalBg, + ops->highlightWidth, ops->highlightWidth, + width_ - 2*ops->highlightWidth, + height_ - 2*ops->highlightWidth, + ops->borderWidth, ops->relief); + + // Draw focus highlight ring + if ((ops->highlightWidth > 0) && (flags & FOCUS)) { + GC gc = Tk_GCForColor(ops->highlightColor, drawable); + Tk_DrawFocusHighlight(tkwin_, gc, ops->highlightWidth, drawable); + } + + // crosshairs + crosshairs_->draw(drawable); + + XCopyArea(display_, drawable, Tk_WindowId(tkwin_), drawGC_, + 0, 0, width_, height_, 0, 0); + + Tk_FreePixmap(display_, drawable); +} + +int Graph::print(const char* ident, PSOutput* psPtr) +{ + GraphOptions* ops = (GraphOptions*)ops_; + PostscriptOptions* pops = (PostscriptOptions*)postscript_->ops_; + + // be sure the window is realized so that relief colors are available + if (flags & REDRAW_PENDING) { + flags |= REDRAW_PENDING; + DisplayGraph(this); + } + + // We need to know how big a graph to print. If the graph hasn't been drawn + // yet, the width and height will be 1. Instead use the requested size of + // the widget. The user can still override this with the -width and -height + // postscript options. + if (pops->reqWidth > 0) + width_ = pops->reqWidth; + else if (width_ < 2) + width_ = Tk_ReqWidth(tkwin_); + + if (pops->reqHeight > 0) + height_ = pops->reqHeight; + else if (height_ < 2) + height_ = Tk_ReqHeight(tkwin_); + + psPtr->computeBBox(width_, height_); + flags |= RESET; + + // Turn on PostScript measurements when computing the graph's layout. + reconfigure(); + + map(); + + int x = left_ - ops->plotBW; + int y = top_ - ops->plotBW; + + int w = (right_ - left_ + 1) + (2*ops->plotBW); + int h = (bottom_ - top_ + 1) + (2*ops->plotBW); + + int result = psPtr->preamble(ident); + if (result != TCL_OK) + goto error; + + psPtr->setFont(ops->titleTextStyle.font); + if (pops->decorations) + psPtr->setBackground(Tk_3DBorderColor(ops->plotBg)); + else + psPtr->setClearBackground(); + + psPtr->fillRectangle(x, y, w, h); + psPtr->append("gsave\n\n"); + + // Start + printMargins(psPtr); + + switch (legend_->position()) { + case Legend::TOP: + case Legend::BOTTOM: + case Legend::RIGHT: + case Legend::LEFT: + legend_->print(psPtr); + break; + default: + break; + } + + printAxesGrids(psPtr); + printAxes(psPtr); + printAxesLimits(psPtr); + + if (!legend_->isRaised()) { + switch (legend_->position()) { + case Legend::PLOT: + case Legend::XY: + legend_->print(psPtr); + break; + default: + break; + } + } + + printMarkers(psPtr, MARKER_UNDER); + printElements(psPtr); + printActiveElements(psPtr); + + if (legend_->isRaised()) { + switch (legend_->position()) { + case Legend::PLOT: + case Legend::XY: + legend_->print(psPtr); + break; + default: + break; + } + } + printMarkers(psPtr, MARKER_ABOVE); + + psPtr->append("\n"); + psPtr->append("% Unset clipping\n"); + psPtr->append("grestore\n\n"); + psPtr->append("showpage\n"); + psPtr->append("%Trailer\n"); + psPtr->append("grestore\n"); + psPtr->append("end\n"); + psPtr->append("%EOF\n"); + + error: + width_ = Tk_Width(tkwin_); + height_ = Tk_Height(tkwin_); + reconfigure(); + + // Redraw the graph in order to re-calculate the layout as soon as + // possible. This is in the case the crosshairs are active. + flags |= LAYOUT; + eventuallyRedraw(); + + return result; +} + +void Graph::eventuallyRedraw() +{ + if (flags & GRAPH_DELETED) + return; + + if (!(flags & REDRAW_PENDING)) { + flags |= REDRAW_PENDING; + Tcl_DoWhenIdle(DisplayGraph, this); + } +} + +void Graph::extents(Region2d* regionPtr) +{ + GraphOptions* ops = (GraphOptions*)ops_; + + regionPtr->left = (double)(hOffset_ - ops->xPad); + regionPtr->top = (double)(vOffset_ - ops->yPad); + regionPtr->right = (double)(hOffset_ + hRange_ + ops->xPad); + regionPtr->bottom = (double)(vOffset_ + vRange_ + ops->yPad); +} + +int Graph::invoke(const Ensemble* ensemble, int cmdIndex, + int objc, Tcl_Obj* const objv[]) +{ + while (cmdIndex < objc) { + int index; + if (Tcl_GetIndexFromObjStruct(interp_, objv[cmdIndex], ensemble, sizeof(ensemble[0]), "command", 0, &index) != TCL_OK) + return TCL_ERROR; + + if (ensemble[index].proc) + return ensemble[index].proc(this, interp_, objc, objv); + + ensemble = ensemble[index].subensemble; + ++cmdIndex; + } + + Tcl_WrongNumArgs(interp_, cmdIndex, objv, "option ?arg ...?"); + return TCL_ERROR; +} + +void Graph::reconfigure() +{ + configure(); + legend_->configure(); + configureElements(); + configureAxes(); + configureMarkers(); +} + +// Margins + +void Graph::drawMargins(Drawable drawable) +{ + GraphOptions* ops = (GraphOptions*)ops_; + Rectangle rects[4]; + + // Draw the four outer rectangles which encompass the plotting + // surface. This clears the surrounding area and clips the plot. + rects[0].x = rects[0].y = rects[3].x = rects[1].x = 0; + rects[0].width = rects[3].width = width_; + rects[0].height = top_; + rects[3].y = bottom_; + rects[3].height = height_ - bottom_; + rects[2].y = rects[1].y = top_; + rects[1].width = left_; + rects[2].height = rects[1].height = bottom_ - top_; + rects[2].x = right_; + rects[2].width = width_ - right_; + + Tk_Fill3DRectangle(tkwin_, drawable, ops->normalBg, + rects[0].x, rects[0].y, rects[0].width, rects[0].height, + 0, TK_RELIEF_FLAT); + Tk_Fill3DRectangle(tkwin_, drawable, ops->normalBg, + rects[1].x, rects[1].y, rects[1].width, rects[1].height, + 0, TK_RELIEF_FLAT); + Tk_Fill3DRectangle(tkwin_, drawable, ops->normalBg, + rects[2].x, rects[2].y, rects[2].width, rects[2].height, + 0, TK_RELIEF_FLAT); + Tk_Fill3DRectangle(tkwin_, drawable, ops->normalBg, + rects[3].x, rects[3].y, rects[3].width, rects[3].height, + 0, TK_RELIEF_FLAT); + + // Draw 3D border around the plotting area + if (ops->plotBW > 0) { + int x = left_ - ops->plotBW; + int y = top_ - ops->plotBW; + int w = (right_ - left_) + (2*ops->plotBW); + int h = (bottom_ - top_) + (2*ops->plotBW); + Tk_Draw3DRectangle(tkwin_, drawable, ops->normalBg, + x, y, w, h, ops->plotBW, ops->plotRelief); + } + + if (ops->title) { + TextStyle ts(this, &ops->titleTextStyle); + ts.drawText(drawable, ops->title, titleX_, titleY_); + } +} + +void Graph::printMargins(PSOutput* psPtr) +{ + GraphOptions* ops = (GraphOptions*)ops_; + PostscriptOptions* pops = (PostscriptOptions*)postscript_->ops_; + Rectangle margin[4]; + + margin[0].x = margin[0].y = margin[3].x = margin[1].x = 0; + margin[0].width = margin[3].width = width_; + margin[0].height = top_; + margin[3].y = bottom_; + margin[3].height = height_ - bottom_; + margin[2].y = margin[1].y = top_; + margin[1].width = left_; + margin[2].height = margin[1].height = bottom_ - top_; + margin[2].x = right_; + margin[2].width = width_ - right_; + + // Clear the surrounding margins and clip the plotting surface + if (pops->decorations) + psPtr->setBackground(Tk_3DBorderColor(ops->normalBg)); + else + psPtr->setClearBackground(); + + psPtr->append("% Margins\n"); + psPtr->fillRectangles(margin, 4); + + if (pops->decorations) { + psPtr->append("% Interior 3D border\n"); + if (ops->plotBW > 0) { + int x = left_ - ops->plotBW; + int y = top_ - ops->plotBW; + int w = (right_ - left_) + (2*ops->plotBW); + int h = (bottom_ - top_) + (2*ops->plotBW); + psPtr->print3DRectangle(ops->normalBg, (double)x, (double)y, w, h, + ops->plotBW, ops->plotRelief); + } + } + + if (ops->title) { + psPtr->append("% Graph title\n"); + TextStyle ts(this, &ops->titleTextStyle); + ts.printText(psPtr, ops->title, titleX_, titleY_); + } +} + +// Pens + +void Graph::destroyPens() +{ + Tcl_HashSearch iter; + for (Tcl_HashEntry *hPtr = Tcl_FirstHashEntry(&penTable_, &iter); + hPtr; hPtr = Tcl_NextHashEntry(&iter)) { + Pen* penPtr = (Pen*)Tcl_GetHashValue(hPtr); + delete penPtr; + } + Tcl_DeleteHashTable(&penTable_); +} + +int Graph::getPen(Tcl_Obj* objPtr, Pen** penPtrPtr) +{ + *penPtrPtr = NULL; + const char *name = Tcl_GetString(objPtr); + if (!name || !name[0]) + return TCL_ERROR; + + Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&penTable_, name); + if (!hPtr) { + Tcl_AppendResult(interp_, "can't find pen \"", name, "\" in \"", + Tk_PathName(tkwin_), "\"", NULL); + return TCL_ERROR; + } + + *penPtrPtr = (Pen*)Tcl_GetHashValue(hPtr); + + return TCL_OK; +} + +// Elements + +void Graph::destroyElements() +{ + Tcl_HashSearch iter; + for (Tcl_HashEntry* hPtr=Tcl_FirstHashEntry(&elements_.table, &iter); + hPtr; hPtr = Tcl_NextHashEntry(&iter)) { + Element* elemPtr = (Element*)Tcl_GetHashValue(hPtr); + legend_->removeElement(elemPtr); + delete elemPtr; + } + + Tcl_DeleteHashTable(&elements_.table); + Tcl_DeleteHashTable(&elements_.tagTable); + delete elements_.displayList; +} + +void Graph::configureElements() +{ + for (ChainLink* link = Chain_FirstLink(elements_.displayList); link; + link = Chain_NextLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + elemPtr->configure(); + } +} + +void Graph::mapElements() +{ + for (ChainLink* link = Chain_FirstLink(elements_.displayList); link; + link = Chain_NextLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + elemPtr->map(); + } +} + +void Graph::drawElements(Drawable drawable) +{ + // Draw with respect to the stacking order + for (ChainLink* link=Chain_LastLink(elements_.displayList); link; + link = Chain_PrevLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + elemPtr->draw(drawable); + } +} + +void Graph::drawActiveElements(Drawable drawable) +{ + for (ChainLink* link = Chain_LastLink(elements_.displayList); link; + link = Chain_PrevLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + elemPtr->drawActive(drawable); + } +} + +void Graph::printElements(PSOutput* psPtr) +{ + for (ChainLink* link = Chain_LastLink(elements_.displayList); link; + link = Chain_PrevLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + elemPtr->print(psPtr); + } +} + +void Graph::printActiveElements(PSOutput* psPtr) +{ + for (ChainLink* link = Chain_LastLink(elements_.displayList); link; + link = Chain_PrevLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + elemPtr->printActive(psPtr); + } +} + +int Graph::getElement(Tcl_Obj *objPtr, Element **elemPtrPtr) +{ + *elemPtrPtr =NULL; + const char* name = Tcl_GetString(objPtr); + if (!name || !name[0]) + return TCL_ERROR; + + Tcl_HashEntry*hPtr = Tcl_FindHashEntry(&elements_.table, name); + if (!hPtr) { + Tcl_AppendResult(interp_, "can't find element \"", name, "\" in \"", + Tk_PathName(tkwin_), "\"", NULL); + return TCL_ERROR; + } + + *elemPtrPtr = (Element*)Tcl_GetHashValue(hPtr); + return TCL_OK; +} + +ClientData Graph::elementTag(const char *tagName) +{ + int isNew; + Tcl_HashEntry* hPtr = + Tcl_CreateHashEntry(&elements_.tagTable, tagName, &isNew); + return Tcl_GetHashKey(&elements_.tagTable, hPtr); +} + +// Markers + +void Graph::destroyMarkers() +{ + Tcl_HashSearch iter; + for (Tcl_HashEntry* hPtr=Tcl_FirstHashEntry(&markers_.table, &iter); + hPtr; hPtr=Tcl_NextHashEntry(&iter)) { + Marker* markerPtr = (Marker*)Tcl_GetHashValue(hPtr); + delete markerPtr; + } + Tcl_DeleteHashTable(&markers_.table); + Tcl_DeleteHashTable(&markers_.tagTable); + delete markers_.displayList; +} + + +void Graph::configureMarkers() +{ + for (ChainLink* link = Chain_FirstLink(markers_.displayList); link; + link = Chain_NextLink(link)) { + Marker* markerPtr = (Marker*)Chain_GetValue(link); + markerPtr->configure(); + } +} + +void Graph::mapMarkers() +{ + for (ChainLink* link = Chain_FirstLink(markers_.displayList); link; + link = Chain_NextLink(link)) { + Marker* markerPtr = (Marker*)Chain_GetValue(link); + MarkerOptions* mops = (MarkerOptions*)markerPtr->ops(); + + if (mops->hide) + continue; + + if ((flags & MAP_MARKERS) || (markerPtr->flags & MAP_ITEM)) { + markerPtr->map(); + markerPtr->flags &= ~MAP_ITEM; + } + } + + flags &= ~MAP_MARKERS; +} + +void Graph::drawMarkers(Drawable drawable, int under) +{ + for (ChainLink* link = Chain_LastLink(markers_.displayList); link; + link = Chain_PrevLink(link)) { + Marker* markerPtr = (Marker*)Chain_GetValue(link); + MarkerOptions* mops = (MarkerOptions*)markerPtr->ops(); + + if ((mops->drawUnder != under) || markerPtr->clipped_ || mops->hide) + continue; + + if (isElementHidden(markerPtr)) + continue; + + markerPtr->draw(drawable); + } +} + +void Graph::printMarkers(PSOutput* psPtr, int under) +{ + for (ChainLink* link = Chain_LastLink(markers_.displayList); link; + link = Chain_PrevLink(link)) { + Marker* markerPtr = (Marker*)Chain_GetValue(link); + MarkerOptions* mops = (MarkerOptions*)markerPtr->ops(); + if (mops->drawUnder != under) + continue; + + if (mops->hide) + continue; + + if (isElementHidden(markerPtr)) + continue; + + psPtr->format("%% Marker \"%s\" is a %s.\n", + markerPtr->name_, markerPtr->className()); + markerPtr->print(psPtr); + } +} + +ClientData Graph::markerTag(const char* tagName) +{ + int isNew; + Tcl_HashEntry* hPtr = Tcl_CreateHashEntry(&markers_.tagTable, tagName,&isNew); + return Tcl_GetHashKey(&markers_.tagTable, hPtr); +} + +Marker* Graph::nearestMarker(int x, int y, int under) +{ + Point2d point; + point.x = (double)x; + point.y = (double)y; + for (ChainLink* link = Chain_FirstLink(markers_.displayList); link; + link = Chain_NextLink(link)) { + Marker* markerPtr = (Marker*)Chain_GetValue(link); + MarkerOptions* mops = (MarkerOptions*)markerPtr->ops(); + + if ((markerPtr->flags & MAP_ITEM) || mops->hide) + continue; + + if (isElementHidden(markerPtr)) + continue; + + if (mops->drawUnder == under) + if (markerPtr->pointIn(&point)) + return markerPtr; + } + return NULL; +} + +int Graph::isElementHidden(Marker* markerPtr) +{ + MarkerOptions* mops = (MarkerOptions*)markerPtr->ops(); + + if (mops->elemName) { + Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&elements_.table, mops->elemName); + if (hPtr) { + Element* elemPtr = (Element*)Tcl_GetHashValue(hPtr); + ElementOptions* eops = (ElementOptions*)elemPtr->ops(); + if (!elemPtr->link || eops->hide) + return 1; + } + } + return 0; +} + +// Axis + +int Graph::createAxes() +{ + for (int ii=0; ii<4; ii++) { + int isNew; + Tcl_HashEntry* hPtr = + Tcl_CreateHashEntry(&axes_.table, axisNames[ii].name, &isNew); + Chain* chain = new Chain(); + + Axis* axisPtr = new Axis(this, axisNames[ii].name, ii, hPtr); + if (!axisPtr) + return TCL_ERROR; + AxisOptions* ops = (AxisOptions*)axisPtr->ops(); + + Tcl_SetHashValue(hPtr, axisPtr); + + axisPtr->refCount_ = 1; + axisPtr->use_ =1; + + axisPtr->setClass(!(ii&1) ? CID_AXIS_X : CID_AXIS_Y); + + if (Tk_InitOptions(interp_, (char*)axisPtr->ops(), + axisPtr->optionTable(), tkwin_) != TCL_OK) + return TCL_ERROR; + + if (axisPtr->configure() != TCL_OK) + return TCL_ERROR; + + if ((axisPtr->margin_ == MARGIN_RIGHT) || (axisPtr->margin_ == MARGIN_TOP)) + ops->hide = 1; + + axisChain_[ii] = chain; + axisPtr->link = chain->append(axisPtr); + axisPtr->chain = chain; + } + return TCL_OK; +} + +int Graph::createAxis(int objc, Tcl_Obj* const objv[]) +{ + char *string = Tcl_GetString(objv[3]); + if (string[0] == '-') { + Tcl_AppendResult(interp_, "name of axis \"", string, + "\" can't start with a '-'", NULL); + return TCL_ERROR; + } + + int isNew; + Tcl_HashEntry* hPtr = Tcl_CreateHashEntry(&axes_.table, string, &isNew); + if (!isNew) { + Tcl_AppendResult(interp_, "axis \"", string, "\" already exists in \"", + Tcl_GetString(objv[0]), "\"", NULL); + return TCL_ERROR; + } + + Axis* axisPtr = new Axis(this, Tcl_GetString(objv[3]), MARGIN_NONE, hPtr); + if (!axisPtr) + return TCL_ERROR; + + Tcl_SetHashValue(hPtr, axisPtr); + + if ((Tk_InitOptions(interp_, (char*)axisPtr->ops(), axisPtr->optionTable(), tkwin_) != TCL_OK) || (AxisObjConfigure(axisPtr, interp_, objc-4, objv+4) != TCL_OK)) { + delete axisPtr; + return TCL_ERROR; + } + + return TCL_OK; +} + +void Graph::destroyAxes() +{ + Tcl_HashSearch cursor; + for (Tcl_HashEntry *hPtr=Tcl_FirstHashEntry(&axes_.table, &cursor); + hPtr; hPtr=Tcl_NextHashEntry(&cursor)) { + Axis *axisPtr = (Axis*)Tcl_GetHashValue(hPtr); + delete axisPtr; + } + Tcl_DeleteHashTable(&axes_.table); + + for (int ii=0; ii<4; ii++) + delete axisChain_[ii]; + + Tcl_DeleteHashTable(&axes_.tagTable); + delete axes_.displayList; +} + +void Graph::configureAxes() +{ + Tcl_HashSearch cursor; + for (Tcl_HashEntry *hPtr=Tcl_FirstHashEntry(&axes_.table, &cursor); + hPtr; hPtr = Tcl_NextHashEntry(&cursor)) { + Axis *axisPtr = (Axis*)Tcl_GetHashValue(hPtr); + axisPtr->configure(); + } +} + +void Graph::mapAxes() +{ + GraphOptions* ops = (GraphOptions*)ops_; + + for (int ii=0; ii<4; ii++) { + int count =0; + int offset =0; + + Chain* chain = ops->margins[ii].axes; + for (ChainLink* link=Chain_FirstLink(chain); link; + link = Chain_NextLink(link)) { + Axis *axisPtr = (Axis*)Chain_GetValue(link); + AxisOptions* aops = (AxisOptions*)axisPtr->ops(); + if (!axisPtr->use_) + continue; + + if (aops->reqNumMajorTicks <= 0) + aops->reqNumMajorTicks = 4; + + if (ops->stackAxes) + axisPtr->mapStacked(count, ii); + else + axisPtr->map(offset, ii); + + if (aops->showGrid) + axisPtr->mapGridlines(); + + offset += axisPtr->isHorizontal() ? axisPtr->height_ : axisPtr->width_; + count++; + } + } +} + +void Graph::drawAxes(Drawable drawable) +{ + GraphOptions* ops = (GraphOptions*)ops_; + + for (int ii=0; ii<4; ii++) { + for (ChainLink* link = Chain_LastLink(ops->margins[ii].axes); link; + link = Chain_PrevLink(link)) { + Axis *axisPtr = (Axis*)Chain_GetValue(link); + axisPtr->draw(drawable); + } + } +} + +void Graph::drawAxesLimits(Drawable drawable) +{ + Tcl_HashSearch cursor; + for (Tcl_HashEntry* hPtr=Tcl_FirstHashEntry(&axes_.table, &cursor); + hPtr; hPtr = Tcl_NextHashEntry(&cursor)) { + Axis *axisPtr = (Axis*)Tcl_GetHashValue(hPtr); + axisPtr->drawLimits(drawable); + } +} + +void Graph::drawAxesGrids(Drawable drawable) +{ + GraphOptions* ops = (GraphOptions*)ops_; + + for (int ii=0; ii<4; ii++) { + for (ChainLink* link = Chain_FirstLink(ops->margins[ii].axes); link; + link = Chain_NextLink(link)) { + Axis *axisPtr = (Axis*)Chain_GetValue(link); + axisPtr->drawGrids(drawable); + } + } +} + +void Graph::printAxes(PSOutput* psPtr) +{ + GraphOptions* ops = (GraphOptions*)ops_; + + for (Margin *mp = ops->margins, *mend = mp + 4; mp < mend; mp++) { + for (ChainLink* link = Chain_FirstLink(mp->axes); link; + link = Chain_NextLink(link)) { + Axis *axisPtr = (Axis*)Chain_GetValue(link); + axisPtr->print(psPtr); + } + } +} + +void Graph::printAxesGrids(PSOutput* psPtr) +{ + GraphOptions* ops = (GraphOptions*)ops_; + + for (int ii=0; ii<4; ii++) { + for (ChainLink* link = Chain_FirstLink(ops->margins[ii].axes); link; + link = Chain_NextLink(link)) { + Axis *axisPtr = (Axis*)Chain_GetValue(link); + axisPtr->printGrids(psPtr); + } + } +} + +void Graph::printAxesLimits(PSOutput* psPtr) +{ + Tcl_HashSearch cursor; + for (Tcl_HashEntry* hPtr=Tcl_FirstHashEntry(&axes_.table, &cursor); + hPtr; hPtr = Tcl_NextHashEntry(&cursor)) { + Axis *axisPtr = (Axis*)Tcl_GetHashValue(hPtr); + axisPtr->printLimits(psPtr); + } +} + +int Graph::getAxis(Tcl_Obj *objPtr, Axis **axisPtrPtr) +{ + *axisPtrPtr = NULL; + const char* name = Tcl_GetString(objPtr); + if (!name || !name[0]) + return TCL_ERROR; + + Tcl_HashEntry* hPtr = Tcl_FindHashEntry(&axes_.table, name); + if (!hPtr) { + Tcl_AppendResult(interp_, "can't find axis \"", name, "\" in \"", + Tk_PathName(tkwin_), "\"", NULL); + return TCL_ERROR; + } + + *axisPtrPtr = (Axis*)Tcl_GetHashValue(hPtr); + return TCL_OK; +} + +ClientData Graph::axisTag(const char *tagName) +{ + int isNew; + Tcl_HashEntry *hPtr = Tcl_CreateHashEntry(&axes_.tagTable, tagName, &isNew); + return Tcl_GetHashKey(&axes_.tagTable, hPtr); +} + +void Graph::adjustAxes() +{ + GraphOptions* ops = (GraphOptions*)ops_; + + if (ops->inverted) { + ops->leftMargin.axes = axisChain_[0]; + ops->bottomMargin.axes = axisChain_[1]; + ops->rightMargin.axes = axisChain_[2]; + ops->topMargin.axes = axisChain_[3]; + } + else { + ops->leftMargin.axes = axisChain_[1]; + ops->bottomMargin.axes = axisChain_[0]; + ops->rightMargin.axes = axisChain_[3]; + ops->topMargin.axes = axisChain_[2]; + } +} + +Point2d Graph::map2D(double x, double y, Axis* xAxis, Axis* yAxis) +{ + GraphOptions* ops = (GraphOptions*)ops_; + + Point2d point; + if (ops->inverted) { + point.x = yAxis->hMap(y); + point.y = xAxis->vMap(x); + } + else { + point.x = xAxis->hMap(x); + point.y = yAxis->vMap(y); + } + return point; +} + +Point2d Graph::invMap2D(double x, double y, Axis* xAxis, Axis* yAxis) +{ + GraphOptions* ops = (GraphOptions*)ops_; + + Point2d point; + if (ops->inverted) { + point.x = xAxis->invVMap(y); + point.y = yAxis->invHMap(x); + } + else { + point.x = xAxis->invHMap(x); + point.y = yAxis->invVMap(y); + } + return point; +} + +void Graph::resetAxes() +{ + // Step 1: Reset all axes. Initialize the data limits of the axis to + // impossible values. + Tcl_HashSearch cursor; + for (Tcl_HashEntry* hPtr = Tcl_FirstHashEntry(&axes_.table, &cursor); + hPtr; hPtr = Tcl_NextHashEntry(&cursor)) { + Axis *axisPtr = (Axis*)Tcl_GetHashValue(hPtr); + axisPtr->min_ = axisPtr->valueRange_.min = DBL_MAX; + axisPtr->max_ = axisPtr->valueRange_.max = -DBL_MAX; + } + + // Step 2: For each element that's to be displayed, get the smallest + // and largest data values mapped to each X and Y-axis. This + // will be the axis limits if the user doesn't override them + // with -min and -max options. + for (ChainLink* link = Chain_FirstLink(elements_.displayList); link; + link = Chain_NextLink(link)) { + Region2d exts; + + Element* elemPtr = (Element*)Chain_GetValue(link); + ElementOptions* elemops = (ElementOptions*)elemPtr->ops(); + elemPtr->extents(&exts); + elemops->xAxis->getDataLimits(exts.left, exts.right); + elemops->yAxis->getDataLimits(exts.top, exts.bottom); + } + + // Step 3: Now that we know the range of data values for each axis, + // set axis limits and compute a sweep to generate tick values. + for (Tcl_HashEntry* hPtr = Tcl_FirstHashEntry(&axes_.table, &cursor); + hPtr; hPtr = Tcl_NextHashEntry(&cursor)) { + Axis *axisPtr = (Axis*)Tcl_GetHashValue(hPtr); + AxisOptions* ops = (AxisOptions*)axisPtr->ops(); + axisPtr->fixRange(); + + double min = axisPtr->min_; + double max = axisPtr->max_; + if ((!isnan(axisPtr->scrollMin_)) && (min < axisPtr->scrollMin_)) + min = axisPtr->scrollMin_; + + if ((!isnan(axisPtr->scrollMax_)) && (max > axisPtr->scrollMax_)) + max = axisPtr->scrollMax_; + + if (ops->logScale) + axisPtr->logScale(min, max); + else + axisPtr->linearScale(min, max); + } +} + +Axis* Graph::nearestAxis(int x, int y) +{ + Tcl_HashSearch cursor; + for (Tcl_HashEntry* hPtr=Tcl_FirstHashEntry(&axes_.table, &cursor); + hPtr; hPtr = Tcl_NextHashEntry(&cursor)) { + Axis *axisPtr = (Axis*)Tcl_GetHashValue(hPtr); + AxisOptions* ops = (AxisOptions*)axisPtr->ops(); + if (ops->hide || !axisPtr->use_) + continue; + + if (ops->showTicks) { + for (ChainLink* link = Chain_FirstLink(axisPtr->tickLabels_); link; + link = Chain_NextLink(link)) { + TickLabel *labelPtr = (TickLabel*)Chain_GetValue(link); + double rw, rh; + Point2d bbox[5]; + getBoundingBox(labelPtr->width, labelPtr->height, ops->tickAngle, + &rw, &rh, bbox); + Point2d t; + t = anchorPoint(labelPtr->anchorPos.x, labelPtr->anchorPos.y, + rw, rh, axisPtr->tickAnchor_); + t.x = x - t.x - (rw * 0.5); + t.y = y - t.y - (rh * 0.5); + + bbox[4] = bbox[0]; + if (pointInPolygon(&t, bbox, 5)) { + return axisPtr; + } + } + } + + if (ops->title) { + int w, h; + double rw, rh; + Point2d bbox[5]; + getTextExtents(ops->titleFont, ops->title, -1, &w, &h); + getBoundingBox(w, h, axisPtr->titleAngle_, &rw, &rh, bbox); + Point2d t = anchorPoint(axisPtr->titlePos_.x, axisPtr->titlePos_.y, + rw, rh, axisPtr->titleAnchor_); + // Translate the point so that the 0,0 is the upper left + // corner of the bounding box + t.x = x - t.x - (rw * 0.5); + t.y = y - t.y - (rh * 0.5); + + bbox[4] = bbox[0]; + if (pointInPolygon(&t, bbox, 5)) { + return axisPtr; + } + } + if (ops->lineWidth > 0) { + if ((x <= axisPtr->right_) && (x >= axisPtr->left_) && + (y <= axisPtr->bottom_) && (y >= axisPtr->top_)) { + return axisPtr; + } + } + } + + return NULL; +} + +// Bind + +const char** Graph::getTags(ClientData object, ClassId classId, int* num) +{ + const char** tags =NULL; + + switch (classId) { + case CID_ELEM_BAR: + case CID_ELEM_LINE: + { + Element* ptr = (Element*)object; + ElementOptions* ops = (ElementOptions*)ptr->ops(); + int cnt =0; + for (const char** pp=ops->tags; *pp; pp++) + cnt++; + cnt +=2; + + tags = new const char*[cnt]; + tags[0] = (const char*)elementTag(ptr->name_); + tags[1] = (const char*)elementTag(ptr->className()); + int ii=2; + for (const char** pp = ops->tags; *pp; pp++, ii++) + tags[ii] = (const char*)elementTag(*pp); + + *num = cnt; + return tags; + } + break; + case CID_AXIS_X: + case CID_AXIS_Y: + { + Axis* ptr = (Axis*)object; + AxisOptions* ops = (AxisOptions*)ptr->ops(); + int cnt =0; + for (const char** pp=ops->tags; *pp; pp++) + cnt++; + cnt +=2; + + tags = new const char*[cnt]; + tags[0] = (const char*)axisTag(ptr->name_); + tags[1] = (const char*)axisTag(ptr->className()); + int ii=2; + for (const char** pp = ops->tags; *pp; pp++, ii++) + tags[ii] = (const char*)axisTag(*pp); + + *num = cnt; + return tags; + } + break; + case CID_MARKER_BITMAP: + case CID_MARKER_LINE: + case CID_MARKER_POLYGON: + case CID_MARKER_TEXT: + { + Marker* ptr = (Marker*)object; + MarkerOptions* ops = (MarkerOptions*)ptr->ops(); + int cnt =0; + for (const char** pp=ops->tags; *pp; pp++) + cnt++; + cnt +=2; + + tags = new const char*[cnt]; + tags[0] = (const char*)markerTag(ptr->name_); + tags[1] = (const char*)markerTag(ptr->className()); + int ii=2; + for (const char** pp = ops->tags; *pp; pp++, ii++) + tags[ii] = (const char*)markerTag(*pp); + + *num = cnt; + return tags; + } + break; + default: + break; + } + + return NULL; +} + +ClientData Graph::pickEntry(int xx, int yy, ClassId* classIdPtr) +{ + if (flags & (LAYOUT | MAP_MARKERS)) { + *classIdPtr = CID_NONE; + return NULL; + } + + // Sample coordinate is in one of the graph margins. Can only pick an axis. + Region2d exts; + extents(&exts); + if (xx>=exts.right || xx=exts.bottom || yyclassId(); + return axisPtr; + } + } + + // From top-to-bottom check: + // 1. markers drawn on top (-under false). + // 2. elements using its display list back to front. + // 3. markers drawn under element (-under true). + Marker* markerPtr = nearestMarker(xx, yy, 0); + if (markerPtr) { + *classIdPtr = markerPtr->classId(); + return markerPtr; + } + + GraphOptions* ops = (GraphOptions*)ops_; + ClosestSearch* searchPtr = &ops->search; + searchPtr->index = -1; + searchPtr->x = xx; + searchPtr->y = yy; + searchPtr->dist = (double)(searchPtr->halo + 1); + + for (ChainLink* link = Chain_LastLink(elements_.displayList); link; + link = Chain_PrevLink(link)) { + Element* elemPtr = (Element*)Chain_GetValue(link); + ElementOptions* eops = (ElementOptions*)elemPtr->ops(); + if (eops->hide) + continue; + elemPtr->closest(); + } + + // Found an element within the minimum halo distance. + if (searchPtr->dist <= (double)searchPtr->halo) { + *classIdPtr = searchPtr->elemPtr->classId(); + return searchPtr->elemPtr; + } + + markerPtr = nearestMarker(xx, yy, 1); + if (markerPtr) { + *classIdPtr = markerPtr->classId(); + return markerPtr; + } + + *classIdPtr = CID_NONE; + return NULL; +} + +int Graph::getXY(const char* string, int* xPtr, int* yPtr) +{ + if (!string || !*string) { + *xPtr = -SHRT_MAX; + *yPtr = -SHRT_MAX; + return TCL_OK; + } + + if (*string != '@') { + Tcl_AppendResult(interp_, "bad position \"", string, + "\": should be \"@x,y\"", (char *)NULL); + return TCL_ERROR; + } + + char* comma = (char*)strchr(string + 1, ','); + if (!comma) { + Tcl_AppendResult(interp_, "bad position \"", string, + "\": should be \"@x,y\"", (char *)NULL); + return TCL_ERROR; + } + + *comma = '\0'; + int x, y; + int result = ((Tk_GetPixels(interp_, tkwin_, string + 1, &x) == TCL_OK) && + (Tk_GetPixels(interp_, tkwin_, comma + 1, &y) == TCL_OK)); + *comma = ','; + if (!result) { + Tcl_AppendResult(interp_, ": can't parse position \"", string, "\"", + (char *)NULL); + return TCL_ERROR; + } + + *xPtr = x; + *yPtr = y; + return TCL_OK; +} + +// Graphics + +void Graph::drawSegments(Drawable drawable, GC gc, + Segment2d* segments, int nSegments) +{ + for (Segment2d *sp = segments, *send = sp + nSegments; sp < send; sp++) + XDrawLine(display_, drawable, gc, (int)sp->p.x, (int)sp->p.y, (int)sp->q.x, (int)sp->q.y); +} + +GC Graph::getPrivateGC(unsigned long gcMask, XGCValues *valuePtr) +{ + Pixmap pixmap = None; + Drawable drawable = Tk_WindowId(tkwin_); + Display* display = Tk_Display(tkwin_); + if (drawable == None) + drawable = RootWindow(Tk_Display(tkwin_),Tk_ScreenNumber(tkwin_)); + + GC gc = XCreateGC(display, drawable, gcMask, valuePtr); + if (pixmap != None) + Tk_FreePixmap(display, pixmap); + + return gc; +} + +void Graph::freePrivateGC(GC gc) +{ + Tk_FreeXId(display_, (XID)XGContextFromGC(gc)); + XFreeGC(display_, gc); +} + +void Graph::setDashes(GC gc, Dashes* dashesPtr) +{ + XSetDashes(display_, gc, dashesPtr->offset, (const char*)dashesPtr->values, + (int)strlen((char*)dashesPtr->values)); +} diff --git a/generic/tkbltGraph.h b/generic/tkbltGraph.h new file mode 100644 index 0000000..6f8df01 --- /dev/null +++ b/generic/tkbltGraph.h @@ -0,0 +1,256 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGraph_h__ +#define __BltGraph_h__ + +#include + +#include "tkbltChain.h" +#include "tkbltGrMisc.h" +#include "tkbltGrText.h" + +typedef struct Ensemble { + const char *name; + Tcl_ObjCmdProc *proc; + const struct Ensemble *subensemble; +} Ensemble; + +namespace Blt { + class Axis; + class BindTable; + class Crosshairs; + class Element; + class Marker; + class Legend; + class Pen; + class Postscript; + class PSOutput; + + class Pick { + public: + virtual ClientData pickEntry(int, int, ClassId*) =0; + }; + + typedef struct { + int halo; + int mode; + int x; + int y; + int along; + + Element* elemPtr; + Point2d point; + int index; + double dist; + } ClosestSearch; + + typedef struct { + int width; + int height; + int axesOffset; + int axesTitleLength; + int maxTickWidth; + int maxTickHeight; + unsigned int nAxes; + Chain* axes; + int reqSize; + int site; + } Margin; + + typedef struct { + Tcl_HashTable table; + Chain* displayList; + Tcl_HashTable tagTable; + } Component; + +#define rightMargin margins[MARGIN_RIGHT] +#define leftMargin margins[MARGIN_LEFT] +#define topMargin margins[MARGIN_TOP] +#define bottomMargin margins[MARGIN_BOTTOM] + + typedef struct { + double aspect; + Tk_3DBorder normalBg; + int borderWidth; + Margin margins[4]; + Tk_Cursor cursor; + TextStyleOptions titleTextStyle; + int reqHeight; + XColor* highlightBgColor; + XColor* highlightColor; + int highlightWidth; + int inverted; + Tk_3DBorder plotBg; + int plotBW; + int xPad; + int yPad; + int plotRelief; + int relief; + ClosestSearch search; + int stackAxes; + const char *takeFocus; // nor used in C code + const char *title; + int reqWidth; + int reqPlotWidth; + int reqPlotHeight; + } GraphOptions; + + class Graph : public Pick { + public: + Tcl_Interp* interp_; + Tk_Window tkwin_; + Display *display_; + Tcl_Command cmdToken_; + Tk_OptionTable optionTable_; + void* ops_; + int valid_; + + unsigned int flags; + int nextMarkerId_; + + Component axes_; + Component elements_; + Component markers_; + Tcl_HashTable penTable_; + BindTable* bindTable_; + Chain* axisChain_[4]; + + Legend* legend_; + Crosshairs* crosshairs_; + Postscript* postscript_; + + int inset_; + int titleX_; + int titleY_; + int titleWidth_; + int titleHeight_; + int width_; + int height_; + int left_; + int right_; + int top_; + int bottom_; + Axis* focusPtr_; + int halo_; + GC drawGC_; + int vRange_; + int hRange_; + int vOffset_; + int hOffset_; + double vScale_; + double hScale_; + Pixmap cache_; + int cacheWidth_; + int cacheHeight_; + + protected: + void layoutGraph(); + + void drawMargins(Drawable); + void printMargins(PSOutput*); + int getMarginGeometry(Margin*); + + void destroyPens(); + + void destroyElements(); + void configureElements(); + virtual void mapElements(); + void drawElements(Drawable); + void drawActiveElements(Drawable); + void printElements(PSOutput*); + void printActiveElements(PSOutput*); + + void destroyMarkers(); + void configureMarkers(); + void mapMarkers(); + void drawMarkers(Drawable, int); + void printMarkers(PSOutput*, int); + + int createAxes(); + void destroyAxes(); + void configureAxes(); + void mapAxes(); + void drawAxes(Drawable); + void drawAxesLimits(Drawable); + void drawAxesGrids(Drawable); + void adjustAxes(); + + public: + Graph(ClientData, Tcl_Interp*, int, Tcl_Obj* const []); + virtual ~Graph(); + + virtual int configure(); + void map(); + void draw(); + void eventuallyRedraw(); + int print(const char*, PSOutput*); + void extents(Region2d*); + int invoke(const Ensemble*, int, int, Tcl_Obj* const []); + void reconfigure(); + + int createAxis(int, Tcl_Obj* const []); + void printAxes(PSOutput*); + void printAxesGrids(PSOutput*); + void printAxesLimits(PSOutput*); + int getAxis(Tcl_Obj*, Axis**); + ClientData axisTag(const char*); + Point2d map2D(double, double, Axis*, Axis*); + Point2d invMap2D(double, double, Axis*, Axis*); + virtual void resetAxes(); + Axis* nearestAxis(int, int); + + ClientData markerTag(const char*); + Marker* nearestMarker(int, int, int); + int isElementHidden(Marker*); + + virtual int createElement(int, Tcl_Obj* const []) =0; + int getElement(Tcl_Obj*, Element**); + ClientData elementTag(const char*); + + virtual int createPen(const char*, int, Tcl_Obj* const []) =0; + int getPen(Tcl_Obj*, Pen**); + + int getXY(const char*, int*, int*); + void getTextExtents(Tk_Font, const char*, int, int*, int*); + void getBoundingBox(int, int, double, double*, double*, Point2d*); + Point2d anchorPoint(double, double, double, double, Tk_Anchor); + + const char** getTags(ClientData, ClassId, int*); + ClientData pickEntry(int, int, ClassId*); + + void drawSegments(Drawable, GC, Segment2d*, int); + void setDashes(GC, Dashes*); + + GC getPrivateGC(unsigned long, XGCValues*); + void freePrivateGC(GC); + }; +}; + +#endif diff --git a/generic/tkbltGraphBar.C b/generic/tkbltGraphBar.C new file mode 100644 index 0000000..861c12a --- /dev/null +++ b/generic/tkbltGraphBar.C @@ -0,0 +1,516 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1991-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "tkbltGraphBar.h" +#include "tkbltGraphOp.h" + +#include "tkbltGrAxis.h" +#include "tkbltGrXAxisOp.h" +#include "tkbltGrPen.h" +#include "tkbltGrPenOp.h" +#include "tkbltGrPenBar.h" +#include "tkbltGrPenLine.h" +#include "tkbltGrElem.h" +#include "tkbltGrElemOp.h" +#include "tkbltGrElemBar.h" +#include "tkbltGrElemLine.h" +#include "tkbltGrMarker.h" +#include "tkbltGrLegd.h" +#include "tkbltGrHairs.h" +#include "tkbltGrPostscript.h" +#include "tkbltGrDef.h" + +using namespace Blt; + +// BarGroup + +BarGroup::BarGroup() +{ + nSegments =0; + xAxis =NULL; + yAxis =NULL; + sum =0; + count =0; + lastY =0; + index =0; +} + +// BarGraph + +static const char* barmodeObjOption[] = + {"normal", "stacked", "aligned", "overlap", NULL}; +static const char* searchModeObjOption[] = {"points", "traces", "auto", NULL}; +static const char* searchAlongObjOption[] = {"x", "y", "both", NULL}; + +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_DOUBLE, "-aspect", "aspect", "Aspect", + "0", -1, Tk_Offset(BarGraphOptions, aspect), 0, NULL, RESET}, + {TK_OPTION_BORDER, "-background", "background", "Background", + STD_NORMAL_BACKGROUND, -1, Tk_Offset(BarGraphOptions, normalBg), + 0, NULL, CACHE}, + {TK_OPTION_STRING_TABLE, "-barmode", "barMode", "BarMode", + "normal", -1, Tk_Offset(BarGraphOptions, barMode), + 0, &barmodeObjOption, RESET}, + {TK_OPTION_DOUBLE, "-barwidth", "barWidth", "BarWidth", + ".9", -1, Tk_Offset(BarGraphOptions, barWidth), 0, NULL, RESET}, + {TK_OPTION_DOUBLE, "-baseline", "baseline", "Baseline", + "0", -1, Tk_Offset(BarGraphOptions, baseline), 0, NULL, RESET}, + {TK_OPTION_SYNONYM, "-bd", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-borderwidth", 0}, + {TK_OPTION_SYNONYM, "-bg", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-background", 0}, + {TK_OPTION_SYNONYM, "-bm", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-bottommargin", 0}, + {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", + STD_BORDERWIDTH, -1, Tk_Offset(BarGraphOptions, borderWidth), + 0, NULL, RESET}, + {TK_OPTION_PIXELS, "-bottommargin", "bottomMargin", "BottomMargin", + "0", -1, Tk_Offset(BarGraphOptions, bottomMargin.reqSize), 0, NULL, RESET}, + {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor", + "crosshair", -1, Tk_Offset(BarGraphOptions, cursor), + TK_OPTION_NULL_OK, NULL, 0}, + {TK_OPTION_SYNONYM, "-fg", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-foreground", 0}, + {TK_OPTION_FONT, "-font", "font", "Font", + STD_FONT_MEDIUM, -1, Tk_Offset(BarGraphOptions, titleTextStyle.font), + 0, NULL, RESET}, + {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground", + STD_NORMAL_FOREGROUND, -1, Tk_Offset(BarGraphOptions, titleTextStyle.color), + 0, NULL, CACHE}, + {TK_OPTION_SYNONYM, "-halo", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-searchhalo", 0}, + {TK_OPTION_PIXELS, "-height", "height", "Height", + "4i", -1, Tk_Offset(BarGraphOptions, reqHeight), 0, NULL, RESET}, + {TK_OPTION_COLOR, "-highlightbackground", "highlightBackground", + "HighlightBackground", + STD_NORMAL_BACKGROUND, -1, Tk_Offset(BarGraphOptions, highlightBgColor), + 0, NULL, CACHE}, + {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", + STD_NORMAL_FOREGROUND, -1, Tk_Offset(BarGraphOptions, highlightColor), + 0, NULL, CACHE}, + {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness", + "HighlightThickness", + "2", -1, Tk_Offset(BarGraphOptions, highlightWidth), 0, NULL, RESET}, + {TK_OPTION_BOOLEAN, "-invertxy", "invertXY", "InvertXY", + "no", -1, Tk_Offset(BarGraphOptions, inverted), 0, NULL, RESET}, + {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify", + "center", -1, Tk_Offset(BarGraphOptions, titleTextStyle.justify), + 0, NULL, RESET}, + {TK_OPTION_PIXELS, "-leftmargin", "leftMargin", "Margin", + "0", -1, Tk_Offset(BarGraphOptions, leftMargin.reqSize), 0, NULL, RESET}, + {TK_OPTION_SYNONYM, "-lm", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-leftmargin", 0}, + {TK_OPTION_BORDER, "-plotbackground", "plotbackground", "PlotBackground", + STD_NORMAL_BACKGROUND, -1, Tk_Offset(BarGraphOptions, plotBg), + 0, NULL, CACHE}, + {TK_OPTION_PIXELS, "-plotborderwidth", "plotBorderWidth", "PlotBorderWidth", + STD_BORDERWIDTH, -1, Tk_Offset(BarGraphOptions, plotBW), 0, NULL, RESET}, + {TK_OPTION_PIXELS, "-plotpadx", "plotPadX", "PlotPad", + "0", -1, Tk_Offset(BarGraphOptions, xPad), 0, NULL, RESET}, + {TK_OPTION_PIXELS, "-plotpady", "plotPadY", "PlotPad", + "0", -1, Tk_Offset(BarGraphOptions, yPad), 0, NULL, RESET}, + {TK_OPTION_RELIEF, "-plotrelief", "plotRelief", "Relief", + "flat", -1, Tk_Offset(BarGraphOptions, plotRelief), 0, NULL, RESET}, + {TK_OPTION_RELIEF, "-relief", "relief", "Relief", + "flat", -1, Tk_Offset(BarGraphOptions, relief), 0, NULL, RESET}, + {TK_OPTION_PIXELS, "-rightmargin", "rightMargin", "Margin", + "0", -1, Tk_Offset(BarGraphOptions, rightMargin.reqSize), 0, NULL, RESET}, + {TK_OPTION_SYNONYM, "-rm", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-rightmargin", 0}, + {TK_OPTION_PIXELS, "-searchhalo", "searchhalo", "SearchHalo", + "2m", -1, Tk_Offset(BarGraphOptions, search.halo), 0, NULL, 0}, + {TK_OPTION_STRING_TABLE, "-searchmode", "searchMode", "SearchMode", + "points", -1, Tk_Offset(BarGraphOptions, search.mode), + 0, &searchModeObjOption, 0}, + {TK_OPTION_STRING_TABLE, "-searchalong", "searchAlong", "SearchAlong", + "both", -1, Tk_Offset(BarGraphOptions, search.along), + 0, &searchAlongObjOption, 0}, + {TK_OPTION_BOOLEAN, "-stackaxes", "stackAxes", "StackAxes", + "no", -1, Tk_Offset(BarGraphOptions, stackAxes), 0, NULL, RESET}, + {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus", + NULL, -1, Tk_Offset(BarGraphOptions, takeFocus), + TK_OPTION_NULL_OK, NULL, 0}, + {TK_OPTION_STRING, "-title", "title", "Title", + NULL, -1, Tk_Offset(BarGraphOptions, title), TK_OPTION_NULL_OK, NULL, RESET}, + {TK_OPTION_SYNONYM, "-tm", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-topmargin", 0}, + {TK_OPTION_PIXELS, "-topmargin", "topMargin", "TopMargin", + "0", -1, Tk_Offset(BarGraphOptions, topMargin.reqSize), 0, NULL, RESET}, + {TK_OPTION_PIXELS, "-width", "width", "Width", + "5i", -1, Tk_Offset(BarGraphOptions, reqWidth), 0, NULL, RESET}, + {TK_OPTION_PIXELS, "-plotwidth", "plotWidth", "PlotWidth", + "0", -1, Tk_Offset(BarGraphOptions, reqPlotWidth), 0, NULL, RESET}, + {TK_OPTION_PIXELS, "-plotheight", "plotHeight", "PlotHeight", + "0", -1, Tk_Offset(BarGraphOptions, reqPlotHeight), 0, NULL, RESET}, + {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, -1, 0, 0, 0} +}; + +// Create + +BarGraph::BarGraph(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) + : Graph(clientData, interp, objc, objv) +{ + // problems so far? + if (!valid_) + return; + + ops_ = (BarGraphOptions*)calloc(1, sizeof(BarGraphOptions)); + BarGraphOptions* ops = (BarGraphOptions*)ops_; + + Tk_SetClass(tkwin_, "Barchart"); + + barGroups_ =NULL; + nBarGroups_ =0; + maxBarSetSize_ =0; + Tcl_InitHashTable(&setTable_, sizeof(BarSetKey)/sizeof(int)); + + ops->bottomMargin.site = MARGIN_BOTTOM; + ops->leftMargin.site = MARGIN_LEFT; + ops->topMargin.site = MARGIN_TOP; + ops->rightMargin.site = MARGIN_RIGHT; + + ops->titleTextStyle.anchor = TK_ANCHOR_N; + ops->titleTextStyle.color =NULL; + ops->titleTextStyle.font =NULL; + ops->titleTextStyle.angle =0; + ops->titleTextStyle.justify =TK_JUSTIFY_LEFT; + + optionTable_ = Tk_CreateOptionTable(interp_, optionSpecs); + if ((Tk_InitOptions(interp_, (char*)ops_, optionTable_, tkwin_) != TCL_OK) || (GraphObjConfigure(this, interp_, objc-2, objv+2) != TCL_OK)) { + valid_ =0; + return; + } + + // do this last after Tk_SetClass set + legend_ = new Legend(this); + crosshairs_ = new Crosshairs(this); + postscript_ = new Postscript(this); + + if (createPen("active", 0, NULL) != TCL_OK) { + valid_ =0; + return; + } + + if (createAxes() != TCL_OK) { + valid_ =0; + return; + } + + adjustAxes(); + + Tcl_SetStringObj(Tcl_GetObjResult(interp_), Tk_PathName(tkwin_), -1); +} + +BarGraph::~BarGraph() +{ + destroyBarSets(); +} + +int BarGraph::configure() +{ + BarGraphOptions* ops = (BarGraphOptions*)ops_; + // Don't allow negative bar widths. Reset to an arbitrary value (0.1) + if (ops->barWidth <= 0.0) + ops->barWidth = 0.9; + + return Graph::configure(); +} + +int BarGraph::createPen(const char* penName, int objc, Tcl_Obj* const objv[]) +{ + int isNew; + Tcl_HashEntry *hPtr = + Tcl_CreateHashEntry(&penTable_, penName, &isNew); + if (!isNew) { + Tcl_AppendResult(interp_, "pen \"", penName, "\" already exists in \"", + Tk_PathName(tkwin_), "\"", (char *)NULL); + return TCL_ERROR; + } + + Pen* penPtr = new BarPen(this, penName, hPtr); + if (!penPtr) + return TCL_ERROR; + + Tcl_SetHashValue(hPtr, penPtr); + + if ((Tk_InitOptions(interp_, (char*)penPtr->ops(), penPtr->optionTable(), tkwin_) != TCL_OK) || (PenObjConfigure(this, penPtr, interp_, objc-4, objv+4) != TCL_OK)) { + delete penPtr; + return TCL_ERROR; + } + + flags |= RESET; + eventuallyRedraw(); + + return TCL_OK; +} + +int BarGraph::createElement(int objc, Tcl_Obj* const objv[]) +{ + char *name = Tcl_GetString(objv[3]); + if (name[0] == '-') { + Tcl_AppendResult(interp_, "name of element \"", name, + "\" can't start with a '-'", NULL); + return TCL_ERROR; + } + + int isNew; + Tcl_HashEntry* hPtr = + Tcl_CreateHashEntry(&elements_.table, name, &isNew); + if (!isNew) { + Tcl_AppendResult(interp_, "element \"", name, + "\" already exists in \"", Tcl_GetString(objv[0]), + "\"", NULL); + return TCL_ERROR; + } + + Element* elemPtr = new BarElement(this, name, hPtr); + if (!elemPtr) + return TCL_ERROR; + + Tcl_SetHashValue(hPtr, elemPtr); + + if ((Tk_InitOptions(interp_, (char*)elemPtr->ops(), elemPtr->optionTable(), tkwin_) != TCL_OK) || (ElementObjConfigure(elemPtr, interp_, objc-4, objv+4) != TCL_OK)) { + delete elemPtr; + return TCL_ERROR; + } + + elemPtr->link = elements_.displayList->append(elemPtr); + + return TCL_OK; +} + +void BarGraph::mapElements() +{ + BarGraphOptions* ops = (BarGraphOptions*)ops_; + if ((BarMode)ops->barMode != INFRONT) + resetBarSets(); + + Graph::mapElements(); +} + +void BarGraph::resetAxes() +{ + BarGraphOptions* ops = (BarGraphOptions*)ops_; + + /* FIXME: This should be called whenever the display list of + * elements change. Maybe yet another flag INIT_STACKS to + * indicate that the element display list has changed. + * Needs to be done before the axis limits are set. + */ + initBarSets(); + if (((BarMode)ops->barMode == STACKED) && (nBarGroups_ > 0)) + computeBarStacks(); + + Graph::resetAxes(); +} + +void BarGraph::initBarSets() +{ + BarGraphOptions* ops = (BarGraphOptions*)ops_; + + // Free resources associated with a previous frequency table. This includes + // the array of frequency information and the table itself + destroyBarSets(); + if ((BarMode)ops->barMode == INFRONT) + return; + + // Initialize a hash table and fill it with unique abscissas. Keep track + // of the frequency of each x-coordinate and how many abscissas have + // duplicate mappings. + Tcl_HashTable setTable; + Tcl_InitHashTable(&setTable, sizeof(BarSetKey)/sizeof(int)); + int nSegs =0; + + for (ChainLink* link = Chain_FirstLink(elements_.displayList); + link; link = Chain_NextLink(link)) { + BarElement* bePtr = (BarElement*)Chain_GetValue(link); + BarElementOptions* ops = (BarElementOptions*)bePtr->ops(); + if (ops->hide) + continue; + + nSegs++; + if (ops->coords.x) { + int nPoints = ops->coords.x->nValues(); + for (double *x=ops->coords.x->values_, *xend=x+nPoints; xxAxis; + key.yAxis =NULL; + + int isNew; + Tcl_HashEntry* hhPtr = + Tcl_CreateHashEntry(&setTable, (char*)&key, &isNew); + Tcl_HashTable* tablePtr; + if (isNew) { + tablePtr = (Tcl_HashTable*)malloc(sizeof(Tcl_HashTable)); + Tcl_InitHashTable(tablePtr, TCL_STRING_KEYS); + Tcl_SetHashValue(hhPtr, tablePtr); + } + else + tablePtr = (Tcl_HashTable*)Tcl_GetHashValue(hhPtr); + + const char* name = ops->groupName ? ops->groupName : ops->yAxis->name_; + Tcl_HashEntry* hhPtr2 = Tcl_CreateHashEntry(tablePtr, name, &isNew); + size_t count =1; + if (!isNew) { + count = (size_t)Tcl_GetHashValue(hhPtr2); + count++; + } + Tcl_SetHashValue(hhPtr2, count); + } + } + } + + // no bar elements to be displayed + if (setTable.numEntries == 0) + return; + + int sum =0; + int max =0; + Tcl_HashSearch iter; + for (Tcl_HashEntry *hhPtr = Tcl_FirstHashEntry(&setTable, &iter); hhPtr; + hhPtr = Tcl_NextHashEntry(&iter)) { + BarSetKey* keyPtr = (BarSetKey*)Tcl_GetHashKey(&setTable, hhPtr); + Tcl_HashTable* tablePtr = (Tcl_HashTable*)Tcl_GetHashValue(hhPtr); + + int isNew; + Tcl_HashEntry* hPtr = + Tcl_CreateHashEntry(&setTable_, (char*)keyPtr, &isNew); + Tcl_SetHashValue(hPtr, tablePtr); + + if (max < tablePtr->numEntries) + max = tablePtr->numEntries; // # of stacks in group + sum += tablePtr->numEntries; + } + + Tcl_DeleteHashTable(&setTable); + + if (sum > 0) { + barGroups_ = new BarGroup[sum]; + BarGroup* groupPtr = barGroups_; + Tcl_HashSearch iter; + for (Tcl_HashEntry* hPtr = Tcl_FirstHashEntry(&setTable_, &iter); + hPtr; hPtr = Tcl_NextHashEntry(&iter)) { + BarSetKey* keyPtr = (BarSetKey*)Tcl_GetHashKey(&setTable_, hPtr); + Tcl_HashTable* tablePtr = (Tcl_HashTable*)Tcl_GetHashValue(hPtr); + + size_t xcount = 0; + Tcl_HashSearch iter2; + for (Tcl_HashEntry *hPtr2 = Tcl_FirstHashEntry(tablePtr, &iter2); + hPtr2; hPtr2 = Tcl_NextHashEntry(&iter2)) { + size_t count = (size_t)Tcl_GetHashValue(hPtr2); + groupPtr->nSegments = count; + groupPtr->xAxis = keyPtr->xAxis; + groupPtr->yAxis = keyPtr->yAxis; + groupPtr->index = xcount++; + Tcl_SetHashValue(hPtr2, groupPtr); + + groupPtr++; + } + } + } + + maxBarSetSize_ = max; + nBarGroups_ = sum; +} + +void BarGraph::destroyBarSets() +{ + delete [] barGroups_; + barGroups_ = NULL; + + nBarGroups_ = 0; + Tcl_HashSearch iter; + for (Tcl_HashEntry* hPtr=Tcl_FirstHashEntry(&setTable_, &iter); hPtr; + hPtr=Tcl_NextHashEntry(&iter)) { + Tcl_HashTable* tablePtr = (Tcl_HashTable*)Tcl_GetHashValue(hPtr); + Tcl_DeleteHashTable(tablePtr); + free(tablePtr); + } + + Tcl_DeleteHashTable(&setTable_); + Tcl_InitHashTable(&setTable_, sizeof(BarSetKey)/sizeof(int)); +} + +void BarGraph::resetBarSets() +{ + for (BarGroup *gp = barGroups_, *gend = gp + nBarGroups_; gp < gend; gp++) { + gp->lastY = 0.0; + gp->count = 0; + } +} + +void BarGraph::computeBarStacks() +{ + BarGraphOptions* ops = (BarGraphOptions*)ops_; + + if (((BarMode)ops->barMode != STACKED) || (nBarGroups_ == 0)) + return; + + // Initialize the stack sums to zero + for (BarGroup *gp = barGroups_, *gend = gp + nBarGroups_; gp < gend; gp++) + gp->sum = 0.0; + + // Consider each bar x-y coordinate. Add the ordinates of duplicate + // abscissas + + for (ChainLink* link = Chain_FirstLink(elements_.displayList); link; + link = Chain_NextLink(link)) { + BarElement* bePtr = (BarElement*)Chain_GetValue(link); + BarElementOptions* ops = (BarElementOptions*)bePtr->ops(); + if (ops->hide) + continue; + + if (ops->coords.x && ops->coords.y) { + for (double *x=ops->coords.x->values_, *y=ops->coords.y->values_, + *xend=x+ops->coords.x->nValues(); xxAxis; + key.yAxis =NULL; + Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&setTable_, (char*)&key); + if (!hPtr) + continue; + + Tcl_HashTable *tablePtr = (Tcl_HashTable*)Tcl_GetHashValue(hPtr); + const char *name = ops->groupName ? ops->groupName : ops->yAxis->name_; + hPtr = Tcl_FindHashEntry(tablePtr, name); + if (!hPtr) + continue; + + BarGroup *groupPtr = (BarGroup*)Tcl_GetHashValue(hPtr); + groupPtr->sum += *y; + } + } + } +} + diff --git a/generic/tkbltGraphBar.h b/generic/tkbltGraphBar.h new file mode 100644 index 0000000..5ee1ab8 --- /dev/null +++ b/generic/tkbltGraphBar.h @@ -0,0 +1,119 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGraphBar_h__ +#define __BltGraphBar_h__ + +#include + +#include "tkbltGraph.h" + +namespace Blt { + + typedef struct { + double value; + Axis* xAxis; + Axis* yAxis; + } BarSetKey; + + class BarGroup { + public: + int nSegments; + Axis* xAxis; + Axis* yAxis; + double sum; + int count; + double lastY; + size_t index; + + public: + BarGroup(); + }; + + typedef struct { + double aspect; + Tk_3DBorder normalBg; + int borderWidth; + Margin margins[4]; + Tk_Cursor cursor; + TextStyleOptions titleTextStyle; + int reqHeight; + XColor* highlightBgColor; + XColor* highlightColor; + int highlightWidth; + int inverted; + Tk_3DBorder plotBg; + int plotBW; + int xPad; + int yPad; + int plotRelief; + int relief; + ClosestSearch search; + int stackAxes; + const char *takeFocus; // nor used in C code + const char *title; + int reqWidth; + int reqPlotWidth; + int reqPlotHeight; + + // bar graph + int barMode; + double barWidth; + double baseline; + } BarGraphOptions; + + class BarGraph : public Graph { + public: + enum BarMode {INFRONT, STACKED, ALIGNED, OVERLAP}; + + public: + BarGroup* barGroups_; + int nBarGroups_; + Tcl_HashTable setTable_; + int maxBarSetSize_; + + protected: + void resetAxes(); + void mapElements(); + void initBarSets(); + void destroyBarSets(); + void resetBarSets(); + void computeBarStacks(); + + public: + BarGraph(ClientData, Tcl_Interp*, int, Tcl_Obj* const []); + virtual ~BarGraph(); + + int configure(); + int createPen(const char*, int, Tcl_Obj* const []); + int createElement(int, Tcl_Obj* const []); + }; +}; + +#endif diff --git a/generic/tkbltGraphLine.C b/generic/tkbltGraphLine.C new file mode 100644 index 0000000..fe3f5d0 --- /dev/null +++ b/generic/tkbltGraphLine.C @@ -0,0 +1,267 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1991-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "tkbltGraphLine.h" +#include "tkbltGraphOp.h" + +#include "tkbltGrAxis.h" +#include "tkbltGrXAxisOp.h" +#include "tkbltGrPen.h" +#include "tkbltGrPenOp.h" +#include "tkbltGrPenBar.h" +#include "tkbltGrPenLine.h" +#include "tkbltGrElem.h" +#include "tkbltGrElemOp.h" +#include "tkbltGrElemBar.h" +#include "tkbltGrElemLine.h" +#include "tkbltGrMarker.h" +#include "tkbltGrLegd.h" +#include "tkbltGrHairs.h" +#include "tkbltGrPostscript.h" +#include "tkbltGrDef.h" + +using namespace Blt; + +static const char* searchModeObjOption[] = {"points", "traces", "auto", NULL}; +static const char* searchAlongObjOption[] = {"x", "y", "both", NULL}; + +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_DOUBLE, "-aspect", "aspect", "Aspect", + "0", -1, Tk_Offset(LineGraphOptions, aspect), 0, NULL, RESET}, + {TK_OPTION_BORDER, "-background", "background", "Background", + STD_NORMAL_BACKGROUND, -1, Tk_Offset(LineGraphOptions, normalBg), + 0, NULL, CACHE}, + {TK_OPTION_SYNONYM, "-bd", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-borderwidth", 0}, + {TK_OPTION_SYNONYM, "-bg", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-background", 0}, + {TK_OPTION_SYNONYM, "-bm", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-bottommargin", 0}, + {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", + STD_BORDERWIDTH, -1, Tk_Offset(LineGraphOptions, borderWidth), + 0, NULL, RESET}, + {TK_OPTION_PIXELS, "-bottommargin", "bottomMargin", "BottomMargin", + "0", -1, Tk_Offset(LineGraphOptions, bottomMargin.reqSize), 0, NULL, RESET}, + {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor", + "crosshair", -1, Tk_Offset(LineGraphOptions, cursor), + TK_OPTION_NULL_OK, NULL, 0}, + {TK_OPTION_SYNONYM, "-fg", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-foreground", 0}, + {TK_OPTION_FONT, "-font", "font", "Font", + STD_FONT_MEDIUM, -1, Tk_Offset(LineGraphOptions, titleTextStyle.font), + 0, NULL, RESET}, + {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground", + STD_NORMAL_FOREGROUND, -1, + Tk_Offset(LineGraphOptions, titleTextStyle.color), 0, NULL, CACHE}, + {TK_OPTION_SYNONYM, "-halo", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-searchhalo", 0}, + {TK_OPTION_PIXELS, "-height", "height", "Height", + "4i", -1, Tk_Offset(LineGraphOptions, reqHeight), 0, NULL, RESET}, + {TK_OPTION_COLOR, "-highlightbackground", "highlightBackground", + "HighlightBackground", + STD_NORMAL_BACKGROUND, -1, Tk_Offset(LineGraphOptions, highlightBgColor), + 0, NULL, CACHE}, + {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", + STD_NORMAL_FOREGROUND, -1, Tk_Offset(LineGraphOptions, highlightColor), + 0, NULL, CACHE}, + {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness", + "HighlightThickness", + "2", -1, Tk_Offset(LineGraphOptions, highlightWidth), 0, NULL, RESET}, + {TK_OPTION_BOOLEAN, "-invertxy", "invertXY", "InvertXY", + "no", -1, Tk_Offset(LineGraphOptions, inverted), 0, NULL, RESET}, + {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify", + "center", -1, Tk_Offset(LineGraphOptions, titleTextStyle.justify), + 0, NULL, RESET}, + {TK_OPTION_PIXELS, "-leftmargin", "leftMargin", "Margin", + "0", -1, Tk_Offset(LineGraphOptions, leftMargin.reqSize), 0, NULL, RESET}, + {TK_OPTION_SYNONYM, "-lm", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-leftmargin", 0}, + {TK_OPTION_BORDER, "-plotbackground", "plotbackground", "PlotBackground", + STD_NORMAL_BACKGROUND, -1, Tk_Offset(LineGraphOptions, plotBg), + 0, NULL, CACHE}, + {TK_OPTION_PIXELS, "-plotborderwidth", "plotBorderWidth", "PlotBorderWidth", + STD_BORDERWIDTH, -1, Tk_Offset(LineGraphOptions, plotBW), 0, NULL, RESET}, + {TK_OPTION_PIXELS, "-plotpadx", "plotPadX", "PlotPad", + "0", -1, Tk_Offset(LineGraphOptions, xPad), 0, NULL, RESET}, + {TK_OPTION_PIXELS, "-plotpady", "plotPadY", "PlotPad", + "0", -1, Tk_Offset(LineGraphOptions, yPad), 0, NULL, RESET}, + {TK_OPTION_RELIEF, "-plotrelief", "plotRelief", "Relief", + "flat", -1, Tk_Offset(LineGraphOptions, plotRelief), 0, NULL, RESET}, + {TK_OPTION_RELIEF, "-relief", "relief", "Relief", + "flat", -1, Tk_Offset(LineGraphOptions, relief), 0, NULL, RESET}, + {TK_OPTION_PIXELS, "-rightmargin", "rightMargin", "Margin", + "0", -1, Tk_Offset(LineGraphOptions, rightMargin.reqSize), 0, NULL, RESET}, + {TK_OPTION_SYNONYM, "-rm", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-rightmargin", 0}, + {TK_OPTION_PIXELS, "-searchhalo", "searchhalo", "SearchHalo", + "2m", -1, Tk_Offset(LineGraphOptions, search.halo), 0, NULL, 0}, + {TK_OPTION_STRING_TABLE, "-searchmode", "searchMode", "SearchMode", + "points", -1, Tk_Offset(LineGraphOptions, search.mode), + 0, &searchModeObjOption, 0}, + {TK_OPTION_STRING_TABLE, "-searchalong", "searchAlong", "SearchAlong", + "both", -1, Tk_Offset(LineGraphOptions, search.along), + 0, &searchAlongObjOption, 0}, + {TK_OPTION_BOOLEAN, "-stackaxes", "stackAxes", "StackAxes", + "no", -1, Tk_Offset(LineGraphOptions, stackAxes), 0, NULL, RESET}, + {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus", + NULL, -1, Tk_Offset(LineGraphOptions, takeFocus), + TK_OPTION_NULL_OK, NULL, 0}, + {TK_OPTION_STRING, "-title", "title", "Title", + NULL, -1, Tk_Offset(LineGraphOptions, title), + TK_OPTION_NULL_OK, NULL, RESET}, + {TK_OPTION_SYNONYM, "-tm", NULL, NULL, + NULL, 0, -1, 0, (ClientData)"-topmargin", 0}, + {TK_OPTION_PIXELS, "-topmargin", "topMargin", "TopMargin", + "0", -1, Tk_Offset(LineGraphOptions, topMargin.reqSize), 0, NULL, RESET}, + {TK_OPTION_PIXELS, "-width", "width", "Width", + "5i", -1, Tk_Offset(LineGraphOptions, reqWidth), 0, NULL, RESET}, + {TK_OPTION_PIXELS, "-plotwidth", "plotWidth", "PlotWidth", + "0", -1, Tk_Offset(LineGraphOptions, reqPlotWidth), 0, NULL, RESET}, + {TK_OPTION_PIXELS, "-plotheight", "plotHeight", "PlotHeight", + "0", -1, Tk_Offset(LineGraphOptions, reqPlotHeight), 0, NULL, RESET}, + {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, -1, 0, 0, 0} +}; + +// Create + +LineGraph::LineGraph(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) + : Graph(clientData, interp, objc, objv) +{ + // problems so far? + if (!valid_) + return; + + ops_ = (LineGraphOptions*)calloc(1, sizeof(LineGraphOptions)); + LineGraphOptions* ops = (LineGraphOptions*)ops_; + + Tk_SetClass(tkwin_, "Graph"); + + ops->bottomMargin.site = MARGIN_BOTTOM; + ops->leftMargin.site = MARGIN_LEFT; + ops->topMargin.site = MARGIN_TOP; + ops->rightMargin.site = MARGIN_RIGHT; + + ops->titleTextStyle.anchor = TK_ANCHOR_N; + ops->titleTextStyle.color =NULL; + ops->titleTextStyle.font =NULL; + ops->titleTextStyle.angle =0; + ops->titleTextStyle.justify =TK_JUSTIFY_LEFT; + + optionTable_ = Tk_CreateOptionTable(interp_, optionSpecs); + if ((Tk_InitOptions(interp_, (char*)ops_, optionTable_, tkwin_) != TCL_OK) || (GraphObjConfigure(this, interp_, objc-2, objv+2) != TCL_OK)) { + valid_ =0; + return; + } + + // do this last after Tk_SetClass set + legend_ = new Legend(this); + crosshairs_ = new Crosshairs(this); + postscript_ = new Postscript(this); + + if (createPen("active", 0, NULL) != TCL_OK) { + valid_ =0; + return; + } + + if (createAxes() != TCL_OK) { + valid_ =0; + return; + } + + adjustAxes(); + + Tcl_SetStringObj(Tcl_GetObjResult(interp_), Tk_PathName(tkwin_), -1); +} + +LineGraph::~LineGraph() +{ +} + +int LineGraph::createPen(const char* penName, int objc, Tcl_Obj* const objv[]) +{ + int isNew; + Tcl_HashEntry *hPtr = + Tcl_CreateHashEntry(&penTable_, penName, &isNew); + if (!isNew) { + Tcl_AppendResult(interp_, "pen \"", penName, "\" already exists in \"", + Tk_PathName(tkwin_), "\"", (char *)NULL); + return TCL_ERROR; + } + + Pen* penPtr = new LinePen(this, penName, hPtr); + if (!penPtr) + return TCL_ERROR; + + Tcl_SetHashValue(hPtr, penPtr); + + if ((Tk_InitOptions(interp_, (char*)penPtr->ops(), penPtr->optionTable(), tkwin_) != TCL_OK) || (PenObjConfigure(this, penPtr, interp_, objc-4, objv+4) != TCL_OK)) { + delete penPtr; + return TCL_ERROR; + } + + return TCL_OK; +} + +int LineGraph::createElement(int objc, Tcl_Obj* const objv[]) +{ + char *name = Tcl_GetString(objv[3]); + if (name[0] == '-') { + Tcl_AppendResult(interp_, "name of element \"", name, + "\" can't start with a '-'", NULL); + return TCL_ERROR; + } + + int isNew; + Tcl_HashEntry* hPtr = + Tcl_CreateHashEntry(&elements_.table, name, &isNew); + if (!isNew) { + Tcl_AppendResult(interp_, "element \"", name, + "\" already exists in \"", Tcl_GetString(objv[0]), + "\"", NULL); + return TCL_ERROR; + } + + Element* elemPtr = new LineElement(this, name, hPtr); + if (!elemPtr) + return TCL_ERROR; + + Tcl_SetHashValue(hPtr, elemPtr); + + if ((Tk_InitOptions(interp_, (char*)elemPtr->ops(), elemPtr->optionTable(), tkwin_) != TCL_OK) || (ElementObjConfigure(elemPtr, interp_, objc-4, objv+4) != TCL_OK)) { + delete elemPtr; + return TCL_ERROR; + } + + elemPtr->link = elements_.displayList->append(elemPtr); + + return TCL_OK; +} diff --git a/generic/tkbltGraphLine.h b/generic/tkbltGraphLine.h new file mode 100644 index 0000000..ea8d2a0 --- /dev/null +++ b/generic/tkbltGraphLine.h @@ -0,0 +1,76 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGraphLine_h__ +#define __BltGraphLine_h__ + +#include + +#include "tkbltGraph.h" + +namespace Blt { + + typedef struct { + double aspect; + Tk_3DBorder normalBg; + int borderWidth; + Margin margins[4]; + Tk_Cursor cursor; + Blt::TextStyleOptions titleTextStyle; + int reqHeight; + XColor* highlightBgColor; + XColor* highlightColor; + int highlightWidth; + int inverted; + Tk_3DBorder plotBg; + int plotBW; + int xPad; + int yPad; + int plotRelief; + int relief; + ClosestSearch search; + int stackAxes; + const char *takeFocus; // nor used in C code + const char *title; + int reqWidth; + int reqPlotWidth; + int reqPlotHeight; + } LineGraphOptions; + + class LineGraph : public Graph { + public: + LineGraph(ClientData, Tcl_Interp*, int objc, Tcl_Obj* const []); + virtual ~LineGraph(); + + int createElement(int, Tcl_Obj* const []); + int createPen(const char*, int, Tcl_Obj* const []); + }; +}; + +#endif diff --git a/generic/tkbltGraphOp.C b/generic/tkbltGraphOp.C new file mode 100644 index 0000000..ada2758 --- /dev/null +++ b/generic/tkbltGraphOp.C @@ -0,0 +1,462 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1991-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "tkbltGraph.h" +#include "tkbltGraphLine.h" +#include "tkbltGraphBar.h" +#include "tkbltGraphOp.h" + +#include "tkbltGrAxis.h" +#include "tkbltGrAxisOp.h" +#include "tkbltGrElem.h" +#include "tkbltGrElemOp.h" +#include "tkbltGrHairs.h" +#include "tkbltGrHairsOp.h" +#include "tkbltGrLegd.h" +#include "tkbltGrLegdOp.h" +#include "tkbltGrMarker.h" +#include "tkbltGrMarkerOp.h" +#include "tkbltGrPostscript.h" +#include "tkbltGrPostscriptOp.h" +#include "tkbltGrPen.h" +#include "tkbltGrPenOp.h" +#include "tkbltGrXAxisOp.h" + +using namespace Blt; + +static Tcl_ObjCmdProc BarchartObjCmd; +static Tcl_ObjCmdProc GraphObjCmd; + +static Axis* GetFirstAxis(Chain* chain); + +int GraphObjConfigure(Graph* graphPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Tk_SavedOptions savedOptions; + int mask =0; + int error; + Tcl_Obj* errorResult; + + for (error=0; error<=1; error++) { + if (!error) { + if (Tk_SetOptions(interp, (char*)graphPtr->ops_, graphPtr->optionTable_, + objc, objv, graphPtr->tkwin_, &savedOptions, &mask) + != TCL_OK) + continue; + } + else { + errorResult = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); + } + + if (graphPtr->configure() != TCL_OK) + return TCL_ERROR; + graphPtr->flags |= mask; + graphPtr->eventuallyRedraw(); + + break; + } + + if (!error) { + Tk_FreeSavedOptions(&savedOptions); + return TCL_OK; + } + else { + Tcl_SetObjResult(interp, errorResult); + Tcl_DecrRefCount(errorResult); + return TCL_ERROR; + } +} + +static int CgetOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "cget option"); + return TCL_ERROR; + } + Tcl_Obj* objPtr = Tk_GetOptionValue(interp, + (char*)graphPtr->ops_, + graphPtr->optionTable_, + objv[2], graphPtr->tkwin_); + if (objPtr == NULL) + return TCL_ERROR; + else + Tcl_SetObjResult(interp, objPtr); + return TCL_OK; +} + +static int ConfigureOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + if (objc <= 3) { + Tcl_Obj* objPtr = Tk_GetOptionInfo(interp, (char*)graphPtr->ops_, + graphPtr->optionTable_, + (objc == 3) ? objv[2] : NULL, + graphPtr->tkwin_); + if (objPtr == NULL) + return TCL_ERROR; + else + Tcl_SetObjResult(interp, objPtr); + return TCL_OK; + } + else + return GraphObjConfigure(graphPtr, interp, objc-2, objv+2); +} + +/* + *--------------------------------------------------------------------------- + * + * ExtentsOp -- + * + * Reports the size of one of several items within the graph. The + * following are valid items: + * + * "bottommargin" Height of the bottom margin + * "leftmargin" Width of the left margin + * "legend" x y w h of the legend + * "plotarea" x y w h of the plotarea + * "plotheight" Height of the plot area + * "rightmargin" Width of the right margin + * "topmargin" Height of the top margin + * "plotwidth" Width of the plot area + * + * Results: + * Always returns TCL_OK. + * + *--------------------------------------------------------------------------- + */ + +static int ExtentsOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + GraphOptions* ops = (GraphOptions*)graphPtr->ops_; + int length; + const char* string = Tcl_GetStringFromObj(objv[2], &length); + char c = string[0]; + if ((c == 'p') && (length > 4) && + (strncmp("plotheight", string, length) == 0)) { + int height = graphPtr->bottom_ - graphPtr->top_ + 1; + Tcl_SetIntObj(Tcl_GetObjResult(interp), height); + } + else if ((c == 'p') && (length > 4) && + (strncmp("plotwidth", string, length) == 0)) { + int width = graphPtr->right_ - graphPtr->left_ + 1; + Tcl_SetIntObj(Tcl_GetObjResult(interp), width); + } + else if ((c == 'p') && (length > 4) && + (strncmp("plotarea", string, length) == 0)) { + Tcl_Obj* listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewIntObj(graphPtr->left_)); + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewIntObj(graphPtr->top_)); + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewIntObj(graphPtr->right_ - graphPtr->left_+1)); + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewIntObj(graphPtr->bottom_ - graphPtr->top_+1)); + Tcl_SetObjResult(interp, listObjPtr); + } + else if ((c == 'l') && (length > 2) && + (strncmp("legend", string, length) == 0)) { + Tcl_Obj* listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewIntObj(graphPtr->legend_->x_)); + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewIntObj(graphPtr->legend_->y_)); + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewIntObj(graphPtr->legend_->width_)); + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewIntObj(graphPtr->legend_->height_)); + Tcl_SetObjResult(interp, listObjPtr); + } + else if ((c == 'l') && (length > 2) && + (strncmp("leftmargin", string, length) == 0)) { + Tcl_SetIntObj(Tcl_GetObjResult(interp), ops->leftMargin.width); + } + else if ((c == 'r') && (length > 1) && + (strncmp("rightmargin", string, length) == 0)) { + Tcl_SetIntObj(Tcl_GetObjResult(interp), ops->rightMargin.width); + } + else if ((c == 't') && (length > 1) && + (strncmp("topmargin", string, length) == 0)) { + Tcl_SetIntObj(Tcl_GetObjResult(interp), ops->topMargin.height); + } + else if ((c == 'b') && (length > 1) && + (strncmp("bottommargin", string, length) == 0)) { + Tcl_SetIntObj(Tcl_GetObjResult(interp), ops->bottomMargin.height); + } + else { + Tcl_AppendResult(interp, "bad extent item \"", objv[2], + "\": should be plotheight, plotwidth, leftmargin, rightmargin, \ +topmargin, bottommargin, plotarea, or legend", (char*)NULL); + return TCL_ERROR; + } + return TCL_OK; +} + +static int InsideOp(ClientData clientData, Tcl_Interp* interp, int objc, + Tcl_Obj* const objv[]) +{ + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "x y"); + return TCL_ERROR; + } + + Graph* graphPtr = (Graph*)clientData; + + int x; + if (Tcl_GetIntFromObj(interp, objv[2], &x) != TCL_OK) + return TCL_ERROR; + + int y; + if (Tcl_GetIntFromObj(interp, objv[3], &y) != TCL_OK) + return TCL_ERROR; + + Region2d exts; + graphPtr->extents(&exts); + + int result = (x<=exts.right && x>=exts.left && y<=exts.bottom && y>=exts.top); + Tcl_SetBooleanObj(Tcl_GetObjResult(interp), result); + + return TCL_OK; +} + +static int InvtransformOp(ClientData clientData, Tcl_Interp* interp, int objc, + Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + double x, y; + if ((Tcl_GetDoubleFromObj(interp, objv[2], &x) != TCL_OK) || + (Tcl_GetDoubleFromObj(interp, objv[3], &y) != TCL_OK)) + return TCL_ERROR; + + if (graphPtr->flags & RESET) + graphPtr->resetAxes(); + + // Perform the reverse transformation, converting from window coordinates + // to graph data coordinates. Note that the point is always mapped to the + // bottom and left axes (which may not be what the user wants) + Axis* xAxis = GetFirstAxis(graphPtr->axisChain_[0]); + Axis* yAxis = GetFirstAxis(graphPtr->axisChain_[1]); + Point2d point = graphPtr->invMap2D(x, y, xAxis, yAxis); + + Tcl_Obj* listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(point.x)); + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(point.y)); + Tcl_SetObjResult(interp, listObjPtr); + + return TCL_OK; +} + +static int TransformOp(ClientData clientData, Tcl_Interp* interp, int objc, + Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + double x, y; + if ((Tcl_GetDoubleFromObj(interp, objv[2], &x) != TCL_OK) || + (Tcl_GetDoubleFromObj(interp, objv[3], &y) != TCL_OK)) + return TCL_ERROR; + + if (graphPtr->flags & RESET) + graphPtr->resetAxes(); + + // Perform the transformation from window to graph coordinates. Note that + // the points are always mapped onto the bottom and left axes (which may + // not be the what the user wants + Axis* xAxis = GetFirstAxis(graphPtr->axisChain_[0]); + Axis* yAxis = GetFirstAxis(graphPtr->axisChain_[1]); + + Point2d point = graphPtr->map2D(x, y, xAxis, yAxis); + + Tcl_Obj* listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewIntObj((int)point.x)); + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewIntObj((int)point.y)); + Tcl_SetObjResult(interp, listObjPtr); + + return TCL_OK; +} + +static const Ensemble graphEnsemble[] = { + {"axis", 0, Blt::axisEnsemble}, + {"bar", 0, Blt::elementEnsemble}, + {"cget", CgetOp, 0}, + {"configure", ConfigureOp, 0}, + {"crosshairs", 0, Blt::crosshairsEnsemble}, + {"element", 0, Blt::elementEnsemble}, + {"extents", ExtentsOp, 0}, + {"inside", InsideOp, 0}, + {"invtransform",InvtransformOp, 0}, + {"legend", 0, Blt::legendEnsemble}, + {"line", 0, Blt::elementEnsemble}, + {"marker", 0, Blt::markerEnsemble}, + {"pen", 0, Blt::penEnsemble}, + {"postscript", 0, Blt::postscriptEnsemble}, + {"transform", TransformOp, 0}, + {"xaxis", 0, Blt::xaxisEnsemble}, + {"yaxis", 0, Blt::xaxisEnsemble}, + {"x2axis", 0, Blt::xaxisEnsemble}, + {"y2axis", 0, Blt::xaxisEnsemble}, + { 0,0,0 } +}; + +// Support + +static Axis* GetFirstAxis(Chain* chain) +{ + ChainLink* link = Chain_FirstLink(chain); + if (!link) + return NULL; + + return (Axis*)Chain_GetValue(link); +} + +// Tk Interface + +int Blt_GraphCmdInitProc(Tcl_Interp* interp) +{ + Tcl_Namespace* nsPtr = Tcl_FindNamespace(interp, "::blt", NULL, + TCL_LEAVE_ERR_MSG); + if (nsPtr == NULL) + return TCL_ERROR; + + { + const char* cmdPath = "::blt::graph"; + Tcl_Command cmdToken = Tcl_FindCommand(interp, cmdPath, NULL, 0); + if (cmdToken) + return TCL_OK; + cmdToken = Tcl_CreateObjCommand(interp, cmdPath, GraphObjCmd, NULL, NULL); + if (Tcl_Export(interp, nsPtr, "graph", 0) != TCL_OK) + return TCL_ERROR; + } + + { + const char* cmdPath = "::blt::barchart"; + Tcl_Command cmdToken = Tcl_FindCommand(interp, cmdPath, NULL, 0); + if (cmdToken) + return TCL_OK; + cmdToken = Tcl_CreateObjCommand(interp, cmdPath, BarchartObjCmd, NULL,NULL); + if (Tcl_Export(interp, nsPtr, "barchart", 0) != TCL_OK) + return TCL_ERROR; + } + + return TCL_OK; +} + +static int GraphObjCmd(ClientData clientData, Tcl_Interp* interp, int objc, + Tcl_Obj* const objv[]) +{ + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?"); + return TCL_ERROR; + } + + Graph* graphPtr = new LineGraph(clientData, interp, objc, objv); + return graphPtr->valid_ ? TCL_OK : TCL_ERROR; +} + +static int BarchartObjCmd(ClientData clientData, Tcl_Interp* interp, int objc, + Tcl_Obj* const objv[]) +{ + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?"); + return TCL_ERROR; + } + + Graph* graphPtr = new BarGraph(clientData, interp, objc, objv); + return graphPtr->valid_ ? TCL_OK : TCL_ERROR; +} + +int GraphInstCmdProc(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph*)clientData; + Tcl_Preserve(graphPtr); + int result = graphPtr->invoke(graphEnsemble, 1, objc, objv); + Tcl_Release(graphPtr); + return result; +} + +// called by Tcl_DeleteCommand +void GraphInstCmdDeleteProc(ClientData clientData) +{ + Graph* graphPtr = (Graph*)clientData; + if (!(graphPtr->flags & GRAPH_DELETED)) + Tk_DestroyWindow(graphPtr->tkwin_); +} + +void GraphEventProc(ClientData clientData, XEvent* eventPtr) +{ + Graph* graphPtr = (Graph*)clientData; + + if (eventPtr->type == Expose) { + if (eventPtr->xexpose.count == 0) + graphPtr->eventuallyRedraw(); + } + else if (eventPtr->type == FocusIn || eventPtr->type == FocusOut) { + if (eventPtr->xfocus.detail != NotifyInferior) { + if (eventPtr->type == FocusIn) + graphPtr->flags |= FOCUS; + else + graphPtr->flags &= ~FOCUS; + graphPtr->eventuallyRedraw(); + } + } + else if (eventPtr->type == DestroyNotify) { + if (!(graphPtr->flags & GRAPH_DELETED)) { + graphPtr->flags |= GRAPH_DELETED; + Tcl_DeleteCommandFromToken(graphPtr->interp_, graphPtr->cmdToken_); + if (graphPtr->flags & REDRAW_PENDING) + Tcl_CancelIdleCall(DisplayGraph, graphPtr); + Tcl_EventuallyFree(graphPtr, DestroyGraph); + } + } + else if (eventPtr->type == ConfigureNotify) { + graphPtr->flags |= RESET; + graphPtr->eventuallyRedraw(); + } +} + +void DisplayGraph(ClientData clientData) +{ + Graph* graphPtr = (Graph*)clientData; + graphPtr->draw(); +} + +// called by Tcl_EventuallyFree and others +void DestroyGraph(char* dataPtr) +{ + Graph* graphPtr = (Graph*)dataPtr; + delete graphPtr; +} + diff --git a/generic/tkbltGraphOp.h b/generic/tkbltGraphOp.h new file mode 100644 index 0000000..ff3f6ef --- /dev/null +++ b/generic/tkbltGraphOp.h @@ -0,0 +1,44 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1991-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltGraphOp_h__ +#define __BltGraphOp_h__ + +#include + +extern int GraphObjConfigure(Blt::Graph* graphPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]); + +extern Tcl_ObjCmdProc GraphInstCmdProc; +extern Tcl_CmdDeleteProc GraphInstCmdDeleteProc; +extern Tk_EventProc GraphEventProc; +extern Tcl_IdleProc DisplayGraph; +extern Tcl_FreeProc DestroyGraph; + +#endif diff --git a/generic/tkbltGraphSup.C b/generic/tkbltGraphSup.C new file mode 100644 index 0000000..d5eb3d1 --- /dev/null +++ b/generic/tkbltGraphSup.C @@ -0,0 +1,686 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#include + +#include "tkbltGraph.h" +#include "tkbltGrAxis.h" +#include "tkbltGrElem.h" +#include "tkbltGrLegd.h" +#include "tkbltGrMisc.h" + +using namespace Blt; + +#define AXIS_PAD_TITLE 2 +#define ROTATE_0 0 +#define ROTATE_90 1 +#define ROTATE_180 2 +#define ROTATE_270 3 + +/* + *--------------------------------------------------------------------------- + * + * layoutGraph -- + * + * Calculate the layout of the graph. Based upon the data, axis limits, + * X and Y titles, and title height, determine the cavity left which is + * the plotting surface. The first step get the data and axis limits for + * calculating the space needed for the top, bottom, left, and right + * margins. + * + * 1) The LEFT margin is the area from the left border to the Y axis + * (not including ticks). It composes the border width, the width an + * optional Y axis label and its padding, and the tick numeric labels. + * The Y axis label is rotated 90 degrees so that the width is the + * font height. + * + * 2) The RIGHT margin is the area from the end of the graph + * to the right window border. It composes the border width, + * some padding, the font height (this may be dubious. It + * appears to provide a more even border), the max of the + * legend width and 1/2 max X tick number. This last part is + * so that the last tick label is not clipped. + * + * Window Width + * ___________________________________________________________ + * | | | | + * | | TOP height of title | | + * | | | | + * | | x2 title | | + * | | | | + * | | height of x2-axis | | + * |__________|_______________________________|_______________| W + * | | -plotpady | | i + * |__________|_______________________________|_______________| n + * | | top right | | d + * | | | | o + * | LEFT | | RIGHT | w + * | | | | + * | y | Free area = 104% | y2 | H + * | | Plotting surface = 100% | | e + * | t | Tick length = 2 + 2% | t | i + * | i | | i | g + * | t | | t legend| h + * | l | | l width| t + * | e | | e | + * | height| |height | + * | of | | of | + * | y-axis| |y2-axis | + * | | | | + * | |origin 0,0 | | + * |__________|_left_________________bottom___|_______________| + * | |-plotpady | | + * |__________|_______________________________|_______________| + * | | (xoffset, yoffset) | | + * | | | | + * | | height of x-axis | | + * | | | | + * | | BOTTOM x title | | + * |__________|_______________________________|_______________| + * + * 3) The TOP margin is the area from the top window border to the top + * of the graph. It composes the border width, twice the height of + * the title font (if one is given) and some padding between the + * title. + * + * 4) The BOTTOM margin is area from the bottom window border to the + * X axis (not including ticks). It composes the border width, the height + * an optional X axis label and its padding, the height of the font + * of the tick labels. + * + * The plotting area is between the margins which includes the X and Y axes + * including the ticks but not the tick numeric labels. The length of the + * ticks and its padding is 5% of the entire plotting area. Hence the entire + * plotting area is scaled as 105% of the width and height of the area. + * + * The axis labels, ticks labels, title, and legend may or may not be + * displayed which must be taken into account. + * + * if reqWidth > 0 : set outer size + * if reqPlotWidth > 0 : set plot size + *--------------------------------------------------------------------------- + */ + +void Graph::layoutGraph() +{ + GraphOptions* ops = (GraphOptions*)ops_; + + int width = width_; + int height = height_; + + // Step 1 + // Compute the amount of space needed to display the axes + // associated with each margin. They can be overridden by + // -leftmargin, -rightmargin, -bottommargin, and -topmargin + // graph options, respectively. + int left = getMarginGeometry(&ops->leftMargin); + int right = getMarginGeometry(&ops->rightMargin); + int top = getMarginGeometry(&ops->topMargin); + int bottom = getMarginGeometry(&ops->bottomMargin); + + int pad = ops->bottomMargin.maxTickWidth; + if (pad < ops->topMargin.maxTickWidth) + pad = ops->topMargin.maxTickWidth; + + pad = pad / 2 + 3; + if (right < pad) + right = pad; + + if (left < pad) + left = pad; + + pad = ops->leftMargin.maxTickHeight; + if (pad < ops->rightMargin.maxTickHeight) + pad = ops->rightMargin.maxTickHeight; + + pad = pad / 2; + if (top < pad) + top = pad; + + if (bottom < pad) + bottom = pad; + + if (ops->leftMargin.reqSize > 0) + left = ops->leftMargin.reqSize; + + if (ops->rightMargin.reqSize > 0) + right = ops->rightMargin.reqSize; + + if (ops->topMargin.reqSize > 0) + top = ops->topMargin.reqSize; + + if (ops->bottomMargin.reqSize > 0) + bottom = ops->bottomMargin.reqSize; + + // Step 2 + // Add the graph title height to the top margin. + if (ops->title) + top += titleHeight_ + 6; + + int inset = (inset_ + ops->plotBW); + int inset2 = 2 * inset; + + // Step 3 + // Estimate the size of the plot area from the remaining + // space. This may be overridden by the -plotwidth and + // -plotheight graph options. We use this to compute the + // size of the legend. + if (width == 0) + width = 400; + + if (height == 0) + height = 400; + + int plotWidth = (ops->reqPlotWidth > 0) ? ops->reqPlotWidth : + width - (inset2 + left + right); + int plotHeight = (ops->reqPlotHeight > 0) ? ops->reqPlotHeight : + height - (inset2 + top + bottom); + legend_->map(plotWidth, plotHeight); + + // Step 4 + // Add the legend to the appropiate margin. + if (!legend_->isHidden()) { + switch (legend_->position()) { + case Legend::RIGHT: + right += legend_->width_ + 2; + break; + case Legend::LEFT: + left += legend_->width_ + 2; + break; + case Legend::TOP: + top += legend_->height_ + 2; + break; + case Legend::BOTTOM: + bottom += legend_->height_ + 2; + break; + case Legend::XY: + case Legend::PLOT: + break; + } + } + + // Recompute the plotarea or graph size, now accounting for the legend. + if (ops->reqPlotWidth == 0) { + plotWidth = width - (inset2 + left + right); + if (plotWidth < 1) + plotWidth = 1; + } + if (ops->reqPlotHeight == 0) { + plotHeight = height - (inset2 + top + bottom); + if (plotHeight < 1) + plotHeight = 1; + } + + // Step 5 + // If necessary, correct for the requested plot area aspect ratio. + if ((ops->reqPlotWidth == 0) && (ops->reqPlotHeight == 0) && + (ops->aspect > 0.0)) { + double ratio; + + // Shrink one dimension of the plotarea to fit the requested + // width/height aspect ratio. + ratio = plotWidth / plotHeight; + if (ratio > ops->aspect) { + // Shrink the width + int scaledWidth = (int)(plotHeight * ops->aspect); + if (scaledWidth < 1) + scaledWidth = 1; + + // Add the difference to the right margin. + // CHECK THIS: w = scaledWidth + right += (plotWidth - scaledWidth); + } + else { + // Shrink the height + int scaledHeight = (int)(plotWidth / ops->aspect); + if (scaledHeight < 1) + scaledHeight = 1; + + // Add the difference to the top margin + // CHECK THIS: h = scaledHeight; + top += (plotHeight - scaledHeight); + } + } + + // Step 6 + // If there's multiple axes in a margin, the axis titles will be + // displayed in the adjoining margins. Make sure there's room + // for the longest axis titles. + if (top < ops->leftMargin.axesTitleLength) + top = ops->leftMargin.axesTitleLength; + + if (right < ops->bottomMargin.axesTitleLength) + right = ops->bottomMargin.axesTitleLength; + + if (top < ops->rightMargin.axesTitleLength) + top = ops->rightMargin.axesTitleLength; + + if (right < ops->topMargin.axesTitleLength) + right = ops->topMargin.axesTitleLength; + + // Step 7 + // Override calculated values with requested margin sizes. + if (ops->leftMargin.reqSize > 0) + left = ops->leftMargin.reqSize; + + if (ops->rightMargin.reqSize > 0) + right = ops->rightMargin.reqSize; + + if (ops->topMargin.reqSize > 0) + top = ops->topMargin.reqSize; + + if (ops->bottomMargin.reqSize > 0) + bottom = ops->bottomMargin.reqSize; + + if (ops->reqPlotWidth > 0) { + // Width of plotarea is constained. If there's extra space, add it to + // the left and/or right margins. If there's too little, grow the + // graph width to accomodate it. + int w = plotWidth + inset2 + left + right; + + // Extra space in window + if (width > w) { + int extra = (width - w) / 2; + if (ops->leftMargin.reqSize == 0) { + left += extra; + if (ops->rightMargin.reqSize == 0) + right += extra; + else + left += extra; + } + else if (ops->rightMargin.reqSize == 0) + right += extra + extra; + } + else if (width < w) + width = w; + } + + // Constrain the plotarea height + if (ops->reqPlotHeight > 0) { + + // Height of plotarea is constained. If there's extra space, + // add it to th top and/or bottom margins. If there's too little, + // grow the graph height to accomodate it. + int h = plotHeight + inset2 + top + bottom; + + // Extra space in window + if (height > h) { + int extra = (height - h) / 2; + if (ops->topMargin.reqSize == 0) { + top += extra; + if (ops->bottomMargin.reqSize == 0) + bottom += extra; + else + top += extra; + } + else if (ops->bottomMargin.reqSize == 0) + bottom += extra + extra; + } + else if (height < h) + height = h; + } + + width_ = width; + height_ = height; + left_ = left + inset; + top_ = top + inset; + right_ = width - right - inset; + bottom_ = height - bottom - inset; + + ops->leftMargin.width = left + inset_; + ops->rightMargin.width = right + inset_; + ops->topMargin.height = top + inset_; + ops->bottomMargin.height = bottom + inset_; + + vOffset_ = top_ + ops->yPad; + vRange_ = plotHeight - 2*ops->yPad; + hOffset_ = left_ + ops->xPad; + hRange_ = plotWidth - 2*ops->xPad; + + if (vRange_ < 1) + vRange_ = 1; + + if (hRange_ < 1) + hRange_ = 1; + + hScale_ = 1.0 / hRange_; + vScale_ = 1.0 / vRange_; + + // Calculate the placement of the graph title so it is centered within the + // space provided for it in the top margin + titleY_ = 3 + inset_; + titleX_ = (right_ + left_) / 2; +} + +int Graph::getMarginGeometry(Margin *marginPtr) +{ + GraphOptions* ops = (GraphOptions*)ops_; + int isHoriz = !(marginPtr->site & 0x1); /* Even sites are horizontal */ + + // Count the visible axes. + unsigned int nVisible = 0; + unsigned int l =0; + int w =0; + int h =0; + + marginPtr->maxTickWidth =0; + marginPtr->maxTickHeight =0; + + if (ops->stackAxes) { + for (ChainLink* link = Chain_FirstLink(marginPtr->axes); link; + link = Chain_NextLink(link)) { + Axis* axisPtr = (Axis*)Chain_GetValue(link); + AxisOptions* ops = (AxisOptions*)axisPtr->ops(); + if (!ops->hide && axisPtr->use_) { + nVisible++; + axisPtr->getGeometry(); + + if (isHoriz) { + if (h < axisPtr->height_) + h = axisPtr->height_; + } + else { + if (w < axisPtr->width_) + w = axisPtr->width_; + } + if (axisPtr->maxTickWidth_ > marginPtr->maxTickWidth) + marginPtr->maxTickWidth = axisPtr->maxTickWidth_; + + if (axisPtr->maxTickHeight_ > marginPtr->maxTickHeight) + marginPtr->maxTickHeight = axisPtr->maxTickHeight_; + } + } + } + else { + for (ChainLink* link = Chain_FirstLink(marginPtr->axes); link; + link = Chain_NextLink(link)) { + Axis* axisPtr = (Axis*)Chain_GetValue(link); + AxisOptions* ops = (AxisOptions*)axisPtr->ops(); + if (!ops->hide && axisPtr->use_) { + nVisible++; + axisPtr->getGeometry(); + + if ((ops->titleAlternate) && (l < axisPtr->titleWidth_)) + l = axisPtr->titleWidth_; + + if (isHoriz) + h += axisPtr->height_; + else + w += axisPtr->width_; + + if (axisPtr->maxTickWidth_ > marginPtr->maxTickWidth) + marginPtr->maxTickWidth = axisPtr->maxTickWidth_; + + if (axisPtr->maxTickHeight_ > marginPtr->maxTickHeight) + marginPtr->maxTickHeight = axisPtr->maxTickHeight_; + } + } + } + // Enforce a minimum size for margins. + if (w < 3) + w = 3; + + if (h < 3) + h = 3; + + marginPtr->nAxes = nVisible; + marginPtr->axesTitleLength = l; + marginPtr->width = w; + marginPtr->height = h; + marginPtr->axesOffset = (isHoriz) ? h : w; + return marginPtr->axesOffset; +} + +void Graph::getTextExtents(Tk_Font font, const char *text, int textLen, + int* ww, int* hh) +{ + if (!text) { + *ww =0; + *hh =0; + return; + } + + Tk_FontMetrics fm; + Tk_GetFontMetrics(font, &fm); + int lineHeight = fm.linespace; + + if (textLen < 0) + textLen = strlen(text); + + int maxWidth =0; + int maxHeight =0; + int lineLen =0; + const char *line =NULL; + const char *p, *pend; + for (p =line=text, pend=text+textLen; p 0) { + int lineWidth = Tk_TextWidth(font, line, lineLen); + if (lineWidth > maxWidth) + maxWidth = lineWidth; + } + maxHeight += lineHeight; + line = p + 1; /* Point to the start of the next line. */ + lineLen = 0; /* Reset counter to indicate the start of a + * new line. */ + continue; + } + lineLen++; + } + + if ((lineLen > 0) && (*(p - 1) != '\n')) { + maxHeight += lineHeight; + int lineWidth = Tk_TextWidth(font, line, lineLen); + if (lineWidth > maxWidth) + maxWidth = lineWidth; + } + + *ww = maxWidth; + *hh = maxHeight; +} + +/* + *--------------------------------------------------------------------------- + * + * Computes the dimensions of the bounding box surrounding a rectangle + * rotated about its center. If pointArr isn't NULL, the coordinates of + * the rotated rectangle are also returned. + * + * The dimensions are determined by rotating the rectangle, and doubling + * the maximum x-coordinate and y-coordinate. + * + * w = 2 * maxX, h = 2 * maxY + * + * Since the rectangle is centered at 0,0, the coordinates of the + * bounding box are (-w/2,-h/2 w/2,-h/2, w/2,h/2 -w/2,h/2). + * + * 0 ------- 1 + * | | + * | x | + * | | + * 3 ------- 2 + * + * Results: + * The width and height of the bounding box containing the rotated + * rectangle are returned. + * + *--------------------------------------------------------------------------- + */ +void Graph::getBoundingBox(int width, int height, double angle, + double *rotWidthPtr, double *rotHeightPtr, + Point2d *bbox) +{ + angle = fmod(angle, 360.0); + if (fmod(angle, 90.0) == 0.0) { + int ll, ur, ul, lr; + double rotWidth, rotHeight; + + // Handle right-angle rotations specially + int quadrant = (int)(angle / 90.0); + switch (quadrant) { + case ROTATE_270: + ul = 3, ur = 0, lr = 1, ll = 2; + rotWidth = (double)height; + rotHeight = (double)width; + break; + case ROTATE_90: + ul = 1, ur = 2, lr = 3, ll = 0; + rotWidth = (double)height; + rotHeight = (double)width; + break; + case ROTATE_180: + ul = 2, ur = 3, lr = 0, ll = 1; + rotWidth = (double)width; + rotHeight = (double)height; + break; + default: + case ROTATE_0: + ul = 0, ur = 1, lr = 2, ll = 3; + rotWidth = (double)width; + rotHeight = (double)height; + break; + } + if (bbox) { + double x = rotWidth * 0.5; + double y = rotHeight * 0.5; + bbox[ll].x = bbox[ul].x = -x; + bbox[ur].y = bbox[ul].y = -y; + bbox[lr].x = bbox[ur].x = x; + bbox[ll].y = bbox[lr].y = y; + } + *rotWidthPtr = rotWidth; + *rotHeightPtr = rotHeight; + return; + } + + // Set the four corners of the rectangle whose center is the origin + Point2d corner[4]; + corner[1].x = corner[2].x = (double)width * 0.5; + corner[0].x = corner[3].x = -corner[1].x; + corner[2].y = corner[3].y = (double)height * 0.5; + corner[0].y = corner[1].y = -corner[2].y; + + double radians = (-angle / 180.0) * M_PI; + double sinTheta = sin(radians); + double cosTheta = cos(radians); + double xMax =0; + double yMax =0; + + // Rotate the four corners and find the maximum X and Y coordinates + for (int ii=0; ii<4; ii++) { + double x = (corner[ii].x * cosTheta) - (corner[ii].y * sinTheta); + double y = (corner[ii].x * sinTheta) + (corner[ii].y * cosTheta); + if (x > xMax) + xMax = x; + + if (y > yMax) + yMax = y; + + if (bbox) { + bbox[ii].x = x; + bbox[ii].y = y; + } + } + + // By symmetry, the width and height of the bounding box are twice the + // maximum x and y coordinates. + *rotWidthPtr = xMax + xMax; + *rotHeightPtr = yMax + yMax; +} + +/* + *--------------------------------------------------------------------------- + * + * Blt_AnchorPoint -- + * + * Translates a position, using both the dimensions of the bounding box, + * and the anchor direction, returning the coordinates of the upper-left + * corner of the box. The anchor indicates where the given x-y position + * is in relation to the bounding box. + * + * 7 nw --- 0 n --- 1 ne + * | | + * 6 w 8 center 2 e + * | | + * 5 sw --- 4 s --- 3 se + * + * The coordinates returned are translated to the origin of the bounding + * box (suitable for giving to XCopyArea, XCopyPlane, etc.) + * + * Results: + * The translated coordinates of the bounding box are returned. + * + *--------------------------------------------------------------------------- + */ +Point2d Graph::anchorPoint(double x, double y, double w, double h, + Tk_Anchor anchor) +{ + Point2d t; + + switch (anchor) { + case TK_ANCHOR_NW: /* 7 Upper left corner */ + break; + case TK_ANCHOR_W: /* 6 Left center */ + y -= (h * 0.5); + break; + case TK_ANCHOR_SW: /* 5 Lower left corner */ + y -= h; + break; + case TK_ANCHOR_N: /* 0 Top center */ + x -= (w * 0.5); + break; + case TK_ANCHOR_CENTER: /* 8 Center */ + x -= (w * 0.5); + y -= (h * 0.5); + break; + case TK_ANCHOR_S: /* 4 Bottom center */ + x -= (w * 0.5); + y -= h; + break; + case TK_ANCHOR_NE: /* 1 Upper right corner */ + x -= w; + break; + case TK_ANCHOR_E: /* 2 Right center */ + x -= w; + y -= (h * 0.5); + break; + case TK_ANCHOR_SE: /* 3 Lower right corner */ + x -= w; + y -= h; + break; + } + + t.x = x; + t.y = y; + return t; +} + diff --git a/generic/tkbltInt.C b/generic/tkbltInt.C new file mode 100644 index 0000000..3f9c3ac --- /dev/null +++ b/generic/tkbltInt.C @@ -0,0 +1,74 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1991-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +using namespace std; + +extern "C" { +DLLEXPORT Tcl_AppInitProc Tkblt_Init; +DLLEXPORT Tcl_AppInitProc Tkblt_SafeInit; +}; + +Tcl_AppInitProc Blt_VectorCmdInitProc; +Tcl_AppInitProc Blt_GraphCmdInitProc; + +#include "tkbltStubInit.c" + +DLLEXPORT int Tkblt_Init(Tcl_Interp* interp) +{ + Tcl_Namespace *nsPtr; + + if (Tcl_InitStubs(interp, TCL_PATCH_LEVEL, 0) == NULL) + return TCL_ERROR; + if (Tk_InitStubs(interp, TK_PATCH_LEVEL, 0) == NULL) + return TCL_ERROR; + + nsPtr = Tcl_FindNamespace(interp, "::blt", (Tcl_Namespace *)NULL, 0); + if (nsPtr == NULL) { + nsPtr = Tcl_CreateNamespace(interp, "::blt", NULL, NULL); + if (nsPtr == NULL) + return TCL_ERROR; + } + + if (Blt_VectorCmdInitProc(interp) != TCL_OK) + return TCL_ERROR; + if (Blt_GraphCmdInitProc(interp) != TCL_OK) + return TCL_ERROR; + + if (Tcl_PkgProvideEx(interp, PACKAGE_NAME, PACKAGE_VERSION, (ClientData)&tkbltStubs) != TCL_OK) + return TCL_ERROR; + + return TCL_OK; +} + +DLLEXPORT int Tkblt_SafeInit(Tcl_Interp* interp) +{ + return Tkblt_Init(interp); +} diff --git a/generic/tkbltInt.h b/generic/tkbltInt.h new file mode 100644 index 0000000..2bf96ee --- /dev/null +++ b/generic/tkbltInt.h @@ -0,0 +1,58 @@ +/* + * Copyright 2017 Patzschke+Rasp Software GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __TKBLT_INT_H__ + +#if defined(_MSC_VER) + +#include + +#if !defined(NAN) +#define NAN (std::numeric_limits::quiet_NaN()) +#endif + +#if !defined(isnan) +#define isnan(x) _isnan(x) +#endif + +#if !defined(isfinite) +#define isfinite(x) _finite(x) +#endif + +#if !defined(isinf) +#define isinf(x) !_finite(x) +#endif + +#if !defined(numeric_limits) +#define numeric_limits(x) _numeric_limits(x) +#endif + +#if _MSC_VER < 1900 +#define snprintf _snprintf +#else +#include //sprintf +#endif + +#endif /* _MSC_VER */ + +#endif /* __TKBLT_INT_H__ */ diff --git a/generic/tkbltNsUtil.C b/generic/tkbltNsUtil.C new file mode 100644 index 0000000..f2ecfa3 --- /dev/null +++ b/generic/tkbltNsUtil.C @@ -0,0 +1,129 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1997-2008 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifdef __CYGWIN__ +extern "C" { +#include +} +#else +#include +#endif + +#include "tkbltNsUtil.h" + +using namespace Blt; + +Tcl_Namespace* Blt::GetCommandNamespace(Tcl_Command cmdToken) +{ + Command* cmdPtr = (Command*)cmdToken; + return (Tcl_Namespace *)cmdPtr->nsPtr; +} + +int Blt::ParseObjectName(Tcl_Interp* interp, const char *path, + Blt_ObjectName *namePtr, unsigned int flags) +{ + namePtr->nsPtr = NULL; + namePtr->name = NULL; + char* colon = NULL; + + /* Find the last namespace separator in the qualified name. */ + char* last = (char *)(path + strlen(path)); + while (--last > path) { + if ((*last == ':') && (*(last - 1) == ':')) { + last++; /* just after the last "::" */ + colon = last - 2; + break; + } + } + if (colon == NULL) { + namePtr->name = path; + if ((flags & BLT_NO_DEFAULT_NS) == 0) { + namePtr->nsPtr = Tcl_GetCurrentNamespace(interp); + } + return 1; /* No namespace designated in name. */ + } + + /* Separate the namespace and the object name. */ + *colon = '\0'; + if (path[0] == '\0') { + namePtr->nsPtr = Tcl_GetGlobalNamespace(interp); + } else { + namePtr->nsPtr = Tcl_FindNamespace(interp, (char *)path, NULL, + (flags & BLT_NO_ERROR_MSG) ? 0 : TCL_LEAVE_ERR_MSG); + } + /* Repair the string. */ *colon = ':'; + + if (namePtr->nsPtr == NULL) { + return 0; /* Namespace doesn't exist. */ + } + namePtr->name =last; + return 1; +} + +char* Blt::MakeQualifiedName(Blt_ObjectName *namePtr, Tcl_DString *resultPtr) +{ + Tcl_DStringInit(resultPtr); + if ((namePtr->nsPtr->fullName[0] != ':') || + (namePtr->nsPtr->fullName[1] != ':') || + (namePtr->nsPtr->fullName[2] != '\0')) { + Tcl_DStringAppend(resultPtr, namePtr->nsPtr->fullName, -1); + } + Tcl_DStringAppend(resultPtr, "::", -1); + Tcl_DStringAppend(resultPtr, (char *)namePtr->name, -1); + return Tcl_DStringValue(resultPtr); +} + +static Tcl_Namespace* NamespaceOfVariable(Var *varPtr) +{ + if (varPtr->flags & VAR_IN_HASHTABLE) { + VarInHash *vhashPtr = (VarInHash *)varPtr; + TclVarHashTable *vtablePtr; + + vtablePtr = (TclVarHashTable *)vhashPtr->entry.tablePtr; + return (Tcl_Namespace*)(vtablePtr->nsPtr); + } + return NULL; +} + +Tcl_Namespace* Blt::GetVariableNamespace(Tcl_Interp* interp, const char *path) +{ + Blt_ObjectName objName; + if (!ParseObjectName(interp, path, &objName, BLT_NO_DEFAULT_NS)) + return NULL; + + if (objName.nsPtr == NULL) { + Var*varPtr = (Var*)Tcl_FindNamespaceVar(interp, (char *)path, + (Tcl_Namespace *)NULL, + TCL_GLOBAL_ONLY); + if (varPtr) + return NamespaceOfVariable(varPtr); + + } + return objName.nsPtr; +} diff --git a/generic/tkbltNsUtil.h b/generic/tkbltNsUtil.h new file mode 100644 index 0000000..950a48a --- /dev/null +++ b/generic/tkbltNsUtil.h @@ -0,0 +1,64 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef BLT_NS_UTIL_H +#define BLT_NS_UTIL_H 1 + +#define NS_SEARCH_NONE (0) +#define NS_SEARCH_CURRENT (1<<0) +#define NS_SEARCH_GLOBAL (1<<1) +#define NS_SEARCH_BOTH (NS_SEARCH_GLOBAL | NS_SEARCH_CURRENT) + +#define BLT_NO_DEFAULT_NS (1<<0) +#define BLT_NO_ERROR_MSG (1<<1) + +namespace Blt { + + typedef struct { + const char *name; + Tcl_Namespace *nsPtr; + } Blt_ObjectName; + + extern Tcl_Namespace* GetVariableNamespace(Tcl_Interp* interp, + const char *varName); + + extern Tcl_Namespace* GetCommandNamespace(Tcl_Command cmdToken); + + extern int ParseObjectName(Tcl_Interp* interp, const char *name, + Blt_ObjectName *objNamePtr, + unsigned int flags); + + extern char* MakeQualifiedName(Blt_ObjectName *objNamePtr, + Tcl_DString *resultPtr); +}; + +#endif /* BLT_NS_UTIL_H */ diff --git a/generic/tkbltOp.C b/generic/tkbltOp.C new file mode 100644 index 0000000..4199a44 --- /dev/null +++ b/generic/tkbltOp.C @@ -0,0 +1,171 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1991-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "tkbltOp.h" + +using namespace Blt; + +static int BinaryOpSearch(Blt_OpSpec *specs, int nSpecs, const char *string, + int length) +{ + int low = 0; + int high = nSpecs - 1; + char c = string[0]; + while (low <= high) { + int median = (low + high) >> 1; + Blt_OpSpec *specPtr = specs + median; + + /* Test the first character */ + int compare = c - specPtr->name[0]; + if (compare == 0) { + /* Now test the entire string */ + compare = strncmp(string, specPtr->name, length); + if (compare == 0) { + if ((int)length < specPtr->minChars) { + return -2; /* Ambiguous operation name */ + } + } + } + if (compare < 0) { + high = median - 1; + } else if (compare > 0) { + low = median + 1; + } else { + return median; /* Op found. */ + } + } + return -1; /* Can't find operation */ +} + +static int LinearOpSearch(Blt_OpSpec *specs, int nSpecs, const char *string, + int length) +{ + char c = string[0]; + int nMatches = 0; + int last = -1; + int i =0; + for (Blt_OpSpec *specPtr = specs; iname[0]) && + (strncmp(string, specPtr->name, length) == 0)) { + last = i; + nMatches++; + if ((int)length == specPtr->minChars) { + break; + } + } + } + if (nMatches > 1) + return -2; /* Ambiguous operation name */ + + if (nMatches == 0) + return -1; /* Can't find operation */ + + return last; /* Op found. */ +} + +void* Blt::GetOpFromObj(Tcl_Interp* interp, int nSpecs, Blt_OpSpec *specs, + int operPos, int objc, Tcl_Obj* const objv[], + int flags) +{ + Blt_OpSpec *specPtr; + int n; + + if (objc <= operPos) { /* No operation argument */ + Tcl_AppendResult(interp, "wrong # args: ", (char *)NULL); + usage: + Tcl_AppendResult(interp, "should be one of...", (char *)NULL); + for (n = 0; n < nSpecs; n++) { + Tcl_AppendResult(interp, "\n ", (char *)NULL); + for (int ii = 0; ii < operPos; ii++) { + Tcl_AppendResult(interp, Tcl_GetString(objv[ii]), " ", + (char *)NULL); + } + specPtr = specs + n; + Tcl_AppendResult(interp, specPtr->name, " ", specPtr->usage, + (char *)NULL); + } + return NULL; + } + + int length; + const char* string = Tcl_GetStringFromObj(objv[operPos], &length); + if (flags & BLT_OP_LINEAR_SEARCH) + n = LinearOpSearch(specs, nSpecs, string, length); + else + n = BinaryOpSearch(specs, nSpecs, string, length); + + if (n == -2) { + char c; + + Tcl_AppendResult(interp, "ambiguous", (char *)NULL); + if (operPos > 2) { + Tcl_AppendResult(interp, " ", Tcl_GetString(objv[operPos - 1]), + (char *)NULL); + } + Tcl_AppendResult(interp, " operation \"", string, "\" matches: ", + (char *)NULL); + + c = string[0]; + for (n = 0; n < nSpecs; n++) { + specPtr = specs + n; + if ((c == specPtr->name[0]) && + (strncmp(string, specPtr->name, length) == 0)) { + Tcl_AppendResult(interp, " ", specPtr->name, (char *)NULL); + } + } + return NULL; + + } else if (n == -1) { /* Can't find operation, display help */ + Tcl_AppendResult(interp, "bad", (char *)NULL); + if (operPos > 2) { + Tcl_AppendResult(interp, " ", Tcl_GetString(objv[operPos - 1]), + (char *)NULL); + } + Tcl_AppendResult(interp, " operation \"", string, "\": ", (char *)NULL); + goto usage; + } + specPtr = specs + n; + if ((objc < specPtr->minArgs) || + ((specPtr->maxArgs > 0) && (objc > specPtr->maxArgs))) { + int i; + + Tcl_AppendResult(interp, "wrong # args: should be \"", (char *)NULL); + for (i = 0; i < operPos; i++) { + Tcl_AppendResult(interp, Tcl_GetString(objv[i]), " ", + (char *)NULL); + } + Tcl_AppendResult(interp, specPtr->name, " ", specPtr->usage, "\"", + (char *)NULL); + return NULL; + } + return specPtr->proc; +} + diff --git a/generic/tkbltOp.h b/generic/tkbltOp.h new file mode 100644 index 0000000..fc9ffb7 --- /dev/null +++ b/generic/tkbltOp.h @@ -0,0 +1,67 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BltOp_h__ +#define __BltOp_h__ + +#include + +#define BLT_OP_BINARY_SEARCH 0 +#define BLT_OP_LINEAR_SEARCH 1 + +namespace Blt { + + typedef struct { + const char *name; /* Name of operation */ + int minChars; /* Minimum # characters to disambiguate */ + void *proc; + int minArgs; /* Minimum # args required */ + int maxArgs; /* Maximum # args required */ + const char *usage; /* Usage message */ + } Blt_OpSpec; + + typedef enum { + BLT_OP_ARG0, /* Op is the first argument. */ + BLT_OP_ARG1, /* Op is the second argument. */ + BLT_OP_ARG2, /* Op is the third argument. */ + BLT_OP_ARG3, /* Op is the fourth argument. */ + BLT_OP_ARG4 /* Op is the fifth argument. */ + + } Blt_OpIndex; + + void *GetOpFromObj(Tcl_Interp* interp, int nSpecs, + Blt_OpSpec *specs, int operPos, int objc, + Tcl_Obj* const objv[], int flags); +}; + +#endif + diff --git a/generic/tkbltParse.C b/generic/tkbltParse.C new file mode 100644 index 0000000..095b16a --- /dev/null +++ b/generic/tkbltParse.C @@ -0,0 +1,388 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * + * This file is copied from tclParse.c in the TCL library distribution. + * + * Copyright (c) 1987-1993 The Regents of the University of + * California. + * + * Copyright (c) 1994-1998 Sun Microsystems, Inc. + * + */ + +/* + * Since TCL 8.1.0 these routines have been replaced by ones that + * generate byte-codes. But since these routines are used in vector + * expressions, where no such byte-compilation is necessary, I now + * include them. In fact, the byte-compiled versions would be slower + * since the compiled code typically runs only one time. + */ + +#include +#include + +#include +#include +#include +using namespace std; + +#include + +#include "tkbltParse.h" + +using namespace Blt; + +/* + * A table used to classify input characters to assist in parsing + * TCL commands. The table should be indexed with a signed character + * using the CHAR_TYPE macro. The character may have a negative + * value. The CHAR_TYPE macro takes a pointer to a signed character + * and a pointer to the last character in the source string. If the + * src pointer is pointing at the terminating null of the string, + * CHAR_TYPE returns TCL_COMMAND_END. + */ + +#define STATIC_STRING_SPACE 150 +#define TCL_NORMAL 0x01 +#define TCL_SPACE 0x02 +#define TCL_COMMAND_END 0x04 +#define TCL_QUOTE 0x08 +#define TCL_OPEN_BRACKET 0x10 +#define TCL_OPEN_BRACE 0x20 +#define TCL_CLOSE_BRACE 0x40 +#define TCL_BACKSLASH 0x80 +#define TCL_DOLLAR 0x00 + +/* + * The following table assigns a type to each character. Only types + * meaningful to TCL parsing are represented here. The table is + * designed to be referenced with either signed or unsigned characters, + * so it has 384 entries. The first 128 entries correspond to negative + * character values, the next 256 correspond to positive character + * values. The last 128 entries are identical to the first 128. The + * table is always indexed with a 128-byte offset (the 128th entry + * corresponds to a 0 character value). + */ + +static unsigned char tclTypeTable[] = +{ + /* + * Negative character values, from -128 to -1: + */ + + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + + /* + * Positive character values, from 0-127: + */ + + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_SPACE, TCL_COMMAND_END, TCL_SPACE, + TCL_SPACE, TCL_SPACE, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_SPACE, TCL_NORMAL, TCL_QUOTE, TCL_NORMAL, + TCL_DOLLAR, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_COMMAND_END, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_OPEN_BRACKET, + TCL_BACKSLASH, TCL_COMMAND_END, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_OPEN_BRACE, + TCL_NORMAL, TCL_CLOSE_BRACE, TCL_NORMAL, TCL_NORMAL, + + /* + * Large unsigned character values, from 128-255: + */ + + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, +}; + +#define CHAR_TYPE(src,last) \ + (((src)==(last))?TCL_COMMAND_END:(tclTypeTable+128)[(int)*(src)]) + +int Blt::ParseNestedCmd(Tcl_Interp* interp, const char *string, + int flags, const char **termPtr, ParseValue *parsePtr) + +{ + return TCL_ERROR; +} + +int Blt::ParseBraces(Tcl_Interp* interp, const char *string, + const char **termPtr, ParseValue *parsePtr) +{ + int level; + const char *src; + char *dest, *end; + char c; + const char *lastChar = string + strlen(string); + + src = string; + dest = parsePtr->next; + end = parsePtr->end; + level = 1; + + /* + * Copy the characters one at a time to the result area, stopping + * when the matching close-brace is found. + */ + + for (;;) { + c = *src; + src++; + + if (dest == end) { + parsePtr->next = dest; + (*parsePtr->expandProc) (parsePtr, 20); + dest = parsePtr->next; + end = parsePtr->end; + } + *dest = c; + dest++; + + if (CHAR_TYPE(src - 1, lastChar) == TCL_NORMAL) { + continue; + } else if (c == '{') { + level++; + } else if (c == '}') { + level--; + if (level == 0) { + dest--; /* Don't copy the last close brace. */ + break; + } + } else if (c == '\\') { + int count; + + /* + * Must always squish out backslash-newlines, even when in + * braces. This is needed so that this sequence can appear + * anywhere in a command, such as the middle of an expression. + */ + + if (*src == '\n') { + dest[-1] = Tcl_Backslash(src - 1, &count); + src += count - 1; + } else { + Tcl_Backslash(src - 1, &count); + while (count > 1) { + if (dest == end) { + parsePtr->next = dest; + (*parsePtr->expandProc) (parsePtr, 20); + dest = parsePtr->next; + end = parsePtr->end; + } + *dest = *src; + dest++; + src++; + count--; + } + } + } else if (c == '\0') { + Tcl_AppendResult(interp, "missing close-brace", (char *)NULL); + *termPtr = string - 1; + return TCL_ERROR; + } + } + + *dest = '\0'; + parsePtr->next = dest; + *termPtr = src; + return TCL_OK; +} + +void Blt::ExpandParseValue(ParseValue *parsePtr, int needed) + +{ + /* + * Either double the size of the buffer or add enough new space + * to meet the demand, whichever produces a larger new buffer. + */ + int size = (parsePtr->end - parsePtr->buffer) + 1; + if (size < needed) + size += needed; + else + size += size; + + char* buffer = (char*)malloc((unsigned int)size); + + /* + * Copy from old buffer to new, free old buffer if needed, and + * mark new buffer as malloc-ed. + */ + memcpy((VOID *) buffer, (VOID *) parsePtr->buffer, + (size_t) (parsePtr->next - parsePtr->buffer)); + parsePtr->next = buffer + (parsePtr->next - parsePtr->buffer); + if (parsePtr->clientData != 0) { + free(parsePtr->buffer); + } + parsePtr->buffer = buffer; + parsePtr->end = buffer + size - 1; + parsePtr->clientData = (ClientData)1; +} + +int Blt::ParseQuotes(Tcl_Interp* interp, const char *string, int termChar, + int flags, const char **termPtr, ParseValue *parsePtr) +{ + const char *src; + char *dest, c; + const char *lastChar = string + strlen(string); + + src = string; + dest = parsePtr->next; + + for (;;) { + if (dest == parsePtr->end) { + /* + * Target buffer space is about to run out. Make more space. + */ + parsePtr->next = dest; + (*parsePtr->expandProc) (parsePtr, 1); + dest = parsePtr->next; + } + c = *src; + src++; + if (c == termChar) { + *dest = '\0'; + parsePtr->next = dest; + *termPtr = src; + return TCL_OK; + } else if (CHAR_TYPE(src - 1, lastChar) == TCL_NORMAL) { + copy: + *dest = c; + dest++; + continue; + } else if (c == '$') { + int length; + const char *value; + + value = Tcl_ParseVar(interp, src - 1, termPtr); + if (value == NULL) { + return TCL_ERROR; + } + src = *termPtr; + length = strlen(value); + if ((parsePtr->end - dest) <= length) { + parsePtr->next = dest; + (*parsePtr->expandProc) (parsePtr, length); + dest = parsePtr->next; + } + strcpy(dest, value); + dest += length; + continue; + } else if (c == '[') { + int result; + + parsePtr->next = dest; + result = ParseNestedCmd(interp, src, flags, termPtr, parsePtr); + if (result != TCL_OK) { + return result; + } + src = *termPtr; + dest = parsePtr->next; + continue; + } else if (c == '\\') { + int nRead; + + src--; + *dest = Tcl_Backslash(src, &nRead); + dest++; + src += nRead; + continue; + } else if (c == '\0') { + Tcl_ResetResult(interp); + ostringstream str; + str << "missing " << termChar << ends; + Tcl_SetStringObj(Tcl_GetObjResult(interp), str.str().c_str(), 9); + *termPtr = string - 1; + return TCL_ERROR; + } else { + goto copy; + } + } +} + diff --git a/generic/tkbltParse.h b/generic/tkbltParse.h new file mode 100644 index 0000000..ee215a5 --- /dev/null +++ b/generic/tkbltParse.h @@ -0,0 +1,55 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _BLT_PARSE_H +#define _BLT_PARSE_H + +namespace Blt { + + typedef struct _ParseValue ParseValue; + struct _ParseValue { + char *buffer; + char *next; + char *end; + void (*expandProc)(ParseValue *pvPtr, int needed); + ClientData clientData; + }; + + extern int ParseBraces(Tcl_Interp* interp, const char *string, + const char **termPtr, ParseValue *pvPtr); + extern int ParseNestedCmd(Tcl_Interp* interp, const char *string, + int flags, const char **termPtr, + ParseValue *pvPtr); + extern int ParseQuotes(Tcl_Interp* interp, const char *string, + int termChar, int flags, const char **termPtr, + ParseValue * pvPtr); + extern void ExpandParseValue(ParseValue *pvPtr, int needed); +} + +#endif diff --git a/generic/tkbltStubInit.c b/generic/tkbltStubInit.c new file mode 100644 index 0000000..354b7f1 --- /dev/null +++ b/generic/tkbltStubInit.c @@ -0,0 +1,30 @@ +#include "tkbltVector.h" + +/* !BEGIN!: Do not edit below this line. */ + +const TkbltStubs tkbltStubs = { + TCL_STUB_MAGIC, + 0, + Blt_CreateVector, /* 0 */ + Blt_CreateVector2, /* 1 */ + Blt_DeleteVectorByName, /* 2 */ + Blt_DeleteVector, /* 3 */ + Blt_GetVector, /* 4 */ + Blt_GetVectorFromObj, /* 5 */ + Blt_ResetVector, /* 6 */ + Blt_ResizeVector, /* 7 */ + Blt_VectorExists, /* 8 */ + Blt_VectorExists2, /* 9 */ + Blt_AllocVectorId, /* 10 */ + Blt_GetVectorById, /* 11 */ + Blt_SetVectorChangedProc, /* 12 */ + Blt_FreeVectorId, /* 13 */ + Blt_NameOfVectorId, /* 14 */ + Blt_NameOfVector, /* 15 */ + Blt_ExprVector, /* 16 */ + Blt_InstallIndexProc, /* 17 */ + Blt_VecMin, /* 18 */ + Blt_VecMax, /* 19 */ +}; + +/* !END!: Do not edit above this line. */ diff --git a/generic/tkbltStubLib.C b/generic/tkbltStubLib.C new file mode 100644 index 0000000..e973063 --- /dev/null +++ b/generic/tkbltStubLib.C @@ -0,0 +1,15 @@ +#ifndef USE_TCL_STUBS +#define USE_TCL_STUBS +#endif + +#include + +ClientData tkbltStubsPtr =NULL; + +const char* Tkblt_InitStubs(Tcl_Interp* interp, const char* version, int exact) +{ + const char* actualVersion = + Tcl_PkgRequireEx(interp, "tkblt", version, exact, &tkbltStubsPtr); + + return (actualVersion && tkbltStubsPtr) ? actualVersion : NULL; +} diff --git a/generic/tkbltSwitch.C b/generic/tkbltSwitch.C new file mode 100644 index 0000000..bb80663 --- /dev/null +++ b/generic/tkbltSwitch.C @@ -0,0 +1,407 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1991-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#include +#include +#include +using namespace std; + +#include + +#include "tkbltSwitch.h" + +using namespace Blt; + +#define COUNT_NNEG 0 +#define COUNT_POS 1 +#define COUNT_ANY 2 + +static char* Blt_Strdup(const char *string) +{ + size_t size = strlen(string) + 1; + char* ptr = (char*)malloc(size * sizeof(char)); + if (ptr != NULL) { + strcpy(ptr, string); + } + return ptr; +} + +static int Blt_GetCountFromObj(Tcl_Interp* interp, Tcl_Obj *objPtr, int check, + long *valuePtr) +{ + long count; + if (Tcl_GetLongFromObj(interp, objPtr, &count) != TCL_OK) + return TCL_ERROR; + + switch (check) { + case COUNT_NNEG: + if (count < 0) { + Tcl_AppendResult(interp, "bad value \"", Tcl_GetString(objPtr), + "\": can't be negative", (char *)NULL); + return TCL_ERROR; + } + break; + case COUNT_POS: + if (count <= 0) { + Tcl_AppendResult(interp, "bad value \"", Tcl_GetString(objPtr), + "\": must be positive", (char *)NULL); + return TCL_ERROR; + } + break; + case COUNT_ANY: + break; + } + *valuePtr = count; + return TCL_OK; +} + +static void DoHelp(Tcl_Interp* interp, Blt_SwitchSpec *specs) +{ + Tcl_DString ds; + Tcl_DStringInit(&ds); + Tcl_DStringAppend(&ds, "following switches are available:", -1); + for (Blt_SwitchSpec *sp = specs; sp->type != BLT_SWITCH_END; sp++) { + Tcl_DStringAppend(&ds, "\n ", 4); + Tcl_DStringAppend(&ds, sp->switchName, -1); + Tcl_DStringAppend(&ds, " ", 1); + Tcl_DStringAppend(&ds, sp->help, -1); + } + Tcl_AppendResult(interp, Tcl_DStringValue(&ds), (char *)NULL); + Tcl_DStringFree(&ds); +} + +static Blt_SwitchSpec *FindSwitchSpec(Tcl_Interp* interp, Blt_SwitchSpec *specs, + const char *name, int length, + int needFlags, int hateFlags) +{ + char c = name[1]; + Blt_SwitchSpec *matchPtr = NULL; + for (Blt_SwitchSpec *sp = specs; sp->type != BLT_SWITCH_END; sp++) { + if (sp->switchName == NULL) + continue; + + if (((sp->flags & needFlags) != needFlags) || (sp->flags & hateFlags)) + continue; + + if ((sp->switchName[1] != c) || (strncmp(sp->switchName,name,length)!=0)) + continue; + + if (sp->switchName[length] == '\0') + return sp; /* Stop on a perfect match. */ + + if (matchPtr != NULL) { + Tcl_AppendResult(interp, "ambiguous switch \"", name, "\"\n", + (char *) NULL); + DoHelp(interp, specs); + return NULL; + } + matchPtr = sp; + } + + if (strcmp(name, "-help") == 0) { + DoHelp(interp, specs); + return NULL; + } + + if (matchPtr == NULL) { + Tcl_AppendResult(interp, "unknown switch \"", name, "\"\n", + (char *)NULL); + DoHelp(interp, specs); + return NULL; + } + + return matchPtr; +} + +static int DoSwitch(Tcl_Interp* interp, Blt_SwitchSpec *sp, + Tcl_Obj *objPtr, void *record) +{ + do { + char *ptr = (char *)record + sp->offset; + switch (sp->type) { + case BLT_SWITCH_BOOLEAN: + { + int boo; + + if (Tcl_GetBooleanFromObj(interp, objPtr, &boo) != TCL_OK) { + return TCL_ERROR; + } + if (sp->mask > 0) { + if (boo) { + *((int *)ptr) |= sp->mask; + } else { + *((int *)ptr) &= ~sp->mask; + } + } else { + *((int *)ptr) = boo; + } + } + break; + + case BLT_SWITCH_DOUBLE: + if (Tcl_GetDoubleFromObj(interp, objPtr, (double *)ptr) != TCL_OK) { + return TCL_ERROR; + } + break; + + case BLT_SWITCH_OBJ: + Tcl_IncrRefCount(objPtr); + *(Tcl_Obj **)ptr = objPtr; + break; + + case BLT_SWITCH_FLOAT: + { + double value; + + if (Tcl_GetDoubleFromObj(interp, objPtr, &value) != TCL_OK) { + return TCL_ERROR; + } + *(float *)ptr = (float)value; + } + break; + + case BLT_SWITCH_INT: + if (Tcl_GetIntFromObj(interp, objPtr, (int *)ptr) != TCL_OK) { + return TCL_ERROR; + } + break; + + case BLT_SWITCH_INT_NNEG: + { + long value; + + if (Blt_GetCountFromObj(interp, objPtr, COUNT_NNEG, + &value) != TCL_OK) { + return TCL_ERROR; + } + *(int *)ptr = (int)value; + } + break; + + case BLT_SWITCH_INT_POS: + { + long value; + + if (Blt_GetCountFromObj(interp, objPtr, COUNT_POS, + &value) != TCL_OK) { + return TCL_ERROR; + } + *(int *)ptr = (int)value; + } + break; + + case BLT_SWITCH_LIST: + { + int argc; + + if (Tcl_SplitList(interp, Tcl_GetString(objPtr), &argc, + (const char ***)ptr) != TCL_OK) { + return TCL_ERROR; + } + } + break; + + case BLT_SWITCH_LONG: + if (Tcl_GetLongFromObj(interp, objPtr, (long *)ptr) != TCL_OK) { + return TCL_ERROR; + } + break; + + case BLT_SWITCH_LONG_NNEG: + { + long value; + + if (Blt_GetCountFromObj(interp, objPtr, COUNT_NNEG, + &value) != TCL_OK) { + return TCL_ERROR; + } + *(long *)ptr = value; + } + break; + + case BLT_SWITCH_LONG_POS: + { + long value; + + if (Blt_GetCountFromObj(interp, objPtr, COUNT_POS, &value) + != TCL_OK) { + return TCL_ERROR; + } + *(long *)ptr = value; + } + break; + + case BLT_SWITCH_STRING: + { + char *value; + + value = Tcl_GetString(objPtr); + value = (*value == '\0') ? NULL : Blt_Strdup(value); + if (*(char **)ptr != NULL) { + free(*(char **)ptr); + } + *(char **)ptr = value; + } + break; + + case BLT_SWITCH_CUSTOM: + if ((*sp->customPtr->parseProc)(sp->customPtr->clientData, interp, + sp->switchName, objPtr, (char *)record, sp->offset, sp->flags) + != TCL_OK) { + return TCL_ERROR; + } + break; + + default: + ostringstream str; + str << sp->type << ends; + Tcl_AppendResult(interp, "bad switch table: unknown type \"", + str.str().c_str(), "\"", NULL); + return TCL_ERROR; + } + sp++; + } while ((sp->switchName == NULL) && (sp->type != BLT_SWITCH_END)); + return TCL_OK; +} + +int Blt::ParseSwitches(Tcl_Interp* interp, Blt_SwitchSpec *specs, + int objc, Tcl_Obj* const objv[], void *record, + int flags) +{ + Blt_SwitchSpec *sp; + int needFlags = flags & ~(BLT_SWITCH_USER_BIT - 1); + int hateFlags = 0; + + /* + * Pass 1: Clear the change flags on all the specs so that we + * can check it later. + */ + for (sp = specs; sp->type != BLT_SWITCH_END; sp++) + sp->flags &= ~BLT_SWITCH_SPECIFIED; + + /* + * Pass 2: Process the arguments that match entries in the specs. + * It's an error if the argument doesn't match anything. + */ + int count; + for (count = 0; count < objc; count++) { + char *arg; + int length; + + arg = Tcl_GetStringFromObj(objv[count], &length); + if (flags & BLT_SWITCH_OBJV_PARTIAL) { + /* + * If the argument doesn't start with a '-' (not a switch) or is + * '--', stop processing and return the number of arguments + * comsumed. + */ + if (arg[0] != '-') { + return count; + } + if ((arg[1] == '-') && (arg[2] == '\0')) { + return count + 1; /* include the "--" in the count. */ + } + } + sp = FindSwitchSpec(interp, specs, arg, length, needFlags, hateFlags); + if (sp == NULL) { + return -1; + } + if (sp->type == BLT_SWITCH_BITMASK) { + char *ptr; + + ptr = (char *)record + sp->offset; + *((int *)ptr) |= sp->mask; + } else if (sp->type == BLT_SWITCH_BITMASK_INVERT) { + char *ptr; + + ptr = (char *)record + sp->offset; + *((int *)ptr) &= ~sp->mask; + } else if (sp->type == BLT_SWITCH_VALUE) { + char *ptr; + + ptr = (char *)record + sp->offset; + *((int *)ptr) = sp->mask; + } else { + count++; + if (count == objc) { + Tcl_AppendResult(interp, "value for \"", arg, "\" missing", + (char *) NULL); + return -1; + } + if (DoSwitch(interp, sp, objv[count], record) != TCL_OK) { + ostringstream str; + str << "\n (processing \"" << sp->switchName << "\" switch)" << ends; + Tcl_AddErrorInfo(interp, str.str().c_str()); + return -1; + } + } + sp->flags |= BLT_SWITCH_SPECIFIED; + } + + return count; +} + +void Blt::FreeSwitches(Blt_SwitchSpec *specs, void *record, int needFlags) +{ + for (Blt_SwitchSpec *sp = specs; sp->type != BLT_SWITCH_END; sp++) { + if ((sp->flags & needFlags) == needFlags) { + char *ptr = (char *)record + sp->offset; + switch (sp->type) { + case BLT_SWITCH_STRING: + case BLT_SWITCH_LIST: + if (*((char **) ptr) != NULL) { + free(*((char **) ptr)); + *((char **) ptr) = NULL; + } + break; + + case BLT_SWITCH_OBJ: + if (*((Tcl_Obj **) ptr) != NULL) { + Tcl_DecrRefCount(*((Tcl_Obj **)ptr)); + *((Tcl_Obj **) ptr) = NULL; + } + break; + + case BLT_SWITCH_CUSTOM: + if ((*(char **)ptr != NULL) && + (sp->customPtr->freeProc != NULL)) { + (*sp->customPtr->freeProc)((char *)record, sp->offset, + sp->flags); + } + break; + + default: + break; + } + } + } +} diff --git a/generic/tkbltSwitch.h b/generic/tkbltSwitch.h new file mode 100644 index 0000000..eed7b31 --- /dev/null +++ b/generic/tkbltSwitch.h @@ -0,0 +1,129 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef BLT_SWITCH_H +#define BLT_SWITCH_H + +#include + +#define BLT_SWITCH_DEFAULTS (0) +#define BLT_SWITCH_ARGV_PARTIAL (1<<1) +#define BLT_SWITCH_OBJV_PARTIAL (1<<1) + + /* + * Possible flag values for Blt_SwitchSpec structures. Any bits at or + * above BLT_SWITCH_USER_BIT may be used by clients for selecting + * certain entries. + */ +#define BLT_SWITCH_NULL_OK (1<<0) +#define BLT_SWITCH_DONT_SET_DEFAULT (1<<3) +#define BLT_SWITCH_SPECIFIED (1<<4) +#define BLT_SWITCH_USER_BIT (1<<8) + +namespace Blt { + + typedef int (Blt_SwitchParseProc)(ClientData clientData, Tcl_Interp* interp, + const char *switchName, + Tcl_Obj *valueObjPtr, char *record, + int offset, int flags); + typedef void (Blt_SwitchFreeProc)(char *record, int offset, int flags); + + typedef struct { + Blt_SwitchParseProc *parseProc; /* Procedure to parse a switch + * value and store it in its * + * converted form in the data * + * record. */ + + Blt_SwitchFreeProc *freeProc; /* Procedure to free a switch. */ + + ClientData clientData; /* Arbitrary one-word value used by + * switch parser, passed to + * parseProc. */ + } Blt_SwitchCustom; + + /* + * Type values for Blt_SwitchSpec structures. See the user + * documentation for details. + */ + typedef enum { + BLT_SWITCH_BOOLEAN, + BLT_SWITCH_DOUBLE, + BLT_SWITCH_BITMASK, + BLT_SWITCH_BITMASK_INVERT, + BLT_SWITCH_FLOAT, + BLT_SWITCH_INT, + BLT_SWITCH_INT_NNEG, + BLT_SWITCH_INT_POS, + BLT_SWITCH_LIST, + BLT_SWITCH_LONG, + BLT_SWITCH_LONG_NNEG, + BLT_SWITCH_LONG_POS, + BLT_SWITCH_OBJ, + BLT_SWITCH_STRING, + BLT_SWITCH_VALUE, + BLT_SWITCH_CUSTOM, + BLT_SWITCH_END + } Blt_SwitchTypes; + + typedef struct { + Blt_SwitchTypes type; /* Type of option, such as + * BLT_SWITCH_COLOR; see definitions + * below. Last option in table must + * have type BLT_SWITCH_END. */ + + const char *switchName; /* Switch used to specify option in + * argv. NULL means this spec is part + * of a group. */ + + const char *help; /* Help string. */ + int offset; /* Where in widget record to store + * value; use Blt_Offset macro to + * generate values for this. */ + + int flags; /* Any combination of the values + * defined below. */ + + unsigned int mask; + + Blt_SwitchCustom *customPtr; /* If type is BLT_SWITCH_CUSTOM then + * this is a pointer to info about how + * to parse and print the option. + * Otherwise it is irrelevant. */ + } Blt_SwitchSpec; + + extern int ParseSwitches(Tcl_Interp* interp, Blt_SwitchSpec *specPtr, + int objc, Tcl_Obj *const *objv, void *rec, + int flags); + extern void FreeSwitches(Blt_SwitchSpec *specs, void *rec, int flags); +}; + +#endif /* BLT_SWITCH_H */ diff --git a/generic/tkbltVecCmd.C b/generic/tkbltVecCmd.C new file mode 100644 index 0000000..8a03fe6 --- /dev/null +++ b/generic/tkbltVecCmd.C @@ -0,0 +1,1821 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1995-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Code for binary data read operation was donated by Harold Kirsch. + * + */ + +/* + * TODO: + * o Add H. Kirsch's vector binary read operation + * x binread file0 + * x binread -file file0 + * + * o Add ASCII/binary file reader + * x read fileName + * + * o Allow Tcl-based client notifications. + * vector x + * x notify call Display + * x notify delete Display + * x notify reorder #1 #2 + */ + +#include +#include +#include +#include + +#include + +#include "tkbltVecInt.h" +#include "tkbltOp.h" +#include "tkbltNsUtil.h" +#include "tkbltSwitch.h" +#include "tkbltInt.h" + +using namespace Blt; + +extern int Blt_SimplifyLine (Point2d *origPts, int low, int high, + double tolerance, int *indices); + +typedef int (VectorCmdProc)(Vector *vPtr, Tcl_Interp* interp, int objc, + Tcl_Obj* const objv[]); +typedef int (QSortCompareProc) (const void *, const void *); + +static Blt_SwitchParseProc ObjToFFTVector; +static Blt_SwitchCustom fftVectorSwitch = { + ObjToFFTVector, NULL, (ClientData)0, +}; + +static Blt_SwitchParseProc ObjToIndex; +static Blt_SwitchCustom indexSwitch = { + ObjToIndex, NULL, (ClientData)0, +}; + +typedef struct { + Tcl_Obj *formatObjPtr; + int from, to; +} PrintSwitches; + +static Blt_SwitchSpec printSwitches[] = + { + {BLT_SWITCH_OBJ, "-format", "string", + Tk_Offset(PrintSwitches, formatObjPtr), 0}, + {BLT_SWITCH_CUSTOM, "-from", "index", + Tk_Offset(PrintSwitches, from), 0, 0, &indexSwitch}, + {BLT_SWITCH_CUSTOM, "-to", "index", + Tk_Offset(PrintSwitches, to), 0, 0, &indexSwitch}, + {BLT_SWITCH_END} + }; + + +typedef struct { + int flags; +} SortSwitches; + +#define SORT_DECREASING (1<<0) +#define SORT_UNIQUE (1<<1) + +static Blt_SwitchSpec sortSwitches[] = + { + {BLT_SWITCH_BITMASK, "-decreasing", "", + Tk_Offset(SortSwitches, flags), 0, SORT_DECREASING}, + {BLT_SWITCH_BITMASK, "-reverse", "", + Tk_Offset(SortSwitches, flags), 0, SORT_DECREASING}, + {BLT_SWITCH_BITMASK, "-uniq", "", + Tk_Offset(SortSwitches, flags), 0, SORT_UNIQUE}, + {BLT_SWITCH_END} + }; + +typedef struct { + double delta; + Vector *imagPtr; /* Vector containing imaginary part. */ + Vector *freqPtr; /* Vector containing frequencies. */ + VectorInterpData *dataPtr; + int mask; /* Flags controlling FFT. */ +} FFTData; + + +static Blt_SwitchSpec fftSwitches[] = { + {BLT_SWITCH_CUSTOM, "-imagpart", "vector", + Tk_Offset(FFTData, imagPtr), 0, 0, &fftVectorSwitch}, + {BLT_SWITCH_BITMASK, "-noconstant", "", + Tk_Offset(FFTData, mask), 0, FFT_NO_CONSTANT}, + {BLT_SWITCH_BITMASK, "-spectrum", "", + Tk_Offset(FFTData, mask), 0, FFT_SPECTRUM}, + {BLT_SWITCH_BITMASK, "-bartlett", "", + Tk_Offset(FFTData, mask), 0, FFT_BARTLETT}, + {BLT_SWITCH_DOUBLE, "-delta", "float", + Tk_Offset(FFTData, mask), 0, 0, }, + {BLT_SWITCH_CUSTOM, "-frequencies", "vector", + Tk_Offset(FFTData, freqPtr), 0, 0, &fftVectorSwitch}, + {BLT_SWITCH_END} +}; + +static int Blt_ExprIntFromObj(Tcl_Interp* interp, Tcl_Obj *objPtr, + int *valuePtr) +{ + // First try to extract the value as a simple integer. + if (Tcl_GetIntFromObj((Tcl_Interp *)NULL, objPtr, valuePtr) == TCL_OK) + return TCL_OK; + + // Otherwise try to parse it as an expression. + long lvalue; + if (Tcl_ExprLong(interp, Tcl_GetString(objPtr), &lvalue) == TCL_OK) { + *valuePtr = lvalue; + return TCL_OK; + } + + return TCL_ERROR; +} + +static int Blt_ExprDoubleFromObj(Tcl_Interp* interp, Tcl_Obj *objPtr, + double *valuePtr) +{ + // First try to extract the value as a double precision number. + if (Tcl_GetDoubleFromObj((Tcl_Interp *)NULL, objPtr, valuePtr) == TCL_OK) + return TCL_OK; + + // Interpret the empty string "" and "NaN" as NaN. + int length; + char *string; + string = Tcl_GetStringFromObj(objPtr, &length); + if (length == 0 || (length == 3 && strcmp(string, "NaN") == 0)) { + *valuePtr = NAN; + return TCL_OK; + } + + // Then try to parse it as an expression. + if (Tcl_ExprDouble(interp, string, valuePtr) == TCL_OK) + return TCL_OK; + + return TCL_ERROR; +} + +static int ObjToFFTVector(ClientData clientData, Tcl_Interp* interp, + const char *switchName, Tcl_Obj *objPtr, + char *record, int offset, int flags) +{ + FFTData *dataPtr = (FFTData *)record; + Vector *vPtr; + Vector **vPtrPtr = (Vector **)(record + offset); + int isNew; /* Not used. */ + char *string; + + string = Tcl_GetString(objPtr); + vPtr = Vec_Create(dataPtr->dataPtr, string, string, string, &isNew); + if (vPtr == NULL) { + return TCL_ERROR; + } + *vPtrPtr = vPtr; + + return TCL_OK; +} + +static int ObjToIndex(ClientData clientData, Tcl_Interp* interp, + const char *switchName, Tcl_Obj *objPtr, char *record, + int offset, int flags) +{ + Vector *vPtr = (Vector*)clientData; + int *indexPtr = (int *)(record + offset); + int index; + + if (Vec_GetIndex(interp, vPtr, Tcl_GetString(objPtr), &index, + INDEX_CHECK, (Blt_VectorIndexProc **)NULL) != TCL_OK) { + return TCL_ERROR; + } + *indexPtr = index; + + return TCL_OK; +} + +static Tcl_Obj* GetValues(Vector *vPtr, int first, int last) +{ + Tcl_Obj *listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + for (double *vp=vPtr->valueArr+first, *vend=vPtr->valueArr+last; + vp <= vend; vp++) + Tcl_ListObjAppendElement(vPtr->interp, listObjPtr, Tcl_NewDoubleObj(*vp)); + + return listObjPtr; +} + +static void ReplicateValue(Vector *vPtr, int first, int last, double value) +{ + for (double *vp=vPtr->valueArr+first, *vend=vPtr->valueArr+last; + vp <= vend; vp++) + *vp = value; + + vPtr->notifyFlags |= UPDATE_RANGE; +} + +static int CopyList(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + if (Vec_SetLength(interp, vPtr, objc) != TCL_OK) + return TCL_ERROR; + + for (int ii = 0; ii < objc; ii++) { + double value; + if (Blt_ExprDoubleFromObj(interp, objv[ii], &value) != TCL_OK) { + Vec_SetLength(interp, vPtr, ii); + return TCL_ERROR; + } + vPtr->valueArr[ii] = value; + } + + return TCL_OK; +} + +static int AppendVector(Vector *destPtr, Vector *srcPtr) +{ + size_t oldSize = destPtr->length; + size_t newSize = oldSize + srcPtr->last - srcPtr->first + 1; + if (Vec_ChangeLength(destPtr->interp, destPtr, newSize) != TCL_OK) { + return TCL_ERROR; + } + size_t nBytes = (newSize - oldSize) * sizeof(double); + memcpy((char *)(destPtr->valueArr + oldSize), + (srcPtr->valueArr + srcPtr->first), nBytes); + destPtr->notifyFlags |= UPDATE_RANGE; + return TCL_OK; +} + +static int AppendList(Vector *vPtr, int objc, Tcl_Obj* const objv[]) +{ + Tcl_Interp* interp = vPtr->interp; + + int oldSize = vPtr->length; + if (Vec_ChangeLength(interp, vPtr, vPtr->length + objc) != TCL_OK) + return TCL_ERROR; + + int count = oldSize; + for (int i = 0; i < objc; i++) { + double value; + if (Blt_ExprDoubleFromObj(interp, objv[i], &value) != TCL_OK) { + Vec_ChangeLength(interp, vPtr, count); + return TCL_ERROR; + } + vPtr->valueArr[count++] = value; + } + vPtr->notifyFlags |= UPDATE_RANGE; + + return TCL_OK; +} + +// Vector instance option commands + +static int AppendOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + for (int i = 2; i < objc; i++) { + Vector* v2Ptr = Vec_ParseElement((Tcl_Interp *)NULL, vPtr->dataPtr, + Tcl_GetString(objv[i]), + (const char **)NULL, NS_SEARCH_BOTH); + int result; + if (v2Ptr != NULL) + result = AppendVector(vPtr, v2Ptr); + else { + int nElem; + Tcl_Obj **elemObjArr; + + if (Tcl_ListObjGetElements(interp, objv[i], &nElem, &elemObjArr) + != TCL_OK) { + return TCL_ERROR; + } + result = AppendList(vPtr, nElem, elemObjArr); + } + + if (result != TCL_OK) + return TCL_ERROR; + } + + if (objc > 2) { + if (vPtr->flush) + Vec_FlushCache(vPtr); + Vec_UpdateClients(vPtr); + } + + return TCL_OK; +} + +static int ClearOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Vec_FlushCache(vPtr); + return TCL_OK; +} + +static int DeleteOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + // FIXME: Don't delete vector with no indices + if (objc == 2) { + Vec_Free(vPtr); + return TCL_OK; + } + + // Allocate an "unset" bitmap the size of the vector + unsigned char* unsetArr = + (unsigned char*)calloc(sizeof(unsigned char), (vPtr->length + 7) / 8); +#define SetBit(i) (unsetArr[(i) >> 3] |= (1 << ((i) & 0x07))) +#define GetBit(i) (unsetArr[(i) >> 3] & (1 << ((i) & 0x07))) + + for (int i = 2; i < objc; i++) { + char* string = Tcl_GetString(objv[i]); + if (Vec_GetIndexRange(interp, vPtr, string, (INDEX_COLON | INDEX_CHECK), + (Blt_VectorIndexProc **) NULL) != TCL_OK) { + free(unsetArr); + return TCL_ERROR; + } + + // Mark the range of elements for deletion + for (int j = vPtr->first; j <= vPtr->last; j++) + SetBit(j); + } + + int count = 0; + for (int i = 0; i < vPtr->length; i++) { + // Skip elements marked for deletion + if (GetBit(i)) + continue; + + if (count < i) { + vPtr->valueArr[count] = vPtr->valueArr[i]; + } + count++; + } + free(unsetArr); + vPtr->length = count; + + if (vPtr->flush) + Vec_FlushCache(vPtr); + Vec_UpdateClients(vPtr); + + return TCL_OK; +} + +static int DupOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + for (int i = 2; i < objc; i++) { + char* name = Tcl_GetString(objv[i]); + int isNew; + Vector* v2Ptr = Vec_Create(vPtr->dataPtr, name, name, name, &isNew); + if (v2Ptr == NULL) + return TCL_ERROR; + + if (v2Ptr == vPtr) + continue; + + if (Vec_Duplicate(v2Ptr, vPtr) != TCL_OK) + return TCL_ERROR; + + if (!isNew) { + if (v2Ptr->flush) + Vec_FlushCache(v2Ptr); + Vec_UpdateClients(v2Ptr); + } + } + + return TCL_OK; +} + +static int FFTOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + FFTData data; + memset(&data, 0, sizeof(data)); + data.delta = 1.0; + + char* realVecName = Tcl_GetString(objv[2]); + int isNew; + Vector* v2Ptr = Vec_Create(vPtr->dataPtr, realVecName, realVecName, + realVecName, &isNew); + if (v2Ptr == NULL) + return TCL_ERROR; + + if (v2Ptr == vPtr) { + Tcl_AppendResult(interp, "real vector \"", realVecName, "\"", + " can't be the same as the source", (char *)NULL); + return TCL_ERROR; + } + + if (ParseSwitches(interp, fftSwitches, objc - 3, objv + 3, &data, + BLT_SWITCH_DEFAULTS) < 0) + return TCL_ERROR; + + if (Vec_FFT(interp, v2Ptr, data.imagPtr, data.freqPtr, data.delta, + data.mask, vPtr) != TCL_OK) + return TCL_ERROR; + + // Update bookkeeping + if (!isNew) { + if (v2Ptr->flush) + Vec_FlushCache(v2Ptr); + Vec_UpdateClients(v2Ptr); + } + + if (data.imagPtr != NULL) { + if (data.imagPtr->flush) + Vec_FlushCache(data.imagPtr); + Vec_UpdateClients(data.imagPtr); + } + + if (data.freqPtr != NULL) { + if (data.freqPtr->flush) + Vec_FlushCache(data.freqPtr); + Vec_UpdateClients(data.freqPtr); + } + + return TCL_OK; +} + +static int InverseFFTOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + char* name = Tcl_GetString(objv[2]); + Vector *srcImagPtr; + if (Vec_LookupName(vPtr->dataPtr, name, &srcImagPtr) != TCL_OK ) + return TCL_ERROR; + + name = Tcl_GetString(objv[3]); + int isNew; + Vector* destRealPtr = Vec_Create(vPtr->dataPtr, name, name, name, &isNew); + name = Tcl_GetString(objv[4]); + Vector* destImagPtr = Vec_Create(vPtr->dataPtr, name, name, name, &isNew); + + if (Vec_InverseFFT(interp, srcImagPtr, destRealPtr, destImagPtr, vPtr) + != TCL_OK ) + return TCL_ERROR; + + if (destRealPtr->flush) + Vec_FlushCache(destRealPtr); + Vec_UpdateClients(destRealPtr); + + if (destImagPtr->flush) + Vec_FlushCache(destImagPtr); + Vec_UpdateClients(destImagPtr); + + return TCL_OK; +} + +static int IndexOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + char* string = Tcl_GetString(objv[2]); + if (Vec_GetIndexRange(interp, vPtr, string, INDEX_ALL_FLAGS, + (Blt_VectorIndexProc **) NULL) != TCL_OK) + return TCL_ERROR; + + int first = vPtr->first; + int last = vPtr->last; + if (objc == 3) { + Tcl_Obj *listObjPtr; + + if (first == vPtr->length) { + Tcl_AppendResult(interp, "can't get index \"", string, "\"", + (char *)NULL); + return TCL_ERROR; /* Can't read from index "++end" */ + } + listObjPtr = GetValues(vPtr, first, last); + Tcl_SetObjResult(interp, listObjPtr); + } + else { + // FIXME: huh? Why set values here? + if (first == SPECIAL_INDEX) { + Tcl_AppendResult(interp, "can't set index \"", string, "\"", + (char *)NULL); + // Tried to set "min" or "max" + return TCL_ERROR; + } + + double value; + if (Blt_ExprDoubleFromObj(interp, objv[3], &value) != TCL_OK) + return TCL_ERROR; + + if (first == vPtr->length) { + if (Vec_ChangeLength(interp, vPtr, vPtr->length + 1) != TCL_OK) + return TCL_ERROR; + } + + ReplicateValue(vPtr, first, last, value); + Tcl_SetObjResult(interp, objv[3]); + if (vPtr->flush) + Vec_FlushCache(vPtr); + Vec_UpdateClients(vPtr); + } + + return TCL_OK; +} + +static int LengthOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + if (objc == 3) { + int nElem; + if (Tcl_GetIntFromObj(interp, objv[2], &nElem) != TCL_OK) + return TCL_ERROR; + + if (nElem < 0) { + Tcl_AppendResult(interp, "bad vector size \"", + Tcl_GetString(objv[2]), "\"", (char *)NULL); + return TCL_ERROR; + } + + if ((Vec_SetSize(interp, vPtr, nElem) != TCL_OK) || + (Vec_SetLength(interp, vPtr, nElem) != TCL_OK)) + return TCL_ERROR; + + if (vPtr->flush) + Vec_FlushCache(vPtr); + Vec_UpdateClients(vPtr); + } + Tcl_SetIntObj(Tcl_GetObjResult(interp), vPtr->length); + + return TCL_OK; +} + +static int MapOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + if (objc > 2) { + if (Vec_MapVariable(interp, vPtr, Tcl_GetString(objv[2])) + != TCL_OK) + return TCL_ERROR; + } + + if (vPtr->arrayName != NULL) + Tcl_SetStringObj(Tcl_GetObjResult(interp), vPtr->arrayName, -1); + + return TCL_OK; +} + +static int MaxOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Tcl_SetDoubleObj(Tcl_GetObjResult(interp), Vec_Max(vPtr)); + return TCL_OK; +} + +static int MergeOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + // Allocate an array of vector pointers of each vector to be + // merged in the current vector. + Vector** vecArr = (Vector**)malloc(sizeof(Vector *) * objc); + Vector** vPtrPtr = vecArr; + + int refSize = -1; + int nElem = 0; + for (int i = 2; i < objc; i++) { + Vector *v2Ptr; + if (Vec_LookupName(vPtr->dataPtr, Tcl_GetString(objv[i]), &v2Ptr) + != TCL_OK) { + free(vecArr); + return TCL_ERROR; + } + + // Check that all the vectors are the same length + int length = v2Ptr->last - v2Ptr->first + 1; + if (refSize < 0) + refSize = length; + else if (length != refSize) { + Tcl_AppendResult(vPtr->interp, "vectors \"", vPtr->name, + "\" and \"", v2Ptr->name, "\" differ in length", + (char *)NULL); + free(vecArr); + return TCL_ERROR; + } + *vPtrPtr++ = v2Ptr; + nElem += refSize; + } + *vPtrPtr = NULL; + + double* valueArr = (double*)malloc(sizeof(double) * nElem); + if (valueArr == NULL) { + Tcl_AppendResult(vPtr->interp, "not enough memory to allocate ", + Itoa(nElem), " vector elements", (char *)NULL); + return TCL_ERROR; + } + + // Merge the values from each of the vectors into the current vector + double* valuePtr = valueArr; + for (int i = 0; i < refSize; i++) { + for (Vector** vpp = vecArr; *vpp != NULL; vpp++) { + *valuePtr++ = (*vpp)->valueArr[i + (*vpp)->first]; + } + } + free(vecArr); + Vec_Reset(vPtr, valueArr, nElem, nElem, TCL_DYNAMIC); + + return TCL_OK; +} + +static int MinOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Tcl_SetDoubleObj(Tcl_GetObjResult(interp), Vec_Min(vPtr)); + return TCL_OK; +} + +static int NormalizeOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Vec_UpdateRange(vPtr); + double range = vPtr->max - vPtr->min; + if (objc > 2) { + char* string = Tcl_GetString(objv[2]); + int isNew; + Vector* v2Ptr = Vec_Create(vPtr->dataPtr, string, string, string, &isNew); + if (v2Ptr == NULL) + return TCL_ERROR; + + if (Vec_SetLength(interp, v2Ptr, vPtr->length) != TCL_OK) + return TCL_ERROR; + + for (int i = 0; i < vPtr->length; i++) + v2Ptr->valueArr[i] = (vPtr->valueArr[i] - vPtr->min) / range; + + Vec_UpdateRange(v2Ptr); + if (!isNew) { + if (v2Ptr->flush) { + Vec_FlushCache(v2Ptr); + } + Vec_UpdateClients(v2Ptr); + } + } + else { + Tcl_Obj* listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + for (int i = 0; i < vPtr->length; i++) { + double norm = (vPtr->valueArr[i] - vPtr->min) / range; + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewDoubleObj(norm)); + } + Tcl_SetObjResult(interp, listObjPtr); + } + + return TCL_OK; +} + +static int NotifyOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + enum optionIndices { + OPTION_ALWAYS, OPTION_NEVER, OPTION_WHENIDLE, + OPTION_NOW, OPTION_CANCEL, OPTION_PENDING + }; + static const char *optionArr[] = { + "always", "never", "whenidle", "now", "cancel", "pending", NULL + }; + + int option; + if (Tcl_GetIndexFromObj(interp, objv[2], optionArr, "qualifier", TCL_EXACT, + &option) != TCL_OK) + return TCL_OK; + + switch (option) { + case OPTION_ALWAYS: + vPtr->notifyFlags &= ~NOTIFY_WHEN_MASK; + vPtr->notifyFlags |= NOTIFY_ALWAYS; + break; + case OPTION_NEVER: + vPtr->notifyFlags &= ~NOTIFY_WHEN_MASK; + vPtr->notifyFlags |= NOTIFY_NEVER; + break; + case OPTION_WHENIDLE: + vPtr->notifyFlags &= ~NOTIFY_WHEN_MASK; + vPtr->notifyFlags |= NOTIFY_WHENIDLE; + break; + case OPTION_NOW: + // FIXME: How does this play when an update is pending? + Blt_Vec_NotifyClients(vPtr); + break; + case OPTION_CANCEL: + if (vPtr->notifyFlags & NOTIFY_PENDING) { + vPtr->notifyFlags &= ~NOTIFY_PENDING; + Tcl_CancelIdleCall(Blt_Vec_NotifyClients, (ClientData)vPtr); + } + break; + case OPTION_PENDING: + int boll = (vPtr->notifyFlags & NOTIFY_PENDING); + Tcl_SetBooleanObj(Tcl_GetObjResult(interp), boll); + break; + } + + return TCL_OK; +} + +static int PopulateOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + char* string = Tcl_GetString(objv[2]); + int isNew; + Vector* v2Ptr = Vec_Create(vPtr->dataPtr, string, string, string, &isNew); + if (v2Ptr == NULL) + return TCL_ERROR; + + // Source vector is empty + if (vPtr->length == 0) + return TCL_OK; + + int density; + if (Tcl_GetIntFromObj(interp, objv[3], &density) != TCL_OK) + return TCL_ERROR; + + if (density < 1) { + Tcl_AppendResult(interp, "bad density \"", Tcl_GetString(objv[3]), + "\"", (char *)NULL); + return TCL_ERROR; + } + int size = (vPtr->length - 1) * (density + 1) + 1; + if (Vec_SetLength(interp, v2Ptr, size) != TCL_OK) + return TCL_ERROR; + + int count = 0; + double* valuePtr = v2Ptr->valueArr; + int i; + for (i = 0; i < (vPtr->length - 1); i++) { + double range = vPtr->valueArr[i + 1] - vPtr->valueArr[i]; + double slice = range / (double)(density + 1); + for (int j = 0; j <= density; j++) { + *valuePtr = vPtr->valueArr[i] + (slice * (double)j); + valuePtr++; + count++; + } + } + count++; + *valuePtr = vPtr->valueArr[i]; + if (!isNew) { + if (v2Ptr->flush) + Vec_FlushCache(v2Ptr); + Vec_UpdateClients(v2Ptr); + } + + return TCL_OK; +} + +static int ValuesOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + PrintSwitches switches; + switches.formatObjPtr = NULL; + switches.from = 0; + switches.to = vPtr->length - 1; + indexSwitch.clientData = vPtr; + if (ParseSwitches(interp, printSwitches, objc - 2, objv + 2, &switches, + BLT_SWITCH_DEFAULTS) < 0) + return TCL_ERROR; + + if (switches.from > switches.to) { + // swap positions + int tmp = switches.to; + switches.to = switches.from; + switches.from = tmp; + } + + if (switches.formatObjPtr == NULL) { + Tcl_Obj* listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + for (int i = switches.from; i <= switches.to; i++) + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewDoubleObj(vPtr->valueArr[i])); + + Tcl_SetObjResult(interp, listObjPtr); + } + else { + Tcl_DString ds; + Tcl_DStringInit(&ds); + const char* fmt = Tcl_GetString(switches.formatObjPtr); + for (int i = switches.from; i <= switches.to; i++) { + char buffer[200]; + sprintf(buffer, fmt, vPtr->valueArr[i]); + Tcl_DStringAppend(&ds, buffer, -1); + } + Tcl_DStringResult(interp, &ds); + Tcl_DStringFree(&ds); + } + + return TCL_OK; +} + +static int RangeOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + int first; + int last; + + if (objc == 2) { + first = 0; + last = vPtr->length - 1; + } + else if (objc == 4) { + if ((Vec_GetIndex(interp, vPtr, Tcl_GetString(objv[2]), &first, + INDEX_CHECK, (Blt_VectorIndexProc **) NULL) != TCL_OK) || + (Vec_GetIndex(interp, vPtr, Tcl_GetString(objv[3]), &last, + INDEX_CHECK, (Blt_VectorIndexProc **) NULL) != TCL_OK)) + return TCL_ERROR; + + } + else { + Tcl_AppendResult(interp, "wrong # args: should be \"", + Tcl_GetString(objv[0]), " range ?first last?", + (char *)NULL); + return TCL_ERROR; + } + + Tcl_Obj* listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + if (first > last) { + // Return the list reversed + for (int i=last; i<=first; i++) + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewDoubleObj(vPtr->valueArr[i])); + } + else { + for (int i=first; i<=last; i++) + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewDoubleObj(vPtr->valueArr[i])); + } + + Tcl_SetObjResult(interp, listObjPtr); + + return TCL_OK; +} + +static int InRange(double value, double min, double max) +{ + double range = max - min; + if (range < DBL_EPSILON) + return (fabs(max - value) < DBL_EPSILON); + + double norm = (value - min) / range; + return ((norm >= -DBL_EPSILON) && ((norm - 1.0) < DBL_EPSILON)); +} + +enum NativeFormats { + FMT_UNKNOWN = -1, + FMT_UCHAR, FMT_CHAR, + FMT_USHORT, FMT_SHORT, + FMT_UINT, FMT_INT, + FMT_ULONG, FMT_LONG, + FMT_FLOAT, FMT_DOUBLE +}; + +/* + *--------------------------------------------------------------------------- + * + * GetBinaryFormat + * + * Translates a format string into a native type. Valid formats are + * + * signed i1, i2, i4, i8 + * unsigned u1, u2, u4, u8 + * real r4, r8, r16 + * + * There must be a corresponding native type. For example, this for + * reading 2-byte binary integers from an instrument and converting them + * to unsigned shorts or ints. + * + *--------------------------------------------------------------------------- + */ +static enum NativeFormats GetBinaryFormat(Tcl_Interp* interp, char *string, + int *sizePtr) +{ + char c = tolower(string[0]); + if (Tcl_GetInt(interp, string + 1, sizePtr) != TCL_OK) { + Tcl_AppendResult(interp, "unknown binary format \"", string, + "\": incorrect byte size", (char *)NULL); + return FMT_UNKNOWN; + } + + switch (c) { + case 'r': + if (*sizePtr == sizeof(double)) + return FMT_DOUBLE; + else if (*sizePtr == sizeof(float)) + return FMT_FLOAT; + + break; + + case 'i': + if (*sizePtr == sizeof(char)) + return FMT_CHAR; + else if (*sizePtr == sizeof(int)) + return FMT_INT; + else if (*sizePtr == sizeof(long)) + return FMT_LONG; + else if (*sizePtr == sizeof(short)) + return FMT_SHORT; + + break; + + case 'u': + if (*sizePtr == sizeof(unsigned char)) + return FMT_UCHAR; + else if (*sizePtr == sizeof(unsigned int)) + return FMT_UINT; + else if (*sizePtr == sizeof(unsigned long)) + return FMT_ULONG; + else if (*sizePtr == sizeof(unsigned short)) + return FMT_USHORT; + + break; + + default: + Tcl_AppendResult(interp, "unknown binary format \"", string, + "\": should be either i#, r#, u# (where # is size in bytes)", + (char *)NULL); + return FMT_UNKNOWN; + } + Tcl_AppendResult(interp, "can't handle format \"", string, "\"", + (char *)NULL); + + return FMT_UNKNOWN; +} + +static int CopyValues(Vector *vPtr, char *byteArr, enum NativeFormats fmt, + int size, int length, int swap, int *indexPtr) +{ + if ((swap) && (size > 1)) { + int nBytes = size * length; + for (int i = 0; i < nBytes; i += size) { + unsigned char* p = (unsigned char *)(byteArr + i); + int left, right; + for (left = 0, right = size - 1; left < right; left++, right--) { + p[left] ^= p[right]; + p[right] ^= p[left]; + p[left] ^= p[right]; + } + } + } + + int newSize = *indexPtr + length; + if (newSize > vPtr->length) { + if (Vec_ChangeLength(vPtr->interp, vPtr, newSize) != TCL_OK) + return TCL_ERROR; + } + +#define CopyArrayToVector(vPtr, arr) \ + for (int i = 0, n = *indexPtr; i < length; i++, n++) { \ + (vPtr)->valueArr[n] = (double)(arr)[i]; \ + } + + switch (fmt) { + case FMT_CHAR: + CopyArrayToVector(vPtr, (char *)byteArr); + break; + + case FMT_UCHAR: + CopyArrayToVector(vPtr, (unsigned char *)byteArr); + break; + + case FMT_INT: + CopyArrayToVector(vPtr, (int *)byteArr); + break; + + case FMT_UINT: + CopyArrayToVector(vPtr, (unsigned int *)byteArr); + break; + + case FMT_LONG: + CopyArrayToVector(vPtr, (long *)byteArr); + break; + + case FMT_ULONG: + CopyArrayToVector(vPtr, (unsigned long *)byteArr); + break; + + case FMT_SHORT: + CopyArrayToVector(vPtr, (short int *)byteArr); + break; + + case FMT_USHORT: + CopyArrayToVector(vPtr, (unsigned short int *)byteArr); + break; + + case FMT_FLOAT: + CopyArrayToVector(vPtr, (float *)byteArr); + break; + + case FMT_DOUBLE: + CopyArrayToVector(vPtr, (double *)byteArr); + break; + + case FMT_UNKNOWN: + break; + } + *indexPtr += length; + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * BinreadOp -- + * + * Reads binary values from a TCL channel. Values are either appended to + * the end of the vector or placed at a given index (using the "-at" + * option), overwriting existing values. Data is read until EOF is found + * on the channel or a specified number of values are read. (note that + * this is not necessarily the same as the number of bytes). + * + * The following flags are supported: + * -swap Swap bytes + * -at index Start writing data at the index. + * -format fmt Specifies the format of the data. + * + * This binary reader was created and graciously donated by Harald Kirsch + * (kir@iitb.fhg.de). Anything that's wrong is due to my (gah) munging + * of the code. + * + * Results: + * Returns a standard TCL result. The interpreter result will contain the + * number of values (not the number of bytes) read. + * + * Caveats: + * Channel reads must end on an element boundary. + * + *--------------------------------------------------------------------------- + */ + +static int BinreadOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + enum NativeFormats fmt; + + char* string = Tcl_GetString(objv[2]); + int mode; + Tcl_Channel channel = Tcl_GetChannel(interp, string, &mode); + if (channel == NULL) + return TCL_ERROR; + + if ((mode & TCL_READABLE) == 0) { + Tcl_AppendResult(interp, "channel \"", string, + "\" wasn't opened for reading", (char *)NULL); + return TCL_ERROR; + } + int first = vPtr->length; + fmt = FMT_DOUBLE; + int size = sizeof(double); + int swap = 0; + int count = 0; + + if (objc > 3) { + string = Tcl_GetString(objv[3]); + if (string[0] != '-') { + long int value; + // Get the number of values to read. + if (Tcl_GetLongFromObj(interp, objv[3], &value) != TCL_OK) + return TCL_ERROR; + + if (value < 0) { + Tcl_AppendResult(interp, "count can't be negative", (char *)NULL); + return TCL_ERROR; + } + count = (size_t)value; + objc--, objv++; + } + } + + // Process any option-value pairs that remain. + for (int i = 3; i < objc; i++) { + string = Tcl_GetString(objv[i]); + if (strcmp(string, "-swap") == 0) + swap = 1; + else if (strcmp(string, "-format") == 0) { + i++; + if (i >= objc) { + Tcl_AppendResult(interp, "missing arg after \"", string, + "\"", (char *)NULL); + return TCL_ERROR; + } + + string = Tcl_GetString(objv[i]); + fmt = GetBinaryFormat(interp, string, &size); + if (fmt == FMT_UNKNOWN) + return TCL_ERROR; + } + else if (strcmp(string, "-at") == 0) { + i++; + if (i >= objc) { + Tcl_AppendResult(interp, "missing arg after \"", string, + "\"", (char *)NULL); + return TCL_ERROR; + } + + string = Tcl_GetString(objv[i]); + if (Vec_GetIndex(interp, vPtr, string, &first, 0, + (Blt_VectorIndexProc **)NULL) != TCL_OK) + return TCL_ERROR; + + if (first > vPtr->length) { + Tcl_AppendResult(interp, "index \"", string, + "\" is out of range", (char *)NULL); + return TCL_ERROR; + } + } + } + +#define BUFFER_SIZE 1024 + int arraySize = (count == 0) ? BUFFER_SIZE*size : count*size; + + char* byteArr = (char*)malloc(arraySize); + // FIXME: restore old channel translation later? + if (Tcl_SetChannelOption(interp, channel, "-translation","binary") != TCL_OK) + return TCL_ERROR; + + int total = 0; + while (!Tcl_Eof(channel)) { + int bytesRead = Tcl_Read(channel, byteArr, arraySize); + if (bytesRead < 0) { + Tcl_AppendResult(interp, "error reading channel: ", + Tcl_PosixError(interp), (char *)NULL); + return TCL_ERROR; + } + + if ((bytesRead % size) != 0) { + Tcl_AppendResult(interp, "error reading channel: short read", + (char *)NULL); + return TCL_ERROR; + } + + int length = bytesRead / size; + if (CopyValues(vPtr, byteArr, fmt, size, length, swap, &first) != TCL_OK) + return TCL_ERROR; + + total += length; + if (count > 0) + break; + } + free(byteArr); + + if (vPtr->flush) + Vec_FlushCache(vPtr); + Vec_UpdateClients(vPtr); + + // Set the result as the number of values read + Tcl_SetIntObj(Tcl_GetObjResult(interp), total); + + return TCL_OK; +} + +static int SearchOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + int wantValue = 0; + char* string = Tcl_GetString(objv[2]); + if ((string[0] == '-') && (strcmp(string, "-value") == 0)) { + wantValue = 1; + objv++, objc--; + } + double min; + if (Blt_ExprDoubleFromObj(interp, objv[2], &min) != TCL_OK) + return TCL_ERROR; + + double max = min; + if (objc > 4) { + Tcl_AppendResult(interp, "wrong # arguments: should be \"", + Tcl_GetString(objv[0]), " search ?-value? min ?max?", + (char *)NULL); + return TCL_ERROR; + } + + if ((objc > 3) && (Blt_ExprDoubleFromObj(interp, objv[3], &max) != TCL_OK)) + return TCL_ERROR; + + // Bogus range. Don't bother looking + if ((min - max) >= DBL_EPSILON) + return TCL_OK; + + Tcl_Obj* listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + if (wantValue) { + for (int i = 0; i < vPtr->length; i++) { + if (InRange(vPtr->valueArr[i], min, max)) + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewDoubleObj(vPtr->valueArr[i])); + } + } + else { + for (int i = 0; i < vPtr->length; i++) { + if (InRange(vPtr->valueArr[i], min, max)) + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewIntObj(i + vPtr->offset)); + } + } + Tcl_SetObjResult(interp, listObjPtr); + + return TCL_OK; +} + +static int OffsetOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + if (objc == 3) { + int newOffset; + if (Tcl_GetIntFromObj(interp, objv[2], &newOffset) != TCL_OK) + return TCL_ERROR; + + vPtr->offset = newOffset; + } + Tcl_SetIntObj(Tcl_GetObjResult(interp), vPtr->offset); + + return TCL_OK; +} + +static int RandomOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + for (int i = 0; i < vPtr->length; i++) + vPtr->valueArr[i] = drand48(); + + if (vPtr->flush) + Vec_FlushCache(vPtr); + Vec_UpdateClients(vPtr); + + return TCL_OK; +} + +static int SeqOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + double start; + if (Blt_ExprDoubleFromObj(interp, objv[2], &start) != TCL_OK) + return TCL_ERROR; + + double stop; + if (Blt_ExprDoubleFromObj(interp, objv[3], &stop) != TCL_OK) + return TCL_ERROR; + + int n = vPtr->length; + if ((objc > 4) && (Blt_ExprIntFromObj(interp, objv[4], &n) != TCL_OK)) + return TCL_ERROR; + + if (n > 1) { + if (Vec_SetLength(interp, vPtr, n) != TCL_OK) + return TCL_ERROR; + + double step = (stop - start) / (double)(n - 1); + for (int i = 0; i < n; i++) + vPtr->valueArr[i] = start + (step * i); + + if (vPtr->flush) + Vec_FlushCache(vPtr); + + Vec_UpdateClients(vPtr); + } + return TCL_OK; +} + +static int SetOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + int nElem; + Tcl_Obj **elemObjArr; + + // The source can be either a list of numbers or another vector. + + Vector* v2Ptr = Vec_ParseElement((Tcl_Interp *)NULL, vPtr->dataPtr, + Tcl_GetString(objv[2]), NULL, + NS_SEARCH_BOTH); + int result; + if (v2Ptr != NULL) { + if (vPtr == v2Ptr) { + // Source and destination vectors are the same. Copy the source + // first into a temporary vector to avoid memory overlaps. + Vector* tmpPtr = Vec_New(vPtr->dataPtr); + result = Vec_Duplicate(tmpPtr, v2Ptr); + if (result == TCL_OK) { + result = Vec_Duplicate(vPtr, tmpPtr); + } + Vec_Free(tmpPtr); + } + else + result = Vec_Duplicate(vPtr, v2Ptr); + } + else if (Tcl_ListObjGetElements(interp, objv[2], &nElem, &elemObjArr) + == TCL_OK) + result = CopyList(vPtr, interp, nElem, elemObjArr); + else + return TCL_ERROR; + + if (result == TCL_OK) { + // The vector has changed; so flush the array indices (they're wrong + // now), find the new range of the data, and notify the vector's + //clients that it's been modified. + if (vPtr->flush) + Vec_FlushCache(vPtr); + Vec_UpdateClients(vPtr); + } + + return result; +} + +static int SimplifyOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + double tolerance = 10.0; + + int nPoints = vPtr->length / 2; + int* simple = (int*)malloc(nPoints * sizeof(int)); + Point2d* reduced = (Point2d*)malloc(nPoints * sizeof(Point2d)); + Point2d* orig = (Point2d *)vPtr->valueArr; + int n = Blt_SimplifyLine(orig, 0, nPoints - 1, tolerance, simple); + for (int i = 0; i < n; i++) + reduced[i] = orig[simple[i]]; + + free(simple); + Vec_Reset(vPtr, (double *)reduced, n * 2, vPtr->length, TCL_DYNAMIC); + // The vector has changed; so flush the array indices (they're wrong + // now), find the new range of the data, and notify the vector's + // clients that it's been modified. + if (vPtr->flush) + Vec_FlushCache(vPtr); + Vec_UpdateClients(vPtr); + + return TCL_OK; +} + +static int SplitOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + int nVectors = objc - 2; + if ((vPtr->length % nVectors) != 0) { + Tcl_AppendResult(interp, "can't split vector \"", vPtr->name, + "\" into ", Itoa(nVectors), " even parts.", (char *)NULL); + return TCL_ERROR; + } + + if (nVectors > 0) { + int extra = vPtr->length / nVectors; + for (int i = 0; i < nVectors; i++) { + char* string = Tcl_GetString(objv[i+2]); + int isNew; + Vector* v2Ptr = Vec_Create(vPtr->dataPtr, string, string, string, &isNew); + int oldSize = v2Ptr->length; + int newSize = oldSize + extra; + if (Vec_SetLength(interp, v2Ptr, newSize) != TCL_OK) + return TCL_ERROR; + + int j,k; + for (j = i, k = oldSize; j < vPtr->length; j += nVectors, k++) + v2Ptr->valueArr[k] = vPtr->valueArr[j]; + + Vec_UpdateClients(v2Ptr); + if (v2Ptr->flush) { + Vec_FlushCache(v2Ptr); + } + } + } + return TCL_OK; +} + + +// Pointer to the array of values currently being sorted. +static Vector **sortVectors; +// Indicates the ordering of the sort. If non-zero, the vectors are sorted in +// decreasing order +static int sortDecreasing; +static int nSortVectors; + +static int CompareVectors(void *a, void *b) +{ + int sign = (sortDecreasing) ? -1 : 1; + for (int i = 0; i < nSortVectors; i++) { + Vector* vPtr = sortVectors[i]; + double delta = vPtr->valueArr[*(int *)a] - vPtr->valueArr[*(int *)b]; + if (delta < 0.0) + return (-1 * sign); + else if (delta > 0.0) + return (1 * sign); + } + + return 0; +} + +size_t* Blt::Vec_SortMap(Vector **vectors, int nVectors) +{ + Vector *vPtr = *vectors; + int length = vPtr->last - vPtr->first + 1; + size_t* map = (size_t*)malloc(sizeof(size_t) * length); + for (int i = vPtr->first; i <= vPtr->last; i++) + map[i] = i; + + // Set global variables for sorting routine + sortVectors = vectors; + nSortVectors = nVectors; + qsort((char *)map, length, sizeof(size_t),(QSortCompareProc *)CompareVectors); + + return map; +} + +static size_t* SortVectors(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + + Vector** vectors = (Vector**)malloc(sizeof(Vector *) * (objc + 1)); + vectors[0] = vPtr; + size_t* map = NULL; + for (int i = 0; i < objc; i++) { + Vector* v2Ptr; + if (Vec_LookupName(vPtr->dataPtr, Tcl_GetString(objv[i]), + &v2Ptr) != TCL_OK) + goto error; + + if (v2Ptr->length != vPtr->length) { + Tcl_AppendResult(interp, "vector \"", v2Ptr->name, + "\" is not the same size as \"", vPtr->name, "\"", + (char *)NULL); + goto error; + } + vectors[i + 1] = v2Ptr; + } + map = Vec_SortMap(vectors, objc + 1); + + error: + free(vectors); + + return map; +} + +static int SortOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + sortDecreasing = 0; + SortSwitches switches; + switches.flags = 0; + int i = ParseSwitches(interp, sortSwitches, objc - 2, objv + 2, &switches, + BLT_SWITCH_OBJV_PARTIAL); + if (i < 0) + return TCL_ERROR; + + objc -= i, objv += i; + sortDecreasing = (switches.flags & SORT_DECREASING); + + size_t *map = (objc > 2) ? SortVectors(vPtr, interp, objc - 2, objv + 2) : + Vec_SortMap(&vPtr, 1); + + if (map == NULL) + return TCL_ERROR; + + int sortLength = vPtr->length; + + // Create an array to store a copy of the current values of the + // vector. We'll merge the values back into the vector based upon the + // indices found in the index array. + size_t nBytes = sizeof(double) * sortLength; + double* copy = (double*)malloc(nBytes); + memcpy((char *)copy, (char *)vPtr->valueArr, nBytes); + if (switches.flags & SORT_UNIQUE) { + int count =1; + for (int n = 1; n < sortLength; n++) { + size_t next = map[n]; + size_t prev = map[n - 1]; + if (copy[next] != copy[prev]) { + map[count] = next; + count++; + } + } + sortLength = count; + nBytes = sortLength * sizeof(double); + } + + if (sortLength != vPtr->length) + Vec_SetLength(interp, vPtr, sortLength); + + for (int n = 0; n < sortLength; n++) + vPtr->valueArr[n] = copy[map[n]]; + + if (vPtr->flush) + Vec_FlushCache(vPtr); + Vec_UpdateClients(vPtr); + + // Now sort any other vectors in the same fashion. The vectors must be + // the same size as the map though + int result = TCL_ERROR; + for (int i = 2; i < objc; i++) { + Vector *v2Ptr; + if (Vec_LookupName(vPtr->dataPtr, Tcl_GetString(objv[i]), &v2Ptr) != TCL_OK) + goto error; + + if (sortLength != v2Ptr->length) + Vec_SetLength(interp, v2Ptr, sortLength); + + memcpy((char *)copy, (char *)v2Ptr->valueArr, nBytes); + for (int n = 0; n < sortLength; n++) + v2Ptr->valueArr[n] = copy[map[n]]; + + Vec_UpdateClients(v2Ptr); + if (v2Ptr->flush) + Vec_FlushCache(v2Ptr); + } + result = TCL_OK; + + error: + free(copy); + free(map); + + return result; +} + +static int InstExprOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + if (Blt_ExprVector(interp, Tcl_GetString(objv[2]), (Blt_Vector *)vPtr) != TCL_OK) + return TCL_ERROR; + + if (vPtr->flush) + Vec_FlushCache(vPtr); + Vec_UpdateClients(vPtr); + + return TCL_OK; +} + +static int ArithOp(Vector *vPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + double value; + double scalar; + + Vector* v2Ptr = Vec_ParseElement((Tcl_Interp *)NULL, vPtr->dataPtr, + Tcl_GetString(objv[2]), NULL, + NS_SEARCH_BOTH); + if (v2Ptr != NULL) { + int length = v2Ptr->last - v2Ptr->first + 1; + if (length != vPtr->length) { + Tcl_AppendResult(interp, "vectors \"", Tcl_GetString(objv[0]), + "\" and \"", Tcl_GetString(objv[2]), + "\" are not the same length", (char *)NULL); + return TCL_ERROR; + } + + char* string = Tcl_GetString(objv[1]); + Tcl_Obj* listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + switch (string[0]) { + case '*': + for (int i = 0, j = v2Ptr->first; i < vPtr->length; i++, j++) { + value = vPtr->valueArr[i] * v2Ptr->valueArr[j]; + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(value)); + } + break; + + case '/': + for (int i = 0, j = v2Ptr->first; i < vPtr->length; i++, j++) { + value = vPtr->valueArr[i] / v2Ptr->valueArr[j]; + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(value)); + } + break; + + case '-': + for (int i = 0, j = v2Ptr->first; i < vPtr->length; i++, j++) { + value = vPtr->valueArr[i] - v2Ptr->valueArr[j]; + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(value)); + } + break; + + case '+': + for (int i = 0, j = v2Ptr->first; i < vPtr->length; i++, j++) { + value = vPtr->valueArr[i] + v2Ptr->valueArr[j]; + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(value)); + } + break; + } + Tcl_SetObjResult(interp, listObjPtr); + + } + else if (Blt_ExprDoubleFromObj(interp, objv[2], &scalar) == TCL_OK) { + Tcl_Obj* listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + char* string = Tcl_GetString(objv[1]); + switch (string[0]) { + case '*': + for (int i = 0; i < vPtr->length; i++) { + value = vPtr->valueArr[i] * scalar; + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(value)); + } + break; + + case '/': + for (int i = 0; i < vPtr->length; i++) { + value = vPtr->valueArr[i] / scalar; + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(value)); + } + break; + + case '-': + for (int i = 0; i < vPtr->length; i++) { + value = vPtr->valueArr[i] - scalar; + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(value)); + } + break; + + case '+': + for (int i = 0; i < vPtr->length; i++) { + value = vPtr->valueArr[i] + scalar; + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(value)); + } + break; + } + Tcl_SetObjResult(interp, listObjPtr); + } + else + return TCL_ERROR; + + return TCL_OK; +} + +static Blt_OpSpec vectorInstOps[] = + { + {"*", 1, (void*)ArithOp, 3, 3, "item",}, /*Deprecated*/ + {"+", 1, (void*)ArithOp, 3, 3, "item",}, /*Deprecated*/ + {"-", 1, (void*)ArithOp, 3, 3, "item",}, /*Deprecated*/ + {"/", 1, (void*)ArithOp, 3, 3, "item",}, /*Deprecated*/ + {"append", 1, (void*)AppendOp, 3, 0, "items ?items...?",}, + {"binread", 1, (void*)BinreadOp, 3, 0, "channel ?numValues? ?flags?",}, + {"clear", 1, (void*)ClearOp, 2, 2, "",}, + {"delete", 2, (void*)DeleteOp, 2, 0, "index ?index...?",}, + {"dup", 2, (void*)DupOp, 3, 0, "vecName",}, + {"expr", 1, (void*)InstExprOp, 3, 3, "expression",}, + {"fft", 1, (void*)FFTOp, 3, 0, "vecName ?switches?",}, + {"index", 3, (void*)IndexOp, 3, 4, "index ?value?",}, + {"inversefft",3, (void*)InverseFFTOp,4, 4, "vecName vecName",}, + {"length", 1, (void*)LengthOp, 2, 3, "?newSize?",}, + {"max", 2, (void*)MaxOp, 2, 2, "",}, + {"merge", 2, (void*)MergeOp, 3, 0, "vecName ?vecName...?",}, + {"min", 2, (void*)MinOp, 2, 2, "",}, + {"normalize", 3, (void*)NormalizeOp, 2, 3, "?vecName?",}, /*Deprecated*/ + {"notify", 3, (void*)NotifyOp, 3, 3, "keyword",}, + {"offset", 1, (void*)OffsetOp, 2, 3, "?offset?",}, + {"populate", 1, (void*)PopulateOp, 4, 4, "vecName density",}, + {"random", 4, (void*)RandomOp, 2, 2, "",}, /*Deprecated*/ + {"range", 4, (void*)RangeOp, 2, 4, "first last",}, + {"search", 3, (void*)SearchOp, 3, 5, "?-value? value ?value?",}, + {"seq", 3, (void*)SeqOp, 4, 5, "begin end ?num?",}, + {"set", 3, (void*)SetOp, 3, 3, "list",}, + {"simplify", 2, (void*)SimplifyOp, 2, 2, }, + {"sort", 2, (void*)SortOp, 2, 0, "?switches? ?vecName...?",}, + {"split", 2, (void*)SplitOp, 2, 0, "?vecName...?",}, + {"values", 3, (void*)ValuesOp, 2, 0, "?switches?",}, + {"variable", 3, (void*)MapOp, 2, 3, "?varName?",}, + }; + +static int nInstOps = sizeof(vectorInstOps) / sizeof(Blt_OpSpec); + +int Blt::Vec_InstCmd(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Vector* vPtr = (Vector*)clientData; + vPtr->first = 0; + vPtr->last = vPtr->length - 1; + VectorCmdProc *proc = + (VectorCmdProc*)GetOpFromObj(interp, nInstOps, vectorInstOps, + BLT_OP_ARG1, objc, objv, 0); + if (proc == NULL) + return TCL_ERROR; + + return (*proc) (vPtr, interp, objc, objv); +} + +#define MAX_ERR_MSG 1023 +static char message[MAX_ERR_MSG + 1]; +char* Blt::Vec_VarTrace(ClientData clientData, Tcl_Interp* interp, + const char *part1, const char *part2, int flags) +{ + Blt_VectorIndexProc *indexProc; + Vector* vPtr = (Vector*)clientData; + + if (part2 == NULL) { + if (flags & TCL_TRACE_UNSETS) { + free((void*)(vPtr->arrayName)); + vPtr->arrayName = NULL; + if (vPtr->freeOnUnset) + Vec_Free(vPtr); + } + + return NULL; + } + + int first; + int last; + int varFlags; + + if (Vec_GetIndexRange(interp, vPtr, part2, INDEX_ALL_FLAGS, &indexProc) + != TCL_OK) + goto error; + + first = vPtr->first; + last = vPtr->last; + varFlags = TCL_LEAVE_ERR_MSG | (TCL_GLOBAL_ONLY & flags); + if (flags & TCL_TRACE_WRITES) { + // Tried to set "min" or "max" + if (first == SPECIAL_INDEX) + return (char *)"read-only index"; + + Tcl_Obj* objPtr = Tcl_GetVar2Ex(interp, part1, part2, varFlags); + if (objPtr == NULL) + goto error; + + double value; + if (Blt_ExprDoubleFromObj(interp, objPtr, &value) != TCL_OK) { + // Single numeric index. Reset the array element to + // its old value on errors + if ((last == first) && (first >= 0)) + Tcl_SetVar2Ex(interp, part1, part2, objPtr, varFlags); + goto error; + } + + if (first == vPtr->length) { + if (Vec_ChangeLength((Tcl_Interp *)NULL, vPtr, vPtr->length + 1) + != TCL_OK) + return (char *)"error resizing vector"; + } + + // Set possibly an entire range of values + ReplicateValue(vPtr, first, last, value); + } + else if (flags & TCL_TRACE_READS) { + Tcl_Obj *objPtr; + + if (vPtr->length == 0) { + if (Tcl_SetVar2(interp, part1, part2, "", varFlags) == NULL) + goto error; + + return NULL; + } + + if (first == vPtr->length) + return (char *)"write-only index"; + + if (first == last) { + double value; + if (first >= 0) + value = vPtr->valueArr[first]; + else { + vPtr->first = 0, vPtr->last = vPtr->length - 1; + value = (*indexProc) ((Blt_Vector *) vPtr); + } + + objPtr = Tcl_NewDoubleObj(value); + if (Tcl_SetVar2Ex(interp, part1, part2, objPtr, varFlags) == NULL) { + Tcl_DecrRefCount(objPtr); + goto error; + } + } + else { + objPtr = GetValues(vPtr, first, last); + if (Tcl_SetVar2Ex(interp, part1, part2, objPtr, varFlags) == NULL) + Tcl_DecrRefCount(objPtr); + goto error; + } + } + else if (flags & TCL_TRACE_UNSETS) { + if ((first == vPtr->length) || (first == SPECIAL_INDEX)) + return (char *)"special vector index"; + + // Collapse the vector from the point of the first unset element. + // Also flush any array variable entries so that the shift is + // reflected when the array variable is read. + for (int i = first, j = last + 1; j < vPtr->length; i++, j++) + vPtr->valueArr[i] = vPtr->valueArr[j]; + + vPtr->length -= ((last - first) + 1); + if (vPtr->flush) + Vec_FlushCache(vPtr); + + } + else + return (char *)"unknown variable trace flag"; + + if (flags & (TCL_TRACE_UNSETS | TCL_TRACE_WRITES)) + Vec_UpdateClients(vPtr); + + Tcl_ResetResult(interp); + return NULL; + + error: + strncpy(message, Tcl_GetStringResult(interp), MAX_ERR_MSG); + message[MAX_ERR_MSG] = '\0'; + return message; +} diff --git a/generic/tkbltVecInt.h b/generic/tkbltVecInt.h new file mode 100644 index 0000000..cc516a1 --- /dev/null +++ b/generic/tkbltVecInt.h @@ -0,0 +1,202 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1995-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#include "tkbltChain.h" +#include "tkbltVector.h" + +#define VECTOR_THREAD_KEY "BLT Vector Data" +#define VECTOR_MAGIC ((unsigned int) 0x46170277) + +/* These defines allow parsing of different types of indices */ + +#define INDEX_SPECIAL (1<<0) /* Recognize "min", "max", and "++end" as + * valid indices */ +#define INDEX_COLON (1<<1) /* Also recognize a range of indices separated + * by a colon */ +#define INDEX_CHECK (1<<2) /* Verify that the specified index or range of + * indices are within limits */ +#define INDEX_ALL_FLAGS (INDEX_SPECIAL | INDEX_COLON | INDEX_CHECK) + +#define SPECIAL_INDEX -2 + +#define FFT_NO_CONSTANT (1<<0) +#define FFT_BARTLETT (1<<1) +#define FFT_SPECTRUM (1<<2) + +#define NOTIFY_UPDATED ((int)BLT_VECTOR_NOTIFY_UPDATE) +#define NOTIFY_DESTROYED ((int)BLT_VECTOR_NOTIFY_DESTROY) + +#define NOTIFY_NEVER (1<<3) /* Never notify clients of updates to + * the vector */ +#define NOTIFY_ALWAYS (1<<4) /* Notify clients after each update + * of the vector is made */ +#define NOTIFY_WHENIDLE (1<<5) /* Notify clients at the next idle point + * that the vector has been updated. */ + +#define NOTIFY_PENDING (1<<6) /* A do-when-idle notification of the + * vector's clients is pending. */ +#define NOTIFY_NOW (1<<7) /* Notify clients of changes once + * immediately */ + +#define NOTIFY_WHEN_MASK (NOTIFY_NEVER|NOTIFY_ALWAYS|NOTIFY_WHENIDLE) + +#define UPDATE_RANGE (1<<9) /* The data of the vector has changed. + * Update the min and max limits when + * they are needed */ + +#define FindRange(array, first, last, min, max) \ + { \ + min = max = 0.0; \ + if (first <= last) { \ + register int i; \ + min = max = array[first]; \ + for (i = first + 1; i <= last; i++) { \ + if (min > array[i]) { \ + min = array[i]; \ + } else if (max < array[i]) { \ + max = array[i]; \ + } \ + } \ + } \ + } + +namespace Blt { + + typedef struct { + double x; + double y; + } Point2d; + + typedef struct { + Tcl_HashTable vectorTable; /* Table of vectors */ + Tcl_HashTable mathProcTable; /* Table of vector math functions */ + Tcl_HashTable indexProcTable; + Tcl_Interp* interp; + unsigned int nextId; + } VectorInterpData; + + typedef struct { + // If you change these fields, make sure you change the definition of + // Blt_Vector in blt.h too. + double *valueArr; /* Array of values (malloc-ed) */ + int length; /* Current number of values in the array. */ + int size; /* Maximum number of values that can be stored + * in the value array. */ + double min, max; /* Minimum and maximum values in the vector */ + int dirty; /* Indicates if the vector has been updated */ + int reserved; + + /* The following fields are local to this module */ + + const char *name; /* The namespace-qualified name of the vector. + * It points to the hash key allocated for the + * entry in the vector hash table. */ + VectorInterpData *dataPtr; + Tcl_Interp* interp; /* Interpreter associated with the vector */ + Tcl_HashEntry *hashPtr; /* If non-NULL, pointer in a hash table to + * track the vectors in use. */ + Tcl_FreeProc *freeProc; /* Address of procedure to call to release + * storage for the value array, Optionally can + * be one of the following: TCL_STATIC, + * TCL_DYNAMIC, or TCL_VOLATILE. */ + const char *arrayName; /* The name of the TCL array variable mapped + * to the vector (malloc'ed). If NULL, + * indicates that the vector isn't mapped to + * any variable */ + Tcl_Namespace *nsPtr; /* Namespace context of the vector itself. */ + int offset; /* Offset from zero of the vector's starting + * index */ + Tcl_Command cmdToken; /* Token for vector's TCL command. */ + Chain* chain; /* List of clients using this vector */ + int notifyFlags; /* Notification flags. See definitions + * below */ + int varFlags; /* Indicate if the variable is global, + * namespace, or local */ + int freeOnUnset; /* For backward compatibility only: If + * non-zero, free the vector when its variable + * is unset. */ + int flush; + int first, last; /* Selected region of vector. This is used + * mostly for the math routines */ + } Vector; + + extern const char* Itoa(int value); + extern int Vec_GetIndex(Tcl_Interp* interp, Vector *vPtr, + const char *string, int *indexPtr, int flags, + Blt_VectorIndexProc **procPtrPtr); + extern int Vec_GetIndexRange(Tcl_Interp* interp, Vector *vPtr, + const char *string, int flags, + Blt_VectorIndexProc **procPtrPtr); + extern Vector* Vec_ParseElement(Tcl_Interp* interp, VectorInterpData *dataPtr, + const char *start, const char **endPtr, + int flags); + extern int Vec_SetLength(Tcl_Interp* interp, Vector *vPtr, int length); + extern int Vec_SetSize(Tcl_Interp* interp, Vector *vPtr, int size); + extern void Vec_FlushCache(Vector *vPtr); + extern void Vec_UpdateRange(Vector *vPtr); + extern void Vec_UpdateClients(Vector *vPtr); + extern void Vec_Free(Vector *vPtr); + extern Vector* Vec_New(VectorInterpData *dataPtr); + extern int Vec_MapVariable(Tcl_Interp* interp, Vector *vPtr, + const char *name); + extern int Vec_ChangeLength(Tcl_Interp* interp, Vector *vPtr, int length); + extern Vector* Vec_Create(VectorInterpData *dataPtr, const char *name, + const char *cmdName, const char *varName, + int *newPtr); + extern int Vec_LookupName(VectorInterpData *dataPtr, const char *vecName, + Vector **vPtrPtr); + extern VectorInterpData* Vec_GetInterpData (Tcl_Interp* interp); + extern int Vec_Reset(Vector *vPtr, double *dataArr, int nValues, + int arraySize, Tcl_FreeProc *freeProc); + extern int Vec_FFT(Tcl_Interp* interp, Vector *realPtr, + Vector *phasesPtr, Vector *freqPtr, double delta, + int flags, Vector *srcPtr); + extern int Vec_InverseFFT(Tcl_Interp* interp, Vector *iSrcPtr, + Vector *rDestPtr, Vector *iDestPtr, + Vector *srcPtr); + extern int Vec_Duplicate(Vector *destPtr, Vector *srcPtr); + extern size_t *Vec_SortMap(Vector **vectors, int nVectors); + extern double Vec_Max(Vector *vecObjPtr); + extern double Vec_Min(Vector *vecObjPtr); + extern int ExprVector(Tcl_Interp* interp, char *string, Blt_Vector *vector); + + extern Tcl_ObjCmdProc Vec_InstCmd; + extern Tcl_VarTraceProc Vec_VarTrace; + extern void Vec_InstallMathFunctions(Tcl_HashTable *tablePtr); + extern void Vec_UninstallMathFunctions(Tcl_HashTable *tablePtr); + extern void Vec_InstallSpecialIndices(Tcl_HashTable *tablePtr); +}; + +extern Tcl_IdleProc Blt_Vec_NotifyClients; + +#ifdef _WIN32 +double drand48(void); +void srand48(long int seed); +#endif diff --git a/generic/tkbltVecMath.C b/generic/tkbltVecMath.C new file mode 100644 index 0000000..03277d4 --- /dev/null +++ b/generic/tkbltVecMath.C @@ -0,0 +1,1612 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1995-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#include + +#include "tkbltInt.h" +#include "tkbltVecInt.h" +#include "tkbltNsUtil.h" +#include "tkbltParse.h" + +using namespace std; +using namespace Blt; + +/* + * Three types of math functions: + * + * ComponentProc Function is applied in multiple calls to + * each component of the vector. + * VectorProc Entire vector is passed, each component is + * modified. + * ScalarProc Entire vector is passed, single scalar value + * is returned. + */ + +typedef double (ComponentProc)(double value); +typedef int (VectorProc)(Vector *vPtr); +typedef double (ScalarProc)(Vector *vPtr); + +/* + * Built-in math functions: + */ +typedef int (GenericMathProc) (void*, Tcl_Interp*, Vector*); + +/* + * MathFunction -- + * + * Contains information about math functions that can be called + * for vectors. The table of math functions is global within the + * application. So you can't define two different "sqrt" + * functions. + */ +typedef struct { + const char *name; /* Name of built-in math function. If + * NULL, indicates that the function + * was user-defined and dynamically + * allocated. Function names are + * global across all interpreters. */ + + void *proc; /* Procedure that implements this math + * function. */ + + ClientData clientData; /* Argument to pass when invoking the + * function. */ + +} MathFunction; + +/* The data structure below is used to describe an expression value, + * which can be either a double-precision floating-point value, or a + * string. A given number has only one value at a time. */ + +#define STATIC_STRING_SPACE 150 + +/* + * Tokens -- + * + * The token types are defined below. In addition, there is a + * table associating a precedence with each operator. The order + * of types is important. Consult the code before changing it. + */ +enum Tokens { + VALUE, OPEN_PAREN, CLOSE_PAREN, COMMA, END, UNKNOWN, + MULT = 8, DIVIDE, MOD, PLUS, MINUS, + LEFT_SHIFT, RIGHT_SHIFT, + LESS, GREATER, LEQ, GEQ, EQUAL, NEQ, + OLD_BIT_AND, EXPONENT, OLD_BIT_OR, OLD_QUESTY, OLD_COLON, + AND, OR, UNARY_MINUS, OLD_UNARY_PLUS, NOT, OLD_BIT_NOT +}; + +typedef struct { + Vector *vPtr; + char staticSpace[STATIC_STRING_SPACE]; + ParseValue pv; /* Used to hold a string value, if any. */ +} Value; + +/* + * ParseInfo -- + * + * The data structure below describes the state of parsing an + * expression. It's passed among the routines in this module. + */ +typedef struct { + const char *expr; /* The entire right-hand side of the + * expression, as originally passed to + * Blt_ExprVector. */ + + const char *nextPtr; /* Position of the next character to + * be scanned from the expression + * string. */ + + enum Tokens token; /* Type of the last token to be parsed + * from nextPtr. See below for + * definitions. Corresponds to the + * characters just before nextPtr. */ + +} ParseInfo; + +/* + * Precedence table. The values for non-operator token types are ignored. + */ +static int precTable[] = + { + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 12, 12, /* MULT, DIVIDE, MOD */ + 11, 11, /* PLUS, MINUS */ + 10, 10, /* LEFT_SHIFT, RIGHT_SHIFT */ + 9, 9, 9, 9, /* LESS, GREATER, LEQ, GEQ */ + 8, 8, /* EQUAL, NEQ */ + 7, /* OLD_BIT_AND */ + 13, /* EXPONENTIATION */ + 5, /* OLD_BIT_OR */ + 4, /* AND */ + 3, /* OR */ + 2, /* OLD_QUESTY */ + 1, /* OLD_COLON */ + 14, 14, 14, 14 /* UNARY_MINUS, OLD_UNARY_PLUS, NOT, + * OLD_BIT_NOT */ + }; + + +/* + * Forward declarations. + */ + +static int NextValue(Tcl_Interp* interp, ParseInfo *piPtr, int prec, + Value *valuePtr); + +static int Sort(Vector *vPtr) +{ + size_t* map = Vec_SortMap(&vPtr, 1); + double* values = (double*)malloc(sizeof(double) * vPtr->length); + for(int ii = vPtr->first; ii <= vPtr->last; ii++) + values[ii] = vPtr->valueArr[map[ii]]; + + free(map); + for (int ii = vPtr->first; ii <= vPtr->last; ii++) + vPtr->valueArr[ii] = values[ii]; + + free(values); + return TCL_OK; +} + +static double Length(Blt_Vector *vectorPtr) +{ + Vector *vPtr = (Vector *)vectorPtr; + return (double)(vPtr->last - vPtr->first + 1); +} + +double Blt_VecMax(Blt_Vector *vectorPtr) +{ + Vector *vPtr = (Vector *)vectorPtr; + return Vec_Max(vPtr); +} + +double Blt_VecMin(Blt_Vector *vectorPtr) +{ + Vector *vPtr = (Vector *)vectorPtr; + return Vec_Min(vPtr); +} + +int Blt_ExprVector(Tcl_Interp* interp, char *string, Blt_Vector *vector) +{ + return ExprVector(interp,string,vector); +} + +static double Product(Blt_Vector *vectorPtr) +{ + Vector *vPtr = (Vector *)vectorPtr; + double prod; + double *vp, *vend; + + prod = 1.0; + for(vp = vPtr->valueArr + vPtr->first, + vend = vPtr->valueArr + vPtr->last; vp <= vend; vp++) { + prod *= *vp; + } + return prod; +} + +static double Sum(Blt_Vector *vectorPtr) +{ + // Kahan summation algorithm + + Vector *vPtr = (Vector *)vectorPtr; + double* vp = vPtr->valueArr + vPtr->first; + double sum = *vp++; + double c = 0.0; /* A running compensation for lost + * low-order bits.*/ + for (double* vend = vPtr->valueArr + vPtr->last; vp <= vend; vp++) { + double y = *vp - c; /* So far, so good: c is zero.*/ + double t = sum + y; /* Alas, sum is big, y small, so + * low-order digits of y are lost.*/ + c = (t - sum) - y; /* (t - sum) recovers the high-order + * part of y; subtracting y recovers + * -(low part of y) */ + sum = t; + } + + return sum; +} + +static double Mean(Blt_Vector *vectorPtr) +{ + Vector *vPtr = (Vector *)vectorPtr; + double sum = Sum(vectorPtr); + int n = vPtr->last - vPtr->first + 1; + + return sum / (double)n; +} + +// var = 1/N Sum( (x[i] - mean)^2 ) +static double Variance(Blt_Vector *vectorPtr) +{ + Vector *vPtr = (Vector *)vectorPtr; + double mean = Mean(vectorPtr); + double var = 0.0; + int count = 0; + for(double *vp=vPtr->valueArr+vPtr->first, *vend=vPtr->valueArr+vPtr->last; + vp <= vend; vp++) { + double dx = *vp - mean; + var += dx * dx; + count++; + } + + if (count < 2) + return 0.0; + + var /= (double)(count - 1); + return var; +} + +// skew = Sum( (x[i] - mean)^3 ) / (var^3/2) +static double Skew(Blt_Vector *vectorPtr) +{ + Vector *vPtr = (Vector *)vectorPtr; + double mean = Mean(vectorPtr); + double var = 0; + double skew = 0; + int count = 0; + for(double *vp=vPtr->valueArr+vPtr->first, *vend=vPtr->valueArr+vPtr->last; + vp <= vend; vp++) { + double diff = *vp - mean; + diff = fabs(diff); + double diffsq = diff * diff; + var += diffsq; + skew += diffsq * diff; + count++; + } + + if (count < 2) + return 0.0; + + var /= (double)(count - 1); + skew /= count * var * sqrt(var); + return skew; +} + +static double StdDeviation(Blt_Vector *vectorPtr) +{ + double var; + + var = Variance(vectorPtr); + if (var > 0.0) { + return sqrt(var); + } + return 0.0; +} + +static double AvgDeviation(Blt_Vector *vectorPtr) +{ + Vector *vPtr = (Vector *)vectorPtr; + double mean = Mean(vectorPtr); + double avg = 0.0; + int count = 0; + for(double *vp=vPtr->valueArr+vPtr->first, *vend=vPtr->valueArr+vPtr->last; + vp <= vend; vp++) { + double diff = *vp - mean; + avg += fabs(diff); + count++; + } + + if (count < 2) + return 0.0; + + avg /= (double)count; + return avg; +} + +static double Kurtosis(Blt_Vector *vectorPtr) +{ + Vector *vPtr = (Vector *)vectorPtr; + double mean = Mean(vectorPtr); + double var = 0; + double kurt = 0; + int count = 0; + for(double *vp=vPtr->valueArr+vPtr->first, *vend=vPtr->valueArr+vPtr->last; + vp <= vend; vp++) { + double diff = *vp - mean; + double diffsq = diff * diff; + var += diffsq; + kurt += diffsq * diffsq; + count++; + } + + if (count < 2) + return 0.0; + + var /= (double)(count - 1); + + if (var == 0.0) + return 0.0; + + kurt /= (count * var * var); + return kurt - 3.0; /* Fisher Kurtosis */ +} + +static double Median(Blt_Vector *vectorPtr) +{ + Vector *vPtr = (Vector *)vectorPtr; + size_t *map; + double q2; + int mid; + + if (vPtr->length == 0) { + return -DBL_MAX; + } + map = Vec_SortMap(&vPtr, 1); + mid = (vPtr->length - 1) / 2; + + /* + * Determine Q2 by checking if the number of elements [0..n-1] is + * odd or even. If even, we must take the average of the two + * middle values. + */ + if (vPtr->length & 1) { /* Odd */ + q2 = vPtr->valueArr[map[mid]]; + } else { /* Even */ + q2 = (vPtr->valueArr[map[mid]] + + vPtr->valueArr[map[mid + 1]]) * 0.5; + } + free(map); + return q2; +} + +static double Q1(Blt_Vector *vectorPtr) +{ + Vector *vPtr = (Vector *)vectorPtr; + double q1; + size_t *map; + + if (vPtr->length == 0) { + return -DBL_MAX; + } + map = Vec_SortMap(&vPtr, 1); + + if (vPtr->length < 4) { + q1 = vPtr->valueArr[map[0]]; + } else { + int mid, q; + + mid = (vPtr->length - 1) / 2; + q = mid / 2; + + /* + * Determine Q1 by checking if the number of elements in the + * bottom half [0..mid) is odd or even. If even, we must + * take the average of the two middle values. + */ + if (mid & 1) { /* Odd */ + q1 = vPtr->valueArr[map[q]]; + } else { /* Even */ + q1 = (vPtr->valueArr[map[q]] + + vPtr->valueArr[map[q + 1]]) * 0.5; + } + } + free(map); + return q1; +} + +static double Q3(Blt_Vector *vectorPtr) +{ + Vector *vPtr = (Vector *)vectorPtr; + double q3; + size_t *map; + + if (vPtr->length == 0) { + return -DBL_MAX; + } + + map = Vec_SortMap(&vPtr, 1); + + if (vPtr->length < 4) { + q3 = vPtr->valueArr[map[vPtr->length - 1]]; + } else { + int mid, q; + + mid = (vPtr->length - 1) / 2; + q = (vPtr->length + mid) / 2; + + /* + * Determine Q3 by checking if the number of elements in the + * upper half (mid..n-1] is odd or even. If even, we must + * take the average of the two middle values. + */ + if (mid & 1) { /* Odd */ + q3 = vPtr->valueArr[map[q]]; + } else { /* Even */ + q3 = (vPtr->valueArr[map[q]] + + vPtr->valueArr[map[q + 1]]) * 0.5; + } + } + free(map); + return q3; +} + +static int Norm(Blt_Vector *vector) +{ + Vector *vPtr = (Vector *)vector; + double norm, range, min, max; + int i; + + min = Vec_Min(vPtr); + max = Vec_Max(vPtr); + range = max - min; + for (i = 0; i < vPtr->length; i++) { + norm = (vPtr->valueArr[i] - min) / range; + vPtr->valueArr[i] = norm; + } + return TCL_OK; +} + +static double Nonzeros(Blt_Vector *vector) +{ + Vector *vPtr = (Vector *)vector; + int count; + double *vp, *vend; + + count = 0; + for(vp = vPtr->valueArr + vPtr->first, vend = vPtr->valueArr + vPtr->last; vp <= vend; vp++) { + if (*vp == 0.0) + count++; + } + return (double) count; +} + +static double Fabs(double value) +{ + if (value < 0.0) + return -value; + return value; +} + +static double Round(double value) +{ + if (value < 0.0) + return ceil(value - 0.5); + else + return floor(value + 0.5); +} + +static double Fmod(double x, double y) +{ + if (y == 0.0) + return 0.0; + return x - (floor(x / y) * y); +} + +/* + *--------------------------------------------------------------------------- + * + * MathError -- + * + * This procedure is called when an error occurs during a + * floating-point operation. It reads errno and sets + * interp->result accordingly. + * + * Results: + * Interp->result is set to hold an error message. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ +static void MathError(Tcl_Interp* interp, double value) +{ + if ((errno == EDOM) || (value != value)) { + Tcl_AppendResult(interp, "domain error: argument not in valid range", + (char *)NULL); + Tcl_SetErrorCode(interp, "ARITH", "DOMAIN", + Tcl_GetStringResult(interp), (char *)NULL); + } + else if ((errno == ERANGE) || isinf(value)) { + if (value == 0.0) { + Tcl_AppendResult(interp, + "floating-point value too small to represent", + (char *)NULL); + Tcl_SetErrorCode(interp, "ARITH", "UNDERFLOW", + Tcl_GetStringResult(interp), (char *)NULL); + } + else { + Tcl_AppendResult(interp, + "floating-point value too large to represent", + (char *)NULL); + Tcl_SetErrorCode(interp, "ARITH", "OVERFLOW", + Tcl_GetStringResult(interp), (char *)NULL); + } + } + else { + Tcl_AppendResult(interp, "unknown floating-point error, ", + "errno = ", Itoa(errno), (char *)NULL); + Tcl_SetErrorCode(interp, "ARITH", "UNKNOWN", + Tcl_GetStringResult(interp), (char *)NULL); + } +} + +static int ParseString(Tcl_Interp* interp, const char *string, Value *valuePtr) +{ + const char *endPtr; + double value; + + errno = 0; + + /* + * The string can be either a number or a vector. First try to + * convert the string to a number. If that fails then see if + * we can find a vector by that name. + */ + + value = strtod(string, (char **)&endPtr); + if ((endPtr != string) && (*endPtr == '\0')) { + if (errno != 0) { + Tcl_ResetResult(interp); + MathError(interp, value); + return TCL_ERROR; + } + /* Numbers are stored as single element vectors. */ + if (Vec_ChangeLength(interp, valuePtr->vPtr, 1) != TCL_OK) { + return TCL_ERROR; + } + valuePtr->vPtr->valueArr[0] = value; + return TCL_OK; + } else { + Vector *vPtr; + + while (isspace((unsigned char)(*string))) { + string++; /* Skip spaces leading the vector name. */ + } + vPtr = Vec_ParseElement(interp, valuePtr->vPtr->dataPtr, + string, &endPtr, NS_SEARCH_BOTH); + if (vPtr == NULL) { + return TCL_ERROR; + } + if (*endPtr != '\0') { + Tcl_AppendResult(interp, "extra characters after vector", + (char *)NULL); + return TCL_ERROR; + } + /* Copy the designated vector to our temporary. */ + Vec_Duplicate(valuePtr->vPtr, vPtr); + } + return TCL_OK; +} + +static int ParseMathFunction(Tcl_Interp* interp, const char *start, + ParseInfo *piPtr, Value *valuePtr) +{ + Tcl_HashEntry *hPtr; + MathFunction *mathPtr; /* Info about math function. */ + char *p; + VectorInterpData *dataPtr; /* Interpreter-specific data. */ + GenericMathProc *proc; + + /* + * Find the end of the math function's name and lookup the + * record for the function. + */ + p = (char *)start; + while (isspace((unsigned char)(*p))) { + p++; + } + piPtr->nextPtr = p; + while (isalnum((unsigned char)(*p)) || (*p == '_')) { + p++; + } + if (*p != '(') { + return TCL_RETURN; /* Must start with open parenthesis */ + } + dataPtr = valuePtr->vPtr->dataPtr; + *p = '\0'; + hPtr = Tcl_FindHashEntry(&dataPtr->mathProcTable, piPtr->nextPtr); + *p = '('; + if (hPtr == NULL) { + return TCL_RETURN; /* Name doesn't match any known function */ + } + /* Pick up the single value as the argument to the function */ + piPtr->token = OPEN_PAREN; + piPtr->nextPtr = p + 1; + valuePtr->pv.next = valuePtr->pv.buffer; + if (NextValue(interp, piPtr, -1, valuePtr) != TCL_OK) { + return TCL_ERROR; /* Parse error */ + } + if (piPtr->token != CLOSE_PAREN) { + Tcl_AppendResult(interp, "unmatched parentheses in expression \"", + piPtr->expr, "\"", (char *)NULL); + return TCL_ERROR; /* Missing right parenthesis */ + } + mathPtr = (MathFunction*)Tcl_GetHashValue(hPtr); + proc = (GenericMathProc*)mathPtr->proc; + if ((*proc) (mathPtr->clientData, interp, valuePtr->vPtr) != TCL_OK) { + return TCL_ERROR; /* Function invocation error */ + } + piPtr->token = VALUE; + return TCL_OK; +} + +static int NextToken(Tcl_Interp* interp, ParseInfo *piPtr, Value *valuePtr) +{ + const char *p; + const char *endPtr; + const char *var; + int result; + + p = piPtr->nextPtr; + while (isspace((unsigned char)(*p))) { + p++; + } + if (*p == '\0') { + piPtr->token = END; + piPtr->nextPtr = p; + return TCL_OK; + } + /* + * Try to parse the token as a floating-point number. But check + * that the first character isn't a "-" or "+", which "strtod" + * will happily accept as an unary operator. Otherwise, we might + * accidently treat a binary operator as unary by mistake, which + * will eventually cause a syntax error. + */ + if ((*p != '-') && (*p != '+')) { + double value; + + errno = 0; + value = strtod(p, (char **)&endPtr); + if (endPtr != p) { + if (errno != 0) { + MathError(interp, value); + return TCL_ERROR; + } + piPtr->token = VALUE; + piPtr->nextPtr = endPtr; + + /* + * Save the single floating-point value as an 1-component vector. + */ + if (Vec_ChangeLength(interp, valuePtr->vPtr, 1) != TCL_OK) { + return TCL_ERROR; + } + valuePtr->vPtr->valueArr[0] = value; + return TCL_OK; + } + } + piPtr->nextPtr = p + 1; + switch (*p) { + case '$': + piPtr->token = VALUE; + var = Tcl_ParseVar(interp, p, &endPtr); + if (var == NULL) { + return TCL_ERROR; + } + piPtr->nextPtr = endPtr; + Tcl_ResetResult(interp); + result = ParseString(interp, var, valuePtr); + return result; + + case '[': + piPtr->token = VALUE; + result = ParseNestedCmd(interp, p + 1, 0, &endPtr, &valuePtr->pv); + if (result != TCL_OK) { + return result; + } + piPtr->nextPtr = endPtr; + Tcl_ResetResult(interp); + result = ParseString(interp, valuePtr->pv.buffer, valuePtr); + return result; + + case '"': + piPtr->token = VALUE; + result = ParseQuotes(interp, p + 1, '"', 0, &endPtr, &valuePtr->pv); + if (result != TCL_OK) { + return result; + } + piPtr->nextPtr = endPtr; + Tcl_ResetResult(interp); + result = ParseString(interp, valuePtr->pv.buffer, valuePtr); + return result; + + case '{': + piPtr->token = VALUE; + result = ParseBraces(interp, p + 1, &endPtr, &valuePtr->pv); + if (result != TCL_OK) { + return result; + } + piPtr->nextPtr = endPtr; + Tcl_ResetResult(interp); + result = ParseString(interp, valuePtr->pv.buffer, valuePtr); + return result; + + case '(': + piPtr->token = OPEN_PAREN; + break; + + case ')': + piPtr->token = CLOSE_PAREN; + break; + + case ',': + piPtr->token = COMMA; + break; + + case '*': + piPtr->token = MULT; + break; + + case '/': + piPtr->token = DIVIDE; + break; + + case '%': + piPtr->token = MOD; + break; + + case '+': + piPtr->token = PLUS; + break; + + case '-': + piPtr->token = MINUS; + break; + + case '^': + piPtr->token = EXPONENT; + break; + + case '<': + switch (*(p + 1)) { + case '<': + piPtr->nextPtr = p + 2; + piPtr->token = LEFT_SHIFT; + break; + case '=': + piPtr->nextPtr = p + 2; + piPtr->token = LEQ; + break; + default: + piPtr->token = LESS; + break; + } + break; + + case '>': + switch (*(p + 1)) { + case '>': + piPtr->nextPtr = p + 2; + piPtr->token = RIGHT_SHIFT; + break; + case '=': + piPtr->nextPtr = p + 2; + piPtr->token = GEQ; + break; + default: + piPtr->token = GREATER; + break; + } + break; + + case '=': + if (*(p + 1) == '=') { + piPtr->nextPtr = p + 2; + piPtr->token = EQUAL; + } else { + piPtr->token = UNKNOWN; + } + break; + + case '&': + if (*(p + 1) == '&') { + piPtr->nextPtr = p + 2; + piPtr->token = AND; + } else { + piPtr->token = UNKNOWN; + } + break; + + case '|': + if (*(p + 1) == '|') { + piPtr->nextPtr = p + 2; + piPtr->token = OR; + } else { + piPtr->token = UNKNOWN; + } + break; + + case '!': + if (*(p + 1) == '=') { + piPtr->nextPtr = p + 2; + piPtr->token = NEQ; + } else { + piPtr->token = NOT; + } + break; + + default: + piPtr->token = VALUE; + result = ParseMathFunction(interp, p, piPtr, valuePtr); + if ((result == TCL_OK) || (result == TCL_ERROR)) { + return result; + } else { + Vector *vPtr; + + while (isspace((unsigned char)(*p))) { + p++; /* Skip spaces leading the vector name. */ + } + vPtr = Vec_ParseElement(interp, valuePtr->vPtr->dataPtr, + p, &endPtr, NS_SEARCH_BOTH); + if (vPtr == NULL) { + return TCL_ERROR; + } + Vec_Duplicate(valuePtr->vPtr, vPtr); + piPtr->nextPtr = endPtr; + } + } + return TCL_OK; +} + +static int NextValue(Tcl_Interp* interp, ParseInfo *piPtr, + int prec, Value *valuePtr) +{ + Value value2; /* Second operand for current operator. */ + int oper; /* Current operator (either unary or binary). */ + int gotOp; /* Non-zero means already lexed the operator + * (while picking up value for unary operator). + * Don't lex again. */ + int result; + Vector *vPtr, *v2Ptr; + int i; + + /* + * There are two phases to this procedure. First, pick off an initial + * value. Then, parse (binary operator, value) pairs until done. + */ + + vPtr = valuePtr->vPtr; + v2Ptr = Vec_New(vPtr->dataPtr); + gotOp = 0; + value2.vPtr = v2Ptr; + value2.pv.buffer = value2.pv.next = value2.staticSpace; + value2.pv.end = value2.pv.buffer + STATIC_STRING_SPACE - 1; + value2.pv.expandProc = ExpandParseValue; + value2.pv.clientData = NULL; + + result = NextToken(interp, piPtr, valuePtr); + if (result != TCL_OK) { + goto done; + } + if (piPtr->token == OPEN_PAREN) { + + /* Parenthesized sub-expression. */ + + result = NextValue(interp, piPtr, -1, valuePtr); + if (result != TCL_OK) { + goto done; + } + if (piPtr->token != CLOSE_PAREN) { + Tcl_AppendResult(interp, "unmatched parentheses in expression \"", + piPtr->expr, "\"", (char *)NULL); + result = TCL_ERROR; + goto done; + } + } else { + if (piPtr->token == MINUS) { + piPtr->token = UNARY_MINUS; + } + if (piPtr->token >= UNARY_MINUS) { + oper = piPtr->token; + result = NextValue(interp, piPtr, precTable[oper], valuePtr); + if (result != TCL_OK) { + goto done; + } + gotOp = 1; + /* Process unary operators. */ + switch (oper) { + case UNARY_MINUS: + for(i = 0; i < vPtr->length; i++) { + vPtr->valueArr[i] = -(vPtr->valueArr[i]); + } + break; + + case NOT: + for(i = 0; i < vPtr->length; i++) { + vPtr->valueArr[i] = (double)(!vPtr->valueArr[i]); + } + break; + default: + Tcl_AppendResult(interp, "unknown operator", (char *)NULL); + goto error; + } + } else if (piPtr->token != VALUE) { + Tcl_AppendResult(interp, "missing operand", (char *)NULL); + goto error; + } + } + if (!gotOp) { + result = NextToken(interp, piPtr, &value2); + if (result != TCL_OK) { + goto done; + } + } + /* + * Got the first operand. Now fetch (operator, operand) pairs. + */ + for (;;) { + oper = piPtr->token; + + value2.pv.next = value2.pv.buffer; + if ((oper < MULT) || (oper >= UNARY_MINUS)) { + if ((oper == END) || (oper == CLOSE_PAREN) || + (oper == COMMA)) { + result = TCL_OK; + goto done; + } else { + Tcl_AppendResult(interp, "bad operator", (char *)NULL); + goto error; + } + } + if (precTable[oper] <= prec) { + result = TCL_OK; + goto done; + } + result = NextValue(interp, piPtr, precTable[oper], &value2); + if (result != TCL_OK) { + goto done; + } + if ((piPtr->token < MULT) && (piPtr->token != VALUE) && + (piPtr->token != END) && (piPtr->token != CLOSE_PAREN) && + (piPtr->token != COMMA)) { + Tcl_AppendResult(interp, "unexpected token in expression", + (char *)NULL); + goto error; + } + /* + * At this point we have two vectors and an operator. + */ + + if (v2Ptr->length == 1) { + double *opnd; + double scalar; + + /* + * 2nd operand is a scalar. + */ + scalar = v2Ptr->valueArr[0]; + opnd = vPtr->valueArr; + switch (oper) { + case MULT: + for(i = 0; i < vPtr->length; i++) { + opnd[i] *= scalar; + } + break; + + case DIVIDE: + if (scalar == 0.0) { + Tcl_AppendResult(interp, "divide by zero", (char *)NULL); + goto error; + } + for(i = 0; i < vPtr->length; i++) { + opnd[i] /= scalar; + } + break; + + case PLUS: + for(i = 0; i < vPtr->length; i++) { + opnd[i] += scalar; + } + break; + + case MINUS: + for(i = 0; i < vPtr->length; i++) { + opnd[i] -= scalar; + } + break; + + case EXPONENT: + for(i = 0; i < vPtr->length; i++) { + opnd[i] = pow(opnd[i], scalar); + } + break; + + case MOD: + for(i = 0; i < vPtr->length; i++) { + opnd[i] = Fmod(opnd[i], scalar); + } + break; + + case LESS: + for(i = 0; i < vPtr->length; i++) { + opnd[i] = (double)(opnd[i] < scalar); + } + break; + + case GREATER: + for(i = 0; i < vPtr->length; i++) { + opnd[i] = (double)(opnd[i] > scalar); + } + break; + + case LEQ: + for(i = 0; i < vPtr->length; i++) { + opnd[i] = (double)(opnd[i] <= scalar); + } + break; + + case GEQ: + for(i = 0; i < vPtr->length; i++) { + opnd[i] = (double)(opnd[i] >= scalar); + } + break; + + case EQUAL: + for(i = 0; i < vPtr->length; i++) { + opnd[i] = (double)(opnd[i] == scalar); + } + break; + + case NEQ: + for(i = 0; i < vPtr->length; i++) { + opnd[i] = (double)(opnd[i] != scalar); + } + break; + + case AND: + for(i = 0; i < vPtr->length; i++) { + opnd[i] = (double)(opnd[i] && scalar); + } + break; + + case OR: + for(i = 0; i < vPtr->length; i++) { + opnd[i] = (double)(opnd[i] || scalar); + } + break; + + case LEFT_SHIFT: + { + int offset; + + offset = (int)scalar % vPtr->length; + if (offset > 0) { + double *hold; + int j; + + hold = (double*)malloc(sizeof(double) * offset); + for (i = 0; i < offset; i++) { + hold[i] = opnd[i]; + } + for (i = offset, j = 0; i < vPtr->length; i++, j++) { + opnd[j] = opnd[i]; + } + for (i = 0, j = vPtr->length - offset; + j < vPtr->length; i++, j++) { + opnd[j] = hold[i]; + } + free(hold); + } + } + break; + + case RIGHT_SHIFT: + { + int offset; + + offset = (int)scalar % vPtr->length; + if (offset > 0) { + double *hold; + int j; + + hold = (double*)malloc(sizeof(double) * offset); + for (i = vPtr->length - offset, j = 0; + i < vPtr->length; i++, j++) { + hold[j] = opnd[i]; + } + for (i = vPtr->length - offset - 1, + j = vPtr->length - 1; i >= 0; i--, j--) { + opnd[j] = opnd[i]; + } + for (i = 0; i < offset; i++) { + opnd[i] = hold[i]; + } + free(hold); + } + } + break; + + default: + Tcl_AppendResult(interp, "unknown operator in expression", + (char *)NULL); + goto error; + } + + } else if (vPtr->length == 1) { + double *opnd; + double scalar; + + /* + * 1st operand is a scalar. + */ + scalar = vPtr->valueArr[0]; + Vec_Duplicate(vPtr, v2Ptr); + opnd = vPtr->valueArr; + switch (oper) { + case MULT: + for(i = 0; i < vPtr->length; i++) { + opnd[i] *= scalar; + } + break; + + case PLUS: + for(i = 0; i < vPtr->length; i++) { + opnd[i] += scalar; + } + break; + + case DIVIDE: + for(i = 0; i < vPtr->length; i++) { + if (opnd[i] == 0.0) { + Tcl_AppendResult(interp, "divide by zero", + (char *)NULL); + goto error; + } + opnd[i] = (scalar / opnd[i]); + } + break; + + case MINUS: + for(i = 0; i < vPtr->length; i++) { + opnd[i] = scalar - opnd[i]; + } + break; + + case EXPONENT: + for(i = 0; i < vPtr->length; i++) { + opnd[i] = pow(scalar, opnd[i]); + } + break; + + case MOD: + for(i = 0; i < vPtr->length; i++) { + opnd[i] = Fmod(scalar, opnd[i]); + } + break; + + case LESS: + for(i = 0; i < vPtr->length; i++) { + opnd[i] = (double)(scalar < opnd[i]); + } + break; + + case GREATER: + for(i = 0; i < vPtr->length; i++) { + opnd[i] = (double)(scalar > opnd[i]); + } + break; + + case LEQ: + for(i = 0; i < vPtr->length; i++) { + opnd[i] = (double)(scalar >= opnd[i]); + } + break; + + case GEQ: + for(i = 0; i < vPtr->length; i++) { + opnd[i] = (double)(scalar <= opnd[i]); + } + break; + + case EQUAL: + for(i = 0; i < vPtr->length; i++) { + opnd[i] = (double)(opnd[i] == scalar); + } + break; + + case NEQ: + for(i = 0; i < vPtr->length; i++) { + opnd[i] = (double)(opnd[i] != scalar); + } + break; + + case AND: + for(i = 0; i < vPtr->length; i++) { + opnd[i] = (double)(opnd[i] && scalar); + } + break; + + case OR: + for(i = 0; i < vPtr->length; i++) { + opnd[i] = (double)(opnd[i] || scalar); + } + break; + + case LEFT_SHIFT: + case RIGHT_SHIFT: + Tcl_AppendResult(interp, "second shift operand must be scalar", + (char *)NULL); + goto error; + + default: + Tcl_AppendResult(interp, "unknown operator in expression", + (char *)NULL); + goto error; + } + } else { + double *opnd1, *opnd2; + /* + * Carry out the function of the specified operator. + */ + if (vPtr->length != v2Ptr->length) { + Tcl_AppendResult(interp, "vectors are different lengths", + (char *)NULL); + goto error; + } + opnd1 = vPtr->valueArr, opnd2 = v2Ptr->valueArr; + switch (oper) { + case MULT: + for (i = 0; i < vPtr->length; i++) { + opnd1[i] *= opnd2[i]; + } + break; + + case DIVIDE: + for (i = 0; i < vPtr->length; i++) { + if (opnd2[i] == 0.0) { + Tcl_AppendResult(interp, + "can't divide by 0.0 vector component", + (char *)NULL); + goto error; + } + opnd1[i] /= opnd2[i]; + } + break; + + case PLUS: + for (i = 0; i < vPtr->length; i++) { + opnd1[i] += opnd2[i]; + } + break; + + case MINUS: + for (i = 0; i < vPtr->length; i++) { + opnd1[i] -= opnd2[i]; + } + break; + + case MOD: + for (i = 0; i < vPtr->length; i++) { + opnd1[i] = Fmod(opnd1[i], opnd2[i]); + } + break; + + case EXPONENT: + for (i = 0; i < vPtr->length; i++) { + opnd1[i] = pow(opnd1[i], opnd2[i]); + } + break; + + case LESS: + for (i = 0; i < vPtr->length; i++) { + opnd1[i] = (double)(opnd1[i] < opnd2[i]); + } + break; + + case GREATER: + for (i = 0; i < vPtr->length; i++) { + opnd1[i] = (double)(opnd1[i] > opnd2[i]); + } + break; + + case LEQ: + for (i = 0; i < vPtr->length; i++) { + opnd1[i] = (double)(opnd1[i] <= opnd2[i]); + } + break; + + case GEQ: + for (i = 0; i < vPtr->length; i++) { + opnd1[i] = (double)(opnd1[i] >= opnd2[i]); + } + break; + + case EQUAL: + for (i = 0; i < vPtr->length; i++) { + opnd1[i] = (double)(opnd1[i] == opnd2[i]); + } + break; + + case NEQ: + for (i = 0; i < vPtr->length; i++) { + opnd1[i] = (double)(opnd1[i] != opnd2[i]); + } + break; + + case AND: + for (i = 0; i < vPtr->length; i++) { + opnd1[i] = (double)(opnd1[i] && opnd2[i]); + } + break; + + case OR: + for (i = 0; i < vPtr->length; i++) { + opnd1[i] = (double)(opnd1[i] || opnd2[i]); + } + break; + + case LEFT_SHIFT: + case RIGHT_SHIFT: + Tcl_AppendResult(interp, "second shift operand must be scalar", + (char *)NULL); + goto error; + + default: + Tcl_AppendResult(interp, "unknown operator in expression", + (char *)NULL); + goto error; + } + } + } + done: + if (value2.pv.buffer != value2.staticSpace) { + free(value2.pv.buffer); + } + Vec_Free(v2Ptr); + return result; + + error: + if (value2.pv.buffer != value2.staticSpace) { + free(value2.pv.buffer); + } + Vec_Free(v2Ptr); + return TCL_ERROR; +} + +static int EvaluateExpression(Tcl_Interp* interp, char *string, + Value *valuePtr) +{ + ParseInfo info; + int result; + Vector *vPtr; + double *vp, *vend; + + info.expr = info.nextPtr = string; + valuePtr->pv.buffer = valuePtr->pv.next = valuePtr->staticSpace; + valuePtr->pv.end = valuePtr->pv.buffer + STATIC_STRING_SPACE - 1; + valuePtr->pv.expandProc = ExpandParseValue; + valuePtr->pv.clientData = NULL; + + result = NextValue(interp, &info, -1, valuePtr); + if (result != TCL_OK) { + return result; + } + if (info.token != END) { + Tcl_AppendResult(interp, ": syntax error in expression \"", + string, "\"", (char *)NULL); + return TCL_ERROR; + } + vPtr = valuePtr->vPtr; + + /* Check for NaN's and overflows. */ + for (vp = vPtr->valueArr, vend = vp + vPtr->length; vp < vend; vp++) { + if (!isfinite(*vp)) { + /* + * IEEE floating-point error. + */ + MathError(interp, *vp); + return TCL_ERROR; + } + } + return TCL_OK; +} + +static int ComponentFunc(ClientData clientData, Tcl_Interp* interp, + Vector *vPtr) +{ + ComponentProc *procPtr = (ComponentProc *) clientData; + double *vp, *vend; + + errno = 0; + for(vp = vPtr->valueArr + vPtr->first, + vend = vPtr->valueArr + vPtr->last; vp <= vend; vp++) { + *vp = (*procPtr) (*vp); + if (errno != 0) { + MathError(interp, *vp); + return TCL_ERROR; + } + if (!isfinite(*vp)) { + /* + * IEEE floating-point error. + */ + MathError(interp, *vp); + return TCL_ERROR; + } + } + return TCL_OK; +} + +static int ScalarFunc(ClientData clientData, Tcl_Interp* interp, Vector *vPtr) +{ + double value; + ScalarProc *procPtr = (ScalarProc *) clientData; + + errno = 0; + value = (*procPtr) (vPtr); + if (errno != 0) { + MathError(interp, value); + return TCL_ERROR; + } + if (Vec_ChangeLength(interp, vPtr, 1) != TCL_OK) { + return TCL_ERROR; + } + vPtr->valueArr[0] = value; + return TCL_OK; +} + +static int VectorFunc(ClientData clientData, Tcl_Interp* interp, Vector *vPtr) +{ + VectorProc *procPtr = (VectorProc *) clientData; + + return (*procPtr) (vPtr); +} + + +static MathFunction mathFunctions[] = + { + {"abs", (void*)ComponentFunc, (ClientData)Fabs}, + {"acos", (void*)ComponentFunc, (ClientData)(double (*)(double))acos}, + {"asin", (void*)ComponentFunc, (ClientData)(double (*)(double))asin}, + {"atan", (void*)ComponentFunc, (ClientData)(double (*)(double))atan}, + {"adev", (void*)ScalarFunc, (ClientData)AvgDeviation}, + {"ceil", (void*)ComponentFunc, (ClientData)(double (*)(double))ceil}, + {"cos", (void*)ComponentFunc, (ClientData)(double (*)(double))cos}, + {"cosh", (void*)ComponentFunc, (ClientData)(double (*)(double))cosh}, + {"exp", (void*)ComponentFunc, (ClientData)(double (*)(double))exp}, + {"floor", (void*)ComponentFunc, (ClientData)(double (*)(double))floor}, + {"kurtosis",(void*)ScalarFunc, (ClientData)Kurtosis}, + {"length", (void*)ScalarFunc, (ClientData)Length}, + {"log", (void*)ComponentFunc, (ClientData)(double (*)(double))log}, + {"log10", (void*)ComponentFunc, (ClientData)(double (*)(double))log10}, + {"max", (void*)ScalarFunc, (ClientData)Blt_VecMax}, + {"mean", (void*)ScalarFunc, (ClientData)Mean}, + {"median", (void*)ScalarFunc, (ClientData)Median}, + {"min", (void*)ScalarFunc, (ClientData)Blt_VecMin}, + {"norm", (void*)VectorFunc, (ClientData)Norm}, + {"nz", (void*)ScalarFunc, (ClientData)Nonzeros}, + {"q1", (void*)ScalarFunc, (ClientData)Q1}, + {"q3", (void*)ScalarFunc, (ClientData)Q3}, + {"prod", (void*)ScalarFunc, (ClientData)Product}, + {"random", (void*)ComponentFunc, (ClientData)drand48}, + {"round", (void*)ComponentFunc, (ClientData)Round}, + {"sdev", (void*)ScalarFunc, (ClientData)StdDeviation}, + {"sin", (void*)ComponentFunc, (ClientData)(double (*)(double))sin}, + {"sinh", (void*)ComponentFunc, (ClientData)(double (*)(double))sinh}, + {"skew", (void*)ScalarFunc, (ClientData)Skew}, + {"sort", (void*)VectorFunc, (ClientData)Sort}, + {"sqrt", (void*)ComponentFunc, (ClientData)(double (*)(double))sqrt}, + {"sum", (void*)ScalarFunc, (ClientData)Sum}, + {"tan", (void*)ComponentFunc, (ClientData)(double (*)(double))tan}, + {"tanh", (void*)ComponentFunc, (ClientData)(double (*)(double))tanh}, + {"var", (void*)ScalarFunc, (ClientData)Variance}, + {(char *)NULL,}, + }; + +void Blt::Vec_InstallMathFunctions(Tcl_HashTable *tablePtr) +{ + MathFunction *mathPtr; + + for (mathPtr = mathFunctions; mathPtr->name != NULL; mathPtr++) { + Tcl_HashEntry *hPtr; + int isNew; + + hPtr = Tcl_CreateHashEntry(tablePtr, mathPtr->name, &isNew); + Tcl_SetHashValue(hPtr, (ClientData)mathPtr); + } +} + +void Blt::Vec_UninstallMathFunctions(Tcl_HashTable *tablePtr) +{ + Tcl_HashEntry *hPtr; + Tcl_HashSearch cursor; + + for (hPtr = Tcl_FirstHashEntry(tablePtr, &cursor); hPtr != NULL; + hPtr = Tcl_NextHashEntry(&cursor)) { + MathFunction *mathPtr = (MathFunction*)Tcl_GetHashValue(hPtr); + if (mathPtr->name == NULL) + free(mathPtr); + } +} + +static void InstallIndexProc(Tcl_HashTable *tablePtr, const char *string, + Blt_VectorIndexProc *procPtr) +{ + Tcl_HashEntry *hPtr; + int dummy; + + hPtr = Tcl_CreateHashEntry(tablePtr, string, &dummy); + if (procPtr == NULL) + Tcl_DeleteHashEntry(hPtr); + else + Tcl_SetHashValue(hPtr, (ClientData)procPtr); +} + +void Blt::Vec_InstallSpecialIndices(Tcl_HashTable *tablePtr) +{ + InstallIndexProc(tablePtr, "min", Blt_VecMin); + InstallIndexProc(tablePtr, "max", Blt_VecMax); + InstallIndexProc(tablePtr, "mean", Mean); + InstallIndexProc(tablePtr, "sum", Sum); + InstallIndexProc(tablePtr, "prod", Product); +} + +int Blt::ExprVector(Tcl_Interp* interp, char *string, Blt_Vector *vector) +{ + VectorInterpData *dataPtr; /* Interpreter-specific data. */ + Vector *vPtr = (Vector *)vector; + Value value; + + dataPtr = (vector != NULL) ? vPtr->dataPtr : Vec_GetInterpData(interp); + value.vPtr = Vec_New(dataPtr); + if (EvaluateExpression(interp, string, &value) != TCL_OK) { + Vec_Free(value.vPtr); + return TCL_ERROR; + } + if (vPtr != NULL) { + Vec_Duplicate(vPtr, value.vPtr); + } else { + Tcl_Obj *listObjPtr; + double *vp, *vend; + + /* No result vector. Put values in interp->result. */ + listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); + for (vp = value.vPtr->valueArr, vend = vp + value.vPtr->length; + vp < vend; vp++) { + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(*vp)); + } + Tcl_SetObjResult(interp, listObjPtr); + } + Vec_Free(value.vPtr); + return TCL_OK; +} + +#ifdef _WIN32 +double drand48(void) +{ + return (double)rand() / (double)RAND_MAX; +} + +void srand48(long int seed) +{ + srand(seed); +} +#endif diff --git a/generic/tkbltVecOp.C b/generic/tkbltVecOp.C new file mode 100644 index 0000000..6c84723 --- /dev/null +++ b/generic/tkbltVecOp.C @@ -0,0 +1,56 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1991-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "tkbltVecInt.h" + +using namespace Blt; + +extern Tcl_ObjCmdProc VectorObjCmd; + +int Blt_VectorCmdInitProc(Tcl_Interp* interp) +{ + + Tcl_Namespace* nsPtr = Tcl_FindNamespace(interp, "::blt", NULL, + TCL_LEAVE_ERR_MSG); + if (nsPtr == NULL) + return TCL_ERROR; + + const char* cmdPath = "::blt::vector"; + Tcl_Command cmdToken = Tcl_FindCommand(interp, cmdPath, NULL, 0); + if (cmdToken) + return TCL_OK; + cmdToken = Tcl_CreateObjCommand(interp, cmdPath, VectorObjCmd, + Vec_GetInterpData(interp), NULL); + if (Tcl_Export(interp, nsPtr, "vector", 0) != TCL_OK) + return TCL_ERROR; + + return TCL_OK; +} diff --git a/generic/tkbltVector.C b/generic/tkbltVector.C new file mode 100644 index 0000000..0837917 --- /dev/null +++ b/generic/tkbltVector.C @@ -0,0 +1,1875 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1995-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * TODO: + * o Add H. Kirsch's vector binary read operation + * x binread file0 + * x binread -file file0 + * + * o Add ASCII/binary file reader + * x read fileName + * + * o Allow Tcl-based client notifications. + * vector x + * x notify call Display + * x notify delete Display + * x notify reorder #1 #2 + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "tkbltInt.h" +#include "tkbltVecInt.h" +#include "tkbltNsUtil.h" +#include "tkbltSwitch.h" +#include "tkbltOp.h" + +using namespace Blt; + +#define DEF_ARRAY_SIZE 64 +#define TRACE_ALL (TCL_TRACE_WRITES | TCL_TRACE_READS | TCL_TRACE_UNSETS) + + +#define VECTOR_CHAR(c) ((isalnum((unsigned char)(c))) || \ + (c == '_') || (c == ':') || (c == '@') || (c == '.')) + +/* + * VectorClient -- + * + * A vector can be shared by several clients. Each client allocates this + * structure that acts as its key for using the vector. Clients can also + * designate a callback routine that is executed whenever the vector is + * updated or destroyed. + * + */ +typedef struct { + unsigned int magic; /* Magic value designating whether this really + * is a vector token or not */ + Vector* serverPtr; /* Pointer to the master record of the vector. + * If NULL, indicates that the vector has been + * destroyed but as of yet, this client hasn't + * recognized it. */ + Blt_VectorChangedProc *proc;/* Routine to call when the contents of the + * vector change or the vector is deleted. */ + ClientData clientData; /* Data passed whenever the vector change + * procedure is called. */ + ChainLink* link; /* Used to quickly remove this entry from its + * server's client chain. */ +} VectorClient; + +static Tcl_CmdDeleteProc VectorInstDeleteProc; +extern Tcl_ObjCmdProc VectorObjCmd; +static Tcl_InterpDeleteProc VectorInterpDeleteProc; + +typedef struct { + char *varName; /* Requested variable name. */ + char *cmdName; /* Requested command name. */ + int flush; /* Flush */ + int watchUnset; /* Watch when variable is unset. */ +} CreateSwitches; + +static Blt_SwitchSpec createSwitches[] = + { + {BLT_SWITCH_STRING, "-variable", "varName", + Tk_Offset(CreateSwitches, varName), BLT_SWITCH_NULL_OK}, + {BLT_SWITCH_STRING, "-command", "command", + Tk_Offset(CreateSwitches, cmdName), BLT_SWITCH_NULL_OK}, + {BLT_SWITCH_BOOLEAN, "-watchunset", "bool", + Tk_Offset(CreateSwitches, watchUnset), 0}, + {BLT_SWITCH_BOOLEAN, "-flush", "bool", + Tk_Offset(CreateSwitches, flush), 0}, + {BLT_SWITCH_END} + }; + +typedef int (VectorCmdProc)(Vector* vecObjPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]); + +static char stringRep[200]; + +const char *Blt::Itoa(int value) +{ + snprintf(stringRep, 200, "%d", value); + return stringRep; +} + +static char* Blt_Strdup(const char *string) +{ + size_t size = strlen(string) + 1; + char* ptr = (char*)malloc(size * sizeof(char)); + if (ptr != NULL) + strcpy(ptr, string); + + return ptr; +} + +static Vector* FindVectorInNamespace(VectorInterpData *dataPtr, + Blt_ObjectName *objNamePtr) +{ + Tcl_DString dString; + const char* name = MakeQualifiedName(objNamePtr, &dString); + Tcl_HashEntry* hPtr = Tcl_FindHashEntry(&dataPtr->vectorTable, name); + Tcl_DStringFree(&dString); + if (hPtr != NULL) + return (Vector*)Tcl_GetHashValue(hPtr); + + return NULL; +} + +static Vector* GetVectorObject(VectorInterpData *dataPtr, const char *name, + int flags) +{ + Tcl_Interp* interp = dataPtr->interp; + Blt_ObjectName objName; + if (!ParseObjectName(interp, name, &objName, BLT_NO_ERROR_MSG | BLT_NO_DEFAULT_NS)) + return NULL; + + Vector* vPtr = NULL; + if (objName.nsPtr != NULL) + vPtr = FindVectorInNamespace(dataPtr, &objName); + else { + if (flags & NS_SEARCH_CURRENT) { + objName.nsPtr = Tcl_GetCurrentNamespace(interp); + vPtr = FindVectorInNamespace(dataPtr, &objName); + } + if ((vPtr == NULL) && (flags & NS_SEARCH_GLOBAL)) { + objName.nsPtr = Tcl_GetGlobalNamespace(interp); + vPtr = FindVectorInNamespace(dataPtr, &objName); + } + } + + return vPtr; +} + +void Blt::Vec_UpdateRange(Vector* vPtr) +{ + double* vp = vPtr->valueArr + vPtr->first; + double* vend = vPtr->valueArr + vPtr->last; + double min = *vp; + double max = *vp++; + for (/* empty */; vp <= vend; vp++) { + if (min > *vp) + min = *vp; + else if (max < *vp) + max = *vp; + } + vPtr->min = min; + vPtr->max = max; + vPtr->notifyFlags &= ~UPDATE_RANGE; +} + +int Blt::Vec_GetIndex(Tcl_Interp* interp, Vector* vPtr, const char *string, + int *indexPtr, int flags, Blt_VectorIndexProc **procPtrPtr) +{ + int value; + char c = string[0]; + + // Treat the index "end" like a numeric index + if ((c == 'e') && (strcmp(string, "end") == 0)) { + if (vPtr->length < 1) { + if (interp != NULL) { + Tcl_AppendResult(interp, "bad index \"end\": vector is empty", + (char *)NULL); + } + return TCL_ERROR; + } + *indexPtr = vPtr->length - 1; + return TCL_OK; + } else if ((c == '+') && (strcmp(string, "++end") == 0)) { + *indexPtr = vPtr->length; + return TCL_OK; + } + if (procPtrPtr != NULL) { + Tcl_HashEntry *hPtr; + + hPtr = Tcl_FindHashEntry(&vPtr->dataPtr->indexProcTable, string); + if (hPtr != NULL) { + *indexPtr = SPECIAL_INDEX; + *procPtrPtr = (Blt_VectorIndexProc*)Tcl_GetHashValue(hPtr); + return TCL_OK; + } + } + if (Tcl_GetInt(interp, (char *)string, &value) != TCL_OK) { + long int lvalue; + /* + * Unlike Tcl_GetInt, Tcl_ExprLong needs a valid interpreter, but the + * interp passed in may be NULL. So we have to use vPtr->interp and + * then reset the result. + */ + if (Tcl_ExprLong(vPtr->interp, (char *)string, &lvalue) != TCL_OK) { + Tcl_ResetResult(vPtr->interp); + if (interp != NULL) { + Tcl_AppendResult(interp, "bad index \"", string, "\"", + (char *)NULL); + } + return TCL_ERROR; + } + value = (int)lvalue; + } + /* + * Correct the index by the current value of the offset. This makes all + * the numeric indices non-negative, which is how we distinguish the + * special non-numeric indices. + */ + value -= vPtr->offset; + + if ((value < 0) || ((flags & INDEX_CHECK) && (value >= vPtr->length))) { + if (interp != NULL) { + Tcl_AppendResult(interp, "index \"", string, "\" is out of range", + (char *)NULL); + } + return TCL_ERROR; + } + *indexPtr = (int)value; + return TCL_OK; +} + +int Blt::Vec_GetIndexRange(Tcl_Interp* interp, Vector* vPtr, const char *string, + int flags, Blt_VectorIndexProc** procPtrPtr) +{ + int ielem; + char* colon = NULL; + if (flags & INDEX_COLON) + colon = (char*)strchr(string, ':'); + + if (colon != NULL) { + if (string == colon) { + vPtr->first = 0; /* Default to the first index */ + } + else { + int result; + + *colon = '\0'; + result = Vec_GetIndex(interp, vPtr, string, &ielem, flags, + (Blt_VectorIndexProc **) NULL); + *colon = ':'; + if (result != TCL_OK) { + return TCL_ERROR; + } + vPtr->first = ielem; + } + if (*(colon + 1) == '\0') { + /* Default to the last index */ + vPtr->last = (vPtr->length > 0) ? vPtr->length - 1 : 0; + } else { + if (Vec_GetIndex(interp, vPtr, colon + 1, &ielem, flags, + (Blt_VectorIndexProc **) NULL) != TCL_OK) { + return TCL_ERROR; + } + vPtr->last = ielem; + } + if (vPtr->first > vPtr->last) { + if (interp != NULL) { + Tcl_AppendResult(interp, "bad range \"", string, + "\" (first > last)", (char *)NULL); + } + return TCL_ERROR; + } + } else { + if (Vec_GetIndex(interp, vPtr, string, &ielem, flags, + procPtrPtr) != TCL_OK) { + return TCL_ERROR; + } + vPtr->last = vPtr->first = ielem; + } + return TCL_OK; +} + +Vector* Blt::Vec_ParseElement(Tcl_Interp* interp, VectorInterpData *dataPtr, + const char* start, const char** endPtr, int flags) +{ + char* p = (char*)start; + // Find the end of the vector name + while (VECTOR_CHAR(*p)) { + p++; + } + char saved = *p; + *p = '\0'; + + Vector* vPtr = GetVectorObject(dataPtr, start, flags); + if (vPtr == NULL) { + if (interp != NULL) { + Tcl_AppendResult(interp, "can't find vector \"", start, "\"", + (char *)NULL); + } + *p = saved; + return NULL; + } + *p = saved; + vPtr->first = 0; + vPtr->last = vPtr->length - 1; + if (*p == '(') { + int count, result; + + start = p + 1; + p++; + + /* Find the matching right parenthesis */ + count = 1; + while (*p != '\0') { + if (*p == ')') { + count--; + if (count == 0) { + break; + } + } else if (*p == '(') { + count++; + } + p++; + } + if (count > 0) { + if (interp != NULL) { + Tcl_AppendResult(interp, "unbalanced parentheses \"", start, + "\"", (char *)NULL); + } + return NULL; + } + *p = '\0'; + result = Vec_GetIndexRange(interp, vPtr, start, (INDEX_COLON | INDEX_CHECK), (Blt_VectorIndexProc **) NULL); + *p = ')'; + if (result != TCL_OK) { + return NULL; + } + p++; + } + if (endPtr != NULL) { + *endPtr = p; + } + return vPtr; +} + +void Blt_Vec_NotifyClients(ClientData clientData) +{ + Vector* vPtr = (Vector*)clientData; + ChainLink *link, *next; + Blt_VectorNotify notify; + + notify = (vPtr->notifyFlags & NOTIFY_DESTROYED) + ? BLT_VECTOR_NOTIFY_DESTROY : BLT_VECTOR_NOTIFY_UPDATE; + vPtr->notifyFlags &= ~(NOTIFY_UPDATED | NOTIFY_DESTROYED | NOTIFY_PENDING); + for (link = Chain_FirstLink(vPtr->chain); link; link = next) { + next = Chain_NextLink(link); + VectorClient *clientPtr = (VectorClient*)Chain_GetValue(link); + if ((clientPtr->proc != NULL) && (clientPtr->serverPtr != NULL)) { + (*clientPtr->proc) (vPtr->interp, clientPtr->clientData, notify); + } + } + + // Some clients may not handle the "destroy" callback properly (they + // should call Blt_FreeVectorId to release the client identifier), so mark + // any remaining clients to indicate that vector's server has gone away. + if (notify == BLT_VECTOR_NOTIFY_DESTROY) { + for (link = Chain_FirstLink(vPtr->chain); link; + link = Chain_NextLink(link)) { + VectorClient *clientPtr = (VectorClient*)Chain_GetValue(link); + clientPtr->serverPtr = NULL; + } + } +} + +void Blt::Vec_UpdateClients(Vector* vPtr) +{ + vPtr->dirty++; + vPtr->max = vPtr->min = NAN; + if (vPtr->notifyFlags & NOTIFY_NEVER) { + return; + } + vPtr->notifyFlags |= NOTIFY_UPDATED; + if (vPtr->notifyFlags & NOTIFY_ALWAYS) { + Blt_Vec_NotifyClients(vPtr); + return; + } + if (!(vPtr->notifyFlags & NOTIFY_PENDING)) { + vPtr->notifyFlags |= NOTIFY_PENDING; + Tcl_DoWhenIdle(Blt_Vec_NotifyClients, vPtr); + } +} + +void Blt::Vec_FlushCache(Vector* vPtr) +{ + Tcl_Interp* interp = vPtr->interp; + + if (vPtr->arrayName == NULL) + return; + + /* Turn off the trace temporarily so that we can unset all the + * elements in the array. */ + + Tcl_UntraceVar2(interp, vPtr->arrayName, (char *)NULL, + TRACE_ALL | vPtr->varFlags, Vec_VarTrace, vPtr); + + /* Clear all the element entries from the entire array */ + Tcl_UnsetVar2(interp, vPtr->arrayName, (char *)NULL, vPtr->varFlags); + + /* Restore the "end" index by default and the trace on the entire array */ + Tcl_SetVar2(interp, vPtr->arrayName, "end", "", vPtr->varFlags); + Tcl_TraceVar2(interp, vPtr->arrayName, (char *)NULL, + TRACE_ALL | vPtr->varFlags, Vec_VarTrace, vPtr); +} + +int Blt::Vec_LookupName(VectorInterpData *dataPtr, const char *vecName, + Vector** vPtrPtr) +{ + + const char *endPtr; + Vector* vPtr = Vec_ParseElement(dataPtr->interp, dataPtr, vecName, &endPtr, NS_SEARCH_BOTH); + if (vPtr == NULL) + return TCL_ERROR; + + if (*endPtr != '\0') { + Tcl_AppendResult(dataPtr->interp, + "extra characters after vector name", (char *)NULL); + return TCL_ERROR; + } + + *vPtrPtr = vPtr; + return TCL_OK; +} + +double Blt::Vec_Min(Vector* vecObjPtr) +{ + double* vp = vecObjPtr->valueArr + vecObjPtr->first; + double* vend = vecObjPtr->valueArr + vecObjPtr->last; + double min = *vp++; + for (/* empty */; vp <= vend; vp++) { + if (min > *vp) + min = *vp; + } + vecObjPtr->min = min; + return vecObjPtr->min; +} + +double Blt::Vec_Max(Vector* vecObjPtr) +{ + double max = NAN; + double* vp = vecObjPtr->valueArr + vecObjPtr->first; + double* vend = vecObjPtr->valueArr + vecObjPtr->last; + max = *vp++; + for (/* empty */; vp <= vend; vp++) { + if (max < *vp) + max = *vp; + } + vecObjPtr->max = max; + return vecObjPtr->max; +} + +static void DeleteCommand(Vector* vPtr) +{ + Tcl_Interp* interp = vPtr->interp; + char *qualName; + Tcl_CmdInfo cmdInfo; + Tcl_DString dString; + Blt_ObjectName objName; + + Tcl_DStringInit(&dString); + objName.name = Tcl_GetCommandName(interp, vPtr->cmdToken); + objName.nsPtr = GetCommandNamespace(vPtr->cmdToken); + qualName = MakeQualifiedName(&objName, &dString); + if (Tcl_GetCommandInfo(interp, qualName, &cmdInfo)) { + // Disable the callback before deleting the TCL command + cmdInfo.deleteProc = NULL; + Tcl_SetCommandInfo(interp, qualName, &cmdInfo); + Tcl_DeleteCommandFromToken(interp, vPtr->cmdToken); + } + Tcl_DStringFree(&dString); + vPtr->cmdToken = 0; +} + +static void UnmapVariable(Vector* vPtr) +{ + Tcl_Interp* interp = vPtr->interp; + + // Unset the entire array + Tcl_UntraceVar2(interp, vPtr->arrayName, (char *)NULL, + (TRACE_ALL | vPtr->varFlags), Vec_VarTrace, vPtr); + Tcl_UnsetVar2(interp, vPtr->arrayName, (char *)NULL, vPtr->varFlags); + + if (vPtr->arrayName != NULL) { + free((void*)(vPtr->arrayName)); + vPtr->arrayName = NULL; + } +} + +int Blt::Vec_MapVariable(Tcl_Interp* interp, Vector* vPtr, const char *path) +{ + Blt_ObjectName objName; + char *newPath; + const char *result; + Tcl_DString dString; + + if (vPtr->arrayName != NULL) { + UnmapVariable(vPtr); + } + if ((path == NULL) || (path[0] == '\0')) { + return TCL_OK; /* If the variable pathname is the empty + * string, simply return after removing any + * existing variable. */ + } + /* Get the variable name (without the namespace qualifier). */ + if (!ParseObjectName(interp, path, &objName, BLT_NO_DEFAULT_NS)) { + return TCL_ERROR; + } + if (objName.nsPtr == NULL) { + /* + * If there was no namespace qualifier, try harder to see if the + * variable is non-local. + */ + objName.nsPtr = GetVariableNamespace(interp, objName.name); + } + Tcl_DStringInit(&dString); + vPtr->varFlags = 0; + if (objName.nsPtr != NULL) { /* Global or namespace variable. */ + newPath = MakeQualifiedName(&objName, &dString); + vPtr->varFlags |= (TCL_GLOBAL_ONLY); + } else { /* Local variable. */ + newPath = (char *)objName.name; + } + + /* + * To play it safe, delete the variable first. This has the benefical + * side-effect of unmapping the variable from another vector that may be + * currently associated with it. + */ + Tcl_UnsetVar2(interp, newPath, (char *)NULL, 0); + + /* + * Set the index "end" in the array. This will create the variable + * immediately so that we can check its namespace context. + */ + result = Tcl_SetVar2(interp, newPath, "end", "", TCL_LEAVE_ERR_MSG); + if (result == NULL) { + Tcl_DStringFree(&dString); + return TCL_ERROR; + } + /* Create a full-array trace on reads, writes, and unsets. */ + Tcl_TraceVar2(interp, newPath, (char *)NULL, TRACE_ALL, Vec_VarTrace, + vPtr); + vPtr->arrayName = Blt_Strdup(newPath); + Tcl_DStringFree(&dString); + return TCL_OK; +} + +int Blt::Vec_SetSize(Tcl_Interp* interp, Vector* vPtr, int newSize) +{ + if (newSize <= 0) { + newSize = DEF_ARRAY_SIZE; + } + if (newSize == vPtr->size) { + /* Same size, use the current array. */ + return TCL_OK; + } + if (vPtr->freeProc == TCL_DYNAMIC) { + /* Old memory was dynamically allocated, so use realloc. */ + double* newArr = (double*)realloc(vPtr->valueArr, newSize * sizeof(double)); + if (newArr == NULL) { + if (interp != NULL) { + Tcl_AppendResult(interp, "can't reallocate ", + Itoa(newSize), " elements for vector \"", + vPtr->name, "\"", (char *)NULL); + } + return TCL_ERROR; + } + vPtr->size = newSize; + vPtr->valueArr = newArr; + return TCL_OK; + } + + { + /* Old memory was created specially (static or special allocator). + * Replace with dynamically allocated memory (malloc-ed). */ + + double* newArr = (double*)calloc(newSize, sizeof(double)); + if (newArr == NULL) { + if (interp != NULL) { + Tcl_AppendResult(interp, "can't allocate ", + Itoa(newSize), " elements for vector \"", + vPtr->name, "\"", (char *)NULL); + } + return TCL_ERROR; + } + { + int used, wanted; + + /* Copy the contents of the old memory into the new. */ + used = vPtr->length; + wanted = newSize; + + if (used > wanted) { + used = wanted; + } + /* Copy any previous data */ + if (used > 0) { + memcpy(newArr, vPtr->valueArr, used * sizeof(double)); + } + } + + /* + * We're not using the old storage anymore, so free it if it's not + * TCL_STATIC. It's static because the user previously reset the + * vector with a statically allocated array (setting freeProc to + * TCL_STATIC). + */ + if (vPtr->freeProc != TCL_STATIC) { + if (vPtr->freeProc == TCL_DYNAMIC) { + free(vPtr->valueArr); + } else { + (*vPtr->freeProc) ((char *)vPtr->valueArr); + } + } + vPtr->freeProc = TCL_DYNAMIC; /* Set the type of the new storage */ + vPtr->valueArr = newArr; + vPtr->size = newSize; + } + return TCL_OK; +} + +int Blt::Vec_SetLength(Tcl_Interp* interp, Vector* vPtr, int newLength) +{ + if (vPtr->size < newLength) { + if (Vec_SetSize(interp, vPtr, newLength) != TCL_OK) { + return TCL_ERROR; + } + } + vPtr->length = newLength; + vPtr->first = 0; + vPtr->last = newLength - 1; + return TCL_OK; +} + +int Blt::Vec_ChangeLength(Tcl_Interp* interp, Vector* vPtr, int newLength) +{ + if (newLength < 0) { + newLength = 0; + } + if (newLength > vPtr->size) { + int newSize; /* Size of array in elements */ + + /* Compute the new size of the array. It's a multiple of + * DEF_ARRAY_SIZE. */ + newSize = DEF_ARRAY_SIZE; + while (newSize < newLength) { + newSize += newSize; + } + if (newSize != vPtr->size) { + if (Vec_SetSize(interp, vPtr, newSize) != TCL_OK) { + return TCL_ERROR; + } + } + } + vPtr->length = newLength; + vPtr->first = 0; + vPtr->last = newLength - 1; + return TCL_OK; + +} + +int Blt::Vec_Reset(Vector* vPtr, double *valueArr, int length, + int size, Tcl_FreeProc *freeProc) +{ + if (vPtr->valueArr != valueArr) { /* New array of values resides + * in different memory than + * the current vector. */ + if ((valueArr == NULL) || (size == 0)) { + /* Empty array. Set up default values */ + valueArr = (double*)malloc(sizeof(double) * DEF_ARRAY_SIZE); + size = DEF_ARRAY_SIZE; + if (valueArr == NULL) { + Tcl_AppendResult(vPtr->interp, "can't allocate ", + Itoa(size), " elements for vector \"", + vPtr->name, "\"", (char *)NULL); + return TCL_ERROR; + } + freeProc = TCL_DYNAMIC; + length = 0; + } + else if (freeProc == TCL_VOLATILE) { + /* Data is volatile. Make a copy of the value array. */ + double* newArr = (double*)malloc(size * sizeof(double)); + if (newArr == NULL) { + Tcl_AppendResult(vPtr->interp, "can't allocate ", + Itoa(size), " elements for vector \"", + vPtr->name, "\"", (char *)NULL); + return TCL_ERROR; + } + memcpy((char *)newArr, (char *)valueArr, + sizeof(double) * length); + valueArr = newArr; + freeProc = TCL_DYNAMIC; + } + + if (vPtr->freeProc != TCL_STATIC) { + /* Old data was dynamically allocated. Free it before attaching + * new data. */ + if (vPtr->freeProc == TCL_DYNAMIC) { + free(vPtr->valueArr); + } else { + (*freeProc) ((char *)vPtr->valueArr); + } + } + vPtr->freeProc = freeProc; + vPtr->valueArr = valueArr; + vPtr->size = size; + } + + vPtr->length = length; + if (vPtr->flush) { + Vec_FlushCache(vPtr); + } + Vec_UpdateClients(vPtr); + return TCL_OK; +} + +Vector* Blt::Vec_New(VectorInterpData *dataPtr) +{ + Vector* vPtr = (Vector*)calloc(1, sizeof(Vector)); + vPtr->valueArr = (double*)malloc(sizeof(double) * DEF_ARRAY_SIZE); + if (vPtr->valueArr == NULL) { + free(vPtr); + return NULL; + } + vPtr->size = DEF_ARRAY_SIZE; + vPtr->freeProc = TCL_DYNAMIC; + vPtr->length = 0; + vPtr->interp = dataPtr->interp; + vPtr->hashPtr = NULL; + vPtr->chain = new Chain(); + vPtr->flush = 0; + vPtr->min = vPtr->max = NAN; + vPtr->notifyFlags = NOTIFY_WHENIDLE; + vPtr->dataPtr = dataPtr; + return vPtr; +} + +void Blt::Vec_Free(Vector* vPtr) +{ + ChainLink* link; + + if (vPtr->cmdToken != 0) { + DeleteCommand(vPtr); + } + if (vPtr->arrayName != NULL) { + UnmapVariable(vPtr); + } + vPtr->length = 0; + + /* Immediately notify clients that vector is going away */ + if (vPtr->notifyFlags & NOTIFY_PENDING) { + vPtr->notifyFlags &= ~NOTIFY_PENDING; + Tcl_CancelIdleCall(Blt_Vec_NotifyClients, vPtr); + } + vPtr->notifyFlags |= NOTIFY_DESTROYED; + Blt_Vec_NotifyClients(vPtr); + + for (link = Chain_FirstLink(vPtr->chain); link; link = Chain_NextLink(link)) { + VectorClient *clientPtr = (VectorClient*)Chain_GetValue(link); + free(clientPtr); + } + delete vPtr->chain; + if ((vPtr->valueArr != NULL) && (vPtr->freeProc != TCL_STATIC)) { + if (vPtr->freeProc == TCL_DYNAMIC) { + free(vPtr->valueArr); + } else { + (*vPtr->freeProc) ((char *)vPtr->valueArr); + } + } + if (vPtr->hashPtr != NULL) { + Tcl_DeleteHashEntry(vPtr->hashPtr); + } +#ifdef NAMESPACE_DELETE_NOTIFY + if (vPtr->nsPtr != NULL) { + Blt_DestroyNsDeleteNotify(vPtr->interp, vPtr->nsPtr, vPtr); + } +#endif /* NAMESPACE_DELETE_NOTIFY */ + free(vPtr); +} + +static void VectorInstDeleteProc(ClientData clientData) +{ + Vector* vPtr = (Vector*)clientData; + vPtr->cmdToken = 0; + Vec_Free(vPtr); +} + +Vector* Blt::Vec_Create(VectorInterpData *dataPtr, const char *vecName, + const char *cmdName, const char *varName, int *isNewPtr) +{ + Tcl_DString dString; + Blt_ObjectName objName; + char *qualName; + Tcl_HashEntry *hPtr; + Tcl_Interp* interp = dataPtr->interp; + + int isNew = 0; + Vector* vPtr = NULL; + + if (!ParseObjectName(interp, vecName, &objName, 0)) + return NULL; + + Tcl_DStringInit(&dString); + if ((objName.name[0] == '#') && (strcmp(objName.name, "#auto") == 0)) { + + do { /* Generate a unique vector name. */ + char string[200]; + + snprintf(string, 200, "vector%d", dataPtr->nextId++); + objName.name = string; + qualName = MakeQualifiedName(&objName, &dString); + hPtr = Tcl_FindHashEntry(&dataPtr->vectorTable, qualName); + } while (hPtr != NULL); + } else { + const char *p; + + for (p = objName.name; *p != '\0'; p++) { + if (!VECTOR_CHAR(*p)) { + Tcl_AppendResult(interp, "bad vector name \"", objName.name, + "\": must contain digits, letters, underscore, or period", + (char *)NULL); + goto error; + } + } + qualName = MakeQualifiedName(&objName, &dString); + vPtr = Vec_ParseElement((Tcl_Interp *)NULL, dataPtr, qualName, + NULL, NS_SEARCH_CURRENT); + } + if (vPtr == NULL) { + hPtr = Tcl_CreateHashEntry(&dataPtr->vectorTable, qualName, &isNew); + vPtr = Vec_New(dataPtr); + vPtr->hashPtr = hPtr; + vPtr->nsPtr = objName.nsPtr; + + vPtr->name = (const char*)Tcl_GetHashKey(&dataPtr->vectorTable, hPtr); +#ifdef NAMESPACE_DELETE_NOTIFY + Blt_CreateNsDeleteNotify(interp, objName.nsPtr, vPtr, + VectorInstDeleteProc); +#endif /* NAMESPACE_DELETE_NOTIFY */ + Tcl_SetHashValue(hPtr, vPtr); + } + if (cmdName != NULL) { + Tcl_CmdInfo cmdInfo; + + if ((cmdName == vecName) || + ((cmdName[0] == '#') && (strcmp(cmdName, "#auto")==0))) { + cmdName = qualName; + } + if (Tcl_GetCommandInfo(interp, (char *)cmdName, &cmdInfo)) { + if (vPtr != cmdInfo.objClientData) { + Tcl_AppendResult(interp, "command \"", cmdName, + "\" already exists", (char *)NULL); + goto error; + } + /* We get here only if the old name is the same as the new. */ + goto checkVariable; + } + } + if (vPtr->cmdToken != 0) { + DeleteCommand(vPtr); /* Command already exists, delete old first */ + } + if (cmdName != NULL) { + Tcl_DString dString2; + + Tcl_DStringInit(&dString2); + if (cmdName != qualName) { + if (!ParseObjectName(interp, cmdName, &objName, 0)) { + goto error; + } + cmdName = MakeQualifiedName(&objName, &dString2); + } + vPtr->cmdToken = Tcl_CreateObjCommand(interp, (char *)cmdName, Vec_InstCmd, + vPtr, VectorInstDeleteProc); + Tcl_DStringFree(&dString2); + } + checkVariable: + if (varName != NULL) { + if ((varName[0] == '#') && (strcmp(varName, "#auto") == 0)) { + varName = qualName; + } + if (Vec_MapVariable(interp, vPtr, varName) != TCL_OK) { + goto error; + } + } + + Tcl_DStringFree(&dString); + *isNewPtr = isNew; + return vPtr; + + error: + Tcl_DStringFree(&dString); + if (vPtr != NULL) { + Vec_Free(vPtr); + } + return NULL; +} + +int Blt::Vec_Duplicate(Vector* destPtr, Vector* srcPtr) +{ + size_t nBytes; + size_t length; + + if (destPtr == srcPtr) { + /* Copying the same vector. */ + } + length = srcPtr->last - srcPtr->first + 1; + if (Vec_ChangeLength(destPtr->interp, destPtr, length) != TCL_OK) { + return TCL_ERROR; + } + nBytes = length * sizeof(double); + memcpy(destPtr->valueArr, srcPtr->valueArr + srcPtr->first, nBytes); + destPtr->offset = srcPtr->offset; + return TCL_OK; +} + + +static int VectorNamesOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + VectorInterpData* dataPtr = (VectorInterpData*)clientData; + Tcl_Obj *listObjPtr; + + listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); + if (objc == 2) { + Tcl_HashEntry *hPtr; + Tcl_HashSearch cursor; + + for (hPtr = Tcl_FirstHashEntry(&dataPtr->vectorTable, &cursor); + hPtr != NULL; hPtr = Tcl_NextHashEntry(&cursor)) { + char *name = (char*)Tcl_GetHashKey(&dataPtr->vectorTable, hPtr); + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewStringObj(name, -1)); + } + } else { + Tcl_HashEntry *hPtr; + Tcl_HashSearch cursor; + + for (hPtr = Tcl_FirstHashEntry(&dataPtr->vectorTable, &cursor); + hPtr != NULL; hPtr = Tcl_NextHashEntry(&cursor)) { + char *name = (char*)Tcl_GetHashKey(&dataPtr->vectorTable, hPtr); + int i; + for (i = 2; i < objc; i++) { + char *pattern; + + pattern = Tcl_GetString(objv[i]); + if (Tcl_StringMatch(name, pattern)) { + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewStringObj(name, -1)); + break; + } + } + } + } + Tcl_SetObjResult(interp, listObjPtr); + return TCL_OK; +} + +static int VectorCreate2(ClientData clientData, Tcl_Interp* interp, + int argStart, int objc, Tcl_Obj* const objv[]) +{ + VectorInterpData *dataPtr = (VectorInterpData*)clientData; + Vector* vPtr; + int count, i; + CreateSwitches switches; + + // Handle switches to the vector command and collect the vector name + // arguments into an array. + count = 0; + vPtr = NULL; + for (i = argStart; i < objc; i++) { + char *string; + + string = Tcl_GetString(objv[i]); + if (string[0] == '-') { + break; + } + } + count = i - argStart; + if (count == 0) { + Tcl_AppendResult(interp, "no vector names supplied", (char *)NULL); + return TCL_ERROR; + } + memset(&switches, 0, sizeof(switches)); + if (ParseSwitches(interp, createSwitches, objc - i, objv + i, + &switches, BLT_SWITCH_DEFAULTS) < 0) { + return TCL_ERROR; + } + if (count > 1) { + if (switches.cmdName != NULL) { + Tcl_AppendResult(interp, + "can't specify more than one vector with \"-command\" switch", + (char *)NULL); + goto error; + } + if (switches.varName != NULL) { + Tcl_AppendResult(interp, + "can't specify more than one vector with \"-variable\" switch", + (char *)NULL); + goto error; + } + } + for (i = 0; i < count; i++) { + char *leftParen, *rightParen; + char *string; + int isNew; + int size, first, last; + + size = first = last = 0; + string = Tcl_GetString(objv[i + argStart]); + leftParen = strchr(string, '('); + rightParen = strchr(string, ')'); + if (((leftParen != NULL) && (rightParen == NULL)) || + ((leftParen == NULL) && (rightParen != NULL)) || + (leftParen > rightParen)) { + Tcl_AppendResult(interp, "bad vector specification \"", string, + "\"", (char *)NULL); + goto error; + } + if (leftParen != NULL) { + int result; + char *colon; + + *rightParen = '\0'; + colon = strchr(leftParen + 1, ':'); + if (colon != NULL) { + + /* Specification is in the form vecName(first:last) */ + *colon = '\0'; + result = Tcl_GetInt(interp, leftParen + 1, &first); + if ((*(colon + 1) != '\0') && (result == TCL_OK)) { + result = Tcl_GetInt(interp, colon + 1, &last); + if (first > last) { + Tcl_AppendResult(interp, "bad vector range \"", + string, "\"", (char *)NULL); + result = TCL_ERROR; + } + size = (last - first) + 1; + } + *colon = ':'; + } else { + /* Specification is in the form vecName(size) */ + result = Tcl_GetInt(interp, leftParen + 1, &size); + } + *rightParen = ')'; + if (result != TCL_OK) { + goto error; + } + if (size < 0) { + Tcl_AppendResult(interp, "bad vector size \"", string, "\"", + (char *)NULL); + goto error; + } + } + if (leftParen != NULL) { + *leftParen = '\0'; + } + /* + * By default, we create a TCL command by the name of the vector. + */ + vPtr = Vec_Create(dataPtr, string, + (switches.cmdName == NULL) ? string : switches.cmdName, + (switches.varName == NULL) ? string : switches.varName, &isNew); + if (leftParen != NULL) { + *leftParen = '('; + } + if (vPtr == NULL) { + goto error; + } + vPtr->freeOnUnset = switches.watchUnset; + vPtr->flush = switches.flush; + vPtr->offset = first; + if (size > 0) { + if (Vec_ChangeLength(interp, vPtr, size) != TCL_OK) { + goto error; + } + } + if (!isNew) { + if (vPtr->flush) { + Vec_FlushCache(vPtr); + } + Vec_UpdateClients(vPtr); + } + } + FreeSwitches(createSwitches, (char *)&switches, 0); + if (vPtr != NULL) { + /* Return the name of the last vector created */ + Tcl_SetStringObj(Tcl_GetObjResult(interp), vPtr->name, -1); + } + return TCL_OK; + error: + FreeSwitches(createSwitches, (char *)&switches, 0); + return TCL_ERROR; +} + +static int VectorCreateOp(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + return VectorCreate2(clientData, interp, 2, objc, objv); +} + +static int VectorDestroyOp(ClientData clientData, Tcl_Interp* interp, + int objc,Tcl_Obj* const objv[]) +{ + VectorInterpData *dataPtr = (VectorInterpData*)clientData; + + for (int ii=2; ii 1) { + char *string; + char c; + int i; + Blt_OpSpec *specPtr; + + string = Tcl_GetString(objv[1]); + c = string[0]; + for (specPtr = vectorCmdOps, i = 0; i < nCmdOps; i++, specPtr++) { + if ((c == specPtr->name[0]) && + (strcmp(string, specPtr->name) == 0)) { + goto doOp; + } + } + // The first argument is not an operation, so assume that its + // actually the name of a vector to be created + return VectorCreate2(clientData, interp, 1, objc, objv); + } + doOp: + /* Do the usual vector operation lookup now. */ + proc = (VectorCmdProc*)GetOpFromObj(interp, nCmdOps, vectorCmdOps, + BLT_OP_ARG1, objc, objv,0); + if (proc == NULL) { + return TCL_ERROR; + } + return (*proc) ((Vector*)clientData, interp, objc, objv); +} + +static void VectorInterpDeleteProc(ClientData clientData, Tcl_Interp* interp) +{ + VectorInterpData *dataPtr = (VectorInterpData*)clientData; + Tcl_HashEntry *hPtr; + Tcl_HashSearch cursor; + + for (hPtr = Tcl_FirstHashEntry(&dataPtr->vectorTable, &cursor); + hPtr != NULL; hPtr = Tcl_NextHashEntry(&cursor)) { + Vector* vPtr = (Vector*)Tcl_GetHashValue(hPtr); + vPtr->hashPtr = NULL; + Vec_Free(vPtr); + } + Tcl_DeleteHashTable(&dataPtr->vectorTable); + + /* If any user-defined math functions were installed, remove them. */ + Vec_UninstallMathFunctions(&dataPtr->mathProcTable); + Tcl_DeleteHashTable(&dataPtr->mathProcTable); + + Tcl_DeleteHashTable(&dataPtr->indexProcTable); + Tcl_DeleteAssocData(interp, VECTOR_THREAD_KEY); + free(dataPtr); +} + +VectorInterpData* Blt::Vec_GetInterpData(Tcl_Interp* interp) +{ + VectorInterpData *dataPtr; + Tcl_InterpDeleteProc *proc; + + dataPtr = (VectorInterpData *) + Tcl_GetAssocData(interp, VECTOR_THREAD_KEY, &proc); + if (dataPtr == NULL) { + dataPtr = (VectorInterpData*)malloc(sizeof(VectorInterpData)); + dataPtr->interp = interp; + dataPtr->nextId = 0; + Tcl_SetAssocData(interp, VECTOR_THREAD_KEY, VectorInterpDeleteProc, + dataPtr); + Tcl_InitHashTable(&dataPtr->vectorTable, TCL_STRING_KEYS); + Tcl_InitHashTable(&dataPtr->mathProcTable, TCL_STRING_KEYS); + Tcl_InitHashTable(&dataPtr->indexProcTable, TCL_STRING_KEYS); + Vec_InstallMathFunctions(&dataPtr->mathProcTable); + Vec_InstallSpecialIndices(&dataPtr->indexProcTable); + srand48((long)time((time_t *) NULL)); + } + return dataPtr; +} + +/* C Application interface to vectors */ + +int Blt_CreateVector2(Tcl_Interp* interp, const char *vecName, + const char *cmdName, const char *varName, + int initialSize, Blt_Vector* *vecPtrPtr) +{ + VectorInterpData *dataPtr; /* Interpreter-specific data. */ + Vector* vPtr; + int isNew; + char *nameCopy; + + if (initialSize < 0) { + Tcl_AppendResult(interp, "bad vector size \"", Itoa(initialSize), + "\"", (char *)NULL); + return TCL_ERROR; + } + dataPtr = Vec_GetInterpData(interp); + + nameCopy = Blt_Strdup(vecName); + vPtr = Vec_Create(dataPtr, nameCopy, cmdName, varName, &isNew); + free(nameCopy); + + if (vPtr == NULL) { + return TCL_ERROR; + } + if (initialSize > 0) { + if (Vec_ChangeLength(interp, vPtr, initialSize) != TCL_OK) { + return TCL_ERROR; + } + } + if (vecPtrPtr != NULL) { + *vecPtrPtr = (Blt_Vector* ) vPtr; + } + return TCL_OK; +} + +int Blt_CreateVector(Tcl_Interp* interp, const char *name, int size, + Blt_Vector* *vecPtrPtr) +{ + return Blt_CreateVector2(interp, name, name, name, size, vecPtrPtr); +} + +int Blt_DeleteVector(Blt_Vector* vecPtr) +{ + Vector* vPtr = (Vector* )vecPtr; + + Vec_Free(vPtr); + return TCL_OK; +} + +int Blt_DeleteVectorByName(Tcl_Interp* interp, const char *name) +{ + // If the vector name was passed via a read-only string (e.g. "x"), the + // Vec_ParseElement routine will segfault when it tries to write into + // the string. Therefore make a writable copy and free it when we're done. + char* nameCopy = Blt_Strdup(name); + VectorInterpData *dataPtr = Vec_GetInterpData(interp); + Vector* vPtr; + int result = Vec_LookupName(dataPtr, nameCopy, &vPtr); + free(nameCopy); + + if (result != TCL_OK) + return TCL_ERROR; + + Vec_Free(vPtr); + return TCL_OK; +} + +int Blt_VectorExists2(Tcl_Interp* interp, const char *vecName) +{ + VectorInterpData *dataPtr; + + dataPtr = Vec_GetInterpData(interp); + if (GetVectorObject(dataPtr, vecName, NS_SEARCH_BOTH) != NULL) { + return 1; + } + return 0; +} + +int Blt_VectorExists(Tcl_Interp* interp, const char *vecName) +{ + char *nameCopy; + int result; + + /* + * If the vector name was passed via a read-only string (e.g. "x"), the + * Blt_VectorParseName routine will segfault when it tries to write into + * the string. Therefore make a writable copy and free it when we're + * done. + */ + nameCopy = Blt_Strdup(vecName); + result = Blt_VectorExists2(interp, nameCopy); + free(nameCopy); + return result; +} + +int Blt_GetVector(Tcl_Interp* interp, const char *name, Blt_Vector* *vecPtrPtr) +{ + VectorInterpData *dataPtr; /* Interpreter-specific data. */ + Vector* vPtr; + char *nameCopy; + int result; + + dataPtr = Vec_GetInterpData(interp); + /* + * If the vector name was passed via a read-only string (e.g. "x"), the + * Blt_VectorParseName routine will segfault when it tries to write into + * the string. Therefore make a writable copy and free it when we're + * done. + */ + nameCopy = Blt_Strdup(name); + result = Vec_LookupName(dataPtr, nameCopy, &vPtr); + free(nameCopy); + if (result != TCL_OK) { + return TCL_ERROR; + } + Vec_UpdateRange(vPtr); + *vecPtrPtr = (Blt_Vector* ) vPtr; + return TCL_OK; +} + +int Blt_GetVectorFromObj(Tcl_Interp* interp, Tcl_Obj *objPtr, + Blt_Vector* *vecPtrPtr) +{ + VectorInterpData *dataPtr; /* Interpreter-specific data. */ + Vector* vPtr; + + dataPtr = Vec_GetInterpData(interp); + if (Vec_LookupName(dataPtr, Tcl_GetString(objPtr), &vPtr) != TCL_OK) { + return TCL_ERROR; + } + Vec_UpdateRange(vPtr); + *vecPtrPtr = (Blt_Vector* ) vPtr; + return TCL_OK; +} + +int Blt_ResetVector(Blt_Vector* vecPtr, double *valueArr, int length, + int size, Tcl_FreeProc *freeProc) +{ + Vector* vPtr = (Vector* )vecPtr; + + if (size < 0) { + Tcl_AppendResult(vPtr->interp, "bad array size", (char *)NULL); + return TCL_ERROR; + } + return Vec_Reset(vPtr, valueArr, length, size, freeProc); +} + +int Blt_ResizeVector(Blt_Vector* vecPtr, int length) +{ + Vector* vPtr = (Vector* )vecPtr; + + if (Vec_ChangeLength((Tcl_Interp *)NULL, vPtr, length) != TCL_OK) { + Tcl_AppendResult(vPtr->interp, "can't resize vector \"", vPtr->name, + "\"", (char *)NULL); + return TCL_ERROR; + } + if (vPtr->flush) { + Vec_FlushCache(vPtr); + } + Vec_UpdateClients(vPtr); + return TCL_OK; +} + +Blt_VectorId Blt_AllocVectorId(Tcl_Interp* interp, const char *name) +{ + VectorInterpData *dataPtr; /* Interpreter-specific data. */ + Vector* vPtr; + VectorClient *clientPtr; + Blt_VectorId clientId; + int result; + char *nameCopy; + + dataPtr = Vec_GetInterpData(interp); + /* + * If the vector name was passed via a read-only string (e.g. "x"), the + * Blt_VectorParseName routine will segfault when it tries to write into + * the string. Therefore make a writable copy and free it when we're + * done. + */ + nameCopy = Blt_Strdup(name); + result = Vec_LookupName(dataPtr, nameCopy, &vPtr); + free(nameCopy); + + if (result != TCL_OK) { + return (Blt_VectorId) 0; + } + /* Allocate a new client structure */ + clientPtr = (VectorClient*)calloc(1, sizeof(VectorClient)); + clientPtr->magic = VECTOR_MAGIC; + + /* Add the new client to the server's list of clients */ + clientPtr->link = vPtr->chain->append(clientPtr); + clientPtr->serverPtr = vPtr; + clientId = (Blt_VectorId) clientPtr; + return clientId; +} + +void Blt_SetVectorChangedProc(Blt_VectorId clientId, + Blt_VectorChangedProc *proc, + ClientData clientData) +{ + VectorClient *clientPtr = (VectorClient *)clientId; + + if (clientPtr->magic != VECTOR_MAGIC) { + return; /* Not a valid token */ + } + clientPtr->clientData = clientData; + clientPtr->proc = proc; +} + +void Blt_FreeVectorId(Blt_VectorId clientId) +{ + VectorClient *clientPtr = (VectorClient *)clientId; + + if (clientPtr->magic != VECTOR_MAGIC) + return; + + if (clientPtr->serverPtr != NULL) { + // Remove the client from the server's list + clientPtr->serverPtr->chain->deleteLink(clientPtr->link); + } + free(clientPtr); +} + +const char* Blt_NameOfVectorId(Blt_VectorId clientId) +{ + VectorClient *clientPtr = (VectorClient *)clientId; + + if ((clientPtr->magic != VECTOR_MAGIC) || (clientPtr->serverPtr == NULL)) { + return NULL; + } + return clientPtr->serverPtr->name; +} + +const char* Blt_NameOfVector(Blt_Vector* vecPtr) /* Vector to query. */ +{ + Vector* vPtr = (Vector* )vecPtr; + return vPtr->name; +} + +int Blt_GetVectorById(Tcl_Interp* interp, Blt_VectorId clientId, + Blt_Vector* *vecPtrPtr) +{ + VectorClient *clientPtr = (VectorClient *)clientId; + + if (clientPtr->magic != VECTOR_MAGIC) { + Tcl_AppendResult(interp, "bad vector token", (char *)NULL); + return TCL_ERROR; + } + if (clientPtr->serverPtr == NULL) { + Tcl_AppendResult(interp, "vector no longer exists", (char *)NULL); + return TCL_ERROR; + } + Vec_UpdateRange(clientPtr->serverPtr); + *vecPtrPtr = (Blt_Vector* ) clientPtr->serverPtr; + return TCL_OK; +} + +void Blt_InstallIndexProc(Tcl_Interp* interp, const char *string, + Blt_VectorIndexProc *procPtr) +{ + VectorInterpData *dataPtr; /* Interpreter-specific data. */ + Tcl_HashEntry *hPtr; + int isNew; + + dataPtr = Vec_GetInterpData(interp); + hPtr = Tcl_CreateHashEntry(&dataPtr->indexProcTable, string, &isNew); + if (procPtr == NULL) { + Tcl_DeleteHashEntry(hPtr); + } else { + Tcl_SetHashValue(hPtr, procPtr); + } +} + +#define SWAP(a,b) tempr=(a);(a)=(b);(b)=tempr + +/* routine by Brenner + * data is the array of complex data points, perversely + * starting at 1 + * nn is the number of complex points, i.e. half the length of data + * isign is 1 for forward, -1 for inverse + */ +static void four1(double *data, unsigned long nn, int isign) +{ + unsigned long n,mmax,m,j,istep,i; + double wtemp,wr,wpr,wpi,wi,theta; + double tempr,tempi; + + n=nn << 1; + j=1; + for (i = 1;i i) { + SWAP(data[j],data[i]); + SWAP(data[j+1],data[i+1]); + } + m=n >> 1; + while (m >= 2 && j > m) { + j -= m; + m >>= 1; + } + j += m; + } + mmax=2; + while (n > mmax) { + istep=mmax << 1; + theta=isign*(6.28318530717959/mmax); + wtemp=sin(0.5*theta); + wpr = -2.0*wtemp*wtemp; + wpi=sin(theta); + wr=1.0; + wi=0.0; + for (m=1;mlast - srcPtr->first + 1; + /* new length */ + pow2len = smallest_power_of_2_not_less_than( length ); + + /* We do not do in-place FFTs */ + if (realPtr == srcPtr) { + Tcl_AppendResult(interp, "real vector \"", realPtr->name, + "\" can't be the same as the source", (char *)NULL); + return TCL_ERROR; + } + if (phasesPtr != NULL) { + if (phasesPtr == srcPtr) { + Tcl_AppendResult(interp, "imaginary vector \"", phasesPtr->name, + "\" can't be the same as the source", (char *)NULL); + return TCL_ERROR; + } + if (Vec_ChangeLength(interp, phasesPtr, + pow2len/2-noconstant+middle) != TCL_OK) { + return TCL_ERROR; + } + } + if (freqPtr != NULL) { + if (freqPtr == srcPtr) { + Tcl_AppendResult(interp, "frequency vector \"", freqPtr->name, + "\" can't be the same as the source", (char *)NULL); + return TCL_ERROR; + } + if (Vec_ChangeLength(interp, freqPtr, + pow2len/2-noconstant+middle) != TCL_OK) { + return TCL_ERROR; + } + } + + /* Allocate memory zero-filled array. */ + paddedData = (double*)calloc(pow2len * 2, sizeof(double)); + if (paddedData == NULL) { + Tcl_AppendResult(interp, "can't allocate memory for padded data", + (char *)NULL); + return TCL_ERROR; + } + + /* + * Since we just do real transforms, only even locations will be + * filled with data. + */ + if (flags & FFT_BARTLETT) { /* Bartlett window 1 - ( (x - N/2) / (N/2) ) */ + double Nhalf = pow2len*0.5; + double Nhalf_1 = 1.0 / Nhalf; + double w; + + for (i = 0; i < length; i++) { + w = 1.0 - fabs( (i-Nhalf) * Nhalf_1 ); + Wss += w; + paddedData[2*i] = w * srcPtr->valueArr[i]; + } + for(/*empty*/; i < pow2len; i++) { + w = 1.0 - fabs((i-Nhalf) * Nhalf_1); + Wss += w; + } + } else { /* Squared window, i.e. no data windowing. */ + for (i = 0; i < length; i++) { + paddedData[2*i] = srcPtr->valueArr[i]; + } + Wss = pow2len; + } + + /* Fourier */ + four1(paddedData-1, pow2len, 1); + + /* + for(i=0;ivalueArr; + + for (i = 0 + noconstant; i < pow2len / 2; i++) { + re = paddedData[2*i]; + im = paddedData[2*i+1]; + reS = paddedData[2*pow2len-2*i-2]; + imS = paddedData[2*pow2len-2*i-1]; + v[i - noconstant] = factor * ( +# if 0 + hypot( paddedData[2*i], paddedData[2*i+1] ) + + hypot( + paddedData[pow2len*2-2*i-2], + paddedData[pow2len*2-2*i-1] + ) +# else + sqrt( re*re + im* im ) + sqrt( reS*reS + imS*imS ) +# endif + ); + } + } else { + for(i = 0 + noconstant; i < pow2len / 2 + middle; i++) { + realPtr->valueArr[i - noconstant] = paddedData[2*i]; + } + } + if( phasesPtr != NULL ){ + for (i = 0 + noconstant; i < pow2len / 2 + middle; i++) { + phasesPtr->valueArr[i-noconstant] = paddedData[2*i+1]; + } + } + + /* Compute frequencies */ + if (freqPtr != NULL) { + double N = pow2len; + double denom = 1.0 / N / delta; + for( i=0+noconstant; ivalueArr[i-noconstant] = ((double) i) * denom; + } + } + + /* Memory is necessarily dynamic, because nobody touched it ! */ + free(paddedData); + + realPtr->offset = 0; + return TCL_OK; +} + + +int Blt::Vec_InverseFFT(Tcl_Interp* interp, Vector* srcImagPtr, + Vector* destRealPtr, Vector* destImagPtr, Vector* srcPtr) +{ + int length; + int pow2len; + double *paddedData; + int i; + double oneOverN; + + if ((destRealPtr == srcPtr) || (destImagPtr == srcPtr )){ + /* we do not do in-place FFTs */ + return TCL_ERROR; + } + length = srcPtr->last - srcPtr->first + 1; + + /* minus one because of the magical middle element! */ + pow2len = smallest_power_of_2_not_less_than( (length-1)*2 ); + oneOverN = 1.0 / pow2len; + + if (Vec_ChangeLength(interp, destRealPtr, pow2len) != TCL_OK) { + return TCL_ERROR; + } + if (Vec_ChangeLength(interp, destImagPtr, pow2len) != TCL_OK) { + return TCL_ERROR; + } + + if( length != (srcImagPtr->last - srcImagPtr->first + 1) ){ + Tcl_AppendResult(srcPtr->interp, + "the length of the imagPart vector must ", + "be the same as the real one", (char *)NULL); + return TCL_ERROR; + } + + paddedData = (double*)malloc( pow2len*2*sizeof(double) ); + if( paddedData == NULL ){ + if (interp != NULL) { + Tcl_AppendResult(interp, "memory allocation failed", (char *)NULL); + } + return TCL_ERROR; + } + for(i=0;ivalueArr[i]; + paddedData[2*i+1] = srcImagPtr->valueArr[i]; + paddedData[pow2len*2 - 2*i - 2 ] = srcPtr->valueArr[i+1]; + paddedData[pow2len*2 - 2*i - 1 ] = - srcImagPtr->valueArr[i+1]; + } + /* mythical middle element */ + paddedData[(length-1)*2] = srcPtr->valueArr[length-1]; + paddedData[(length-1)*2+1] = srcImagPtr->valueArr[length-1]; + + /* + for(i=0;ivalueArr[i] = paddedData[2*i] * oneOverN; + destImagPtr->valueArr[i] = paddedData[2*i+1] * oneOverN; + } + + /* memory is necessarily dynamic, because nobody touched it ! */ + free( paddedData ); + + return TCL_OK; +} + +static double FindSplit(Point2d *points, int i, int j, int *split) +{ + double maxDist2; + + maxDist2 = -1.0; + if ((i + 1) < j) { + int k; + double a, b, c; + + /* + * + * dist2 P(k) = | 1 P(i).x P(i).y | + * | 1 P(j).x P(j).y | + * | 1 P(k).x P(k).y | + * ------------------------------------------ + * (P(i).x - P(j).x)^2 + (P(i).y - P(j).y)^2 + */ + + a = points[i].y - points[j].y; + b = points[j].x - points[i].x; + c = (points[i].x * points[j].y) - (points[i].y * points[j].x); + for (k = (i + 1); k < j; k++) { + double dist2; + + dist2 = (points[k].x * a) + (points[k].y * b) + c; + if (dist2 < 0.0) { + dist2 = -dist2; + } + if (dist2 > maxDist2) { + maxDist2 = dist2; /* Track the maximum. */ + *split = k; + } + } + /* Correction for segment length---should be redone if can == 0 */ + maxDist2 *= maxDist2 / (a * a + b * b); + } + return maxDist2; +} + +// Douglas-Peucker line simplification algorithm */ +int Blt_SimplifyLine(Point2d *inputPts, int low, int high, double tolerance, + int *indices) +{ +#define StackPush(a) s++, stack[s] = (a) +#define StackPop(a) (a) = stack[s], s-- +#define StackEmpty() (s < 0) +#define StackTop() stack[s] + int *stack; + int split = -1; + double dist2, tolerance2; + int s = -1; /* Points to top stack item. */ + int count; + + stack = (int*)malloc(sizeof(int) * (high - low + 1)); + StackPush(high); + count = 0; + indices[count++] = 0; + tolerance2 = tolerance * tolerance; + while (!StackEmpty()) { + dist2 = FindSplit(inputPts, low, StackTop(), &split); + if (dist2 > tolerance2) { + StackPush(split); + } else { + indices[count++] = StackTop(); + StackPop(low); + } + } + free(stack); + return count; +} + diff --git a/generic/tkbltVector.h b/generic/tkbltVector.h new file mode 100644 index 0000000..45ddf6e --- /dev/null +++ b/generic/tkbltVector.h @@ -0,0 +1,140 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1993-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _BLT_VECTOR_H +#define _BLT_VECTOR_H + +#include + +#ifdef BUILD_tkblt +# define TKBLT_STORAGE_CLASS DLLEXPORT +#else +# ifdef USE_TCL_STUBS +# define TKBLT_STORAGE_CLASS /* */ +# else +# define TKBLT_STORAGE_CLASS DLLIMPORT +# endif +#endif + + +typedef enum { + BLT_VECTOR_NOTIFY_UPDATE = 1, /* The vector's values has been updated */ + BLT_VECTOR_NOTIFY_DESTROY /* The vector has been destroyed and the client + * should no longer use its data (calling + * Blt_FreeVectorId) */ +} Blt_VectorNotify; + +typedef struct _Blt_VectorId *Blt_VectorId; + +typedef void (Blt_VectorChangedProc)(Tcl_Interp* interp, ClientData clientData, + Blt_VectorNotify notify); + +typedef struct { + double *valueArr; /* Array of values (possibly malloc-ed) */ + int numValues; /* Number of values in the array */ + int arraySize; /* Size of the allocated space */ + double min, max; /* Minimum and maximum values in the vector */ + int dirty; /* Indicates if the vector has been updated */ + int reserved; /* Reserved for future use */ + +} Blt_Vector; + +typedef double (Blt_VectorIndexProc)(Blt_Vector * vecPtr); + +typedef enum { + BLT_MATH_FUNC_SCALAR = 1, /* The function returns a single double + * precision value. */ + BLT_MATH_FUNC_VECTOR /* The function processes the entire vector. */ +} Blt_MathFuncType; + +/* + * To be safe, use the macros below, rather than the fields of the + * structure directly. + * + * The Blt_Vector is basically an opaque type. But it's also the + * actual memory address of the vector itself. I wanted to make the + * API as unobtrusive as possible. So instead of giving you a copy of + * the vector, providing various functions to access and update the + * vector, you get your hands on the actual memory (array of doubles) + * shared by all the vector's clients. + * + * The trade-off for speed and convenience is safety. You can easily + * break things by writing into the vector when other clients are + * using it. Use Blt_ResetVector to get around this. At least the + * macros are a reminder it isn't really safe to reset the data + * fields, except by the API routines. + */ +#define Blt_VecData(v) ((v)->valueArr) +#define Blt_VecLength(v) ((v)->numValues) +#define Blt_VecSize(v) ((v)->arraySize) +#define Blt_VecDirty(v) ((v)->dirty) + +#ifdef __cplusplus +extern "C" { +#endif + TKBLT_STORAGE_CLASS int Blt_CreateVector(Tcl_Interp* interp, const char *vecName, + int size, Blt_Vector** vecPtrPtr); + TKBLT_STORAGE_CLASS int Blt_CreateVector2(Tcl_Interp* interp, const char *vecName, + const char *cmdName, const char *varName, + int initialSize, Blt_Vector **vecPtrPtr); + TKBLT_STORAGE_CLASS int Blt_DeleteVectorByName(Tcl_Interp* interp, const char *vecName); + TKBLT_STORAGE_CLASS int Blt_DeleteVector(Blt_Vector *vecPtr); + TKBLT_STORAGE_CLASS int Blt_GetVector(Tcl_Interp* interp, const char *vecName, + Blt_Vector **vecPtrPtr); + TKBLT_STORAGE_CLASS int Blt_GetVectorFromObj(Tcl_Interp* interp, Tcl_Obj *objPtr, + Blt_Vector **vecPtrPtr); + TKBLT_STORAGE_CLASS int Blt_ResetVector(Blt_Vector *vecPtr, double *dataArr, int n, + int arraySize, Tcl_FreeProc *freeProc); + TKBLT_STORAGE_CLASS int Blt_ResizeVector(Blt_Vector *vecPtr, int n); + TKBLT_STORAGE_CLASS int Blt_VectorExists(Tcl_Interp* interp, const char *vecName); + TKBLT_STORAGE_CLASS int Blt_VectorExists2(Tcl_Interp* interp, const char *vecName); + TKBLT_STORAGE_CLASS Blt_VectorId Blt_AllocVectorId(Tcl_Interp* interp, const char *vecName); + TKBLT_STORAGE_CLASS int Blt_GetVectorById(Tcl_Interp* interp, Blt_VectorId clientId, + Blt_Vector **vecPtrPtr); + TKBLT_STORAGE_CLASS void Blt_SetVectorChangedProc(Blt_VectorId clientId, + Blt_VectorChangedProc *proc, + ClientData clientData); + TKBLT_STORAGE_CLASS void Blt_FreeVectorId(Blt_VectorId clientId); + TKBLT_STORAGE_CLASS const char *Blt_NameOfVectorId(Blt_VectorId clientId); + TKBLT_STORAGE_CLASS const char *Blt_NameOfVector(Blt_Vector *vecPtr); + TKBLT_STORAGE_CLASS int Blt_ExprVector(Tcl_Interp* interp, char *expr, Blt_Vector *vecPtr); + TKBLT_STORAGE_CLASS void Blt_InstallIndexProc(Tcl_Interp* interp, const char *indexName, + Blt_VectorIndexProc * procPtr); + TKBLT_STORAGE_CLASS double Blt_VecMin(Blt_Vector *vPtr); + TKBLT_STORAGE_CLASS double Blt_VecMax(Blt_Vector *vPtr); +#ifdef __cplusplus +} +#endif + +#include "tkbltDecls.h" + +#endif /* _BLT_VECTOR_H */ diff --git a/library/graph.tcl b/library/graph.tcl new file mode 100644 index 0000000..a4dfe8e --- /dev/null +++ b/library/graph.tcl @@ -0,0 +1,554 @@ +package provide Tkblt 3.0 + +namespace eval ::blt::legend { + variable _private + array set _private { + afterId "" + scroll 0 + space off + drag 0 + x 0 + y 0 + } +} + +namespace eval ::blt::ZoomStack { + variable _private + array set _private { + afterId "" + scroll 0 + space off + drag 0 + x 0 + y 0 + } +} + +proc blt::legend::SetSelectionAnchor { w tagOrId } { + set elem [$w legend get $tagOrId] + # If the anchor hasn't changed, don't do anything + if { $elem != [$w legend get anchor] } { + $w legend selection clearall + $w legend focus $elem + $w legend selection set $elem + $w legend selection anchor $elem + } +} + +# ---------------------------------------------------------------------- +# +# MoveFocus -- +# +# Invoked by KeyPress bindings. Moves the active selection to +# the entry , which is an index such as "up", "down", +# "prevsibling", "nextsibling", etc. +# +# ---------------------------------------------------------------------- +proc blt::legend::MoveFocus { w elem } { + catch {$w legend focus $elem} result + puts stderr "result=$result elem=$elem" + if { [$w legend cget -selectmode] == "single" } { + $w legend selection clearall + $w legend selection set focus + $w legend selection anchor focus + } +} + + +proc Blt_ActiveLegend { g } { + $g legend bind all [list blt::ActivateLegend $g ] + $g legend bind all [list blt::DeactivateLegend $g] + $g legend bind all [list blt::HighlightLegend $g] +} + +proc Blt_Crosshairs { g } { + blt::Crosshairs $g +} + +proc Blt_ResetCrosshairs { g state } { + blt::Crosshairs $g "Any-Motion" $state +} + +proc Blt_ZoomStack { g args } { + array set params { + -mode click + -button "ButtonPress-3" + } + array set params $args + if { $params(-mode) == "click" } { + blt::ZoomStack::ClickClick $g $params(-button) + } else { + blt::ZoomStack::ClickRelease $g $params(-button) + } +} + +proc Blt_ClosestPoint { g } { + blt::ClosestPoint $g +} + +# +# The following procedures that reside in the "blt" namespace are +# supposed to be private. +# + +proc blt::ActivateLegend { g } { + set elem [$g legend get current] + $g legend activate $elem +} +proc blt::DeactivateLegend { g } { + set elem [$g legend get current] + $g legend deactivate $elem +} + +proc blt::HighlightLegend { g } { + set elem [$g legend get current] + if { $elem != "" } { + set relief [$g element cget $elem -legendrelief] + if { $relief == "flat" } { + $g element configure $elem -legendrelief raised + $g element activate $elem + } else { + $g element configure $elem -legendrelief flat + $g element deactivate $elem + } + } +} + +proc blt::Crosshairs { g {event "Any-Motion"} {state "on"}} { + $g crosshairs $state + bind crosshairs-$g <$event> { + %W crosshairs configure -position @%x,%y + } + bind crosshairs-$g { + %W crosshairs off + } + bind crosshairs-$g { + %W crosshairs on + } + $g crosshairs configure -color red + if { $state == "on" } { + blt::AddBindTag $g crosshairs-$g + } elseif { $state == "off" } { + blt::RemoveBindTag $g crosshairs-$g + } +} + +proc blt::ClosestPoint { g {event "Control-ButtonPress-2"} } { + bind closest-point-$g <$event> { + blt::FindElement %W %x %y + } + blt::AddBindTag $g closest-point-$g +} + +proc blt::AddBindTag { widget tag } { + set oldTagList [bindtags $widget] + if { [lsearch $oldTagList $tag] < 0 } { + bindtags $widget [linsert $oldTagList 0 $tag] + } +} + +proc blt::RemoveBindTag { widget tag } { + set oldTagList [bindtags $widget] + set index [lsearch $oldTagList $tag] + if { $index >= 0 } { + bindtags $widget [lreplace $oldTagList $index $index] + } +} + +proc blt::FindElement { g x y } { + array set info [$g element closest $x $y -interpolate yes] + if { ![info exists info(name)] } { + beep + return + } + # -------------------------------------------------------------- + # find(name) - element Id + # find(index) - index of closest point + # find(x) find(y) - coordinates of closest point + # or closest point on line segment. + # find(dist) - distance from sample coordinate + # -------------------------------------------------------------- + set markerName "bltClosest_$info(name)" + catch { $g marker delete $markerName } + $g marker create text $markerName \ + -coords "$info(x) $info(y)" \ + -text "$info(name): $info(dist)\nindex $info(index)" \ + -anchor center -justify left \ + -yoffset 0 -bg {} + + set coords [$g invtransform $x $y] + set nx [lindex $coords 0] + set ny [lindex $coords 1] + + $g marker create line line.$markerName -coords "$nx $ny $info(x) $info(y)" + + blt::FlashPoint $g $info(name) $info(index) 10 + blt::FlashPoint $g $info(name) [expr $info(index) + 1] 10 +} + +proc blt::FlashPoint { g name index count } { + if { $count & 1 } { + $g element deactivate $name + } else { + $g element activate $name $index + } + incr count -1 + if { $count > 0 } { + after 200 blt::FlashPoint $g $name $index $count + update + } else { + catch {eval $g marker delete [$g marker names "bltClosest_*"]} + } +} + + +proc blt::ZoomStack::Init { g } { + variable _private + set _private($g,interval) 100 + set _private($g,afterId) 0 + set _private($g,A,x) {} + set _private($g,A,y) {} + set _private($g,B,x) {} + set _private($g,B,y) {} + set _private($g,stack) {} + set _private($g,corner) A +} + +proc blt::ZoomStack::ClickClick { g reset } { + variable _private + + Init $g + + bind zoom-$g "focus %W" + bind zoom-$g { blt::ZoomStack::Reset %W } + bind zoom-$g { blt::ZoomStack::SetPoint %W %x %y } + bind zoom-$g <${reset}> { + if { [%W inside %x %y] } { + blt::ZoomStack::Reset %W + } + } + blt::AddBindTag $g zoom-$g +} + +proc blt::ZoomStack::ClickRelease { g reset } { + variable _private + + Init $g + bind zoom-$g "focus %W" + bind zoom-$g {blt::ZoomStack::Reset %W} + bind zoom-$g {blt::ZoomStack::DragStart %W %x %y} + bind zoom-$g {blt::ZoomStack::DragMotion %W %x %y} + bind zoom-$g {blt::ZoomStack::DragFinish %W %x %y} + bind zoom-$g <${reset}> { + if { [%W inside %x %y] } { + blt::ZoomStack::Reset %W + } + } + blt::AddBindTag $g zoom-$g +} + +proc blt::ZoomStack::GetCoords { g x y index } { + variable _private + if { [$g cget -invertxy] } { + set _private($g,$index,x) $y + set _private($g,$index,y) $x + } else { + set _private($g,$index,x) $x + set _private($g,$index,y) $y + } +} + +proc blt::ZoomStack::MarkPoint { g index } { + variable _private + + if { [llength [$g xaxis use]] > 0 } { + set x [$g xaxis invtransform $_private($g,$index,x)] + } else if { [llength [$g x2axis use]] > 0 } { + set x [$g x2axis invtransform $_private($g,$index,x)] + } + if { [llength [$g yaxis use]] > 0 } { + set y [$g yaxis invtransform $_private($g,$index,y)] + } else if { [llength [$g y2axis use]] > 0 } { + set y [$g y2axis invtransform $_private($g,$index,y)] + } + set marker "zoomText_$index" + set text [format "x=%.4g\ny=%.4g" $x $y] + + if [$g marker exists $marker] { + $g marker configure $marker -coords "$x $y" -text $text + } else { + $g marker create text $marker \ + -coords "$x $y" \ + -text $text -anchor center -bg {} -justify left + } +} + +proc blt::ZoomStack::DestroyTitle { g } { + variable _private + + if { $_private($g,corner) == "A" } { + catch { $g marker delete "zoomTitle" } + } +} + +proc blt::ZoomStack::Pop { g } { + variable _private + + set zoomStack $_private($g,stack) + if { [llength $zoomStack] > 0 } { + set cmd [lindex $zoomStack 0] + set _private($g,stack) [lrange $zoomStack 1 end] + eval $cmd + TitleLast $g + update + after 2000 [list blt::ZoomStack::DestroyTitle $g] + } else { + catch { $g marker delete "zoomTitle" } + } +} + +# Push the old axis limits on the stack and set the new ones + +proc blt::ZoomStack::Push { g } { + variable _private + + catch {eval $g marker delete [$g marker names "zoom*"]} + if { [info exists _private($g,afterId)] } { + after cancel $_private($g,afterId) + } + set x1 $_private($g,A,x) + set y1 $_private($g,A,y) + set x2 $_private($g,B,x) + set y2 $_private($g,B,y) + + if { ($x1 == $x2) || ($y1 == $y2) } { + # No delta, revert to start + return + } + set cmd {} + foreach axis [$g axis names] { + if { [$g axis cget $axis -hide] } { + continue + } + set min [$g axis cget $axis -min] + set max [$g axis cget $axis -max] + set logscale [$g axis cget $axis -logscale] + # Save the current scale (log or linear) so that we can restore it. + # This is for the case where the user changes to logscale while + # zooming. A previously pushed axis limit could be negative. It + # seems better for popping the zoom stack to restore a previous view + # (not convert the ranges). + set c [list $g axis configure $axis] + lappend c -min $min -max $max -logscale $logscale + append cmd "$c\n" + } + + # This effectively pushes the command to reset the graph to the current + # zoom level onto the stack. This is useful if the new axis ranges are + # bad and we need to reset the zoom stack. + set _private($g,stack) [linsert $_private($g,stack) 0 $cmd] + foreach axis [$g axis names] { + if { [$g axis cget $axis -hide] } { + continue; # Don't set zoom on axes not displayed. + } + set type [$g axis type $axis] + if { $type == "x" } { + set min [$g axis invtransform $axis $x1] + set max [$g axis invtransform $axis $x2] + } elseif { $type == "y" } { + set min [$g axis invtransform $axis $y1] + set max [$g axis invtransform $axis $y2] + } else { + continue; # Axis is not bound to any margin. + } + if { ![SetAxisRanges $g $axis $min $max] } { + Pop $g + bell + return + } + } + update; # This "update" redraws the graph +} + +proc blt::ZoomStack::SetAxisRanges { g axis min max } { + if { $min > $max } { + set tmp $max; set max $min; set min $tmp + } + if { [catch { $g axis configure $axis -min $min -max $max }] != 0 } { + return 0 + } + return 1 +} + +# +# This routine terminates either an existing zoom, or pops back to +# the previous zoom level (if no zoom is in progress). +# +proc blt::ZoomStack::Reset { g } { + variable _private + + if { ![info exists _private($g,corner)] } { + Init $g + } + catch {eval $g marker delete [$g marker names "zoom*"]} + + if { $_private($g,corner) == "A" } { + # Reset the whole axis + Pop $g + } else { + set _private($g,corner) A + blt::RemoveBindTag $g select-region-$g + } +} + +proc blt::ZoomStack::TitleNext { g } { + variable _private + + set level [expr [llength $_private($g,stack)] + 1] + if { [$g cget -invertxy] } { + set coords "Inf -Inf" + } else { + set coords "-Inf Inf" + } + set marker "zoomTitle" + if {![$g marker exists $marker]} { + $g marker create text $marker -bindtags "" -anchor nw + } + $g marker configure $marker -text "Zoom #$level" -coords $coords +} + +proc blt::ZoomStack::TitleLast { g } { + variable _private + + set level [llength $_private($g,stack)] + if { [$g cget -invertxy] } { + set coords "Inf -Inf" + } else { + set coords "-Inf Inf" + } + + set marker "zoomTitle" + if { $level > 0 } { + if {![$g marker exists $marker]} { + $g marker create text "zoomTitle" -anchor nw + } + $g marker configure $marker -text "Zoom #$level" -coords $coords + } +} + + +proc blt::ZoomStack::SetPoint { g x y } { + variable _private + if { ![info exists _private($g,corner)] } { + Init $g + } + GetCoords $g $x $y $_private($g,corner) + bind select-region-$g { + blt::ZoomStack::GetCoords %W %x %y B + #blt::ZoomStack::MarkPoint $g B + blt::ZoomStack::Box %W + } + if { $_private($g,corner) == "A" } { + if { ![$g inside $x $y] } { + return + } + # First corner selected, start watching motion events + + #MarkPoint $g A + TitleNext $g + + blt::AddBindTag $g select-region-$g + set _private($g,corner) B + } else { + # Delete the modal binding + blt::RemoveBindTag $g select-region-$g + Push $g + set _private($g,corner) A + } +} + +proc blt::ZoomStack::DragStart { g x y } { + variable _private + if { ![info exists _private($g,corner)] } { + Init $g + } + GetCoords $g $x $y A + if { ![$g inside $x $y] } { + return + } + set _private(drag) 1 + TitleNext $g +} + +proc blt::ZoomStack::DragMotion { g x y } { + variable _private + + if { $_private(drag) } { + GetCoords $g $x $y B + set dx [expr abs($_private($g,B,x) - $_private($g,A,x))] + set dy [expr abs($_private($g,B,y) - $_private($g,A,y))] + Box $g + if { $dy > 10 && $dx > 10 } { + return 1 + } + } + return 0 +} + +proc blt::ZoomStack::DragFinish { g x y } { + variable _private + if { [DragMotion $g $x $y] } { + Push $g + } else { + catch {eval $g marker delete [$g marker names "zoom*"]} + if { [info exists _private($g,afterId)] } { + after cancel $_private($g,afterId) + } + } + set _private(drag) 0 +} + + +proc blt::ZoomStack::MarchingAnts { g offset } { + variable _private + + incr offset + # wrap the counter after 2^16 + set offset [expr $offset & 0xFFFF] + if { [$g marker exists zoomOutline] } { + $g marker configure zoomOutline -dashoffset $offset + set interval $_private($g,interval) + set id [after $interval [list blt::ZoomStack::MarchingAnts $g $offset]] + set _private($g,afterId) $id + } +} + +proc blt::ZoomStack::Box { g } { + variable _private + + if { $_private($g,A,x) > $_private($g,B,x) } { + set x1 [$g xaxis invtransform $_private($g,B,x)] + set y1 [$g yaxis invtransform $_private($g,B,y)] + set x2 [$g xaxis invtransform $_private($g,A,x)] + set y2 [$g yaxis invtransform $_private($g,A,y)] + } else { + set x1 [$g xaxis invtransform $_private($g,A,x)] + set y1 [$g yaxis invtransform $_private($g,A,y)] + set x2 [$g xaxis invtransform $_private($g,B,x)] + set y2 [$g yaxis invtransform $_private($g,B,y)] + } + set coords "$x1 $y1 $x2 $y1 $x2 $y2 $x1 $y2 $x1 $y1" + if { [$g marker exists "zoomOutline"] } { + $g marker configure "zoomOutline" -coords $coords + } else { + set X [lindex [$g xaxis use] 0] + set Y [lindex [$g yaxis use] 0] + $g marker create line "zoomOutline" \ + -coords $coords -mapx $X -mapy $Y \ + -dashes 4 -linewidth 1 + set interval $_private($g,interval) + set id [after $interval [list blt::ZoomStack::MarchingAnts $g 0]] + set _private($g,afterId) $id + } +} + diff --git a/pkgIndex.tcl.in b/pkgIndex.tcl.in new file mode 100644 index 0000000..ea7d80b --- /dev/null +++ b/pkgIndex.tcl.in @@ -0,0 +1,5 @@ +# +# Tcl package index file +# +package ifneeded @PACKAGE_NAME@ @PACKAGE_VERSION@ \ + [list load [file join $dir @PKG_LIB_FILE@] @PACKAGE_NAME@]\n[list source [file join $dir graph.tcl]] diff --git a/tclconfig/ChangeLog b/tclconfig/ChangeLog new file mode 100644 index 0000000..9504def --- /dev/null +++ b/tclconfig/ChangeLog @@ -0,0 +1,1003 @@ +2016-03-11 Sean Woods + *tcl.m4 Fixed the search for Tcl and Wish shells under MinGW. Static builds and threaded builds + get an "s" or "t" added to the name. + +2015-08-28 Jan Nijtmans + + * tcl.m4: Rfe [00189c4afc]: Allow semi-static UCRT build on + Windows with VC 14.0 + +2013-10-08 Jan Nijtmans + + * tcl.m4: Bug [172223e008]: Wrong filename in + --disable-shared compile on MinGW + +2013-10-04 Jan Nijtmans + + * tcl.m4: stub library is no longer linked with msvcrt??.dll. + +2013-10-01 Jan Nijtmans + + * tcl.m4: Workaround for MinGW bug #2065: "gcc --shared" links + with libgcc_s_dw2-1.dll when using 64-bit division in C + +2013-07-04 Jan Nijtmans + + * tcl.m4: Bug [3324676]: AC_PROG_INSTALL incompat, + Bug [3606445]: Unneeded -DHAVE_NO_SEH=1 when not building on Windows + +2013-07-02 Jan Nijtmans + + * tcl.m4: Bug [32afa6e256]: dirent64 check is incorrect in tcl.m4 + (thanks to Brian Griffin) + +2013-06-20 Jan Nijtmans + + * tcl.m4: Use X11/Xlib.h for checking where X11 can be found + in stead of X11/XIntrinsic.h. Suggested by Pietro Cerutti. + +2013-06-04 Jan Nijtmans + + * tcl.m4: Eliminate NO_VIZ macro as current + zlib uses HAVE_HIDDEN in stead. One more last-moment + fix for FreeBSD by Pietro Cerutti + +2013-05-19 Jan Nijtmans + + * tcl.m4: Fix for FreeBSD, and remove support for old + FreeBSD versions. Patch by Pietro Cerutti + +2013-03-12 Jan Nijtmans + + * tcl.m4: Patch by Andrew Shadura, providing better support for + * three architectures they have in Debian. + +2012-08-07 Stuart Cassoff + + * tcl.m4: Added "-DNDEBUG" to CFLAGS_DEFAULT + when building with --disable-symbols. + +2012-08-07 Stuart Cassoff + + * tcl.m4: [Bug 3555058]: Checkin [30736d63f0] broke + CFLAGS_DEFAULT, LDFLAGS_DEFAULT + +2012-08-07 Stuart Cassoff + + * tcl.m4: [Bug 3511806]: Checkin [30736d63f0] broke CFLAGS + +2012-08-07 Jan Nijtmans + + * tcl.m4: [Bug 3511806]: Checkin [30736d63f0] broke CFLAGS + +2012-07-25 Jan Nijtmans + + * tcl.m4: My previous commit (2012-04-03) broke the ActiveTcl + build for AMD64, because of the quotes in "C://AMD64/cl.exe". + It turns out that the AC_TRY_COMPILE macro cannot handle that. + +2012-07-22 Stuart Cassoff + + * tcl.m4: Tidy: consistency, spelling, phrasing, whitespace. + No functional change. + +2012-04-03 Jan Nijtmans + + * tcl.m4: [Bug 3511806] Compiler checks too early + This change allows to build the cygwin and mingw32 ports of + Tcl/Tk extensions to build out-of-the-box using a native or + cross-compiler, e.g. on Cygwin, Linux or Darwin. + +2011-04-02 Jan Nijtmans + + * install-sh: Fix issue with library stripping in install-sh + (backported from kevin_walzer's patch from Tcl 8.6 trunk) + +2011-04-05 Andreas Kupries + + * tcl.m4: Applied patch by Jeff Lawson. Nicer error message when + tclConfig.sh was not found. + +2010-12-15 Stuart Cassoff + + * install-sh: Upgrade to newer install-sh and use it. + * tcl.m4: + +2010-12-14 Stuart Cassoff + + * tcl.m4: Better building on OpenBSD. + +2010-12-14 Jan Nijtmans + + * tcl.m4: when using gcc, don't try to determine Win64 SDK + +2010-12-12 Jan Nijtmans + + * tcl.m4: Determine correctly a cross-compiler-windres + +2010-11-23 Jan Nijtmans + + * tcl.m4: add some cross-compile support, borrowed from Tcl 8.6 + +2010-09-16 Jeff Hobbs + + * tcl.m4: correct HP-UX LDFLAGS (only used when building big shell) + +2010-09-14 Jeff Hobbs + + * tcl.m4: add extra if check for .manifest file generation + Add notice about package name and version being built. + +2010-09-09 Jan Nijtmans + + * tcl.m4: [FREQ #3058486] TEA_LOAD_CONFIG doesn't set all BUILD_ vars + Slightly related: defining BUILD_$1 on all platforms - not only win - + allows the -fvisibility feature to be used in extensions as well, at + least if you compile against tcl >= 8.5. + +2010-08-26 Jeff Hobbs + + * tcl.m4: ensure safe quoting for autoheader usage + +2010-08-19 Jeff Hobbs + + * tcl.m4: add TEA_ADD_CLEANFILES macro to make adding cleanfiles + easier, and add *.exp to CLEANFILES Windows default. + (TEA_MAKE_LIB): Enhanced to check for MSVC that requires manifests + and auto-embed it into proj DLL via MAKE_SHARED_LIB. Also define + VC_MANIFEST_EMBED_DLL and VC_MANIFEST_EMBED_EXE that do the same + magic in case it is needed for extended TEA projects. + +2010-08-16 Jeff Hobbs + + *** Bump to TEA_VERSION 3.9 *** + If upgrading from TEA_VERSION 3.8, copy over tcl.m4, change + TEA_INIT to use 3.9 and reconfigure (ac-2.59+). + BUILD_${PACKAGE_NAME} will be auto-defined on Windows for + correct setting of TCL_STORAGE_CLASS. + TEA_LOAD_CONFIG users should remove the SHLIB_LD_LIBS setting done + in configure.in (LIBS will be automagically populated by + TEA_LOAD_CONFIG). + TEA_EXPORT_CONFIG has been added for ${pkg}Config.sh creators + SHLIB_LD_FLAGS was deprecated a while ago, remove it if it is + still in your Makefile.in. + + * tcl.m4: add /usr/lib64 to set of auto-search dirs. [Bug 1230554] + Auto-define BUILD_$PACKAGE_NAME so users don't need to. This + needs to correspond with $pkg.h define magic for TCL_STORAGE_CLASS. + Auto-define CLEANFILES. Users can expand it. + (SHLIB_LD_LIBS): define to '${LIBS}' default and change it only if + necessary. Platforms not using this may simply not work or have + very funky linkers. + (TEA_LOAD_CONFIG): When loading config for another extension, + auto-add stub libraries found with TEA_ADD_LIBS. Eases + configure.in for modules like itk and img::*. + (TEA_EXPORT_CONFIG): Add standardized function for exporting a + ${pkg}Config.sh. See use by img::* and itcl. + +2010-08-12 Jeff Hobbs + + *** Bump to TEA_VERSION 3.8 *** + If upgrading from TEA_VERSION 3.7, copy over tcl.m4, change + TEA_INIT to use 3.8 and reconfigure (ac-2.59+). + No other changes should be necessary. + + * tcl.m4: remove more vestigial bits from removed platforms. + Add back SCO_SV-3.2*. + Remove use of DL_LIBS and DL_OBJS and related baggage - these are + only needed by the core to support 'load'. + Allow for macosx in TEA_ADD_SOURCES. + Correct check for found_xincludes=no in TEA_PATH_UNIX_X. + +2010-08-11 Jeff Hobbs + + * tcl.m4: remove the following old platform configurations: + UNIX_SV*|UnixWare-5*, SunOS-4.*, SINIX*5.4*, SCO_SV-3.2*, + OSF1-1.*, NEXTSTEP-*, NetBSD-1.*|FreeBSD-[[1-2]].*, MP-RAS-*, + IRIX-5.*, HP-UX-*.08.*|HP-UX-*.09.*|HP-UX-*.10.*, dgux*, + BSD/OS-2.1*|BSD/OS-3* + (AIX): drop AIX-pre4 support and use of ldAix, use -bexpall/-brtl + +2010-07-05 Jan Nijtmans + + * tcl.m4: [Patch #1055668] removal of exported internals from + tclInt.h (EXTERN macro) + +2010-04-14 Jan Nijtmans + + * tcl.m4 - Backport a lot of quoting fixes from tcl8.6/unix/tcl.m4 + - Fix determination of CYGPATH for CYGWIN + With those fixes, itcl and tdbc compile fine with CYGWIN + +2010-04-06 Jan Nijtmans + + * install-sh [Bug 2982540] configure and install* script files + should always have LF + +2010-02-19 Stuart Cassoff + + * tcl.m4: Correct compiler/linker flags for threaded builds on + OpenBSD. + +2010-01-19 Jan Nijtmans + + * tcl.m4: Detect CYGWIN variant: win32 or unix + +2010-01-03 Donal K. Fellows + + * unix/tcl.m4 (TEA_CONFIG_CFLAGS): [Tcl Bug 1636685]: Use the + configuration for modern FreeBSD suggested by the FreeBSD porter. + +2009-10-22 Jan Nijtmans + + * tcl.m4: [Tcl Patch #2883533] tcl.m4 support for Haiku OS + +2009-04-27 Jeff Hobbs + + * tcl.m4 (TEA_CONFIG_CFLAGS): harden the check to add _r to CC on + AIX with threads. + +2009-04-10 Daniel Steffen + + * tcl.m4 (Darwin): check for 64-bit TkAqua. + +2009-03-26 Jan Nijtmans + + * tclconfig/tcl.m4: Adapt LDFLAGS and LD_SEARCH_FLAGS + together with SHLIB_LD definition to unbreak building on HPUX. + +2009-03-20 Andreas Kupries + + * tclconfig/tcl.m4: Changed SHLIB_LD definition to unbreak + building on HPUX. + +2009-03-16 Joe English + + * tcl.m4(TEA_PUBLIC_TK_HEADERS): Look at ${TK_INCLUDE_SPEC} + (found in tkConfig.sh) when trying to guess where tk.h might be + [Patch 1960628]. + +2009-03-11 Joe English + + * tcl.m4: Allow ${SHLIB_SUFFIX} to be overridden at + configure-time [Patch 1960628]. Also fix some comment typos, + and an uninitialized variable bug-waiting-to-happen. + +2008-12-21 Jan Nijtmans + + * tcl.m4: [Bug 2073255] Tcl_GetString(NULL) doesn't crash on HP-UX + (this bug report was for Tcl, but holds for TEA as well.) + +2008-12-20 Daniel Steffen + + * tcl.m4: sync with tdbc tcl.m4 changes + (SunOS-5.11): Sun cc SHLIB_LD: use LDFLAGS_DEFAULT instead of LDFLAGS + +2008-12-02 Jeff Hobbs + + *** Bump to TEA_VERSION 3.7 *** + + * tcl.m4: in private header check, check for Port.h instead + of Int.h to ensure all private headers are available. + +2008-11-04 Daniel Steffen + + * tcl.m4 (Darwin): sync TEA_PRIVATE_TK_HEADERS handling of + Tk.framework PrivateHeaders with TEA_PRIVATE_TCL_HEADERS. + +2008-11-04 Jeff Hobbs + + * tcl.m4 (TEA_PATH_TCLCONFIG, TEA_PATH_TKCONFIG): exit with error + when tclConfig.sh cannot be found. [Bug #1997760] + (TEA_PRIVATE_TCL_HEADERS, TEA_PRIVATE_TK_HEADERS): allow for + finding the headers installed in the public areas, e.g. a result of + make install-private-headers. [Bug #1631922] + +2008-08-12 Daniel Steffen + + * tcl.m4 (Darwin): link shlib with current and compatiblity version + flags; look for libX11.dylib when searching for X11 libraries. + +2008-06-12 Daniel Steffen + + * tcl.m4 (SunOS-5.11): fix 64bit amd64 support with gcc & Sun cc. + +2008-03-27 Daniel Steffen + + * tcl.m4 (SunOS-5.1x): fix 64bit support for Sun cc. [Bug 1921166] + +2008-02-01 Donal K. Fellows + + * tcl.m4 (TEA_CONFIG_CFLAGS): Updated to work at least in part with + more modern VC versions. Currently just made the linker flags more + flexible; more work may be needed. + +2007-10-26 Daniel Steffen + + * tcl.m4 (Darwin): add support for 64-bit X11. + +2007-10-23 Jeff Hobbs + + *** Tagged tea-3-branch to start TEA 4 development on HEAD *** + +2007-09-17 Joe English + + * tcl.m4: use '${CC} -shared' instead of 'ld -Bshareable' + to build shared libraries on current NetBSDs [Bug 1749251]. + +2007-09-15 Daniel Steffen + + * tcl.m4: replace all direct references to compiler by ${CC} to + enable CC overriding at configure & make time. + (SunOS-5.1x): replace direct use of '/usr/ccs/bin/ld' in SHLIB_LD by + 'cc' compiler driver. + +2007-08-08 Jeff Hobbs + + * tcl.m4: check Ttk dir for Tk private headers (8.5). + Add some comments to other bits. + +2007-06-25 Jeff Hobbs + + * tcl.m4 (TEA_PROG_TCLSH, TEA_PROG_WISH): move where / is added. + +2007-06-13 Jeff Hobbs + + * tcl.m4: fix --with-tkinclude alignment. [Bug 1506111] + +2007-06-06 Daniel Steffen + + * tcl.m4 (Darwin): fix 64bit arch removal in fat 32&64bit builds. + +2007-05-18 Donal K. Fellows + + * tcl.m4: Added quoting so that paths with spaces cause fewer + problems. + +2007-03-07 Daniel Steffen + + * tcl.m4 (Darwin): s/CFLAGS/CPPFLAGS/ in -mmacosx-version-min check. + +2007-02-15 Jeff Hobbs + + * tcl.m4: correct private header check to search in generic subdir + +2007-02-09 Jeff Hobbs + + *** Bump to TEA_VERSION 3.6 *** + + * tcl.m4: correct -d to -f + (TEA_CONFIG_CFLAGS): SHLIB_SUFFIX is .so on HP ia64 [Bug 1615058] + +2007-02-08 Jeff Hobbs + + * tcl.m4 (TEA_PRIVATE_TCL_HEADERS, TEA_PRIVATE_TK_HEADERS): check + that the dirs actually have private headers. [Bug 1631922] + +2007-02-04 Daniel Steffen + + * tcl.m4: add caching to -pipe check. + +2007-01-25 Daniel Steffen + + * tcl.m4: integrate CPPFLAGS into CFLAGS as late as possible and + move (rather than duplicate) -isysroot flags from CFLAGS to CPPFLAGS to + avoid errors about multiple -isysroot flags from some older gcc builds. + +2006-01-19 Daniel Steffen + + * tcl.m4: ensure CPPFLAGS env var is used when set. [Bug 1586861] + (Darwin): add -isysroot and -mmacosx-version-min flags to CPPFLAGS when + present in CFLAGS to avoid discrepancies between what headers configure + sees during preprocessing tests and compiling tests. + +2006-12-19 Daniel Steffen + + * tcl.m4 (Darwin): --enable-64bit: verify linking with 64bit -arch flag + succeeds before enabling 64bit build. + +2006-12-16 Daniel Steffen + + * tcl.m4 (Linux): fix previous change to use makefile variable + LDFLAGS_DEFAULT instead of LDFLAGS in SHLIB_LD, to ensure linker + flags in sampleextension Makefile are picked up. + +2006-11-26 Daniel Steffen + + * tcl.m4 (Linux): --enable-64bit support. [Patch 1597389], [Bug 1230558] + +2006-08-18 Daniel Steffen + + * tcl.m4 (Darwin): add support for --enable-64bit on x86_64, for + universal builds including x86_64 and for use of -mmacosx-version-min + instead of MACOSX_DEPLOYMENT_TARGET. For Tk extensions, remove 64-bit + arch flags from CFLAGS like in the Tk configure, as neither TkAqua nor + TkX11 can be built for 64-bit at present. + +2006-03-28 Jeff Hobbs + + * tcl.m4: []-quote AC_DEFUN functions. + (TEA_PATH_TKCONFIG): Fixed Windows-specific check for tkConfig.sh. + (TEA_MAKE_LIB): Prepend 'lib' for Windows-gcc configs. + +2006-03-07 Joe English + + * tcl.m4: Set SHLIB_LD_FLAGS='${LIBS}' on NetBSD, + as per the other *BSD variants [Bug 1334613]. + +2006-01-25 Jeff Hobbs + + *** Bump to TEA version 3.5 *** + + * tcl.m4: keep LD_SEARCH_FLAGS and CC_SEARCH_FLAGS synchronous + with core tcl.m4 meaning. + +2006-01-24 Daniel Steffen + + * tcl.m4 (Darwin): use makefile variable LDFLAGS_DEFAULT instead of + LDFLAGS in SHLIB_LD, to ensure linker flags in sampleextension Makefile + are picked up. [Bug 1403343] + +2006-01-23 Jeff Hobbs + + * tcl.m4: add C:/Tcl/lib and C:/Progra~1/Tcl/lib dirs to check for + *Config.sh on Windows. [Bug 1407544] + +2006-01-23 Daniel Steffen + + * tcl.m4 (Darwin): for Tk extensions, remove -arch ppc64 from CFLAGS + like in the Tk configure, as neither TkAqua nor TkX11 can be built for + 64bit at present (no 64bit GUI libraries). + +2006-01-22 Jeff Hobbs + + * tcl.m4: restore system=windows on Windows. + Remove error if 'ar' isn't found (it may not be on Windows). + Do not add -lxnet or define _XOPEN_SOURCE on HP-UX by default. + Ensure the C|LDFLAGS_DEFAULT gets the fully sub'd value at + configure time. + +2006-01-10 Daniel Steffen + + * tcl.m4: add caching, use AC_CACHE_CHECK instead of AC_CACHE_VAL + where possible, consistent message quoting, sync relevant + tcl/unix/tcl.m4 HEAD changes and gratuitous formatting differences + (notably sunc removal of support for for ancient BSD's, IRIX 4, + RISCos and Ultrix by kennykb), Darwin improvements to + TEA_LOAD_*CONFIG to make linking work against Tcl/Tk frameworks + installed in arbitrary location, change TEA_PROG_* search order + (look in *_BIN_DIR parents before *_PREFIX). + +2006-01-05 Jeff Hobbs + + * tcl.m4: add dkf's system config refactor + +2006-01-04 Jeff Hobbs + + * tcl.m4: remove extraneous ' that causes bash 3.1 to choke + +2005-12-19 Joe English + + * tcl.m4 (TEA_PATH_TCLCONFIG &c): Look for tclConfig.sh &c + in ${libdir}, where they are installed by default [Patch #1377407]. + +2005-12-05 Don Porter + + * tcl.m4 (TEA_PUBLIC_*_HEADERS): Better support for finding + header files for uninstalled Tcl and Tk. + +2005-12-02 Jeff Hobbs + + * tcl.m4: correctly bump TEA_VERSION var to 3.4 + +2005-12-01 Daniel Steffen + + * unix/tcl.m4 (Darwin): fixed error when MACOSX_DEPLOYMENT_TARGET unset + +2005-11-29 Jeff Hobbs + + * tcl.m4: *** Bump to TEA version 3.4 *** + Add Windows x64 build support. + Remove TEA_PATH_NOSPACE and handle the problem with ""s where + necessary - the macro relied on TCLSH_PROG which didn't work for + cross-compiles. + +2005-11-27 Daniel Steffen + + * tcl.m4 (Darwin): add 64bit support, add CFLAGS to SHLIB_LD to + support passing -isysroot in env(CFLAGS) to configure (flag can't + be present twice, so can't be in both CFLAGS and LDFLAGS during + configure), don't use -prebind when deploying on 10.4. + (TEA_ENABLE_LANGINFO, TEA_TIME_HANDLER): add/fix caching. + +2005-10-30 Daniel Steffen + + * tcl.m4: fixed two tests for TEA_WINDOWINGSYSTEM = "aqua" that + should have been for `uname -s` = "Darwin" instead; added some + missing quoting. + (TEA_PROG_TCLSH, TEA_PROG_WISH): fix incorrect assumption that + install location of tclConfig.sh/tkConfig.sh allows to determine + the tclsh/wish install dir via ../bin. Indeed tcl/tk can be + configured with arbitrary --libdir and --bindir (independent of + prefix) and such a configuration is in fact standard with Darwin + framework builds. At least now also check ${TCL_PREFIX}/bin + resp. ${TK_PREFIX}/bin for presence of tclsh resp. wish (if tcl/tk + have been configured with arbitrary --bindir, this will still not + find them, for a general solution *Config.sh would need to contain + the values of bindir/libdir/includedir passed to configure). + +2005-10-07 Jeff Hobbs + + * tcl.m4: Fix Solaris 5.10 check and Solaris AMD64 64-bit builds. + +2005-10-04 Jeff Hobbs + + * tcl.m4 (TEA_PRIVATE_TCL_HEADERS): add / to finish sed macro + (TEA_ENABLE_THREADS): don't check for pthread_attr_setstacksize func + +2005-09-13 Jeff Hobbs + + * tcl.m4: *** Update to TEA version 3.3 *** + define TEA_WINDOWINGSYSTEM in TEA_LOAD_TKCONFIG. + Make --enable-threads the default (users can --disable-threads). + Improve AIX ${CC}_r fix to better check existing ${CC} value. + Do the appropriate evals to not require the *TOP_DIR_NATIVE vars + be set for extensions that use private headers. + Make aqua check for Xlib compat headers the same as win32. + +2005-07-26 Mo DeJong + + * tcl.m4 (TEA_PROG_TCLSH, TEA_BUILD_TCLSH, + TEA_PROG_WISH, TEA_BUILD_WISH): Remove + TEA_BUILD_TCLSH and TEA_BUILD_WISH because + of complaints that it broke the build when + only an installed version of Tcl was available + at extension build time. The TEA_PROG_TCLSH and + TEA_PROG_WISH macros will no longer search the + path at all. The build tclsh or installed + tclsh shell will now be found by TEA_PROG_TCLSH. + +2005-07-24 Mo DeJong + + * tcl.m4 (TEA_PROG_TCLSH, TEA_BUILD_TCLSH, + TEA_PROG_WISH, TEA_BUILD_WISH): + Split confused search for tclsh on PATH and + build and install locations into two macros. + TEA_PROG_TCLSH and TEA_PROG_WISH search the + system PATH for an installed tclsh or wish. + The TEA_BUILD_TCLSH and TEA_BUILD_WISH + macros determine the name of tclsh or + wish in the Tcl or Tk build directory even + if tclsh or wish has not yet been built. + [Tcl bug 1160114] + [Tcl patch 1244153] + +2005-06-23 Daniel Steffen + + * tcl.m4 (TEA_PRIVATE_TK_HEADERS): add ${TK_SRC_DIR}/macosx to + TK_INCLUDES when building against TkAqua. + + * tcl.m4 (TEA_PATH_X): fixed missing comma in AC_DEFINE + + * tcl.m4: changes to better support framework builds of Tcl and Tk out + of the box: search framework install locations for *Config.sh, and if in + presence of a framework build, use the framework's Headers and + PrivateHeaders directories for public and private includes. [FR 947735] + +2005-06-18 Daniel Steffen + + * tcl.m4 (Darwin): add -headerpad_max_install_names to LDFLAGS to + ensure we can always relocate binaries with install_name_tool. + +2005-06-04 Daniel Steffen + + * tcl.m4 (TEA_PATH_X): for TEA_WINDOWINGSYSTEM == aqua, check if xlib + compat headers are available in tkheaders location, otherwise add xlib + sourcedir to TK_XINCLUDES. + +2005-04-25 Daniel Steffen + + * tcl.m4: added AC_DEFINE* descriptions (from core tcl.m4) to allow + use with autoheader. + (Darwin): added configure checks for recently added linker flags + -single_module and -search_paths_first to allow building with older + tools (and on Mac OS X 10.1), use -single_module in SHLIB_LD. + (TEA_MISSING_POSIX_HEADERS): added caching of dirent.h check. + (TEA_BUGGY_STRTOD): added caching (sync with core tcl.m4). + +2005-03-24 Jeff Hobbs + + * tcl.m4 (TEA_TCL_64BIT_FLAGS): use Tcl header defaults for wide + int type only on Windows when __int64 is detected as valid. + +2005-03-24 Don Porter + + * README.txt: Update reference to "SC_* macros" to "TEA_* macros". + * tcl.m4: Incorporated recent improvements in SC_PATH_TCLCONFIG + and SC_PATH_TKCONFIG into TEA_PATH_TCLCONFIG and TEA_PATH_TKCONFIG. + Corrected search path in TEA_PATH_CONFIG and added + AC_SUBST($1_BIN_DIR) to TEA_LOAD_CONFIG so that packages that load + the configuration of another package can know where they loaded + it from. + +2005-03-18 Jeff Hobbs + + * tcl.m4 (TEA_CONFIG_CFLAGS): correct 2005-03-17 change to have + variant LD_SEARCH_FLAGS for gcc and cc builds. + + * tcl.m4 (TEA_PROG_TCLSH, TEA_PROG_WISH): correct x-compile check. + +2005-03-17 Jeff Hobbs + + * tcl.m4: Correct gcc build and HP-UX-11. + +2005-02-08 Jeff Hobbs + + * tcl.m4 (TEA_ADD_LIBS): don't touch lib args starting with -. + (TEA_CONFIG_CFLAGS): only define _DLL for CE in shared build. + (TEA_MAKE_LIB): set RANLIB* to : on Windows (it's not needed). + +2005-02-01 Jeff Hobbs + + * tcl.m4: redo of 2005-01-27 changes to correctly handle paths + with spaces. Win/CE and Win/64 builds now require a prebuilt + tclsh to handle conversion to short pathnames. This is done in + the new TEA_PATH_NOSPACE macro. For Win/CE|64, make CC just the + compiler and move the necessary includes to CFLAGS. + (TEA_CONFIG_CFLAGS): Add Solaris 64-bit gcc build support. + (TEA_PROG_TCLSH, TEA_PROG_WISH): Allow TCLSH_PROG and WISH_PROG to + be set in the env and prevent resetting. + (TEA_ADD_LIBS): On Windows using GCC (mingw), convert foo.lib + args to -lfoo, for use with mingw. + *** POTENTIAL INCOMPATABILITY *** + (TEA_CONFIG_CFLAGS): Fix AIX gcc builds to work out-of-box. + Bumped TEA to 3.2. + +2005-01-27 Jeff Hobbs + + * tcl.m4: remove cygpath calls to support msys. + Update base CE build assumption to "420,ARMV4,ARM,Pocket PC 2003". + Make STLIB_LD use $LINKBIN -lib. + +2005-01-25 Daniel Steffen + + * tcl.m4 (Darwin): fixed bug with static build linking to dynamic + library in /usr/lib etc instead of linking to static library earlier + in search path. [Tcl Bug 956908] + Removed obsolete references to Rhapsody. + +2004-12-29 Jeff Hobbs + + * tcl.m4: Updates for VC7 compatibility, fixing CFLAGS and LDFLAGS + options, using better default -O levels. [Bug 1092952, 1091967] + +2004-12-29 Joe English + + * tcl.m4: Do not use ${DBGX} suffix when building + shared libraries [patch #1081595, TIP #34] + +2004-09-07 Jeff Hobbs + + * tcl.m4 (TEA_CONFIG_CFLAGS): support eVC4 Win/CE builds + +2004-08-10 Jeff Hobbs + + * tcl.m4 (TEA_INIT, TEA_PREFIX): update handling of exec_prefix to + work around subdir configures since autoconf only propagates the + prefix (not exec_prefix). + +2004-07-23 Daniel Steffen + + * tcl.m4 (TEA_CONFIG_CFLAGS): Darwin section: brought inline with + Tcl 8.5 HEAD config, removed core specific & obsolete settings. + +2004-07-22 Jeff Hobbs + + * tcl.m4 (TEA_PATH_X): check in TK_DEFS for MAC_OSX_TK to see if + we are compiling on Aqua. Add TEA_WINDOWINGSYSTEM var that + reflects 'tk windowingsystem' value. + +2004-07-16 Jeff Hobbs + + * tcl.m4 (TEA_ENABLE_THREADS): force a threaded build when + building against a threaded core. + (CFLAGS_WARNING): Remove -Wconversion for gcc builds + (TEA_CONFIG_CFLAGS): Reorder configure.in for better 64-bit build + configuration, replacing EXTRA_CFLAGS with CFLAGS. [Bug #874058] + Update to latest Tcl 8.5 head config settings. + Call this TEA version 3.1. + +2004-04-29 Jeff Hobbs + + * tcl.m4 (TEA_TCL_64BIT_FLAGS): replace AC_TRY_RUN test with + AC_TRY_COMPILE for the long vs. long long check. (kenny) + +2004-04-26 Jeff Hobbs + + * tcl.m4 (TEA_TCL_64BIT_FLAGS): update against core tcl.m4 to + define TCL_WIDE_INT_IS_LONG if 'using long'. + +2004-03-19 Jeff Hobbs + + * tcl.m4: correct Windows builds getting LDFLAGS info in MAKE_LIB + +2004-02-11 Jeff Hobbs + + * tcl.m4: correct TCL_INCLUDES for private headers on Windows - it + doesn't need the eval. + +2004-02-10 Jeff Hobbs + + * tcl.m4: don't require TK_INCLUDES and TCL_INCLUDES to have the + DIR_NATIVE vars defined when using private headers on unix. + Allow $... to TEA_ADD_SOURCES for constructs like + TEA_ADD_SOURCES([\$(WIN_OBJECTS)]), that allow the developer to + place more in the Makefile.in. + tkUnixPort.h checks for HAVE_LIMITS_H, so do both HAVE and + CHECK on limits.h + +2003-12-10 Jeff Hobbs + + * Makefile.in: added TEA_ADD_LIBS, TEA_ADD_INCLUDES and + * configure: TEA_ADD_CFLAGS to configurable parameters with + * configure.in: PKG_* equivs in the Makefile. This allows the + * tclconfig/tcl.m4: user to worry less about actual magic VAR names. + Corrected Makefile.in to note that TEA_ADD_TCL_SOURCES requires + exact file names. + +2003-12-09 Jeff Hobbs + + * tcl.m4: updated OpenBSD support based on [Patch #775246] (cassoff) + +2003-12-05 Jeff Hobbs + + * configure: + * configure.in: + * Makefile.in (VPATH): readd $(srcdir) to front of VPATH as the + first part of VPATH can get chopped off. + Change .c.$(OBJEXT) rule to .c.@OBJEXT@ to support more makes. + * tclconfig/tcl.m4: add TEA_ADD_STUB_SOURCES to support libstub + generation and TEA_ADD_TCL_SOURCES to replace RUNTIME_SOURCES as + the way the user specifies library files. + +2003-12-03 Jeff Hobbs + + * configure: Update of TEA spec to (hopefully) simplify + * configure.in: some aspects of TEA by making use of more + * Makefile.in: AC 2.5x features. Use PACKAGE_NAME (instead + * generic/tclsample.c: of PACKAGE) and PACKAGE_VERSION (instead of + * tclconfig/tcl.m4: VERSION) arguments to AC_INIT as the TEA + package name and version. + Provide a version argument to TEA_INIT - starting with 3.0. + Drop all use of interior shell substs that older makefiles didn't + like. Use PKG_* naming convention instead. + Move specification of source files and public headers into + configure.in with TEA_ADD_SOURCES and TEA_ADD_HEADERS. These will + be munged during ./configure into the right obj file names (no + $(SOURCES:.c=.obj) needed). + There is almost nothing that should be touched in Makefile.in now + for the developer. May want to add a TEA_ADD_TCL_SOURCES for the + RUNTIME_SOURCES that remains. + Use SHLID_LD_FLAGS (instead of SHLID_LDFLAGS) as Tcl does. + Only specify the user requested LDFLAGS/CFLAGS in the Makefile, + don't mention the _OPTIMIZE/_DEBUG variants. + +2003-10-15 Jeff Hobbs + + * tcl.m4: create a TEA_SETUP_COMPILER_CC the precedes the + TEA_SETUP_COMPILER macro. They are split so the check for CC + occurs before any use of CC. Also add AC_PROG_CPP to the compiler + checks. + +2003-10-06 Jeff Hobbs + + * tcl.m4: Updated for autoconf 2.5x prereq. + Where TCL_WIDE_INT_TYPE would be __int64, defer to the code checks + in tcl.h, which also handles TCL_LL_MODIFIER* properly. + +2003-04-22 Jeff Hobbs + + * tcl.m4: correct default setting of ARCH for WinCE builds. + Correct \ escaping for CE sed macros. + +2003-04-10 Jeff Hobbs + + * tcl.m4: replace $(syscal) construct with older `syscall` for + systems where sh != bash. + +2003-04-09 Jeff Hobbs + + * tcl.m4 (TEA_WITH_CELIB): add --enable-wince and --with-celib + options for Windows/CE compilation support. Requires the + Microsoft eMbedded SDK and Keuchel's celib emulation layer. + +2003-02-18 Jeff Hobbs + + * tcl.m4 (TEA_ENABLE_THREADS): Make sure -lpthread gets passed on + the link line when checking for the pthread_attr_setstacksize + symbol. (dejong) + + * tcl.m4 (TEA_SETUP_COMPILER): added default calls to + TEA_TCL_EARLY_FLAGS, TEA_TCL_64BIT_FLAGS, + TEA_MISSING_POSIX_HEADERS and TEA_BUGGY_STRTOD. + +2003-02-14 Jeff Hobbs + + * tcl.m4: correct HP-UX ia64 --enable-64bit build flags + +2003-01-29 Jeff Hobbs + + * tcl.m4: check $prefix/lib as well as $exec_prefix/lib when + looking for tcl|tkConfig.sh, as this check is done before we would + set exec_prefix when the user does not define it. + +2003-01-21 Mo DeJong + + * tcl.m4 (TEA_CONFIG_CFLAGS): Fix build support + for mingw, the previous implementation would + use VC++ when compiling with mingw gcc. Don't + pass -fPIC since gcc always compiles pic code + under win32. Change some hard coded cases + of gcc to ${CC}. + +2002-10-15 Jeff Hobbs + + * tcl.m4: move the CFLAGS definition from TEA_ENABLE_SHARED to + TEA_MAKE_LIB because setting too early confuses other AC_* macros. + Correct the HP-11 SHLIB_LD_LIBS setting. + + * tcl.m4: add the CFLAGS definition into TEA_ENABLE_SHARED and + make it pick up the env CFLAGS at configure time. + +2002-10-09 Jeff Hobbs + + * tcl.m4: add --enable-symbols=mem option to enable TCL_MEM_DEBUG. + Improved AIX 64-bit build support, allow it on AIX-4 as well. + Enable 64-bit HP-11 compilation with gcc. + Enable 64-bit IRIX64-6 cc build support. + Correct FreeBSD thread library linkage. + Add OSF1 static build support. + Improve SunOS-5 shared build SHLIB_LD macro. + +2002-07-20 Zoran Vasiljevic + + * tcl.m4: Added MINGW32 to list of systems checked for Windows build. + Also, fixes some indentation issues with "--with-XXX" options. + +2002-04-23 Jeff Hobbs + + * tcl.m4 (TEA_ENABLE_THREADS): added USE_THREAD_ALLOC define to + use new threaded allocatory by default on Unix for Tcl 8.4. + (TEA_CONFIG_CFLAGS): corrected LD_SEARCH_FLAGS for FreeBSD-3+. + +2002-04-22 Jeff Hobbs + + * tcl.m4 (TEA_SETUP_COMPILER): removed call to AC_CYGWIN so that + we can use autoconf 2.5x as well as 2.13. This prevents us from + being able to warn against the use of cygwin gcc at configure + time, but allows autoconf 2.5x, which is what is shipped with most + newer systems. + +2002-04-11 Jeff Hobbs + + * tcl.m4: Enabled COFF as well as CV style debug info with + --enable-symbols to allow Dr. Watson users to see function info. + More info on debugging levels can be obtained at: + http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp + +2002-04-03 Jeff Hobbs + + * tcl.m4: change all SC_* macros to TEA_*. The SC_ was for + Scriptics, which is no more. TEA represents a better, independent + prefix that won't need changing. + Added preliminary mingw gcc support. [Patch #538772] + Added TEA_PREFIX macro that handles defaulting the prefix and + exec_prefix vars to those used by Tcl if none were specified. + Added TEA_SETUP_COMPILER macro that encompasses the AC_PROG_CC + check and several other basic AC_PROG checks needed for making + executables. This greatly simplifies user's configure.in files. + Collapsed AIX-5 defines into AIX-* with extra checks for doing the + ELF stuff on AIX-5-ia64. + Updated TEA_ENABLE_THREADS to take an optional arg to allow + switching it on by default (for Thread) and add sanity checking to + warn the user if configuring threads incompatibly. + +2002-03-29 Jeff Hobbs + + * tcl.m4: made sure that SHLIB_LDFLAGS was set to LDFLAGS_DEFAULT. + Removed --enable-64bit support for AIX-4 because it wasn't correct. + Added -MT or -MD Windows linker switches to properly support + symbols-enabled builds. + +2002-03-28 Jeff Hobbs + + * tcl.m4: called AC_MSG_ERROR when SC_TEA_INIT wasn't called first + instead of calling it as that inlines it each time in shell code. + Changed Windows CFLAGS_OPTIMIZE to use -O2 instead of -Oti. + Noted TCL_LIB_VERSIONS_OK=nodots for Windows builds. + A few changes to support itcl (and perhaps others): + Added support for making your own stub libraries to SC_MAKE_LIB. + New SC_PATH_CONFIG and SC_LOAD_CONFIG that take a package name arg + and find that ${pkg}Config.sh file. itk uses this for itcl. + +2002-03-27 Jeff Hobbs + + * tcl.m4: made SC_LOAD_TKCONFIG recognize when working with a Tk + build dir setup. + Added EXTRA_CFLAGS and SHLIB_LD_LIBS substs to SC_CONFIG_CFLAGS. + Added XLIBSW onto LIBS when it is defined. + Remove TCL_LIBS from MAKE_LIB and correctly use SHLIB_LD_LIBS + instead to not rely as much on tclConfig.sh cached info. + Add TK_BIN_DIR to paths to find wish in SC_PROG_WISH. + These move towards making TEA much more independent of *Config.sh. + +2002-03-19 Jeff Hobbs + + * tcl.m4: corrected forgotten (UN)SHARED_LIB_SUFFIX and + SHLIB_SUFFIX defines for Win. + (SC_PATH_X): made this only do the check on unix platforms. + +2002-03-12 Jeff Hobbs + + * README.txt: updated to reflect fewer files + +2002-03-06 Jeff Hobbs + + * config.guess (removed): + * config.sub (removed): removed unnecessary files + + * installFile.tcl (removed): + * mkinstalldirs (removed): these aren't really necessary for + making TEA work + + * tcl.m4 (SC_PUBLIC_TCL_HEADERS, SC_PUBLIC_TK_HEADERS): don't + check /usr(/local)/include for includes on Windows when not using + gcc + +2002-03-05 Jeff Hobbs + + * tcl.m4: added warnings on Windows, removed RELPATH define and + added TCL_LIBS to MAKE_LIB macro. + + This import represents 2.0.0, or a new start at attempting to + make TEA much easier for C extension developers. + + **** moved from tclpro project to core tcl project, **** + **** renamed to 'tclconfig' **** + +2001-03-15 Karl Lehenbauer + + * installFile.tcl: Added updating of the modification time of + the target file whether we overwrote it or decided that it + hadn't changed. This was necessary for us to be able to + determine whether or not a module install touched the file. + +2001-03-08 Karl Lehenbauer + + * installFile.tcl: Added support for converting new-style (1.1+) + Cygnus drive paths to Tcl-style. + +2001-01-15 + + * tcl.m4: Added FreeBSD clause. + +2001-01-03 + + * tcl.m4: Fixed typo in SC_LIB_SPEC where it is checking + for exec-prefix. + +2000-12-01 + + * tcl.m4: Concatenated most of the Ajuba acsite.m4 file + so we don't need to modify the autoconf installation. + * config.guess: + * config.sub: + * installFile.tcl: + Added files from the itcl config subdirectory, + which should go away. + +2000-7-29 + + * Fixed the use of TCL_SRC_DIR and TK_SRC_DIR within + TCL_PRIVATE_INCLUDES and TK_PRIVATE_INCLUDES to match their recent + change from $(srcdir) to $(srcdir)/.. diff --git a/tclconfig/README.txt b/tclconfig/README.txt new file mode 100644 index 0000000..59b5a3e --- /dev/null +++ b/tclconfig/README.txt @@ -0,0 +1,26 @@ +These files comprise the basic building blocks for a Tcl Extension +Architecture (TEA) extension. For more information on TEA see: + + http://www.tcl.tk/doc/tea/ + +This package is part of the Tcl project at SourceForge, and latest +sources should be available there: + + http://tcl.sourceforge.net/ + +This package is a freely available open source package. You can do +virtually anything you like with it, such as modifying it, redistributing +it, and selling it either in whole or in part. + +CONTENTS +======== +The following is a short description of the files you will find in +the sample extension. + +README.txt This file + +install-sh Program used for copying binaries and script files + to their install locations. + +tcl.m4 Collection of Tcl autoconf macros. Included by a package's + aclocal.m4 to define TEA_* macros. diff --git a/tclconfig/install-sh b/tclconfig/install-sh new file mode 100755 index 0000000..7c34c3f --- /dev/null +++ b/tclconfig/install-sh @@ -0,0 +1,528 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2011-04-20.01; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +nl=' +' +IFS=" "" $nl" + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit=${DOITPROG-} +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_glob='?' +initialize_posix_glob=' + test "$posix_glob" != "?" || { + if (set -f) 2>/dev/null; then + posix_glob= + else + posix_glob=: + fi + } +' + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +no_target_directory= + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -S $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -S) stripcmd="$stripprog $2" + shift;; + + -t) dst_arg=$2 + shift;; + + -T) no_target_directory=true;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + do_exit='(exit $ret); exit $ret' + trap "ret=129; $do_exit" 1 + trap "ret=130; $do_exit" 2 + trap "ret=141; $do_exit" 13 + trap "ret=143; $do_exit" 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dst_arg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writeable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + -*) prefix='./';; + *) prefix='';; + esac + + eval "$initialize_posix_glob" + + oIFS=$IFS + IFS=/ + $posix_glob set -f + set fnord $dstdir + shift + $posix_glob set +f + IFS=$oIFS + + prefixes= + + for d + do + test -z "$d" && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + + eval "$initialize_posix_glob" && + $posix_glob set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + $posix_glob set +f && + + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/tclconfig/tcl.m4 b/tclconfig/tcl.m4 new file mode 100644 index 0000000..655be25 --- /dev/null +++ b/tclconfig/tcl.m4 @@ -0,0 +1,4176 @@ +# tcl.m4 -- +# +# This file provides a set of autoconf macros to help TEA-enable +# a Tcl extension. +# +# Copyright (c) 1999-2000 Ajuba Solutions. +# Copyright (c) 2002-2005 ActiveState Corporation. +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. + +AC_PREREQ(2.57) + +# Possible values for key variables defined: +# +# TEA_WINDOWINGSYSTEM - win32 aqua x11 (mirrors 'tk windowingsystem') +# TEA_PLATFORM - windows unix +# TEA_TK_EXTENSION - True if this is a Tk extension +# + +#------------------------------------------------------------------------ +# TEA_PATH_TCLCONFIG -- +# +# Locate the tclConfig.sh file and perform a sanity check on +# the Tcl compile flags +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --with-tcl=... +# +# Defines the following vars: +# TCL_BIN_DIR Full path to the directory containing +# the tclConfig.sh file +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PATH_TCLCONFIG], [ + dnl TEA specific: Make sure we are initialized + AC_REQUIRE([TEA_INIT]) + # + # Ok, lets find the tcl configuration + # First, look for one uninstalled. + # the alternative search directory is invoked by --with-tcl + # + + if test x"${no_tcl}" = x ; then + # we reset no_tcl in case something fails here + no_tcl=true + AC_ARG_WITH(tcl, + AC_HELP_STRING([--with-tcl], + [directory containing tcl configuration (tclConfig.sh)]), + with_tclconfig="${withval}") + AC_MSG_CHECKING([for Tcl configuration]) + AC_CACHE_VAL(ac_cv_c_tclconfig,[ + + # First check to see if --with-tcl was specified. + if test x"${with_tclconfig}" != x ; then + case "${with_tclconfig}" in + */tclConfig.sh ) + if test -f "${with_tclconfig}"; then + AC_MSG_WARN([--with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself]) + with_tclconfig="`echo "${with_tclconfig}" | sed 's!/tclConfig\.sh$!!'`" + fi ;; + esac + if test -f "${with_tclconfig}/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd "${with_tclconfig}"; pwd)`" + else + AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh]) + fi + fi + + # then check for a private Tcl installation + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in \ + ../tcl \ + `ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ + ../../tcl \ + `ls -dr ../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ + ../../../tcl \ + `ls -dr ../../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do + if test "${TEA_PLATFORM}" = "windows" \ + -a -f "$i/win/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/win; pwd)`" + break + fi + if test -f "$i/unix/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" + break + fi + done + fi + + # on Darwin, check in Framework installation locations + if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then + for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ + `ls -d /Library/Frameworks 2>/dev/null` \ + `ls -d /Network/Library/Frameworks 2>/dev/null` \ + `ls -d /System/Library/Frameworks 2>/dev/null` \ + `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Library/Frameworks/Tcl.framework 2>/dev/null` \ + `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Network/Library/Frameworks/Tcl.framework 2>/dev/null` \ + `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Tcl.framework 2>/dev/null` \ + ; do + if test -f "$i/Tcl.framework/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`" + break + fi + done + fi + + # TEA specific: on Windows, check in common installation locations + if test "${TEA_PLATFORM}" = "windows" \ + -a x"${ac_cv_c_tclconfig}" = x ; then + for i in `ls -d C:/Tcl/lib 2>/dev/null` \ + `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ + ; do + if test -f "$i/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i; pwd)`" + break + fi + done + fi + + # check in a few common install locations + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in `ls -d ${libdir} 2>/dev/null` \ + `ls -d ${exec_prefix}/lib 2>/dev/null` \ + `ls -d ${prefix}/lib 2>/dev/null` \ + `ls -d /usr/local/lib 2>/dev/null` \ + `ls -d /usr/contrib/lib 2>/dev/null` \ + `ls -d /usr/pkg/lib 2>/dev/null` \ + `ls -d /usr/lib 2>/dev/null` \ + `ls -d /usr/lib64 2>/dev/null` \ + `ls -d /usr/lib/tcl8.6 2>/dev/null` \ + `ls -d /usr/lib/tcl8.5 2>/dev/null` \ + `ls -d /usr/local/lib/tcl8.6 2>/dev/null` \ + `ls -d /usr/local/lib/tcl8.5 2>/dev/null` \ + `ls -d /usr/local/lib/tcl/tcl8.6 2>/dev/null` \ + `ls -d /usr/local/lib/tcl/tcl8.5 2>/dev/null` \ + ; do + if test -f "$i/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i; pwd)`" + break + fi + done + fi + + # check in a few other private locations + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in \ + ${srcdir}/../tcl \ + `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do + if test "${TEA_PLATFORM}" = "windows" \ + -a -f "$i/win/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/win; pwd)`" + break + fi + if test -f "$i/unix/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" + break + fi + done + fi + ]) + + if test x"${ac_cv_c_tclconfig}" = x ; then + TCL_BIN_DIR="# no Tcl configs found" + AC_MSG_ERROR([Can't find Tcl configuration definitions. Use --with-tcl to specify a directory containing tclConfig.sh]) + else + no_tcl= + TCL_BIN_DIR="${ac_cv_c_tclconfig}" + AC_MSG_RESULT([found ${TCL_BIN_DIR}/tclConfig.sh]) + fi + fi +]) + +#------------------------------------------------------------------------ +# TEA_PATH_TKCONFIG -- +# +# Locate the tkConfig.sh file +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --with-tk=... +# +# Defines the following vars: +# TK_BIN_DIR Full path to the directory containing +# the tkConfig.sh file +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PATH_TKCONFIG], [ + # + # Ok, lets find the tk configuration + # First, look for one uninstalled. + # the alternative search directory is invoked by --with-tk + # + + if test x"${no_tk}" = x ; then + # we reset no_tk in case something fails here + no_tk=true + AC_ARG_WITH(tk, + AC_HELP_STRING([--with-tk], + [directory containing tk configuration (tkConfig.sh)]), + with_tkconfig="${withval}") + AC_MSG_CHECKING([for Tk configuration]) + AC_CACHE_VAL(ac_cv_c_tkconfig,[ + + # First check to see if --with-tkconfig was specified. + if test x"${with_tkconfig}" != x ; then + case "${with_tkconfig}" in + */tkConfig.sh ) + if test -f "${with_tkconfig}"; then + AC_MSG_WARN([--with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself]) + with_tkconfig="`echo "${with_tkconfig}" | sed 's!/tkConfig\.sh$!!'`" + fi ;; + esac + if test -f "${with_tkconfig}/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd "${with_tkconfig}"; pwd)`" + else + AC_MSG_ERROR([${with_tkconfig} directory doesn't contain tkConfig.sh]) + fi + fi + + # then check for a private Tk library + if test x"${ac_cv_c_tkconfig}" = x ; then + for i in \ + ../tk \ + `ls -dr ../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../tk[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../tk[[8-9]].[[0-9]]* 2>/dev/null` \ + ../../tk \ + `ls -dr ../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../../tk[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../tk[[8-9]].[[0-9]]* 2>/dev/null` \ + ../../../tk \ + `ls -dr ../../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../../../tk[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do + if test "${TEA_PLATFORM}" = "windows" \ + -a -f "$i/win/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/win; pwd)`" + break + fi + if test -f "$i/unix/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" + break + fi + done + fi + + # on Darwin, check in Framework installation locations + if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tkconfig}" = x ; then + for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ + `ls -d /Library/Frameworks 2>/dev/null` \ + `ls -d /Network/Library/Frameworks 2>/dev/null` \ + `ls -d /System/Library/Frameworks 2>/dev/null` \ + `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Library/Frameworks/Tcl.framework 2>/dev/null` \ + `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Network/Library/Frameworks/Tcl.framework 2>/dev/null` \ + `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Tcl.framework 2>/dev/null` \ + ; do + if test -f "$i/Tk.framework/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/Tk.framework; pwd)`" + break + fi + done + fi + + # check in a few common install locations + if test x"${ac_cv_c_tkconfig}" = x ; then + for i in `ls -d ${libdir} 2>/dev/null` \ + `ls -d ${exec_prefix}/lib 2>/dev/null` \ + `ls -d ${prefix}/lib 2>/dev/null` \ + `ls -d /usr/local/lib 2>/dev/null` \ + `ls -d /usr/contrib/lib 2>/dev/null` \ + `ls -d /usr/pkg/lib 2>/dev/null` \ + `ls -d /usr/lib 2>/dev/null` \ + `ls -d /usr/lib64 2>/dev/null` \ + `ls -d /usr/lib/tk8.6 2>/dev/null` \ + `ls -d /usr/lib/tk8.5 2>/dev/null` \ + `ls -d /usr/local/lib/tk8.6 2>/dev/null` \ + `ls -d /usr/local/lib/tk8.5 2>/dev/null` \ + `ls -d /usr/local/lib/tcl/tk8.6 2>/dev/null` \ + `ls -d /usr/local/lib/tcl/tk8.5 2>/dev/null` \ + ; do + if test -f "$i/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i; pwd)`" + break + fi + done + fi + + # TEA specific: on Windows, check in common installation locations + if test "${TEA_PLATFORM}" = "windows" \ + -a x"${ac_cv_c_tkconfig}" = x ; then + for i in `ls -d C:/Tcl/lib 2>/dev/null` \ + `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ + ; do + if test -f "$i/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i; pwd)`" + break + fi + done + fi + + # check in a few other private locations + if test x"${ac_cv_c_tkconfig}" = x ; then + for i in \ + ${srcdir}/../tk \ + `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do + if test "${TEA_PLATFORM}" = "windows" \ + -a -f "$i/win/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/win; pwd)`" + break + fi + if test -f "$i/unix/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" + break + fi + done + fi + ]) + + if test x"${ac_cv_c_tkconfig}" = x ; then + TK_BIN_DIR="# no Tk configs found" + AC_MSG_ERROR([Can't find Tk configuration definitions. Use --with-tk to specify a directory containing tkConfig.sh]) + else + no_tk= + TK_BIN_DIR="${ac_cv_c_tkconfig}" + AC_MSG_RESULT([found ${TK_BIN_DIR}/tkConfig.sh]) + fi + fi +]) + +#------------------------------------------------------------------------ +# TEA_LOAD_TCLCONFIG -- +# +# Load the tclConfig.sh file +# +# Arguments: +# +# Requires the following vars to be set: +# TCL_BIN_DIR +# +# Results: +# +# Substitutes the following vars: +# TCL_BIN_DIR +# TCL_SRC_DIR +# TCL_LIB_FILE +# TCL_ZIP_FILE +# TCL_ZIPFS_SUPPORT +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_LOAD_TCLCONFIG], [ + AC_MSG_CHECKING([for existence of ${TCL_BIN_DIR}/tclConfig.sh]) + + if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then + AC_MSG_RESULT([loading]) + . "${TCL_BIN_DIR}/tclConfig.sh" + else + AC_MSG_RESULT([could not find ${TCL_BIN_DIR}/tclConfig.sh]) + fi + + # eval is required to do the TCL_DBGX substitution + eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" + eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" + + # If the TCL_BIN_DIR is the build directory (not the install directory), + # then set the common variable name to the value of the build variables. + # For example, the variable TCL_LIB_SPEC will be set to the value + # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC + # instead of TCL_BUILD_LIB_SPEC since it will work with both an + # installed and uninstalled version of Tcl. + if test -f "${TCL_BIN_DIR}/Makefile" ; then + TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}" + TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}" + TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}" + elif test "`uname -s`" = "Darwin"; then + # If Tcl was built as a framework, attempt to use the libraries + # from the framework at the given location so that linking works + # against Tcl.framework installed in an arbitrary location. + case ${TCL_DEFS} in + *TCL_FRAMEWORK*) + if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then + for i in "`cd "${TCL_BIN_DIR}"; pwd`" \ + "`cd "${TCL_BIN_DIR}"/../..; pwd`"; do + if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then + TCL_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TCL_LIB_FILE}" + break + fi + done + fi + if test -f "${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"; then + TCL_STUB_LIB_SPEC="-L`echo "${TCL_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TCL_STUB_LIB_FLAG}" + TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" + fi + ;; + esac + fi + + # eval is required to do the TCL_DBGX substitution + eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" + eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" + eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" + eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" + + AC_SUBST(TCL_VERSION) + AC_SUBST(TCL_PATCH_LEVEL) + AC_SUBST(TCL_BIN_DIR) + AC_SUBST(TCL_SRC_DIR) + + AC_SUBST(TCL_LIB_FILE) + AC_SUBST(TCL_LIB_FLAG) + AC_SUBST(TCL_LIB_SPEC) + + AC_SUBST(TCL_STUB_LIB_FILE) + AC_SUBST(TCL_STUB_LIB_FLAG) + AC_SUBST(TCL_STUB_LIB_SPEC) + + AC_MSG_CHECKING([platform]) + hold_cc=$CC; CC="$TCL_CC" + AC_TRY_COMPILE(,[ + #ifdef _WIN32 + #error win32 + #endif + ], [ + TEA_PLATFORM="unix" + CYGPATH=echo + ], [ + TEA_PLATFORM="windows" + AC_CHECK_PROG(CYGPATH, cygpath, cygpath -m, echo) ] + ) + CC=$hold_cc + AC_MSG_RESULT($TEA_PLATFORM) + + # The BUILD_$pkg is to define the correct extern storage class + # handling when making this package + AC_DEFINE_UNQUOTED(BUILD_${PACKAGE_NAME}, [], + [Building extension source?]) + # Do this here as we have fully defined TEA_PLATFORM now + if test "${TEA_PLATFORM}" = "windows" ; then + EXEEXT=".exe" + CLEANFILES="$CLEANFILES *.lib *.dll *.pdb *.exp" + fi + + # TEA specific: + AC_SUBST(CLEANFILES) + AC_SUBST(TCL_LIBS) + AC_SUBST(TCL_DEFS) + AC_SUBST(TCL_EXTRA_CFLAGS) + AC_SUBST(TCL_LD_FLAGS) + AC_SUBST(TCL_SHLIB_LD_LIBS) +]) + +#------------------------------------------------------------------------ +# TEA_LOAD_TKCONFIG -- +# +# Load the tkConfig.sh file +# +# Arguments: +# +# Requires the following vars to be set: +# TK_BIN_DIR +# +# Results: +# +# Sets the following vars that should be in tkConfig.sh: +# TK_BIN_DIR +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_LOAD_TKCONFIG], [ + AC_MSG_CHECKING([for existence of ${TK_BIN_DIR}/tkConfig.sh]) + + if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then + AC_MSG_RESULT([loading]) + . "${TK_BIN_DIR}/tkConfig.sh" + else + AC_MSG_RESULT([could not find ${TK_BIN_DIR}/tkConfig.sh]) + fi + + # eval is required to do the TK_DBGX substitution + eval "TK_LIB_FILE=\"${TK_LIB_FILE}\"" + eval "TK_STUB_LIB_FILE=\"${TK_STUB_LIB_FILE}\"" + + # If the TK_BIN_DIR is the build directory (not the install directory), + # then set the common variable name to the value of the build variables. + # For example, the variable TK_LIB_SPEC will be set to the value + # of TK_BUILD_LIB_SPEC. An extension should make use of TK_LIB_SPEC + # instead of TK_BUILD_LIB_SPEC since it will work with both an + # installed and uninstalled version of Tcl. + if test -f "${TK_BIN_DIR}/Makefile" ; then + TK_LIB_SPEC="${TK_BUILD_LIB_SPEC}" + TK_STUB_LIB_SPEC="${TK_BUILD_STUB_LIB_SPEC}" + TK_STUB_LIB_PATH="${TK_BUILD_STUB_LIB_PATH}" + elif test "`uname -s`" = "Darwin"; then + # If Tk was built as a framework, attempt to use the libraries + # from the framework at the given location so that linking works + # against Tk.framework installed in an arbitrary location. + case ${TK_DEFS} in + *TK_FRAMEWORK*) + if test -f "${TK_BIN_DIR}/${TK_LIB_FILE}"; then + for i in "`cd "${TK_BIN_DIR}"; pwd`" \ + "`cd "${TK_BIN_DIR}"/../..; pwd`"; do + if test "`basename "$i"`" = "${TK_LIB_FILE}.framework"; then + TK_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TK_LIB_FILE}" + break + fi + done + fi + if test -f "${TK_BIN_DIR}/${TK_STUB_LIB_FILE}"; then + TK_STUB_LIB_SPEC="-L` echo "${TK_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TK_STUB_LIB_FLAG}" + TK_STUB_LIB_PATH="${TK_BIN_DIR}/${TK_STUB_LIB_FILE}" + fi + ;; + esac + fi + + # eval is required to do the TK_DBGX substitution + eval "TK_LIB_FLAG=\"${TK_LIB_FLAG}\"" + eval "TK_LIB_SPEC=\"${TK_LIB_SPEC}\"" + eval "TK_STUB_LIB_FLAG=\"${TK_STUB_LIB_FLAG}\"" + eval "TK_STUB_LIB_SPEC=\"${TK_STUB_LIB_SPEC}\"" + + # TEA specific: Ensure windowingsystem is defined + if test "${TEA_PLATFORM}" = "unix" ; then + case ${TK_DEFS} in + *MAC_OSX_TK*) + AC_DEFINE(MAC_OSX_TK, 1, [Are we building against Mac OS X TkAqua?]) + TEA_WINDOWINGSYSTEM="aqua" + ;; + *) + TEA_WINDOWINGSYSTEM="x11" + ;; + esac + elif test "${TEA_PLATFORM}" = "windows" ; then + TEA_WINDOWINGSYSTEM="win32" + fi + + AC_SUBST(TK_VERSION) + AC_SUBST(TK_BIN_DIR) + AC_SUBST(TK_SRC_DIR) + + AC_SUBST(TK_LIB_FILE) + AC_SUBST(TK_LIB_FLAG) + AC_SUBST(TK_LIB_SPEC) + + AC_SUBST(TK_STUB_LIB_FILE) + AC_SUBST(TK_STUB_LIB_FLAG) + AC_SUBST(TK_STUB_LIB_SPEC) + + # TEA specific: + AC_SUBST(TK_LIBS) + AC_SUBST(TK_XINCLUDES) +]) + +#------------------------------------------------------------------------ +# TEA_PROG_TCLSH +# Determine the fully qualified path name of the tclsh executable +# in the Tcl build directory or the tclsh installed in a bin +# directory. This macro will correctly determine the name +# of the tclsh executable even if tclsh has not yet been +# built in the build directory. The tclsh found is always +# associated with a tclConfig.sh file. This tclsh should be used +# only for running extension test cases. It should never be +# or generation of files (like pkgIndex.tcl) at build time. +# +# Arguments: +# none +# +# Results: +# Substitutes the following vars: +# TCLSH_PROG +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PROG_TCLSH], [ + AC_MSG_CHECKING([for tclsh]) + if test -f "${TCL_BIN_DIR}/Makefile" ; then + # tclConfig.sh is in Tcl build directory + if test "${TEA_PLATFORM}" = "windows"; then + if test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" ; then + TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" + elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}s${EXEEXT}" ; then + TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}s${EXEEXT}" + elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}t${EXEEXT}" ; then + TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}t${EXEEXT}" + elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}st${EXEEXT}" ; then + TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}st${EXEEXT}" + fi + else + TCLSH_PROG="${TCL_BIN_DIR}/tclsh" + fi + else + # tclConfig.sh is in install location + if test "${TEA_PLATFORM}" = "windows"; then + TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" + else + TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}${TCL_DBGX}" + fi + list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \ + `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \ + `ls -d ${TCL_PREFIX}/bin 2>/dev/null`" + for i in $list ; do + if test -f "$i/${TCLSH_PROG}" ; then + REAL_TCL_BIN_DIR="`cd "$i"; pwd`/" + break + fi + done + TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}" + fi + AC_MSG_RESULT([${TCLSH_PROG}]) + AC_SUBST(TCLSH_PROG) +]) + +#------------------------------------------------------------------------ +# TEA_PROG_WISH +# Determine the fully qualified path name of the wish executable +# in the Tk build directory or the wish installed in a bin +# directory. This macro will correctly determine the name +# of the wish executable even if wish has not yet been +# built in the build directory. The wish found is always +# associated with a tkConfig.sh file. This wish should be used +# only for running extension test cases. It should never be +# or generation of files (like pkgIndex.tcl) at build time. +# +# Arguments: +# none +# +# Results: +# Substitutes the following vars: +# WISH_PROG +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PROG_WISH], [ + AC_MSG_CHECKING([for wish]) + if test -f "${TK_BIN_DIR}/Makefile" ; then + # tkConfig.sh is in Tk build directory + if test "${TEA_PLATFORM}" = "windows"; then + if test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" ; then + WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" + elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}s${EXEEXT}" ; then + WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}$s{EXEEXT}" + elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}t${EXEEXT}" ; then + WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}t${EXEEXT}" + elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}st${EXEEXT}" ; then + WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}st${EXEEXT}" + fi + else + WISH_PROG="${TK_BIN_DIR}/wish" + fi + else + # tkConfig.sh is in install location + if test "${TEA_PLATFORM}" = "windows"; then + WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" + else + WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}${TK_DBGX}" + fi + list="`ls -d ${TK_BIN_DIR}/../bin 2>/dev/null` \ + `ls -d ${TK_BIN_DIR}/.. 2>/dev/null` \ + `ls -d ${TK_PREFIX}/bin 2>/dev/null`" + for i in $list ; do + if test -f "$i/${WISH_PROG}" ; then + REAL_TK_BIN_DIR="`cd "$i"; pwd`/" + break + fi + done + WISH_PROG="${REAL_TK_BIN_DIR}${WISH_PROG}" + fi + AC_MSG_RESULT([${WISH_PROG}]) + AC_SUBST(WISH_PROG) +]) + +#------------------------------------------------------------------------ +# TEA_ENABLE_SHARED -- +# +# Allows the building of shared libraries +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --enable-shared=yes|no +# --enable-stubs=yes|no +# +# Defines the following vars: +# STATIC_BUILD Used for building import/export libraries +# on Windows. +# +# Sets the following vars: +# SHARED_BUILD Value of 1 or 0 +# STUBS_BUILD Value if 1 or 0 +# USE_TCL_STUBS Value true: if SHARED_BUILD or --enable-stubs +# USE_TCLOO_STUBS Value true: if SHARED_BUILD or --enable-stubs +# USE_TK_STUBS Value true: if SHARED_BUILD or --enable-stubs +# AND TEA_WINDOWING_SYSTEM != "" +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ENABLE_SHARED], [ + AC_MSG_CHECKING([how to build libraries]) + AC_ARG_ENABLE(shared, + AC_HELP_STRING([--enable-shared], + [build and link with shared libraries (default: on)]), + [shared_ok=$enableval], [shared_ok=yes]) + + if test "${enable_shared+set}" = set; then + enableval="$enable_shared" + shared_ok=$enableval + else + shared_ok=yes + fi + + AC_ARG_ENABLE(stubs, + AC_HELP_STRING([--enable-stubs], + [build and link with stub libraries. Always true for shared builds (default: on)]), + [stubs_ok=$enableval], [stubs_ok=yes]) + + if test "${enable_stubs+set}" = set; then + enableval="$enable_stubs" + stubs_ok=$enableval + else + stubs_ok=yes + fi + + # Stubs are always enabled for shared builds + if test "$shared_ok" = "yes" ; then + AC_MSG_RESULT([shared]) + SHARED_BUILD=1 + STUBS_BUILD=1 + else + AC_MSG_RESULT([static]) + SHARED_BUILD=0 + AC_DEFINE(STATIC_BUILD, 1, [This a static build]) + if test "$stubs_ok" = "yes" ; then + STUBS_BUILD=1 + else + STUBS_BUILD=0 + fi + fi + if test "${STUBS_BUILD}" = "1" ; then + AC_DEFINE(USE_TCL_STUBS, 1, [Use Tcl stubs]) + AC_DEFINE(USE_TCLOO_STUBS, 1, [Use TclOO stubs]) + if test "${TEA_WINDOWINGSYSTEM}" != ""; then + AC_DEFINE(USE_TK_STUBS, 1, [Use Tk stubs]) + fi + fi + + AC_SUBST(SHARED_BUILD) + AC_SUBST(STUBS_BUILD) +]) + +#------------------------------------------------------------------------ +# TEA_ENABLE_THREADS -- +# +# Specify if thread support should be enabled. If "yes" is specified +# as an arg (optional), threads are enabled by default, "no" means +# threads are disabled. "yes" is the default. +# +# TCL_THREADS is checked so that if you are compiling an extension +# against a threaded core, your extension must be compiled threaded +# as well. +# +# Note that it is legal to have a thread enabled extension run in a +# threaded or non-threaded Tcl core, but a non-threaded extension may +# only run in a non-threaded Tcl core. +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --enable-threads +# +# Sets the following vars: +# THREADS_LIBS Thread library(s) +# +# Defines the following vars: +# TCL_THREADS +# _REENTRANT +# _THREAD_SAFE +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_ENABLE_THREADS], [ + AC_ARG_ENABLE(threads, + AC_HELP_STRING([--enable-threads], + [build with threads (default: on)]), + [tcl_ok=$enableval], [tcl_ok=yes]) + + if test "${enable_threads+set}" = set; then + enableval="$enable_threads" + tcl_ok=$enableval + else + tcl_ok=yes + fi + + if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then + TCL_THREADS=1 + + if test "${TEA_PLATFORM}" != "windows" ; then + # We are always OK on Windows, so check what this platform wants: + + # USE_THREAD_ALLOC tells us to try the special thread-based + # allocator that significantly reduces lock contention + AC_DEFINE(USE_THREAD_ALLOC, 1, + [Do we want to use the threaded memory allocator?]) + AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) + if test "`uname -s`" = "SunOS" ; then + AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, + [Do we really want to follow the standard? Yes we do!]) + fi + AC_DEFINE(_THREAD_SAFE, 1, [Do we want the thread-safe OS API?]) + AC_CHECK_LIB(pthread,pthread_mutex_init,tcl_ok=yes,tcl_ok=no) + if test "$tcl_ok" = "no"; then + # Check a little harder for __pthread_mutex_init in the same + # library, as some systems hide it there until pthread.h is + # defined. We could alternatively do an AC_TRY_COMPILE with + # pthread.h, but that will work with libpthread really doesn't + # exist, like AIX 4.2. [Bug: 4359] + AC_CHECK_LIB(pthread, __pthread_mutex_init, + tcl_ok=yes, tcl_ok=no) + fi + + if test "$tcl_ok" = "yes"; then + # The space is needed + THREADS_LIBS=" -lpthread" + else + AC_CHECK_LIB(pthreads, pthread_mutex_init, + tcl_ok=yes, tcl_ok=no) + if test "$tcl_ok" = "yes"; then + # The space is needed + THREADS_LIBS=" -lpthreads" + else + AC_CHECK_LIB(c, pthread_mutex_init, + tcl_ok=yes, tcl_ok=no) + if test "$tcl_ok" = "no"; then + AC_CHECK_LIB(c_r, pthread_mutex_init, + tcl_ok=yes, tcl_ok=no) + if test "$tcl_ok" = "yes"; then + # The space is needed + THREADS_LIBS=" -pthread" + else + TCL_THREADS=0 + AC_MSG_WARN([Do not know how to find pthread lib on your system - thread support disabled]) + fi + fi + fi + fi + fi + else + TCL_THREADS=0 + fi + # Do checking message here to not mess up interleaved configure output + AC_MSG_CHECKING([for building with threads]) + if test "${TCL_THREADS}" = 1; then + AC_DEFINE(TCL_THREADS, 1, [Are we building with threads enabled?]) + AC_MSG_RESULT([yes (default)]) + else + AC_MSG_RESULT([no]) + fi + # TCL_THREADS sanity checking. See if our request for building with + # threads is the same as the way Tcl was built. If not, warn the user. + case ${TCL_DEFS} in + *THREADS=1*) + if test "${TCL_THREADS}" = "0"; then + AC_MSG_WARN([ + Building ${PACKAGE_NAME} without threads enabled, but building against Tcl + that IS thread-enabled. It is recommended to use --enable-threads.]) + fi + ;; + esac + AC_SUBST(TCL_THREADS) +]) + +#------------------------------------------------------------------------ +# TEA_ENABLE_SYMBOLS -- +# +# Specify if debugging symbols should be used. +# Memory (TCL_MEM_DEBUG) debugging can also be enabled. +# +# Arguments: +# none +# +# TEA varies from core Tcl in that C|LDFLAGS_DEFAULT receives +# the value of C|LDFLAGS_OPTIMIZE|DEBUG already substituted. +# Requires the following vars to be set in the Makefile: +# CFLAGS_DEFAULT +# LDFLAGS_DEFAULT +# +# Results: +# +# Adds the following arguments to configure: +# --enable-symbols +# +# Defines the following vars: +# CFLAGS_DEFAULT Sets to $(CFLAGS_DEBUG) if true +# Sets to "$(CFLAGS_OPTIMIZE) -DNDEBUG" if false +# LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true +# Sets to $(LDFLAGS_OPTIMIZE) if false +# DBGX Formerly used as debug library extension; +# always blank now. +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_ENABLE_SYMBOLS], [ + dnl TEA specific: Make sure we are initialized + AC_REQUIRE([TEA_CONFIG_CFLAGS]) + AC_MSG_CHECKING([for build with symbols]) + AC_ARG_ENABLE(symbols, + AC_HELP_STRING([--enable-symbols], + [build with debugging symbols (default: off)]), + [tcl_ok=$enableval], [tcl_ok=no]) + DBGX="" + if test "$tcl_ok" = "no"; then + CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE} -DNDEBUG" + LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}" + AC_MSG_RESULT([no]) + else + CFLAGS_DEFAULT="${CFLAGS_DEBUG}" + LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}" + if test "$tcl_ok" = "yes"; then + AC_MSG_RESULT([yes (standard debugging)]) + fi + fi + # TEA specific: + if test "${TEA_PLATFORM}" != "windows" ; then + LDFLAGS_DEFAULT="${LDFLAGS}" + fi + AC_SUBST(CFLAGS_DEFAULT) + AC_SUBST(LDFLAGS_DEFAULT) + AC_SUBST(TCL_DBGX) + + if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then + AC_DEFINE(TCL_MEM_DEBUG, 1, [Is memory debugging enabled?]) + fi + + if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then + if test "$tcl_ok" = "all"; then + AC_MSG_RESULT([enabled symbols mem debugging]) + else + AC_MSG_RESULT([enabled $tcl_ok debugging]) + fi + fi +]) + +#------------------------------------------------------------------------ +# TEA_ENABLE_LANGINFO -- +# +# Allows use of modern nl_langinfo check for better l10n. +# This is only relevant for Unix. +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --enable-langinfo=yes|no (default is yes) +# +# Defines the following vars: +# HAVE_LANGINFO Triggers use of nl_langinfo if defined. +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_ENABLE_LANGINFO], [ + AC_ARG_ENABLE(langinfo, + AC_HELP_STRING([--enable-langinfo], + [use nl_langinfo if possible to determine encoding at startup, otherwise use old heuristic (default: on)]), + [langinfo_ok=$enableval], [langinfo_ok=yes]) + + HAVE_LANGINFO=0 + if test "$langinfo_ok" = "yes"; then + AC_CHECK_HEADER(langinfo.h,[langinfo_ok=yes],[langinfo_ok=no]) + fi + AC_MSG_CHECKING([whether to use nl_langinfo]) + if test "$langinfo_ok" = "yes"; then + AC_CACHE_VAL(tcl_cv_langinfo_h, [ + AC_TRY_COMPILE([#include ], [nl_langinfo(CODESET);], + [tcl_cv_langinfo_h=yes],[tcl_cv_langinfo_h=no])]) + AC_MSG_RESULT([$tcl_cv_langinfo_h]) + if test $tcl_cv_langinfo_h = yes; then + AC_DEFINE(HAVE_LANGINFO, 1, [Do we have nl_langinfo()?]) + fi + else + AC_MSG_RESULT([$langinfo_ok]) + fi +]) + +#-------------------------------------------------------------------- +# TEA_CONFIG_SYSTEM +# +# Determine what the system is (some things cannot be easily checked +# on a feature-driven basis, alas). This can usually be done via the +# "uname" command. +# +# Arguments: +# none +# +# Results: +# Defines the following var: +# +# system - System/platform/version identification code. +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_CONFIG_SYSTEM], [ + AC_CACHE_CHECK([system version], tcl_cv_sys_version, [ + # TEA specific: + if test "${TEA_PLATFORM}" = "windows" ; then + tcl_cv_sys_version=windows + else + tcl_cv_sys_version=`uname -s`-`uname -r` + if test "$?" -ne 0 ; then + AC_MSG_WARN([can't find uname command]) + tcl_cv_sys_version=unknown + else + if test "`uname -s`" = "AIX" ; then + tcl_cv_sys_version=AIX-`uname -v`.`uname -r` + fi + fi + fi + ]) + system=$tcl_cv_sys_version +]) + +#-------------------------------------------------------------------- +# TEA_CONFIG_CFLAGS +# +# Try to determine the proper flags to pass to the compiler +# for building shared libraries and other such nonsense. +# +# Arguments: +# none +# +# Results: +# +# Defines and substitutes the following vars: +# +# DL_OBJS, DL_LIBS - removed for TEA, only needed by core. +# LDFLAGS - Flags to pass to the compiler when linking object +# files into an executable application binary such +# as tclsh. +# LD_SEARCH_FLAGS-Flags to pass to ld, such as "-R /usr/local/tcl/lib", +# that tell the run-time dynamic linker where to look +# for shared libraries such as libtcl.so. Depends on +# the variable LIB_RUNTIME_DIR in the Makefile. Could +# be the same as CC_SEARCH_FLAGS if ${CC} is used to link. +# CC_SEARCH_FLAGS-Flags to pass to ${CC}, such as "-Wl,-rpath,/usr/local/tcl/lib", +# that tell the run-time dynamic linker where to look +# for shared libraries such as libtcl.so. Depends on +# the variable LIB_RUNTIME_DIR in the Makefile. +# SHLIB_CFLAGS - Flags to pass to cc when compiling the components +# of a shared library (may request position-independent +# code, among other things). +# SHLIB_LD - Base command to use for combining object files +# into a shared library. +# SHLIB_LD_LIBS - Dependent libraries for the linker to scan when +# creating shared libraries. This symbol typically +# goes at the end of the "ld" commands that build +# shared libraries. The value of the symbol defaults to +# "${LIBS}" if all of the dependent libraries should +# be specified when creating a shared library. If +# dependent libraries should not be specified (as on +# SunOS 4.x, where they cause the link to fail, or in +# general if Tcl and Tk aren't themselves shared +# libraries), then this symbol has an empty string +# as its value. +# SHLIB_SUFFIX - Suffix to use for the names of dynamically loadable +# extensions. An empty string means we don't know how +# to use shared libraries on this platform. +# LIB_SUFFIX - Specifies everything that comes after the "libfoo" +# in a static or shared library name, using the $PACKAGE_VERSION variable +# to put the version in the right place. This is used +# by platforms that need non-standard library names. +# Examples: ${PACKAGE_VERSION}.so.1.1 on NetBSD, since it needs +# to have a version after the .so, and ${PACKAGE_VERSION}.a +# on AIX, since a shared library needs to have +# a .a extension whereas shared objects for loadable +# extensions have a .so extension. Defaults to +# ${PACKAGE_VERSION}${SHLIB_SUFFIX}. +# CFLAGS_DEBUG - +# Flags used when running the compiler in debug mode +# CFLAGS_OPTIMIZE - +# Flags used when running the compiler in optimize mode +# CFLAGS - Additional CFLAGS added as necessary (usually 64-bit) +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_CONFIG_CFLAGS], [ + dnl TEA specific: Make sure we are initialized + AC_REQUIRE([TEA_INIT]) + + # Step 0.a: Enable 64 bit support? + + AC_MSG_CHECKING([if 64bit support is requested]) + AC_ARG_ENABLE(64bit, + AC_HELP_STRING([--enable-64bit], + [enable 64bit support (default: off)]), + [do64bit=$enableval], [do64bit=no]) + AC_MSG_RESULT([$do64bit]) + + # Step 0.b: Enable Solaris 64 bit VIS support? + + AC_MSG_CHECKING([if 64bit Sparc VIS support is requested]) + AC_ARG_ENABLE(64bit-vis, + AC_HELP_STRING([--enable-64bit-vis], + [enable 64bit Sparc VIS support (default: off)]), + [do64bitVIS=$enableval], [do64bitVIS=no]) + AC_MSG_RESULT([$do64bitVIS]) + # Force 64bit on with VIS + AS_IF([test "$do64bitVIS" = "yes"], [do64bit=yes]) + + # Step 0.c: Check if visibility support is available. Do this here so + # that platform specific alternatives can be used below if this fails. + + AC_CACHE_CHECK([if compiler supports visibility "hidden"], + tcl_cv_cc_visibility_hidden, [ + hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror" + AC_TRY_LINK([ + extern __attribute__((__visibility__("hidden"))) void f(void); + void f(void) {}], [f();], tcl_cv_cc_visibility_hidden=yes, + tcl_cv_cc_visibility_hidden=no) + CFLAGS=$hold_cflags]) + AS_IF([test $tcl_cv_cc_visibility_hidden = yes], [ + AC_DEFINE(MODULE_SCOPE, + [extern __attribute__((__visibility__("hidden")))], + [Compiler support for module scope symbols]) + AC_DEFINE(HAVE_HIDDEN, [1], [Compiler support for module scope symbols]) + ]) + + # Step 0.d: Disable -rpath support? + + AC_MSG_CHECKING([if rpath support is requested]) + AC_ARG_ENABLE(rpath, + AC_HELP_STRING([--disable-rpath], + [disable rpath support (default: on)]), + [doRpath=$enableval], [doRpath=yes]) + AC_MSG_RESULT([$doRpath]) + + # TEA specific: Cross-compiling options for Windows/CE builds? + + AS_IF([test "${TEA_PLATFORM}" = windows], [ + AC_MSG_CHECKING([if Windows/CE build is requested]) + AC_ARG_ENABLE(wince, + AC_HELP_STRING([--enable-wince], + [enable Win/CE support (where applicable)]), + [doWince=$enableval], [doWince=no]) + AC_MSG_RESULT([$doWince]) + ]) + + # Set the variable "system" to hold the name and version number + # for the system. + + TEA_CONFIG_SYSTEM + + # Require ranlib early so we can override it in special cases below. + + AC_REQUIRE([AC_PROG_RANLIB]) + + # Set configuration options based on system name and version. + # This is similar to Tcl's unix/tcl.m4 except that we've added a + # "windows" case and removed some core-only vars. + + do64bit_ok=no + # default to '{$LIBS}' and set to "" on per-platform necessary basis + SHLIB_LD_LIBS='${LIBS}' + # When ld needs options to work in 64-bit mode, put them in + # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load] + # is disabled by the user. [Bug 1016796] + LDFLAGS_ARCH="" + UNSHARED_LIB_SUFFIX="" + # TEA specific: use PACKAGE_VERSION instead of VERSION + TCL_TRIM_DOTS='`echo ${PACKAGE_VERSION} | tr -d .`' + ECHO_VERSION='`echo ${PACKAGE_VERSION}`' + TCL_LIB_VERSIONS_OK=ok + CFLAGS_DEBUG=-g + AS_IF([test "$GCC" = yes], [ + CFLAGS_OPTIMIZE=-O2 + CFLAGS_WARNING="-Wall" + ], [ + CFLAGS_OPTIMIZE=-O + CFLAGS_WARNING="" + ]) + AC_CHECK_TOOL(AR, ar) + STLIB_LD='${AR} cr' + LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" + AS_IF([test "x$SHLIB_VERSION" = x],[SHLIB_VERSION=""],[SHLIB_VERSION=".$SHLIB_VERSION"]) + case $system in + # TEA specific: + windows) + # This is a 2-stage check to make sure we have the 64-bit SDK + # We have to know where the SDK is installed. + # This magic is based on MS Platform SDK for Win2003 SP1 - hobbs + # MACHINE is IX86 for LINK, but this is used by the manifest, + # which requires x86|amd64|ia64. + MACHINE="X86" + if test "$do64bit" != "no" ; then + if test "x${MSSDK}x" = "xx" ; then + MSSDK="C:/Progra~1/Microsoft Platform SDK" + fi + MSSDK=`echo "$MSSDK" | sed -e 's!\\\!/!g'` + PATH64="" + case "$do64bit" in + amd64|x64|yes) + MACHINE="AMD64" ; # default to AMD64 64-bit build + PATH64="${MSSDK}/Bin/Win64/x86/AMD64" + ;; + ia64) + MACHINE="IA64" + PATH64="${MSSDK}/Bin/Win64" + ;; + esac + if test "$GCC" != "yes" -a ! -d "${PATH64}" ; then + AC_MSG_WARN([Could not find 64-bit $MACHINE SDK to enable 64bit mode]) + AC_MSG_WARN([Ensure latest Platform SDK is installed]) + do64bit="no" + else + AC_MSG_RESULT([ Using 64-bit $MACHINE mode]) + do64bit_ok="yes" + fi + fi + + if test "$doWince" != "no" ; then + if test "$do64bit" != "no" ; then + AC_MSG_ERROR([Windows/CE and 64-bit builds incompatible]) + fi + if test "$GCC" = "yes" ; then + AC_MSG_ERROR([Windows/CE and GCC builds incompatible]) + fi + TEA_PATH_CELIB + # Set defaults for common evc4/PPC2003 setup + # Currently Tcl requires 300+, possibly 420+ for sockets + CEVERSION=420; # could be 211 300 301 400 420 ... + TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ... + ARCH=ARM; # could be ARM MIPS X86EM ... + PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002" + if test "$doWince" != "yes"; then + # If !yes then the user specified something + # Reset ARCH to allow user to skip specifying it + ARCH= + eval `echo $doWince | awk -F, '{ \ + if (length([$]1)) { printf "CEVERSION=\"%s\"\n", [$]1; \ + if ([$]1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \ + if (length([$]2)) { printf "TARGETCPU=\"%s\"\n", toupper([$]2) }; \ + if (length([$]3)) { printf "ARCH=\"%s\"\n", toupper([$]3) }; \ + if (length([$]4)) { printf "PLATFORM=\"%s\"\n", [$]4 }; \ + }'` + if test "x${ARCH}" = "x" ; then + ARCH=$TARGETCPU; + fi + fi + OSVERSION=WCE$CEVERSION; + if test "x${WCEROOT}" = "x" ; then + WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0" + if test ! -d "${WCEROOT}" ; then + WCEROOT="C:/Program Files/Microsoft eMbedded Tools" + fi + fi + if test "x${SDKROOT}" = "x" ; then + SDKROOT="C:/Program Files/Windows CE Tools" + if test ! -d "${SDKROOT}" ; then + SDKROOT="C:/Windows CE Tools" + fi + fi + WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'` + SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'` + if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" \ + -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then + AC_MSG_ERROR([could not find PocketPC SDK or target compiler to enable WinCE mode [$CEVERSION,$TARGETCPU,$ARCH,$PLATFORM]]) + doWince="no" + else + # We could PATH_NOSPACE these, but that's not important, + # as long as we quote them when used. + CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include" + if test -d "${CEINCLUDE}/${TARGETCPU}" ; then + CEINCLUDE="${CEINCLUDE}/${TARGETCPU}" + fi + CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" + fi + fi + + if test "$GCC" != "yes" ; then + if test "${SHARED_BUILD}" = "0" ; then + runtime=-MT + else + runtime=-MD + fi + case "x`echo \${VisualStudioVersion}`" in + x1[[4-9]]*) + lflags="${lflags} -nodefaultlib:libucrt.lib" + TEA_ADD_LIBS([ucrt.lib]) + ;; + *) + ;; + esac + + if test "$do64bit" != "no" ; then + # All this magic is necessary for the Win64 SDK RC1 - hobbs + CC="\"${PATH64}/cl.exe\"" + CFLAGS="${CFLAGS} -I\"${MSSDK}/Include\" -I\"${MSSDK}/Include/crt\" -I\"${MSSDK}/Include/crt/sys\"" + RC="\"${MSSDK}/bin/rc.exe\"" + lflags="${lflags} -nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\"" + LINKBIN="\"${PATH64}/link.exe\"" + CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d" + CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" + # Avoid 'unresolved external symbol __security_cookie' + # errors, c.f. http://support.microsoft.com/?id=894573 + TEA_ADD_LIBS([bufferoverflowU.lib]) + elif test "$doWince" != "no" ; then + CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin" + if test "${TARGETCPU}" = "X86"; then + CC="\"${CEBINROOT}/cl.exe\"" + else + CC="\"${CEBINROOT}/cl${ARCH}.exe\"" + fi + CFLAGS="$CFLAGS -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\"" + RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\"" + arch=`echo ${ARCH} | awk '{print tolower([$]0)}'` + defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _WINDOWS" + if test "${SHARED_BUILD}" = "1" ; then + # Static CE builds require static celib as well + defs="${defs} _DLL" + fi + for i in $defs ; do + AC_DEFINE_UNQUOTED($i, 1, [WinCE def ]$i) + done + AC_DEFINE_UNQUOTED(_WIN32_WCE, $CEVERSION, [_WIN32_WCE version]) + AC_DEFINE_UNQUOTED(UNDER_CE, $CEVERSION, [UNDER_CE version]) + CFLAGS_DEBUG="-nologo -Zi -Od" + CFLAGS_OPTIMIZE="-nologo -Ox" + lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'` + lflags="${lflags} -MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo" + LINKBIN="\"${CEBINROOT}/link.exe\"" + AC_SUBST(CELIB_DIR) + else + RC="rc" + lflags="${lflags} -nologo" + LINKBIN="link" + CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d" + CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" + fi + fi + + if test "$GCC" = "yes"; then + # mingw gcc mode + AC_CHECK_TOOL(RC, windres) + CFLAGS_DEBUG="-g" + CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" + SHLIB_LD='${CC} -shared' + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' + LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" + LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" + + AC_CACHE_CHECK(for cross-compile version of gcc, + ac_cv_cross, + AC_TRY_COMPILE([ + #ifdef _WIN32 + #error cross-compiler + #endif + ], [], + ac_cv_cross=yes, + ac_cv_cross=no) + ) + if test "$ac_cv_cross" = "yes"; then + case "$do64bit" in + amd64|x64|yes) + CC="x86_64-w64-mingw32-gcc" + LD="x86_64-w64-mingw32-ld" + AR="x86_64-w64-mingw32-ar" + RANLIB="x86_64-w64-mingw32-ranlib" + RC="x86_64-w64-mingw32-windres" + ;; + *) + CC="i686-w64-mingw32-gcc" + LD="i686-w64-mingw32-ld" + AR="i686-w64-mingw32-ar" + RANLIB="i686-w64-mingw32-ranlib" + RC="i686-w64-mingw32-windres" + ;; + esac + fi + + else + SHLIB_LD="${LINKBIN} -dll ${lflags}" + # link -lib only works when -lib is the first arg + STLIB_LD="${LINKBIN} -lib ${lflags}" + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.lib' + PATHTYPE=-w + # For information on what debugtype is most useful, see: + # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp + # and also + # http://msdn2.microsoft.com/en-us/library/y0zzbyt4%28VS.80%29.aspx + # This essentially turns it all on. + LDFLAGS_DEBUG="-debug -debugtype:cv" + LDFLAGS_OPTIMIZE="-release" + if test "$doWince" != "no" ; then + LDFLAGS_CONSOLE="-link ${lflags}" + LDFLAGS_WINDOW=${LDFLAGS_CONSOLE} + else + LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}" + LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}" + fi + fi + + SHLIB_SUFFIX=".dll" + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll' + + TCL_LIB_VERSIONS_OK=nodots + ;; + AIX-*) + AS_IF([test "${TCL_THREADS}" = "1" -a "$GCC" != "yes"], [ + # AIX requires the _r compiler when gcc isn't being used + case "${CC}" in + *_r|*_r\ *) + # ok ... + ;; + *) + # Make sure only first arg gets _r + CC=`echo "$CC" | sed -e 's/^\([[^ ]]*\)/\1_r/'` + ;; + esac + AC_MSG_RESULT([Using $CC for compiling with threads]) + ]) + LIBS="$LIBS -lc" + SHLIB_CFLAGS="" + SHLIB_SUFFIX=".so" + + LD_LIBRARY_PATH_VAR="LIBPATH" + + # Check to enable 64-bit flags for compiler/linker + AS_IF([test "$do64bit" = yes], [ + AS_IF([test "$GCC" = yes], [ + AC_MSG_WARN([64bit mode not supported with GCC on $system]) + ], [ + do64bit_ok=yes + CFLAGS="$CFLAGS -q64" + LDFLAGS_ARCH="-q64" + RANLIB="${RANLIB} -X64" + AR="${AR} -X64" + SHLIB_LD_FLAGS="-b64" + ]) + ]) + + AS_IF([test "`uname -m`" = ia64], [ + # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC + SHLIB_LD="/usr/ccs/bin/ld -G -z text" + AS_IF([test "$GCC" = yes], [ + CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' + ], [ + CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}' + ]) + LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' + ], [ + AS_IF([test "$GCC" = yes], [ + SHLIB_LD='${CC} -shared -Wl,-bexpall' + ], [ + SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bexpall -H512 -T512 -bnoentry" + LDFLAGS="$LDFLAGS -brtl" + ]) + SHLIB_LD="${SHLIB_LD} ${SHLIB_LD_FLAGS}" + CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ]) + ;; + BeOS*) + SHLIB_CFLAGS="-fPIC" + SHLIB_LD='${CC} -nostart' + SHLIB_SUFFIX=".so" + + #----------------------------------------------------------- + # Check for inet_ntoa in -lbind, for BeOS (which also needs + # -lsocket, even if the network functions are in -lnet which + # is always linked to, for compatibility. + #----------------------------------------------------------- + AC_CHECK_LIB(bind, inet_ntoa, [LIBS="$LIBS -lbind -lsocket"]) + ;; + BSD/OS-4.*) + SHLIB_CFLAGS="-export-dynamic -fPIC" + SHLIB_LD='${CC} -shared' + SHLIB_SUFFIX=".so" + LDFLAGS="$LDFLAGS -export-dynamic" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + CYGWIN_*) + SHLIB_CFLAGS="" + SHLIB_LD='${CC} -shared' + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,--out-implib,\$[@].a" + SHLIB_SUFFIX=".dll" + EXEEXT=".exe" + do64bit_ok=yes + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + Haiku*) + LDFLAGS="$LDFLAGS -Wl,--export-dynamic" + SHLIB_CFLAGS="-fPIC" + SHLIB_SUFFIX=".so" + SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS} -shared' + AC_CHECK_LIB(network, inet_ntoa, [LIBS="$LIBS -lnetwork"]) + ;; + HP-UX-*.11.*) + # Use updated header definitions where possible + AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, [Do we want to use the XOPEN network library?]) + # TEA specific: Needed by Tcl, but not most extensions + #AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?]) + #LIBS="$LIBS -lxnet" # Use the XOPEN network library + + AS_IF([test "`uname -m`" = ia64], [ + SHLIB_SUFFIX=".so" + # Use newer C++ library for C++ extensions + #if test "$GCC" != "yes" ; then + # CPPFLAGS="-AA" + #fi + ], [ + SHLIB_SUFFIX=".sl" + ]) + AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) + AS_IF([test "$tcl_ok" = yes], [ + LDFLAGS="$LDFLAGS -Wl,-E" + CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' + LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' + LD_LIBRARY_PATH_VAR="SHLIB_PATH" + ]) + AS_IF([test "$GCC" = yes], [ + SHLIB_LD='${CC} -shared' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ], [ + CFLAGS="$CFLAGS -z" + # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc + #CFLAGS="$CFLAGS +DAportable" + SHLIB_CFLAGS="+z" + SHLIB_LD="ld -b" + ]) + + # Check to enable 64-bit flags for compiler/linker + AS_IF([test "$do64bit" = "yes"], [ + AS_IF([test "$GCC" = yes], [ + case `${CC} -dumpmachine` in + hppa64*) + # 64-bit gcc in use. Fix flags for GNU ld. + do64bit_ok=yes + SHLIB_LD='${CC} -shared' + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ;; + *) + AC_MSG_WARN([64bit mode not supported with GCC on $system]) + ;; + esac + ], [ + do64bit_ok=yes + CFLAGS="$CFLAGS +DD64" + LDFLAGS_ARCH="+DD64" + ]) + ]) ;; + IRIX-6.*) + SHLIB_CFLAGS="" + SHLIB_LD="ld -n32 -shared -rdata_shared" + SHLIB_SUFFIX=".so" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) + AS_IF([test "$GCC" = yes], [ + CFLAGS="$CFLAGS -mabi=n32" + LDFLAGS="$LDFLAGS -mabi=n32" + ], [ + case $system in + IRIX-6.3) + # Use to build 6.2 compatible binaries on 6.3. + CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS" + ;; + *) + CFLAGS="$CFLAGS -n32" + ;; + esac + LDFLAGS="$LDFLAGS -n32" + ]) + ;; + IRIX64-6.*) + SHLIB_CFLAGS="" + SHLIB_LD="ld -n32 -shared -rdata_shared" + SHLIB_SUFFIX=".so" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) + + # Check to enable 64-bit flags for compiler/linker + + AS_IF([test "$do64bit" = yes], [ + AS_IF([test "$GCC" = yes], [ + AC_MSG_WARN([64bit mode not supported by gcc]) + ], [ + do64bit_ok=yes + SHLIB_LD="ld -64 -shared -rdata_shared" + CFLAGS="$CFLAGS -64" + LDFLAGS_ARCH="-64" + ]) + ]) + ;; + Linux*|GNU*|NetBSD-Debian) + SHLIB_CFLAGS="-fPIC" + SHLIB_SUFFIX=".so" + + # TEA specific: + CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" + + # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS + SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS_DEFAULT} -shared' + LDFLAGS="$LDFLAGS -Wl,--export-dynamic" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"]) + AS_IF([test $do64bit = yes], [ + AC_CACHE_CHECK([if compiler accepts -m64 flag], tcl_cv_cc_m64, [ + hold_cflags=$CFLAGS + CFLAGS="$CFLAGS -m64" + AC_TRY_LINK(,, tcl_cv_cc_m64=yes, tcl_cv_cc_m64=no) + CFLAGS=$hold_cflags]) + AS_IF([test $tcl_cv_cc_m64 = yes], [ + CFLAGS="$CFLAGS -m64" + do64bit_ok=yes + ]) + ]) + + # The combo of gcc + glibc has a bug related to inlining of + # functions like strtod(). The -fno-builtin flag should address + # this problem but it does not work. The -fno-inline flag is kind + # of overkill but it works. Disable inlining only when one of the + # files in compat/*.c is being linked in. + + AS_IF([test x"${USE_COMPAT}" != x],[CFLAGS="$CFLAGS -fno-inline"]) + ;; + Lynx*) + SHLIB_CFLAGS="-fPIC" + SHLIB_SUFFIX=".so" + CFLAGS_OPTIMIZE=-02 + SHLIB_LD='${CC} -shared' + LD_FLAGS="-Wl,--export-dynamic" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) + ;; + OpenBSD-*) + arch=`arch -s` + case "$arch" in + alpha|sparc64) + SHLIB_CFLAGS="-fPIC" + ;; + *) + SHLIB_CFLAGS="-fpic" + ;; + esac + SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared' + SHLIB_SUFFIX=".so" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so${SHLIB_VERSION}' + LDFLAGS="-Wl,-export-dynamic" + CFLAGS_OPTIMIZE="-O2" + AS_IF([test "${TCL_THREADS}" = "1"], [ + # On OpenBSD: Compile with -pthread + # Don't link with -lpthread + LIBS=`echo $LIBS | sed s/-lpthread//` + CFLAGS="$CFLAGS -pthread" + ]) + # OpenBSD doesn't do version numbers with dots. + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' + TCL_LIB_VERSIONS_OK=nodots + ;; + NetBSD-*) + # NetBSD has ELF and can use 'cc -shared' to build shared libs + SHLIB_CFLAGS="-fPIC" + SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared' + SHLIB_SUFFIX=".so" + LDFLAGS="$LDFLAGS -export-dynamic" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + AS_IF([test "${TCL_THREADS}" = "1"], [ + # The -pthread needs to go in the CFLAGS, not LIBS + LIBS=`echo $LIBS | sed s/-pthread//` + CFLAGS="$CFLAGS -pthread" + LDFLAGS="$LDFLAGS -pthread" + ]) + ;; + DragonFly-*|FreeBSD-*) + # This configuration from FreeBSD Ports. + SHLIB_CFLAGS="-fPIC" + SHLIB_LD="${CC} -shared" + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,-soname,\$[@]" + SHLIB_SUFFIX=".so" + LDFLAGS="" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) + AS_IF([test "${TCL_THREADS}" = "1"], [ + # The -pthread needs to go in the LDFLAGS, not LIBS + LIBS=`echo $LIBS | sed s/-pthread//` + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LDFLAGS="$LDFLAGS $PTHREAD_LIBS"]) + case $system in + FreeBSD-3.*) + # Version numbers are dot-stripped by system policy. + TCL_TRIM_DOTS=`echo ${PACKAGE_VERSION} | tr -d .` + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1' + TCL_LIB_VERSIONS_OK=nodots + ;; + esac + ;; + Darwin-*) + CFLAGS_OPTIMIZE="-Os" + SHLIB_CFLAGS="-fno-common" + # To avoid discrepancies between what headers configure sees during + # preprocessing tests and compiling tests, move any -isysroot and + # -mmacosx-version-min flags from CFLAGS to CPPFLAGS: + CPPFLAGS="${CPPFLAGS} `echo " ${CFLAGS}" | \ + awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ + if ([$]i~/^(isysroot|mmacosx-version-min)/) print "-"[$]i}'`" + CFLAGS="`echo " ${CFLAGS}" | \ + awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ + if (!([$]i~/^(isysroot|mmacosx-version-min)/)) print "-"[$]i}'`" + AS_IF([test $do64bit = yes], [ + case `arch` in + ppc) + AC_CACHE_CHECK([if compiler accepts -arch ppc64 flag], + tcl_cv_cc_arch_ppc64, [ + hold_cflags=$CFLAGS + CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" + AC_TRY_LINK(,, tcl_cv_cc_arch_ppc64=yes, + tcl_cv_cc_arch_ppc64=no) + CFLAGS=$hold_cflags]) + AS_IF([test $tcl_cv_cc_arch_ppc64 = yes], [ + CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" + do64bit_ok=yes + ]);; + i386) + AC_CACHE_CHECK([if compiler accepts -arch x86_64 flag], + tcl_cv_cc_arch_x86_64, [ + hold_cflags=$CFLAGS + CFLAGS="$CFLAGS -arch x86_64" + AC_TRY_LINK(,, tcl_cv_cc_arch_x86_64=yes, + tcl_cv_cc_arch_x86_64=no) + CFLAGS=$hold_cflags]) + AS_IF([test $tcl_cv_cc_arch_x86_64 = yes], [ + CFLAGS="$CFLAGS -arch x86_64" + do64bit_ok=yes + ]);; + *) + AC_MSG_WARN([Don't know how enable 64-bit on architecture `arch`]);; + esac + ], [ + # Check for combined 32-bit and 64-bit fat build + AS_IF([echo "$CFLAGS " |grep -E -q -- '-arch (ppc64|x86_64) ' \ + && echo "$CFLAGS " |grep -E -q -- '-arch (ppc|i386) '], [ + fat_32_64=yes]) + ]) + # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS + SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}' + AC_CACHE_CHECK([if ld accepts -single_module flag], tcl_cv_ld_single_module, [ + hold_ldflags=$LDFLAGS + LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" + AC_TRY_LINK(, [int i;], tcl_cv_ld_single_module=yes, tcl_cv_ld_single_module=no) + LDFLAGS=$hold_ldflags]) + AS_IF([test $tcl_cv_ld_single_module = yes], [ + SHLIB_LD="${SHLIB_LD} -Wl,-single_module" + ]) + # TEA specific: link shlib with current and compatibility version flags + vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([[0-9]]\{1,5\}\)\(\(\.[[0-9]]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d` + SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}" + SHLIB_SUFFIX=".dylib" + # Don't use -prebind when building for Mac OS X 10.4 or later only: + AS_IF([test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int([$]2)}'`" -lt 4 -a \ + "`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int([$]2)}'`" -lt 4], [ + LDFLAGS="$LDFLAGS -prebind"]) + LDFLAGS="$LDFLAGS -headerpad_max_install_names" + AC_CACHE_CHECK([if ld accepts -search_paths_first flag], + tcl_cv_ld_search_paths_first, [ + hold_ldflags=$LDFLAGS + LDFLAGS="$LDFLAGS -Wl,-search_paths_first" + AC_TRY_LINK(, [int i;], tcl_cv_ld_search_paths_first=yes, + tcl_cv_ld_search_paths_first=no) + LDFLAGS=$hold_ldflags]) + AS_IF([test $tcl_cv_ld_search_paths_first = yes], [ + LDFLAGS="$LDFLAGS -Wl,-search_paths_first" + ]) + AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ + AC_DEFINE(MODULE_SCOPE, [__private_extern__], + [Compiler support for module scope symbols]) + tcl_cv_cc_visibility_hidden=yes + ]) + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" + # TEA specific: for combined 32 & 64 bit fat builds of Tk + # extensions, verify that 64-bit build is possible. + AS_IF([test "$fat_32_64" = yes && test -n "${TK_BIN_DIR}"], [ + AS_IF([test "${TEA_WINDOWINGSYSTEM}" = x11], [ + AC_CACHE_CHECK([for 64-bit X11], tcl_cv_lib_x11_64, [ + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' + done + CPPFLAGS="$CPPFLAGS -I/usr/X11R6/include" + LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11" + AC_TRY_LINK([#include ], [XrmInitialize();], + tcl_cv_lib_x11_64=yes, tcl_cv_lib_x11_64=no) + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval $v'="$hold_'$v'"' + done]) + ]) + AS_IF([test "${TEA_WINDOWINGSYSTEM}" = aqua], [ + AC_CACHE_CHECK([for 64-bit Tk], tcl_cv_lib_tk_64, [ + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' + done + CPPFLAGS="$CPPFLAGS -DUSE_TCL_STUBS=1 -DUSE_TK_STUBS=1 ${TCL_INCLUDES} ${TK_INCLUDES}" + LDFLAGS="$LDFLAGS ${TCL_STUB_LIB_SPEC} ${TK_STUB_LIB_SPEC}" + AC_TRY_LINK([#include ], [Tk_InitStubs(NULL, "", 0);], + tcl_cv_lib_tk_64=yes, tcl_cv_lib_tk_64=no) + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval $v'="$hold_'$v'"' + done]) + ]) + # remove 64-bit arch flags from CFLAGS et al. if configuration + # does not support 64-bit. + AS_IF([test "$tcl_cv_lib_tk_64" = no -o "$tcl_cv_lib_x11_64" = no], [ + AC_MSG_NOTICE([Removing 64-bit architectures from compiler & linker flags]) + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval $v'="`echo "$'$v' "|sed -e "s/-arch ppc64 / /g" -e "s/-arch x86_64 / /g"`"' + done]) + ]) + ;; + OS/390-*) + CFLAGS_OPTIMIZE="" # Optimizer is buggy + AC_DEFINE(_OE_SOCKETS, 1, # needed in sys/socket.h + [Should OS/390 do the right thing with sockets?]) + ;; + OSF1-V*) + # Digital OSF/1 + SHLIB_CFLAGS="" + AS_IF([test "$SHARED_BUILD" = 1], [ + SHLIB_LD='ld -shared -expect_unresolved "*"' + ], [ + SHLIB_LD='ld -non_shared -expect_unresolved "*"' + ]) + SHLIB_SUFFIX=".so" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) + AS_IF([test "$GCC" = yes], [CFLAGS="$CFLAGS -mieee"], [ + CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee"]) + # see pthread_intro(3) for pthread support on osf1, k.furukawa + AS_IF([test "${TCL_THREADS}" = 1], [ + CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" + CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" + LIBS=`echo $LIBS | sed s/-lpthreads//` + AS_IF([test "$GCC" = yes], [ + LIBS="$LIBS -lpthread -lmach -lexc" + ], [ + CFLAGS="$CFLAGS -pthread" + LDFLAGS="$LDFLAGS -pthread" + ]) + ]) + ;; + QNX-6*) + # QNX RTP + # This may work for all QNX, but it was only reported for v6. + SHLIB_CFLAGS="-fPIC" + SHLIB_LD="ld -Bshareable -x" + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + SCO_SV-3.2*) + AS_IF([test "$GCC" = yes], [ + SHLIB_CFLAGS="-fPIC -melf" + LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" + ], [ + SHLIB_CFLAGS="-Kpic -belf" + LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" + ]) + SHLIB_LD="ld -G" + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + SunOS-5.[[0-6]]) + # Careful to not let 5.10+ fall into this case + + # Note: If _REENTRANT isn't defined, then Solaris + # won't define thread-safe library routines. + + AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) + AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, + [Do we really want to follow the standard? Yes we do!]) + + SHLIB_CFLAGS="-KPIC" + SHLIB_SUFFIX=".so" + AS_IF([test "$GCC" = yes], [ + SHLIB_LD='${CC} -shared' + CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ], [ + SHLIB_LD="/usr/ccs/bin/ld -G -z text" + CC_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ]) + ;; + SunOS-5*) + # Note: If _REENTRANT isn't defined, then Solaris + # won't define thread-safe library routines. + + AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) + AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, + [Do we really want to follow the standard? Yes we do!]) + + SHLIB_CFLAGS="-KPIC" + + # Check to enable 64-bit flags for compiler/linker + AS_IF([test "$do64bit" = yes], [ + arch=`isainfo` + AS_IF([test "$arch" = "sparcv9 sparc"], [ + AS_IF([test "$GCC" = yes], [ + AS_IF([test "`${CC} -dumpversion | awk -F. '{print [$]1}'`" -lt 3], [ + AC_MSG_WARN([64bit mode not supported with GCC < 3.2 on $system]) + ], [ + do64bit_ok=yes + CFLAGS="$CFLAGS -m64 -mcpu=v9" + LDFLAGS="$LDFLAGS -m64 -mcpu=v9" + SHLIB_CFLAGS="-fPIC" + ]) + ], [ + do64bit_ok=yes + AS_IF([test "$do64bitVIS" = yes], [ + CFLAGS="$CFLAGS -xarch=v9a" + LDFLAGS_ARCH="-xarch=v9a" + ], [ + CFLAGS="$CFLAGS -xarch=v9" + LDFLAGS_ARCH="-xarch=v9" + ]) + # Solaris 64 uses this as well + #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" + ]) + ], [AS_IF([test "$arch" = "amd64 i386"], [ + AS_IF([test "$GCC" = yes], [ + case $system in + SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) + do64bit_ok=yes + CFLAGS="$CFLAGS -m64" + LDFLAGS="$LDFLAGS -m64";; + *) + AC_MSG_WARN([64bit mode not supported with GCC on $system]);; + esac + ], [ + do64bit_ok=yes + case $system in + SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) + CFLAGS="$CFLAGS -m64" + LDFLAGS="$LDFLAGS -m64";; + *) + CFLAGS="$CFLAGS -xarch=amd64" + LDFLAGS="$LDFLAGS -xarch=amd64";; + esac + ]) + ], [AC_MSG_WARN([64bit mode not supported for $arch])])]) + ]) + + SHLIB_SUFFIX=".so" + AS_IF([test "$GCC" = yes], [ + SHLIB_LD='${CC} -shared' + CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + AS_IF([test "$do64bit_ok" = yes], [ + AS_IF([test "$arch" = "sparcv9 sparc"], [ + # We need to specify -static-libgcc or we need to + # add the path to the sparv9 libgcc. + # JH: static-libgcc is necessary for core Tcl, but may + # not be necessary for extensions. + SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc" + # for finding sparcv9 libgcc, get the regular libgcc + # path, remove so name and append 'sparcv9' + #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..." + #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir" + ], [AS_IF([test "$arch" = "amd64 i386"], [ + # JH: static-libgcc is necessary for core Tcl, but may + # not be necessary for extensions. + SHLIB_LD="$SHLIB_LD -m64 -static-libgcc" + ])]) + ]) + ], [ + case $system in + SunOS-5.[[1-9]][[0-9]]*) + # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS + SHLIB_LD='${CC} -G -z text ${LDFLAGS_DEFAULT}';; + *) + SHLIB_LD='/usr/ccs/bin/ld -G -z text';; + esac + CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' + ]) + ;; + UNIX_SV* | UnixWare-5*) + SHLIB_CFLAGS="-KPIC" + SHLIB_LD='${CC} -G' + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + # Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers + # that don't grok the -Bexport option. Test that it does. + AC_CACHE_CHECK([for ld accepts -Bexport flag], tcl_cv_ld_Bexport, [ + hold_ldflags=$LDFLAGS + LDFLAGS="$LDFLAGS -Wl,-Bexport" + AC_TRY_LINK(, [int i;], tcl_cv_ld_Bexport=yes, tcl_cv_ld_Bexport=no) + LDFLAGS=$hold_ldflags]) + AS_IF([test $tcl_cv_ld_Bexport = yes], [ + LDFLAGS="$LDFLAGS -Wl,-Bexport" + ]) + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + esac + + AS_IF([test "$do64bit" = yes -a "$do64bit_ok" = no], [ + AC_MSG_WARN([64bit support being disabled -- don't know magic for this platform]) + ]) + +dnl # Add any CPPFLAGS set in the environment to our CFLAGS, but delay doing so +dnl # until the end of configure, as configure's compile and link tests use +dnl # both CPPFLAGS and CFLAGS (unlike our compile and link) but configure's +dnl # preprocessing tests use only CPPFLAGS. + AC_CONFIG_COMMANDS_PRE([CFLAGS="${CFLAGS} ${CPPFLAGS}"; CPPFLAGS=""]) + + # Add in the arch flags late to ensure it wasn't removed. + # Not necessary in TEA, but this is aligned with core + LDFLAGS="$LDFLAGS $LDFLAGS_ARCH" + + # If we're running gcc, then change the C flags for compiling shared + # libraries to the right flags for gcc, instead of those for the + # standard manufacturer compiler. + + AS_IF([test "$GCC" = yes], [ + case $system in + AIX-*) ;; + BSD/OS*) ;; + CYGWIN_*|MINGW32_*|MINGW64_*) ;; + IRIX*) ;; + NetBSD-*|DragonFly-*|FreeBSD-*|OpenBSD-*) ;; + Darwin-*) ;; + SCO_SV-3.2*) ;; + windows) ;; + *) SHLIB_CFLAGS="-fPIC" ;; + esac]) + + AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ + AC_DEFINE(MODULE_SCOPE, [extern], + [No Compiler support for module scope symbols]) + ]) + + AS_IF([test "$SHARED_LIB_SUFFIX" = ""], [ + # TEA specific: use PACKAGE_VERSION instead of VERSION + SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}']) + AS_IF([test "$UNSHARED_LIB_SUFFIX" = ""], [ + # TEA specific: use PACKAGE_VERSION instead of VERSION + UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a']) + + if test "${GCC}" = "yes" -a ${SHLIB_SUFFIX} = ".dll"; then + AC_CACHE_CHECK(for SEH support in compiler, + tcl_cv_seh, + AC_TRY_RUN([ +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN + + int main(int argc, char** argv) { + int a, b = 0; + __try { + a = 666 / b; + } + __except (EXCEPTION_EXECUTE_HANDLER) { + return 0; + } + return 1; + } + ], + tcl_cv_seh=yes, + tcl_cv_seh=no, + tcl_cv_seh=no) + ) + if test "$tcl_cv_seh" = "no" ; then + AC_DEFINE(HAVE_NO_SEH, 1, + [Defined when mingw does not support SEH]) + fi + + # + # Check to see if the excpt.h include file provided contains the + # definition for EXCEPTION_DISPOSITION; if not, which is the case + # with Cygwin's version as of 2002-04-10, define it to be int, + # sufficient for getting the current code to work. + # + AC_CACHE_CHECK(for EXCEPTION_DISPOSITION support in include files, + tcl_cv_eh_disposition, + AC_TRY_COMPILE([ +# define WIN32_LEAN_AND_MEAN +# include +# undef WIN32_LEAN_AND_MEAN + ],[ + EXCEPTION_DISPOSITION x; + ], + tcl_cv_eh_disposition=yes, + tcl_cv_eh_disposition=no) + ) + if test "$tcl_cv_eh_disposition" = "no" ; then + AC_DEFINE(EXCEPTION_DISPOSITION, int, + [Defined when cygwin/mingw does not support EXCEPTION DISPOSITION]) + fi + + # Check to see if winnt.h defines CHAR, SHORT, and LONG + # even if VOID has already been #defined. The win32api + # used by mingw and cygwin is known to do this. + + AC_CACHE_CHECK(for winnt.h that ignores VOID define, + tcl_cv_winnt_ignore_void, + AC_TRY_COMPILE([ +#define VOID void +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN + ], [ + CHAR c; + SHORT s; + LONG l; + ], + tcl_cv_winnt_ignore_void=yes, + tcl_cv_winnt_ignore_void=no) + ) + if test "$tcl_cv_winnt_ignore_void" = "yes" ; then + AC_DEFINE(HAVE_WINNT_IGNORE_VOID, 1, + [Defined when cygwin/mingw ignores VOID define in winnt.h]) + fi + fi + + # See if the compiler supports casting to a union type. + # This is used to stop gcc from printing a compiler + # warning when initializing a union member. + + AC_CACHE_CHECK(for cast to union support, + tcl_cv_cast_to_union, + AC_TRY_COMPILE([], + [ + union foo { int i; double d; }; + union foo f = (union foo) (int) 0; + ], + tcl_cv_cast_to_union=yes, + tcl_cv_cast_to_union=no) + ) + if test "$tcl_cv_cast_to_union" = "yes"; then + AC_DEFINE(HAVE_CAST_TO_UNION, 1, + [Defined when compiler supports casting to union type.]) + fi + + AC_SUBST(CFLAGS_DEBUG) + AC_SUBST(CFLAGS_OPTIMIZE) + AC_SUBST(CFLAGS_WARNING) + + AC_SUBST(STLIB_LD) + AC_SUBST(SHLIB_LD) + + AC_SUBST(SHLIB_LD_LIBS) + AC_SUBST(SHLIB_CFLAGS) + + AC_SUBST(LD_LIBRARY_PATH_VAR) + + # These must be called after we do the basic CFLAGS checks and + # verify any possible 64-bit or similar switches are necessary + TEA_TCL_EARLY_FLAGS + TEA_TCL_64BIT_FLAGS +]) + +#-------------------------------------------------------------------- +# TEA_SERIAL_PORT +# +# Determine which interface to use to talk to the serial port. +# Note that #include lines must begin in leftmost column for +# some compilers to recognize them as preprocessor directives, +# and some build environments have stdin not pointing at a +# pseudo-terminal (usually /dev/null instead.) +# +# Arguments: +# none +# +# Results: +# +# Defines only one of the following vars: +# HAVE_SYS_MODEM_H +# USE_TERMIOS +# USE_TERMIO +# USE_SGTTY +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_SERIAL_PORT], [ + AC_CHECK_HEADERS(sys/modem.h) + AC_CACHE_CHECK([termios vs. termio vs. sgtty], tcl_cv_api_serial, [ + AC_TRY_RUN([ +#include + +int main() { + struct termios t; + if (tcgetattr(0, &t) == 0) { + cfsetospeed(&t, 0); + t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; + return 0; + } + return 1; +}], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) + if test $tcl_cv_api_serial = no ; then + AC_TRY_RUN([ +#include + +int main() { + struct termio t; + if (ioctl(0, TCGETA, &t) == 0) { + t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; + return 0; + } + return 1; +}], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) + fi + if test $tcl_cv_api_serial = no ; then + AC_TRY_RUN([ +#include + +int main() { + struct sgttyb t; + if (ioctl(0, TIOCGETP, &t) == 0) { + t.sg_ospeed = 0; + t.sg_flags |= ODDP | EVENP | RAW; + return 0; + } + return 1; +}], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=no, tcl_cv_api_serial=no) + fi + if test $tcl_cv_api_serial = no ; then + AC_TRY_RUN([ +#include +#include + +int main() { + struct termios t; + if (tcgetattr(0, &t) == 0 + || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { + cfsetospeed(&t, 0); + t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; + return 0; + } + return 1; +}], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) + fi + if test $tcl_cv_api_serial = no; then + AC_TRY_RUN([ +#include +#include + +int main() { + struct termio t; + if (ioctl(0, TCGETA, &t) == 0 + || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { + t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; + return 0; + } + return 1; + }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) + fi + if test $tcl_cv_api_serial = no; then + AC_TRY_RUN([ +#include +#include + +int main() { + struct sgttyb t; + if (ioctl(0, TIOCGETP, &t) == 0 + || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { + t.sg_ospeed = 0; + t.sg_flags |= ODDP | EVENP | RAW; + return 0; + } + return 1; +}], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=none, tcl_cv_api_serial=none) + fi]) + case $tcl_cv_api_serial in + termios) AC_DEFINE(USE_TERMIOS, 1, [Use the termios API for serial lines]);; + termio) AC_DEFINE(USE_TERMIO, 1, [Use the termio API for serial lines]);; + sgtty) AC_DEFINE(USE_SGTTY, 1, [Use the sgtty API for serial lines]);; + esac +]) + +#-------------------------------------------------------------------- +# TEA_PATH_X +# +# Locate the X11 header files and the X11 library archive. Try +# the ac_path_x macro first, but if it doesn't find the X stuff +# (e.g. because there's no xmkmf program) then check through +# a list of possible directories. Under some conditions the +# autoconf macro will return an include directory that contains +# no include files, so double-check its result just to be safe. +# +# This should be called after TEA_CONFIG_CFLAGS as setting the +# LIBS line can confuse some configure macro magic. +# +# Arguments: +# none +# +# Results: +# +# Sets the following vars: +# XINCLUDES +# XLIBSW +# PKG_LIBS (appends to) +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_PATH_X], [ + if test "${TEA_WINDOWINGSYSTEM}" = "x11" ; then + TEA_PATH_UNIX_X + fi +]) + +AC_DEFUN([TEA_PATH_UNIX_X], [ + AC_PATH_X + not_really_there="" + if test "$no_x" = ""; then + if test "$x_includes" = ""; then + AC_TRY_CPP([#include ], , not_really_there="yes") + else + if test ! -r $x_includes/X11/Xlib.h; then + not_really_there="yes" + fi + fi + fi + if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then + AC_MSG_CHECKING([for X11 header files]) + found_xincludes="no" + AC_TRY_CPP([#include ], found_xincludes="yes", found_xincludes="no") + if test "$found_xincludes" = "no"; then + dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include" + for i in $dirs ; do + if test -r $i/X11/Xlib.h; then + AC_MSG_RESULT([$i]) + XINCLUDES=" -I$i" + found_xincludes="yes" + break + fi + done + fi + else + if test "$x_includes" != ""; then + XINCLUDES="-I$x_includes" + found_xincludes="yes" + fi + fi + if test "$found_xincludes" = "no"; then + AC_MSG_RESULT([couldn't find any!]) + fi + + if test "$no_x" = yes; then + AC_MSG_CHECKING([for X11 libraries]) + XLIBSW=nope + dirs="/usr/unsupported/lib /usr/local/lib /usr/X386/lib /usr/X11R6/lib /usr/X11R5/lib /usr/lib/X11R5 /usr/lib/X11R4 /usr/openwin/lib /usr/X11/lib /usr/sww/X11/lib" + for i in $dirs ; do + if test -r $i/libX11.a -o -r $i/libX11.so -o -r $i/libX11.sl -o -r $i/libX11.dylib; then + AC_MSG_RESULT([$i]) + XLIBSW="-L$i -lX11" + x_libraries="$i" + break + fi + done + else + if test "$x_libraries" = ""; then + XLIBSW=-lX11 + else + XLIBSW="-L$x_libraries -lX11" + fi + fi + if test "$XLIBSW" = nope ; then + AC_CHECK_LIB(Xwindow, XCreateWindow, XLIBSW=-lXwindow) + fi + if test "$XLIBSW" = nope ; then + AC_MSG_RESULT([could not find any! Using -lX11.]) + XLIBSW=-lX11 + fi + # TEA specific: + if test x"${XLIBSW}" != x ; then + PKG_LIBS="${PKG_LIBS} ${XLIBSW}" + fi +]) + +#-------------------------------------------------------------------- +# TEA_BLOCKING_STYLE +# +# The statements below check for systems where POSIX-style +# non-blocking I/O (O_NONBLOCK) doesn't work or is unimplemented. +# On these systems (mostly older ones), use the old BSD-style +# FIONBIO approach instead. +# +# Arguments: +# none +# +# Results: +# +# Defines some of the following vars: +# HAVE_SYS_IOCTL_H +# HAVE_SYS_FILIO_H +# USE_FIONBIO +# O_NONBLOCK +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_BLOCKING_STYLE], [ + AC_CHECK_HEADERS(sys/ioctl.h) + AC_CHECK_HEADERS(sys/filio.h) + TEA_CONFIG_SYSTEM + AC_MSG_CHECKING([FIONBIO vs. O_NONBLOCK for nonblocking I/O]) + case $system in + OSF*) + AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?]) + AC_MSG_RESULT([FIONBIO]) + ;; + *) + AC_MSG_RESULT([O_NONBLOCK]) + ;; + esac +]) + +#-------------------------------------------------------------------- +# TEA_TIME_HANDLER +# +# Checks how the system deals with time.h, what time structures +# are used on the system, and what fields the structures have. +# +# Arguments: +# none +# +# Results: +# +# Defines some of the following vars: +# USE_DELTA_FOR_TZ +# HAVE_TM_GMTOFF +# HAVE_TM_TZADJ +# HAVE_TIMEZONE_VAR +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_TIME_HANDLER], [ + AC_CHECK_HEADERS(sys/time.h) + AC_HEADER_TIME + AC_STRUCT_TIMEZONE + + AC_CHECK_FUNCS(gmtime_r localtime_r) + + AC_CACHE_CHECK([tm_tzadj in struct tm], tcl_cv_member_tm_tzadj, [ + AC_TRY_COMPILE([#include ], [struct tm tm; tm.tm_tzadj;], + tcl_cv_member_tm_tzadj=yes, tcl_cv_member_tm_tzadj=no)]) + if test $tcl_cv_member_tm_tzadj = yes ; then + AC_DEFINE(HAVE_TM_TZADJ, 1, [Should we use the tm_tzadj field of struct tm?]) + fi + + AC_CACHE_CHECK([tm_gmtoff in struct tm], tcl_cv_member_tm_gmtoff, [ + AC_TRY_COMPILE([#include ], [struct tm tm; tm.tm_gmtoff;], + tcl_cv_member_tm_gmtoff=yes, tcl_cv_member_tm_gmtoff=no)]) + if test $tcl_cv_member_tm_gmtoff = yes ; then + AC_DEFINE(HAVE_TM_GMTOFF, 1, [Should we use the tm_gmtoff field of struct tm?]) + fi + + # + # Its important to include time.h in this check, as some systems + # (like convex) have timezone functions, etc. + # + AC_CACHE_CHECK([long timezone variable], tcl_cv_timezone_long, [ + AC_TRY_COMPILE([#include ], + [extern long timezone; + timezone += 1; + exit (0);], + tcl_cv_timezone_long=yes, tcl_cv_timezone_long=no)]) + if test $tcl_cv_timezone_long = yes ; then + AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) + else + # + # On some systems (eg IRIX 6.2), timezone is a time_t and not a long. + # + AC_CACHE_CHECK([time_t timezone variable], tcl_cv_timezone_time, [ + AC_TRY_COMPILE([#include ], + [extern time_t timezone; + timezone += 1; + exit (0);], + tcl_cv_timezone_time=yes, tcl_cv_timezone_time=no)]) + if test $tcl_cv_timezone_time = yes ; then + AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) + fi + fi +]) + +#-------------------------------------------------------------------- +# TEA_BUGGY_STRTOD +# +# Under Solaris 2.4, strtod returns the wrong value for the +# terminating character under some conditions. Check for this +# and if the problem exists use a substitute procedure +# "fixstrtod" (provided by Tcl) that corrects the error. +# Also, on Compaq's Tru64 Unix 5.0, +# strtod(" ") returns 0.0 instead of a failure to convert. +# +# Arguments: +# none +# +# Results: +# +# Might defines some of the following vars: +# strtod (=fixstrtod) +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_BUGGY_STRTOD], [ + AC_CHECK_FUNC(strtod, tcl_strtod=1, tcl_strtod=0) + if test "$tcl_strtod" = 1; then + AC_CACHE_CHECK([for Solaris2.4/Tru64 strtod bugs], tcl_cv_strtod_buggy,[ + AC_TRY_RUN([ + extern double strtod(); + int main() { + char *infString="Inf", *nanString="NaN", *spaceString=" "; + char *term; + double value; + value = strtod(infString, &term); + if ((term != infString) && (term[-1] == 0)) { + exit(1); + } + value = strtod(nanString, &term); + if ((term != nanString) && (term[-1] == 0)) { + exit(1); + } + value = strtod(spaceString, &term); + if (term == (spaceString+1)) { + exit(1); + } + exit(0); + }], tcl_cv_strtod_buggy=ok, tcl_cv_strtod_buggy=buggy, + tcl_cv_strtod_buggy=buggy)]) + if test "$tcl_cv_strtod_buggy" = buggy; then + AC_LIBOBJ([fixstrtod]) + USE_COMPAT=1 + AC_DEFINE(strtod, fixstrtod, [Do we want to use the strtod() in compat?]) + fi + fi +]) + +#-------------------------------------------------------------------- +# TEA_TCL_EARLY_FLAGS +# +# Check for what flags are needed to be passed so the correct OS +# features are available. +# +# Arguments: +# None +# +# Results: +# +# Might define the following vars: +# _ISOC99_SOURCE +# _LARGEFILE64_SOURCE +# _LARGEFILE_SOURCE64 +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_TCL_EARLY_FLAG],[ + AC_CACHE_VAL([tcl_cv_flag_]translit($1,[A-Z],[a-z]), + AC_TRY_COMPILE([$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no, + AC_TRY_COMPILE([[#define ]$1[ 1 +]$2], $3, + [tcl_cv_flag_]translit($1,[A-Z],[a-z])=yes, + [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no))) + if test ["x${tcl_cv_flag_]translit($1,[A-Z],[a-z])[}" = "xyes"] ; then + AC_DEFINE($1, 1, [Add the ]$1[ flag when building]) + tcl_flags="$tcl_flags $1" + fi +]) + +AC_DEFUN([TEA_TCL_EARLY_FLAGS],[ + AC_MSG_CHECKING([for required early compiler flags]) + tcl_flags="" + TEA_TCL_EARLY_FLAG(_ISOC99_SOURCE,[#include ], + [char *p = (char *)strtoll; char *q = (char *)strtoull;]) + TEA_TCL_EARLY_FLAG(_LARGEFILE64_SOURCE,[#include ], + [struct stat64 buf; int i = stat64("/", &buf);]) + TEA_TCL_EARLY_FLAG(_LARGEFILE_SOURCE64,[#include ], + [char *p = (char *)open64;]) + if test "x${tcl_flags}" = "x" ; then + AC_MSG_RESULT([none]) + else + AC_MSG_RESULT([${tcl_flags}]) + fi +]) + +#-------------------------------------------------------------------- +# TEA_TCL_64BIT_FLAGS +# +# Check for what is defined in the way of 64-bit features. +# +# Arguments: +# None +# +# Results: +# +# Might define the following vars: +# TCL_WIDE_INT_IS_LONG +# TCL_WIDE_INT_TYPE +# HAVE_STRUCT_DIRENT64 +# HAVE_STRUCT_STAT64 +# HAVE_TYPE_OFF64_T +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_TCL_64BIT_FLAGS], [ + AC_MSG_CHECKING([for 64-bit integer type]) + AC_CACHE_VAL(tcl_cv_type_64bit,[ + tcl_cv_type_64bit=none + # See if the compiler knows natively about __int64 + AC_TRY_COMPILE(,[__int64 value = (__int64) 0;], + tcl_type_64bit=__int64, tcl_type_64bit="long long") + # See if we should use long anyway Note that we substitute in the + # type that is our current guess for a 64-bit type inside this check + # program, so it should be modified only carefully... + AC_TRY_COMPILE(,[switch (0) { + case 1: case (sizeof(]${tcl_type_64bit}[)==sizeof(long)): ; + }],tcl_cv_type_64bit=${tcl_type_64bit})]) + if test "${tcl_cv_type_64bit}" = none ; then + AC_DEFINE(TCL_WIDE_INT_IS_LONG, 1, [Are wide integers to be implemented with C 'long's?]) + AC_MSG_RESULT([using long]) + elif test "${tcl_cv_type_64bit}" = "__int64" \ + -a "${TEA_PLATFORM}" = "windows" ; then + # TEA specific: We actually want to use the default tcl.h checks in + # this case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER* + AC_MSG_RESULT([using Tcl header defaults]) + else + AC_DEFINE_UNQUOTED(TCL_WIDE_INT_TYPE,${tcl_cv_type_64bit}, + [What type should be used to define wide integers?]) + AC_MSG_RESULT([${tcl_cv_type_64bit}]) + + # Now check for auxiliary declarations + AC_CACHE_CHECK([for struct dirent64], tcl_cv_struct_dirent64,[ + AC_TRY_COMPILE([#include +#include ],[struct dirent64 p;], + tcl_cv_struct_dirent64=yes,tcl_cv_struct_dirent64=no)]) + if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then + AC_DEFINE(HAVE_STRUCT_DIRENT64, 1, [Is 'struct dirent64' in ?]) + fi + + AC_CACHE_CHECK([for struct stat64], tcl_cv_struct_stat64,[ + AC_TRY_COMPILE([#include ],[struct stat64 p; +], + tcl_cv_struct_stat64=yes,tcl_cv_struct_stat64=no)]) + if test "x${tcl_cv_struct_stat64}" = "xyes" ; then + AC_DEFINE(HAVE_STRUCT_STAT64, 1, [Is 'struct stat64' in ?]) + fi + + AC_CHECK_FUNCS(open64 lseek64) + AC_MSG_CHECKING([for off64_t]) + AC_CACHE_VAL(tcl_cv_type_off64_t,[ + AC_TRY_COMPILE([#include ],[off64_t offset; +], + tcl_cv_type_off64_t=yes,tcl_cv_type_off64_t=no)]) + dnl Define HAVE_TYPE_OFF64_T only when the off64_t type and the + dnl functions lseek64 and open64 are defined. + if test "x${tcl_cv_type_off64_t}" = "xyes" && \ + test "x${ac_cv_func_lseek64}" = "xyes" && \ + test "x${ac_cv_func_open64}" = "xyes" ; then + AC_DEFINE(HAVE_TYPE_OFF64_T, 1, [Is off64_t in ?]) + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + fi +]) + +## +## Here ends the standard Tcl configuration bits and starts the +## TEA specific functions +## + +#------------------------------------------------------------------------ +# TEA_INIT -- +# +# Init various Tcl Extension Architecture (TEA) variables. +# This should be the first called TEA_* macro. +# +# Arguments: +# none +# +# Results: +# +# Defines and substs the following vars: +# CYGPATH +# EXEEXT +# Defines only: +# TEA_VERSION +# TEA_INITED +# TEA_PLATFORM (windows or unix) +# +# "cygpath" is used on windows to generate native path names for include +# files. These variables should only be used with the compiler and linker +# since they generate native path names. +# +# EXEEXT +# Select the executable extension based on the host type. This +# is a lightweight replacement for AC_EXEEXT that doesn't require +# a compiler. +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_INIT], [ + TEA_VERSION="3.13" + + AC_MSG_CHECKING([TEA configuration]) + if test x"${PACKAGE_NAME}" = x ; then + AC_MSG_ERROR([ +The PACKAGE_NAME variable must be defined by your TEA configure.ac]) + fi + AC_MSG_RESULT([ok (TEA ${TEA_VERSION})]) + + # If the user did not set CFLAGS, set it now to keep macros + # like AC_PROG_CC and AC_TRY_COMPILE from adding "-g -O2". + if test "${CFLAGS+set}" != "set" ; then + CFLAGS="" + fi + + case "`uname -s`" in + *win32*|*WIN32*|*MINGW32_*|*MINGW64_*) + AC_CHECK_PROG(CYGPATH, cygpath, cygpath -m, echo) + EXEEXT=".exe" + TEA_PLATFORM="windows" + ;; + *CYGWIN_*) + EXEEXT=".exe" + # CYGPATH and TEA_PLATFORM are determined later in LOAD_TCLCONFIG + ;; + *) + CYGPATH=echo + # Maybe we are cross-compiling.... + case ${host_alias} in + *mingw32*) + EXEEXT=".exe" + TEA_PLATFORM="windows" + ;; + *) + EXEEXT="" + TEA_PLATFORM="unix" + ;; + esac + ;; + esac + + # Check if exec_prefix is set. If not use fall back to prefix. + # Note when adjusted, so that TEA_PREFIX can correct for this. + # This is needed for recursive configures, since autoconf propagates + # $prefix, but not $exec_prefix (doh!). + if test x$exec_prefix = xNONE ; then + exec_prefix_default=yes + exec_prefix=$prefix + fi + + AC_MSG_NOTICE([configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}]) + + AC_SUBST(EXEEXT) + AC_SUBST(CYGPATH) + + # This package name must be replaced statically for AC_SUBST to work + AC_SUBST(PKG_LIB_FILE) + # Substitute STUB_LIB_FILE in case package creates a stub library too. + AC_SUBST(PKG_STUB_LIB_FILE) + + # We AC_SUBST these here to ensure they are subst'ed, + # in case the user doesn't call TEA_ADD_... + AC_SUBST(PKG_STUB_SOURCES) + AC_SUBST(PKG_STUB_OBJECTS) + AC_SUBST(PKG_TCL_SOURCES) + AC_SUBST(PKG_HEADERS) + AC_SUBST(PKG_INCLUDES) + AC_SUBST(PKG_LIBS) + AC_SUBST(PKG_CFLAGS) + + # Configure the installer. + TEA_INSTALLER +]) + +#------------------------------------------------------------------------ +# TEA_ADD_SOURCES -- +# +# Specify one or more source files. Users should check for +# the right platform before adding to their list. +# It is not important to specify the directory, as long as it is +# in the generic, win or unix subdirectory of $(srcdir). +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_SOURCES +# PKG_OBJECTS +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_SOURCES], [ + vars="$@" + for i in $vars; do + case $i in + [\$]*) + # allow $-var names + PKG_SOURCES="$PKG_SOURCES $i" + PKG_OBJECTS="$PKG_OBJECTS $i" + ;; + *) + # check for existence - allows for generic/win/unix VPATH + # To add more dirs here (like 'src'), you have to update VPATH + # in Makefile.in as well + if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ + -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ + -a ! -f "${srcdir}/macosx/$i" \ + ; then + AC_MSG_ERROR([could not find source file '$i']) + fi + PKG_SOURCES="$PKG_SOURCES $i" + # this assumes it is in a VPATH dir + i=`basename $i` + # handle user calling this before or after TEA_SETUP_COMPILER + if test x"${OBJEXT}" != x ; then + j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" + else + j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" + fi + PKG_OBJECTS="$PKG_OBJECTS $j" + ;; + esac + done + AC_SUBST(PKG_SOURCES) + AC_SUBST(PKG_OBJECTS) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_STUB_SOURCES -- +# +# Specify one or more source files. Users should check for +# the right platform before adding to their list. +# It is not important to specify the directory, as long as it is +# in the generic, win or unix subdirectory of $(srcdir). +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_STUB_SOURCES +# PKG_STUB_OBJECTS +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_STUB_SOURCES], [ + vars="$@" + for i in $vars; do + # check for existence - allows for generic/win/unix VPATH + if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ + -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ + -a ! -f "${srcdir}/macosx/$i" \ + ; then + AC_MSG_ERROR([could not find stub source file '$i']) + fi + PKG_STUB_SOURCES="$PKG_STUB_SOURCES $i" + # this assumes it is in a VPATH dir + i=`basename $i` + # handle user calling this before or after TEA_SETUP_COMPILER + if test x"${OBJEXT}" != x ; then + j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" + else + j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" + fi + PKG_STUB_OBJECTS="$PKG_STUB_OBJECTS $j" + done + AC_SUBST(PKG_STUB_SOURCES) + AC_SUBST(PKG_STUB_OBJECTS) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_TCL_SOURCES -- +# +# Specify one or more Tcl source files. These should be platform +# independent runtime files. +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_TCL_SOURCES +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_TCL_SOURCES], [ + vars="$@" + for i in $vars; do + # check for existence, be strict because it is installed + if test ! -f "${srcdir}/$i" ; then + AC_MSG_ERROR([could not find tcl source file '${srcdir}/$i']) + fi + PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i" + done + AC_SUBST(PKG_TCL_SOURCES) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_HEADERS -- +# +# Specify one or more source headers. Users should check for +# the right platform before adding to their list. +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_HEADERS +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_HEADERS], [ + vars="$@" + for i in $vars; do + # check for existence, be strict because it is installed + if test ! -f "${srcdir}/$i" ; then + AC_MSG_ERROR([could not find header file '${srcdir}/$i']) + fi + PKG_HEADERS="$PKG_HEADERS $i" + done + AC_SUBST(PKG_HEADERS) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_INCLUDES -- +# +# Specify one or more include dirs. Users should check for +# the right platform before adding to their list. +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_INCLUDES +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_INCLUDES], [ + vars="$@" + for i in $vars; do + PKG_INCLUDES="$PKG_INCLUDES $i" + done + AC_SUBST(PKG_INCLUDES) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_LIBS -- +# +# Specify one or more libraries. Users should check for +# the right platform before adding to their list. For Windows, +# libraries provided in "foo.lib" format will be converted to +# "-lfoo" when using GCC (mingw). +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_LIBS +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_LIBS], [ + vars="$@" + for i in $vars; do + if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then + # Convert foo.lib to -lfoo for GCC. No-op if not *.lib + i=`echo "$i" | sed -e 's/^\([[^-]].*\)\.lib[$]/-l\1/i'` + fi + PKG_LIBS="$PKG_LIBS $i" + done + AC_SUBST(PKG_LIBS) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_CFLAGS -- +# +# Specify one or more CFLAGS. Users should check for +# the right platform before adding to their list. +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_CFLAGS +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_CFLAGS], [ + PKG_CFLAGS="$PKG_CFLAGS $@" + AC_SUBST(PKG_CFLAGS) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_CLEANFILES -- +# +# Specify one or more CLEANFILES. +# +# Arguments: +# one or more file names to clean target +# +# Results: +# +# Appends to CLEANFILES, already defined for subst in LOAD_TCLCONFIG +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_CLEANFILES], [ + CLEANFILES="$CLEANFILES $@" +]) + +#------------------------------------------------------------------------ +# TEA_PREFIX -- +# +# Handle the --prefix=... option by defaulting to what Tcl gave +# +# Arguments: +# none +# +# Results: +# +# If --prefix or --exec-prefix was not specified, $prefix and +# $exec_prefix will be set to the values given to Tcl when it was +# configured. +#------------------------------------------------------------------------ +AC_DEFUN([TEA_PREFIX], [ + if test "${prefix}" = "NONE"; then + prefix_default=yes + if test x"${TCL_PREFIX}" != x; then + AC_MSG_NOTICE([--prefix defaulting to TCL_PREFIX ${TCL_PREFIX}]) + prefix=${TCL_PREFIX} + else + AC_MSG_NOTICE([--prefix defaulting to /usr/local]) + prefix=/usr/local + fi + fi + if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" \ + -o x"${exec_prefix_default}" = x"yes" ; then + if test x"${TCL_EXEC_PREFIX}" != x; then + AC_MSG_NOTICE([--exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}]) + exec_prefix=${TCL_EXEC_PREFIX} + else + AC_MSG_NOTICE([--exec-prefix defaulting to ${prefix}]) + exec_prefix=$prefix + fi + fi +]) + +#------------------------------------------------------------------------ +# TEA_SETUP_COMPILER_CC -- +# +# Do compiler checks the way we want. This is just a replacement +# for AC_PROG_CC in TEA configure.ac files to make them cleaner. +# +# Arguments: +# none +# +# Results: +# +# Sets up CC var and other standard bits we need to make executables. +#------------------------------------------------------------------------ +AC_DEFUN([TEA_SETUP_COMPILER_CC], [ + # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE) + # in this macro, they need to go into TEA_SETUP_COMPILER instead. + + AC_PROG_CC + AC_PROG_CPP + + #-------------------------------------------------------------------- + # Checks to see if the make program sets the $MAKE variable. + #-------------------------------------------------------------------- + + AC_PROG_MAKE_SET + + #-------------------------------------------------------------------- + # Find ranlib + #-------------------------------------------------------------------- + + AC_CHECK_TOOL(RANLIB, ranlib) + + #-------------------------------------------------------------------- + # Determines the correct binary file extension (.o, .obj, .exe etc.) + #-------------------------------------------------------------------- + + AC_OBJEXT + AC_EXEEXT +]) + +#------------------------------------------------------------------------ +# TEA_SETUP_COMPILER -- +# +# Do compiler checks that use the compiler. This must go after +# TEA_SETUP_COMPILER_CC, which does the actual compiler check. +# +# Arguments: +# none +# +# Results: +# +# Sets up CC var and other standard bits we need to make executables. +#------------------------------------------------------------------------ +AC_DEFUN([TEA_SETUP_COMPILER], [ + # Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here. + AC_REQUIRE([TEA_SETUP_COMPILER_CC]) + + #------------------------------------------------------------------------ + # If we're using GCC, see if the compiler understands -pipe. If so, use it. + # It makes compiling go faster. (This is only a performance feature.) + #------------------------------------------------------------------------ + + if test -z "$no_pipe" -a -n "$GCC"; then + AC_CACHE_CHECK([if the compiler understands -pipe], + tcl_cv_cc_pipe, [ + hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" + AC_TRY_COMPILE(,, tcl_cv_cc_pipe=yes, tcl_cv_cc_pipe=no) + CFLAGS=$hold_cflags]) + if test $tcl_cv_cc_pipe = yes; then + CFLAGS="$CFLAGS -pipe" + fi + fi + + #-------------------------------------------------------------------- + # Common compiler flag setup + #-------------------------------------------------------------------- + + AC_C_BIGENDIAN +]) + +#------------------------------------------------------------------------ +# TEA_MAKE_LIB -- +# +# Generate a line that can be used to build a shared/unshared library +# in a platform independent manner. +# +# Arguments: +# none +# +# Requires: +# +# Results: +# +# Defines the following vars: +# CFLAGS - Done late here to note disturb other AC macros +# MAKE_LIB - Command to execute to build the Tcl library; +# differs depending on whether or not Tcl is being +# compiled as a shared library. +# MAKE_SHARED_LIB Makefile rule for building a shared library +# MAKE_STATIC_LIB Makefile rule for building a static library +# MAKE_STUB_LIB Makefile rule for building a stub library +# VC_MANIFEST_EMBED_DLL Makefile rule for embedded VC manifest in DLL +# VC_MANIFEST_EMBED_EXE Makefile rule for embedded VC manifest in EXE +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_MAKE_LIB], [ + if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then + MAKE_STATIC_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_OBJECTS)" + MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LD_LIBS} \${LDFLAGS_DEFAULT} -out:\[$]@ \$(PKG_OBJECTS)" + AC_EGREP_CPP([manifest needed], [ +#if defined(_MSC_VER) && _MSC_VER >= 1400 +print("manifest needed") +#endif + ], [ + # Could do a CHECK_PROG for mt, but should always be with MSVC8+ + VC_MANIFEST_EMBED_DLL="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest -outputresource:\[$]@\;2 ; fi" + VC_MANIFEST_EMBED_EXE="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest -outputresource:\[$]@\;1 ; fi" + MAKE_SHARED_LIB="${MAKE_SHARED_LIB} ; ${VC_MANIFEST_EMBED_DLL}" + TEA_ADD_CLEANFILES([*.manifest]) + ]) + MAKE_STUB_LIB="\${STLIB_LD} -nodefaultlib -out:\[$]@ \$(PKG_STUB_OBJECTS)" + else + MAKE_STATIC_LIB="\${STLIB_LD} \[$]@ \$(PKG_OBJECTS)" + MAKE_SHARED_LIB="\${SHLIB_LD} -o \[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" + MAKE_STUB_LIB="\${STLIB_LD} \[$]@ \$(PKG_STUB_OBJECTS)" + fi + + if test "${SHARED_BUILD}" = "1" ; then + MAKE_LIB="${MAKE_SHARED_LIB} " + else + MAKE_LIB="${MAKE_STATIC_LIB} " + fi + + #-------------------------------------------------------------------- + # Shared libraries and static libraries have different names. + # Use the double eval to make sure any variables in the suffix is + # substituted. (@@@ Might not be necessary anymore) + #-------------------------------------------------------------------- + + if test "${TEA_PLATFORM}" = "windows" ; then + if test "${SHARED_BUILD}" = "1" ; then + # We force the unresolved linking of symbols that are really in + # the private libraries of Tcl and Tk. + if test x"${TK_BIN_DIR}" != x ; then + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\"" + fi + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\"" + if test "$GCC" = "yes"; then + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -static-libgcc" + fi + eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" + else + eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" + if test "$GCC" = "yes"; then + PKG_LIB_FILE=lib${PKG_LIB_FILE} + fi + fi + # Some packages build their own stubs libraries + eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" + if test "$GCC" = "yes"; then + PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE} + fi + # These aren't needed on Windows (either MSVC or gcc) + RANLIB=: + RANLIB_STUB=: + else + RANLIB_STUB="${RANLIB}" + if test "${SHARED_BUILD}" = "1" ; then + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}" + if test x"${TK_BIN_DIR}" != x ; then + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" + fi + eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" + RANLIB=: + else + eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" + fi + # Some packages build their own stubs libraries + eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" + fi + + # These are escaped so that only CFLAGS is picked up at configure time. + # The other values will be substituted at make time. + CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}" + if test "${SHARED_BUILD}" = "1" ; then + CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}" + fi + + AC_SUBST(MAKE_LIB) + AC_SUBST(MAKE_SHARED_LIB) + AC_SUBST(MAKE_STATIC_LIB) + AC_SUBST(MAKE_STUB_LIB) + AC_SUBST(RANLIB_STUB) + AC_SUBST(VC_MANIFEST_EMBED_DLL) + AC_SUBST(VC_MANIFEST_EMBED_EXE) +]) + +#------------------------------------------------------------------------ +# TEA_LIB_SPEC -- +# +# Compute the name of an existing object library located in libdir +# from the given base name and produce the appropriate linker flags. +# +# Arguments: +# basename The base name of the library without version +# numbers, extensions, or "lib" prefixes. +# extra_dir Extra directory in which to search for the +# library. This location is used first, then +# $prefix/$exec-prefix, then some defaults. +# +# Requires: +# TEA_INIT and TEA_PREFIX must be called first. +# +# Results: +# +# Defines the following vars: +# ${basename}_LIB_NAME The computed library name. +# ${basename}_LIB_SPEC The computed linker flags. +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_LIB_SPEC], [ + AC_MSG_CHECKING([for $1 library]) + + # Look in exec-prefix for the library (defined by TEA_PREFIX). + + tea_lib_name_dir="${exec_prefix}/lib" + + # Or in a user-specified location. + + if test x"$2" != x ; then + tea_extra_lib_dir=$2 + else + tea_extra_lib_dir=NONE + fi + + for i in \ + `ls -dr ${tea_extra_lib_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ + `ls -dr ${tea_extra_lib_dir}/lib$1[[0-9]]* 2>/dev/null ` \ + `ls -dr ${tea_lib_name_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ + `ls -dr ${tea_lib_name_dir}/lib$1[[0-9]]* 2>/dev/null ` \ + `ls -dr /usr/lib/$1[[0-9]]*.lib 2>/dev/null ` \ + `ls -dr /usr/lib/lib$1[[0-9]]* 2>/dev/null ` \ + `ls -dr /usr/lib64/$1[[0-9]]*.lib 2>/dev/null ` \ + `ls -dr /usr/lib64/lib$1[[0-9]]* 2>/dev/null ` \ + `ls -dr /usr/local/lib/$1[[0-9]]*.lib 2>/dev/null ` \ + `ls -dr /usr/local/lib/lib$1[[0-9]]* 2>/dev/null ` ; do + if test -f "$i" ; then + tea_lib_name_dir=`dirname $i` + $1_LIB_NAME=`basename $i` + $1_LIB_PATH_NAME=$i + break + fi + done + + if test "${TEA_PLATFORM}" = "windows"; then + $1_LIB_SPEC=\"`${CYGPATH} ${$1_LIB_PATH_NAME} 2>/dev/null`\" + else + # Strip off the leading "lib" and trailing ".a" or ".so" + + tea_lib_name_lib=`echo ${$1_LIB_NAME}|sed -e 's/^lib//' -e 's/\.[[^.]]*$//' -e 's/\.so.*//'` + $1_LIB_SPEC="-L${tea_lib_name_dir} -l${tea_lib_name_lib}" + fi + + if test "x${$1_LIB_NAME}" = x ; then + AC_MSG_ERROR([not found]) + else + AC_MSG_RESULT([${$1_LIB_SPEC}]) + fi +]) + +#------------------------------------------------------------------------ +# TEA_PRIVATE_TCL_HEADERS -- +# +# Locate the private Tcl include files +# +# Arguments: +# +# Requires: +# TCL_SRC_DIR Assumes that TEA_LOAD_TCLCONFIG has +# already been called. +# +# Results: +# +# Substitutes the following vars: +# TCL_TOP_DIR_NATIVE +# TCL_INCLUDES +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PRIVATE_TCL_HEADERS], [ + # Allow for --with-tclinclude to take effect and define ${ac_cv_c_tclh} + AC_REQUIRE([TEA_PUBLIC_TCL_HEADERS]) + AC_MSG_CHECKING([for Tcl private include files]) + + TCL_SRC_DIR_NATIVE=`${CYGPATH} ${TCL_SRC_DIR}` + TCL_TOP_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}\" + + # Check to see if tclPort.h isn't already with the public headers + # Don't look for tclInt.h because that resides with tcl.h in the core + # sources, but the Port headers are in a different directory + if test "${TEA_PLATFORM}" = "windows" -a \ + -f "${ac_cv_c_tclh}/tclWinPort.h"; then + result="private headers found with public headers" + elif test "${TEA_PLATFORM}" = "unix" -a \ + -f "${ac_cv_c_tclh}/tclUnixPort.h"; then + result="private headers found with public headers" + else + TCL_GENERIC_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/generic\" + if test "${TEA_PLATFORM}" = "windows"; then + TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/win\" + else + TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/unix\" + fi + # Overwrite the previous TCL_INCLUDES as this should capture both + # public and private headers in the same set. + # We want to ensure these are substituted so as not to require + # any *_NATIVE vars be defined in the Makefile + TCL_INCLUDES="-I${TCL_GENERIC_DIR_NATIVE} -I${TCL_PLATFORM_DIR_NATIVE}" + if test "`uname -s`" = "Darwin"; then + # If Tcl was built as a framework, attempt to use + # the framework's Headers and PrivateHeaders directories + case ${TCL_DEFS} in + *TCL_FRAMEWORK*) + if test -d "${TCL_BIN_DIR}/Headers" -a \ + -d "${TCL_BIN_DIR}/PrivateHeaders"; then + TCL_INCLUDES="-I\"${TCL_BIN_DIR}/Headers\" -I\"${TCL_BIN_DIR}/PrivateHeaders\" ${TCL_INCLUDES}" + else + TCL_INCLUDES="${TCL_INCLUDES} ${TCL_INCLUDE_SPEC} `echo "${TCL_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" + fi + ;; + esac + result="Using ${TCL_INCLUDES}" + else + if test ! -f "${TCL_SRC_DIR}/generic/tclInt.h" ; then + AC_MSG_ERROR([Cannot find private header tclInt.h in ${TCL_SRC_DIR}]) + fi + result="Using srcdir found in tclConfig.sh: ${TCL_SRC_DIR}" + fi + fi + + AC_SUBST(TCL_TOP_DIR_NATIVE) + + AC_SUBST(TCL_INCLUDES) + AC_MSG_RESULT([${result}]) +]) + +#------------------------------------------------------------------------ +# TEA_PUBLIC_TCL_HEADERS -- +# +# Locate the installed public Tcl header files +# +# Arguments: +# None. +# +# Requires: +# CYGPATH must be set +# +# Results: +# +# Adds a --with-tclinclude switch to configure. +# Result is cached. +# +# Substitutes the following vars: +# TCL_INCLUDES +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PUBLIC_TCL_HEADERS], [ + AC_MSG_CHECKING([for Tcl public headers]) + + AC_ARG_WITH(tclinclude, [ --with-tclinclude directory containing the public Tcl header files], with_tclinclude=${withval}) + + AC_CACHE_VAL(ac_cv_c_tclh, [ + # Use the value from --with-tclinclude, if it was given + + if test x"${with_tclinclude}" != x ; then + if test -f "${with_tclinclude}/tcl.h" ; then + ac_cv_c_tclh=${with_tclinclude} + else + AC_MSG_ERROR([${with_tclinclude} directory does not contain tcl.h]) + fi + else + list="" + if test "`uname -s`" = "Darwin"; then + # If Tcl was built as a framework, attempt to use + # the framework's Headers directory + case ${TCL_DEFS} in + *TCL_FRAMEWORK*) + list="`ls -d ${TCL_BIN_DIR}/Headers 2>/dev/null`" + ;; + esac + fi + + # Look in the source dir only if Tcl is not installed, + # and in that situation, look there before installed locations. + if test -f "${TCL_BIN_DIR}/Makefile" ; then + list="$list `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`" + fi + + # Check order: pkg --prefix location, Tcl's --prefix location, + # relative to directory of tclConfig.sh. + + eval "temp_includedir=${includedir}" + list="$list \ + `ls -d ${temp_includedir} 2>/dev/null` \ + `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ + `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" + if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then + list="$list /usr/local/include /usr/include" + if test x"${TCL_INCLUDE_SPEC}" != x ; then + d=`echo "${TCL_INCLUDE_SPEC}" | sed -e 's/^-I//'` + list="$list `ls -d ${d} 2>/dev/null`" + fi + fi + for i in $list ; do + if test -f "$i/tcl.h" ; then + ac_cv_c_tclh=$i + break + fi + done + fi + ]) + + # Print a message based on how we determined the include path + + if test x"${ac_cv_c_tclh}" = x ; then + AC_MSG_ERROR([tcl.h not found. Please specify its location with --with-tclinclude]) + else + AC_MSG_RESULT([${ac_cv_c_tclh}]) + fi + + # Convert to a native path and substitute into the output files. + + INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}` + + TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" + + AC_SUBST(TCL_INCLUDES) +]) + +#------------------------------------------------------------------------ +# TEA_PRIVATE_TK_HEADERS -- +# +# Locate the private Tk include files +# +# Arguments: +# +# Requires: +# TK_SRC_DIR Assumes that TEA_LOAD_TKCONFIG has +# already been called. +# +# Results: +# +# Substitutes the following vars: +# TK_INCLUDES +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PRIVATE_TK_HEADERS], [ + # Allow for --with-tkinclude to take effect and define ${ac_cv_c_tkh} + AC_REQUIRE([TEA_PUBLIC_TK_HEADERS]) + AC_MSG_CHECKING([for Tk private include files]) + + TK_SRC_DIR_NATIVE=`${CYGPATH} ${TK_SRC_DIR}` + TK_TOP_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}\" + + # Check to see if tkPort.h isn't already with the public headers + # Don't look for tkInt.h because that resides with tk.h in the core + # sources, but the Port headers are in a different directory + if test "${TEA_PLATFORM}" = "windows" -a \ + -f "${ac_cv_c_tkh}/tkWinPort.h"; then + result="private headers found with public headers" + elif test "${TEA_PLATFORM}" = "unix" -a \ + -f "${ac_cv_c_tkh}/tkUnixPort.h"; then + result="private headers found with public headers" + else + TK_GENERIC_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/generic\" + TK_XLIB_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/xlib\" + if test "${TEA_PLATFORM}" = "windows"; then + TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/win\" + else + TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/unix\" + fi + # Overwrite the previous TK_INCLUDES as this should capture both + # public and private headers in the same set. + # We want to ensure these are substituted so as not to require + # any *_NATIVE vars be defined in the Makefile + TK_INCLUDES="-I${TK_GENERIC_DIR_NATIVE} -I${TK_PLATFORM_DIR_NATIVE}" + # Detect and add ttk subdir + if test -d "${TK_SRC_DIR}/generic/ttk"; then + TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/generic/ttk\"" + fi + if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then + TK_INCLUDES="${TK_INCLUDES} -I\"${TK_XLIB_DIR_NATIVE}\"" + fi + if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then + TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/macosx\"" + fi + if test "`uname -s`" = "Darwin"; then + # If Tk was built as a framework, attempt to use + # the framework's Headers and PrivateHeaders directories + case ${TK_DEFS} in + *TK_FRAMEWORK*) + if test -d "${TK_BIN_DIR}/Headers" -a \ + -d "${TK_BIN_DIR}/PrivateHeaders"; then + TK_INCLUDES="-I\"${TK_BIN_DIR}/Headers\" -I\"${TK_BIN_DIR}/PrivateHeaders\" ${TK_INCLUDES}" + else + TK_INCLUDES="${TK_INCLUDES} ${TK_INCLUDE_SPEC} `echo "${TK_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" + fi + ;; + esac + result="Using ${TK_INCLUDES}" + else + if test ! -f "${TK_SRC_DIR}/generic/tkInt.h" ; then + AC_MSG_ERROR([Cannot find private header tkInt.h in ${TK_SRC_DIR}]) + fi + result="Using srcdir found in tkConfig.sh: ${TK_SRC_DIR}" + fi + fi + + AC_SUBST(TK_TOP_DIR_NATIVE) + AC_SUBST(TK_XLIB_DIR_NATIVE) + + AC_SUBST(TK_INCLUDES) + AC_MSG_RESULT([${result}]) +]) + +#------------------------------------------------------------------------ +# TEA_PUBLIC_TK_HEADERS -- +# +# Locate the installed public Tk header files +# +# Arguments: +# None. +# +# Requires: +# CYGPATH must be set +# +# Results: +# +# Adds a --with-tkinclude switch to configure. +# Result is cached. +# +# Substitutes the following vars: +# TK_INCLUDES +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PUBLIC_TK_HEADERS], [ + AC_MSG_CHECKING([for Tk public headers]) + + AC_ARG_WITH(tkinclude, [ --with-tkinclude directory containing the public Tk header files], with_tkinclude=${withval}) + + AC_CACHE_VAL(ac_cv_c_tkh, [ + # Use the value from --with-tkinclude, if it was given + + if test x"${with_tkinclude}" != x ; then + if test -f "${with_tkinclude}/tk.h" ; then + ac_cv_c_tkh=${with_tkinclude} + else + AC_MSG_ERROR([${with_tkinclude} directory does not contain tk.h]) + fi + else + list="" + if test "`uname -s`" = "Darwin"; then + # If Tk was built as a framework, attempt to use + # the framework's Headers directory. + case ${TK_DEFS} in + *TK_FRAMEWORK*) + list="`ls -d ${TK_BIN_DIR}/Headers 2>/dev/null`" + ;; + esac + fi + + # Look in the source dir only if Tk is not installed, + # and in that situation, look there before installed locations. + if test -f "${TK_BIN_DIR}/Makefile" ; then + list="$list `ls -d ${TK_SRC_DIR}/generic 2>/dev/null`" + fi + + # Check order: pkg --prefix location, Tk's --prefix location, + # relative to directory of tkConfig.sh, Tcl's --prefix location, + # relative to directory of tclConfig.sh. + + eval "temp_includedir=${includedir}" + list="$list \ + `ls -d ${temp_includedir} 2>/dev/null` \ + `ls -d ${TK_PREFIX}/include 2>/dev/null` \ + `ls -d ${TK_BIN_DIR}/../include 2>/dev/null` \ + `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ + `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" + if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then + list="$list /usr/local/include /usr/include" + if test x"${TK_INCLUDE_SPEC}" != x ; then + d=`echo "${TK_INCLUDE_SPEC}" | sed -e 's/^-I//'` + list="$list `ls -d ${d} 2>/dev/null`" + fi + fi + for i in $list ; do + if test -f "$i/tk.h" ; then + ac_cv_c_tkh=$i + break + fi + done + fi + ]) + + # Print a message based on how we determined the include path + + if test x"${ac_cv_c_tkh}" = x ; then + AC_MSG_ERROR([tk.h not found. Please specify its location with --with-tkinclude]) + else + AC_MSG_RESULT([${ac_cv_c_tkh}]) + fi + + # Convert to a native path and substitute into the output files. + + INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tkh}` + + TK_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" + + AC_SUBST(TK_INCLUDES) + + if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then + # On Windows and Aqua, we need the X compat headers + AC_MSG_CHECKING([for X11 header files]) + if test ! -r "${INCLUDE_DIR_NATIVE}/X11/Xlib.h"; then + INCLUDE_DIR_NATIVE="`${CYGPATH} ${TK_SRC_DIR}/xlib`" + TK_XINCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" + AC_SUBST(TK_XINCLUDES) + fi + AC_MSG_RESULT([${INCLUDE_DIR_NATIVE}]) + fi +]) + +#------------------------------------------------------------------------ +# TEA_PATH_CONFIG -- +# +# Locate the ${1}Config.sh file and perform a sanity check on +# the ${1} compile flags. These are used by packages like +# [incr Tk] that load *Config.sh files from more than Tcl and Tk. +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --with-$1=... +# +# Defines the following vars: +# $1_BIN_DIR Full path to the directory containing +# the $1Config.sh file +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PATH_CONFIG], [ + # + # Ok, lets find the $1 configuration + # First, look for one uninstalled. + # the alternative search directory is invoked by --with-$1 + # + + if test x"${no_$1}" = x ; then + # we reset no_$1 in case something fails here + no_$1=true + AC_ARG_WITH($1, [ --with-$1 directory containing $1 configuration ($1Config.sh)], with_$1config=${withval}) + AC_MSG_CHECKING([for $1 configuration]) + AC_CACHE_VAL(ac_cv_c_$1config,[ + + # First check to see if --with-$1 was specified. + if test x"${with_$1config}" != x ; then + case ${with_$1config} in + */$1Config.sh ) + if test -f ${with_$1config}; then + AC_MSG_WARN([--with-$1 argument should refer to directory containing $1Config.sh, not to $1Config.sh itself]) + with_$1config=`echo ${with_$1config} | sed 's!/$1Config\.sh$!!'` + fi;; + esac + if test -f "${with_$1config}/$1Config.sh" ; then + ac_cv_c_$1config=`(cd ${with_$1config}; pwd)` + else + AC_MSG_ERROR([${with_$1config} directory doesn't contain $1Config.sh]) + fi + fi + + # then check for a private $1 installation + if test x"${ac_cv_c_$1config}" = x ; then + for i in \ + ../$1 \ + `ls -dr ../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ + `ls -dr ../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ + `ls -dr ../$1*[[0-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ + ../../$1 \ + `ls -dr ../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ + `ls -dr ../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ + `ls -dr ../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ + ../../../$1 \ + `ls -dr ../../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ + `ls -dr ../../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ + `ls -dr ../../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ + ${srcdir}/../$1 \ + `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ + `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ + `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ + ; do + if test -f "$i/$1Config.sh" ; then + ac_cv_c_$1config=`(cd $i; pwd)` + break + fi + if test -f "$i/unix/$1Config.sh" ; then + ac_cv_c_$1config=`(cd $i/unix; pwd)` + break + fi + done + fi + + # check in a few common install locations + if test x"${ac_cv_c_$1config}" = x ; then + for i in `ls -d ${libdir} 2>/dev/null` \ + `ls -d ${exec_prefix}/lib 2>/dev/null` \ + `ls -d ${prefix}/lib 2>/dev/null` \ + `ls -d /usr/local/lib 2>/dev/null` \ + `ls -d /usr/contrib/lib 2>/dev/null` \ + `ls -d /usr/pkg/lib 2>/dev/null` \ + `ls -d /usr/lib 2>/dev/null` \ + `ls -d /usr/lib64 2>/dev/null` \ + ; do + if test -f "$i/$1Config.sh" ; then + ac_cv_c_$1config=`(cd $i; pwd)` + break + fi + done + fi + ]) + + if test x"${ac_cv_c_$1config}" = x ; then + $1_BIN_DIR="# no $1 configs found" + AC_MSG_WARN([Cannot find $1 configuration definitions]) + exit 0 + else + no_$1= + $1_BIN_DIR=${ac_cv_c_$1config} + AC_MSG_RESULT([found $$1_BIN_DIR/$1Config.sh]) + fi + fi +]) + +#------------------------------------------------------------------------ +# TEA_LOAD_CONFIG -- +# +# Load the $1Config.sh file +# +# Arguments: +# +# Requires the following vars to be set: +# $1_BIN_DIR +# +# Results: +# +# Substitutes the following vars: +# $1_SRC_DIR +# $1_LIB_FILE +# $1_LIB_SPEC +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_LOAD_CONFIG], [ + AC_MSG_CHECKING([for existence of ${$1_BIN_DIR}/$1Config.sh]) + + if test -f "${$1_BIN_DIR}/$1Config.sh" ; then + AC_MSG_RESULT([loading]) + . "${$1_BIN_DIR}/$1Config.sh" + else + AC_MSG_RESULT([file not found]) + fi + + # + # If the $1_BIN_DIR is the build directory (not the install directory), + # then set the common variable name to the value of the build variables. + # For example, the variable $1_LIB_SPEC will be set to the value + # of $1_BUILD_LIB_SPEC. An extension should make use of $1_LIB_SPEC + # instead of $1_BUILD_LIB_SPEC since it will work with both an + # installed and uninstalled version of Tcl. + # + + if test -f "${$1_BIN_DIR}/Makefile" ; then + AC_MSG_WARN([Found Makefile - using build library specs for $1]) + $1_LIB_SPEC=${$1_BUILD_LIB_SPEC} + $1_STUB_LIB_SPEC=${$1_BUILD_STUB_LIB_SPEC} + $1_STUB_LIB_PATH=${$1_BUILD_STUB_LIB_PATH} + $1_INCLUDE_SPEC=${$1_BUILD_INCLUDE_SPEC} + $1_LIBRARY_PATH=${$1_LIBRARY_PATH} + fi + + AC_SUBST($1_VERSION) + AC_SUBST($1_BIN_DIR) + AC_SUBST($1_SRC_DIR) + + AC_SUBST($1_LIB_FILE) + AC_SUBST($1_LIB_SPEC) + + AC_SUBST($1_STUB_LIB_FILE) + AC_SUBST($1_STUB_LIB_SPEC) + AC_SUBST($1_STUB_LIB_PATH) + + # Allow the caller to prevent this auto-check by specifying any 2nd arg + AS_IF([test "x$2" = x], [ + # Check both upper and lower-case variants + # If a dev wanted non-stubs libs, this function could take an option + # to not use _STUB in the paths below + AS_IF([test "x${$1_STUB_LIB_SPEC}" = x], + [TEA_LOAD_CONFIG_LIB(translit($1,[a-z],[A-Z])_STUB)], + [TEA_LOAD_CONFIG_LIB($1_STUB)]) + ]) +]) + +#------------------------------------------------------------------------ +# TEA_LOAD_CONFIG_LIB -- +# +# Helper function to load correct library from another extension's +# ${PACKAGE}Config.sh. +# +# Results: +# Adds to LIBS the appropriate extension library +#------------------------------------------------------------------------ +AC_DEFUN([TEA_LOAD_CONFIG_LIB], [ + AC_MSG_CHECKING([For $1 library for LIBS]) + # This simplifies the use of stub libraries by automatically adding + # the stub lib to your path. Normally this would add to SHLIB_LD_LIBS, + # but this is called before CONFIG_CFLAGS. More importantly, this adds + # to PKG_LIBS, which becomes LIBS, and that is only used by SHLIB_LD. + if test "x${$1_LIB_SPEC}" != "x" ; then + if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes" ; then + TEA_ADD_LIBS([\"`${CYGPATH} ${$1_LIB_PATH}`\"]) + AC_MSG_RESULT([using $1_LIB_PATH ${$1_LIB_PATH}]) + else + TEA_ADD_LIBS([${$1_LIB_SPEC}]) + AC_MSG_RESULT([using $1_LIB_SPEC ${$1_LIB_SPEC}]) + fi + else + AC_MSG_RESULT([file not found]) + fi +]) + +#------------------------------------------------------------------------ +# TEA_EXPORT_CONFIG -- +# +# Define the data to insert into the ${PACKAGE}Config.sh file +# +# Arguments: +# +# Requires the following vars to be set: +# $1 +# +# Results: +# Substitutes the following vars: +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_EXPORT_CONFIG], [ + #-------------------------------------------------------------------- + # These are for $1Config.sh + #-------------------------------------------------------------------- + + # pkglibdir must be a fully qualified path and (not ${exec_prefix}/lib) + eval pkglibdir="[$]{libdir}/$1${PACKAGE_VERSION}" + if test "${TCL_LIB_VERSIONS_OK}" = "ok"; then + eval $1_LIB_FLAG="-l$1${PACKAGE_VERSION}${DBGX}" + eval $1_STUB_LIB_FLAG="-l$1stub${PACKAGE_VERSION}${DBGX}" + else + eval $1_LIB_FLAG="-l$1`echo ${PACKAGE_VERSION} | tr -d .`${DBGX}" + eval $1_STUB_LIB_FLAG="-l$1stub`echo ${PACKAGE_VERSION} | tr -d .`${DBGX}" + fi + $1_BUILD_LIB_SPEC="-L`$CYGPATH $(pwd)` ${$1_LIB_FLAG}" + $1_LIB_SPEC="-L`$CYGPATH ${pkglibdir}` ${$1_LIB_FLAG}" + $1_BUILD_STUB_LIB_SPEC="-L`$CYGPATH $(pwd)` [$]{$1_STUB_LIB_FLAG}" + $1_STUB_LIB_SPEC="-L`$CYGPATH ${pkglibdir}` [$]{$1_STUB_LIB_FLAG}" + $1_BUILD_STUB_LIB_PATH="`$CYGPATH $(pwd)`/[$]{PKG_STUB_LIB_FILE}" + $1_STUB_LIB_PATH="`$CYGPATH ${pkglibdir}`/[$]{PKG_STUB_LIB_FILE}" + + AC_SUBST($1_BUILD_LIB_SPEC) + AC_SUBST($1_LIB_SPEC) + AC_SUBST($1_BUILD_STUB_LIB_SPEC) + AC_SUBST($1_STUB_LIB_SPEC) + AC_SUBST($1_BUILD_STUB_LIB_PATH) + AC_SUBST($1_STUB_LIB_PATH) + + AC_SUBST(MAJOR_VERSION) + AC_SUBST(MINOR_VERSION) + AC_SUBST(PATCHLEVEL) +]) + + +#------------------------------------------------------------------------ +# TEA_PATH_CELIB -- +# +# Locate Keuchel's celib emulation layer for targeting Win/CE +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --with-celib=... +# +# Defines the following vars: +# CELIB_DIR Full path to the directory containing +# the include and platform lib files +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PATH_CELIB], [ + # First, look for one uninstalled. + # the alternative search directory is invoked by --with-celib + + if test x"${no_celib}" = x ; then + # we reset no_celib in case something fails here + no_celib=true + AC_ARG_WITH(celib,[ --with-celib=DIR use Windows/CE support library from DIR], with_celibconfig=${withval}) + AC_MSG_CHECKING([for Windows/CE celib directory]) + AC_CACHE_VAL(ac_cv_c_celibconfig,[ + # First check to see if --with-celibconfig was specified. + if test x"${with_celibconfig}" != x ; then + if test -d "${with_celibconfig}/inc" ; then + ac_cv_c_celibconfig=`(cd ${with_celibconfig}; pwd)` + else + AC_MSG_ERROR([${with_celibconfig} directory doesn't contain inc directory]) + fi + fi + + # then check for a celib library + if test x"${ac_cv_c_celibconfig}" = x ; then + for i in \ + ../celib-palm-3.0 \ + ../celib \ + ../../celib-palm-3.0 \ + ../../celib \ + `ls -dr ../celib-*3.[[0-9]]* 2>/dev/null` \ + ${srcdir}/../celib-palm-3.0 \ + ${srcdir}/../celib \ + `ls -dr ${srcdir}/../celib-*3.[[0-9]]* 2>/dev/null` \ + ; do + if test -d "$i/inc" ; then + ac_cv_c_celibconfig=`(cd $i; pwd)` + break + fi + done + fi + ]) + if test x"${ac_cv_c_celibconfig}" = x ; then + AC_MSG_ERROR([Cannot find celib support library directory]) + else + no_celib= + CELIB_DIR=${ac_cv_c_celibconfig} + CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'` + AC_MSG_RESULT([found $CELIB_DIR]) + fi + fi +]) + +#------------------------------------------------------------------------ +# TEA_INSTALLER -- +# +# Configure the installer. +# +# Arguments: +# none +# +# Results: +# Substitutes the following vars: +# INSTALL +# INSTALL_DATA_DIR +# INSTALL_DATA +# INSTALL_PROGRAM +# INSTALL_SCRIPT +# INSTALL_LIBRARY +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_INSTALLER], [ + INSTALL='$(SHELL) $(srcdir)/tclconfig/install-sh -c' + INSTALL_DATA_DIR='${INSTALL} -d -m 755' + INSTALL_DATA='${INSTALL} -m 644' + INSTALL_PROGRAM='${INSTALL} -m 755' + INSTALL_SCRIPT='${INSTALL} -m 755' + + TEA_CONFIG_SYSTEM + case $system in + HP-UX-*) INSTALL_LIBRARY='${INSTALL} -m 755' ;; + *) INSTALL_LIBRARY='${INSTALL} -m 644' ;; + esac + + AC_SUBST(INSTALL) + AC_SUBST(INSTALL_DATA_DIR) + AC_SUBST(INSTALL_DATA) + AC_SUBST(INSTALL_PROGRAM) + AC_SUBST(INSTALL_SCRIPT) + AC_SUBST(INSTALL_LIBRARY) +]) + +### +# Tip 430 - ZipFS Modifications +### +#------------------------------------------------------------------------ +# SC_ZIPFS_SUPPORT +# Locate a zip encoder installed on the system path, or none. +# +# Arguments: +# none +# +# Results: +# Substitutes the following vars: +# TCL_ZIP_FILE +# TCL_ZIPFS_SUPPORT +# TCL_ZIPFS_FLAG +# ZIP_PROG +#------------------------------------------------------------------------ + +#------------------------------------------------------------------------ +# SC_PROG_ZIP +# Locate a zip encoder installed on the system path, or none. +# +# Arguments: +# none +# +# Results: +# Substitutes the following vars: +# ZIP_PROG +# ZIP_PROG_OPTIONS +# ZIP_PROG_VFSSEARCH +# ZIP_INSTALL_OBJS +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ZIPFS_SUPPORT], [ + AC_MSG_CHECKING([for zipfs support]) + ZIP_PROG="" + ZIP_PROG_OPTIONS="" + ZIP_PROG_VFSSEARCH="" + INSTALL_MSGS="" + # If our native tclsh processes the "install" command line option + # we can use it to mint zip files + AS_IF([$TCLSH_PROG install],[ + ZIP_PROG=${TCLSH_PROG} + ZIP_PROG_OPTIONS="install mkzip" + ZIP_PROG_VFSSEARCH="." + AC_MSG_RESULT([Can use Native Tclsh for Zip encoding]) + ]) + if test "x$ZIP_PROG" = "x" ; then + AC_CACHE_VAL(ac_cv_path_zip, [ + search_path=`echo ${PATH} | sed -e 's/:/ /g'` + for dir in $search_path ; do + for j in `ls -r $dir/zip 2> /dev/null` \ + `ls -r $dir/zip 2> /dev/null` ; do + if test x"$ac_cv_path_zip" = x ; then + if test -f "$j" ; then + ac_cv_path_zip=$j + break + fi + fi + done + done + ]) + if test -f "$ac_cv_path_zip" ; then + ZIP_PROG="$ac_cv_path_zip " + AC_MSG_RESULT([$ZIP_PROG]) + ZIP_PROG_OPTIONS="-rq" + ZIP_PROG_VFSSEARCH="." + AC_MSG_RESULT([Found INFO Zip in environment]) + # Use standard arguments for zip + fi + fi + if test "x$ZIP_PROG" = "x" ; then + # It is not an error if an installed version of Zip can't be located. + ZIP_PROG="" + ZIP_PROG_OPTIONS="" + ZIP_PROG_VFSSEARCH="" + TCL_ZIPFS_SUPPORT=0 + TCL_ZIPFS_FLAG= + else + # ZIPFS Support + eval "TCL_ZIP_FILE=\"${TCL_ZIP_FILE}\"" + if test ${TCL_ZIP_FILE} = "" ; then + TCL_ZIPFS_SUPPORT=0 + TCL_ZIPFS_FLAG= + INSTALL_LIBRARIES=install-libraries + INSTALL_MSGS=install-msgs + else + if test ${SHARED_BUILD} = 1 ; then + TCL_ZIPFS_SUPPORT=1 + INSTALL_LIBRARIES=install-libraries-zipfs-shared + else + TCL_ZIPFS_SUPPORT=2 + INSTALL_LIBRARIES=install-libraries-zipfs-static + fi + TCL_ZIPFS_FLAG=-DTCL_ZIPFS_SUPPORT + fi + fi + + AC_SUBST(TCL_ZIP_FILE) + AC_SUBST(TCL_ZIPFS_SUPPORT) + AC_SUBST(TCL_ZIPFS_FLAG) + AC_SUBST(ZIP_PROG) + AC_SUBST(ZIP_PROG_OPTIONS) + AC_SUBST(ZIP_PROG_VFSSEARCH) + AC_SUBST(INSTALL_LIBRARIES) + AC_SUBST(INSTALL_MSGS) +]) + +# Local Variables: +# mode: autoconf +# End: diff --git a/tests/all.tcl b/tests/all.tcl new file mode 100644 index 0000000..badd21f --- /dev/null +++ b/tests/all.tcl @@ -0,0 +1,11 @@ +source linegraph.tcl +source lineelement.tcl +source linepen.tcl +source bargraph.tcl +source barelement.tcl +source barpen.tcl +source axis.tcl +source legend.tcl +source crosshairs.tcl +source markers.tcl + diff --git a/tests/axis.tcl b/tests/axis.tcl new file mode 100644 index 0000000..80f97ea --- /dev/null +++ b/tests/axis.tcl @@ -0,0 +1,105 @@ +source base.tcl + +set w .line +set graph [bltLineGraph $w] + +$graph axis configure x -bd 2 -background cyan -title "X\nAxis" -limitsformat "%g" +$graph axis configure y -bd 2 -background cyan -title "Y\nAxis" +bltCmd $graph axis activate y + +puts stderr "Testing Axis..." + +bltTest3 $graph axis y -activeforeground red $dops +bltTest3 $graph axis y -activerelief sunken $dops +#bltTest3 $graph axis x -autorange 10 $dops +bltTest3 $graph axis x -background yellow $dops +bltTest3 $graph axis x -bg blue $dops +bltTest3 $graph axis x -bindtags {aa} 0 +bltTest3 $graph axis y -bd 4 $dops +bltTest3 $graph axis y -borderwidth 4 $dops +#bltTest3 $graph axis x -checklimits $dops +bltTest3 $graph axis x -color red $dops +#bltTest3 $graph axis x -command $dops +bltTest3 $graph axis x -descending yes $dops +bltTest3 $graph axis x -exterior no $dops +bltTest3 $graph axis x -fg magenta $dops +bltTest3 $graph axis x -foreground yellow $dops +bltTest3 $graph axis x -grid no $dops +bltTest3 $graph axis x -gridcolor blue $dops +bltTest3 $graph axis x -griddashes {8 3} $dops +bltTest3 $graph axis x -gridlinewidth 2 $dops +bltTest3 $graph axis x -gridminor no $dops +bltTest3 $graph axis x -gridminorcolor blue $dops +bltTest3 $graph axis x -gridminordashes {8 3} $dops +bltTest3 $graph axis x -gridminorlinewidth 2 $dops +bltTest3 $graph axis x -hide yes $dops +bltTest3 $graph axis x -justify left $dops +bltTest3 $graph axis x -justify center $dops +bltTest3 $graph axis x -justify right $dops +bltTest3 $graph axis x -labeloffset yes $dops +bltTest3 $graph axis x -limitscolor red $dops +bltTest3 $graph axis x -limitsfont {times 18 bold italic} $dops +bltTest3 $graph axis x -limitsformat "%e" $dops +bltTest3 $graph axis x -linewidth 2 $dops +bltTest3 $graph axis x -logscale yes $dops +#bltTest3 $graph axis x -loosemin $dops +#bltTest3 $graph axis x -loosemax $dops +#bltTest3 $graph axis x -majorticks $dops +#bltTest3 $graph axis x -max $dops +#bltTest3 $graph axis x -min $dops +#bltTest3 $graph axis x -minorticks $dops +bltTest3 $graph axis x -relief flat $dops +bltTest3 $graph axis x -relief groove $dops +bltTest3 $graph axis x -relief raised $dops +bltTest3 $graph axis x -relief ridge $dops +bltTest3 $graph axis x -relief solid $dops +bltTest3 $graph axis x -relief sunken $dops +bltTest3 $graph axis x -rotate 45 $dops +#bltTest3 $graph axis x -scrollcommand $dops +#bltTest3 $graph axis x -scrollincrement $dops +#bltTest3 $graph axis x -scrollmax $dops +#bltTest3 $graph axis x -scrollmin $dops +##bltTest3 $graph axis x -shiftby 10 $dops +bltTest3 $graph axis x -showticks no $dops +bltTest3 $graph axis x -stepsize 10 $dops +bltTest3 $graph axis x -subdivisions 4 $dops +##bltTest3 $graph axis x -tickanchor n $dops +bltTest3 $graph axis x -tickfont {times 12 bold italic} $dops +bltTest3 $graph axis x -ticklength 20 $dops +bltTest3 $graph axis x -tickdefault 10 $dops +bltTest3 $graph axis x -title {This is a Title} $dops +bltTest3 $graph axis x -titlealternate yes $dops +bltTest3 $graph axis x -titlecolor yellow $dops +bltTest3 $graph axis x -titlefont {times 24 bold italic} $dops + +#bltCmd $graph axis activate foo +#bltCmd $graph axis bind x +bltCmd $graph axis cget x -color +bltCmd $graph axis configure x +bltCmd $graph axis configure x -color +#bltCmd $graph axis create foo +#bltCmd $graph axis deactivate foo +#bltCmd $graph axis delete foo +#bltCmd $graph axis invtransform x +#bltCmd $graph axis limits x +#bltCmd $graph axis margin x +#bltCmd $graph axis names x +#bltCmd $graph axis transform x +#bltCmd $graph axis type x +#bltCmd $graph axis view x + +#bltCmd $graph xaxis activate +#bltCmd $graph xaxis bind +bltCmd $graph xaxis cget -color +bltCmd $graph xaxis configure +bltCmd $graph xaxis configure -color +#bltCmd $graph xaxis deactivate +#bltCmd $graph xaxis invtransform +#bltCmd $graph xaxis limits +#bltCmd $graph xaxis transform +#bltCmd $graph xaxis use +#bltCmd $graph xaxis view + +puts stderr "done" +bltPlotDestroy $w + diff --git a/tests/barelement.tcl b/tests/barelement.tcl new file mode 100644 index 0000000..5b8cb07 --- /dev/null +++ b/tests/barelement.tcl @@ -0,0 +1,97 @@ +source base.tcl + +set w .bar +set graph [bltBarGraph $w] + +$graph element configure data1 -color red -showvalues y +$graph element configure data2 -color blue + +$graph pen create foo -showvalues y -color purple +$graph element activate data3 + +puts stderr "Testing Bar Element..." + +bltTest3 $graph element data3 -activepen foo $dops +bltTest3 $graph element data2 -background yellow $dops +bltTest3 $graph element data2 -barwidth 1 $dops +bltTest3 $graph element data2 -bd 4 $dops +bltTest3 $graph element data2 -bg yellow $dops +bltTest3 $graph element data2 -bindtags {aa} 0 +bltTest3 $graph element data2 -borderwidth 4 $dops +bltTest3 $graph element data2 -color yellow $dops +bltTest3 $graph element data1 -data {0.2 8 0.4 20 0.6 31 0.8 41 1.0 50 1.2 59 1.4 65 1.6 70 1.8 75 2.0 85} $dops +bltTest3 $graph element data2 -errorbarcolor green $dops +bltTest3 $graph element data2 -errorbarwidth 2 $dops +bltTest3 $graph element data2 -errorbarcap 10 $dops +bltTest3 $graph element data2 -fg yellow $dops +bltTest3 $graph element data1 -fill cyan $dops +bltTest3 $graph element data2 -foreground green $dops +bltTest3 $graph element data2 -hide yes $dops +bltTest3 $graph element data2 -label "This is a test" $dops +bltTest3 $graph element data2 -legendrelief groove $dops +bltTest3 $graph element data2 -mapx x2 $dops +bltTest3 $graph element data2 -mapy y2 $dops +bltTest3 $graph element data1 -outline red $dops +bltTest3 $graph element data2 -pen foo $dops +bltTest3 $graph element data2 -relief flat $dops +bltTest3 $graph element data2 -relief groove $dops +bltTest3 $graph element data2 -relief raised $dops +bltTest3 $graph element data2 -relief ridge $dops +bltTest3 $graph element data2 -relief solid $dops +bltTest3 $graph element data2 -relief sunken $dops +bltTest3 $graph element data2 -showerrorbars no $dops +bltTest3 $graph element data1 -showvalues none $dops +bltTest3 $graph element data1 -showvalues x $dops +bltTest3 $graph element data1 -showvalues both $dops +#bltTest3 $graph element data2 -stack $dops +#bltTest3 $graph element data2 -styles $dops +bltTest3 $graph element data1 -valueanchor nw $dops +bltTest3 $graph element data1 -valueanchor n $dops +bltTest3 $graph element data1 -valueanchor ne $dops +bltTest3 $graph element data1 -valueanchor e $dops +bltTest3 $graph element data1 -valueanchor se $dops +bltTest3 $graph element data1 -valueanchor s $dops +bltTest3 $graph element data1 -valueanchor sw $dops +bltTest3 $graph element data1 -valueanchor w $dops +bltTest3 $graph element data1 -valuecolor cyan $dops +bltTest3 $graph element data1 -valuefont {times 18 bold italic} $dops +bltTest3 $graph element data1 -valueformat "%e" $dops +bltTest3 $graph element data1 -valuerotate 45 $dops +#bltTest3 $graph element data2 -weights $dops +bltTest3 $graph element data1 -x {0 .2 .4 .6 .8 1 1.2 1.4 1.6 1.8} $dops +bltTest3 $graph element data1 -xdata {0 .2 .4 .6 .8 1 1.2 1.4 1.6 1.8} $dops +bltTest3 $graph element data2 -xerror {.1 .1 .1 .1 .1 .1 .1 .1 .1 .1 .1} $dops +#bltTest3 $graph element data2 -xhigh $dops +#bltTest3 $graph element data2 -xlow $dops +bltTest3 $graph element data1 -y {8 20 31 41 50 59 65 70 75 85} $dops +bltTest3 $graph element data1 -ydata {8 20 31 41 50 59 65 70 75 85} $dops +bltTest3 $graph element data2 -yerror {5 5 5 5 5 5 5 5 5 5 5} $dops +#bltTest3 $graph element data2 -yhigh $dops +#bltTest3 $graph element data2 -ylow $dops + +bltCmd $graph element activate data2 +bltCmd $graph element deactivate data2 +#bltCmd $graph element bind data1 [list puts "%x %y"] +bltCmd $graph element cget data1 -showvalues +bltCmd $graph element configure data1 +bltCmd $graph element configure data1 -showvalues +#bltCmd $graph element closest 50 50 +#bltCmd $graph element closest 50 50 data1 data2 +bltCmd $graph element create data4 +bltCmd $graph element create data5 +bltCmd $graph element delete data4 data5 +bltCmd $graph element exists data1 +bltCmd $graph element lower data1 +bltCmd $graph element lower data2 data3 +bltCmd $graph element names +bltCmd $graph element names data1 +bltCmd $graph element raise data2 +bltCmd $graph element raise data2 data3 +bltCmd $graph element raise data1 +bltCmd $graph element show data2 +bltCmd $graph element show {data1 data2 data3} +bltCmd $graph element type data1 + +puts stderr "done" +bltPlotDestroy $w + diff --git a/tests/bargraph.tcl b/tests/bargraph.tcl new file mode 100644 index 0000000..20f067d --- /dev/null +++ b/tests/bargraph.tcl @@ -0,0 +1,80 @@ +source base.tcl + +set w .bar +set graph [bltBarGraph $w] + +puts stderr "Testing Bar Graph..." + +# Graph +bltTest $graph -aspect 2 $dops +bltTest $graph -background red $dops +bltTest $graph -barmode stacked $dops +bltTest $graph -barmode aligned $dops +bltTest $graph -barmode overlap $dops +bltTest $graph -barwidth .15 $dops +#bltTest $graph -baseline $dops +bltTest $graph -bd 50 $dops +bltTest $graph -bg green $dops +bltTest $graph -bm 50 $dops +bltTest $graph -borderwidth 50 $dops +bltTest $graph -bottommargin 50 $dops +#bltTest $graph -bufferelements $dops +#bltTest $graph -buffergraph $dops +bltTest $graph -cursor cross $dops +bltTest $graph -fg blue $dops +bltTest $graph -font {times 36 bold italic} $dops +bltTest $graph -foreground cyan $dops +#bltTest $graph -halo $dops +bltTest $graph -height 300 $dops +#bltTest $graph -highlightbackground $dops +#bltTest $graph -highlightcolor $dops +#bltTest $graph -highlightthickness $dops +bltTest $graph -invertxy yes $dops +bltTest $graph -justify left $dops +bltTest $graph -justify center $dops +bltTest $graph -justify right $dops +bltTest $graph -leftmargin 50 $dops +bltTest $graph -lm 50 $dops +bltTest $graph -plotbackground cyan $dops +bltTest $graph -plotborderwidth 50 $dops +bltTest $graph -plotpadx 50 $dops +bltTest $graph -plotpady 50 $dops +bltTest $graph -plotrelief groove $dops +bltTest $graph -relief groove $dops +bltTest $graph -rightmargin 50 $dops +bltTest $graph -rm 50 $dops +#bltTest $graph -searchhalo $dops +#bltTest $graph -searchmode $dops +#bltTest $graph -searchalong $dops +#bltTest $graph -stackaxes $dops +#bltTest $graph -takefocus $dops +bltTest $graph -title "This is a Title" $dops +bltTest $graph -tm 50 $dops +bltTest $graph -topmargin 50 $dops +bltTest $graph -width 300 $dops +bltTest $graph -plotwidth 300 $dops +bltTest $graph -plotheight 300 $dops + +##bltCmd $graph axis +bltCmd $graph cget -background +bltCmd $graph configure +bltCmd $graph configure +bltCmd $graph configure -background cyan +##bltCmd $graph crosshairs +##bltCmd $graph element +#bltCmd $graph extents +#bltCmd $graph inside +#bltCmd $graph invtransform +##bltCmd $graph legend +##bltCmd $graph marker +##bltCmd $graph pen +##bltCmd $graph postscript +#bltCmd $graph transform +##bltCmd $graph x2axis +##bltCmd $graph xaxis +##bltCmd $graph y2axis +##bltCmd $graph yaxis + +puts stderr "done" +bltPlotDestroy $w + diff --git a/tests/barpen.tcl b/tests/barpen.tcl new file mode 100644 index 0000000..d06928b --- /dev/null +++ b/tests/barpen.tcl @@ -0,0 +1,51 @@ +source base.tcl + +set w .bar +set graph [bltBarGraph $w] + +$graph pen create foo -color red -showvalues y +$graph element configure data2 -pen foo + +puts stderr "Testing Bar Pen..." + +bltTest3 $graph pen foo -background yellow $dops +bltTest3 $graph pen foo -bd 4 $dops +bltTest3 $graph pen foo -bg yellow $dops +bltTest3 $graph pen foo -borderwidth 4 $dops +bltTest3 $graph pen foo -color yellow $dops +bltTest3 $graph pen foo -errorbarcolor green $dops +bltTest3 $graph pen foo -errorbarwidth 2 $dops +bltTest3 $graph pen foo -errorbarcap 10 $dops +bltTest3 $graph pen foo -fg yellow $dops +bltTest3 $graph pen foo -fill cyan $dops +bltTest3 $graph pen foo -foreground green $dops +bltTest3 $graph pen foo -outline red $dops +bltTest3 $graph pen foo -relief flat $dops +bltTest3 $graph pen foo -showerrorbars no $dops +bltTest3 $graph pen foo -showvalues none $dops +bltTest3 $graph pen foo -showvalues x $dops +bltTest3 $graph pen foo -showvalues both $dops +bltTest3 $graph pen foo -valueanchor nw $dops +bltTest3 $graph pen foo -valueanchor n $dops +bltTest3 $graph pen foo -valueanchor ne $dops +bltTest3 $graph pen foo -valueanchor e $dops +bltTest3 $graph pen foo -valueanchor se $dops +bltTest3 $graph pen foo -valueanchor s $dops +bltTest3 $graph pen foo -valueanchor sw $dops +bltTest3 $graph pen foo -valueanchor w $dops +bltTest3 $graph pen foo -valuecolor cyan $dops +bltTest3 $graph pen foo -valuefont {times 18 bold italic} $dops +bltTest3 $graph pen foo -valueformat "%e" $dops +bltTest3 $graph pen foo -valuerotate 45 $dops + +bltCmd $graph pen cget foo -color +bltCmd $graph pen configure foo +bltCmd $graph pen configure foo -color +bltCmd $graph pen create bar +bltCmd $graph pen delete bar +bltCmd $graph pen names +bltCmd $graph pen type foo + +puts stderr "done" +bltPlotDestroy $w + diff --git a/tests/base.tcl b/tests/base.tcl new file mode 100644 index 0000000..e3dac2e --- /dev/null +++ b/tests/base.tcl @@ -0,0 +1,142 @@ +package require tkblt + +#set sleep 1000 +set sleep 500 +if {![info exists dops]} { + set dops 0 +} + +proc bltPlot {w title} { + toplevel $w + wm title $w $title + wm protocol $w WM_DELETE_WINDOW [list bltPlotDestroy $w] + + set mb ${w}mb + menu $mb + $w configure -menu $mb +} + +proc bltPlotDestroy {w} { + destroy ${w}mb + destroy $w +} + +proc bltTest {graph option value {dops 0}} { + global sleep + + puts stderr " $option $value" + set org [$graph cget $option] + $graph configure $option $value + update + if {$dops} { + $graph postscript output foo.ps + exec open /Applications/Preview.app/ foo.ps + } + after $sleep +# read stdin 1 + $graph configure $option $org + update + after $sleep +} + +proc bltTest2 {graph which option value {dops 0}} { + global sleep + + puts stderr " $option $value" + set org [$graph $which cget $option] + $graph $which configure $option $value + update + if {$dops} { + $graph postscript output foo.ps + exec open /Applications/Preview.app/ foo.ps + } + after $sleep +# read stdin 1 + $graph $which configure $option $org + update + after $sleep +} + +proc bltTest3 {graph which item option value {dops 0}} { + global sleep + + puts stderr " $item $option $value" + set org [$graph $which cget $item $option] + $graph $which configure $item $option $value + update + if {$dops} { + $graph postscript output foo.ps + exec open /Applications/Preview.app/ foo.ps + } + after $sleep +# read stdin 1 + $graph $which configure $item $option $org + update + after $sleep +} + +proc bltCmd {graph args} { + global sleep + + puts stderr " $graph $args" + eval $graph $args + update + after $sleep +# read stdin 1 +} + +proc bltElements {graph} { + blt::vector create xv(10) + blt::vector create yv(10) + xv set { 0.2 0.4 0.6 0.8 1.0 1.2 1.4 1.6 1.8 2.0 } + yv set { 5 10 10 15 15 10 20 25 30 35 } + + $graph element create data1 -data {0.2 13 0.4 25 0.6 36 0.8 46 1.0 55 1.2 64 1.4 70 1.6 75 1.8 80 2.0 90} + + $graph element create data2 \ + -xdata {0.2 0.4 0.6 0.8 1.0 1.2 1.4 1.6 1.8 2.0} \ + -ydata {26 50 72 92 110 128 140 150 160 180} \ + -xerror {.05 .05 .05 .05 .05 .05 .05 .05 .05 .05} \ + -yerror {10 10 10 10 10 10 10 10 10 10 10} \ + -color red + + $graph element create data3 -xdata xv -ydata yv -color green + + $graph legend configure -title "Legend" +} + +proc bltBarGraph {w} { + global sleep + + bltPlot $w "Bar Graph" + set graph [blt::barchart ${w}.gr \ + -width 600 \ + -height 500 \ + -title "Bar\nGraph" \ + -barwidth .2 \ + -barmode aligned \ + ] + pack $graph -expand yes -fill both + bltElements $graph + + update + after $sleep + return $graph +} + +proc bltLineGraph {w} { + global sleep + + bltPlot $w "Line Graph" + set graph [blt::graph ${w}.gr \ + -width 600 \ + -height 500 \ + -title "Line\nGraph" \ + ] + pack $graph -expand yes -fill both + bltElements $graph + + update + after $sleep + return $graph +} diff --git a/tests/crosshairs.tcl b/tests/crosshairs.tcl new file mode 100644 index 0000000..c63cea5 --- /dev/null +++ b/tests/crosshairs.tcl @@ -0,0 +1,26 @@ +source base.tcl + +set w .line +set graph [bltLineGraph $w] + +$graph crosshairs on +$graph crosshairs configure -x 200 -y 200 + +puts stderr "Testing Crosshairs..." + +bltTest2 $graph crosshairs -color green +bltTest2 $graph crosshairs -dashes "8 3" +bltTest2 $graph crosshairs -linewidth 3 +bltTest2 $graph crosshairs -x 100 +bltTest2 $graph crosshairs -y 100 + +bltCmd $graph crosshairs cget -color +bltCmd $graph crosshairs configure +bltCmd $graph crosshairs configure -color +bltCmd $graph crosshairs on +bltCmd $graph crosshairs off +bltCmd $graph crosshairs toggle + +puts stderr "done" +bltPlotDestroy $w + diff --git a/tests/legend.tcl b/tests/legend.tcl new file mode 100644 index 0000000..dba8da0 --- /dev/null +++ b/tests/legend.tcl @@ -0,0 +1,101 @@ +source base.tcl + +set w .line +set graph [bltLineGraph $w] + +$graph legend selection set data2 +$graph legend focus data1 +$graph legend configure -selectrelief groove + +puts stderr "Testing Legend..." + +#bltTest2 $graph legend -activebackground $dops +#bltTest2 $graph legend -activeborderwidth $dops +#bltTest2 $graph legend -activeforeground $dops +#bltTest2 $graph legend -activerelief $dops +bltTest2 $graph legend -anchor nw $dops +bltTest2 $graph legend -anchor n $dops +bltTest2 $graph legend -anchor ne $dops +bltTest2 $graph legend -anchor e $dops +bltTest2 $graph legend -anchor se $dops +bltTest2 $graph legend -anchor s $dops +bltTest2 $graph legend -anchor sw $dops +bltTest2 $graph legend -anchor w $dops +bltTest2 $graph legend -bg pink $dops +bltTest2 $graph legend -background cyan $dops +bltTest2 $graph legend -borderwidth 20 $dops +bltTest2 $graph legend -bd 20 $dops +bltTest2 $graph legend -columns 2 $dops +#bltTest2 $graph legend -exportselection $dops +bltTest2 $graph legend -focusdashes "8 3" $dops +bltTest2 $graph legend -focusforeground red $dops +bltTest2 $graph legend -font {times 18 bold italic} $dops +bltTest2 $graph legend -fg yellow $dops +bltTest2 $graph legend -foreground purple $dops +bltTest2 $graph legend -hide yes $dops +bltTest2 $graph legend -ipadx 20 $dops +bltTest2 $graph legend -ipady 20 $dops +#bltTest2 $graph legend -nofocusselectbackground $dops +#bltTest2 $graph legend -nofocusselectforeground $dops +bltTest2 $graph legend -padx 20 $dops +bltTest2 $graph legend -pady 20 $dops +bltTest2 $graph legend -position rightmargin $dops +bltTest2 $graph legend -position leftmargin $dops +bltTest2 $graph legend -position topmargin $dops +bltTest2 $graph legend -position bottommargin $dops +bltTest2 $graph legend -position plotarea $dops +bltTest2 $graph legend -position xy $dops +bltTest2 $graph legend -x 250 $dops +bltTest2 $graph legend -y 100 $dops +bltTest2 $graph legend -raised yes $dops +bltTest2 $graph legend -relief flat $dops +bltTest2 $graph legend -relief groove $dops +bltTest2 $graph legend -relief raised $dops +bltTest2 $graph legend -relief ridge $dops +bltTest2 $graph legend -relief solid $dops +bltTest2 $graph legend -relief sunken $dops +bltTest2 $graph legend -rows 1 $dops +#bltTest2 $graph legend -selectbackground $dops +bltTest2 $graph legend -selectborderwidth 3 $dops +#bltTest2 $graph legend -selectcommand $dops +#bltTest2 $graph legend -selectforeground $dops +#bltTest2 $graph legend -selectmode $dops +bltTest2 $graph legend -selectrelief flat $dops +bltTest2 $graph legend -title "Hello World" $dops +bltTest2 $graph legend -titlecolor red $dops +bltTest2 $graph legend -titlefont {times 24 bold italic} $dops + +#bltCmd $graph legend activate +#bltCmd $graph legend bind +bltCmd $graph legend cget -fg +bltCmd $graph legend configure +bltCmd $graph legend configure -fg +#bltCmd $graph legend curselection +#bltCmd $graph legend deactivate +bltCmd $graph legend focus data1 +bltCmd $graph legend focus +#bltCmd $graph legend get anchor +#bltCmd $graph legend get current +#bltCmd $graph legend get first +#bltCmd $graph legend get last +#bltCmd $graph legend get end +#bltCmd $graph legend get next.row +#bltCmd $graph legend get next.column +#bltCmd $graph legend get previous.row +#bltCmd $graph legend get previous.column +#bltCmd $graph legend get @100,100 +#bltCmd $graph legend get data1 +bltCmd $graph legend selection anchor data1 +bltCmd $graph legend selection mark data1 +bltCmd $graph legend selection includes data2 +bltCmd $graph legend selection present +bltCmd $graph legend selection set data1 data2 +bltCmd $graph legend selection clear data1 data2 +bltCmd $graph legend selection set data1 data2 +bltCmd $graph legend selection toggle data1 data2 +bltCmd $graph legend selection set data1 data2 +bltCmd $graph legend selection clearall + +puts stderr "done" +bltPlotDestroy $w + diff --git a/tests/lineelement.tcl b/tests/lineelement.tcl new file mode 100644 index 0000000..5edb38e --- /dev/null +++ b/tests/lineelement.tcl @@ -0,0 +1,105 @@ +source base.tcl + +set w .line +set graph [bltLineGraph $w] + +$graph element configure data1 -dash {8 3} -showvalues y -smooth step -symbol circle -outline yellow -outlinewidth 3 -pixels 10 + +$graph pen create foo -showvalues y -symbol circle -dashes {8 3} -color purple -linewidth 2 +$graph element activate data3 + +puts stderr "Testing Line Element.." + +bltTest3 $graph element data3 -activepen foo $dops +bltTest3 $graph element data2 -areabackground yellow $dops +bltTest3 $graph element data2 -bindtags {aa} +bltTest3 $graph element data2 -color yellow $dops +bltTest3 $graph element data2 -dashes {8 3} $dops +bltTest3 $graph element data1 -data {0.2 8 0.4 20 0.6 31 0.8 41 1.0 50 1.2 59 1.4 65 1.6 70 1.8 75 2.0 85} $dops +bltTest3 $graph element data2 -errorbarcolor green $dops +bltTest3 $graph element data2 -errorbarwidth 2 $dops +bltTest3 $graph element data2 -errorbarcap 10 $dops +bltTest3 $graph element data1 -fill cyan $dops +bltTest3 $graph element data2 -hide yes $dops +bltTest3 $graph element data2 -label "This is a test" $dops +bltTest3 $graph element data2 -legendrelief groove $dops +bltTest3 $graph element data2 -linewidth 3 $dops +bltTest3 $graph element data2 -mapx x2 $dops +bltTest3 $graph element data2 -mapy y2 $dops +bltTest3 $graph element data1 -maxsymbols 4 $dops +bltTest3 $graph element data1 -offdash black $dops +bltTest3 $graph element data1 -outline green $dops +bltTest3 $graph element data1 -outlinewidth 5 $dops +bltTest3 $graph element data2 -pen foo $dops +bltTest3 $graph element data1 -pixels 20 $dops +#bltTest3 $graph element data2 -reduce $dops +bltTest3 $graph element data1 -scalesymbols no $dops +bltTest3 $graph element data2 -showerrorbars no $dops +bltTest3 $graph element data1 -showvalues none $dops +bltTest3 $graph element data1 -showvalues x $dops +bltTest3 $graph element data1 -showvalues both $dops +bltTest3 $graph element data1 -smooth linear $dops +bltTest3 $graph element data1 -smooth cubic $dops +bltTest3 $graph element data1 -smooth quadratic $dops +bltTest3 $graph element data1 -smooth catrom $dops +#bltTest3 $graph element data2 -styles $dops +bltTest3 $graph element data1 -symbol arrow $dops +bltTest3 $graph element data1 -symbol cross $dops +bltTest3 $graph element data1 -symbol diamond $dops +bltTest3 $graph element data1 -symbol none $dops +bltTest3 $graph element data1 -symbol plus $dops +bltTest3 $graph element data1 -symbol scross $dops +bltTest3 $graph element data1 -symbol splus $dops +bltTest3 $graph element data1 -symbol square $dops +bltTest3 $graph element data1 -symbol triangle $dops +bltTest3 $graph element data2 -trace both $dops +bltTest3 $graph element data1 -valueanchor nw $dops +bltTest3 $graph element data1 -valueanchor n $dops +bltTest3 $graph element data1 -valueanchor ne $dops +bltTest3 $graph element data1 -valueanchor e $dops +bltTest3 $graph element data1 -valueanchor se $dops +bltTest3 $graph element data1 -valueanchor s $dops +bltTest3 $graph element data1 -valueanchor sw $dops +bltTest3 $graph element data1 -valueanchor w $dops +bltTest3 $graph element data1 -valuecolor cyan $dops +bltTest3 $graph element data1 -valuefont {times 18 bold italic} $dops +bltTest3 $graph element data1 -valueformat "%e" $dops +bltTest3 $graph element data1 -valuerotate 45 $dops +#bltTest3 $graph element data2 -weights $dops +bltTest3 $graph element data1 -x {0 .2 .4 .6 .8 1 1.2 1.4 1.6 1.8} $dops +bltTest3 $graph element data1 -xdata {0 .2 .4 .6 .8 1 1.2 1.4 1.6 1.8} $dops +bltTest3 $graph element data2 -xerror {.1 .1 .1 .1 .1 .1 .1 .1 .1 .1 .1} $dops +#bltTest3 $graph element data2 -xhigh $dops +#bltTest3 $graph element data2 -xlow $dops +bltTest3 $graph element data1 -y {8 20 31 41 50 59 65 70 75 85} $dops +bltTest3 $graph element data1 -ydata {8 20 31 41 50 59 65 70 75 85} $dops +bltTest3 $graph element data2 -yerror {5 5 5 5 5 5 5 5 5 5 5} $dops +#bltTest3 $graph element data2 -yhigh $dops +#bltTest3 $graph element data2 -ylow $dops + +bltCmd $graph element activate data2 +bltCmd $graph element deactivate data2 +#bltCmd $graph element bind data1 [list puts "%x %y"] +bltCmd $graph element cget data1 -smooth +bltCmd $graph element configure data1 +bltCmd $graph element configure data1 -smooth +#bltCmd $graph element closest 50 50 +#bltCmd $graph element closest 50 50 data1 data2 +bltCmd $graph element create data4 +bltCmd $graph element create data5 +bltCmd $graph element delete data4 data5 +bltCmd $graph element exists data1 +bltCmd $graph element lower data1 +bltCmd $graph element lower data2 data3 +bltCmd $graph element names +bltCmd $graph element names data1 +bltCmd $graph element raise data2 +bltCmd $graph element raise data2 data3 +bltCmd $graph element raise data1 +bltCmd $graph element show data2 +bltCmd $graph element show {data1 data2 data3} +bltCmd $graph element type data1 + +puts stderr "done" +bltPlotDestroy $w + diff --git a/tests/linegraph.tcl b/tests/linegraph.tcl new file mode 100644 index 0000000..6204e72 --- /dev/null +++ b/tests/linegraph.tcl @@ -0,0 +1,75 @@ +source base.tcl + +set w .line +set graph [bltLineGraph $w] + +puts stderr "Testing Line Graph..." + +bltTest $graph -aspect 2 $dops +bltTest $graph -background red $dops +#bltTest $graph -baseline $dops +bltTest $graph -bd 50 $dops +bltTest $graph -bg green $dops +bltTest $graph -bm 50 $dops +bltTest $graph -borderwidth 50 $dops +bltTest $graph -bottommargin 50 $dops +#bltTest $graph -bufferelements $dops +#bltTest $graph -buffergraph $dops +bltTest $graph -cursor cross $dops +bltTest $graph -fg blue $dops +bltTest $graph -font {times 36 bold italic} $dops +bltTest $graph -foreground cyan $dops +#bltTest $graph -halo $dops +bltTest $graph -height 300 $dops +#bltTest $graph -highlightbackground $dops +#bltTest $graph -highlightcolor $dops +#bltTest $graph -highlightthickness $dops +bltTest $graph -invertxy yes $dops +bltTest $graph -justify left $dops +bltTest $graph -justify center $dops +bltTest $graph -justify right $dops +bltTest $graph -leftmargin 50 $dops +bltTest $graph -lm 50 $dops +bltTest $graph -plotbackground cyan $dops +bltTest $graph -plotborderwidth 50 $dops +bltTest $graph -plotpadx 50 $dops +bltTest $graph -plotpady 50 $dops +bltTest $graph -plotrelief groove $dops +bltTest $graph -relief groove $dops +bltTest $graph -rightmargin 50 $dops +bltTest $graph -rm 50 $dops +#bltTest $graph -searchhalo $dops +#bltTest $graph -searchmode $dops +#bltTest $graph -searchalong $dops +#bltTest $graph -stackaxes $dops +#bltTest $graph -takefocus $dops +bltTest $graph -title "This is a Title" $dops +bltTest $graph -tm 50 $dops +bltTest $graph -topmargin 50 $dops +bltTest $graph -width 300 $dops +bltTest $graph -plotwidth 300 $dops +bltTest $graph -plotheight 300 $dops + +##bltCmd $graph axis +bltCmd $graph cget -background +bltCmd $graph configure +bltCmd $graph configure +bltCmd $graph configure -background cyan +##bltCmd $graph crosshairs +##bltCmd $graph element +#bltCmd $graph extents +#bltCmd $graph inside +#bltCmd $graph invtransform +##bltCmd $graph legend +##bltCmd $graph marker +##bltCmd $graph pen +#bltCmd $graph postscript output foo.ps +#bltCmd $graph transform +##bltCmd $graph x2axis +##bltCmd $graph xaxis +##bltCmd $graph y2axis +##bltCmd $graph yaxis + +puts stderr "done" +bltPlotDestroy $w + diff --git a/tests/linemarker.tcl b/tests/linemarker.tcl new file mode 100644 index 0000000..3b66ba6 --- /dev/null +++ b/tests/linemarker.tcl @@ -0,0 +1,34 @@ +source base.tcl + +set w .line +set graph [bltLineGraph $w] + +set mm [$graph marker create line tt -element data2 \ + -coords {1 50 1.5 100 1 150} -linewidth 5] +set nn [$graph marker create line ss -element data2 \ + -coords {1 150 .5 100 1 50} -linewidth 2 \ + -outline green -dashes 4] +$graph element configure data1 -hide yes + +puts stderr "Testing Line Marker..." + +bltTest3 $graph marker $mm -bindtags {aa} 0 +bltTest3 $graph marker $mm -cap round $dops +bltTest3 $graph marker $mm -coords {1 50 1.5 100 2 150} $dops +bltTest3 $graph marker $mm -dashes {8 3} $dops +bltTest3 $graph marker $nn -dashoffset 10 $dops +bltTest3 $graph marker $mm -element data1 $dops +bltTest3 $graph marker $nn -fill yellow $dops +bltTest3 $graph marker $mm -join round $dops +bltTest3 $graph marker $mm -linewidth 1 $dops +bltTest3 $graph marker $mm -hide yes $dops +bltTest3 $graph marker $mm -mapx x2 $dops +bltTest3 $graph marker $mm -mapy y2 $dops +bltTest3 $graph marker $mm -outline green $dops +bltTest3 $graph marker $mm -under yes $dops +bltTest3 $graph marker $mm -xoffset 20 $dops +bltTest3 $graph marker $mm -yoffset 20 $dops + +puts stderr "done" +bltPlotDestroy $w + diff --git a/tests/linepen.tcl b/tests/linepen.tcl new file mode 100644 index 0000000..e47b243 --- /dev/null +++ b/tests/linepen.tcl @@ -0,0 +1,55 @@ +source base.tcl + +set w .line +set graph [bltLineGraph $w] + +$graph pen create foo -color red -showvalues y -symbol circle -dashes {4 4} +$graph element configure data2 -pen foo + +puts stderr "Testing Line Pen..." + +bltTest3 $graph pen foo -color yellow $dops +bltTest3 $graph pen foo -dashes {8 3} $dops +bltTest3 $graph pen foo -errorbarcolor green $dops +bltTest3 $graph pen foo -errorbarwidth 2 $dops +bltTest3 $graph pen foo -errorbarcap 10 $dops +bltTest3 $graph pen foo -fill cyan $dops +bltTest3 $graph pen foo -linewidth 3 $dops +bltTest3 $graph pen foo -offdash black $dops +bltTest3 $graph pen foo -outline green $dops +bltTest3 $graph pen foo -outlinewidth 5 $dops +bltTest3 $graph pen foo -pixels 20 $dops +bltTest3 $graph pen foo -showvalues none $dops +bltTest3 $graph pen foo -symbol arrow $dops +bltTest3 $graph pen foo -symbol cross $dops +bltTest3 $graph pen foo -symbol diamond $dops +bltTest3 $graph pen foo -symbol none $dops +bltTest3 $graph pen foo -symbol plus $dops +bltTest3 $graph pen foo -symbol scross $dops +bltTest3 $graph pen foo -symbol splus $dops +bltTest3 $graph pen foo -symbol square $dops +bltTest3 $graph pen foo -symbol triangle $dops +bltTest3 $graph pen foo -valueanchor nw $dops +bltTest3 $graph pen foo -valueanchor n $dops +bltTest3 $graph pen foo -valueanchor ne $dops +bltTest3 $graph pen foo -valueanchor e $dops +bltTest3 $graph pen foo -valueanchor se $dops +bltTest3 $graph pen foo -valueanchor s $dops +bltTest3 $graph pen foo -valueanchor sw $dops +bltTest3 $graph pen foo -valueanchor w $dops +bltTest3 $graph pen foo -valuecolor cyan $dops +bltTest3 $graph pen foo -valuefont {times 18 bold italic} $dops +bltTest3 $graph pen foo -valueformat "%e" $dops +bltTest3 $graph pen foo -valuerotate 45 $dops + +bltCmd $graph pen cget foo -color +bltCmd $graph pen configure foo +bltCmd $graph pen configure foo -color +bltCmd $graph pen create bar +bltCmd $graph pen delete bar +bltCmd $graph pen names +bltCmd $graph pen type foo + +puts stderr "done" +bltPlotDestroy $w + diff --git a/tests/marker.tcl b/tests/marker.tcl new file mode 100644 index 0000000..8a09a43 --- /dev/null +++ b/tests/marker.tcl @@ -0,0 +1,33 @@ +source base.tcl + +set w .line +set graph [bltLineGraph $w] + +set mm [$graph marker create line tt -element data1 \ + -coords {1 50 1.5 100 1 150} -linewidth 5 -bind {aa}] +set nn [$graph marker create line ss -element data1 \ + -coords {1 150 .5 100 1 50} -linewidth 1 \ + -outline green -dashes 4] + +puts stderr "Testing Marker..." + +#bltCmd $graph marker bind aa [list puts "%x %y"] +bltCmd $graph marker cget $mm -cap +bltCmd $graph marker configure $mm +bltCmd $graph marker configure $mm -cap +set foo [$graph marker create line] +bltCmd $graph marker delete $foo +set foo [$graph marker create line foo] +bltCmd $graph marker delete $foo +bltCmd $graph marker exists $mm +bltCmd $graph marker find enclosed 0 0 2 200 +bltCmd $graph marker lower $mm +bltCmd $graph marker lower $mm $nn +bltCmd $graph marker names +bltCmd $graph marker raise $mm +bltCmd $graph marker raise $mm $nn +bltCmd $graph marker type $mm + +puts stderr "done" +bltPlotDestroy $w + diff --git a/tests/markers.tcl b/tests/markers.tcl new file mode 100644 index 0000000..2f43c8b --- /dev/null +++ b/tests/markers.tcl @@ -0,0 +1,4 @@ +source marker.tcl +source linemarker.tcl +source polygonmarker.tcl +source textmarker.tcl diff --git a/tests/polygonmarker.tcl b/tests/polygonmarker.tcl new file mode 100644 index 0000000..b1712b0 --- /dev/null +++ b/tests/polygonmarker.tcl @@ -0,0 +1,30 @@ +source base.tcl + +set w .line +set graph [bltLineGraph $w] + +set mm [$graph marker create polygon tt -element data2 \ + -coords {1 50 1.5 100 1 150} -linewidth 5] +$graph element configure data1 -hide yes + +puts stderr "Testing Polygon Marker..." + +bltTest3 $graph marker $mm -bindtags {aa} 0 +bltTest3 $graph marker $mm -cap round $dops +bltTest3 $graph marker $mm -coords {1 50 1.5 100 2 150} $dops +bltTest3 $graph marker $mm -dashes {8 3} $dops +bltTest3 $graph marker $mm -element data1 $dops +bltTest3 $graph marker $mm -fill yellow $dops +bltTest3 $graph marker $mm -join round $dops +bltTest3 $graph marker $mm -linewidth 1 $dops +bltTest3 $graph marker $mm -hide yes $dops +bltTest3 $graph marker $mm -mapx x2 $dops +bltTest3 $graph marker $mm -mapy y2 $dops +bltTest3 $graph marker $mm -outline yellow $dops +bltTest3 $graph marker $mm -under yes $dops +bltTest3 $graph marker $mm -xoffset 20 $dops +bltTest3 $graph marker $mm -yoffset 20 $dops + +puts stderr "done" +bltPlotDestroy $w + diff --git a/tests/ps.tcl b/tests/ps.tcl new file mode 100644 index 0000000..7a9ce23 --- /dev/null +++ b/tests/ps.tcl @@ -0,0 +1,29 @@ +source base.tcl + +set w .line +set graph [bltLineGraph $w] + +$graph axis configure x -title "X\nAxis" -limitsformat "%g" +$graph axis configure y -title "Y\nAxis" + +$graph element configure data1 -dash {8 3} -showvalues y -smooth step -symbol circle -outline yellow -outlinewidth 3 -pixels 10 -valuefont "times 14 italic" -valuerotate 45 + +$graph legend configure -relief raised +$graph xaxis configure -bg cyan -relief raised +$graph configure -relief raised +$graph configure -plotrelief raised + +$graph legend selection set data2 +$graph legend focus data1 +$graph legend configure -selectrelief groove + +$graph postscript configure -decorations yes +$graph postscript output foo.ps +$graph postscript configure -decorations no +$graph postscript output bar.ps + +#set graph [bltBarGraph $w] + +#puts stderr "done" +#bltPlotDestroy $w + diff --git a/tests/test.tcl b/tests/test.tcl new file mode 100644 index 0000000..df6ffd8 --- /dev/null +++ b/tests/test.tcl @@ -0,0 +1,10 @@ +source base.tcl + +set w .line +set graph [bltLineGraph $w] + +#set graph [bltBarGraph $w] + +#puts stderr "done" +#bltPlotDestroy $w + diff --git a/tests/textmarker.tcl b/tests/textmarker.tcl new file mode 100644 index 0000000..ba3defc --- /dev/null +++ b/tests/textmarker.tcl @@ -0,0 +1,44 @@ +source base.tcl + +set w .line +set graph [bltLineGraph $w] + +set mm [$graph marker create text tt -element data2 \ + -coords {1. 112} -text "Text\nMarker" -font {helvetica 24}] +$graph element configure data1 -hide yes + +puts stderr "Testing Text Marker..." + +bltTest3 $graph marker $mm -anchor nw $dops +bltTest3 $graph marker $mm -anchor n $dops +bltTest3 $graph marker $mm -anchor ne $dops +bltTest3 $graph marker $mm -anchor e $dops +bltTest3 $graph marker $mm -anchor se $dops +bltTest3 $graph marker $mm -anchor s $dops +bltTest3 $graph marker $mm -anchor sw $dops +bltTest3 $graph marker $mm -anchor w $dops +bltTest3 $graph marker $mm -background yellow $dops +bltTest3 $graph marker $mm -bg red $dops +bltTest3 $graph marker $mm -bindtags {aa} 0 +bltTest3 $graph marker $mm -coords {1 50} $dops +bltTest3 $graph marker $mm -element data1 $dops +bltTest3 $graph marker $mm -fg cyan $dops +bltTest3 $graph marker $mm -fill yellow $dops +bltTest3 $graph marker $mm -font {times 24 bold italic} $dops +bltTest3 $graph marker $mm -foreground blue $dops +bltTest3 $graph marker $mm -justify left $dops +bltTest3 $graph marker $mm -justify center $dops +bltTest3 $graph marker $mm -justify right $dops +bltTest3 $graph marker $mm -hide yes $dops +bltTest3 $graph marker $mm -mapx x2 $dops +bltTest3 $graph marker $mm -mapy y2 $dops +bltTest3 $graph marker $mm -outline green $dops +bltTest3 $graph marker $mm -rotate 45 $dops +bltTest3 $graph marker $mm -text {Hello World} $dops +bltTest3 $graph marker $mm -under yes $dops +bltTest3 $graph marker $mm -xoffset 20 $dops +bltTest3 $graph marker $mm -yoffset 20 $dops + +puts stderr "done" +bltPlotDestroy $w + diff --git a/tkbltConfig.sh.in b/tkbltConfig.sh.in new file mode 100755 index 0000000..5464ed6 --- /dev/null +++ b/tkbltConfig.sh.in @@ -0,0 +1,45 @@ +# tkbltConfig.sh -- +# +# This shell script (for sh) is generated automatically by tkblt's +# configure script. It will create shell variables for most of +# the configuration options discovered by the configure script. +# This script is intended to be included by the configure scripts +# for tkblt extensions so that they don't have to figure this all +# out for themselves. This file does not duplicate information +# already provided by tclConfig.sh, so you may need to use that +# file in addition to this one. +# +# The information in this file is specific to a single platform. + +# tkblt's version number. +tkblt_VERSION='@PACKAGE_VERSION@' + +# The name of the tkblt library (may be either a .a file or a shared library): +tkblt_LIB_FILE=@PKG_LIB_FILE@ + +# String to pass to linker to pick up the tkblt library from its +# build directory. +tkblt_BUILD_LIB_SPEC='@tkblt_BUILD_LIB_SPEC@' + +# String to pass to linker to pick up the tkblt library from its +# installed directory. +tkblt_LIB_SPEC='@tkblt_LIB_SPEC@' + +# The name of the tkblt stub library (a .a file): +tkblt_STUB_LIB_FILE=@PKG_STUB_LIB_FILE@ + +# String to pass to linker to pick up the tkblt stub library from its +# build directory. +tkblt_BUILD_STUB_LIB_SPEC='@tkblt_BUILD_STUB_LIB_SPEC@' + +# String to pass to linker to pick up the tkblt stub library from its +# installed directory. +tkblt_STUB_LIB_SPEC='@tkblt_STUB_LIB_SPEC@' + +# String to pass to linker to pick up the tkblt stub library from its +# build directory. +tkblt_BUILD_STUB_LIB_PATH='@tkblt_BUILD_STUB_LIB_PATH@' + +# String to pass to linker to pick up the tkblt stub library from its +# installed directory. +tkblt_STUB_LIB_PATH='@tkblt_STUB_LIB_PATH@' diff --git a/tools/genStubs.tcl b/tools/genStubs.tcl new file mode 100644 index 0000000..7a75dc6 --- /dev/null +++ b/tools/genStubs.tcl @@ -0,0 +1,1179 @@ +# genStubs.tcl -- +# +# This script generates a set of stub files for a given +# interface. +# +# +# Copyright (c) 1998-1999 by Scriptics Corporation. +# Copyright (c) 2007 Daniel A. Steffen +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. + +package require Tcl 8.4 + +namespace eval genStubs { + # libraryName -- + # + # The name of the entire library. This value is used to compute + # the USE_*_STUBS macro and the name of the init file. + + variable libraryName "UNKNOWN" + + # interfaces -- + # + # An array indexed by interface name that is used to maintain + # the set of valid interfaces. The value is empty. + + array set interfaces {} + + # curName -- + # + # The name of the interface currently being defined. + + variable curName "UNKNOWN" + + # scspec -- + # + # Storage class specifier for external function declarations. + # Normally "EXTERN", may be set to something like XYZAPI + # + variable scspec "EXTERN" + + # epoch, revision -- + # + # The epoch and revision numbers of the interface currently being defined. + # (@@@TODO: should be an array mapping interface names -> numbers) + # + + variable epoch {} + variable revision 0 + + # hooks -- + # + # An array indexed by interface name that contains the set of + # subinterfaces that should be defined for a given interface. + + array set hooks {} + + # stubs -- + # + # This three dimensional array is indexed first by interface name, + # second by platform name, and third by a numeric offset or the + # constant "lastNum". The lastNum entry contains the largest + # numeric offset used for a given interface/platform combo. Each + # numeric offset contains the C function specification that + # should be used for the given entry in the stub table. The spec + # consists of a list in the form returned by parseDecl. + + array set stubs {} + + # outDir -- + # + # The directory where the generated files should be placed. + + variable outDir . +} + +# genStubs::library -- +# +# This function is used in the declarations file to set the name +# of the library that the interfaces are associated with (e.g. "tcl"). +# This value will be used to define the inline conditional macro. +# +# Arguments: +# name The library name. +# +# Results: +# None. + +proc genStubs::library {name} { + variable libraryName $name +} + +# genStubs::interface -- +# +# This function is used in the declarations file to set the name +# of the interface currently being defined. +# +# Arguments: +# name The name of the interface. +# +# Results: +# None. + +proc genStubs::interface {name} { + variable curName $name + variable interfaces + + set interfaces($name) {} + return +} + +# genStubs::scspec -- +# +# Define the storage class macro used for external function declarations. +# Typically, this will be a macro like XYZAPI or EXTERN that +# expands to either DLLIMPORT or DLLEXPORT, depending on whether +# -DBUILD_XYZ has been set. +# +proc genStubs::scspec {value} { + variable scspec $value +} + +# genStubs::epoch -- +# +# Define the epoch number for this library. The epoch +# should be incrememented when a release is made that +# contains incompatible changes to the public API. +# +proc genStubs::epoch {value} { + variable epoch $value +} + +# genStubs::hooks -- +# +# This function defines the subinterface hooks for the current +# interface. +# +# Arguments: +# names The ordered list of interfaces that are reachable through the +# hook vector. +# +# Results: +# None. + +proc genStubs::hooks {names} { + variable curName + variable hooks + + set hooks($curName) $names + return +} + +# genStubs::declare -- +# +# This function is used in the declarations file to declare a new +# interface entry. +# +# Arguments: +# index The index number of the interface. +# platform The platform the interface belongs to. Should be one +# of generic, win, unix, or macosx or aqua or x11. +# decl The C function declaration, or {} for an undefined +# entry. +# +# Results: +# None. + +proc genStubs::declare {args} { + variable stubs + variable curName + variable revision + + incr revision + if {[llength $args] == 2} { + lassign $args index decl + set platformList generic + } elseif {[llength $args] == 3} { + lassign $args index platformList decl + } else { + puts stderr "wrong # args: declare $args" + return + } + + # Check for duplicate declarations, then add the declaration and + # bump the lastNum counter if necessary. + + foreach platform $platformList { + if {[info exists stubs($curName,$platform,$index)]} { + puts stderr "Duplicate entry: declare $args" + } + } + regsub -all "\[ \t\n\]+" [string trim $decl] " " decl + set decl [parseDecl $decl] + + foreach platform $platformList { + if {$decl ne ""} { + set stubs($curName,$platform,$index) $decl + if {![info exists stubs($curName,$platform,lastNum)] \ + || ($index > $stubs($curName,$platform,lastNum))} { + set stubs($curName,$platform,lastNum) $index + } + } + } + return +} + +# genStubs::export -- +# +# This function is used in the declarations file to declare a symbol +# that is exported from the library but is not in the stubs table. +# +# Arguments: +# decl The C function declaration, or {} for an undefined +# entry. +# +# Results: +# None. + +proc genStubs::export {args} { + if {[llength $args] != 1} { + puts stderr "wrong # args: export $args" + } + return +} + +# genStubs::rewriteFile -- +# +# This function replaces the machine generated portion of the +# specified file with new contents. It looks for the !BEGIN! and +# !END! comments to determine where to place the new text. +# +# Arguments: +# file The name of the file to modify. +# text The new text to place in the file. +# +# Results: +# None. + +proc genStubs::rewriteFile {file text} { + if {![file exists $file]} { + puts stderr "Cannot find file: $file" + return + } + set in [open ${file} r] + set out [open ${file}.new w] + fconfigure $out -translation lf + + while {![eof $in]} { + set line [gets $in] + if {[string match "*!BEGIN!*" $line]} { + break + } + puts $out $line + } + puts $out "/* !BEGIN!: Do not edit below this line. */" + puts $out $text + while {![eof $in]} { + set line [gets $in] + if {[string match "*!END!*" $line]} { + break + } + } + puts $out "/* !END!: Do not edit above this line. */" + puts -nonewline $out [read $in] + close $in + close $out + file rename -force ${file}.new ${file} + return +} + +# genStubs::addPlatformGuard -- +# +# Wrap a string inside a platform #ifdef. +# +# Arguments: +# plat Platform to test. +# +# Results: +# Returns the original text inside an appropriate #ifdef. + +proc genStubs::addPlatformGuard {plat iftxt {eltxt {}} {withCygwin 0}} { + set text "" + switch $plat { + win { + append text "#if defined(_WIN32)" + if {$withCygwin} { + append text " || defined(__CYGWIN__)" + } + append text " /* WIN */\n${iftxt}" + if {$eltxt ne ""} { + append text "#else /* WIN */\n${eltxt}" + } + append text "#endif /* WIN */\n" + } + unix { + append text "#if !defined(_WIN32)" + if {$withCygwin} { + append text " && !defined(__CYGWIN__)" + } + append text " && !defined(MAC_OSX_TCL)\ + /* UNIX */\n${iftxt}" + if {$eltxt ne ""} { + append text "#else /* UNIX */\n${eltxt}" + } + append text "#endif /* UNIX */\n" + } + macosx { + append text "#ifdef MAC_OSX_TCL /* MACOSX */\n${iftxt}" + if {$eltxt ne ""} { + append text "#else /* MACOSX */\n${eltxt}" + } + append text "#endif /* MACOSX */\n" + } + aqua { + append text "#ifdef MAC_OSX_TK /* AQUA */\n${iftxt}" + if {$eltxt ne ""} { + append text "#else /* AQUA */\n${eltxt}" + } + append text "#endif /* AQUA */\n" + } + x11 { + append text "#if !(defined(_WIN32)" + if {$withCygwin} { + append text " || defined(__CYGWIN__)" + } + append text " || defined(MAC_OSX_TK))\ + /* X11 */\n${iftxt}" + if {$eltxt ne ""} { + append text "#else /* X11 */\n${eltxt}" + } + append text "#endif /* X11 */\n" + } + default { + append text "${iftxt}${eltxt}" + } + } + return $text +} + +# genStubs::emitSlots -- +# +# Generate the stub table slots for the given interface. If there +# are no generic slots, then one table is generated for each +# platform, otherwise one table is generated for all platforms. +# +# Arguments: +# name The name of the interface being emitted. +# textVar The variable to use for output. +# +# Results: +# None. + +proc genStubs::emitSlots {name textVar} { + upvar $textVar text + + forAllStubs $name makeSlot 1 text {" void (*reserved$i)(void);\n"} + return +} + +# genStubs::parseDecl -- +# +# Parse a C function declaration into its component parts. +# +# Arguments: +# decl The function declaration. +# +# Results: +# Returns a list of the form {returnType name args}. The args +# element consists of a list of type/name pairs, or a single +# element "void". If the function declaration is malformed +# then an error is displayed and the return value is {}. + +proc genStubs::parseDecl {decl} { + if {![regexp {^(.*)\((.*)\)$} $decl all prefix args]} { + set prefix $decl + set args {} + } + set prefix [string trim $prefix] + if {![regexp {^(.+[ ][*]*)([^ *]+)$} $prefix all rtype fname]} { + puts stderr "Bad return type: $decl" + return + } + set rtype [string trim $rtype] + if {$args eq ""} { + return [list $rtype $fname {}] + } + foreach arg [split $args ,] { + lappend argList [string trim $arg] + } + if {![string compare [lindex $argList end] "..."]} { + set args TCL_VARARGS + foreach arg [lrange $argList 0 end-1] { + set argInfo [parseArg $arg] + if {[llength $argInfo] == 2 || [llength $argInfo] == 3} { + lappend args $argInfo + } else { + puts stderr "Bad argument: '$arg' in '$decl'" + return + } + } + } else { + set args {} + foreach arg $argList { + set argInfo [parseArg $arg] + if {![string compare $argInfo "void"]} { + lappend args "void" + break + } elseif {[llength $argInfo] == 2 || [llength $argInfo] == 3} { + lappend args $argInfo + } else { + puts stderr "Bad argument: '$arg' in '$decl'" + return + } + } + } + return [list $rtype $fname $args] +} + +# genStubs::parseArg -- +# +# This function parses a function argument into a type and name. +# +# Arguments: +# arg The argument to parse. +# +# Results: +# Returns a list of type and name with an optional third array +# indicator. If the argument is malformed, returns "". + +proc genStubs::parseArg {arg} { + if {![regexp {^(.+[ ][*]*)([^][ *]+)(\[\])?$} $arg all type name array]} { + if {$arg eq "void"} { + return $arg + } else { + return + } + } + set result [list [string trim $type] $name] + if {$array ne ""} { + lappend result $array + } + return $result +} + +# genStubs::makeDecl -- +# +# Generate the prototype for a function. +# +# Arguments: +# name The interface name. +# decl The function declaration. +# index The slot index for this function. +# +# Results: +# Returns the formatted declaration string. + +proc genStubs::makeDecl {name decl index} { + variable scspec + lassign $decl rtype fname args + + append text "/* $index */\n" + set line "$scspec $rtype" + set count [expr {2 - ([string length $line] / 8)}] + append line [string range "\t\t\t" 0 $count] + set pad [expr {24 - [string length $line]}] + if {$pad <= 0} { + append line " " + set pad 0 + } + if {$args eq ""} { + append line $fname + append text $line + append text ";\n" + return $text + } + append line $fname + + set arg1 [lindex $args 0] + switch -exact $arg1 { + void { + append line "(void)" + } + TCL_VARARGS { + set sep "(" + foreach arg [lrange $args 1 end] { + append line $sep + set next {} + append next [lindex $arg 0] + if {[string index $next end] ne "*"} { + append next " " + } + append next [lindex $arg 1] [lindex $arg 2] + if {[string length $line] + [string length $next] \ + + $pad > 76} { + append text [string trimright $line] \n + set line "\t\t\t\t" + set pad 28 + } + append line $next + set sep ", " + } + append line ", ...)" + if {[lindex $args end] eq "{const char *} format"} { + append line " TCL_FORMAT_PRINTF(" [expr [llength $args] - 1] ", " [llength $args] ")" + } + } + default { + set sep "(" + foreach arg $args { + append line $sep + set next {} + append next [lindex $arg 0] + if {[string index $next end] ne "*"} { + append next " " + } + append next [lindex $arg 1] [lindex $arg 2] + if {[string length $line] + [string length $next] \ + + $pad > 76} { + append text [string trimright $line] \n + set line "\t\t\t\t" + set pad 28 + } + append line $next + set sep ", " + } + append line ")" + } + } + return "$text$line;\n" +} + +# genStubs::makeMacro -- +# +# Generate the inline macro for a function. +# +# Arguments: +# name The interface name. +# decl The function declaration. +# index The slot index for this function. +# +# Results: +# Returns the formatted macro definition. + +proc genStubs::makeMacro {name decl index} { + lassign $decl rtype fname args + + set lfname [string tolower [string index $fname 0]] + append lfname [string range $fname 1 end] + + set text "#define $fname \\\n\t(" + if {$args eq ""} { + append text "*" + } + append text "${name}StubsPtr->$lfname)" + append text " /* $index */\n" + return $text +} + +# genStubs::makeSlot -- +# +# Generate the stub table entry for a function. +# +# Arguments: +# name The interface name. +# decl The function declaration. +# index The slot index for this function. +# +# Results: +# Returns the formatted table entry. + +proc genStubs::makeSlot {name decl index} { + lassign $decl rtype fname args + + set lfname [string tolower [string index $fname 0]] + append lfname [string range $fname 1 end] + + set text " " + if {$args eq ""} { + append text $rtype " *" $lfname "; /* $index */\n" + return $text + } + if {[string range $rtype end-8 end] eq "__stdcall"} { + append text [string trim [string range $rtype 0 end-9]] " (__stdcall *" $lfname ") " + } else { + append text $rtype " (*" $lfname ") " + } + set arg1 [lindex $args 0] + switch -exact $arg1 { + void { + append text "(void)" + } + TCL_VARARGS { + set sep "(" + foreach arg [lrange $args 1 end] { + append text $sep [lindex $arg 0] + if {[string index $text end] ne "*"} { + append text " " + } + append text [lindex $arg 1] [lindex $arg 2] + set sep ", " + } + append text ", ...)" + if {[lindex $args end] eq "{const char *} format"} { + append text " TCL_FORMAT_PRINTF(" [expr [llength $args] - 1] ", " [llength $args] ")" + } + } + default { + set sep "(" + foreach arg $args { + append text $sep [lindex $arg 0] + if {[string index $text end] ne "*"} { + append text " " + } + append text [lindex $arg 1] [lindex $arg 2] + set sep ", " + } + append text ")" + } + } + + append text "; /* $index */\n" + return $text +} + +# genStubs::makeInit -- +# +# Generate the prototype for a function. +# +# Arguments: +# name The interface name. +# decl The function declaration. +# index The slot index for this function. +# +# Results: +# Returns the formatted declaration string. + +proc genStubs::makeInit {name decl index} { + if {[lindex $decl 2] eq ""} { + append text " &" [lindex $decl 1] ", /* " $index " */\n" + } else { + append text " " [lindex $decl 1] ", /* " $index " */\n" + } + return $text +} + +# genStubs::forAllStubs -- +# +# This function iterates over all of the platforms and invokes +# a callback for each slot. The result of the callback is then +# placed inside appropriate platform guards. +# +# Arguments: +# name The interface name. +# slotProc The proc to invoke to handle the slot. It will +# have the interface name, the declaration, and +# the index appended. +# onAll If 1, emit the skip string even if there are +# definitions for one or more platforms. +# textVar The variable to use for output. +# skipString The string to emit if a slot is skipped. This +# string will be subst'ed in the loop so "$i" can +# be used to substitute the index value. +# +# Results: +# None. + +proc genStubs::forAllStubs {name slotProc onAll textVar + {skipString {"/* Slot $i is reserved */\n"}}} { + variable stubs + upvar $textVar text + + set plats [array names stubs $name,*,lastNum] + if {[info exists stubs($name,generic,lastNum)]} { + # Emit integrated stubs block + set lastNum -1 + foreach plat [array names stubs $name,*,lastNum] { + if {$stubs($plat) > $lastNum} { + set lastNum $stubs($plat) + } + } + for {set i 0} {$i <= $lastNum} {incr i} { + set slots [array names stubs $name,*,$i] + set emit 0 + if {[info exists stubs($name,generic,$i)]} { + if {[llength $slots] > 1} { + puts stderr "conflicting generic and platform entries:\ + $name $i" + } + append text [$slotProc $name $stubs($name,generic,$i) $i] + set emit 1 + } elseif {[llength $slots] > 0} { + array set slot {unix 0 x11 0 win 0 macosx 0 aqua 0} + foreach s $slots { + set slot([lindex [split $s ,] 1]) 1 + } + # "aqua", "macosx" and "x11" are special cases: + # "macosx" implies "unix", "aqua" implies "macosx" and "x11" + # implies "unix", so we need to be careful not to emit + # duplicate stubs entries: + if {($slot(unix) && $slot(macosx)) || ( + ($slot(unix) || $slot(macosx)) && + ($slot(x11) || $slot(aqua)))} { + puts stderr "conflicting platform entries: $name $i" + } + ## unix ## + set temp {} + set plat unix + if {!$slot(aqua) && !$slot(x11)} { + if {$slot($plat)} { + append temp [$slotProc $name $stubs($name,$plat,$i) $i] + } elseif {$onAll} { + eval {append temp} $skipString + } + } + if {$temp ne ""} { + append text [addPlatformGuard $plat $temp] + set emit 1 + } + ## x11 ## + set temp {} + set plat x11 + if {!$slot(unix) && !$slot(macosx)} { + if {$slot($plat)} { + append temp [$slotProc $name $stubs($name,$plat,$i) $i] + } elseif {$onAll} { + eval {append temp} $skipString + } + } + if {$temp ne ""} { + append text [addPlatformGuard $plat $temp] + set emit 1 + } + ## win ## + set temp {} + set plat win + if {$slot($plat)} { + append temp [$slotProc $name $stubs($name,$plat,$i) $i] + } elseif {$onAll} { + eval {append temp} $skipString + } + if {$temp ne ""} { + append text [addPlatformGuard $plat $temp] + set emit 1 + } + ## macosx ## + set temp {} + set plat macosx + if {!$slot(aqua) && !$slot(x11)} { + if {$slot($plat)} { + append temp [$slotProc $name $stubs($name,$plat,$i) $i] + } elseif {$slot(unix)} { + append temp [$slotProc $name $stubs($name,unix,$i) $i] + } elseif {$onAll} { + eval {append temp} $skipString + } + } + if {$temp ne ""} { + append text [addPlatformGuard $plat $temp] + set emit 1 + } + ## aqua ## + set temp {} + set plat aqua + if {!$slot(unix) && !$slot(macosx)} { + if {[string range $skipString 1 2] ne "/*"} { + # genStubs.tcl previously had a bug here causing it to + # erroneously generate both a unix entry and an aqua + # entry for a given stubs table slot. To preserve + # backwards compatibility, generate a dummy stubs entry + # before every aqua entry (note that this breaks the + # correspondence between emitted entry number and + # actual position of the entry in the stubs table, e.g. + # TkIntStubs entry 113 for aqua is in fact at position + # 114 in the table, entry 114 at position 116 etc). + eval {append temp} $skipString + set temp "[string range $temp 0 end-1] /*\ + Dummy entry for stubs table backwards\ + compatibility */\n" + } + if {$slot($plat)} { + append temp [$slotProc $name $stubs($name,$plat,$i) $i] + } elseif {$onAll} { + eval {append temp} $skipString + } + } + if {$temp ne ""} { + append text [addPlatformGuard $plat $temp] + set emit 1 + } + } + if {!$emit} { + eval {append text} $skipString + } + } + } else { + # Emit separate stubs blocks per platform + array set block {unix 0 x11 0 win 0 macosx 0 aqua 0} + foreach s [array names stubs $name,*,lastNum] { + set block([lindex [split $s ,] 1]) 1 + } + ## unix ## + if {$block(unix) && !$block(x11)} { + set temp {} + set plat unix + set lastNum $stubs($name,$plat,lastNum) + for {set i 0} {$i <= $lastNum} {incr i} { + if {[info exists stubs($name,$plat,$i)]} { + append temp [$slotProc $name $stubs($name,$plat,$i) $i] + } else { + eval {append temp} $skipString + } + } + append text [addPlatformGuard $plat $temp {} true] + } + ## win ## + if {$block(win)} { + set temp {} + set plat win + set lastNum $stubs($name,$plat,lastNum) + for {set i 0} {$i <= $lastNum} {incr i} { + if {[info exists stubs($name,$plat,$i)]} { + append temp [$slotProc $name $stubs($name,$plat,$i) $i] + } else { + eval {append temp} $skipString + } + } + append text [addPlatformGuard $plat $temp {} true] + } + ## macosx ## + if {($block(unix) || $block(macosx)) && !$block(aqua) && !$block(x11)} { + set temp {} + set lastNum -1 + foreach plat {unix macosx} { + if {$block($plat)} { + set lastNum [expr {$lastNum > $stubs($name,$plat,lastNum) + ? $lastNum : $stubs($name,$plat,lastNum)}] + } + } + for {set i 0} {$i <= $lastNum} {incr i} { + set emit 0 + foreach plat {unix macosx} { + if {[info exists stubs($name,$plat,$i)]} { + append temp [$slotProc $name $stubs($name,$plat,$i) $i] + set emit 1 + break + } + } + if {!$emit} { + eval {append temp} $skipString + } + } + append text [addPlatformGuard macosx $temp] + } + ## aqua ## + if {$block(aqua)} { + set temp {} + set lastNum -1 + foreach plat {unix macosx aqua} { + if {$block($plat)} { + set lastNum [expr {$lastNum > $stubs($name,$plat,lastNum) + ? $lastNum : $stubs($name,$plat,lastNum)}] + } + } + for {set i 0} {$i <= $lastNum} {incr i} { + set emit 0 + foreach plat {unix macosx aqua} { + if {[info exists stubs($name,$plat,$i)]} { + append temp [$slotProc $name $stubs($name,$plat,$i) $i] + set emit 1 + break + } + } + if {!$emit} { + eval {append temp} $skipString + } + } + append text [addPlatformGuard aqua $temp] + } + ## x11 ## + if {$block(x11)} { + set temp {} + set lastNum -1 + foreach plat {unix macosx x11} { + if {$block($plat)} { + set lastNum [expr {$lastNum > $stubs($name,$plat,lastNum) + ? $lastNum : $stubs($name,$plat,lastNum)}] + } + } + for {set i 0} {$i <= $lastNum} {incr i} { + set emit 0 + foreach plat {unix macosx x11} { + if {[info exists stubs($name,$plat,$i)]} { + if {$plat ne "macosx"} { + append temp [$slotProc $name \ + $stubs($name,$plat,$i) $i] + } else { + eval {set etxt} $skipString + append temp [addPlatformGuard $plat [$slotProc \ + $name $stubs($name,$plat,$i) $i] $etxt true] + } + set emit 1 + break + } + } + if {!$emit} { + eval {append temp} $skipString + } + } + append text [addPlatformGuard x11 $temp {} true] + } + } +} + +# genStubs::emitDeclarations -- +# +# This function emits the function declarations for this interface. +# +# Arguments: +# name The interface name. +# textVar The variable to use for output. +# +# Results: +# None. + +proc genStubs::emitDeclarations {name textVar} { + upvar $textVar text + + append text "\n/*\n * Exported function declarations:\n */\n\n" + forAllStubs $name makeDecl 0 text + return +} + +# genStubs::emitMacros -- +# +# This function emits the inline macros for an interface. +# +# Arguments: +# name The name of the interface being emitted. +# textVar The variable to use for output. +# +# Results: +# None. + +proc genStubs::emitMacros {name textVar} { + variable libraryName + upvar $textVar text + + set upName [string toupper $libraryName] + append text "\n#if defined(USE_${upName}_STUBS)\n" + append text "\n/*\n * Inline function declarations:\n */\n\n" + + forAllStubs $name makeMacro 0 text + + append text "\n#endif /* defined(USE_${upName}_STUBS) */\n" + return +} + +# genStubs::emitHeader -- +# +# This function emits the body of the Decls.h file for +# the specified interface. +# +# Arguments: +# name The name of the interface being emitted. +# +# Results: +# None. + +proc genStubs::emitHeader {name} { + variable outDir + variable hooks + variable epoch + variable revision + + set capName [string toupper [string index $name 0]] + append capName [string range $name 1 end] + + if {$epoch ne ""} { + set CAPName [string toupper $name] + append text "\n" + append text "#define ${CAPName}_STUBS_EPOCH $epoch\n" + append text "#define ${CAPName}_STUBS_REVISION $revision\n" + } + + append text "\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n" + + emitDeclarations $name text + + if {[info exists hooks($name)]} { + append text "\ntypedef struct {\n" + foreach hook $hooks($name) { + set capHook [string toupper [string index $hook 0]] + append capHook [string range $hook 1 end] + append text " const struct ${capHook}Stubs *${hook}Stubs;\n" + } + append text "} ${capName}StubHooks;\n" + } + append text "\ntypedef struct ${capName}Stubs {\n" + append text " int magic;\n" + if {$epoch ne ""} { + append text " int epoch;\n" + append text " int revision;\n" + } + if {[info exists hooks($name)]} { + append text " const ${capName}StubHooks *hooks;\n\n" + } else { + append text " void *hooks;\n\n" + } + + emitSlots $name text + + append text "} ${capName}Stubs;\n\n" + + append text "extern const ${capName}Stubs *${name}StubsPtr;\n\n" + append text "#ifdef __cplusplus\n}\n#endif\n" + + emitMacros $name text + + rewriteFile [file join $outDir ${name}Decls.h] $text + return +} + +# genStubs::emitInit -- +# +# Generate the table initializers for an interface. +# +# Arguments: +# name The name of the interface to initialize. +# textVar The variable to use for output. +# +# Results: +# Returns the formatted output. + +proc genStubs::emitInit {name textVar} { + variable hooks + variable interfaces + variable epoch + upvar $textVar text + set root 1 + + set capName [string toupper [string index $name 0]] + append capName [string range $name 1 end] + + if {[info exists hooks($name)]} { + append text "\nstatic const ${capName}StubHooks ${name}StubHooks = \{\n" + set sep " " + foreach sub $hooks($name) { + append text $sep "&${sub}Stubs" + set sep ",\n " + } + append text "\n\};\n" + } + foreach intf [array names interfaces] { + if {[info exists hooks($intf)]} { + if {[lsearch -exact $hooks($intf) $name] >= 0} { + set root 0 + break + } + } + } + + append text "\n" + if {!$root} { + append text "static " + } + append text "const ${capName}Stubs ${name}Stubs = \{\n TCL_STUB_MAGIC,\n" + if {$epoch ne ""} { + set CAPName [string toupper $name] + append text " ${CAPName}_STUBS_EPOCH,\n" + append text " ${CAPName}_STUBS_REVISION,\n" + } + if {[info exists hooks($name)]} { + append text " &${name}StubHooks,\n" + } else { + append text " 0,\n" + } + + forAllStubs $name makeInit 1 text {" 0, /* $i */\n"} + + append text "\};\n" + return +} + +# genStubs::emitInits -- +# +# This function emits the body of the StubInit.c file for +# the specified interface. +# +# Arguments: +# name The name of the interface being emitted. +# +# Results: +# None. + +proc genStubs::emitInits {} { + variable hooks + variable outDir + variable libraryName + variable interfaces + + # Assuming that dependencies only go one level deep, we need to emit + # all of the leaves first to avoid needing forward declarations. + + set leaves {} + set roots {} + foreach name [lsort [array names interfaces]] { + if {[info exists hooks($name)]} { + lappend roots $name + } else { + lappend leaves $name + } + } + foreach name $leaves { + emitInit $name text + } + foreach name $roots { + emitInit $name text + } + + rewriteFile [file join $outDir ${libraryName}StubInit.c] $text +} + +# genStubs::init -- +# +# This is the main entry point. +# +# Arguments: +# None. +# +# Results: +# None. + +proc genStubs::init {} { + global argv argv0 + variable outDir + variable interfaces + + if {[llength $argv] < 2} { + puts stderr "usage: $argv0 outDir declFile ?declFile...?" + exit 1 + } + + set outDir [lindex $argv 0] + + foreach file [lrange $argv 1 end] { + source $file + } + + foreach name [lsort [array names interfaces]] { + puts "Emitting $name" + emitHeader $name + } + + emitInits +} + +# lassign -- +# +# This function emulates the TclX lassign command. +# +# Arguments: +# valueList A list containing the values to be assigned. +# args The list of variables to be assigned. +# +# Results: +# Returns any values that were not assigned to variables. + +if {[string length [namespace which lassign]] == 0} { + proc lassign {valueList args} { + if {[llength $args] == 0} { + error "wrong # args: should be \"lassign list varName ?varName ...?\"" + } + uplevel [list foreach $args $valueList {break}] + return [lrange $valueList [llength $args] end] + } +} + +genStubs::init -- cgit v0.12