pax_global_header00006660000000000000000000000064135767677020014536gustar00rootroot0000000000000052 comment=a266a2e815802331387f666c4c53c8891bfb9403 tkblt-3.2.21/000077500000000000000000000000001357676770200127435ustar00rootroot00000000000000tkblt-3.2.21/.gitignore000066400000000000000000000003661357676770200147400ustar00rootroot00000000000000# 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 *~ tkblt-3.2.21/LICENSE000066400000000000000000000023061357676770200137510ustar00rootroot00000000000000Smithsonian 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. tkblt-3.2.21/Makefile.in000066400000000000000000000416551357676770200150230ustar00rootroot00000000000000# 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@ CXX = @CXX@ 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@ CXXFLAGS = @CXXFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS_DEFAULT) $(CFLAGS_WARNING) $(SHLIB_CFLAGS) $(CFLAGS) COMPILE_CXX = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS_DEFAULT) $(CFLAGS_WARNING) $(SHLIB_CFLAGS) $(CXXFLAGS) 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_CXX) -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 *.$(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: tkblt-3.2.21/README.md000066400000000000000000000025731357676770200142310ustar00rootroot00000000000000[![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. tkblt-3.2.21/aclocal.m4000066400000000000000000000002231357676770200146000ustar00rootroot00000000000000# # Include the TEA standard macro set # builtin(include,tclconfig/tcl.m4) # # Add here whatever m4 macros you want to define for your package # tkblt-3.2.21/configure000077500000000000000000011163641357676770200146660ustar00rootroot00000000000000#! /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 ac_ct_CXX CXXFLAGS CXX 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 runstatedir 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 CXX CXXFLAGS CCC 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' runstatedir='${localstatedir}/run' 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 ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -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 runstatedir 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] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --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 CXX C++ compiler command CXXFLAGS C++ compiler flags 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_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_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_cxx_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_cxx_try_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 if test "${TEA_PLATFORM}" != "windows" ; then ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC 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_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # 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_CXX="$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 CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC 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_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # 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_CXX="$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_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" 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 CXX=$ac_ct_CXX fi fi fi fi # 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_cxx_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_cxx_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_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if ${ac_cv_prog_cxx_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes else CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_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_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= 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 fi #----------------------------------------------------------------------- # __CHANGE__ # Specify the C source files to compile in TEA_ADD_SOURCES, # public headers that need to be installed in TEA_ADD_HEADERS, # stub library C source files to compile in TEA_ADD_STUB_SOURCES, # and runtime Tcl library files in TEA_ADD_TCL_SOURCES. # This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS # and PKG_TCL_SOURCES. #----------------------------------------------------------------------- vars=" 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 if test "${TEA_PLATFORM}" = "windows" ; then CXX="$CC" CXXFLAGS="$CFLAGS" 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 tkblt-3.2.21/configure.ac000066400000000000000000000207011357676770200152310ustar00rootroot00000000000000#!/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 if test "${TEA_PLATFORM}" != "windows" ; then AC_PROG_CXX fi #----------------------------------------------------------------------- # __CHANGE__ # Specify the C source files to compile in TEA_ADD_SOURCES, # public headers that need to be installed in TEA_ADD_HEADERS, # stub library C source files to compile in TEA_ADD_STUB_SOURCES, # and runtime Tcl library files in TEA_ADD_TCL_SOURCES. # This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS # and PKG_TCL_SOURCES. #----------------------------------------------------------------------- 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 if test "${TEA_PLATFORM}" = "windows" ; then CXX="$CC" CXXFLAGS="$CFLAGS" fi #-------------------------------------------------------------------- # 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() tkblt-3.2.21/doc/000077500000000000000000000000001357676770200135105ustar00rootroot00000000000000tkblt-3.2.21/doc/BLT.html000066400000000000000000000044171357676770200150250ustar00rootroot00000000000000


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
tkblt-3.2.21/doc/BLT.n000066400000000000000000000057651357676770200143250ustar00rootroot00000000000000'\" '\" 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 tkblt-3.2.21/doc/barchart.html000066400000000000000000002726141357676770200162000ustar00rootroot00000000000000


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
tkblt-3.2.21/doc/barchart.n000066400000000000000000002734671357676770200155000ustar00rootroot00000000000000'\" '\" 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 tkblt-3.2.21/doc/graph.html000066400000000000000000003105151357676770200155040ustar00rootroot00000000000000


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
tkblt-3.2.21/doc/graph.n000066400000000000000000003122131357676770200147720ustar00rootroot00000000000000'\" '\" 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 tkblt-3.2.21/doc/vector.html000066400000000000000000001116151357676770200157050ustar00rootroot00000000000000


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
tkblt-3.2.21/doc/vector.n000066400000000000000000001144141357676770200151760ustar00rootroot00000000000000'\" '\" 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 tkblt-3.2.21/generic/000077500000000000000000000000001357676770200143575ustar00rootroot00000000000000tkblt-3.2.21/generic/tkblt.decls000066400000000000000000000037761357676770200165300ustar00rootroot00000000000000library 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) } tkblt-3.2.21/generic/tkbltChain.C000066400000000000000000000100001357676770200165350ustar00rootroot00000000000000/* * 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; } tkblt-3.2.21/generic/tkbltChain.h000066400000000000000000000051521357676770200166160ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltConfig.C000066400000000000000000000136341357676770200167400ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltDecls.h000066400000000000000000000132171357676770200166270ustar00rootroot00000000000000/* !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. */ tkblt-3.2.21/generic/tkbltGrAxis.C000066400000000000000000001526741357676770200167400ustar00rootroot00000000000000/* * 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 != 0.0)) { 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 != 0.0)) { 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; } tkblt-3.2.21/generic/tkbltGrAxis.h000066400000000000000000000135031357676770200167700ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrAxisOp.C000066400000000000000000000434031357676770200172240ustar00rootroot00000000000000/* * 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; default: return TCL_OK; } } 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; } tkblt-3.2.21/generic/tkbltGrAxisOp.h000066400000000000000000000047251357676770200172750ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrAxisOption.C000066400000000000000000000157171357676770200201250ustar00rootroot00000000000000/* * 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); } tkblt-3.2.21/generic/tkbltGrAxisOption.h000066400000000000000000000031001357676770200201510ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrBind.C000066400000000000000000000142211357676770200166710ustar00rootroot00000000000000/* * 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_); } tkblt-3.2.21/generic/tkbltGrBind.h000066400000000000000000000040321357676770200167350ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrDef.h000066400000000000000000000033241357676770200165620ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrElem.C000066400000000000000000000145041357676770200167030ustar00rootroot00000000000000/* * 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); } } } tkblt-3.2.21/generic/tkbltGrElem.h000066400000000000000000000112511357676770200167440ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrElemBar.C000066400000000000000000001155131357676770200173320ustar00rootroot00000000000000/* * 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); } } tkblt-3.2.21/generic/tkbltGrElemBar.h000066400000000000000000000067651357676770200174070ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrElemLine.C000066400000000000000000002173601357676770200175200ustar00rootroot00000000000000/* * 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; } } #define CLIP_TOP (1<<0) #define CLIP_BOTTOM (1<<1) #define CLIP_RIGHT (1<<2) #define CLIP_LEFT (1<<3) int LineElement::outCode(Region2d *extsPtr, Point2d *p) { int code =0; if (p->x > extsPtr->right) code |= CLIP_RIGHT; else if (p->x < extsPtr->left) code |= CLIP_LEFT; if (p->y > extsPtr->bottom) code |= CLIP_BOTTOM; else if (p->y < extsPtr->top) code |= CLIP_TOP; return code; } int LineElement::clipSegment(Region2d *extsPtr, int code1, int code2, Point2d *p, Point2d *q) { int inside = ((code1 | code2) == 0); int outside = ((code1 & code2) != 0); /* * In the worst case, we'll clip the line segment against each of the four * sides of the bounding rectangle. */ while ((!outside) && (!inside)) { if (code1 == 0) { Point2d *tmp; int code; /* Swap pointers and out codes */ tmp = p, p = q, q = tmp; code = code1, code1 = code2, code2 = code; } if (code1 & CLIP_LEFT) { p->y += (q->y - p->y) * (extsPtr->left - p->x) / (q->x - p->x); p->x = extsPtr->left; } else if (code1 & CLIP_RIGHT) { p->y += (q->y - p->y) * (extsPtr->right - p->x) / (q->x - p->x); p->x = extsPtr->right; } else if (code1 & CLIP_BOTTOM) { p->x += (q->x - p->x) * (extsPtr->bottom - p->y) / (q->y - p->y); p->y = extsPtr->bottom; } else if (code1 & CLIP_TOP) { p->x += (q->x - p->x) * (extsPtr->top - p->y) / (q->y - p->y); p->y = extsPtr->top; } code1 = outCode(extsPtr, p); inside = ((code1 | code2) == 0); outside = ((code1 & code2) != 0); } return (!inside); } 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; int code1 = outCode(&exts, mapPtr->screenPts); Point2d* p = mapPtr->screenPts; Point2d* q = p + 1; int start; int ii; for (ii=1; iinScreenPts; ii++, p++, q++) { Point2d s; s.x = 0; s.y = 0; int code2 = outCode(&exts, q); // Save the coordinates of the last point, before clipping if (code2 != 0) s = *q; int broken = BROKEN_TRACE(ops->penDir, p->x, q->x); int offscreen = clipSegment(&exts, code1, code2, p, q); if (broken || offscreen) { // 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 (code2 != 0) { start = ii - (count - 1); saveTrace(start, count, mapPtr); mapPtr->screenPts[ii] = s; count = 1; } } code1 = code2; } 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); } } tkblt-3.2.21/generic/tkbltGrElemLine.h000066400000000000000000000127511357676770200175620ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrElemLineSpline.C000066400000000000000000001006361357676770200206700ustar00rootroot00000000000000/* * 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; } tkblt-3.2.21/generic/tkbltGrElemOp.h000066400000000000000000000030361357676770200172450ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrElemOption.C000066400000000000000000000253061357676770200200760ustar00rootroot00000000000000/* * 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; } tkblt-3.2.21/generic/tkbltGrElemOption.h000066400000000000000000000031131357676770200201330ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrHairs.C000066400000000000000000000101111357676770200170550ustar00rootroot00000000000000/* * 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); } } } tkblt-3.2.21/generic/tkbltGrHairs.h000066400000000000000000000037401357676770200171340ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrHairsOp.C000066400000000000000000000104621357676770200173650ustar00rootroot00000000000000/* * 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 } }; tkblt-3.2.21/generic/tkbltGrHairsOp.h000066400000000000000000000026711357676770200174350ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrLegd.C000066400000000000000000000745531357676770200167060ustar00rootroot00000000000000/* * 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); } tkblt-3.2.21/generic/tkbltGrLegd.h000066400000000000000000000110711357676770200167350ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrLegdOp.C000066400000000000000000000336301357676770200171740ustar00rootroot00000000000000/* * 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(); } tkblt-3.2.21/generic/tkbltGrLegdOp.h000066400000000000000000000027271357676770200172440ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrMarker.C000066400000000000000000000111511357676770200172350ustar00rootroot00000000000000/* * 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); } } tkblt-3.2.21/generic/tkbltGrMarker.h000066400000000000000000000053641357676770200173130ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrMarkerLine.C000066400000000000000000000217571357676770200200620ustar00rootroot00000000000000/* * 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_); } } tkblt-3.2.21/generic/tkbltGrMarkerLine.h000066400000000000000000000045021357676770200201140ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrMarkerOp.C000066400000000000000000000334021357676770200175370ustar00rootroot00000000000000/* * 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; } tkblt-3.2.21/generic/tkbltGrMarkerOp.h000066400000000000000000000026601357676770200176060ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrMarkerOption.C000066400000000000000000000136751357676770200204430ustar00rootroot00000000000000/* * 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; } tkblt-3.2.21/generic/tkbltGrMarkerOption.h000066400000000000000000000030741357676770200205000ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrMarkerPolygon.C000066400000000000000000000217271357676770200206170ustar00rootroot00000000000000/* * 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_); } } tkblt-3.2.21/generic/tkbltGrMarkerPolygon.h000066400000000000000000000045171357676770200206620ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrMarkerText.C000066400000000000000000000211221357676770200201010ustar00rootroot00000000000000/* * 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); } tkblt-3.2.21/generic/tkbltGrMarkerText.h000066400000000000000000000043751357676770200201610ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrMisc.C000066400000000000000000000210351357676770200167110ustar00rootroot00000000000000/* * 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" 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); } 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; } if (t > *t1) { *t1 = t; } } else if (ds > 0.0) { t = dr / ds; if (t < *t1) { return 0; } 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. * * Reference: * Liang, Y-D., and B. Barsky, A new concept and method for * Line Clipping, ACM, TOG,3(1), 1984, pp.1-22. *--------------------------------------------------------------------------- */ int Blt::lineRectClip(Region2d* regionPtr, Point2d *p, Point2d *q) { double t1, t2; double dx, dy; 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))) { 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; } if (t1 > 0.0) { p->x += t1 * dx; p->y += t1 * dy; } return 1; } } return 0; } /* *--------------------------------------------------------------------------- * 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; } tkblt-3.2.21/generic/tkbltGrMisc.h000066400000000000000000000060571357676770200167650ustar00rootroot00000000000000/* * 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; 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 int lineRectClip(Region2d *regionPtr, Point2d *p, Point2d *q); extern Point2d getProjection (int x, int y, Point2d *p, Point2d *q); }; #endif tkblt-3.2.21/generic/tkbltGrPSOutput.C000066400000000000000000000656511357676770200175750ustar00rootroot00000000000000/* * 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" " /yy exch def\n" " /xx exch def\n" " /rr 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" " xx yy translate\n" " % Translate to offset\n" " xoffset rr cos mul yoffset rr sin mul add /xxo exch def\n" " xoffset rr sin mul neg yoffset rr cos mul add /yyo exch def\n" " ww xxo mul hh yyo mul translate\n" " % rotate\n" " ww 2 div hh 2 div translate\n" " rr 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" ); } tkblt-3.2.21/generic/tkbltGrPSOutput.h000066400000000000000000000055051357676770200176320ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrPen.C000066400000000000000000000035041357676770200165410ustar00rootroot00000000000000/* * 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_); } tkblt-3.2.21/generic/tkbltGrPen.h000066400000000000000000000042431357676770200166070ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrPenBar.C000066400000000000000000000144411357676770200171700ustar00rootroot00000000000000/* * 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; } tkblt-3.2.21/generic/tkbltGrPenBar.h000066400000000000000000000041071357676770200172330ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrPenLine.C000066400000000000000000000204401357676770200173470ustar00rootroot00000000000000/* * 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; } tkblt-3.2.21/generic/tkbltGrPenLine.h000066400000000000000000000047301357676770200174200ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrPenOp.C000066400000000000000000000134711357676770200170440ustar00rootroot00000000000000/* * 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 } }; tkblt-3.2.21/generic/tkbltGrPenOp.h000066400000000000000000000030611357676770200171030ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrPenOption.C000066400000000000000000000052211357676770200177300ustar00rootroot00000000000000/* * 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_--; } tkblt-3.2.21/generic/tkbltGrPostscript.C000066400000000000000000000067601357676770200202000ustar00rootroot00000000000000/* * 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_); } tkblt-3.2.21/generic/tkbltGrPostscript.h000066400000000000000000000037021357676770200202360ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrPostscriptOp.C000066400000000000000000000116731357676770200204760ustar00rootroot00000000000000/* * 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 } }; tkblt-3.2.21/generic/tkbltGrPostscriptOp.h000066400000000000000000000030631357676770200205350ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrText.C000066400000000000000000000143731357676770200167510ustar00rootroot00000000000000/* * 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_; } tkblt-3.2.21/generic/tkbltGrText.h000066400000000000000000000043751357676770200170170ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGrXAxisOp.C000066400000000000000000000155411357676770200173560ustar00rootroot00000000000000/* * 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 } }; tkblt-3.2.21/generic/tkbltGrXAxisOp.h000066400000000000000000000026531357676770200174230ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGraph.C000066400000000000000000001123631357676770200165730ustar00rootroot00000000000000/* * 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)); } tkblt-3.2.21/generic/tkbltGraph.h000066400000000000000000000143411357676770200166350ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGraphBar.C000066400000000000000000000413151357676770200172160ustar00rootroot00000000000000/* * 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; } } } } tkblt-3.2.21/generic/tkbltGraphBar.h000066400000000000000000000056301357676770200172630ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGraphLine.C000066400000000000000000000240251357676770200174000ustar00rootroot00000000000000/* * 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; } tkblt-3.2.21/generic/tkbltGraphLine.h000066400000000000000000000043431357676770200174460ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGraphOp.C000066400000000000000000000337631357676770200171000ustar00rootroot00000000000000/* * 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->flags |= RESET; 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; } tkblt-3.2.21/generic/tkbltGraphOp.h000066400000000000000000000032261357676770200171340ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltGraphSup.C000066400000000000000000000506351357676770200172660ustar00rootroot00000000000000/* * 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: if (!ops->rightMargin.reqSize) right += legend_->width_ + 2; break; case Legend::LEFT: if (!ops->leftMargin.reqSize) left += legend_->width_ + 2; break; case Legend::TOP: if (!ops->topMargin.reqSize) top += legend_->height_ + 2; break; case Legend::BOTTOM: if (!ops->bottomMargin.reqSize) 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; } tkblt-3.2.21/generic/tkbltInt.C000066400000000000000000000044731357676770200162660ustar00rootroot00000000000000/* * 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); } tkblt-3.2.21/generic/tkbltInt.h000066400000000000000000000032171357676770200163260ustar00rootroot00000000000000/* * 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__ */ tkblt-3.2.21/generic/tkbltNsUtil.C000066400000000000000000000075411357676770200167510ustar00rootroot00000000000000/* * 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; } tkblt-3.2.21/generic/tkbltNsUtil.h000066400000000000000000000040721357676770200170120ustar00rootroot00000000000000/* * 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 */ tkblt-3.2.21/generic/tkbltOp.C000066400000000000000000000117761357676770200161160ustar00rootroot00000000000000/* * 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; } tkblt-3.2.21/generic/tkbltOp.h000066400000000000000000000042251357676770200161520ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltParse.C000066400000000000000000000276271357676770200166140ustar00rootroot00000000000000/* * 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; } } } tkblt-3.2.21/generic/tkbltParse.h000066400000000000000000000037621357676770200166530ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltStubInit.c000066400000000000000000000014341357676770200173270ustar00rootroot00000000000000#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. */ tkblt-3.2.21/generic/tkbltStubLib.C000066400000000000000000000005521357676770200170720ustar00rootroot00000000000000#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; } tkblt-3.2.21/generic/tkbltSwitch.C000066400000000000000000000233501357676770200167700ustar00rootroot00000000000000/* * 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; } } } } tkblt-3.2.21/generic/tkbltSwitch.h000066400000000000000000000100031357676770200170240ustar00rootroot00000000000000/* * 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 */ tkblt-3.2.21/generic/tkbltVecCmd.C000066400000000000000000001411721357676770200166730ustar00rootroot00000000000000/* * 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; } tkblt-3.2.21/generic/tkbltVecInt.h000066400000000000000000000174301357676770200167660ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltVecMath.C000066400000000000000000001131541357676770200170600ustar00rootroot00000000000000/* * 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 tkblt-3.2.21/generic/tkbltVecOp.C000066400000000000000000000036261357676770200165470ustar00rootroot00000000000000/* * 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; } tkblt-3.2.21/generic/tkbltVector.C000066400000000000000000001445331357676770200170000ustar00rootroot00000000000000/* * 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; } tkblt-3.2.21/generic/tkbltVector.h000066400000000000000000000131261357676770200170360ustar00rootroot00000000000000/* * 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 */ tkblt-3.2.21/library/000077500000000000000000000000001357676770200144075ustar00rootroot00000000000000tkblt-3.2.21/library/graph.tcl000066400000000000000000000340371357676770200162230ustar00rootroot00000000000000package 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 } } tkblt-3.2.21/pkgIndex.tcl.in000066400000000000000000000002721357676770200156260ustar00rootroot00000000000000# # 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]] tkblt-3.2.21/tclconfig/000077500000000000000000000000001357676770200147135ustar00rootroot00000000000000tkblt-3.2.21/tclconfig/ChangeLog000066400000000000000000001101121357676770200164610ustar00rootroot000000000000002016-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)/.. tkblt-3.2.21/tclconfig/README.txt000066400000000000000000000014541357676770200164150ustar00rootroot00000000000000These 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. tkblt-3.2.21/tclconfig/install-sh000077500000000000000000000330541357676770200167240ustar00rootroot00000000000000#!/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: tkblt-3.2.21/tclconfig/tcl.m4000066400000000000000000004110661357676770200157470ustar00rootroot00000000000000# 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: tkblt-3.2.21/tests/000077500000000000000000000000001357676770200141055ustar00rootroot00000000000000tkblt-3.2.21/tests/all.tcl000066400000000000000000000003071357676770200153610ustar00rootroot00000000000000source 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 tkblt-3.2.21/tests/axis.tcl000066400000000000000000000074441357676770200155660ustar00rootroot00000000000000source 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 tkblt-3.2.21/tests/barelement.tcl000066400000000000000000000102241357676770200167260ustar00rootroot00000000000000source 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 tkblt-3.2.21/tests/bargraph.tcl000066400000000000000000000044161357676770200164040ustar00rootroot00000000000000source 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 tkblt-3.2.21/tests/barpen.tcl000066400000000000000000000033431357676770200160630ustar00rootroot00000000000000source 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 tkblt-3.2.21/tests/base.tcl000066400000000000000000000056711357676770200155340ustar00rootroot00000000000000package 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 } tkblt-3.2.21/tests/crosshairs.tcl000066400000000000000000000011171357676770200167710ustar00rootroot00000000000000source 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 tkblt-3.2.21/tests/legend.tcl000066400000000000000000000073241357676770200160550ustar00rootroot00000000000000source 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 tkblt-3.2.21/tests/lineelement.tcl000066400000000000000000000112571357676770200171200ustar00rootroot00000000000000source 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 tkblt-3.2.21/tests/linegraph.tcl000066400000000000000000000042011357676770200165570ustar00rootroot00000000000000source 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 tkblt-3.2.21/tests/linemarker.tcl000066400000000000000000000021771357676770200167510ustar00rootroot00000000000000source 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 tkblt-3.2.21/tests/linepen.tcl000066400000000000000000000036671357676770200162570ustar00rootroot00000000000000source 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 tkblt-3.2.21/tests/marker.tcl000066400000000000000000000016741357676770200161020ustar00rootroot00000000000000source 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 tkblt-3.2.21/tests/markers.tcl000066400000000000000000000001271357676770200162550ustar00rootroot00000000000000source marker.tcl source linemarker.tcl source polygonmarker.tcl source textmarker.tcl tkblt-3.2.21/tests/polygonmarker.tcl000066400000000000000000000017211357676770200175030ustar00rootroot00000000000000source 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 tkblt-3.2.21/tests/ps.tcl000066400000000000000000000014621357676770200152360ustar00rootroot00000000000000source 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 tkblt-3.2.21/tests/test.tcl000066400000000000000000000001771357676770200155750ustar00rootroot00000000000000source base.tcl set w .line set graph [bltLineGraph $w] #set graph [bltBarGraph $w] #puts stderr "done" #bltPlotDestroy $w tkblt-3.2.21/tests/textmarker.tcl000066400000000000000000000031331357676770200167770ustar00rootroot00000000000000source 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 tkblt-3.2.21/tkbltConfig.sh.in000077500000000000000000000031741357676770200161620ustar00rootroot00000000000000# 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@' tkblt-3.2.21/tools/000077500000000000000000000000001357676770200141035ustar00rootroot00000000000000tkblt-3.2.21/tools/genStubs.tcl000066400000000000000000000704351357676770200164120ustar00rootroot00000000000000# 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