blt-2.4z.orig/0042755000175000017500000000000007553201263011754 5ustar dokodokoblt-2.4z.orig/MANIFEST0100644000175000017500000002472607553201474013117 0ustar dokodokoblt2.4z blt2.4z/MANIFEST blt2.4z/INSTALL blt2.4z/cf blt2.4z/cf/config.guess blt2.4z/cf/config.sub blt2.4z/cf/install-sh blt2.4z/cf/install.sh blt2.4z/cf/ldAix blt2.4z/html blt2.4z/html/BLT.html blt2.4z/html/Makefile.vc blt2.4z/html/barchart.html blt2.4z/html/beep.html blt2.4z/html/bgexec.html blt2.4z/html/bitmap.html blt2.4z/html/bltdebug.html blt2.4z/html/busy.html blt2.4z/html/container.html blt2.4z/html/cutbuffer.html blt2.4z/html/dragdrop.html blt2.4z/html/eps.html blt2.4z/html/graph.html blt2.4z/html/hierbox.html blt2.4z/html/hiertable.html blt2.4z/html/htext.html blt2.4z/html/spline.html blt2.4z/html/stripchart.html blt2.4z/html/table.html blt2.4z/html/tabset.html blt2.4z/html/tile.html blt2.4z/html/tree.html blt2.4z/html/treeview.html blt2.4z/html/vector.html blt2.4z/html/watch.html blt2.4z/html/winop.html blt2.4z/Makefile.in blt2.4z/Makefile.vc blt2.4z/NEWS blt2.4z/PROBLEMS blt2.4z/README blt2.4z/acconfig.h blt2.4z/aclocal.m4 blt2.4z/blt.mak blt2.4z/configure blt2.4z/configure.in blt2.4z/demos blt2.4z/demos/bitmaps blt2.4z/demos/bitmaps/fish blt2.4z/demos/bitmaps/fish/left.xbm blt2.4z/demos/bitmaps/fish/left1.xbm blt2.4z/demos/bitmaps/fish/left1m.xbm blt2.4z/demos/bitmaps/fish/leftm.xbm blt2.4z/demos/bitmaps/fish/mid.xbm blt2.4z/demos/bitmaps/fish/midm.xbm blt2.4z/demos/bitmaps/fish/right.xbm blt2.4z/demos/bitmaps/fish/right1.xbm blt2.4z/demos/bitmaps/fish/right1m.xbm blt2.4z/demos/bitmaps/fish/rightm.xbm blt2.4z/demos/bitmaps/hand blt2.4z/demos/bitmaps/hand/hand01.xbm blt2.4z/demos/bitmaps/hand/hand01m.xbm blt2.4z/demos/bitmaps/hand/hand02.xbm blt2.4z/demos/bitmaps/hand/hand02m.xbm blt2.4z/demos/bitmaps/hand/hand03.xbm blt2.4z/demos/bitmaps/hand/hand03m.xbm blt2.4z/demos/bitmaps/hand/hand04.xbm blt2.4z/demos/bitmaps/hand/hand04m.xbm blt2.4z/demos/bitmaps/hand/hand05.xbm blt2.4z/demos/bitmaps/hand/hand05m.xbm blt2.4z/demos/bitmaps/hand/hand06.xbm blt2.4z/demos/bitmaps/hand/hand06m.xbm blt2.4z/demos/bitmaps/hand/hand07.xbm blt2.4z/demos/bitmaps/hand/hand07m.xbm blt2.4z/demos/bitmaps/hand/hand08.xbm blt2.4z/demos/bitmaps/hand/hand08m.xbm blt2.4z/demos/bitmaps/hand/hand09.xbm blt2.4z/demos/bitmaps/hand/hand09m.xbm blt2.4z/demos/bitmaps/hand/hand10.xbm blt2.4z/demos/bitmaps/hand/hand10m.xbm blt2.4z/demos/bitmaps/hand/hand11.xbm blt2.4z/demos/bitmaps/hand/hand11m.xbm blt2.4z/demos/bitmaps/hand/hand12.xbm blt2.4z/demos/bitmaps/hand/hand12m.xbm blt2.4z/demos/bitmaps/hand/hand13.xbm blt2.4z/demos/bitmaps/hand/hand13m.xbm blt2.4z/demos/bitmaps/hand/hand14.xbm blt2.4z/demos/bitmaps/hand/hand14m.xbm blt2.4z/demos/bitmaps/face.xbm blt2.4z/demos/bitmaps/greenback.xbm blt2.4z/demos/bitmaps/hobbes.xbm blt2.4z/demos/bitmaps/hobbes_mask.xbm blt2.4z/demos/bitmaps/sharky.xbm blt2.4z/demos/bitmaps/xbob.xbm blt2.4z/demos/Makefile.in blt2.4z/demos/Makefile.vc blt2.4z/demos/barchart1.tcl blt2.4z/demos/barchart2.tcl blt2.4z/demos/barchart3.tcl blt2.4z/demos/barchart4.tcl blt2.4z/demos/barchart5.tcl blt2.4z/demos/bgexec1.tcl blt2.4z/demos/bgexec2.tcl blt2.4z/demos/bgexec3.tcl blt2.4z/demos/bgexec4.tcl blt2.4z/demos/bgexec5.tcl blt2.4z/demos/bitmap.tcl blt2.4z/demos/bitmap2.tcl blt2.4z/demos/busy1.tcl blt2.4z/demos/busy2.tcl blt2.4z/demos/container.tcl blt2.4z/demos/container3.tcl blt2.4z/demos/dnd1.tcl blt2.4z/demos/dnd2.tcl blt2.4z/demos/dragdrop1.tcl blt2.4z/demos/dragdrop2.tcl blt2.4z/demos/eps.tcl blt2.4z/demos/graph1.tcl blt2.4z/demos/graph2.tcl blt2.4z/demos/graph3.tcl blt2.4z/demos/graph4.tcl blt2.4z/demos/graph5.tcl blt2.4z/demos/graph6.tcl blt2.4z/demos/graph7.tcl blt2.4z/demos/hierbox1.tcl blt2.4z/demos/hierbox2.tcl blt2.4z/demos/hierbox3.tcl blt2.4z/demos/hierbox4.tcl blt2.4z/demos/hiertable1.tcl blt2.4z/demos/hiertable2.tcl blt2.4z/demos/hiertable3.tcl blt2.4z/demos/htext.txt blt2.4z/demos/htext1.tcl blt2.4z/demos/spline.tcl blt2.4z/demos/stripchart1.tcl blt2.4z/demos/tabnotebook1.tcl blt2.4z/demos/tabnotebook2.tcl blt2.4z/demos/tabnotebook3.tcl blt2.4z/demos/tabset1.tcl blt2.4z/demos/tabset2.tcl blt2.4z/demos/tabset3.tcl blt2.4z/demos/tabset4.tcl blt2.4z/demos/tour.tcl blt2.4z/demos/treeview1.tcl blt2.4z/demos/winop1.tcl blt2.4z/demos/winop2.tcl blt2.4z/demos/images blt2.4z/demos/images/blt98.gif blt2.4z/demos/images/buckskin.gif blt2.4z/demos/images/chalk.gif blt2.4z/demos/images/close.gif blt2.4z/demos/images/close2.gif blt2.4z/demos/images/clouds.gif blt2.4z/demos/images/corrugated_metal.gif blt2.4z/demos/images/folder.gif blt2.4z/demos/images/jan25_palm3x_L.jpg blt2.4z/demos/images/mini-book1.gif blt2.4z/demos/images/mini-book2.gif blt2.4z/demos/images/mini-display.gif blt2.4z/demos/images/mini-doc.gif blt2.4z/demos/images/mini-filemgr.gif blt2.4z/demos/images/mini-ofolder.gif blt2.4z/demos/images/mini-windows.gif blt2.4z/demos/images/ofolder.gif blt2.4z/demos/images/open.gif blt2.4z/demos/images/open2.gif blt2.4z/demos/images/out.ps blt2.4z/demos/images/qv100.t.gif blt2.4z/demos/images/rain.gif blt2.4z/demos/images/sample.gif blt2.4z/demos/images/smblue_rock.gif blt2.4z/demos/images/stopsign.gif blt2.4z/demos/images/tan_paper.gif blt2.4z/demos/images/tan_paper2.gif blt2.4z/demos/images/txtrflag.gif blt2.4z/demos/scripts blt2.4z/demos/scripts/barchart2.tcl blt2.4z/demos/scripts/bgtest.tcl blt2.4z/demos/scripts/clone.tcl blt2.4z/demos/scripts/demo.tcl blt2.4z/demos/scripts/globe.tcl blt2.4z/demos/scripts/graph1.tcl blt2.4z/demos/scripts/graph2.tcl blt2.4z/demos/scripts/graph3.tcl blt2.4z/demos/scripts/graph5.tcl blt2.4z/demos/scripts/graph8.tcl blt2.4z/demos/scripts/page.tcl blt2.4z/demos/scripts/patterns.tcl blt2.4z/demos/scripts/ps.tcl blt2.4z/demos/scripts/send.tcl blt2.4z/demos/scripts/stipples.tcl blt2.4z/demos/scripts/xcolors.tcl blt2.4z/examples blt2.4z/examples/calendar.tcl blt2.4z/examples/form.tcl blt2.4z/examples/pareto.tcl blt2.4z/library blt2.4z/library/dd_protocols blt2.4z/library/dd_protocols/dd-color.tcl blt2.4z/library/dd_protocols/dd-file.tcl blt2.4z/library/dd_protocols/dd-number.tcl blt2.4z/library/dd_protocols/dd-text.tcl blt2.4z/library/dd_protocols/tclIndex blt2.4z/library/Makefile.in blt2.4z/library/Makefile.vc blt2.4z/library/ZoomStack.itcl blt2.4z/library/bltCanvEps.pro blt2.4z/library/bltGraph.pro blt2.4z/library/dnd.tcl blt2.4z/library/dragdrop.tcl blt2.4z/library/graph.tcl blt2.4z/library/hierbox.tcl blt2.4z/library/hiertable.tcl blt2.4z/library/pkgIndex.tcl.in blt2.4z/library/tabnotebook.tcl blt2.4z/library/tabset.tcl blt2.4z/library/tclIndex blt2.4z/library/treeview.cur blt2.4z/library/treeview.tcl blt2.4z/library/treeview.xbm blt2.4z/library/treeview_m.xbm blt2.4z/man blt2.4z/man/BLT.mann blt2.4z/man/Blt_Tree.man3 blt2.4z/man/Blt_TreeCreate.man3 blt2.4z/man/Blt_TreeCreateNode.man3 blt2.4z/man/Blt_TreeDeleteNode.man3 blt2.4z/man/Blt_TreeExists.man3 blt2.4z/man/Blt_TreeGetNode.man3 blt2.4z/man/Blt_TreeGetToken.man3 blt2.4z/man/Blt_TreeName.man3 blt2.4z/man/Blt_TreeNodeId.man3 blt2.4z/man/Blt_TreeReleaseToken.man3 blt2.4z/man/Makefile.in blt2.4z/man/barchart.mann blt2.4z/man/beep.mann blt2.4z/man/bgexec.mann blt2.4z/man/bitmap.mann blt2.4z/man/bltdebug.mann blt2.4z/man/busy.mann blt2.4z/man/container.mann blt2.4z/man/cutbuffer.mann blt2.4z/man/dragdrop.mann blt2.4z/man/eps.mann blt2.4z/man/graph.mann blt2.4z/man/hierbox.mann blt2.4z/man/hiertable.mann blt2.4z/man/htext.mann blt2.4z/man/man.macros blt2.4z/man/spline.mann blt2.4z/man/stripchart.mann blt2.4z/man/table.mann blt2.4z/man/tabset.mann blt2.4z/man/tile.mann blt2.4z/man/tree.mann blt2.4z/man/treeview.mann blt2.4z/man/vector.mann blt2.4z/man/watch.mann blt2.4z/man/winop.mann blt2.4z/src blt2.4z/src/shared blt2.4z/src/shared/Makefile.in blt2.4z/src/Makefile-cyg.in blt2.4z/src/Makefile.bc blt2.4z/src/Makefile.in blt2.4z/src/Makefile.vc blt2.4z/src/TODO blt2.4z/src/blt.h blt2.4z/src/blt.mak blt2.4z/src/bltAlloc.c blt2.4z/src/bltArrayObj.c blt2.4z/src/bltBeep.c blt2.4z/src/bltBgexec.c blt2.4z/src/bltBind.c blt2.4z/src/bltBind.h blt2.4z/src/bltBitmap.c blt2.4z/src/bltBusy.c blt2.4z/src/bltCanvEps.c blt2.4z/src/bltChain.c blt2.4z/src/bltChain.h blt2.4z/src/bltColor.c blt2.4z/src/bltConfig.c blt2.4z/src/bltConfig.h.in blt2.4z/src/bltContainer.c blt2.4z/src/bltCutbuffer.c blt2.4z/src/bltDebug.c blt2.4z/src/bltDragdrop.c blt2.4z/src/bltGrAxis.c blt2.4z/src/bltGrAxis.h blt2.4z/src/bltGrBar.c blt2.4z/src/bltGrElem.c blt2.4z/src/bltGrElem.h blt2.4z/src/bltGrGrid.c blt2.4z/src/bltGrHairs.c blt2.4z/src/bltGrLegd.c blt2.4z/src/bltGrLegd.h blt2.4z/src/bltGrLine.c blt2.4z/src/bltGrMarker.c blt2.4z/src/bltGrMisc.c blt2.4z/src/bltGrPen.c blt2.4z/src/bltGrPs.c blt2.4z/src/bltGraph.c blt2.4z/src/bltGraph.h blt2.4z/src/bltHash.c blt2.4z/src/bltHash.h.in blt2.4z/src/bltHierbox.c blt2.4z/src/bltHtext.c blt2.4z/src/bltImage.c blt2.4z/src/bltImage.h blt2.4z/src/bltInit.c blt2.4z/src/bltInt.h blt2.4z/src/bltInterp.h blt2.4z/src/bltList.c blt2.4z/src/bltList.h blt2.4z/src/bltMath.h blt2.4z/src/bltNsUtil.c blt2.4z/src/bltNsUtil.h blt2.4z/src/bltObjConfig.c blt2.4z/src/bltObjConfig.h blt2.4z/src/bltParse.c blt2.4z/src/bltPool.c blt2.4z/src/bltPool.h blt2.4z/src/bltPs.c blt2.4z/src/bltPs.h blt2.4z/src/bltScrollbar.c blt2.4z/src/bltSpline.c blt2.4z/src/bltSwitch.c blt2.4z/src/bltSwitch.h blt2.4z/src/bltTable.c blt2.4z/src/bltTable.h blt2.4z/src/bltTabnotebook.c blt2.4z/src/bltTabset.c blt2.4z/src/bltTed.c blt2.4z/src/bltText.c blt2.4z/src/bltText.h blt2.4z/src/bltTile.c blt2.4z/src/bltTile.h blt2.4z/src/bltTkInt.h blt2.4z/src/bltTree.c blt2.4z/src/bltTree.h blt2.4z/src/bltTreeCmd.c blt2.4z/src/bltTreeView.c blt2.4z/src/bltTreeView.h blt2.4z/src/bltTreeViewCmd.c blt2.4z/src/bltTreeViewColumn.c blt2.4z/src/bltTreeViewEdit.c blt2.4z/src/bltTreeViewStyle.c blt2.4z/src/bltTuple.c blt2.4z/src/bltTuple.h blt2.4z/src/bltTupleCmd.c blt2.4z/src/bltUnixDnd.c blt2.4z/src/bltUnixImage.c blt2.4z/src/bltUnixMain.c blt2.4z/src/bltUnixPipe.c blt2.4z/src/bltUtil.c blt2.4z/src/bltVecCmd.c blt2.4z/src/bltVecInt.h blt2.4z/src/bltVecMath.c blt2.4z/src/bltVecObjCmd.c blt2.4z/src/bltVector.c blt2.4z/src/bltVector.h blt2.4z/src/bltWait.h blt2.4z/src/bltWatch.c blt2.4z/src/bltWin.h blt2.4z/src/bltWinConfig.h blt2.4z/src/bltWinDde.c blt2.4z/src/bltWinDraw.c blt2.4z/src/bltWinImage.c blt2.4z/src/bltWinMain.c blt2.4z/src/bltWinPipe.c blt2.4z/src/bltWinPrnt.c blt2.4z/src/bltWinUtil.c blt2.4z/src/bltWindow.c blt2.4z/src/bltWinop.c blt2.4z/src/missing.h blt2.4z/src/pure_api.c blt2.4z/src/tkButton.c blt2.4z/src/tkConsole.c blt2.4z/src/tkFrame.c blt2.4z/src/tkMenubutton.c blt2.4z/src/tkScrollbar.c blt2.4z/win blt2.4z/win/install.tcl blt2.4z/win/README blt2.4z/win/X11 blt2.4z/win/X11/Xatom.h blt2.4z/win/X11/X.h blt2.4z/win/X11/Xfuncproto.h blt2.4z/win/X11/Xlib.h blt2.4z/win/X11/Xutil.h blt2.4z/win/X11/cursorfont.h blt2.4z/win/X11/keysym.h blt2.4z/win/X11/keysymdef.h blt2.4z/win/makedefs blt-2.4z.orig/INSTALL0100644000175000017500000000635707514411220013004 0ustar dokodokoThis file describes how to compile and install the BLT library for UNIX. [See the file ./win/README for details on how to build under Win32.] 1. Uncompress and untar the distribution file. zcat BLT2.4.tar.gz | tar -xvf - This will create a directory "blt2.4" with the following subdirectories: blt2.4 ______________|_____________________________ | | | | | | | demos examples html library man src win | | | scripts shared X11 2. Run ./configure Go into the "blt2.4" directory cd blt2.4 and run the auto-configuration script "./configure". Tell where to find the Tcl and Tk header files and libraries with the "--with-tcl" switch. ./configure --with-tcl=/util/lang/tcl Switches: --prefix=path Specifies the path where "bltwish", the BLT header files, libraries, scripts, and manual pages are installed. The default is "/usr/local/blt". This switch also indicates where to find the Tcl/Tk header files and libraries. You can use the --with-tcl and --with-tk switches to override this value if the location of the Tcl/Tk files is different. --with-tcl=dir Directory where Tcl and/or Tk is installed. --with-tk=dir Directory where Tk is installed if different from "--with-tcl". --with-cc=program Lets you specify the C compiler, such as "acc" or "gcc". The configure script creates a header file "src/bltConfig.h". It will also generate new Makefiles from their respective templates (Makefile.in). Makefile.in ==> Makefile src/Makefile.in ==> src/Makefile src/shared/Makefile.in ==> src/shared/Makefile man/Makefile.in ==> man/Makefile library/Makefile.in ==> library/Makefile 3. Compile the libraries and build the demonstration program "bltwish". make The program "bltwish" will be created in the ./src directory. 4. Test by running the demos. Go into the demos directory cd demos and run the test scripts. ./graph1.tcl If your system doesn't support "#!" in shell scripts, then it's ../src/bltwish ./graph1.tcl 5. Installing BLT make install The following directories will be created when BLT is installed. By default, the top directory is /usr/local/blt. ___________|__________ | | | | bin include lib man | blt2.4 ____|____ | | demos dd_protocols You can change the top directory by supplying the "--prefix=dir" switch to ./configure. *6. (Optional) Compiling BLT into your own custom "wish". [If your version of "wish" supports dynamic loading of packages you can simply add package require BLT to the start of your script.] Add the following lines to your program's Tcl_AppInit routine in tkAppInit.c if (Blt_Init(interp) != TCL_OK) { return TCL_ERROR; } then link with libBLT.a. And that's all there's to it. blt-2.4z.orig/cf/0042755000175000017500000000000007553201205012340 5ustar dokodokoblt-2.4z.orig/cf/config.guess0100755000175000017500000011576307547207255014706 0ustar dokodoko#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002 Free Software Foundation, Inc. timestamp='2002-09-03' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner . # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # This shell variable is my proudest work .. or something. --bje set_cc_for_build='tmpdir=${TMPDIR-/tmp}/config-guess-$$ ; (old=`umask` && umask 077 && mkdir $tmpdir && umask $old && unset old) || (echo "$me: cannot create $tmpdir" >&2 && exit 1) ; dummy=$tmpdir/dummy ; files="$dummy.c $dummy.o $dummy.rel $dummy" ; trap '"'"'rm -f $files; rmdir $tmpdir; exit 1'"'"' 1 2 15 ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c $dummy.c -c -o $dummy.o) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; rm -f $files ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; unset files' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit 0 ;; amiga:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; arc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; hp300:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mac68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; macppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme88k:OpenBSD:*:*) echo m88k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvmeppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; pmax:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sgi:OpenBSD:*:*) echo mipseb-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sun3:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; wgrisc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; *:OpenBSD:*:*) echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} exit 0 ;; alpha:OSF1:*:*) if test $UNAME_RELEASE = "V4.0"; then UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` fi # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. eval $set_cc_for_build cat <$dummy.s .data \$Lformat: .byte 37,100,45,37,120,10,0 # "%d-%x\n" .text .globl main .align 4 .ent main main: .frame \$30,16,\$26,0 ldgp \$29,0(\$27) .prologue 1 .long 0x47e03d80 # implver \$0 lda \$2,-1 .long 0x47e20c21 # amask \$2,\$1 lda \$16,\$Lformat mov \$0,\$17 not \$1,\$18 jsr \$26,printf ldgp \$29,0(\$26) mov 0,\$16 jsr \$26,exit .end main EOF $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null if test "$?" = 0 ; then case `$dummy` in 0-0) UNAME_MACHINE="alpha" ;; 1-0) UNAME_MACHINE="alphaev5" ;; 1-1) UNAME_MACHINE="alphaev56" ;; 1-101) UNAME_MACHINE="alphapca56" ;; 2-303) UNAME_MACHINE="alphaev6" ;; 2-307) UNAME_MACHINE="alphaev67" ;; 2-1307) UNAME_MACHINE="alphaev68" ;; 3-1307) UNAME_MACHINE="alphaev7" ;; esac fi rm -f $dummy.s $dummy && rmdir $tmpdir echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit 0 ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit 0 ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit 0 ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit 0;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit 0 ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit 0 ;; *:OS/390:*:*) echo i370-ibm-openedition exit 0 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit 0;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit 0;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit 0 ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit 0 ;; DRS?6000:UNIX_SV:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7 && exit 0 ;; esac ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; i86pc:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit 0 ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit 0 ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit 0 ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit 0 ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit 0 ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit 0 ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit 0 ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit 0 ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit 0 ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit 0 ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit 0 ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit 0 ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD $dummy.c -o $dummy \ && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ && rm -f $dummy.c $dummy && rmdir $tmpdir && exit 0 rm -f $dummy.c $dummy && rmdir $tmpdir echo mips-mips-riscos${UNAME_RELEASE} exit 0 ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit 0 ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit 0 ;; Night_Hawk:*:*:PowerMAX_OS) echo powerpc-harris-powermax exit 0 ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit 0 ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit 0 ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit 0 ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit 0 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit 0 ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit 0 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit 0 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit 0 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit 0 ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit 0 ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit 0 ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF $CC_FOR_BUILD $dummy.c -o $dummy && $dummy && rm -f $dummy.c $dummy && rmdir $tmpdir && exit 0 rm -f $dummy.c $dummy && rmdir $tmpdir echo rs6000-ibm-aix3.2.5 elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit 0 ;; *:AIX:*:[45]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:*:*) echo rs6000-ibm-aix exit 0 ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit 0 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit 0 ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit 0 ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit 0 ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit 0 ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit 0 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null) && HP_ARCH=`$dummy` if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi rm -f $dummy.c $dummy && rmdir $tmpdir fi ;; esac echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit 0 ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit 0 ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD $dummy.c -o $dummy && $dummy && rm -f $dummy.c $dummy && rmdir $tmpdir && exit 0 rm -f $dummy.c $dummy && rmdir $tmpdir echo unknown-hitachi-hiuxwe2 exit 0 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit 0 ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit 0 ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit 0 ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit 0 ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit 0 ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit 0 ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit 0 ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit 0 ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit 0 ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit 0 ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit 0 ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*T3D:*:*:*) echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit 0 ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit 0 ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:FreeBSD:*:*) # Determine whether the default compiler uses glibc. eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #if __GLIBC__ >= 2 LIBC=gnu #else LIBC= #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` rm -f $dummy.c && rmdir $tmpdir echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC} exit 0 ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit 0 ;; i*:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit 0 ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit 0 ;; x86:Interix*:3*) echo i386-pc-interix3 exit 0 ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i386-pc-interix exit 0 ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit 0 ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit 0 ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; *:GNU:*:*) echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit 0 ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit 0 ;; arm*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; mips:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips #undef mipsel #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mipsel #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` rm -f $dummy.c && rmdir $tmpdir test x"${CPU}" != x && echo "${CPU}-pc-linux-gnu" && exit 0 ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit 0 ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit 0 ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit 0 ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit 0 ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit 0 ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit 0 ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit 0 ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit 0 ;; coff-i386) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit 0 ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" exit 0 ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 LIBC=gnu # else LIBC=gnulibc1 # endif # else LIBC=gnulibc1 # endif #else #ifdef __INTEL_COMPILER LIBC=gnu #else LIBC=gnuaout #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` rm -f $dummy.c && rmdir $tmpdir test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0 test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit 0 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit 0 ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit 0 ;; i*86:*:5:[78]*) case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit 0 ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit 0 ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit 0 ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp exit 0 ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit 0 ;; paragon:*:*:*) echo i860-intel-osf1 exit 0 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit 0 ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit 0 ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit 0 ;; M68*:*:R3V[567]*:*) test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4.3${OS_REL} && exit 0 /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4 && exit 0 ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit 0 ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit 0 ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit 0 ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit 0 ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit 0 ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit 0 ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit 0 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit 0 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit 0 ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit 0 ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit 0 ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit 0 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit 0 ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit 0 ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit 0 ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit 0 ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit 0 ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit 0 ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit 0 ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Darwin:*:*) echo `uname -p`-apple-darwin${UNAME_RELEASE} exit 0 ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit 0 ;; *:QNX:*:4*) echo i386-pc-qnx exit 0 ;; NSR-[DGKLNPTVW]:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit 0 ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit 0 ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit 0 ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit 0 ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit 0 ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit 0 ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit 0 ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit 0 ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit 0 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit 0 ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit 0 ;; *:ITS:*:*) echo pdp10-unknown-its exit 0 ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit 0 ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit 0 ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && $dummy && rm -f $dummy.c $dummy && rmdir $tmpdir && exit 0 rm -f $dummy.c $dummy && rmdir $tmpdir # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit 0 ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; c34*) echo c34-convex-bsd exit 0 ;; c38*) echo c38-convex-bsd exit 0 ;; c4*) echo c4-convex-bsd exit 0 ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp 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` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: blt-2.4z.orig/cf/config.sub0100755000175000017500000007167407547207255014353 0ustar dokodoko#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002 Free Software Foundation, Inc. timestamp='2002-09-05' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit 0;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | freebsd*-gnu* | storm-chaos* | os2-emx* | windows32-* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ | clipper \ | d10v | d30v | dlx | dsp16xx \ | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k \ | m32r | m68000 | m68k | m88k | mcore \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64vr | mips64vrel \ | mips64orion | mips64orionel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mipsisa32 | mipsisa32el \ | mipsisa64 | mipsisa64el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | ns16k | ns32k \ | openrisc | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | sh | sh[1234] | sh3e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \ | strongarm \ | tahoe | thumb | tic80 | tron \ | v850 | v850e \ | we32k \ | x86 | xscale | xstormy16 | xtensa \ | z8k) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* \ | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* \ | clipper-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* \ | m32r-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | mcore-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64vr-* | mips64vrel-* \ | mips64orion-* | mips64orionel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39 | mipstx39el \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | sh-* | sh[1234]-* | sh3e-* | sh[34]eb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* | tic30-* | tic4x-* | tic54x-* | tic80-* | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \ | xtensa-* \ | ymp-* \ | z8k-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; c90) basic_machine=c90-cray os=-unicos ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; crds | unos) basic_machine=m68k-crds ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; mmix*) basic_machine=mmix-knuth os=-mmixware ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; or32 | or32-*) basic_machine=or32-unknown os=-coff ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2) basic_machine=i686-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3d) basic_machine=alpha-cray os=-unicos ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic4x | c4x*) basic_machine=tic4x-unknown os=-coff ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; windows32) basic_machine=i386-pc os=-windows32-msvcrt ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh3 | sh4 | sh3eb | sh4eb | sh[1234]le | sh3ele) basic_machine=sh-unknown ;; sh64) basic_machine=sh64-unknown ;; sparc | sparcv9 | sparcv9b) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* | -powermax*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto*) os=-nto-qnx ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-ibm) os=-aix ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -ptx*) vendor=sequent ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: blt-2.4z.orig/cf/install-sh0100755000175000017500000001273607240160070014345 0ustar dokodoko#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # 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. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: chmodcmd="" else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # 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 $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 blt-2.4z.orig/cf/install.sh0100644000175000017500000001123307240160070014332 0ustar dokodoko # # install - install a program, script, or datafile # This comes from X11R5. # # 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. # # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # 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 $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 blt-2.4z.orig/cf/ldAix0100644000175000017500000000506607240160070013323 0ustar dokodoko # # ldAix ldCmd ldArg ldArg ... # # This shell script provides a wrapper for ld under AIX in order to # create the .exp file required for linking. Its arguments consist # of the name and arguments that would normally be provided to the # ld command. This script extracts the names of the object files # from the argument list, creates a .exp file describing all of the # symbols exported by those files, and then invokes "ldCmd" to # perform the real link. # # SCCS: @(#) ldAix 1.8 97/02/21 14:50:27 # Extract from the arguments the names of all of the object files. args=$* ofiles="" for i do x=`echo $i | grep '[^.].o$'` if test "$x" != ""; then ofiles="$ofiles $i" fi done # Create the export file from all of the object files, using nm followed # by sed editing. Here are some tricky aspects of this: # # 1. Nm produces different output under AIX 4.1 than under AIX 3.2.5; # the following statements handle both versions. # 2. Use the -g switch to nm instead of -e under 4.1 (this shows just # externals, not statics; -g isn't available under 3.2.5, though). # 3. Eliminate lines that end in ":": these are the names of object # files (relevant in 4.1 only). # 4. Eliminate entries with the "U" key letter; these are undefined # symbols (relevant in 4.1 only). # 5. Eliminate lines that contain the string "0|extern" preceded by space; # in 3.2.5, these are undefined symbols (address 0). # 6. Eliminate lines containing the "unamex" symbol. In 3.2.5, these # are also undefined symbols. # 7. If a line starts with ".", delete the leading ".", since this will # just cause confusion later. # 8. Eliminate everything after the first field in a line, so that we're # left with just the symbol name. nmopts="-g -C" osver=`uname -v` if test $osver -eq 3; then nmopts="-e" fi rm -f lib.exp echo "#! " >lib.exp /usr/ccs/bin/nm $nmopts -h $ofiles | sed -e '/:$/d' -e '/ U /d' -e '/[ ]0|extern/d' -e '/unamex/d' -e 's/^\.//' -e 's/[ |].*//' | sort | uniq >>lib.exp # Extract the name of the object file that we're linking. If it's a .a # file, then link all the objects together into a single file "shr.o" # and then put that into the archive. Otherwise link the object files # directly into the .a file. outputFile=`echo $args | sed -e 's/.*-o \([^ ]*\).*/\1/'` noDotA=`echo $outputFile | sed -e '/\.a$/d'` echo "noDotA=\"$noDotA\"" if test "$noDotA" = "" ; then linkArgs=`echo $args | sed -e 's/-o .*\.a /-o shr.o /'` echo $linkArgs eval $linkArgs echo ar cr $outputFile shr.o ar cr $outputFile shr.o rm -f shr.o else eval $args fi blt-2.4z.orig/html/0042755000175000017500000000000007553201220012711 5ustar dokodokoblt-2.4z.orig/html/BLT.html0100644000175000017500000001521207434255425014232 0ustar dokodoko graph(n) manual page Table of Contents

Name

BLT - Introduction to the BLT library

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:
table
A table geometry manager for Tk. You specify window placements as table row,column positions and windows can also span multiple rows or columns. It also has many options for setting and/or bounding window sizes.
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.
spline
Computes a spline fitting a set of data points (x and y vectors) and produces a vector of the interpolated images (y-coordinates) at a given set of x-coordinates.
bgexec
Like Tcl's exec command, bgexec runs a pipeline of Unix commands in the background. Unlike exec, the output of the last process is collected and a global Tcl variable is set upon its completion. bgexec can be used with tkwait to wait for Unix commands to finish while still handling expose events. Intermediate output is also available while the pipeline is active.
busy
Creates a "busy window" which prevents user-interaction when an application is busy. The busy window also provides an easy way to have temporary busy cursors (such as a watch or hourglass).
bitmap
Reads and writes bitmaps from Tcl. New X bitmaps can be defined on-the-fly from Tcl, obviating the need to copy around bitmap files. Other options query loaded X bitmap's dimensions and data.
drag&drop
Provides a drag-and-drop facility for Tk. Information (represented by a token window) can be dragged to and from any Tk window, including those of another Tk application. drag&drop acts as a coordinator, directing Tk send commands between (or within) TCL/Tk applications.
htext
A simple hypertext widget. Combines text and Tk widgets into a single scroll-able window. Tcl commands can be embedded into text, which are invoked as the text is parsed. In addition, Tk widgets can be appended to the window at the current point in the text. Htext can be also used to create scrolled windows of Tk widgets.
winop
Raise, lower, map, or, unmap any window. The raise and lower functions are useful for stacking windows above or below "busy windows".
watch
Arranges for Tcl procedures to be called before and/or after the execution of every Tcl command. This command may be used in the logging, profiling, or tracing of Tcl code.
bltdebug
A simple Tcl command tracing facility useful for debugging Tcl code. Displays each Tcl command before and after substitution along its level in the interpreter on standard error.

Variables

The following Tcl variables are either set or used by BLT at various times in its execution:

blt_library
This variable contains the name of a directory containing a library of Tcl scripts and other files related to BLT. Currently, this directory contains the drag&drop protocol scripts and the PostScript prolog used by graph and barchart. The value of this variable is taken from the BLT_LIBRARY environment variable, if one exists, or else from a default value compiled into the BLT library.
blt_versions
This variable is set in the interpreter for each application. It is an array of the current version numbers for each of the BLT commands in the form major.minor. Major and minor are integers. The major version number increases in any command that includes changes that are not backward compatible (i.e. whenever existing applications and scripts may have to change to work with the new release). The minor version number increases with each new release of a command, except that it resets to zero whenever the major version number changes. The array is indexed by the individual command name.

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 (Blt_Init(interp) != TCL_OK) {
return TCL_ERROR;
}

Recompile and link with the BLT library (libBLT.a) and that's it.

Alternately, you can dynamically load BLT, simply by invoking the command
package require BLT

from your Tcl script.

Bugs

Send bug reports, requests, suggestions, etc. to gah@siliconmetrics.com or gah@myfirstlink.net

Keywords

BLT


Table of Contents

blt-2.4z.orig/html/Makefile.vc0100644000175000017500000000133207240160077014761 0ustar dokodoko# ------------------------------------------------------------------------ # Makefile for HTML files # ------------------------------------------------------------------------ include ../win/makedefs srcdir = . instdirs = $(prefix) $(libdir) $(scriptdir) $(scriptdir)/html all: install: install-dirs install-html install-dirs: @for i in $(instdirs) ; do \ if test -d "$$i" ; then : ; else \ echo "mkdir $$i" ; \ mkdir "$$i" ; \ fi ; \ done install-html: install-dirs for i in $(srcdir)/*.html ; do \ $(RM) $(scriptdir)/html/$$i ; \ $(INSTALL_DATA) $(srcdir)/$$i $(scriptdir)/html ; \ done clean: $(RM) $(srcdir)/*.bak $(srcdir)/*\~ $(srcdir)/"#"* distclean: clean $(RM) Makefile blt-2.4z.orig/html/barchart.html0100644000175000017500000031713307434255425015406 0ustar dokodoko barchat(n) manual page Table of Contents

Name

barchart - Bar chart for plotting X-Y coordinate data.

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 displayed in top margin.

A barchart 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.

axis

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.

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

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.

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 text marker to label a particular data point. Markers come in various forms: text strings, bitmaps, connected line segments, images, polygons, or embedded widgets.
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 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 BARCHART OPERATIONS section.

The command can also be used to access components of the graph.

pathName component operation ?arg?...

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.

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 yVector

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 -barwidth option.
# 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

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 elements side-by-side.
.b configure -barmode aligned

By default, the element'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 operation.
# 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 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 .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 configuration 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 value. Markers are created using the marker operation.
# 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

This creates a line marker named low_water. 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 -under option.
# Draw the marker before elements are drawn.
.b marker configure low_water -under yes

You can add cross hairs or grid lines using the crosshairs and grid components.
# Display both cross hairs and grid lines.
.b crosshairs configure -hide no -color red
.b grid configure -hide no -dashes { 2 2 }

Finally, to get hardcopy of the graph, use the postscript component.
# Print the bar chart into file "file.ps"
.b postscript output file.ps -maxpect 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 (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 operations to query or modify the bar chart. It has the general form:

pathName 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 configure 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 be drawn. Mode can be infront, aligned, overlap, or stacked. The default mode is infront.
infront
Each successive segment is drawn in front of the previous.
stacked
Each successive segment is stacked vertically on top of the previous.
aligned
Segments is displayed aligned from right-to-left.
overlap
Like aligned but segments slightly overlap each other.
-barwidth value
Specifies the width of the bars. This value can be overrided 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 border 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 display 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 matters only when the title contains more than one line of text. Justify must be left, right, or center. The default is center.
-leftmargin pixels
Sets the size of the margin from the left edge of the window to the Y-coordinate axis. If pixels is 0, the size is calculated automatically. 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 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 window 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
Specifies a tiled background for the widget. If image isn't "", the background is tiled using image. Otherwise, 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
Specifies the size of the margin above the x2 axis. If pixels is 0, the margin size is calculated automatically.
-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 coordinates.
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 automatically 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
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.

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.

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 plotted. 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 "temperature"
.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 temperature 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 bottom 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 components: 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.
# Display 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.

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.
pathName axis configure axisName ?axisName?... ?option value?...
Queries or modifies the configuration options of axisName. Several axes can be changed. If option isn't specified, a list describing all the current options for axisName 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 axis option option is set to value. The following options are valid for axes.
-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 configuration options. But do not reset options, because this can have unexpected results.

-descending boolean
Indicates whether the values along the axis are monotonically 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 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 "" is given as either description, then the that limit will not be displayed. The default is "".
-linewidth pixels
Sets the width of the axis and tick lines. The default is 1 pixel.
-logscale boolean
Indicates whether the scale of the axis is logarithmic or linear. If boolean is true, the axis is logarithmic. The default scale is linear.
-loose boolean
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 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 computed. 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 intervals. 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 automatically 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 is drawn. The default is 1.
-stepsize value
Specifies the interval between major axis ticks. If value isn't a valid interval (must be less than the axis range), the request is ignored and the step size is automatically calculated.
-subdivisions number
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-*.
-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 *-Helvetica-Bold-R-Normal-*-14-140-*.

Axis configuration options may be also be set by the option command. The resource class is Axis. The resource names are the names of the axes (such as x or x2).
option add *Barchart.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 elements.
pathName axis invtransform axisName value
Performs the inverse transformation, changing the screen coordinate 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 mapping the it to axisName. Returns the transformed screen coordinate.

Only four axes can be displayed simultaneously. By default, they are x, y, x2, and y2. You can 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 component does. The xaxis component manages the X-axis located in the bottom margin (whatever axis that happens to be). Likewise, yaxis uses the Y-axis in the left margin, x2axis the top X-axis, and y2axis the right Y-axis.

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. 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 location. 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 without 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.
-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 *Barchart.Crosshairs.LineWidth 2
option add *Barchart.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 mapping 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 command except that it operates on graph elements, 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 tagName. If the first character of command is + then command augments an existing binding rather than replacing it. If no command 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 bindings 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?...
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 displayed. If no elements are specified, then all displayed elements are searched. It returns a 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.
-baseline value
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 0.0.
-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.
-data coordList
Specifies the X-Y coordinates of the data. CoordList is a list of numeric expressions representing the X-Y coordinate 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 indicates 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 fashion.
-xdata xVector
Specifies the x-coordinate vector of the data. XVector is the name of a BLT vector or a list of numeric expressions.
-ydata yVector
Specifies the y-coordinate vector of the data. YVector is the name of a BLT vector or a list of numeric expressions.

Element configuration options may also be set by the option command. The resource names in the option database are prefixed by elem.
option add *Barchart.Element.background blue

pathName element create elemName ?option value?...

Creates a new element elemName. Element names must be unique, so an element elemName may not already exist. If additional arguments are present, they specify any of the element options valid for element configure operation.
pathName element deactivate pattern...
Deactivates all the elements matching pattern for the graph. Elements whose names match any of the patterns given are redrawn using their normal colors.
pathName element delete ?pattern?...
Deletes all the elements matching pattern for the graph. Elements whose names match any of the patterns given are deleted. The graph will be redrawn without the deleted elements.
pathName element exists elemName
Returns 1 if an element elemName currently exists and 0 otherwise.
pathName element names ?pattern?...
Returns the elements matching one or more pattern. If no pattern is given, the names of all elements is returned.
pathName element show ?nameList?
Queries or modifies the element display list. The element display 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 display 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 horizontally 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 following 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 true, grid lines are not shown. The default is yes.
-linewidth pixels
Sets the width of grid lines. The default width is 1.
-mapx xAxis
Specifies the X-axis to display grid lines. XAxis must be the name of an axis or "" for no grid lines. The default is "".
-mapy yAxis
Specifies the Y-axis to display grid lines. YAxis must be the name of an axis or "" for no grid lines. The default is y.
-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 command. The resource name and class are grid and Grid respectively.
option add *Barchart.grid.LineWidth 2
option add *Barchart.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 positioned 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 colors 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 tagName. If the first character of command is + then command augments an existing binding rather than replacing it. If no command 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 bindings have been defined for tagName.

pathName legend cget option
Returns the current value of a legend configuration option. Option may be any option described below in the legend configure operation.
pathName legend configure ?option value?...
Queries or modifies the configuration options for the legend. If option isn't specified, a list describing the current legend 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 legend option option is set to value. The following options are valid for the legend.
-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 legend, relative to the surface of the legend. The default is flat.
-anchor anchor
Tells how to position the legend relative to the positioning 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 legend vertically.
top or bottom
The anchor describes how to position the legend horizontally.
@x,y
The anchor specifies how to position the legend 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 occupied by the legend will be at the positioning point.
plotarea
The anchor specifies how to position the legend relative to the plotting area. For example, 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 plotting area.
-background color
Sets the background color of the legend. If color is "", the legend background with be transparent.
-bindtags tagList
Specifies the binding tags for legend entries. TagList 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 all.
-borderwidth pixels
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 *-Helvetica-Bold-R-Normal-*-12-120-*.
-foreground color
Sets the foreground color of the text drawn for the element'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 bottom 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 distances. 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.
-position pos
Specifies where the legend is drawn. The -anchor option also affects where the legend is positioned. If pos is left, left, top, or bottom, the legend is drawn in the specified margin. If pos is plotarea, then the legend is drawn inside the plotting area at a particular anchor. If pos is in the form "@x,y", where x and y are the window coordinates, the legend is drawn in the plotting area at the specified coordinates. The default is right.
-raised boolean
Indicates whether the legend is above or below the data elements. This matters only if the legend is in the 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 legend. 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 command. The resource name and class are legend and Legend respectively.
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 colors 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 several 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 element's default attributes.

The following operations are available for pen components.

pathName pen cget penName option
Returns the current value of the option given by option for penName. Option may be any option described below for the pen configure operation.
pathName pen configure penName ?penName... ?option value?...
Queries or modifies the configuration options of penName. Several pens can be modified at once. If option isn't specified, a list describing the current options for penName 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 pen option option is set to 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 indicates 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 fashion.
-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 command. 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 elements.
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 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.

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 postscript 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 PostScript. Each element of varName must consist of PostScript code to set a particular color value (e.g. ``1.0 1.0 0.0 setrgbcolor''). When generating color information 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 PostScript. 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). 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 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 graph will 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 bar chart 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 (``landscape'' orientation). Defaults to 0.
-maxpect boolean
Indicates to scale the plot so that it fills the PostScript 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.Decorations false
option add *Barchart.Postscript.Landscape true

pathName postscript output ?fileName? ?option value?...

Outputs a file of encapsulated PostScript. If a fileName argument 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 coordinate 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 command except that it operates on graph markers, 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 tagName. If the first character of command is + then command augments an existing binding rather than replacing it. If no command 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 bindings 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.
-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 horizontally. 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 vertically. 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 command. The resource class is either BitmapMarker, ImageMarker, LineMarker, PolygonMarker, TextMarker, or WindowMarker, depending on the type of marker. The resource name is the name of the marker.
option add *Barchart.TextMarker.Foreground white
option add *Barchart.BitmapMarker.Foreground white
option add *Barchart.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 provided 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 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.

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 background 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 representing 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 positioning 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 rectangular 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 markers 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 -fdashesR 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 connected line segments. It is assumed the first and last points are connected. 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.
-stipple bitmap
Specifies that the polygon should be drawn with a stippled pattern 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 annotate 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 positioning 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 background 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 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 positioning 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 barchart. PathName must be a child of the barchart widget.

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 commands 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 command.

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 format.

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.

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", 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;
}

See the vector manual page for more details.

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.
    ·
  • Try to minimize the number of data points. The more data points looked at, the more work the bar chart must do.
  • ·
  • 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.
  • ·
  • Don't stipple or dash the element. Solid bars are much faster.
  • ·
  • 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 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.

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 Reference Manual, page 568). The work-around is to break the polygon into separate pieces.

Keywords

bar chart, widget


Table of Contents

blt-2.4z.orig/html/beep.html0100644000175000017500000000275007434255425014527 0ustar dokodoko beep(n) manual page Table of Contents

Name

beep - ring the bell

Synopsis

beep ?percent?

Description

The beep command rings the keyboard bell. Percent is relative to the base volume of the keyboard bell and can range from -100 to 100 inclusive.

If percent is nonnegative then the bell volume is:
base - [(base * percent) / 100] + percent

If percent is negative then the bell volume is:
base + [(base * percent) / 100]

The default percent is 50.

Example


beep

Keywords

bell, beep


Table of Contents

blt-2.4z.orig/html/bgexec.html0100644000175000017500000003351307434255425015052 0ustar dokodoko bgexec(n) manual page Table of Contents

Name

bgexec - Run programs in the background while handling Tk events.

Synopsis

blt::bgexec varName ?option value?... program ?arg?...

Description

The bgexec command executes programs in the background, allowing Tk to handle events. A global Tcl variable varName is set when the program has completed.

Introduction

Tcl's exec command is very useful for gathering information from the operating system. It runs a program and returns the output as its result. This works well for Tcl-only applications. But for Tk applications, a problem occurs when the program takes time to process. Let's say we want the get the disk usage of a directory. We'll use the Unix program du to get the summary.
set out [exec du -s $dir]
puts "Disk usage for $dir is $out"

While du is running, scrollbars won't respond. None of the Tk widgets will be redrawn properly. The send command won't work. And the worst part is that the application appears hung up or dead. The problem is that while exec is waiting for du to finish, Tk is not able to handle X events.

The bgexec command performs the same functions as exec, but also allows Tk to handle events. You can execute a long-running program and the Tk widgets will behave normally. When the program finishes, its output and the exit status are written to Tcl variables. This makes it easy to monitor and save the output of a program.

Example

Here is the disk usage example again, this time using bgexec. The syntax to invoke "du" is exactly the same as the previous example, when we used exec.
global myStatus myOutput
blt::bgexec myStatus -output myOutput du -s $dir
puts "Disk usage for $dir is $myOutput"

Two global variables, myStatus and myOutput, will be set by bgexec when du has completed. MyStatus will contain the program's exit status. MyOutput, specified by the -output option, will store the output of the program.

You can also terminate the program by setting the variable myStatus. If myStatus is set before du has completed, the process is killed. Under Unix, this is done sending by a configurable signal (by default it's SIGKILL). Under Win32, this is done by calling TerminateProcess. It makes no difference what myStatus is set to.
set myStatus {}

There are several bgexec options to collect different types of information.
global myStatus myOutput myErrs
blt::bgexec myStatus -output myOutput -error myErrs du -s $dir

The -error option is similar to -output. It sets a global variable when the program completes. The variable will contain any data written to stderr by the program.

The -output and -error variables are set only after the program completes. But if the program takes a long time, to run you may want to receive its partial output. You can gather data as it becomes available using the -onoutput option. It specifies a Tcl command prefix. Whenever new data is available, this command is executed, with the data appended as an argument to the command.
proc GetInfo { data } {
puts $data
}
blt::bgexec myStatus -onoutput GetInfo du -s $dir

When output is available, the procedure GetInfo is called. The -onerror option performs a similar function for the stderr data stream.

Like exec, bgexec returns an error if the exit code of the program is not zero. If you think you may get a non-zero exit code, you might want to invoke bgexec from within a catch.
catch { blt::bgexec myStatus -output myOutput du -s $dir }

By default, bgexec will wait for the program to finish. But you can detach the program making ampersand (&) the last argument on the command line.
global myStatus myOutput
blt::bgexec myStatus -output myOutput du -s $dir &

Bgexec will return immediately and its result will be a list of the spawned process ids. If at some point you need to wait for the program to finish up, you can use tkwait. When the program finishes, the variable myStatus will be written to, breaking out the tkwait command.
global myStatus myOutput
blt::bgexec myStatus -output myOutput du -s $dir &
   ...
tkwait variable myStatus

Syntax

The bgexec command takes the following form:

   blt::bgexec varName ?option value?... program ?arg?...

VarName is the name of a global variable which is set when program has finished executing. The exit status of will be stored in varName. The exit status is a list of a status token, the process-id of the program, the exit code, and a status message. You can also prematurely terminate the program by setting varName. Under Unix, the program will be sent a signal to terminate it (by default the signal is a SIGKILL; see the -killsignal option).

Program is the name of the program to be executed and args are any extra arguments for program. The syntax of program and args is the same as the exec command. So you can redirect I/O, execute pipelines, etc. (see the exec manual for further information) just like exec. If the last argument is an ampersand (&), the program will be run detached, and bgexec will return immediately. VarName will still be set with the return status when program completes.

Options

Option refers to the switch name always beginning with a dash (-). Value is the value of the option. Option-value pairs are terminated either by the program name, or double dashes (--). The following options are available for bgexec:
-decodeerror encodingName

Specifies the encoding of the stderr channel. This affects only data returned to the Tcl interpreter. No translation is done on file redirection.
For example if data is to be converted from Unicode for use in Tcl, you would use the "unicode" encoding. The default is that no tranlation is performed.
-decodeoutput encodingName

Specifies the encoding of the stdout channels. This affects only data returned to the Tcl interpreter. No translation is done on file redirection.
For example if data is to be converted from Unicode for use in Tcl, you would use the "unicode" encoding. The default is that no tranlation is performed.
-error varName

Specifies that a global variable varName is to be set with the contents of stderr after the program has completed.
-keepnewline boolean
Specifies that a trailing newline should be retained in the output. If boolean is true, the trailing newline is truncated from the output of the -onoutput and -output variables. The default value is true.
-killsignal signal
Specifies the signal to be sent to the program when terminating. This is available only under Unix. Signal can either be a number (typically 1-32) or a mnemonic (such as SIGINT). If signal is the empty string, then no signal is sent. The default signal is 9 (SIGKILL).
-lasterror varName
Specifies a variable varName that is updated whenever data becomes available from standard error of the program. VarName is a global variable. Unlike the -error option, data is available as soon as it arrives.
-lastoutput varName
Specifies a variable varName that is updated whenever data becomes available from standard output of the program. VarName is a global variable. Unlike the -output option, data is available as soon as it arrives.
-linebuffered boolean
Specifies that updates should be made on a line-by-line basis. Normally when new data is available bgexec will set the variable (-lastoutput and -lasterror options) or invoke the command (-onoutput and -onerror options) delivering all the new data currently available. If boolean is true, only one line at a time will be delivered. This can be useful when you want to process the output on a line-by-line basis. The default value is false.
-output varName

Specifies that a global variable varName is to be set with the output of the program, once it has completed. If this option is not set, no output will be accumulated.
-onerror command
Specifies the start of a Tcl command that will be executed whenever new data is available from standard error. The data is appended to the command as an extra argument before it is executed.
-onoutput command
Specifies the start of a Tcl command that will be executed whenever new data is available from standard output. The data is appended to the command as an extra argument before it is executed.
-update varName
Deprecated. This option is replaced by -lasterror.
--
This marks the end of the options. The following argument will be considered the name of a program even if it starts with a dash (-).

Preemption

Because bgexec allows Tk to handle events while a program is running, it's possible for an application to preempt itself with further user-interactions. Let's say your application has a button that runs the disk usage example. And while the du program is running, the user accidently presses the button again. A second bgexec program will preempt the first. What this means is that the first program can not finish until the second program has completed.

Care must be taken to prevent an application from preempting itself by blocking further user-interactions (such as button clicks). The BLT busy command is very useful for just these situations. See the busy manual for details.

Differences with Fileevent

Since Tk 4.0, a subset of bgexec can be also achieved using the fileevent command. The steps for running a program in the background are:

Execute the program with the open command (using the "|" syntax) and save the file handle.
global fileId
set fileId [open "|du -s $dir" r]

Next register a Tcl code snippet with fileevent to be run whenever output is available on the file handle. The code snippet will read from the file handle and save the output in a variable.
fileevent fileId readable {
if { [gets $fileId line] < 0 } {
   close $fileId
   set output $temp
   unset fileId temp
} else {
   append temp $line
}
}

The biggest advantage of bgexec is that, unlike fileevent, it requires no additional Tcl code to run a program. It's simpler and less error prone. You don't have to worry about non-blocking I/O. It's handled tranparently for you.

Bgexec runs programs that fileevent can not. Fileevent assumes that the when stdout is closed the program has completed. But some programs, like the Unix compress program, reopen stdout, fooling fileevent into thinking the program has terminated. In the example above, we assume that the program will write and flush its output line-by-line. However running another program, your application may block in the gets command reading a partial line.

Bgexec lets you get back the exit status of the program. It also allows you to collect data from both stdout and stderr simultaneously. Finally, since data collection is handled in C code, bgexec is faster. You get back to the Tk event loop more quickly, making your application seem more responsive.

See Also

busy, exec, tkwait

Keywords

exec, background, busy


Table of Contents

blt-2.4z.orig/html/bitmap.html0100644000175000017500000002171507434255425015072 0ustar dokodoko bitmap(n) manual page Table of Contents

Name

bitmap - Define a new bitmap from a Tcl script

Synopsis

bitmap define bitmapName data ?option value?...

bitmap compose bitmapName text ?option value?...

bitmap exists bitmapName

bitmap source bitmapName

bitmap data bitmapName

bitmap height bitmapName

bitmap width bitmapName

Description

The bitmap command lets you create new bitmaps directly from your Tcl script. The bitmap can be specified as a list of data or a text string which is converted into a bitmap. You can arbitrarily scale or rotate the bitmap too.

Introduction

Bitmaps are commonly used within Tk. In label and button widgets, you display bitmaps them instead of text strings and in the canvas and text widgets, they're used for stippling. But Tk let's you can create new bitmaps only by reading the bitmap data from a file. This makes bitmaps cumbersome to manage, especially in packaging the program as a wish script, since each bitmap must be its own file. It would be nicer if you could create new bitmaps directly from your Tcl script.

The bitmap command lets you do just that. You can specify the bitmap as in various formats (such as the X11 bitmap format). You can also compose a bitmap from a text string. The bitmap command also lets you and arbitrarily rotate or scale the bitmap. For example, you could use this to create button widgets with the text label rotated 90 degrees.

Example

<<<<<<< bitmap.mann You can define a new bitmap with the define operation. For example, let's say you are using the X11 bitmap "gray1". Normally to use it, you would specify the location of the file.
label .l -bitmap @/usr/X11R6/include/X11/bitmaps/gray1

But you can simply cut and paste the contents of "gray1" into the bitmap command.
bitmap define gray1 {
#define gray1_width 2
#define gray1_height 2
static char gray1_bits[] = {
0x01, 0x02};
}
label .l -bitmap gray1

Tk will recognize "gray1" as a bitmap which can now be used with any widget that accepts bitmaps.

The bitmap data can be specified in a mulitude of forms. The following commands are all equivalent.
bitmap define gray1 {
#define gray1_width 2
#define gray1_height 2
static char gray1_bits[] = {
0x01, 0x02};
}
bitmap define gray1 { { 2 2 } { 0x01, 0x02 } }
bitmap define gray1 { { 2 2 } { 0x01 0x02 } }
bitmap define gray1 { { 2 2 } { 1 2 } }

Either the data is in the standard X11 bitmap form, or it's a list of two lists. The first list contains the height and width of the bitmap. The second list is the bitmap source data. Each element of that list is an hexadecimal number specifying which pixels are foreground (1) and which are background (0) of the bitmap. Note that the format of the source data is exactly that of the XBM format.

You can scale or rotate the bitmap as you create it, by using the -scale or-rotate options.
bitmap define gray1 {
#define gray1_width 2
#define gray1_height 2
static char gray1_bits[] = {
0x01, 0x02};
} -scale 2.0 -rotate 90.0

In addition, you can compose bitmaps from text strings. This makes it easy to create rotated buttons or labels. The text string can have multi-line.
bitmap compose rot_text "This is rotated\ntext" \
   -rotate 90.0 -font fixed

There are also a number of ways to query bitmaps. This isn't limited to bitmaps that you create, but any bitmap.
bitmap exists rot_text
bitmap width rot_text
bitmap height rot_text
bitmap data rot_text
bitmap source rot_text

The exists operation indicates if a bitmap by that name is defined. You can query the dimensions of the bitmap using the width and height operations. The data operation returns the list of the data used to create the bitmap. For example, you could query the data of a bitmap and send it across the network to another Tk application.
set data [bitmap data @/usr/X11R6/include/X11/bitmaps/ghost.xbm]
send {wish #2} bitmap define ghost $data

Operations

The following operations are available for bitmap:
bitmap compose bitmapName text ?option value?...
Creates a bitmap bitmapName from the text string text. A bitmap bitmapName can not already exist. The following options are available.
-font fontName
Specifies a font to use when drawing text into the bitmap. If this option isn't specified then fontName defaults to *-Helvetica-Bold-R-Normal-*-140-*.
-rotate theta
Specifies the angle of rotation of the text in the bitmap. Theta is a real number representing the angle in degrees. It defaults to 0.0 degrees.
-scale value
Specifies the scale of the bitmap. Value is a real number representing the scale. A scale of 1.0 indicates no scaling is necessary, while 2.0 would double the size of the bitmap. There is no way to specify differents scales for the width and height of the bitmap. The default scale is 1.0.
bitmap data bitmapName
Returns a list of both the dimensions of the bitmap bitmapName and its source data.
bitmap define bitmapName data ?option value?...
Associates bitmapName with in-memory bitmap data so that bitmapName can be used in later calls to Tk_GetBitmap. The bitmapName argument is the name of the bitmap; it must not previously have been defined in either a call to Tk_DefineBitmap or bitmap. The argument data describes the bitmap to be created. It is either the X11 bitmap format (a C structure) or a list of two lists: the dimensions and source data. The dimensions are a list of two numbers which are the width and height of the bitmap. The source data is a list of hexadecimal values in a format similar to the X11 or X10 bitmap format. The values may be optionally separated by commas and do not need to be prefixed with "0x". The following options are available.
-rotate theta
Specifies how many degrees to rotate the bitmap. Theta is a real number representing the angle. The default is 0.0 degrees.
-scale value
Specifies how to scale the bitmap. Value is a real number representing the scale. A scale of 1.0 indicates no scaling is necessary, while 2.0 would double the size of the bitmap. There is no way to specify differents scales for the width and height of the bitmap. The default scale is 1.0.
bitmap exists bitmapName
Returns 1 if a bitmap bitmapName exists, otherwise 0.
bitmap height bitmapName
Returns the height in pixels of the bitmap bitmapName.
bitmap source bitmapName
Returns the source data of the bitmap bitmapName. The source data is a list of the hexadecimal values.
bitmap width bitmapName
Returns the width in pixels of the bitmap bitmapName.

Limitations

Tk currently offers no way of destroying bitmaps. Once a bitmap is created, it exists until the application terminates.

Keywords

bitmap


Table of Contents

blt-2.4z.orig/html/bltdebug.html0100644000175000017500000000256607434255425015411 0ustar dokodoko bltdebug(n) manual page Table of Contents

Name

bltdebug - print Tcl commands before execution

Synopsis

bltdebug ?level?

Description

The bltdebug command is a simple tracing facility for Tcl commands. Each command line is printed before it is executed on standard error. The output consists of the command line both before and after substitutions have occurred. Level indicates at what level to stop tracing commands. If level is 0, no tracing is performed. This is the default. If no level argument is given, the current level is printed.

Keywords

debug


Table of Contents

blt-2.4z.orig/html/busy.html0100644000175000017500000002471507434255425014603 0ustar dokodoko busy(n) manual page Table of Contents

Name

busy - Make Tk widgets busy, temporarily blocking user interactions.

Synopsis

busy hold window ?option value?...

busy release window ?window?...

busy configure window ?option value?...

busy forget window ?window?...

busy isbusy ?pattern?

busy names ?pattern?

busy status window

Description

The busy command provides a simple means to block keyboard, button, and pointer events from Tk widgets, while overriding the widget's cursor with a configurable busy cursor.

Introduction

There are many times in applications where you want to temporarily restrict what actions the user can take. For example, an application could have a "run" button that when pressed causes some processing to occur. But while the application is busy processing, you probably don't want the the user to be able to click the "run" button again. You may also want restrict the user from other tasks such as clicking a "print" button.

The busy command lets you make Tk widgets busy. This means that user interactions such as button clicks, moving the mouse, typing at the keyboard, etc. are ignored by the widget. You can set a special cursor (like a watch) that overrides the widget's normal cursor, providing feedback that the application (widget) is temporarily busy.

When a widget is made busy, the widget and all of its descendents will ignore events. It's easy to make an entire panel of widgets busy. You can simply make the toplevel widget (such as ".") busy. This is easier and far much more efficient than recursively traversing the widget hierarchy, disabling each widget and re-configuring its cursor.

Often, the busy command can be used instead of Tk's grab command. Unlike grab which restricts all user interactions to one widget, with the busy command you can have more than one widget active (for example, a "cancel" dialog and a "help" button).

Example

You can make several widgets busy by simply making its ancestor widget busy using the hold operation.
frame .top
button .top.button; canvas .top.canvas
pack .top.button .top.canvas
pack .top
. . .
busy hold .top
update

All the widgets within .top (including .top) are now busy. Using update insures that busy command will take effect before any other user events can occur.

When the application is no longer busy processing, you can allow user interactions again by the release operation.

    busy release .top 
The busy window has a configurable cursor. You can change the busy cursor using the configure operation.
    busy configure .top -cursor "watch"
Finally, when you no longer need to the busy window, invoke the forget operation to free any resources it allocated.
    busy forget .top 
Destroying the widget will also clean up any resources allocated by the busy command.

Operations

The following operations are available for the busy command:
busy hold window ?option value?...
Makes the widget window (and its descendants in the Tk window hierarchy) busy. Window must be a valid path name of a Tk widget. The busy window is mapped the next time idle tasks are processed, and the widget and its descendants will be blocked from user interactions. All events in the widget window and its descendants are ignored. Normally update should be called immediately afterward to insure that the hold operation is in effect before the application starts its processing. The following configuration options are valid:
-cursor cursorName
Specifies the cursor to be displayed when the widget is made busy. CursorName can be in any form accepted by Tk_GetCursor. The default cursor is watch.
busy configure window ?option value?...
Queries or modifies the busy command configuration options for window. Window must be the path name of a widget previously made busy by the hold operation. If no options are specified, a list describing all of the available options for window (see Tk_ConfigureInfo for information on the format of this list) is returned. If option is specified with no value, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns the empty string. Option may have any of the values accepted by the hold operation.

Please note that the option database is referenced through window. For example, if the widget .frame is to be made busy, the busy cursor can be specified for it by either option command:

    option add *frame.busyCursor gumby
    option add *Frame.BusyCursor gumby
busy forget window ?window?...
Releases resources allocated by the busy command for window, including the busy window. User events will again be received again by window. Resources are also released when window is destroyed. Window must be the name of a widget specified in the hold operation, otherwise an error is reported.
busy isbusy ?pattern?
Returns the pathnames of all widgets that are currently busy. If a pattern is given, the path names of busy widgets matching pattern are returned.
busy names ?pattern?
Returns the pathnames of all widgets that have previously been made busy (i.e. a busy window is allocated and associated with the widget). It makes no difference if the window is currently busy or not. If a pattern is given, the path names of busy widgets matching pattern are returned.
busy release window ?window?...
Restores user interactions to the widget window again. This differs from the forget operation in that the busy window is not destroyed, but simply unmapped. Window must be the name of a widget specified in a hold operation, otherwise an error is reported.
busy status window
Returns the status of a widget window previously made busy. An error is reported if window was never made busy, or the forget operation was invoked (i.e. does not currently have a busy window associated with it). If window is presently can not receive user interactions, 1 is returned, otherwise 0.

Bindings

The event blocking feature is implemented by creating and mapping a transparent window that completely covers the widget. When the busy window is mapped, it invisibly shields the widget and its hierarchy from all events that may be sent. Like Tk widgets, busy windows have widget names in the Tk window hierarchy. This means that you can use the bind command, to handle events in the busy window.
busy hold .frame.canvas
bind .frame.canvas_Busy <Enter> { ... }

Normally the busy window is a sibling of the widget. The name of the busy window is "widget_Busy" where widget is the name of the widget to be made busy. In the previous example, the pathname of the busy window is ".frame.canvas_Busy" The exception is when the widget is a toplevel widget (such as ".") where the busy window can't be made a sibling. The busy window is then a child of the widget named "widget._Busy" where widget is the name of the toplevel widget. In the following example, the pathname of the busy window is "._Busy"
busy hold .
bind ._Busy <Enter> { ... }

Enter/Leave Events

Mapping and unmapping busy windows generates Enter/Leave events for all widgets they cover. Please note this if you are tracking Enter/Leave events in widgets.

Keyboard Events

When a widget is made busy, the widget is prevented from gaining the keyboard focus by the busy window. But if the widget already had focus, it still may received keyboard events. To prevent this, you must move focus to another window.
busy hold .frame
label .dummy
focus .dummy
update

The above example moves the focus from .frame immediately after invoking the hold so that no keyboard events will be sent to .frame or any of its descendants.

Keywords

busy, keyboard events, pointer events, window, cursor


Table of Contents

blt-2.4z.orig/html/container.html0100644000175000017500000003316707434255425015604 0ustar dokodoko container(n) manual page Table of Contents

Name

container - Widget to contain a foreign window.

Synopsis

container pathName ?options?

Description

The container widget lets you embed an X11 window from a foreign application into your Tk application. The foreign window is reparented inside of the widget. You can then place and arrange the container just as you would any Tk widget.

Introduction

Notebooks are a popular graphical paradigm. They allow you to organize many windows in a single widget. For example, you might have an application the displays several X-Y graphs at the same time. Typically, you can't pack the graphs into the same frame because they are too large. The other alternative is to pack the graphs into several toplevel widgets, allowing them to overlap on the screen. The problem is that all the different toplevel windows clutter the screen and are difficult to manage.

The container widget lets organize your application by displaying each graph as a page in a folder of a notebook. Only one page is visible at a time. When you click on a tab, the folder (graph) corresponding to the tab is displayed in the container widget. The container also lets you temporarily tear pages out of the notebook into a separate toplevel widget, and put them back in the container later. For example, you could compare two graphs side-by-side by tearing them out, and then replace them when you are finished.

A container may contain an unlimited number of folders. If there are too many tabs to view, you can arrange them as multiple tiers or scroll the tabs. The container uses the conventional Tk scrollbar syntax, so you can attach a scrollbar too.

Example

You create a container widget with the container command.
# Create a new container
container .c

A new Tcl command .c is also created. This command can be used to query and modify the container. For example, to change the default borderwidth, you use the new command and the container's configure operation.
# Change the default font.
.c configure -borderwidth 2

You can then add folders using the insert operation.
# Create a new folder "f1"
.c coinsert 0 "f1"

This inserts the new tab named "f1" into the container. The index 0 indicates location to insert the new tab. You can also use the index end to append a tab to the end of the container. By default, the text of the tab is the name of the tab. You can change this by configuring the -text option.
# Change the label of "f1"
.ts tab configure "f1" -label "Tab #1"

The insert operation lets you add one or more folders at a time.
.ts insert end "f2" -label "Tab #2" "f3" "f4"

The tab on each folder contains a label. A label may display both an image and a text string. You can reconfigure the tab's attributes (foreground/background colors, font, rotation, etc) using the tab configure operation.
# Add an image to the label of "f1"
set image [image create photo -file stopsign.gif]
.ts tab configure "f1" -image $image
.ts tab configure "f2" -rotate 90

Each folder may contain an embedded widget to represent its contents. The widget to be embedded must be a child of the container widget. Using the -window option, you specify the name of widget to be embedded. But don't pack the widget, the container takes care of placing and arranging the widget for you.
graph .ts.graph
.ts tab configure "f1" -window ".ts.graph" \
-fill both -padx 0.25i -pady 0.25i

The size of the folder is determined the sizes of the Tk widgets embedded inside each folder. The folder will be as wide as the widest widget in any folder. The tallest determines the height. You can use the tab's -pagewidth and -pageheight options override this.

Other options control how the widget appears in the folder. The -fill option says that you wish to have the widget stretch to fill the available space in the folder.
.ts tab configure "f1" -fill both -padx 0.25i -pady 0.25i

Now when you click the left mouse button on "f1", the graph will be displayed in the folder. It will be automatically hidden when another folder is selected. If you click on the right mouse button, the embedded widget will be moved into a toplevel widget of its own. Clicking again on the right mouse button puts it back into the folder.

If you want to share a page between two different folders, the -command option lets you specify a Tcl command to be invoked whenever the folder is selected. You can reset the -window option for the tab whenever it's clicked.
.ts tab configure "f2" -command {
.ts tab configure "f2" -window ".ts.graph"
}
.ts tab configure "f1" -command {
.ts tab configure "f1" -window ".ts.graph"
}

If you have many folders, you may wish to stack tabs in multiple tiers. The container's -tiers option requests a maximum number of tiers. The default is one tier.
.ts configure -tiers 2

If the tabs can fit in less tiers, the widget will use that many. Whenever there are more tabs than can be displayed in the maximum number of tiers, the container will automatically let you scroll the tabs. You can even attach a scrollbar to the container.
.ts configure -scrollcommand { .sbar set } -scrollincrement 20
.sbar configure -orient horizontal -command { .ts view }

By default tabs are along the top of the container from left to right. But tabs can be placed on any side of the container using the -side option.
# Arrange tabs along the right side of the container.
.ts configure -side right -rotate 270

Syntax

The container command creates a new window using the pathName argument and makes it into a container widget.
container pathName ?option value?...

Additional options may be specified on the command line or in the option database to configure aspects of the container such as its colors, font, text, and relief. The container command returns its pathName argument. At the time this command is invoked, there must not exist a window named pathName, but pathName's parent must exist.

When first created, a new container contains no tabs. Tabs are added or deleted using widget operations described below. It is not necessary for all the tabs to be displayed in the container window at once; commands described below may be used to change the view in the window. Containers allow scrolling of tabs using the -scrollcommand option. They also support scanning (see the scan operation). Tabs may be arranged along any side of the container window using the -side option.

The size of the container window is determined the number of tiers of tabs and the sizes of the Tk widgets embedded inside each folder. The widest widget determines the width of the folder. The tallest determines the height. If no folders contain an embedded widget, the size is detemined solely by the size of the tabs.

You can override either dimension with the container's -width and -height options.

Container Operations

All container operations are invoked by specifying the widget's pathname, the operation, and any arguments that pertain to that operation. The general form is:


   pathName operation ?arg arg ...?

Operation and the args determine the exact behavior of the command. The following operations are available for container widgets:

pathName cget option
Returns the current value of the configuration option given by option. Option may have any of the values accepted by the configure operation described below.
pathName configure ?option? ?value option value ...?
Query or modify the configuration options of the widget. If no option is specified, returns a list describing all the available options for pathName (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. Option and value are described below:
-background color
Sets the border color of the container.
-borderwidth pixels
Sets the width of the 3-D border around the outside edge of the widget. The -relief option determines how the border is to be drawn. The default is 2.
-command pattern
Specifies to search for a window whose WM_COMMAND property matches the given pattern. If no windows, or more than one window, matches the pattern, an error is generated. If pattern is the empty string, then no command search is performed. The default is "".
-cursor cursor
Specifies the widget's cursor. The default cursor is "".
-height pixels
Specifies the requested height of widget. If pixels is 0, then the height is height the embedded window plus the specified borderwidth. The default is 0.
-highlightbackground color
Sets the color to display in the traversal highlight region when the container does not have the input focus.
-highlightcolor color
Sets the color to use for the traversal highlight rectangle that is drawn around the widget when it has the input focus. The default is black.
-highlightthickness pixels
Sets the width of the highlight rectangle to draw around the outside of the widget when it has the input focus. Pixels is a non-negative value and may have any of the forms acceptable to Tk_GetPixels. If the value is zero, no focus highlight is drawn around the widget. The default is 2.
-name pattern
Specifies to search for a window whose WM_NAME property matches the given pattern. If no windows, or more than one window, matches the pattern, an error is generated. If pattern is the empty string, then no name search is performed. The default is "".
-relief relief
Specifies the 3-D effect for the container widget. Relief specifies how the container should appear relative to widget that it is packed into; for example, raised means the container should appear to protrude. The default is sunken.
-takefocus focus
Provides information used when moving the focus from window 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 decide whether to focus on the window. The default is 1.
-width pixels
Specifies the requested width of the widget. If pixels is 0, then the width is the width the embedded window and the specified borderwidth. The default is 0.
-window id
Specifies the foreign embedded using its X window id.
pathName find -command|-name pattern
Searches for all windows that match the given pattern. If the -command switch is given, all windows whose WWM_COMMAND property match pattern are returned in a list. If the -name switch is given, all windows whose WWM_NAME property match pattern are returned in a list. The list returned will contains pairs of the window id and the matching property.

Keywords

container, widget


Table of Contents

blt-2.4z.orig/html/cutbuffer.html0100644000175000017500000000406407434255425015601 0ustar dokodoko cutbuffer(n) manual page Table of Contents

Name

cutbuffer - Manipulate X cut buffer properties

Synopsis

cutbuffer get ?number?
cutbuffer rotate ?count?
cutbuffer set value ?number?

Description

The cutbuffer command allows you to read or modify the eight X cut buffer properties. You can also rotate the buffers properties.

Operations

The following operations are available for the cutbuffer command:
cutbuffer get ?number?
Returns the value of a cutbuffer number. Number must be a number between 0 and 7. The default is 0. The cutbuffer is returned exactly, except that NUL bytes are converted to '@' characters. If a cut buffer number does not exist, then "" is returned.
cutbuffer rotate ?count?
Rotates the cut buffers by count. Count must be a number between -7 and 7. The default is 1.
cutbuffer set value ?number?
Sets the cutbuffer number to value. Number must be a number between 0 and 7. The default is 0.

Keywords

cut buffer, property


Table of Contents

blt-2.4z.orig/html/dragdrop.html0100644000175000017500000004774307434255425015431 0ustar dokodoko drag&drop(n) manual page Table of Contents

Name

drag&drop - facilities for handling drag&drop data transfers

Synopsis

drag&drop source
drag&drop source window ?options?
drag&drop source window handler ?dataType? ?command arg arg...?

drag&drop target
drag&drop target window handler ?dataType command arg arg...?

drag&drop target window handle dataType ?value?

drag&drop token window

drag&drop drag window x y
drag&drop drop window x y
drag&drop active
drag&drop errors ?proc?
drag&drop location ?x y?

Description

The drag&drop command provides access to a set of facilities for managing drag-and-drop data transfers. Any of the usual Tk widgets can be registered to participate in the drag-and-drop process. Widgets registered as a drag&drop source can export data to other widgets registered as a drag&drop target. Note that a particular widget can be registered as a source, as a target, or as both.

The drag-and-drop process begins when the user clicks and holds a mouse button in a source window; a token window appears with an icon or message to represent the data being transferred. As the user moves the mouse pointer, the token window follows along, acting as a movable packet of data. Whenever the mouse pointer falls on a valid target window, the border of the token window is changed to a raised (active) state. When the mouse button is released over the target window, a Tcl routine is invoked to send the data to the desired application, and the target window is asked to "handle" the data. If this communication process fails, a rejection symbol (a circle with a line through it) is displayed on the token window to indicate failure.

The details of the communication process are fully configurable by the application developer. In the simplest case, the value that is sent to the target window is a simple string. The target window is simply asked to "handle" that string value. In general, the source window can have a special "handler" procedure to transfer a particular data type by issuing a series of "send" commands. After this, the target window is again asked to "handle" the result.

Both sources and targets can have a list of "handlers" for different data types. As a token window is dragged from its source to various targets, each target is checked to see if it recognizes a handler offered by the source. If it does, it is treated as a valid target. Otherwise, it is ignored. This scheme allows the same source to interact with many different kinds of targets. For example, a source for RGB color samples might have "color" and "string" handlers. This would allow it to communicate with "color" targets (sending RGB data) as well as entry widgets (sending strings of the form "#rrggbb").

This introduction was presented as a brief overview of the communication process; further details are presented below:

drag&drop source
Returns a list of path names for widgets registered as drag&drop sources. Returns an empty string if no widgets have been registered.
drag&drop source window ?options?
Registers a new drag&drop source window with the given options, or modifies the options for an existing window:


Name:    buttonBinding
Class:    ButtonBinding
Switch:    -button n
Specifies the mouse button (integer 1-5) that will invoke the drag&drop
operation on the source window. This causes the following bindings to be added to the widget:


bind win <ButtonPress-n> {drag&drop drag %W %X %Y}
bind win <Bn-Motion> {drag&drop drag %W %X %Y}
bind win <ButtonRelease-n> {drag&drop drop %W %X %Y}

The default value is button 3. If the value "0" is specified, then no bindings are added; this enables the user to establish bindings manually.


Name:    packageCommand
Class:    Command
Switch:    -packagecmd command
Specifies a Tcl command used to establish the appearance of the token
window at the start of each drag&drop operation. This command is automatically invoked by the drag&drop drag command whenever the token window is about to be mapped for a drag operation. It should update the appearance of the token window to represent the data that is being moved.

The following substitutions are made in the command string before it is executed:

%t
Replaced with the window path name for the token which represents the data being dragged.
%W
Replaced with the window path name for the drag&drop source.

The return value from the package command represents the data being transferred. If the package command returns an empty string, the drag operation is quietly aborted. This can be used to disallow drag&drop operations from certain parts of a widget, if the drag position is inappropriate.

For example, the following package routine will select an item from a listbox and configure the token window to display the selected string. It uses the drag&drop location command to determine the entry in the listbox that the user has selected and it returns this as the data value:


proc package_list_item {lbox token} {
    set xy [drag&drop location]
    set y  [expr [lindex $xy 1]-[winfo rooty $lbox]]
    set str [$lbox get [$lbox nearest $y]]
    $token.value configure -text $str
    return $str
}

The return value is available later when the source and target communicate. If the source has a command associated with its data handler, then this value is substituted in place of "%v" in the source handler. Otherwise, it is substituted in place of "%v" in the target handler.


Name:    rejectBackground
Class:    Background
Switch:    -rejectbg color
Specifies the color used to draw the background of the rejection symbol
on the token window. The rejection symbol (a circle with a line through it--the international "no") appears whenever communication fails.


Name:    rejectForeground
Class:    Foreground
Switch:    -rejectfg color
Specifies the color used to draw the foreground of the rejection symbol
on the token window.


Name:    rejectStipple
Class:    Stipple
Switch:    -rejectstipple pattern
Specifies a stipple pattern used to draw the foreground of the rejection
symbol on the token window. Any of the forms acceptable to Tk_GetBitmap can be used.


Name:    selfTarget
Class:    SelfTarget
Switch:    -selftarget boolean
If the boolean value is true, and if a source widget is also
registered as a compatible target, then the source will be able to transmit to itself during drag&drop operations. This is primarily useful for complex sources such as a canvas widget, where items may be moved from place to place within the same widget. By default, this option is disabled.


Name:    send
Class:    Send
Switch:    -send list
Specifies a list of dataTypes enabled for communication. Only
dataTypes defined by commands of the form "drag&drop source window handler ?dataType ?command arg arg...?" are allowed. This list also determines the priority of the various dataTypes. When a token window is over a potential drag&drop target, this list is searched from start to finish for a dataType that is also recognized by the target. The first matching dataType found determines the value that will be sent if the token is dropped. If no matching dataType is found, then the target is incompatible, and is ignored. By default, this option has the value "all", indicating that all dataTypes should be considered in the order that they were defined for the source.

Note that this option makes it easy to control a drag&drop source. Setting the value to an empty string disables the source; setting the value back to "all" restores communication.


Name:    siteCommand
Class:    Command
Switch:    -sitecmd command
Specifies a Tcl command used to update the appearance of the token window.
If specified, this command is automatically invoked by the drag&drop drag command whenever the token window is over a compatible drag&drop target.

The following substitutions are made in the command string before it is executed:

%s
Replaced with "1" if the token window is over a compatible target, and "0" otherwise.
%t
Replaced with the window path name for the token which represents the data being dragged.

Regardless of this command, border of the token window will become raised whenever the token is over a valid target. This command can be used to display other visual cues.


Name:    tokenAnchor
Class:    Anchor
Switch:    -tokenanchor anchor
Specifies how the token window is positioned relative to the mouse
pointer coordinates passed to the drag&drop drag command. Must be one of the values n, s, e, w, center, nw, ne, sw or se. For example, "nw" means to position the token such that its upper-left corner is at the mouse pointer. The default value is "center".


Name:    tokenBackground
Class:    Background
Switch:    -tokenbg color
Specifies the color used to draw the background of the token window.


Name:    tokenBorderWidth
Class:    BorderWidth
Switch:    -tokenborderwidth size
Specifies the width in pixels of the border around the token window.
This border becomes raised to indicate when the token is over a compatible drag&drop target site. The value may have any of the forms acceptable to Tk_GetPixels. The default value is "3".


Name:    tokenCursor
Class:    Cursor
Switch:    -tokencursor cursor
Specifies the cursor used when a token window is active. The value
may have any of the forms acceptable to Tk_GetCursor. The default value is "center_ptr".
drag&drop source window handler ?dataType? ?command arg arg...?
With no extra arguments, this command returns a list of all dataType names that have been registered for the source window. If only the dataType is specified, then the dataType is created if necessary, and the command associated with the dataType is returned. Otherwise, it concatenates the command and any extra arg strings, and registers a new dataType with this command.

The following substitutions are made in the command string before it is executed:

%i
Replaced with the name of the interpreter for the target application.
%v
Replaced with the value returned from the "-packagecmd" command.
%w
Replaced with the window path name for the target window.

A typical source handler contains one or more "send" commands which transfer data to the remote application. The target window is then asked to handle the new data. Whatever value is returned by the source command handler is automatically substituted into the "%v" fields of the target handler.

This separation between the transfer and the handling of the data is important. It allows the same source handler to transfer data for many different targets, and it allows each of the targets to handle the incoming data differently. If an error is encountered during the communication process, the rejection symbol is posted on the token window to indicate failure.

drag&drop target
Returns a list of path names for widgets registered as drag&drop targets. Returns an empty string if no widgets have been registered.
drag&drop target window handler ?dataType command arg arg...?
Registers a new drag&drop target window with a given handler, or modifies the handlers for an existing window. If no dataType is specified, this command returns the current list of recognized dataType strings. Each dataType is a symbolic name representing a form of data, and the corresponding command is a Tcl command that specifies how the target will make use of the data. This command is invoked indirectly after a source has transferred data to a target application.

The following substitutions are made in the command string before it is executed:

%v
In the simplest case, the source window does not have a handler command for the selected dataType, and this field is replaced with the result from the "-packagecmd" command. When the source does have a handler command, the result from the "-packagecmd" command is substituted into its "%v" field, and the result from this command is substituted into this field in the target command.
%W
Replaced with the window path name for the target window.
drag&drop target window handle dataType ?value?
Searches for the given dataType name among the handlers registered for the target window, and invokes the appropriate command. If a value is specified, it is substituted into any "%v" fields in the handler command associated with the dataType. If the dataType name is not recognized, this command returns an error. This command is invoked automatically by the drag&drop facility when data is being transferred from a source to a target.
drag&drop token window
Returns the token window associated with a drag&drop source window. The token window is used to represent data as it is being dragged from the source to a target. When a source is first established, its token window must be filled with widgets to display the source data. For example,


drag&drop source .foo
set win [drag&drop token .foo]
label $win.label -text "Data"
pack $win.label

drag&drop drag window x y
Marks the start of (or movement during) a drag&drop operation. If the token window is unmapped when this command is invoked, then the -packagecmd for the source window is executed. If this command is successful and returns a non-null string, the token window is mapped. On subsequent calls, the token window is moved to the new x y location. Unless the "-button 0" option is specified for the source, this command is automatically bound to <ButtonPress-n> and <Bn-Motion> events for "-button n" of the source widget.
drag&drop drop window x y
Marks the end of a drag&drop operation. If the mouse pointer is over a compatible target window, then the appropriate send handler for the first compatible dataType is invoked to handle the data transfer. If the data transfer is successful, then the token window is unmapped; otherwise, a rejection symbol is drawn on the token window, and the window is unmapped after a small delay. Unless the "-button 0" option is specified for the source, this command is automatically bound to the <ButtonRelease-n> event for "-button n" of the source widget.
drag&drop active
Returns "1" if a drag&drop operation is in progress, and "0" otherwise. A drag&drop operation officially starts after the package command has been executed successfully, and ends after the send handler has been executed (successfully or otherwise).
drag&drop errors ?proc?
Specifies a Tcl proc used to handle errors encountered during drag&drop operations. If a proc is not specified, this command returns the current error handler. By default, all errors are sent to the usual tkerror command, and therefore appear in a dialog box to the user. This behavior is quite useful when debugging communication protocols, but may not be desirable in a finished application. Errors can be suppressed entirely (leaving the rejection symbol as the only error indicator) by specifying a null string in place of the proc name.
drag&drop location ?x y?
Used to set or query the pointer location during a drag&drop operation. The x y arguments specify the current location; if these arguments are missing, then the last reported (x,y) location is returned as a list with two elements. This command is issued automatically within the drag&drop drag and drag&drop drop commands, to keep track of pointer movement.

Keywords

drag&drop, send, bind, widget


Table of Contents

blt-2.4z.orig/html/eps.html0100644000175000017500000015772407434255425014417 0ustar dokodoko graph(n) manual page Table of Contents

Name

eps - Encapsulated PostScript canvas item.

Synopsis

canvas create eps x y ?option value?...

Description

The eps canvas item lets you place encapulated PostScript (EPS) on a canvas, controlling its size and placement. The EPS item is displayed either as a solid rectangle or a preview image. The preview image is designated in one of two ways: 1) the EPS file contains an ASCII hexidecimal preview, or 2) a Tk photo image. When the canvas generates PostScript output, the EPS will be inserted with the proper translation and scaling to match that of the EPS item. So can use the canvas widget as a page layout tool.

Example

Let's say you have for PostScript files of four graphs which you want to tile two-by-two on a single page. Maybe you'd like to annotate the graphs by putting a caption at the bottom of each graph.

Normally, you would have to resort to an external tool or write your own PostScript program. The eps canvas item lets you do this through Tk's canvas widget. An eps item displays an image (or rectangle) representing the encapsulated PostScript file. It also scales and translates the EPS file when the canvas is printed.

Syntax


canvas create eps x y ?option value?...

The eps item creates a new canvas item. Canvas is the name of a canvas widget. You must supply the X-Y coordinate of the new eps item. How the coordinate is exactly interpretered is controlled by the -anchor option (see below).

Additional options may be specified on the command line to configure aspects of the eps item such as its color, stipple, and font. The following option and value pairs are valid.

-anchor anchor
Tells how to position the EPS item relative to its X-Y coordinate. The default is center.
-background color
Sets the background color of the EPS rectangle.
-borderwidth pixels
Sets the width of the 3-D border around the outside edge of the item. The -relief option determines if the border is to be drawn. The default is 0.
-file fileName
Specifies the name of the EPS file. The first line of an EPS file must start with "%!PS" and contain a "EPS" version specification. The other requirement is that there be a "%%BoundingBox:" entry which contains four integers representing the lower-left and upper-right coordinates of the area bounding the EPS. The default is "".
-font fontName
Specifies the font of the title. The default is *-Helvetica-Bold-R-Normal-*-18-180-*.
-foreground color
Specifies the foreground color of the EPS rectangle. The option matters only when the -stipple option is set. The default is white.
-height pixels
Specifies the height EPS item. If pixels is 0, then the height is determined from the PostScript "BoundingBox:" entry in the EPS file. The default is 0.
-image photo
Specifies the name of a Tk photo image to be displayed as in the item as a preview image. This option overrides any preview specification found in the EPS file. The default is "".
-justify justify
Specifies how the title should be justified. This matters only when the title contains more than one line of text. Justify must be left, right, or center. The default is center.
-relief relief
Specifies the 3-D effect for the EPS item. Relief specifies how the item should appear relative to canvas; for example, raised means the item should appear to protrude. The default is flat.
-shadowcolor color
Specifies the color of the drop shadow used for the title. The option with the -shadowoffset option control how the title's drop shadow appears. The default is grey.
-shadowoffset pixels
Specifies the offset of the drop shadow from the title's text. If pixels is 0, no shadow will be seen. The default is 0.
-showimage boolean
Indicates whether to display the image preview (if one exists), or a simple rectangle. The default is yes.
-stipple bitmap
Specifies a bitmap to used to stipple the rectangle representing the EPS item. The default is "".
-title string
Sets the title of the EPS item. If string is "", then the title specified by the PostScript "Title:" entry is used. You can set the string a single space to display no title. The default is "".
-titleanchor anchor
Tells how to position the title within EPS item. The default is n.
-titlecolor color
Specifies the color of the title. The default is white.
-titlerotate degrees
Sets the rotation of the title. Degrees is a real number representing the angle of rotation. The title is first rotated in space and then placed according to the -titleanchor position. The default rotation is 0.0.
-width pixels
Specifies the width EPS item. If pixels is 0, then the width is determined from the PostScript "BoundingBox:" entry in the EPS file. The default is 0. 5i.

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 and 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 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 display the new values.
# Change the X-Y coordinates of the first point.
set xVec(0) 0.18
set yVec(0) 25.18

An element named line1 is now created in .g. By default, the element's label in the legend will be also line1. You can change the label, or specify no legend entry, again using the element's configure operation.
# Don't display "line1" in the legend.
.g element configure line1 -label ""

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.
.g element configure line1 -symbol square -color red \
   -dashes { 2 4 2 } -linewidth 2 -pixels 2c

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 "line1" on the alternate Y-axis "y2".
.g element configure line1 -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.
.g 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.
.g axis configure 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 configuration 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 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 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 configure 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 configure -hide no -dashes { 2 2 }

Finally, to get hardcopy of the graph, use the postscript component.
# Print the graph into file "file.ps"
.g postscript output file.ps -maxpect 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 (i.e. the background of the margins, legend, and plotting area will be white).

Graph Operations

pathName axis operation ?arg?...
See the AXIS COMPONENTS section.
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 configure 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.
-borderwidth pixels
Sets the width of the 3-D border around the outside edge of the widget. The -relief option determines if the border 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 display 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 matters only when the title contains more than one line of text. Justify must be left, right, or center. The default is center.
-leftmargin pixels
Sets the size of the margin from the left edge of the window to the Y-coordinate axis. If pixels is 0, the size is calculated automatically. 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
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 window 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
Specifies a tiled background for the widget. If image isn't "", the background is tiled using image. Otherwise, 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
Specifies the size of the margin above the x2 axis. If pixels is 0, the margin size is calculated automatically.
-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
Reports the size of a particular items 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 y graph coordinates.
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 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
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 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.

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 plotted. 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 "tempAxis"
.g axis create tempAxis

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 tempAxis data to this axis.
.g element create "e1" -xdata $x -ydata $y -mapy tempAxis

While you can create many axes, only four 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 bottom 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 components: 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.
# Display the axis tempAxis in the left margin.
.g yaxis use tempAxis

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 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.
pathName axis configure axisName ?axisName?... ?option value?...
Queries or modifies the configuration options of axisName. Several axes can be changed. If option isn't specified, a list describing all the current options for axisName 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 axis option option is set to value. The following options are valid for axes.
-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 graph is redrawn. You may query configuration options. But do not them, because this can have unexpected results.

-descending boolean
Indicates whether the values along the axis are monotonically 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 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 "" is given as either description, then the that limit will not be displayed. The default is "".
-linewidth pixels
Sets the width of the axis and tick lines. The default is 1 pixel.
-logscale boolean
Indicates whether the scale of the axis is logarithmic or linear. If boolean is true, the axis is logarithmic. The default scale is linear.
-loose boolean
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 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 computed. 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 intervals. 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 automatically 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.
-showticks boolean
Indicates whether axis ticks should be drawn. If boolean is true, ticks are drawn. If false, only the axis line is drawn. The default is 1.
-stepsize value
Specifies the interval between major axis ticks. If value isn't a valid interval (must be less than the axis range), the request is ignored and the step size is automatically calculated.
-subdivisions number
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-*.
-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 *-Helvetica-Bold-R-Normal-*-14-140-*.

Axis configuration options may be also be set by the option command. 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 elements.
pathName axis invtransform axisName value
Performs the inverse transformation, changing the screen coordinate 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 mapping the it to axisName. Returns the transformed screen coordinate.

Only four axes can be displayed simultaneously. By default, they are x, y, x2, and y2. You can 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 component does. The xaxis component manages the X-axis located in the bottom margin (whatever axis that happens to be). Likewise, yaxis uses the Y-axis in the left margin, x2axis the top X-axis, and y2axis the right Y-axis.

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. 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 location. 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 without redrawing the entire graph.

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.
-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 mapping 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 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.

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 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 varName ?option value?... ?elemName?...
Finds the data point closest to the window coordinates x and y in the element elemName. ElemName is the name of an element, that must not be hidden. If no elements are specified, then all visible elements are searched. It returns via the array variable varName the name of the closest element, the index of its closest point, and the graph coordinates of the point. Returns 0, if no data point within the threshold distance can be found, otherwise 1 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 graph's -halo option.
-interpolate boolean
Indicates that both the data points and interpolated points along the line segment formed should be considered. If boolean is true, the closest line segment will be selected instead of the closest point. If this option isn't specified, boolean defaults to 0.
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.
-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 a list of numeric expressions representing the X-Y coordinate pairs of each data point.
-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.
-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.
-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" pixels 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 defcolor, 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.
-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 false, the element's symbols are drawn at the designated size, regardless of axis scales. The default is 0.
-smooth smooth
Specifies how connecting line segments are drawn between data points. Smooth can be either linear, step, natural, or quadratic. If smooth is linear, a single line segment is drawn, connecting both data points. When smooth is step, 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 natural and quadratic generate multiple segments between data points. If natural, the segments are generated using a cubic spline. If quadratic, a quadratic 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 bitmap'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 monotonically 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 representing 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 command. 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 create elemName ?option value?...

Creates a new element elemName. It's an error is an element elemName already exists. If additional arguments are present, they specify options valid for the element configure operation.
pathName element deactivate elemName ?elemName?...
Deactivates all the elements matching pattern. Elements whose names match any of the patterns given are redrawn using their normal colors.
pathName element delete ?elemName?...
Deletes all the named elements. The graph is automatically redrawn.
pathName element exists elemName
Returns 1 if an element elemName currently exists and 0 otherwise.
pathName element names ?pattern?...
Returns the elements matching one or more pattern. If no pattern is given, the names of all elements is returned.
pathName element show ?nameList?
Queries or modifies the element display list. The element display 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 display 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 horizontally 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 following 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 true, grid lines are not shown. The default is yes.
-linewidth pixels
Sets the width of grid lines. The default width is 1.
-mapx xAxis
Specifies the X-axis to display grid lines. XAxis must be the name of an axis. The default is x.
-mapy yAxis
Specifies the Y-axis to display grid lines. YAxis must be the name of an axis. The default is y.
-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.

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.
    ·
  • Try to minimize the number of data points. The more data points the looked at, the more work the graph must do.
  • ·
  • 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.
  • ·
  • 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.
  • ·
  • Don't stipple or dash the element. Solid lines are much faster.
  • ·
  • 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 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.

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 Reference Manual, page 568). The work-around is to break the polygon into separate pieces.

Future Incompatibility

The -mapped options are obsoleted and will be removed. You can achieve the same results using the -hide option instead.
# Works for now.
.g legend configure -mapped no

# Instead use this.
.g legend configure -hide yes

Keywords

graph, widget


Table of Contents

blt-2.4z.orig/html/graph.html0100644000175000017500000032656207434255425014727 0ustar dokodoko graph(n) manual page Table of Contents

Name

graph - 2D graph for plotting X-Y coordinate data.

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 annotation 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 symbol, 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 widgets.
pen
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 -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


graph pathName ?option value?...

The graph command creates a new window pathName and makes it into a graph 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, graph 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:

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.

pathName component operation ?arg?...

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.

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 coordinates.
# 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 -barwidth option.
# Change the X-Y coordinates of the first point.
set xVec(0) 0.18
set yVec(0) 25.18

An element named line1 is now created in .g. By default, the element's label in the legend will be also line1. You can change the label, or specify no legend entry, again using the element's configure operation.
# Don't display "line1" in the legend.
.g element configure line1 -label ""

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.
.g element configure line1 -symbol square -color red \
   -dashes { 2 4 2 } -linewidth 2 -pixels 2c

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 "line1" on the alternate Y-axis "y2".
.g element configure line1 -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.
.g 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.
.g axis configure 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 configuration 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 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 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 configure 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 configure -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 repositioned 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 -maxpect 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 (i.e. the background of the margins, legend, and plotting area will be white).

Graph Operations

pathName axis operation ?arg?...
See the AXIS COMPONENTS section.
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 configure 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.
-borderwidth pixels
Sets the width of the 3-D border around the outside edge of the widget. The -relief option determines if the border 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 display 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 matters only when the title contains more than one line of 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-coordinate 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 extending from the plotting area to the right edge of the window. By default, the legend is drawn in this margin. If pixels is 0, the automatically computed size is used. The default is 0.
-takefocus focus
Provides information used when moving the focus from window 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
Specifies a tiled background for the widget. If image isn't "", the background is tiled using image. Otherwise, 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 coordinates.
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 graph. If present, fileName is the file name of the new metafile. Otherwise, the metafile is automatically 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
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 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.

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 plotted. By default, the minimum and maximum limits are determined from the data, but you can reset either limit.

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 element's -mapy and -mapx configuration options. They specify the coordinate 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 component 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 command 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 tagName. If the first character of command is + then command augments an existing binding rather than replacing it. If no command 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 bindings 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.
pathName axis configure axisName ?axisName?... ?option value?...
Queries or modifies the configuration options of axisName. Several axes can be changed. If option isn't specified, a list describing all the current options for axisName 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 axis option option is set to value. The following options are valid for axes.
-bindtags tagList
Specifies the binding tags for the axis. TagList 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 all.
-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 graph is redrawn. You may query configuration options. But do not them, because this can have unexpected results.

-descending boolean
Indicates whether the values along the axis are monotonically increasing or decreasing. If boolean is true, the axis values will be decreasing. The default is 0.
-hide string
Indicates if the axis and all the elements mapped to it will be displayed. The valid values for string are shown below. The default value is 0.
false
The axis and its data elements are displayed.
true
The axis is hidden, but the data elements mapped to it are displayed.
all
The axis and its data elements are hidden.
-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 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 "" is given as either description, then the that limit will not be displayed. The default is "".
-linewidth pixels
Sets the width of the axis and tick lines. The default is 1 pixel.
-logscale boolean
Indicates whether the scale of the axis is logarithmic or linear. If boolean is true, the axis is logarithmic. The default scale is linear.
-loose boolean
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 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 computed. 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 intervals. 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 automatically 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.
-showticks boolean
Indicates whether axis ticks should be drawn. If boolean is true, ticks are drawn. If false, only the axis line is drawn. The default is 1.
-stepsize value
Specifies the interval between major axis ticks. If value isn't a valid interval (must be less than the axis range), the request is ignored and the step size is automatically calculated.
-subdivisions number
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-*.
-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 *-Helvetica-Bold-R-Normal-*-14-140-*.

Axis configuration options may be also be set by the option command. 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 elements.
pathName axis invtransform axisName value
Performs the inverse transformation, changing the screen coordinate 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 mapping the it to axisName. Returns the transformed screen coordinate.

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 component 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 location. 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 without redrawing the entire graph.

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.
-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 mapping 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 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.

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 command except that it operates on graph elements, 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 tagName. If the first character of command is + then command augments an existing binding rather than replacing it. If no command 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 bindings 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 varName ?option value?... ?elemName?...
Finds the data point closest to the window coordinates x and y in the element elemName. ElemName is the name of an element, that must not be hidden. If no elements are specified, then all visible elements are searched. It returns via the array variable varName the name of the closest element, the index of its closest point, and the graph coordinates of the point. Returns 0, if no data point within the threshold distance can be found, otherwise 1 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 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 values for string are described below.
no
Search only for the closest data point.
yes
Search includes projections that lie along the line segments connecting the data points.
x
Search includes vertical projections from the given X-coordinate.
y
Search includes horizontal projections from the given Y-coordinate.
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 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 a list of numeric expressions representing the X-Y coordinate pairs of each data point.
-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.
-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.
-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" pixels 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 defcolor, 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.
-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 false, the element's symbols are drawn at the designated size, regardless of axis scales. The default is 0.
-smooth smooth
Specifies how connecting line segments are drawn between data points. Smooth can be either linear, step, natural, or quadratic. If smooth is linear, a single line segment is drawn, connecting both data points. When smooth is step, 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 natural and quadratic generate multiple segments between data points. If natural, the segments are generated using a cubic spline. If quadratic, a quadratic 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 bitmap'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 monotonically 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 representing 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 command. 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 create elemName ?option value?...

Creates a new element elemName. It's an error is an element elemName already exists. If additional arguments are present, they specify options valid for the element configure operation.
pathName element deactivate elemName ?elemName?...
Deactivates all the elements matching pattern. Elements whose names match any of the patterns given are redrawn using their normal colors.
pathName element delete ?elemName?...
Deletes all the named elements. The graph is automatically redrawn.
pathName element exists elemName
Returns 1 if an element elemName currently exists and 0 otherwise.
pathName element names ?pattern?...
Returns the elements matching one or more pattern. If no pattern is given, the names of all elements is returned.
pathName element show ?nameList?
Queries or modifies the element display list. The element display 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 display 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 horizontally 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 following 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 true, grid lines are not shown. The default is yes.
-linewidth pixels
Sets the width of grid lines. The default width is 1.
-mapx xAxis
Specifies the X-axis to display grid lines. XAxis must be the name of an axis or "" for no grid lines. The default is "".
-mapy yAxis
Specifies the Y-axis to display grid lines. YAxis must be the name of an axis or "" for no grid lines. The default is y.
-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 command. The resource name and class are grid and Grid respectively.
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 positioned 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 colors 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 tagName. If the first character of command is + then command augments an existing binding rather than replacing it. If no command 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 bindings have been defined for tagName.

pathName legend cget option
Returns the current value of a legend configuration option. Option may be any option described below in the legend configure operation.
pathName legend configure ?option value?...
Queries or modifies the configuration options for the legend. If option isn't specified, a list describing the current legend 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 legend option option is set to value. The following options are valid for the legend.
-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 legend, relative to the surface of the legend. The default is flat.
-anchor anchor
Tells how to position the legend relative to the positioning 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 legend vertically.
top or bottom
The anchor describes how to position the legend horizontally.
@x,y
The anchor specifies how to position the legend 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 occupied by the legend will be at the positioning point.
plotarea
The anchor specifies how to position the legend relative to the plotting area. For example, 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 plotting area.
-background color
Sets the background color of the legend. If color is "", the legend background with be transparent.
-bindtags tagList
Specifies the binding tags for legend entries. TagList 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 all.
-borderwidth pixels
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 *-Helvetica-Bold-R-Normal-*-12-120-*.
-foreground color
Sets the foreground color of the text drawn for the element'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 bottom 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 distances. 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.
-position pos
Specifies where the legend is drawn. The -anchor option also affects where the legend is positioned. If pos is left, left, top, or bottom, the legend is drawn in the specified margin. If pos is plotarea, then the legend is drawn inside the plotting area at a particular anchor. If pos is in the form "@x,y", where x and y are the window coordinates, the legend is drawn in the plotting area at the specified coordinates. The default is right.
-raised boolean
Indicates whether the legend is above or below the data elements. This matters only if the legend is in the 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 legend. 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 command. The resource name and class are legend and Legend respectively.
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 colors 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 operation.
.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 element's default attributes.

The following operations are available for pen components.

pathName pen cget penName option
Returns the current value of the option given by option for penName. Option may be any option described below for the pen configure operation.
pathName pen configure penName ?penName... ?option value?...
Queries or modifies the configuration options of penName. Several pens can be modified at once. If option isn't specified, a list describing the current options for penName 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 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" pixels 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 defcolor, 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 bitmap's optional mask. The default is circle.
-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 "line".

Pen configuration options may be also be set by the option command. The resource class is Pen. The resource names are the names of the pens.
option add *Graph.Pen.Color blue
option add *Graph.activeLine.color 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 elements.
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 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.

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 postscript 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 PostScript. Each element of varName must consist of PostScript code to set a particular color value (e.g. ``1.0 1.0 0.0 setrgbcolor''). When generating color information 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 PostScript. 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). 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 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 (``landscape'' orientation). Defaults to 0.
-maxpect boolean
Indicates to scale the plot so that it fills the PostScript 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 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 *Graph.postscript.Decorations false
option add *Graph.Postscript.Landscape true

pathName postscript output ?fileName? ?option value?...

Outputs a file of encapsulated PostScript. If a fileName argument 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 coordinate 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 command except that it operates on graph markers, 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 tagName. If the first character of command is + then command augments an existing binding rather than replacing it. If no command 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 bindings 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.
-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 element symbols and lines. Otherwise, the marker is drawn on top of the element. The default is 0.
-xoffset pixels
Specifies a screen distance to offset the marker horizontally. 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 vertically. 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 command. The resource class is either BitmapMarker, ImageMarker, LineMarker, PolygonMarker, TextMarker, or WindowMarker, depending 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 provided 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 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.

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 background 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 representing 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 positioning 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 rectangular 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 markers 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 -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 connected line segments. It is assumed the first and last points are connected. 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.
-stipple bitmap
Specifies that the polygon should be drawn with a stippled pattern 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 annotate 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 positioning 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 background 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 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 positioning 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 commands 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 command.

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 format.

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.

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.
    ·
  • Try to minimize the number of data points. The more data points the looked at, the more work the graph must do.
  • ·
  • 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.
  • ·
  • 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.
  • ·
  • Don't stipple or dash the element. Solid lines are much faster.
  • ·
  • 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 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.

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 Reference Manual, page 568). The work-around is to break the polygon into separate pieces.

Keywords

graph, widget


Table of Contents

blt-2.4z.orig/html/hierbox.html0100644000175000017500000030020707434255425015252 0ustar dokodoko treeview(n) manual page Table of Contents

Name

treeview - Create and manipulate hierarchical table widgets

Synopsis

treeview pathName ?options?

Description

The treeview widget displays a tree of data. It replaces both the hiertable and hierbox widgets. The treeview is 100% syntax compatible with the hiertable widget. The hiertable command is retained for sake of script-level compatibility. This widget obsoletes the hierbox widget. It does everything the old hierbox widget did, but also provides data sharing (via tree data objects) and the ability to tag nodes.

Introduction

The treeview widget displays hierarchical data. Data is represented as nodes in a general-ordered tree. Each node may have sub-nodes and these nodes can in turn has their own children.

A node is displayed as a row entry in the widget. Each entry has a text label and icon. When a node has children, its entry is drawn with a small button to the left of the label. Clicking the mouse over this button opens or closes the node. When a node is open, its children are exposed. When it is closed, the children and their descedants are hidden. The button is normally a + or - symbol (ala Windows Explorer), but can be replaced with a pair of Tk images (open and closed images).

If the node has data associated with it, they can be displayed in columns running vertically on either side the tree. You can control the color, font, etc of each entry. Any entry label or data field can be edited in-place.

Tree Data Object

The tree is not stored inside the widget but in a tree data object (see the tree command for a further explanation). Tree data objects can be shared among different clients, such as a treeview widget or the tree command. You can walk the tree and manage its data with the tree command tree, while displaying it with the treeview widget. Whenever the tree is updated, the treeview widget is automatically redrawn.

By default, the treeview widget creates its own tree object. The tree initially contains just a root node. But you can also display trees created by the tree command using the -tree configuration option. Treeview widgets can share the same tree object, possibly displaying different views of the same data.

A tree object has both a Tcl and C API. You can insert or delete nodes using treeview widget or tree command operations, but also from C code. For example, you can load the tree from your C code while still managing and displaying the tree from Tcl. The widget is automatically notified whenever the tree is modified via C or Tcl.

Syntax


treeview pathName ?option value?...

The treeview command creates a new window pathName and makes it into a treeview 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 widget 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, treeview 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 widget. The general form is:

pathName operation ?arg?...

Both operation and its arguments determine the exact behavior of the command. The operations available are described in the TREEVIEW OPERATIONS section.

IDs and Tags

Nodes can be inserted into a tree using the treeview widget
blt::treeview .t
set node [.t insert end root "one"]

or tree command.
set tree [blt::tree create]
set node [$tree insert root "one"]

In both cases, a number identifying the node is returned (the value of $node). This serial number or id uniquely identifies the node. Please note that you can't infer a location or position of a node from its id. The only exception is that the root node is always id 0. Since nodes may have the same labels or be moved within the tree, ids provide an convenient way to identify nodes. If a tree is shared, the ids will be the same regardless if you are using by the treeview widget or the tree command. Ids are recycled when the node deleted.

A node may also have any number of tags associated with it. A tag is just a string of characters, and it may take any form except that of an integer. For example, "x123" is valid, but "123" isn't. The same tag may be associated with many different nodes. This is typically done to associate a group of nodes. Many operations in the treeview widget take either node ids or tag names as arguments. Using a tag says to apply the operation to all nodes with that tag.

The tag all is implicitly associated with every node in the tree. It may be used to invoke operations on all the nodes in the tree.

Tags may be shared, just like trees, between clients. For example, you can use the tags created by the tree command with treeview widgets.

Special Node IDs

There are also several special non-numeric ids. Special ids differ from tags in that they are always translated to their numeric equivalent. They also take precedence over tags. For example, you can't use a tag name that is a special id. These ids are specific to the treeview widget.
active
The node where the mouse pointer is currently located. When a node is active, it is drawn using its active icon (see the -activeicon option). The active id is changed automatically by moving the mouse pointer over another node or by using the entry activate operation. Note that there can be only one active node at a time.
anchor
The node representing the fixed end of the current selection. The anchor is set by the selection anchor operation.
current
The node where the mouse pointer is currently located. But unlike active, this id changes while the selection is dragged. It is used to determine the current node during button drags.
down
The next open node from the current focus. The down of the last open node is the same.
end
The last open node (in depth-first order) on the tree.
focus
The node that currently has focus. When a node has focus, it receives key events. To indicate focus, the node is drawn with a dotted line around its label. You can change the focus using the focus operation.
last
The last open node from the current focus. But unlike up, when the focus is at root, last wraps around to the last open node in the tree.
mark
The node representing the non-fixed end of the current selection. The mark is set by the selection mark operation.
next
The next open node from the current focus. But unlike down, when the focus is on last open node, next wraps around to the root node.
nextsibling
The next sibling from the node with the current focus. If the node is already the last sibling then it is the nextsibling.
parent
The parent of the node with the current focus. The parent of the root is also the root.
prevsibling
The previous sibling from the node with the current focus. If the node is already the first sibling then it is the prevsibling.
root
The root node. You can also use id 0 to indicate the root.
up
The last open node (in depth-first order) from the current focus. The up of the root node (i.e. the root has focus) is also the root.
view.top
First node that's current visible in the widget.
view.bottom
Last node that's current visible in the widget.
path
Absolute path of a node. Path names refer to the node name, not their entry labels. Paths don't have to start with a separator (see the -separator configuration option), but component names must be separated by the designated separator.
@x,y
Indicates the node that covers the point in the treeview window specified by x and y (in pixel coordinates). If no part of the entryd covers that point, then the closest node to that point is used.

A node may be specified as an id or tag. If the specifier is an integer then it is assumed to refer to the single node with that id. If the specifier is not an integer, it's checked to see if it's a special id (such as focus). Otherwise, it's assumed to be tag. Some operations only operate on a single node at a time; if a tag refers to more than one node, then an error is generated.

Data Fields

A node in the tree can have data fields. A data field is a name-value pair, used to represent arbitrary data in the node. Nodes can contain different fields (they aren't required to contain the same fields). You can optionally display these fields in the treeview widget in columns running on either side of the displayed tree. A node's value for the field is drawn in the column along side its node in the hierarchy. Any node that doesn't have a specific field is left blank. Columns can be interactively resized, hidden, or, moved.

Entry Bindings

You can bind Tcl commands to be invoked when events occur on nodes (much like Tk canvas items). You can bind a node using its id or its bindtags. Bindtags are simply names that associate a binding with one or more nodes. There is a built-in tag all that all node entries automatically have.

Treeview Operations

The treeview operations are the invoked by specifying the widget's pathname, the operation, and any arguments that pertain to that operation. The general form is:


pathName operation ?arg arg ...?

Operation and the args determine the exact behavior of the command. The following operation are available for treeview widgets:

pathName bbox ?-screen? tagOrId...
Returns a list of 4 numbers, representing a bounding box of around the specified entries. The entries is given by one or more tagOrId arguments. If the -screen flag is given, then the x-y coordinates of the bounding box are returned as screen coordinates, not virtual coordinates. Virtual coordinates start from 0 from the root node. The returned list contains the following values.
x
X-coordinate of the upper-left corner of the bounding box.
y
Y-coordinate of the upper-left corner of the bounding box.
width
Width of the bounding box.
height
Height of the bounding box.
pathName bind tagName ?sequence command?
Associates command with tagName such that whenever the event sequence given by sequence occurs for a node with this tag, command will be invoked. The syntax is similar to the bind command except that it operates on treeview 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 tagName. If the first character of command is + then command augments an existing binding rather than replacing it. If no command 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 bindings have been defined for tagName.

pathName button operation ?args?
This command is used to control the button selectors within a treeview widget. It has several forms, depending on operation:
pathName button activate tagOrId
Designates the node given by tagOrId as active. When a node is active it's entry is drawn using its active icon (see the -activeicon option). Note that there can be only one active entry at a time. The special id active indicates the currently active node.
pathName button bind tagName ?sequence command?
Associates command with tagName such that whenever the event sequence given by sequence occurs for an button of a node entry with this tag, command will be invoked. The syntax is similar to the bind command except that it operates on treeview buttons, 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 tagName. If the first character of command is + then command augments an existing binding rather than replacing it. If no command 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 bindings have been defined for tagName.

pathName button cget option
Returns the current value of the configuration option given by option. Option may have any of the values accepted by the configure operation described below.
pathName button configure ?option? ?value option value ...?
Query or modify the configuration options of the widget. If no option is specified, returns a list describing all of the available options for pathName (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. Option and value are described in the section BUTTON OPTIONS below.
pathName cget option
Returns the current value of the configuration option given by option. Option may have any of the values accepted by the configure operation described below.
pathName close ?-recurse? tagOrId...
Closes the node specified by tagOrId. In addition, if a Tcl script was specified by the -closecommand option, it is invoked. If the node is already closed, this command has no effect. If the -recurse flag is present, each child node is recursively closed.
pathName column operation ?args?
The following operations are available for treeview columns.
pathName column activate column
Sets the active column to column. Column is the name of a column in the widget. When a column is active, it's drawn using its -activetitlebackground and -activetitleforeground options. If column is the "", then no column will be active. If no column argument is provided, then the name of the currently active column is returned.
pathName column cget name option
Returns the current value of the column configuration option given by option for name. Name is the name of column that corresponds to a data field. Option may have any of the values accepted by the configure operation described below.
pathName column configure name ?option? ?value option value ...?
Query or modify the configuration options of the column designated by name. Name is the name of the column corresponding to a data field. If no option is specified, returns a list describing all of the available options for pathName (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. Option and value are described in the section COLUMN OPTIONS below.
pathName column delete field ?field...?
Deletes one of more columns designated by field. Note that this does not delete the data fields themselves.
pathName column insert position field ?options...?
Inserts one of more columns designated by field. A column displays each node's data field by the same name. If the node doesn't have the given field, the cell is left blank. Position indicates where in the list of columns to add the new column. It may be either a number or end.
pathName column invoke field
Invokes the Tcl command associated with the column field, if there is one (using the column's -command option). The command is ignored if the column's -state option set to disabled.
pathName column move name dest
Moves the column name to the destination position. Dest is the name of another column or a screen position in the form @x,y.
pathName column names
Returns a list of the names of all columns in the widget. The list is ordered as the columns are drawn from left-to-right.
pathName column nearest x ?y?
Returns the name of the column closest to the given X-Y screen coordinate. If you provide a y argument (it's optional), a name is returned only when if the point is over a column's title.
pathName configure ?option? ?value option value ...?
Query or modify the configuration options of the widget. If no option is specified, returns a list describing all of the available options for pathName (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. Option and value are described in the section TREEVIEW OPTIONS below.
pathName curselection
Returns a list containing the ids of all of the entries that are currently selected. If there are no entries selected, then the empty string is returned.
pathName delete tagOrId...
Deletes one or more entries given by tagOrId and its children.
pathName entry operation ?args?
The following operations are available for treeview entries.
pathName entry activate tagOrId
Sets the active entry to the one specified by tagOrId. When an entry is active it is drawn using its active icon (see the -activeicon option). Note that there can be only one active node at a time. The special id of the currently active node is active.
pathName entry cget option
Returns the current value of the configuration option given by option. Option may have any of the values accepted by the configure operation described below.
pathName entry children tagOrId ?first? ?last?
Returns a list of ids for the given range of children of tagOrId. TagOrId is the id or tag of the node to be examined. If only a first argument is present, then the id of the that child at that numeric position is returned. If both first and last arguments are given, then the ids of all the children in that range are returned. Otherwise the ids of all children are returned.
pathName entry configure ?option? ?value option value ...?
Query or modify the configuration options of the widget. If no option is specified, returns a list describing all of the available options for pathName (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. Option and value are described below:
pathName entry delete tagOrId ?first ?last?
Deletes the one or more children nodes of the parent tagOrId. If first and last arguments are present, they are positions designating a range of children nodes to be deleted.
pathName entry isbefore tagOrId1 tagOrId2
Returns 1 if tagOrId1 is before tagOrId2 and 0 otherwise.
pathName entry ishidden tagOrId
Returns 1 if the node is currently hidden and 0 otherwise. A node is also hidden if any of its ancestor nodes are closed or hidden.
pathName entry isopen tagOrId
Returns 1 if the node is currently open and 0 otherwise.
pathName entry size -recurse tagOrId
Returns the number of children for parent node tagOrId. If the -recurse flag is set, the number of all its descendants is returned. The node itself is not counted.
pathName find ?flags? first last
Finds for all entries matching the criteria given by flags. A list of ids for all matching nodes is returned. First and last are ids designating the range of the search in depth-first order. If last is before first, then nodes are searched in reverse order. The valid flags are:
-name pattern
Specifies pattern to match against node names.
-full pattern
Specifies pattern to match against node pathnames.
-option pattern
Specifies pattern to match against the node entry's configuration option.
-exact
Patterns must match exactly. The is the default.
-glob
Use global pattern matching. Matching is done in a fashion similar to that used by the C-shell. For the two strings to match, their contents must be identical except that the following special sequences may appear in pattern:
*
Matches any sequence of characters in string, including a null string.
?
Matches any single character in string.
[chars]
Matches any character in the set given by chars. If a sequence of the form x-y appears in chars, then any character between x and y, inclusive, will match.
\x
Matches the single character x. This provides a way of avoiding the special interpretation of the characters *?[]\ in the pattern.
-regexp
Use regular expression pattern matching (i.e. the same as implemented by the regexp command).
-nonmatching
Pick entries that don't match.
-exec string
Specifies a Tcl script to be invoked for each matching node. Percent substitutions are performed on string before it is executed. The following substitutions are valid:
%W
The pathname of the widget.
%p
The name of the node.
%P
The full pathname of the node.
%#
The id of the node.
%%
Translates to a single percent.
-count number
Stop searching after number matches.
--
Indicates the end of flags.
pathName focus tagOrId
Sets the focus to the node given by tagOrId. When a node has focus, it can receive keyboard events. The special id focus designates the node that currently has focus.
pathName get ?-full? tagOrId tagOrId...
Translates one or more ids to their node entry names. It returns a list of names for all the ids specified. If the -full flag is set, then the full pathnames are returned.
pathName hide ?flags? tagOrId...
Hides all nodes matching the criteria given by flags. The search is performed recursively for each node given by tagOrId. The valid flags are described below:
-name pattern
Specifies pattern to match against node names.
-full pattern
Specifies pattern to match against node pathnames.
-option pattern
Specifies pattern to match against the node entry's configuration option.
-exact
Match patterns exactly. The is the default.
-glob
Use global pattern matching. Matching is done in a fashion similar to that used by the C-shell. For the two strings to match, their contents must be identical except that the following special sequences may appear in pattern:
*
Matches any sequence of characters in string, including a null string.
?
Matches any single character in string.
[chars]
Matches any character in the set given by chars. If a sequence of the form x-y appears in chars, then any character between x and y, inclusive, will match.
\x
Matches the single character x. This provides a way of avoiding the special interpretation of the characters *?[]\ in the pattern.
-regexp
Use regular expression pattern matching (i.e. the same as implemented by the regexp command).
-nonmatching
Hide nodes that don't match.
--
Indicates the end of flags.
pathName index ?-at tagOrId? string
Returns the id of the node specified by string. String may be a tag or node id. Some special ids are normally relative to the node that has focus. The -at flag lets you select another node.
pathName insert ?-at tagOrId? position path ?options...? ?path? ?options...?
Inserts one or more nodes at position. Position is the location (number or end) where the new nodes are added to the parent node. Path is the pathname of the new node. Pathnames can be formated either as a Tcl list (each element is a path component) or as a string separated by a special character sequence (using the -separator option). Pathnames are normally absolute, but the -at switch lets you select a relative starting point. Its value is the id of the starting node.

All ancestors of the new node must already exist, unless the -autocreate option is set. It is also an error if a node already exists, unless the -allowduplicates option is set.

Option and value may have any of the values accepted by the entry configure operation described in the ENTRY OPERATIONS section below. This command returns a list of the ids of the new entries.

pathName move tagOrId how destId
Moves the node given by tagOrId to the destination node. The node can not be an ancestor of the destination. DestId is the id of the destination node and can not be the root of the tree. In conjunction with how, it describes how the move is performed.
before
Moves the node before the destination node.
after
Moves the node after the destination node.
into
Moves the node to the end of the destination's list of children.
pathName nearest x y ?varName?
Returns the id of the node entry closest to the given X-Y screen coordinate. The optional argument varName is the name of variable which is set to either button or select to indicate over what part of the node the coordinate lies. If the coordinate is not directly over any node, then varName will contain the empty string.
pathName open ?-recurse? tagOrId...
Opens the one or more nodes specified by tagOrId. If a node is not already open, the Tcl script specified by the -opencommand option is invoked. If the -recurse flag is present, then each descendant is recursively opened.
pathName range ?-open? first last
Returns the ids in depth-first order of the nodes between the first and last ids. If the -open flag is present, it indicates to consider only open nodes. If last is before first, then the ids are returned in reverse order.
pathName scan option args
This command implements scanning. It has two forms, depending on option:
pathName scan mark x y
Records x and y and the current view in the treeview window; used in conjunction with later scan dragto commands. Typically this command is associated with a mouse button press in the widget. It returns an empty string.
pathName scan dragto x y.
Computes the difference between its x and y arguments and the x and y arguments to the last scan mark command for the widget. It then adjusts the view by 10 times the difference in coordinates. This command is typically associated with mouse motion events in the widget, to produce the effect of dragging the list at high speed through the window. The return value is an empty string.
pathName see ?-anchor anchor? tagOrId
Adjusts the view of entries so that the node given by tagOrId is visible in the widget window. It is an error if tagOrId is a tag that refers to more than one node. By default the node's entry is displayed in the middle of the window. This can changed using the -anchor flag. Its value is a Tk anchor position.
pathName selection option arg
This command is used to adjust the selection within a treeview widget. It has several forms, depending on option:
pathName selection anchor tagOrId
Sets the selection anchor to the node given by tagOrId. If tagOrId refers to a non-existent node, then the closest node is used. The selection anchor is the end of the selection that is fixed while dragging out a selection with the mouse. The special id anchor may be used to refer to the anchor node.
pathName selection cancel
Clears the temporary selection of entries back to the current anchor. Temporary selections are created by the selection mark operation.
pathName selection clear first ?last?
Removes the entries between first and last (inclusive) from the selection. Both first and last are ids representing a range of entries. If last isn't given, then only first is deselected. Entries outside the selection are not affected.
pathName selection clearall
Clears the entire selection.
pathName selection mark tagOrId
Sets the selection mark to the node given by tagOrId. This causes the range of entries between the anchor and the mark to be temporarily added to the selection. The selection mark is the end of the selection that is fixed while dragging out a selection with the mouse. The special id mark may be used to refer to the current mark node. If tagOrId refers to a non-existent node, then the mark is ignored. Resetting the mark will unselect the previous range. Setting the anchor finalizes the range.
pathName selection includes tagOrId
Returns 1 if the node given by tagOrId is currently selected, 0 if it isn't.
pathName selection present
Returns 1 if any nodes are currently selected and 0 otherwise.
pathName selection set first ?last?
Selects all of the nodes in the range between first and last, inclusive, without affecting the selection state of nodes outside that range.
pathName selection toggle first ?last?
Selects/deselects nodes in the range between first and last, inclusive, from the selection. If a node is currently selected, it becomes deselected, and visa versa.
pathName show ?flags? tagOrId...
Exposes all nodes matching the criteria given by flags. This is the inverse of the hide operation. The search is performed recursively for each node given by tagOrId. The valid flags are described below:
-name pattern
Specifies pattern to match against node names.
-full pattern
Specifies pattern to match against node pathnames.
-option pattern
Specifies pattern to match against the entry's configuration option.
-exact
Match patterns exactly. The is the default.
-glob
-glob Use global pattern matching. Matching is done in a fashion similar to that used by the C-shell. For the two strings to match, their contents must be identical except that the following special sequences may appear in pattern:
*
Matches any sequence of characters in string, including a null string.
?
Matches any single character in string.
[chars]
Matches any character in the set given by chars. If a sequence of the form x-y appears in chars, then any character between x and y, inclusive, will match.
\x
Matches the single character x. This provides a way of avoiding the special interpretation of the characters *?[]\ in the pattern.
-regexp
Use regular expression pattern matching (i.e. the same as implemented by the regexp command).
-nonmatching
Expose nodes that don't match.
--
Indicates the end of flags.
pathName sort ?operation? args...
pathName sort auto ?boolean
Turns on/off automatic sorting of node entries. If boolean is true, entries will be automatically sorted as they are opened, closed, inserted, or deleted. If no boolean argument is provided, the current state is returned.
pathName sort cget option
Returns the current value of the configuration option given by option. Option may have any of the values accepted by the configure operation described below.
pathName sort configure ?option? ?value option value ...?
Query or modify the sorting configuration options of the widget. If no option is specified, returns a list describing all of the available options for pathName (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given sorting option(s) to have the given value(s); in this case the command returns an empty string. Option and value are described below:
-column string
Specifies the column to sort. Entries in the widget are rearranged according to this column. If column is "" then no sort is performed.
-command string
Specifies a Tcl procedure to be called when sorting nodes. The procedure is called with three arguments: the pathname of the widget and the fields of two entries. The procedure returns 1 if the first node is greater than the second, -1 is the second is greater, and 0 if equal.
-decreasing boolean
Indicates to sort in ascending/descending order. If boolean is true, then the entries as in descending order. The default is no.
-mode string
Specifies how to compare entries when sorting. String may be one of the following:
ascii
Use string comparison based upon the ASCII collation order.
dictionary
Use dictionary-style comparison. This is the same as ascii except (a) case is ignored except as a tie-breaker and (b) if two strings contain embedded numbers, the numbers compare as integers, not characters. For example, "bigBoy" sorts between "bigbang" and "bigboy", and "x10y" sorts between "x9y" and "x11y".
integer
Compares fields as integers.
real
Compares fields as floating point numbers.
command
Use the Tcl proc specified by the -command option to compare entries when sorting. If no command is specified, the sort reverts to ascii sorting.
pathName sort once ?flags? tagOrId...
Sorts the children for each entries specified by tagOrId. By default, entries are sorted by name, but you can specify a Tcl proc to do your own comparisons.
-recurse
Recursively sort the entire branch, not just the children.
pathName tag operation args
Tags are a general means of selecting and marking nodes in the tree. A tag is just a string of characters, and it may take any form except that of an integer. The same tag may be associated with many different nodes.

Both operation and its arguments determine the exact behavior of the command. The operations available for tags are listed below.

pathName tag add string id...
Adds the tag string to one of more entries.
pathName tag delete string id...
Deletes the tag string from one or more entries.
pathName tag forget string
Removes the tag string from all entries. It's not an error if no entries are tagged as string.
pathName tag names ?id?
Returns a list of tags used. If an id argument is present, only those tags used by the node designated by id are returned.
pathName tag nodes string
Returns a list of ids that have the tag string. If no node is tagged as string, then an empty string is returned.
pathName text operation ?args?
This operation is used to provide text editing for cells (data fields in a column) or entry labels. It has several forms, depending on operation:
pathName text apply
Applies the edited buffer, replacing the entry label or data field. The edit window is hidden.
pathName text cancel
Cancels the editing operation, reverting the entry label or data value back to the previous value. The edit window is hidden.
pathName text cget value
Returns the current value of the configuration option given by option. Option may have any of the values accepted by the configure operation described below.
pathName text configure ?option value?
Query or modify the configuration options of the edit window. If no option is specified, returns a list describing all of the available options (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. Option and value are described in the section TEXT EDITING OPTIONS below.
pathName text delete first last
Deletes the characters in the edit buffer between the two given character positions.
pathName text get ?-root? x y
pathName text icursor index
pathName text index index
Returns the text index of given index.
pathName text insert index string
Insert the text string string into the edit buffer at the index index. For example, the index 0 will prepend the buffer.
pathName text selection args
This operation controls the selection of the editing window. Note that this differs from the selection of entries. It has the following forms:
pathName text selection adjust index
Adjusts either the first or last index of the selection.
pathName text selection clear
Clears the selection.
pathName text selection from index
Sets the anchor of the selection.
pathName text selection present
Indicates if a selection is present.
pathName text selection range start end
Sets both the anchor and mark of the selection.
pathName text selection to index
Sets the unanchored end (mark) of the selection.
pathName toggle tagOrId
Opens or closes the node given by tagOrId. If the corresponding -opencommand or -closecommand option is set, then that command is also invoked.
pathName xview args
This command is used to query and change the horizontal position of the information in the widget's window. It can take any of the following forms:
pathName xview
Returns a list containing two elements. Each element is a real fraction between 0 and 1; together they describe the horizontal span that is visible in the window. For example, if the first element is .2 and the second element is .6, 20% of the treeview widget's text is off-screen to the left, the middle 40% is visible in the window, and 40% of the text is off-screen to the right. These are the same values passed to scrollbars via the -xscrollcommand option.
pathName xview tagOrId
Adjusts the view in the window so that the character position given by tagOrId is displayed at the left edge of the window. Character positions are defined by the width of the character 0.
pathName xview moveto fraction
Adjusts the view in the window so that fraction of the total width of the treeview widget's text is off-screen to the left. fraction must be a fraction between 0 and 1.
pathName xview scroll number what
This command shifts the view in the window left or right according to number and what. Number must be an integer. What must be either units or pages or an abbreviation of one of these. If what is units, the view adjusts left or right by number character units (the width of the 0 character) on the display; if it is pages then the view adjusts by number screenfuls. If number is negative then characters farther to the left become visible; if it is positive then characters farther to the right become visible.
pathName yview ?args?
This command is used to query and change the vertical position of the text in the widget's window. It can take any of the following forms:
pathName yview
Returns a list containing two elements, both of which are real fractions between 0 and 1. The first element gives the position of the node at the top of the window, relative to the widget as a whole (0.5 means it is halfway through the treeview window, for example). The second element gives the position of the node just after the last one in the window, relative to the widget as a whole. These are the same values passed to scrollbars via the -yscrollcommand option.
pathName yview tagOrId
Adjusts the view in the window so that the node given by tagOrId is displayed at the top of the window.
pathName yview moveto fraction
Adjusts the view in the window so that the node given by fraction appears at the top of the window. Fraction is a fraction between 0 and 1; 0 indicates the first node, 0.33 indicates the node one-third the way through the treeview widget, and so on.
pathName yview scroll number what
This command adjusts the view in the window up or down according to number and what. Number must be an integer. What must be either units or pages. If what is units, the view adjusts up or down by number lines; if it is pages then the view adjusts by number screenfuls. If number is negative then earlier nodes become visible; if it is positive then later nodes become visible.

Treeview Options

In addition to the configure operation, widget configuration options may also be set by the Tk option command. The class resource name is TreeView.
option add *TreeView.Foreground white
option add *TreeView.Background blue

The following widget options are available:

-activebackground color
Sets the background color for active entries. A node is active when the mouse passes over it's entry or using the activate operation.
-activeforeground color
Sets the foreground color of the active node. A node is active when the mouse passes over it's entry or using the activate operation.
-activeicons images
Specifies images to be displayed for an entry's icon when it is active. Images is a list of two Tk images: the first image is displayed when the node is open, the second when it is closed.
-autocreate boolean
If boolean is true, automatically create missing ancestor nodes when inserting new nodes. Otherwise flag an error. The default is no.
-allowduplicates boolean
If boolean is true, allow nodes with duplicate pathnames when inserting new nodes. Otherwise flag an error. The default is no.
-background color
Sets the background color of the widget. The default is white.
-borderwidth pixels
Sets the width of the 3-D border around the outside edge of the widget. The -relief option determines if the border is to be drawn. The default is 2.
-closecommand string
Specifies a Tcl script to be invoked when a node is closed. You can overrider this for individual entries using the entry's -closecommand option. The default is "". Percent substitutions are performed on string before it is executed. The following substitutions are valid:
%W
The pathname of the widget.
%p
The name of the node.
%P
The full pathname of the node.
%#
The id of the node.
%%
Translates to a single percent.
-cursor cursor
Specifies the widget's cursor. The default cursor is "".
-dashes number
Sets the dash style of the horizontal and vertical lines drawn connecting entries. Number is the length in pixels of the dashes and gaps in the line. If number is 0, solid lines will be drawn. The default is 1 (dotted).
-exportselection boolean
Indicates if the selection is exported. If the widget is exporting its selection then it will observe the standard X11 protocols for handling the selection. Selections are available as type STRING; the value of the selection will be the label of the selected nodes, separated by newlines. The default is no.
-flat boolean
Indicates whether to display the tree as a flattened list. If boolean is true, then the hierarchy will be a list of full paths for the nodes. This option also has affect on sorting. See the SORT OPERATIONS section for more information. The default is no.
-focusdashes dashList
Sets the dash style of the outline rectangle drawn around the entry label of the node that current has focus. Number is the length in pixels of the dashes and gaps in the line. If number is 0, a solid line will be drawn. The default is 1.
-focusforeground color
Sets the color of the focus rectangle. The default is black.
-font fontName
Specifies the font for entry labels. You can override this for individual entries with the entry's -font configuration option. The default is *-Helvetica-Bold-R-Normal-*-12-120-*.
-foreground color
Sets the text color of entry labels. You can override this for individual entries with the entry's -foreground configuration option. The default is black.
-height pixels
Specifies the requested height of widget. The default is 400.
-hideroot boolean
If boolean is true, it indicates that no entry for the root node should be displayed. The default is no.
-highlightbackground color
Specifies the normal color of the traversal highlight region when the widget does not have the input focus.
-highlightcolor color
Specifies the color of the traversal highlight rectangle when the widget has the input focus. The default is black.
-highlightthickness pixels
Specifies the width of the highlight rectangle indicating when the widget has input focus. The value may have any of the forms acceptable to Tk_GetPixels. If the value is zero, no focus highlight will be displayed. The default is 2.
-icons images
Specifies images for the entry's icon. Images is a list of two Tk images: the first image is displayed when the node is open, the second when it is closed.
-linecolor color
Sets the color of the connecting lines drawn between entries. The default is black.
-linespacing pixels
Sets the number of pixels spacing between entries. The default is 0.
-linewidth pixels
Set the width of the lines drawn connecting entries. If pixels is 0, no vertical or horizontal lines are drawn. The default is 1.
-opencommand string
Specifies a Tcl script to be invoked when a node is open. You can override this for individual entries with the entry's -opencommand configuration option. The default is "". Percent substitutions are performed on string before it is executed. The following substitutions are valid:
%W
The pathname of the widget.
%p
The name of the node.
%P
The full pathname of the node.
%#
The id of the node.
%%
Translates to a single percent.
-relief relief
Specifies the 3-D effect for the widget. Relief specifies how the treeview widget should appear relative to widget it is packed into; for example, raised means the treeview widget should appear to protrude. The default is sunken.
-scrollmode mode
Specifies the style of scrolling to be used. The following styles are valid. This is the default is hierbox.
listbox
Like the listbox widget, the last entry can always be scrolled to the top of the widget window. This allows the scrollbar thumb to shrink as the last entry is scrolled upward.
hierbox
Like the hierbox widget, the last entry can only be viewed at the bottom of the widget window. The scrollbar stays a constant size.
canvas
Like the canvas widget, the entries are bound within the scrolling area.
-selectbackground color
Sets the background color selected node entries. The default is #ffffea.
-selectborderwidth pixels
Sets the width of the raised 3-D border drawn around the labels of selected entries. The default is 0. -selectcommand string Specifies a Tcl script to invoked when the set of selected nodes changes. The default is "".
-selectforeground color
Sets the color of the labels of selected node entries. The default is black.
-selectmode mode
Specifies the selection mode. If mode is single, only one node can be selected at a time. If multiple more than one node can be selected. The default is single.
-separator string
Specifies the character sequence to use when spliting the path components. The separator may be several characters wide (such as "::") Consecutive separators in a pathname are treated as one. If string is the empty string, the pathnames are Tcl lists. Each element is a path component. The default is "".
-showtitles boolean
If boolean is false, column titles are not be displayed. The default is yes.
-sortselection boolean
If boolean is true, nodes in the selection are ordered as they are currently displayed (depth-first or sorted), not in the order they were selected. The default is no.
-takefocus focus
Provides information used when moving the focus from window 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 "1".
-trim string
Specifies a string leading characters to trim from entry pathnames before parsing. This only makes sense if the -separator is also set. The default is "".
-width pixels
Sets the requested width of the widget. If pixels is 0, then the with is computed from the contents of the treeview widget. The default is 200.
-xscrollcommand string
Specifies the prefix for a command used to communicate with horizontal scrollbars. Whenever the horizontal view in the widget's window changes, the widget will generate a Tcl command by concatenating the scroll command and two numbers. If this option is not specified, then no command will be executed.
-xscrollincrement pixels
Sets the horizontal scrolling distance. The default is 20 pixels.
-yscrollcommand string
Specifies the prefix for a command used to communicate with vertical scrollbars. Whenever the vertical view in the widget's window changes, the widget will generate a Tcl command by concatenating the scroll command and two numbers. If this option is not specified, then no command will be executed.
-yscrollincrement pixels
Sets the vertical scrolling distance. The default is 20 pixels.

Entry Options

Many widget configuration options have counterparts in entries. For example, there is a -closecommand configuration option for both widget itself and for individual entries. Options set at the widget level are global for all entries. If the entry configuration option is set, then it overrides the widget option. This is done to avoid wasting memory by replicated options. Most entries will have redundant options.

There is no resource class or name for entries.

-activeicons images
Specifies images to be displayed as the entry's icon when it is active. This overrides the global -activeicons configuration option for the specific entry. Images is a list of two Tk images: the first image is displayed when the node is open, the second when it is closed.
-bindtags tagList
Specifies the binding tags for nodes. TagList is a list of binding tag names. The tags and their order will determine how events are handled for nodes. Each tag in the list matching the current event sequence will have its Tcl command executed. The default value is all.
-button string
Indicates whether a button should be displayed on the left side of the node entry. String can be yes, no, or auto. If auto, then a button is automatically displayed if the node has children. This is the default.
-closecommand string
Specifies a Tcl script to be invoked when the node is closed. This overrides the global -closecommand option for this entry. The default is "". Percent substitutions are performed on string before it is executed. The following substitutions are valid:
%W
The pathname of the widget.
%p
The name of the node.
%P
The full pathname of the node.
%#
The id of the node.
%%
Translates to a single percent.
-data string
Sets data fields for the node. String is a list of name-value pairs to be set. The default is "".
-font fontName
Sets the font for entry labels. This overrides the widget's -font option for this node. The default is *-Helvetica-Bold-R-Normal-*-12-120-*.
-foreground color
Sets the text color of the entry label. This overrides the widget's -foreground configuration option. The default is "".
-icons images
Specifies images to be displayed for the entry's icon. This overrides the global -icons configuration option. Images is a list of two Tk images: the first image is displayed when the node is open, the second when it is closed.
-label string
Sets the text for the entry's label. If not set, this defaults to the name of the node. The default is "".
-opencommand string
Specifies a Tcl script to be invoked when the entry is opened. This overrides the widget's -opencommand option for this node. The default is "". Percent substitutions are performed on string before it is executed. The following substitutions are valid:
%W
The pathname of the widget.
%p
The name of the node.
%P
The full pathname of the node.
%#
The id of the node.
%%
Translates to a single percent.

Button Options

Button configuration options may also be set by the option command. The resource subclass is Button. The resource name is always button.
option add *TreeView.Button.Foreground white
option add *TreeView.button.Background blue

The following are the configuration options available for buttons.

-activebackground color
Sets the background color of active buttons. A button is made active when the mouse passes over it or by the button activate operation.
-activeforeground color
Sets the foreground color of active buttons. A button is made active when the mouse passes over it or by the button activate operation.
-background color
Sets the background of the button. The default is white.
-borderwidth pixels
Sets the width of the 3-D border around the button. The -relief option determines if a border is to be drawn. The default is 1.
-closerelief relief
Specifies the 3-D effect for the closed button. Relief indicates how the button should appear relative to the widget; for example, raised means the button should appear to protrude. The default is solid.
-cursor cursor
Sets the widget's cursor. The default cursor is "".
-foreground color
Sets the foreground color of buttons. The default is black.
-images images
Specifies images to be displayed for the button. Images is a list of two Tk images: the first image is displayed when the button is open, the second when it is closed. If the images is the empty string, then a plus/minus gadget is drawn. The default is "".
-openrelief relief
Specifies the 3-D effect of the open button. Relief indicates how the button should appear relative to the widget; for example, raised means the button should appear to protrude. The default is flat.
-size pixels
Sets the requested size of the button. The default is 0.

Column Options

Column configuration options may also be set by the option command. The resource subclass is Column. The resource name is the name of the column.
option add *TreeView.Column.Foreground white
option add *TreeView.treeView.Background blue

The following configuration options are available for columns.

-background color
Sets the background color of the column. This overrides the widget's -background option. The default is white.
-borderwidth pixels
Sets the width of the 3-D border of the column. The -relief option determines if a border is to be drawn. The default is 0.
-edit boolean
Indicates if the column's data fields can be edited. If boolean is false, the data fields in the column may not be edited. The default is yes.
-foreground color
Specifies the foreground color of the column. You can override this for individual entries with the entry's -foreground option. The default is black.
-font fontName
Sets the font for a column. You can override this for individual entries with the entry's -font option. The default is *-Helvetica-Bold-R-Normal-*-12-120-*.
-hide boolean
If boolean is true, the column is not displayed. The default is yes.
-justify justify
Specifies how the column data fields title should be justified within the column. This matters only when the column is wider than the data field to be display. Justify must be left, right, or center. The default is left.
-pad pad
Specifies how much padding for the left and right sides of the column. Pad is a list of one or two screen distances. If pad has two elements, the left side of the column 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 2.
-relief relief
Specifies the 3-D effect of the column. Relief specifies how the column should appear relative to the widget; for example, raised means the column should appear to protrude. The default is flat.
-state state
Sets the state of the column. If state is disable then the column title can not be activated nor invoked. The default is normal.
-text string
Sets the title for the column. The default is "".
-titleforeground color
Sets the foreground color of the column title. The default is black.
-titleshadow color
Sets the color of the drop shadow of the column title. The default is "".
-width pixels
Sets the requested width of the column. This overrides the computed with of the column. If pixels is 0, the width is computed as from the contents of the column. The default is 0.

Text Editing Options

Text edit window configuration options may also be set by the option command. The resource class is TreeViewEditor. The resource name is always edit.
option add *TreeViewEditor.Foreground white
option add *edit.Background blue

The following are the configuration options available for the text editing window.

-background color
Sets the background of the text edit window. The default is white.
-borderwidth pixels
Sets the width of the 3-D border around the edit window. The -relief option determines if a border is to be drawn. The default is 1.
-exportselection boolean
Indicates if the text selection is exported. If the edit window is exporting its selection then it will observe the standard X11 protocols for handling the selection. Selections are available as type STRING. The default is no.
-relief relief
Specifies the 3-D effect of the edit window. Relief indicates how the background should appear relative to the edit window; for example, raised means the background should appear to protrude. The default is solid.
-selectbackground color
Sets the background of the selected text in the edit window. The default is white.
-selectborderwidth pixels
Sets the width of the 3-D border around the selected text in the edit window. The -selectrelief option determines if a border is to be drawn. The default is 1.
-selectforeground color
Sets the foreground of the selected text in the edit window. The default is white.
-selectrelief relief
Specifies the 3-D effect of the selected text in the edit window. Relief indicates how the text should appear relative to the edit window; for example, raised means the text should appear to protrude. The default is flat.

Default Bindings

Tk automatically creates class bindings for treeviews that give them Motif-like behavior. Much of the behavior of a treeview widget is determined by its -selectmode option, which selects one of two ways of dealing with the selection.

If the selection mode is single, only one node can be selected at a time. Clicking button 1 on an node selects it and deselects any other selected item.

If the selection mode is multiple, any number of entries may be selected at once, including discontiguous ranges. Clicking Control-Button-1 on a node entry toggles its selection state without affecting any other entries. Pressing Shift-Button-1 on a node entry selects it, extends the selection.

  1. In extended mode, the selected range can be adjusted by pressing button 1 with the Shift key down: this modifies the selection to consist of the entries between the anchor and the entry under the mouse, inclusive. The un-anchored end of this new selection can also be dragged with the button down.
  2. In extended mode, pressing button 1 with the Control key down starts a toggle operation: the anchor is set to the entry under the mouse, and its selection state is reversed. The selection state of other entries isn't changed. If the mouse is dragged with button 1 down, then the selection state of all entries between the anchor and the entry under the mouse is set to match that of the anchor entry; the selection state of all other entries remains what it was before the toggle operation began.
  3. If the mouse leaves the treeview window with button 1 down, the window scrolls away from the mouse, making information visible that used to be off-screen on the side of the mouse. The scrolling continues until the mouse re-enters the window, the button is released, or the end of the hierarchy is reached.
  4. Mouse button 2 may be used for scanning. If it is pressed and dragged over the treeview widget, the contents of the hierarchy drag at high speed in the direction the mouse moves.
  5. If the Up or Down key is pressed, the location cursor (active entry) moves up or down one entry. If the selection mode is browse or extended then the new active entry is also selected and all other entries are deselected. In extended mode the new active entry becomes the selection anchor.
  6. In extended mode, Shift-Up and Shift-Down move the location cursor (active entry) up or down one entry and also extend the selection to that entry in a fashion similar to dragging with mouse button 1.
  7. The Left and Right keys scroll the treeview widget view left and right by the width of the character 0. Control-Left and Control-Right scroll the treeview widget view left and right by the width of the window. Control-Prior and Control-Next also scroll left and right by the width of the window.
  8. The Prior and Next keys scroll the treeview widget view up and down by one page (the height of the window).
  9. The Home and End keys scroll the treeview widget horizontally to the left and right edges, respectively.
  10. Control-Home sets the location cursor to the the first entry, selects that entry, and deselects everything else in the widget.
  11. Control-End sets the location cursor to the the last entry, selects that entry, and deselects everything else in the widget.
  12. In extended mode, Control-Shift-Home extends the selection to the first entry and Control-Shift-End extends the selection to the last entry.
  13. In multiple mode, Control-Shift-Home moves the location cursor to the first entry and Control-Shift-End moves the location cursor to the last entry.
  14. The space and Select keys make a selection at the location cursor (active entry) just as if mouse button 1 had been pressed over this entry.
  15. In extended mode, Control-Shift-space and Shift-Select extend the selection to the active entry just as if button 1 had been pressed with the Shift key down.
  16. In extended mode, the Escape key cancels the most recent selection and restores all the entries in the selected range to their previous selection state.
  17. Control-slash selects everything in the widget, except in single and browse modes, in which case it selects the active entry and deselects everything else.
  18. Control-backslash deselects everything in the widget, except in browse mode where it has no effect.
  19. The F16 key (labelled Copy on many Sun workstations) or Meta-w copies the selection in the widget to the clipboard, if there is a selection.

The behavior of treeview widgets can be changed by defining new bindings for individual widgets or by redefining the class bindings.

Widget Bindings

In addition to the above behavior, the following additional behavior is defined by the default widget class (TreeView) bindings.
<ButtonPress-2>
Starts scanning.
<B2-Motion>
Adjusts the scan.
<ButtonRelease-2>
Stops scanning.
<B1-Leave>
Starts auto-scrolling.
<B1-Enter>
Starts auto-scrolling
<KeyPress-Up>
Moves the focus to the previous entry.
<KeyPress-Down>
Moves the focus to the next entry.
<Shift-KeyPress-Up>
Moves the focus to the previous sibling.
<Shift-KeyPress-Down>
Moves the focus to the next sibling.
<KeyPress-Prior>
Moves the focus to first entry. Closed or hidden entries are ignored.
<KeyPress-Next>
Move the focus to the last entry. Closed or hidden entries are ignored.
<KeyPress-Left>
Closes the entry. It is not an error if the entry has no children.
<KeyPress-Right>
Opens the entry, displaying its children. It is not an error if the entry has no children.
<KeyPress-space>
In "single" select mode this selects the entry. In "multiple" mode, it toggles the entry (if it was previous selected, it is not deselected).
<KeyRelease-space>
Turns off select mode.
<KeyPress-Return>
Sets the focus to the current entry.
<KeyRelease-Return>
Turns off select mode.
<KeyPress>
Moves to the next entry whose label starts with the letter typed.
<KeyPress-Home>
Moves the focus to first entry. Closed or hidden entries are ignored.
<KeyPress-End>
Move the focus to the last entry. Closed or hidden entries are ignored.
<KeyPress-F1>
Opens all entries.
<KeyPress-F2>
Closes all entries (except root).

Button Bindings

Buttons have bindings. There are associated with the "all" bindtag (see the entry's -bindtag option). You can use the bind operation to change them.
<Enter>
Highlights the button of the current entry.
<Leave>
Returns the button back to its normal state.
<ButtonRelease-1>
Adjust the view so that the current entry is visible.

Entry Bindings

Entries have default bindings. There are associated with the "all" bindtag (see the entry's -bindtag option). You can use the bind operation to modify them.
<Enter>
Highlights the current entry.
<Leave>
Returns the entry back to its normal state.
<ButtonPress-1>
Sets the selection anchor the current entry.
<Double-ButtonPress-1>
Toggles the selection of the current entry.
<B1-Motion>
For "multiple" mode only. Saves the current location of the pointer for auto-scrolling. Resets the selection mark.
<ButtonRelease-1>
For "multiple" mode only. Sets the selection anchor to the current entry.
<Shift-ButtonPress-1>
For "multiple" mode only. Extends the selection.
<Shift-Double-ButtonPress-1>
Place holder. Does nothing.
<Shift-B1-Motion>
Place holder. Does nothing.
<Shift-ButtonRelease-1>
Stop auto-scrolling.
<Control-ButtonPress-1>
For "multiple" mode only. Toggles and extends the selection.
<Control-Double-ButtonPress-1>
Place holder. Does nothing.
<Control-B1-Motion>
Place holder. Does nothing.
<Control-ButtonRelease-1>
Stops auto-scrolling.
<Control-Shift-ButtonPress-1>
???
<Control-Shift-Double-ButtonPress-1>
Place holder. Does nothing.
<Control-Shift-B1-Motion>
Place holder. Does nothing.

Column Bindings

Columns have bindings too. They are associated with the column's "all" bindtag (see the column -bindtag option). You can use the column bind operation to change them.
<Enter>
Highlights the current column title.
<Leave>
Returns the column back to its normal state.
<ButtonRelease-1>
Invokes the command (see the column's -command option) if one if specified.

Column Rule Bindings

<Enter>
Highlights the current and activates the ruler.
<Leave>
Returns the column back to its normal state. Deactivates the ruler.
<ButtonPress-1>
Sets the resize anchor for the column.
<B1-Motion>
Sets the resize mark for the column.
<ButtonRelease-1>
Adjust the size of the column, based upon the resize anchor and mark positions.

Example

The treeview command creates a new widget.
treeview .h -bg white

A new Tcl command .h is also created. This command can be used to query and modify the treeview widget. For example, to change the background color of the table to "green", you use the new command and the widget's configure operation.
# Change the background color.
.h configure -background "green"

By default, the treeview widget will automatically create a new tree object to contain the data. The name of the new tree is the pathname of the widget. Above, the new tree object name is ".h". But you can use the -tree option to specify the name of another tree.
# View the tree "myTree".
.h configure -tree "myTree"

When a new tree is created, it contains only a root node. The node is automatically opened. The id of the root node is always 0 (you can use also use the special id root). The insert operation lets you insert one or more new entries into the tree. The last argument is the node's pathname.
# Create a new entry named "myEntry"
set id [.h insert end "myEntry"]

This appends a new node named "myEntry". It will positioned as the last child of the root of the tree (using the position "end"). You can supply another position to order the node within its siblings.
# Prepend "fred".
set id [.h insert 0 "fred"]

Entry names do not need to be unique. By default, the node's label is its name. To supply a different text label, add the -label option.
# Create a new node named "fred"
set id [.h insert end "fred" -label "Fred Flintstone"]

The insert operation returns the id of the new node. You can also use the index operation to get this information.
# Get the id of "fred"
.h index "fred"

To insert a node somewhere other than root, use the -at switch. It takes the id of the node where the new child will be added.
# Create a new node "barney" in "fred".
.h insert -at $id end "barney"

A pathname describes the path to an entry in the hierarchy. It's a list of entry names that compose the path in the tree. Therefore, you can also add "barney" to "fred" as follows.
# Create a new sub-entry of "fred"
.h insert end "fred barney"

Every name in the list is ancestor of the next. All ancestors must already exist. That means that an entry "fred" is an ancestor of "barney" and must already exist. But you can use the -autocreate configuration option to force the creation of ancestor nodes.
# Force the creation of ancestors.
.h configure -autocreate yes
.h insert end "fred barney wilma betty"

Sometimes the pathname is already separated by a character sequence rather than formed as a list. A file name is a good example of this. You can use the -separator option to specify a separator string to split the path into its components. Each pathname inserted is automatically split using the separator string as a separator. Multiple separators are treated as one.
.h configure -separator /
.h insert end "/usr/local/tcl/bin"

If the path is prefixed by extraneous characters, you can automatically trim it off using the -trim option. It removed the string from the path before it is parsed.
.h configure -trim C:/windows -separator /
.h insert end "C:/window/system"

You can insert more than one entry at a time with the insert operation. This can be much faster than looping over a list of names.
# The slow way
foreach f [glob $dir/*] {
.h insert end $f
}
# The fast way
eval .h insert end [glob $dir/*]

In this case, the insert operation will return a list of ids of the new entries.

You can delete entries with the delete operation. It takes one or more tags of ids as its argument. It deletes the entry and all its children.
.h delete $id

Entries have several configuration options. They control the appearance of the entry's icon and label. We have already seen the -label option that sets the entry's text label. The entry configure operation lets you set or modify an entry's configuration options.
.h entry configure $id -color red -font fixed

You can hide an entry and its children using the -hide option.
.h entry configure $id -hide yes

More that one entry can be configured at once. All entries specified are configured with the same options.
.h entry configure $i1 $i2 $i3 $i4 -color brown

An icon is displayed for each entry. It's a Tk image drawn to the left of the label. You can set the icon with the entry's -icons option. It takes a list of two image names: one to represent the open entry, another when it is closed.
set im1 [image create photo -file openfolder.gif]
set im2 [image create photo -file closefolder.gif]
.h entry configure $id -icons "$im1 $im2"

If -icons is set to the empty string, no icons are display.

If an entry has children, a button is displayed to the left of the icon. Clicking the mouse on this button opens or closes the sub-hierarchy. The button is normally a + or - symbol, but can be configured in a variety of ways using the button configure operation. For example, the + and - symbols can be replaced with Tk images.
set im1 [image create photo -file closefolder.gif]
set im2 [image create photo -file downarrow.gif]
.h button configure $id -images "$im1 $im2" \
-openrelief raised -closerelief raised

Entries can contain an arbitrary number of data fields. Data fields are name-value pairs. Both the value and name are strings. The entry's -data option lets you set data fields.
.h entry configure $id -data {mode 0666 group users}

The -data takes a list of name-value pairs.

You can display these data fields as columns in the treeview widget. You can create and configure columns with the column operation. For example, to add a new column to the widget, use the column insert operation. The last argument is the name of the data field that you want to display.
.h column insert end "mode"

The column title is displayed at the top of the column. By default, it's is the field name. You can override this using the column's -text option.
.h column insert end "mode" -text "File Permissions"

Columns have several configuration options. The column configure operation lets you query or modify column options.
.h column configure "mode" -justify left

The -justify option says how the data is justified within in the column. The -hide option indicates whether the column is displayed.
.h column configure "mode" -hide yes

Entries can be selected by clicking on the mouse. Selected entries are drawn using the colors specified by the -selectforeground and -selectbackground configuration options. The selection itself is managed by the selection operation.
# Clear all selections
.h selection clear 0 end
# Select the root node
.h selection set 0

The curselection operation returns a list of ids of all the selected entries.
set ids [.h curselection]

You can use the get operation to convert the ids to their pathnames.
set names [eval .h get -full $ids]

If a treeview is exporting its selection (using the -exportselection option), then it will observe the standard X11 protocols for handling the selection. Treeview selections are available as type STRING; the value of the selection will be the pathnames of the selected entries, separated by newlines.

The treeview supports two modes of selection: single and multiple. In single select mode, only one entry can be selected at a time, while multiple select mode allows several entries to be selected. The mode is set by the widget's -selectmode option.
.h configure -selectmode "multiple"

You can be notified when the list of selected entries changes. The widget's -selectcommand specifies a Tcl procedure that is called whenever the selection changes.
proc SelectNotify { widget } {
set ids [$widget curselection]
}
.h configure -selectcommand "SelectNotify .h"

The widget supports the standard Tk scrolling and scanning operations. The treeview can be both horizontally and vertically. You can attach scrollbars to the treeview the same way as the listbox or canvas widgets.
scrollbar .xbar -orient horizontal -command ".h xview"
scrollbar .ybar -orient vertical -command ".h yview"
.h configure -xscrollcommand ".xbar set" \
-yscrollcommand ".ybar set"

There are three different modes of scrolling: listbox, canvas, and hierbox. In listbox mode, the last entry can always be scrolled to the top of the widget. In hierbox mode, the last entry is always drawn at the bottom of the widget. The scroll mode is set by the widget's -selectmode option.
.h configure -scrollmode "listbox"

Entries can be programmatically opened or closed using the open and close operations respectively.
.h open $id
.h close $id

When an entry is opened, a Tcl procedure can be automatically invoked. The -opencommand option specifies this procedure. This procedure can lazily insert entries as needed.
proc AddEntries { dir } {
eval .h insert end [glob -nocomplain $dir/*]
}
.h configure -opencommand "AddEntries %P"

Now when an entry is opened, the procedure AddEntries is called and adds children to the entry. Before the command is invoked, special "%" substitutions (like bind) are performed. Above, %P is translated to the pathname of the entry.

The same feature exists when an entry is closed. The -closecommand option specifies the procedure.
proc DeleteEntries { id } {
.h entry delete $id 0 end
}
.h configure -closecommand "DeleteEntries %#"

When an entry is closed, the procedure DeleteEntries is called and deletes the entry's children using the entry delete operation (%# is the id of entry).

Keywords

treeview, widget


Table of Contents

blt-2.4z.orig/html/hiertable.html0100644000175000017500000030020707434255425015551 0ustar dokodoko treeview(n) manual page Table of Contents

Name

treeview - Create and manipulate hierarchical table widgets

Synopsis

treeview pathName ?options?

Description

The treeview widget displays a tree of data. It replaces both the hiertable and hierbox widgets. The treeview is 100% syntax compatible with the hiertable widget. The hiertable command is retained for sake of script-level compatibility. This widget obsoletes the hierbox widget. It does everything the old hierbox widget did, but also provides data sharing (via tree data objects) and the ability to tag nodes.

Introduction

The treeview widget displays hierarchical data. Data is represented as nodes in a general-ordered tree. Each node may have sub-nodes and these nodes can in turn has their own children.

A node is displayed as a row entry in the widget. Each entry has a text label and icon. When a node has children, its entry is drawn with a small button to the left of the label. Clicking the mouse over this button opens or closes the node. When a node is open, its children are exposed. When it is closed, the children and their descedants are hidden. The button is normally a + or - symbol (ala Windows Explorer), but can be replaced with a pair of Tk images (open and closed images).

If the node has data associated with it, they can be displayed in columns running vertically on either side the tree. You can control the color, font, etc of each entry. Any entry label or data field can be edited in-place.

Tree Data Object

The tree is not stored inside the widget but in a tree data object (see the tree command for a further explanation). Tree data objects can be shared among different clients, such as a treeview widget or the tree command. You can walk the tree and manage its data with the tree command tree, while displaying it with the treeview widget. Whenever the tree is updated, the treeview widget is automatically redrawn.

By default, the treeview widget creates its own tree object. The tree initially contains just a root node. But you can also display trees created by the tree command using the -tree configuration option. Treeview widgets can share the same tree object, possibly displaying different views of the same data.

A tree object has both a Tcl and C API. You can insert or delete nodes using treeview widget or tree command operations, but also from C code. For example, you can load the tree from your C code while still managing and displaying the tree from Tcl. The widget is automatically notified whenever the tree is modified via C or Tcl.

Syntax


treeview pathName ?option value?...

The treeview command creates a new window pathName and makes it into a treeview 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 widget 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, treeview 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 widget. The general form is:

pathName operation ?arg?...

Both operation and its arguments determine the exact behavior of the command. The operations available are described in the TREEVIEW OPERATIONS section.

IDs and Tags

Nodes can be inserted into a tree using the treeview widget
blt::treeview .t
set node [.t insert end root "one"]

or tree command.
set tree [blt::tree create]
set node [$tree insert root "one"]

In both cases, a number identifying the node is returned (the value of $node). This serial number or id uniquely identifies the node. Please note that you can't infer a location or position of a node from its id. The only exception is that the root node is always id 0. Since nodes may have the same labels or be moved within the tree, ids provide an convenient way to identify nodes. If a tree is shared, the ids will be the same regardless if you are using by the treeview widget or the tree command. Ids are recycled when the node deleted.

A node may also have any number of tags associated with it. A tag is just a string of characters, and it may take any form except that of an integer. For example, "x123" is valid, but "123" isn't. The same tag may be associated with many different nodes. This is typically done to associate a group of nodes. Many operations in the treeview widget take either node ids or tag names as arguments. Using a tag says to apply the operation to all nodes with that tag.

The tag all is implicitly associated with every node in the tree. It may be used to invoke operations on all the nodes in the tree.

Tags may be shared, just like trees, between clients. For example, you can use the tags created by the tree command with treeview widgets.

Special Node IDs

There are also several special non-numeric ids. Special ids differ from tags in that they are always translated to their numeric equivalent. They also take precedence over tags. For example, you can't use a tag name that is a special id. These ids are specific to the treeview widget.
active
The node where the mouse pointer is currently located. When a node is active, it is drawn using its active icon (see the -activeicon option). The active id is changed automatically by moving the mouse pointer over another node or by using the entry activate operation. Note that there can be only one active node at a time.
anchor
The node representing the fixed end of the current selection. The anchor is set by the selection anchor operation.
current
The node where the mouse pointer is currently located. But unlike active, this id changes while the selection is dragged. It is used to determine the current node during button drags.
down
The next open node from the current focus. The down of the last open node is the same.
end
The last open node (in depth-first order) on the tree.
focus
The node that currently has focus. When a node has focus, it receives key events. To indicate focus, the node is drawn with a dotted line around its label. You can change the focus using the focus operation.
last
The last open node from the current focus. But unlike up, when the focus is at root, last wraps around to the last open node in the tree.
mark
The node representing the non-fixed end of the current selection. The mark is set by the selection mark operation.
next
The next open node from the current focus. But unlike down, when the focus is on last open node, next wraps around to the root node.
nextsibling
The next sibling from the node with the current focus. If the node is already the last sibling then it is the nextsibling.
parent
The parent of the node with the current focus. The parent of the root is also the root.
prevsibling
The previous sibling from the node with the current focus. If the node is already the first sibling then it is the prevsibling.
root
The root node. You can also use id 0 to indicate the root.
up
The last open node (in depth-first order) from the current focus. The up of the root node (i.e. the root has focus) is also the root.
view.top
First node that's current visible in the widget.
view.bottom
Last node that's current visible in the widget.
path
Absolute path of a node. Path names refer to the node name, not their entry labels. Paths don't have to start with a separator (see the -separator configuration option), but component names must be separated by the designated separator.
@x,y
Indicates the node that covers the point in the treeview window specified by x and y (in pixel coordinates). If no part of the entryd covers that point, then the closest node to that point is used.

A node may be specified as an id or tag. If the specifier is an integer then it is assumed to refer to the single node with that id. If the specifier is not an integer, it's checked to see if it's a special id (such as focus). Otherwise, it's assumed to be tag. Some operations only operate on a single node at a time; if a tag refers to more than one node, then an error is generated.

Data Fields

A node in the tree can have data fields. A data field is a name-value pair, used to represent arbitrary data in the node. Nodes can contain different fields (they aren't required to contain the same fields). You can optionally display these fields in the treeview widget in columns running on either side of the displayed tree. A node's value for the field is drawn in the column along side its node in the hierarchy. Any node that doesn't have a specific field is left blank. Columns can be interactively resized, hidden, or, moved.

Entry Bindings

You can bind Tcl commands to be invoked when events occur on nodes (much like Tk canvas items). You can bind a node using its id or its bindtags. Bindtags are simply names that associate a binding with one or more nodes. There is a built-in tag all that all node entries automatically have.

Treeview Operations

The treeview operations are the invoked by specifying the widget's pathname, the operation, and any arguments that pertain to that operation. The general form is:


pathName operation ?arg arg ...?

Operation and the args determine the exact behavior of the command. The following operation are available for treeview widgets:

pathName bbox ?-screen? tagOrId...
Returns a list of 4 numbers, representing a bounding box of around the specified entries. The entries is given by one or more tagOrId arguments. If the -screen flag is given, then the x-y coordinates of the bounding box are returned as screen coordinates, not virtual coordinates. Virtual coordinates start from 0 from the root node. The returned list contains the following values.
x
X-coordinate of the upper-left corner of the bounding box.
y
Y-coordinate of the upper-left corner of the bounding box.
width
Width of the bounding box.
height
Height of the bounding box.
pathName bind tagName ?sequence command?
Associates command with tagName such that whenever the event sequence given by sequence occurs for a node with this tag, command will be invoked. The syntax is similar to the bind command except that it operates on treeview 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 tagName. If the first character of command is + then command augments an existing binding rather than replacing it. If no command 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 bindings have been defined for tagName.

pathName button operation ?args?
This command is used to control the button selectors within a treeview widget. It has several forms, depending on operation:
pathName button activate tagOrId
Designates the node given by tagOrId as active. When a node is active it's entry is drawn using its active icon (see the -activeicon option). Note that there can be only one active entry at a time. The special id active indicates the currently active node.
pathName button bind tagName ?sequence command?
Associates command with tagName such that whenever the event sequence given by sequence occurs for an button of a node entry with this tag, command will be invoked. The syntax is similar to the bind command except that it operates on treeview buttons, 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 tagName. If the first character of command is + then command augments an existing binding rather than replacing it. If no command 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 bindings have been defined for tagName.

pathName button cget option
Returns the current value of the configuration option given by option. Option may have any of the values accepted by the configure operation described below.
pathName button configure ?option? ?value option value ...?
Query or modify the configuration options of the widget. If no option is specified, returns a list describing all of the available options for pathName (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. Option and value are described in the section BUTTON OPTIONS below.
pathName cget option
Returns the current value of the configuration option given by option. Option may have any of the values accepted by the configure operation described below.
pathName close ?-recurse? tagOrId...
Closes the node specified by tagOrId. In addition, if a Tcl script was specified by the -closecommand option, it is invoked. If the node is already closed, this command has no effect. If the -recurse flag is present, each child node is recursively closed.
pathName column operation ?args?
The following operations are available for treeview columns.
pathName column activate column
Sets the active column to column. Column is the name of a column in the widget. When a column is active, it's drawn using its -activetitlebackground and -activetitleforeground options. If column is the "", then no column will be active. If no column argument is provided, then the name of the currently active column is returned.
pathName column cget name option
Returns the current value of the column configuration option given by option for name. Name is the name of column that corresponds to a data field. Option may have any of the values accepted by the configure operation described below.
pathName column configure name ?option? ?value option value ...?
Query or modify the configuration options of the column designated by name. Name is the name of the column corresponding to a data field. If no option is specified, returns a list describing all of the available options for pathName (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. Option and value are described in the section COLUMN OPTIONS below.
pathName column delete field ?field...?
Deletes one of more columns designated by field. Note that this does not delete the data fields themselves.
pathName column insert position field ?options...?
Inserts one of more columns designated by field. A column displays each node's data field by the same name. If the node doesn't have the given field, the cell is left blank. Position indicates where in the list of columns to add the new column. It may be either a number or end.
pathName column invoke field
Invokes the Tcl command associated with the column field, if there is one (using the column's -command option). The command is ignored if the column's -state option set to disabled.
pathName column move name dest
Moves the column name to the destination position. Dest is the name of another column or a screen position in the form @x,y.
pathName column names
Returns a list of the names of all columns in the widget. The list is ordered as the columns are drawn from left-to-right.
pathName column nearest x ?y?
Returns the name of the column closest to the given X-Y screen coordinate. If you provide a y argument (it's optional), a name is returned only when if the point is over a column's title.
pathName configure ?option? ?value option value ...?
Query or modify the configuration options of the widget. If no option is specified, returns a list describing all of the available options for pathName (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. Option and value are described in the section TREEVIEW OPTIONS below.
pathName curselection
Returns a list containing the ids of all of the entries that are currently selected. If there are no entries selected, then the empty string is returned.
pathName delete tagOrId...
Deletes one or more entries given by tagOrId and its children.
pathName entry operation ?args?
The following operations are available for treeview entries.
pathName entry activate tagOrId
Sets the active entry to the one specified by tagOrId. When an entry is active it is drawn using its active icon (see the -activeicon option). Note that there can be only one active node at a time. The special id of the currently active node is active.
pathName entry cget option
Returns the current value of the configuration option given by option. Option may have any of the values accepted by the configure operation described below.
pathName entry children tagOrId ?first? ?last?
Returns a list of ids for the given range of children of tagOrId. TagOrId is the id or tag of the node to be examined. If only a first argument is present, then the id of the that child at that numeric position is returned. If both first and last arguments are given, then the ids of all the children in that range are returned. Otherwise the ids of all children are returned.
pathName entry configure ?option? ?value option value ...?
Query or modify the configuration options of the widget. If no option is specified, returns a list describing all of the available options for pathName (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. Option and value are described below:
pathName entry delete tagOrId ?first ?last?
Deletes the one or more children nodes of the parent tagOrId. If first and last arguments are present, they are positions designating a range of children nodes to be deleted.
pathName entry isbefore tagOrId1 tagOrId2
Returns 1 if tagOrId1 is before tagOrId2 and 0 otherwise.
pathName entry ishidden tagOrId
Returns 1 if the node is currently hidden and 0 otherwise. A node is also hidden if any of its ancestor nodes are closed or hidden.
pathName entry isopen tagOrId
Returns 1 if the node is currently open and 0 otherwise.
pathName entry size -recurse tagOrId
Returns the number of children for parent node tagOrId. If the -recurse flag is set, the number of all its descendants is returned. The node itself is not counted.
pathName find ?flags? first last
Finds for all entries matching the criteria given by flags. A list of ids for all matching nodes is returned. First and last are ids designating the range of the search in depth-first order. If last is before first, then nodes are searched in reverse order. The valid flags are:
-name pattern
Specifies pattern to match against node names.
-full pattern
Specifies pattern to match against node pathnames.
-option pattern
Specifies pattern to match against the node entry's configuration option.
-exact
Patterns must match exactly. The is the default.
-glob
Use global pattern matching. Matching is done in a fashion similar to that used by the C-shell. For the two strings to match, their contents must be identical except that the following special sequences may appear in pattern:
*
Matches any sequence of characters in string, including a null string.
?
Matches any single character in string.
[chars]
Matches any character in the set given by chars. If a sequence of the form x-y appears in chars, then any character between x and y, inclusive, will match.
\x
Matches the single character x. This provides a way of avoiding the special interpretation of the characters *?[]\ in the pattern.
-regexp
Use regular expression pattern matching (i.e. the same as implemented by the regexp command).
-nonmatching
Pick entries that don't match.
-exec string
Specifies a Tcl script to be invoked for each matching node. Percent substitutions are performed on string before it is executed. The following substitutions are valid:
%W
The pathname of the widget.
%p
The name of the node.
%P
The full pathname of the node.
%#
The id of the node.
%%
Translates to a single percent.
-count number
Stop searching after number matches.
--
Indicates the end of flags.
pathName focus tagOrId
Sets the focus to the node given by tagOrId. When a node has focus, it can receive keyboard events. The special id focus designates the node that currently has focus.
pathName get ?-full? tagOrId tagOrId...
Translates one or more ids to their node entry names. It returns a list of names for all the ids specified. If the -full flag is set, then the full pathnames are returned.
pathName hide ?flags? tagOrId...
Hides all nodes matching the criteria given by flags. The search is performed recursively for each node given by tagOrId. The valid flags are described below:
-name pattern
Specifies pattern to match against node names.
-full pattern
Specifies pattern to match against node pathnames.
-option pattern
Specifies pattern to match against the node entry's configuration option.
-exact
Match patterns exactly. The is the default.
-glob
Use global pattern matching. Matching is done in a fashion similar to that used by the C-shell. For the two strings to match, their contents must be identical except that the following special sequences may appear in pattern:
*
Matches any sequence of characters in string, including a null string.
?
Matches any single character in string.
[chars]
Matches any character in the set given by chars. If a sequence of the form x-y appears in chars, then any character between x and y, inclusive, will match.
\x
Matches the single character x. This provides a way of avoiding the special interpretation of the characters *?[]\ in the pattern.
-regexp
Use regular expression pattern matching (i.e. the same as implemented by the regexp command).
-nonmatching
Hide nodes that don't match.
--
Indicates the end of flags.
pathName index ?-at tagOrId? string
Returns the id of the node specified by string. String may be a tag or node id. Some special ids are normally relative to the node that has focus. The -at flag lets you select another node.
pathName insert ?-at tagOrId? position path ?options...? ?path? ?options...?
Inserts one or more nodes at position. Position is the location (number or end) where the new nodes are added to the parent node. Path is the pathname of the new node. Pathnames can be formated either as a Tcl list (each element is a path component) or as a string separated by a special character sequence (using the -separator option). Pathnames are normally absolute, but the -at switch lets you select a relative starting point. Its value is the id of the starting node.

All ancestors of the new node must already exist, unless the -autocreate option is set. It is also an error if a node already exists, unless the -allowduplicates option is set.

Option and value may have any of the values accepted by the entry configure operation described in the ENTRY OPERATIONS section below. This command returns a list of the ids of the new entries.

pathName move tagOrId how destId
Moves the node given by tagOrId to the destination node. The node can not be an ancestor of the destination. DestId is the id of the destination node and can not be the root of the tree. In conjunction with how, it describes how the move is performed.
before
Moves the node before the destination node.
after
Moves the node after the destination node.
into
Moves the node to the end of the destination's list of children.
pathName nearest x y ?varName?
Returns the id of the node entry closest to the given X-Y screen coordinate. The optional argument varName is the name of variable which is set to either button or select to indicate over what part of the node the coordinate lies. If the coordinate is not directly over any node, then varName will contain the empty string.
pathName open ?-recurse? tagOrId...
Opens the one or more nodes specified by tagOrId. If a node is not already open, the Tcl script specified by the -opencommand option is invoked. If the -recurse flag is present, then each descendant is recursively opened.
pathName range ?-open? first last
Returns the ids in depth-first order of the nodes between the first and last ids. If the -open flag is present, it indicates to consider only open nodes. If last is before first, then the ids are returned in reverse order.
pathName scan option args
This command implements scanning. It has two forms, depending on option:
pathName scan mark x y
Records x and y and the current view in the treeview window; used in conjunction with later scan dragto commands. Typically this command is associated with a mouse button press in the widget. It returns an empty string.
pathName scan dragto x y.
Computes the difference between its x and y arguments and the x and y arguments to the last scan mark command for the widget. It then adjusts the view by 10 times the difference in coordinates. This command is typically associated with mouse motion events in the widget, to produce the effect of dragging the list at high speed through the window. The return value is an empty string.
pathName see ?-anchor anchor? tagOrId
Adjusts the view of entries so that the node given by tagOrId is visible in the widget window. It is an error if tagOrId is a tag that refers to more than one node. By default the node's entry is displayed in the middle of the window. This can changed using the -anchor flag. Its value is a Tk anchor position.
pathName selection option arg
This command is used to adjust the selection within a treeview widget. It has several forms, depending on option:
pathName selection anchor tagOrId
Sets the selection anchor to the node given by tagOrId. If tagOrId refers to a non-existent node, then the closest node is used. The selection anchor is the end of the selection that is fixed while dragging out a selection with the mouse. The special id anchor may be used to refer to the anchor node.
pathName selection cancel
Clears the temporary selection of entries back to the current anchor. Temporary selections are created by the selection mark operation.
pathName selection clear first ?last?
Removes the entries between first and last (inclusive) from the selection. Both first and last are ids representing a range of entries. If last isn't given, then only first is deselected. Entries outside the selection are not affected.
pathName selection clearall
Clears the entire selection.
pathName selection mark tagOrId
Sets the selection mark to the node given by tagOrId. This causes the range of entries between the anchor and the mark to be temporarily added to the selection. The selection mark is the end of the selection that is fixed while dragging out a selection with the mouse. The special id mark may be used to refer to the current mark node. If tagOrId refers to a non-existent node, then the mark is ignored. Resetting the mark will unselect the previous range. Setting the anchor finalizes the range.
pathName selection includes tagOrId
Returns 1 if the node given by tagOrId is currently selected, 0 if it isn't.
pathName selection present
Returns 1 if any nodes are currently selected and 0 otherwise.
pathName selection set first ?last?
Selects all of the nodes in the range between first and last, inclusive, without affecting the selection state of nodes outside that range.
pathName selection toggle first ?last?
Selects/deselects nodes in the range between first and last, inclusive, from the selection. If a node is currently selected, it becomes deselected, and visa versa.
pathName show ?flags? tagOrId...
Exposes all nodes matching the criteria given by flags. This is the inverse of the hide operation. The search is performed recursively for each node given by tagOrId. The valid flags are described below:
-name pattern
Specifies pattern to match against node names.
-full pattern
Specifies pattern to match against node pathnames.
-option pattern
Specifies pattern to match against the entry's configuration option.
-exact
Match patterns exactly. The is the default.
-glob
-glob Use global pattern matching. Matching is done in a fashion similar to that used by the C-shell. For the two strings to match, their contents must be identical except that the following special sequences may appear in pattern:
*
Matches any sequence of characters in string, including a null string.
?
Matches any single character in string.
[chars]
Matches any character in the set given by chars. If a sequence of the form x-y appears in chars, then any character between x and y, inclusive, will match.
\x
Matches the single character x. This provides a way of avoiding the special interpretation of the characters *?[]\ in the pattern.
-regexp
Use regular expression pattern matching (i.e. the same as implemented by the regexp command).
-nonmatching
Expose nodes that don't match.
--
Indicates the end of flags.
pathName sort ?operation? args...
pathName sort auto ?boolean
Turns on/off automatic sorting of node entries. If boolean is true, entries will be automatically sorted as they are opened, closed, inserted, or deleted. If no boolean argument is provided, the current state is returned.
pathName sort cget option
Returns the current value of the configuration option given by option. Option may have any of the values accepted by the configure operation described below.
pathName sort configure ?option? ?value option value ...?
Query or modify the sorting configuration options of the widget. If no option is specified, returns a list describing all of the available options for pathName (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given sorting option(s) to have the given value(s); in this case the command returns an empty string. Option and value are described below:
-column string
Specifies the column to sort. Entries in the widget are rearranged according to this column. If column is "" then no sort is performed.
-command string
Specifies a Tcl procedure to be called when sorting nodes. The procedure is called with three arguments: the pathname of the widget and the fields of two entries. The procedure returns 1 if the first node is greater than the second, -1 is the second is greater, and 0 if equal.
-decreasing boolean
Indicates to sort in ascending/descending order. If boolean is true, then the entries as in descending order. The default is no.
-mode string
Specifies how to compare entries when sorting. String may be one of the following:
ascii
Use string comparison based upon the ASCII collation order.
dictionary
Use dictionary-style comparison. This is the same as ascii except (a) case is ignored except as a tie-breaker and (b) if two strings contain embedded numbers, the numbers compare as integers, not characters. For example, "bigBoy" sorts between "bigbang" and "bigboy", and "x10y" sorts between "x9y" and "x11y".
integer
Compares fields as integers.
real
Compares fields as floating point numbers.
command
Use the Tcl proc specified by the -command option to compare entries when sorting. If no command is specified, the sort reverts to ascii sorting.
pathName sort once ?flags? tagOrId...
Sorts the children for each entries specified by tagOrId. By default, entries are sorted by name, but you can specify a Tcl proc to do your own comparisons.
-recurse
Recursively sort the entire branch, not just the children.
pathName tag operation args
Tags are a general means of selecting and marking nodes in the tree. A tag is just a string of characters, and it may take any form except that of an integer. The same tag may be associated with many different nodes.

Both operation and its arguments determine the exact behavior of the command. The operations available for tags are listed below.

pathName tag add string id...
Adds the tag string to one of more entries.
pathName tag delete string id...
Deletes the tag string from one or more entries.
pathName tag forget string
Removes the tag string from all entries. It's not an error if no entries are tagged as string.
pathName tag names ?id?
Returns a list of tags used. If an id argument is present, only those tags used by the node designated by id are returned.
pathName tag nodes string
Returns a list of ids that have the tag string. If no node is tagged as string, then an empty string is returned.
pathName text operation ?args?
This operation is used to provide text editing for cells (data fields in a column) or entry labels. It has several forms, depending on operation:
pathName text apply
Applies the edited buffer, replacing the entry label or data field. The edit window is hidden.
pathName text cancel
Cancels the editing operation, reverting the entry label or data value back to the previous value. The edit window is hidden.
pathName text cget value
Returns the current value of the configuration option given by option. Option may have any of the values accepted by the configure operation described below.
pathName text configure ?option value?
Query or modify the configuration options of the edit window. If no option is specified, returns a list describing all of the available options (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. Option and value are described in the section TEXT EDITING OPTIONS below.
pathName text delete first last
Deletes the characters in the edit buffer between the two given character positions.
pathName text get ?-root? x y
pathName text icursor index
pathName text index index
Returns the text index of given index.
pathName text insert index string
Insert the text string string into the edit buffer at the index index. For example, the index 0 will prepend the buffer.
pathName text selection args
This operation controls the selection of the editing window. Note that this differs from the selection of entries. It has the following forms:
pathName text selection adjust index
Adjusts either the first or last index of the selection.
pathName text selection clear
Clears the selection.
pathName text selection from index
Sets the anchor of the selection.
pathName text selection present
Indicates if a selection is present.
pathName text selection range start end
Sets both the anchor and mark of the selection.
pathName text selection to index
Sets the unanchored end (mark) of the selection.
pathName toggle tagOrId
Opens or closes the node given by tagOrId. If the corresponding -opencommand or -closecommand option is set, then that command is also invoked.
pathName xview args
This command is used to query and change the horizontal position of the information in the widget's window. It can take any of the following forms:
pathName xview
Returns a list containing two elements. Each element is a real fraction between 0 and 1; together they describe the horizontal span that is visible in the window. For example, if the first element is .2 and the second element is .6, 20% of the treeview widget's text is off-screen to the left, the middle 40% is visible in the window, and 40% of the text is off-screen to the right. These are the same values passed to scrollbars via the -xscrollcommand option.
pathName xview tagOrId
Adjusts the view in the window so that the character position given by tagOrId is displayed at the left edge of the window. Character positions are defined by the width of the character 0.
pathName xview moveto fraction
Adjusts the view in the window so that fraction of the total width of the treeview widget's text is off-screen to the left. fraction must be a fraction between 0 and 1.
pathName xview scroll number what
This command shifts the view in the window left or right according to number and what. Number must be an integer. What must be either units or pages or an abbreviation of one of these. If what is units, the view adjusts left or right by number character units (the width of the 0 character) on the display; if it is pages then the view adjusts by number screenfuls. If number is negative then characters farther to the left become visible; if it is positive then characters farther to the right become visible.
pathName yview ?args?
This command is used to query and change the vertical position of the text in the widget's window. It can take any of the following forms:
pathName yview
Returns a list containing two elements, both of which are real fractions between 0 and 1. The first element gives the position of the node at the top of the window, relative to the widget as a whole (0.5 means it is halfway through the treeview window, for example). The second element gives the position of the node just after the last one in the window, relative to the widget as a whole. These are the same values passed to scrollbars via the -yscrollcommand option.
pathName yview tagOrId
Adjusts the view in the window so that the node given by tagOrId is displayed at the top of the window.
pathName yview moveto fraction
Adjusts the view in the window so that the node given by fraction appears at the top of the window. Fraction is a fraction between 0 and 1; 0 indicates the first node, 0.33 indicates the node one-third the way through the treeview widget, and so on.
pathName yview scroll number what
This command adjusts the view in the window up or down according to number and what. Number must be an integer. What must be either units or pages. If what is units, the view adjusts up or down by number lines; if it is pages then the view adjusts by number screenfuls. If number is negative then earlier nodes become visible; if it is positive then later nodes become visible.

Treeview Options

In addition to the configure operation, widget configuration options may also be set by the Tk option command. The class resource name is TreeView.
option add *TreeView.Foreground white
option add *TreeView.Background blue

The following widget options are available:

-activebackground color
Sets the background color for active entries. A node is active when the mouse passes over it's entry or using the activate operation.
-activeforeground color
Sets the foreground color of the active node. A node is active when the mouse passes over it's entry or using the activate operation.
-activeicons images
Specifies images to be displayed for an entry's icon when it is active. Images is a list of two Tk images: the first image is displayed when the node is open, the second when it is closed.
-autocreate boolean
If boolean is true, automatically create missing ancestor nodes when inserting new nodes. Otherwise flag an error. The default is no.
-allowduplicates boolean
If boolean is true, allow nodes with duplicate pathnames when inserting new nodes. Otherwise flag an error. The default is no.
-background color
Sets the background color of the widget. The default is white.
-borderwidth pixels
Sets the width of the 3-D border around the outside edge of the widget. The -relief option determines if the border is to be drawn. The default is 2.
-closecommand string
Specifies a Tcl script to be invoked when a node is closed. You can overrider this for individual entries using the entry's -closecommand option. The default is "". Percent substitutions are performed on string before it is executed. The following substitutions are valid:
%W
The pathname of the widget.
%p
The name of the node.
%P
The full pathname of the node.
%#
The id of the node.
%%
Translates to a single percent.
-cursor cursor
Specifies the widget's cursor. The default cursor is "".
-dashes number
Sets the dash style of the horizontal and vertical lines drawn connecting entries. Number is the length in pixels of the dashes and gaps in the line. If number is 0, solid lines will be drawn. The default is 1 (dotted).
-exportselection boolean
Indicates if the selection is exported. If the widget is exporting its selection then it will observe the standard X11 protocols for handling the selection. Selections are available as type STRING; the value of the selection will be the label of the selected nodes, separated by newlines. The default is no.
-flat boolean
Indicates whether to display the tree as a flattened list. If boolean is true, then the hierarchy will be a list of full paths for the nodes. This option also has affect on sorting. See the SORT OPERATIONS section for more information. The default is no.
-focusdashes dashList
Sets the dash style of the outline rectangle drawn around the entry label of the node that current has focus. Number is the length in pixels of the dashes and gaps in the line. If number is 0, a solid line will be drawn. The default is 1.
-focusforeground color
Sets the color of the focus rectangle. The default is black.
-font fontName
Specifies the font for entry labels. You can override this for individual entries with the entry's -font configuration option. The default is *-Helvetica-Bold-R-Normal-*-12-120-*.
-foreground color
Sets the text color of entry labels. You can override this for individual entries with the entry's -foreground configuration option. The default is black.
-height pixels
Specifies the requested height of widget. The default is 400.
-hideroot boolean
If boolean is true, it indicates that no entry for the root node should be displayed. The default is no.
-highlightbackground color
Specifies the normal color of the traversal highlight region when the widget does not have the input focus.
-highlightcolor color
Specifies the color of the traversal highlight rectangle when the widget has the input focus. The default is black.
-highlightthickness pixels
Specifies the width of the highlight rectangle indicating when the widget has input focus. The value may have any of the forms acceptable to Tk_GetPixels. If the value is zero, no focus highlight will be displayed. The default is 2.
-icons images
Specifies images for the entry's icon. Images is a list of two Tk images: the first image is displayed when the node is open, the second when it is closed.
-linecolor color
Sets the color of the connecting lines drawn between entries. The default is black.
-linespacing pixels
Sets the number of pixels spacing between entries. The default is 0.
-linewidth pixels
Set the width of the lines drawn connecting entries. If pixels is 0, no vertical or horizontal lines are drawn. The default is 1.
-opencommand string
Specifies a Tcl script to be invoked when a node is open. You can override this for individual entries with the entry's -opencommand configuration option. The default is "". Percent substitutions are performed on string before it is executed. The following substitutions are valid:
%W
The pathname of the widget.
%p
The name of the node.
%P
The full pathname of the node.
%#
The id of the node.
%%
Translates to a single percent.
-relief relief
Specifies the 3-D effect for the widget. Relief specifies how the treeview widget should appear relative to widget it is packed into; for example, raised means the treeview widget should appear to protrude. The default is sunken.
-scrollmode mode
Specifies the style of scrolling to be used. The following styles are valid. This is the default is hierbox.
listbox
Like the listbox widget, the last entry can always be scrolled to the top of the widget window. This allows the scrollbar thumb to shrink as the last entry is scrolled upward.
hierbox
Like the hierbox widget, the last entry can only be viewed at the bottom of the widget window. The scrollbar stays a constant size.
canvas
Like the canvas widget, the entries are bound within the scrolling area.
-selectbackground color
Sets the background color selected node entries. The default is #ffffea.
-selectborderwidth pixels
Sets the width of the raised 3-D border drawn around the labels of selected entries. The default is 0. -selectcommand string Specifies a Tcl script to invoked when the set of selected nodes changes. The default is "".
-selectforeground color
Sets the color of the labels of selected node entries. The default is black.
-selectmode mode
Specifies the selection mode. If mode is single, only one node can be selected at a time. If multiple more than one node can be selected. The default is single.
-separator string
Specifies the character sequence to use when spliting the path components. The separator may be several characters wide (such as "::") Consecutive separators in a pathname are treated as one. If string is the empty string, the pathnames are Tcl lists. Each element is a path component. The default is "".
-showtitles boolean
If boolean is false, column titles are not be displayed. The default is yes.
-sortselection boolean
If boolean is true, nodes in the selection are ordered as they are currently displayed (depth-first or sorted), not in the order they were selected. The default is no.
-takefocus focus
Provides information used when moving the focus from window 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 "1".
-trim string
Specifies a string leading characters to trim from entry pathnames before parsing. This only makes sense if the -separator is also set. The default is "".
-width pixels
Sets the requested width of the widget. If pixels is 0, then the with is computed from the contents of the treeview widget. The default is 200.
-xscrollcommand string
Specifies the prefix for a command used to communicate with horizontal scrollbars. Whenever the horizontal view in the widget's window changes, the widget will generate a Tcl command by concatenating the scroll command and two numbers. If this option is not specified, then no command will be executed.
-xscrollincrement pixels
Sets the horizontal scrolling distance. The default is 20 pixels.
-yscrollcommand string
Specifies the prefix for a command used to communicate with vertical scrollbars. Whenever the vertical view in the widget's window changes, the widget will generate a Tcl command by concatenating the scroll command and two numbers. If this option is not specified, then no command will be executed.
-yscrollincrement pixels
Sets the vertical scrolling distance. The default is 20 pixels.

Entry Options

Many widget configuration options have counterparts in entries. For example, there is a -closecommand configuration option for both widget itself and for individual entries. Options set at the widget level are global for all entries. If the entry configuration option is set, then it overrides the widget option. This is done to avoid wasting memory by replicated options. Most entries will have redundant options.

There is no resource class or name for entries.

-activeicons images
Specifies images to be displayed as the entry's icon when it is active. This overrides the global -activeicons configuration option for the specific entry. Images is a list of two Tk images: the first image is displayed when the node is open, the second when it is closed.
-bindtags tagList
Specifies the binding tags for nodes. TagList is a list of binding tag names. The tags and their order will determine how events are handled for nodes. Each tag in the list matching the current event sequence will have its Tcl command executed. The default value is all.
-button string
Indicates whether a button should be displayed on the left side of the node entry. String can be yes, no, or auto. If auto, then a button is automatically displayed if the node has children. This is the default.
-closecommand string
Specifies a Tcl script to be invoked when the node is closed. This overrides the global -closecommand option for this entry. The default is "". Percent substitutions are performed on string before it is executed. The following substitutions are valid:
%W
The pathname of the widget.
%p
The name of the node.
%P
The full pathname of the node.
%#
The id of the node.
%%
Translates to a single percent.
-data string
Sets data fields for the node. String is a list of name-value pairs to be set. The default is "".
-font fontName
Sets the font for entry labels. This overrides the widget's -font option for this node. The default is *-Helvetica-Bold-R-Normal-*-12-120-*.
-foreground color
Sets the text color of the entry label. This overrides the widget's -foreground configuration option. The default is "".
-icons images
Specifies images to be displayed for the entry's icon. This overrides the global -icons configuration option. Images is a list of two Tk images: the first image is displayed when the node is open, the second when it is closed.
-label string
Sets the text for the entry's label. If not set, this defaults to the name of the node. The default is "".
-opencommand string
Specifies a Tcl script to be invoked when the entry is opened. This overrides the widget's -opencommand option for this node. The default is "". Percent substitutions are performed on string before it is executed. The following substitutions are valid:
%W
The pathname of the widget.
%p
The name of the node.
%P
The full pathname of the node.
%#
The id of the node.
%%
Translates to a single percent.

Button Options

Button configuration options may also be set by the option command. The resource subclass is Button. The resource name is always button.
option add *TreeView.Button.Foreground white
option add *TreeView.button.Background blue

The following are the configuration options available for buttons.

-activebackground color
Sets the background color of active buttons. A button is made active when the mouse passes over it or by the button activate operation.
-activeforeground color
Sets the foreground color of active buttons. A button is made active when the mouse passes over it or by the button activate operation.
-background color
Sets the background of the button. The default is white.
-borderwidth pixels
Sets the width of the 3-D border around the button. The -relief option determines if a border is to be drawn. The default is 1.
-closerelief relief
Specifies the 3-D effect for the closed button. Relief indicates how the button should appear relative to the widget; for example, raised means the button should appear to protrude. The default is solid.
-cursor cursor
Sets the widget's cursor. The default cursor is "".
-foreground color
Sets the foreground color of buttons. The default is black.
-images images
Specifies images to be displayed for the button. Images is a list of two Tk images: the first image is displayed when the button is open, the second when it is closed. If the images is the empty string, then a plus/minus gadget is drawn. The default is "".
-openrelief relief
Specifies the 3-D effect of the open button. Relief indicates how the button should appear relative to the widget; for example, raised means the button should appear to protrude. The default is flat.
-size pixels
Sets the requested size of the button. The default is 0.

Column Options

Column configuration options may also be set by the option command. The resource subclass is Column. The resource name is the name of the column.
option add *TreeView.Column.Foreground white
option add *TreeView.treeView.Background blue

The following configuration options are available for columns.

-background color
Sets the background color of the column. This overrides the widget's -background option. The default is white.
-borderwidth pixels
Sets the width of the 3-D border of the column. The -relief option determines if a border is to be drawn. The default is 0.
-edit boolean
Indicates if the column's data fields can be edited. If boolean is false, the data fields in the column may not be edited. The default is yes.
-foreground color
Specifies the foreground color of the column. You can override this for individual entries with the entry's -foreground option. The default is black.
-font fontName
Sets the font for a column. You can override this for individual entries with the entry's -font option. The default is *-Helvetica-Bold-R-Normal-*-12-120-*.
-hide boolean
If boolean is true, the column is not displayed. The default is yes.
-justify justify
Specifies how the column data fields title should be justified within the column. This matters only when the column is wider than the data field to be display. Justify must be left, right, or center. The default is left.
-pad pad
Specifies how much padding for the left and right sides of the column. Pad is a list of one or two screen distances. If pad has two elements, the left side of the column 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 2.
-relief relief
Specifies the 3-D effect of the column. Relief specifies how the column should appear relative to the widget; for example, raised means the column should appear to protrude. The default is flat.
-state state
Sets the state of the column. If state is disable then the column title can not be activated nor invoked. The default is normal.
-text string
Sets the title for the column. The default is "".
-titleforeground color
Sets the foreground color of the column title. The default is black.
-titleshadow color
Sets the color of the drop shadow of the column title. The default is "".
-width pixels
Sets the requested width of the column. This overrides the computed with of the column. If pixels is 0, the width is computed as from the contents of the column. The default is 0.

Text Editing Options

Text edit window configuration options may also be set by the option command. The resource class is TreeViewEditor. The resource name is always edit.
option add *TreeViewEditor.Foreground white
option add *edit.Background blue

The following are the configuration options available for the text editing window.

-background color
Sets the background of the text edit window. The default is white.
-borderwidth pixels
Sets the width of the 3-D border around the edit window. The -relief option determines if a border is to be drawn. The default is 1.
-exportselection boolean
Indicates if the text selection is exported. If the edit window is exporting its selection then it will observe the standard X11 protocols for handling the selection. Selections are available as type STRING. The default is no.
-relief relief
Specifies the 3-D effect of the edit window. Relief indicates how the background should appear relative to the edit window; for example, raised means the background should appear to protrude. The default is solid.
-selectbackground color
Sets the background of the selected text in the edit window. The default is white.
-selectborderwidth pixels
Sets the width of the 3-D border around the selected text in the edit window. The -selectrelief option determines if a border is to be drawn. The default is 1.
-selectforeground color
Sets the foreground of the selected text in the edit window. The default is white.
-selectrelief relief
Specifies the 3-D effect of the selected text in the edit window. Relief indicates how the text should appear relative to the edit window; for example, raised means the text should appear to protrude. The default is flat.

Default Bindings

Tk automatically creates class bindings for treeviews that give them Motif-like behavior. Much of the behavior of a treeview widget is determined by its -selectmode option, which selects one of two ways of dealing with the selection.

If the selection mode is single, only one node can be selected at a time. Clicking button 1 on an node selects it and deselects any other selected item.

If the selection mode is multiple, any number of entries may be selected at once, including discontiguous ranges. Clicking Control-Button-1 on a node entry toggles its selection state without affecting any other entries. Pressing Shift-Button-1 on a node entry selects it, extends the selection.

  1. In extended mode, the selected range can be adjusted by pressing button 1 with the Shift key down: this modifies the selection to consist of the entries between the anchor and the entry under the mouse, inclusive. The un-anchored end of this new selection can also be dragged with the button down.
  2. In extended mode, pressing button 1 with the Control key down starts a toggle operation: the anchor is set to the entry under the mouse, and its selection state is reversed. The selection state of other entries isn't changed. If the mouse is dragged with button 1 down, then the selection state of all entries between the anchor and the entry under the mouse is set to match that of the anchor entry; the selection state of all other entries remains what it was before the toggle operation began.
  3. If the mouse leaves the treeview window with button 1 down, the window scrolls away from the mouse, making information visible that used to be off-screen on the side of the mouse. The scrolling continues until the mouse re-enters the window, the button is released, or the end of the hierarchy is reached.
  4. Mouse button 2 may be used for scanning. If it is pressed and dragged over the treeview widget, the contents of the hierarchy drag at high speed in the direction the mouse moves.
  5. If the Up or Down key is pressed, the location cursor (active entry) moves up or down one entry. If the selection mode is browse or extended then the new active entry is also selected and all other entries are deselected. In extended mode the new active entry becomes the selection anchor.
  6. In extended mode, Shift-Up and Shift-Down move the location cursor (active entry) up or down one entry and also extend the selection to that entry in a fashion similar to dragging with mouse button 1.
  7. The Left and Right keys scroll the treeview widget view left and right by the width of the character 0. Control-Left and Control-Right scroll the treeview widget view left and right by the width of the window. Control-Prior and Control-Next also scroll left and right by the width of the window.
  8. The Prior and Next keys scroll the treeview widget view up and down by one page (the height of the window).
  9. The Home and End keys scroll the treeview widget horizontally to the left and right edges, respectively.
  10. Control-Home sets the location cursor to the the first entry, selects that entry, and deselects everything else in the widget.
  11. Control-End sets the location cursor to the the last entry, selects that entry, and deselects everything else in the widget.
  12. In extended mode, Control-Shift-Home extends the selection to the first entry and Control-Shift-End extends the selection to the last entry.
  13. In multiple mode, Control-Shift-Home moves the location cursor to the first entry and Control-Shift-End moves the location cursor to the last entry.
  14. The space and Select keys make a selection at the location cursor (active entry) just as if mouse button 1 had been pressed over this entry.
  15. In extended mode, Control-Shift-space and Shift-Select extend the selection to the active entry just as if button 1 had been pressed with the Shift key down.
  16. In extended mode, the Escape key cancels the most recent selection and restores all the entries in the selected range to their previous selection state.
  17. Control-slash selects everything in the widget, except in single and browse modes, in which case it selects the active entry and deselects everything else.
  18. Control-backslash deselects everything in the widget, except in browse mode where it has no effect.
  19. The F16 key (labelled Copy on many Sun workstations) or Meta-w copies the selection in the widget to the clipboard, if there is a selection.

The behavior of treeview widgets can be changed by defining new bindings for individual widgets or by redefining the class bindings.

Widget Bindings

In addition to the above behavior, the following additional behavior is defined by the default widget class (TreeView) bindings.
<ButtonPress-2>
Starts scanning.
<B2-Motion>
Adjusts the scan.
<ButtonRelease-2>
Stops scanning.
<B1-Leave>
Starts auto-scrolling.
<B1-Enter>
Starts auto-scrolling
<KeyPress-Up>
Moves the focus to the previous entry.
<KeyPress-Down>
Moves the focus to the next entry.
<Shift-KeyPress-Up>
Moves the focus to the previous sibling.
<Shift-KeyPress-Down>
Moves the focus to the next sibling.
<KeyPress-Prior>
Moves the focus to first entry. Closed or hidden entries are ignored.
<KeyPress-Next>
Move the focus to the last entry. Closed or hidden entries are ignored.
<KeyPress-Left>
Closes the entry. It is not an error if the entry has no children.
<KeyPress-Right>
Opens the entry, displaying its children. It is not an error if the entry has no children.
<KeyPress-space>
In "single" select mode this selects the entry. In "multiple" mode, it toggles the entry (if it was previous selected, it is not deselected).
<KeyRelease-space>
Turns off select mode.
<KeyPress-Return>
Sets the focus to the current entry.
<KeyRelease-Return>
Turns off select mode.
<KeyPress>
Moves to the next entry whose label starts with the letter typed.
<KeyPress-Home>
Moves the focus to first entry. Closed or hidden entries are ignored.
<KeyPress-End>
Move the focus to the last entry. Closed or hidden entries are ignored.
<KeyPress-F1>
Opens all entries.
<KeyPress-F2>
Closes all entries (except root).

Button Bindings

Buttons have bindings. There are associated with the "all" bindtag (see the entry's -bindtag option). You can use the bind operation to change them.
<Enter>
Highlights the button of the current entry.
<Leave>
Returns the button back to its normal state.
<ButtonRelease-1>
Adjust the view so that the current entry is visible.

Entry Bindings

Entries have default bindings. There are associated with the "all" bindtag (see the entry's -bindtag option). You can use the bind operation to modify them.
<Enter>
Highlights the current entry.
<Leave>
Returns the entry back to its normal state.
<ButtonPress-1>
Sets the selection anchor the current entry.
<Double-ButtonPress-1>
Toggles the selection of the current entry.
<B1-Motion>
For "multiple" mode only. Saves the current location of the pointer for auto-scrolling. Resets the selection mark.
<ButtonRelease-1>
For "multiple" mode only. Sets the selection anchor to the current entry.
<Shift-ButtonPress-1>
For "multiple" mode only. Extends the selection.
<Shift-Double-ButtonPress-1>
Place holder. Does nothing.
<Shift-B1-Motion>
Place holder. Does nothing.
<Shift-ButtonRelease-1>
Stop auto-scrolling.
<Control-ButtonPress-1>
For "multiple" mode only. Toggles and extends the selection.
<Control-Double-ButtonPress-1>
Place holder. Does nothing.
<Control-B1-Motion>
Place holder. Does nothing.
<Control-ButtonRelease-1>
Stops auto-scrolling.
<Control-Shift-ButtonPress-1>
???
<Control-Shift-Double-ButtonPress-1>
Place holder. Does nothing.
<Control-Shift-B1-Motion>
Place holder. Does nothing.

Column Bindings

Columns have bindings too. They are associated with the column's "all" bindtag (see the column -bindtag option). You can use the column bind operation to change them.
<Enter>
Highlights the current column title.
<Leave>
Returns the column back to its normal state.
<ButtonRelease-1>
Invokes the command (see the column's -command option) if one if specified.

Column Rule Bindings

<Enter>
Highlights the current and activates the ruler.
<Leave>
Returns the column back to its normal state. Deactivates the ruler.
<ButtonPress-1>
Sets the resize anchor for the column.
<B1-Motion>
Sets the resize mark for the column.
<ButtonRelease-1>
Adjust the size of the column, based upon the resize anchor and mark positions.

Example

The treeview command creates a new widget.
treeview .h -bg white

A new Tcl command .h is also created. This command can be used to query and modify the treeview widget. For example, to change the background color of the table to "green", you use the new command and the widget's configure operation.
# Change the background color.
.h configure -background "green"

By default, the treeview widget will automatically create a new tree object to contain the data. The name of the new tree is the pathname of the widget. Above, the new tree object name is ".h". But you can use the -tree option to specify the name of another tree.
# View the tree "myTree".
.h configure -tree "myTree"

When a new tree is created, it contains only a root node. The node is automatically opened. The id of the root node is always 0 (you can use also use the special id root). The insert operation lets you insert one or more new entries into the tree. The last argument is the node's pathname.
# Create a new entry named "myEntry"
set id [.h insert end "myEntry"]

This appends a new node named "myEntry". It will positioned as the last child of the root of the tree (using the position "end"). You can supply another position to order the node within its siblings.
# Prepend "fred".
set id [.h insert 0 "fred"]

Entry names do not need to be unique. By default, the node's label is its name. To supply a different text label, add the -label option.
# Create a new node named "fred"
set id [.h insert end "fred" -label "Fred Flintstone"]

The insert operation returns the id of the new node. You can also use the index operation to get this information.
# Get the id of "fred"
.h index "fred"

To insert a node somewhere other than root, use the -at switch. It takes the id of the node where the new child will be added.
# Create a new node "barney" in "fred".
.h insert -at $id end "barney"

A pathname describes the path to an entry in the hierarchy. It's a list of entry names that compose the path in the tree. Therefore, you can also add "barney" to "fred" as follows.
# Create a new sub-entry of "fred"
.h insert end "fred barney"

Every name in the list is ancestor of the next. All ancestors must already exist. That means that an entry "fred" is an ancestor of "barney" and must already exist. But you can use the -autocreate configuration option to force the creation of ancestor nodes.
# Force the creation of ancestors.
.h configure -autocreate yes
.h insert end "fred barney wilma betty"

Sometimes the pathname is already separated by a character sequence rather than formed as a list. A file name is a good example of this. You can use the -separator option to specify a separator string to split the path into its components. Each pathname inserted is automatically split using the separator string as a separator. Multiple separators are treated as one.
.h configure -separator /
.h insert end "/usr/local/tcl/bin"

If the path is prefixed by extraneous characters, you can automatically trim it off using the -trim option. It removed the string from the path before it is parsed.
.h configure -trim C:/windows -separator /
.h insert end "C:/window/system"

You can insert more than one entry at a time with the insert operation. This can be much faster than looping over a list of names.
# The slow way
foreach f [glob $dir/*] {
.h insert end $f
}
# The fast way
eval .h insert end [glob $dir/*]

In this case, the insert operation will return a list of ids of the new entries.

You can delete entries with the delete operation. It takes one or more tags of ids as its argument. It deletes the entry and all its children.
.h delete $id

Entries have several configuration options. They control the appearance of the entry's icon and label. We have already seen the -label option that sets the entry's text label. The entry configure operation lets you set or modify an entry's configuration options.
.h entry configure $id -color red -font fixed

You can hide an entry and its children using the -hide option.
.h entry configure $id -hide yes

More that one entry can be configured at once. All entries specified are configured with the same options.
.h entry configure $i1 $i2 $i3 $i4 -color brown

An icon is displayed for each entry. It's a Tk image drawn to the left of the label. You can set the icon with the entry's -icons option. It takes a list of two image names: one to represent the open entry, another when it is closed.
set im1 [image create photo -file openfolder.gif]
set im2 [image create photo -file closefolder.gif]
.h entry configure $id -icons "$im1 $im2"

If -icons is set to the empty string, no icons are display.

If an entry has children, a button is displayed to the left of the icon. Clicking the mouse on this button opens or closes the sub-hierarchy. The button is normally a + or - symbol, but can be configured in a variety of ways using the button configure operation. For example, the + and - symbols can be replaced with Tk images.
set im1 [image create photo -file closefolder.gif]
set im2 [image create photo -file downarrow.gif]
.h button configure $id -images "$im1 $im2" \
-openrelief raised -closerelief raised

Entries can contain an arbitrary number of data fields. Data fields are name-value pairs. Both the value and name are strings. The entry's -data option lets you set data fields.
.h entry configure $id -data {mode 0666 group users}

The -data takes a list of name-value pairs.

You can display these data fields as columns in the treeview widget. You can create and configure columns with the column operation. For example, to add a new column to the widget, use the column insert operation. The last argument is the name of the data field that you want to display.
.h column insert end "mode"

The column title is displayed at the top of the column. By default, it's is the field name. You can override this using the column's -text option.
.h column insert end "mode" -text "File Permissions"

Columns have several configuration options. The column configure operation lets you query or modify column options.
.h column configure "mode" -justify left

The -justify option says how the data is justified within in the column. The -hide option indicates whether the column is displayed.
.h column configure "mode" -hide yes

Entries can be selected by clicking on the mouse. Selected entries are drawn using the colors specified by the -selectforeground and -selectbackground configuration options. The selection itself is managed by the selection operation.
# Clear all selections
.h selection clear 0 end
# Select the root node
.h selection set 0

The curselection operation returns a list of ids of all the selected entries.
set ids [.h curselection]

You can use the get operation to convert the ids to their pathnames.
set names [eval .h get -full $ids]

If a treeview is exporting its selection (using the -exportselection option), then it will observe the standard X11 protocols for handling the selection. Treeview selections are available as type STRING; the value of the selection will be the pathnames of the selected entries, separated by newlines.

The treeview supports two modes of selection: single and multiple. In single select mode, only one entry can be selected at a time, while multiple select mode allows several entries to be selected. The mode is set by the widget's -selectmode option.
.h configure -selectmode "multiple"

You can be notified when the list of selected entries changes. The widget's -selectcommand specifies a Tcl procedure that is called whenever the selection changes.
proc SelectNotify { widget } {
set ids [$widget curselection]
}
.h configure -selectcommand "SelectNotify .h"

The widget supports the standard Tk scrolling and scanning operations. The treeview can be both horizontally and vertically. You can attach scrollbars to the treeview the same way as the listbox or canvas widgets.
scrollbar .xbar -orient horizontal -command ".h xview"
scrollbar .ybar -orient vertical -command ".h yview"
.h configure -xscrollcommand ".xbar set" \
-yscrollcommand ".ybar set"

There are three different modes of scrolling: listbox, canvas, and hierbox. In listbox mode, the last entry can always be scrolled to the top of the widget. In hierbox mode, the last entry is always drawn at the bottom of the widget. The scroll mode is set by the widget's -selectmode option.
.h configure -scrollmode "listbox"

Entries can be programmatically opened or closed using the open and close operations respectively.
.h open $id
.h close $id

When an entry is opened, a Tcl procedure can be automatically invoked. The -opencommand option specifies this procedure. This procedure can lazily insert entries as needed.
proc AddEntries { dir } {
eval .h insert end [glob -nocomplain $dir/*]
}
.h configure -opencommand "AddEntries %P"

Now when an entry is opened, the procedure AddEntries is called and adds children to the entry. Before the command is invoked, special "%" substitutions (like bind) are performed. Above, %P is translated to the pathname of the entry.

The same feature exists when an entry is closed. The -closecommand option specifies the procedure.
proc DeleteEntries { id } {
.h entry delete $id 0 end
}
.h configure -closecommand "DeleteEntries %#"

When an entry is closed, the procedure DeleteEntries is called and deletes the entry's children using the entry delete operation (%# is the id of entry).

Keywords

treeview, widget


Table of Contents

blt-2.4z.orig/html/htext.html0100644000175000017500000004403107434255426014747 0ustar dokodoko htext(n) manual page Table of Contents

Name

htext - Create and manipulate hypertext widgets

Synopsis

htext pathName ?option value?...

Description

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

The htext widget is hybrid of a non-editable text widget and a geometry manager (e.g. the packer). It displays text (optionally read from file) in a window. Text can be scrolled either horizontally or vertically using the htext window as a viewport. In addition, Tcl commands can be embedded into the text which are evaluated as the text is parsed. Text between special double characters (percent signs "%%") is immediately passed to the Tcl interpreter for evaluation.

Furthermore, any widget or widget hierarchy can be packed in-line and made to appear on the current line of the text. Widgets are packed using the htext append command. All widgets must be children of the htext window and must already exist before packing. Once a widget has been packed it cannot be moved to a different position within the text. Widgets can be resized but they will remain at the same position within the text.

Before a file or text string is parsed by the htext widget, all the widget's current children are destroyed. You can reload files or text without worrying about unmapping or destroying each child window beforehand.

Setting the either the -filename or -text configuration option will adjust the value of the other. If both options are set, the file takes precedence. When a new file is read using the -filename option, the value of the -text option is reset to the empty string. Likewise, when the -text option is set, the string representing the -filename option is cleared.

File Format

The format of htext text file is typically ASCII text. Text enclosed by special double characters (by default, percent signs '%%') is interpreted and executed as Tcl commands. The special character may be specified by the -specialchar option. In the following example of a htext file, a button widget is appended to the text between the words "a" and "which". The pathName of the htext widget is ".ht".
This will be displayed as normal text.
But this will become a %%
button .ht.button -text "button" -fg red
.ht append .ht.button
%% which can invoke a Tcl command.

Indices

Some of the widget operations (selection, gotoline, search, etc.) take one or more indices as arguments. An index is a string used to indicate a particular place within the text, such as the first and last characters in a range to be selected.

An index must have one of the following forms:

line.char
Indicates char'th character on line line. Both lines and characters are number from 0, so "0.0" is the first beginning of the text. Char may be undesignated. In this case a character position of 0 is assumed.
@x,y
Indicates the character that covers the pixel whose x and y coordinates within the text's window are x and y.
end
Indicates the end of the text.
anchor
Indicates the anchor point for the selection, which is set with the selection operation.
sel.first
Indicates the first character in the selection. It is an error to use this form if the selection isn't in the entry window.
sel.last
Indicates the character just after the last one in the selection. It is an error to use this form if the selection isn't in the entry window.

Variables

The following global Tcl variables are maintained when an htext file is parsed.

htext(widget)
is the pathname of the htext widget.
htext(file)
is the name of the file the htext widget is currently parsing. It is the empty string when the -text option is used.
htext(line)
is the current line number in the text.

This information might be used to construct hyper links between different files and/or lines.

Syntax

The htext command creates a new Tcl command whose name is pathName. This command may be used to invoke various operations on the widget. It has the following general form:

pathName oper ?args?

Oper and args determine the exact behavior of the command.

Operations

The following operations are available for htext widgets:
pathName append window ?option value?...
Embeds the widget window into the htext widget. Window is the pathname of the widget to be embedded which must be a child of pathName. Window will be positioned in the htext widget at the current location of the text. If option and value pairs are present, they configure various aspects how window appears in pathName. The following options are available.
-anchor anchorPos
Specifies how window will be arranged if there is any extra space in the cavity surrounding the window. For example, if anchorPos is center then the window is centered in the cavity; if anchorPos is w then the window will be drawn such it touches the leftmost edge of the cavity. The default is center.
-fill style
Specifies how the window should be stretched to occupy the extra space in the cavity surrounding it (if any exists). Style is none, x, y, both. If style is x, the width of window is expanded to fill the cavity. If style is y, the height is expanded. The default is none.
-height pixels
Sets the height of the cavity surrounding window. If pixels is zero, the height of the cavity will be the same as the requested height of window. If pixels is less than the requested height of window, window will be reduced to fit the cavity. The default is 0.
-ipadx pad
Sets the amount of internal padding to be added to the width window. Pad can be a list of one or two numbers. If pad has two elements, the left side of window is extended by the first value and the right side by the second value. If pad is just one value, both the left and right sides are padded by evenly by the value. The default is 0.
-ipady pad
Sets an amount of internal padding to be added to the height of window. Pad can be a list of one or two numbers. If pad has two elements, the top of window is padded by the first value and the bottom by the second value. If pad is just one number, both the top and bottom are padded evenly by the value. The default is 0.
-justify justify
Justifies window vertically within the cavity containing it in relation to the line of text. Justify is top, bottom, or center. If justify is center the widget is centered along the baseline of the line of text. The default is center.
-padx pad
Sets the padding on the left and right sides of window. Pad can be a list of one or two numbers. If pad has two elements, the left side of window is padded by the first value and the right side by the second value. If pad has just one value, both the left and right sides are padded evenly by the value. The default is 0.
-pady pad
Sets the padding above and below window. Pad can be a list of one or two numbers. If pad has two elements, the area above window is padded by the first value and the area below by the second value. If pad is just one number, both the top and bottom are padded by the value. The default is 0.
-relheight value
Specifies the height of the cavity containing window relative to the height of pathName. Value is real number indicating the ratio of the height of the cavity to the height of pathName. As the height of pathName changes, so will the height of window. If value is 0.0 or less, the height of the cavity is the requested height window. The default is 0.0.
-relwidth value
Specifies the width of the cavity containing window relative to the width of pathName. Value is real number indicating the ratio of the width of the cavity to the width of IpathName. As the height of pathName changes, so will the height of window. If value is 0.0 or less, the width of the cavity is the requested width of window. The default is 0.0.
-width value
Species the width of the cavity containing the child window. Value must be in a form accepted by Tk_GetPixels. If value is greater than zero, the cavity is resized to that width. If the requested window width is greater than the cavity's width, the window will be reduced to fit the cavity. By default, the cavity is requested width of the child window.
pathName configure ?window? ?option? ?value option value ...?
Queries or modifies the configuration options of the text widget or one of its embedded widgets. If no window argument is present, the htext widget itself is configured. Otherwise window is the pathname of a widget already embedded into the htext widget. Then this command configure the options for the embedded widget.

If option isn't specified, a list describing all of the current options for pathName or window 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 htext or embedded window option option is set to value.

The following options are valid for the htext widget.

-background color
Sets the background of the htext widget to color. This default is white.
-cursor cursor
Specifies the cursor for the htext widget. The default cursor is pencil.
-filename fileName
Specifies a htext file to be displayed in the window. If the value is the empty string, the -text option is used instead. See the section FILE for a description of the htext file format.
-font fontName
Sets the font of the text in the htext widget to fontName. The default is *-Helvetica-Bold-R-Normal-*-12-120-*.
-foreground color
Sets the foreground of the htext widget to color. This is the color of the text. This default is black.
-height pixels
Specifies the height of the htext widget window.
-linespacing pixels
Specifies the spacing between each line of text. The value must be in a form accepted by Tk_GetPixels. The default value is 1 pixel.
-specialchar number
Specifies the ASCII value of the special double character delimiters. In htext files, the text between these special characters is evaluated as a block of Tcl commands. The default special character is the 0x25 (percent sign).
-text text
Specifies the text to be displayed in the htext widget. Text can be any valid string of characters. See FILE FORMAT for a description.
-xscrollcommand string
Specifies the prefix for a command used to communicate with horizontal scrollbars. When the view in the htext widget's window changes (or whenever anything else occurs that could change the display in a scrollbar, such as a change in the total size of the widget's contents), the widget invoke string concatenated by two numbers. Each of the numbers is a fraction between 0 and 1, which indicates a position in the document. If this option is not specified, then no command will be executed.
-yscrollcommand string
Specifies the prefix for a command used to communicate with vertical scrollbars. When the view in the htext widget's window changes (or whenever anything else occurs that could change the display in a scrollbar, such as a change in the total size of the widget's contents), the widget invoke string concatenated by two numbers. Each of the numbers is a fraction between 0 and 1, which indicates a position in the document. If this option is not specified, then no command will be executed.
-width pixels
Specifies the desired width of the viewport window. If the pixels is less than one, the window will grow to accommodate the widest line of text.
-xscrollunits pixels
Specifies the horizontal scrolling distance. The default is 10 pixels.
-yscrollunits pixels
Specifies the vertical scrolling distance. The default is 10 pixels.
pathName gotoline ?index?
Sets the top line of the text to index. Index must be a valid text index (the character offset is ignored). If an index isn't provided, the current line number is returned.
pathName scan mark position
Records position and the current view in the text window; used in conjunction with later scan dragto commands. Position must be in the form "@x,y, where x and y are window coordinates. Typically this command is associated with a mouse button press in the widget. It returns an empty string.
pathName scan dragto position
Computes the difference between position and the position registered in the last scan mark command for the widget. The view is then adjusted up or down by 10 times the difference in coordinates. This command is can be associated with mouse motion events to produce the effect of dragging the text at high speed through the window. Position must be in the form "@x,y, where x and y are window coordinates. The command returns an empty string.
pathName search pattern ?from? ?to?
Returns the number of the next line matching pattern. Pattern is a string which obeys the matching rules of Tcl_StringMatch. From and to are text line numbers (inclusive) which bound the search. If no match for pattern can be found, -1 is returned.
pathName xview ?position?
Moves the viewport horizontally to the new text x-coordinate position. Position is the offset from the left side of the text to the current position and must be in a form accepted by Tk_GetPixels. If position is not present, the current text position is returned.
pathName yview ?position?
Moves the viewport vertically to the new text y-coordinate position. Position is the offset from the top of the text to the current position and must be in a form accepted by Tk_GetPixels. If position is not present, the current text position is returned.

Bugs

Text with embedded tabs can be obscured by child windows when scrolled horizontally.

Keywords

hypertext, widget


Table of Contents

blt-2.4z.orig/html/spline.html0100644000175000017500000001775507434255426015122 0ustar dokodoko spline(n) manual page Table of Contents

Name

spline - Fit curves with spline interpolation

Synopsis

spline natural x y sx sy

spline quadratic x y sx sy

Description

The spline command computes a spline fitting a set of data points (x and y vectors) and produces a vector of the interpolated images (y-coordinates) at a given set of x-coordinates.

Introduction

Curve fitting has many applications. In graphs, curve fitting can be useful for displaying curves which are aesthetically pleasing to the eye. Another advantage is that you can quickly generate arbitrary points on the curve from a small set of data points.

A spline is a device used in drafting to produce smoothed curves. The points of the curve, known as knots, are fixed and the spline, typically a thin strip of wood or metal, is bent around the knots to create the smoothed curve. Spline interpolation is the mathematical equivalent. The curves between adjacent knots are piecewise functions such that the resulting spline runs exactly through all the knots. The order and coefficients of the polynominal determine the "looseness" or "tightness" of the curve fit from the line segments formed by the knots.

The spline command performs spline interpolation using cubic ("natural") or quadratic polynomial functions. It computes the spline based upon the knots, which are given as x and y vectors. The interpolated new points are determined by another vector which represents the abscissas (x-coordinates) or the new points. The ordinates (y-coordinates) are interpolated using the spline and written to another vector.

Example

Before we can use the spline command, we need to create two BLT vectors which will represent the knots (x and y coordinates) of the data that we're going to fit. Obviously, both vectors must be the same length.
# Create sample data of ten points.
vector x(10) y(10)

for {set i 10} {$i > 0} {incr i -1} {
set x($i-1) [expr $i*$i]
set y($i-1) [expr sin($i*$i*$i)]
}

We now have two vectors x and y representing the ten data points we're trying to fit. The order of the values of x must be monotonically increasing. We can use the vector's sort operation to sort the vectors.
x sort y

The components of x are sorted in increasing order. The components of y are rearranged so that the original x,y coordinate pairings are retained.

A third vector is needed to indicate the abscissas (x-coordinates) of the new points to be interpolated by the spline. Like the x vector, the vector of abscissas must be monotonically increasing. All the abscissas must lie between the first and last knots (x vector) forming the spline.

How the abscissas are picked is arbitrary. But if we are going to plot the spline, we will want to include the knots too. Since both the quadratic and natural splines preserve the knots (an abscissa from the x vector will always produce the corresponding ordinate from the y vector), we can simply make the new vector a superset of x. It will contain the same coordinates as x, but also the abscissas of the new points we want interpolated. A simple way is to use the vector's populate operation.
x populate sx 10

This creates a new vector sx. It contains the abscissas of x, but in addition sx will have ten evenly distributed values between each abscissa. You can interpolate any points you wish, simply by setting the vector values.

Finally, we generate the ordinates (the images of the spline) using the spline command. The ordinates are stored in a fourth vector.
spline natural x y sx sy

This creates a new vector sy. It will have the same length as sx. The vectors sx and sy represent the smoothed curve which we can now plot.
graph .graph
.graph element create original -x x -y x -color blue
.graph element create spline -x sx -y sy -color red
table . .graph

The natural operation employs a cubic interpolant when forming the spline. In terms of the draftmen's spline, a natural spline requires the least amount of energy to bend the spline (strip of wood), while still passing through each knot. In mathematical terms, the second derivatives of the first and last points are zero.

Alternatively, you can generate a spline using the quadratic operation. Quadratic interpolation produces a spline which follows the line segments of the data points much more closely.
spline quadratic x y sx sy

Operations

spline natural x y sx sy
Computes a cubic spline from the data points represented by the vectors x and y and interpolates new points using vector sx as the x-coordinates. The resulting y-coordinates are written to a new vector sy. The vectors x and y must be the same length and contain at least three components. The order of the components of x must be monotonically increasing. Sx is the vector containing the x-coordinates of the points to be interpolated. No component of sx can be less than first component of x or greater than the last component. The order of the components of sx must be monotonically increasing. Sy is the name of the vector where the calculated y-coordinates will be stored. If sy does not already exist, a new vector will be created.
spline quadratic x y sx sy
Computes a quadratic spline from the data points represented by the vectors x and y and interpolates new points using vector sx as the x-coordinates. The resulting y-coordinates are written to a new vector sy. The vectors x and y must be the same length and contain at least three components. The order of the components of x must be monotonically increasing. Sx is the vector containing the x-coordinates of the points to be interpolated. No component of sx can be less than first component of x or greater than the last component. The order of the components of sx must be monotonically increasing. Sy is the name of the vector where the calculated y-coordinates are stored. If sy does not already exist, a new vector will be created.

References


Numerical Analysis
by R. Burden, J. Faires and A. Reynolds.    
Prindle, Weber & Schmidt, 1981, pp. 112

Shape Preserving Quadratic Splines 
by D.F.Mcallister & J.A.Roulier
Coded by S.L.Dodd & M.Roulier N.C.State University.

The original code for the quadratric spline can be found in TOMS #574.

Keywords

spline, vector, graph


Table of Contents

blt-2.4z.orig/html/stripchart.html0100644000175000017500000031110607434255426015776 0ustar dokodoko stripchart(n) manual page Table of Contents

Name

stripchart - 2D strip chart for plotting x and y coordinate data.

Synopsis

stripchart pathName ?option value?...

Description

The stripchart command creates a strip chart 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 strip chart.

The stripchart is essentially the same as the graph widget. It works almost exactly the very same way.

The use of a strip chart differs in that the X-axis typically refers to time points. Data values are added at intervals. The strip chart lets you automatically maintain a view of the most recent time points. The axis options -shiftby and -autorange control this. You can specify different line styles for data points (see the -styles option).

Introduction

The stripchart command creates a new window for plotting two-dimensional data (x,y coordinates). Data points are plotted in a box displayed in the center of the new window. This is the plotting area. The coordinate axes are displayed in the margins around the plotting area. By default, the legend is displayed in the right margin. The title is displayed in top margin.

A strip chart is composed of several components: coordinate axes, data elements, legend, grid, cross hairs, pens, postscript, and annotation markers.

axis
The stripchart widget can display up to four coordinate axes (two X-coordinate and two Y-coordinate axes), 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 of each major tick.
crosshairs
Cross hairs are used to finely position the mouse pointer in relation to the coordinate axes. Two perpendicular lines are drawn across the plotting area, intersecting at the current location of the mouse pointer.
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 symbol, 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 widgets.
pen
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 -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


stripchart pathName ?option value?...

The stripchart command creates a new window pathName and makes it into a stripchart 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 strip 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, stripchart returns the path name of the widget. It also creates a new Tcl command by the same name. You can use this command to perform 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 strip chart are described in the STRIPCHART OPERATIONS section.

The command can also be used to access components of the strip chart.

pathName component operation ?arg?...

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.

Example

The stripchart command creates a new strip chart.
# Create a new strip chart. Plotting area is black.
stripchart .s -plotbackground black

A new Tcl command .s is also created. This command can be used to query and modify the strip chart. For example, to change the title of the strip chart to "My Plot", you use the new command and the widget's configure operation.
# Change the title.
.s configure -title "My Plot"

A strip chart 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"
.s 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 and 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 strip chart.
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 }
.s element create line1 -xdata xVec -ydata yVec

The advantage of using vectors is that when you modify one, the graph is automatically redrawn to display the new values.
# Change the X-Y coordinates of the first point.
set xVec(0) 0.18
set yVec(0) 25.18

An element named line1 is now created in .s. By default, the element's label in the legend will be also line1. You can change the label, or specify no legend entry, again using the element's configure operation.
# Don't display "line1" in the legend.
.s element configure line1 -label ""

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.
.s element configure line1 -symbol square -color red \
   -dashes { 2 4 2 } -linewidth 2 -pixels 2c

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 "line1" on the alternate Y-axis "y2".
.s element configure line1 -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 operation.
# Y-axis is log scale.
.s axis configure y -logscale yes

Axis limits are reset by simply specifying new axis limits using the -min and -max configuration options.
.s axis configure x -min 1.0 -max 1.5
.s axis configure y -min 12.0 -max 55.15

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.
.s axis configure x -min {} -max {}
.s axis configure y -min {} -max {}

It's common with strip charts to automatically maintain a view of the most recent time points. You can do this my setting the -autorange option.
.s axis configure x -autorange 20.0

If the time points are added in X-coordinates 1.0 unit, only the last twenty time points will be displayed. As more data is added, the view will march along.

Sometimes the rate of data is so high that changing the axis limits with each additional time point is prohibitive. You can use the -shiftby option to define an increment to shift the view when needed.
.s axis configure x -shiftby 15.0

When the view is shifted, it will allow a range of 15 new time points to be added until the axis limits are recomputed.

By default, the legend is displayed in the right margin. You can change this or any other legend configuration options using the legend component.
# Configure the legend font, color, and relief
.s 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.
.s legend configure -hide yes

The stripchart widget has simple drawing procedures called markers. They can be used to highlight or annotate data in the strip chart. The types of markers available are bitmaps, images, polygons, lines, or windows. Markers can be used, for example, to mark or brush points. Here is a text marker which labels the data first point. Markers are created using the marker operation.
# Create a label for the first data point of "line1".
.s 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 actual 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.
.s marker configure first_marker -under yes

You can add cross hairs or grid lines using the crosshairs and grid operations.
# Display both cross hairs and grid lines.
.s crosshairs configure -hide no -color red
.s grid configure -hide no -dashes { 2 2 }

Finally, to get hardcopy of the strip chart, use the postscript operation.
# Print the strip chart into file "file.ps"
.s postscript output file.ps -maxpect yes -decorations no

This generates a file file.ps containing the encapsulated PostScript of the strip chart. The option -maxpect says to scale the plot to the size of the page. Turning off the -decorations option indicates that no borders or color backgrounds should be displayed (i.e. the background of the margins, legend, and plotting area will be white).

Stripchart Operations

pathName axis operation ?arg?...
See the AXIS COMPONENTS section.
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 stripchart configuration option given by option. Option may be any option described below for the configure operation.
pathName configure ?option value?...
Queries or modifies the configuration options of the strip chart. If option isn't specified, a list describing all of 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 stripchart option option is set to value. The following options are valid for the stripchart.
-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 border 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 to draw elements into a pixmap before displaying them on the screen. The advantage of buffering elements is when markers are used heavily. Markers can be moved and redrawn without requiring every element to be redrawn again. The disadvantage is that it takes slightly longer to draw the graph. If boolean is true, data elements are drawn to an internal pixmap. The option should be turned off if the plot is updated frequently. See the SPEED TIPS section. The default is 1.
-buffergraph boolean
Indicates whether to draw the graph into a pixmap first. If boolean is true, the entire graph is drawn into a pixmap and then copied onto the screen. This reduces flashing. If false, the graph is drawn directly into the window. Especially under Windows, turning off the option can be helpful when the stripchart is updated frequently. Turning off this option also turns -bufferelements off. 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 title font. 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 matters only when the title contains more than one line of text. Justify must be left, right, or center. The default is center.
-leftmargin pixels
Sets the size of the margin from the left edge of the window to the Y-coordinate axis. If pixels is 0, the size is calculated automatically. 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 indicates how the interior of the plotting area should appear relative to rest of the strip chart; for example, raised means the plot should appear to protrude from the strip chart, relative to the surface of the strip chart. The default is sunken.
-relief relief
Specifies the 3-D effect for the widget. Relief indicates how the strip chart should appear relative to widget it is packed into; for example, raised means the strip chart 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 displayed in this margin. If pixels is than 1, the margin size is selected automatically.
-takefocus focus
Provides information used when moving the focus from window 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
Specifies a tiled background. If image isn't "", the background is tiled using image. Otherwise, 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
Specifies the size of the margin above the x2 axis. If pixels is 0, the margin size is calculated automatically.
-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 strip chart. 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 graph coordinates.
pathName legend operation ?arg?...
See the LEGEND COMPONENT section.
pathName line elemName ?option value?...
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 stripchart. If present, fileName is the file name of the new metafile. Otherwise, the metafile is automatically added to the clipboard.
pathName postscript operation ?arg?...
See the POSTSCRIPT COMPONENT section.
pathName snap photoName
Takes a snapshot of the strip chart 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
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.

Stripchart Components

A strip chart 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 strip chart is partitioned, where each component has its own configuration options and operations that specifically control that aspect or part of the strip chart.

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 plotted. 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 "temperature"
.s 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 temperature data to this axis.
.s 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 bottom 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 components: 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.
# Display the axis temperature in the left margin.
.s 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 as 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 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.
pathName axis configure axisName ?option value?...
Queries or modifies the configuration options of axisName. If option isn't specified, a list describing all the current options for axisName 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 axis option option is set to value. The following options are valid for axes.
-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 strip chart is redrawn. You may query the configuration options. But do not reset them, because this can have unexpected results.

-descending boolean
Indicates whether the values along the axis are monotonically 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 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 "" is given as either description, then the that limit will not be displayed. The default is "".
-linewidth pixels
Sets the width of the axis and tick lines. The default is 1 pixel.
-logscale boolean
Indicates whether the scale of the axis is logarithmic or linear. If boolean is true, the axis is logarithmic. The default scale is linear.
-loose boolean
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 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 computed. 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 intervals. 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 automatically 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 done. 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 is drawn. The default is 1.
-stepsize value
Specifies the interval between major axis ticks. If value isn't a valid interval (must be less than the axis range), the request is ignored and the step size is automatically calculated.
-subdivisions number
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-*.
-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 *-Helvetica-Bold-R-Normal-*-14-140-*.

Axis configuration options may be also be set by the option command. The resource class is Axis. The resource names are the names of the axes (such as x or x2).
option add *Stripchart.Axis.Color blue
option add *Stripchart.x.LogScale true
option add *Stripchart.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 elements.
pathName axis invtransform axisName value
Performs the inverse transformation, changing the screen coordinate 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 mapping the it to axisName. Returns the transformed screen coordinate.

Only four axes can be displayed simultaneously. By default, they are x, y, x2, and y2. You can 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 component does. The xaxis component manages the X-axis located in the bottom margin (whatever axis that happens to be). Likewise, yaxis uses the Y-axis in the left margin, x2axis the top X-axis, and y2axis the right Y-axis.

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. 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 location. 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 without redrawing the entire strip chart.

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.
-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 *Stripchart.Crosshairs.LineWidth 2
option add *Stripchart.Crosshairs.Color red

pathName crosshairs off

Turns of 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 mapping 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 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.

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 cget elemName option
Returns the current value of the element configuration option given by option. Option may be any option described below for the element configure operation.
pathName element closest x y varName ?option value?... ?elemName?...
Finds the data point closest to the window coordinates x and y in the element elemName. ElemName is the name of an element, that must not be hidden. If no elements are specified, then all visible elements are searched. It returns via the array variable varName the name of the closest element, the index of its closest point, and the graph coordinates of the point. Returns 0, if no data point within the threshold distance can be found, otherwise 1 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 stripchart's -halo option.
-interpolate boolean
Indicates that both the data points and interpolated points along the line segment formed should be considered. If boolean is true, the closest line segment will be selected instead of the closest point. If this option isn't specified, boolean defaults to 0.
pathName element configure elemName ?option value?...
Queries or modifies the configuration options for elements. 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.
-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 a list of numeric expressions representing the X-Y coordinate pairs of each data point.
-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.
-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.
-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" pixels 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 defcolor, 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.
-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 false, the element's symbols are drawn at the designated size, regardless of axis scales. The default is 0.
-smooth smooth
Specifies how connecting line segments are drawn between data points. Smooth can be either linear, step, natural, or quadratic. If smooth is linear, a single line segment is drawn, connecting both data points. When smooth is step, two line segments are drawn. The first is a horizontal line segment which steps the next x-coordinate. The second is a vertical line, moving to the next y-coordinate. Both natural and quadratic generate multiple segments between data points. If natural, the segments are generated using a cubic spline. If quadratic, a quadratic spline is used. The default is linear.
-styles styleList
Specifies what pen to use based upon 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 number of the pen in the list.
-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 bitmap's optional mask. The default is circle.
-weights wVec
Specifies the weights of the individual data points. This, in conjunction 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 representing 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 command. The resource class is Element. The resource name is the name of the element.
option add *Stripchart.Element.symbol line
option add *Stripchart.e1.symbol line

pathName element create elemName ?option value?...

Creates a new element elemName. It's an error is an element elemName already exists. If additional arguments are present, they specify options valid for element configure operation.
pathName element deactivate elemName ?elemName?...
Deactivates all the elements matching pattern. Elements whose names match any of the patterns given are redrawn using their normal colors.
pathName element delete ?elemName?...
Deletes all the named elements. The graph is automatically redrawn.
pathName element exists elemName
Returns 1 if an element elemName currently exists and 0 otherwise.
pathName element names ?pattern?...
Returns the elements matching one or more pattern. If no pattern is given, the names of all elements is returned.
pathName element show ?nameList?
Queries or modifies the element display list. The element display 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 display 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 horizontally 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 following 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 true, grid lines are not shown. The default is yes.
-linewidth pixels
Sets the width of grid lines. The default width is 1.
-mapx xAxis
Specifies the X-axis to display grid lines. XAxis must be the name of an axis. The default is x.
-mapy yAxis
Specifies the Y-axis to display grid lines. YAxis must be the name of an axis. The default is y.
-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 command. The resource name and class are grid and Grid respectively.
option add *Stripchart.grid.LineWidth 2
option add *Stripchart.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 positioned 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 colors and relief. All entries whose element names match pattern are selected. To be selected, the element name must match only one pattern.
pathName legend cget option
Returns the current value of a legend configuration option. Option may be any option described below in the legend configure operation.
pathName legend configure ?option value?...
Queries or modifies the configuration options for the legend. If option isn't specified, a list describing the current legend 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 legend option option is set to value. The following options are valid for the legend.
-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 legend, relative to the surface of the legend. The default is flat.
-anchor anchor
Tells how to position the legend relative to the positioning 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 legend vertically.
top or bottom
The anchor describes how to position the legend horizontally.
@x,y
The anchor specifies how to position the legend 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 occupied by the legend will be at the positioning point.
plotarea
The anchor specifies how to position the legend relative to the plotting area. For example, 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 plotting area.
-background color
Sets the background color of the legend. If color is "", the legend background with be transparent.
-borderwidth pixels
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 *-Helvetica-Bold-R-Normal-*-12-120-*.
-foreground color
Sets the foreground color of the text drawn for the element'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 bottom 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 distances. 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.
-position pos
Specifies where the legend is drawn. The -anchor option also affects where the legend is positioned. If pos is left, left, top, or bottom, the legend is drawn in the specified margin. If pos is plotarea, then the legend is drawn inside the plotting area at a particular anchor. If pos is in the form "@x,y", where x and y are the window coordinates, the legend is drawn in the plotting area at the specified coordinates. The default is right.
-raised boolean
Indicates whether the legend is above or below the data elements. This matters only if the legend is in the 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 legend. Relief specifies how the interior of the legend should appear relative to the strip chart; for example, raised means the legend should appear to protrude from the strip chart, relative to the surface of the strip chart. The default is sunken.

Legend configuration options may also be set by the option command. The resource name and class are legend and Legend respectively.
option add *Stripchart.legend.Foreground blue
option add *Stripchart.Legend.Relief raised

pathName legend deactivate pattern...

Selects legend entries to be drawn using the normal legend colors 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.
.s pen configure "activeLine" -color green

You can create and use any number of pens. To create a pen, invoke the pen component and its create operation.
.s pen create myPen

You map pens to a data element using either the element's -pen or -activepen options.
.s 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).
.s 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 element's default attributes.

The following operations are available for pen components.

pathName pen cget penName option
Returns the current value of the option given by option for penName. Option may be any option described below for the pen configure operation.
pathName pen configure penName ?option value?...
Queries or modifies the configuration options of penName. If option isn't specified, a list describing the current options for penName 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 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" pixels 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 defcolor, 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 bitmap's optional mask. The default is circle.
-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 "line".

Pen configuration options may be also be set by the option command. The resource class is Pen. The resource names are the names of the pens.
option add *Stripchart.Pen.Color blue
option add *Stripchart.activeLine.color 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 elements.
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 strip chart can generate encapsulated PostScript output. There are several configuration options you can specify to control how the plot is 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 postscript 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 PostScript. Each element of varName must consist of PostScript code to set a particular color value (e.g. ``1.0 1.0 0.0 setrgbcolor''). When outputting color information in PostScript, the array variable varName is checked to see if an element of the name of the color exists. If so, it uses the value of the element 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 PostScript. Each element of varName must consist of a Tcl list with one or two elements, which are 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 an element of 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 Adobe (such as Times, Helvetica, Courier, etc.). If all of this fails then the font defaults to Helvetica-Bold.
-decorations boolean
Indicates if PostScript commands to generate color backgrounds and 3-D borders should 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 plot the stripchart with a height different from the one displayed on the screen. If pixels is 0, the height is the same as the displayed 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 (``landscape'' orientation). Defaults to 0.
-maxpect boolean
Indicates to scale the the plot so that it fills the PostScript page. The aspect ratio of the strip chart 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 plot the strip chart with a width different from the one drawn on the screen. 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 *Stripchart.postscript.Decorations false
option add *Stripchart.Postscript.Landscape true

pathName postscript output ?fileName? ?option value?...

Outputs a file of encapsulated PostScript. If a fileName argument 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 strip chart. 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 coordinate 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 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.

-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 element symbols and lines. Otherwise, the marker is drawn on top of the element. The default is 0.
-xoffset pixels
Specifies a screen distance to offset the marker horizontally. 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 vertically. 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 command. The resource class is either BitmapMarker, ImageMarker, LineMarker, PolygonMarker, TextMarker, or WindowMarker, depending on the type of marker. The resource name is the name of the marker.
option add *Stripchart.TextMarker.Foreground white
option add *Stripchart.BitmapMarker.Foreground white
option add *Stripchart.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 provided 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 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.

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
Sets the background color of the bitmap. If color is "", the background color will be transparent. The default background color is white.
-bitmap bitmap
Specifies the bitmap to be displayed. If bitmap is "", the marker will not be displayed. The default is "".
-foreground color
Sets the foreground color of the bitmap. The default foreground color is black.
-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 "".
-rotate theta
Sets the rotation of the bitmap. Theta 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 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 positioning 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 rectangular 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 markers 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:

-background color
Sets the background color of the line. The option is affects the line color only when the -stipple option is set. If this option isn't specified then it defaults to white.
-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.
-foreground color
Sets the foreground color. The default foreground color is black.
-linewidth pixels
Sets the width of the lines. The default width is 0.
-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 connected line segments. It is assumed the first and last points are connected. 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.
-stipple bitmap
Specifies that the polygon should be drawn with a stippled pattern 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 annotate regions of the strip chart. 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 positioning 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
Sets the background color of the text string. If color is "", the background will be transparent. The default is white.
-font fontName
Specifies the font of the text. The default is *-Helvetica-Bold-R-Normal-*-120-*.
-foreground color
Sets the foreground color of the text. The default is black.
-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.
-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 positioning 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. PathName must be a child of the stripchart widget.

Graph Component Bindings

Specific stripchart 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 commands 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 command.

The -bindtagsR 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 format.

Data can manipulated from the C language using BLT vectors. You specify the x and y data coordinates of an element as vectors and manipulate the vector from C. The strip chart will be redrawn automatically after the vectors are updated.

From Tcl, create the vectors and configure the element to use them.
vector X Y
.s 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 strip chart 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", 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;
}

See the vector manual page for more details.

Speed Tips

There may be cases where the strip 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.
    ·
  • Try to minimize the number of data points. The more data points the looked at, the more work the strip chart must do.
  • ·
  • 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.
  • ·
  • 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.
  • ·
  • Don't stipple or dash the element. Solid lines are much faster.
  • ·
  • If you update data elements frequently, try turning off the widget's -bufferelements option. When the strip chart is first displayed, it draws data elements into an internal pixmap. The pixmap acts as a cache, so that when the strip 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 strip chart. But if the strip 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 Reference Manual, page 568). The work-around is to break the polygon into separate pieces.

Future Incompatibility

The -mapped options are obsoleted and will be removed. You can achieve the same results using the -hide option instead.
# Works for now.
.s legend configure -mapped no

# Instead use this.
.s legend configure -hide yes

Keywords

stripchart, graph, widget


Table of Contents

blt-2.4z.orig/html/table.html0100644000175000017500000007765507434255426014724 0ustar dokodoko table(n) manual page Table of Contents

Name

table - Arranges widgets in a table

Synopsis

table container ?widget index option value?...

table arrange container

table cget container ?item? option

table configure container ?item?... ?option value?...

table extents container item

table forget widget ?widget?...

table info container item

table locate container x y

table containers ?switch? ?arg?

table save container

table search container ?switch arg?...

Description

The table command arranges widgets in a table. The alignment of widgets is detemined by their row and column positions and the number of rows or columns that they span.

Introduction

Probably the most painstaking aspect of building a graphical application is getting the placement and size of the widgets just right. It usually takes many iterations to align widgets and adjust their spacing. That's because managing the geometry of widgets is simply not a packing problem, but also graphical design problem. Attributes such as alignment, symmetry, and balance are more important than minimizing the amount of space used for packing.

The table geometry manager arranges widgets in a table. It's easy to align widgets (horizontally and vertically) or to create empty space to balance the arrangement of the widgets. Widgets (called slaves in the Tk parlance) are arranged inside a containing widget (called the master). Widgets are positioned at row,column locations and may span any number of rows or columns. More than one widget can occupy a single location.

The placement of widget windows determines both the size and arrangement of the table. The table queries the requested size of each widget. The requested size of a widget is the natural size of the widget (before the widget is shrunk or expanded). The height of each row and the width of each column is the largest widget spanning that row or column. The size of the table is in turn the sum of the row and column sizes. This is the table's normal size.

The total number of rows and columns in a table is determined from the indices specified. The table grows dynamically as windows are added at larger indices.

Example

The table geometry manager is created by invoking the table command.
# Create a table in the root window
table .

The window . is now the container of the table. Widgets are packed into the table and displayed within the confines of the container.

You add widgets to the table by row and column location. Row and column indices start from zero.
label .title -text "This is a title"

# Add a label to the table
table . .title 0,0

The label .title is added to the table. We can add more widgets in the same way.
button .ok -text "Ok"
button .cancel -text "Cancel"

# Add two buttons
table . .ok 1,0
table . .cancel 1,1

Two buttons .ok and .cancel are now packed into the second row of the table. They each occupy one cell of the table. By default, widgets span only a single row and column.

The first column contains two widgets, .title and .ok. By default, the widest of the two widgets will define the width of the column. However, we want .title to be centered horizontally along the top of the table. We can make .title span two columns using the configure operation.
# Make the label span both columns
table configure . .title -cspan 2

The label .title will now be centered along the top row of the table.

In the above example, we've create and arranged the layout for the table invoking the table command several times. Alternately, we could have used a single table command.
label .title -text "This is a title"
button .ok -text "Ok"
button .cancel -text "Cancel"

# Create and pack the table
table . \
.title 0,0 -cspan 2 \
.ok 1,0 \
.cancel 1,1

The table will override the requested width and height of the container so that the window fits the table exactly. This also means that any change to the size of table will be propagated up through the Tk window hierarchy. This feature can be turned off using the configure operation again.
table configure . -propagate no

You can also set the width of height of the table to a specific value. This supersedes the calculated table size.
# Make the container 4 inches wide, 3 inches high
table configure . -reqwidth 4i -reqheight 3i

If a widget is smaller than the cell(s) it occupies, the widget will float within the extra space. By default, the widget will be centered within the space, but you can anchor the widget to any side of cell using the -anchor configuration option.
table configure . .ok -anchor w

The -fill option expands the widget to fill the extra space either vertically or horizontally (or both).
# Make the title label fill the entire top row
table configure . .title -cspan 2 -fill x

# Each button will be as height of the 2nd row.
table configure . .ok .cancel -fill y

The width of .title will be the combined widths of both columns. Both .ok and .cancel will become as tall as the second row.

The -padx and -pady options control the amount of padding around the widget. Both options take a list of one or two values.
# Pad the title by two pixels above and below.
table configure . .title -pady 2

# Pad each button 2 pixels on the left, and 4 on the right.
table configure . .ok .cancel -padx { 2 4 }

If the list has only one value, then both exterior sides (top and bottom or left and right) of the widget are padded by that amount. If the list has two elements, the first specifies padding for the top or left side and the second for the bottom or right side.

Like the container, you can also override the requested widths and heights of widgets using the -reqwidth and -reqheight options. This is especially useful with character-based widgets (such as buttons, labels, text, listbox, etc) that let you specify their size only in units of characters and lines, instead of pixels.
# Make all buttons one inch wide
table configure . .ok .cancel -reqwidth 1i

Each row and column of the table can be configured, again using the configure operation. Rows are and columns are designated by Ri and Ci respectively, where i is the index of the row or column.

For example, you can set the size of a row or column.
# Make the 1st column 2 inches wide
table configure . c0 -width 2.0i

# Make the 2nd row 1/2 inch high.
table configure . r1 -height 0.5i

The new size for the row or column overrides its calculated size. If no widgets span the row or column, its height or width is zero. So you can use the -width and -height options to create empty spaces in the table.
# Create an empty row and column
table configure . r2 c2 -width 1i

The -pady option lets you add padding to the top and bottom sides of rows. The -padx option adds padding to the left and right sides of columns. Both options take a list of one or two values.
# Pad above the title by two pixels
table configure . r0 -pady { 2 0 }

# Pad each column 4 pixels on the left, and 2 on the right.
table configure . c* -padx { 2 4 }

Notice that you can configure all the rows and columns using either R* or C*.

When the container is resized, the rows and columns of the table are also resized. Only the rows or columns that contain widgets (a widget spans the row or column) grow or shrink. The -resize option indicates whether the row or column can be shrunk or stretched. If the value is shrink, the row or column can only be resized smaller. If expand, it can only be resized larger. If none, the row or column is frozen at its requested size.
# Let the 1st column get smaller, but not bigger
table configure . c0 -resize shrink

# Let the 2nd column get bigger, not smaller
table configure . c1 -resize expand

# Don't resize the first row
table configure . r0 -resize none

The following example packs a canvas, two scrollbars, and a title. The rows and columns containing the scrollbars are frozen at their requested size, so that even if the frame is resized, the scrollbars will remain the same width.
table . \
.title 0,0 -cspan 3 \
.canvas 1,1 -fill both \
.vscroll 1,2 -fill y \
.hscroll 2,1 -fill x

# Don't let the scrollbars resize
table configure . c2 r2 -resize none

# Create an empty space to balance the scrollbar
table configure . c0 -width .vscroll

Note that the value of the -width option is the name of a widget window. This indicates that the width of the column should be the same as the requested width of .vscroll.

Finally, the forget operation removes widgets from the table.
# Remove the windows from the table
table forget .quit .frame

It's not necessary to specify the container. The table command determines the container from the widget name.

Operations

The following operations are available for the table:
table container ?widget index option value?...
Adds the widget widget to the table at index. Index is a row,column position in the table. It must be in the form row,column where row and column are the respective row and column numbers, starting from zero (0,0 is the upper leftmost position). Row and column may also be numeric expressions that are recursively evaluated. If a table doesn't exist for container, one is created. Widget is the path name of the window, that must already exist, to be arranged inside of container. Option and value are described in the WIDGET section.
table arrange container
Forces the table to compute its layout immediately. Normally, the table geometry manager will wait until the next idle point, before calculating the size of its rows and columns. This is useful for collecting the normal sizes of rows and columns, that are based upon the requested widget sizes.
table cget container ?item? option
Returns the current value of the configuration option specific to item given by option. Item is either a row or column index, or the path name of a widget. Item can be in any form describe in the configure operation below. If no item argument is provided, then the configuration option is for the table itself. Option may be any one of the options described in the appropiate section for item.
table configure container item... ?option value?...
Queries or modifies the configuration options specific to item. If no option is specified, this command returns a list describing all of the available options for item If the argument item is omitted, then the specified configuration options are for the table itself. Otherwise item must be either a row or column specification, or the path name of a widget. The following item types are available.
Ci
Specifies the column of container to be configured. Item must be in the form Cn, where i is the index of the column. See the COLUMN section.
Ri
Specifies the row of container to be configured. Item must be in the form Ri, where i is the index of the row. See the ROW section.
widget
Specifies a widget of container to be queried. Widget is the path name of a widget packed in container. See the WIDGET section.
No argument
Specifies that the table itself is to be queried. See the TABLE section for a description of the option-value pairs for the table.

The option and value pairs are specific to item. If option is specified with no value, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given option(s) to have the given value(s); in this case the command returns the empty string.

table extents container index
Queries the location and dimensions of row and columns in the table. Index can be either a row or column index or a table index. Returns a list of the x,y coordinates (upperleft corner) and dimensions (width and height) of the cell, row, or column.
table forget widget ?widget?...
Requests that widget no longer have its geometry managed. Widget is the pathname of the window currently managed by some table. The window will be unmapped so that it no longer appears on the screen. If widget is not currently managed by any table, an error message is returned, otherwise the empty string.
table info container item
Returns a list of the current configuration options for item. The list returned is exactly in the form that might be specified to the table command. It can be used to save and reset table configurations. Item must be one of the following.
Ci
Specifies the column of container to be queried. Item must be in the form Cn, where n is the index of the column.
Ri
Specifies the row of container to be queried. Item must be in the form Ri, where i is the index of the row.
widget
Specifies a widget of container to be queried. Widget is the path name of a widget packed in container.
No argument
Specifies that the table itself is to be queried.
table locate container x y
Returns the table index (row,column) of the cell containing the given screen coordinates. The x and y arguments represent the x and y coordinates of the sample point to be tested.
table containers ?switch arg?
Returns a list of all container windows matching a given criteria (using switch and arg). If no switch and arg arguments are given, the names of all container windows (only those using the table command) are returned. The following are valid switches:
-pattern pattern
Returns a list of pathnames of all container windows matching pattern.
-slave window
Returns the name of the container window of table managing window. Window must be the path name of widget. If window is not managed by any table, the empty string is returned.
table search container ?switch arg?...
Returns the names of all the widgets in container matching the criteria given by switch and arg. Container is name of the container window associated with the table to be searched. The name of the widget is returned if any one switch-arg criteria matches. If no switch-arg arguments are given, the names of all widgets managed by container are returned. The following are switches are available:
-pattern pattern
Returns the names of any names of the widgets matching pattern.
-span index
Returns the names of widgets that span index. A widget does not need to start at index to be included. Index must be in the form row,column, where row and column are valid row and column numbers.
-start index
Returns the names of widgets that start at index. Index must be in the form row,column, where row and column are valid row and column numbers.

Table Options

To configure the table itself, you omit the item argument when invoking the configure operation.
table configure container ?option value?...

The following options are available for the table:

-padx pad
Sets how much padding to add to the left and right exteriors of the table. Pad can be a list of one or two numbers. If pad has two elements, the left side of the table is padded by the first value and the right side by the second value. If pad has just one value, both the left and right sides are padded evenly by the value. The default is 0.
-pady pad
Sets how much padding to add to the top and bottom exteriors of the table. Pad can be a list of one or two numbers. If pad has two elements, the area above the table is padded by the first value and the area below by the second value. If pad is just one number, both the top and bottom areas are padded by the value. The default is 0.
-propagate boolean
Indicates if the table should override the requested width and height of the container window. If boolean is false, container will not be resized. Container will be its requested size. The default is 1.

Widget Options

widgets are configured by specifying the name of the widget when invoking the configure operation.

table configure container widget ?option value?...

Widget must be the path name of a window already packed in the table associated with container. The following options are available for widgets:

-anchor anchor
Anchors widget to a particular edge of the cell(s) it resides. This option has effect only if the space of the spans surrounding widget is larger than widget. Anchor specifies how widget will be positioned in the space. For example, if anchor is center then the window is centered in the rows and columns it spans; if anchor is w then the window will be aligned with the leftmost edge of the span. The default is center.
-columnspan number
Sets the number of columns widget will span. The default is 1.
-columncontrol control
Specifies how the width of widget should control the width of the columns it spans. Control is either normal, none, or full. The default is normal.
none
The width of widget is not considered.
full
Only the width of widget will be considered when computing the widths of the columns.
normal
Indicates that the widest widget spanning the column will determine the width of the span.
-fill fill
Specifies if widget should be stretched to fill any free space in the span surrounding widget. Fill is either none, x, y, both. The default is none.
x
The widget can grow horizontally.
y
The widget can grow vertically.
both
The widget can grow both vertically and horizontally.
none
The widget does not grow along with the span.
-ipadx pixels
Sets how much horizontal padding to add internally on the left and right sides of widget. Pixels must be a valid screen distance like 2 or 0.3i. The default is 0.
-ipady pixels
Sets how much vertical padding to add internally on the top and bottom of widget. Pixels must be a valid screen distance like 2 or 0.3i. The default is 0.
-padx pad
Sets how much padding to add to the left and right exteriors of widget. Pad can be a list of one or two numbers. If pad has two elements, the left side of widget is padded by the first value and the right side by the second value. If pad has just one value, both the left and right sides are padded evenly by the value. The default is 0.
-pady pad
Sets how much padding to add to the top and bottom exteriors of widget. Pad can be a list of one or two numbers. If pad has two elements, the area above widget is padded by the first value and the area below by the second value. If pad is just one number, both the top and bottom areas are padded by the value. The default is 0.
-reqheight height
Specifies the limits of the requested height for widget. Height is a list of bounding values. See the BOUNDING section for a description of this list. By default, the height of widget is its requested height with its internal padding (see the -ipady option). The bounds specified by height either override the height completely, or bound the height between two sizes. The default is "".
-reqwidth width
Specifies the limits of the requested width for widget. Width is a list of bounding values. See the BOUNDING section for a description of this list. By default, the width of widget is its requested width with its internal padding (set the -ipadx option). The bounds specified by width either override the width completely, or bound the height between two sizes. The default is "".
-rowspan number
Sets the number of rows widget will span. The default is 1.
-rowcontrol control
Specifies how the height of widget should control the height of the rows it spans. Control is either normal, none, or full. The default is normal.
none
The height of widget is not considered.
full
Only the height of widget will be considered when computing the heights of the rows.
normal
Indicates that the tallest widget spanning the row will determine the height of the span.

Column Options

To configure a column in the table, specify the column index as Ci, where i is the index of the column to be configured.

table configure container Ci ?option value?...

If the index is specified as C*, then all columns of the table will be configured. The following options are available for table columns.

-padx pad
Sets the padding to the left and right of the column. Pad can be a list of one or two numbers. If pad has two elements, the left side of the column is padded by the first value and the right side by the second value. If pad has just one value, both the left and right sides are padded evenly by the value. The default is 0.
-resize mode
Indicates that the column can expand or shrink from its requested width when the table is resized. Mode must be one of the following: none, expand, shrink, or both. If mode is expand the width of the column is expanded if there is extra space in the container window. If mode is shrink its width may be reduced beyond its requested width if there is not enough space in the container. The default is none.
-width width
Specifies the limits within that the width of the column may expand or shrink. Width is a list of bounding values. See the section BOUNDING for a description of this list. By default there are no constraints.

Row Options

To configure a row in the table, specify the row index as Ri, where i is the index of the row to be configured.

table configure container Ri ?option value?...

If the index is specified as R*, then all rows of the table will be configured. The following options are available for table rows.

-height height
Specifies the limits of the height that the row may expand or shrink to. Height is a list of bounding values. See the section BOUNDING for a description of this list. By default there are no constraints.
-pady pad
Sets the padding above and below the row. Pad can be a list of one or two numbers. If pad has two elements, the area above the row is padded by the first value and the area below by the second value. If pad is just one number, both the top and bottom areas are padded by the value. The default is 0.
-resize mode
Indicates that the row can expand or shrink from its requested height when the table is resized. Mode must be one of the following: none, expand, shrink, or both. If mode is expand the height of the row is expanded if there is extra space in the container. If mode is shrink its height may be reduced beyond its requested height if there is not enough space in the container. The default is none.

Bounding Sizes

Sometimes it's more useful to limit resizes to an acceptable range, than to fix the size to a particular value or disallow resizing altogether. Similar to the way the wm command lets you specify a minsize and maxsize for a toplevel window, you can bound the sizes the container, a widget, row, or column may take. The -width, -height, -reqwidth, and -reqheight options, take a list of one, two, or three values. We can take a previous example and instead preventing resizing, bound the size of the scrollbars between two values.
table . \
.title 0,0 -cspan 3 \
.canvas 1,1 -fill both \
.vscroll 1,2 -fill y \
.hscroll 2,1 -fill x

# Bound the scrollbars between 1/8 and 1/2 inch
table configure . c2 -width { 0.125 0.5 }
table configure . r2 -height { 0.125 0.5 }
table configure . vscroll .hscroll -fill both

The scrollbars will get no smaller than 1/8 of an inch, or bigger than 1/2 inch. The initial size will be their requested size, so long as it is within the specified bounds.

How the elements of the list are interpreted is dependent upon the number of elements in the list.

{}
Empty list. No bounds are set. The default sizing is performed.
{ x }
Fixes the size to x. The window or partition cannot grow or shrink.
{ min max }
Sets up minimum and maximum limits for the size of the window or partition. The window or partition can be reduced less than min, nor can it be stretched beyond max.
{ min max nom }
Specifies minimum and maximum size limits, but also specifies a nominal size nom. This overrides the calculated size of the window or partition.

Miscellaneous

Another feature is that you can put two widgets in the same cell of the table. This is useful when you want to add decorations around a widget.
frame .frame -bd 1 -relief sunken
button .quit -text "Quit"

# Put both the frame and the button in the same cell.
table . \
.quit 1,0 -padx 2 -pady 2 \
.frame 1,0 -fill both

Limitations

A long standing bug in Tk (circa 1993), there is no way to detect if a window is already a container of a different geometry manager. This is usually done by accident, such as the following where all three widgets are arranged in the same container ".", but using different geometry managers.
table .f1
   ...
pack .f2
   ...
grid .f3

This leads to bizarre window resizing, as each geometry manager applies its own brand of layout policies. When the container is a top level window (such as "."), your window manager may become locked as it responds to the never-ending stream of resize requests.

Keywords

frame, geometry manager, location, table, size


Table of Contents

blt-2.4z.orig/html/tabset.html0100644000175000017500000012357407434255426015107 0ustar dokodoko tabset(n) manual page Table of Contents

Name

tabset - Create and manipulate tabset widgets

Synopsis

tabset pathName ?options?

Description

The tabset widget displays a series of overlapping folders. Only the contents of one folder at a time is displayed. By clicking on the tab's of a folder, you can view other folders. Each folder may contain any Tk widget that can be automatically positioned and resized in the folder.

There's no limit to the number of folders. Tabs can be tiered or scrolled. Pages (i.e. embedded widgets) can be torn off and displayed in another toplevel widget, and also restored. A tabset can also be used as just a set of tabs, without a displaying any pages. You can bind events to individual tabs, so it's easy to add features like "balloon help".

Introduction

Notebooks are a popular graphical paradigm. They allow you to organize many windows in a single widget. For example, you might have an application the displays several X-Y graphs at the same time. Typically, you can't pack the graphs into the same frame because they are too large. The other alternative is to pack the graphs into several toplevel widgets, allowing them to overlap on the screen. The problem is that all the different toplevel windows clutter the screen and are difficult to manage.

The tabset widget lets organize your application by displaying each graph as a page in a folder of a notebook. Only one page is visible at a time. When you click on a tab, the folder (graph) corresponding to the tab is displayed in the tabset widget. The tabset also lets you temporarily tear pages out of the notebook into a separate toplevel widget, and put them back in the tabset later. For example, you could compare two graphs side-by-side by tearing them out, and then replace them when you are finished.

A tabset may contain an unlimited number of folders. If there are too many tabs to view, you can arrange them as multiple tiers or scroll the tabs. The tabset uses the conventional Tk scrollbar syntax, so you can attach a scrollbar too.

Example

You create a tabset widget with the tabset command.
# Create a new tabset
tabset .ts -relief sunken -borderwidth 2

A new Tcl command .ts is also created. This command can be used to query and modify the tabset. For example, to change the default font used by all the tab labels, you use the new command and the tabset's configure operation.
# Change the default font.
.ts configure -font "fixed"

You can then add folders using the insert operation.
# Create a new folder "f1"
.ts insert 0 "f1"

This inserts the new tab named "f1" into the tabset. The index 0 indicates location to insert the new tab. You can also use the index end to append a tab to the end of the tabset. By default, the text of the tab is the name of the tab. You can change this by configuring the -text option.
# Change the label of "f1"
.ts tab configure "f1" -label "Tab #1"

The insert operation lets you add one or more folders at a time.
.ts insert end "f2" -label "Tab #2" "f3" "f4"

The tab on each folder contains a label. A label may display both an image and a text string. You can reconfigure the tab's attributes (foreground/background colors, font, rotation, etc) using the tab configure operation.
# Add an image to the label of "f1"
set image [image create photo -file stopsign.gif]
.ts tab configure "f1" -image $image
.ts tab configure "f2" -rotate 90

Each folder may contain an embedded widget to represent its contents. The widget to be embedded must be a child of the tabset widget. Using the -window option, you specify the name of widget to be embedded. But don't pack the widget, the tabset takes care of placing and arranging the widget for you.
graph .ts.graph
.ts tab configure "f1" -window ".ts.graph" \
-fill both -padx 0.25i -pady 0.25i

The size of the folder is determined the sizes of the Tk widgets embedded inside each folder. The folder will be as wide as the widest widget in any folder. The tallest determines the height. You can use the tab's -pagewidth and -pageheight options override this.

Other options control how the widget appears in the folder. The -fill option says that you wish to have the widget stretch to fill the available space in the folder.
.ts tab configure "f1" -fill both -padx 0.25i -pady 0.25i

Now when you click the left mouse button on "f1", the graph will be displayed in the folder. It will be automatically hidden when another folder is selected. If you click on the right mouse button, the embedded widget will be moved into a toplevel widget of its own. Clicking again on the right mouse button puts it back into the folder.

If you want to share a page between two different folders, the -command option lets you specify a Tcl command to be invoked whenever the folder is selected. You can reset the -window option for the tab whenever it's clicked.
.ts tab configure "f2" -command {
.ts tab configure "f2" -window ".ts.graph"
}
.ts tab configure "f1" -command {
.ts tab configure "f1" -window ".ts.graph"
}

If you have many folders, you may wish to stack tabs in multiple tiers. The tabset's -tiers option requests a maximum number of tiers. The default is one tier.
.ts configure -tiers 2

If the tabs can fit in less tiers, the widget will use that many. Whenever there are more tabs than can be displayed in the maximum number of tiers, the tabset will automatically let you scroll the tabs. You can even attach a scrollbar to the tabset.
.ts configure -scrollcommand { .sbar set } -scrollincrement 20
.sbar configure -orient horizontal -command { .ts view }

By default tabs are along the top of the tabset from left to right. But tabs can be placed on any side of the tabset using the -side option.
# Arrange tabs along the right side of the tabset.
.ts configure -side right -rotate 270

Syntax

The tabset command creates a new window using the pathName argument and makes it into a tabset widget.

tabset pathName ?option value?...

Additional options may be specified on the command line or in the option database to configure aspects of the tabset such as its colors, font, text, and relief. The tabset command returns its pathName argument. At the time this command is invoked, there must not exist a window named pathName, but pathName's parent must exist.

When first created, a new tabset contains no tabs. Tabs are added or deleted using widget operations described below. It is not necessary for all the tabs to be displayed in the tabset window at once; commands described below may be used to change the view in the window. Tabsets allow scrolling of tabs using the -scrollcommand option. They also support scanning (see the scan operation). Tabs may be arranged along any side of the tabset window using the -side option.

The size of the tabset window is determined the number of tiers of tabs and the sizes of the Tk widgets embedded inside each folder. The widest widget determines the width of the folder. The tallest determines the height. If no folders contain an embedded widget, the size is detemined solely by the size of the tabs.

You can override either dimension with the tabset's -width and -height options.

Tabset Indices

Indices refer to individual tabs/folders in the tabset. Many of the operations for tabset widgets take one or more indices as arguments. An index may take several forms:
number
Unique node id of the tab.
@x,y
Tab that covers the point in the tabset window specified by x and y (in screen coordinates). If no tab covers that point, then the index is ignored.
select
The currently selected tab. The select index is typically changed by either clicking on the tab with the left mouse button or using the widget's invoke operation.
active
The tab where the mouse pointer is currently located. The label is drawn using its active colors (see the -activebackground and -activeforeground options). The active index is typically changed by moving the mouse pointer over a tab or using the widget's activate operation. There can be only one active tab at a time. If there is no tab located under the mouse pointer, the index is ignored.
focus
Tab that currently has the widget's focus. This tab is displayed with a dashed line around its label. You can change this using the focus operation. If no tab has focus, then the index is ignored.
down
Tab immediately below the tab that currently has focus, if there is one. If there is no tab below, the current tab is returned.
left
Tab immediately to the left the tab that currently has focus, if there is one. If there is no tab to the left, the current tab is returned.
right
Tab immediately to the right the tab that currently has focus, if there is one. If there is no tab to the right, the current tab is returned.
up
Tab immediately above, if there is one, to the tab that currently has focus. If there is no tab above, the current tab is returned.
end
Last tab in the tabset. If there are no tabs in the tabset then the index is ignored.

Some indices may not always be available. For example, if the mouse is not over any tab, "active" does not have an index. For most tabset operations this is harmless and ignored.

Tabset Operations

All tabset operations are invoked by specifying the widget's pathname, the operation, and any arguments that pertain to that operation. The general form is:


   pathName operation ?arg arg ...?

Operation and the args determine the exact behavior of the command. The following operations are available for tabset widgets:

pathName activate index
Sets the active tab to the one indicated by index. The active tab is drawn with its active colors (see the -activebackground and -activeforeground options) and may be retrieved with the index active. Only one tab may be active at a time. If index is the empty string, then all tabs will be drawn with their normal foreground and background colors.
pathName bind tagName ?sequence? ?command?
Associates command with tagName such that whenever the event sequence given by sequence occurs for a tab with this tag, command will be invoked. The syntax is similar to the bind command except that it operates on tabs, rather than widgets. See the bind manual entry for complete details on sequence and the substitutions performed on command.

If all arguments are specified then a new binding is created, replacing any existing binding for the same sequence and tagName. If the first character of command is + then command augments an existing binding rather than replacing it. If no command 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 bindings have been defined for tagName.

pathName cget option
Returns the current value of the configuration option given by option. Option may have any of the values accepted by the configure operation described below.
pathName configure ?option? ?value option value ...?
Query or modify the configuration options of the widget. If no option is specified, returns a list describing all the available options for pathName (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. Option and value are described below:
-activebackground color
Sets the default active background color for tabs. A tab is active when the mouse is positioned over it or set by the activate operation. Individual tabs may override this option by setting the tab's -activebackground option.
-activeforeground color
Sets the default active foreground color for tabs. A tab is active when the mouse is positioned over it or set by the activate operation. Individual tabs may override this option by setting the tab's -activeforeground option.
-background color
Sets the background color of the tabset.
-borderwidth pixels
Sets the width of the 3-D border around the outside edge of the widget. The -relief option determines how the border is to be drawn. The default is 2.
-cursor cursor
Specifies the widget's cursor. The default cursor is "".
-dashes dashList
Sets the dash style of the focus outline. When a tab has the widget's focus, it is drawn with a dashed outline around its label. 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 outline will be a solid line. The default value is 5 2.
-font fontName
Sets the default font for the text in tab labels. Individual tabs may override this by setting the tab's -font option. The default value is *-Helvetica-Bold-R-Normal-*-12-120-*.
-foreground color
Sets the default color of tab labels. Individual tabs may override this option by setting the tab's -foreground option. The default value is black.
-gap size
Sets the gap (in pixels) between tabs. The default value is 2.
-height pixels
Specifies the requested height of widget. If pixels is 0, then the height of the widget will be calculated based on the size the tabs and their pages. The default is 0.
-highlightbackground color
Sets the color to display in the traversal highlight region when the tabset does not have the input focus.
-highlightcolor color
Sets the color to use for the traversal highlight rectangle that is drawn around the widget when it has the input focus. The default is black.
-highlightthickness pixels
Sets the width of the highlight rectangle to draw around the outside of the widget when it has the input focus. Pixels is a non-negative value and may have any of the forms acceptable to Tk_GetPixels. If the value is zero, no focus highlight is drawn around the widget. The default is 2.
-pageheight pixels
Sets the requested height of the page. The page is the area under the tab used to display the page contents. If pixels is 0, the maximum height of all embedded tab windows is used. The default is 0.
-pagewidth pixels
Sets the requested width of the page. The page is the area under the tab used to display the page contents. If pixels is 0, the maximum width of all embedded tab windows is used. The default is 0.
-relief relief
Specifies the 3-D effect for the tabset widget. Relief specifies how the tabset should appear relative to widget that it is packed into; for example, raised means the tabset should appear to protrude. The default is sunken.
-rotate theta
Specifies the degrees to rotate text in tab labels. Theta is a real value representing the number of degrees to rotate the tick labels. The default is 0.0 degrees.
-samewidth boolean
Indicates if each tab should be the same width. If true, each tab will be as wide as the widest tab. The default is no.
-scrollcommand string
Specifies the prefix for a command for communicating with scrollbars. Whenever the view in the widget's window changes, the widget will generate a Tcl command by concatenating the scroll command and two numbers. If this option is not specified, then no command will be executed.
-scrollincrement pixels
Sets the smallest number of pixels to scroll the tabs. If pixels is greater than 0, this sets the units for scrolling (e.g., when you the change the view by clicking on the left and right arrows of a scrollbar).
-selectbackground color
Sets the color to use when displaying background of the selected tab. Individual tabs can override this option by setting the tab's -selectbackground option.
-selectborderwidth pixels
Sets the width of the raised 3-D border to draw around the label of the selected tab. Pixels must be a non-negative value. The default value is 1.
-selectcommand string
Specifies a default Tcl script to be associated with tabs. This command is typically invoked when left mouse button is released over the tab. Individual tabs may override this with the tab's -command option. The default value is "".
-selectforeground color
Sets the default color of the selected tab's text label. Individual tabs can override this option by setting the tab's -selectforeground option. The default value is black.
-selectpad pixels
Specifies extra padding to be displayed around the selected tab. The default value is 3.
-side side
Specifies the side of the widget to place tabs. The following values are valid for side. The default value is top.
top
Tabs are drawn along the top.
left
Tabs are drawn along the left side.
right
Tabs are drawn along the right side.
both
Tabs are drawn along the bottom side.
-slant slant
Specifies if the tabs should be slanted 45 degrees on the left and/or right sides. The following values are valid for slant. The default is none.
none
Tabs are drawn as a rectangle.
left
The left side of the tab is slanted.
right
The right side of the tab is slanted.
both
Boths sides of the tab are slanted.
-tabbackground color
Sets the default background color of tabs. Individual tabs can override this option by setting the tab's -background option.
-tabborderwidth pixels
Sets the width of the 3-D border around the outside edge of the tab. The -tabrelief option determines how the border is to be drawn. The default is 2.
-tabforeground color
Specifies the color to use when displaying a tab's label. Individual tabs can override this option by setting the tab's -foreground option.
-tabrelief relief
Specifies the 3-D effect for both tabs and folders. Relief specifies how the tabs should appear relative to background of the widget; for example, raised means the tab should appear to protrude. The default is raised.
-takefocus focus
Provides information used when moving the focus from window 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 decide whether to focus on the window. The default is 1.
-textside side
If both images and text are specified for a tab, this option determines on which side of the tab the text is to be displayed. The valid sides are left, right, top, and bottom. The default value is left.
-tiers number
Specifies the maximum number of tiers to use to display the tabs. The default value is 1.
-tile image
Specifies a tiled background for the widget. If image isn't "", the background is tiled using image. Otherwise, the normal background color is drawn (see the -background option). Image must be an image created using the Tk image command. The default is "".
-width pixels
Specifies the requested width of the widget. If pixels is 0, then the width of the widget will be calculated based on the size the tabs and their pages. The default is 0.
pathName delete first ?last?
Deletes one or more tabs from the tabset. First and last are the first and last indices, defining a range of tabs to be deleted. If last isn't specified, then only the tab at first is deleted.
pathName focus index
Designates a tab to get the widget's focus. This tab is displayed with a dashed line around its label.
pathName get index
Returns the name of the tab. The value of index may be in any form described in the section TABSET INDICES
pathName index ?flag? string
Returns the node id of the tab specified by string. If flag is -name, then string is the name of a tab. If flag is -index, string is an index such as "active" or "focus". If flag isn't specified, it defaults to -index.
pathName insert position name ?option value?...
Inserts new tabs into the tabset. Tabs are inserted just before the tab given by position. Position may be either a number, indicating where in the list the new tab should be added, or end, indicating that the new tab is to be added the end of the list. Name is the symbolic name of the tab. Be careful not to use a number. Otherwise the tabset will confuse it with tab indices. Returns a list of indices for all the new tabs.
pathName invoke index
Selects the tab given by index, maps the tab's embedded widget, and invokes the Tcl command associated with the tab, if there is one. The return value is the return value from the Tcl command, or an empty string if there is no command associated with the tab. This command is ignored if the tab's state (see the -state option) is disabled.
pathName move index before|after index
Moves the tab index to a new position in the tabset.
pathName nearest x y
Returns the name of the tab nearest to given X-Y screen coordinate.
pathName scan option args
This command implements scanning on tabsets. It has two forms, depending on option:
pathName scan mark x y
Records x and y and the current view in the tabset window; used with later scan dragto commands. Typically this command is associated with a mouse button press in the widget. It returns an empty string.
pathName scan dragto x y.
This command computes the difference between its x and y arguments and the x and y arguments to the last scan mark command for the widget. It then adjusts the view by 10 times the difference in coordinates. This command is typically associated with mouse motion events in the widget, to produce the effect of dragging the list at high speed through the window. The return value is an empty string.
pathName see index
Scrolls the tabset so that the tab index is visible in the widget's window.
pathName size
Returns the number of tabs in the tabset.
pathName tab operation ?args?
See the TAB OPERATIONS section below.
pathName view args
This command queries or changes the position of the tabset in the widget's window. It can take any of the following forms:
pathName view
Returns a list of two numbers between 0.0 and 1.0 that describe the amount and position of the tabset that is visible in the window. For example, if view is "0.2 0.6", 20% of the tabset's text is off-screen to the left, 40% is visible in the window, and 40% of the tabset is off-screen to the right. These are the same values passed to scrollbars via the -scrollcommand option.
pathName view moveto fraction
Adjusts the view in the window so that fraction of the total width of the tabset text is off-screen to the left. fraction must be a number between 0.0 and 1.0.
pathName view scroll number what
This command shifts the view in the window (left/top or right/bottom) according to number and what. Number must be an integer. What must be either units or pages or an abbreviation of these. If what is units, the view adjusts left or right by number scroll units (see the -scrollincrement option). ; if it is pages then the view adjusts by number widget windows. If number is negative then tabs farther to the left become visible; if it is positive then tabs farther to the right become visible.

Tab Operations

pathName tab cget nameOrIndex option
Returns the current value of the configuration option given by option. Option may have any of the values accepted by the tab configure operation described below.
pathName tab configure nameOrIndex ?nameOrIndex...? option? ?value option value ...?
Query or modify the configuration options of one or more tabs. If no option is specified, this operation returns a list describing all the available options for nameOrIndex. NameOrIndex can be either the name of a tab or its index. Names of tabs take precedence over their indices. That means a tab named focus is picked over the "focus" tab.

If option is specified, but not value, then a list describing the one named option is returned. If one or more option-value pairs are specified, then each named tab (specified by nameOrIndex) will have its configurations option(s) set the given value(s). In this last case, the empty string is returned. Option and value are described below:

-activebackground color
Sets the active background color for nameOrIndex. A tab is active when the mouse is positioned over it or set by the activate operation. This overrides the widget's -activebackground option.
-activeforeground color
Sets the default active foreground color nameOrIndex. A tab is "active" when the mouse is positioned over it or set by the activate operation. Individual tabs may override this option by setting the tab's -activeforeground option.
-anchor anchor
Anchors the tab's embedded widget to a particular edge of the folder. This option has effect only if the space in the folder surrounding the embedded widget is larger than the widget itself. Anchor specifies how the widget will be positioned in the extra space. For example, if anchor is center then the window is centered in the folder ; if anchor is w then the window will be aligned with the leftmost edge of the folder. The default value is center.
-background color
Sets the background color for nameOrIndex. Setting this option overides the widget's -tabbackground option.
-bindtags tagList
Specifies the binding tags for this tab. TagList is a list of binding tag names. The tags and their order will determine how commands for events in tabs are invoked. Each tag in the list matching the event sequence will have its Tcl command executed. Implicitly the name of the tab is always the first tag in the list. The default value is all.
-command string
Specifies a Tcl script to be associated with nameOrIndex. This command is typically invoked when left mouse button is released over the tab. Setting this option overrides the widget's -selectcommand option.
-data string
Specifies a string to be associated with nameOrIndex. This value isn't used in the widget code. It may be used in Tcl bindings to associate extra data (other than the image or text) with the tab. The default value is "".
-fill fill
If the space in the folder surrounding the tab's embedded widget is larger than the widget, then fill indicates if the embedded widget should be stretched to occupy the extra space. Fill is either none, x, y, both. For example, if fill is x, then the widget is stretched horizontally. If fill is y, the widget is stretched vertically. The default is none.
-font fontName
Sets the font for the text in tab labels. If fontName is not the empty string, this overrides the tabset's -font option. The default value is "".
-foreground color
Sets the color of the label for nameOrIndex. If color is not the empty string, this overrides the widget's -tabforeground option. The default value is "".
-image imageName
Specifies the image to be drawn in label for nameOrIndex. If image is "", no image will be drawn. Both text and images may be displayed at the same time in tab labels. The default value is "".
-ipadx pad
Sets the padding to the left and right of the label. Pad can be a list of one or two screen distances. If pad has two elements, the left side of the label 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 value is 0.
-ipady pad
Sets the padding to the top and bottom of the label. Pad can be a list of one or two screen distances. If pad has two elements, the top of the label is padded by the first distance and the bottom by the second. If pad has just one distance, both the top and bottom sides are padded evenly. The default value is 0.
-padx pad
Sets the padding around the left and right of the embedded widget, if one exists. Pad can be a list of one or two screen distances. If pad has two elements, the left side of the widget 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 value is 0.
-pady pad
Sets the padding around the top and bottom of the embedded widget, if one exists. Pad can be a list of one or two screen distances. If pad has two elements, the top of the widget is padded by the first distance and the bottom by the second. If pad has just one distance, both the top and bottom sides are padded evenly. The default value is 0.
-selectbackground color
Sets the color to use when displaying background of the selected tab. If color is not the empty string, this overrides the widget's -selectbackground option. The default value is "".
-shadow color
Sets the shadow color for the text in the tab's label. Drop shadows are useful when both the foreground and background of the tab have similar color intensities. If color is the empty string, no shadow is drawn. The default value is "".
-state state
Sets the state of the tab. If state is disable the text of the tab is drawn as engraved and operations on the tab (such as invoke and tab tearoff) are ignored. The default is normal.
-stipple bitmap
Specifies a stipple pattern to use for the background of the folder when the window is torn off. Bitmap specifies a bitmap to use as the stipple pattern. The default is BLT.
-text text
Specifies the text of the tab's label. The exact way the text is drawn may be affected by other options such as -state or -rotate.
-window pathName
Specifies the widget to be embedded into the tab. PathName must be a child of the tabset widget. The tabset will "pack" and manage the size and placement of pathName. The default value is "".
-windowheight pixels
Sets the requested height of the page. The page is the area under the tab used to display the page contents. If pixels is 0, the maximum height of all embedded tab windows is used. The default is 0.
-windowwidth pixels
Sets the requested width of the page. The page is the area under the tab used to display the page contents. If pixels is 0, the maximum width of all embedded tab windows is used. The default is 0.
pathName tab names ?pattern?
Returns the names of all the tabs matching the given pattern. If no pattern argument is provided, then all tab names are returned.
pathName tab tearoff index ?newName?
Reparents the widget embedded into index, placing it inside of newName. NewName is either the name of an new widget that will contain the embedded widget or the name of the tabset widget. It the last case, the embedded widget is put back into the folder.

If no newName argument is provided, then the name of the current parent of the embedded widget is returned.

Default Bindings

BLT automatically generates class bindings that supply tabsets their default behaviors. The following event sequences are set by default for tabsets (via the class bind tag Tabset):

<ButtonPress-2>
<B2-Motion>
<ButtonRelease-2>
Mouse button 2 may be used for scanning. If it is pressed and dragged over the tabset, the contents of the tabset drag at high speed in the direction the mouse moves.
<KeyPress-Up>
<KeyPress-Down>
The up and down arrow keys move the focus to the tab immediately above or below the current focus tab. The tab with focus is drawn with the a dashed outline around the tab label.
<KeyPress-Left>
<KeyPress-Right>
The left and right arrow keys move the focus to the tab immediately to the left or right of the current focus tab. The tab with focus is drawn with the a dashed outline around the tab label.
<KeyPress-space>
<KeyPress-Return>
The space and return keys select the current tab given focus. When a folder is selected, it's command is invoked and the embedded widget is mapped.

Each tab, by default, also has a set of bindings (via the tag all). These bindings may be reset using the tabset's bind operation.

<Enter>
<Leave>
When the mouse pointer enters a tab, it is activated (i.e. drawn in its active colors) and when the pointer leaves, it is redrawn in its normal colors.
<ButtonRelease-1>
Clicking with the left mouse button on a tab causes the tab to be selected and its Tcl script (see the -command or -selectcommand options) to be invoked. The folder and any embedded widget (if one is specified) is automatically mapped.
<ButtonRelease-3>
<Control-ButtonRelease-1>
Clicking on the right mouse button (or the left mouse button with the Control key held down) tears off the current page into its own toplevel widget. The embedded widget is re-packed into a new toplevel and an outline of the widget is drawn in the folder. Clicking again (toggling) will reverse this operation and replace the page back in the folder.

Bind Tags

You can bind commands to tabs that are triggered when a particular event sequence 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).

It is possible for multiple bindings to match a particular event. This could occur, for example, if one binding is associated with the tab name and another is associated with the tab's tags (see the -bindtags option). When this occurs, all the matching bindings are invoked. A binding associated with the tab name is invoked first, followed by one binding for each of the tab'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.

The -bindtags option for tabs controls addition tag names that can be matched. Implicitly the first tag for each tab is its name. Setting the value of the -bindtags option doesn't change this.

Keywords

tabset, widget


Table of Contents

blt-2.4z.orig/html/tile.html0100644000175000017500000001074007434255426014550 0ustar dokodoko tile(n) manual page Table of Contents

Name

tile - Tiling versions of Tk widgets

Synopsis

tile::button pathName option value...

tile::checkbutton pathName option value...

tile::frame pathName option value...

tile::label pathName option value...

tile::radiobutton pathName option value...

tile::scrollbar pathName option value...

tile::toplevel pathName option value...

Description

The tile widgets let you create textured backgrounds. The texture is a Tk image which is tiled over the entire background of the widget.

Introduction

With the advent of Tk 4.0, images are now easy to create and use in applications. Images add interest to applications and they convey more information. But one area where Tk hasn't taken advantage of images is using images as textures for widgets. Since tiling is a standard feature of windowing systems, it's very easy to use images as textures.

The tile widgets take the standard Tk 4.0 widgets and add tiling configuration options to them. Textures are specified by the name of the image you wish to be tiled across the background of the widget.

Example

To add tiling to a widget, you simply create an image using Tk's image command and use the image name as the value for the -tile configuration option of the widget.
image create photo my_texture -file tan_paper.gif
blt::tile::frame .f -tile my_texture

The image my_texture is added to the frame. If my_texture is updated, so will the widget background.
image create photo my_texture -file rain.gif

The tile widget commands reside in the "blt::tile" namespace, so as not to collide with the normal Tk widgets. An easy way to add tiling to existing programs is to import the tile widget commands into the global namespace.
image create photo my_texture -file tan_paper.gif
namespace import -force blt::tile::*
frame .f -tile my_texture

To use one image for all texturing, you can use the "Tile" option class name to specify the same image for all tile widgets.
image create photo my_texture -file tan_paper.gif
option add *Tile my_texture

Options

The following configurations options are added to the widgets. If a -tile or -activetile option is specified, it overrides the background color of the widget.
-activetile image
Specifies a textured background to display when the widget is active. This option is available for the tilebutton, tilecheckbutton, tileradiobutton, and tilescrollbar widgets. Image is the name an image created using Tk's image command. The background of the widget is tiled with image. If image is "", then the active background color is displayed. The default is "".
-tile image
Specifies a textured background to display for the widget. Image is the name an image created using Tk's image command. The background of the widget is tiled with image. If image is "", then the normal background color is displayed. The default is "".

Keywords

tile, texture, button, label, radiobutton, checkbutton, scrollbar, frame, toplevel


Table of Contents

blt-2.4z.orig/html/tree.html0100644000175000017500000011375207434255426014561 0ustar dokodoko tree(n) manual page Table of Contents

Name

tree - Create and manage tree data objects.

Synopsis

blt::tree create ?treeName?

blt::tree destroy treeName...

blt::tree names ?pattern?

Description

The tree command creates tree data objects. A tree object is general ordered tree of nodes. Each node has both a label and a key-value list of data. Data can be heterogeneous, since nodes do not have to contain the same data keys. It is associated with a Tcl command that you can use to access and modify the its structure and data. Tree objects can also be managed via a C API.

Introduction

Example

Syntax

tree create ?treeName?
Creates a new tree object. The name of the new tree is returned. If no treeName argument is present, then the name of the tree is automatically generated in the form "tree0", "tree1", etc. If the substring "#auto" is found in treeName, it is automatically substituted by a generated name. For example, the name .foo.#auto.bar will be translated to .foo.tree0.bar.

A new Tcl command (by the same name as the tree) is also created. Another Tcl command or tree object can not already exist as treeName. If the Tcl command is deleted, the tree will also be freed. The new tree will contain just the root node. Trees are by default, created in the current namespace, not the global namespace, unless treeName contains a namespace qualifier, such as "fred::myTree".

tree destroy treeName...
Releases one of more trees. The Tcl command associated with treeName is also removed. Trees are reference counted. The internal tree data object isn't destroyed until no one else is using the tree.
tree names ?pattern?
Returns the names of all tree objects. if a pattern argument is given, then the only those trees whose name matches pattern will be listed.

Node IDs and Tags

Nodes in a tree object may be referred in either of two ways: by id or by tag. Each node has a unique serial number or id that is assigned to that node when it's created. The id of an node never changes and id numbers are not re-used.

A node may also have any number of tags associated with it. A tag is just a string of characters, and it may take any form except that of an integer. For example, "x123" is valid, but "123" isn't. The same tag may be associated with many different nodes. This is commonly done to group nodes in various interesting ways.

There are two built-in tags: The tag all is implicitly associated with every node in the tree. It may be used to invoke operations on all the nodes in the tree. The tag root is managed automatically by the tree object. It applies to the node current set as root.

When specifying nodes in tree object commands, if the specifier is an integer then it is assumed to refer to the single node with that id. If the specifier is not an integer, then it is assumed to refer to all of the nodes in the tree that have a tag matching the specifier. The symbol node is used below to indicate that an argument specifies either an id that selects a single node or a tag that selects zero or more nodes. Many tree commands only operate on a single node at a time; if node is specified in a way that names multiple items, then an error "refers to more than one node" is generated.

Node Modifiers

You can also specify node in relation to another node by appending one or more modifiers to the node id or tag. A modifier refers to a node in relation to the specified node. For example, "root->firstchild" selects the first subtree of the root node.

The following modifiers are available:

firstchild
Selects the first child of the node.
lastchild
Selects the last child of the node.
next
Selects the next node in preorder to the node.
nextsibling
Selects the next sibling of the node.
parent
Selects the parent of the node.
previous
Selects the previous node in preorder to the node.
prevsibling
Selects the previous sibling of the node.
"label"
Selects the node whose label is label. Enclosing label in quotes indicates to always search for a node by its label (for example, even if the node is labeled "parent").

It's an error the node can't be found. For example, lastchild and firstchild will generate errors if the node has no children. The exception to this is the index operation. You can use index to test if a modifier is valid.

Tree Operations

Once you create a tree object, you can use its Tcl command to query or modify it. The general form is

treeName operation ?arg?...

Both operation and its arguments determine the exact behavior of the command. The operations available for trees are listed below.

treeName ancestor node1 node2
Returns the mutual ancestor of the two nodes node1 and node2. The ancestor can be one of the two nodes. For example, if node1 and node2 are the same nodes, their ancestor is node1.
treeName apply node ?switches?
Runs commands for all nodes matching the criteria given by switches for the subtree designated by node. By default all nodes match, but you can set switches to narrow the match. This operation differs from find in two ways: 1) Tcl commands can be invoked both pre- and post-traversal of a node and 2) the tree is always traversed in depth first order.

The -exact, -glob, and -regexp switches indicate both what kind of pattern matching to perform and the pattern. Pattern matching is done, by default, against each node's label. But if the -path switch is present, it will match the full path of the node (a list containing the labels of the node's ancestors too). If the -key switch is used, it designates the data field to be matched.

The valid switches are listed below:

-depth number
Descend at most number (a non-negative integer) levels If number is 1 this means only apply the tests to the children of node.
-exact string
Matches each node using string. The node must match string exactly.
-glob string
Test each node to string using global pattern matching. Matching is done in a fashion similar to that used by the C-shell.
-invert
Select non-matching nodes. Any node that doesn't match the given criteria will be selected.
-key key
If pattern matching is selected (using the -exact, -glob, or -regexp switches), compare the values of the data field keyed by key instead of the node's label. If no pattern matching switches are set, then any node with this data key will match.
-leafonly
Only test nodes with no children.
-nocase
Ignore case when matching patterns.
-path
Use the node's full path when comparing nodes.
-precommand command
Invoke command for each matching node. Before command is invoked, the id of the node is appended. You can control processing by the return value of command. If command generates an error, processing stops and the find operation returns an error. But if command returns break, then processing stops, no error is generated. If command returns continue, then processing stops on that subtree and continues on the next.
-postcommand command
Invoke command for each matching node. Before command is invoked, the id of the node is appended. You can control processing by the return value of command. If command generates an error, processing stops and the find operation returns an error. But if command returns break, then processing stops, no error is generated. If command returns continue, then processing stops on that subtree and continues on the next.
-regexp string
Test each node using string as a regular expression pattern.
-tag string
Only test nodes that have the tag string.
treeName attach treeObject
Attaches to an existing tree object treeObject. This is for cases where the tree object was previously created via the C API. The current tree associated with treeName is discarded. In addition, the current set of tags, notifier events, and traces are removed.
treeName children node
Returns a list of children for node. If node is a leaf, then an empty string is returned.
treeName copy srcNode ?destTree? destNode ?switches?
Copies srcNode into destNode. Both nodes srcNode and destNode must already exist. If destTree argument is present, it indicates the name of the destination tree. By default both the source and destination trees are the same. The valid switches are listed below:
-overwrite
Overwrite nodes that already exist. Normally nodes are always created, even if there already exists a node by the same name. This switch indicates to add or overwrite the node's data fields.
-recurse
Recursively copy all the subtrees of srcNode as well. In this case, srcNode can't be an ancestor of destNode as it would result in a cyclic copy.
-tags
Copy tag inforation. Normally the following node is copied: its label and data fields. This indicates to copy tags as well.
treeName degree node
Returns the number of children of node.
treeName delete node...
Recursively deletes one or more nodes from the tree. The node and all its descendants are removed. The one exception is the root node. In this case, only its descendants are removed. The root node will remain. Any tags or traces on the nodes are released.
treeName depth node
Returns the depth of the node. The depth is the number of steps from the node to the root of the tree. The depth of the root node is 0.
treeName dump node
Returns a list of the paths and respective data for node and its descendants. The subtree designated by node is traversed returning the following information for each node: 1) the node's path relative to node, 2) a sublist key value pairs representing the node's data fields, and 3) a sublist of tags. This list returned can be used later to copy or restore the tree with the restore operation.
treeName dumpfile node fileName
Writes a list of the paths and respective data for node and its descendants to the given file fileName. The subtree designated by node is traversed returning the following information for each node: 1) the node's path relative to node, 2) a sublist key value pairs representing the node's data fields, and 3) a sublist of tags. This list returned can be used later to copy or restore the tree with the restore operation.
treeName exists node ?key?
Indicates if node exists in the tree. If a key argument is present then the command also indicates if the named data field exists.
treeName find node ?switches?
Finds for all nodes matching the criteria given by switches for the subtree designated by node. A list of the selected nodes is returned. By default all nodes match, but you can set switches to narrow the match.

The -exact, -glob, and -regexp switches indicate both what kind of pattern matching to perform and the pattern. Pattern matching is done, by default, against each node's label. But if the -path switch is present, it will match the full path of the node. If the -key switch is used, it designates the data field to be matched.

The order in which the nodes are traversed is controlled by the -order switch. The possible orderings are preorder, postorder, inorder, and breadthfirst. The default is postorder.

The valid switches are listed below:

-addtag string
Add the tag string to each selected node.
-count number
Stop processing after number (a positive integer) matches.
-depth number
Descend at most number (a non-negative integer) levels If number is 1 this means only apply the tests to the children of node.
-exact string
Matches each node using string. The node must match string exactly.
-exec command
Invoke command for each matching node. Before command is invoked, the id of the node is appended. You can control processing by the return value of command. If command generates an error, processing stops and the find operation returns an error. But if command returns break, then processing stops, no error is generated. If command returns continue, then processing stops on that subtree and continues on the next.
-glob string
Test each node to string using global pattern matching. Matching is done in a fashion similar to that used by the C-shell.
-invert
Select non-matching nodes. Any node that doesn't match the given criteria will be selected.
-key key
If pattern matching is selected (using the -exact, -glob, or -regexp switches), compare the values of the data field keyed by key instead of the node's label. If no pattern matching switches are set, then any node with this data key will match.
-leafonly
Only test nodes with no children.
-nocase
Ignore case when matching patterns.
-order string
Traverse the tree and process nodes according to string. String can be one of the following:
breadthfirst
Process the node and the subtrees at each sucessive level. Each node on a level is processed before going to the next level.
inorder
Recursively process the nodes of the first subtree, the node itself, and any the remaining subtrees.
postorder
Recursively process all subtrees before the node.
preorder
Recursively process the node first, then any subtrees.
-path
Use the node's full path when comparing nodes.
-regexp string
Test each node using string as a regular expression pattern.
-tag string
Only test nodes that have the tag string.
treeName findchild node label
Searches for a child node Ilabel in node. The id of the child node is returned if found. Otherwise -1 is returned.
treeName firstchild node
Returns the id of the first child in the node's list of subtrees. If node is a leaf (has no children), then -1 is returned.
treeName get node ?key? ?defaultValue?
Returns a list of key-value pairs of data for the node. If key is present, then onlyx the value for that particular data field is returned. It's normally an error if node does not contain the data field key. But if you provide a defaultValue argument, this value is returned instead (node will still not contain key). This feature can be used to access a data field of node without first testing if it exists. This operation may trigger read data traces.
treeName index node
Returns the id of node. If node is a tag, it can only specify one node. If node does not represent a valid node id or tag, or has modifiers that are invalid, then -1 is returned.
treeName insert parent ?switches?
Inserts a new node into parent node parent. The id of the new node is returned. The following switches are available:
-at number
Inserts the node into parent's list of children at position number. The default is to append node.
-data dataList
Sets the value for each data field in dataList for the new node. DataList is a list of key-value pairs.
-label string
Designates the labels of the node as string. By default, nodes are labeled as node0, node1, etc.
-tags tagList
Adds each tag in tagList to the new node. TagList is a list of tags, so be careful if a tag has embedded space.
treeName is property args
Indicates the property of a node. Both property and args determine the property being tested. Returns 1 if true and 0 otherwise. The following property and args are valid:
ancestor node1 node2
Indicates if node1 is an ancestor of node2.
before node1 node2
Indicates if node1 is before node2 in depth first traversal.
leaf node
Indicates if node is a leaf (it has no subtrees).
root node
Indicates if node is the designated root. This can be changed by the root operation.
treeName label node ?newLabel?
Returns the label of the node designated by node. If newLabel is present, the node is relabeled using it as the new label.
treeName lastchild node
Returns the id of the last child in the node's list of subtrees. If node is a leaf (has no children), then -1 is returned.
treeName move node newParent ?switches?
Moves node into newParent. Node is appended to the list children of newParent. Node can not be an ancestor of newParent. The valid flags for switches are described below.
-after child
Position node after child. The node child must be a child of newParent.
-at number
Inserts node into parent's list of children at position number. The default is to append the node.
-before child
Position node before child. The node child must be a child of newParent.
treeName next node
Returns the next node from node in a preorder traversal. If node is the last node in the tree, then -1 is returned.
treeName nextsibling node
Returns the node representing the next subtree from node in its parent's list of children. If node is the last child, then -1 is returned.
treeName notify args
Manages notification events that indicate that the tree structure has been changed. See the NOTIFY OPERATIONS section below.
treeName parent node
Returns the parent node of node. If node is the root of the tree, then -1 is returned.
treeName path node
Returns the full path (from root) of node.
treeName position node
Returns the position of the node in its parent's list of children. Positions are numbered from 0. The position of the root node is always 0.
treeName previous node
Returns the previous node from node in a preorder traversal. If node is the root of the tree, then -1 is returned.
treeName prevsibling node
Returns the node representing the previous subtree from node in its parent's list of children. If node is the first child, then -1 is returned.
treeName restore node dataString switches
Performs the inverse function of the dump operation, restoring nodes to the tree. The format of dataString is exactly what is returned by the dump operation. It's a list containing information for each node to be restored. The information consists of 1) the relative path of the node, 2) a sublist of key value pairs representing the node's data, and 3) a list of tags for the node. Nodes are created starting from node. Nodes can be listed in any order. If a node's path describes ancestor nodes that do not already exist, they are automatically created. The valid switches are listed below:
-overwrite
Overwrite nodes that already exist. Normally nodes are always created, even if there already exists a node by the same name. This switch indicates to add or overwrite the node's data fields.
treeName restorefile node fileName switches
Performs the inverse function of the dumpfile operation, restoring nodes to the tree from the file fileName. The format of fileName is exactly what is returned by the dumpfile operation. It's a list containing information for each node to be restored. The information consists of 1) the relative path of the node, 2) a sublist of key value pairs representing the node's data, and 3) a list of tags for the node. Nodes are created starting from node. Nodes can be listed in any order. If a node's path describes ancestor nodes that do not already exist, they are automatically created. The valid switches are listed below:
-overwrite
Overwrite nodes that already exist. Normally nodes are always created, even if there already exists a node by the same name. This switch indicates to add or overwrite the node's data fields.
treeName root ?node?
Returns the id of the root node. Normally this is node 0. If a node argument is provided, it will become the new root of the tree. This lets you temporarily work within a subset of the tree. Changing root affects operations such as next, path, previous, etc.
treeName set node key value ?key value...?
Sets one or more data fields in node. Node may be a tag that represents several nodes. Key is the name of the data field to be set and value is its respective value. This operation may trigger write and create data traces.
treeName size node
Returns the number of nodes in the subtree. This includes the node and all its descendants. The size of a leaf node is 1.
treeName sort node ?switches?
-ascii
Compare strings using the ASCII collation order.
-command string
Use command string as a comparison command. To compare two elements, evaluate a Tcl script consisting of command with the two elements appended as additional arguments. The script should return an integer less than, equal to, or greater than zero if the first element is to be considered less than, equal to, or greater than the second, respectively.
-decreasing
Sort in decreasing order (largest items come first).
-dictionary
Compare strings using a dictionary-style comparison. This is the same as -ascii except (a) case is ignored except as a tie-breaker and (b) if two strings contain embedded numbers, the numbers compare as integers, not characters. For example, in -dictionary mode, bigBoy sorts between bigbang and bigboy, and x10y sorts between x9y and x11y.
-integer
Compare the nodes as integers.
-key string
Sort based upon the node's data field keyed by string. Normally nodes are sorted according to their label.
-path
Compare the full path of each node. The default is to compare only its label.
-real
Compare the nodes as real numbers.
-recurse
Recursively sort the entire subtree rooted at node.
-reorder
Recursively sort subtrees for each node. Warning. Unlike the normal flat sort, where a list of nodes is returned, this will reorder the tree.
treeName tag args
Manages tags for the tree object. See the TAG OPERATIONS section below.
treeName trace args
Manages traces for data fields in the tree object. Traces cause Tcl commands to be executed whenever a data field of a node is created, read, written, or unset. Traces can be set for a specific node or a tag, representing possibly many nodes. See the TRACE OPERATIONS section below.
treeName unset node key...
Removes one or more data fields from node. Node may be a tag that represents several nodes. Key is the name of the data field to be removed. It's not an error is node does not contain key. This operation may trigger unset data traces.

Tag Operations

Tags are a general means of selecting and marking nodes in the tree. A tag is just a string of characters, and it may take any form except that of an integer. The same tag may be associated with many different nodes.

There are two built-in tags: The tag all is implicitly associated with every node in the tree. It may be used to invoke operations on all the nodes in the tree. The tag root is managed automatically by the tree object. It specifies the node that is currently set as the root of the tree.

Most tree operations use tags. And several operations let you operate on multiple nodes at once. For example, you can use the set operation with the tag all to set a data field in for all nodes in the tree.

Tags are invoked by the tag operation. The general form is

treeName tag operation ?arg?...

Both operation and its arguments determine the exact behavior of the command. The operations available for tags are listed below.

treeName tag add string node...
Adds the tag string to one of more nodes.
treeName tag delete string node...
Deletes the tag string from one or more nodes.
treeName tag forget string
Removes the tag string from all nodes. It's not an error if no nodes are tagged as string.
treeName tag names ?node?
Returns a list of tags used by the tree. If a node argument is present, only those tags used by node are returned.
treeName tag nodes string
Returns a list of nodes that have the tag string. If no node is tagged as string, then an empty string is returned.

Trace Operations

Data fields can be traced much in the same way that you can trace Tcl variables. Data traces cause Tcl commands to be executed whenever a particular data field of a node is created, read, written, or unset. A trace can apply to one or more nodes. You can trace a specific node by using its id, or a group of nodes by a their tag.

The tree's get, set, and unset operations can trigger various traces. The get operation can cause a read trace to fire. The set operation causes a write trace to fire. And if the data field is written for the first time, you will also get a create trace. The unset operation triggers unset traces.

Data traces are invoked by the trace operation. The general form is

treeName trace operation ?arg?...

Both operation and its arguments determine the exact behavior of the command. The operations available for traces are listed below.

treeName trace create node key ops command
Creates a trace for node on data field key. Node can refer to more than one node (for example, the tag all). If node is a tag, any node with that tag can possibly trigger a trace, invoking command. Command is command prefix, typically a procedure name. Whenever a trace is triggered, four arguments are appended to command before it is invoked: treeName, id of the node, key and, ops. Note that no nodes need have the field key. A trace identifier in the form "trace0", "trace1", etc. is returned.

Ops indicates which operations are of interest, and consists of one or more of the following letters:

r
Invoke command whenever key is read. Both read and write traces are temporarily disabled when command is executed.
w
Invoke command whenever key is written. Both read and write traces are temporarily disabled when command is executed.
c
Invoke command whenever key is created.
u
Invoke command whenever key is unset. Data fields are typically unset with the unset command. Data fields are also unset when the tree is released, but all traces are disabled prior to that.

treeName trace delete traceId...
Deletes one of more traces. TraceId is the trace identifier returned by the trace create operation.
treeName trace info traceId
Returns information about the trace traceId. TraceId is a trace identifier previously returned by the trace create operation. It's the same information specified for the trace create operation. It consists of the node id or tag, data field key, a string of letters indicating the operations that are traced (it's in the same form as ops) and, the command prefix.
treeName trace names
Returns a list of identifers for all the current traces.

Notify Operations

Tree objects can be shared among many clients, such as a hiertable widget. Any client can create or delete nodes, sorting the tree, etc. You can request to be notified whenever these events occur. Notify events cause Tcl commands to be executed whenever the tree structure is changed.

Notifications are handled by the notify operation. The general form is

treeName notify operation ?arg?...

Both operation and its arguments determine the exact behavior of the command. The operations available for events are listed below.

treeName notify create ?switches? command ?args?...
Creates a notifier for the tree. A notify identifier in the form "notify0", "notify1", etc. is returned.

Command and args are saved and invoked whenever the tree structure is changed (according to switches). Two arguments are appended to command and args before it's invoked: the id of the node and a string representing the type of event that occured. One of more switches can be set to indicate the events that are of interest. The valid switches are as follows:

-create
Invoke command whenever a new node has been added.
-delete
Invoke command whenever a node has been deleted.
-move
Invoke command whenever a node has been moved.
-sort
Invoke command whenever the tree has been sorted and reordered.
-relabel
Invoke command whenever a node has been relabeled.
-allevents
Invoke command whenever any of the above events occur.
-whenidle
When an event occurs don't invoke command immediately, but queue it to be run the next time the event loop is entered and there are no events to process. If subsequent events occur before the event loop is entered, command will still be invoked only once.
treeName notify delete notifyId
Deletes one or more notifiers from the tree. NotifyId is the notifier identifier returned by the notify create operation.
treeName notify info notifyId
Returns information about the notify event notifyId. NotifyId is a notify identifier previously returned by the notify create operation. It's the same information specified for the notify create operation. It consists of the notify id, a sublist of event flags (it's in the same form as flags) and, the command prefix.
treeName notify names
Returns a list of identifers for all the current notifiers.

C Language API

Blt_TreeApply, Blt_TreeApplyBFS, Blt_TreeApplyDFS, Blt_TreeChangeRoot, Blt_TreeCreate, Blt_TreeCreateEventHandler, Blt_TreeCreateNode, Blt_TreeCreateTrace, Blt_TreeDeleteEventHandler, Blt_TreeDeleteNode, Blt_TreeDeleteTrace, Blt_TreeExists, Blt_TreeFindChild, Blt_TreeFirstChild, Blt_TreeFirstKey, Blt_TreeGetNode, Blt_TreeGetToken, Blt_TreeGetValue, Blt_TreeIsAncestor, Blt_TreeIsBefore, Blt_TreeIsLeaf, Blt_TreeLastChild, Blt_TreeMoveNode, Blt_TreeName, Blt_TreeNextKey, Blt_TreeNextNode, Blt_TreeNextSibling, Blt_TreeNodeDegree, Blt_TreeNodeDepth, Blt_TreeNodeId, Blt_TreeNodeLabel, Blt_TreeNodeParent, Blt_TreePrevNode, Blt_TreePrevSibling, Blt_TreeRelabelNode, Blt_TreeReleaseToken, Blt_TreeRootNode, Blt_TreeSetValue, Blt_TreeSize, Blt_TreeSortNode, and Blt_TreeUnsetValue.

Keywords

tree, hiertable, widget


Table of Contents

blt-2.4z.orig/html/treeview.html0100644000175000017500000030050607434307126015442 0ustar dokodoko treeview(n) manual page Table of Contents

Name

treeview - Create and manipulate hierarchical table widgets

Synopsis

treeview pathName ?options?

Description

The treeview widget displays a tree of data. It replaces both the hiertable and hierbox widgets. The treeview is 100% syntax compatible with the hiertable widget. The hiertable command is retained for sake of script-level compatibility. This widget obsoletes the hierbox widget. It does everything the old hierbox widget did, but also provides data sharing (via tree data objects) and the ability to tag nodes.

Introduction

The treeview widget displays hierarchical data. Data is represented as nodes in a general-ordered tree. Each node may have sub-nodes and these nodes can in turn has their own children.

A node is displayed as a row entry in the widget. Each entry has a text label and icon. When a node has children, its entry is drawn with a small button to the left of the label. Clicking the mouse over this button opens or closes the node. When a node is open, its children are exposed. When it is closed, the children and their descedants are hidden. The button is normally a + or - symbol (ala Windows Explorer), but can be replaced with a pair of Tk images (open and closed images).

If the node has data associated with it, they can be displayed in columns running vertically on either side the tree. You can control the color, font, etc of each entry. Any entry label or data field can be edited in-place.

Tree Data Object

The tree is not stored inside the widget but in a tree data object (see the tree command for a further explanation). Tree data objects can be shared among different clients, such as a treeview widget or the tree command. You can walk the tree and manage its data with the tree command tree, while displaying it with the treeview widget. Whenever the tree is updated, the treeview widget is automatically redrawn.

By default, the treeview widget creates its own tree object. The tree initially contains just a root node. But you can also display trees created by the tree command using the -tree configuration option. Treeview widgets can share the same tree object, possibly displaying different views of the same data.

A tree object has both a Tcl and C API. You can insert or delete nodes using treeview widget or tree command operations, but also from C code. For example, you can load the tree from your C code while still managing and displaying the tree from Tcl. The widget is automatically notified whenever the tree is modified via C or Tcl.

Syntax


treeview pathName ?option value?...

The treeview command creates a new window pathName and makes it into a treeview 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 widget 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, treeview 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 widget. The general form is:

pathName operation ?arg?...

Both operation and its arguments determine the exact behavior of the command. The operations available are described in the TREEVIEW OPERATIONS section.

IDs and Tags

Nodes can be inserted into a tree using the treeview widget
blt::treeview .t
set node [.t insert end root "one"]

or tree command.
set tree [blt::tree create]
set node [$tree insert root "one"]

In both cases, a number identifying the node is returned (the value of $node). This serial number or id uniquely identifies the node. Please note that you can't infer a location or position of a node from its id. The only exception is that the root node is always id 0. Since nodes may have the same labels or be moved within the tree, ids provide an convenient way to identify nodes. If a tree is shared, the ids will be the same regardless if you are using by the treeview widget or the tree command. Ids are recycled when the node deleted.

A node may also have any number of tags associated with it. A tag is just a string of characters, and it may take any form except that of an integer. For example, "x123" is valid, but "123" isn't. The same tag may be associated with many different nodes. This is typically done to associate a group of nodes. Many operations in the treeview widget take either node ids or tag names as arguments. Using a tag says to apply the operation to all nodes with that tag.

The tag all is implicitly associated with every node in the tree. It may be used to invoke operations on all the nodes in the tree.

Tags may be shared, just like trees, between clients. For example, you can use the tags created by the tree command with treeview widgets.

Special Node IDs

There are also several special non-numeric ids. Special ids differ from tags in that they are always translated to their numeric equivalent. They also take precedence over tags. For example, you can't use a tag name that is a special id. These ids are specific to the treeview widget.
active
The node where the mouse pointer is currently located. When a node is active, it is drawn using its active icon (see the -activeicon option). The active id is changed automatically by moving the mouse pointer over another node or by using the entry activate operation. Note that there can be only one active node at a time.
anchor
The node representing the fixed end of the current selection. The anchor is set by the selection anchor operation.
current
The node where the mouse pointer is currently located. But unlike active, this id changes while the selection is dragged. It is used to determine the current node during button drags.
down
The next open node from the current focus. The down of the last open node is the same.
end
The last open node (in depth-first order) on the tree.
focus
The node that currently has focus. When a node has focus, it receives key events. To indicate focus, the node is drawn with a dotted line around its label. You can change the focus using the focus operation.
last
The last open node from the current focus. But unlike up, when the focus is at root, last wraps around to the last open node in the tree.
mark
The node representing the non-fixed end of the current selection. The mark is set by the selection mark operation.
next
The next open node from the current focus. But unlike down, when the focus is on last open node, next wraps around to the root node.
nextsibling
The next sibling from the node with the current focus. If the node is already the last sibling then it is the nextsibling.
parent
The parent of the node with the current focus. The parent of the root is also the root.
prevsibling
The previous sibling from the node with the current focus. If the node is already the first sibling then it is the prevsibling.
root
The root node. You can also use id 0 to indicate the root.
up
The last open node (in depth-first order) from the current focus. The up of the root node (i.e. the root has focus) is also the root.
view.top
First node that's current visible in the widget.
view.bottom
Last node that's current visible in the widget.
path
Absolute path of a node. Path names refer to the node name, not their entry labels. Paths don't have to start with a separator (see the -separator configuration option), but component names must be separated by the designated separator.
@x,y
Indicates the node that covers the point in the treeview window specified by x and y (in pixel coordinates). If no part of the entryd covers that point, then the closest node to that point is used.

A node may be specified as an id or tag. If the specifier is an integer then it is assumed to refer to the single node with that id. If the specifier is not an integer, it's checked to see if it's a special id (such as focus). Otherwise, it's assumed to be tag. Some operations only operate on a single node at a time; if a tag refers to more than one node, then an error is generated.

Data Fields

A node in the tree can have data fields. A data field is a name-value pair, used to represent arbitrary data in the node. Nodes can contain different fields (they aren't required to contain the same fields). You can optionally display these fields in the treeview widget in columns running on either side of the displayed tree. A node's value for the field is drawn in the column along side its node in the hierarchy. Any node that doesn't have a specific field is left blank. Columns can be interactively resized, hidden, or, moved.

Entry Bindings

You can bind Tcl commands to be invoked when events occur on nodes (much like Tk canvas items). You can bind a node using its id or its bindtags. Bindtags are simply names that associate a binding with one or more nodes. There is a built-in tag all that all node entries automatically have.

Treeview Operations

The treeview operations are the invoked by specifying the widget's pathname, the operation, and any arguments that pertain to that operation. The general form is:


pathName operation ?arg arg ...?

Operation and the args determine the exact behavior of the command. The following operation are available for treeview widgets:

pathName bbox ?-screen? tagOrId...
Returns a list of 4 numbers, representing a bounding box of around the specified entries. The entries is given by one or more tagOrId arguments. If the -screen flag is given, then the x-y coordinates of the bounding box are returned as screen coordinates, not virtual coordinates. Virtual coordinates start from 0 from the root node. The returned list contains the following values.
x
X-coordinate of the upper-left corner of the bounding box.
y
Y-coordinate of the upper-left corner of the bounding box.
width
Width of the bounding box.
height
Height of the bounding box.
pathName bind tagName ?sequence command?
Associates command with tagName such that whenever the event sequence given by sequence occurs for a node with this tag, command will be invoked. The syntax is similar to the bind command except that it operates on treeview 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 tagName. If the first character of command is + then command augments an existing binding rather than replacing it. If no command 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 bindings have been defined for tagName.

pathName button operation ?args?
This command is used to control the button selectors within a treeview widget. It has several forms, depending on operation:
pathName button activate tagOrId
Designates the node given by tagOrId as active. When a node is active it's entry is drawn using its active icon (see the -activeicon option). Note that there can be only one active entry at a time. The special id active indicates the currently active node.
pathName button bind tagName ?sequence command?
Associates command with tagName such that whenever the event sequence given by sequence occurs for an button of a node entry with this tag, command will be invoked. The syntax is similar to the bind command except that it operates on treeview buttons, 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 tagName. If the first character of command is + then command augments an existing binding rather than replacing it. If no command 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 bindings have been defined for tagName.

pathName button cget option
Returns the current value of the configuration option given by option. Option may have any of the values accepted by the configure operation described below.
pathName button configure ?option? ?value option value ...?
Query or modify the configuration options of the widget. If no option is specified, returns a list describing all of the available options for pathName (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. Option and value are described in the section BUTTON OPTIONS below.
pathName cget option
Returns the current value of the configuration option given by option. Option may have any of the values accepted by the configure operation described below.
pathName close ?-recurse? tagOrId...
Closes the node specified by tagOrId. In addition, if a Tcl script was specified by the -closecommand option, it is invoked. If the node is already closed, this command has no effect. If the -recurse flag is present, each child node is recursively closed.
pathName column operation ?args?
The following operations are available for treeview columns.
pathName column activate column
Sets the active column to column. Column is the name of a column in the widget. When a column is active, it's drawn using its -activetitlebackground and -activetitleforeground options. If column is the "", then no column will be active. If no column argument is provided, then the name of the currently active column is returned.
pathName column cget name option
Returns the current value of the column configuration option given by option for name. Name is the name of column that corresponds to a data field. Option may have any of the values accepted by the configure operation described below.
pathName column configure name ?option? ?value option value ...?
Query or modify the configuration options of the column designated by name. Name is the name of the column corresponding to a data field. If no option is specified, returns a list describing all of the available options for pathName (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. Option and value are described in the section COLUMN OPTIONS below.
pathName column delete field ?field...?
Deletes one of more columns designated by field. Note that this does not delete the data fields themselves.
pathName column insert position field ?options...?
Inserts one of more columns designated by field. A column displays each node's data field by the same name. If the node doesn't have the given field, the cell is left blank. Position indicates where in the list of columns to add the new column. It may be either a number or end.
pathName column invoke field
Invokes the Tcl command associated with the column field, if there is one (using the column's -command option). The command is ignored if the column's -state option set to disabled.
pathName column move name dest
Moves the column name to the destination position. Dest is the name of another column or a screen position in the form @x,y.
pathName column names
Returns a list of the names of all columns in the widget. The list is ordered as the columns are drawn from left-to-right.
pathName column nearest x ?y?
Returns the name of the column closest to the given X-Y screen coordinate. If you provide a y argument (it's optional), a name is returned only when if the point is over a column's title.
pathName configure ?option? ?value option value ...?
Query or modify the configuration options of the widget. If no option is specified, returns a list describing all of the available options for pathName (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. Option and value are described in the section TREEVIEW OPTIONS below.
pathName curselection
Returns a list containing the ids of all of the entries that are currently selected. If there are no entries selected, then the empty string is returned.
pathName delete tagOrId...
Deletes one or more entries given by tagOrId and its children.
pathName entry operation ?args?
The following operations are available for treeview entries.
pathName entry activate tagOrId
Sets the active entry to the one specified by tagOrId. When an entry is active it is drawn using its active icon (see the -activeicon option). Note that there can be only one active node at a time. The special id of the currently active node is active.
pathName entry cget option
Returns the current value of the configuration option given by option. Option may have any of the values accepted by the configure operation described below.
pathName entry children tagOrId ?first? ?last?
Returns a list of ids for the given range of children of tagOrId. TagOrId is the id or tag of the node to be examined. If only a first argument is present, then the id of the that child at that numeric position is returned. If both first and last arguments are given, then the ids of all the children in that range are returned. Otherwise the ids of all children are returned.
pathName entry configure ?option? ?value option value ...?
Query or modify the configuration options of the widget. If no option is specified, returns a list describing all of the available options for pathName (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. Option and value are described below:
pathName entry delete tagOrId ?first ?last?
Deletes the one or more children nodes of the parent tagOrId. If first and last arguments are present, they are positions designating a range of children nodes to be deleted.
pathName entry isbefore tagOrId1 tagOrId2
Returns 1 if tagOrId1 is before tagOrId2 and 0 otherwise.
pathName entry ishidden tagOrId
Returns 1 if the node is currently hidden and 0 otherwise. A node is also hidden if any of its ancestor nodes are closed or hidden.
pathName entry isopen tagOrId
Returns 1 if the node is currently open and 0 otherwise.
pathName entry size -recurse tagOrId
Returns the number of children for parent node tagOrId. If the -recurse flag is set, the number of all its descendants is returned. The node itself is not counted.
pathName find ?flags? first last
Finds for all entries matching the criteria given by flags. A list of ids for all matching nodes is returned. First and last are ids designating the range of the search in depth-first order. If last is before first, then nodes are searched in reverse order. The valid flags are:
-name pattern
Specifies pattern to match against node names.
-full pattern
Specifies pattern to match against node pathnames.
-option pattern
Specifies pattern to match against the node entry's configuration option.
-exact
Patterns must match exactly. The is the default.
-glob
Use global pattern matching. Matching is done in a fashion similar to that used by the C-shell. For the two strings to match, their contents must be identical except that the following special sequences may appear in pattern:
*
Matches any sequence of characters in string, including a null string.
?
Matches any single character in string.
[chars]
Matches any character in the set given by chars. If a sequence of the form x-y appears in chars, then any character between x and y, inclusive, will match.
\x
Matches the single character x. This provides a way of avoiding the special interpretation of the characters *?[]\ in the pattern.
-regexp
Use regular expression pattern matching (i.e. the same as implemented by the regexp command).
-nonmatching
Pick entries that don't match.
-exec string
Specifies a Tcl script to be invoked for each matching node. Percent substitutions are performed on string before it is executed. The following substitutions are valid:
%W
The pathname of the widget.
%p
The name of the node.
%P
The full pathname of the node.
%#
The id of the node.
%%
Translates to a single percent.
-count number
Stop searching after number matches.
--
Indicates the end of flags.
pathName focus tagOrId
Sets the focus to the node given by tagOrId. When a node has focus, it can receive keyboard events. The special id focus designates the node that currently has focus.
pathName get ?-full? tagOrId tagOrId...
Translates one or more ids to their node entry names. It returns a list of names for all the ids specified. If the -full flag is set, then the full pathnames are returned.
pathName hide ?flags? tagOrId...
Hides all nodes matching the criteria given by flags. The search is performed recursively for each node given by tagOrId. The valid flags are described below:
-name pattern
Specifies pattern to match against node names.
-full pattern
Specifies pattern to match against node pathnames.
-option pattern
Specifies pattern to match against the node entry's configuration option.
-exact
Match patterns exactly. The is the default.
-glob
Use global pattern matching. Matching is done in a fashion similar to that used by the C-shell. For the two strings to match, their contents must be identical except that the following special sequences may appear in pattern:
*
Matches any sequence of characters in string, including a null string.
?
Matches any single character in string.
[chars]
Matches any character in the set given by chars. If a sequence of the form x-y appears in chars, then any character between x and y, inclusive, will match.
\x
Matches the single character x. This provides a way of avoiding the special interpretation of the characters *?[]\ in the pattern.
-regexp
Use regular expression pattern matching (i.e. the same as implemented by the regexp command).
-nonmatching
Hide nodes that don't match.
--
Indicates the end of flags.
pathName index ?-at tagOrId? string
Returns the id of the node specified by string. String may be a tag or node id. Some special ids are normally relative to the node that has focus. The -at flag lets you select another node.
pathName insert ?-at tagOrId? position path ?options...? ?path? ?options...?
Inserts one or more nodes at position. Position is the location (number or end) where the new nodes are added to the parent node. Path is the pathname of the new node. Pathnames can be formated either as a Tcl list (each element is a path component) or as a string separated by a special character sequence (using the -separator option). Pathnames are normally absolute, but the -at switch lets you select a relative starting point. Its value is the id of the starting node.

All ancestors of the new node must already exist, unless the -autocreate option is set. It is also an error if a node already exists, unless the -allowduplicates option is set.

Option and value may have any of the values accepted by the entry configure operation described in the ENTRY OPERATIONS section below. This command returns a list of the ids of the new entries.

pathName move tagOrId how destId
Moves the node given by tagOrId to the destination node. The node can not be an ancestor of the destination. DestId is the id of the destination node and can not be the root of the tree. In conjunction with how, it describes how the move is performed.
before
Moves the node before the destination node.
after
Moves the node after the destination node.
into
Moves the node to the end of the destination's list of children.
pathName nearest x y ?varName?
Returns the id of the node entry closest to the given X-Y screen coordinate. The optional argument varName is the name of variable which is set to either button or select to indicate over what part of the node the coordinate lies. If the coordinate is not directly over any node, then varName will contain the empty string.
pathName open ?-recurse? tagOrId...
Opens the one or more nodes specified by tagOrId. If a node is not already open, the Tcl script specified by the -opencommand option is invoked. If the -recurse flag is present, then each descendant is recursively opened.
pathName range ?-open? first last
Returns the ids in depth-first order of the nodes between the first and last ids. If the -open flag is present, it indicates to consider only open nodes. If last is before first, then the ids are returned in reverse order.
pathName scan option args
This command implements scanning. It has two forms, depending on option:
pathName scan mark x y
Records x and y and the current view in the treeview window; used in conjunction with later scan dragto commands. Typically this command is associated with a mouse button press in the widget. It returns an empty string.
pathName scan dragto x y.
Computes the difference between its x and y arguments and the x and y arguments to the last scan mark command for the widget. It then adjusts the view by 10 times the difference in coordinates. This command is typically associated with mouse motion events in the widget, to produce the effect of dragging the list at high speed through the window. The return value is an empty string.
pathName see ?-anchor anchor? tagOrId
Adjusts the view of entries so that the node given by tagOrId is visible in the widget window. It is an error if tagOrId is a tag that refers to more than one node. By default the node's entry is displayed in the middle of the window. This can changed using the -anchor flag. Its value is a Tk anchor position.
pathName selection option arg
This command is used to adjust the selection within a treeview widget. It has several forms, depending on option:
pathName selection anchor tagOrId
Sets the selection anchor to the node given by tagOrId. If tagOrId refers to a non-existent node, then the closest node is used. The selection anchor is the end of the selection that is fixed while dragging out a selection with the mouse. The special id anchor may be used to refer to the anchor node.
pathName selection cancel
Clears the temporary selection of entries back to the current anchor. Temporary selections are created by the selection mark operation.
pathName selection clear first ?last?
Removes the entries between first and last (inclusive) from the selection. Both first and last are ids representing a range of entries. If last isn't given, then only first is deselected. Entries outside the selection are not affected.
pathName selection clearall
Clears the entire selection.
pathName selection mark tagOrId
Sets the selection mark to the node given by tagOrId. This causes the range of entries between the anchor and the mark to be temporarily added to the selection. The selection mark is the end of the selection that is fixed while dragging out a selection with the mouse. The special id mark may be used to refer to the current mark node. If tagOrId refers to a non-existent node, then the mark is ignored. Resetting the mark will unselect the previous range. Setting the anchor finalizes the range.
pathName selection includes tagOrId
Returns 1 if the node given by tagOrId is currently selected, 0 if it isn't.
pathName selection present
Returns 1 if any nodes are currently selected and 0 otherwise.
pathName selection set first ?last?
Selects all of the nodes in the range between first and last, inclusive, without affecting the selection state of nodes outside that range.
pathName selection toggle first ?last?
Selects/deselects nodes in the range between first and last, inclusive, from the selection. If a node is currently selected, it becomes deselected, and visa versa.
pathName show ?flags? tagOrId...
Exposes all nodes matching the criteria given by flags. This is the inverse of the hide operation. The search is performed recursively for each node given by tagOrId. The valid flags are described below:
-name pattern
Specifies pattern to match against node names.
-full pattern
Specifies pattern to match against node pathnames.
-option pattern
Specifies pattern to match against the entry's configuration option.
-exact
Match patterns exactly. The is the default.
-glob
-glob Use global pattern matching. Matching is done in a fashion similar to that used by the C-shell. For the two strings to match, their contents must be identical except that the following special sequences may appear in pattern:
*
Matches any sequence of characters in string, including a null string.
?
Matches any single character in string.
[chars]
Matches any character in the set given by chars. If a sequence of the form x-y appears in chars, then any character between x and y, inclusive, will match.
\x
Matches the single character x. This provides a way of avoiding the special interpretation of the characters *?[]\ in the pattern.
-regexp
Use regular expression pattern matching (i.e. the same as implemented by the regexp command).
-nonmatching
Expose nodes that don't match.
--
Indicates the end of flags.
pathName sort ?operation? args...
pathName sort auto ?boolean
Turns on/off automatic sorting of node entries. If boolean is true, entries will be automatically sorted as they are opened, closed, inserted, or deleted. If no boolean argument is provided, the current state is returned.
pathName sort cget option
Returns the current value of the configuration option given by option. Option may have any of the values accepted by the configure operation described below.
pathName sort configure ?option? ?value option value ...?
Query or modify the sorting configuration options of the widget. If no option is specified, returns a list describing all of the available options for pathName (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given sorting option(s) to have the given value(s); in this case the command returns an empty string. Option and value are described below:
-column string
Specifies the column to sort. Entries in the widget are rearranged according to this column. If column is "" then no sort is performed.
-command string
Specifies a Tcl procedure to be called when sorting nodes. The procedure is called with three arguments: the pathname of the widget and the fields of two entries. The procedure returns 1 if the first node is greater than the second, -1 is the second is greater, and 0 if equal.
-decreasing boolean
Indicates to sort in ascending/descending order. If boolean is true, then the entries as in descending order. The default is no.
-mode string
Specifies how to compare entries when sorting. String may be one of the following:
ascii
Use string comparison based upon the ASCII collation order.
dictionary
Use dictionary-style comparison. This is the same as ascii except (a) case is ignored except as a tie-breaker and (b) if two strings contain embedded numbers, the numbers compare as integers, not characters. For example, "bigBoy" sorts between "bigbang" and "bigboy", and "x10y" sorts between "x9y" and "x11y".
integer
Compares fields as integers.
real
Compares fields as floating point numbers.
command
Use the Tcl proc specified by the -command option to compare entries when sorting. If no command is specified, the sort reverts to ascii sorting.
pathName sort once ?flags? tagOrId...
Sorts the children for each entries specified by tagOrId. By default, entries are sorted by name, but you can specify a Tcl proc to do your own comparisons.
-recurse
Recursively sort the entire branch, not just the children.
pathName tag operation args
Tags are a general means of selecting and marking nodes in the tree. A tag is just a string of characters, and it may take any form except that of an integer. The same tag may be associated with many different nodes.

Both operation and its arguments determine the exact behavior of the command. The operations available for tags are listed below.

pathName tag add string id...
Adds the tag string to one of more entries.
pathName tag delete string id...
Deletes the tag string from one or more entries.
pathName tag forget string
Removes the tag string from all entries. It's not an error if no entries are tagged as string.
pathName tag names ?id?
Returns a list of tags used. If an id argument is present, only those tags used by the node designated by id are returned.
pathName tag nodes string
Returns a list of ids that have the tag string. If no node is tagged as string, then an empty string is returned.
pathName text operation ?args?
This operation is used to provide text editing for cells (data fields in a column) or entry labels. It has several forms, depending on operation:
pathName text apply
Applies the edited buffer, replacing the entry label or data field. The edit window is hidden.
pathName text cancel
Cancels the editing operation, reverting the entry label or data value back to the previous value. The edit window is hidden.
pathName text cget value
Returns the current value of the configuration option given by option. Option may have any of the values accepted by the configure operation described below.
pathName text configure ?option value?
Query or modify the configuration options of the edit window. If no option is specified, returns a list describing all of the available options (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. Option and value are described in the section TEXT EDITING OPTIONS below.
pathName text delete first last
Deletes the characters in the edit buffer between the two given character positions.
pathName text get ?-root? x y
pathName text icursor index
pathName text index index
Returns the text index of given index.
pathName text insert index string
Insert the text string string into the edit buffer at the index index. For example, the index 0 will prepend the buffer.
pathName text selection args
This operation controls the selection of the editing window. Note that this differs from the selection of entries. It has the following forms:
pathName text selection adjust index
Adjusts either the first or last index of the selection.
pathName text selection clear
Clears the selection.
pathName text selection from index
Sets the anchor of the selection.
pathName text selection present
Indicates if a selection is present.
pathName text selection range start end
Sets both the anchor and mark of the selection.
pathName text selection to index
Sets the unanchored end (mark) of the selection.
pathName toggle tagOrId
Opens or closes the node given by tagOrId. If the corresponding -opencommand or -closecommand option is set, then that command is also invoked.
pathName xview args
This command is used to query and change the horizontal position of the information in the widget's window. It can take any of the following forms:
pathName xview
Returns a list containing two elements. Each element is a real fraction between 0 and 1; together they describe the horizontal span that is visible in the window. For example, if the first element is .2 and the second element is .6, 20% of the treeview widget's text is off-screen to the left, the middle 40% is visible in the window, and 40% of the text is off-screen to the right. These are the same values passed to scrollbars via the -xscrollcommand option.
pathName xview tagOrId
Adjusts the view in the window so that the character position given by tagOrId is displayed at the left edge of the window. Character positions are defined by the width of the character 0.
pathName xview moveto fraction
Adjusts the view in the window so that fraction of the total width of the treeview widget's text is off-screen to the left. fraction must be a fraction between 0 and 1.
pathName xview scroll number what
This command shifts the view in the window left or right according to number and what. Number must be an integer. What must be either units or pages or an abbreviation of one of these. If what is units, the view adjusts left or right by number character units (the width of the 0 character) on the display; if it is pages then the view adjusts by number screenfuls. If number is negative then characters farther to the left become visible; if it is positive then characters farther to the right become visible.
pathName yview ?args?
This command is used to query and change the vertical position of the text in the widget's window. It can take any of the following forms:
pathName yview
Returns a list containing two elements, both of which are real fractions between 0 and 1. The first element gives the position of the node at the top of the window, relative to the widget as a whole (0.5 means it is halfway through the treeview window, for example). The second element gives the position of the node just after the last one in the window, relative to the widget as a whole. These are the same values passed to scrollbars via the -yscrollcommand option.
pathName yview tagOrId
Adjusts the view in the window so that the node given by tagOrId is displayed at the top of the window.
pathName yview moveto fraction
Adjusts the view in the window so that the node given by fraction appears at the top of the window. Fraction is a fraction between 0 and 1; 0 indicates the first node, 0.33 indicates the node one-third the way through the treeview widget, and so on.
pathName yview scroll number what
This command adjusts the view in the window up or down according to number and what. Number must be an integer. What must be either units or pages. If what is units, the view adjusts up or down by number lines; if it is pages then the view adjusts by number screenfuls. If number is negative then earlier nodes become visible; if it is positive then later nodes become visible.

Treeview Options

In addition to the configure operation, widget configuration options may also be set by the Tk option command. The class resource name is TreeView.
option add *TreeView.Foreground white
option add *TreeView.Background blue

The following widget options are available:

-activebackground color
Sets the background color for active entries. A node is active when the mouse passes over it's entry or using the activate operation.
-activeforeground color
Sets the foreground color of the active node. A node is active when the mouse passes over it's entry or using the activate operation.
-activeicons images
Specifies images to be displayed for an entry's icon when it is active. Images is a list of two Tk images: the first image is displayed when the node is open, the second when it is closed.
-autocreate boolean
If boolean is true, automatically create missing ancestor nodes when inserting new nodes. Otherwise flag an error. The default is no.
-allowduplicates boolean
If boolean is true, allow nodes with duplicate pathnames when inserting new nodes. Otherwise flag an error. The default is no.
-background color
Sets the background color of the widget. The default is white.
-borderwidth pixels
Sets the width of the 3-D border around the outside edge of the widget. The -relief option determines if the border is to be drawn. The default is 2.
-closecommand string
Specifies a Tcl script to be invoked when a node is closed. You can overrider this for individual entries using the entry's -closecommand option. The default is "". Percent substitutions are performed on string before it is executed. The following substitutions are valid:
%W
The pathname of the widget.
%p
The name of the node.
%P
The full pathname of the node.
%#
The id of the node.
%%
Translates to a single percent.
-cursor cursor
Specifies the widget's cursor. The default cursor is "".
-dashes number
Sets the dash style of the horizontal and vertical lines drawn connecting entries. Number is the length in pixels of the dashes and gaps in the line. If number is 0, solid lines will be drawn. The default is 1 (dotted).
-exportselection boolean
Indicates if the selection is exported. If the widget is exporting its selection then it will observe the standard X11 protocols for handling the selection. Selections are available as type STRING; the value of the selection will be the label of the selected nodes, separated by newlines. The default is no.
-flat boolean
Indicates whether to display the tree as a flattened list. If boolean is true, then the hierarchy will be a list of full paths for the nodes. This option also has affect on sorting. See the SORT OPERATIONS section for more information. The default is no.
-focusdashes dashList
Sets the dash style of the outline rectangle drawn around the entry label of the node that current has focus. Number is the length in pixels of the dashes and gaps in the line. If number is 0, a solid line will be drawn. The default is 1.
-focusforeground color
Sets the color of the focus rectangle. The default is black.
-font fontName
Specifies the font for entry labels. You can override this for individual entries with the entry's -font configuration option. The default is *-Helvetica-Bold-R-Normal-*-12-120-*.
-foreground color
Sets the text color of entry labels. You can override this for individual entries with the entry's -foreground configuration option. The default is black.
-height pixels
Specifies the requested height of widget. The default is 400.
-hideroot boolean
If boolean is true, it indicates that no entry for the root node should be displayed. The default is no.
-highlightbackground color
Specifies the normal color of the traversal highlight region when the widget does not have the input focus.
-highlightcolor color
Specifies the color of the traversal highlight rectangle when the widget has the input focus. The default is black.
-highlightthickness pixels
Specifies the width of the highlight rectangle indicating when the widget has input focus. The value may have any of the forms acceptable to Tk_GetPixels. If the value is zero, no focus highlight will be displayed. The default is 2.
-icons images
Specifies images for the entry's icon. Images is a list of two Tk images: the first image is displayed when the node is open, the second when it is closed.
-linecolor color
Sets the color of the connecting lines drawn between entries. The default is black.
-linespacing pixels
Sets the number of pixels spacing between entries. The default is 0.
-linewidth pixels
Set the width of the lines drawn connecting entries. If pixels is 0, no vertical or horizontal lines are drawn. The default is 1.
-newtags boolean
If boolean is true, when sharing a tree object (see the -tree option), don't share its tags too. The default is 0.
-opencommand string
Specifies a Tcl script to be invoked when a node is open. You can override this for individual entries with the entry's -opencommand configuration option. The default is "". Percent substitutions are performed on string before it is executed. The following substitutions are valid:
%W
The pathname of the widget.
%p
The name of the node.
%P
The full pathname of the node.
%#
The id of the node.
%%
Translates to a single percent.
-relief relief
Specifies the 3-D effect for the widget. Relief specifies how the treeview widget should appear relative to widget it is packed into; for example, raised means the treeview widget should appear to protrude. The default is sunken.
-scrollmode mode
Specifies the style of scrolling to be used. The following styles are valid. This is the default is hierbox.
listbox
Like the listbox widget, the last entry can always be scrolled to the top of the widget window. This allows the scrollbar thumb to shrink as the last entry is scrolled upward.
hierbox
Like the hierbox widget, the last entry can only be viewed at the bottom of the widget window. The scrollbar stays a constant size.
canvas
Like the canvas widget, the entries are bound within the scrolling area.
-selectbackground color
Sets the background color selected node entries. The default is #ffffea.
-selectborderwidth pixels
Sets the width of the raised 3-D border drawn around the labels of selected entries. The default is 0. -selectcommand string Specifies a Tcl script to invoked when the set of selected nodes changes. The default is "".
-selectforeground color
Sets the color of the labels of selected node entries. The default is black.
-selectmode mode
Specifies the selection mode. If mode is single, only one node can be selected at a time. If multiple more than one node can be selected. The default is single.
-separator string
Specifies the character sequence to use when spliting the path components. The separator may be several characters wide (such as "::") Consecutive separators in a pathname are treated as one. If string is the empty string, the pathnames are Tcl lists. Each element is a path component. The default is "".
-showtitles boolean
If boolean is false, column titles are not be displayed. The default is yes.
-sortselection boolean
If boolean is true, nodes in the selection are ordered as they are currently displayed (depth-first or sorted), not in the order they were selected. The default is no.
-takefocus focus
Provides information used when moving the focus from window 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 "1".
-trim string
Specifies a string leading characters to trim from entry pathnames before parsing. This only makes sense if the -separator is also set. The default is "".
-width pixels
Sets the requested width of the widget. If pixels is 0, then the with is computed from the contents of the treeview widget. The default is 200.
-xscrollcommand string
Specifies the prefix for a command used to communicate with horizontal scrollbars. Whenever the horizontal view in the widget's window changes, the widget will generate a Tcl command by concatenating the scroll command and two numbers. If this option is not specified, then no command will be executed.
-xscrollincrement pixels
Sets the horizontal scrolling distance. The default is 20 pixels.
-yscrollcommand string
Specifies the prefix for a command used to communicate with vertical scrollbars. Whenever the vertical view in the widget's window changes, the widget will generate a Tcl command by concatenating the scroll command and two numbers. If this option is not specified, then no command will be executed.
-yscrollincrement pixels
Sets the vertical scrolling distance. The default is 20 pixels.

Entry Options

Many widget configuration options have counterparts in entries. For example, there is a -closecommand configuration option for both widget itself and for individual entries. Options set at the widget level are global for all entries. If the entry configuration option is set, then it overrides the widget option. This is done to avoid wasting memory by replicated options. Most entries will have redundant options.

There is no resource class or name for entries.

-activeicons images
Specifies images to be displayed as the entry's icon when it is active. This overrides the global -activeicons configuration option for the specific entry. Images is a list of two Tk images: the first image is displayed when the node is open, the second when it is closed.
-bindtags tagList
Specifies the binding tags for nodes. TagList is a list of binding tag names. The tags and their order will determine how events are handled for nodes. Each tag in the list matching the current event sequence will have its Tcl command executed. The default value is all.
-button string
Indicates whether a button should be displayed on the left side of the node entry. String can be yes, no, or auto. If auto, then a button is automatically displayed if the node has children. This is the default.
-closecommand string
Specifies a Tcl script to be invoked when the node is closed. This overrides the global -closecommand option for this entry. The default is "". Percent substitutions are performed on string before it is executed. The following substitutions are valid:
%W
The pathname of the widget.
%p
The name of the node.
%P
The full pathname of the node.
%#
The id of the node.
%%
Translates to a single percent.
-data string
Sets data fields for the node. String is a list of name-value pairs to be set. The default is "".
-font fontName
Sets the font for entry labels. This overrides the widget's -font option for this node. The default is *-Helvetica-Bold-R-Normal-*-12-120-*.
-foreground color
Sets the text color of the entry label. This overrides the widget's -foreground configuration option. The default is "".
-icons images
Specifies images to be displayed for the entry's icon. This overrides the global -icons configuration option. Images is a list of two Tk images: the first image is displayed when the node is open, the second when it is closed.
-label string
Sets the text for the entry's label. If not set, this defaults to the name of the node. The default is "".
-opencommand string
Specifies a Tcl script to be invoked when the entry is opened. This overrides the widget's -opencommand option for this node. The default is "". Percent substitutions are performed on string before it is executed. The following substitutions are valid:
%W
The pathname of the widget.
%p
The name of the node.
%P
The full pathname of the node.
%#
The id of the node.
%%
Translates to a single percent.

Button Options

Button configuration options may also be set by the option command. The resource subclass is Button. The resource name is always button.
option add *TreeView.Button.Foreground white
option add *TreeView.button.Background blue

The following are the configuration options available for buttons.

-activebackground color
Sets the background color of active buttons. A button is made active when the mouse passes over it or by the button activate operation.
-activeforeground color
Sets the foreground color of active buttons. A button is made active when the mouse passes over it or by the button activate operation.
-background color
Sets the background of the button. The default is white.
-borderwidth pixels
Sets the width of the 3-D border around the button. The -relief option determines if a border is to be drawn. The default is 1.
-closerelief relief
Specifies the 3-D effect for the closed button. Relief indicates how the button should appear relative to the widget; for example, raised means the button should appear to protrude. The default is solid.
-cursor cursor
Sets the widget's cursor. The default cursor is "".
-foreground color
Sets the foreground color of buttons. The default is black.
-images images
Specifies images to be displayed for the button. Images is a list of two Tk images: the first image is displayed when the button is open, the second when it is closed. If the images is the empty string, then a plus/minus gadget is drawn. The default is "".
-openrelief relief
Specifies the 3-D effect of the open button. Relief indicates how the button should appear relative to the widget; for example, raised means the button should appear to protrude. The default is flat.
-size pixels
Sets the requested size of the button. The default is 0.

Column Options

Column configuration options may also be set by the option command. The resource subclass is Column. The resource name is the name of the column.
option add *TreeView.Column.Foreground white
option add *TreeView.treeView.Background blue

The following configuration options are available for columns.

-background color
Sets the background color of the column. This overrides the widget's -background option. The default is white.
-borderwidth pixels
Sets the width of the 3-D border of the column. The -relief option determines if a border is to be drawn. The default is 0.
-edit boolean
Indicates if the column's data fields can be edited. If boolean is false, the data fields in the column may not be edited. The default is yes.
-foreground color
Specifies the foreground color of the column. You can override this for individual entries with the entry's -foreground option. The default is black.
-font fontName
Sets the font for a column. You can override this for individual entries with the entry's -font option. The default is *-Helvetica-Bold-R-Normal-*-12-120-*.
-hide boolean
If boolean is true, the column is not displayed. The default is yes.
-justify justify
Specifies how the column data fields title should be justified within the column. This matters only when the column is wider than the data field to be display. Justify must be left, right, or center. The default is left.
-pad pad
Specifies how much padding for the left and right sides of the column. Pad is a list of one or two screen distances. If pad has two elements, the left side of the column 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 2.
-relief relief
Specifies the 3-D effect of the column. Relief specifies how the column should appear relative to the widget; for example, raised means the column should appear to protrude. The default is flat.
-state state
Sets the state of the column. If state is disable then the column title can not be activated nor invoked. The default is normal.
-text string
Sets the title for the column. The default is "".
-titleforeground color
Sets the foreground color of the column title. The default is black.
-titleshadow color
Sets the color of the drop shadow of the column title. The default is "".
-width pixels
Sets the requested width of the column. This overrides the computed with of the column. If pixels is 0, the width is computed as from the contents of the column. The default is 0.

Text Editing Options

Text edit window configuration options may also be set by the option command. The resource class is TreeViewEditor. The resource name is always edit.
option add *TreeViewEditor.Foreground white
option add *edit.Background blue

The following are the configuration options available for the text editing window.

-background color
Sets the background of the text edit window. The default is white.
-borderwidth pixels
Sets the width of the 3-D border around the edit window. The -relief option determines if a border is to be drawn. The default is 1.
-exportselection boolean
Indicates if the text selection is exported. If the edit window is exporting its selection then it will observe the standard X11 protocols for handling the selection. Selections are available as type STRING. The default is no.
-relief relief
Specifies the 3-D effect of the edit window. Relief indicates how the background should appear relative to the edit window; for example, raised means the background should appear to protrude. The default is solid.
-selectbackground color
Sets the background of the selected text in the edit window. The default is white.
-selectborderwidth pixels
Sets the width of the 3-D border around the selected text in the edit window. The -selectrelief option determines if a border is to be drawn. The default is 1.
-selectforeground color
Sets the foreground of the selected text in the edit window. The default is white.
-selectrelief relief
Specifies the 3-D effect of the selected text in the edit window. Relief indicates how the text should appear relative to the edit window; for example, raised means the text should appear to protrude. The default is flat.

Default Bindings

Tk automatically creates class bindings for treeviews that give them Motif-like behavior. Much of the behavior of a treeview widget is determined by its -selectmode option, which selects one of two ways of dealing with the selection.

If the selection mode is single, only one node can be selected at a time. Clicking button 1 on an node selects it and deselects any other selected item.

If the selection mode is multiple, any number of entries may be selected at once, including discontiguous ranges. Clicking Control-Button-1 on a node entry toggles its selection state without affecting any other entries. Pressing Shift-Button-1 on a node entry selects it, extends the selection.

  1. In extended mode, the selected range can be adjusted by pressing button 1 with the Shift key down: this modifies the selection to consist of the entries between the anchor and the entry under the mouse, inclusive. The un-anchored end of this new selection can also be dragged with the button down.
  2. In extended mode, pressing button 1 with the Control key down starts a toggle operation: the anchor is set to the entry under the mouse, and its selection state is reversed. The selection state of other entries isn't changed. If the mouse is dragged with button 1 down, then the selection state of all entries between the anchor and the entry under the mouse is set to match that of the anchor entry; the selection state of all other entries remains what it was before the toggle operation began.
  3. If the mouse leaves the treeview window with button 1 down, the window scrolls away from the mouse, making information visible that used to be off-screen on the side of the mouse. The scrolling continues until the mouse re-enters the window, the button is released, or the end of the hierarchy is reached.
  4. Mouse button 2 may be used for scanning. If it is pressed and dragged over the treeview widget, the contents of the hierarchy drag at high speed in the direction the mouse moves.
  5. If the Up or Down key is pressed, the location cursor (active entry) moves up or down one entry. If the selection mode is browse or extended then the new active entry is also selected and all other entries are deselected. In extended mode the new active entry becomes the selection anchor.
  6. In extended mode, Shift-Up and Shift-Down move the location cursor (active entry) up or down one entry and also extend the selection to that entry in a fashion similar to dragging with mouse button 1.
  7. The Left and Right keys scroll the treeview widget view left and right by the width of the character 0. Control-Left and Control-Right scroll the treeview widget view left and right by the width of the window. Control-Prior and Control-Next also scroll left and right by the width of the window.
  8. The Prior and Next keys scroll the treeview widget view up and down by one page (the height of the window).
  9. The Home and End keys scroll the treeview widget horizontally to the left and right edges, respectively.
  10. Control-Home sets the location cursor to the the first entry, selects that entry, and deselects everything else in the widget.
  11. Control-End sets the location cursor to the the last entry, selects that entry, and deselects everything else in the widget.
  12. In extended mode, Control-Shift-Home extends the selection to the first entry and Control-Shift-End extends the selection to the last entry.
  13. In multiple mode, Control-Shift-Home moves the location cursor to the first entry and Control-Shift-End moves the location cursor to the last entry.
  14. The space and Select keys make a selection at the location cursor (active entry) just as if mouse button 1 had been pressed over this entry.
  15. In extended mode, Control-Shift-space and Shift-Select extend the selection to the active entry just as if button 1 had been pressed with the Shift key down.
  16. In extended mode, the Escape key cancels the most recent selection and restores all the entries in the selected range to their previous selection state.
  17. Control-slash selects everything in the widget, except in single and browse modes, in which case it selects the active entry and deselects everything else.
  18. Control-backslash deselects everything in the widget, except in browse mode where it has no effect.
  19. The F16 key (labelled Copy on many Sun workstations) or Meta-w copies the selection in the widget to the clipboard, if there is a selection.

The behavior of treeview widgets can be changed by defining new bindings for individual widgets or by redefining the class bindings.

Widget Bindings

In addition to the above behavior, the following additional behavior is defined by the default widget class (TreeView) bindings.
<ButtonPress-2>
Starts scanning.
<B2-Motion>
Adjusts the scan.
<ButtonRelease-2>
Stops scanning.
<B1-Leave>
Starts auto-scrolling.
<B1-Enter>
Starts auto-scrolling
<KeyPress-Up>
Moves the focus to the previous entry.
<KeyPress-Down>
Moves the focus to the next entry.
<Shift-KeyPress-Up>
Moves the focus to the previous sibling.
<Shift-KeyPress-Down>
Moves the focus to the next sibling.
<KeyPress-Prior>
Moves the focus to first entry. Closed or hidden entries are ignored.
<KeyPress-Next>
Move the focus to the last entry. Closed or hidden entries are ignored.
<KeyPress-Left>
Closes the entry. It is not an error if the entry has no children.
<KeyPress-Right>
Opens the entry, displaying its children. It is not an error if the entry has no children.
<KeyPress-space>
In "single" select mode this selects the entry. In "multiple" mode, it toggles the entry (if it was previous selected, it is not deselected).
<KeyRelease-space>
Turns off select mode.
<KeyPress-Return>
Sets the focus to the current entry.
<KeyRelease-Return>
Turns off select mode.
<KeyPress>
Moves to the next entry whose label starts with the letter typed.
<KeyPress-Home>
Moves the focus to first entry. Closed or hidden entries are ignored.
<KeyPress-End>
Move the focus to the last entry. Closed or hidden entries are ignored.
<KeyPress-F1>
Opens all entries.
<KeyPress-F2>
Closes all entries (except root).

Button Bindings

Buttons have bindings. There are associated with the "all" bindtag (see the entry's -bindtag option). You can use the bind operation to change them.
<Enter>
Highlights the button of the current entry.
<Leave>
Returns the button back to its normal state.
<ButtonRelease-1>
Adjust the view so that the current entry is visible.

Entry Bindings

Entries have default bindings. There are associated with the "all" bindtag (see the entry's -bindtag option). You can use the bind operation to modify them.
<Enter>
Highlights the current entry.
<Leave>
Returns the entry back to its normal state.
<ButtonPress-1>
Sets the selection anchor the current entry.
<Double-ButtonPress-1>
Toggles the selection of the current entry.
<B1-Motion>
For "multiple" mode only. Saves the current location of the pointer for auto-scrolling. Resets the selection mark.
<ButtonRelease-1>
For "multiple" mode only. Sets the selection anchor to the current entry.
<Shift-ButtonPress-1>
For "multiple" mode only. Extends the selection.
<Shift-Double-ButtonPress-1>
Place holder. Does nothing.
<Shift-B1-Motion>
Place holder. Does nothing.
<Shift-ButtonRelease-1>
Stop auto-scrolling.
<Control-ButtonPress-1>
For "multiple" mode only. Toggles and extends the selection.
<Control-Double-ButtonPress-1>
Place holder. Does nothing.
<Control-B1-Motion>
Place holder. Does nothing.
<Control-ButtonRelease-1>
Stops auto-scrolling.
<Control-Shift-ButtonPress-1>
???
<Control-Shift-Double-ButtonPress-1>
Place holder. Does nothing.
<Control-Shift-B1-Motion>
Place holder. Does nothing.

Column Bindings

Columns have bindings too. They are associated with the column's "all" bindtag (see the column -bindtag option). You can use the column bind operation to change them.
<Enter>
Highlights the current column title.
<Leave>
Returns the column back to its normal state.
<ButtonRelease-1>
Invokes the command (see the column's -command option) if one if specified.

Column Rule Bindings

<Enter>
Highlights the current and activates the ruler.
<Leave>
Returns the column back to its normal state. Deactivates the ruler.
<ButtonPress-1>
Sets the resize anchor for the column.
<B1-Motion>
Sets the resize mark for the column.
<ButtonRelease-1>
Adjust the size of the column, based upon the resize anchor and mark positions.

Example

The treeview command creates a new widget.
treeview .h -bg white

A new Tcl command .h is also created. This command can be used to query and modify the treeview widget. For example, to change the background color of the table to "green", you use the new command and the widget's configure operation.
# Change the background color.
.h configure -background "green"

By default, the treeview widget will automatically create a new tree object to contain the data. The name of the new tree is the pathname of the widget. Above, the new tree object name is ".h". But you can use the -tree option to specify the name of another tree.
# View the tree "myTree".
.h configure -tree "myTree"

When a new tree is created, it contains only a root node. The node is automatically opened. The id of the root node is always 0 (you can use also use the special id root). The insert operation lets you insert one or more new entries into the tree. The last argument is the node's pathname.
# Create a new entry named "myEntry"
set id [.h insert end "myEntry"]

This appends a new node named "myEntry". It will positioned as the last child of the root of the tree (using the position "end"). You can supply another position to order the node within its siblings.
# Prepend "fred".
set id [.h insert 0 "fred"]

Entry names do not need to be unique. By default, the node's label is its name. To supply a different text label, add the -label option.
# Create a new node named "fred"
set id [.h insert end "fred" -label "Fred Flintstone"]

The insert operation returns the id of the new node. You can also use the index operation to get this information.
# Get the id of "fred"
.h index "fred"

To insert a node somewhere other than root, use the -at switch. It takes the id of the node where the new child will be added.
# Create a new node "barney" in "fred".
.h insert -at $id end "barney"

A pathname describes the path to an entry in the hierarchy. It's a list of entry names that compose the path in the tree. Therefore, you can also add "barney" to "fred" as follows.
# Create a new sub-entry of "fred"
.h insert end "fred barney"

Every name in the list is ancestor of the next. All ancestors must already exist. That means that an entry "fred" is an ancestor of "barney" and must already exist. But you can use the -autocreate configuration option to force the creation of ancestor nodes.
# Force the creation of ancestors.
.h configure -autocreate yes
.h insert end "fred barney wilma betty"

Sometimes the pathname is already separated by a character sequence rather than formed as a list. A file name is a good example of this. You can use the -separator option to specify a separator string to split the path into its components. Each pathname inserted is automatically split using the separator string as a separator. Multiple separators are treated as one.
.h configure -separator /
.h insert end "/usr/local/tcl/bin"

If the path is prefixed by extraneous characters, you can automatically trim it off using the -trim option. It removed the string from the path before it is parsed.
.h configure -trim C:/windows -separator /
.h insert end "C:/window/system"

You can insert more than one entry at a time with the insert operation. This can be much faster than looping over a list of names.
# The slow way
foreach f [glob $dir/*] {
.h insert end $f
}
# The fast way
eval .h insert end [glob $dir/*]

In this case, the insert operation will return a list of ids of the new entries.

You can delete entries with the delete operation. It takes one or more tags of ids as its argument. It deletes the entry and all its children.
.h delete $id

Entries have several configuration options. They control the appearance of the entry's icon and label. We have already seen the -label option that sets the entry's text label. The entry configure operation lets you set or modify an entry's configuration options.
.h entry configure $id -color red -font fixed

You can hide an entry and its children using the -hide option.
.h entry configure $id -hide yes

More that one entry can be configured at once. All entries specified are configured with the same options.
.h entry configure $i1 $i2 $i3 $i4 -color brown

An icon is displayed for each entry. It's a Tk image drawn to the left of the label. You can set the icon with the entry's -icons option. It takes a list of two image names: one to represent the open entry, another when it is closed.
set im1 [image create photo -file openfolder.gif]
set im2 [image create photo -file closefolder.gif]
.h entry configure $id -icons "$im1 $im2"

If -icons is set to the empty string, no icons are display.

If an entry has children, a button is displayed to the left of the icon. Clicking the mouse on this button opens or closes the sub-hierarchy. The button is normally a + or - symbol, but can be configured in a variety of ways using the button configure operation. For example, the + and - symbols can be replaced with Tk images.
set im1 [image create photo -file closefolder.gif]
set im2 [image create photo -file downarrow.gif]
.h button configure $id -images "$im1 $im2" \
-openrelief raised -closerelief raised

Entries can contain an arbitrary number of data fields. Data fields are name-value pairs. Both the value and name are strings. The entry's -data option lets you set data fields.
.h entry configure $id -data {mode 0666 group users}

The -data takes a list of name-value pairs.

You can display these data fields as columns in the treeview widget. You can create and configure columns with the column operation. For example, to add a new column to the widget, use the column insert operation. The last argument is the name of the data field that you want to display.
.h column insert end "mode"

The column title is displayed at the top of the column. By default, it's is the field name. You can override this using the column's -text option.
.h column insert end "mode" -text "File Permissions"

Columns have several configuration options. The column configure operation lets you query or modify column options.
.h column configure "mode" -justify left

The -justify option says how the data is justified within in the column. The -hide option indicates whether the column is displayed.
.h column configure "mode" -hide yes

Entries can be selected by clicking on the mouse. Selected entries are drawn using the colors specified by the -selectforeground and -selectbackground configuration options. The selection itself is managed by the selection operation.
# Clear all selections
.h selection clear 0 end
# Select the root node
.h selection set 0

The curselection operation returns a list of ids of all the selected entries.
set ids [.h curselection]

You can use the get operation to convert the ids to their pathnames.
set names [eval .h get -full $ids]

If a treeview is exporting its selection (using the -exportselection option), then it will observe the standard X11 protocols for handling the selection. Treeview selections are available as type STRING; the value of the selection will be the pathnames of the selected entries, separated by newlines.

The treeview supports two modes of selection: single and multiple. In single select mode, only one entry can be selected at a time, while multiple select mode allows several entries to be selected. The mode is set by the widget's -selectmode option.
.h configure -selectmode "multiple"

You can be notified when the list of selected entries changes. The widget's -selectcommand specifies a Tcl procedure that is called whenever the selection changes.
proc SelectNotify { widget } {
set ids [$widget curselection]
}
.h configure -selectcommand "SelectNotify .h"

The widget supports the standard Tk scrolling and scanning operations. The treeview can be both horizontally and vertically. You can attach scrollbars to the treeview the same way as the listbox or canvas widgets.
scrollbar .xbar -orient horizontal -command ".h xview"
scrollbar .ybar -orient vertical -command ".h yview"
.h configure -xscrollcommand ".xbar set" \
-yscrollcommand ".ybar set"

There are three different modes of scrolling: listbox, canvas, and hierbox. In listbox mode, the last entry can always be scrolled to the top of the widget. In hierbox mode, the last entry is always drawn at the bottom of the widget. The scroll mode is set by the widget's -selectmode option.
.h configure -scrollmode "listbox"

Entries can be programmatically opened or closed using the open and close operations respectively.
.h open $id
.h close $id

When an entry is opened, a Tcl procedure can be automatically invoked. The -opencommand option specifies this procedure. This procedure can lazily insert entries as needed.
proc AddEntries { dir } {
eval .h insert end [glob -nocomplain $dir/*]
}
.h configure -opencommand "AddEntries %P"

Now when an entry is opened, the procedure AddEntries is called and adds children to the entry. Before the command is invoked, special "%" substitutions (like bind) are performed. Above, %P is translated to the pathname of the entry.

The same feature exists when an entry is closed. The -closecommand option specifies the procedure.
proc DeleteEntries { id } {
.h entry delete $id 0 end
}
.h configure -closecommand "DeleteEntries %#"

When an entry is closed, the procedure DeleteEntries is called and deletes the entry's children using the entry delete operation (%# is the id of entry).

Keywords

treeview, widget


Table of Contents

blt-2.4z.orig/html/vector.html0100644000175000017500000012472607434255426015127 0ustar dokodoko vector(n) manual page Table of Contents

Name

vector - Vector data type for Tcl

Synopsis

vector create vecName ?vecName...? ?switches?

vector destroy vecName ?vecName...?

vector expr expression

vector names ?pattern...?

Description

The vector command 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.

Introduction

A vector is simply an ordered set of numbers. The components of a vector are real numbers, indexed by counting numbers.

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.

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.

    ·
  • 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.
  • ·
  • 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.
  • ·
  • 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.

The vector command tries to overcome these disadvantages while still retaining the ease of use of Tcl arrays. The vector 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 parray 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.

Example

You create vectors using the vector command and its create operation.
# Create a new vector.
vector create y(50)

This creates a new vector named y. It has fifty components, by default, initialized to 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 element 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 component 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 components of a new vector
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, it may trigger call-backs to notify the clients of the vector. For example, when a vector used in the graph 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 notify operation.
# Make vector x notify after every change
x notify always
   ...
# Never notify
x notify never
   ...
# Force notification now
x notify now

To delete a vector, use the vector delete command. Both the vector and its corresponding Tcl command are destroyed.
# Remove vector x
vector destroy x

Syntax

Vectors are created using the vector create operation. Th create operation can be invoked in one of three forms:
vector create vecName
This creates a new vector vecName which initially has no components.
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.
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
vector create 1abc

You can automatically generate vector names using the "#auto" vector name. The create operation will generate a unique vector name.
set vec [vector create #auto]
puts "$vec has [$vec length] components"

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.

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 vector'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 vecName($n+3) 50.2

The following special non-numeric indices are available: min, max, end, and ++end.
puts "min = $vecName($min)"
set vecName(end) -1.2

The indices min and max will return the minimum and maximum 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 vecName(++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

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 vecName 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 vecName is unset, the vector and its Tcl command are also destroyed.

The vector has optional switches that affect how the vector is created. They are as follows:

-variable varName
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 varName is the empty string, 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 mapping 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.
vector destroy vecName ?vecName...?
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 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.

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).
< > <= >=
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.
== !=
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.
|
Bit-wise OR. (Not implemented).
&&
Logical AND. Produces a 1 result if both operands are non-zero, 0 otherwise.
||
Logical OR. Produces a 0 result if both operands 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 distributed 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 portion of the first vector component. All other components 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 component and the mean, divided by the length of the vector).
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.
mean
Returns the mean value of the vector.
median
Returns the median of the vector.
min
Returns the vector's minimum value.
q1
Returns the first quartile of the vector.
q3
Returns the third quartile of the vector.
prod
Returns the product of the components.
sdev
Returns the standard deviation (defined as the square root of the variance) of the vector.
skew
Returns the skewness (or third moment) of the vector. This characterizes the degree of asymmetry of the vector 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 argument.

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 clear
Clears the element indices from the array variable associated with vecName. 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.
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 compacted after all the indices have been deleted.
vecName dup destName
Copies vecName to destName. DestName is the name of a destination vector. If a vector destName already exists, it is overwritten 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 vectors.
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 truncated. 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 vector. 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 vector.
pending
Returns 1 if a client notification is pending, and 0 otherwise.
vecName offset ?value?
Shifts the indices of the vector by the amount specified by value. Value is an integer number. If no value argument is given, the current offset is returned.
vecName populate destName ?density?
Creates a vector destName which is a superset of vecName. DestName will include all the components of vecName, in addition the interval between each of the original components will contain a density 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.
vecName range firstIndex ?lastIndex?...
Returns a list of numeric values representing the vector components 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 components 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 vectors 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 {
double *valueArr;
int numValues;
int arraySize;
double min, max;
} Blt_Vector;

The field valueArr points to memory holding the vector components. The components are stored in a double precision array, whose size size is represented by arraySize. NumValues is the length of vector. The size of the array is always equal to or larger than the length of the vector. Min and max are minimum and maximum component values.

Library Routines

The following routines are available from C to manage vectors. Vectors are identified by the vector name.

Blt_CreateVector

Synopsis:

int Blt_CreateVector (interp, vecName, length, vecPtrPtr)
Tcl_Interp *interp;
char *vecName;
int length;
Blt_Vector **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 vector, 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 vector 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 returned and interp->result will contain an error message.

Blt_GetVector

Synopsis:

int Blt_GetVector (interp, vecName, vecPtrPtr)
Tcl_Interp *interp;
char *vecName;
Blt_Vector **vecPtrPtr;

Description:

Retrieves the vector vecName. VecName is the name of a vector which must already exist. VecPtrPtr will point be set to the address of the vector.
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 doubles 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 vector 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 message.

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 TCL_OK if the vector is successfully resized. If newSize is negative or memory can not be allocated for the vector, then TCL_ERROR is returned and interp->result will contain an error message.

Blt_VectorExists

Synopsis:

int Blt_VectorExists (interp, vecName)
Tcl_Interp *interp;
char *vecName;

Description:

Indicates if a vector named vecName exists in interp.
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 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.

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 vecName. 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 Blt_AllocVectorId. VecPtrPtr will point be set to the address of the vector.
Results:
Returns TCL_OK if the vector is successfully retrieved.

Blt_SetVectorChangedProc

Synopsis:

void Blt_SetVectorChangedProc (clientId, proc, clientData);
Blt_VectorId clientId;
Blt_VectorChangedProc *proc;
ClientData *clientData;

Description:

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 notified.
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. The function must return a double representing the value at the index.

Results:
The new index is installed into the vector.

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 Blt_VectorExists, Blt_GetVector is called to get the pointer to the vector. Otherwise the routine Blt_CreateVector 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 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>                

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


Table of Contents

blt-2.4z.orig/html/watch.html0100644000175000017500000001315107434255426014720 0ustar dokodoko watch(n) manual page Table of Contents

Name

watch - call Tcl procedures before and after each command

Synopsis

watch create watchName ?options?

watch activate watchName

watch deactivate watchName

watch delete watchName

watch configure watchName ?options

watch info watchName

watch names

Description

The watch command arranges for Tcl procedures to be invoked before and after the execution of each Tcl command.

Introduction

When an error occurs in Tcl, the global variable errorInfo will contain a stack-trace of the active procedures when the error occured. Sometimes, however, the stack trace is insufficient. You may need to know exactly where in the program's execution the error occured. In cases like this, a more general tracing facility would be useful.

The watch command lets you designate Tcl procedures to be invoked before and after the execution of each Tcl command. This means you can display the command line and its results for each command as it executes. Another use is to profile your Tcl commands. You can profile any Tcl command (like if and set), not just Tcl procedures.

Example

The following example use watch to trace Tcl commands (printing to standard error) both before and after they are executed.
proc preCmd { level command argv } {
set name [lindex $argv 0]
puts stderr "$level $name => $command"
}

proc postCmd { level command argv retcode results } {
set name [lindex $argv 0]
puts stderr "$level $name => $argv0= ($retcode) $results"
}
watch create trace \
   -postcmd postCmd -precmd preCmd

Operations

The following operations are available for the watch command:
watch activate watchName
Activates the watch, causing Tcl commands the be traced to the maximum depth selected.
watch create watchName ?options?...
Creates a new watch watchName. It's an error if another watch watchName already exists and an error message will be returned. Options may have any of the values accepted by the watch configure command. This command returns the empty string.
watch configure watchName ?options...?
Queries or modifies the configuration options of the watch watchName. WatchName is the name of a watch. Options may have any of the following values:
-active boolean
Specifies if the watch is active. By default, watches are active when created.
-postcmd string
Specifies a Tcl procedure to be called immediately after each Tcl command. String is name of a Tcl procedure and any extra arguments to be passed to it. Before string is invoked, five more arguments are appended: 1) the current level 2) the current command line 3) a list containing the command after substitutions and split into words 4) the return code of the command, and 5) the results of the command. The return status of the postcmd procedure is always ignored.
-precmd string
Specifies a Tcl procedure to be called immediately before each Tcl command. String is name of a Tcl procedure and any extra arguments to be passed to it. Before string is invoked, three arguments are appended: 1) the current level 2) the current command line, and 3) a list containing the command after substitutions and split into words. The return status of the -precmd procedure is always ignored.
-maxlevel number
Specifies the maximum evaluation depth to watch Tcl commands. The default maximum level is 10000.
watch deactivate watchName
Deactivates the watch. The -precmd and -postcmd procedures will no longer be invoked.
watch info watchName
Returns the configuration information associated with the watch watchName. WatchName is the name of a watch.
watch names ?state?
Lists the names of the watches for a given state. State may be one of the following: active, idle, or ignore. If a state argument isn't specified, all watches are
listed.

Keywords

debug, profile


Table of Contents

blt-2.4z.orig/html/winop.html0100644000175000017500000001203007434255426014741 0ustar dokodoko winop(n) manual page Table of Contents

Name

winop - Perform assorted window operations

Synopsis

winop lower ?window?...

winop map ?window?...

winop move window x y

winop raise ?window?...

winop snap window photoName

winop unmap ?window?...

winop warpto ?window?

Description

The winop command performs various window operations on Tk windows using low-level Xlib function calls to work around window manager pecularities.

Introduction

Tk has several commands for manipulating its windows: raise, lower, wm, etc. These commands ask the window manager to perform operations on Tk windows. In some cases, a particular window manager won't perform the operation as expected.

For example, if you positioned a toplevel window using wm geometry, the window may not actually be at those particular coordinates. The position of the window may be offset by dimensions of the title bar added by the window manager.

In situations like these, the winop command can be used to workaround these difficulties. Instead, it makes low-level Xlib (such XRaiseWindow and XMapWindow) calls to perform these operations.
toplevel .top
wm withdraw .top

# Set the geometry to make the window manager
# place the window.
wm geometry .top +100+100

# Move the window to the desired location
# and "update" to force the window manager
# to recognize it.
winop move .top 100 100
update

wm deiconify .top
winop move .top 100 100

Operations

The following operations are available for the winop command:
winop lower ?window?...
Lowers window to the bottom of the X window stack. Window is the path name of a Tk window.
winop map ?window?...
Maps window on the screen. Window is the path name of a Tk window. If window is already mapped, this command has no effect.
winop move window x y
Move window to the screen location specified by x and y. Window is the path name of a Tk window, while x and y are screen coordinates. This command returns the empty string.
winop raise ?window?...
Raises window to the top of the X window stack. Window must be a valid path name of a Tk window. This command returns the empty string.
winop snap window photoName
Takes a snapshot of the window and stores the contents in the photo image photoName. Window is the valid path name of a Tk window which must be totally visible (unobscured). PhotoName is the name of a Tk photo image which must already exist. This command can fail if the window is obscured in any fashion, such as covered by another window or partially offscreen. In that case, an error message is returned.
winop unmap ?window?...
Unmaps window from the screen. Window is the path name of a Tk window.
winop warpto ?window?
Warps the pointer to window. Window is the path name of a Tk window which must be mapped. If window is in the form @x,y, where x and y are root screen coordinates, the pointer is warped to that location on the screen.

[I've never heard a good case for warping the pointer in an application. It can be useful for testing, but in applications, it's always a bad idea. Simply stated, the user owns the pointer, not the application. If you have an application that needs it, I'd like to hear about it.]

If no window argument is present the current location of the pointer is returned. The location is returned as a list in the form "x y", where x and y are the current coordinates of the pointer.

Keywords

window, map, raise, lower, pointer, warp


Table of Contents

blt-2.4z.orig/Makefile.in0100644000175000017500000000364107434314077014026 0ustar dokodoko# ------------------------------------------------------------------------ # Makefile for BLT distribution # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ # Source and target installation directories # ------------------------------------------------------------------------ prefix = @prefix@ exec_prefix = @exec_prefix@ srcdir = @srcdir@ bindir = @bindir@ includedir = @includedir@ libdir = @libdir@ version = @BLT_VERSION@ scriptdir = $(prefix)/lib/blt$(version) instdirs = $(prefix) \ $(exec_prefix) \ $(bindir) \ $(libdir) \ $(includedir) \ $(scriptdir) # ------------------------------------------------------------------------ # Don't edit anything beyond this point # ------------------------------------------------------------------------ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_ROOT = SHELL = /bin/sh RM = rm -f subdirs = src library man demos all: (cd src; $(MAKE) all) (cd library; $(MAKE) all) (cd man; $(MAKE) all) (cd demos; $(MAKE) all) install: mkdirs install-all install-all: (cd src; $(MAKE) install) (cd library; $(MAKE) install) (cd man; $(MAKE) install) (cd demos; $(MAKE) install) $(INSTALL_DATA) $(srcdir)/README $(INSTALL_DIR)$(scriptdir) $(INSTALL_DATA) $(srcdir)/PROBLEMS $(INSTALL_DIR)$(scriptdir) $(INSTALL_DATA) $(srcdir)/NEWS $(INSTALL_DIR)$(scriptdir) mkdirs: @for i in $(instdirs) ; do \ if test -d $(INSTALL_ROOT)$$i ; then \ : ; \ else \ echo " mkdir $(INSTALL_ROOT)$$i" ; \ mkdir $(INSTALL_ROOT)$$i ; \ fi ; \ done clean: (cd src; $(MAKE) clean) (cd library; $(MAKE) clean) (cd man; $(MAKE) clean) (cd demos; $(MAKE) clean) $(RM) *.bak *\~ "#"* *pure* .pure* GENERATED_FILES = \ config.status config.cache config.log Makefile distclean: clean $(RM) $(GENERATED_FILES) blt-2.4z.orig/Makefile.vc0100644000175000017500000000367107535436721014036 0ustar dokodoko # ------------------------------------------------------------------------ # Makefile for demonstation shell of BLT library # ------------------------------------------------------------------------ include ./win/makedefs # ------------------------------------------------------------------------ # Source and target installation directories # ------------------------------------------------------------------------ srcdir = . instdirs = $(prefix) $(exec_prefix) $(bindir) $(libdir) $(includedir) # ------------------------------------------------------------------------ # Don't edit anything beyond this point # ------------------------------------------------------------------------ subdirs = src demos library html all: (cd src; $(MAKE) -f Makefile.vc all) (cd demos; $(MAKE) -f Makefile.vc all) (cd library; $(MAKE) -f Makefile.vc all) (cd html; $(MAKE) -f Makefile.vc all) install: install-dirs install-all install-readme install-all: (cd src; $(MAKE) -f Makefile.vc install) (cd demos; $(MAKE) -f Makefile.vc install) (cd library; $(MAKE) -f Makefile.vc install) (cd html; $(MAKE) -f Makefile.vc install) install-dirs: @for i in $(instdirs) ; do \ if test ! -d "$$i" ; then \ echo " mkdir $$i" ; \ mkdir $$i ; \ fi ; \ done install-readme: $(INSTALL_DATA) $(srcdir)/README $(scriptdir) $(INSTALL_DATA) $(srcdir)/PROBLEMS $(scriptdir) $(INSTALL_DATA) $(srcdir)/NEWS $(scriptdir) clean: (cd src; $(MAKE) -f Makefile.vc clean) (cd demos; $(MAKE) -f Makefile.vc clean) (cd library; $(MAKE) -f Makefile.vc clean) (cd html; $(MAKE) -f Makefile.vc clean) $(RM) *.bak *\~ "#"* *pure* .pure* GENERATED_FILES = \ config.status config.cache config.log Makefile distclean: clean (cd src; $(MAKE) -f Makefile.vc distclean) (cd demos; $(MAKE) -f Makefile.vc distclean) (cd library; $(MAKE) -f Makefile.vc distclean) (cd html; $(MAKE) -f Makefile.vc distclean) $(RM) $(GENERATED_FILES) blt-2.4z.orig/NEWS0100644000175000017500000006252407537450773012475 0ustar dokodoko Changes from 2.4y to 2.4z FEATURES ======== graph/stripchart/barchart Under Windows, both the "print1" and "print2" operations will pop-up a standard printer dialog when you don't pass a printer argument. graph/stripchart/barchart New -state option for both elements and markers. If "disabled", marker or element isn't eligible for binding events. This is useful when you have lots (>100,000) of data points. graph/stripchart/barchart New axis option -titlealternate lets you place the axis title to the top or right of the axis. This used to automatically happen when you had more than one axis in a margin. This option lets you control it. tree Both "find" and "apply" operations may be given more than one pattern switch (-exact, -glob, or -regexp). This performs a logical "or"--if any one of the pattern matches, the node is a match. tree Both "find" and "apply" operations now have addition switches -keyexact, -keyglob, and -keyregexp (the -key switch works like -keyexact). You may supply more than one switch. This performs a logical "or"--if any one of the pattern matches, the node is a match. graph/stripchart/barchart New axis options -scrollmin and -scrollmax allow you to specify the scroll region. Thanks to both Meaghan Parizeau and Julian H J Loaring for the solution. graph/stripchart/barchart Polygon marker will trigger bindings even if the marker is not filled (-fill "") or has no outline (-linewidth 0). Interior is always considered part of the polygon. tree Tree adaptively restructures data values from a linked list into a hash table when the number of values exceeds 20. configure.in Can build BLT with cygwin (gcc under Windows) distribution. Type ./configure and make to build. Use -disable-cygwin switch to build "mingw" version. Many thanks to Mumit Khan for all the hard work of porting the configure.in and Makefiles. BUG FIXES ========= eps Canvas item errors out with "can't get handle to EPS file" message. Thanks to Shamil Daghestani for the bug report. graph/stripchart/barchart Image marker doesn't get scaled correctly when scaling factor is large. Thanks to Paul Kienzle for the bug report and example script. It really helped. vector "min" and "max" initially don't report the correct value. Many thanks to Alexander Eisenhuth for the bug report. treeview/tree "show -full $key" operation doesn't work. graph/stripchart/barchart Doesn't display trailing data points when there are more than 65331 points. Thanks to Val Shkolnikov for the bug report. vector Vectors leak memory when accessing them through the Tcl array variable. Thanks to Alexander Eisenhuth for the bug report and especially the test script to demonstrate the problem. treeview/tree In "apply" operation, -regexp, -exact, or -glob switches don't work. Always matches every node. graph/stripchart/barchart Axis "-hide" option no longer accepts "all" value. "all" was supposed to hide the axis *and* all the elements mapped to it. I don't think this option ever worked correctly. It was also unclear whether to hide the legend entry, markers, etc. graph/stripchart/barchart Changing a marker's -hide option doesn't take effect until the graph is redrawn. Thanks to Alex Verstak for the bug report. graph/stripchart/barchart Spurious characters in PostScript output generated under Windows. Thanks to Cary D. Renzema for the bug report and sample files. graph/stripchart/barchart "snap" operation core dumps or returns X protocol error depending on arguments. Thanks to Carsten Mortensen for both the bug report and the fix. graph/stripchart/barchart Polygon marker not drawn unless no outline is specified (-linewith 0). Thanks to Nestor Patino for the bug report. treeview/tree Tags are removed when tree or treeview widget is destroyed. Many thanks to Todd Copeland for the report. treeview/tree "index" operation segfaults when tag is empty. Again thanks to Todd Copeland for the report. pkgIndex.tcl Added checks for package directory and its parent when searching for BLT shared library. Thanks to Anton Hartl for the bug report. Changes from 2.4x to 2.4y FEATURES ======== tree Added -notags switch to "restore" operation. tree Added additional fields to the tree "dump" format. When trees are restored, will try to reuse old node ids (not always possible). tree Added -label switch to "copy" operation. This lets you relabel the destination node. BUG FIXES ========= graph/stripchart/barchart PostScript output sometimes includes a spurious box around an axis. Thanks to Harvey.Davies@csiro.au for the bug report and example. tabset/tabnotebook On errors tabnotebook grows ad infinitum. Thanks to Terri Fischer for the bug report and example. Tcl_Init fails with "can't find usable init.tcl" when running bltsh or bltwish compile with ActiveTcl. Changed Tcl_AppInit to set global "tclDefaultLibrary" variable. graph "legend get" operation doesn't account for hidden entries (i.e. -label is configured to ""). Thanks to Karl Voskuil for the bug report and the fix. graph NULL pointer referenced (bindingTable) when destroying axis. bgexec File redirection broken under Windows. graph Area under curve not stippled correctly when bitmap is greater than 8x8 (W95/W98) or device context is a metafile (all?). Created XFillPolygon replacement for Windows. tree Node modifiers are incorrectly ignored when first component is a tag. treeview -shadow option no longer accepts empty string (no shadow). Many thanks to Todd Copeland for the report. vector Vector "create" operation slows down using #auto as more vectors are created. Thanks to Todd Copeland for the bug report. treeview/hiertable Widget doesn't scroll horizontally correctly when -hideleaves is true. Ignores last level when computing world width. treeview/hiertable Deleting a node doesn't remove tag references to it. Thanks to Steven Hafer for the bug report. treeview/hiertable Giving the -path option to the "index" operation always fails. Thanks to Paul Robins for the bug report. Documentation for the "get" operation isn't clear that it always returns a list of lists when the -separator option is "" (the default), even when there is only one node specified. Changes from 2.4w to 2.4x FEATURES ======== dragdrop Back ported 8.3 "dde" command for use with 8.0. BUG FIXES ========= treeview/hiertable Can't create column that starts with a minus. Thanks to Todd Copeland for the bug report. pkgIndex.tcl file not getting rebuilt. Thanks to Terri Fischer for the bug report and fix. Send emulation script isn't needed for Tcl8.0 under Windows. Thanks to Linh H Phan for the bug report. graph/stripchart/barchart Using pen styles results in a bus error. Thanks to Julian H J Loaring for the bug report. hiertable/treeview/tree List of data values is reversed from 2.4v. Thanks to Jorge Suit Prez Ronda for the bug report. Missing header file for varargs. Thanks to Terri Fischer for the bug report and fix. TclpAlloc and TclpFree not found in Tcl 8.0. Again, thanks to Terri Fischer for the bug report and fix. Updated manual pages graciously provided by Terri Fischer . Changes from 2.4v to 2.4w FEATURES ======== treeview New treeview widget is updated version of hiertable. Uses Tcl_Objs. The "hiertable" and "treeview" are the 100% syntax compatible. The old hiertable is temporariliy available as "hiertable-old" should you find errors. Also use the "treeview" instead of the "hierbox" widget. The "hierbox" isn't as capable and doesn't use tree data objects. treeview/hiertable Added tagging operations similar to the "tree" command. Attaching a tree to the treeview/hiertable (the -tree option) now gives you access to the tree's tags too. Don't confuse this with "bindtags". For example, you can tag nodes with the "tree" command and operate on them in the treeview/hiertable widget using that tag. If you don't want to share tags, the -newtags option will prevent this. There's an update "treeview" manual entry to describe this. treeview/hiertable The "nearest" operation can report what part of the entry the pointer is over. If a variable name argument is given, the variable will contain either "button", "label", "icon", or "". eps/winop Faster image zooming and rotation (fixed-point arithmetic). BUG FIXES ========= vector Test of real number in a range is broken. Thanks to Paul Robins for the bug report. treeview/hiertable "nearest" operation doesn't allow an optional "variable" argument. hiertable/hierbox The -selectioncommand command is invoked when closing an entry with no selected descendants. Thanks to Jorge Suit Prez Ronda for the bug report. hiertable/hierbox In single "mode", the selection anchor is not updated when the selection is moved via the keyboard. Thanks to Jorge Suit Prez Ronda for the bug report. hiertable Editor overwrites memory (seen best under Windows). hiertable The "open" and "close" operations don't check for no arguments. hiertable Vertical dotted lines start on wrong y-coordinate when clipped. hiertable Active button isn't clipped by column titles. hiertable Column titles are still displayed and picked despite -showtitles set to "no". hiertable Editor doesn't automatically select acquired text. hiertable Moving the cursor in the editor doesn't clear the selection. hiertable Typing a "space" doesn't replace the selection with a space. tree Traces on the same node loop infinitely. TRACE_ACTIVE flag not set/unset. tree The "restore" and "restorefile" operations don't handle newlines in data key/values, node labels, or tags. graph/barchart/stripchart Crosshairs left on screen when the mouse is pulled quicky from the widget. graph/barchart/stripchart Spurious crosshairs also left on the screen if axes are reconfigured (active axes). graph/barchart/stripchart Image marker not updated if image is changed. graph/barchart/stripchart PostScript not generated for -showvalues option. graph/barchart/stripchart PostScript not generated for errorbars. bgexec No check for wrong number of arguments if switch is present. Blt_MallocProcPtr and Blt_FreeProcPtr not declared extern in bltInt.h Bogus test for mask in Blt_TilePolygon routine. Counter for transparent pixels wrong in Win32 version of Blt_PolygonMask. blt_version not set when dynamically loaded into wish83.exe. Note: Stub support is still missing although patches have been graciously provided for the 2.4q release. This will be added as soon as I can get some free time. Changes from 2.4u to 2.4v FEATURES ======== bgexec New -linebuffered switch. bgexec myVar -linebuffered yes -onoutput ShowLine myProg & This option lets you process updated data (-onerror, -onoutput, -error, or -output) on a line by line basis. Normally notifications occur once for entire data block. This switch causes separate notifications to made for each complete line. bgexec New -decodeoutput and -decodeerror switches. bgexec myVar -decodeoutput unicode -output myOut myProg & Translates data from the specified encoding to UTF before passing it to the Tcl interpreter. Normally no translation is made (under Windows CR-LF conversions are made) and the raw, typically ASCII, characters are passed back to the Tcl interpreter. Binary data can be collected with the "binary" encoding. For versions using Tcl 8.1 or greater, data is returned as Tcl byte array object, so you can use the "binary" command to convert it as needed. set out [bgexec myVar -decodeoutput binary myProg] binary scan $myOut f values tree New "dumpfile" and "restorefile" operations to "tree" command. tree Extended -> syntax in tree command to use node names. set data [$tree get root->"fred"->"pebbles"] tree Improved memory handling of large trees. Pool allocators added to reduce overall memory consumption. graph/stripchart/barchart New -buffergraph switch. .graph configure -buffergraph no graph New options to fill area under curve of an element. .graph element configure line1 -areapattern solid .graph element configure line2 -areapattern BLT graph/stripchart/barchart New -reduce option. .graph element configure line1 -abstol 0.5 Designates error tolerance for line simplificiation. Points that vary less than the given tolerance are merged into a single line segment. miscellaneous Can globally replace memory allocation routines by setting pointers Blt_MallocProcPtr and Blt_FreeProcPtr. winop New "rotate" operation lets you rotate photo images. BUG FIXES ========= bgexec Fixed a race condition that caused assertion under Windows to fail. When both stdout and stderr are collected, if the stdout handler finishes first, the memory used by read thread handler could be freed before the stderr pipe was closed. graph/stripchart/barchart PostScript coordinates are no longer integers (screen resolution). graph/stripchart/barchart Polygon markers now clipped properly. vector Vectors can't be mapped to local variables. This was broken in the 2.4r release. Thanks to Johannes Zellner for the bug report. vector Tcl command associated with a vector not destroyed when the vector is deleted. Much thanks to Alexander Eisenhuth for the bug report and the example script. drag&drop "drag&drop" command fails when multiple formats are specified. Seen in the dragdrop2.tcl demo. spline Incorrectly reports the spline's x-vector to be non-monotonic. Thanks to Chang Li for the bug report. Fixed pkgIndex.tcl.in to figure out whether to load libBLT24.so or libBLTlite24.so when BLT is loaded, not when the package is registered. Thanks to Dr. Dieter Ruppert for the bug report and fix. Changes from 2.4t to 2.4u BUG FIXES ========= <./configure> Fixed my stupid error (missing close brace) in ./configure file. Makefile in src/shared doesn't define BLT_LIBRARY. Thanks to terri@ner.com (Terri L. Fischer) for the bug report and fix. graph/barchart/stripchart graph doesn't find vector in global namespace when inside of another namespace. Thanks to Julian H J Loaring for the bug report. graph/barchart/stripchart Scratch buffer to small for PostScript prolog. Thanks again to Julian H J Loaring for the bug report and fix. graph "bind" would fail on elements without traces (-linewidth 0). Thanks again to terri@ner.com (Terri L. Fischer) for the bug report. o Many changes to "dnd" command. + -package option is treated as a command prefix (like the scrollbar), not a script. Percent sign substitutions are no longer allowed. Information is passed via key-value parameters like the -onleave, -ondrop procedures. Procedure must return 1 if operation was Ok, and 0 if it failed. + The command arguments for both the "setdata" and "getdata" operations have changed from an arbitrary Tcl script with percent sign substitutions, to a command prefix with key-value arguments appended. The general form is procName widget args... where args is one of more key value pairs. x Relative X-coordinate of drop or pickup. y Relative Y-coordinate of drop or pickup. timestamp Timestamp of transaction. format Format desired. value Value transfered (setdata only). You can use array set to parse "args". For example: proc GetColor { widget args } { array set info $args puts "x-coordinate is $info(x)" puts "selected format is $info(format)" return [$widget cget -bg] } + If an -onmotion procedure is specified for the target, it is automatically invoked on drops before the -dropcmd is run. If it returns 0, the drop is canceled. + Added ./demos/dnd2.tcl to show more complicated example. Just like dnd1.tcl, you need to run two of them at the same time to see the drag-and-drop operations. + Target property wasn't getting reset when changing -onmotion, -onleave, etc. procedures. + Timestamps now displayed as unsigned. Many thanks to Tom Lane for all his help and suggestions. Changes from 2.4s to 2.4t o Tree command syntax changes. Notify and trace operation now work as advertised and a copy operation added. Many thanks to Matt Newman for meticulously reviewing the command. o graph "snap" operation syntax change. Added support for generating Aldus metafiles and enhanced metafiles under Windows. # Normal syntax. set image [image create photo] .graph snap $image # New additions. .graph snap -format emf myFile.emf ;# Enhanced metafile .graph snap -format wmf myFile.wmf ;# Aldus placable metafile .graph snap -format emf CLIPBOARD ;# Metafile written into clipboard. Old width and height arguments are replaced with -width and -height switches. .graph snap $image 500 500 ;# Old .graph snap -width 500 -height 500 $image ;# New Thanks to Alain Zuur for the enhancement. o Tabset/Tabnotebook -selectforeground option for tabs using wrong configuration option type. Both the bug report and fix are from Mark E. Smith . Thanks. o graph "bind" to use closest point instead of line segment when element contains only 1 point. Thanks to Uwe Klein for the bug report and script. o Hiertable tree view column has been internally renamed to "BLT Hiertable widgetName". It was formerly the name of the widget. Fortunately, you can refer to the column as "treeView" instead. .ht column configure treeView -text "View Label" o There's no ".tree" suffix anymore on the default tree created by the hiertable widget. It's now just the widget name. o Many hiertable column bug fixes. Thanks to Julian H J Loaring for all the tests and reports. o Rotated text displayed incorrectly under Windows 95/98 using non-TrueType fonts. A test for typetype fonts has been restored. Thanks to James Pakko for the bug report and script. Under Windows, Non-TrueType fonts are drawn into a bitmap and the bitmap is rotated. This provides the same quality as using rotated fonts for on-screen display. Unfortunately it's much poorer for higher resolution devices such as printers. The best bet is to simply choose TrueType fonts if you can. o Improved Hiertable folder images. Many thanks to Tom Lane for the new images. o Bgexec segfaults under Windows (NT/95) if file handler is deleted inside of callback. Thanks to Chris Oliver for the bug report. o graph segfaults if pen style range min/max are the same. Thanks to Thomas Wu for the bug report and script. o tabnotebook and tabset widgets would generate X11 errors if embedded window was resize to zero width/height. Thanks to Ed Ohsone for the report and the script to demonstrate the error. Changes from 2.4r to 2.4s o Fixed bug in stripchart (introduced in 2.4r) allowing uninitialized data to be displayed. Thanks to Dick Gooris for the bug report. o AIX dynamic loading. Actually made it work on a 4.3 AIX box. o Fixed -tree option in hiertable. Would segfault if tree was not fully initialized first. o Tree insert operation syntax changed from tree0 insert $node key1 value1 key2 value2 to tree0 insert $node -data { key1 value1 key2 value2 } o Fixed tree label operation. Save uid instead of string. o Bug in TreeEventProc, should be node != NULL instead of node >= 0 Thanks to Julian H J Loaring for the bug report. What's new in 2.4? 1. "eps" canvas item. An encapsulated PostScript canvas item lets you embed an EPS file into the canvas. The "eps" item displays either a EPS preview image found in the file, or a Tk image that you provide. 2. "hierbox" and "hiertable" widget. Hierarchical listbox widget. Displays a general ordered tree which may be built on-the-fly or all at once. 3. "tabset" and "tabnotebook" widget. Can be used either as a tab notebook or simple tabset. Tabs can be arranged in a variety of ways: multi-tiered, scrolled, and attached to any of the four sides. Tab labels can contain both images and text (text can be arbitrarily rotated). Notebook pages can be torn-off into separate windows and replaced later. 4. Changes to vectors. New features: o Vector expressions. The vector now has an "expr" operation that lets you perform math (including math library functions) on vectors. There are several new functions (such as "max", "min", "mean" "median", "q1", "q3", "prod", "sum", "adev", "sdev", "skew", ...) vector expr { sin(x)^2 + cos(x)^2 } y expr { log(x) * $value } o New syntax to create and destroy vectors: vector create x vector destroy x The old syntax for creating vectors still works. vector x o Vectors are *not* automatically deleted when their Tcl variable is unset anymore. This means that you can temporarily map vectors to variables and use them as you would an ordinary Tcl array (kind of like "upvar"). proc AddValue { vecName value } { $vecName variable x set x(++end) $value } There's an "-watchunset" flag to restore the old behavior if you need it. vector create x -watchunset yes o Vectors still automatically create Tcl variables by default. I'd like to change this, but it silently breaks lots of code, so it will stay. Bug fixes: o Vector reallocation failed when shrinking the vector. o Vector "destroy" callback made after vector was already freed. o Fixed vector/scalar operations. o Always store results in temporary, so not to overwrite accidently current vector values. 5. Changes to Graph, Barchart, Stripchart widgets. New features: o Drop shadows for text (titles, markers, etc). Drop shadows improve contrast when displaying text over a background with similar color intensities. o Postscript "-preview" option to generate a EPS PostScript preview image that can be read and displayed by the EPS canvas item. o New "-topvariable", "-bottomvariable", "-leftvariable", and "-rightvariable" options. They specify variables to contain the current margin sizes. These variables are updated whenever the graph is redrawn. o New "-aspect" option. Let's you maintain a particular aspect ratio for the the graph. o Image markers can now be stretched and zoomed like bitmap markers. o Bind operation for legend entries, markers, and elements. Much thanks to Julian Loaring for the idea. o New "-xor" option for line markers, lets you draw the line by rubberbanded by XOR-ing without requiring the graph to be redrawn. This can be used, for example, to select regions for zooming. Thanks to Johannes Zellner (joze@krisal.physik.uni-karlsruhe.de) for the idea. o Can attach a scrollbar to an axis. .sbar configure -command { .graph axis view y } .graph axis configure y -scrollcommand { .sbar set } Bug fixes: o Closest line (point) broken when using pens styles. o Marker elastic coordinates were wrong. o PostScript bounding box included the border of the page. o Bad PostScript generated for barchart symbols with stipples. o Wrong dimensions computed with postscript " -maxpect" option. o Text markers fixed. Thanks to De Clarke for the bug report and fix. o Renamed axis configuration from "-range" to "-autorange" to match the documentation. Thanks to Brian Smith for the correction. o Fixed polygon marker pick routine. o Fixed active tab labels overlapping the selected tab. o PostScript graph footer turned off by default. Use -footer option to turn on. .graph postscript configure -footer yes blt-2.4z.orig/PROBLEMS0100644000175000017500000001242607452716430013127 0ustar dokodokoSpecific problems: 1. I've built BLT, but when I run "bltwish", it doesn't know about any of the BLT commands. % graph .g invalid command name "graph" Starting with Tcl 8.x, the BLT commands are stored in their own namespace called "blt". The idea is to prevent name clashes with Tcl commands and variables from other packages, such as a "table" command in two different packages. You can access the BLT commands in a couple of ways. Prefix the BLT commands with the namespace qualifier "blt::" % blt::graph .g % blt::table . .g -resize both or import the BLT commands into the global namespace. % namespace import blt::* % graph .g % table . .g -resize both 2. I'm try to compile BLT with ActiveState's Tcl/Tk distribution, but all the demos core dump. Look in the "include" directory where you installed ActiveState. Is there an "X11" directory? Remove it and recompile BLT. It contains all the fake X11 headers needed for Windows builds. So it's okay to remove it for Solaris and Linux. 3. Under Windows the "drag&drop" command doesn't work for me. The "drag&drop" command uses the "send" command to communicate between Tk applications and under Windows Tk has no built-in "send" command. In ./demos/scripts/send.tcl there is a "send" look-a-like that uses the DDE package. Source this first and make sure you invoke the procedures "SendInit" and "SendVerify" *before* you create and drag-and-drop targets. 4. I'm using Windows 95/98 and the -stipple option doesn't seem to work. Under Windows 95/98, your bitmap must be exactly 8x8. If you use a bigger or smaller bitmap, Windows won't stipple the pattern correctly. For bitmaps larger than 8x8, only the upper-left 8x8 corner of the bitmap is used. For smaller bitmaps, the bitmap is extended to 8x8 with the new bits 0 (blank). This is a limitation of Windows 95/98, not Tk. 5. I can't run bltwish.exe under Windows with Tcl/Tk version 8.0. Did you compile and install Tcl/Tk yourself? Tcl is expecting a registry key to be set. The installer normally does that for you. The key tells Tcl where to find the Tcl library scripts. Setting the TCL_LIBRARY environment variable to the location of the Tcl script directory (where init.tcl is located) will fix things. Dynamic loading (package require BLT) of BLT should also work. This problem is fixed in later versions of Tcl. 6. I'm on a DEC Alpha running the graph widget. I don't see any ticks or lines. There's a problem with code generated by the GNU C compiler 2.8.[0-1] for bltGrAxis.c and bltGrLine.c (I think it's just these two files). Try compiling with either the native "cc" compiler or compile the two modules with -O0. 7. When I compile BLT on Solaris (maybe others?), I get lots of error messages in the form: 0xf44 /usr/local/lib/libtcl7.6.a(tclCmdIL.o) 0xf3c /usr/local/lib/libtcl7.6.a(tclCmdIL.o) 0x628 /usr/local/lib/libtcl7.6.a(tclCmdIL.o) This is because Tcl and Tk have been installed only as static libraries, not shared libraries. The ./src/shared/Makefile creates the shared BLT library with a back-link to these libraries. The advantage of this link is that when you dynamically load BLT, the correct Tcl/Tk libraries are automatically searched for any unresolved references. You can fix this in one of two ways. o Remove the back-link. Edit ./src/shared/Makefile and cut the "-ltcl* -ltk*" references from the SHLIB_LD_LIBS macro. o Create shared libraries for Tcl and Tk. Re-configure, compile, and install Tcl/Tk from their sources. Make sure you add the "--enable-shared" switch to "configure". ./configure --enable-shared 8. How do I create a shared library of BLT under AIX? Check that Tcl and Tk were both configured with the --enable-shared flag. When you compile each of them, a "lib.exp" file is created in their respective "unix" subdirectories. The lib.exp files are removed when you do a "make clean", so you may need to recompile. The BLT Makefile uses the TCL_SRC_DIR and TK_SRC_DIR values in the tclConfig.sh and tkConfig.sh files to find these lib.exp files. You may need to edit ./src/Makefile/shared to reflect the real paths of the Tcl and Tk source distributions. General Problems: 1. I can't compile BLT. Send the output of both "./configure" and "make" to me at gah@myfirstlink.net gah@silconmetrics.com This will make it easier to track down the exact problem. 2. I get a segfault when running BLT in my application. The best method is to send a Tcl script that I can run to demonstrate the problem. The hard work you do pruning down the problem into a small script will greatly help solve it. Once I see what the problem is, I can usually fix it right away. Make sure you include all the necessary pieces to make it run (e.g. data file). If it's needed, also include directions how to make the problem occur (e.g. "double click on the left mouse button"). 3. The manual page lies. I appreciate any help in pointing out errors, omissions, or lies in the manuals. If you have ideas how they might be improved, I'd love to hear them. blt-2.4z.orig/README0100644000175000017500000001323307553177373012647 0ustar dokodoko This is version 2.4 of the BLT library. It's an extension to the Tcl/Tk toolkit. You simply compile and link with the Tcl/Tk libraries. It does not require the Tcl or Tk source files. BLT is available from www.sourceforge.net/projects/blt/files This release has been built and tested with the following Tcl/Tk versions: Tcl 7.5 / Tk 4.1 Tcl 7.6 / Tk 4.2 Tcl/Tk 8.0 Tcl/Tk 8.1 Tcl/Tk 8.2 Tcl/Tk 8.3 Tcl/Tk 8.4 thru 8.4.0 Avoid alpha and beta versions of Tcl/Tk. They probably won't work. What is BLT? BLT is an extension to Tcl/Tk. It adds plotting widgets (X-Y graph, barchart, stripchart), a powerful geometry manager, a new canvas item, and several new commands to Tk. Plotting widgets: graph, barchart, stripchart BLT has X-Y graph, barchart, and stripchart widgets that are both easy to use and customize. All the widgets work with BLT vector data objects, which makes it easy to manage data. Tree viewer treeview Displays a general ordered tree which may be built on-the-fly or all at once. tree Tree data object. Tab set: tabset Can be used either as a tab notebook or simple tabset. Multi-tiered and/or scrolled tabsets are available. Notebook pages can be torn-off into separate windows and later put back. Geometry Manager: table A table-based geometry manager. Lets you specify widget layouts by row and column positions in the table. Unlike the packer or grid, you can finely control and constrain window sizes. Vector Data Object: vector Lets you manage a vector of floating point values in a high-level fashion. Vectors inter-operate seamlessly with the plotting widgets. The graphs will automatically redraw themselves when the vector data changes. Vector's components can be managed through a Tcl array variable, a Tcl command, or the using its own C API. Background Program Execution: bgexec Like Tcl's "exec ... &", but collects the output, error, and status of the detached UNIX subprocesses. Sets a Tcl variable upon completion. Busy Command: busy For preventing user-interactions when the application is busy. Manages an invisible "busy" window which prevents further user interactions (keyboard, mouse, button, etc.). Also you can provide a busy cursor that temporarily overrides those of the Tk widgets. New Canvas Item: eps An new item is added to the Tk canvas for handling encapsulated PostScript. It lets you embed an EPS file into the canvas displaying either an EPS preview image found in the file, or a Tk image that you provide. When you print the canvas the EPS item will automatically include the EPS file, translating and scaling the PostScript. For example, you could use "eps" items to tile several PostScript pages into single page. The "eps" item can also be used as a replacement for "image" canvas items. Unlike "image" canvas items, the image of an eps item can be printed and scaled arbitrarily. Drag & Drop Facility: drag&drop Adds drag-n-drop capabilities to Tk. It uses "send"-style communication between drag-drop sources and targets. The result is a much more powerful drag-and-drop mechanism than is available with OpenLook or Motif. Bitmap Command: bitmap Lets you read and write bitmaps from Tcl. You can define bitmaps from ordinary text strings. Bitmaps can also be scaled and rotated. For example, you can create a button with rotated text by defining a bitmap from a text string and rotating it. You can then use the bitmap in the button widget. Miscellaneous Commands: winop Basic window operations. You can raise, lower, map, or, unmap windows. Other operations let you move the pointer or take photo image snapshots of Tk widgets. bltdebug Lets you trace the execution of Tcl commands and procedures. Prints out each Tcl command before it's executed. watch Lets you specify Tcl procedures to be run before and/or after every Tcl command. May be used for logging, tracing, profiling, or debugging or Tcl code. spline Computes a spline fitting a set of data points (x and y vectors) and produces a vector of the interpolated images (y-coordinates) at a given set of x-coordinates. htext A simple hypertext widget. Allows text and Tk widgets to be combined in a scroll-able text window. Any Tk widget can be embedded and used to form hyper-links. Other options allow for selections and text searches. How to compile and test BLT? See the file "INSTALL" for instructions. Does BLT work under Windows? Yes. Windows 95/98/ME/NT/2000/XP. I've compiled it with both MS VC++ 5.0/6.0p4 and EGCS 1.1.1. Self-installing pre-compiled versions are available. What are the differences between the Windows and Unix releases? All commands work: graphs, bgexec, busy, drag&drop etc. except the "container", and "cutbuffer" widgets. The "drag&drop" command still needs to use "send" to transfer information between Tk applications. You can use ./demos/scripts/send.tcl to imitate "send" using DDE. Just source the script and execute SendInit SendVerify to set up the new send command. When will...? In general, I can't answer the "When will" questions, mostly out of embarrassment. My estimates of when new features and releases will occur usually turn out to be way way off. What does BLT stand for? Whatever you want it to. Where to send bugs reports, suggestions, etc. ? gah@siliconmetrics.com -and- ghowlett@grandecom.net (best to send to both addresses) Make sure you include BLT and the version number in the subject line. --gah blt-2.4z.orig/acconfig.h0100644000175000017500000000224607407476537013715 0ustar dokodoko/* acconfig.h This file is in the public domain. Descriptive text for the C preprocessor macros that the distributed Autoconf macros can define. No software package will use all of them; autoheader copies the ones your configure.in uses into your configuration header file templates. The entries are in sort -df order: alphabetical, case insensitive, ignoring punctuation (such as underscores). Although this order can split up related entries, it makes it easier to check whether a given entry is in the file. Leave the following blank line there!! Autoheader needs it. */ #define BLT_CONFIG_H 1 /* Define if DBL_EPSILON is not defined in float.h */ #undef BLT_DBL_EPSILON /* Define if drand48 isn't declared in math.h. */ #undef NEED_DECL_DRAND48 /* Define if srand48 isn't declared in math.h. */ #undef NEED_DECL_SRAND48 /* Define if strdup isn't declared in a standard header file. */ #undef NEED_DECL_STRDUP /* Define if j1 isn't declared in a standard header file. */ #undef NEED_DECL_J1 /* Define if union wait type is defined incorrectly. */ #undef HAVE_UNION_WAIT /* Define if isfinite is found in libm. */ #undef HAVE_ISFINITE blt-2.4z.orig/aclocal.m40100644000175000017500000000163707452536160013623 0ustar dokodokodnl AC_TRY_RUN_WITH_OUTPUT(VARIABLE, PROGRAM,) AC_DEFUN(AC_TRY_RUN_WITH_OUTPUT, [AC_REQUIRE([AC_PROG_CC])dnl if test "$cross_compiling" = yes; then ifelse([$3], , [errprint(__file__:__line__: warning: [AC_TRY_RUN_WITH_OUTPUT] called without default to allow cross compiling )dnl AC_MSG_ERROR(can not run test program while cross compiling)], [$3]) else cat > conftest.$ac_ext < ./conftest.stdout; exit) 2>/dev/null; then $1=`cat ./conftest.stdout` else $1="" fi fi rm -fr conftest*]) dnl AC_GREP_SYMBOL(VARIABLE, SYMBOL, FILE) AC_DEFUN(AC_GREP_SYMBOL, [AC_REQUIRE([AC_PROG_AWK])dnl cat > conftest.awk <&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` eval "enable_${ac_feature}=no" ;; -enable-* | --enable-*) ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "enable_${ac_feature}='$ac_optarg'" ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix="$ac_optarg" ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he) # 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 << EOF Usage: configure [options] [host] Options: [defaults in brackets after descriptions] Configuration: --cache-file=FILE cache test results in FILE --help print this message --no-create do not create output files --quiet, --silent do not print \`checking...' messages --version print the version of autoconf that created configure Directory and file names: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [same as prefix] --bindir=DIR user executables in DIR [EPREFIX/bin] --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] --libexecdir=DIR program executables in DIR [EPREFIX/libexec] --datadir=DIR read-only architecture-independent data in DIR [PREFIX/share] --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data in DIR [PREFIX/com] --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] --libdir=DIR object code libraries in DIR [EPREFIX/lib] --includedir=DIR C header files in DIR [PREFIX/include] --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] --infodir=DIR info documentation in DIR [PREFIX/info] --mandir=DIR man documentation in DIR [PREFIX/man] --srcdir=DIR find the sources in DIR [configure dir or ..] --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names EOF cat << EOF Host type: --build=BUILD configure for building on BUILD [BUILD=HOST] --host=HOST configure for HOST [guessed] --target=TARGET configure for TARGET [TARGET=HOST] Features and packages: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --x-includes=DIR X include files are in DIR --x-libraries=DIR X library files are in DIR EOF if test -n "$ac_help"; then echo "--enable and --with options recognized:$ac_help" fi exit 0 ;; -host | --host | --hos | --ho) ac_prev=host ;; -host=* | --host=* | --hos=* | --ho=*) host="$ac_optarg" ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir="$ac_optarg" ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir="$ac_optarg" ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir="$ac_optarg" ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir="$ac_optarg" ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst \ | --locals | --local | --loca | --loc | --lo) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* \ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) localstatedir="$ac_optarg" ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir="$ac_optarg" ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir="$ac_optarg" ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix="$ac_optarg" ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix="$ac_optarg" ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix="$ac_optarg" ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name="$ac_optarg" ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir="$ac_optarg" ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir="$ac_optarg" ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site="$ac_optarg" ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir="$ac_optarg" ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir="$ac_optarg" ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target="$ac_optarg" ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers) echo "configure generated by autoconf version 2.13" exit 0 ;; -with-* | --with-*) ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "with_${ac_package}='$ac_optarg'" ;; -without-* | --without-*) ac_package=`echo $ac_option|sed -e 's/-*without-//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` eval "with_${ac_package}=no" ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes="$ac_optarg" ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries="$ac_optarg" ;; -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } ;; *) if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then echo "configure: warning: $ac_option: invalid host type" 1>&2 fi if test "x$nonopt" != xNONE; then { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } fi nonopt="$ac_option" ;; esac done if test -n "$ac_prev"; then { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } fi trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 # File descriptor usage: # 0 standard input # 1 file creation # 2 errors and warnings # 3 some systems may open it to /dev/tty # 4 used on the Kubota Titan # 6 checking for... messages and results # 5 compiler messages saved in config.log if test "$silent" = yes; then exec 6>/dev/null else exec 6>&1 fi exec 5>./config.log echo "\ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. " 1>&5 # Strip out --no-create and --no-recursion so they do not pile up. # Also quote any args containing shell metacharacters. ac_configure_args= for ac_arg do case "$ac_arg" in -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c) ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) ac_configure_args="$ac_configure_args '$ac_arg'" ;; *) ac_configure_args="$ac_configure_args $ac_arg" ;; esac done # NLS nuisances. # Only set these to C if already set. These must not be set unconditionally # because not all systems understand e.g. LANG=C (notably SCO). # Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! # Non-C LC_CTYPE values break the ctype check. if test "${LANG+set}" = set; then LANG=C; export LANG; fi if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo > confdefs.h # A filename unique to this package, relative to the directory that # configure is in, which we can look for to find out if srcdir is correct. ac_unique_file=src/bltInit.c # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then its parent. ac_prog=$0 ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. srcdir=$ac_confdir if test ! -r $srcdir/$ac_unique_file; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r $srcdir/$ac_unique_file; then if test "$ac_srcdir_defaulted" = yes; then { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } else { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } fi fi srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` # Prefer explicitly selected file to automatically selected ones. if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then echo "loading site script $ac_site_file" . "$ac_site_file" fi done ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross ac_exeext= ac_objext=o if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then ac_n= ac_c=' ' ac_t=' ' else ac_n=-n ac_c= ac_t= fi else ac_n= ac_c='\c' ac_t= fi ac_aux_dir= for ac_dir in cf $srcdir/cf; 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 fi done if test -z "$ac_aux_dir"; then { echo "configure: error: can not find install-sh or install.sh in cf $srcdir/cf" 1>&2; exit 1; } fi ac_config_guess=$ac_aux_dir/config.guess ac_config_sub=$ac_aux_dir/config.sub ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. # ----------------------------------------------------------------------- # # Handle command line options # # --with-tcl=DIR # --with-tk=DIR # --with-cc=CC # --with-cflags=flags This is probably for me only # --with-gnu-ld # # ----------------------------------------------------------------------- INC_SPECS="" LIB_SPECS="" TCL_ONLY_LIB_SPECS="" loader_run_path="" DEFINES="" blt_with_tcl="" blt_with_tk="" blt_enable_jpeg="no" blt_enable_cygwin="yes" blt_with_cc="" blt_with_cflags="$CFLAGS" blt_with_gnu_ld="no" blt_with_tcl_includes="" blt_with_tk_includes="" blt_with_tcl_libraries="" blt_with_tk_libraries="" blt_with_scriptdir="" # Check whether --with-blt or --without-blt was given. if test "${with_blt+set}" = set; then withval="$with_blt" blt_with_scriptdir=$withval fi # Check whether --with-tcl or --without-tcl was given. if test "${with_tcl+set}" = set; then withval="$with_tcl" blt_with_tcl=$withval fi # Check whether --with-tk or --without-tk was given. if test "${with_tk+set}" = set; then withval="$with_tk" blt_with_tk=$withval fi # Check whether --with-tclincls or --without-tclincls was given. if test "${with_tclincls+set}" = set; then withval="$with_tclincls" blt_with_tcl_includes=$withval fi # Check whether --with-tkincls or --without-tkincls was given. if test "${with_tkincls+set}" = set; then withval="$with_tkincls" blt_with_tk_includes=$withval fi # Check whether --with-tcllibs or --without-tcllibs was given. if test "${with_tcllibs+set}" = set; then withval="$with_tcllibs" blt_with_tcl_libraries=$withval fi # Check whether --with-tklibs or --without-tklibs was given. if test "${with_tklibs+set}" = set; then withval="$with_tklibs" blt_with_tk_libraries=$withval fi # Check whether --enable-jpeg or --disable-jpeg was given. if test "${enable_jpeg+set}" = set; then enableval="$enable_jpeg" unset ac_cv_header_jpeglib_h unset ac_cv_lib_jpeg ac_cv_lib_jpeg_jpeg_read_header blt_enable_jpeg=$enableval fi # Check whether --enable-cygwin or --disable-cygwin was given. if test "${enable_cygwin+set}" = set; then enableval="$enable_cygwin" blt_enable_cygwin=$enableval fi # Check whether --with-cc or --without-cc was given. if test "${with_cc+set}" = set; then withval="$with_cc" blt_with_cc=$with_cc unset ac_cv_prog_CC unset ac_cv_prog_CPP fi # Check whether --with-cflags or --without-cflags was given. if test "${with_cflags+set}" = set; then withval="$with_cflags" blt_with_cflags="$with_cflags" fi # Check whether --with-gnu_ld or --without-gnu_ld was given. if test "${with_gnu_ld+set}" = set; then withval="$with_gnu_ld" blt_with_gnu_ld="yes" fi # Do some error checking and defaulting for the host and target type. # The inputs are: # configure --host=HOST --target=TARGET --build=BUILD NONOPT # # The rules are: # 1. You are not allowed to specify --host, --target, and nonopt at the # same time. # 2. Host defaults to nonopt. # 3. If nonopt is not specified, then host defaults to the current host, # as determined by config.guess. # 4. Target and build default to nonopt. # 5. If nonopt is not specified, then target and build default to host. # The aliases save the names the user supplied, while $host etc. # will get canonicalized. case $host---$target---$nonopt in NONE---*---* | *---NONE---* | *---*---NONE) ;; *) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;; esac # Make sure we can run config.sub. if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then : else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } fi echo $ac_n "checking host system type""... $ac_c" 1>&6 echo "configure:705: checking host system type" >&5 host_alias=$host case "$host_alias" in NONE) case $nonopt in NONE) if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then : else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } fi ;; *) host_alias=$nonopt ;; esac ;; esac host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias` host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` echo "$ac_t""$host" 1>&6 echo $ac_n "checking target system type""... $ac_c" 1>&6 echo "configure:726: checking target system type" >&5 target_alias=$target case "$target_alias" in NONE) case $nonopt in NONE) target_alias=$host_alias ;; *) target_alias=$nonopt ;; esac ;; esac target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias` target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` echo "$ac_t""$target" 1>&6 echo $ac_n "checking build system type""... $ac_c" 1>&6 echo "configure:744: checking build system type" >&5 build_alias=$build case "$build_alias" in NONE) case $nonopt in NONE) build_alias=$host_alias ;; *) build_alias=$nonopt ;; esac ;; esac build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias` build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` echo "$ac_t""$build" 1>&6 test "$host_alias" != "$target_alias" && test "$program_prefix$program_suffix$program_transform_name" = \ NONENONEs,x,x, && program_prefix=${target_alias}- if test "x$prefix" = xNONE; then echo $ac_n "checking for prefix by $ac_c" 1>&6 # Extract the first word of "wish", so it can be a program name with args. set dummy wish; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:771: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_WISH'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else case "$WISH" in /*) ac_cv_path_WISH="$WISH" # Let the user override the test with a path. ;; ?:/*) ac_cv_path_WISH="$WISH" # Let the user override the test with a dos path. ;; *) IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_path_WISH="$ac_dir/$ac_word" break fi done IFS="$ac_save_ifs" ;; esac fi WISH="$ac_cv_path_WISH" if test -n "$WISH"; then echo "$ac_t""$WISH" 1>&6 else echo "$ac_t""no" 1>&6 fi if test -n "$ac_cv_path_WISH"; then prefix=`echo $ac_cv_path_WISH|sed 's%/[^/][^/]*//*[^/][^/]*$%%'` fi fi # ----------------------------------------------------------------------- # # Set a variable containing current working directory if /bin/sh # doesn't do it already. # # ----------------------------------------------------------------------- PWD=`pwd` # ----------------------------------------------------------------------- # # C compiler and debugging flags # # ----------------------------------------------------------------------- BLT_ENV_CC=$CC # # CC search order # # 1. command line (--with-cc) # 2. environment variable ($CC) # 3. cached variable ($blt_cv_prog_cc) # 4. check for program (AC_PROG_CC) # 4. default to cc # echo $ac_n "checking which C compiler""... $ac_c" 1>&6 echo "configure:837: checking which C compiler" >&5 if test "x${blt_with_cc}" != "x" ; then CC=${blt_with_cc} unset ac_cv_prog_CPP unset ac_cv_prog_CC elif test "x${BLT_ENV_CC}" != "x" ; then unset ac_cv_prog_CPP unset ac_cv_prog_CC elif test "x${blt_cv_prog_cc}" != "x" ; then CC=${blt_cv_prog_cc} unset ac_cv_prog_CC else # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:852: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_CC="gcc" break fi done IFS="$ac_save_ifs" fi fi CC="$ac_cv_prog_CC" if test -n "$CC"; then echo "$ac_t""$CC" 1>&6 else echo "$ac_t""no" 1>&6 fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:882: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_prog_rejected=no ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" break fi done IFS="$ac_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 $# -gt 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 set dummy "$ac_dir/$ac_word" "$@" shift ac_cv_prog_CC="$@" fi fi fi fi CC="$ac_cv_prog_CC" if test -n "$CC"; then echo "$ac_t""$CC" 1>&6 else echo "$ac_t""no" 1>&6 fi if test -z "$CC"; then case "`uname -s`" in *win32* | *WIN32*) # Extract the first word of "cl", so it can be a program name with args. set dummy cl; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:933: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_CC="cl" break fi done IFS="$ac_save_ifs" fi fi CC="$ac_cv_prog_CC" if test -n "$CC"; then echo "$ac_t""$CC" 1>&6 else echo "$ac_t""no" 1>&6 fi ;; esac fi test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 echo "configure:965: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross cat > conftest.$ac_ext << EOF #line 976 "configure" #include "confdefs.h" main(){return(0);} EOF if { (eval echo configure:981: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then ac_cv_prog_cc_works=yes # If we can't run a trivial program, we are probably using a cross compiler. if (./conftest; exit) 2>/dev/null; then ac_cv_prog_cc_cross=no else ac_cv_prog_cc_cross=yes fi else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 ac_cv_prog_cc_works=no fi rm -fr conftest* ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 if test $ac_cv_prog_cc_works = no; then { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 echo "configure:1007: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 cross_compiling=$ac_cv_prog_cc_cross echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 echo "configure:1012: checking whether we are using GNU C" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no fi fi echo "$ac_t""$ac_cv_prog_gcc" 1>&6 if test $ac_cv_prog_gcc = yes; then GCC=yes else GCC= fi ac_test_CFLAGS="${CFLAGS+set}" ac_save_CFLAGS="$CFLAGS" CFLAGS= echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 echo "configure:1040: checking whether ${CC-cc} accepts -g" >&5 if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else echo 'void f(){}' > conftest.c if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then ac_cv_prog_cc_g=yes else ac_cv_prog_cc_g=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_prog_cc_g" 1>&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 fi if test "x${CC}" = "x" ; then CC=cc fi case $target in *-*-cygwin*|*-*-mingw*) if test "${blt_enable_cygwin}" = "no" ; then CC="${CC} -mno-cygwin" fi ;; esac echo "$ac_t""$CC" 1>&6 unset blt_cv_prog_cc if eval "test \"`echo '$''{'blt_cv_prog_cc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else blt_cv_prog_cc=$CC fi echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 echo "configure:1095: checking how to run the C preprocessor" >&5 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else # This must be in double quotes, not single quotes, because CPP may get # substituted into the Makefile and "${CC-cc}" will confuse make. CPP="${CC-cc} -E" # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1116: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1133: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* CPP="${CC-cc} -nologo -E" cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1150: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* CPP=/lib/cpp fi rm -f conftest* fi rm -f conftest* fi rm -f conftest* ac_cv_prog_CPP="$CPP" fi CPP="$ac_cv_prog_CPP" else ac_cv_prog_CPP="$CPP" fi echo "$ac_t""$CPP" 1>&6 if test "x${GCC}" != "x" ; then blt_have_gcc="yes" else echo $ac_n "checking if C compiler is really gcc""... $ac_c" 1>&6 echo "configure:1178: checking if C compiler is really gcc" >&5 cat > conftest.$ac_ext <&5 | egrep "_cc_is_gcc_" >/dev/null 2>&1; then rm -rf conftest* blt_have_gcc=yes else rm -rf conftest* blt_have_gcc=no fi rm -f conftest* echo "$ac_t""$blt_have_gcc" 1>&6 fi # # CFLAGS search order # # 1. command line (--with-cflags) # 2. cached variable ($blt_cv_prog_cflags) # 3. set to "-O6" if using gcc ($blt_have_gcc) # 4. otherwise, default to "-O" # echo $ac_n "checking default compiler flags""... $ac_c" 1>&6 echo "configure:1210: checking default compiler flags" >&5 if test "x${blt_with_cflags}" != "x" ; then CFLAGS=${blt_with_cflags} elif test "x${blt_cv_prog_cflags}" != "x" ; then CFLAGS=${blt_cv_prog_cflags} elif test "${blt_have_gcc}" = "yes" ; then CFLAGS=-O6 else CFLAGS=-O fi echo "$ac_t""$CFLAGS" 1>&6 unset blt_cv_prog_cflags if eval "test \"`echo '$''{'blt_cv_prog_cflags'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else blt_cv_prog_cflags=$CFLAGS fi GCCFLAGS="" if test "${blt_have_gcc}" = "yes" ; then GCCFLAGS="-Wall" if test "${CFLAGS}" = "-g" ; then GCCFLAGS="-Wshadow -Winline -Wpointer-arith ${GCCFLAGS}" fi fi echo $ac_n "checking for Cygwin environment""... $ac_c" 1>&6 echo "configure:1240: checking for Cygwin environment" >&5 if eval "test \"`echo '$''{'ac_cv_cygwin'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_cygwin=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_cygwin=no fi rm -f conftest* rm -f conftest* fi echo "$ac_t""$ac_cv_cygwin" 1>&6 CYGWIN= test "$ac_cv_cygwin" = yes && CYGWIN=yes blt_lib_prefix="lib" case $target in *-*-cygwin*|*-*-mingw*) blt_platform="win" if test "$ac_cv_cygwin" = "yes" ; then blt_lib_prefix="cyg" else blt_lib_prefix="" fi ;; *-*-macosx) blt_platform="macosx" ;; *) blt_platform="unix" ;; esac # ----------------------------------------------------------------------- # # Programs: Check for existence of ranlib and install programs # # ----------------------------------------------------------------------- for ac_prog in mawk gawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:1302: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_AWK="$ac_prog" break fi done IFS="$ac_save_ifs" fi fi AWK="$ac_cv_prog_AWK" if test -n "$AWK"; then echo "$ac_t""$AWK" 1>&6 else echo "$ac_t""no" 1>&6 fi test -n "$AWK" && break done # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 echo "configure:1343: checking for a BSD compatible install" >&5 if test -z "$INSTALL"; then if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" for ac_dir in $PATH; do # Account for people who put trailing slashes in PATH elements. case "$ac_dir/" in /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do if test -f $ac_dir/$ac_prog; then if test $ac_prog = install && grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : else ac_cv_path_install="$ac_dir/$ac_prog -c" break 2 fi fi done ;; esac done IFS="$ac_save_IFS" fi if test "${ac_cv_path_install+set}" = set; then INSTALL="$ac_cv_path_install" else # As a last resort, use the slow shell script. We don't cache a # path for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the path is relative. INSTALL="$ac_install_sh" fi fi echo "$ac_t""$INSTALL" 1>&6 # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:1398: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_RANLIB="ranlib" break fi done IFS="$ac_save_ifs" test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" fi fi RANLIB="$ac_cv_prog_RANLIB" if test -n "$RANLIB"; then echo "$ac_t""$RANLIB" 1>&6 else echo "$ac_t""no" 1>&6 fi echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6 echo "configure:1426: checking whether ln -s works" >&5 if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else rm -f conftestdata if ln -s X conftestdata 2>/dev/null then rm -f conftestdata ac_cv_prog_LN_S="ln -s" else ac_cv_prog_LN_S=ln fi fi LN_S="$ac_cv_prog_LN_S" if test "$ac_cv_prog_LN_S" = "ln -s"; then echo "$ac_t""yes" 1>&6 else echo "$ac_t""no" 1>&6 fi # ----------------------------------------------------------------------- # # Libraries: Check for libraries used # # ----------------------------------------------------------------------- echo $ac_n "checking for main in -lsocket""... $ac_c" 1>&6 echo "configure:1453: checking for main in -lsocket" >&5 ac_lib_var=`echo socket'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lsocket $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_lib=HAVE_LIB`echo socket | sed -e 's/[^a-zA-Z0-9_]/_/g' \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` cat >> confdefs.h <&6 fi echo $ac_n "checking for main in -lnsl""... $ac_c" 1>&6 echo "configure:1496: checking for main in -lnsl" >&5 ac_lib_var=`echo nsl'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lnsl $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_lib=HAVE_LIB`echo nsl | sed -e 's/[^a-zA-Z0-9_]/_/g' \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` cat >> confdefs.h <&6 fi echo $ac_n "checking for main in -lm""... $ac_c" 1>&6 echo "configure:1539: checking for main in -lm" >&5 ac_lib_var=`echo m'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lm $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_lib=HAVE_LIB`echo m | sed -e 's/[^a-zA-Z0-9_]/_/g' \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` cat >> confdefs.h <&6 fi # ----------------------------------------------------------------------- # # Headers: Check for header files used # # ----------------------------------------------------------------------- echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 echo "configure:1588: checking for ANSI C header files" >&5 if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include #include #include EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1601: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* ac_cv_header_stdc=yes else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_header_stdc=no fi rm -f conftest* if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat > conftest.$ac_ext < EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "memchr" >/dev/null 2>&1; then : else rm -rf conftest* ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat > conftest.$ac_ext < EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "free" >/dev/null 2>&1; then : else rm -rf conftest* ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : else cat > conftest.$ac_ext < #define ISLOWER(c) ('a' <= (c) && (c) <= 'z') #define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); exit (0); } EOF if { (eval echo configure:1668: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then : else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* ac_cv_header_stdc=no fi rm -fr conftest* fi fi fi echo "$ac_t""$ac_cv_header_stdc" 1>&6 if test $ac_cv_header_stdc = yes; then cat >> confdefs.h <<\EOF #define STDC_HEADERS 1 EOF fi echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6 echo "configure:1692: checking for sys/wait.h that is POSIX.1 compatible" >&5 if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include #ifndef WEXITSTATUS #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) #endif #ifndef WIFEXITED #define WIFEXITED(stat_val) (((stat_val) & 255) == 0) #endif int main() { int s; wait (&s); s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; ; return 0; } EOF if { (eval echo configure:1713: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_header_sys_wait_h=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_header_sys_wait_h=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&6 if test $ac_cv_header_sys_wait_h = yes; then cat >> confdefs.h <<\EOF #define HAVE_SYS_WAIT_H 1 EOF fi echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 echo "configure:1734: checking whether time.h and sys/time.h may both be included" >&5 if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include #include int main() { struct tm *tp; ; return 0; } EOF if { (eval echo configure:1748: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_header_time=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_header_time=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_header_time" 1>&6 if test $ac_cv_header_time = yes; then cat >> confdefs.h <<\EOF #define TIME_WITH_SYS_TIME 1 EOF fi for ac_hdr in inttypes.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo "configure:1773: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1783: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` cat >> confdefs.h <&6 fi done if test "${ac_cv_header_inttypes_h}" = "yes" ; then HAVE_INTTYPES_H=1 else HAVE_INTTYPES_H=0 fi for ac_hdr in limits.h sys/param.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo "configure:1820: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1830: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` cat >> confdefs.h <&6 fi done for ac_hdr in string.h ctype.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo "configure:1860: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1870: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` cat >> confdefs.h <&6 fi done for ac_hdr in errno.h float.h math.h ieeefp.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo "configure:1900: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1910: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` cat >> confdefs.h <&6 fi done for ac_hdr in sys/time.h waitflags.h sys/wait.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo "configure:1940: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1950: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` cat >> confdefs.h <&6 fi done for ac_hdr in malloc.h memory.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo "configure:1980: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1990: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` cat >> confdefs.h <&6 fi done for ac_hdr in setjmp.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo "configure:2020: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:2030: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` cat >> confdefs.h <&6 fi done if test "${blt_enable_jpeg}" != "no" ; then jpeg_save_CPPFLAGS=${CPPFLAGS} CPPFLAGS="" if test "${blt_enable_jpeg}" != "yes" ; then CPPFLAGS="-I${blt_enable_jpeg}/include" fi for ac_hdr in jpeglib.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo "configure:2067: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:2077: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` cat >> confdefs.h <&6 JPEG_INC_SPEC="" fi done CPPFLAGS=${jpeg_save_CPPFLAGS} fi # Run this check after jpeglib.h because jpeglib.h sets HAVE_STDLIB_H for ac_hdr in stdlib.h unistd.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo "configure:2112: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:2122: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` cat >> confdefs.h <&6 fi done # ----------------------------------------------------------------------- # # Types: Check for existence of types of size_t and pid_t # # ----------------------------------------------------------------------- echo $ac_n "checking for size_t""... $ac_c" 1>&6 echo "configure:2155: checking for size_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS #include #include #endif EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then rm -rf conftest* ac_cv_type_size_t=yes else rm -rf conftest* ac_cv_type_size_t=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_type_size_t" 1>&6 if test $ac_cv_type_size_t = no; then cat >> confdefs.h <<\EOF #define size_t unsigned EOF fi echo $ac_n "checking for pid_t""... $ac_c" 1>&6 echo "configure:2188: checking for pid_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS #include #include #endif EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "(^|[^a-zA-Z_0-9])pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then rm -rf conftest* ac_cv_type_pid_t=yes else rm -rf conftest* ac_cv_type_pid_t=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_type_pid_t" 1>&6 if test $ac_cv_type_pid_t = no; then cat >> confdefs.h <<\EOF #define pid_t int EOF fi echo $ac_n "checking whether union wait is defined correctly""... $ac_c" 1>&6 echo "configure:2222: checking whether union wait is defined correctly" >&5 if eval "test \"`echo '$''{'blt_cv_struct_wait_works'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include int main() { /* * Check whether defines the type "union wait" * correctly. It's needed because of weirdness in HP-UX where * "union wait" is defined in both the BSD and SYS-V environments. * Checking the usability of WIFEXITED seems to do the trick. */ union wait x; WIFEXITED(x); /* Generates compiler error if WIFEXITED * uses an int. */ ; return 0; } EOF if { (eval echo configure:2245: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* blt_cv_struct_wait_works="yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* blt_cv_struct_wait_works="no" fi rm -f conftest* fi if test "${blt_cv_struct_wait_works}" = "yes"; then cat >> confdefs.h <<\EOF #define HAVE_UNION_WAIT 1 EOF fi echo "$ac_t""$blt_cv_struct_wait_works" 1>&6 # ----------------------------------------------------------------------- # # Compiler characteristics: # Check for existence of types of size_t and pid_t # # ----------------------------------------------------------------------- echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6 echo "configure:2274: checking whether byte ordering is bigendian" >&5 if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_cv_c_bigendian=unknown # See if sys/param.h defines the BYTE_ORDER macro. cat > conftest.$ac_ext < #include int main() { #if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN bogus endian macros #endif ; return 0; } EOF if { (eval echo configure:2292: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* # It does; now see whether it defined to BIG_ENDIAN or not. cat > conftest.$ac_ext < #include int main() { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } EOF if { (eval echo configure:2307: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_bigendian=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_c_bigendian=no fi rm -f conftest* else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -f conftest* if test $ac_cv_c_bigendian = unknown; then if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_c_bigendian=no else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* ac_cv_c_bigendian=yes fi rm -fr conftest* fi fi fi echo "$ac_t""$ac_cv_c_bigendian" 1>&6 if test $ac_cv_c_bigendian = yes; then cat >> confdefs.h <<\EOF #define WORDS_BIGENDIAN 1 EOF fi echo $ac_n "checking size of int""... $ac_c" 1>&6 echo "configure:2364: checking size of int" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_int'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < main() { FILE *f=fopen("conftestval", "w"); if (!f) exit(1); fprintf(f, "%d\n", sizeof(int)); exit(0); } EOF if { (eval echo configure:2383: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_sizeof_int=`cat conftestval` else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* ac_cv_sizeof_int=0 fi rm -fr conftest* fi fi echo "$ac_t""$ac_cv_sizeof_int" 1>&6 cat >> confdefs.h <&6 echo "configure:2403: checking size of long" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_long'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < main() { FILE *f=fopen("conftestval", "w"); if (!f) exit(1); fprintf(f, "%d\n", sizeof(long)); exit(0); } EOF if { (eval echo configure:2422: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_sizeof_long=`cat conftestval` else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* ac_cv_sizeof_long=0 fi rm -fr conftest* fi fi echo "$ac_t""$ac_cv_sizeof_long" 1>&6 cat >> confdefs.h <&6 echo "configure:2442: checking size of long long" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_long_long'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < main() { FILE *f=fopen("conftestval", "w"); if (!f) exit(1); fprintf(f, "%d\n", sizeof(long long)); exit(0); } EOF if { (eval echo configure:2461: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_sizeof_long_long=`cat conftestval` else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* ac_cv_sizeof_long_long=0 fi rm -fr conftest* fi fi echo "$ac_t""$ac_cv_sizeof_long_long" 1>&6 cat >> confdefs.h <&6 echo "configure:2481: checking size of void *" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_void_p'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < main() { FILE *f=fopen("conftestval", "w"); if (!f) exit(1); fprintf(f, "%d\n", sizeof(void *)); exit(0); } EOF if { (eval echo configure:2500: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_sizeof_void_p=`cat conftestval` else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* ac_cv_sizeof_void_p=0 fi rm -fr conftest* fi fi echo "$ac_t""$ac_cv_sizeof_void_p" 1>&6 cat >> confdefs.h <&6 echo "configure:2538: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else $ac_func(); #endif ; return 0; } EOF if { (eval echo configure:2566: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_$ac_func=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` cat >> confdefs.h <&6 fi done # For HPUX it's a little more complicated to search for isfinite echo $ac_n "checking for isfinite""... $ac_c" 1>&6 echo "configure:2593: checking for isfinite" >&5 if eval "test \"`echo '$''{'blt_cv_have_isfinite'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { double x = 1.0; if (isfinite(x)) { return 0; } ; return 0; } EOF if { (eval echo configure:2610: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* blt_cv_have_isfinite="yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* blt_cv_have_isfinite="no" fi rm -f conftest* fi if test "${blt_cv_have_isfinite}" = "yes"; then cat >> confdefs.h <<\EOF #define HAVE_ISFINITE 1 EOF fi echo "$ac_t""$blt_cv_have_isfinite" 1>&6 # ----------------------------------------------------------------------- # # Check the smallest value such that 1.0 + x != 1.0. # For ANSI compilers this is DBL_EPSILON in float.h # #-------------------------------------------------------------------- echo $ac_n "checking whether DBL_EPSILON is defined in float.h""... $ac_c" 1>&6 echo "configure:2639: checking whether DBL_EPSILON is defined in float.h" >&5 if eval "test \"`echo '$''{'blt_cv_found_dbl_epsilon'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #endif #ifdef DBL_EPSILON yes #endif EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "yes" >/dev/null 2>&1; then rm -rf conftest* blt_cv_found_dbl_epsilon=yes else rm -rf conftest* blt_cv_found_dbl_epsilon=no fi rm -f conftest* fi echo "$ac_t""${blt_cv_found_dbl_epsilon}" 1>&6 if test "${blt_cv_found_dbl_epsilon}" = "no" ; then if eval "test \"`echo '$''{'blt_cv_dbl_epsilon'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else old_flags="$CFLAGS" CFLAGS="-g -lm" echo $ac_n "checking whether DBL_EPSILON can be computed""... $ac_c" 1>&6 echo "configure:2677: checking whether DBL_EPSILON can be computed" >&5 if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < ./conftest.stdout; exit) 2>/dev/null; then blt_cv_dbl_epsilon=`cat ./conftest.stdout` else blt_cv_dbl_epsilon="" fi fi rm -fr conftest* CFLAGS="$old_flags" cat >> confdefs.h <&6 fi fi echo $ac_n "checking whether declaration is needed for strdup""... $ac_c" 1>&6 echo "configure:2724: checking whether declaration is needed for strdup" >&5 if eval "test \"`echo '$''{'blt_cv_nedd_decl_strdup'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "strdup" >/dev/null 2>&1; then rm -rf conftest* blt_cv_need_decl_strdup=no else rm -rf conftest* blt_cv_need_decl_strdup=yes fi rm -f conftest* fi if test "${blt_cv_need_decl_strdup}" = "yes"; then cat >> confdefs.h <<\EOF #define NEED_DECL_STRDUP 1 EOF fi echo "$ac_t""$blt_cv_need_decl_strdup" 1>&6 echo $ac_n "checking whether declaration is needed for drand48""... $ac_c" 1>&6 echo "configure:2765: checking whether declaration is needed for drand48" >&5 if eval "test \"`echo '$''{'blt_cv_need_decl_drand48'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #endif #ifdef HAVE_MATH_H #include #endif #ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "drand48" >/dev/null 2>&1; then rm -rf conftest* blt_cv_need_decl_drand48=no else rm -rf conftest* blt_cv_need_decl_drand48=yes fi rm -f conftest* fi if test "${blt_cv_need_decl_drand48}" = "yes"; then cat >> confdefs.h <<\EOF #define NEED_DECL_DRAND48 1 EOF fi echo "$ac_t""$blt_cv_need_decl_drand48" 1>&6 echo $ac_n "checking whether declaration is needed for srand48""... $ac_c" 1>&6 echo "configure:2806: checking whether declaration is needed for srand48" >&5 if eval "test \"`echo '$''{'blt_cv_need_decl_srand48'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #endif #ifdef HAVE_MATH_H #include #endif #ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "srand48" >/dev/null 2>&1; then rm -rf conftest* blt_cv_need_decl_srand48=no else rm -rf conftest* blt_cv_need_decl_srand48=yes fi rm -f conftest* fi if test "${blt_cv_need_decl_srand48}" = "yes"; then cat >> confdefs.h <<\EOF #define NEED_DECL_SRAND48 1 EOF fi echo "$ac_t""$blt_cv_need_decl_srand48" 1>&6 echo $ac_n "checking whether declaration is needed for j1""... $ac_c" 1>&6 echo "configure:2847: checking whether declaration is needed for j1" >&5 if eval "test \"`echo '$''{'blt_cv_need_decl_j1'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #endif #ifdef HAVE_MATH_H #include #endif #ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "j1" >/dev/null 2>&1; then rm -rf conftest* blt_cv_need_decl_j1=no else rm -rf conftest* blt_cv_need_decl_j1=yes fi rm -f conftest* fi if test "${blt_cv_need_decl_j1}" = "yes"; then cat >> confdefs.h <<\EOF #define NEED_DECL_J1 1 EOF fi echo "$ac_t""$blt_cv_need_decl_j1" 1>&6 # ----------------------------------------------------------------------- # # System services: X, Tcl, Tk # # ----------------------------------------------------------------------- # If we find X, set shell vars x_includes and x_libraries to the # paths, otherwise set no_x=yes. # Uses ac_ vars as temps to allow command line to override cache and checks. # --without-x overrides everything else, but does not touch the cache. echo $ac_n "checking for X""... $ac_c" 1>&6 echo "configure:2897: checking for X" >&5 # Check whether --with-x or --without-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 if test "x$x_includes" != xNONE && test "x$x_libraries" != xNONE; then # Both variables are already set. have_x=yes else if eval "test \"`echo '$''{'ac_cv_have_x'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&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 -fr conftestdir if mkdir conftestdir; then cd conftestdir # Make sure to not put "make" in the Imakefile rules, since we grep it out. cat > Imakefile <<'EOF' acfindx: @echo 'ac_im_incroot="${INCROOT}"; ac_im_usrlibdir="${USRLIBDIR}"; ac_im_libdir="${LIBDIR}"' EOF if (xmkmf) >/dev/null 2>/dev/null && test -f Makefile; then # GNU make sometimes prints "make[1]: Entering...", which would confuse us. eval `${MAKE-make} acfindx 2>/dev/null | grep -v make` # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. for ac_extension in a so sl; 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) ;; *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes="$ac_im_incroot" ;; esac case "$ac_im_usrlibdir" in /usr/lib | /lib) ;; *) test -d "$ac_im_usrlibdir" && ac_x_libraries="$ac_im_usrlibdir" ;; esac fi cd .. rm -fr conftestdir fi if test "$ac_x_includes" = NO; then # Guess where to find include files, by looking for this one X11 .h file. test -z "$x_direct_test_include" && x_direct_test_include=X11/Intrinsic.h # First, try using that file with no special directory specified. cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:2964: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* # We can compile using X headers with no special include directory. ac_x_includes= else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* # Look for the header file in a standard set of common directories. # Check X11 before X11Rn because it is often a symlink to the current release. for ac_dir in \ /usr/X11/include \ /usr/X11R6/include \ /usr/X11R5/include \ /usr/X11R4/include \ \ /usr/include/X11 \ /usr/include/X11R6 \ /usr/include/X11R5 \ /usr/include/X11R4 \ \ /usr/local/X11/include \ /usr/local/X11R6/include \ /usr/local/X11R5/include \ /usr/local/X11R4/include \ \ /usr/local/include/X11 \ /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 \ ; \ do if test -r "$ac_dir/$x_direct_test_include"; then ac_x_includes=$ac_dir break fi done fi rm -f conftest* fi # $ac_x_includes = NO if test "$ac_x_libraries" = NO; then # Check for the libraries. test -z "$x_direct_test_library" && x_direct_test_library=Xt test -z "$x_direct_test_function" && x_direct_test_function=XtMalloc # See if we find them without any special options. # Don't add to $LIBS permanently. ac_save_LIBS="$LIBS" LIBS="-l$x_direct_test_library $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* LIBS="$ac_save_LIBS" # We can link X programs with no special library path. ac_x_libraries= else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* LIBS="$ac_save_LIBS" # First see if replacing the include by lib works. # Check X11 before X11Rn because it is often a symlink to the current release. for ac_dir in `echo "$ac_x_includes" | sed s/include/lib/` \ /usr/X11/lib \ /usr/X11R6/lib \ /usr/X11R5/lib \ /usr/X11R4/lib \ \ /usr/lib/X11 \ /usr/lib/X11R6 \ /usr/lib/X11R5 \ /usr/lib/X11R4 \ \ /usr/local/X11/lib \ /usr/local/X11R6/lib \ /usr/local/X11R5/lib \ /usr/local/X11R4/lib \ \ /usr/local/lib/X11 \ /usr/local/lib/X11R6 \ /usr/local/lib/X11R5 \ /usr/local/lib/X11R4 \ \ /usr/X386/lib \ /usr/x386/lib \ /usr/XFree86/lib/X11 \ \ /usr/lib \ /usr/local/lib \ /usr/unsupported/lib \ /usr/athena/lib \ /usr/local/x11r5/lib \ /usr/lpp/Xamples/lib \ /lib/usr/lib/X11 \ \ /usr/openwin/lib \ /usr/openwin/share/lib \ ; \ do for ac_extension in a so sl; do if test -r $ac_dir/lib${x_direct_test_library}.$ac_extension; then ac_x_libraries=$ac_dir break 2 fi done done fi rm -f conftest* fi # $ac_x_libraries = NO if test "$ac_x_includes" = NO || test "$ac_x_libraries" = NO; then # Didn't find X anywhere. Cache the known absence of X. ac_cv_have_x="have_x=no" else # 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" fi fi fi eval "$ac_cv_have_x" fi # $with_x != no if test "$have_x" != yes; then echo "$ac_t""$have_x" 1>&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" echo "$ac_t""libraries $x_libraries, headers $x_includes" 1>&6 fi # ----------------------------------------------------------------------- # # Find the Tcl build configuration file "tclConfig.sh" # # ----------------------------------------------------------------------- echo $ac_n "checking for tclConfig.sh""... $ac_c" 1>&6 echo "configure:3134: checking for tclConfig.sh" >&5 tcl_config_sh="" if test "x$blt_with_tcl" != "x" ; then # Verify that a tclConfig.sh file exists in the directory specified # by --with-tcl. for dir in \ $blt_with_tcl do if test -r "$dir/tclConfig.sh" ; then tcl_config_sh="$dir/tclConfig.sh" break elif test -r "$dir/lib/tclConfig.sh" ; then tcl_config_sh="$dir/lib/tclConfig.sh" break elif test -r "$dir/$blt_platform/tclConfig.sh" ; then tcl_config_sh="$dir/$blt_platform/tclConfig.sh" break fi done else # Otherwise, search for Tcl configuration file. # 1. Search previously named locations. for dir in \ $prefix \ $exec_prefix \ $blt_cv_tcl_lib do if test -r "$dir/tclConfig.sh" ; then tcl_config_sh="$dir/tclConfig.sh" break elif test -r "$dir/lib/tclConfig.sh" ; then tcl_config_sh="$dir/lib/tclConfig.sh" break elif test -r "$dir/$blt_platform/tclConfig.sh" ; then tcl_config_sh="$dir/$blt_platform/tclConfig.sh" break fi done # 2. Search source directories. if test "x$tcl_config_sh" = "x" ; then for dir in \ `ls -dr ../tcl[7-9].[0-9]* 2>/dev/null` \ ../tcl \ `ls -dr ../../tcl[7-9].[0-9]* 2>/dev/null` \ ../../tcl \ `ls -dr ../../../tcl[7-9].[0-9]* 2>/dev/null` \ ../../../tcl do if test -r "$dir/$blt_platform/tclConfig.sh" ; then tcl_config_sh="$dir/$blt_platform/tclConfig.sh" break fi done fi # 3. Search standard locations. if test "x$tcl_config_sh" = "x" ; then for dir in \ `ls -dr /usr/local/tcl/tcl[7-9].[0-9]* 2>/dev/null` \ /usr/local/tcl \ /usr/local \ /usr do if test -r "$dir/tclConfig.sh" ; then tcl_config_sh="$dir/tclConfig.sh" break elif test -r "$dir/lib/tclConfig.sh" ; then tcl_config_sh="$dir/lib/tclConfig.sh" break fi done fi fi echo "$ac_t""${tcl_config_sh}" 1>&6 if test "x$tcl_config_sh" = "x" ; then echo "can't find Tcl configuration script \"tclConfig.sh\"" exit 1 fi # ----------------------------------------------------------------------- # # Find the Tk build configuration file "tkConfig.sh" # # ----------------------------------------------------------------------- echo $ac_n "checking for tkConfig.sh""... $ac_c" 1>&6 echo "configure:3230: checking for tkConfig.sh" >&5 tk_config_sh="" if test "x$blt_with_tk" != "x" -o "x$blt_with_tcl" != "x"; then # Verify that a tkConfig.sh file exists in the directory specified # by --with-tcl or --with-tk. for dir in \ $blt_with_tk \ $blt_with_tcl do if test -r "$dir/tkConfig.sh" ; then tk_config_sh="$dir/tkConfig.sh" break elif test -r "$dir/lib/tkConfig.sh" ; then tk_config_sh="$dir/lib/tkConfig.sh" break elif test -r "$dir/$blt_platform/tkConfig.sh" ; then tk_config_sh="$dir/$blt_platform/tkConfig.sh" break fi done else # Search for Tk configuration file. # 1. Search previously named locations. for dir in \ $prefix \ $exec_prefix \ $blt_cv_tk_lib \ $blt_cv_tcl_lib do if test -r "$dir/tkConfig.sh" ; then tk_config_sh="$dir/tkConfig.sh" break elif test -r "$dir/lib/tkConfig.sh" ; then tk_config_sh="$dir/lib/tkConfig.sh" break elif test -r "$dir/$blt_platform/tkConfig.sh" ; then tk_config_sh="$dir/$blt_platform/tkConfig.sh" break fi done # 2. Search source directories. if test "x$tk_config_sh" = "x" ; then for dir in \ ../tcl \ `ls -dr ../tk[4-9].[0-9]* 2>/dev/null` \ ../../tcl \ `ls -dr ../../tk[4-9].[0-9]* 2>/dev/null` \ ../../../tcl \ `ls -dr ../../../tk[4-9].[0-9]* 2>/dev/null` do if test -r "$dir/$blt_platform/tkConfig.sh"; then tk_config_sh="$dir/$blt_platform/tkConfig.sh" break fi done fi # 3. Search standard locations. if test "x$tk_config_sh" = "x" ; then for dir in \ `ls -dr /usr/local/tcl/tcl[7-9].[0-9]* 2>/dev/null` \ /usr/local/tcl \ /usr/local \ ${x_libraries} \ /usr do if test -r "$dir/tkConfig.sh" ; then tk_config_sh="$dir/tkConfig.sh" break elif test -r "$dir/lib/tkConfig.sh" ; then tk_config_sh="$dir/lib/tkConfig.sh" break fi done fi fi echo "$ac_t""${tk_config_sh}" 1>&6 if test "x$tk_config_sh" = "x" ; then echo "can't find Tk configuration script \"tkConfig.sh\"" exit 1 fi # ----------------------------------------------------------------------- # # Source in the Tcl/Tk configuration scripts. # # ----------------------------------------------------------------------- . $tcl_config_sh . $tk_config_sh TCL_INC_DIR="" TK_INC_DIR="" if test "x${blt_with_tcl_includes}" != "x" ; then if test -r "${blt_with_tcl_includes}/tcl.h" ; then TCL_INC_DIR=${blt_with_tcl_includes} else echo "Can't find tcl.h in \"${blt_with_tcl_includes}\"" exit 1 fi else for dir in \ ${TCL_PREFIX}/include/tcl${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION} \ ${TCL_PREFIX}/include \ ${TCL_SRC_DIR}/generic do if test -r "$dir/tcl.h" ; then TCL_INC_DIR=$dir break fi done if test "x${TCL_INC_DIR}" = "x" ; then echo "Can't find tcl.h header file" exit 1 fi fi if test "x${blt_with_tk_includes}" != "x" ; then if test -r "${blt_with_tk_includes}/tk.h" ; then TK_INC_DIR=${blt_with_tk_includes} else echo "Can't find tk.h in \"${blt_with_tk_includes}\"" exit 1 fi else for dir in \ ${TK_PREFIX}/include/tk${TK_MAJOR_VERSION}.${TK_MINOR_VERSION} \ ${TK_PREFIX}/include \ ${TK_SRC_DIR}/generic \ ${TCL_INC_DIR} do if test -r "$dir/tk.h" ; then TK_INC_DIR=$dir break fi done if test "x${TK_INC_DIR}" = "x" ; then echo "Can't find tk.h header file" exit 1 fi fi case $target in *-sunos4*|*-*-netbsd|NetBSD-*|FreeBSD-*|OpenBSD-*|*-*-cygwin*|*-*-mingw*) TCL_LIB_NAME="tcl${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}" TK_LIB_NAME="tk${TK_MAJOR_VERSION}${TK_MINOR_VERSION}" ;; *) TCL_LIB_NAME="tcl${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}" TK_LIB_NAME="tk${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}" ;; esac TCL_LIB_SPEC="-l${TCL_LIB_NAME}" TK_LIB_SPEC="-l${TK_LIB_NAME}" case $target in *-hpux*) SHLIB_SUFFIX="sl" ;; *) SHLIB_SUFFIX="so" ;; esac TCL_LIB_DIR="${TCL_SRC_DIR}/$blt_platform" TK_LIB_DIR="${TK_SRC_DIR}/$blt_platform" if test "x${blt_with_tcl_libraries}" != "x" ; then for libname in \ "${blt_with_tcl_libraries}/lib${TCL_LIB_NAME}.${SHLIB_SUFFIX}" \ "${blt_with_tcl_libraries}/lib${TCL_LIB_NAME}.a" do if test -r "$libname" ; then TCL_LIB_DIR="${blt_with_tcl_libraries}" break fi done if test "x${TCL_LIB_DIR}" = "x" ; then echo "Can't find tcl library in \"${blt_with_tcl_libraries}\"" exit 1 fi else for libname in \ "${TCL_EXEC_PREFIX}/lib/lib${TCL_LIB_NAME}.${SHLIB_SUFFIX}" \ "${TCL_EXEC_PREFIX}/lib/lib${TCL_LIB_NAME}.a" do if test -r "$libname" ; then TCL_LIB_DIR="${TCL_EXEC_PREFIX}/lib" break fi done if test "x${TCL_LIB_DIR}" = "x" ; then echo "Can't find tcl library" exit 1 fi fi if test "x${blt_with_tk_libraries}" != "x" ; then for libname in \ "${blt_with_tk_libraries}/lib${TK_LIB_NAME}.${SHLIB_SUFFIX}" \ "${blt_with_tk_libraries}/lib${TK_LIB_NAME}.a" do if test -r "$libname" ; then TK_LIB_DIR="${blt_with_tk_libraries}" break fi done if test "x${TK_LIB_DIR}" = "x" ; then echo "Can't find tk library in \"${blt_with_tk_libraries}\"" exit 1 fi else for libname in \ "${TK_EXEC_PREFIX}/lib/lib${TK_LIB_NAME}.${SHLIB_SUFFIX}" \ "${TK_EXEC_PREFIX}/lib/lib${TK_LIB_NAME}.a" do if test -r "$libname" ; then TK_LIB_DIR="${TK_EXEC_PREFIX}/lib" break fi done if test "x${TK_LIB_DIR}" = "x" ; then echo "Can't find tk library" exit 1 fi fi # ----------------------------------------------------------------------- # # Include files # # Append to INC_SPECS the various include files specifications # (built fromt the include directory information). # # ----------------------------------------------------------------------- # JPEG include files if test "${blt_enable_jpeg}" != "no" ; then if test "x${JPEG_INC_SPEC}" != "x" ; then INC_SPECS="${INC_SPECS} ${JPEG_INC_SPEC}" fi fi # Tk include files if test "${TK_INC_DIR}" != "/usr/include" ; then INC_SPECS="${INC_SPECS} -I${TK_INC_DIR}" fi # Tcl include files # # Add the include directory specification only if the Tcl # headers reside in a different directory from Tk's. if test "${TCL_INC_DIR}" != "/usr/include" -a \ "${TCL_INC_DIR}" != "${TK_INC_DIR}" ; then INC_SPECS="${INC_SPECS} -I${TCL_INC_DIR}" fi # On Windows, override the default include directory with our own. if test "${blt_platform}" = "win"; then x_includes="NONE" fi # X11 include files if test "x${x_includes}" != "x" -a \ "${x_includes}" != "NONE" -a \ "${x_includes}" != "/usr/include" -a \ "${x_includes}" != "${TK_INC_DIR}" -a \ "${x_includes}" != "${TCL_INC_DIR}" ; then INC_SPECS="${INC_SPECS} -I${x_includes}" fi # ----------------------------------------------------------------------- # # Libraries # # Append to LIB the various library specifications # (built from the library directory information). # # ----------------------------------------------------------------------- # Tk libraries if test "${TK_LIB_DIR}" = "/usr/lib" ; then LIB_SPECS="${LIB_SPECS} ${TK_LIB_SPEC}" else LIB_SPECS="${LIB_SPECS} -L${TK_LIB_DIR} ${TK_LIB_SPEC}" if test "x${loader_run_path}" = "x" ; then loader_run_path="${TK_LIB_DIR}" else loader_run_path="${TK_LIB_DIR}:${loader_run_path}" fi fi # Tcl libraries if test "${TCL_LIB_DIR}" = "/usr/lib" -o \ "${TCL_LIB_DIR}" = "${TK_LIB_DIR}" ; then LIB_SPECS="${LIB_SPECS} ${TCL_LIB_SPEC}" else LIB_SPECS="${LIB_SPECS} -L${TCL_LIB_DIR} ${TCL_LIB_SPEC}" if test "x${loader_run_path}" = "x" ; then loader_run_path="${TCL_LIB_DIR}" else loader_run_path="${TCL_LIB_DIR}:${loader_run_path}" fi fi if test "${TCL_LIB_DIR}" = "/usr/lib" ; then TCL_ONLY_LIB_SPECS="${TCL_LIB_SPEC}" else TCL_ONLY_LIB_SPECS="-L${TCL_LIB_DIR} ${TCL_LIB_SPEC}" fi # Collect the libraries for AIX that aren't using stubs. aix_lib_specs="" if test "${blt_platform}" = "win"; then LIB_SPECS="${LIB_SPECS} -mwindows" elif test "${blt_platform}" = "unix"; then # Add specification for X11 library only on Unix platforms. if test "x${x_libraries}" = "x" -o \ "x${x_libraries}" = "NONE" -o \ "${x_libraries}" = "/usr/lib" -o \ "${x_libraries}" = "${TK_LIB_DIR}" -o \ "${x_libraries}" = "${TCL_LIB_DIR}" ; then LIB_SPECS="${LIB_SPECS} -lX11" aix_lib_specs="${aix_lib_specs} -lX11" else LIB_SPECS="${LIB_SPECS} -L${x_libraries} -lX11" aix_lib_specs="${aix_lib_specs} -L${x_libraries} -lX11" if test "x${loader_run_path}" = "x" ; then loader_run_path="${x_libraries}" else loader_run_path="${loader_run_path}:${x_libraries}" fi fi fi # JPEG library if test "${blt_enable_jpeg}" != "no" ; then jpeg_save_LDFlags="${LDFLAGS}" JPEG_LIB_SPEC="-ljpeg" JPEG_LIB_DIR="" if test "${blt_enable_jpeg}" != "yes" ; then JPEG_LIB_DIR="${blt_enable_jpeg}/lib" JPEG_LIB_SPEC="-L${JPEG_LIB_DIR} ${JPEG_LIB_SPEC}" LDFLAGS="-L${JPEG_LIB_DIR} ${LDFLAGS}" fi echo $ac_n "checking for jpeg_read_header in -ljpeg""... $ac_c" 1>&6 echo "configure:3593: checking for jpeg_read_header in -ljpeg" >&5 ac_lib_var=`echo jpeg'_'jpeg_read_header | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-ljpeg $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 found=yes else echo "$ac_t""no" 1>&6 found=no fi if test "${found}" = "yes" ; then LIB_SPECS="${LIB_SPECS} ${JPEG_LIB_SPEC}" aix_lib_specs="${aix_lib_specs} ${JPEG_LIB_SPEC}" if test "x${JPEG_LIB_DIR}" != "x" ; then loader_run_path="${loader_run_path}:${JPEG_LIB_DIR}" fi fi LDFLAGS=${jpeg_save_LDFlags} fi save_libs=$LIBS LIBS="$LIB_SPECS $LIBS" for ac_func in XExtendedMaxRequestSize do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 echo "configure:3648: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else $ac_func(); #endif ; return 0; } EOF if { (eval echo configure:3676: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_$ac_func=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` cat >> confdefs.h <&6 fi done LIBS=$save_libs # ----------------------------------------------------------------------- # # Set up a new default prefix to installation path. The ways # the prefix can be set and their precedence are as follows: # # 1. --prefix option given to ./configure. (prefix != NONE) # 2. use previously configured Tk prefix # # ----------------------------------------------------------------------- if test "$prefix" = "NONE" ; then prefix=${TCL_PREFIX} fi if test "$exec_prefix" = "NONE" ; then exec_prefix=${TCL_EXEC_PREFIX} fi # ------------------------------------------------------------------------- # # Extract the BLT version number for the blt.h header # # ------------------------------------------------------------------------- echo $ac_n "checking BLT_MAJOR_VERSION""... $ac_c" 1>&6 echo "configure:3726: checking BLT_MAJOR_VERSION" >&5 if eval "test \"`echo '$''{'blt_cv_major_version'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.awk <&6 echo $ac_n "checking BLT_MINOR_VERSION""... $ac_c" 1>&6 echo "configure:3742: checking BLT_MINOR_VERSION" >&5 if eval "test \"`echo '$''{'blt_cv_minor_version'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.awk <&6 BLT_MINOR_VERSION=${blt_cv_minor_version} BLT_VERSION=${BLT_MAJOR_VERSION}.${BLT_MINOR_VERSION} # Add BLT to the run path libdir=${exec_prefix}/lib if test "x${libdir}" != "x" -a \ "${libdir}" != "/usr/lib" -a \ "${libdir}" != "${x_libraries}" -a \ "${libdir}" != "${TK_LIB_DIR}" -a \ "${libdir}" != "${TCL_LIB_DIR}" ; then if test "x${loader_run_path}" = "x" ; then loader_run_path="${libdir}" else loader_run_path="${libdir}:${loader_run_path}" fi fi aix_lib_specs="${aix_lib_specs} ${LIBS}" LIB_SPECS="${LIB_SPECS} ${LIBS}" TCL_ONLY_LIB_SPECS="${TCL_ONLY_LIB_SPECS} ${LIBS}" # ------------------------------------------------------------------------- # # Extract the Tcl version number for the tcl.h header # # ------------------------------------------------------------------------- echo $ac_n "checking TCL_VERSION in tcl.h""... $ac_c" 1>&6 echo "configure:3784: checking TCL_VERSION in tcl.h" >&5 if eval "test \"`echo '$''{'blt_cv_tcl_h_version'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.awk <&6 if test "${TCL_H_VERSION}" != "${TCL_VERSION}" ; then echo "Error: Tcl version mismatch. " echo " ${TCL_VERSION} ${tcl_config_sh}" echo " ${TCL_H_VERSION} ${TCL_INC_DIR}/tcl.h" exit 1 fi echo $ac_n "checking TK_VERSION in tk.h""... $ac_c" 1>&6 echo "configure:3805: checking TK_VERSION in tk.h" >&5 if eval "test \"`echo '$''{'blt_cv_tk_h_version'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.awk <&6 if test "${TK_H_VERSION}" != "${TK_VERSION}" ; then echo "Error: Tk version mismatch." echo " ${TK_VERSION} ${tk_config_sh}" echo " ${TK_H_VERSION} ${TK_INC_DIR}/tk.h" exit 1 fi if test "$TCL_VERSION" = "7.6" -a "$TK_VERSION" = "4.2" ; then : elif test "$TCL_VERSION" = "7.5" -a "$TK_VERSION" = "4.1" ; then : elif test "$TCL_VERSION" = "$TK_VERSION" ; then : else echo "Mismatched Tcl/Tk versions ($TCL_VERSION != $TK_VERSION)" exit 1 fi #-------------------------------------------------------------------- # # Check if we can generate shared libraries on this system. Set flags # to generate shared libraries for systems that we know about. Start # with the values found in tclConfig.sh, make changes as we know about # the different systems. # #-------------------------------------------------------------------- LIB_BASE_NAME=libBLT # Initialize shared library build variables SHLIB_CFLAGS="$TCL_SHLIB_CFLAGS" SHLIB_LD="$TCL_SHLIB_LD" SHLIB_LD_FLAGS="$TCL_LD_FLAGS" SHLIB_RUNPATH="$TCL_LD_SEARCH_FLAGS" SHLIB_SUFFIX=".so" SHLIB_TARGET="" SHLIB_CFLAGS="" SHLIB_LIB_SPECS="${JPEG_LIB_SPEC}" SHLIB_TCL_ONLY_LIB_SPECS="${TCL_ONLY_LIB_SPECS}" SHLIB_TCL_ONLY_LIB_SPECS="" LDFLAGS="" LD_RUN_PATH="" EXTRA_LIB_SPECS="" build_shared="yes" library_name=libBLT${BLT_MAJOR_VERSION}${BLT_MINOR_VERSION} case $target in *-aix4.[2-9]*) # No Position-Independent flags needed SHLIB_CFLAGS="" # Use the installed export file or the one found in the source directory. if test -r "${TCL_LIB_DIR}/lib${TCL_LIB_NAME}.exp" ; then tcl_exp="${TCL_LIB_DIR}/lib${TCL_LIB_NAME}.exp" else tcl_exp="${TCL_SRC_DIR}/unix/lib.exp" fi if test -r "${TK_LIB_DIR}/lib${TK_LIB_NAME}.exp" ; then tk_exp="${TK_LIB_DIR}/lib${TK_LIB_NAME}.exp" else tk_exp="${TK_SRC_DIR}/unix/lib.exp" fi full_src_path=`cd ${srcdir}; pwd` # Use shell-script to link shared library SHLIB_LD="${full_src_path}/cf/ldAix /bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry -bI:${tk_exp} -bI:${tcl_exp}" SHLIB_LIB_SPECS="${aix_lib_specs} -lc" LDFLAGS="-L${loader_run_path}" EXTRA_LIB_SPECS="-ldl" ;; *-aix*) # No Position-Independent flags needed SHLIB_CFLAGS="" # Use the installed export file or the one found in the source directory. if test -r "${TCL_LIB_DIR}/lib${TCL_LIB_NAME}.exp" ; then tcl_exp="${TCL_LIB_DIR}/lib${TCL_LIB_NAME}.exp" else tcl_exp="${TCL_SRC_DIR}/unix/lib.exp" fi if test -r "${TK_LIB_DIR}/lib${TK_LIB_NAME}.exp" ; then tk_exp="${TK_LIB_DIR}/lib${TK_LIB_NAME}.exp" else tk_exp="${TK_SRC_DIR}/unix/lib.exp" fi full_src_path=`cd ${srcdir}/cf; pwd` # Use shell-script to link shared library SHLIB_LD="${full_src_path}/ldAix /bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry -bI:${tk_exp} -bI:${tcl_exp}" SHLIB_LIB_SPECS="${aix_lib_specs} -lc" LDFLAGS="-L${loader_run_path}" EXTRA_LIB_SPECS="-lld" ;; *-bsdi2*|*-bsdi3*) SHLIB_CFLAGS="" SHLIB_LD="shlicc" SHLIB_LD_FLAGS="-r" EXTRA_LIB_SPECS="-ldl" ;; *-bsdi4*) SHLIB_CFLAGS="-export-dynamic -fPIC" SHLIB_LD="${CC}" SHLIB_LD_FLAGS='-shared -Wl,-E -Wl,-soname,$@' ;; *-*-cygwin* | *-*-mingw*) SHLIB_LD="${CC}" SHLIB_LD_FLAGS='-shared -Wl,-E -Wl,--out-implib,$@' EXTRA_LIB_SPECS="-lwinspool" LDFLAGS="" ;; *-dgux*) SHLIB_CFLAGS="-K PIC" SHLIB_LD="cc" SHLIB_LD_FLAGS="-G" EXTRA_LIB_SPECS="-ldl" ;; *-hpux*) if test "$blt_have_gcc" = "no" ; then DEFINES="$DEFINES -D_HPUX_SOURCE" fi echo $ac_n "checking for shl_load in -ldld""... $ac_c" 1>&6 echo "configure:3960: checking for shl_load in -ldld" >&5 ac_lib_var=`echo dld'_'shl_load | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-ldld $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 found=yes else echo "$ac_t""no" 1>&6 found=no fi if test "${found}" = "yes" ; then SHLIB_CFLAGS="+Z" SHLIB_LD="ld" SHLIB_LD_FLAGS="-b -E -n +s +b,${loader_run_path}:." SHLIB_SUFFIX=".sl" # The run path is included in both LDFLAGS and SHLIB_LD_FLAGS # because SHLIB_LD is ld and LD is cc/gcc. LDFLAGS="-Wl,-E -Wl,+s,+b,${loader_run_path}:." EXTRA_LIB_SPECS="-ldld" fi ;; *-irix64-6.5*) SHLIB_CFLAGS="" SHLIB_LD="ld" SHLIB_LD_FLAGS="-32 -shared -rdata_shared" LD_RUN_PATH="-Wl,-rpath,${loader_run_path}" ;; *-irix-56.*|*-irix64-*) SHLIB_CFLAGS="" SHLIB_LD="ld" SHLIB_LD_FLAGS="-shared -rdata_shared" LD_RUN_PATH="-Wl,-rpath,${loader_run_path}" LDFLAGS="" if test "$blt_have_gcc" = "yes" ; then SHLIB_CFLAGS="-mabi=n32 $SHLIB_CFLAGS" SHLIB_LD_FLAGS="-mabi=n32 $SHLIB_LD_FLAGS" LDFLAGS="-mabi=n32 $LDFLAGS" else CFLAGS="-n32 $CFLAGS" LDFLAGS="-n32 $LDFLAGS" fi ;; *-linux*) SHLIB_CFLAGS="-fPIC" SHLIB_LD="${CC}" SHLIB_LD_FLAGS='-rdynamic -shared -Wl,-E -Wl,-soname,$@' LD_RUN_PATH="-Wl,-rpath,${loader_run_path}" LDFLAGS="" EXTRA_LIB_SPECS="-ldl" ;; *-mp-ras-02*) SHLIB_CFLAGS="-G -K PIC" SHLIB_LD="${CC}" SHLIB_LD_FLAGS="" ;; *-mp-ras-*) SHLIB_CFLAGS="-G -K PIC" SHLIB_LD="${CC}" SHLIB_LD_FLAGS="-Wl,-Bexport" ;; *-ncr-sysv4-*2*) SHLIB_CFLAGS="-K PIC" SHLIB_LD="cc" SHLIB_LD_FLAGS="-G" EXTRA_LIB_SPECS="-ldl" ;; *-ncr-sysv4*) SHLIB_CFLAGS="-K PIC" SHLIB_LD="cc" SHLIB_LD_FLAGS="-G -Wl,-Bexport" LDFLAGS="-Wl,-Bexport" EXTRA_LIB_SPECS="-ldl" ;; *-netbsd*|*-freebsd*|*-openbsd*) # Not available on all versions: check for include file. ac_safe=`echo "dlfcn.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for dlfcn.h""... $ac_c" 1>&6 echo "configure:4080: checking for dlfcn.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:4090: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 test_ok=yes else echo "$ac_t""no" 1>&6 test_ok=no fi if test "$test_ok" = yes; then SHLIB_CFLAGS="-fpic" SHLIB_LD="ld" SHLIB_LD_FLAGS="-Bshareable -x" fi ;; *-nextstep*) SHLIB_CFLAGS="" SHLIB_LD="cc" SHLIB_LD_FLAGS="-nostdlib -r" ;; *-osf1-1.012*) # OSF/1 1.[012] from OSF, and derivatives, including Paragon OSF/1 SHLIB_CFLAGS="" # Warning: Ugly Makefile Hack # Make package name same as library name SHLIB_LD='ld -R -export $@:' ;; *-osf1-1.*) # OSF/1 1.3 from OSF using ELF, and derivatives, including AD2 SHLIB_CFLAGS="-fpic" SHLIB_LD="ld -shared" ;; *-osf1V*) # Digital OSF/1 SHLIB_CFLAGS="" SHLIB_LD='ld' SHLIB_LD_FLAGS='-shared -expect_unresolved "*"' LD_RUN_PATH="-Wl,-rpath,${loader_run_path}" LDFLAGS="" ;; *-sco*) # Note, dlopen is available only on SCO 3.2.5 and greater. However, # this test works, since "uname -s" was non-standard in 3.2.4 and # below. SHLIB_CFLAGS="-Kpic -belf" SHLIB_LD="ld" SHLIB_LD_FLAGS="-G" LDFLAGS="-belf -Wl,-Bexport" ;; *-sni-sysv*) SHLIB_CFLAGS="-K PIC" SHLIB_LD="cc" SHLIB_LD_FLAGS="-G" EXTRA_LIB_SPECS="-ldl" ;; *-sunos4*) SHLIB_CFLAGS="-PIC" SHLIB_LD="ld" SHLIB_LD_FLAGS="-assert pure-text" EXTRA_LIB_SPECS="-ldl" ;; *-solaris2*) SHLIB_CFLAGS="-KPIC" if test "${blt_with_gnu_ld}" = "yes" -a "$blt_have_gcc" = "yes" ; then SHLIB_LD="gcc" SHLIB_LD_FLAGS='-rdynamic -shared -Wl,-E -Wl,-soname,$@' LD_RUN_PATH="-Wl,-rpath,${loader_run_path}" else SHLIB_LD="/usr/ccs/bin/ld" SHLIB_LD_FLAGS="-G -z text" LD_RUN_PATH="-R ${loader_run_path}" fi EXTRA_LIB_SPECS="-ldl" ;; *-mips-dde-sysv*) SHLIB_CFLAGS="-KPIC" SHLIB_LD="cc" SHLIB_LD_FLAGS="-G" EXTRA_LIB_SPECS="-ldl" ;; *-pc-sysv4* | *-unixware-5*) SHLIB_CFLAGS="-G -KPIC" SHLIB_LD="${CC}" SHLIB_LD_FLAGS=" -Wl,-Bexport" ;; *) build_shared="no" ;; esac # If we're running gcc, then set SHLIB_CFLAGS flags for compiling # shared libraries for gcc, instead of those of the vendor's # compiler. if test "$blt_have_gcc" = "yes" ; then SHLIB_CFLAGS="-fPIC" fi # We can't back link against static versions of Tcl/Tk. # If # ${TCL_SHARED_BUILD} can't be found or isn't "1", assume that # shared libraies weren't built. if test "${TCL_SHARED_BUILD}" != "1" ; then SHLIB_LIB_SPECS="" fi if test "${build_shared}" = "yes" ; then SHLIB_TARGET="build_shared" fi LIBS=${LIB_SPECS} INCLUDES=${INC_SPECS} BLT_LIB_PREFIX=${blt_lib_prefix} #-------------------------------------------------------------------- # The BLT script directory was either specified or we # assume /lib #-------------------------------------------------------------------- if test "x${blt_with_scriptdir}" = "x" ; then BLT_LIBRARY="${prefix}/lib/blt${BLT_VERSION}" else BLT_LIBRARY="${blt_with_scriptdir}/blt${BLT_VERSION}" fi #-------------------------------------------------------------------- # Print out some of the more important settings #-------------------------------------------------------------------- echo "" echo "Configuration results:" echo "" echo " tcl.h found in $TCL_INC_DIR" echo " tk.h found in $TK_INC_DIR" echo " X11/Xlib.h found in $x_includes" echo " lib${TCL_LIB_NAME} found in $TCL_LIB_DIR" echo " lib${TK_LIB_NAME} found in $TK_LIB_DIR" echo " libX11 found in $x_libraries" echo "" echo "Directories where BLT is to be installed:" echo "" echo " \"\$prefix\" is $prefix" echo " \"\$exec_prefix\" is $exec_prefix" echo "" echo " bltwish to be installed in $bindir" echo " libBLT.a to be installed in $libdir" echo " scripts to be installed in $BLT_LIBRARY" echo " manual pages to be installed in $mandir" echo "" #-------------------------------------------------------------------- # # Generate the following Makefiles # # ./Makefile # ./src/Makefile # ./src/shared/Makefile # ./man/Makefile # ./library/Makefile # ./demos/Makefile # #-------------------------------------------------------------------- src_Makefile="src/Makefile" if test "${blt_platform}" = "win"; then src_Makefile="src/Makefile:src/Makefile-cyg.in" fi trap '' 1 2 15 trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Any assignment to VPATH causes Sun make to only execute # the first set of double-colon rules, so remove it if not needed. # If there is a colon in the path, we need to keep it. if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' fi trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 DEFS=-DHAVE_CONFIG_H # Without the "./", some shells look in PATH for config.status. : ${CONFIG_STATUS=./config.status} echo creating $CONFIG_STATUS rm -f $CONFIG_STATUS cat > $CONFIG_STATUS </dev/null | sed 1q`: # # $0 $ac_configure_args # # Compiler output produced by configure, useful for debugging # configure, is in ./config.log if it exists. ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" for ac_option do case "\$ac_option" in -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; -version | --version | --versio | --versi | --vers | --ver | --ve | --v) echo "$CONFIG_STATUS generated by autoconf version 2.13" exit 0 ;; -help | --help | --hel | --he | --h) echo "\$ac_cs_usage"; exit 0 ;; *) echo "\$ac_cs_usage"; exit 1 ;; esac done ac_given_srcdir=$srcdir ac_given_INSTALL="$INSTALL" trap 'rm -fr `echo "Makefile ${src_Makefile} src/bltHash.h src/shared/Makefile man/Makefile library/Makefile demos/Makefile src/bltConfig.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 EOF cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF $ac_vpsub $extrasub s%@SHELL@%$SHELL%g s%@CFLAGS@%$CFLAGS%g s%@CPPFLAGS@%$CPPFLAGS%g s%@CXXFLAGS@%$CXXFLAGS%g s%@FFLAGS@%$FFLAGS%g s%@DEFS@%$DEFS%g s%@LDFLAGS@%$LDFLAGS%g s%@LIBS@%$LIBS%g s%@exec_prefix@%$exec_prefix%g s%@prefix@%$prefix%g s%@program_transform_name@%$program_transform_name%g s%@bindir@%$bindir%g s%@sbindir@%$sbindir%g s%@libexecdir@%$libexecdir%g s%@datadir@%$datadir%g s%@sysconfdir@%$sysconfdir%g s%@sharedstatedir@%$sharedstatedir%g s%@localstatedir@%$localstatedir%g s%@libdir@%$libdir%g s%@includedir@%$includedir%g s%@oldincludedir@%$oldincludedir%g s%@infodir@%$infodir%g s%@mandir@%$mandir%g s%@host@%$host%g s%@host_alias@%$host_alias%g s%@host_cpu@%$host_cpu%g s%@host_vendor@%$host_vendor%g s%@host_os@%$host_os%g s%@target@%$target%g s%@target_alias@%$target_alias%g s%@target_cpu@%$target_cpu%g s%@target_vendor@%$target_vendor%g s%@target_os@%$target_os%g s%@build@%$build%g s%@build_alias@%$build_alias%g s%@build_cpu@%$build_cpu%g s%@build_vendor@%$build_vendor%g s%@build_os@%$build_os%g s%@WISH@%$WISH%g s%@CC@%$CC%g s%@CPP@%$CPP%g s%@GCCFLAGS@%$GCCFLAGS%g s%@AWK@%$AWK%g s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g s%@INSTALL_DATA@%$INSTALL_DATA%g s%@RANLIB@%$RANLIB%g s%@LN_S@%$LN_S%g s%@HAVE_INTTYPES_H@%$HAVE_INTTYPES_H%g s%@SIZEOF_INT@%$SIZEOF_INT%g s%@SIZEOF_LONG@%$SIZEOF_LONG%g s%@SIZEOF_LONG_LONG@%$SIZEOF_LONG_LONG%g s%@SIZEOF_VOID_P@%$SIZEOF_VOID_P%g s%@SHLIB_CFLAGS@%$SHLIB_CFLAGS%g s%@SHLIB_TARGET@%$SHLIB_TARGET%g s%@SHLIB_LD@%$SHLIB_LD%g s%@SHLIB_LD_FLAGS@%$SHLIB_LD_FLAGS%g s%@SHLIB_LIB_SPECS@%$SHLIB_LIB_SPECS%g s%@SHLIB_TCL_ONLY_LIB_SPECS@%$SHLIB_TCL_ONLY_LIB_SPECS%g s%@SHLIB_SUFFIX@%$SHLIB_SUFFIX%g s%@LD_RUN_PATH@%$LD_RUN_PATH%g s%@LIB_SPECS@%$LIB_SPECS%g s%@TCL_ONLY_LIB_SPECS@%$TCL_ONLY_LIB_SPECS%g s%@EXTRA_LIB_SPECS@%$EXTRA_LIB_SPECS%g s%@INCLUDES@%$INCLUDES%g s%@DEFINES@%$DEFINES%g s%@BLT_MAJOR_VERSION@%$BLT_MAJOR_VERSION%g s%@BLT_MINOR_VERSION@%$BLT_MINOR_VERSION%g s%@BLT_VERSION@%$BLT_VERSION%g s%@AUX_LIBS@%$AUX_LIBS%g s%@TCL_LIB_DIR@%$TCL_LIB_DIR%g s%@TCL_VERSION@%$TCL_VERSION%g s%@BLT_LIB_PREFIX@%$BLT_LIB_PREFIX%g s%@BLT_LIBRARY@%$BLT_LIBRARY%g CEOF EOF cat >> $CONFIG_STATUS <<\EOF # Split the substitutions into bite-sized pieces for seds with # small command number limits, like on Digital OSF/1 and HP-UX. ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. ac_file=1 # Number of current file. ac_beg=1 # First line for current file. ac_end=$ac_max_sed_cmds # Line after last line for current file. ac_more_lines=: ac_sed_cmds="" while $ac_more_lines; do if test $ac_beg -gt 1; then sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file else sed "${ac_end}q" conftest.subs > conftest.s$ac_file fi if test ! -s conftest.s$ac_file; then ac_more_lines=false rm -f conftest.s$ac_file else if test -z "$ac_sed_cmds"; then ac_sed_cmds="sed -f conftest.s$ac_file" else ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" fi ac_file=`expr $ac_file + 1` ac_beg=$ac_end ac_end=`expr $ac_end + $ac_max_sed_cmds` fi done if test -z "$ac_sed_cmds"; then ac_sed_cmds=cat fi EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case "$ac_file" in *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; *) ac_file_in="${ac_file}.in" ;; esac # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. # Remove last slash and all that follows it. Not all systems have dirname. ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then # The file is in a subdirectory. test ! -d "$ac_dir" && mkdir "$ac_dir" ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" # A "../" for each directory in $ac_dir_suffix. ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` else ac_dir_suffix= ac_dots= fi case "$ac_given_srcdir" in .) srcdir=. if test -z "$ac_dots"; then top_srcdir=. else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; *) # Relative path. srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" top_srcdir="$ac_dots$ac_given_srcdir" ;; esac case "$ac_given_INSTALL" in [/$]*) INSTALL="$ac_given_INSTALL" ;; *) INSTALL="$ac_dots$ac_given_INSTALL" ;; esac echo creating "$ac_file" rm -f "$ac_file" configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." case "$ac_file" in *Makefile*) ac_comsub="1i\\ # $configure_input" ;; *) ac_comsub= ;; esac ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` sed -e "$ac_comsub s%@configure_input@%$configure_input%g s%@srcdir@%$srcdir%g s%@top_srcdir@%$top_srcdir%g s%@INSTALL@%$INSTALL%g " $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file fi; done rm -f conftest.s* # These sed commands are passed to sed as "A NAME B NAME C VALUE D", where # NAME is the cpp macro being defined and VALUE is the value it is being given. # # ac_d sets the value in "#define NAME VALUE" lines. ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' ac_dC='\3' ac_dD='%g' # ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' ac_uB='\([ ]\)%\1#\2define\3' ac_uC=' ' ac_uD='\4%g' # ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' ac_eB='$%\1#\2define\3' ac_eC=' ' ac_eD='%g' if test "${CONFIG_HEADERS+set}" != set; then EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF fi for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case "$ac_file" in *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; *) ac_file_in="${ac_file}.in" ;; esac echo creating $ac_file rm -f conftest.frag conftest.in conftest.out ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` cat $ac_file_inputs > conftest.in EOF # Transform confdefs.h into a sed script conftest.vals that substitutes # the proper values into config.h.in to produce config.h. And first: # Protect against being on the right side of a sed subst in config.status. # Protect against being in an unquoted here document in config.status. rm -f conftest.vals cat > conftest.hdr <<\EOF s/[\\&%]/\\&/g s%[\\$`]%\\&%g s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp s%ac_d%ac_u%gp s%ac_u%ac_e%gp EOF sed -n -f conftest.hdr confdefs.h > conftest.vals rm -f conftest.hdr # This sed command replaces #undef with comments. This is necessary, for # example, in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. cat >> conftest.vals <<\EOF s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% EOF # Break up conftest.vals because some shells have a limit on # the size of here documents, and old seds have small limits too. rm -f conftest.tail while : do ac_lines=`grep -c . conftest.vals` # grep -c gives empty output for an empty file on some AIX systems. if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi # Write a limited-size here document to conftest.frag. echo ' cat > conftest.frag <> $CONFIG_STATUS sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS echo 'CEOF sed -f conftest.frag conftest.in > conftest.out rm -f conftest.in mv conftest.out conftest.in ' >> $CONFIG_STATUS sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail rm -f conftest.vals mv conftest.tail conftest.vals done rm -f conftest.vals cat >> $CONFIG_STATUS <<\EOF rm -f conftest.frag conftest.h echo "/* $ac_file. Generated automatically by configure. */" > conftest.h cat conftest.in >> conftest.h rm -f conftest.in if cmp -s $ac_file conftest.h 2>/dev/null; then echo "$ac_file is unchanged" rm -f conftest.h else # Remove last slash and all that follows it. Not all systems have dirname. ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then # The file is in a subdirectory. test ! -d "$ac_dir" && mkdir "$ac_dir" fi rm -f $ac_file mv conftest.h $ac_file fi fi; done EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF exit 0 EOF chmod +x $CONFIG_STATUS rm -fr confdefs* $ac_clean_files test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 blt-2.4z.orig/configure.in0100644000175000017500000011076607547224043014277 0ustar dokodokodefine([AC_CACHE_LOAD], )dnl define([AC_CACHE_SAVE], )dnl AC_INIT(src/bltInit.c) AC_CONFIG_HEADER(src/bltConfig.h) AC_CONFIG_AUX_DIR(cf) AC_PREREQ(2.0) # ----------------------------------------------------------------------- # # Handle command line options # # --with-tcl=DIR # --with-tk=DIR # --with-cc=CC # --with-cflags=flags This is probably for me only # --with-gnu-ld # # ----------------------------------------------------------------------- INC_SPECS="" LIB_SPECS="" TCL_ONLY_LIB_SPECS="" loader_run_path="" DEFINES="" blt_with_tcl="" blt_with_tk="" blt_enable_jpeg="no" blt_enable_cygwin="yes" blt_with_cc="" blt_with_cflags="$CFLAGS" blt_with_gnu_ld="no" blt_with_tcl_includes="" blt_with_tk_includes="" blt_with_tcl_libraries="" blt_with_tk_libraries="" blt_with_scriptdir="" AC_ARG_WITH(blt, [ --with-blt=DIR Install BLT scripts in DIR], blt_with_scriptdir=$withval) AC_ARG_WITH(tcl, [ --with-tcl=DIR Find tclConfig.sh in DIR], blt_with_tcl=$withval) AC_ARG_WITH(tk, [ --with-tk=DIR Find tkConfig.sh in DIR], blt_with_tk=$withval) AC_ARG_WITH(tclincls, [ --with-tclincls=DIR Find tcl.h in DIR], blt_with_tcl_includes=$withval) AC_ARG_WITH(tkincls, [ --with-tkincls=DIR Find tk.h in DIR], blt_with_tk_includes=$withval) AC_ARG_WITH(tcllibs, [ --with-tcllibs=DIR Find Tcl library in DIR], blt_with_tcl_libraries=$withval) AC_ARG_WITH(tklibs, [ --with-tklibs=DIR Find Tk library in DIR], blt_with_tk_libraries=$withval) AC_ARG_ENABLE(jpeg, [ --enable-jpeg=DIR Find JPEG headers and libraries in DIR], [ unset ac_cv_header_jpeglib_h unset ac_cv_lib_jpeg ac_cv_lib_jpeg_jpeg_read_header blt_enable_jpeg=$enableval ]) AC_ARG_ENABLE(cygwin, [ --enable-cygwin Use cygwin Tcl/Tk libraries. Requires cygwin1.dll], [ blt_enable_cygwin=$enableval ]) AC_ARG_WITH(cc, [ --with-cc=CC Set C compiler to CC], [ blt_with_cc=$with_cc unset ac_cv_prog_CC unset ac_cv_prog_CPP ]) AC_ARG_WITH(cflags, [ --with-cflags=FLAGS Set compiler flags to FLAGS], blt_with_cflags="$with_cflags") AC_ARG_WITH(gnu_ld, [ --with-gnu-ld Use GNU linker], blt_with_gnu_ld="yes") AC_CANONICAL_SYSTEM AC_PREFIX_PROGRAM(wish) # ----------------------------------------------------------------------- # # Set a variable containing current working directory if /bin/sh # doesn't do it already. # # ----------------------------------------------------------------------- PWD=`pwd` # ----------------------------------------------------------------------- # # C compiler and debugging flags # # ----------------------------------------------------------------------- BLT_ENV_CC=$CC # # CC search order # # 1. command line (--with-cc) # 2. environment variable ($CC) # 3. cached variable ($blt_cv_prog_cc) # 4. check for program (AC_PROG_CC) # 4. default to cc # AC_MSG_CHECKING([which C compiler]) if test "x${blt_with_cc}" != "x" ; then CC=${blt_with_cc} unset ac_cv_prog_CPP unset ac_cv_prog_CC elif test "x${BLT_ENV_CC}" != "x" ; then unset ac_cv_prog_CPP unset ac_cv_prog_CC elif test "x${blt_cv_prog_cc}" != "x" ; then CC=${blt_cv_prog_cc} unset ac_cv_prog_CC else AC_PROG_CC fi if test "x${CC}" = "x" ; then CC=cc fi case $target in *-*-cygwin*|*-*-mingw*) if test "${blt_enable_cygwin}" = "no" ; then CC="${CC} -mno-cygwin" fi ;; esac AC_MSG_RESULT([$CC]) unset blt_cv_prog_cc AC_CACHE_VAL(blt_cv_prog_cc, blt_cv_prog_cc=$CC) AC_SUBST(CC) AC_PROG_CPP if test "x${GCC}" != "x" ; then blt_have_gcc="yes" else AC_MSG_CHECKING([if C compiler is really gcc]) AC_EGREP_CPP(_cc_is_gcc_, [ #ifdef __GNUC__ _cc_is_gcc_ #endif ], [blt_have_gcc=yes], [blt_have_gcc=no]) AC_MSG_RESULT([$blt_have_gcc]) fi # # CFLAGS search order # # 1. command line (--with-cflags) # 2. cached variable ($blt_cv_prog_cflags) # 3. set to "-O6" if using gcc ($blt_have_gcc) # 4. otherwise, default to "-O" # AC_MSG_CHECKING([default compiler flags]) if test "x${blt_with_cflags}" != "x" ; then CFLAGS=${blt_with_cflags} elif test "x${blt_cv_prog_cflags}" != "x" ; then CFLAGS=${blt_cv_prog_cflags} elif test "${blt_have_gcc}" = "yes" ; then CFLAGS=-O6 else CFLAGS=-O fi AC_MSG_RESULT([$CFLAGS]) unset blt_cv_prog_cflags AC_CACHE_VAL(blt_cv_prog_cflags, blt_cv_prog_cflags=$CFLAGS) AC_SUBST(CFLAGS) GCCFLAGS="" if test "${blt_have_gcc}" = "yes" ; then GCCFLAGS="-Wall" if test "${CFLAGS}" = "-g" ; then GCCFLAGS="-Wshadow -Winline -Wpointer-arith ${GCCFLAGS}" fi fi AC_SUBST(GCCFLAGS) AC_CYGWIN blt_lib_prefix="lib" case $target in *-*-cygwin*|*-*-mingw*) blt_platform="win" if test "$ac_cv_cygwin" = "yes" ; then blt_lib_prefix="cyg" else blt_lib_prefix="" fi ;; *-*-macosx) blt_platform="macosx" ;; *) blt_platform="unix" ;; esac # ----------------------------------------------------------------------- # # Programs: Check for existence of ranlib and install programs # # ----------------------------------------------------------------------- AC_PROG_AWK AC_PROG_INSTALL AC_PROG_RANLIB AC_PROG_LN_S # ----------------------------------------------------------------------- # # Libraries: Check for libraries used # # ----------------------------------------------------------------------- AC_CHECK_LIB(socket, main) AC_CHECK_LIB(nsl, main) AC_CHECK_LIB(m, main) # ----------------------------------------------------------------------- # # Headers: Check for header files used # # ----------------------------------------------------------------------- AC_HEADER_STDC AC_HEADER_SYS_WAIT AC_HEADER_TIME AC_CHECK_HEADERS(inttypes.h) if test "${ac_cv_header_inttypes_h}" = "yes" ; then HAVE_INTTYPES_H=1 else HAVE_INTTYPES_H=0 fi AC_SUBST(HAVE_INTTYPES_H) AC_CHECK_HEADERS(limits.h sys/param.h) AC_CHECK_HEADERS(string.h ctype.h) AC_CHECK_HEADERS(errno.h float.h math.h ieeefp.h) AC_CHECK_HEADERS(sys/time.h waitflags.h sys/wait.h) AC_CHECK_HEADERS(malloc.h memory.h) AC_CHECK_HEADERS(setjmp.h) if test "${blt_enable_jpeg}" != "no" ; then jpeg_save_CPPFLAGS=${CPPFLAGS} CPPFLAGS="" if test "${blt_enable_jpeg}" != "yes" ; then CPPFLAGS="-I${blt_enable_jpeg}/include" fi AC_CHECK_HEADERS(jpeglib.h, [JPEG_INC_SPEC="${CPPFLAGS}"], [JPEG_INC_SPEC=""]) CPPFLAGS=${jpeg_save_CPPFLAGS} fi # Run this check after jpeglib.h because jpeglib.h sets HAVE_STDLIB_H AC_CHECK_HEADERS(stdlib.h unistd.h) # ----------------------------------------------------------------------- # # Types: Check for existence of types of size_t and pid_t # # ----------------------------------------------------------------------- AC_TYPE_SIZE_T AC_TYPE_PID_T AC_MSG_CHECKING([whether union wait is defined correctly]) AC_CACHE_VAL(blt_cv_struct_wait_works, AC_TRY_COMPILE([#include #include ], [ /* * Check whether defines the type "union wait" * correctly. It's needed because of weirdness in HP-UX where * "union wait" is defined in both the BSD and SYS-V environments. * Checking the usability of WIFEXITED seems to do the trick. */ union wait x; WIFEXITED(x); /* Generates compiler error if WIFEXITED * uses an int. */ ], [blt_cv_struct_wait_works="yes"], [blt_cv_struct_wait_works="no"])) if test "${blt_cv_struct_wait_works}" = "yes"; then AC_DEFINE(HAVE_UNION_WAIT) fi AC_MSG_RESULT([$blt_cv_struct_wait_works]) # ----------------------------------------------------------------------- # # Compiler characteristics: # Check for existence of types of size_t and pid_t # # ----------------------------------------------------------------------- AC_C_BIGENDIAN AC_CHECK_SIZEOF(int) AC_CHECK_SIZEOF(long) AC_CHECK_SIZEOF(long long) AC_CHECK_SIZEOF(void *) SIZEOF_LONG="${ac_cv_sizeof_long}" SIZEOF_LONG_LONG="${ac_cv_sizeof_long_long}" SIZEOF_VOID_P="${ac_cv_sizeof_void_p}" SIZEOF_INT="${ac_cv_sizeof_int}" AC_SUBST(SIZEOF_INT) AC_SUBST(SIZEOF_LONG) AC_SUBST(SIZEOF_LONG_LONG) AC_SUBST(SIZEOF_VOID_P) # ----------------------------------------------------------------------- # # Library Functions: Check for strdup, drand48, and srand48. # # ----------------------------------------------------------------------- AC_HAVE_FUNCS(strdup strcasecmp strncasecmp drand48 srand48 finite isnan) # For HPUX it's a little more complicated to search for isfinite AC_MSG_CHECKING([for isfinite]) AC_CACHE_VAL(blt_cv_have_isfinite, AC_TRY_LINK([#include ], [ double x = 1.0; if (isfinite(x)) { return 0; } ], [blt_cv_have_isfinite="yes"], [blt_cv_have_isfinite="no"])) if test "${blt_cv_have_isfinite}" = "yes"; then AC_DEFINE(HAVE_ISFINITE) fi AC_MSG_RESULT([$blt_cv_have_isfinite]) # ----------------------------------------------------------------------- # # Check the smallest value such that 1.0 + x != 1.0. # For ANSI compilers this is DBL_EPSILON in float.h # #-------------------------------------------------------------------- AC_MSG_CHECKING([whether DBL_EPSILON is defined in float.h]) AC_CACHE_VAL(blt_cv_found_dbl_epsilon, AC_EGREP_CPP(yes, [ #ifdef HAVE_FLOAT_H #include #endif #ifdef DBL_EPSILON yes #endif ], blt_cv_found_dbl_epsilon=yes, blt_cv_found_dbl_epsilon=no) ) AC_MSG_RESULT([${blt_cv_found_dbl_epsilon}]) if test "${blt_cv_found_dbl_epsilon}" = "no" ; then AC_CACHE_VAL(blt_cv_dbl_epsilon, old_flags="$CFLAGS" CFLAGS="-g -lm" AC_MSG_CHECKING([whether DBL_EPSILON can be computed]) AC_TRY_RUN_WITH_OUTPUT(blt_cv_dbl_epsilon, [ main () { double e, u; /* * Check the smallest value such that 1.0 + x != 1.0. * For ANSI compilers this is DBL_EPSILON in float.h */ u = 1.0; for(;;) { u *= 0.5; if ((1.0 + u) == 1.0) { break; } } e = u * 2.0; printf("%.17e\n", e); exit(0); }]) CFLAGS="$old_flags" AC_DEFINE_UNQUOTED(BLT_DBL_EPSILON, ${blt_cv_dbl_epsilon}) AC_MSG_RESULT([${blt_cv_dbl_epsilon}]) ) fi AC_MSG_CHECKING([whether declaration is needed for strdup]) AC_CACHE_VAL(blt_cv_nedd_decl_strdup, AC_EGREP_CPP(strdup, [ #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ ], [blt_cv_need_decl_strdup=no], [blt_cv_need_decl_strdup=yes])) if test "${blt_cv_need_decl_strdup}" = "yes"; then AC_DEFINE(NEED_DECL_STRDUP) fi AC_MSG_RESULT([$blt_cv_need_decl_strdup]) AC_MSG_CHECKING([whether declaration is needed for drand48]) AC_CACHE_VAL(blt_cv_need_decl_drand48, AC_EGREP_CPP(drand48, [ #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_MATH_H #include #endif #ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ ], [blt_cv_need_decl_drand48=no], [blt_cv_need_decl_drand48=yes])) if test "${blt_cv_need_decl_drand48}" = "yes"; then AC_DEFINE(NEED_DECL_DRAND48) fi AC_MSG_RESULT([$blt_cv_need_decl_drand48]) AC_MSG_CHECKING([whether declaration is needed for srand48]) AC_CACHE_VAL(blt_cv_need_decl_srand48, AC_EGREP_CPP(srand48, [ #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_MATH_H #include #endif #ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ ], [blt_cv_need_decl_srand48=no], [blt_cv_need_decl_srand48=yes])) if test "${blt_cv_need_decl_srand48}" = "yes"; then AC_DEFINE(NEED_DECL_SRAND48) fi AC_MSG_RESULT([$blt_cv_need_decl_srand48]) AC_MSG_CHECKING([whether declaration is needed for j1]) AC_CACHE_VAL(blt_cv_need_decl_j1, AC_EGREP_CPP(j1, [ #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_MATH_H #include #endif #ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ ], [blt_cv_need_decl_j1=no], [blt_cv_need_decl_j1=yes])) if test "${blt_cv_need_decl_j1}" = "yes"; then AC_DEFINE(NEED_DECL_J1) fi AC_MSG_RESULT([$blt_cv_need_decl_j1]) # ----------------------------------------------------------------------- # # System services: X, Tcl, Tk # # ----------------------------------------------------------------------- AC_PATH_X # ----------------------------------------------------------------------- # # Find the Tcl build configuration file "tclConfig.sh" # # ----------------------------------------------------------------------- AC_MSG_CHECKING([for tclConfig.sh]) tcl_config_sh="" if test "x$blt_with_tcl" != "x" ; then # Verify that a tclConfig.sh file exists in the directory specified # by --with-tcl. for dir in \ $blt_with_tcl do if test -r "$dir/tclConfig.sh" ; then tcl_config_sh="$dir/tclConfig.sh" break elif test -r "$dir/lib/tclConfig.sh" ; then tcl_config_sh="$dir/lib/tclConfig.sh" break elif test -r "$dir/$blt_platform/tclConfig.sh" ; then tcl_config_sh="$dir/$blt_platform/tclConfig.sh" break fi done else # Otherwise, search for Tcl configuration file. # 1. Search previously named locations. for dir in \ $prefix \ $exec_prefix \ $blt_cv_tcl_lib do if test -r "$dir/tclConfig.sh" ; then tcl_config_sh="$dir/tclConfig.sh" break elif test -r "$dir/lib/tclConfig.sh" ; then tcl_config_sh="$dir/lib/tclConfig.sh" break elif test -r "$dir/$blt_platform/tclConfig.sh" ; then tcl_config_sh="$dir/$blt_platform/tclConfig.sh" break fi done # 2. Search source directories. if test "x$tcl_config_sh" = "x" ; then for dir in \ `ls -dr ../tcl[[7-9]].[[0-9]]* 2>/dev/null` \ ../tcl \ `ls -dr ../../tcl[[7-9]].[[0-9]]* 2>/dev/null` \ ../../tcl \ `ls -dr ../../../tcl[[7-9]].[[0-9]]* 2>/dev/null` \ ../../../tcl do if test -r "$dir/$blt_platform/tclConfig.sh" ; then tcl_config_sh="$dir/$blt_platform/tclConfig.sh" break fi done fi # 3. Search standard locations. if test "x$tcl_config_sh" = "x" ; then for dir in \ `ls -dr /usr/local/tcl/tcl[[7-9]].[[0-9]]* 2>/dev/null` \ /usr/local/tcl \ /usr/local \ /usr do if test -r "$dir/tclConfig.sh" ; then tcl_config_sh="$dir/tclConfig.sh" break elif test -r "$dir/lib/tclConfig.sh" ; then tcl_config_sh="$dir/lib/tclConfig.sh" break fi done fi fi AC_MSG_RESULT([${tcl_config_sh}]) if test "x$tcl_config_sh" = "x" ; then echo "can't find Tcl configuration script \"tclConfig.sh\"" exit 1 fi # ----------------------------------------------------------------------- # # Find the Tk build configuration file "tkConfig.sh" # # ----------------------------------------------------------------------- AC_MSG_CHECKING([for tkConfig.sh]) tk_config_sh="" if test "x$blt_with_tk" != "x" -o "x$blt_with_tcl" != "x"; then # Verify that a tkConfig.sh file exists in the directory specified # by --with-tcl or --with-tk. for dir in \ $blt_with_tk \ $blt_with_tcl do if test -r "$dir/tkConfig.sh" ; then tk_config_sh="$dir/tkConfig.sh" break elif test -r "$dir/lib/tkConfig.sh" ; then tk_config_sh="$dir/lib/tkConfig.sh" break elif test -r "$dir/$blt_platform/tkConfig.sh" ; then tk_config_sh="$dir/$blt_platform/tkConfig.sh" break fi done else # Search for Tk configuration file. # 1. Search previously named locations. for dir in \ $prefix \ $exec_prefix \ $blt_cv_tk_lib \ $blt_cv_tcl_lib do if test -r "$dir/tkConfig.sh" ; then tk_config_sh="$dir/tkConfig.sh" break elif test -r "$dir/lib/tkConfig.sh" ; then tk_config_sh="$dir/lib/tkConfig.sh" break elif test -r "$dir/$blt_platform/tkConfig.sh" ; then tk_config_sh="$dir/$blt_platform/tkConfig.sh" break fi done # 2. Search source directories. if test "x$tk_config_sh" = "x" ; then for dir in \ ../tcl \ `ls -dr ../tk[[4-9]].[[0-9]]* 2>/dev/null` \ ../../tcl \ `ls -dr ../../tk[[4-9]].[[0-9]]* 2>/dev/null` \ ../../../tcl \ `ls -dr ../../../tk[[4-9]].[[0-9]]* 2>/dev/null` do if test -r "$dir/$blt_platform/tkConfig.sh"; then tk_config_sh="$dir/$blt_platform/tkConfig.sh" break fi done fi # 3. Search standard locations. if test "x$tk_config_sh" = "x" ; then for dir in \ `ls -dr /usr/local/tcl/tcl[[7-9]].[[0-9]]* 2>/dev/null` \ /usr/local/tcl \ /usr/local \ ${x_libraries} \ /usr do if test -r "$dir/tkConfig.sh" ; then tk_config_sh="$dir/tkConfig.sh" break elif test -r "$dir/lib/tkConfig.sh" ; then tk_config_sh="$dir/lib/tkConfig.sh" break fi done fi fi AC_MSG_RESULT([${tk_config_sh}]) if test "x$tk_config_sh" = "x" ; then echo "can't find Tk configuration script \"tkConfig.sh\"" exit 1 fi # ----------------------------------------------------------------------- # # Source in the Tcl/Tk configuration scripts. # # ----------------------------------------------------------------------- . $tcl_config_sh . $tk_config_sh TCL_INC_DIR="" TK_INC_DIR="" if test "x${blt_with_tcl_includes}" != "x" ; then if test -r "${blt_with_tcl_includes}/tcl.h" ; then TCL_INC_DIR=${blt_with_tcl_includes} else echo "Can't find tcl.h in \"${blt_with_tcl_includes}\"" exit 1 fi else for dir in \ ${TCL_PREFIX}/include/tcl${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION} \ ${TCL_PREFIX}/include \ ${TCL_SRC_DIR}/generic do if test -r "$dir/tcl.h" ; then TCL_INC_DIR=$dir break fi done if test "x${TCL_INC_DIR}" = "x" ; then echo "Can't find tcl.h header file" exit 1 fi fi if test "x${blt_with_tk_includes}" != "x" ; then if test -r "${blt_with_tk_includes}/tk.h" ; then TK_INC_DIR=${blt_with_tk_includes} else echo "Can't find tk.h in \"${blt_with_tk_includes}\"" exit 1 fi else for dir in \ ${TK_PREFIX}/include/tk${TK_MAJOR_VERSION}.${TK_MINOR_VERSION} \ ${TK_PREFIX}/include \ ${TK_SRC_DIR}/generic \ ${TCL_INC_DIR} do if test -r "$dir/tk.h" ; then TK_INC_DIR=$dir break fi done if test "x${TK_INC_DIR}" = "x" ; then echo "Can't find tk.h header file" exit 1 fi fi case $target in *-sunos4*|*-*-netbsd|NetBSD-*|FreeBSD-*|OpenBSD-*|*-*-cygwin*|*-*-mingw*) TCL_LIB_NAME="tcl${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}" TK_LIB_NAME="tk${TK_MAJOR_VERSION}${TK_MINOR_VERSION}" ;; *) TCL_LIB_NAME="tcl${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}" TK_LIB_NAME="tk${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}" ;; esac TCL_LIB_SPEC="-l${TCL_LIB_NAME}" TK_LIB_SPEC="-l${TK_LIB_NAME}" case $target in *-hpux*) SHLIB_SUFFIX="sl" ;; *) SHLIB_SUFFIX="so" ;; esac TCL_LIB_DIR="${TCL_SRC_DIR}/$blt_platform" TK_LIB_DIR="${TK_SRC_DIR}/$blt_platform" if test "x${blt_with_tcl_libraries}" != "x" ; then for libname in \ "${blt_with_tcl_libraries}/lib${TCL_LIB_NAME}.${SHLIB_SUFFIX}" \ "${blt_with_tcl_libraries}/lib${TCL_LIB_NAME}.a" do if test -r "$libname" ; then TCL_LIB_DIR="${blt_with_tcl_libraries}" break fi done if test "x${TCL_LIB_DIR}" = "x" ; then echo "Can't find tcl library in \"${blt_with_tcl_libraries}\"" exit 1 fi else for libname in \ "${TCL_EXEC_PREFIX}/lib/lib${TCL_LIB_NAME}.${SHLIB_SUFFIX}" \ "${TCL_EXEC_PREFIX}/lib/lib${TCL_LIB_NAME}.a" do if test -r "$libname" ; then TCL_LIB_DIR="${TCL_EXEC_PREFIX}/lib" break fi done if test "x${TCL_LIB_DIR}" = "x" ; then echo "Can't find tcl library" exit 1 fi fi if test "x${blt_with_tk_libraries}" != "x" ; then for libname in \ "${blt_with_tk_libraries}/lib${TK_LIB_NAME}.${SHLIB_SUFFIX}" \ "${blt_with_tk_libraries}/lib${TK_LIB_NAME}.a" do if test -r "$libname" ; then TK_LIB_DIR="${blt_with_tk_libraries}" break fi done if test "x${TK_LIB_DIR}" = "x" ; then echo "Can't find tk library in \"${blt_with_tk_libraries}\"" exit 1 fi else for libname in \ "${TK_EXEC_PREFIX}/lib/lib${TK_LIB_NAME}.${SHLIB_SUFFIX}" \ "${TK_EXEC_PREFIX}/lib/lib${TK_LIB_NAME}.a" do if test -r "$libname" ; then TK_LIB_DIR="${TK_EXEC_PREFIX}/lib" break fi done if test "x${TK_LIB_DIR}" = "x" ; then echo "Can't find tk library" exit 1 fi fi # ----------------------------------------------------------------------- # # Include files # # Append to INC_SPECS the various include files specifications # (built fromt the include directory information). # # ----------------------------------------------------------------------- # JPEG include files if test "${blt_enable_jpeg}" != "no" ; then if test "x${JPEG_INC_SPEC}" != "x" ; then INC_SPECS="${INC_SPECS} ${JPEG_INC_SPEC}" fi fi # Tk include files if test "${TK_INC_DIR}" != "/usr/include" ; then INC_SPECS="${INC_SPECS} -I${TK_INC_DIR}" fi # Tcl include files # # Add the include directory specification only if the Tcl # headers reside in a different directory from Tk's. if test "${TCL_INC_DIR}" != "/usr/include" -a \ "${TCL_INC_DIR}" != "${TK_INC_DIR}" ; then INC_SPECS="${INC_SPECS} -I${TCL_INC_DIR}" fi # On Windows, override the default include directory with our own. if test "${blt_platform}" = "win"; then x_includes="NONE" fi # X11 include files if test "x${x_includes}" != "x" -a \ "${x_includes}" != "NONE" -a \ "${x_includes}" != "/usr/include" -a \ "${x_includes}" != "${TK_INC_DIR}" -a \ "${x_includes}" != "${TCL_INC_DIR}" ; then INC_SPECS="${INC_SPECS} -I${x_includes}" fi # ----------------------------------------------------------------------- # # Libraries # # Append to LIB the various library specifications # (built from the library directory information). # # ----------------------------------------------------------------------- # Tk libraries if test "${TK_LIB_DIR}" = "/usr/lib" ; then LIB_SPECS="${LIB_SPECS} ${TK_LIB_SPEC}" else LIB_SPECS="${LIB_SPECS} -L${TK_LIB_DIR} ${TK_LIB_SPEC}" if test "x${loader_run_path}" = "x" ; then loader_run_path="${TK_LIB_DIR}" else loader_run_path="${TK_LIB_DIR}:${loader_run_path}" fi fi # Tcl libraries if test "${TCL_LIB_DIR}" = "/usr/lib" -o \ "${TCL_LIB_DIR}" = "${TK_LIB_DIR}" ; then LIB_SPECS="${LIB_SPECS} ${TCL_LIB_SPEC}" else LIB_SPECS="${LIB_SPECS} -L${TCL_LIB_DIR} ${TCL_LIB_SPEC}" if test "x${loader_run_path}" = "x" ; then loader_run_path="${TCL_LIB_DIR}" else loader_run_path="${TCL_LIB_DIR}:${loader_run_path}" fi fi if test "${TCL_LIB_DIR}" = "/usr/lib" ; then TCL_ONLY_LIB_SPECS="${TCL_LIB_SPEC}" else TCL_ONLY_LIB_SPECS="-L${TCL_LIB_DIR} ${TCL_LIB_SPEC}" fi # Collect the libraries for AIX that aren't using stubs. aix_lib_specs="" if test "${blt_platform}" = "win"; then LIB_SPECS="${LIB_SPECS} -mwindows" elif test "${blt_platform}" = "unix"; then # Add specification for X11 library only on Unix platforms. if test "x${x_libraries}" = "x" -o \ "x${x_libraries}" = "NONE" -o \ "${x_libraries}" = "/usr/lib" -o \ "${x_libraries}" = "${TK_LIB_DIR}" -o \ "${x_libraries}" = "${TCL_LIB_DIR}" ; then LIB_SPECS="${LIB_SPECS} -lX11" aix_lib_specs="${aix_lib_specs} -lX11" else LIB_SPECS="${LIB_SPECS} -L${x_libraries} -lX11" aix_lib_specs="${aix_lib_specs} -L${x_libraries} -lX11" if test "x${loader_run_path}" = "x" ; then loader_run_path="${x_libraries}" else loader_run_path="${loader_run_path}:${x_libraries}" fi fi fi # JPEG library if test "${blt_enable_jpeg}" != "no" ; then jpeg_save_LDFlags="${LDFLAGS}" JPEG_LIB_SPEC="-ljpeg" JPEG_LIB_DIR="" if test "${blt_enable_jpeg}" != "yes" ; then JPEG_LIB_DIR="${blt_enable_jpeg}/lib" JPEG_LIB_SPEC="-L${JPEG_LIB_DIR} ${JPEG_LIB_SPEC}" LDFLAGS="-L${JPEG_LIB_DIR} ${LDFLAGS}" fi AC_CHECK_LIB(jpeg, jpeg_read_header, [found=yes], [found=no], ) if test "${found}" = "yes" ; then LIB_SPECS="${LIB_SPECS} ${JPEG_LIB_SPEC}" aix_lib_specs="${aix_lib_specs} ${JPEG_LIB_SPEC}" if test "x${JPEG_LIB_DIR}" != "x" ; then loader_run_path="${loader_run_path}:${JPEG_LIB_DIR}" fi fi LDFLAGS=${jpeg_save_LDFlags} fi save_libs=$LIBS LIBS="$LIB_SPECS $LIBS" AC_CHECK_FUNCS(XExtendedMaxRequestSize) LIBS=$save_libs # ----------------------------------------------------------------------- # # Set up a new default prefix to installation path. The ways # the prefix can be set and their precedence are as follows: # # 1. --prefix option given to ./configure. (prefix != NONE) # 2. use previously configured Tk prefix # # ----------------------------------------------------------------------- if test "$prefix" = "NONE" ; then prefix=${TCL_PREFIX} fi if test "$exec_prefix" = "NONE" ; then exec_prefix=${TCL_EXEC_PREFIX} fi # ------------------------------------------------------------------------- # # Extract the BLT version number for the blt.h header # # ------------------------------------------------------------------------- AC_MSG_CHECKING([BLT_MAJOR_VERSION]) AC_CACHE_VAL(blt_cv_major_version, AC_GREP_SYMBOL(blt_cv_major_version, BLT_MAJOR_VERSION, ${srcdir}/src/blt.h) ) BLT_MAJOR_VERSION=${blt_cv_major_version} AC_MSG_RESULT([$blt_cv_major_version]) AC_MSG_CHECKING([BLT_MINOR_VERSION]) AC_CACHE_VAL(blt_cv_minor_version, AC_GREP_SYMBOL(blt_cv_minor_version, BLT_MINOR_VERSION, ${srcdir}/src/blt.h) ) AC_MSG_RESULT([$blt_cv_minor_version]) BLT_MINOR_VERSION=${blt_cv_minor_version} BLT_VERSION=${BLT_MAJOR_VERSION}.${BLT_MINOR_VERSION} # Add BLT to the run path libdir=${exec_prefix}/lib if test "x${libdir}" != "x" -a \ "${libdir}" != "/usr/lib" -a \ "${libdir}" != "${x_libraries}" -a \ "${libdir}" != "${TK_LIB_DIR}" -a \ "${libdir}" != "${TCL_LIB_DIR}" ; then if test "x${loader_run_path}" = "x" ; then loader_run_path="${libdir}" else loader_run_path="${libdir}:${loader_run_path}" fi fi aix_lib_specs="${aix_lib_specs} ${LIBS}" LIB_SPECS="${LIB_SPECS} ${LIBS}" TCL_ONLY_LIB_SPECS="${TCL_ONLY_LIB_SPECS} ${LIBS}" # ------------------------------------------------------------------------- # # Extract the Tcl version number for the tcl.h header # # ------------------------------------------------------------------------- AC_MSG_CHECKING([TCL_VERSION in tcl.h]) AC_CACHE_VAL(blt_cv_tcl_h_version, AC_GREP_SYMBOL(blt_cv_tcl_h_version, [TCL_VERSION], ${TCL_INC_DIR}/tcl.h) ) eval TCL_H_VERSION=${blt_cv_tcl_h_version} AC_MSG_RESULT([$TCL_H_VERSION]) if test "${TCL_H_VERSION}" != "${TCL_VERSION}" ; then echo "Error: Tcl version mismatch. " echo " ${TCL_VERSION} ${tcl_config_sh}" echo " ${TCL_H_VERSION} ${TCL_INC_DIR}/tcl.h" exit 1 fi AC_MSG_CHECKING([TK_VERSION in tk.h]) AC_CACHE_VAL(blt_cv_tk_h_version, AC_GREP_SYMBOL(blt_cv_tk_h_version, [TK_VERSION], ${TK_INC_DIR}/tk.h) ) eval TK_H_VERSION=${blt_cv_tk_h_version} AC_MSG_RESULT([$TK_H_VERSION]) if test "${TK_H_VERSION}" != "${TK_VERSION}" ; then echo "Error: Tk version mismatch." echo " ${TK_VERSION} ${tk_config_sh}" echo " ${TK_H_VERSION} ${TK_INC_DIR}/tk.h" exit 1 fi if test "$TCL_VERSION" = "7.6" -a "$TK_VERSION" = "4.2" ; then : elif test "$TCL_VERSION" = "7.5" -a "$TK_VERSION" = "4.1" ; then : elif test "$TCL_VERSION" = "$TK_VERSION" ; then : else echo "Mismatched Tcl/Tk versions ($TCL_VERSION != $TK_VERSION)" exit 1 fi #-------------------------------------------------------------------- # # Check if we can generate shared libraries on this system. Set flags # to generate shared libraries for systems that we know about. Start # with the values found in tclConfig.sh, make changes as we know about # the different systems. # #-------------------------------------------------------------------- LIB_BASE_NAME=libBLT # Initialize shared library build variables SHLIB_CFLAGS="$TCL_SHLIB_CFLAGS" SHLIB_LD="$TCL_SHLIB_LD" SHLIB_LD_FLAGS="$TCL_LD_FLAGS" SHLIB_RUNPATH="$TCL_LD_SEARCH_FLAGS" SHLIB_SUFFIX=".so" SHLIB_TARGET="" SHLIB_CFLAGS="" SHLIB_LIB_SPECS="${JPEG_LIB_SPEC}" SHLIB_TCL_ONLY_LIB_SPECS="${TCL_ONLY_LIB_SPECS}" SHLIB_TCL_ONLY_LIB_SPECS="" LDFLAGS="" LD_RUN_PATH="" EXTRA_LIB_SPECS="" build_shared="yes" library_name=libBLT${BLT_MAJOR_VERSION}${BLT_MINOR_VERSION} case $target in *-aix4.[[2-9]]*) # No Position-Independent flags needed SHLIB_CFLAGS="" # Use the installed export file or the one found in the source directory. if test -r "${TCL_LIB_DIR}/lib${TCL_LIB_NAME}.exp" ; then tcl_exp="${TCL_LIB_DIR}/lib${TCL_LIB_NAME}.exp" else tcl_exp="${TCL_SRC_DIR}/unix/lib.exp" fi if test -r "${TK_LIB_DIR}/lib${TK_LIB_NAME}.exp" ; then tk_exp="${TK_LIB_DIR}/lib${TK_LIB_NAME}.exp" else tk_exp="${TK_SRC_DIR}/unix/lib.exp" fi full_src_path=`cd ${srcdir}; pwd` # Use shell-script to link shared library SHLIB_LD="${full_src_path}/cf/ldAix /bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry -bI:${tk_exp} -bI:${tcl_exp}" SHLIB_LIB_SPECS="${aix_lib_specs} -lc" LDFLAGS="-L${loader_run_path}" EXTRA_LIB_SPECS="-ldl" ;; *-aix*) # No Position-Independent flags needed SHLIB_CFLAGS="" # Use the installed export file or the one found in the source directory. if test -r "${TCL_LIB_DIR}/lib${TCL_LIB_NAME}.exp" ; then tcl_exp="${TCL_LIB_DIR}/lib${TCL_LIB_NAME}.exp" else tcl_exp="${TCL_SRC_DIR}/unix/lib.exp" fi if test -r "${TK_LIB_DIR}/lib${TK_LIB_NAME}.exp" ; then tk_exp="${TK_LIB_DIR}/lib${TK_LIB_NAME}.exp" else tk_exp="${TK_SRC_DIR}/unix/lib.exp" fi full_src_path=`cd ${srcdir}/cf; pwd` # Use shell-script to link shared library SHLIB_LD="${full_src_path}/ldAix /bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry -bI:${tk_exp} -bI:${tcl_exp}" SHLIB_LIB_SPECS="${aix_lib_specs} -lc" LDFLAGS="-L${loader_run_path}" EXTRA_LIB_SPECS="-lld" ;; *-bsdi2*|*-bsdi3*) SHLIB_CFLAGS="" SHLIB_LD="shlicc" SHLIB_LD_FLAGS="-r" EXTRA_LIB_SPECS="-ldl" ;; *-bsdi4*) SHLIB_CFLAGS="-export-dynamic -fPIC" SHLIB_LD="${CC}" SHLIB_LD_FLAGS='-shared -Wl,-E -Wl,-soname,$@' ;; *-*-cygwin* | *-*-mingw*) SHLIB_LD="${CC}" SHLIB_LD_FLAGS='-shared -Wl,-E -Wl,--out-implib,$@' EXTRA_LIB_SPECS="-lwinspool" LDFLAGS="" ;; *-dgux*) SHLIB_CFLAGS="-K PIC" SHLIB_LD="cc" SHLIB_LD_FLAGS="-G" EXTRA_LIB_SPECS="-ldl" ;; *-hpux*) if test "$blt_have_gcc" = "no" ; then DEFINES="$DEFINES -D_HPUX_SOURCE" fi AC_CHECK_LIB(dld, shl_load, [found=yes], [found=no]) if test "${found}" = "yes" ; then SHLIB_CFLAGS="+Z" SHLIB_LD="ld" SHLIB_LD_FLAGS="-b -E -n +s +b,${loader_run_path}:." SHLIB_SUFFIX=".sl" # The run path is included in both LDFLAGS and SHLIB_LD_FLAGS # because SHLIB_LD is ld and LD is cc/gcc. LDFLAGS="-Wl,-E -Wl,+s,+b,${loader_run_path}:." EXTRA_LIB_SPECS="-ldld" fi ;; *-irix64-6.5*) SHLIB_CFLAGS="" SHLIB_LD="ld" SHLIB_LD_FLAGS="-32 -shared -rdata_shared" LD_RUN_PATH="-Wl,-rpath,${loader_run_path}" ;; *-irix-[56].*|*-irix64-*) SHLIB_CFLAGS="" SHLIB_LD="ld" SHLIB_LD_FLAGS="-shared -rdata_shared" LD_RUN_PATH="-Wl,-rpath,${loader_run_path}" LDFLAGS="" if test "$blt_have_gcc" = "yes" ; then SHLIB_CFLAGS="-mabi=n32 $SHLIB_CFLAGS" SHLIB_LD_FLAGS="-mabi=n32 $SHLIB_LD_FLAGS" LDFLAGS="-mabi=n32 $LDFLAGS" else CFLAGS="-n32 $CFLAGS" LDFLAGS="-n32 $LDFLAGS" fi ;; *-linux*) SHLIB_CFLAGS="-fPIC" SHLIB_LD="${CC}" SHLIB_LD_FLAGS='-rdynamic -shared -Wl,-E -Wl,-soname,$@' LD_RUN_PATH="-Wl,-rpath,${loader_run_path}" LDFLAGS="" EXTRA_LIB_SPECS="-ldl" ;; *-mp-ras-02*) SHLIB_CFLAGS="-G -K PIC" SHLIB_LD="${CC}" SHLIB_LD_FLAGS="" ;; *-mp-ras-*) SHLIB_CFLAGS="-G -K PIC" SHLIB_LD="${CC}" SHLIB_LD_FLAGS="-Wl,-Bexport" ;; *-ncr-sysv4-*2*) SHLIB_CFLAGS="-K PIC" SHLIB_LD="cc" SHLIB_LD_FLAGS="-G" EXTRA_LIB_SPECS="-ldl" ;; *-ncr-sysv4*) SHLIB_CFLAGS="-K PIC" SHLIB_LD="cc" SHLIB_LD_FLAGS="-G -Wl,-Bexport" LDFLAGS="-Wl,-Bexport" EXTRA_LIB_SPECS="-ldl" ;; *-netbsd*|*-freebsd*|*-openbsd*) # Not available on all versions: check for include file. AC_CHECK_HEADER(dlfcn.h, test_ok=yes, test_ok=no) if test "$test_ok" = yes; then SHLIB_CFLAGS="-fpic" SHLIB_LD="ld" SHLIB_LD_FLAGS="-Bshareable -x" fi ;; *-nextstep*) SHLIB_CFLAGS="" SHLIB_LD="cc" SHLIB_LD_FLAGS="-nostdlib -r" ;; *-osf1-1.[012]*) # OSF/1 1.[012] from OSF, and derivatives, including Paragon OSF/1 SHLIB_CFLAGS="" # Warning: Ugly Makefile Hack # Make package name same as library name SHLIB_LD='ld -R -export $@:' ;; *-osf1-1.*) # OSF/1 1.3 from OSF using ELF, and derivatives, including AD2 SHLIB_CFLAGS="-fpic" SHLIB_LD="ld -shared" ;; *-osf1V*) # Digital OSF/1 SHLIB_CFLAGS="" SHLIB_LD='ld' SHLIB_LD_FLAGS='-shared -expect_unresolved "*"' LD_RUN_PATH="-Wl,-rpath,${loader_run_path}" LDFLAGS="" ;; *-sco*) # Note, dlopen is available only on SCO 3.2.5 and greater. However, # this test works, since "uname -s" was non-standard in 3.2.4 and # below. SHLIB_CFLAGS="-Kpic -belf" SHLIB_LD="ld" SHLIB_LD_FLAGS="-G" LDFLAGS="-belf -Wl,-Bexport" ;; *-sni-sysv*) SHLIB_CFLAGS="-K PIC" SHLIB_LD="cc" SHLIB_LD_FLAGS="-G" EXTRA_LIB_SPECS="-ldl" ;; *-sunos4*) SHLIB_CFLAGS="-PIC" SHLIB_LD="ld" SHLIB_LD_FLAGS="-assert pure-text" EXTRA_LIB_SPECS="-ldl" ;; *-solaris2*) SHLIB_CFLAGS="-KPIC" if test "${blt_with_gnu_ld}" = "yes" -a "$blt_have_gcc" = "yes" ; then SHLIB_LD="gcc" SHLIB_LD_FLAGS='-rdynamic -shared -Wl,-E -Wl,-soname,$@' LD_RUN_PATH="-Wl,-rpath,${loader_run_path}" else SHLIB_LD="/usr/ccs/bin/ld" SHLIB_LD_FLAGS="-G -z text" LD_RUN_PATH="-R ${loader_run_path}" fi EXTRA_LIB_SPECS="-ldl" ;; *-mips-dde-sysv*) SHLIB_CFLAGS="-KPIC" SHLIB_LD="cc" SHLIB_LD_FLAGS="-G" EXTRA_LIB_SPECS="-ldl" ;; *-pc-sysv4* | *-unixware-5*) SHLIB_CFLAGS="-G -KPIC" SHLIB_LD="${CC}" SHLIB_LD_FLAGS=" -Wl,-Bexport" ;; *) build_shared="no" ;; esac # If we're running gcc, then set SHLIB_CFLAGS flags for compiling # shared libraries for gcc, instead of those of the vendor's # compiler. if test "$blt_have_gcc" = "yes" ; then SHLIB_CFLAGS="-fPIC" fi # We can't back link against static versions of Tcl/Tk. # If # ${TCL_SHARED_BUILD} can't be found or isn't "1", assume that # shared libraies weren't built. if test "${TCL_SHARED_BUILD}" != "1" ; then SHLIB_LIB_SPECS="" fi if test "${build_shared}" = "yes" ; then SHLIB_TARGET="build_shared" AC_SUBST(SHLIB_CFLAGS) AC_SUBST(SHLIB_TARGET) AC_SUBST(SHLIB_LD) AC_SUBST(SHLIB_LD_FLAGS) AC_SUBST(SHLIB_LIB_SPECS) AC_SUBST(SHLIB_TCL_ONLY_LIB_SPECS) AC_SUBST(SHLIB_SUFFIX) fi AC_SUBST(LDFLAGS) AC_SUBST(LD_RUN_PATH) LIBS=${LIB_SPECS} AC_SUBST(LIB_SPECS) AC_SUBST(TCL_ONLY_LIB_SPECS) AC_SUBST(EXTRA_LIB_SPECS) INCLUDES=${INC_SPECS} AC_SUBST(INCLUDES) AC_SUBST(DEFINES) AC_SUBST(BLT_MAJOR_VERSION) AC_SUBST(BLT_MINOR_VERSION) AC_SUBST(BLT_VERSION) AC_SUBST(AUX_LIBS) AC_SUBST(TCL_LIB_DIR) AC_SUBST(TCL_VERSION) BLT_LIB_PREFIX=${blt_lib_prefix} AC_SUBST(BLT_LIB_PREFIX) #-------------------------------------------------------------------- # The BLT script directory was either specified or we # assume /lib #-------------------------------------------------------------------- if test "x${blt_with_scriptdir}" = "x" ; then BLT_LIBRARY="${prefix}/lib/blt${BLT_VERSION}" else BLT_LIBRARY="${blt_with_scriptdir}/blt${BLT_VERSION}" fi AC_SUBST(BLT_LIBRARY) #-------------------------------------------------------------------- # Print out some of the more important settings #-------------------------------------------------------------------- echo "" echo "Configuration results:" echo "" echo " tcl.h found in $TCL_INC_DIR" echo " tk.h found in $TK_INC_DIR" echo " X11/Xlib.h found in $x_includes" echo " lib${TCL_LIB_NAME} found in $TCL_LIB_DIR" echo " lib${TK_LIB_NAME} found in $TK_LIB_DIR" echo " libX11 found in $x_libraries" echo "" echo "Directories where BLT is to be installed:" echo "" echo " \"\$prefix\" is $prefix" echo " \"\$exec_prefix\" is $exec_prefix" echo "" echo " bltwish to be installed in $bindir" echo " libBLT.a to be installed in $libdir" echo " scripts to be installed in $BLT_LIBRARY" echo " manual pages to be installed in $mandir" echo "" #-------------------------------------------------------------------- # # Generate the following Makefiles # # ./Makefile # ./src/Makefile # ./src/shared/Makefile # ./man/Makefile # ./library/Makefile # ./demos/Makefile # #-------------------------------------------------------------------- src_Makefile="src/Makefile" if test "${blt_platform}" = "win"; then src_Makefile="src/Makefile:src/Makefile-cyg.in" fi AC_OUTPUT(Makefile ${src_Makefile} src/bltHash.h src/shared/Makefile man/Makefile library/Makefile demos/Makefile) blt-2.4z.orig/demos/0042755000175000017500000000000007553201213013056 5ustar dokodokoblt-2.4z.orig/demos/bitmaps/0042755000175000017500000000000007553201207014520 5ustar dokodokoblt-2.4z.orig/demos/bitmaps/fish/0042755000175000017500000000000007553201207015451 5ustar dokodokoblt-2.4z.orig/demos/bitmaps/fish/left.xbm0100644000175000017500000000051407240160072017103 0ustar dokodoko#define fc_left_width 16 #define fc_left_height 16 #define fc_left_x_hot 8 #define fc_left_y_hot 8 static char fc_left_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x04, 0x70, 0x82, 0x8c, 0xe2, 0x22, 0x9c, 0x2d, 0x90, 0x2d, 0x80, 0x21, 0x90, 0x22, 0x9c, 0x1c, 0xe3, 0x70, 0x82, 0x80, 0x02, 0x00, 0x07, 0x00, 0x00}; blt-2.4z.orig/demos/bitmaps/fish/left1.xbm0100644000175000017500000000052107240160072017162 0ustar dokodoko#define fc_left1_width 16 #define fc_left1_height 16 #define fc_left1_x_hot 8 #define fc_left1_y_hot 8 static char fc_left1_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x02, 0xe0, 0x14, 0x10, 0x1f, 0xd8, 0x14, 0xd8, 0x14, 0x08, 0x10, 0x08, 0x14, 0xd0, 0x14, 0x70, 0x1e, 0x60, 0x13, 0x80, 0x01, 0x00, 0x01, 0x00, 0x00}; blt-2.4z.orig/demos/bitmaps/fish/left1m.xbm0100644000175000017500000000052607240160072017344 0ustar dokodoko#define fc_left1m_width 16 #define fc_left1m_height 16 #define fc_left1m_x_hot 8 #define fc_left1m_y_hot 8 static char fc_left1m_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x03, 0xe0, 0x17, 0xf0, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf0, 0x1f, 0xf0, 0x1f, 0xe0, 0x13, 0x80, 0x01, 0x00, 0x01, 0x00, 0x00}; blt-2.4z.orig/demos/bitmaps/fish/leftm.xbm0100644000175000017500000000052107240160072017256 0ustar dokodoko#define fc_leftm_width 16 #define fc_leftm_height 16 #define fc_leftm_x_hot 8 #define fc_leftm_y_hot 8 static char fc_leftm_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x07, 0xf0, 0x83, 0xfc, 0xe3, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfc, 0xe3, 0xf0, 0x83, 0x80, 0x03, 0x00, 0x07, 0x00, 0x00}; blt-2.4z.orig/demos/bitmaps/fish/mid.xbm0100644000175000017500000000050707240160072016724 0ustar dokodoko#define fc_mid_width 16 #define fc_mid_height 16 #define fc_mid_x_hot 8 #define fc_mid_y_hot 8 static char fc_mid_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x80, 0x03, 0x40, 0x04, 0x20, 0x08, 0xe0, 0x0e, 0xe0, 0x0e, 0x20, 0x08, 0xa0, 0x0b, 0xe0, 0x0f, 0xa0, 0x0b, 0x40, 0x04, 0x80, 0x03, 0x80, 0x03, 0x00, 0x00}; blt-2.4z.orig/demos/bitmaps/fish/midm.xbm0100644000175000017500000000051407240160072017077 0ustar dokodoko#define fc_midm_width 16 #define fc_midm_height 16 #define fc_midm_x_hot 8 #define fc_midm_y_hot 8 static char fc_midm_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x80, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xe0, 0x0f, 0xe0, 0x0f, 0xe0, 0x0f, 0xe0, 0x0f, 0xe0, 0x0f, 0xe0, 0x0f, 0xc0, 0x07, 0x80, 0x03, 0x80, 0x03, 0x00, 0x00}; blt-2.4z.orig/demos/bitmaps/fish/right.xbm0100644000175000017500000000052107240160072017264 0ustar dokodoko#define fc_right_width 16 #define fc_right_height 16 #define fc_right_x_hot 8 #define fc_right_y_hot 8 static char fc_right_bits[] = { 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x20, 0x03, 0x41, 0x0e, 0x47, 0x30, 0x39, 0x44, 0x09, 0xb4, 0x01, 0xb4, 0x09, 0x84, 0x39, 0x44, 0xc7, 0x38, 0x41, 0x0e, 0x40, 0x01, 0xe0, 0x00, 0x00, 0x00}; blt-2.4z.orig/demos/bitmaps/fish/right1.xbm0100644000175000017500000000052607240160072017352 0ustar dokodoko#define fc_right1_width 16 #define fc_right1_height 16 #define fc_right1_x_hot 8 #define fc_right1_y_hot 8 static char fc_right1_bits[] = { 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x40, 0x03, 0x28, 0x07, 0xf8, 0x08, 0x28, 0x1b, 0x28, 0x1b, 0x08, 0x10, 0x28, 0x10, 0x28, 0x0b, 0x38, 0x0e, 0xc8, 0x06, 0x80, 0x01, 0x80, 0x00, 0x00, 0x00}; blt-2.4z.orig/demos/bitmaps/fish/right1m.xbm0100644000175000017500000000053307240160072017525 0ustar dokodoko#define fc_right1m_width 16 #define fc_right1m_height 16 #define fc_right1m_x_hot 8 #define fc_right1m_y_hot 8 static char fc_right1m_bits[] = { 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0xc0, 0x03, 0xe8, 0x07, 0xf8, 0x0f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x0f, 0xf8, 0x0f, 0xc8, 0x07, 0x80, 0x01, 0x80, 0x00, 0x00, 0x00}; blt-2.4z.orig/demos/bitmaps/fish/rightm.xbm0100644000175000017500000000052607240160072017446 0ustar dokodoko#define fc_rightm_width 16 #define fc_rightm_height 16 #define fc_rightm_x_hot 8 #define fc_rightm_y_hot 8 static char fc_rightm_bits[] = { 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0xe0, 0x03, 0xc1, 0x0f, 0xc7, 0x3f, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xc7, 0x3f, 0xc1, 0x0f, 0xc0, 0x01, 0xe0, 0x00, 0x00, 0x00}; blt-2.4z.orig/demos/bitmaps/hand/0042755000175000017500000000000007553201207015432 5ustar dokodokoblt-2.4z.orig/demos/bitmaps/hand/hand01.xbm0100644000175000017500000000052607240160072017210 0ustar dokodoko#define hand6-1_width 16 #define hand6-1_height 16 #define hand6-1_x_hot 8 #define hand6-1_y_hot 10 static unsigned char hand6-1_bits[] = { 0x00, 0x00, 0x80, 0x03, 0xe0, 0x0e, 0xa0, 0x1a, 0xa0, 0x2a, 0xa0, 0x2a, 0xa0, 0x2a, 0xb8, 0x2a, 0x28, 0x28, 0x28, 0x20, 0x28, 0x20, 0x08, 0x20, 0x08, 0x20, 0x10, 0x20, 0x20, 0x10, 0xe0, 0x1f}; blt-2.4z.orig/demos/bitmaps/hand/hand01m.xbm0100644000175000017500000000053207240160072017362 0ustar dokodoko#define hand6-1m_width 16 #define hand6-1m_height 16 #define hand6-1m_x_hot 8 #define hand6-1m_y_hot 9 static unsigned char hand6-1m_bits[] = { 0x00, 0x00, 0x80, 0x03, 0xe0, 0x0f, 0xe0, 0x1f, 0xe0, 0x3f, 0xe0, 0x3f, 0xe0, 0x3f, 0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x3f, 0xf0, 0x3f, 0xe0, 0x1f, 0xe0, 0x1f}; blt-2.4z.orig/demos/bitmaps/hand/hand02.xbm0100644000175000017500000000053407240160072017210 0ustar dokodoko#define hand6-02_width 16 #define hand6-02_height 16 #define hand6-02_x_hot 10 #define hand6-02_y_hot 11 static unsigned char hand6-02_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x80, 0x3b, 0x80, 0x2a, 0x80, 0x6a, 0x80, 0xaa, 0xbc, 0xaa, 0xa4, 0xaa, 0xa4, 0xa0, 0xbc, 0x80, 0x80, 0x80, 0xf8, 0x80, 0x08, 0x80, 0xf8, 0xc0, 0x80, 0x7f}; blt-2.4z.orig/demos/bitmaps/hand/hand02m.xbm0100644000175000017500000000054107240160072017363 0ustar dokodoko#define hand6-02m_width 16 #define hand6-02m_height 16 #define hand6-02m_x_hot 10 #define hand6-02m_y_hot 11 static unsigned char hand6-02m_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x80, 0x3f, 0x80, 0x3f, 0x80, 0x7f, 0x80, 0xff, 0xbc, 0xff, 0xbc, 0xff, 0xbc, 0xff, 0xbc, 0xff, 0x80, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0x80, 0x7f}; blt-2.4z.orig/demos/bitmaps/hand/hand03.xbm0100644000175000017500000000053407240160072017211 0ustar dokodoko#define hand6-03_width 16 #define hand6-03_height 16 #define hand6-03_x_hot 10 #define hand6-03_y_hot 11 static unsigned char hand6-03_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x80, 0x3b, 0x80, 0x2a, 0x80, 0x6a, 0xbc, 0xaa, 0xa4, 0xaa, 0xa4, 0xaa, 0xbc, 0xa0, 0x80, 0x80, 0x80, 0x80, 0xf8, 0x80, 0x08, 0x80, 0xf8, 0xc0, 0x80, 0x7f}; blt-2.4z.orig/demos/bitmaps/hand/hand03m.xbm0100644000175000017500000000054107240160072017364 0ustar dokodoko#define hand6-03m_width 16 #define hand6-03m_height 16 #define hand6-03m_x_hot 10 #define hand6-03m_y_hot 11 static unsigned char hand6-03m_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x80, 0x3f, 0x80, 0x3f, 0x80, 0x7f, 0xbc, 0xff, 0xbc, 0xff, 0xbc, 0xff, 0xbc, 0xff, 0x80, 0xff, 0x80, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0x80, 0x7f}; blt-2.4z.orig/demos/bitmaps/hand/hand04.xbm0100644000175000017500000000053407240160072017212 0ustar dokodoko#define hand6-04_width 16 #define hand6-04_height 16 #define hand6-04_x_hot 10 #define hand6-04_y_hot 11 static unsigned char hand6-04_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x80, 0x3b, 0x80, 0x2a, 0xbc, 0x6a, 0xa4, 0xaa, 0xa4, 0xaa, 0xbc, 0xaa, 0x80, 0xa0, 0xb8, 0x80, 0xc8, 0x80, 0x98, 0x80, 0x30, 0x80, 0xe0, 0xc0, 0x80, 0x7f}; blt-2.4z.orig/demos/bitmaps/hand/hand04m.xbm0100644000175000017500000000054107240160072017365 0ustar dokodoko#define hand6-04m_width 16 #define hand6-04m_height 16 #define hand6-04m_x_hot 10 #define hand6-04m_y_hot 11 static unsigned char hand6-04m_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x80, 0x3f, 0x80, 0x3f, 0xbc, 0x7f, 0xbc, 0xff, 0xbc, 0xff, 0xbc, 0xff, 0x80, 0xff, 0xb8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf0, 0xff, 0xe0, 0xff, 0x80, 0x7f}; blt-2.4z.orig/demos/bitmaps/hand/hand05.xbm0100644000175000017500000000053407240160072017213 0ustar dokodoko#define hand6-05_width 16 #define hand6-05_height 16 #define hand6-05_x_hot 10 #define hand6-05_y_hot 11 static unsigned char hand6-05_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xbc, 0x3b, 0xa4, 0x2a, 0xa4, 0x6a, 0xbc, 0xaa, 0x80, 0xaa, 0x80, 0xaa, 0x80, 0xa0, 0xb8, 0x80, 0xc8, 0x80, 0x98, 0x80, 0x30, 0x80, 0xe0, 0xc0, 0x80, 0x7f}; blt-2.4z.orig/demos/bitmaps/hand/hand05m.xbm0100644000175000017500000000054107240160072017366 0ustar dokodoko#define hand6-05m_width 16 #define hand6-05m_height 16 #define hand6-05m_x_hot 10 #define hand6-05m_y_hot 11 static unsigned char hand6-05m_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xbc, 0x3f, 0xbc, 0x3f, 0xbc, 0x7f, 0xbc, 0xff, 0x80, 0xff, 0x80, 0xff, 0x80, 0xff, 0xb8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf0, 0xff, 0xe0, 0xff, 0x80, 0x7f}; blt-2.4z.orig/demos/bitmaps/hand/hand06.xbm0100644000175000017500000000053407240160072017214 0ustar dokodoko#define hand6-06_width 16 #define hand6-06_height 16 #define hand6-06_x_hot 10 #define hand6-06_y_hot 11 static unsigned char hand6-06_bits[] = { 0x00, 0x00, 0x3c, 0x00, 0x24, 0x0e, 0xa4, 0x3b, 0xbc, 0x2a, 0x80, 0x6a, 0x80, 0xaa, 0x80, 0xaa, 0x80, 0xaa, 0x80, 0xa0, 0xb8, 0x80, 0xc8, 0x80, 0x98, 0x80, 0x30, 0x80, 0xe0, 0xc0, 0x80, 0x7f}; blt-2.4z.orig/demos/bitmaps/hand/hand06m.xbm0100644000175000017500000000054107240160072017367 0ustar dokodoko#define hand6-06m_width 16 #define hand6-06m_height 16 #define hand6-06m_x_hot 10 #define hand6-06m_y_hot 11 static unsigned char hand6-06m_bits[] = { 0x00, 0x00, 0x3c, 0x00, 0x3c, 0x0e, 0xbc, 0x3f, 0xbc, 0x3f, 0x80, 0x7f, 0x80, 0xff, 0x80, 0xff, 0x80, 0xff, 0x80, 0xff, 0xb8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf0, 0xff, 0xe0, 0xff, 0x80, 0x7f}; blt-2.4z.orig/demos/bitmaps/hand/hand07.xbm0100644000175000017500000000053407240160072017215 0ustar dokodoko#define hand6-07_width 16 #define hand6-07_height 16 #define hand6-07_x_hot 10 #define hand6-07_y_hot 11 static unsigned char hand6-07_bits[] = { 0x1e, 0x00, 0x12, 0x00, 0x12, 0x0e, 0x9e, 0x3b, 0x80, 0x2a, 0x80, 0x6a, 0x80, 0xaa, 0x80, 0xaa, 0xe0, 0xaa, 0xa0, 0xa0, 0xa0, 0x80, 0xa0, 0x80, 0x20, 0x80, 0x60, 0x80, 0xc0, 0xc0, 0x80, 0x7f}; blt-2.4z.orig/demos/bitmaps/hand/hand07m.xbm0100644000175000017500000000054107240160072017370 0ustar dokodoko#define hand6-07m_width 16 #define hand6-07m_height 16 #define hand6-07m_x_hot 10 #define hand6-07m_y_hot 11 static unsigned char hand6-07m_bits[] = { 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x0e, 0x9e, 0x3f, 0x80, 0x3f, 0x80, 0x7f, 0x80, 0xff, 0x80, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xc0, 0xff, 0x80, 0x7f}; blt-2.4z.orig/demos/bitmaps/hand/hand08.xbm0100644000175000017500000000053407240160072017216 0ustar dokodoko#define hand6-08_width 16 #define hand6-08_height 16 #define hand6-08_x_hot 10 #define hand6-08_y_hot 11 static unsigned char hand6-08_bits[] = { 0x00, 0x00, 0x0f, 0x00, 0x09, 0x0e, 0x89, 0x3b, 0x8f, 0x2a, 0x80, 0x6a, 0x80, 0xaa, 0x80, 0xaa, 0xe0, 0xaa, 0xa0, 0xa0, 0xa0, 0x80, 0xa0, 0x80, 0x20, 0x80, 0x60, 0x80, 0xc0, 0xc0, 0x80, 0x7f}; blt-2.4z.orig/demos/bitmaps/hand/hand08m.xbm0100644000175000017500000000054107240160072017371 0ustar dokodoko#define hand6-08m_width 16 #define hand6-08m_height 16 #define hand6-08m_x_hot 10 #define hand6-08m_y_hot 11 static unsigned char hand6-08m_bits[] = { 0x00, 0x00, 0x0f, 0x00, 0x0f, 0x0e, 0x8f, 0x3f, 0x8f, 0x3f, 0x80, 0x7f, 0x80, 0xff, 0x80, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xc0, 0xff, 0x80, 0x7f}; blt-2.4z.orig/demos/bitmaps/hand/hand09.xbm0100644000175000017500000000053407240160072017217 0ustar dokodoko#define hand6-09_width 16 #define hand6-09_height 16 #define hand6-09_x_hot 10 #define hand6-09_y_hot 11 static unsigned char hand6-09_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0e, 0x89, 0x3b, 0x89, 0x2a, 0x8f, 0x6a, 0x80, 0xaa, 0x80, 0xaa, 0xe0, 0xaa, 0xa0, 0xa0, 0xa0, 0x80, 0xa0, 0x80, 0x20, 0x80, 0x60, 0x80, 0xc0, 0xc0, 0x80, 0x7f}; blt-2.4z.orig/demos/bitmaps/hand/hand09m.xbm0100644000175000017500000000054107240160072017372 0ustar dokodoko#define hand6-09m_width 16 #define hand6-09m_height 16 #define hand6-09m_x_hot 10 #define hand6-09m_y_hot 11 static unsigned char hand6-09m_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0e, 0x8f, 0x3f, 0x8f, 0x3f, 0x8f, 0x7f, 0x80, 0xff, 0x80, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xc0, 0xff, 0x80, 0x7f}; blt-2.4z.orig/demos/bitmaps/hand/hand10.xbm0100644000175000017500000000053407240160072017207 0ustar dokodoko#define hand6-10_width 16 #define hand6-10_height 16 #define hand6-10_x_hot 10 #define hand6-10_y_hot 11 static unsigned char hand6-10_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x80, 0x3b, 0x8f, 0x2a, 0x89, 0x6a, 0x89, 0xaa, 0x8f, 0xaa, 0xe0, 0xaa, 0xa0, 0xa0, 0xa0, 0x80, 0xa0, 0x80, 0x20, 0x80, 0x60, 0x80, 0xc0, 0xc0, 0x80, 0x7f}; blt-2.4z.orig/demos/bitmaps/hand/hand10m.xbm0100644000175000017500000000054107240160072017362 0ustar dokodoko#define hand6-10m_width 16 #define hand6-10m_height 16 #define hand6-10m_x_hot 10 #define hand6-10m_y_hot 11 static unsigned char hand6-10m_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x80, 0x3f, 0x8f, 0x3f, 0x8f, 0x7f, 0x8f, 0xff, 0x8f, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xc0, 0xff, 0x80, 0x7f}; blt-2.4z.orig/demos/bitmaps/hand/hand11.xbm0100644000175000017500000000053407240160072017210 0ustar dokodoko#define hand6-11_width 16 #define hand6-11_height 16 #define hand6-11_x_hot 10 #define hand6-11_y_hot 11 static unsigned char hand6-11_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x80, 0x3b, 0x80, 0x2a, 0x80, 0x6a, 0x8f, 0xaa, 0x89, 0xaa, 0xe9, 0xaa, 0xaf, 0xa0, 0xa0, 0x80, 0xa0, 0x80, 0x20, 0x80, 0x60, 0x80, 0xc0, 0xc0, 0x80, 0x7f}; blt-2.4z.orig/demos/bitmaps/hand/hand11m.xbm0100644000175000017500000000054107240160072017363 0ustar dokodoko#define hand6-11m_width 16 #define hand6-11m_height 16 #define hand6-11m_x_hot 10 #define hand6-11m_y_hot 11 static unsigned char hand6-11m_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x80, 0x3f, 0x80, 0x3f, 0x80, 0x7f, 0x8f, 0xff, 0x8f, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xc0, 0xff, 0x80, 0x7f}; blt-2.4z.orig/demos/bitmaps/hand/hand12.xbm0100644000175000017500000000053407240160072017211 0ustar dokodoko#define hand6-12_width 16 #define hand6-12_height 16 #define hand6-12_x_hot 10 #define hand6-12_y_hot 11 static unsigned char hand6-12_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x80, 0x3b, 0x80, 0x2a, 0x80, 0x6a, 0x80, 0xaa, 0x80, 0xaa, 0xef, 0xaa, 0xa9, 0xa0, 0xa9, 0x80, 0xaf, 0x80, 0x20, 0x80, 0x60, 0x80, 0xc0, 0xc0, 0x80, 0x7f}; blt-2.4z.orig/demos/bitmaps/hand/hand12m.xbm0100644000175000017500000000054107240160072017364 0ustar dokodoko#define hand6-12m_width 16 #define hand6-12m_height 16 #define hand6-12m_x_hot 10 #define hand6-12m_y_hot 11 static unsigned char hand6-12m_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x80, 0x3f, 0x80, 0x3f, 0x80, 0x7f, 0x80, 0xff, 0x80, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xc0, 0xff, 0x80, 0x7f}; blt-2.4z.orig/demos/bitmaps/hand/hand13.xbm0100644000175000017500000000053407240160072017212 0ustar dokodoko#define hand6-13_width 16 #define hand6-13_height 16 #define hand6-13_x_hot 10 #define hand6-13_y_hot 11 static unsigned char hand6-13_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x80, 0x3b, 0x80, 0x2a, 0x80, 0x6a, 0x80, 0xaa, 0x80, 0xaa, 0xe0, 0xaa, 0xa0, 0xa0, 0xaf, 0x80, 0xa9, 0x80, 0x29, 0x80, 0x6f, 0x80, 0xc0, 0xc0, 0x80, 0x7f}; blt-2.4z.orig/demos/bitmaps/hand/hand13m.xbm0100644000175000017500000000054107240160072017365 0ustar dokodoko#define hand6-13m_width 16 #define hand6-13m_height 16 #define hand6-13m_x_hot 10 #define hand6-13m_y_hot 11 static unsigned char hand6-13m_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x80, 0x3f, 0x80, 0x3f, 0x80, 0x7f, 0x80, 0xff, 0x80, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xc0, 0xff, 0x80, 0x7f}; blt-2.4z.orig/demos/bitmaps/hand/hand14.xbm0100644000175000017500000000053407240160072017213 0ustar dokodoko#define hand6-14_width 16 #define hand6-14_height 16 #define hand6-14_x_hot 10 #define hand6-14_y_hot 11 static unsigned char hand6-14_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x80, 0x3b, 0x80, 0x2a, 0x80, 0x6a, 0x80, 0xaa, 0x80, 0xaa, 0xe0, 0xaa, 0xa0, 0xa0, 0xa0, 0x80, 0xa0, 0x80, 0x2f, 0x80, 0x69, 0x80, 0xc9, 0xc0, 0x8f, 0x7f}; blt-2.4z.orig/demos/bitmaps/hand/hand14m.xbm0100644000175000017500000000054107240160072017366 0ustar dokodoko#define hand6-14m_width 16 #define hand6-14m_height 16 #define hand6-14m_x_hot 10 #define hand6-14m_y_hot 11 static unsigned char hand6-14m_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x80, 0x3f, 0x80, 0x3f, 0x80, 0x7f, 0x80, 0xff, 0x80, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xef, 0xff, 0xef, 0xff, 0xcf, 0xff, 0x8f, 0x7f}; blt-2.4z.orig/demos/bitmaps/face.xbm0100644000175000017500000003060407240160072016121 0ustar dokodoko#define face_width 108 #define face_height 144 static char face_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x20, 0x80, 0x24, 0x05, 0x00, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x88, 0x24, 0x20, 0x80, 0x24, 0x00, 0x00, 0x00, 0x10, 0x80, 0x04, 0x00, 0x01, 0x00, 0x01, 0x40, 0x0a, 0x09, 0x00, 0x92, 0x04, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x12, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x84, 0x24, 0x40, 0x22, 0xa8, 0x02, 0x14, 0x84, 0x92, 0x40, 0x42, 0x12, 0x04, 0x10, 0x00, 0x00, 0x00, 0x00, 0x52, 0x00, 0x52, 0x11, 0x00, 0x12, 0x00, 0x40, 0x02, 0x00, 0x20, 0x00, 0x08, 0x00, 0xaa, 0x02, 0x54, 0x85, 0x24, 0x00, 0x10, 0x12, 0x00, 0x00, 0x81, 0x44, 0x00, 0x90, 0x5a, 0x00, 0xea, 0x1b, 0x00, 0x80, 0x40, 0x40, 0x02, 0x00, 0x08, 0x00, 0x20, 0xa2, 0x05, 0x8a, 0xb4, 0x6e, 0x45, 0x12, 0x04, 0x08, 0x00, 0x00, 0x00, 0x10, 0x02, 0xa8, 0x92, 0x00, 0xda, 0x5f, 0x10, 0x00, 0x10, 0xa1, 0x04, 0x20, 0x41, 0x02, 0x00, 0x5a, 0x25, 0xa0, 0xff, 0xfb, 0x05, 0x41, 0x02, 0x04, 0x00, 0x00, 0x08, 0x40, 0x80, 0xec, 0x9b, 0xec, 0xfe, 0x7f, 0x01, 0x04, 0x20, 0x90, 0x02, 0x04, 0x00, 0x08, 0x20, 0xfb, 0x2e, 0xf5, 0xff, 0xff, 0x57, 0x00, 0x04, 0x02, 0x00, 0x00, 0x20, 0x01, 0xc1, 0x6e, 0xab, 0xfa, 0xff, 0xff, 0x05, 0x90, 0x20, 0x48, 0x02, 0x00, 0x04, 0x20, 0xa8, 0xdf, 0xb5, 0xfe, 0xff, 0xff, 0x0b, 0x01, 0x00, 0x01, 0x00, 0x80, 0x80, 0x04, 0xe0, 0xbb, 0xef, 0xff, 0xff, 0x7f, 0x01, 0x00, 0x04, 0x48, 0x02, 0x00, 0x20, 0x80, 0xf4, 0x6f, 0xfb, 0xff, 0xff, 0xff, 0x20, 0x90, 0x40, 0x02, 0x00, 0x00, 0x04, 0x08, 0xb8, 0xf6, 0xff, 0xff, 0xdf, 0xbe, 0x12, 0x45, 0x10, 0x90, 0x04, 0x90, 0x00, 0x22, 0xfa, 0xff, 0xff, 0xff, 0xbb, 0xd7, 0xe9, 0x3a, 0x02, 0x02, 0x00, 0x04, 0x90, 0x80, 0xfe, 0xdf, 0xf6, 0xb7, 0xef, 0xbe, 0x56, 0x57, 0x40, 0x48, 0x09, 0x00, 0x04, 0x00, 0xfa, 0xf5, 0xdf, 0xed, 0x5a, 0xd5, 0xea, 0xbd, 0x09, 0x00, 0x00, 0x40, 0x00, 0x92, 0xfe, 0xbf, 0x7d, 0xb7, 0x6a, 0x55, 0xbf, 0xf7, 0x02, 0x11, 0x01, 0x00, 0x91, 0x00, 0xff, 0xff, 0xaf, 0x55, 0x55, 0x5b, 0xeb, 0xef, 0x22, 0x04, 0x04, 0x04, 0x00, 0xa4, 0xff, 0xf7, 0xad, 0xaa, 0xaa, 0xaa, 0xbe, 0xfe, 0x03, 0x20, 0x00, 0x10, 0x44, 0x80, 0xff, 0x7f, 0x55, 0x12, 0x91, 0x2a, 0xeb, 0xbf, 0x0b, 0x82, 0x02, 0x00, 0x00, 0xd1, 0x7f, 0xdf, 0xa2, 0xa4, 0x54, 0x55, 0xfd, 0xfd, 0x47, 0x08, 0x08, 0x00, 0x21, 0xe4, 0xff, 0x37, 0x11, 0x09, 0xa5, 0xaa, 0xb6, 0xff, 0x0d, 0x80, 0x00, 0x00, 0x04, 0xd0, 0xff, 0x4f, 0x44, 0x20, 0x48, 0x55, 0xfb, 0xff, 0x27, 0x11, 0x02, 0x40, 0x40, 0xe2, 0xfb, 0x15, 0x11, 0x4a, 0x55, 0x4a, 0x7d, 0xf7, 0x0f, 0x00, 0x00, 0x04, 0x08, 0xf8, 0xdf, 0x52, 0x44, 0x01, 0x52, 0xb5, 0xfa, 0xff, 0x0f, 0x49, 0x02, 0x00, 0x02, 0xe9, 0xf6, 0x0a, 0x11, 0xa4, 0x88, 0x4a, 0x6d, 0xff, 0x5f, 0x00, 0x00, 0x10, 0x20, 0xf0, 0x2f, 0x21, 0x44, 0x10, 0x52, 0xb5, 0xfa, 0xff, 0x0f, 0x44, 0x04, 0x80, 0x08, 0xf8, 0xab, 0x8a, 0x00, 0x81, 0xa4, 0xd4, 0xd6, 0xfe, 0x2f, 0x00, 0x00, 0x04, 0x40, 0xb5, 0x2d, 0x21, 0x08, 0x04, 0x90, 0xaa, 0xfa, 0xff, 0x1f, 0x11, 0x01, 0x00, 0x04, 0xf0, 0x57, 0x0a, 0x22, 0x40, 0x4a, 0xda, 0x5e, 0xfb, 0x1f, 0x40, 0x00, 0x40, 0x20, 0xba, 0x95, 0x90, 0x00, 0x01, 0xa0, 0xaa, 0xea, 0xff, 0x5f, 0x02, 0x02, 0x00, 0x01, 0xe8, 0x57, 0x05, 0x00, 0x00, 0x12, 0xd5, 0xfe, 0xfd, 0x1f, 0x48, 0x00, 0x04, 0x48, 0x7a, 0x95, 0x08, 0x02, 0x10, 0x40, 0xaa, 0x55, 0xf7, 0x1f, 0x00, 0x09, 0x20, 0x00, 0xf8, 0x57, 0x22, 0x10, 0x00, 0x28, 0xa9, 0xfa, 0xff, 0x5f, 0x02, 0x00, 0x00, 0x49, 0xdd, 0x29, 0x01, 0x00, 0x80, 0x80, 0xaa, 0xd7, 0xff, 0x0f, 0x10, 0x00, 0x08, 0x00, 0xf8, 0x96, 0x08, 0x00, 0x00, 0x20, 0x54, 0xfa, 0xee, 0x3f, 0x81, 0x04, 0x40, 0x24, 0xfe, 0x55, 0x82, 0x00, 0x00, 0x82, 0xd2, 0xad, 0xff, 0x0f, 0x08, 0x00, 0x04, 0x80, 0x6c, 0x97, 0x00, 0x00, 0x02, 0x20, 0xa9, 0xf6, 0xdf, 0x5f, 0x00, 0x02, 0x20, 0x09, 0xfa, 0x49, 0x12, 0x00, 0x20, 0x84, 0x54, 0xdb, 0xfe, 0x1f, 0x91, 0x00, 0x00, 0x00, 0xf8, 0x2b, 0x00, 0x20, 0x00, 0x40, 0xa4, 0xf6, 0xbb, 0x1f, 0x04, 0x00, 0x44, 0x92, 0x7e, 0x95, 0x02, 0x00, 0x00, 0x89, 0xaa, 0xdd, 0xff, 0x1f, 0x20, 0x09, 0x10, 0x00, 0xf4, 0x57, 0x20, 0x01, 0x08, 0x20, 0xa9, 0x76, 0xff, 0x5f, 0x02, 0x00, 0x00, 0x21, 0xfc, 0x4a, 0x05, 0x00, 0x01, 0x80, 0x54, 0xdb, 0xff, 0x1e, 0x08, 0x02, 0x04, 0x08, 0xf9, 0x2b, 0x00, 0x00, 0x40, 0x28, 0xd2, 0xf6, 0xff, 0xbf, 0x80, 0x00, 0x90, 0x00, 0xbc, 0x92, 0x08, 0x10, 0x00, 0x82, 0x54, 0xdb, 0xff, 0x1f, 0x20, 0x00, 0x00, 0x44, 0xf9, 0x55, 0x02, 0x01, 0x00, 0x20, 0xaa, 0xbd, 0xfd, 0x3f, 0x08, 0x04, 0x04, 0x10, 0xf4, 0x2a, 0x01, 0x00, 0x22, 0x80, 0xd4, 0xf6, 0xff, 0x5f, 0x82, 0x00, 0x40, 0x02, 0xf8, 0x55, 0x20, 0x00, 0x00, 0x50, 0x6a, 0xdf, 0xfe, 0x3f, 0x00, 0x00, 0x00, 0x48, 0xe9, 0x4a, 0x05, 0x08, 0x00, 0xa5, 0xd5, 0xf5, 0xff, 0x3f, 0x10, 0x01, 0x10, 0x01, 0xb0, 0xab, 0x92, 0x02, 0x40, 0xf8, 0xbf, 0xde, 0xfe, 0x5f, 0x02, 0x04, 0x04, 0x48, 0xfa, 0xd4, 0x6f, 0x20, 0x84, 0xef, 0xff, 0xfb, 0xff, 0x1f, 0x20, 0x00, 0x00, 0x00, 0xe0, 0xed, 0xbf, 0x0b, 0xa1, 0x7e, 0xff, 0xbf, 0xfd, 0x5f, 0x04, 0x01, 0x20, 0x49, 0xd2, 0xfb, 0xfe, 0x55, 0xd4, 0xff, 0xff, 0xf6, 0xff, 0x07, 0x00, 0x04, 0x00, 0x00, 0xc0, 0xaa, 0xfb, 0x2b, 0xa2, 0xfe, 0xff, 0xdf, 0xee, 0x1f, 0x91, 0x00, 0x82, 0xa4, 0xa4, 0xf5, 0xff, 0x57, 0xd5, 0xff, 0xbf, 0xfd, 0xff, 0x4d, 0x00, 0x00, 0x20, 0x00, 0x88, 0x5b, 0xff, 0x2f, 0x69, 0xff, 0xff, 0xdb, 0xfe, 0x1f, 0x24, 0x02, 0x00, 0x49, 0xa2, 0xd6, 0xff, 0x5f, 0xea, 0xff, 0x7f, 0x7f, 0x7f, 0x0d, 0x00, 0x00, 0x10, 0x00, 0x40, 0xab, 0xf7, 0xbb, 0xf0, 0xdf, 0xff, 0xd5, 0xff, 0xbf, 0x82, 0x04, 0x42, 0x24, 0x91, 0xd5, 0xaa, 0xae, 0xd4, 0xaa, 0x52, 0x7b, 0xff, 0x15, 0x08, 0x00, 0x00, 0x01, 0x04, 0x55, 0xd5, 0x55, 0x70, 0x5b, 0x75, 0xdd, 0xdf, 0x1f, 0x40, 0x00, 0x08, 0x48, 0xa0, 0x4a, 0xa9, 0x56, 0xea, 0x56, 0xad, 0x6a, 0x7d, 0x9b, 0x04, 0x01, 0x00, 0x02, 0x42, 0x2a, 0xd5, 0xaa, 0xa8, 0xaa, 0xaa, 0xfa, 0xdf, 0x2f, 0x10, 0x04, 0x22, 0x48, 0x08, 0x45, 0x2a, 0x15, 0x68, 0x55, 0x55, 0xd7, 0x76, 0x1b, 0x00, 0x00, 0x00, 0x01, 0x40, 0x2a, 0x80, 0xa0, 0xb2, 0x09, 0x48, 0xb9, 0xdf, 0x17, 0x22, 0x01, 0x00, 0x24, 0x45, 0x8a, 0x24, 0x4a, 0x54, 0x51, 0x91, 0xf6, 0x6e, 0x4b, 0x00, 0x04, 0x90, 0x00, 0x80, 0x52, 0x00, 0x20, 0x69, 0x05, 0xa4, 0xaa, 0xff, 0x1e, 0x48, 0x00, 0x02, 0x92, 0x08, 0x05, 0x81, 0x94, 0xd4, 0x92, 0x40, 0xfd, 0xb6, 0x8b, 0x00, 0x01, 0x40, 0x00, 0x82, 0x54, 0x00, 0x48, 0x68, 0x05, 0x90, 0xa4, 0xef, 0x06, 0x24, 0x00, 0x08, 0x12, 0x10, 0x05, 0x00, 0x10, 0xb5, 0x01, 0x42, 0xfb, 0xbf, 0x43, 0x00, 0x09, 0x00, 0x40, 0x81, 0xa8, 0x08, 0x4a, 0xaa, 0x96, 0x90, 0xac, 0x6d, 0x15, 0x22, 0x00, 0x20, 0x09, 0x04, 0x15, 0x80, 0x28, 0xdc, 0x01, 0x24, 0xfb, 0xbf, 0x01, 0x80, 0x04, 0x09, 0x00, 0x40, 0x48, 0x02, 0x45, 0xb2, 0x2e, 0x41, 0x6d, 0xef, 0x05, 0x11, 0x00, 0x40, 0x52, 0x02, 0x15, 0x29, 0x2a, 0xac, 0x42, 0x54, 0xfb, 0x3b, 0x51, 0x84, 0x00, 0x08, 0x00, 0x20, 0x54, 0x80, 0x05, 0xb5, 0x3d, 0xa2, 0xb6, 0xdf, 0x00, 0x20, 0x04, 0x20, 0x49, 0x89, 0xa8, 0x6a, 0x29, 0xac, 0xd6, 0x54, 0xff, 0x3f, 0x84, 0x00, 0x01, 0x04, 0x10, 0x00, 0x94, 0xa8, 0x56, 0xda, 0x5f, 0xab, 0xd5, 0x1e, 0x10, 0x48, 0x00, 0x90, 0x82, 0x48, 0xa8, 0xb2, 0xac, 0xfd, 0x55, 0xd5, 0xfe, 0x9f, 0x80, 0x00, 0x0a, 0x02, 0x08, 0x02, 0x55, 0x5a, 0x75, 0xff, 0xaf, 0xb6, 0xf7, 0x2d, 0x12, 0x92, 0x00, 0x10, 0x20, 0x10, 0xa8, 0x54, 0xd5, 0xbf, 0x5d, 0xad, 0xdd, 0x0f, 0x00, 0x00, 0x04, 0x40, 0x09, 0x84, 0xa8, 0xaa, 0x5a, 0xed, 0xeb, 0x6a, 0xff, 0x9f, 0xa4, 0x24, 0x01, 0x02, 0xa0, 0x20, 0x50, 0x55, 0xd5, 0xbe, 0xae, 0xad, 0xfd, 0x16, 0x00, 0x10, 0x04, 0x20, 0x0a, 0x08, 0xb4, 0xaa, 0x95, 0xaa, 0x7b, 0xb7, 0xdb, 0x5f, 0x92, 0x04, 0x01, 0x84, 0x20, 0x21, 0x51, 0xd5, 0x2a, 0xa9, 0xee, 0xd5, 0xfe, 0x0d, 0x00, 0x20, 0x04, 0x10, 0x00, 0x08, 0x50, 0xe9, 0xd7, 0xd4, 0xfb, 0xb5, 0xff, 0x9f, 0x24, 0x09, 0x01, 0x42, 0x4a, 0xa2, 0x64, 0xd5, 0x55, 0x7b, 0x7f, 0xda, 0x7d, 0x4f, 0x00, 0x20, 0x04, 0x00, 0x80, 0x00, 0xa0, 0x2a, 0x13, 0x84, 0x6a, 0x55, 0xff, 0x1d, 0x48, 0x8a, 0x00, 0x94, 0x24, 0x8a, 0xc8, 0xaa, 0x42, 0x20, 0x5d, 0xf5, 0xff, 0x5f, 0x01, 0x00, 0x02, 0x01, 0x00, 0x20, 0xa2, 0x4a, 0x1a, 0x82, 0x56, 0xda, 0xbd, 0x3f, 0x92, 0x92, 0x00, 0x90, 0x92, 0x00, 0x40, 0x95, 0x6a, 0xf4, 0x55, 0x6d, 0xff, 0xd6, 0x00, 0x00, 0x0a, 0x04, 0x20, 0x14, 0x49, 0x4b, 0xaa, 0xaa, 0x56, 0xf5, 0xff, 0xbf, 0xab, 0xa4, 0x00, 0x20, 0x89, 0x40, 0x80, 0xaa, 0xaa, 0xaa, 0xaa, 0xde, 0xbf, 0xeb, 0x03, 0x00, 0x02, 0x04, 0x02, 0x0a, 0x10, 0x2b, 0x2a, 0x55, 0x5b, 0xf5, 0xff, 0xd7, 0x2f, 0x92, 0x00, 0x10, 0x28, 0x21, 0x01, 0x56, 0x95, 0xa0, 0x56, 0xdf, 0xef, 0xea, 0x87, 0x40, 0x0a, 0x42, 0x41, 0x00, 0x90, 0xaa, 0x52, 0xb6, 0xad, 0xfa, 0xff, 0xd5, 0x2f, 0x14, 0x00, 0x00, 0x04, 0x95, 0x04, 0xaa, 0xac, 0x55, 0x6b, 0xff, 0xb7, 0xea, 0x9f, 0x40, 0x02, 0x28, 0x51, 0x00, 0x40, 0x58, 0xd5, 0xda, 0xd6, 0x6e, 0x7f, 0xf9, 0x3f, 0x12, 0x04, 0x02, 0x04, 0x49, 0x25, 0x55, 0xaa, 0x77, 0xab, 0xff, 0x2b, 0xfd, 0x3f, 0x48, 0x01, 0x20, 0x41, 0x00, 0x00, 0x58, 0xa9, 0xda, 0xea, 0xfd, 0xaf, 0xfa, 0xff, 0x02, 0x04, 0x08, 0x14, 0x29, 0x49, 0x52, 0x55, 0x55, 0x55, 0xff, 0x8d, 0xfe, 0x3f, 0xa8, 0x00, 0x02, 0x41, 0x00, 0x02, 0xa0, 0xa2, 0xaa, 0xea, 0xff, 0x53, 0xfd, 0xff, 0x02, 0x04, 0x50, 0x04, 0x25, 0xa8, 0x54, 0x49, 0x52, 0xb5, 0xbf, 0x8a, 0xfe, 0xff, 0xa9, 0x08, 0x04, 0x50, 0x80, 0x02, 0xa1, 0x2a, 0x95, 0xea, 0xff, 0xa1, 0xff, 0xff, 0x03, 0x02, 0x90, 0x02, 0x09, 0x08, 0x44, 0x49, 0x52, 0xbd, 0x7f, 0xca, 0xff, 0xff, 0x2b, 0x09, 0x04, 0x48, 0x40, 0x82, 0x90, 0x56, 0xa9, 0xf6, 0xbf, 0xd0, 0xff, 0xff, 0x47, 0x00, 0x50, 0x02, 0x15, 0x11, 0x40, 0x95, 0xaa, 0xfd, 0x2f, 0xe9, 0xff, 0xff, 0x8f, 0x0a, 0x84, 0x50, 0x40, 0x84, 0x14, 0xaa, 0x6a, 0xff, 0x5f, 0xf2, 0xff, 0xff, 0x7f, 0x00, 0x10, 0x02, 0x09, 0x10, 0x40, 0x7d, 0xf7, 0xff, 0x0b, 0xfc, 0xff, 0xff, 0xaf, 0x02, 0x84, 0x50, 0x42, 0x85, 0x12, 0xd0, 0xdd, 0xff, 0xa7, 0xf2, 0xff, 0xff, 0xff, 0x04, 0x00, 0x0a, 0x08, 0x10, 0x48, 0xf8, 0xff, 0xff, 0x0a, 0xfe, 0xff, 0xff, 0x7f, 0x03, 0xa4, 0x80, 0xa2, 0x8a, 0x02, 0x68, 0xff, 0xff, 0x52, 0xfd, 0xff, 0xff, 0xff, 0x07, 0x00, 0x2a, 0x08, 0x20, 0x28, 0xdc, 0xff, 0x5f, 0x05, 0xff, 0xff, 0xff, 0xff, 0x0d, 0x92, 0x40, 0x22, 0x09, 0x02, 0xea, 0xfb, 0xaf, 0x48, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x12, 0x81, 0xa0, 0x48, 0x9c, 0x6e, 0x93, 0xa2, 0xff, 0xff, 0xff, 0xff, 0x07, 0xa8, 0x40, 0x28, 0x0a, 0x02, 0x74, 0xb5, 0x45, 0x81, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x02, 0x0a, 0x81, 0x20, 0x08, 0xae, 0xaa, 0x90, 0xe8, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x90, 0x40, 0x28, 0x88, 0x12, 0x58, 0x15, 0x50, 0xd0, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x44, 0x0a, 0x41, 0x21, 0x08, 0xae, 0x04, 0x14, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x10, 0x40, 0x14, 0x88, 0x04, 0xba, 0x02, 0x28, 0xe8, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x42, 0x15, 0x41, 0x21, 0x05, 0xad, 0x00, 0x05, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x10, 0x40, 0x24, 0x8a, 0x0e, 0x36, 0x00, 0x0a, 0xf4, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x42, 0x25, 0x90, 0xd0, 0x8b, 0xc2, 0x41, 0x05, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x10, 0x08, 0x05, 0xe8, 0x8e, 0x58, 0x80, 0x02, 0xfa, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x4a, 0x20, 0xa8, 0xba, 0x0b, 0x2b, 0x51, 0x01, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x8a, 0x02, 0xe8, 0xaf, 0x84, 0x90, 0x04, 0xfd, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x52, 0x21, 0x54, 0xbf, 0x1f, 0x15, 0xa5, 0x02, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x08, 0x01, 0xfa, 0xb6, 0xa4, 0x52, 0x40, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x4a, 0xa2, 0x54, 0xef, 0x5f, 0x4b, 0xa4, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x80, 0x10, 0x82, 0xfe, 0xbf, 0x92, 0x52, 0x42, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x12, 0x42, 0xa8, 0xbf, 0x1f, 0x24, 0x80, 0xa0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x84, 0x28, 0x8a, 0xf7, 0x37, 0x80, 0x52, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x10, 0x82, 0xe0, 0xff, 0x1f, 0x00, 0x20, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x84, 0x28, 0xca, 0xff, 0x1f, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x10, 0x42, 0xf0, 0xfd, 0x1b, 0x00, 0x50, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xa4, 0x10, 0xc5, 0xff, 0x1f, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x22, 0xf8, 0xff, 0x0e, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xaa, 0x88, 0xe2, 0xff, 0x0f, 0x10, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x25, 0xfa, 0xff, 0x0f, 0x01, 0x11, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xfb, 0xfb, 0xff, 0x7f, 0x5d, 0xd5, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f}; blt-2.4z.orig/demos/bitmaps/greenback.xbm0100644000175000017500000020464507240160072017154 0ustar dokodoko#define greenback_width 499 #define greenback_height 210 static char greenback_bits[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x44, 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x21,0x09,0x10,0x00,0x00,0x00, 0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00, 0x20,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x22,0x00,0x40,0x00, 0x08,0x20,0x20,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x10, 0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x02,0x00, 0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x08,0x11,0x00,0x00,0x01,0x00, 0x00,0x00,0x48,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x20,0x02,0x04, 0x48,0x10,0x02,0x01,0x01,0x09,0x00,0x00,0x80,0x00,0x80,0x00,0x00,0x00,0x00, 0x22,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x04,0x04,0x48,0x10,0x01, 0x41,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x02,0x04,0x10,0x40,0x00,0x00,0x00, 0x40,0x00,0x02,0x08,0x48,0x00,0x02,0x80,0x20,0x00,0x00,0x80,0x04,0x00,0x00, 0x01,0x40,0x00,0x00,0x04,0x10,0x00,0x44,0x00,0x00,0x00,0x10,0x14,0x22,0x54, 0xa4,0xb6,0xf7,0xfe,0x6f,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0x9f,0xaa,0xd9, 0x95,0xef,0xfe,0xba,0xda,0xd7,0x56,0x77,0xaf,0x56,0x7d,0x81,0x50,0x45,0x15, 0xc9,0x00,0x00,0x00,0x6d,0xb5,0xd3,0x95,0xab,0xaa,0x35,0xad,0xaa,0x4a,0x29, 0x40,0x92,0x40,0x80,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x20,0x11,0x22,0x12,0x00,0x21,0x25,0x55,0xa8,0xa4,0x54,0xa9,0xaa,0x92,0x7e, 0x6f,0x7b,0xed,0xbe,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x88,0x00,0x42,0xa4,0x00,0x08, 0x41,0x00,0x00,0x01,0x00,0x81,0x80,0xa4,0x54,0x5b,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe7,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x08,0x00,0x10,0xfd,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe7,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xbb,0xf7,0x80,0x84, 0x28,0x22,0x00,0x06,0x14,0x0c,0x68,0x04,0x08,0x80,0xf7,0xf7,0xfd,0xff,0xbf, 0xfb,0xff,0xf3,0xff,0xff,0xbb,0xea,0xef,0xbb,0xbf,0x00,0x00,0x00,0xdd,0xbf, 0xfe,0xbf,0xfe,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xef,0xe7,0x8a,0x5a, 0x82,0x92,0xb4,0x40,0x48,0x40,0x7f,0x7b,0x54,0x3e,0x02,0x06,0x00,0x07,0x00, 0x00,0x0c,0x06,0x03,0x23,0x08,0x1e,0x30,0x8e,0xe1,0x84,0x08,0x0e,0xe7,0xbf, 0xbe,0xef,0x7b,0xf5,0xda,0xb5,0xbd,0x5f,0xbf,0xff,0xee,0xae,0xbf,0x00,0x00, 0x00,0xf5,0x5d,0x9f,0xdf,0xdf,0xff,0xff,0xef,0xbf,0x63,0xeb,0xfe,0xbf,0xd6, 0xe5,0xc0,0x18,0x1c,0x83,0xc1,0xe0,0x38,0x1a,0x3c,0xf0,0x81,0x3f,0x18,0x18, 0x1c,0x83,0x7f,0xf0,0x1c,0x06,0x02,0x77,0x78,0x3e,0x61,0x83,0x43,0x82,0x19, 0x2c,0x67,0xd5,0x6f,0x53,0xb7,0xdd,0xff,0xe5,0x67,0xed,0xee,0xae,0xe7,0x7d, 0xab,0x08,0x00,0x00,0xbd,0xdf,0xaf,0x7f,0xbb,0xfd,0xee,0xcf,0xfb,0xdf,0xbf, 0xff,0xfd,0xfb,0xe7,0xc1,0x19,0x2c,0x87,0xc1,0x61,0x3b,0x1c,0x1c,0xf0,0xc1, 0x7f,0x38,0x38,0x6c,0x01,0xf0,0xa0,0x1d,0x06,0x06,0x7f,0xc8,0x7f,0xc0,0x83, 0xc3,0x96,0x9b,0xf0,0xe7,0xfe,0xdd,0xdd,0xfd,0xdf,0xae,0xa4,0xbb,0xba,0xbf, 0xdd,0x77,0xff,0xbb,0x00,0x00,0x00,0xf5,0x6e,0xaf,0x6f,0xfe,0x5f,0xfb,0xd7, 0xbf,0x7b,0xff,0x4e,0x77,0xef,0xe5,0x01,0x1e,0xe2,0x87,0xc3,0x21,0x3f,0x80, 0xdf,0xe0,0xe1,0xff,0x00,0x3e,0xe4,0x03,0x60,0x10,0x3f,0x82,0x0f,0x7a,0xd0, 0xfe,0x01,0x83,0xc3,0x87,0x1f,0x6c,0xe7,0x5b,0x7f,0xbf,0xb7,0xad,0x7b,0xe6, 0xad,0x6a,0xd7,0xfb,0xcd,0xbe,0xbd,0x20,0x00,0x24,0x5d,0xbf,0xb6,0x5f,0xdd, 0x57,0xfd,0x95,0xff,0xf7,0xdb,0xbd,0xbf,0xde,0xe7,0xc1,0x9e,0x6c,0x87,0xc1, 0x61,0x3b,0x08,0x2e,0xe0,0xe1,0x7f,0x18,0x3c,0x6c,0x17,0x60,0xa2,0x1d,0x06, 0x0f,0x3c,0x78,0x7e,0x03,0x83,0xc3,0x03,0x1f,0x3c,0xf7,0xfe,0xdb,0xfb,0xee, 0xff,0x7f,0xe6,0xdf,0xf7,0xf6,0x76,0xcb,0xbe,0xbd,0x02,0x00,0x00,0xf5,0x7b, 0x33,0xb5,0x5e,0xeb,0x57,0x97,0xdf,0xb5,0x7f,0xff,0xb5,0x5f,0xe3,0xc0,0x1f, 0x1c,0x83,0xc1,0xe0,0x38,0x18,0xe6,0xc0,0x61,0x3c,0x10,0x18,0x0c,0xf3,0x70, 0x30,0x0c,0x24,0x1e,0x1e,0x08,0x1e,0x46,0x8f,0xf1,0x03,0x86,0x04,0xa7,0xdd, 0xb6,0xfe,0xba,0xaf,0x7f,0x67,0xf7,0xdf,0xbf,0xdb,0xdb,0x7f,0xbe,0x00,0x00, 0x00,0xdd,0xfc,0xaa,0x2e,0xff,0xfa,0xff,0x27,0x7f,0x7b,0xb3,0x77,0x7b,0xdb, 0x67,0x10,0x06,0x00,0x49,0xba,0x2a,0x08,0x25,0x80,0x00,0x84,0x2c,0x64,0x00, 0x50,0x57,0xbf,0xdf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xe7,0xfe,0xea,0xff,0xb3,0xff,0x6f,0xd7,0xfa,0xb5,0xf6,0xeb,0x9a,0x9f, 0xb6,0x20,0x00,0x00,0xbd,0x79,0x3b,0xb6,0xde,0xde,0xdb,0x35,0xef,0xf6,0x5d, 0xf7,0xdb,0x7e,0xe7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xe7,0xff,0xff,0xff,0xff,0xff,0xbf,0x47,0x6d,0xff,0xba, 0xff,0xdb,0x97,0xbe,0x08,0x00,0x00,0xcd,0xf6,0xb6,0xae,0xad,0xf7,0x76,0x35, 0xfe,0xff,0xff,0xff,0xff,0xff,0xa7,0x56,0x7b,0x55,0x92,0x52,0x40,0x22,0x01, 0x08,0xa4,0x54,0x4a,0x01,0x12,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0xe0,0xe7, 0xd6,0xef,0xe7,0x91,0x35,0x57,0xbe,0x00,0x00,0x00,0xfd,0xe6,0x3c,0xf7,0x5a, 0xfc,0xcf,0x32,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x10,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x01, 0x00,0x00,0x42,0x04,0xb5,0xd2,0xaa,0xfa,0xef,0xff,0xf7,0xf7,0xbd,0x55,0xdd, 0xb6,0xad,0xc7,0xf3,0xfe,0xfe,0xe3,0x9d,0x6b,0xbe,0x00,0x00,0x40,0xdd,0xde, 0x77,0x8e,0xc5,0x7f,0xaf,0x5f,0xf2,0xff,0xff,0xff,0xff,0xbf,0xed,0x75,0xab, 0xd6,0x5a,0x55,0x8b,0x54,0x55,0xa9,0xab,0xaa,0xaa,0xaa,0x00,0x02,0x08,0x80, 0x10,0x10,0x00,0x84,0x20,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xa2,0xd3,0xfd,0x4b,0x49,0x40,0x77,0x7f,0xbe,0x02,0x00, 0x00,0xfd,0xd6,0xbd,0x81,0xb6,0xfd,0xaf,0x3b,0x02,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x04,0x20,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x92,0xe7,0x74,0x01,0x00,0x04,0x00,0x20, 0xbe,0x00,0x00,0x08,0xed,0xaa,0x7d,0x48,0x1d,0xee,0x6f,0x7e,0x36,0x40,0x80, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x04,0x00,0x00,0x00,0x41,0x20,0x84,0x00,0x02,0x00,0x00,0x08,0x10,0x00,0x20, 0x42,0x02,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x55,0xf7,0xa7,0xad, 0xfe,0x6d,0x79,0xbf,0x40,0x00,0x00,0xfd,0x96,0x3d,0x82,0xeb,0xba,0x7f,0x2b, 0x15,0x02,0x21,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x24,0x22,0x00, 0x00,0x00,0x00,0x28,0x00,0x42,0x00,0x00,0x02,0x00,0x00,0x00,0x11,0x00,0x00, 0x00,0x44,0x08,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x82,0x00,0x21,0xb0,0x67, 0xa7,0xe7,0xff,0xf7,0xff,0x1b,0xbf,0x00,0x00,0x00,0xed,0xb4,0x0d,0xfc,0x14, 0xf4,0xed,0x7c,0x82,0x10,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x80,0x80,0x24, 0x00,0x00,0x04,0x01,0x00,0x20,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x40,0x00, 0x00,0x02,0x00,0x08,0x00,0x02,0x80,0x10,0x80,0x40,0x04,0x11,0x20,0x40,0x10, 0x08,0xa9,0xad,0xe5,0xb7,0xff,0x7b,0xff,0x5a,0xb3,0x08,0x00,0x00,0xdd,0x2a, 0x01,0x7f,0xff,0xe9,0xef,0xb8,0x0a,0x00,0x00,0x20,0x00,0x00,0x04,0x00,0x08, 0x20,0x08,0x80,0x08,0x00,0x40,0x00,0x40,0x00,0x00,0x09,0x01,0x20,0x00,0x00, 0x10,0x00,0x00,0xc0,0x40,0x42,0x02,0x0a,0xa8,0x60,0xeb,0x7f,0x5a,0x1b,0xd5, 0xa1,0x0a,0x0c,0x00,0xa5,0xaf,0x53,0xb3,0xde,0xfa,0x57,0xdb,0xbf,0x00,0x00, 0x20,0xfd,0x4a,0x93,0x6f,0xf7,0xc9,0xaf,0x78,0x03,0x40,0x24,0x8a,0x02,0x40, 0x01,0x25,0x21,0x15,0xa5,0x02,0x52,0x49,0x05,0xad,0x00,0x80,0x11,0x52,0x42, 0x41,0xb5,0xfd,0x17,0xbd,0x07,0x10,0x45,0x95,0x00,0x10,0x00,0x49,0x55,0xd1, 0xea,0x4a,0xfd,0xc8,0x16,0x28,0x00,0xda,0x7d,0xe5,0x52,0xff,0xb3,0x7f,0xd2, 0xbb,0x00,0x00,0x08,0xad,0x1a,0xc8,0xdb,0xef,0x87,0xaf,0xb8,0x2e,0xf8,0xff, 0x3f,0x3f,0x3f,0x17,0xf0,0x79,0x5e,0xcf,0xf7,0xff,0xbc,0x9e,0xdf,0x04,0x68, 0xfe,0xff,0x87,0xe1,0xef,0x78,0x5c,0x8c,0x0b,0x34,0x16,0x8e,0x0b,0x5c,0xf6, 0xf2,0xc0,0xe1,0xf2,0x78,0x79,0x74,0x5c,0x5c,0x00,0xe5,0xff,0xe2,0x79,0xdf, 0xcc,0xb7,0xe7,0xbf,0x00,0x00,0x00,0xfd,0x65,0xe4,0x7f,0xfe,0x1e,0xaf,0x7d, 0x0b,0x78,0x67,0x3c,0x1e,0x3e,0x07,0xf8,0x60,0xbe,0x86,0xf7,0xef,0x38,0x5c, 0x1e,0x0b,0x70,0x9c,0xbb,0xc7,0xe5,0xde,0x71,0x9c,0x07,0x03,0x3d,0xae,0x8e, 0x43,0x98,0xf8,0xe5,0xd9,0xe9,0xf4,0x78,0x7a,0x7a,0x4a,0x1c,0x00,0x6d,0x3f, 0x13,0x38,0xa9,0xf9,0xad,0x85,0xb6,0x09,0x00,0x00,0x5d,0x69,0x75,0xb3,0xd4, 0x9b,0x0e,0xbb,0x01,0xb8,0xef,0xbc,0x9e,0x9c,0x6e,0xf0,0x29,0x3d,0xa1,0x77, 0xce,0x38,0x1b,0x1e,0x2f,0x3c,0xb1,0x79,0xd3,0x73,0xce,0x70,0x3e,0xe7,0x36, 0x9c,0x5e,0x4f,0x13,0x3e,0xe2,0xe9,0xf4,0xe9,0xf4,0xfe,0x7a,0x3a,0x95,0xbe, 0x41,0xb9,0x5d,0x30,0xdf,0x76,0xb7,0xd7,0x1f,0xf6,0x00,0x00,0x04,0xad,0x12, 0xb2,0x7e,0xbe,0x39,0xae,0x71,0x08,0x10,0xe7,0x3e,0x9e,0x9c,0xa6,0xf0,0x34, 0x7d,0x94,0x33,0xcf,0x38,0x5c,0x9f,0x4f,0x78,0xbd,0x39,0xd6,0x63,0x9e,0x79, 0x18,0x4f,0x27,0x1d,0x9f,0x8e,0x12,0x3e,0xf1,0xe9,0xec,0xd9,0xfc,0x7c,0x3a, 0x3e,0xcb,0x3d,0x02,0x7a,0x5b,0xa5,0xff,0xfc,0x08,0x4e,0x7f,0xbf,0x00,0x00, 0x00,0xbd,0x37,0xb9,0xda,0x5e,0xea,0x4c,0x73,0x05,0x99,0x67,0xbc,0x9f,0x9e, 0x26,0xf0,0x8c,0xfa,0xb0,0x37,0xcf,0x3c,0x8b,0x1e,0xcf,0xfc,0x85,0x78,0xd7, 0x73,0x4f,0x71,0x0a,0xff,0x10,0x9e,0x3f,0x4e,0x33,0x39,0xd3,0xe3,0xc5,0x59, 0xf8,0x7a,0x7e,0x3d,0x41,0x78,0x02,0xe6,0xbe,0xe2,0xb7,0x70,0xa5,0xe6,0xbb, 0xb7,0x00,0x00,0x00,0xdd,0x2d,0x3d,0xb7,0xfa,0x79,0xcd,0xb3,0x28,0x54,0x6f, 0x3e,0x9e,0xdc,0x6a,0xf0,0x2e,0xf1,0xd0,0x27,0xcf,0x3c,0x4b,0x9f,0x8f,0xf8, 0x9f,0x3c,0xa5,0x27,0xdf,0x78,0x83,0xff,0x33,0x3e,0x9f,0x7e,0x10,0x78,0xd2, 0xeb,0xec,0x1f,0xfb,0x3e,0x79,0x7c,0xd3,0x78,0x06,0x6a,0x5d,0x62,0xfa,0x6c, 0x00,0xb6,0x97,0xbf,0x00,0x00,0x00,0xbd,0x9b,0x5c,0x7a,0x5f,0xf6,0x5a,0x33, 0x0d,0x40,0x47,0xbc,0x9e,0xdc,0x24,0xf0,0x84,0xe2,0x93,0x93,0x9e,0xb8,0x53, 0x1f,0x5f,0xf0,0xff,0x7a,0x05,0xa7,0x8e,0x74,0xd3,0xfe,0x17,0x9f,0x3e,0x6f, 0xae,0xf1,0x8d,0xe7,0xc4,0xd9,0xf4,0x9c,0x7d,0x3d,0xb5,0x7c,0x04,0xec,0x59, 0x73,0x9f,0x39,0x00,0xd7,0x9d,0xbd,0x10,0x00,0x08,0xad,0x4e,0xbe,0x1d,0x50, 0xdd,0xb1,0x5b,0x06,0xa0,0x2f,0x3f,0x9e,0x9c,0x28,0xf0,0x24,0xdb,0xb3,0x77, 0x4f,0x3a,0x21,0x9e,0xcf,0x88,0x3f,0x3a,0x89,0xaf,0xce,0x75,0x3a,0xa0,0x07, 0x9e,0x9e,0x4e,0x81,0xfa,0x94,0xf7,0xec,0x89,0xf0,0x78,0x38,0x3e,0x19,0xf0, 0x04,0x54,0x57,0x33,0xfd,0x06,0x00,0xeb,0xaf,0xbb,0x04,0x00,0x00,0xfd,0x4f, 0xce,0xd5,0xcb,0xfa,0x35,0x13,0x0d,0x81,0x47,0x3c,0x9f,0x3c,0x0c,0xf2,0x24, 0xe1,0xd3,0xa7,0xce,0x3c,0x14,0x9e,0x8e,0x04,0x3c,0x79,0x52,0x2f,0x0f,0x79, 0x00,0x82,0x27,0x3d,0x9f,0x4e,0x86,0xf0,0xcc,0xe7,0xcd,0xc9,0xf2,0x7a,0x7b, 0x39,0x91,0xe1,0x09,0x95,0xa7,0xb6,0xfb,0x11,0x10,0x6e,0x47,0xbf,0x00,0x00, 0x00,0x5d,0xa3,0xdf,0x09,0xc0,0xad,0x77,0xab,0x06,0x88,0x67,0xbe,0x9e,0x9e, 0x4e,0xf0,0x8d,0x92,0xab,0x17,0x4f,0x38,0x39,0x1f,0x4f,0xd8,0x3a,0x3d,0x0d, 0x5e,0xde,0x70,0xba,0x79,0x66,0x9e,0x9e,0xce,0xc3,0xe4,0x99,0xf3,0xc4,0xfb, 0xf4,0x7a,0x7e,0x7a,0xc6,0xfc,0x09,0xd8,0x6a,0xbd,0x5e,0x0f,0x01,0xdf,0x65, 0xbf,0x00,0x00,0x00,0xfd,0x27,0xd7,0x06,0xd0,0xf7,0xeb,0x0a,0x2a,0x85,0x27, 0xbc,0x1e,0xbd,0x4e,0xf0,0x24,0xb3,0xd3,0x13,0xcf,0x3c,0x9f,0x9e,0xcf,0x98, 0x32,0x7b,0xca,0x9e,0x9e,0x75,0x1e,0x53,0x47,0x3c,0x8f,0x8e,0xa2,0xee,0x91, 0xea,0xd5,0xe9,0xf8,0x7c,0x79,0x76,0xca,0xf0,0x09,0x30,0x75,0x9b,0xfa,0x1e, 0x80,0xb6,0x57,0xbb,0x00,0x00,0x00,0xbd,0x65,0xfb,0x09,0xd0,0x5d,0xf7,0x62, 0x07,0xa0,0x6f,0x3d,0x9f,0x1e,0x4f,0xe0,0x09,0x47,0xd3,0xb7,0x9f,0xba,0x3c, 0x1e,0xa3,0x38,0x3b,0x7d,0x1a,0x9d,0x1f,0x79,0xbe,0xcf,0x31,0x34,0xe7,0x7f, 0xf8,0xf5,0x7b,0xf9,0xfa,0xab,0x74,0xf5,0xac,0xec,0xb1,0x96,0x32,0x60,0xaf, 0xed,0x54,0xbf,0x00,0xdf,0xd2,0xbf,0x12,0x00,0x00,0xed,0x96,0x6b,0x82,0xc0, 0xb7,0x4e,0xa2,0x85,0xa0,0x1f,0xff,0xbf,0xbf,0x8f,0xd0,0x8b,0x1f,0xe6,0xaf, 0xbf,0x7e,0x9f,0xdf,0x51,0xfc,0x8c,0xfd,0x5e,0x7f,0x7f,0xfd,0x1a,0xbf,0x28, 0xa4,0x21,0x84,0x00,0x09,0x80,0x01,0x00,0x00,0x00,0x04,0x00,0x12,0x00,0x00, 0x10,0x61,0x9a,0x7d,0xb6,0x2d,0x10,0x77,0x99,0xbb,0x00,0x00,0x08,0xad,0x93, 0xd6,0x24,0xd8,0xfd,0xf5,0xd5,0x25,0x20,0x40,0x00,0x00,0x00,0x40,0x00,0x60, 0x40,0x10,0x00,0x00,0x02,0x80,0x00,0x2c,0x00,0x20,0x02,0x80,0x00,0x00,0x02, 0x00,0x01,0x14,0x10,0xd0,0x28,0x61,0x50,0x55,0xbe,0xaf,0xba,0xae,0x95,0xb6, 0x4d,0x7e,0x6b,0x37,0x40,0x6a,0x9f,0xed,0xbd,0x00,0xbf,0xeb,0xb7,0x00,0x00, 0x00,0xfd,0x92,0xfd,0x01,0xe0,0x1f,0x6d,0x97,0x05,0x44,0xa5,0x2a,0xa0,0xaa, 0x52,0xc0,0xa0,0x52,0xb4,0x52,0x4a,0x69,0x55,0x15,0x29,0x20,0x68,0x00,0x84, 0x24,0xa9,0x55,0xf7,0x4a,0x0b,0x90,0x2c,0x57,0x81,0x47,0x55,0x61,0x55,0xeb, 0x52,0xeb,0xda,0xa6,0x45,0xad,0xea,0x80,0x59,0x8c,0x6a,0x37,0x00,0xfb,0x7b, 0xbe,0x10,0x00,0x00,0xfd,0xa9,0xb3,0x0f,0xd0,0xab,0xdd,0xe9,0x0a,0x00,0x5b, 0xd5,0xaf,0x5a,0xad,0x00,0x5d,0xac,0x28,0x6d,0xb4,0x52,0x55,0x55,0x0b,0xc0, 0x17,0xf8,0xb5,0xea,0x6a,0x53,0x4d,0xb9,0x02,0x40,0x05,0x54,0x02,0x95,0xaa, 0x4a,0xad,0x2a,0x45,0x15,0xa5,0x0a,0x02,0x83,0x04,0x08,0xff,0x4d,0xb1,0x9f, 0x00,0x5e,0x41,0xbd,0x00,0x00,0x00,0xad,0xd9,0xcf,0x06,0xf2,0x53,0xee,0x6d, 0x01,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xa8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8, 0x4e,0x6a,0x3d,0x88,0xab,0x35,0xb6,0x00,0x00,0x00,0x7d,0xa9,0xbd,0x13,0xc0, 0x09,0xd3,0x7a,0x03,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x10,0x00, 0x10,0x05,0x78,0x35,0x6d,0xb7,0x00,0x1e,0x2d,0xb7,0x08,0x00,0x00,0x9d,0xa9, 0x3f,0x06,0xd0,0x7c,0xa2,0x6b,0x10,0x90,0x04,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x20, 0x08,0x00,0x00,0x00,0x80,0x42,0x00,0x00,0x00,0x20,0x00,0x00,0x80,0x00,0x00, 0x00,0x00,0x20,0x00,0x18,0x62,0xfd,0xf2,0xb0,0x80,0xe2,0xc9,0xbb,0x00,0x00, 0x20,0xdd,0xa8,0xb6,0x15,0xf2,0x1d,0xf2,0xbe,0x82,0x00,0x20,0x00,0x00,0x00, 0x00,0x80,0x00,0x00,0x02,0x00,0x04,0x00,0x40,0x40,0x00,0x00,0x00,0x00,0x00, 0x00,0x10,0x00,0x02,0x02,0x80,0x10,0x08,0x00,0x00,0x11,0x00,0x04,0x41,0x00, 0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x90,0xc8,0xec,0xf5,0x35,0x20,0xf7,0xe9, 0xbd,0x00,0x00,0x04,0xbd,0xa9,0xaf,0x85,0xc0,0x35,0xd4,0x54,0x28,0x80,0x00, 0x10,0x11,0x01,0x04,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x09,0x00,0x00,0x00, 0x00,0x04,0x00,0x00,0x00,0x10,0x40,0x20,0x22,0x80,0x00,0x00,0x40,0x00,0x21, 0x01,0x00,0x00,0x08,0x20,0x04,0x88,0x08,0x02,0x00,0xbc,0xe5,0x1f,0xf1,0xbd, 0x08,0x6b,0xe9,0xbf,0x22,0x00,0x00,0xdc,0x98,0xb7,0x17,0xd8,0x7d,0xae,0xad, 0x02,0x20,0x00,0x04,0x00,0x20,0x01,0x10,0x00,0x00,0x00,0x24,0x00,0x49,0x00, 0x00,0x00,0x22,0x04,0x80,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x40, 0x10,0x00,0x00,0x00,0x20,0x84,0x80,0x00,0x80,0x00,0x00,0x20,0x04,0x64,0x92, 0x1d,0x65,0x2d,0x00,0xde,0x65,0xb5,0x00,0x00,0x00,0xdd,0x28,0xfb,0x07,0xc0, 0xfb,0x6c,0x23,0x5a,0x08,0x20,0x00,0x00,0x00,0x00,0x00,0x20,0x01,0x00,0x00, 0x10,0x00,0x00,0x10,0x20,0x00,0x20,0x02,0x10,0x00,0x40,0x80,0x08,0x00,0x00, 0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x40,0xb8,0xa7,0xdb,0xf3,0xb6,0x80,0x66,0xf1,0xbb,0x08,0x00,0x00,0x7d,0x4c, 0x5f,0x17,0xd0,0x5b,0xe4,0x00,0x20,0x01,0x04,0x00,0x00,0x00,0x00,0x00,0x00, 0x20,0x02,0x00,0x00,0x00,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0x00, 0x00,0x44,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x40,0x10, 0x00,0x00,0x00,0x00,0x68,0x55,0xda,0xe3,0x1e,0x00,0xdf,0xf5,0xbd,0x00,0x00, 0x00,0x9d,0x58,0xf7,0x82,0xd0,0x9f,0x2d,0x9f,0x97,0x06,0x00,0x00,0x38,0x15, 0x62,0x1f,0x9f,0xfc,0x8a,0xcb,0xbe,0x87,0x20,0x00,0x00,0x00,0x00,0x40,0x00, 0x00,0x00,0x10,0x90,0x00,0x22,0x0a,0x09,0x92,0x10,0x84,0x20,0x00,0x80,0x10, 0x00,0x04,0x00,0x20,0x82,0x08,0x00,0xc0,0x75,0xeb,0x62,0xbd,0x00,0x5a,0x75, 0xb7,0x02,0x00,0x00,0xed,0xc8,0x94,0x15,0xe4,0x55,0xc9,0x3c,0x10,0x8c,0x00, 0x00,0x90,0x35,0x0e,0x09,0x8d,0xd4,0x0b,0xe9,0xaa,0x23,0x00,0xa0,0x2a,0xad, 0x57,0x09,0x8a,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08, 0x00,0x24,0x04,0x44,0x00,0x00,0x08,0x20,0x00,0x02,0x00,0xde,0xae,0xe7,0x3a, 0x88,0xd7,0x9b,0xbf,0x10,0x00,0x00,0x7d,0xd8,0x2c,0x04,0xd0,0x58,0xab,0x77, 0xa0,0x0c,0x00,0x00,0x41,0x00,0x26,0x2b,0x89,0x71,0x0d,0x81,0x9a,0x13,0x00, 0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x84,0x48,0xa5,0xa2,0x4a,0x45,0x00, 0x84,0x00,0x00,0x04,0x00,0x00,0x01,0x00,0x04,0x00,0x00,0x00,0x00,0x20,0x70, 0xcd,0x62,0xad,0x00,0x4b,0xb5,0xbb,0x0a,0x00,0x00,0x9d,0xa8,0xb1,0x07,0xe0, 0xbb,0xca,0x99,0xd2,0x11,0x04,0x10,0x00,0x14,0x00,0x10,0x00,0x00,0x40,0x00, 0x00,0x00,0x01,0x40,0xc7,0x9f,0x7c,0xef,0x87,0xff,0xff,0xe3,0x97,0xbd,0xfc, 0xe5,0x02,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x08,0x01,0x00,0x00,0x40, 0x00,0x42,0xa0,0xff,0xe3,0x1d,0x00,0xb6,0x5b,0xbd,0x00,0x00,0x00,0x6c,0x1c, 0xdb,0x15,0xd1,0xbb,0xd1,0xf6,0x85,0x3b,0x00,0x01,0x00,0x80,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x50,0x00,0x00,0x33,0x1f,0x34,0xeb,0xf1,0xff,0xff,0x8f, 0x77,0x5d,0xfd,0xd0,0x05,0x00,0x00,0x00,0x80,0x40,0x00,0x00,0x00,0x01,0x80, 0x00,0x00,0x02,0x40,0x80,0x6a,0xbb,0x73,0xb6,0x90,0xae,0xf3,0xbf,0x00,0x00, 0x00,0xfd,0x88,0xea,0x07,0xd0,0xfb,0xe9,0xa9,0xa2,0x6e,0x00,0x10,0x11,0x01, 0x08,0x25,0x00,0x02,0x42,0x10,0x2a,0x09,0x0c,0x40,0xfd,0xe0,0xb7,0x7f,0xfe, 0xff,0xff,0x7f,0xfc,0xcb,0x27,0xbf,0x04,0x80,0x10,0x04,0x20,0x00,0x08,0x00, 0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0xd6,0xee,0xf3,0x3d,0x00,0xab,0x93, 0xbf,0x00,0x00,0x00,0x6d,0x58,0xd8,0x05,0xc4,0xdd,0xab,0xe2,0x4f,0x7f,0x02, 0xb7,0xa5,0xc4,0xed,0x37,0x3e,0xd6,0x67,0x72,0x6c,0xab,0x0f,0x49,0xeb,0xe5, 0xd7,0x1b,0xff,0xff,0xff,0xff,0xd1,0xeb,0xcf,0xbf,0x05,0x00,0x00,0x00,0x04, 0x00,0x80,0x10,0x10,0x00,0x00,0x08,0x08,0x00,0x00,0x00,0xb8,0x5d,0x73,0x97, 0x00,0xde,0x73,0xb5,0x02,0x00,0x40,0x6d,0x32,0x7f,0x97,0xd0,0x7b,0xeb,0xcd, 0xf2,0x5a,0x00,0x8e,0x61,0xc4,0xed,0x32,0x9e,0x52,0xa1,0x56,0x7c,0x2d,0x0d, 0x00,0x3f,0xeb,0xf9,0xe7,0xff,0xff,0xff,0xff,0x47,0xdf,0xaa,0xee,0x02,0x00, 0x44,0x80,0x00,0x40,0x20,0x00,0x02,0x20,0x00,0x80,0x00,0x20,0x00,0x00,0x42, 0xb7,0xf9,0xbe,0x90,0xee,0xf3,0xbf,0x20,0x00,0x10,0x7c,0x30,0xbe,0x07,0xd2, 0xff,0xd3,0xc2,0xc7,0xf5,0x20,0xab,0x71,0x44,0xa5,0x02,0x24,0x96,0x65,0x54, 0x42,0x65,0x05,0x40,0xc3,0xee,0xf7,0xe2,0xff,0x7f,0xf5,0xff,0x9f,0xb5,0xab, 0x83,0x01,0x09,0x00,0x20,0x00,0x08,0x04,0x10,0x40,0x02,0x00,0x00,0x40,0x08, 0x00,0x10,0xa0,0xfb,0xd9,0x2a,0x04,0xf7,0xa2,0xbd,0x08,0x00,0x00,0xfd,0x5a, 0xbc,0x04,0xf0,0xda,0xeb,0x94,0x0d,0x68,0x00,0x22,0x08,0xca,0x64,0xb2,0x66, 0x52,0x82,0x14,0x40,0x14,0x04,0x00,0x3c,0x6b,0xbd,0xfc,0xff,0x02,0x80,0xff, 0x3f,0xbe,0xcd,0x3c,0x02,0x80,0x40,0x08,0x00,0x02,0x00,0x00,0x00,0x80,0x88, 0x00,0x08,0x00,0x08,0x00,0xb4,0xee,0xf9,0xb6,0xa0,0xea,0xe7,0xb7,0x02,0x00, 0x00,0xcd,0x30,0xbd,0x17,0xd1,0x2c,0xaa,0xe5,0x27,0x80,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x43,0x77,0x3d,0xff,0x0b, 0x0a,0x21,0xfc,0xff,0x68,0xef,0x80,0x00,0x00,0x10,0x00,0x80,0x80,0x00,0x08, 0x42,0x08,0x00,0x08,0x00,0x01,0x00,0x01,0x51,0xfb,0xf9,0xb1,0x00,0xd6,0xe7, 0xbe,0x00,0x00,0x00,0xfd,0x68,0xcc,0x06,0xd0,0xfd,0xeb,0x8c,0x0d,0x00,0x08, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x40,0x80,0xb6, 0x16,0xff,0xf5,0x00,0x00,0xf1,0xff,0xf1,0x7a,0x02,0x20,0x00,0x00,0x08,0x20, 0x02,0x00,0x20,0x10,0x00,0x01,0x05,0x00,0x28,0x40,0x10,0x8c,0xb5,0x59,0x39, 0x90,0x66,0xe5,0xbb,0x00,0x00,0x00,0xad,0xd8,0xbe,0x13,0xd0,0xe7,0xdb,0xe4, 0x06,0x12,0x00,0x00,0x09,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00, 0x88,0x01,0x7a,0xc7,0x7f,0x83,0x90,0x44,0x82,0xff,0xcf,0x6f,0xc3,0x03,0x00, 0x00,0xfa,0x80,0x8f,0x3e,0x3e,0xe4,0xd1,0xc7,0x9d,0x3e,0x78,0xc1,0x10,0x60, 0xbd,0x6c,0x36,0x82,0xbe,0xcf,0xb5,0x40,0x00,0x04,0xed,0xe8,0xf6,0x07,0xe2, 0x4b,0xd9,0xb4,0x87,0x80,0x00,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x00, 0x11,0x00,0x10,0x40,0x85,0xd6,0xe3,0xbf,0x14,0x00,0x42,0xc0,0xff,0xcf,0x7c, 0x23,0x06,0x20,0x10,0xa4,0x80,0x19,0x3a,0x20,0x30,0x43,0x84,0x00,0x22,0xca, 0xc0,0x10,0xc5,0xda,0xbc,0x5d,0x00,0x6a,0xdb,0xbb,0x00,0x00,0x20,0x99,0x31, 0x57,0x07,0xd0,0xbb,0xee,0xaa,0x0b,0x00,0x08,0x00,0x00,0x00,0x08,0x40,0x20, 0x42,0x00,0x10,0x00,0x04,0x00,0x60,0x09,0xfa,0xf8,0xbf,0x89,0x42,0x00,0x01, 0xff,0xbf,0x6b,0xd3,0x0a,0x02,0x00,0x09,0x81,0x10,0x03,0x10,0x10,0x22,0x84, 0x00,0x60,0x84,0x40,0x10,0x22,0x2c,0x56,0x47,0xad,0xf8,0x9c,0xbd,0x20,0x00, 0x00,0xfd,0x32,0xff,0x91,0xd0,0x7f,0x56,0xd8,0x0b,0x00,0x00,0x81,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x01,0x44,0x02,0xde,0xfd,0x9f,0x02, 0x04,0x48,0x24,0xff,0x3f,0x7f,0x51,0x8d,0x00,0x00,0x88,0x00,0x18,0x23,0xa0, 0x00,0x40,0x86,0x00,0x20,0x48,0xc0,0x18,0x62,0x4a,0xf6,0x03,0x00,0xd0,0x9b, 0xbf,0x04,0x00,0x00,0xdc,0xf1,0x75,0x0f,0xd0,0x9f,0x7a,0xb5,0x05,0x10,0x41, 0x00,0x40,0x10,0x01,0x08,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x90,0x08,0x7a, 0xfe,0x77,0x5c,0x11,0x02,0x01,0xf8,0x7f,0x4e,0x23,0x0d,0x00,0x08,0xd4,0x10, 0x0e,0x3c,0x30,0x00,0xc3,0x91,0x1f,0x1c,0x7c,0x40,0x4f,0x08,0x6d,0xab,0xfe, 0xff,0xff,0x2a,0xb7,0x00,0x00,0x00,0xfd,0xf1,0xf6,0x03,0xe4,0x66,0x55,0xa0, 0x07,0x00,0x00,0x00,0x02,0x00,0x40,0x00,0x00,0x10,0x08,0x00,0x00,0x00,0x80, 0xa0,0x88,0x6a,0xfe,0x6b,0x05,0x00,0x40,0x00,0xf4,0x7f,0x5c,0x23,0x09,0x00, 0x00,0xf8,0x04,0x16,0x36,0x24,0xc4,0x91,0x86,0x10,0x38,0xd9,0xc0,0x10,0x12, 0x15,0xeb,0xff,0xff,0xbf,0x35,0xbf,0x40,0x00,0x00,0xfd,0xa5,0xaf,0x44,0x01, 0xef,0x39,0x42,0x05,0x02,0x10,0x40,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x02, 0x81,0x00,0x20,0xc0,0x98,0x9e,0xff,0x5a,0x05,0x90,0x10,0x90,0xf0,0xff,0xf9, 0x12,0x06,0x00,0x01,0x84,0x80,0x18,0x23,0x20,0x70,0x60,0x04,0x10,0x60,0x84, 0xc2,0x10,0x81,0xab,0x5f,0xff,0xff,0xff,0x5e,0xbe,0x00,0x00,0x40,0xac,0xe1, 0x6e,0x10,0x80,0xfa,0x3e,0x80,0x03,0x00,0x04,0x00,0x40,0x00,0x00,0x00,0x04, 0x02,0x00,0x40,0x00,0x10,0x00,0x00,0x88,0xda,0xbf,0x55,0x50,0x00,0x04,0x22, 0xc4,0xff,0xb3,0x32,0x00,0x00,0x00,0x08,0x01,0x10,0x41,0x20,0x10,0x64,0x0c, 0x08,0x00,0x84,0x40,0x10,0xd3,0x90,0x7b,0x45,0xa1,0xdd,0x77,0xbe,0x40,0x00, 0x08,0x7d,0xe9,0xdf,0xff,0xff,0xff,0x36,0x80,0x01,0x80,0x00,0x00,0x10,0x00, 0x00,0x04,0x00,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x48,0xcf,0x7f,0xc6,0x0a, 0x14,0x41,0x08,0xc1,0xff,0xe7,0x10,0x00,0x00,0x80,0x88,0x00,0x18,0x23,0x30, 0x12,0x20,0x04,0x18,0x61,0xcc,0xc0,0x10,0x75,0x34,0xdf,0x7e,0x55,0xdd,0x3f, 0xbe,0x04,0x00,0x02,0xdd,0xe2,0xd7,0xff,0xff,0x6f,0x9d,0x10,0x00,0x20,0x00, 0x20,0x00,0x40,0x10,0x40,0x20,0x00,0x24,0x00,0x00,0x00,0x00,0x10,0x48,0xe7, 0xaf,0x35,0x05,0x10,0x88,0x41,0x94,0xff,0xcf,0x34,0x80,0x10,0x00,0x7c,0x80, 0x0f,0x3e,0xae,0xf0,0xc3,0x83,0x07,0x1e,0x38,0xc0,0x10,0x0b,0x40,0xd4,0xf5, 0xfb,0xf7,0x8c,0xbf,0x10,0x00,0x00,0xfa,0xcb,0x3d,0xad,0x7f,0x79,0x0d,0x00, 0x00,0x01,0x00,0x00,0x02,0x00,0x02,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00, 0x04,0x0c,0xf3,0x9f,0x0a,0x01,0x40,0x20,0x04,0x01,0xff,0xcf,0x14,0x00,0x00, 0x08,0x68,0x80,0x02,0x0c,0xfc,0xd8,0x02,0x41,0x05,0x14,0x40,0x00,0x00,0x05, 0x80,0xc9,0xea,0xde,0xda,0xc0,0xb7,0x00,0x00,0x00,0x9d,0xca,0xaf,0x7e,0xeb, 0xba,0x0f,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xa4,0xf9,0x55,0xa1,0x08,0x0d,0x00,0x00,0x24,0xdf,0x9f, 0x2d,0x20,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11, 0x10,0x40,0x02,0x40,0xa2,0x7a,0xf3,0x67,0xf2,0xbf,0x00,0x00,0x00,0xfc,0x97, 0x37,0x6b,0x6f,0xbd,0x06,0x00,0x00,0x00,0x20,0x00,0x00,0x40,0x00,0x00,0x42, 0x00,0x00,0x82,0x00,0x04,0x00,0x00,0xa8,0xf9,0x37,0x54,0x10,0x90,0x20,0xa8, 0x00,0xfc,0x1f,0x2b,0x00,0x00,0x00,0x00,0x08,0x80,0x00,0x00,0x00,0x08,0x10, 0x20,0x00,0x00,0x00,0x10,0x90,0x00,0x96,0xea,0xfd,0x57,0x7b,0xbf,0x44,0x00, 0x00,0xad,0x57,0xcf,0x7d,0xfd,0x4c,0x83,0x00,0x42,0x00,0x02,0x40,0x20,0x08, 0x00,0x92,0x00,0x04,0x00,0x20,0x20,0x80,0x00,0x01,0xd6,0xfc,0x6b,0xa9,0x84, 0x04,0x14,0x48,0xa0,0xfc,0x7f,0x4b,0x00,0x00,0x81,0x00,0x00,0x24,0x40,0x00, 0x80,0x40,0x04,0x04,0x04,0x00,0x00,0x00,0x04,0x08,0x88,0xdd,0xbb,0x6d,0xde, 0xb9,0x00,0x00,0x00,0xf9,0x06,0x5b,0x3f,0xef,0xd9,0x0b,0x00,0x00,0x20,0x00, 0x04,0x08,0x02,0x80,0x00,0x00,0x00,0x80,0x00,0x08,0x00,0x20,0x00,0xc2,0xfe, 0xa7,0x5c,0x0e,0xaa,0x00,0x15,0x09,0xfc,0x7f,0x53,0x00,0x04,0x20,0x00,0x00, 0x00,0x01,0x80,0x24,0x00,0x00,0x01,0x41,0x02,0x00,0x00,0x00,0x80,0x94,0xf4, 0xf3,0xa7,0x7c,0xbb,0x00,0x00,0x00,0x7c,0x4b,0xcf,0x6d,0xba,0xa9,0x01,0x00, 0x10,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x80,0x80,0x08,0x00,0x00,0x00,0x08, 0x80,0x62,0xfe,0x8d,0xb2,0x20,0x0a,0xa1,0x00,0x50,0xf9,0xff,0xf4,0x08,0x01, 0x00,0x00,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x40,0x00,0x80,0x08,0x11,0x00, 0x00,0x92,0xf5,0x6a,0xef,0xfe,0xb7,0x08,0x00,0x40,0xad,0x2f,0xf4,0x7e,0x6f, 0xf5,0x05,0x40,0x00,0x08,0x24,0x00,0x00,0x00,0x40,0x00,0x08,0x10,0x00,0x00, 0x00,0x00,0x00,0x00,0x2b,0xff,0xb7,0xaa,0x14,0x56,0x48,0x55,0x00,0xf2,0xff, 0xac,0x00,0x00,0x00,0x00,0x04,0xdb,0x10,0x00,0x00,0x04,0x40,0xa8,0xc2,0x12, 0x00,0x00,0x02,0x40,0x88,0xdb,0xed,0xb5,0xfe,0xbf,0x00,0x00,0x00,0xdd,0x0d, 0xff,0x5b,0xfb,0xdb,0x00,0x11,0x00,0x02,0x00,0x20,0x40,0x00,0x08,0x00,0x00, 0x00,0x00,0x00,0x00,0x04,0x01,0x10,0x35,0xff,0x2d,0x65,0x81,0x08,0x11,0x00, 0x95,0xf9,0xfb,0x2d,0x00,0x00,0x04,0x00,0x41,0x5a,0x40,0xa9,0x55,0x55,0x4c, 0x47,0x44,0x04,0x00,0x00,0x10,0x09,0x8a,0x7f,0x5b,0x7f,0xb6,0xbb,0x40,0x00, 0x00,0xae,0x7a,0xb2,0xff,0xde,0x6d,0x40,0x00,0x80,0x00,0x00,0x00,0x00,0x00, 0x02,0x80,0x80,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0xd0,0xff,0xd5,0x9a,0xa7, 0x52,0x02,0x0a,0x28,0x62,0xff,0x4b,0x01,0x80,0x80,0x40,0x00,0x16,0x33,0x24, 0x8c,0x50,0xb3,0x41,0xc4,0x00,0x40,0x80,0x00,0x00,0x30,0xdf,0xea,0x2f,0x6f, 0xae,0x08,0x00,0x08,0xfd,0xdf,0xfa,0x7e,0xff,0x7e,0x08,0x00,0x08,0x00,0x82, 0x04,0x00,0x90,0x00,0x08,0x00,0x00,0x52,0x08,0x91,0x00,0x00,0x84,0xd8,0xff, 0x9a,0xed,0x2a,0x25,0x24,0xd1,0x44,0xf1,0xff,0x53,0x81,0x00,0x00,0x10,0x00, 0x36,0xf4,0xbd,0xb1,0x40,0xb2,0x45,0x56,0x84,0x10,0x08,0x00,0x80,0x74,0xff, 0xfb,0x37,0xfb,0xbf,0x00,0x00,0x00,0xda,0xdf,0xd4,0x5f,0x3f,0x1f,0x02,0x00, 0x00,0x40,0x00,0x00,0x12,0x02,0x60,0x06,0x24,0x40,0x00,0x00,0x00,0x00,0x10, 0x80,0xca,0xff,0xf5,0xab,0x4b,0x4d,0x45,0x00,0x00,0xc2,0xff,0xb3,0x00,0x08, 0x20,0x00,0x00,0x24,0x94,0x06,0xa5,0x66,0xb2,0x9a,0xd4,0x18,0x04,0x20,0x48, 0x12,0x80,0x7c,0xfb,0x9e,0x97,0xbe,0x00,0x00,0x00,0xbd,0xad,0x94,0x7b,0xf5, 0x8d,0x00,0x00,0x00,0x04,0x08,0x00,0x80,0x00,0x61,0x0c,0x01,0x12,0x00,0x00, 0x00,0x00,0x01,0x00,0xca,0x7f,0x7d,0x55,0xbd,0x96,0x10,0x49,0x49,0xd1,0xff, 0xb7,0x20,0x00,0x04,0x04,0x00,0xa4,0xbd,0xb4,0x2c,0x65,0xda,0xde,0x92,0x0a, 0x00,0x00,0x02,0x00,0xd2,0xfc,0xb3,0xcf,0xdf,0xbe,0x44,0x00,0x00,0xfd,0xb7, 0xb3,0x7c,0xbd,0x03,0x00,0x44,0x90,0x00,0x00,0x80,0x00,0x50,0xff,0xff,0x00, 0x00,0x00,0x02,0x00,0x10,0x40,0x42,0xe5,0xff,0x6b,0xbb,0x53,0x2b,0xaa,0x80, 0x90,0xca,0xbb,0x2f,0x03,0x40,0x00,0x01,0x20,0x10,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xa0,0xf3,0xf5,0xf3,0x7f,0xbe,0x00,0x00, 0x10,0xaa,0x2a,0x63,0x43,0xde,0x09,0x00,0x00,0x04,0x00,0x00,0x04,0x00,0x00, 0xdf,0xf2,0x01,0x00,0x84,0x00,0x00,0x00,0x00,0x50,0xf4,0x7f,0xd7,0xea,0x96, 0xcc,0x3e,0x12,0x04,0xc2,0xff,0x0f,0x01,0x00,0x40,0x00,0x00,0x04,0x00,0x00, 0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x42,0x00,0x00,0x14,0xc3,0xca,0xfc,0xac, 0xae,0x00,0x00,0x00,0x6d,0x57,0x8f,0xb8,0xf3,0x02,0x40,0x00,0x00,0x88,0x80, 0x00,0x20,0xf8,0xbe,0xff,0x9e,0x42,0x00,0x80,0x44,0x00,0x40,0x80,0xf2,0xff, 0xbd,0xbe,0xaa,0xb3,0xf4,0xa7,0xf9,0x92,0xff,0x4f,0x05,0x08,0x02,0x80,0x00, 0x01,0x00,0x02,0x42,0x82,0x00,0x90,0x80,0x00,0x40,0x00,0x00,0x41,0xd0,0x1e, 0x3f,0xe4,0x77,0xbc,0x24,0x00,0x00,0xbc,0x77,0x14,0x0b,0x5d,0x00,0x04,0x00, 0x00,0x00,0x10,0x00,0x08,0xdc,0x99,0x93,0x1b,0x00,0x00,0x00,0x00,0x80,0x00, 0xa0,0xfb,0x7f,0x6d,0xa9,0x4a,0xaf,0xe6,0x05,0x7e,0xa5,0xff,0xdf,0x02,0x02, 0x10,0x00,0x40,0x00,0x05,0x80,0x00,0x20,0x40,0x00,0x10,0x00,0x01,0x00,0x00, 0x10,0xa0,0xef,0x8c,0xcb,0x5a,0xbe,0x00,0x00,0x00,0xfd,0xea,0xba,0x74,0x9f, 0x88,0x00,0x10,0x49,0x00,0x00,0x42,0x80,0xec,0x9b,0xe3,0x2e,0x10,0x20,0x00, 0x00,0x08,0x10,0x08,0xfb,0xdf,0xde,0x5a,0xe3,0xfa,0xcd,0xab,0xe7,0x87,0xfb, 0x9f,0x82,0x80,0x00,0x02,0x10,0x40,0x88,0xb0,0x1a,0x50,0xbf,0xbf,0x6f,0x1f, 0x00,0x00,0x00,0x00,0xe8,0xbf,0xc0,0x8b,0xbb,0xbc,0x00,0x00,0x10,0xfa,0xad, 0x7e,0xa4,0x30,0x80,0x04,0x04,0x00,0x42,0x00,0x10,0xc0,0xfb,0xff,0xdf,0xda, 0x03,0x02,0x00,0x00,0x00,0x00,0x42,0xfd,0x77,0x69,0x69,0x88,0x55,0x21,0x8f, 0x0b,0xa5,0xff,0x3f,0x06,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x22,0x00,0x22, 0x40,0x80,0x04,0x00,0x80,0x20,0x02,0xf2,0x7f,0xeb,0x1b,0x2f,0xbc,0x04,0x00, 0x00,0xbe,0xf4,0xae,0x0a,0xd2,0x40,0x80,0x00,0x00,0x00,0x44,0x00,0x82,0x6f, 0xbf,0x7a,0xff,0x01,0x00,0x08,0x08,0x00,0x40,0x40,0xfd,0x6f,0x5f,0xcb,0x65, 0xff,0xbf,0x57,0xb7,0x25,0xfe,0x3f,0x05,0x30,0x80,0x20,0x02,0x10,0x20,0x80, 0x04,0x01,0x15,0x34,0x81,0x02,0x00,0x08,0x00,0x00,0x40,0x7d,0xf6,0x95,0x5f, 0xbd,0x40,0x00,0x00,0xf8,0xfe,0xf7,0x43,0xe0,0xc8,0x30,0x00,0x80,0x08,0x00, 0x00,0x90,0x9f,0xc7,0xf4,0xe5,0x21,0x08,0x02,0x00,0x00,0x01,0xc0,0xfc,0xd5, 0xd0,0x28,0xb2,0xcd,0xc7,0x96,0xfd,0x02,0xff,0x3e,0x05,0x00,0x00,0x02,0x00, 0x20,0x80,0x10,0x18,0x90,0x0a,0x50,0x00,0x04,0x08,0x00,0x00,0x00,0x81,0xf2, 0xf9,0x18,0x1b,0xb6,0x00,0x00,0x00,0x3f,0xff,0xb6,0x0e,0xb0,0xc0,0x40,0x00, 0x22,0x00,0x00,0x04,0x80,0xcd,0x9e,0x32,0xaf,0x02,0x00,0x00,0x01,0x02,0x00, 0xa0,0xfc,0x7b,0xd5,0x82,0x45,0x57,0xcd,0x2e,0xbe,0x2b,0xfc,0x7f,0x05,0x00, 0x10,0x08,0x80,0x14,0x04,0x01,0x25,0x00,0x12,0x60,0x01,0x15,0x02,0x00,0x00, 0x51,0x00,0xc5,0x70,0x15,0x9f,0xbe,0x00,0x00,0x00,0xd8,0x7f,0xb3,0xfd,0xda, 0x80,0x31,0x00,0xc0,0x03,0x00,0x00,0xf8,0xf6,0xfc,0x3f,0xdd,0x9d,0x80,0x00, 0x00,0x00,0x00,0x82,0xde,0xa5,0x16,0xd0,0x78,0xe0,0x11,0x9d,0x40,0x42,0xfa, 0x7f,0x08,0x00,0x00,0x00,0x22,0x02,0x80,0x00,0x48,0x66,0x0a,0x90,0x40,0x04, 0x00,0x01,0x78,0x04,0x08,0xd7,0x67,0x59,0x1f,0xbe,0x00,0x00,0x40,0xfa,0x75, 0x72,0xb7,0xbb,0x00,0x01,0x10,0xf0,0x83,0x10,0x00,0xb1,0xfc,0xff,0x7b,0x7d, 0x0f,0x00,0x00,0x48,0x20,0x24,0xa0,0xfe,0xdb,0xf5,0x93,0x83,0x95,0x26,0x1b, 0x69,0xdd,0xfc,0xf7,0x0a,0x10,0x80,0x80,0x00,0x00,0x00,0x22,0x6a,0x56,0x83, 0x60,0x10,0x0a,0x00,0x80,0xf8,0x00,0x40,0x09,0xe9,0x15,0x5f,0xb6,0x10,0x00, 0x00,0xda,0x3f,0xf3,0x7a,0xf8,0x00,0x00,0x04,0x39,0x0e,0x00,0x22,0xf0,0x6f, 0x0b,0xb0,0x27,0x0d,0x04,0x00,0x02,0x00,0x00,0x40,0xff,0x6d,0x05,0xa4,0x75, 0xa2,0x00,0x2a,0x21,0x22,0xba,0xfd,0x1a,0x00,0x20,0x24,0x00,0x0c,0x80,0x04, 0xd4,0xff,0x3f,0x90,0x00,0x00,0x00,0x00,0x8e,0x03,0x04,0x16,0x86,0x3b,0x0e, 0xb6,0x00,0x00,0x08,0x5e,0x27,0x73,0x4d,0xa8,0x08,0x48,0x00,0x00,0x2c,0x80, 0x00,0x38,0xf3,0x01,0x80,0xf3,0x0f,0x01,0x00,0x00,0x08,0x00,0x50,0xff,0xf7, 0x3e,0x79,0xb9,0x23,0x52,0x15,0x44,0xac,0xf4,0xef,0x14,0x01,0x01,0x00,0x00, 0x01,0x40,0x01,0xfc,0x68,0xf9,0x29,0x01,0x84,0x00,0x00,0x02,0x03,0x10,0x04, 0xba,0x9d,0x5e,0xbf,0x00,0x00,0x00,0xf9,0x3d,0x6b,0x10,0xf9,0x00,0x00,0x00, 0x10,0x0c,0x00,0x00,0xfe,0x67,0x00,0x00,0xaf,0x3a,0x40,0x00,0x00,0x00,0x01, 0x70,0xff,0xff,0xf5,0x6e,0xe5,0x54,0x44,0xb5,0xa4,0x2a,0xeb,0x7b,0x15,0x10, 0x00,0x08,0x80,0x0a,0x42,0x80,0x3c,0xff,0xcf,0x61,0x01,0x24,0x20,0x08,0x00, 0x03,0x80,0x94,0xda,0x35,0x16,0xbb,0x44,0x00,0x00,0x1a,0x3b,0xe2,0x5a,0x2e, 0x00,0x00,0x00,0x82,0x07,0x22,0x80,0x9e,0x7f,0x10,0x10,0xfe,0x69,0x00,0x20, 0x01,0x00,0x00,0x68,0x7f,0xff,0x5a,0xbb,0xf5,0x09,0x21,0x54,0x02,0x94,0x77, 0xdf,0x05,0x00,0x00,0x01,0x10,0x04,0x80,0x83,0xf7,0xbd,0x24,0x5f,0x20,0x00, 0x00,0x02,0xc0,0x81,0x00,0x08,0x34,0xbd,0x8e,0xbf,0x00,0x00,0x00,0x7d,0x39, 0xeb,0xb1,0x3d,0x80,0x44,0x90,0xc0,0x27,0x00,0x08,0x9e,0x3f,0x00,0x01,0xfc, 0x7d,0x00,0x02,0x08,0x12,0x10,0xa9,0xdf,0xff,0xef,0x75,0x75,0x57,0x44,0x25, 0xd4,0x5a,0xca,0xf7,0x35,0x00,0x08,0x00,0x80,0x02,0x40,0x8a,0xbb,0xfb,0xfa, 0x5e,0x01,0x08,0x00,0x00,0xf0,0x00,0x48,0x32,0x68,0x3f,0xae,0xbb,0x20,0x00, 0x00,0xfa,0xa0,0x73,0xde,0x0f,0x10,0x00,0x00,0xf0,0x00,0x00,0x01,0xfc,0x1f, 0x7f,0x9e,0xf8,0x17,0x08,0x00,0x00,0x00,0x04,0xa8,0xff,0xfb,0xff,0xdd,0xf5, 0x57,0x84,0x58,0x2a,0xda,0xf6,0xff,0x21,0x00,0x02,0x10,0x01,0x4c,0x44,0xf5, 0xec,0xd4,0xfb,0x5a,0x80,0x08,0x00,0x40,0x3c,0x00,0x00,0xd0,0xa0,0xba,0xd2, 0xbd,0x00,0x00,0x10,0xfd,0x29,0x63,0xad,0x8f,0x00,0x10,0x04,0x30,0x00,0x41, 0x40,0xee,0x1f,0x7c,0x3c,0xe8,0xbb,0x40,0x00,0x00,0x00,0x00,0xa8,0xfd,0xdf, 0xfd,0xfb,0xaa,0xad,0x18,0x95,0x88,0x7a,0xe9,0xfd,0x29,0x88,0x00,0x04,0x80, 0x13,0x40,0x72,0xbf,0x2f,0xdf,0xf6,0x11,0x08,0x08,0x10,0x0c,0x20,0x40,0x70, 0x65,0x3e,0x96,0xb7,0x14,0x00,0x00,0xba,0xed,0x75,0xda,0x00,0x04,0x82,0x00, 0x18,0x20,0x00,0x80,0xbb,0x07,0x38,0x3c,0xf0,0xef,0x00,0x00,0x00,0x00,0x00, 0xa0,0xef,0xef,0xff,0xaf,0x55,0x2b,0x51,0x5a,0xa4,0xfa,0xee,0xff,0x69,0x00, 0x40,0x00,0x10,0x04,0x80,0xb4,0xeb,0xfe,0x75,0x59,0x00,0x00,0x00,0x00,0x06, 0x08,0x08,0x82,0x83,0x35,0xd7,0xbe,0x00,0x00,0x00,0xed,0xd1,0x73,0x7e,0x01, 0x00,0x00,0x00,0x19,0x00,0x00,0x88,0xe7,0x0e,0xbc,0x3c,0x72,0xe6,0x01,0x20, 0x01,0x80,0x80,0x84,0xff,0xfe,0x7e,0xa6,0xf6,0x5b,0x26,0x25,0x88,0x7a,0xe9, 0xf7,0x29,0x20,0x00,0x00,0x41,0x05,0x40,0x9f,0xb6,0x7b,0xc7,0xf5,0x01,0x00, 0x00,0x04,0x06,0x00,0x40,0xa0,0x0e,0xad,0xea,0xb5,0x04,0x00,0x00,0xda,0x8c, 0xf9,0x3c,0x04,0x01,0x04,0x40,0xf8,0x0f,0x04,0x02,0x5d,0x0b,0x78,0xbc,0xc0, 0xb3,0x00,0x04,0x00,0x10,0x10,0x90,0xff,0xff,0xdf,0x9f,0xab,0x5e,0x14,0x5b, 0x52,0xdb,0x7b,0xbf,0x69,0x00,0x00,0x00,0x40,0x11,0x44,0xfd,0xee,0xef,0x3f, 0xbb,0x93,0x00,0x80,0x00,0xfe,0x03,0x01,0x04,0x71,0xbe,0xed,0xb6,0x00,0x00, 0x00,0xbf,0x39,0xb3,0xdf,0x41,0x90,0x40,0x08,0x00,0x89,0x40,0x00,0x76,0x47, 0x3c,0x3c,0xe0,0xbe,0x08,0x01,0x20,0x04,0x04,0x94,0xef,0xad,0xff,0xbf,0xf5, 0x59,0x83,0xff,0xaa,0x7a,0xfb,0xff,0x5b,0x04,0x00,0x08,0x40,0x06,0x41,0x27, 0xfb,0xde,0xfe,0x66,0x02,0x08,0x11,0x00,0x20,0x04,0x08,0x48,0xe0,0x1d,0xfb, 0xbf,0x00,0x00,0x00,0xea,0x28,0xb3,0x6f,0x08,0x00,0x00,0x00,0x40,0x00,0x00, 0x00,0x6e,0x07,0x3c,0x3c,0xe0,0xde,0x40,0x00,0x00,0x00,0x01,0x94,0x7b,0xff, 0xf7,0xaf,0xf7,0xb7,0xa4,0xdd,0x46,0xdd,0xff,0xff,0x5b,0x00,0x42,0x00,0x49, 0x11,0x40,0xf5,0xbf,0x9f,0xdf,0xb7,0x43,0x00,0x00,0x00,0x01,0x00,0x02,0x41, 0xe1,0xbb,0xda,0xbd,0x20,0x00,0x20,0xfa,0x9c,0xeb,0xe3,0x00,0x00,0x00,0x02, 0x02,0x20,0x08,0x80,0xef,0x07,0xf8,0x07,0xa0,0xa2,0x00,0x00,0x00,0x00,0x00, 0xdc,0xff,0xb7,0xfe,0xff,0x6c,0x6d,0x91,0xfe,0xa9,0xba,0xff,0xfd,0x4b,0x10, 0x00,0x40,0x80,0x16,0x40,0xaf,0x0c,0x44,0x84,0xf9,0x8d,0x00,0x00,0x40,0x10, 0x11,0x40,0x10,0xf4,0xba,0x7d,0xbb,0x00,0x00,0x00,0x7e,0x7a,0xff,0x65,0x00, 0x80,0x00,0x40,0x00,0x00,0x00,0xe0,0x67,0x47,0xf8,0x07,0xe0,0xde,0x03,0x01, 0x00,0x22,0x00,0x94,0xdf,0xfd,0xfb,0xff,0xef,0xab,0x26,0xbd,0x89,0xdd,0x7f, 0xdf,0x57,0x81,0x00,0x04,0x40,0x05,0x10,0xcb,0x46,0x37,0x22,0xef,0x0d,0x00, 0x00,0x02,0x00,0x04,0x01,0x83,0x10,0xf7,0xfe,0xb7,0x08,0x00,0x00,0xd9,0x54, 0xd5,0xb0,0x20,0x02,0x10,0x00,0x00,0x04,0x82,0x04,0x7d,0x0f,0x3a,0xbc,0xa8, 0x96,0x10,0x00,0x84,0x00,0x20,0xdd,0x77,0xdf,0xae,0xef,0xd5,0xb5,0x11,0x01, 0x52,0xfe,0xdf,0xff,0x53,0x20,0x10,0x01,0xa0,0x92,0xc0,0x3d,0x47,0xfa,0x05, 0xb6,0xa6,0x90,0x40,0x00,0x00,0x01,0x08,0x1f,0xed,0xb5,0xff,0xbe,0x00,0x00, 0x00,0xfa,0x32,0xbb,0x92,0x04,0x00,0x00,0x02,0x40,0x00,0x20,0x00,0xfd,0x07, 0x38,0x3c,0xe0,0xbe,0x00,0x00,0x01,0x00,0x04,0xdc,0xfd,0xff,0xf7,0xdd,0x55, 0x6f,0x64,0x52,0x88,0xd5,0xfe,0xdb,0x57,0x10,0x00,0x80,0x88,0x14,0xc0,0xcf, 0x93,0xff,0x4f,0xee,0x1e,0x00,0x00,0x00,0x40,0x00,0x00,0x2d,0xa9,0xd7,0x6b, 0xbb,0x00,0x00,0x40,0xfe,0xd4,0x6a,0x19,0x00,0x00,0x02,0x00,0x10,0x80,0x00, 0x00,0x7e,0x07,0x78,0x78,0xe0,0xbe,0x88,0x00,0x00,0x04,0x00,0xea,0xff,0xff, 0xdf,0xbe,0xef,0x5f,0x8a,0x04,0x56,0xfd,0xf7,0xff,0x17,0x00,0x00,0x00,0x20, 0x05,0x80,0xaf,0xc7,0x62,0x30,0xfa,0xab,0x00,0x08,0x00,0x00,0x40,0x00,0xff, 0x70,0x2f,0x8f,0xb5,0x00,0x00,0x04,0xda,0xaa,0x7e,0x9a,0x00,0x00,0x00,0x41, 0x04,0x00,0x00,0x00,0xfc,0x0f,0x3a,0x78,0xc0,0xbf,0x00,0x10,0x00,0x40,0x08, 0xda,0xff,0xb7,0xfd,0xd7,0xfb,0xd4,0x24,0x89,0x28,0xbe,0x7f,0xbd,0xd7,0x00, 0x00,0x04,0x80,0x12,0xc0,0xaa,0x47,0x6e,0x12,0xde,0x1d,0x00,0x00,0x00,0x08, 0x08,0x84,0xac,0x81,0x7b,0x87,0xbf,0x20,0x00,0x00,0xfb,0x6d,0xab,0x7c,0x00, 0x20,0x00,0x10,0x00,0x44,0x08,0x84,0xef,0x0b,0x78,0x78,0xf2,0xf7,0x01,0x00, 0x80,0x00,0x00,0xea,0xbf,0xff,0xef,0xfd,0x56,0x57,0xed,0xff,0x5f,0xfa,0xff, 0xf7,0x06,0x20,0x02,0x81,0x20,0x15,0xc0,0xaa,0xa5,0x35,0xbc,0xde,0xb2,0x88, 0x00,0x20,0x00,0x00,0x00,0x7b,0xf5,0xbf,0xf7,0xbf,0x08,0x00,0x00,0xba,0xb1, 0x3d,0x8d,0x80,0x08,0x00,0x00,0x00,0x00,0x40,0x00,0xfa,0x4f,0x3c,0x7c,0xf0, 0xf7,0x08,0x02,0x00,0x10,0x80,0xea,0xef,0xff,0x7b,0xaf,0xff,0xaf,0x09,0x40, 0x02,0xff,0xdd,0xfe,0x97,0x00,0x40,0x00,0x80,0x14,0x68,0xdf,0x67,0x6d,0x4a, 0x36,0x77,0x00,0x40,0x00,0x02,0x00,0x01,0x71,0xe3,0xea,0x8b,0xb5,0x00,0x00, 0x00,0xfa,0x7b,0x35,0x5e,0x04,0x00,0x40,0x00,0x00,0x00,0x00,0x01,0xde,0x1f, 0x38,0x3c,0xe8,0x73,0x80,0x80,0x00,0x02,0x00,0xea,0xff,0xfd,0xff,0xdf,0xfb, 0x5b,0x13,0x08,0x28,0xdd,0xff,0xd7,0x87,0x10,0x10,0x00,0x90,0x05,0xc2,0xdd, 0x56,0x7d,0x6e,0xfe,0x35,0x00,0x00,0x00,0x40,0x42,0x00,0xe6,0x66,0xf7,0x7e, 0xb7,0x00,0x00,0x00,0xda,0xa7,0xad,0x9f,0x00,0x00,0x04,0x04,0x41,0x00,0x08, 0x00,0xfe,0x39,0x7f,0x0f,0xf0,0x1b,0x00,0x00,0x80,0x00,0x22,0xea,0x7e,0xdf, 0xee,0xb6,0x5e,0xbf,0xd4,0x22,0x49,0xff,0xf7,0xfd,0xa6,0x00,0x02,0x80,0xa4, 0x12,0x40,0xf7,0x6b,0xd9,0x59,0xbe,0x57,0x10,0x04,0x00,0x00,0x10,0x10,0x00, 0x97,0xbd,0xdf,0xbb,0x00,0x00,0x00,0xfa,0x37,0x4b,0xcf,0x40,0x00,0x01,0x00, 0x04,0x48,0x42,0x10,0xbe,0x2e,0xff,0x03,0x3e,0x1f,0x08,0x00,0x04,0x00,0x00, 0xea,0xf7,0xff,0xbb,0xdf,0xf6,0x6d,0x25,0x4b,0x12,0xed,0xbd,0xff,0x87,0x00, 0x00,0x00,0x80,0x14,0x40,0xdf,0xc7,0xbe,0x35,0x36,0xb5,0x04,0x00,0x80,0x08, 0x00,0x00,0x95,0x8b,0x7f,0xff,0xbf,0x20,0x00,0x40,0xfa,0x4e,0x8b,0x5f,0x00, 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0xf6,0x7b,0x00,0x40,0xee,0x6d,0x00,0x00, 0x00,0x00,0x00,0xea,0xff,0xdf,0xff,0xaf,0xbe,0x5f,0xd5,0xd4,0x44,0xff,0xff, 0xb7,0xa7,0x80,0x00,0x10,0x20,0x93,0x70,0x77,0x03,0x77,0x27,0xfe,0x76,0x80, 0x40,0x20,0x00,0x00,0x02,0x4c,0xbd,0xfe,0x7b,0xbd,0x00,0x00,0x10,0xfe,0xef, 0xcd,0x5b,0x10,0x00,0x00,0x40,0x00,0x02,0x00,0x00,0xfe,0xfb,0x00,0x00,0xc5, 0x7f,0x00,0x20,0x00,0x04,0x04,0xaa,0xbf,0xf7,0x5a,0xbd,0xed,0xfb,0x2a,0xa9, 0x55,0xff,0xee,0xfe,0x87,0x08,0x00,0x00,0x80,0x14,0xc0,0xdb,0x47,0xfb,0x0e, 0xae,0x7d,0x00,0x00,0x08,0x00,0x00,0x00,0x48,0x5d,0xb7,0x95,0xbf,0x00,0x00, 0x00,0xda,0x95,0xf5,0x4c,0x00,0x00,0x00,0x10,0x04,0x00,0x00,0x41,0xf8,0xcf, 0x01,0xc0,0xdb,0x0f,0x00,0x01,0x01,0x81,0x00,0xea,0xed,0xfd,0xef,0x6f,0xfb, 0xae,0xa5,0x50,0xb4,0xdf,0xff,0xff,0x87,0x00,0x00,0x00,0x40,0x13,0x48,0xff, 0xc5,0xde,0xbd,0x7e,0x17,0x00,0x00,0x00,0x40,0x20,0x00,0x30,0xf5,0xef,0xea, 0xb2,0x10,0x00,0x00,0xfa,0xbf,0xfd,0xb9,0x00,0x21,0x80,0x00,0x00,0x00,0x21, 0x08,0xf0,0xed,0x07,0x60,0xf9,0x07,0x08,0x00,0x40,0x00,0x40,0xea,0xff,0xbf, 0xba,0x5f,0xdd,0xff,0x4d,0x85,0xca,0xff,0xef,0xdd,0xa7,0x00,0x00,0x04,0x41, 0x15,0xc0,0xdf,0xf3,0xee,0x2b,0xbe,0x17,0x00,0x10,0x00,0x04,0x00,0x48,0xb0, 0x7c,0xbd,0xfd,0xbf,0x00,0x00,0x00,0xfa,0xa9,0x1d,0x4c,0x10,0x00,0x12,0x00, 0x00,0x21,0x00,0x00,0x50,0xfd,0xfe,0xff,0x56,0x0e,0x40,0x10,0x10,0x00,0x00, 0xea,0xff,0xdd,0xef,0x7f,0x6b,0xfb,0x2a,0x5a,0xf2,0xb7,0x7d,0xf7,0x87,0x00, 0x81,0x40,0x50,0x05,0xf0,0xde,0x3e,0x33,0xef,0xf6,0x35,0x02,0x04,0x00,0x00, 0x84,0x00,0x84,0xd5,0xd7,0x03,0xba,0x20,0x00,0x00,0x5a,0x2f,0x6d,0x5a,0x04, 0x00,0x00,0x10,0x40,0x00,0x00,0x80,0xf8,0xf7,0xfa,0xdf,0x9c,0x1d,0x01,0x00, 0x00,0x00,0x01,0x62,0x7b,0xaf,0xbd,0xdf,0xec,0xfe,0x7f,0x45,0xfa,0xfd,0xdf, 0x7f,0x97,0x00,0x20,0x00,0x40,0x11,0x82,0x87,0xcf,0xa8,0xac,0x5f,0x11,0x90, 0x00,0x02,0x10,0x00,0x00,0x40,0xee,0xdf,0xc9,0xbd,0x00,0x00,0x00,0xfe,0xdd, 0x3e,0x58,0x01,0x08,0x00,0x04,0x09,0x00,0x80,0x04,0x6a,0xed,0x78,0xb7,0xbe, 0x43,0x10,0x00,0x01,0x20,0x00,0xca,0xff,0xbf,0xff,0x7f,0xdb,0xbf,0x6e,0x55, 0xbd,0xef,0xff,0xfb,0xa7,0x88,0x00,0x00,0x80,0x96,0xc0,0xba,0xb7,0x6e,0x7b, 0x7b,0x8b,0x08,0x00,0x20,0x01,0x00,0x08,0x90,0xd8,0xee,0x74,0xb7,0x08,0x00, 0x00,0x5a,0x73,0xbc,0x5a,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x00,0x80,0xcf, 0x7b,0xf3,0x7f,0x01,0x00,0x40,0x00,0x00,0x40,0xea,0xff,0xfb,0xbf,0xbd,0x6e, 0xfb,0xfb,0xcb,0xfa,0xba,0xfb,0xde,0x97,0x00,0x00,0x00,0x40,0x11,0xc0,0xf7, 0x3f,0xc9,0xce,0xef,0x1b,0x08,0x80,0x00,0x00,0x41,0x82,0x00,0x61,0x77,0xa5, 0x9a,0x00,0x00,0x00,0xde,0x73,0x2d,0x5d,0x00,0x40,0x00,0x00,0x00,0x48,0x00, 0x40,0x80,0x4f,0x7f,0xd7,0xe6,0x09,0x00,0x10,0x00,0x01,0x10,0xca,0xbf,0xbf, 0xef,0xff,0xbd,0xef,0xdf,0x7e,0xef,0xff,0xaf,0xff,0x86,0x00,0x00,0x10,0x04, 0x56,0xd0,0x7b,0x2d,0xb8,0xe5,0x7e,0x3f,0x00,0x08,0x00,0x04,0x10,0x00,0x44, 0x60,0xbd,0x10,0xa5,0x00,0x00,0x80,0x5a,0x99,0x3e,0x4c,0x00,0x04,0x40,0x20, 0x00,0x01,0x80,0x00,0x80,0xff,0xf5,0x2f,0xd9,0x01,0x00,0x00,0x00,0x20,0x00, 0xda,0xff,0xfb,0xfe,0xff,0xd2,0xbc,0xff,0xfb,0x7e,0xeb,0xfe,0xdb,0x57,0x40, 0x08,0x00,0x00,0x05,0x84,0x4d,0xcf,0xff,0x13,0x53,0x05,0x04,0x02,0x20,0x21, 0x00,0x00,0x00,0xc1,0x52,0x40,0xb9,0x40,0x00,0x00,0xda,0x6f,0x3d,0x5e,0x80, 0x00,0x00,0x04,0x20,0x00,0x00,0x00,0xa0,0xbc,0x75,0x6e,0x2d,0x00,0x00,0x02, 0x20,0x00,0x00,0xd8,0xfb,0xbf,0x5f,0x7f,0xed,0xfb,0xfa,0x3f,0xff,0xbf,0x77, 0x7f,0x13,0x00,0x00,0x00,0x01,0x15,0x40,0xcb,0x6f,0x82,0x12,0x77,0x05,0x8c, 0x00,0x00,0x00,0x02,0x08,0x08,0xf0,0xd7,0x27,0xbc,0x00,0x00,0x00,0xfa,0xdf, 0x96,0x5c,0x20,0x00,0x08,0x00,0x04,0x00,0x00,0x00,0x00,0xf8,0xf7,0xa6,0x1b, 0x24,0x40,0x00,0x00,0x08,0x22,0xda,0xff,0xf7,0xff,0xdf,0xab,0xdd,0xdf,0x6f, 0x6f,0xf7,0xff,0xed,0x57,0x00,0x00,0x02,0x40,0x12,0xd0,0xbb,0xde,0xab,0xce, 0xbb,0x0d,0x20,0x00,0x20,0x00,0x00,0x80,0x42,0xe5,0xfc,0xff,0xbf,0x00,0x00, 0x00,0x7a,0xbf,0x0d,0xce,0x00,0x00,0x00,0x00,0x00,0x20,0x10,0x42,0x08,0xf8, 0xff,0xfc,0x1f,0x00,0x02,0x00,0x08,0x00,0x00,0x9c,0x7f,0xef,0xee,0xf7,0x77, 0x7f,0xfb,0x1a,0xfb,0xfd,0xed,0xbf,0x53,0x10,0x00,0x00,0x90,0x02,0x82,0xbe, 0x3a,0xa0,0xc1,0xf0,0x0f,0x08,0x00,0x09,0x00,0x00,0x01,0x00,0xe0,0xbb,0xf7, 0xbf,0x00,0x00,0x00,0xba,0x6f,0xab,0x5d,0x00,0x20,0x00,0x01,0x20,0x04,0x04, 0x00,0x00,0x00,0xfb,0xcf,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0xd4,0xf7,0xbf, 0x7f,0xff,0xab,0xf6,0xb7,0x17,0xff,0xdf,0x7f,0xff,0x5b,0x00,0x00,0x40,0x00, 0x14,0x40,0xc7,0xb7,0xa5,0xfe,0x5e,0x02,0x06,0x00,0x00,0x80,0x10,0x00,0x40, 0x62,0x5e,0xdf,0xaf,0x10,0x00,0x00,0xfa,0x87,0x83,0x5f,0x00,0x00,0x02,0x10, 0x01,0x00,0x00,0x00,0x00,0x00,0xf1,0xcf,0x00,0x00,0x00,0x80,0x00,0x00,0x20, 0x94,0xfd,0xda,0xf7,0xff,0xdf,0xed,0xfe,0x05,0x7f,0xfb,0xde,0xfb,0x53,0x04, 0x22,0x00,0x00,0x09,0x40,0xed,0xef,0xcf,0x37,0xff,0x01,0x09,0x00,0x00,0x02, 0x00,0x40,0x20,0xe5,0xbe,0xbd,0xba,0x00,0x00,0x00,0x5a,0x82,0xa1,0x5e,0x00, 0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x61,0x0e,0x00,0x10,0x00,0x00, 0x00,0x01,0x09,0x94,0xbf,0xff,0xdb,0xef,0xd7,0xbf,0xff,0x83,0xff,0xbf,0xf7, 0xff,0x69,0x00,0x00,0x00,0x00,0x02,0x80,0xde,0xde,0x9b,0x9e,0xdb,0x03,0x0d, 0x40,0x40,0x08,0x0f,0x11,0x00,0x70,0xf7,0xab,0xad,0x00,0x00,0x00,0x7a,0xe9, 0x4a,0x4f,0x04,0x00,0x20,0x00,0x84,0x08,0x00,0x11,0x01,0x00,0x20,0x00,0x00, 0x05,0x00,0x00,0x40,0x40,0x00,0x90,0xf7,0xd7,0xfe,0xff,0xaf,0xea,0xb6,0x20, 0xbf,0xed,0xff,0xdf,0x69,0x00,0x00,0x02,0x04,0x08,0x91,0xb0,0x6f,0xfe,0xf3, 0x7f,0x00,0x00,0x10,0x00,0x00,0x01,0x00,0x08,0xa0,0x9b,0xde,0xba,0x00,0x00, 0x00,0xda,0x63,0xe2,0x5f,0x40,0x08,0x01,0x08,0x00,0x02,0x04,0x00,0x20,0x80, 0x04,0x00,0x00,0x00,0x40,0x40,0x08,0x04,0x00,0x90,0xbe,0xff,0xff,0xff,0xbf, 0xff,0x5f,0x04,0xfe,0xff,0xfb,0xf6,0x69,0x00,0x00,0x20,0x00,0x42,0x00,0xb0, 0xbb,0x51,0x7d,0x6b,0x41,0x8e,0x04,0x00,0x89,0x01,0x00,0x40,0xea,0x77,0xb5, 0xbf,0x20,0x00,0x80,0xfa,0xf9,0xff,0x5f,0x00,0x00,0x00,0x40,0x88,0x00,0x40, 0x00,0x00,0x22,0x00,0x10,0x10,0x00,0x11,0x00,0x00,0x00,0x00,0xa0,0xef,0x6d, 0xb5,0xfa,0xff,0x6a,0x17,0xa0,0xee,0x7b,0xff,0xff,0x29,0x00,0x01,0x00,0x80, 0x04,0x40,0xc9,0xfe,0xfa,0xff,0x7b,0x81,0x04,0x00,0x24,0x80,0x40,0x4b,0x01, 0xe0,0xb7,0x6f,0xaf,0x08,0x00,0x00,0xfa,0x62,0xb5,0x4f,0x01,0x41,0x00,0x01, 0x00,0x20,0x00,0x04,0x04,0x00,0x00,0x00,0x02,0x40,0x00,0x10,0x00,0x00,0x00, 0xa9,0xff,0xfb,0xef,0xdf,0xbf,0xbd,0x2d,0x00,0x7b,0xdf,0xdf,0xff,0x21,0x08, 0x00,0x00,0x02,0x20,0x90,0xc0,0xfd,0x46,0xea,0x18,0x81,0x01,0x00,0x00,0x08, 0x51,0xab,0x88,0xf0,0xdf,0xbb,0xbc,0x00,0x00,0x00,0xba,0x2e,0xee,0x5b,0x10, 0x10,0x14,0x10,0x02,0x04,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x00,0x00, 0x00,0x00,0x00,0x28,0x77,0xdf,0xf7,0xff,0x3b,0x56,0x00,0xa1,0xcf,0xfb,0x7b, 0xff,0x25,0x00,0x00,0x04,0x00,0x10,0x20,0xa0,0xd7,0xde,0x3b,0x6f,0x41,0x06, 0x00,0x80,0x00,0x47,0x93,0x00,0x42,0x7f,0xff,0xbf,0x08,0x00,0x00,0xfa,0xd6, 0xfb,0x5d,0x00,0x00,0x00,0x00,0x20,0x01,0x00,0x00,0x00,0x00,0x42,0x00,0x00, 0x00,0x00,0x00,0x00,0x10,0x40,0x68,0xff,0x7f,0xfe,0x6f,0xff,0xbf,0x11,0x80, 0xdf,0xde,0xfe,0xfb,0x14,0x02,0x00,0x01,0x00,0x20,0x14,0xa4,0xae,0x7b,0x3d, 0x1b,0x01,0x20,0x04,0x01,0x00,0x00,0x00,0x00,0xe0,0x7e,0xf7,0xba,0x00,0x00, 0x20,0x3a,0x7f,0xfb,0x4e,0x00,0x00,0x80,0x00,0x08,0x00,0x02,0x40,0x40,0x04, 0x00,0x84,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x69,0xff,0xef,0xdb,0xfe,0x3f, 0xa5,0x00,0xe9,0xdf,0xf7,0xef,0xdf,0x16,0x01,0x40,0x40,0x40,0x00,0x03,0xa8, 0xfe,0xaa,0xd2,0x55,0x2a,0x09,0x20,0x00,0x08,0x00,0x00,0x20,0xb8,0xb5,0xbf, 0xb7,0x00,0x00,0x00,0xba,0xf7,0xbf,0x5d,0x00,0x00,0x01,0x00,0x00,0x82,0x80, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x40,0x00,0x80,0x52,0x7f,0x77, 0xff,0xff,0xbe,0x2d,0x40,0xd0,0xdd,0x7a,0x7f,0xf7,0x92,0x00,0x10,0x00,0x10, 0x00,0x00,0x00,0xc0,0xff,0x3f,0x00,0x00,0x00,0x00,0x84,0x00,0x00,0x00,0x04, 0x66,0xc2,0xef,0xbd,0x40,0x00,0x00,0x7a,0xbf,0xdf,0x4e,0x00,0x09,0x00,0x08, 0x01,0x20,0x20,0x10,0x08,0x40,0x04,0x00,0x80,0x00,0x00,0x04,0x04,0x00,0x84, 0x59,0xef,0xdd,0xfb,0xef,0xbf,0x2a,0x2a,0xd4,0xff,0xdf,0xff,0xff,0x9e,0x00, 0x01,0x00,0x04,0x88,0x00,0x01,0x40,0xf6,0x33,0x00,0x00,0x00,0x00,0x20,0x90, 0x40,0x04,0x01,0xce,0xef,0xf6,0xbb,0x00,0x00,0x00,0xba,0xef,0xab,0x7d,0x04, 0x80,0x10,0x40,0xf8,0x00,0x0c,0x10,0x78,0x10,0x41,0x12,0x37,0x34,0x68,0x00, 0x21,0x00,0x80,0x06,0xfe,0xbf,0x7f,0xfd,0xff,0xaa,0x02,0xf0,0x7f,0xf7,0x7b, 0xff,0x58,0x41,0x00,0x00,0x00,0x02,0x40,0x00,0x00,0x22,0x00,0x10,0x00,0x00, 0x01,0x04,0x04,0x00,0x02,0x00,0xe5,0xb9,0xff,0xb7,0x10,0x00,0x00,0x7a,0xff, 0xfe,0x82,0x43,0x00,0x80,0x00,0xd0,0x01,0x1e,0x7c,0x58,0xc0,0x01,0x07,0x6f, 0x28,0xd0,0x01,0x21,0x00,0x20,0x8b,0xfe,0xf7,0xfa,0xdf,0xbf,0xaa,0x00,0xe8, 0xbd,0xfc,0xde,0x6b,0x9a,0x01,0x00,0x00,0x00,0x80,0x10,0x10,0x00,0x20,0x00, 0x00,0x00,0x02,0x00,0x00,0x00,0x10,0x80,0x40,0x81,0xff,0x6f,0xbd,0x00,0x00, 0x00,0xba,0xbf,0x1f,0x04,0x08,0x20,0x00,0x00,0x08,0x03,0x21,0x4c,0x20,0x60, 0x86,0x0c,0x01,0xcc,0x98,0x21,0x21,0x00,0x80,0xba,0xfc,0xef,0xef,0xff,0x3f, 0x44,0x00,0x75,0xff,0xcb,0xff,0x7f,0xe9,0x04,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x04,0x80,0x00,0x00,0x01,0x00,0x04,0x01,0x28,0x27,0xbd,0xbe, 0xb5,0x00,0x00,0x00,0xfa,0xfa,0xaf,0x95,0x30,0x08,0x02,0x08,0x08,0x03,0x23, 0x44,0x40,0x22,0x86,0x08,0x01,0xc4,0x18,0x01,0x21,0x00,0x42,0xac,0xfc,0xbb, 0xff,0xbf,0x7d,0xa8,0x40,0x52,0xbd,0xf2,0xff,0x7f,0xac,0x05,0x00,0x84,0x40, 0x20,0x00,0x00,0x80,0x02,0x00,0x00,0x12,0x00,0x48,0x88,0x10,0x00,0x00,0x04, 0x03,0xed,0xdd,0xbd,0x00,0x00,0x00,0x7a,0x7d,0x91,0x5e,0xc4,0x00,0x08,0x80, 0x18,0x21,0x30,0x4d,0x60,0x00,0x84,0x08,0x01,0xc0,0x88,0x01,0x29,0x10,0xc0, 0xb9,0x7c,0xef,0xf7,0x6f,0x7f,0x01,0x06,0x74,0xbd,0x4e,0xff,0x3f,0xed,0x07, 0x88,0x00,0x10,0x00,0x02,0x00,0x20,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00, 0x40,0x80,0x08,0xee,0xb2,0x7b,0xb6,0x00,0x00,0x00,0xfa,0xed,0x6b,0xc7,0x01, 0x00,0x20,0x20,0x90,0x03,0x18,0x54,0x60,0x00,0x86,0x0d,0x1d,0x50,0xf0,0x00, 0x3f,0x04,0x40,0x69,0xfc,0xff,0xbb,0xfa,0xf5,0x22,0x43,0xc8,0x7e,0xdb,0xf4, 0x3f,0xa7,0x45,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x80,0x40,0x00,0x00, 0x01,0x00,0x08,0x01,0x00,0x2c,0x6b,0xf1,0x56,0x3f,0x20,0x00,0x10,0xfa,0xba, 0xb5,0x1e,0x97,0x82,0x08,0x01,0x78,0x01,0x1c,0x5c,0x60,0xc0,0x81,0x0b,0x23, 0x70,0x98,0x01,0x21,0x00,0x88,0x49,0xfd,0xfd,0xff,0xff,0xfd,0x41,0x2e,0x81, 0xf6,0xae,0x4f,0xaf,0xd6,0x25,0x00,0x20,0x04,0x02,0x20,0x00,0x01,0x00,0x10, 0x10,0x00,0x00,0x00,0x40,0x00,0x20,0x80,0xb0,0xff,0x0d,0x95,0xbf,0x00,0x00, 0x00,0xba,0x53,0xfd,0xe5,0x7f,0x08,0x00,0x00,0x08,0x03,0x20,0xc4,0x60,0x60, 0x40,0x18,0x60,0xc0,0x18,0x09,0x21,0x01,0xc1,0x1b,0x73,0x77,0xe7,0xbb,0xef, 0x57,0x25,0x24,0xf8,0xd5,0xbd,0x9f,0xa2,0x09,0x00,0x08,0x41,0x20,0x08,0x08, 0x00,0x08,0x00,0x00,0x20,0x21,0x10,0x04,0x00,0x24,0x60,0xe7,0x85,0x47,0xbc, 0xba,0x08,0x00,0x00,0xda,0xa6,0x59,0x00,0xfe,0x08,0x05,0x10,0x09,0x03,0x20, 0x86,0x20,0x20,0x80,0x10,0x60,0xc0,0x08,0x03,0x21,0x00,0xd0,0xcb,0xfa,0xdf, 0xfb,0xfe,0xfb,0x23,0x4b,0x08,0xea,0x5d,0xef,0xda,0xea,0x15,0x02,0x00,0x10, 0x00,0x01,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x42,0x50,0x10,0xe3, 0x00,0xce,0xa8,0xb7,0x00,0x00,0x00,0xba,0x57,0x37,0xde,0xd0,0x93,0x80,0x00, 0x58,0x43,0x33,0x44,0x60,0x28,0x80,0x08,0x30,0xc6,0xd8,0x41,0x21,0x00,0x40, 0xa7,0xb2,0xff,0xdf,0xf7,0xb7,0x47,0x1e,0x80,0xf5,0xfd,0xbb,0x4f,0x4d,0x35, 0x40,0x08,0x00,0x04,0x00,0x08,0x00,0x00,0x82,0x00,0x04,0x00,0x40,0x20,0x00, 0x02,0x92,0x33,0xfe,0x80,0xdb,0xbd,0x00,0x00,0x00,0xea,0xf5,0x8f,0x55,0xe1, 0x07,0x00,0x00,0xb8,0x81,0x2f,0x7c,0xf8,0xd3,0x87,0x0d,0x1f,0xdc,0x78,0x01, 0x21,0x00,0x50,0x27,0xf4,0xeb,0xfd,0xef,0xff,0xc7,0x0a,0x51,0xee,0xaf,0xfe, 0x0a,0xc1,0x06,0x00,0x02,0x01,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00, 0x08,0x00,0x20,0x28,0xd8,0x0b,0xff,0xf3,0xb3,0x2e,0x00,0x00,0x00,0xfa,0xc3, 0x47,0xed,0xcf,0x67,0x90,0x20,0x20,0x00,0x08,0x10,0x08,0xa0,0x04,0x07,0x05, 0x10,0x00,0x00,0x00,0x20,0xa8,0xf5,0xe5,0xbb,0xfb,0xfb,0xfb,0x9f,0x1a,0xa4, 0xd0,0xbf,0xeb,0xa7,0xd7,0x11,0x00,0x40,0x10,0x41,0x00,0x00,0x02,0x80,0x00, 0x00,0x80,0x00,0x00,0x00,0x08,0x21,0xe0,0xc3,0x13,0xcb,0xe7,0xb5,0x20,0x00, 0x00,0xfa,0x65,0x71,0xab,0x95,0x5e,0x02,0x04,0x02,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x01,0x22,0xa5,0xcd,0xfe,0x7f,0xbf,0xef, 0x5e,0x2a,0x69,0xda,0x7b,0xbd,0xb3,0xd5,0x04,0x01,0x00,0x04,0x00,0x20,0x80, 0x00,0x10,0x10,0x08,0x00,0x04,0x42,0x90,0x00,0x14,0xe4,0xb3,0xee,0xcd,0xaf, 0xbf,0x00,0x00,0x00,0x7a,0x13,0x91,0x7e,0x29,0x9f,0x20,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x57,0xcb,0xf7, 0xd7,0xef,0xbf,0x8f,0x3a,0x85,0xa2,0xbb,0xdf,0xd3,0xd7,0x4c,0x00,0x08,0x00, 0x00,0x00,0x00,0x40,0x00,0x00,0x40,0x10,0x80,0x00,0x02,0x42,0x02,0x72,0x59, 0x7f,0x3b,0x9d,0x37,0x00,0x00,0x80,0xea,0xf8,0xfc,0x04,0x35,0xba,0x22,0x00, 0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x40, 0x6e,0xc2,0xbf,0xfc,0xf5,0xfb,0x2f,0x6a,0xad,0xa9,0xeb,0xf6,0xd3,0x76,0x15, 0x20,0x40,0x80,0x10,0x01,0x02,0x00,0x00,0x00,0x01,0x04,0x00,0x20,0x00,0x00, 0x0c,0xfa,0xdc,0x81,0x3a,0x97,0xb7,0x10,0x00,0x00,0xda,0xf9,0xa4,0x03,0xef, 0x6e,0x01,0x40,0x04,0x08,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x11, 0x04,0x20,0x88,0xd8,0x93,0xf7,0x6b,0xef,0xd7,0x9f,0xad,0x12,0x85,0xf6,0xbd, 0xc9,0xb7,0x02,0x08,0xfa,0xff,0x0e,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00, 0x00,0x91,0x88,0x10,0xbc,0xb8,0x81,0x7d,0xb8,0xba,0x00,0x00,0x00,0xba,0x7c, 0x56,0x80,0xdb,0x6c,0x00,0x15,0x00,0x81,0xe0,0x00,0x01,0x14,0x00,0x08,0x40, 0x10,0x10,0x00,0x80,0x08,0x44,0x7f,0x2e,0xfd,0xff,0xbf,0xff,0x5f,0x35,0x50, 0xa5,0x6e,0xff,0x64,0xd7,0x4b,0x04,0xf8,0xce,0x0e,0x00,0x10,0x00,0x00,0x04, 0x00,0x40,0x00,0x10,0x00,0x00,0x0d,0x7d,0xe6,0x80,0xdb,0x3c,0x33,0x04,0x00, 0x00,0xea,0x5c,0x6e,0x00,0x6f,0x79,0x00,0x00,0x40,0x00,0x18,0x10,0xc0,0x3f, 0x04,0x80,0x88,0x04,0x04,0x00,0x00,0x80,0x82,0xd4,0x2a,0xff,0xdf,0xf7,0xfe, 0xbf,0xa6,0x6a,0xca,0xff,0xb7,0xf4,0xbf,0xaa,0x93,0x68,0x5a,0x28,0x01,0x00, 0x00,0x40,0x00,0x08,0x00,0x12,0x04,0x0a,0x42,0x02,0x6d,0x3d,0x80,0xbf,0x5c, 0xbb,0x00,0x00,0x00,0xba,0x3e,0xfd,0x80,0xfd,0xe8,0x13,0x00,0x02,0x00,0x04, 0x0c,0x30,0x01,0xc0,0x00,0xe0,0x03,0xc1,0x87,0x00,0x80,0x7d,0xfa,0xcd,0xee, 0xf6,0xde,0xef,0xbe,0xde,0x06,0x51,0xcf,0x7e,0xb2,0xca,0x7a,0x04,0x00,0x00, 0x00,0x08,0x00,0x78,0x00,0x00,0x80,0x19,0x00,0x00,0xc1,0x20,0x85,0x3e,0x7b, 0x80,0xb5,0x79,0x3e,0x10,0x00,0x00,0x7a,0x3e,0x7b,0x81,0xdb,0xf9,0x02,0x10, 0x2c,0x00,0x26,0x00,0x90,0x00,0xe0,0x00,0xe0,0x8e,0xc0,0x0d,0x00,0x64,0xab, 0xe2,0xdf,0xfe,0xff,0x7f,0xff,0x7f,0xa9,0xac,0xc8,0xfd,0x7b,0xbb,0xf7,0x4e, 0x05,0x40,0xb3,0x05,0x10,0x80,0x44,0x01,0x00,0x01,0x09,0x60,0x00,0x10,0x48, 0x83,0x2e,0xd7,0x80,0xef,0x69,0xbe,0x00,0x00,0x00,0x7a,0x16,0xb5,0x91,0xb5, 0xda,0x01,0x01,0x7f,0x20,0x90,0x00,0x38,0x11,0x60,0xa0,0x42,0x0a,0x42,0x00, 0x04,0x81,0xfc,0x0f,0x3e,0xdd,0x6d,0xef,0x5f,0xff,0xae,0x22,0x42,0xef,0x3f, 0xf9,0xc6,0x17,0x01,0x40,0x8d,0x41,0x02,0x40,0x02,0x01,0x00,0x41,0x09,0x20, 0x00,0x00,0xe0,0x8b,0x9e,0xbd,0x91,0x7b,0xba,0x36,0x00,0x00,0x00,0x7a,0xbe, 0xf7,0x01,0x77,0x73,0x01,0x80,0xe3,0x08,0xd1,0x20,0x08,0x19,0x25,0xcf,0x30, 0x65,0x67,0x22,0x00,0x20,0xd1,0x95,0x3c,0xf9,0xdf,0xfb,0xfb,0x7b,0x93,0x20, 0xc1,0x5d,0x9f,0xbc,0xa3,0x8d,0x44,0x44,0x97,0x00,0x00,0x00,0x02,0x01,0x00, 0xc5,0x3f,0x00,0x00,0x00,0xe8,0x8f,0x16,0xdb,0x80,0xaf,0xdb,0xbe,0x24,0x00, 0x00,0x5a,0x96,0xda,0x80,0xff,0xb2,0x11,0x80,0xc1,0x80,0xdd,0x28,0x80,0xd4, 0xdf,0x29,0x98,0x3c,0xb8,0xb3,0x41,0x88,0xf6,0x57,0x77,0xf1,0xff,0xff,0xfd, 0xdf,0x5e,0x2b,0xb0,0xfe,0x97,0x5e,0xf8,0xe7,0x93,0x40,0x93,0x20,0x00,0x00, 0x02,0x4d,0x99,0x07,0xcb,0x93,0x8d,0x01,0x31,0x09,0x8e,0xdd,0x81,0xfb,0xf2, 0x3a,0x00,0x00,0x20,0x7a,0x8e,0x5a,0x89,0x55,0xd3,0x81,0x08,0xd0,0x00,0xe7, 0x1b,0x80,0xbc,0x33,0x3c,0x04,0x36,0xe4,0xe9,0x00,0x62,0x2f,0xbf,0xee,0xf2, 0xfd,0xbf,0xff,0x7d,0x2b,0x63,0x60,0xf7,0x4f,0x46,0xbd,0xfa,0x2d,0x00,0x08, 0x08,0x00,0x03,0x46,0x6b,0x4d,0x03,0x4d,0x59,0x4b,0x01,0xa4,0x2a,0x9f,0xb7, 0x80,0x53,0xb3,0xbe,0x04,0x00,0x00,0x7a,0xdb,0xbe,0x21,0xff,0x76,0x05,0x00, 0xe5,0x10,0xc0,0x20,0x08,0x40,0x01,0x00,0x80,0x00,0x00,0x00,0x00,0xe8,0xcd, 0x65,0xfc,0xe4,0x77,0xf7,0x77,0xff,0x5a,0x54,0xa2,0xb6,0x67,0x7f,0x7a,0x0b, 0x77,0x11,0x0c,0x00,0x01,0x20,0x3c,0xd9,0x3b,0x0d,0xc9,0x37,0xb9,0x07,0x48, 0x4a,0x92,0x6c,0x81,0xf5,0xb2,0x3c,0x00,0x00,0x00,0x7a,0xcb,0xdd,0x81,0xed, 0xe7,0x05,0x02,0x3e,0x00,0x60,0x00,0x00,0x90,0x00,0x01,0x00,0x00,0x00,0x00, 0x08,0x11,0xb5,0xde,0xb8,0xc9,0xff,0xff,0xfd,0xff,0xd5,0x90,0xb0,0xba,0x93, 0xdb,0x8d,0xbf,0x42,0x02,0x1e,0x42,0x00,0x22,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x40,0x65,0x4f,0x9f,0xbf,0x91,0x7f,0xd7,0xbd,0x00,0x00,0x80,0x7a,0x5d, 0x6f,0x21,0xe7,0x66,0x83,0x00,0x0f,0x02,0x40,0x80,0x20,0xd2,0x00,0x00,0x00, 0x00,0x00,0x20,0x00,0xae,0xae,0xd3,0xf3,0x9b,0xd7,0xef,0xbf,0xff,0x1f,0x2c, 0x2d,0xdd,0x99,0x7f,0x57,0x4a,0xac,0x41,0x14,0x08,0x10,0x00,0x00,0x20,0x00, 0x00,0x10,0x00,0x00,0x00,0xe8,0x47,0xd3,0x6d,0x81,0xf7,0x75,0x35,0x04,0x00, 0x00,0x3a,0xd7,0xdc,0x89,0xef,0xe5,0x22,0xa0,0x83,0x00,0x10,0x00,0x00,0x20, 0x00,0x00,0x80,0xc0,0x08,0x00,0x00,0x61,0x11,0xea,0xce,0x36,0x7f,0xbf,0xff, 0xfe,0x69,0x0b,0x4d,0xf7,0xe4,0xca,0xb5,0x8e,0x2b,0x04,0x88,0x00,0x0b,0x08, 0x00,0x00,0x10,0x20,0x00,0x00,0x84,0x00,0x72,0x40,0x8b,0xef,0x81,0x55,0xd3, 0xbd,0x00,0x00,0x10,0x78,0xd5,0xdf,0x81,0x7b,0xa7,0x05,0x01,0x09,0x90,0x00, 0x10,0x04,0x38,0x80,0x00,0x00,0x30,0x01,0x82,0x20,0x40,0xc4,0xb0,0xbf,0x27, 0xfe,0xfb,0xaf,0xff,0x5b,0x93,0x4a,0x75,0xe4,0xfb,0x4a,0x3d,0x29,0x81,0x00, 0xa0,0x34,0x00,0x08,0x08,0x00,0x00,0x02,0x04,0x00,0x50,0xa8,0x00,0xdb,0xad, 0xa0,0xef,0xf7,0xbc,0x00,0x00,0x00,0x7a,0xdb,0xde,0x81,0xed,0xf6,0x22,0x88, 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0c,0x02,0x20,0x00,0xa8,0x7f, 0xaf,0xb6,0x6d,0xee,0xbf,0xfb,0x00,0x00,0x0c,0x54,0xfd,0xec,0xb7,0xfd,0xfd, 0x5f,0x10,0x24,0x04,0x3e,0x00,0x00,0x01,0x04,0x01,0x80,0x80,0x00,0x04,0x32, 0x40,0x95,0xcf,0x81,0x73,0x55,0x2d,0x00,0x00,0x04,0x7a,0xc5,0x5b,0x11,0xff, 0xe5,0x09,0x80,0xff,0x00,0x04,0x02,0x80,0x00,0x00,0x00,0x40,0xe0,0x40,0x00, 0x08,0xe9,0xff,0x7e,0x7d,0x27,0xfe,0xf7,0x8f,0x0b,0xee,0xe3,0x49,0xed,0xd9, 0xff,0x77,0xd7,0xb6,0xef,0xdf,0xfb,0x57,0x40,0x40,0x80,0x00,0x70,0x04,0x00, 0x00,0x80,0x68,0x0d,0x9b,0x7e,0x81,0x7f,0xf3,0xbd,0x20,0x00,0x00,0x5a,0x97, 0xde,0x81,0x6d,0xb7,0x00,0x02,0x20,0x22,0x89,0x80,0x00,0x20,0x10,0x18,0x02, 0x94,0x03,0x04,0x00,0x00,0x00,0x00,0x00,0x90,0x61,0x3f,0x34,0xaa,0xea,0x60, 0xd9,0x16,0x22,0x00,0x89,0x2a,0x55,0xb5,0x6a,0xad,0x56,0x48,0x04,0x00,0x74, 0x10,0x90,0x10,0x44,0x00,0xf6,0x4f,0x96,0xeb,0x88,0xf7,0x5a,0x37,0x00,0x00, 0x00,0x6a,0x8a,0xb9,0x80,0x73,0xd3,0x01,0x20,0x09,0x00,0x04,0x20,0xa0,0x42, 0x00,0x0a,0x02,0xb0,0xef,0xfb,0x77,0x7f,0xf7,0xb7,0xef,0x9f,0xcd,0x57,0x9b, 0x03,0x00,0x52,0xa5,0x7e,0xe6,0xff,0xfe,0xdd,0xfb,0xdd,0xff,0xf7,0x71,0x00, 0xd5,0x3e,0xe5,0xd2,0x96,0x0f,0x00,0x20,0x01,0x00,0x95,0xde,0x81,0xb9,0x73, 0xae,0x04,0x00,0x00,0x58,0xb6,0xf7,0x00,0xbb,0xba,0x4a,0x00,0x00,0x91,0xba, 0x86,0x9a,0xa9,0xf2,0xe1,0x1c,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 0xd3,0x84,0xf0,0xff,0xff,0x1f,0x06,0xb1,0x0f,0x00,0x00,0x00,0x00,0x12,0x12, 0x24,0x2a,0xc0,0x58,0xa1,0x92,0x28,0x65,0x10,0x00,0x21,0x34,0x84,0x86,0xb9, 0xa0,0x7f,0xdb,0xb6,0x10,0x00,0x00,0xaa,0x26,0x3d,0x91,0xbd,0x59,0x03,0x00, 0x00,0x00,0xa5,0x6a,0x05,0x46,0x24,0x49,0x45,0xdc,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x69,0x82,0xff,0xff,0xff,0xff,0x87,0xce,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x27,0x03,0x00,0x10,0x00,0x00,0x00,0x02,0x44,0x88,0x00, 0xa1,0x36,0x7f,0x81,0xcd,0x19,0xbe,0x00,0x00,0x08,0xfa,0x2e,0x7b,0x01,0x7b, 0xb9,0x43,0x04,0x48,0x94,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xb3,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xf3,0xf8,0xff,0xfd,0xff,0xff,0xbf,0x8e,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdb,0x02,0x04,0x00,0x00,0x00,0x00,0x02, 0x01,0x40,0x2a,0x80,0x36,0xb3,0x80,0xbd,0x79,0xbe,0x00,0x00,0x00,0xba,0x5b, 0x6f,0x00,0xcd,0x49,0x00,0x21,0x04,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00, 0xd5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xff,0x5f,0x95,0x00,0xf0, 0xff,0xff,0xe7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x25,0x1a,0x42,0x48,0x41, 0x08,0x00,0x48,0x21,0xad,0x31,0x14,0x65,0xef,0x08,0xef,0x0c,0x31,0x10,0x00, 0x80,0xea,0x55,0x0a,0x04,0x58,0xac,0x54,0x00,0x00,0x08,0x00,0x00,0x01,0x00, 0x00,0x00,0x10,0x15,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd5,0xee,0xb7, 0xad,0xfe,0x8b,0xfe,0xf7,0xa9,0xda,0xff,0xff,0xff,0xff,0xff,0xff,0x95,0xc6, 0x90,0x5a,0x1d,0x73,0x6f,0x27,0x94,0x5a,0xce,0x51,0x55,0x1d,0x40,0xbc,0x5c, 0xbf,0x00,0x00,0x00,0xf8,0xc5,0xfc,0xff,0xbf,0x56,0x9b,0x73,0x6b,0xe7,0xac, 0xbd,0xae,0x95,0xb3,0x56,0x4b,0xe5,0x49,0x0a,0x00,0x02,0x40,0x00,0x00,0x00, 0x3e,0x00,0x00,0x2b,0x20,0x30,0x00,0x70,0x01,0xe0,0x88,0xc0,0x06,0x40,0x80, 0x85,0x84,0x88,0xb4,0x56,0x45,0xa5,0x52,0x6a,0xa9,0xb5,0xab,0xb4,0x68,0xf6, 0xff,0xf7,0xb4,0xbf,0x04,0x00,0x00,0x9a,0xb9,0xd4,0xff,0x97,0x26,0x2d,0x55, 0x6d,0x55,0x1a,0x63,0x4a,0x90,0x54,0x2d,0x2a,0x95,0x56,0x05,0x07,0x06,0xc0, 0x61,0x00,0x00,0xe2,0x00,0x03,0x2f,0x70,0xe0,0x01,0xfc,0x03,0xf0,0x7f,0xc0, 0x1d,0xc0,0x00,0xb7,0x2b,0x53,0x6a,0xd7,0x56,0x49,0x0c,0x2b,0x2d,0xdf,0x67, 0xb5,0x88,0xd8,0xff,0x57,0xae,0xb5,0x00,0x00,0x00,0xda,0x1b,0xb9,0xb6,0x2e, 0xcb,0x4e,0x4b,0x0c,0xa9,0xb5,0xba,0xb7,0xb5,0x96,0xb2,0x57,0xb1,0xed,0x00, 0x0f,0x18,0x80,0xf7,0x00,0x07,0xae,0x09,0x07,0x0c,0x70,0x80,0x03,0xfc,0x07, 0xf8,0x2b,0x80,0x7f,0xc0,0x01,0x5f,0x72,0xb6,0xdf,0xfa,0xbd,0xf7,0xfb,0xea, 0xd6,0x6a,0xda,0x4b,0xdb,0xbd,0xfe,0x3d,0x93,0xbb,0x00,0x00,0x10,0xfa,0xaa, 0xe3,0xba,0x3c,0xab,0xfd,0xf7,0xf7,0xf7,0x6e,0x77,0xad,0x77,0xf7,0xfd,0xd6, 0x4e,0x5f,0x01,0x0f,0x38,0x04,0xf7,0x00,0x17,0x5e,0x81,0x97,0x0c,0x70,0x80, 0x03,0xbe,0x05,0xfc,0x5f,0x08,0x77,0xc0,0x20,0xbe,0x35,0x0a,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x04,0x20,0x56,0xd1,0x2e,0x16,0x47,0x3d,0x00,0x00, 0x00,0xe8,0x27,0xa6,0xb5,0x87,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x80,0x78,0xb7,0x00,0x0f,0xb8,0x00,0xf6,0x00,0xe1,0xdf,0x00,0x07, 0x08,0x70,0x80,0x01,0x6e,0x02,0xbc,0xb0,0x01,0x5f,0xe0,0x80,0x9f,0xca,0xf1, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x87,0x63,0x5b,0xc5,0x69, 0xae,0x40,0x00,0x00,0xfa,0x2c,0x8d,0xaf,0xe3,0xe8,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xaf,0xb7,0x5a,0x08,0x0f,0xb8,0x01,0xf0,0x04,0xf1, 0xb7,0x01,0x07,0x08,0x70,0xc0,0x03,0x3e,0x06,0x6c,0x8d,0x01,0x5e,0x40,0xc8, 0xbf,0xfc,0xc7,0xd5,0xbe,0xc5,0xba,0xea,0xff,0xdd,0xff,0xf7,0xff,0x6f,0x8c, 0x57,0x63,0xe4,0xbb,0x10,0x00,0x00,0xba,0x5c,0x1c,0xd6,0x70,0xe4,0xff,0xfd, 0xf7,0xee,0xfd,0xff,0xff,0x6f,0xfb,0xee,0xd7,0x6d,0xdd,0x00,0x07,0xb8,0x21, 0xb0,0x00,0xe3,0x5c,0x13,0x07,0x08,0xf0,0x80,0x23,0x5e,0x06,0xfc,0xdc,0x21, 0x3e,0xd0,0x80,0xaf,0xae,0xae,0xff,0xff,0xaa,0xfe,0xde,0xdf,0xf7,0xfd,0x55, 0xbf,0x9d,0x0e,0xdd,0xf1,0xb2,0xbd,0x00,0x00,0x00,0xea,0x9e,0x71,0x00,0x1c, 0xf5,0xfa,0x2b,0xfd,0xb7,0xbf,0xcf,0xf5,0xad,0xde,0x7f,0x6b,0x7f,0xbe,0x40, 0x0f,0xb8,0x07,0xf0,0x00,0x37,0x56,0x04,0x47,0x0e,0x71,0x80,0x03,0x1e,0x86, 0x38,0xec,0x01,0x7c,0xe0,0x80,0xb7,0xfa,0xcd,0xdf,0xdd,0x75,0xb7,0x55,0xf7, 0xbd,0xff,0xd5,0xbf,0x2f,0x71,0x00,0x1c,0xf9,0xb9,0x00,0x00,0x40,0x7a,0x3f, 0xe5,0x01,0x2f,0xda,0xdb,0x55,0x5f,0xef,0xed,0xfb,0xbe,0x6d,0xeb,0xaa,0xe3, 0xfb,0x7a,0x01,0x8f,0x18,0x0f,0xf0,0x00,0x0f,0xde,0x01,0x07,0x1c,0x70,0xc0, 0x01,0x0f,0x06,0x3c,0xcc,0x03,0x38,0xc4,0x04,0xaf,0xad,0xaa,0x97,0xfb,0xcd, 0xdb,0xff,0x3a,0xd7,0xfd,0xba,0xfd,0x7f,0xf5,0x21,0xaf,0x7c,0xb7,0x00,0x00, 0x00,0x48,0xfb,0x92,0xff,0xa3,0xfd,0xf6,0xe7,0xfe,0xd6,0x77,0xdf,0xf7,0xa7, 0x7e,0xf3,0x74,0x77,0xaf,0x00,0x07,0x1e,0x1b,0xf0,0x20,0x03,0xae,0x00,0x03, 0x1e,0x30,0xe0,0x00,0x02,0x02,0x08,0x84,0x01,0x18,0xc0,0x00,0x6f,0xbe,0x4d, 0x1c,0xfb,0xba,0xbe,0x55,0xef,0x7b,0xbb,0xad,0xdb,0xad,0x04,0xef,0x25,0xfe, 0xbb,0x20,0x00,0x00,0xfa,0xff,0x84,0x7c,0x80,0xee,0x7b,0x37,0xfb,0xbf,0xfb, 0xeb,0x6d,0x5b,0xfd,0xf1,0x6a,0x5d,0x7d,0x06,0x07,0x0e,0x2c,0x30,0x08,0x00, 0x1e,0x00,0x41,0x7f,0x20,0x38,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x01,0x83, 0xd8,0xfd,0xae,0xa5,0xbd,0x5d,0xef,0xef,0xef,0xfe,0x7e,0x5a,0xef,0xbb,0x28, 0xd6,0x12,0xf7,0x3d,0x00,0x00,0x00,0x9a,0xb5,0x33,0x02,0x2a,0xdb,0xf6,0xd5, 0x6a,0xdd,0xde,0xdf,0xd7,0xf5,0xba,0x2d,0x60,0xb4,0xde,0xfd,0xfa,0xff,0xdf, 0xff,0xff,0xff,0xf7,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x5f,0x5a,0x2a,0x3b,0xf7,0xbe,0xaf,0x5b,0xf7,0xeb,0x73,0xfd, 0x5e,0xcf,0x03,0x20,0xc9,0xbd,0xbb,0x08,0x00,0x00,0x7a,0xf7,0x62,0x01,0x88, 0x75,0xef,0x73,0xfd,0xdb,0xbf,0xef,0xef,0x5b,0x7d,0xcb,0xe5,0x75,0xbf,0xfe, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x75,0x57,0xac,0x75,0xba,0x7c,0xaf,0xe7, 0xfb,0xae,0xad,0xd5,0xbf,0x07,0x50,0x60,0x6f,0xb5,0x00,0x00,0x00,0xba,0x7d, 0x1f,0xfe,0x71,0xb7,0xdf,0xdc,0xb6,0x7d,0xcf,0xbb,0xfb,0xf2,0xd7,0x51,0x51, 0x8f,0x77,0xfb,0xff,0xff,0x7f,0xff,0xff,0xff,0xdf,0xff,0xff,0x6f,0xff,0xaf, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xdd,0x1e,0xc7,0xaf,0x7d, 0xa7,0xff,0xdf,0xbf,0xdb,0xfa,0xfe,0xfb,0xff,0xa0,0xfe,0xef,0x3f,0x00,0x00, 0x40,0x72,0xdf,0xff,0x00,0xce,0xdf,0xb7,0x7b,0xef,0x77,0x7f,0xff,0xde,0xff, 0xff,0xff,0xff,0xfb,0x5d,0xea,0xff,0xe5,0xef,0xfe,0xff,0xff,0x37,0xff,0xff, 0xdb,0xee,0x7b,0xff,0xff,0xff,0xdd,0xf7,0xff,0x7b,0xab,0xaa,0x2a,0x85,0x54, 0x55,0x54,0x52,0x52,0x51,0x04,0x84,0x14,0x02,0x08,0x04,0x00,0x12,0x09,0x00, 0x80,0x00,0x00,0x10,0xf8,0xff,0xff,0xd7,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xbf,0xff,0xde,0x56,0xad,0xaa,0x56,0x53,0x15,0x04,0x0a,0x11,0x01,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, 0x00,0x00,0x20,0x80,0x24,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x22,0x22,0x91,0xac,0xea,0x6a,0x7b,0xed, 0xbe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xff,0xff,0xff,0xb7, 0xde,0xff,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x20,0x04,0x01,0x00,0x00,0x00,0x4a,0xca,0xaa,0xbe,0xdd, 0x76,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xef,0xfd,0x6d,0x6d,0xab,0xaa, 0x9a,0x4a,0x81,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x40,0x02,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x01,0x00,0x20,0x80,0x00,0x00,0x00, 0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x01,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x44,0x10,0xa4,0x08,0x80,0x80,0x00,0x08, 0x80,0x00,0x00,0x00,0x00,0x01,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x02,0x21, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20, 0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x04,0x00,0x00,0x00, 0x20,0x00,0x00,0x10,0x10,0x00,0x80,0x40,0x00,0x80,0x00,0x00,0x00,0x00,0x00, 0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x08,0x00,0x00,0x42,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x10, 0x41,0x00,0x02,0x04,0x00,0x10,0x00,0x00,0x08,0x00,0x00,0x40,0x04,0x00,0x80, 0x00,0x00,0x20,0x00,0x10,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x04,0x02, 0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x10,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x02,0x10,0x02,0x80,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x10,0x00,0x00,0x00,0x00,0x10,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x22,0x02,0x00,0x00,0x01,0x00, 0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x84,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0x00,0x00,0x00,0x20,0x04,0x00, 0x08,0x00,0x04,0x80,0x10,0x02,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x02,0x00, 0x00,0x00,0x40,0x24,0x84,0x20,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x80,0x00,0x80,0x00,0x00,0x00,0x02,0x00,0x01,0x20,0x10,0x84, 0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x08,0x20,0x00,0x01,0x00,0x00,0x00, 0x00,0x00,0x00,0x02,0x80,0x00,0x00,0x00,0x20,0x00,0x00,0x01,0x00,0x00,0x01, 0x00,0x00,0x00,0x24,0x02,0x01,0x00,0x00,0x00,0x00,0x20,0x00,0x14,0x88,0x10, 0x00,0x00,0x84,0x00,0x00,0x00,0x04,0x10,0x00,0x40,0x00,0x40,0x00,0x42,0x00, 0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x21,0x00,0x08,0x04,0x01,0x08,0x00,0x48, 0x00,0x00,0x04,0x08,0x00,0x80,0x00,0x10,0x00,0x20,0x00,0x08,0x00,0x40,0x00, 0x00,0x00,0x00,0x08,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; blt-2.4z.orig/demos/bitmaps/hobbes.xbm0100644000175000017500000000136507240160072016467 0ustar dokodoko#define hobbes_width 25 #define hobbes_height 25 #define hobbes_x_hot 16 #define hobbes_y_hot 15 static char hobbes_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x78, 0xe0, 0x07, 0x00, 0xfc, 0xf8, 0x07, 0x00, 0xcc, 0x07, 0x04, 0x00, 0x0c, 0xf0, 0x0b, 0x00, 0x7c, 0x1c, 0x06, 0x00, 0x38, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x10, 0x00, 0xe0, 0x41, 0x11, 0x00, 0x20, 0x40, 0x11, 0x00, 0xe0, 0x07, 0x10, 0x00, 0xe0, 0xc1, 0x17, 0x00, 0x10, 0xe0, 0x2f, 0x00, 0x20, 0xe0, 0x6f, 0x00, 0x18, 0xe0, 0x2f, 0x00, 0x20, 0xc6, 0x67, 0x00, 0x18, 0x84, 0x2b, 0x00, 0x20, 0x08, 0x64, 0x00, 0x70, 0xf0, 0x13, 0x00, 0x80, 0x01, 0x08, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; blt-2.4z.orig/demos/bitmaps/hobbes_mask.xbm0100644000175000017500000000137407240160072017502 0ustar dokodoko#define hobbes_width 25 #define hobbes_height 25 #define hobbes_x_hot 16 #define hobbes_y_hot 15 static unsigned char hobbes_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x78, 0xe0, 0x07, 0x00, 0xfc, 0xf8, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0xf8, 0xff, 0x0f, 0x00, 0xe0, 0xff, 0x1f, 0x00, 0xe0, 0xff, 0x1f, 0x00, 0xe0, 0xff, 0x1f, 0x00, 0xe0, 0xff, 0x1f, 0x00, 0xe0, 0xff, 0x1f, 0x00, 0xf0, 0xff, 0x3f, 0x00, 0xe0, 0xff, 0x7f, 0x00, 0xf8, 0xff, 0x3f, 0x00, 0xe0, 0xff, 0x7f, 0x00, 0xf8, 0xff, 0x3f, 0x00, 0xe0, 0xff, 0x7f, 0x00, 0xf0, 0xff, 0x1f, 0x00, 0x80, 0xff, 0x0f, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; blt-2.4z.orig/demos/bitmaps/sharky.xbm0100644000175000017500000002233107240160072016522 0ustar dokodoko#define sharky_width 171 #define sharky_height 68 static char sharky_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0xfd, 0x03, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x49, 0x92, 0x54, 0x55, 0x45, 0xeb, 0x07, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x41, 0x55, 0x84, 0x44, 0x85, 0xa2, 0x50, 0x94, 0x0f, 0x00, 0x00, 0x06, 0x00, 0xfc, 0x17, 0x00, 0x40, 0x12, 0x12, 0x42, 0x00, 0x01, 0x04, 0x04, 0x51, 0x75, 0x75, 0xd5, 0xae, 0x55, 0x10, 0x00, 0x80, 0x0f, 0x00, 0xfe, 0x1f, 0x00, 0x5c, 0x54, 0x45, 0x89, 0x04, 0x10, 0x00, 0x80, 0x08, 0x55, 0xd5, 0x5e, 0x55, 0xa5, 0x25, 0x15, 0xa0, 0x1f, 0x00, 0xfe, 0x1f, 0x00, 0xde, 0x55, 0xb5, 0x76, 0x65, 0x25, 0x52, 0x22, 0xd0, 0x56, 0x7b, 0xd5, 0xff, 0x5d, 0xb5, 0xa2, 0xd7, 0x1f, 0x00, 0xff, 0x0d, 0x00, 0x17, 0x41, 0x40, 0x00, 0x7a, 0x95, 0x00, 0x91, 0x0a, 0xd9, 0xed, 0x7f, 0xd5, 0x73, 0x5b, 0x55, 0x54, 0x7f, 0x80, 0xde, 0x07, 0x00, 0xab, 0x54, 0x14, 0x49, 0xa8, 0x6e, 0x55, 0x0c, 0x64, 0x75, 0xff, 0xff, 0xbf, 0xde, 0x57, 0xd5, 0x95, 0xfa, 0x43, 0x7f, 0x07, 0x00, 0x17, 0x00, 0x09, 0x00, 0x74, 0xd1, 0x5b, 0xb5, 0xa9, 0xdd, 0xd5, 0xf7, 0xfd, 0x5f, 0x5e, 0x55, 0x52, 0x95, 0xdd, 0xfd, 0x05, 0x00, 0x76, 0x55, 0x52, 0x25, 0xf9, 0x15, 0x76, 0x6f, 0xb6, 0xf7, 0xff, 0xff, 0xff, 0xfb, 0xd7, 0xf7, 0xaa, 0x75, 0xf7, 0xf7, 0x03, 0x00, 0xd8, 0x15, 0x50, 0x00, 0xf8, 0x60, 0xe8, 0xdd, 0x5d, 0x7f, 0xff, 0xff, 0xef, 0xff, 0xfd, 0x5e, 0x5b, 0xff, 0xbf, 0xad, 0x03, 0x00, 0x70, 0x27, 0x05, 0x49, 0xf9, 0x0a, 0x12, 0xb6, 0xf5, 0xfd, 0x7f, 0xdf, 0xfd, 0xff, 0xff, 0xdf, 0xff, 0xbd, 0x6d, 0xd6, 0x07, 0x00, 0xe0, 0x5b, 0x75, 0x04, 0x7c, 0x01, 0x40, 0xa8, 0xee, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xbf, 0xff, 0xeb, 0xd7, 0xd5, 0xbd, 0x05, 0x00, 0x80, 0x7f, 0x05, 0x51, 0xb1, 0x44, 0x95, 0x46, 0x75, 0xe7, 0xff, 0xff, 0xff, 0xde, 0xfb, 0xfb, 0x7e, 0x7d, 0x75, 0xef, 0x07, 0x00, 0x00, 0x7e, 0x5b, 0x12, 0x00, 0x10, 0x00, 0x18, 0x4a, 0x9d, 0xfd, 0xdf, 0xf6, 0xfb, 0xff, 0xdf, 0xd7, 0xa5, 0x4d, 0xd5, 0x06, 0x00, 0x00, 0xf8, 0xd7, 0xad, 0x0a, 0x02, 0x44, 0x82, 0x52, 0x77, 0xef, 0xfd, 0xbf, 0xdf, 0xd6, 0xf6, 0x7e, 0x5f, 0x03, 0xf7, 0x0f, 0x00, 0x00, 0xe0, 0x5f, 0xb6, 0x44, 0x08, 0x11, 0x51, 0x54, 0x4a, 0xbb, 0xf7, 0xed, 0x7a, 0xdf, 0xdd, 0xd5, 0x75, 0x00, 0x5e, 0x1d, 0x00, 0x00, 0x00, 0x3f, 0x93, 0x5d, 0x43, 0x44, 0x08, 0x11, 0x69, 0xd5, 0x5e, 0x7f, 0xdf, 0x7b, 0x77, 0x75, 0x3b, 0x00, 0xf0, 0x2b, 0x00, 0x00, 0x00, 0xfc, 0x5d, 0x67, 0x11, 0x00, 0x21, 0x44, 0x55, 0x7b, 0x75, 0xd5, 0x6b, 0xd5, 0x6d, 0x5f, 0x07, 0x00, 0x50, 0x37, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x9d, 0x84, 0x48, 0x48, 0x89, 0x50, 0xb6, 0xd6, 0xbd, 0x5a, 0x77, 0xdb, 0xd6, 0x3d, 0x00, 0xc0, 0x76, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x57, 0x40, 0x02, 0x45, 0x44, 0xd7, 0x55, 0x55, 0xd5, 0x54, 0x55, 0x35, 0x33, 0x00, 0x80, 0xdf, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x3f, 0x15, 0x50, 0x50, 0xd1, 0x7f, 0x54, 0xb5, 0x56, 0xdd, 0xf6, 0x1d, 0x5c, 0x00, 0x00, 0xf5, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x40, 0x45, 0x09, 0x41, 0xe4, 0x5f, 0x95, 0x52, 0x55, 0x25, 0x55, 0x07, 0x74, 0x00, 0x00, 0xbc, 0x01, 0x00, 0x00, 0x00, 0x80, 0x54, 0x12, 0x32, 0x11, 0x15, 0xf1, 0xff, 0x52, 0x15, 0x53, 0xa9, 0xdd, 0x1f, 0x10, 0x00, 0x00, 0xe8, 0x02, 0x00, 0x00, 0x00, 0x40, 0x05, 0xc9, 0x44, 0x49, 0x55, 0xf4, 0xf7, 0x12, 0x45, 0x11, 0x55, 0xd5, 0x1f, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x56, 0x5b, 0xb5, 0xa4, 0xea, 0x5f, 0x4f, 0x51, 0xcc, 0xd6, 0x3f, 0x74, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf5, 0x56, 0x5b, 0xf5, 0xff, 0x50, 0x55, 0xdb, 0xff, 0x1f, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xbf, 0xff, 0x55, 0xff, 0xff, 0xaf, 0xd6, 0xff, 0xc1, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xef, 0xfe, 0xf7, 0xff, 0xdf, 0xff, 0x05, 0xe0, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x40, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xaf, 0x1f, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x02, 0x00, 0x3c, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x1f, 0x00, 0x00, 0xe0, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x03, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x03, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; blt-2.4z.orig/demos/bitmaps/xbob.xbm0100644000175000017500000000516007240160072016154 0ustar dokodoko #define bob_x_hot 30 #define bob_y_hot 37 #define bob_width 61 #define bob_height 75 static short bobr_bits[] = { /* a right-going ``Bob'' */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffe0, 0x07ff, 0x0000, 0x0000, 0xfffe, 0x1fff, 0x0000, 0x8000, 0xffff, 0xfbff, 0x0000, 0xc000, 0xcfff, 0xd19f, 0x0003, 0xf000, 0x8c7f, 0x9133, 0x0007, 0xf800, 0x18a7, 0xb127, 0x0006, 0xfc00, 0x3147, 0xa64e, 0x000e, 0xfe00, 0x214f, 0xae4c, 0x003d, 0xff00, 0x23df, 0xbe8d, 0x007d, 0xff80, 0x67ff, 0xfebd, 0x01ff, 0xff80, 0x7fff, 0xffbf, 0x03ff, 0xffc0, 0xffff, 0xffbf, 0x07f8, 0xffc0, 0xffff, 0x3fbf, 0x07f8, 0xffc0, 0xffff, 0x07ff, 0x0ff8, 0xffc0, 0xffff, 0x003f, 0x0ff8, 0x7fe0, 0xf800, 0x0007, 0x0ff0, 0x3fe0, 0x0000, 0x0000, 0x07f0, 0x3fe0, 0x0000, 0x0000, 0x07f0, 0x3fe0, 0x0000, 0x0000, 0x07f4, 0x3fe0, 0x0000, 0x0000, 0x07e4, 0x3fe0, 0x0000, 0x0000, 0x07e4, 0x3fe0, 0x0000, 0x0000, 0x07e6, 0x3fe0, 0x0000, 0x0000, 0x07e7, 0x3fe0, 0x0000, 0x0000, 0x07e6, 0x3fe0, 0x0000, 0x0000, 0x07e6, 0x3fe0, 0x0000, 0x0000, 0x07e6, 0x3fc0, 0x0000, 0x7800, 0x07f6, 0xbfa0, 0x00ff, 0xff00, 0x07f7, 0x9f70, 0x01ff, 0xff80, 0x07ef, 0x1cf0, 0x0380, 0x01e0, 0x07ef, 0x1ff0, 0x07be, 0x3ff0, 0x07ee, 0x9de0, 0x1f83, 0xe1f8, 0x07dc, 0xc1e0, 0x1f7f, 0xfffc, 0x07c8, 0xc1e0, 0x1e69, 0xca7e, 0x03c0, 0x81e0, 0x1fb8, 0x0ec0, 0x03c0, 0x01e0, 0x1bc0, 0xcfc0, 0x03c1, 0x03c0, 0x11f7, 0x7f00, 0x03c0, 0x03c0, 0x187c, 0x1c00, 0x02c0, 0x02c0, 0x0830, 0x0000, 0x0340, 0x0340, 0x0800, 0x0000, 0x0240, 0x1340, 0x0c00, 0x0000, 0x0260, 0x1240, 0x0e00, 0x0000, 0x03c0, 0x3380, 0x0e80, 0x0000, 0x01a8, 0x3300, 0x0f40, 0x03a0, 0x002c, 0x7400, 0x0f30, 0x0738, 0x002e, 0x7400, 0x1f98, 0x1e1e, 0x002f, 0xfc00, 0xff8f, 0xfc0f, 0x002f, 0xf800, 0xffe3, 0xf803, 0x002f, 0xf800, 0xfffd, 0xff81, 0x003f, 0xb800, 0x1ff9, 0x0ff8, 0x001e, 0x3000, 0xf0f1, 0x030f, 0x000e, 0x3000, 0x01f1, 0x0180, 0x000f, 0x2000, 0xf7f1, 0x00ff, 0x0007, 0x6000, 0x01e3, 0x8060, 0x0007, 0x6000, 0xefc3, 0x803f, 0x0003, 0x4000, 0xffc2, 0xc00f, 0x0003, 0xc000, 0x1fe6, 0xc000, 0x0001, 0x8000, 0xfef4, 0xe03f, 0x0000, 0x8000, 0xfe79, 0xe01f, 0x0000, 0x01c0, 0x3e3d, 0x7000, 0x0000, 0x0630, 0x0f3e, 0x3800, 0x0000, 0x8cc8, 0x071f, 0x3800, 0x0000, 0xccf4, 0x078f, 0x1c00, 0x0000, 0xee72, 0x07f7, 0x0e00, 0x0000, 0xff02, 0x07e3, 0x0700, 0x0000, 0xfe32, 0xffc1, 0x038f, 0x0000, 0xfe3e, 0xff80, 0x01ff, 0x0000, 0x7c7e, 0x0000, 0x007e, 0x0000, 0x3c7c, 0x0000, 0x0000, 0x0000, 0x1cfc, 0x0000, 0x0000, 0x0000, 0x1cf8, 0x0000, 0x0000, 0x0000, 0x0ff0, 0x0000, 0x0000, 0x0000, 0x07e0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}; blt-2.4z.orig/demos/Makefile.in0100644000175000017500000000462307434314102015123 0ustar dokodoko# ------------------------------------------------------------------------ # Makefile for demos # ------------------------------------------------------------------------ prefix = @prefix@ exec_prefix = @exec_prefix@ version = @BLT_VERSION@ libdir = @libdir@ scriptdir = $(prefix)/lib/blt$(version) destdir = $(scriptdir)/demos srcdir = @srcdir@ SHELL = /bin/sh RM = rm -rf INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_ROOT = instdirs = $(prefix) \ $(exec_prefix) \ $(libdir) \ $(scriptdir) \ $(destdir) \ $(destdir)/bitmaps \ $(destdir)/bitmaps/hand \ $(destdir)/bitmaps/fish \ $(destdir)/images \ $(destdir)/scripts demos = barchart1.tcl barchart2.tcl barchart3.tcl barchart4.tcl \ barchart5.tcl \ bgexec1.tcl bgexec2.tcl bgexec3.tcl bgexec4.tcl \ bitmap.tcl \ busy1.tcl busy2.tcl \ dnd1.tcl dnd2.tcl dragdrop1.tcl dragdrop2.tcl \ eps.tcl \ graph1.tcl graph2.tcl graph3.tcl graph4.tcl graph5.tcl \ graph6.tcl graph7.tcl \ hierbox1.tcl hierbox2.tcl hierbox3.tcl hierbox4.tcl \ hiertable1.tcl hiertable2.tcl \ htext1.tcl htext.txt \ spline.tcl stripchart1.tcl \ tabset1.tcl tabset2.tcl tabset3.tcl tabset4.tcl \ tabnotebook1.tcl tabnotebook2.tcl tabnotebook3.tcl \ treeview1.tcl \ winop1.tcl winop2.tcl all: install: mkdirs install-bitmaps install-images install-scripts install-scripts: for i in $(srcdir)/scripts/*.tcl ; do \ $(INSTALL) $$i $(INSTALL_ROOT)$(destdir)/scripts ; \ done for i in $(demos) ; do \ $(INSTALL) $(srcdir)/$$i $(INSTALL_ROOT)$(destdir)/$$i ; \ done install-bitmaps: for i in $(srcdir)/bitmaps/*.xbm ; do \ $(INSTALL_DATA) $$i $(INSTALL_ROOT)$(destdir)/bitmaps ; \ done for i in $(srcdir)/bitmaps/hand/*.xbm ; do \ $(INSTALL_DATA) $$i $(INSTALL_ROOT)$(destdir)/bitmaps/hand ; \ done for i in $(srcdir)/bitmaps/fish/*.xbm ; do \ $(INSTALL_DATA) $$i $(INSTALL_ROOT)$(destdir)/bitmaps/fish ; \ done install-images: for i in $(srcdir)/images/*.gif $(srcdir)/images/*.ps ; do \ $(INSTALL_DATA) $$i $(INSTALL_ROOT)$(destdir)/images ; \ done mkdirs: @for i in $(instdirs) ; do \ if test -d $(INSTALL_ROOT)"$$i" ; then \ : ; \ else \ echo " mkdir $(INSTALL_ROOT)$$i" ; \ mkdir $(INSTALL_ROOT)"$$i" ; \ fi ; \ done clean: $(RM) $(srcdir)/*.bak $(srcdir)/*\~ $(srcdir)/"#"* distclean: clean $(RM) *.ps Makefile blt-2.4z.orig/demos/Makefile.vc0100644000175000017500000000402207434307126015126 0ustar dokodoko# ------------------------------------------------------------------------ # Makefile for demos # ------------------------------------------------------------------------ include ../win/makedefs destdir = $(scriptdir)/demos srcdir = . SHELL = bash RM = rm -rf INSTALL = install -m 0755 INSTALL_DATA = install -m 0644 instdirs = $(prefix) $(exec_prefix) $(libdir) $(scriptdir) \ $(destdir) \ $(destdir)/bitmaps \ $(destdir)/bitmaps/hand \ $(destdir)/bitmaps/fish \ $(destdir)/images \ $(destdir)/scripts demos = barchart1.tcl barchart2.tcl barchart3.tcl barchart4.tcl \ barchart5.tcl \ bgexec1.tcl bgexec2.tcl bgexec3.tcl bgexec4.tcl \ bitmap.tcl \ busy1.tcl \ dragdrop1.tcl dragdrop2.tcl \ eps.tcl \ graph1.tcl graph2.tcl graph3.tcl graph4.tcl graph5.tcl \ graph6.tcl graph7.tcl \ hierbox1.tcl hierbox2.tcl hierbox3.tcl hierbox4.tcl \ hiertable1.tcl hiertable2.tcl hiertable3.tcl \ htext1.tcl htext.txt \ spline.tcl stripchart1.tcl \ tabset1.tcl tabset2.tcl tabset3.tcl tabset4.tcl \ tabnotebook1.tcl tabnotebook2.tcl tabnotebook3.tcl \ treeview1.tcl \ winop1.tcl winop2.tcl all: install: inst-dirs inst-bitmaps inst-images inst-scripts inst-scripts: for i in $(srcdir)/scripts/*.tcl ; do \ $(INSTALL) $$i $(destdir)/scripts ; \ done for i in $(demos) ; do \ $(INSTALL) $(srcdir)/$$i $(destdir)/$$i ; \ done inst-bitmaps: for i in $(srcdir)/bitmaps/*.xbm ; do \ $(INSTALL_DATA) $$i $(destdir)/bitmaps ; \ done for i in $(srcdir)/bitmaps/hand/*.xbm ; do \ $(INSTALL_DATA) $$i $(destdir)/bitmaps/hand ; \ done for i in $(srcdir)/bitmaps/fish/*.xbm ; do \ $(INSTALL_DATA) $$i $(destdir)/bitmaps/fish ; \ done inst-images: for i in $(srcdir)/images/*.gif $(srcdir)/images/*.ps ; do \ $(INSTALL_DATA) $$i $(destdir)/images ; \ done inst-dirs: @for i in $(instdirs) ; do \ if test -d "$$i" ; then : ; else mkdir "$$i" ; fi ; \ done clean: $(RM) $(srcdir)/*.bak $(srcdir)/*\~ $(srcdir)/"#"* distclean: clean $(RM) *.ps Makefile blt-2.4z.orig/demos/barchart1.tcl0100755000175000017500000001055307464424604015447 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl set graph .bc proc random {{max 1.0} {min 0.0}} { global randomSeed set randomSeed [expr (7141*$randomSeed+54773) % 259200] set num [expr $randomSeed/259200.0*($max-$min)+$min] return $num } set randomSeed 148230 proc FormatLabel { w value } { # Determine the element name from the value set names [$w element show] set index [expr round($value)] if { $index != $value } { return $value } global elemLabels if { [info exists elemLabels($index)] } { return $elemLabels($index) } return $value } source scripts/stipples.tcl image create photo bgTexture -file ./images/rain.gif option add *tile bgTexture option add *Button.tile "" option add *Htext.tileOffset no option add *Htext.font { Times 12 } option add *Barchart.title "A Simple Barchart" option add *Axis.tickFont { Courier 10 } option add *Axis.titleFont { Helvetica 12 bold } option add *x.Title "X Axis Label" option add *x.Rotate 90 option add *x.Command FormatLabel option add *y.Title "Y Axis Label" option add *Element.Background white option add *Element.Relief solid option add *Element.BorderWidth 1 option add *Legend.hide yes option add *Grid.hide no option add *Grid.dashes { 2 4 } option add *Grid.mapX "" set visual [winfo screenvisual .] if { $visual != "staticgray" && $visual != "grayscale" } { option add *print.background yellow option add *quit.background red option add *graph.background palegreen } htext .header -text { The barchart has several components: coordinate axes, data elements, legend, crosshairs, grid, postscript, and markers. They each control various aspects of the barchart. For example, the postscript component lets you generate PostScript output. Pressing the %% set w $htext(widget) button $w.print -text {Print} -command { .bc postscript output bar.ps } $w append $w.print %% button will create a file "bar.ps" } htext .footer -text { Hit the %% set w $htext(widget) button $w.quit -text quit -command exit $w append $w.quit %% button when you've seen enough.%% label $w.logo -bitmap BLT $w append $w.logo -padx 20 %% } barchart .bc # # Element attributes: # # Label Foreground Background Stipple Pattern source scripts/stipples.tcl set bitmaps { bdiagonal1 bdiagonal2 checker2 checker3 cross1 cross2 cross3 crossdiag dot1 dot2 dot3 dot4 fdiagonal1 fdiagonal2 hline1 hline2 lbottom ltop rbottom rtop vline1 vline2 } set count 1 foreach stipple $bitmaps { set label [file tail $stipple] set label [file root $label] set y [random -2 10] set yhigh [expr $y + 0.5] set ylow [expr $y - 0.5] .bc element create $label -y $y -x $count \ -fg brown -bg orange -stipple $stipple -yhigh $yhigh -ylow $ylow set elemLabels($count) $label incr count } table . \ 0,0 .header -fill x \ 1,0 .bc -fill both \ 2,0 .footer -fill x table configure . r0 r2 -resize none Blt_ZoomStack .bc Blt_Crosshairs .bc Blt_ActiveLegend .bc Blt_ClosestPoint .bc if 0 { set printer [printer open [lindex [printer names] 0]] printer getattr $printer attrs set attrs(Orientation) Portrait printer setattr $printer attrs after 2000 { $graph print2 $printer printer close $printer } } .bc axis bind x { set axis [%W axis get current] %W axis configure $axis -color blue3 -titlecolor blue3 } .bc axis bind x { set axis [%W axis get current] %W axis configure $axis -color black -titlecolor black } blt-2.4z.orig/demos/barchart2.tcl0100755000175000017500000001514607521160503015440 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl proc FormatXTicks { w value } { # Determine the element name from the value set index [expr round($value)] if { $index != $value } { return $value } incr index -1 set name [lindex { A1 B1 A2 B2 C1 D1 C2 A3 E1 } $index] return $name } source scripts/stipples.tcl #image create photo bgTexture -file ./images/chalk.gif image create photo bgTexture -file ./images/rain.gif option add *Button.padX 5 option add *tile bgTexture option add *Radiobutton.font -*-courier*-medium-r-*-*-14-*-* option add *Radiobutton.relief flat option add *Radiobutton.borderWidth 2 option add *Radiobutton.highlightThickness 0 option add *Htext.font -*-times*-bold-r-*-*-14-*-* option add *Htext.tileOffset no option add *header.font -*-times*-medium-r-*-*-14-*-* option add *Barchart.font -*-helvetica-bold-r-*-*-14-*-* option add *Barchart.title "Comparison of Simulators" option add *Axis.tickFont -*-helvetica-medium-r-*-*-12-*-* option add *Axis.titleFont -*-helvetica-bold-r-*-*-12-*-* option add *x.Command FormatXTicks option add *x.Title "Simulator" option add *y.Title "Time (hrs)" option add *activeBar.Foreground pink option add *activeBar.stipple dot3 option add *Element.Background red option add *Element.Relief solid option add *Grid.dashes { 2 4 } option add *Grid.hide no option add *Grid.mapX "" option add *Legend.Font "-*-helvetica*-bold-r-*-*-12-*-*" option add *Legend.activeBorderWidth 2 option add *Legend.activeRelief raised option add *Legend.anchor ne option add *Legend.borderWidth 0 option add *Legend.position right option add *TextMarker.Font *Helvetica-Bold-R*14* set visual [winfo screenvisual .] if { $visual != "staticgray" && $visual != "grayscale" } { option add *print.background yellow option add *quit.background red option add *quit.activeBackground red2 } htext .title -text { Data points with like x-coordinates, can have their bar segments displayed in one of the following modes (using the -barmode option): } htext .header -text { %% radiobutton .header.stacked -text stacked -variable barMode \ -anchor w -value "stacked" -selectcolor red -command { .graph configure -barmode $barMode } .header append .header.stacked -width 1.5i -anchor w %% Bars are stacked on top of each other. The overall height is the sum of the y-coordinates. %% radiobutton .header.aligned -text aligned -variable barMode \ -anchor w -value "aligned" -selectcolor yellow -command { .graph configure -barmode $barMode } .header append .header.aligned -width 1.5i -fill x %% Bars are drawn side-by-side at a fraction of their normal width. %% radiobutton .header.overlap -text "overlap" -variable barMode \ -anchor w -value "overlap" -selectcolor green -command { .graph configure -barmode $barMode } .header append .header.overlap -width 1.5i -fill x %% Bars overlap slightly. %% radiobutton .header.normal -text "normal" -variable barMode \ -anchor w -value "normal" -selectcolor blue -command { .graph configure -barmode $barMode } .header append .header.normal -width 1.5i -fill x %% Bars are overlayed one on top of the next. } htext .footer -text { Hit the %% set im [image create photo -file ./images/stopsign.gif] button $htext(widget).quit -image $im -command { exit } $htext(widget) append $htext(widget).quit -pady 2 %% button when you've seen enough. %% label $htext(widget).logo -bitmap BLT $htext(widget) append $htext(widget).logo %%} barchart .graph -tile bgTexture vector X Y0 Y1 Y2 Y3 Y4 X set { 1 2 3 4 5 6 7 8 9 } Y0 set { 0.729111111 0.002250000 0.09108333 0.006416667 0.026509167 0.007027778 0.1628611 0.06405278 0.08786667 } Y1 set { 0.003120278 0.004638889 0.01113889 0.048888889 0.001814722 0.291388889 0.0503500 0.13876389 0.04513333 } Y2 set { 11.534444444 3.879722222 4.54444444 4.460277778 2.334055556 1.262194444 1.8009444 4.12194444 3.24527778 } Y3 set { 1.015750000 0.462888889 0.49394444 0.429166667 1.053694444 0.466111111 1.4152500 2.17538889 2.55294444 } Y4 set { 0.022018611 0.516333333 0.54772222 0.177638889 0.021703889 0.134305556 0.5189278 0.07957222 0.41155556 } # # Element attributes: # # Label yData Foreground Background Stipple Borderwidth set attributes { "Setup" Y1 lightyellow3 lightyellow1 fdiagonal1 1 "Read In" Y0 lightgoldenrod3 lightgoldenrod1 bdiagonal1 1 "Other" Y4 lightpink3 lightpink1 fdiagonal1 1 "Solve" Y3 cyan3 cyan1 bdiagonal1 1 "Load" Y2 lightblue3 "" fdiagonal1 1 } foreach {label yData fg bg stipple bd} $attributes { .graph element create $yData -label $label -bd $bd \ -y $yData -x X -fg "" -bg $bg -stipple $stipple } .header.stacked invoke table . \ 0,0 .title -fill x \ 1,0 .header -fill x \ 2,0 .graph -fill both \ 3,0 .footer -fill x table configure . r0 r1 r3 -resize none Blt_ZoomStack .graph Blt_Crosshairs .graph Blt_ActiveLegend .graph Blt_ClosestPoint .graph .graph marker bind all { set coords [%W invtransform %x %y] catch { %W marker configure [%W marker get current] -coords $coords } } .graph marker bind all { set marker [%W marker get current] catch { %W marker configure $marker -bg green} } .graph marker bind all { set marker [%W marker get current] catch { %W marker configure $marker -bg ""} } .graph element bind all { .graph element closest %x %y info puts stderr "$info(x) $info(y)" } blt-2.4z.orig/demos/barchart3.tcl0100755000175000017500000001076607454755156015467 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl source scripts/stipples.tcl source scripts/patterns.tcl option add *graph.xTitle "X Axis Label" option add *graph.yTitle "Y Axis Label" option add *graph.title "A Simple Barchart" option add *graph.xFont *Times-Medium-R*12* option add *graph.elemBackground white option add *graph.elemRelief raised set visual [winfo screenvisual .] if { $visual != "staticgray" && $visual != "grayscale" } { option add *print.background yellow option add *quit.background red } htext .header -text { This is an example of the barchart widget. To create a postscript file "bar.ps", press the %% button $htext(widget).print -text {Print} -command { $graph postscript output bar.ps -maxpect 1 } $htext(widget) append $htext(widget).print %% button.} set graph [barchart .b] $graph configure \ -invert true \ -baseline 1.2 $graph xaxis configure \ -command FormatLabel \ -descending true $graph legend configure \ -hide yes htext .footer -text {Hit the %% button $htext(widget).quit -text quit -command exit $htext(widget) append $htext(widget).quit %% button when you've seen enough.%% label $htext(widget).logo -bitmap BLT $htext(widget) append $htext(widget).logo -padx 20 %%} set names { One Two Three Four Five Six Seven Eight } if { $visual == "staticgray" || $visual == "grayscale" } { set fgcolors { white white white white white white white white } set bgcolors { black black black black black black black black } } else { set fgcolors { red green blue purple orange brown cyan navy } set bgcolors { green blue purple orange brown cyan navy red } } set bitmaps { bdiagonal1 bdiagonal2 checker2 checker3 cross1 cross2 cross3 crossdiag dot1 dot2 dot3 dot4 fdiagonal1 fdiagonal2 hline1 hline2 lbottom ltop rbottom rtop vline1 vline2 } set numColors [llength $names] for { set i 0} { $i < $numColors } { incr i } { $graph element create [lindex $names $i] \ -data { $i+1 $i+1 } \ -fg [lindex $fgcolors $i] \ -bg [lindex $bgcolors $i] \ -stipple [lindex $bitmaps $i] \ -relief raised \ -bd 2 } $graph element create Nine \ -data { 9 -1.0 } \ -fg red \ -relief sunken $graph element create Ten \ -data { 10 2 } \ -fg seagreen \ -stipple hobbes \ -background palegreen $graph element create Eleven \ -data { 11 3.3 } \ -fg blue # -coords { -Inf Inf } $graph marker create bitmap \ -coords { 11 3.3 } -anchor center \ -bitmap @bitmaps/sharky.xbm \ -name bitmap \ -fill "" $graph marker create polygon \ -coords { 5 0 7 2 10 10 10 2 } \ -name poly -linewidth 0 -fill "" table . \ .header 0,0 -padx .25i \ $graph 1,0 -fill both \ .footer 2,0 -padx .25i table configure . r0 r2 -resize none wm min . 0 0 proc FormatLabel { w value } { # Determine the element name from the value set displaylist [$w element show] set index [expr round($value)-1] set name [lindex $displaylist $index] if { $name == "" } { return $name } # Return the element label set info [$w element configure $name -label] return [lindex $info 4] } Blt_ZoomStack $graph Blt_Crosshairs $graph Blt_ActiveLegend $graph Blt_ClosestPoint $graph $graph marker bind all { set coords [%W invtransform %x %y] catch { %W marker configure [%W marker get current] -coords $coords } } $graph marker bind all { set marker [%W marker get current] catch { %W marker configure $marker -fill green -outline black} } $graph marker bind all { set marker [%W marker get current] catch { set default [lindex [%W marker configure $marker -fill] 3] %W marker configure $marker -fill "$default" } } blt-2.4z.orig/demos/barchart4.tcl0100755000175000017500000000660507240160070015437 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl proc random {{max 1.0} {min 0.0}} { global randomSeed set randomSeed [expr (7141*$randomSeed+54773) % 259200] set num [expr $randomSeed/259200.0*($max-$min)+$min] return $num } set randomSeed 14823 set graph .graph source scripts/stipples.tcl source scripts/patterns.tcl option add *Barchart.title "A Simple Barchart" option add *Barchart.relief raised option add *Barchart.borderWidth 2 option add *Barchart.plotBackground white option add *Barchart.baseline 57.299 option add *Element.borderWidth 2 option add *Element.Background white option add *Element.Relief raised option add *x.Title "X Axis" option add *x.Font *Times-Medium-R*10* option add *y.Title "Y Axis" option add *LineMarker.Foreground yellow set visual [winfo screenvisual .] if { $visual != "staticgray" && $visual != "grayscale" } { option add *print.background yellow option add *quit.background red option add *graph.background palegreen } htext .header -text \ { This is an example of the barchart widget. The barchart has many components; x and y axis, legend, crosshairs, elements, etc. To create a postscript file "bar.ps", press the %% set w $htext(widget) button $w.print -text {Print} -command { $graph postscript output bar.ps } $w append $w.print %% button. } barchart $graph $graph xaxis configure -rotate 90 -stepsize 0 htext .footer -text { Hit the %% set im [image create photo -file ./images/stopsign.gif] button $htext(widget).quit -image $im -command { exit } $htext(widget) append $htext(widget).quit -pady 2 %% button when you've seen enough. %% label $htext(widget).logo -bitmap BLT $htext(widget) append $htext(widget).logo %%} set attributes { red bdiagonal1 orange bdiagonal2 yellow fdiagonal1 green fdiagonal2 blue hline1 cyan hline2 magenta vline1 violetred vline2 purple crossdiag lightblue hobbes } set count 0 foreach { color stipple } $attributes { $graph pen create pen$count -fg ${color}1 -bg ${color}4 -stipple $stipple lappend styles [list pen$count $count $count] incr count } vector x y w x seq 0 1000 y expr random(x)*90.0 w expr round(y/10.0)%$count y expr y+10.0 $graph element create data -label {} \ -x x -y y -weight w -styles $styles table . \ 0,0 .header -fill x \ 1,0 .graph -fill both \ 2,0 .footer -fill x table configure . r0 r2 -resize none wm min . 0 0 Blt_ZoomStack $graph Blt_Crosshairs $graph Blt_ActiveLegend $graph Blt_ClosestPoint $graph blt-2.4z.orig/demos/barchart5.tcl0100755000175000017500000000573607433613270015455 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl source scripts/stipples.tcl option add *graph.x.Title "X Axis Label" option add *graph.y.Title "Y Axis Label" option add *graph.title "A Simple Barchart" option add *graph.x.Font { Times 10 } option add *graph.Element.Relief raised set visual [winfo screenvisual .] if { $visual != "staticgray" && $visual != "grayscale" } { option add *graph.LineMarker.color yellow option add *graph.Element.Background white option add *graph.Legend.activeForeground pink option add *print.background yellow option add *quit.background red option add *graph.background palegreen option add *graph.plotBackground lightblue } htext .htext -text \ { This is an example of the barchart widget. The barchart has many components; x and y axis, legend, crosshairs, elements, etc. To create a postscript file "bar.ps", press the %% set w $htext(widget) button $w.print -text {Print} -command { $graph postscript output bar.ps } $w append $w.print %% button. %% set graph [barchart .htext.graph] $graph configure \ -relief raised \ -bd 2 $graph xaxis configure \ -rotate 90 \ -stepsize 0 $w append $graph -fill both -padx 4 %% Hit the %% button $w.quit -text quit -command exit $w append $w.quit %% button when you've seen enough.%% label $w.logo -bitmap BLT $w append $w.logo -padx 20 %% } set names { One Two Three Four Five Six Seven Eight } if { $visual == "staticgray" || $visual == "grayscale" } { set fgcolors { white white white white white white white white } set bgcolors { black black black black black black black black } } else { set fgcolors { yellow orange red magenta purple blue cyan green } set bgcolors { yellow4 orange4 red4 magenta4 purple4 blue4 cyan4 green4 } } set numColors [llength $names] set tcl_precision 15 vector create x vector create y x seq -5.0 5.0 0.2 y expr sin(x) set barWidth 0.19 $graph element create sin -relief raised -bd 1 -x x -y y -barwidth $barWidth table . .htext -fill both wm min . 0 0 Blt_ZoomStack $graph Blt_Crosshairs $graph Blt_ActiveLegend $graph Blt_ClosestPoint $graph blt-2.4z.orig/demos/bgexec1.tcl0100755000175000017500000001537507240160070015107 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl bitmap define blt.0 {{40 40} { 00 00 00 00 00 00 fc 07 00 00 00 04 08 00 00 00 04 04 00 00 00 e4 03 00 00 00 64 fe 07 00 00 64 02 04 00 00 e4 03 04 00 00 64 7e 02 00 00 64 1a 02 00 00 e4 1b 01 00 00 04 1a 01 00 00 04 1a 01 00 00 fc 1b 02 00 00 0c 1a 02 00 00 0c 02 04 00 00 0c 02 f4 03 80 ed fe 07 04 e0 0c 00 20 09 10 0c 00 00 12 10 0c 00 00 10 30 00 00 00 19 d0 03 00 00 14 b0 fe ff ff 1b 50 55 55 55 0d e8 aa aa aa 16 e4 ff ff ff 2f f4 ff ff ff 27 d8 ae aa bd 2d 6c 5f d5 67 1b bc f3 7f d0 36 f8 01 10 cc 1f e0 45 8e 92 0f b0 32 41 43 0b d0 cf 3c 7c 0d b0 aa c2 ab 0a 60 55 55 55 05 c0 ff ab aa 03 00 00 fe ff 00 00 00 00 00 00} } bitmap define blt.1 {{40 40} { 00 00 00 00 00 00 fc 07 00 00 00 04 08 00 00 00 04 04 00 00 00 e4 ff 0f 00 00 64 06 08 00 00 64 06 08 00 00 e4 ff 04 00 00 64 36 04 00 00 64 36 02 00 00 e4 37 02 00 00 04 34 02 00 00 04 34 04 00 00 fc 35 04 00 00 0c 04 08 00 00 0c 04 08 00 00 0c fc ef 03 80 ed 01 00 04 e0 0c 00 20 09 10 0c 00 00 12 10 0c 00 00 10 30 00 00 00 19 d0 03 00 00 14 b0 fe ff ff 1b 50 55 55 55 0d e8 aa aa aa 16 e4 ff ff ff 2f f4 ff ff ff 27 d8 ae aa bd 2d 6c 5f d5 67 1b bc f3 7f d0 36 f8 01 10 cc 1f e0 45 8e 92 0f b0 32 41 43 0b d0 cf 3c 7c 0d b0 aa c2 ab 0a 60 55 55 55 05 c0 ff ab aa 03 00 00 fe ff 00 00 00 00 00 00} } bitmap define blt.2 {{40 40} { 00 00 00 00 00 00 fc 0f 00 00 00 04 10 00 00 00 04 10 00 00 00 e4 fb 3f 00 00 64 0e 20 00 00 64 0e 20 00 00 e4 fb 13 00 00 64 ce 10 00 00 64 ce 08 00 00 e4 cb 08 00 00 04 c8 08 00 00 04 c8 10 00 00 fc cf 10 00 00 0c 08 20 00 00 0c 08 20 00 00 0c f8 bf 03 80 ed 03 00 04 e0 0c 00 20 09 10 0c 00 00 12 10 0c 00 00 10 30 00 00 00 19 d0 03 00 00 14 b0 fe ff ff 1b 50 55 55 55 0d e8 aa aa aa 16 e4 ff ff ff 2f f4 ff ff ff 27 d8 ae aa bd 2d 6c 5f d5 67 1b bc f3 7f d0 36 f8 01 10 cc 1f e0 45 8e 92 0f b0 32 41 43 0b d0 cf 3c 7c 0d b0 aa c2 ab 0a 60 55 55 55 05 c0 ff ab aa 03 00 00 fe ff 00 00 00 00 00 00} } bitmap define blt.3 {{40 40} { 00 00 00 00 00 00 fc 0f 00 00 00 04 f0 ff 00 00 04 00 80 00 00 e4 03 80 00 00 64 d6 4f 00 00 64 16 43 00 00 e4 13 23 00 00 64 16 23 00 00 64 16 23 00 00 e4 13 43 00 00 04 70 43 00 00 04 00 80 00 00 fc 0f 80 00 00 0c f0 ff 00 00 0c 00 00 00 00 0c f8 ff 03 80 ed 07 00 04 e0 0c 00 20 09 10 0c 00 00 12 10 0c 00 00 10 30 00 00 00 19 d0 03 00 00 14 b0 fe ff ff 1b 50 55 55 55 0d e8 aa aa aa 16 e4 ff ff ff 2f f4 ff ff ff 27 d8 ae aa bd 2d 6c 5f d5 67 1b bc f3 7f d0 36 f8 01 10 cc 1f e0 45 8e 92 0f b0 32 41 43 0b d0 cf 3c 7c 0d b0 aa c2 ab 0a 60 55 55 55 05 c0 ff ab aa 03 00 00 fe ff 00 00 00 00 00 00} } bitmap define blt.4 {{40 40} { 00 00 00 00 00 00 fc ff ff 03 00 04 00 00 02 00 04 00 00 02 00 e4 33 3f 01 00 64 36 0c 01 00 64 36 8c 00 00 e4 33 8c 00 00 64 36 8c 00 00 64 36 0c 01 00 e4 f3 0d 01 00 04 00 00 02 00 04 00 00 02 00 fc ff ff 03 00 0c 00 00 00 00 0c 00 00 00 00 0c f8 ff 03 80 ed 07 00 04 e0 0c 00 20 09 10 0c 00 00 12 10 0c 00 00 10 30 00 00 00 19 d0 03 00 00 14 b0 fe ff ff 1b 50 55 55 55 0d e8 aa aa aa 16 e4 ff ff ff 2f f4 ff ff ff 27 d8 ae aa bd 2d 6c 5f d5 67 1b bc f3 7f d0 36 f8 01 10 cc 1f e0 45 8e 92 0f b0 32 41 43 0b d0 cf 3c 7c 0d b0 aa c2 ab 0a 60 55 55 55 05 c0 ff ab aa 03 00 00 fe ff 00 00 00 00 00 00} } #set animate(colors) { #ff8813 #ffaa13 #ffcc13 #ffff13 #ffcc13 #ffaa13 #ff8813 } bitmap define blt.5 [bitmap data blt.3] bitmap define blt.6 [bitmap data blt.2] bitmap define blt.7 [bitmap data blt.1] set interval 200 proc AnimateBitmap { index } { global interval afterId if { ![winfo exists .logo] } { return } if { $index >= 0 } { .logo configure -bitmap blt.$index incr index if { $index >= 7 } { set index 0 } set afterId [after $interval "AnimateBitmap $index"] } } set length 80 option add *text.yScrollCommand { .vscroll set } option add *text.relief sunken option add *text.width $length option add *text.height 10 option add *text.borderWidth 2 option add *vscroll.command { .text yview } option add *vscroll.minSlider 4p option add *quit.command { exit } option add *quit.text { quit } option add *stop.command { set bgStatus {} } option add *stop.text { stop } option add *logo.relief sunken option add *logo.padX 4 option add *title.text "Virtual Memory Statistics" option add *title.font -*-Helvetica-Bold-R-*-*-14-*-*-*-*-*-*-* set visual [winfo screenvisual .] if { $visual != "staticgray" && $visual != "grayscale" } { option add *text.background lightblue option add *text.foreground blue option add *quit.background red option add *quit.foreground white option add *stop.background yellow option add *stop.foreground navyblue option add *logo.background beige option add *logo.foreground brown } # Create widgets text .text scrollbar .vscroll button .quit button .stop label .logo label .title # Layout widgets in table table . \ .title 0,0 -columnspan 4 \ .text 1,0 -columnspan 3 \ .vscroll 1,3 -fill y \ .logo 2,0 -anchor w -padx 10 -reqheight .6i -pady 4 \ .stop 2,1 \ .quit 2,2 set buttonWidth 1i table configure . c1 c2 -width 1i table configure . c3 -resize none table configure . .stop .quit -reqwidth $buttonWidth -anchor e table configure . .title .text -fill both wm min . 0 0 proc DisplayStats { data } { .text insert end "$data\n" set textlen [expr int([.text index end])] scan [.vscroll get] "%s %s %s %s" total window first last if { $textlen > $total } { .text yview [expr $textlen-$window] } update idletasks } set bgStatus {} AnimateBitmap 0 # # Pick a command that # 1) periodically writes output and # 2) flushes output each time. # set command { vmstat 1 } #set command { netstat -c } catch { eval "bgexec bgStatus -onoutput DisplayStats $command" } # Turn off animation by canceling any pending after task. if { [info exists afterId] } { after cancel $afterId } blt-2.4z.orig/demos/bgexec2.tcl0100755000175000017500000000240007515754666015122 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl proc ShowResult { name1 name2 how } { global var .l$name2 configure -text "$var($name2)" after 2000 "table forget .l$name2" } for { set i 1 } { $i <= 20 } { incr i } { label .l$i table . .l$i $i,0 set pid [bgexec var($i) du /usr/include &] .l$i configure -text "Starting #$i pid=$pid" trace variable var($i) w ShowResult update after 500 } blt-2.4z.orig/demos/bgexec3.tcl0100755000175000017500000001725207403612562015116 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl bitmap define blt.0 {{40 40} { 00 00 00 00 00 00 fc 07 00 00 00 04 08 00 00 00 04 04 00 00 00 e4 03 00 00 00 64 fe 07 00 00 64 02 04 00 00 e4 03 04 00 00 64 7e 02 00 00 64 1a 02 00 00 e4 1b 01 00 00 04 1a 01 00 00 04 1a 01 00 00 fc 1b 02 00 00 0c 1a 02 00 00 0c 02 04 00 00 0c 02 f4 03 80 ed fe 07 04 e0 0c 00 20 09 10 0c 00 00 12 10 0c 00 00 10 30 00 00 00 19 d0 03 00 00 14 b0 fe ff ff 1b 50 55 55 55 0d e8 aa aa aa 16 e4 ff ff ff 2f f4 ff ff ff 27 d8 ae aa bd 2d 6c 5f d5 67 1b bc f3 7f d0 36 f8 01 10 cc 1f e0 45 8e 92 0f b0 32 41 43 0b d0 cf 3c 7c 0d b0 aa c2 ab 0a 60 55 55 55 05 c0 ff ab aa 03 00 00 fe ff 00 00 00 00 00 00} } bitmap define blt.1 {{40 40} { 00 00 00 00 00 00 fc 07 00 00 00 04 08 00 00 00 04 04 00 00 00 e4 ff 0f 00 00 64 06 08 00 00 64 06 08 00 00 e4 ff 04 00 00 64 36 04 00 00 64 36 02 00 00 e4 37 02 00 00 04 34 02 00 00 04 34 04 00 00 fc 35 04 00 00 0c 04 08 00 00 0c 04 08 00 00 0c fc ef 03 80 ed 01 00 04 e0 0c 00 20 09 10 0c 00 00 12 10 0c 00 00 10 30 00 00 00 19 d0 03 00 00 14 b0 fe ff ff 1b 50 55 55 55 0d e8 aa aa aa 16 e4 ff ff ff 2f f4 ff ff ff 27 d8 ae aa bd 2d 6c 5f d5 67 1b bc f3 7f d0 36 f8 01 10 cc 1f e0 45 8e 92 0f b0 32 41 43 0b d0 cf 3c 7c 0d b0 aa c2 ab 0a 60 55 55 55 05 c0 ff ab aa 03 00 00 fe ff 00 00 00 00 00 00} } bitmap define blt.2 {{40 40} { 00 00 00 00 00 00 fc 0f 00 00 00 04 10 00 00 00 04 10 00 00 00 e4 fb 3f 00 00 64 0e 20 00 00 64 0e 20 00 00 e4 fb 13 00 00 64 ce 10 00 00 64 ce 08 00 00 e4 cb 08 00 00 04 c8 08 00 00 04 c8 10 00 00 fc cf 10 00 00 0c 08 20 00 00 0c 08 20 00 00 0c f8 bf 03 80 ed 03 00 04 e0 0c 00 20 09 10 0c 00 00 12 10 0c 00 00 10 30 00 00 00 19 d0 03 00 00 14 b0 fe ff ff 1b 50 55 55 55 0d e8 aa aa aa 16 e4 ff ff ff 2f f4 ff ff ff 27 d8 ae aa bd 2d 6c 5f d5 67 1b bc f3 7f d0 36 f8 01 10 cc 1f e0 45 8e 92 0f b0 32 41 43 0b d0 cf 3c 7c 0d b0 aa c2 ab 0a 60 55 55 55 05 c0 ff ab aa 03 00 00 fe ff 00 00 00 00 00 00} } bitmap define blt.3 {{40 40} { 00 00 00 00 00 00 fc 0f 00 00 00 04 f0 ff 00 00 04 00 80 00 00 e4 03 80 00 00 64 d6 4f 00 00 64 16 43 00 00 e4 13 23 00 00 64 16 23 00 00 64 16 23 00 00 e4 13 43 00 00 04 70 43 00 00 04 00 80 00 00 fc 0f 80 00 00 0c f0 ff 00 00 0c 00 00 00 00 0c f8 ff 03 80 ed 07 00 04 e0 0c 00 20 09 10 0c 00 00 12 10 0c 00 00 10 30 00 00 00 19 d0 03 00 00 14 b0 fe ff ff 1b 50 55 55 55 0d e8 aa aa aa 16 e4 ff ff ff 2f f4 ff ff ff 27 d8 ae aa bd 2d 6c 5f d5 67 1b bc f3 7f d0 36 f8 01 10 cc 1f e0 45 8e 92 0f b0 32 41 43 0b d0 cf 3c 7c 0d b0 aa c2 ab 0a 60 55 55 55 05 c0 ff ab aa 03 00 00 fe ff 00 00 00 00 00 00} } bitmap define blt.4 {{40 40} { 00 00 00 00 00 00 fc ff ff 03 00 04 00 00 02 00 04 00 00 02 00 e4 33 3f 01 00 64 36 0c 01 00 64 36 8c 00 00 e4 33 8c 00 00 64 36 8c 00 00 64 36 0c 01 00 e4 f3 0d 01 00 04 00 00 02 00 04 00 00 02 00 fc ff ff 03 00 0c 00 00 00 00 0c 00 00 00 00 0c f8 ff 03 80 ed 07 00 04 e0 0c 00 20 09 10 0c 00 00 12 10 0c 00 00 10 30 00 00 00 19 d0 03 00 00 14 b0 fe ff ff 1b 50 55 55 55 0d e8 aa aa aa 16 e4 ff ff ff 2f f4 ff ff ff 27 d8 ae aa bd 2d 6c 5f d5 67 1b bc f3 7f d0 36 f8 01 10 cc 1f e0 45 8e 92 0f b0 32 41 43 0b d0 cf 3c 7c 0d b0 aa c2 ab 0a 60 55 55 55 05 c0 ff ab aa 03 00 00 fe ff 00 00 00 00 00 00} } set program ../src/bltwish if { [info exists tcl_platform ] } { puts stderr $tcl_platform(platform) if { $tcl_platform(platform) == "windows" } { set shells [glob C:/Program\ Files/Tcl/bin/tclsh8*.exe ] set program [lindex $shells 0] } } if { ![file executable $program] } { error "Can't execute $program" } set command [list $program scripts/bgtest.tcl] set animate(index) -1 set animate(interval) 200 #set animate(colors) { #ff8813 #ffaa13 #ffcc13 #ffff13 #ffcc13 #ffaa13 #ff8813 } bitmap define blt.5 [bitmap data blt.3] bitmap define blt.6 [bitmap data blt.2] bitmap define blt.7 [bitmap data blt.1] proc Animate {} { global animate if { [info commands .logo] != ".logo" } { set animate(index) 0 return } if { $animate(index) >= 0 } { .logo configure -bitmap blt.$animate(index) incr animate(index) if { $animate(index) >= 7 } { set animate(index) 0 } after $animate(interval) Animate } } proc InsertText { string tag } { .text insert end "$tag: " "" $string $tag set textlen [expr int([.text index end])] scan [.vscroll get] "%s %s %s %s" total window first last if { $textlen > $total } { .text yview [expr $textlen-$window] } update idletasks update } proc DisplayOutput { data } { InsertText "$data\n" stdout } proc DisplayErrors { data } { InsertText "$data\n" stderr } set length 80 option add *text.yScrollCommand { .vscroll set } option add *text.relief sunken option add *text.width 20 option add *text.height 10 option add *text.height 10 option add *text.borderWidth 2 option add *vscroll.command { .text yview } option add *vscroll.minSlider 4p option add *stop.command { set results {} } option add *stop.text { stop } option add *logo.relief sunken option add *logo.padX 4 option add *title.text "Catching stdout and stderr" option add *title.font -*-Helvetica-Bold-R-*-*-14-*-*-*-*-*-*-* set visual [winfo screenvisual .] if { [string match *color $visual] } { option add *text.background white option add *text.foreground blue option add *stop.background yellow option add *stop.activeBackground yellow2 option add *stop.foreground navyblue option add *start.activeBackground green2 option add *start.background green option add *start.foreground navyblue option add *logo.background beige option add *logo.foreground brown } proc Start { command } { global results animate .text delete 1.0 end if { $animate(index) < 0 } { set results {} set animate(index) 0 eval "bgexec results -error barney -output fred -killsignal SIGINT \ -onoutput DisplayOutput -onerror DisplayErrors -linebuffered no \ $command &" Animate } } proc Stop { } { global results animate set results {} set animate(index) -1 } # Create widgets text .text .text tag configure stdout -font { Courier-Bold 14 } -foreground green2 .text tag configure stderr -font { Courier 14 } -foreground red2 scrollbar .vscroll button .start -text "Start" -command [list Start $command] button .stop -text "Stop" -command Stop label .logo -bitmap blt.0 label .title # Layout widgets in table table . \ .title 0,0 -columnspan 4 \ .text 1,0 -columnspan 3 \ .vscroll 1,3 -fill y \ .logo 2,0 -anchor w -padx 10 -reqheight .6i -pady 4 \ .start 2,1 \ .stop 2,2 set buttonWidth 1i table configure . c1 c2 -width 1i table configure . c3 r0 r2 -resize none table configure . .start .stop -reqwidth $buttonWidth -anchor e table configure . .title .text -fill both wm min . 0 0 blt-2.4z.orig/demos/bgexec4.tcl0100755000175000017500000001134607240160070015104 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl source scripts/globe.tcl option add *HighlightThickness 0 set program ../src/bltwish if { [info exists tcl_platform ] } { puts stderr $tcl_platform(platform) if { $tcl_platform(platform) == "windows" } { set shells [glob C:/Program\ Files/Tcl/bin/tclsh8*.exe ] set program [lindex $shells 0] } } if { ![file executable $program] } { error "Can't execute $program" } set command [list $program scripts/bgtest.tcl] array set animate { index -1 interval 200 colors "#ff8813 #ffaa13 #ffcc13 #ffff13 #ffcc13 #ffaa13 #ff8813" numBitmaps 30 prefix globe } proc Animate {} { global animate if { [info commands .logo] != ".logo" } { set animate(index) 0 return } if { $animate(index) >= 0 } { .logo configure -bitmap $animate(prefix).$animate(index) incr animate(index) if { $animate(index) >= $animate(numBitmaps) } { set animate(index) 0 } after $animate(interval) Animate } } proc InsertText { string tag } { .text insert end "$tag: " "" $string $tag set textlen [expr int([.text index end])] scan [.vscroll get] "%s %s %s %s" total window first last if { $textlen > $total } { .text yview [expr $textlen-$window] } update idletasks } proc DisplayOutput { name1 name2 how } { upvar #0 $name1 arr InsertText "$arr($name2)\n" stdout set arr($name2) {} } proc DisplayErrors { name1 name2 how } { upvar #0 $name1 arr InsertText "$arr($name2)\n" stderr set arr($name2) {} } option add *text.yScrollCommand { .vscroll set } option add *text.relief sunken option add *text.width 20 option add *text.height 10 option add *text.height 10 option add *text.borderWidth 2 option add *vscroll.command { .text yview } option add *vscroll.minSlider 4p option add *stop.command { set results {} } option add *stop.text { stop } option add *logo.padX 4 option add *title.text "Catching stdout and stderr" option add *title.font -*-Helvetica-Bold-R-*-*-14-*-*-*-*-*-*-* set visual [winfo screenvisual .] if { [string match *color $visual] } { option add *text.background white option add *text.foreground blue option add *stop.background yellow option add *stop.activeBackground yellow2 option add *stop.foreground navyblue option add *start.activeBackground green2 option add *start.background green option add *start.foreground navyblue option add *logo.background beige option add *logo.foreground brown option add *logo.foreground green4 option add *title.background lightblue option add *logo.background lightblue } . configure -bg lightblue trace variable results(stdout) w DisplayOutput trace variable results(stderr) w DisplayErrors proc Start { command } { global results animate .text delete 1.0 end if { $animate(index) < 0 } { set results(status) {} eval "bgexec results(status) -lasterror results(stderr) \ -lastoutput results(stdout) $command &" set animate(index) 0 Animate } } proc Stop { } { global results animate set results(status) {} set animate(index) -1 } # Create widgets text .text .text tag configure stdout -font -*-Helvetica-Bold-R-*-*-18-*-*-*-*-*-*-* \ -foreground green2 .text tag configure stderr -font -*-Helvetica-Medium-O-*-*-18-*-*-*-*-*-*-* \ -foreground red2 scrollbar .vscroll button .start -text "Start" -command [list Start $command] button .stop -text "Stop" -command Stop label .logo -bitmap globe.0 label .title # Layout widgets in table table . \ .title 0,0 -columnspan 4 \ .text 1,0 -columnspan 3 \ .vscroll 1,3 -fill y \ .logo 2,0 -anchor w -padx 10 -reqheight .6i -pady 4 \ .start 2,1 \ .stop 2,2 set buttonWidth 1i table configure . c1 c2 -width 1i table configure . c3 r0 r2 -resize none table configure . .start .stop -reqwidth $buttonWidth -anchor e table configure . .title .text -fill both wm min . 0 0 blt-2.4z.orig/demos/bgexec5.tcl0100755000175000017500000000234607240160070015105 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl set shell bltwish if { [info exists tcl_platform] && $tcl_platform(platform) == "windows" } { set shell "$shell.exe" } if { [file executable "../src/$shell"] } { set shell "../src/$shell" } set count 0 foreach demo [glob barchart?.tcl] { bgexec var $shell $demo & } button .kill -text "Kill All" -command { set var 0 } table . .kill -fill both blt-2.4z.orig/demos/bitmap.tcl0100755000175000017500000002544207525316724015060 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl source scripts/stipples.tcl source scripts/patterns.tcl bitmap define wide_weave { #define wide_weave_width 16 #define wide_weave_height 16 static char wide_weave_bits[] = { 0x11, 0x11, 0xb8, 0xb8, 0x7c, 0x7c, 0x3a, 0x3a, 0x11, 0x11, 0xa3, 0xa3, 0xc7, 0xc7, 0x8b, 0x8b, 0x11, 0x11, 0xb8, 0xb8, 0x7c, 0x7c, 0x3a, 0x3a, 0x11, 0x11, 0xa3, 0xa3, 0xc7, 0xc7, 0x8b, 0x8b}; } bitmap define hobbes3 { #define hobbes_width 25 #define hobbes_height 25 static char hobbes_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x78, 0xe0, 0x07, 0x00, 0xfc, 0xf8, 0x07, 0x00, 0xcc, 0x07, 0x04, 0x00, 0x0c, 0xf0, 0x0b, 0x00, 0x7c, 0x1c, 0x06, 0x00, 0x38, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x10, 0x00, 0xe0, 0x41, 0x11, 0x00, 0x20, 0x40, 0x11, 0x00, 0xe0, 0x07, 0x10, 0x00, 0xe0, 0xc1, 0x17, 0x00, 0x10, 0xe0, 0x2f, 0x00, 0x20, 0xe0, 0x6f, 0x00, 0x18, 0xe0, 0x2f, 0x00, 0x20, 0xc6, 0x67, 0x00, 0x18, 0x84, 0x2b, 0x00, 0x20, 0x08, 0x64, 0x00, 0x70, 0xf0, 0x13, 0x00, 0x80, 0x01, 0x08, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; } -scale 3.0 bitmap define gort { #define gort_width 64 #define gort_height 64 static char gort_bits[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xff, 0xff, 0x07, 0x00, 0x80, 0x01, 0x00, 0xc0, 0xdf, 0x0f, 0x1e, 0x00, 0x80, 0x01, 0x00, 0x60, 0xdf, 0x7f, 0x38, 0x00, 0x80, 0x01, 0x00, 0x30, 0x84, 0xfd, 0x67, 0x00, 0x80, 0x01, 0x00, 0x18, 0x04, 0xf6, 0xef, 0x00, 0x80, 0x01, 0x00, 0x0c, 0x86, 0xe1, 0xc7, 0x01, 0x80, 0x01, 0x00, 0x06, 0x06, 0xc0, 0x96, 0x01, 0x80, 0x01, 0x00, 0x06, 0x06, 0x00, 0x97, 0x03, 0x80, 0x01, 0x00, 0x06, 0x06, 0x00, 0x3c, 0x03, 0x80, 0x01, 0x00, 0x03, 0x06, 0x00, 0x5c, 0x07, 0x80, 0x01, 0x00, 0x03, 0x02, 0x00, 0xd8, 0x06, 0x80, 0x01, 0x00, 0x03, 0x02, 0x00, 0xd8, 0x06, 0x80, 0x01, 0x00, 0x43, 0x02, 0x00, 0xb0, 0x0c, 0x80, 0x01, 0x80, 0x31, 0x03, 0x00, 0xe0, 0x0d, 0x80, 0x01, 0x80, 0x61, 0x03, 0x00, 0xe0, 0x0d, 0x80, 0x01, 0x80, 0x1b, 0x03, 0x00, 0xf0, 0x0c, 0x80, 0x01, 0x80, 0xb3, 0x03, 0xff, 0xff, 0x1d, 0x80, 0x01, 0xc0, 0xeb, 0xfb, 0xff, 0xff, 0x1d, 0x80, 0x01, 0xe0, 0xc5, 0x7f, 0xfe, 0x7f, 0x3f, 0x01, 0xe0, 0xeb, 0xe3, 0xff, 0xff, 0x6e, 0x80, 0x01, 0xd0, 0x3b, 0xfe, 0x01, 0x80, 0x40, 0xcf, 0x80, 0x01, 0xf0, 0xf7, 0x07, 0x00, 0x30, 0x8e, 0x80, 0x01, 0xf0, 0xf4, 0x00, 0x00, 0x1b, 0x98, 0x80, 0x01, 0x70, 0x14, 0x00, 0x00, 0x1f, 0xdc, 0x80, 0x01, 0x30, 0xfe, 0xff, 0x1f, 0xc8, 0xff, 0x80, 0x01, 0x20, 0xee, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0x20, 0xf7, 0xff, 0x7f, 0xfe, 0x7f, 0x80, 0x01, 0xc0, 0xe1, 0xff, 0xff, 0xfe, 0x3f, 0x80, 0x01, 0x80, 0xed, 0xff, 0xff, 0xff, 0x19, 0x80, 0x01, 0x80, 0x99, 0xff, 0xff, 0xff, 0x18, 0x80, 0x01, 0x00, 0x63, 0x83, 0xff, 0x7f, 0x08, 0x80, 0x01, 0x00, 0xc3, 0x06, 0x00, 0x00, 0x0c, 0x80, 0x01, 0x00, 0x9b, 0x07, 0x00, 0x00, 0x0c, 0x80, 0x01, 0x00, 0xb6, 0x07, 0x00, 0x10, 0x0c, 0x80, 0x01, 0x00, 0xc6, 0x07, 0x00, 0x10, 0x04, 0x80, 0x01, 0x00, 0x36, 0x06, 0x00, 0x18, 0x06, 0x80, 0x01, 0x00, 0x66, 0x06, 0x00, 0x18, 0x06, 0x80, 0x01, 0x00, 0x8c, 0x0d, 0x00, 0x18, 0x02, 0x80, 0x01, 0x00, 0x18, 0x0e, 0x00, 0x18, 0x03, 0x80, 0x01, 0x00, 0xf0, 0x0c, 0x00, 0x18, 0x03, 0x80, 0x01, 0x00, 0x30, 0x0f, 0x00, 0x98, 0x01, 0x80, 0x01, 0x00, 0xb0, 0x1f, 0x01, 0x98, 0x01, 0x80, 0x01, 0x00, 0x60, 0x1f, 0x03, 0xdc, 0x00, 0x80, 0x01, 0x00, 0xe0, 0x3f, 0x03, 0xdc, 0x00, 0x80, 0x01, 0x00, 0xe0, 0x3b, 0x07, 0xee, 0x00, 0x80, 0x01, 0x00, 0x70, 0xf8, 0xff, 0xff, 0x01, 0x80, 0x01, 0x00, 0xf0, 0x80, 0xff, 0x37, 0x03, 0x80, 0x01, 0x00, 0xfc, 0x00, 0x08, 0xd8, 0x03, 0x80, 0x01, 0x00, 0xfe, 0x03, 0xf8, 0x7f, 0x07, 0x80, 0x01, 0xc0, 0x87, 0x07, 0xe0, 0x3f, 0x1c, 0x80, 0x01, 0xf0, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x8f, 0x81, 0xff, 0x00, 0x38, 0x00, 0xf6, 0xf9, 0xff, 0xfd, 0x3f, 0x00, 0xe0, 0x00, 0x83, 0x8f, 0xff, 0xff, 0x00, 0x00, 0x80, 0x01, 0x00, 0xfc, 0xc0, 0x07, 0x0e, 0x00, 0x38, 0xe0, 0x00, 0xe0, 0x9f, 0xf9, 0x07, 0x00, 0x00, 0x80, 0x03, 0x00, 0xff, 0x7f, 0x80, 0x01, 0x00, 0xc0, 0x00, 0x00, 0xf0, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0xf0, 0x00, 0x38, 0x00, 0x00, 0x00, 0x80, 0x01, 0x30, 0x00, 0x00, 0x38, 0xc0, 0xc0, 0x80, 0x01, 0x1c, 0xe0, 0x00, 0x0c, 0xc0, 0x83, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; } -rotate 180 bitmap define xbob { #define bob_x_hot 30 #define bob_y_hot 37 #define bob_width 61 #define bob_height 75 static char bob_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xfb, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xcf, 0x9f, 0xd1, 0x03, 0x00, 0x00, 0xf0, 0x7f, 0x8c, 0x33, 0x91, 0x07, 0x00, 0x00, 0xf8, 0xa7, 0x18, 0x27, 0xb1, 0x06, 0x00, 0x00, 0xfc, 0x47, 0x31, 0x4e, 0xa6, 0x0e, 0x00, 0x00, 0xfe, 0x4f, 0x21, 0x4c, 0xae, 0x3d, 0x00, 0x00, 0xff, 0xdf, 0x23, 0x8d, 0xbe, 0x7d, 0x00, 0x80, 0xff, 0xff, 0x67, 0xbd, 0xfe, 0xff, 0x01, 0x80, 0xff, 0xff, 0x7f, 0xbf, 0xff, 0xff, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xf8, 0x07, 0xc0, 0xff, 0xff, 0xff, 0xbf, 0x3f, 0xf8, 0x07, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x07, 0xf8, 0x0f, 0xc0, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xf8, 0x0f, 0xe0, 0x7f, 0x00, 0xf8, 0x07, 0x00, 0xf0, 0x0f, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x07, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x07, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x07, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x07, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x07, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x07, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x07, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x07, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x07, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x07, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x78, 0xf6, 0x07, 0xa0, 0xbf, 0xff, 0x00, 0x00, 0xff, 0xf7, 0x07, 0x70, 0x9f, 0xff, 0x01, 0x80, 0xff, 0xef, 0x07, 0xf0, 0x1c, 0x80, 0x03, 0xe0, 0x01, 0xef, 0x07, 0xf0, 0x1f, 0xbe, 0x07, 0xf0, 0x3f, 0xee, 0x07, 0xe0, 0x9d, 0x83, 0x1f, 0xf8, 0xe1, 0xdc, 0x07, 0xe0, 0xc1, 0x7f, 0x1f, 0xfc, 0xff, 0xc8, 0x07, 0xe0, 0xc1, 0x69, 0x1e, 0x7e, 0xca, 0xc0, 0x03, 0xe0, 0x81, 0xb8, 0x1f, 0xc0, 0x0e, 0xc0, 0x03, 0xe0, 0x01, 0xc0, 0x1b, 0xc0, 0xcf, 0xc1, 0x03, 0xc0, 0x03, 0xf7, 0x11, 0x00, 0x7f, 0xc0, 0x03, 0xc0, 0x03, 0x7c, 0x18, 0x00, 0x1c, 0xc0, 0x02, 0xc0, 0x02, 0x30, 0x08, 0x00, 0x00, 0x40, 0x03, 0x40, 0x03, 0x00, 0x08, 0x00, 0x00, 0x40, 0x02, 0x40, 0x13, 0x00, 0x0c, 0x00, 0x00, 0x60, 0x02, 0x40, 0x12, 0x00, 0x0e, 0x00, 0x00, 0xc0, 0x03, 0x80, 0x33, 0x80, 0x0e, 0x00, 0x00, 0xa8, 0x01, 0x00, 0x33, 0x40, 0x0f, 0xa0, 0x03, 0x2c, 0x00, 0x00, 0x74, 0x30, 0x0f, 0x38, 0x07, 0x2e, 0x00, 0x00, 0x74, 0x98, 0x1f, 0x1e, 0x1e, 0x2f, 0x00, 0x00, 0xfc, 0x8f, 0xff, 0x0f, 0xfc, 0x2f, 0x00, 0x00, 0xf8, 0xe3, 0xff, 0x03, 0xf8, 0x2f, 0x00, 0x00, 0xf8, 0xfd, 0xff, 0x81, 0xff, 0x3f, 0x00, 0x00, 0xb8, 0xf9, 0x1f, 0xf8, 0x0f, 0x1e, 0x00, 0x00, 0x30, 0xf1, 0xf0, 0x0f, 0x03, 0x0e, 0x00, 0x00, 0x30, 0xf1, 0x01, 0x80, 0x01, 0x0f, 0x00, 0x00, 0x20, 0xf1, 0xf7, 0xff, 0x00, 0x07, 0x00, 0x00, 0x60, 0xe3, 0x01, 0x60, 0x80, 0x07, 0x00, 0x00, 0x60, 0xc3, 0xef, 0x3f, 0x80, 0x03, 0x00, 0x00, 0x40, 0xc2, 0xff, 0x0f, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0xe6, 0x1f, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0xf4, 0xfe, 0x3f, 0xe0, 0x00, 0x00, 0x00, 0x80, 0x79, 0xfe, 0x1f, 0xe0, 0x00, 0x00, 0xc0, 0x01, 0x3d, 0x3e, 0x00, 0x70, 0x00, 0x00, 0x30, 0x06, 0x3e, 0x0f, 0x00, 0x38, 0x00, 0x00, 0xc8, 0x8c, 0x1f, 0x07, 0x00, 0x38, 0x00, 0x00, 0xf4, 0xcc, 0x8f, 0x07, 0x00, 0x1c, 0x00, 0x00, 0x72, 0xee, 0xf7, 0x07, 0x00, 0x0e, 0x00, 0x00, 0x02, 0xff, 0xe3, 0x07, 0x00, 0x07, 0x00, 0x00, 0x32, 0xfe, 0xc1, 0xff, 0x8f, 0x03, 0x00, 0x00, 0x3e, 0xfe, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00, 0x7e, 0x7c, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; } -rotate -123 bitmap compose top "Top\nScaled 2x" -pady 5 -padx 10 -rotate 0 -scale 2.0 bitmap compose left "Left\na\nb\nc" -rotate 90 bitmap compose right {Right} -rotate 270 bitmap compose center {Center} -rotate 45 bitmap compose bottom {Bottom} -rotate 180 # # Test bitmap # # 1. Test of rotated text bitmap # 2. Define bitmap from output of "data" command # 3. Define bitmap from X11 bitmap file # 4. Define bitmap from X10 bitmap file # 5. Define bitmap from internal Tcl list # 6. Use predefined internal bitmap # proc ChangeBitmap { w } { global count bitmapList if { [incr count] >= [llength $bitmapList] } { exit } $w configure -bitmap [lindex $bitmapList $count] } set count -1 set bitmapList { sharky hobbes3 xbob gort question large_question questhead large_questhead hobbes BLT } option add *center*padX 8 option add *center*padY 4 button .left -bitmap left -command { .center configure -bitmap sharky ; set count -1 } button .top -bitmap top -command { .center configure -bitmap hobbes3 ; set count 0 } button .right -bitmap right -command { .center configure -bitmap xbob ; set count 1 } button .bottom -bitmap bottom -command { .center configure -bitmap gort ; set count 2 } button .center -bitmap center -command "ChangeBitmap .center" set bitmapFile @bitmaps/sharky.xbm bitmap define sharky [bitmap data $bitmapFile] -rotate 45 -scale 0.75 bitmap define large_question [bitmap data question] -scale 2.0 bitmap define large_questhead [bitmap data questhead] -scale 2.0 table . \ .top 0,1 -fill x \ .left 1,0 -fill y \ .center 1,1 -fill both \ .right 1,2 -fill y \ .bottom 2,1 -fill x blt-2.4z.orig/demos/bitmap2.tcl0100755000175000017500000002464207525557176015153 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl source scripts/stipples.tcl source scripts/patterns.tcl bitmap define hobbes { #define hobbes_width 25 #define hobbes_height 25 static char hobbes_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x78, 0xe0, 0x07, 0x00, 0xfc, 0xf8, 0x07, 0x00, 0xcc, 0x07, 0x04, 0x00, 0x0c, 0xf0, 0x0b, 0x00, 0x7c, 0x1c, 0x06, 0x00, 0x38, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x10, 0x00, 0xe0, 0x41, 0x11, 0x00, 0x20, 0x40, 0x11, 0x00, 0xe0, 0x07, 0x10, 0x00, 0xe0, 0xc1, 0x17, 0x00, 0x10, 0xe0, 0x2f, 0x00, 0x20, 0xe0, 0x6f, 0x00, 0x18, 0xe0, 0x2f, 0x00, 0x20, 0xc6, 0x67, 0x00, 0x18, 0x84, 0x2b, 0x00, 0x20, 0x08, 0x64, 0x00, 0x70, 0xf0, 0x13, 0x00, 0x80, 0x01, 0x08, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; } bitmap define gort { #define gort_width 64 #define gort_height 64 static char gort_bits[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xff, 0xff, 0x07, 0x00, 0x80, 0x01, 0x00, 0xc0, 0xdf, 0x0f, 0x1e, 0x00, 0x80, 0x01, 0x00, 0x60, 0xdf, 0x7f, 0x38, 0x00, 0x80, 0x01, 0x00, 0x30, 0x84, 0xfd, 0x67, 0x00, 0x80, 0x01, 0x00, 0x18, 0x04, 0xf6, 0xef, 0x00, 0x80, 0x01, 0x00, 0x0c, 0x86, 0xe1, 0xc7, 0x01, 0x80, 0x01, 0x00, 0x06, 0x06, 0xc0, 0x96, 0x01, 0x80, 0x01, 0x00, 0x06, 0x06, 0x00, 0x97, 0x03, 0x80, 0x01, 0x00, 0x06, 0x06, 0x00, 0x3c, 0x03, 0x80, 0x01, 0x00, 0x03, 0x06, 0x00, 0x5c, 0x07, 0x80, 0x01, 0x00, 0x03, 0x02, 0x00, 0xd8, 0x06, 0x80, 0x01, 0x00, 0x03, 0x02, 0x00, 0xd8, 0x06, 0x80, 0x01, 0x00, 0x43, 0x02, 0x00, 0xb0, 0x0c, 0x80, 0x01, 0x80, 0x31, 0x03, 0x00, 0xe0, 0x0d, 0x80, 0x01, 0x80, 0x61, 0x03, 0x00, 0xe0, 0x0d, 0x80, 0x01, 0x80, 0x1b, 0x03, 0x00, 0xf0, 0x0c, 0x80, 0x01, 0x80, 0xb3, 0x03, 0xff, 0xff, 0x1d, 0x80, 0x01, 0xc0, 0xeb, 0xfb, 0xff, 0xff, 0x1d, 0x80, 0x01, 0xe0, 0xc5, 0x7f, 0xfe, 0x7f, 0x3f, 0x01, 0xe0, 0xeb, 0xe3, 0xff, 0xff, 0x6e, 0x80, 0x01, 0xd0, 0x3b, 0xfe, 0x01, 0x80, 0x40, 0xcf, 0x80, 0x01, 0xf0, 0xf7, 0x07, 0x00, 0x30, 0x8e, 0x80, 0x01, 0xf0, 0xf4, 0x00, 0x00, 0x1b, 0x98, 0x80, 0x01, 0x70, 0x14, 0x00, 0x00, 0x1f, 0xdc, 0x80, 0x01, 0x30, 0xfe, 0xff, 0x1f, 0xc8, 0xff, 0x80, 0x01, 0x20, 0xee, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0x20, 0xf7, 0xff, 0x7f, 0xfe, 0x7f, 0x80, 0x01, 0xc0, 0xe1, 0xff, 0xff, 0xfe, 0x3f, 0x80, 0x01, 0x80, 0xed, 0xff, 0xff, 0xff, 0x19, 0x80, 0x01, 0x80, 0x99, 0xff, 0xff, 0xff, 0x18, 0x80, 0x01, 0x00, 0x63, 0x83, 0xff, 0x7f, 0x08, 0x80, 0x01, 0x00, 0xc3, 0x06, 0x00, 0x00, 0x0c, 0x80, 0x01, 0x00, 0x9b, 0x07, 0x00, 0x00, 0x0c, 0x80, 0x01, 0x00, 0xb6, 0x07, 0x00, 0x10, 0x0c, 0x80, 0x01, 0x00, 0xc6, 0x07, 0x00, 0x10, 0x04, 0x80, 0x01, 0x00, 0x36, 0x06, 0x00, 0x18, 0x06, 0x80, 0x01, 0x00, 0x66, 0x06, 0x00, 0x18, 0x06, 0x80, 0x01, 0x00, 0x8c, 0x0d, 0x00, 0x18, 0x02, 0x80, 0x01, 0x00, 0x18, 0x0e, 0x00, 0x18, 0x03, 0x80, 0x01, 0x00, 0xf0, 0x0c, 0x00, 0x18, 0x03, 0x80, 0x01, 0x00, 0x30, 0x0f, 0x00, 0x98, 0x01, 0x80, 0x01, 0x00, 0xb0, 0x1f, 0x01, 0x98, 0x01, 0x80, 0x01, 0x00, 0x60, 0x1f, 0x03, 0xdc, 0x00, 0x80, 0x01, 0x00, 0xe0, 0x3f, 0x03, 0xdc, 0x00, 0x80, 0x01, 0x00, 0xe0, 0x3b, 0x07, 0xee, 0x00, 0x80, 0x01, 0x00, 0x70, 0xf8, 0xff, 0xff, 0x01, 0x80, 0x01, 0x00, 0xf0, 0x80, 0xff, 0x37, 0x03, 0x80, 0x01, 0x00, 0xfc, 0x00, 0x08, 0xd8, 0x03, 0x80, 0x01, 0x00, 0xfe, 0x03, 0xf8, 0x7f, 0x07, 0x80, 0x01, 0xc0, 0x87, 0x07, 0xe0, 0x3f, 0x1c, 0x80, 0x01, 0xf0, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x8f, 0x81, 0xff, 0x00, 0x38, 0x00, 0xf6, 0xf9, 0xff, 0xfd, 0x3f, 0x00, 0xe0, 0x00, 0x83, 0x8f, 0xff, 0xff, 0x00, 0x00, 0x80, 0x01, 0x00, 0xfc, 0xc0, 0x07, 0x0e, 0x00, 0x38, 0xe0, 0x00, 0xe0, 0x9f, 0xf9, 0x07, 0x00, 0x00, 0x80, 0x03, 0x00, 0xff, 0x7f, 0x80, 0x01, 0x00, 0xc0, 0x00, 0x00, 0xf0, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0xf0, 0x00, 0x38, 0x00, 0x00, 0x00, 0x80, 0x01, 0x30, 0x00, 0x00, 0x38, 0xc0, 0xc0, 0x80, 0x01, 0x1c, 0xe0, 0x00, 0x0c, 0xc0, 0x83, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; } bitmap define xbob { #define bob_x_hot 30 #define bob_y_hot 37 #define bob_width 61 #define bob_height 75 static char bob_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xfb, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xcf, 0x9f, 0xd1, 0x03, 0x00, 0x00, 0xf0, 0x7f, 0x8c, 0x33, 0x91, 0x07, 0x00, 0x00, 0xf8, 0xa7, 0x18, 0x27, 0xb1, 0x06, 0x00, 0x00, 0xfc, 0x47, 0x31, 0x4e, 0xa6, 0x0e, 0x00, 0x00, 0xfe, 0x4f, 0x21, 0x4c, 0xae, 0x3d, 0x00, 0x00, 0xff, 0xdf, 0x23, 0x8d, 0xbe, 0x7d, 0x00, 0x80, 0xff, 0xff, 0x67, 0xbd, 0xfe, 0xff, 0x01, 0x80, 0xff, 0xff, 0x7f, 0xbf, 0xff, 0xff, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xf8, 0x07, 0xc0, 0xff, 0xff, 0xff, 0xbf, 0x3f, 0xf8, 0x07, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x07, 0xf8, 0x0f, 0xc0, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xf8, 0x0f, 0xe0, 0x7f, 0x00, 0xf8, 0x07, 0x00, 0xf0, 0x0f, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x07, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x07, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x07, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x07, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x07, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x07, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x07, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x07, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x07, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x07, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x78, 0xf6, 0x07, 0xa0, 0xbf, 0xff, 0x00, 0x00, 0xff, 0xf7, 0x07, 0x70, 0x9f, 0xff, 0x01, 0x80, 0xff, 0xef, 0x07, 0xf0, 0x1c, 0x80, 0x03, 0xe0, 0x01, 0xef, 0x07, 0xf0, 0x1f, 0xbe, 0x07, 0xf0, 0x3f, 0xee, 0x07, 0xe0, 0x9d, 0x83, 0x1f, 0xf8, 0xe1, 0xdc, 0x07, 0xe0, 0xc1, 0x7f, 0x1f, 0xfc, 0xff, 0xc8, 0x07, 0xe0, 0xc1, 0x69, 0x1e, 0x7e, 0xca, 0xc0, 0x03, 0xe0, 0x81, 0xb8, 0x1f, 0xc0, 0x0e, 0xc0, 0x03, 0xe0, 0x01, 0xc0, 0x1b, 0xc0, 0xcf, 0xc1, 0x03, 0xc0, 0x03, 0xf7, 0x11, 0x00, 0x7f, 0xc0, 0x03, 0xc0, 0x03, 0x7c, 0x18, 0x00, 0x1c, 0xc0, 0x02, 0xc0, 0x02, 0x30, 0x08, 0x00, 0x00, 0x40, 0x03, 0x40, 0x03, 0x00, 0x08, 0x00, 0x00, 0x40, 0x02, 0x40, 0x13, 0x00, 0x0c, 0x00, 0x00, 0x60, 0x02, 0x40, 0x12, 0x00, 0x0e, 0x00, 0x00, 0xc0, 0x03, 0x80, 0x33, 0x80, 0x0e, 0x00, 0x00, 0xa8, 0x01, 0x00, 0x33, 0x40, 0x0f, 0xa0, 0x03, 0x2c, 0x00, 0x00, 0x74, 0x30, 0x0f, 0x38, 0x07, 0x2e, 0x00, 0x00, 0x74, 0x98, 0x1f, 0x1e, 0x1e, 0x2f, 0x00, 0x00, 0xfc, 0x8f, 0xff, 0x0f, 0xfc, 0x2f, 0x00, 0x00, 0xf8, 0xe3, 0xff, 0x03, 0xf8, 0x2f, 0x00, 0x00, 0xf8, 0xfd, 0xff, 0x81, 0xff, 0x3f, 0x00, 0x00, 0xb8, 0xf9, 0x1f, 0xf8, 0x0f, 0x1e, 0x00, 0x00, 0x30, 0xf1, 0xf0, 0x0f, 0x03, 0x0e, 0x00, 0x00, 0x30, 0xf1, 0x01, 0x80, 0x01, 0x0f, 0x00, 0x00, 0x20, 0xf1, 0xf7, 0xff, 0x00, 0x07, 0x00, 0x00, 0x60, 0xe3, 0x01, 0x60, 0x80, 0x07, 0x00, 0x00, 0x60, 0xc3, 0xef, 0x3f, 0x80, 0x03, 0x00, 0x00, 0x40, 0xc2, 0xff, 0x0f, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0xe6, 0x1f, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0xf4, 0xfe, 0x3f, 0xe0, 0x00, 0x00, 0x00, 0x80, 0x79, 0xfe, 0x1f, 0xe0, 0x00, 0x00, 0xc0, 0x01, 0x3d, 0x3e, 0x00, 0x70, 0x00, 0x00, 0x30, 0x06, 0x3e, 0x0f, 0x00, 0x38, 0x00, 0x00, 0xc8, 0x8c, 0x1f, 0x07, 0x00, 0x38, 0x00, 0x00, 0xf4, 0xcc, 0x8f, 0x07, 0x00, 0x1c, 0x00, 0x00, 0x72, 0xee, 0xf7, 0x07, 0x00, 0x0e, 0x00, 0x00, 0x02, 0xff, 0xe3, 0x07, 0x00, 0x07, 0x00, 0x00, 0x32, 0xfe, 0xc1, 0xff, 0x8f, 0x03, 0x00, 0x00, 0x3e, 0xfe, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00, 0x7e, 0x7c, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; } blt::bitmap compose text "Text String" -font {courier 12} . configure -bg grey80 label .angle -text "Angle" -font { Helvetica 12 bold } -bg grey80 label .scale -text "Scale" -font { Helvetica 12 bold } -bg grey80 blt::table . \ 0,0 .angle -fill both \ 0,5 .scale -fill both set row 1 foreach angle { 0 90 180 270 360 45 -45 101 } { label .angle$angle -text $angle -bg grey80 blt::table . \ $row,0 .angle$angle -fill both set column 1 foreach bitmap { hobbes gort xbob text } { set data [blt::bitmap data $bitmap] blt::bitmap define $bitmap$row$column $data -rotate $angle label .$bitmap$row$column -bitmap $bitmap$row$column -bg white blt::table . \ $row,$column .$bitmap$row$column incr column } incr row } set row 1 foreach scale { 1.0 0.5 0.75 1.4 3.0 } { label .scale$row -text $scale -bg grey80 blt::table . \ $row,5 .scale$row -fill both set column 6 foreach bitmap { hobbes gort xbob text } { set data [blt::bitmap data $bitmap] blt::bitmap define $bitmap$row$column $data -scale $scale label .$bitmap$row$column -bitmap $bitmap$row$column -bg white blt::table . \ $row,$column .$bitmap$row$column incr column } incr row } foreach scale { 2.0 0.8 1.2 } angle { 45 -45 101 } { label .scale$row -text "$scale/$angle" -bg grey80 blt::table . \ $row,5 .scale$row -fill both set column 6 foreach bitmap { hobbes gort xbob text } { set data [blt::bitmap data $bitmap] blt::bitmap define $bitmap$row $data -scale $scale -rotate $angle label .$bitmap$row -bitmap $bitmap$row -bg white blt::table . \ $row,$column .$bitmap$row incr column } incr row } blt::table configure . c* -padx 2blt-2.4z.orig/demos/busy1.tcl0100755000175000017500000001427607240160070014633 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl # # Script to test the "busy" command. # # # General widget class resource attributes # option add *Button.padX 10 option add *Button.padY 2 option add *Scale.relief sunken #option add *Scale.orient horizontal option add *Entry.relief sunken option add *Frame.borderWidth 2 set visual [winfo screenvisual .] if { $visual == "staticgray" || $visual == "grayscale" } { set activeBg black set normalBg white set bitmapFg black set bitmapBg white option add *f1.background white } else { set activeBg red set normalBg springgreen set bitmapFg blue set bitmapBg green option add *Button.background khaki2 option add *Button.activeBackground khaki1 option add *Frame.background khaki2 option add *f2.tile textureBg # option add *Button.tile textureBg option add *releaseButton.background limegreen option add *releaseButton.activeBackground springgreen option add *releaseButton.foreground black option add *holdButton.background red option add *holdButton.activeBackground pink option add *holdButton.foreground black option add *f1.background springgreen } # # Instance specific widget options # option add *f1.relief sunken option add *f1.background $normalBg option add *testButton.text "Test" option add *quitButton.text "Quit" option add *newButton.text "New\nButton" option add *holdButton.text "Hold" option add *releaseButton.text "Release" option add *buttonLabel.text "Buttons" option add *entryLabel.text "Entries" option add *scaleLabel.text "Scales" option add *textLabel.text "Text" bind keepRaised { raise %W } proc KeepRaised { w } { bindtags $w keepRaised } set file ./images/chalk.gif image create photo textureBg -file $file # # This never gets used; it's reset by the Animate proc. It's # here to just demonstrate how to set busy window options via # the host window path name # #option add *f1.busyCursor bogosity # # Counter for new buttons created by the "New button" button # set numWin 0 # # Create two frames. The top frame will be the host window for the # busy window. It'll contain widgets to test the effectiveness of # the busy window. The bottom frame will contain buttons to # control the testing. # frame .f1 frame .f2 # # Create some widgets to test the busy window and its cursor # label .buttonLabel button .testButton -command { puts stdout "Not busy." } button .quitButton -command { exit } entry .entry scale .scale text .text -width 20 -height 4 # # The following buttons sit in the lower frame to control the demo # button .newButton -command { global numWin incr numWin set name button#${numWin} button .f1.$name -text "$name" \ -command [list .f1 configure -bg blue] table .f1 \ .f1.$name $numWin+3,0 -padx 10 -pady 10 } button .holdButton -command { if { [busy isbusy .f1] == "" } { global activeBg .f1 configure -bg $activeBg } busy .f1 focus -force . } button .releaseButton -command { if { [busy isbusy .f1] == ".f1" } { busy release .f1 } global normalBg .f1 configure -bg $normalBg } # # Notice that the widgets packed in .f1 and .f2 are not their children # table .f1 \ 0,0 .testButton \ 1,0 .scale -fill y \ 0,1 .entry -fill x \ 1,1 .text -fill both \ 2,0 .quitButton -cspan 2 table .f2 \ 0,0 .holdButton \ 0,1 .releaseButton \ 0,2 .newButton table configure .f1 \ .testButton .scale .entry .quitButton -padx 10 -pady 10 table configure .f2 \ .newButton .holdButton .releaseButton -padx 10 -pady 4 -reqwidth 1.i table configure .f1 r0 r2 -resize none table configure .f2 r* -resize none # # Finally, realize and map the top level window # table . \ 0,0 .f1 -fill both \ 1,0 .f2 -fill both table configure . r1 -resize none table configure .f1 c1 -weight 2.0 # Initialize a list of bitmap file names which make up the animated # fish cursor. The bitmap mask files have a "m" appended to them. set bitmapList { left left1 mid right1 right } # # Simple cursor animation routine: Uses the "after" command to # circulate through a list of cursors every 0.075 seconds. The # first pass through the cursor list may appear sluggish because # the bitmaps have to be read from the disk. Tk's cursor cache # takes care of it afterwards. # proc StartAnimation { widget count } { global bitmapList set prefix bitmaps/fish/[lindex $bitmapList $count] set cursor [list @${prefix}.xbm ${prefix}m.xbm blue green ] busy configure $widget -cursor $cursor incr count set limit [llength $bitmapList] if { $count >= $limit } { set count 0 } global afterId set afterId($widget) [after 125 StartAnimation $widget $count] } proc StopAnimation { widget } { global afterId after cancel $afterId($widget) } proc TranslateBusy { window } { set widget [string trimright $window "_Busy"] if { $widget != "." } { set widget [string trimright $widget "."] } return $widget } if { [info exists tcl_platform] && $tcl_platform(platform) == "unix" } { bind Busy { StartAnimation [TranslateBusy %W] 0 } bind Busy { StopAnimation [TranslateBusy %W] } } # # For testing, allow the top level window to be resized # wm min . 0 0 # # Force the demo to stay raised # raise . KeepRaised . blt-2.4z.orig/demos/busy2.tcl0100755000175000017500000001467407240160070014636 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -fill both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -fill both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* # namespace import -force blt::tile::* } #source scripts/demo.tcl # # Script to test the "busy" command. # # # General widget class resource attributes # option add *Button.padX 10 option add *Button.padY 2 option add *Scale.relief sunken #option add *Scale.orient horizontal option add *Entry.relief sunken option add *Frame.borderWidth 2 set visual [winfo screenvisual .] if { $visual == "staticgray" || $visual == "grayscale" } { set activeBg black set normalBg white set bitmapFg black set bitmapBg white option add *f1.background white } else { set activeBg red set normalBg springgreen set bitmapFg blue set bitmapBg green option add *Button.background khaki2 option add *Button.activeBackground khaki1 option add *Frame.background khaki2 option add *f2.tile textureBg # option add *Button.tile textureBg option add *releaseButton.background limegreen option add *releaseButton.activeBackground springgreen option add *releaseButton.foreground black option add *holdButton.background red option add *holdButton.activeBackground pink option add *holdButton.foreground black option add *f1.background springgreen } # # Instance specific widget options # option add *f1.relief sunken option add *f1.background $normalBg option add *testButton.text "Test" option add *quitButton.text "Quit" option add *newButton.text "New button" option add *holdButton.text "Hold" option add *releaseButton.text "Release" option add *buttonLabel.text "Buttons" option add *entryLabel.text "Entries" option add *scaleLabel.text "Scales" option add *textLabel.text "Text" proc LoseFocus {} { focus -force . } proc KeepRaised { w } { bindtags $w keepRaised } bind keepRaised { raise %W } set file ./images/chalk.gif image create photo textureBg -file $file # # This never gets used; it's reset by the Animate proc. It's # here to just demonstrate how to set busy window options via # the host window path name # #option add *f1.busyCursor bogosity # # Counter for new buttons created by the "New button" button # set numWin 0 menu .menu .menu add command -label "First" .menu add command -label "Second" .menu add command -label "Third" .menu add command -label "Fourth" . configure -menu .menu # # Create two frames. The top frame will be the host window for the # busy window. It'll contain widgets to test the effectiveness of # the busy window. The bottom frame will contain buttons to # control the testing. # frame .f1 frame .f2 # # Create some widgets to test the busy window and its cursor # label .buttonLabel button .testButton -command { puts stdout "Not busy." } button .quitButton -command { exit } entry .entry scale .scale text .text -width 20 -height 4 # # The following buttons sit in the lower frame to control the demo # button .newButton -command { global numWin incr numWin set name button#${numWin} button .f1.$name -text "$name" \ -command [list .f1 configure -bg blue] table .f1 \ .f1.$name $numWin+3,0 -padx 10 -pady 10 } button .holdButton -command { if { [busy isbusy .f1] == "" } { global activeBg .f1 configure -bg $activeBg } busy .f1 busy .#menu LoseFocus } button .releaseButton -command { if { [busy isbusy .f1] == ".f1" } { busy release .f1 busy release .#menu } global normalBg .f1 configure -bg $normalBg } # # Notice that the widgets packed in .f1 and .f2 are not their children # table .f1 \ .testButton 0,0 \ .scale 1,0 \ .entry 0,1 \ .text 1,1 -fill both \ .quitButton 2,0 table .f2 \ .newButton 0,0 \ .holdButton 1,0 \ .releaseButton 2,0 table configure .f1 .testButton .scale .entry .quitButton -padx 10 -pady 10 -fill both table configure .f2 .newButton .holdButton .releaseButton -padx 10 -pady 10 table configure .f2 c0 -resize none # # Finally, realize and map the top level window # table . \ .f1 0,0 \ .f2 1,0 table configure . .f1 .f2 -fill both # Initialize a list of bitmap file names which make up the animated # fish cursor. The bitmap mask files have a "m" appended to them. table configure . r1 -resize none set bitmapList { left left1 mid right1 right } # # Simple cursor animation routine: Uses the "after" command to # circulate through a list of cursors every 0.075 seconds. The # first pass through the cursor list may appear sluggish because # the bitmaps have to be read from the disk. Tk's cursor cache # takes care of it afterwards. # proc StartAnimation { widget count } { global bitmapList set prefix "bitmaps/fish/[lindex $bitmapList $count]" set cursor [list @${prefix}.xbm ${prefix}m.xbm black white ] busy configure $widget -cursor $cursor incr count set limit [llength $bitmapList] if { $count >= $limit } { set count 0 } global afterId set afterId($widget) [after 125 StartAnimation $widget $count] } proc StopAnimation { widget } { global afterId after cancel $afterId($widget) } proc TranslateBusy { window } { #set widget [string trimright $window "_Busy"] set widget [string trimright $window "Busy"] set widget [string trimright $widget "_"] # if { [winfo toplevel $widget] != $widget } { # set widget [string trimright $widget "."] # } return $widget } if { [info exists tcl_platform] && $tcl_platform(platform) == "unix" } { bind Busy { StartAnimation [TranslateBusy %W] 0 } bind Busy { StopAnimation [TranslateBusy %W] } } # # For testing, allow the top level window to be resized # wm min . 0 0 # # Force the demo to stay raised # raise . KeepRaised . blt-2.4z.orig/demos/container.tcl0100755000175000017500000000046407332636776015573 0ustar dokodoko#!../src/bltwish package require BLT namespace import blt::* set cmd "xterm -geom +4000+4000" #set cmd "xclock -name fred -geom +4000+4000" eval bgexec myVar $cmd & container .c pack .c -fill both -expand yes #.c configure -relief raised -bd 2 -name fred .c configure -relief raised -bd 2 -command $cmd blt-2.4z.orig/demos/container3.tcl0100755000175000017500000003576207425460266015657 0ustar dokodoko#!../src/bltwish package require BLT namespace import blt::* image create photo mini-apm-alert -data { R0lGODdhEAAQAPIAALLA3AAAAAAAoMDAwKCgoICAgP8AAP///ywAAAAAEAAQAAADSgiq1bGQ tTNKuBHMMmrwEdeMDfEAhqENROu2Z7q6xhurXJvWsCLnOpsPx3q5bjNjD0VULhdAJTJqnBZ0 qZbgBAkIvuBtRnEpYyIJADs= } image create photo mini-apm-empty -data { R0lGODdhEAAQAPIAALLA3AAAAMDAwKCgoICAgP8AAP///wAAACwAAAAAEAAQAAADSQiq1LGQ NSNIuBFMImrwUVE0ZCNGhDisq/hAnNoWw7twgyrbjDDTK57Gl5PVUD4dUBgDFo8w40woZZ1g BJYWCglsgxnFZYyJJAAAOw== } image create photo mini-apm-full -data { R0lGODdhEAAQAPIAALLA3AAAAAAAoMDAwICAgP8AAP///wAAACwAAAAAEAAQAAADQAiq1LGQ NTNIuBFMMmrwEdeMjfBAnKCu6rmkasG6zBAXchva8byzPhQPaPoRi8Ij8jUE0jSEW265CByf 1YsWmwAAOw== } image create photo mini-apm-half -data { R0lGODdhEAAQAPIAALLA3AAAAAAAoMDAwKCgoICAgP8AAP///ywAAAAAEAAQAAADRwiq1bGQ tTNKuBHMMmrwEdeMDfFAHKGu6rmkqsG6zBAbchva8byzKwFNMxAYj8YhB4lUFpnJHTSKKhhx huMQEJhuFZcwJpIAADs= } image create photo mini-apm-loading -data { R0lGODdhEAAQAPMAALLA3AAAAP//AMDAwKCgoICAgP8AAICAAP///wAAAAAAAAAAAAAAAAAA AAAAAAAAACwAAAAAEAAQAAAEXRBIWWo4oNyZKxqHcFzi5BUDKBYhRg1VFcqC9hJ4rFvZkH+p ICzQwxk0gaSSWDQWENCUrfkTTlGCbA0oZWK1ggBw2gNnl5yd9smkPKGI2KcNgCoH8AEdkOQv +xwAEQA7 } image create photo mini-apm-online -data { R0lGODdhEAAQAPIAALLA3AAAAICAAMDAwICAgP//AP///wAAACwAAAAAEAAQAAADRQi6QCHt sSkKrHAuDLhWFUGEwSeeaMkQxuC+g6M5QW2rs6G7stm+vRwsqAn8iJ/bBLVg4RosneHUeups A+ngCagtblxAAgA7 } image create photo mini-apm-unknown -data { R0lGODdhEAAQAPIAALLA3AAAAP//AMDAwICAgP8AAP///wAAACwAAAAAEAAQAAADRAiq1LGQ NTNIuBFMMmrwEdeMjfBAnKCu6rmkQiGvLjPEa9GGt676Nc0tR+MRi6ghDvlSskzGHytYeu4i ASs0A7h4MZEEADs= } image create photo mini-folder -data { R0lGODdhIAAbAPIAALLA3ICAgP//////AMDAwAAAAICAAAAAACwAAAAAIAAbAAADeQgK0e4r yhmDuBgHyqUdBCiGxNZxHzmO5lkRcCzPT10XTKbvPF8UqZVqKBQagAKisrg8BpdQpjPJrEan 1qxyGu0Wsd4wiKsth8BmLVnsRbOt6/QVKVcj3206Hn6vz59+Rn17TXqBW0AGiouMjY6Pijg/ k5SVlpeTAAkAOw== } image create photo mini-arch -data { R0lGODdhEAAQAPEAAICAgAAAAMBkMv+gMiwAAAAAEAAQAAACQQSCqXoi46B7YtlVA51Q1sxN EaQhmyKWmoMYzTCoZOUes/kF9SrHtKvxIW47mIr1M/AyxqQtF2wVYzpG7ZC4arcFADs= } image create photo mini-asmail -data { R0lGODdhEAAQAPMAAJSUlP///97e3mNjYzz4NK2trfgUQL29vXNzc0JCQoCAgAAAAAAAAAAA AAAAAAAAACwAAAAAEAAQAAAEVFDJOYGgmA5iMwaGIYwfAAzDqJLT6q4ScMyvOsSyW9i3MhwC hGo3GhR6JuHLeEAoAgUTcGVEWA9Q089WOCQTWROgcBxYv2GxWoxIeK3weDzhqdvrEQA7 } image create photo mini-audiovol -data { R0lGODdhDgAOAPEAALLA3AAA7v///2ZmZiwAAAAADgAOAAACMYQdcxgLkdhQK8E0oIMz4+19 ztMNwohQ5zkmK8BK0Xtel0I/tgv3uq3y7SiGmARlKAAAOw== } image create photo mini-ball -data { R0lGODdhEAAQAPEAALLA3AAAAP///4CAgCwAAAAAEAAQAAACG4SPqcvtD1mYMAhBncVh6Dl5 Xyc6wxml6so+BQA7 } image create photo mini-bball -data { R0lGODdhEAAQAPEAALLA3AAA/////4CAgCwAAAAAEAAQAAACG4SPqcvtD1mYMAhBncVh6Dl5 Xyc6wxml6so+BQA7 } image create photo mini-bomb -data { R0lGODdhEAAQAPIAALLA3AAAAICAgMDAwP//AP///wAAAAAAACwAAAAAEAAQAAADPAi63K4h vhZWneDaGTV0nbQxgVAMHbkIQcF2wpgFw5sqBJCHHVHlhNwsJEDhggpbhBXTUXgeh62JqVon CQA7 } image create photo mini-book1 -data { R0lGODdhEAAQAPIAALLA3AAAAP8AAP//AICAgP///wAAAAAAACwAAAAAEAAQAAADPAi63K4h vBaFkLNai5neWwcEwwCeXVSeIBZcK8uNXNymtckFBeHlkUKPIHpdeMOI48UjEEWUwHPigVKv CQA7 } image create photo mini-book2 -data { R0lGODdhEAAQAPEAAL+/vwAAAICAgP///ywAAAAAEAAQAAACOYSPeRHqIUZbLMEhAcNzRf5J lXFxGNiVUgil7Lm6p9p6M1zbK5fbgYgRdDwMgdE4JLUYzKTSAY0CCgA7 } image create photo mini-books -data { R0lGODdhEAAQAPIAAICAgP////8AAAAA/wAAAP//AAAAAAAAACwAAAAAEAAQAAADSgi63B3B wRdFGGoSBy5exaYIwjJgRQGECwlgJ0Bs7FjGqFoDLgGvOhGvJIgBV0KXwKdIIVtEX+6Zqcww k11PQVMJZbPG7MspmzkJADs= } image create photo mini-briefcase -data { R0lGODdhEAAQAPIAALLA3ICAAMDAwAAAAICAgP///wAAAAAAACwAAAAAEAAQAAADSQi63B4Q OhaKuCJMFcT4g9ZEZFgClWANAuGpahBegTsUa1eHRY17v5lMRyrWCLwOZpnJzJo6aAZZiVqh z6uVauzKAKCw+LMpJwAAOw== } image create photo mini-bug1 -data { R0lGODdhEAAQAPIAALLA3AAAAMDAwICAgP///wAAAAAAAAAAACwAAAAAEAAQAAADNAi63P5Q hTWjDDUKzEUcAcENEChiIOlgxCCA2MoF2yxjddwEMD1mjA4H4ituLDygZckEJAAAOw== } image create photo mini-bug2 -data { R0lGODdhEAAQAPIAALLA3AAAAICAgMDAwP///wAAAAAAAAAAACwAAAAAEAAQAAADOAi63A5h xceCpUvYLajQW/A9FsFdjWZ+oFiV1hCiyiyHjT1XbXBbmtzmN+ENTw/QrYMBCAbMZjMBADs= } image create photo mini-bx2 -data { R0lGODdhEAAQAPAAALLA3AAAACwAAAAAEAAQAAACIoSPqcuNAeEKL9Kn7AU7ae5EoAOKDfVN R4pVptGtFknXdQEAOw== } image create photo mini-calc -data { R0lGODdhEAAQAPIAALLA3ICAgP///wAAANnZ2QAAAAAAAAAAACwAAAAAEAAQAAADRAi63Bow SgmCuDjjUQUhQyiKYPcN2hWU1jdJrPfN9NkFA4Hr+c5ZIVAuSLz1jrwYcciM7Z7In2AprP5q WBtgxB05vo0EADs= } image create photo mini-camera -data { R0lGODdhEAAQAPEAALLA3AAAAP///4CAgCwAAAAAEAAQAAACNYSPqRDta4KYNCAnhxviyYo1 YBgMJplp5XSWqtByptrC9HyLc7O7bx/q2YA4DQNFgiiXTGYBADs= } image create photo mini-cat -data { R0lGODdhEAAQAPEAAICAgAAAAP//AP8AACwAAAAAEAAQAAACOYSPecGqIUR4YNZoEdw36yh1 FTNBoGSa2Cah5xsN2AW/llqHHYjPdErydTiblCG1wvhIo2PJ44gWAAA7 } image create photo mini-cave -data { R0lGODdhEAAQAPMAAAD//wBy/QAA/AAAuAD/jwD/Cv+EAHL/AP//AA8Pbf8AAP9FAP/HAAAA AAAAAAAAACwAAAAAEAAQAAAEWhBIGaq4I+c5a7iCNhBEYRzGCFjggCAJARCJ8hKskOwJIAAw Cc5C4yVgiUEBODHydL9dgVRw8haJxeKAtO4WBgSDofAaGYcD1sxD49iJwAE9hbcRZXtPz7dH AAA7 } image create photo mini-cd -data { R0lGODdhEAAQAPIAALLA3ICAgP//AMDAwAAAAAD//wD/AP///ywAAAAAEAAQAAADUQiq0b2Q BSGGJSSCUGi1FxQYRfdZx5AxBkmBqcpYbYeCcgCSAaHjmR8tQ8DlcIceB7iBoQyCAmili9Gi 0tXGesVqm7gW5SvZGTCaRQNDTrsVCQA7 } image create photo mini-cdlabel -data { R0lGODdhEAAQAPEAALLA3AAAAICAgAAAACwAAAAAEAAQAAACM4SPecEg8SJcIFQpqVWpsfcx 21aVBmmlZTqpbinE66yeVUt7NC2/qAkciYYQEeeITCoTBQA7 } image create photo mini-chinese -data { R0lGODdhEAAQAPAAAICAgAAA/ywAAAAAEAAQAAACJoQdB6kXrx5ri0FapZ4R2baFEpVAHFkt WCaunuuFcDq/NV1f91oAADs= } image create photo mini-clipboard -data { R0lGODdhEAAQAPIAALLA3AAAAP//AICAAICAgMDAwAAAgP///ywAAAAAEAAQAAADUgi63B4w OBWhEFXSQUbAX9ARmkgWaCp6BBBwWUSQ7TpyeCe6+WD8QMPOxjEcjsdfrWdEHowG141gjDyB r1vTmSRSD7Gnq7LlRgGzWXB9bqTfswQAOw== } image create photo mini-clock -data { R0lGODdhEAAQAPEAALLA3AAAAP///8DAwCwAAAAAEAAQAAACMoSPqRDda5qY86UwaKAjXCps GiJqYHiU1elFoPSmrNoybDjKZ55me6eAaWpBBxGCTCoKADs= } image create photo mini-colors -data { R0lGODdhEAAQAPIAALLA3ICAgP8AAP//AAAA/wAAAP///wAAACwAAAAAEAAQAAADPgi63P4w skCrtSqILYYfREgEBaBxHyiSJtd94lieWxqzgaEbVuEXuB2v8gPOhL1fcJf04S5QSglQrFYl WGwCADs= } image create photo mini-connect -data { R0lGODdhEAAQAPIAALLA3AAAAICAgP8AAP//AAAAAAAAAAAAACwAAAAAEAAQAAADLwi63P7Q hbgECJaKMfJ8GzdcWROKHXSKpYl2n7MKsUkIOK3edFAzAh6l0tIMj44EADs= } image create photo mini-crosbone -data { R0lGODdhEAAQAPEAAICAgAAAAP///8DAwCwAAAAAEAAQAAACQUQCqXqMu5qRMJ0HxBV8jygM 4jhoUPAhKTBgVnvAqGtkIcrVJ1uKeoUi0Rwz2SnQmSE1j4PgJXowLRHKr4LNagEFADs= } image create photo mini-cross -data { R0lGODdhEAAQAPEAALLA3P8AAICAgAAAACwAAAAAEAAQAAACKISPqcsbHgQKFEpAM8x0DMYF X8ONYNhgovpApqasU5TItWngiZ72TAEAOw== } image create photo mini-desktop -data { R0lGODdhEAAQAPIAAICAgACAgAAAAAD//8DAwP///4CAAP//ACwAAAAAEAAQAAADQgi6EMIQ BveidEBUG8asWqSNobJZzIku6tq62UIARSEQhkHsRDXXNtwhd/PRgoaD8vB49EjPkekIrAJj K0iTxCUpEgA7 } image create photo mini-dfolder -data { R0lGODdhEAAQAPIAALLA3ICAgMDAwP//AAAA/wAAAP///wAAACwAAAAAEAAQAAADSQi63BsQ OhbEsCJMUK/PkcQZZGmSQTF+YTtiwWkWsRcTeB7TBmwQP52BZwvmCLuY74hLGopM5LAVo+4A hax2u93ESJkNlqsFJAAAOw== } image create photo mini-diff -data { R0lGODdhEAAQAPEAALLA3P8AAAAAAP///ywAAAAAEAAQAAACQYSPqcLtckSYQYyLIZDGVnxB HDBYw5dtAbldaKhGrhkyVTODTBnU07PjUSiaTsZBlIEyydbS93M+RVGgo1NUaA0FADs= } image create photo mini-diskette -data { R0lGODdhEAAQAPIAAAAAgAAAAICAgP//AODg4P///8DAwAAAACwAAAAAEAAQAAADQAgQ3B5K qEGrHQoCwrsnmVKMZFmE2/ehZouq6yK2JarcOK4pRu8bOhwQ8AvehsXbjsjzGXnNnk4STWYE goe2kQAAOw== } image create photo mini-display -data { R0lGODdhEAAQAPIAALLA3ICAgP///wAAAAAA/8DAwAAAAAAAACwAAAAAEAAQAAADPgi63Bsw SviEvdgOFcT4INhtwEic6DlyHiGkqscOMLqWbU3cps7ntd9gIpHhMkgSIMQEOTqXQkC5aDYd 2EYCADs= } image create photo mini-doc -data { R0lGODdhEAAQAPIAALLA3ICAgMDAwAAAAP///wAAAAAAAAAAACwAAAAAEAAQAAADNAix3PAw kEmnCPDJSgXBEUcN5BCKnamh6ckKqsJa8fbWMwG76L7OPhkQN4wIjshksMRsqhIAOw== } image create photo mini-doc1 -data { R0lGODdhEAAQAPEAALLA3AAAAP///4CAgCwAAAAAEAAQAAACOYSPicEdeoKYk0EghxbyKUlx zSdomxYMCRhW6lKaW7q2FA3L8xvZbq0bcHgGVgsXcSiJhqDsAgUUAAA7 } image create photo mini-dog -data { R0lGODdhEAAQAPEAAICAgAAAAP///8DAwCwAAAAAEAAQAAACPoSPqRbt6oKYgiEpxqA1XKkJ zeRdGTZg4pVybgk0sTvFMENydhJsI3WbTVIRnoiSWqhsMmOIEzRwntGFFVAAADs= } image create photo mini-edit -data { R0lGODdhEAAQAPIAALLA3AAAAICAgP///wAA/wAAAAAAAAAAACwAAAAAEAAQAAADPwi63CAw RveGvUMEJ7LMw7YQHWZpgUiQXoRta1CaVxBX0ndXtLXjOQ1BpJi9UkRgBBliGEMvZ6/GQFqv lGwjAQA7 } image create photo mini-espada -data { R0lGODdhEAAQAPAAAICAgAAAACwAAAAAEAAQAAACIoSPqRbr7RSMJ1jK7I26v+4l4CiOYWVq 0tWo1IQBMHfGSwEAOw== } image create photo mini-exclam -data { R0lGODdhEAAQAPIAALLA3ICAgACAAP///wAAAAAAAAAAAAAAACwAAAAAEAAQAAADLQi6GsKQ hSFEiJJWglf9XOeAV/dtnXKGKZh6AvvGLyOnU1UDZznHPhwhuEslAAA7 } image create photo mini-exp -data { R0lGODdhEAAQAPEAALLA3AAAAICAgP//ACwAAAAAEAAQAAACMoSPqRbrzYQDYbQAD97VWtUN 4shJzIiSSZhmDKuuaayJmN1lHGVT2GHSuAJB0OSInBQAADs= } image create photo mini-eye -data { R0lGODdhEAAQAPEAALLA3AAAAIKCgsPDwywAAAAAEAAQAAACK4SPqcvtb4KcYs1wKJIADzF0 HTZGgBBU5JiaX0hWh6Bmp5yoHA71/g+EFAAAOw== } image create photo mini-eyes -data { R0lGODdhEAAQAPIAALLA3AAAAICAgMDAwP///wAAAAAAAAAAACwAAAAAEAAQAAADPwi63P4w tkDDqvYOQoYNW5eBHOeF5leWwcoFQuvKK9xSLIG/sSefO48AQBL1UoIhsZJcUpqLJBQgVUqu 2KwiAQA7 } image create photo mini-fax -data { R0lGODdhEAAQAPIAALLA3ICAgAAAAMDAwP///wAAAAAAAAAAACwAAAAAEAAQAAADSAi6HM5w BUIfdI5qIuQk39Yp0zBkokScpTlwJ1DOQuAKZkYHtXvWu17OAaSYhBii0DhMdnC5VZI3Agig LGXEitNuF9fqd7xIAAA7 } image create photo mini-fdisk -data { R0lGODdhEAAQAPIAALLA3ICAgMDAwAAAAP8AAP///wAAAAAAACwAAAAAEAAQAAADMgi63P4w yhmqvVYFwbvnwRAUZGmSlfh9hJBu3eW9bjrcVq125hxiQMtAcSsajZOkcpkAADs= } image create photo mini-filemgr -data { R0lGODdhEAAQAPIAALLA3ICAgMDAwAAAAP///wAAAAAAAAAAACwAAAAAEAAQAAADPggK0f5L BUGraCO+jTX5IDF0S0BY1Bhk5TkMlcpKJyp7qHCXb9+TtNBnR8sRGS5YCog0riJN24zn60Gv 2EUCADs= } image create photo mini-folder -data { R0lGODdhEAAQAPIAALLA3ICAgMDAwP//AAAAAP///wAAAAAAACwAAAAAEAAQAAADOwi63BsQ OhbEsCJMUK/PkcQVZGmSATF+rJWOWHu9QSHHdBHvs1rfnhxvlwO6fKFkSAUgOJ9Q6GZKdSQA ADs= } image create photo mini-font -data { R0lGODdhEAAQAPEAALLA3AAAAICAgAAAACwAAAAAEAAQAAACJ4SPqcvtF8IzMYhXrYuCN95p Cwh4Y2YmoBBequWWIpLKMcIm+cQ3BQA7 } image create photo mini-fractal -data { R0lGODdhEAAQAPIAALLA3AAAAICAgP8AAP//AMDAwACAAAAA/ywAAAAAEAAQAAADSQi63BpB MAHjqvCNQXh4T7V15Fd8gZF24iZpxqBe3hXPALp9j4HzgcMAuBnmLofDK7AL5ZJE1iMJvZQu kFeOZHTQrt4HlxcuexMAOw== } image create photo mini-frame -data { R0lGODdhEAAQAPEAALLA3P8AAAAAAAAAACwAAAAAEAAQAAACM4SPqcGsGISU4YF43V3izrpx IdMlWFRhZqeeD+rFJniWEHu4ptGwNmSQyF4NlQUw+R2PBQA7 } image create photo mini-ftp -data { R0lGODdhEAAQAPEAAICAgP///wAAAAAA/ywAAAAAEAAQAAACNoSPqcEdelwDDwh7w9hN+ItI EhhtphmQhuiolMa1l/eyaQKf3ZzZd3gatHA+l+93+CiVkCagAAA7 } image create photo mini-gball -data { R0lGODdhEAAQAPEAALLA3ACAAP///4CAgCwAAAAAEAAQAAACG4SPqcvtD1mYMAhBncVh6Dl5 Xyc6wxml6so+BQA7 } image create photo mini-go -data { R0lGODdhEAAQAPEAAICAgAAA//8AAP///ywAAAAAEAAQAAACMoSPecEpj8IYzYgJjaTh3JEB zOg9oViVgsK27gtbJ9p52KpN6Rduu4mjpQCmBCmGdBUAADs= } image create photo mini-gopher -data { R0lGODdhEAAQAPIAAICAgICAAIAAAP///wAAAAAAAAAAAAAAACwAAAAAEAAQAAADSQgKESLN LRXAg+41SzO+zbM4Q0mawuQQxECy0ijAGZzKmheOHst+qcvFRwAKQT8joIhkhggK5oywoq4m LFSJNZloB92weExWJAAAOw== } image create photo mini-graph -data { R0lGODdhEAAQAPIAAICAgAAAAP8A/wAA/wD/AP8AAAAAAAAAACwAAAAAEAAQAAADOwi6G86Q CRGindUCV7EGw9BRXzhmlgl4DAeKK8kQRKWyC23Dnqu/J0ChUPndSMNiDRirJDnQKPRDrSoS ADs= } image create photo mini-gv -data { R0lGODdhEAAQAPEAALLA3AAAAP///wAAACwAAAAAEAAQAAACMYSPqcGhGYQU7oE4ZV1ZP0Zp FINgYYhtZjdtF9tyrHussdzRL0yV7e+pNS4kkuUIKAAAOw== } image create photo mini-hammer -data { R0lGODdhEAAQAPEAAL+/vwAAAP///4CAgCwAAAAAEAAQAAACK4SPiRHAr5wQYdqWqt00i6FN TLc0TzA4WAQZq9JG5SurtBzXtn7ktc8L6goAOw== } image create photo mini-happy -data { R0lGODdhEAAQAPEAALLA3AAAAP//AAAAACwAAAAAEAAQAAACM4SPqRDda5qY86VAc70VSxEg WAeO4GFK3xlpbti6GcxU2kjXpbOJFN8TmToQhiNXTCoPBQA7 } image create photo mini-hdisk -data { R0lGODdhEAAQAPIAALLA3ICAgMDAwAAAAACAAP///wAAAAAAACwAAAAAEAAQAAADLgi63P4w yhmqvVYFwbvnwRAUZGmSlfh9hJBu6/e62EWr53nXfKgMwKAwOCkajwkAOw== } image create photo mini-heart -data { R0lGODdhEAAQAPAAAICAgAAAACwAAAAAEAAQAAACIoSPqbvh54KKj0pogb16b+RRSRhNIeMx RqauTwvBoBzTbQEAOw== } image create photo mini-hex -data { R0lGODdhEAAQAPEAAICAgP///wAAAAAA/ywAAAAAEAAQAAACO4SPecHdIBIbjQYQ4qLcQqFh 3FRlS2ChZei0DauSJDtYY20a8qjC6Z/DuFq+0myjulFoydjyAIpKpYACADs= } image create photo mini-hextris -data { R0lGODdhEAAQAPIAALLA3ICAgP//AAAAAP8AAAAAAAAAAAAAACwAAAAAEAAQAAADNAi63P5Q hRlXEHjUSzrR0eANQQUMaLlhAvlM3EhZrNgNtSR4H7qPCttHJXQFUwyU0cRsMhMAOw== } image create photo mini-iconify -data { R0lGODdhEAAOAPEAALLA3P8AAAAAAAAAACwAAAAAEAAOAAACKoyPKSHt7xgDtFoqxd0g8+tV iIYtJHacIWqopgWJ7ydPdGnfUsKn0A8pAAA7 } image create photo mini-icons -data { R0lGODdhEAAQAPIAAICAgP///wAAAAAA/wD/AP8AAP//AAAAACwAAAAAEAAQAAADPAi63BoQ ihfDBGFo+4jnmDaAgUeQImmS1VWBQiwr8uzceL68bvsUQJJhSAIWhESXEWlgRXpPWu0yvega CQA7 } image create photo mini-keyboard -data { R0lGODdhEQAQAPEAAICAgP///wAAAMDAwCwAAAAAEQAQAAACPYSPecHtDgQIqsY5hwiab31R QzQKZRlqwsq2kuTFHQPC2nkPqO32LxZrdGoYnI50gUV8rYul8mL2ntRqogAAOw== } set images1 { apm-alert apm-empty apm-full apm-half apm-loading apm-online apm-unknown folder arch asmail audiovol ball bball } set images2 { bomb book1 book2 books briefcase bug1 bug2 bx2 calc camera cat cave cd cdlabel chinese clipboard clock colors connect crosbone } set images3 { cross desktop dfolder diff diskette display doc doc1 dog edit espada exclam exp eye eyes fax fdisk filemgr font fractal } set images4 { frame ftp gball go gopher graph gv hammer happy hdisk heart hex hextris iconify icons keyboard } proc MakeContainer { count images } { set c .c$count set top .top$count set b .b$count blt::container $c -bd 0 -highlightthickness 0 toplevel $top wm withdraw $top wm protocol $top WM_DELETE_WINDOW "$b invoke" frame $top.f -relief raised -highlightthickness 0 pack $top.f -expand yes -fill x foreach img $images { button $top.f.$img -image mini-$img -bd 1 -command "puts $img" \ -highlightthickness 0 pack $top.f.$img -side left -padx 0 -pady 0 } global $img checkbutton $b -variable $img -onvalue $top -offvalue "" -command \ [subst -nocommands { $c configure -window \$$img }] $b select blt::table . \ $b $count,0 -anchor w \ $c $count,1 -fill x blt::table configure . c0 -resize none blt::table configure . r$count -resize none after 1 [subst { update wm deiconify $top $c configure -window $top }] return $c } MakeContainer 1 $images1 MakeContainer 2 $images2 MakeContainer 3 $images3 MakeContainer 4 $images4 canvas .a blt::table . .a -cspan 40 blt-2.4z.orig/demos/dnd1.tcl0100755000175000017500000001573107240160070014413 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl if { ([info exists tcl_platform]) && ($tcl_platform(platform) == "windows") } { source scripts/send.tcl SendInit SendVerify } proc OnEnter { widget args } { array set info $args $widget configure -highlightbackground red return 1 } proc OnMotion { widget args } { array set info $args set x1 [$widget cget -bd] set x1 20 set y1 $x1 set x2 [expr [winfo width $widget] - $x1] set y2 [expr [winfo height $widget] - $y1] if { ($info(x) >= $x1) && ($info(x) <= $x2) && ($info(y) >= $y1) && ($info(y) <= $y2) } { $widget configure -highlightbackground red return 1 } $widget configure -highlightbackground grey return 0 } proc OnLeave { widget args } { $widget configure -highlightbackground grey return 0 } option add *OnEnter OnEnter option add *OnLeave OnLeave option add *OnMotion OnMotion # ---------------------------------------------------------------------- # This procedure is invoked each time a token is grabbed from the # sample window. It configures the token to display the current # color, and returns the color value that is later passed to the # target handler. # ---------------------------------------------------------------------- proc PackageSample { widget args } { array set info $args set bg [.sample cget -background] set fg [.sample cget -foreground] $info(token).label configure -background $bg -foreground $fg return 1 } proc ShowResult { widget args } { array set info $args puts "drop transaction($info(timestamp)) completed: result was $info(action)" } # ---------------------------------------------------------------------- # Main application window... # ---------------------------------------------------------------------- image create photo openFolder -format gif -data { R0lGODdhEAAOAPIAAP///wAAAH9/f9nZ2f//AAAAAAAAAAAAACwAAAAAEAAOAAADOwgqzPoQ iDjjAoPkIZuTgCZykBCA2ziaXusRrFUGQ5zeRMCcE76xvJBPozuBVCmT0eUKGAHOqFQqqwIS ADs= } label .sample -text "Color" -height 12 -width 20 -bd 2 -relief raised \ -highlightthickness 2 set cursors { { @bitmaps/hand/hand01.xbm bitmaps/hand/hand01m.xbm black white } { @bitmaps/hand/hand02.xbm bitmaps/hand/hand02m.xbm black white } { @bitmaps/hand/hand03.xbm bitmaps/hand/hand03m.xbm black white } { @bitmaps/hand/hand04.xbm bitmaps/hand/hand04m.xbm black white } { @bitmaps/hand/hand05.xbm bitmaps/hand/hand05m.xbm black white } { @bitmaps/hand/hand06.xbm bitmaps/hand/hand06m.xbm black white } { @bitmaps/hand/hand07.xbm bitmaps/hand/hand07m.xbm black white } { @bitmaps/hand/hand08.xbm bitmaps/hand/hand08m.xbm black white } { @bitmaps/hand/hand09.xbm bitmaps/hand/hand09m.xbm black white } { @bitmaps/hand/hand10.xbm bitmaps/hand/hand10m.xbm black white } { @bitmaps/hand/hand11.xbm bitmaps/hand/hand11m.xbm black white } { @bitmaps/hand/hand12.xbm bitmaps/hand/hand12m.xbm black white } { @bitmaps/hand/hand13.xbm bitmaps/hand/hand13m.xbm black white } { @bitmaps/hand/hand14.xbm bitmaps/hand/hand14m.xbm black white } } # Set up the color sample as a drag&drop source and target for "color" values: dnd register .sample -source yes -target yes \ -package PackageSample \ -result ShowResult \ -cursors $cursors dnd getdata .sample color GetColor dnd setdata .sample color SetColor # Establish the appearance of the token window: set token [dnd token window .sample] label $token.label -text "Color" -bd 2 -highlightthickness 1 pack $token.label dnd token configure .sample -borderwidth 2 \ -relief raised -activerelief raised \ -outline pink -fill red \ -anchor s if 1 { scale .redScale -label "Red" -orient horizontal \ -from 0 -to 255 -command adjust_color frame .red -width 20 -height 20 -borderwidth 3 -relief sunken scale .greenScale -label "Green" -orient horizontal \ -from 0 -to 255 -command adjust_color frame .green -width 20 -height 20 -borderwidth 3 -relief sunken scale .blueScale -label "Blue" -orient horizontal \ -from 0 -to 255 -command adjust_color frame .blue -width 20 -height 20 -borderwidth 3 -relief sunken # ---------------------------------------------------------------------- # This procedure loads a new color value into this editor. # ---------------------------------------------------------------------- proc GetColor { widget args } { return [$widget cget -bg] } proc SetColor { widget args } { array set info $args set rgb [winfo rgb . $info(value)] set r [lindex $rgb 0] set g [lindex $rgb 1] set b [lindex $rgb 2] .redScale set [expr round($r/65535.0 * 255)] .greenScale set [expr round($g/65535.0 * 255)] .blueScale set [expr round($b/65535.0 * 255)] } # ---------------------------------------------------------------------- # This procedure is invoked whenever an RGB slider changes to # update the color samples in this display. # ---------------------------------------------------------------------- proc adjust_color {args} { set rval [.redScale get] .red configure -background [format "#%.2x0000" $rval] set gval [.greenScale get] .green configure -background [format "#00%.2x00" $gval] set bval [.blueScale get] .blue configure -background [format "#0000%.2x" $bval] .sample configure -background \ [format "#%.2x%.2x%.2x" $rval $gval $bval] if {$rval+$gval+$bval < 1.5*255} { .sample configure -foreground white } else { .sample configure -foreground black } } table . .redScale 1,0 -fill both table . .red 1,1 -fill both table . .greenScale 2,0 -fill both table . .green 2,1 -fill both table . .blueScale 3,0 -fill both table . .blue 3,1 -fill both } table . .sample 0,0 -columnspan 2 -fill both -pady {0 4} proc random {{max 1.0} {min 0.0}} { global randomSeed set randomSeed [expr (7141*$randomSeed+54773) % 259200] set num [expr $randomSeed/259200.0*($max-$min)+$min] return $num } set randomSeed [clock clicks] .redScale set [expr round([random 255.0])] .blueScale set [expr round([random 255.0])] .greenScale set [expr round([random 255.0])] bind .sample { dnd cancel .sample } focus .sample blt-2.4z.orig/demos/dnd2.tcl0100755000175000017500000002227107240160070014411 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl if { ([info exists tcl_platform]) && ($tcl_platform(platform) == "windows") } { error "This script works only under X11" } canvas .c -width 320 -height 320 -background white blt::table . .c -fill both set lastCell "" set cellWidth 1 set cellHeight 1 proc RedrawWorld { canvas } { global cells cellWidth cellHeight $canvas delete all set width [winfo width $canvas] set height [winfo height $canvas] set cellWidth [expr $width / 8] set cellHeight [expr $height / 8] for { set row 0 } { $row < 8 } { incr row } { set y [expr $row * $cellHeight] set h [expr $y + $cellHeight] for { set column 0 } { $column < 8 } { incr column } { set x [expr $column * $cellWidth] set w [expr $x + $cellWidth] $canvas create rectangle $x $y $w $h -fill white -outline "" \ -tags "$row,$column" } } for { set row 0 } { $row < 8 } { incr row } { set y [expr $row * $cellHeight] $canvas create line 0 $y $width $y } for { set column 0 } { $column < 8 } { incr column } { set x [expr $column * $cellWidth] $canvas create line $x 0 $x $height } foreach name [array names cells] { set rc [split $name ,] set row [lindex $rc 0] set column [lindex $rc 1] set x [expr ($column * $cellWidth) + 5] set y [expr ($row * $cellHeight) + 5] set w [expr $cellWidth - 10] set h [expr $cellHeight - 10] set color [lindex $cells($name) 0] set type [lindex $cells($name) 1] set pi1_2 [expr 3.14159265358979323846/180.0] set points {} switch $type { hexagon { lappend points $x [expr $y + $h/2] [expr $x + $w * 1/3] \ $y [expr $x + $w * 2/3] $y [expr $x + $w] [expr $y + $h/2] \ [expr $x + $w * 2/3] [expr $y + $h] \ [expr $x + $w * 1/3] [expr $y + $h] } parallelogram { lappend points $x [expr $y + $h * 2/3] \ [expr $x + $w * 2/3] $y \ [expr $x + $w] [expr $y + $h * 1/3] \ [expr $x + $w * 1/3] [expr $y + $h] } triangle { lappend points \ $x [expr $y + $h] \ [expr $x + $w * 1/2] $y \ [expr $x + $w] [expr $y + $h] } } eval .c create polygon $points -fill $color -outline black } } bind .c { RedrawWorld %W } # ---------------------------------------------------------------------- # USAGE: random ?? ?? # # Returns a random number in the range to . # If is not specified, the default is 0; if max is not # specified, the default is 1. # ---------------------------------------------------------------------- proc random {{max 1.0} {min 0.0}} { global randomSeed set randomSeed [expr (7141*$randomSeed+54773) % 259200] set num [expr $randomSeed/259200.0*($max-$min)+$min] return $num } set randomSeed [clock clicks] set itemTypes { parallelogram hexagon triangle } set itemTypes { hexagon triangle parallelogram } for { set i 0 } { $i < 20 } { incr i } { while { 1 } { set row [expr int([random 8])] set column [expr int([random 8])] set type [expr int([random 3])] set type [lindex $itemTypes $type] if { ![info exists cells($row,$column)] } { set r [expr int([random 256 128])] set g [expr int([random 256 128])] set b [expr int([random 256 128])] set cells($row,$column) [format "#%.2x%.2x%.2x %s" $r $g $b $type] break } } } proc ScreenToCell { widget x y } { global cellWidth cellHeight set column [expr $x / $cellWidth] set row [expr $y / $cellHeight] return $row,$column } set count 0 foreach i [winfo interps] { puts $i if { [string match "dnd2.tcl*" $i] } { incr count } } if { $count == 1 } { toplevel .info raise .info text .info.text -width 65 -height 12 -font { Helvetica 10 } -bg white \ -tabs { 0.25i } .info.text insert end { This is a more involved example of the new "dnd" command. Run this script again to get another window. You can then drag and drop symbols between the windows by clicking with the left mouse button on a symbol. It demonstates how to o Drag-and-drop on specific areas (canvas items) of a widget. o How to receive and handle Enter/Leave/Motion events in the target. o How to send drag feedback to the source. o Use a drag threshold. } button .info.quit -text "Dismiss" -command { destroy .info } blt::table .info \ 0,0 .info.text -fill both \ 1,0 .info.quit } # ----------------------------------------------------------------- # # Setup finished. Start of drag-and-drop code here. # # Set up the entire canvas as a drag&drop source. dnd register .c -source yes -dragthreshold 5 -button 1 # Register code to pick up the information about a canvas item dnd getdata .c color GetColor proc GetColor { widget args } { array set info $args global itemInfo set id $itemInfo($info(timestamp)) set color [$widget itemcget $id -fill] set ncoords [llength [$widget coords $id]] if { $ncoords == 6 } { set type triangle } elseif { $ncoords == 8 } { set type parallelogram } elseif { $ncoords == 12 } { set type hexagon } else { error "unknown type n=$ncoords" } return [list $color $type] } dnd configure .c -package PackageSample proc PackageSample { widget args } { array set info $args # Check if we're over a canvas item set items [$widget find overlapping $info(x) $info(y) $info(x) $info(y)] set pickedItem "" foreach i $items { if { [$widget type $i] == "polygon" } { set pickedItem $i break } } if { $pickedItem == "" } { # Cancel the drag puts "Cancel the drag x=$info(x) y=$info(y)" return 0 } set fill [$widget itemcget $pickedItem -fill] set outline [$widget itemcget $pickedItem -outline] set ncoords [llength [$widget coords $pickedItem]] if { $ncoords == 6 } { set type triangle } elseif { $ncoords == 8 } { set type parallelogram } elseif { $ncoords == 12 } { set type hexagon } else { error "unknown type n=$ncoords" } set tag [ScreenToCell $widget $info(x) $info(y)] $info(token).label configure -background $fill -foreground $outline \ -text $type update idletasks update global itemInfo set itemInfo($info(timestamp)) $pickedItem return 1 } # Configure a set of animated cursors. dnd configure .c -cursors { { @bitmaps/hand/hand01.xbm bitmaps/hand/hand01m.xbm black white } { @bitmaps/hand/hand02.xbm bitmaps/hand/hand02m.xbm black white } { @bitmaps/hand/hand03.xbm bitmaps/hand/hand03m.xbm black white } { @bitmaps/hand/hand04.xbm bitmaps/hand/hand04m.xbm black white } { @bitmaps/hand/hand05.xbm bitmaps/hand/hand05m.xbm black white } { @bitmaps/hand/hand06.xbm bitmaps/hand/hand06m.xbm black white } { @bitmaps/hand/hand07.xbm bitmaps/hand/hand07m.xbm black white } { @bitmaps/hand/hand08.xbm bitmaps/hand/hand08m.xbm black white } { @bitmaps/hand/hand09.xbm bitmaps/hand/hand09m.xbm black white } { @bitmaps/hand/hand10.xbm bitmaps/hand/hand10m.xbm black white } { @bitmaps/hand/hand11.xbm bitmaps/hand/hand11m.xbm black white } { @bitmaps/hand/hand12.xbm bitmaps/hand/hand12m.xbm black white } { @bitmaps/hand/hand13.xbm bitmaps/hand/hand13m.xbm black white } { @bitmaps/hand/hand14.xbm bitmaps/hand/hand14m.xbm black white } } # Create a widget to place in the drag-and-drop token set token [dnd token window .c] label $token.label -bd 2 -highlightthickness 1 pack $token.label dnd token configure .c \ -borderwidth 2 \ -relief raised -activerelief raised \ -outline pink -fill red \ -anchor s dnd configure .c -target yes dnd setdata .c color { NewObject } proc NewObject { widget args } { array set info $args set tag [ScreenToCell $widget $info(x) $info(y)] global cells if { [info exists cells($tag)] } { error "Cell already exists" } set cells($tag) $info(value) RedrawWorld $widget } dnd configure .c -onmotion OnMotion -onenter OnMotion -onleave OnMotion proc OnMotion { widget args } { global cells lastCell array set info $args set tag [ScreenToCell $widget $info(x) $info(y)] if { $lastCell != "" } { $widget itemconfigure $lastCell -fill white -outline "" -width 1 \ -stipple "" } # Check that we're not over a canvas item if { ![info exists cells($tag)] } { $widget itemconfigure $tag -outline lightblue -fill lightblue \ -width 2 -stipple BLT set lastCell $tag return 1 } return 0 } blt-2.4z.orig/demos/dragdrop1.tcl0100755000175000017500000001041507440122334015445 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl if { ([info exists tcl_platform]) && ($tcl_platform(platform) == "windows") } { source scripts/send.tcl SendInit SendVerify } # ---------------------------------------------------------------------- # This procedure is invoked each time a token is grabbed from the # sample window. It configures the token to display the current # color, and returns the color value that is later passed to the # target handler. # ---------------------------------------------------------------------- proc package_color {token} { set bg [.sample cget -background] set fg [.sample cget -foreground] $token.label configure -background $bg -foreground $fg return $bg } # ---------------------------------------------------------------------- # Main application window... # ---------------------------------------------------------------------- label .sample -text "Color" -height 2 -bd 10 -relief sunken # # Set up the color sample as a drag&drop source for "color" values: # drag&drop source .sample \ -packagecmd {package_color %t} \ -sitecmd { puts "%s %t" } drag&drop source .sample handler color # # Set up the color sample as a drag&drop target for "color" values: # drag&drop target .sample handler color {set_color %v} # # Establish the appearance of the token window: # set token [drag&drop token .sample] label $token.label -text "Color" pack $token.label scale .redScale -label "Red" -orient horizontal \ -from 0 -to 255 -command adjust_color frame .redSample -width 20 -height 20 -borderwidth 3 -relief sunken scale .greenScale -label "Green" -orient horizontal \ -from 0 -to 255 -command adjust_color frame .greenSample -width 20 -height 20 -borderwidth 3 -relief sunken scale .blueScale -label "Blue" -orient horizontal \ -from 0 -to 255 -command adjust_color frame .blueSample -width 20 -height 20 -borderwidth 3 -relief sunken # ---------------------------------------------------------------------- # This procedure loads a new color value into this editor. # ---------------------------------------------------------------------- proc set_color {cval} { set rgb [winfo rgb . $cval] set rval [expr round([lindex $rgb 0]/65535.0*255)] .redScale set $rval set gval [expr round([lindex $rgb 1]/65535.0*255)] .greenScale set $gval set bval [expr round([lindex $rgb 2]/65535.0*255)] .blueScale set $bval } # ---------------------------------------------------------------------- # This procedure is invoked whenever an RGB slider changes to # update the color samples in this display. # ---------------------------------------------------------------------- proc adjust_color {args} { set rval [.redScale get] .redSample configure -background [format "#%.2x0000" $rval] set gval [.greenScale get] .greenSample configure -background [format "#00%.2x00" $gval] set bval [.blueScale get] .blueSample configure -background [format "#0000%.2x" $bval] .sample configure -background \ [format "#%.2x%.2x%.2x" $rval $gval $bval] if {$rval+$gval+$bval < 1.5*255} { .sample configure -foreground white } else { .sample configure -foreground black } } table . .sample 0,0 -columnspan 2 -fill both -pady {0 4} table . .redScale 1,0 -fill both table . .redSample 1,1 -fill both table . .greenScale 2,0 -fill both table . .greenSample 2,1 -fill both table . .blueScale 3,0 -fill both table . .blueSample 3,1 -fill both blt-2.4z.orig/demos/dragdrop2.tcl0100755000175000017500000001315107440122334015446 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl if { ([info exists tcl_platform]) && ($tcl_platform(platform) == "windows") } { source scripts/send.tcl SendInit SendVerify } # ---------------------------------------------------------------------- # This procedure is invoked each time a token is grabbed from the # sample window. It configures the token to display the current # color, and returns the color value that is later passed to the # target handler. # ---------------------------------------------------------------------- proc package_color {token} { set bg [.sample cget -background] set fg [.sample cget -foreground] $token.label configure -text "Color" -background $bg -foreground $fg return $bg } # ---------------------------------------------------------------------- # This procedure is invoked each time a token is grabbed from an # entry widget. It configures the token to display the current # string, and returns the string that is later passed to the target # handler. # ---------------------------------------------------------------------- proc package_string {str token} { if {[string length $str] > 20} { set mesg "[string range $str 0 19]..." } else { set mesg $str } $token.label configure -text $mesg return $str } # ---------------------------------------------------------------------- # Main application window... # ---------------------------------------------------------------------- label .sample -text "Color" -height 2 -borderwidth 3 -relief sunken # # Set up the color sample as a drag&drop source for "color" values # and "string" values # drag&drop source .sample -packagecmd {package_color %t} drag&drop source .sample handler color drag&drop source .sample handler string # # Set up the color sample as a drag&drop target for "color" values: # drag&drop target .sample handler color {set_color %v} # # Establish the appearance of the token window: # set token [drag&drop token .sample -activebackground yellow ] label $token.label -text "Color" pack $token.label scale .redScale -label "Red" -orient horizontal \ -from 0 -to 255 -command adjust_color frame .redSample -width 20 -height 20 -borderwidth 3 -relief sunken scale .greenScale -label "Green" -orient horizontal \ -from 0 -to 255 -command adjust_color frame .greenSample -width 20 -height 20 -borderwidth 3 -relief sunken scale .blueScale -label "Blue" -orient horizontal \ -from 0 -to 255 -command adjust_color frame .blueSample -width 20 -height 20 -borderwidth 3 -relief sunken frame .color label .color.label -text "Color:" pack .color.label -side left entry .color.value -width 10 pack .color.value -side left -expand yes -fill both bind .color.value {set_color [%W get]} # # Set up the entry widget as a drag&drop source for "string" values: # drag&drop source .color.value \ -packagecmd {package_string [%W get] %t} \ -selftarget yes drag&drop source .color.value handler string # # Set up the entry widget as a drag&drop target for "string" values: # drag&drop target .color.value handler string { %W delete 0 end %W insert 0 "%v" } # # Establish the appearance of the token window: # set token [drag&drop token .color.value] label $token.label pack $token.label # ---------------------------------------------------------------------- # This procedure loads a new color value into this editor. # ---------------------------------------------------------------------- proc set_color {cval} { set rgb [winfo rgb . $cval] set rval [expr round([lindex $rgb 0]/65535.0*255)] .redScale set $rval set gval [expr round([lindex $rgb 1]/65535.0*255)] .greenScale set $gval set bval [expr round([lindex $rgb 2]/65535.0*255)] .blueScale set $bval } # ---------------------------------------------------------------------- # This procedure is invoked whenever an RGB slider changes to # update the color samples in this display. # ---------------------------------------------------------------------- proc adjust_color {args} { set rval [.redScale get] .redSample configure -background [format "#%.2x0000" $rval] set gval [.greenScale get] .greenSample configure -background [format "#00%.2x00" $gval] set bval [.blueScale get] .blueSample configure -background [format "#0000%.2x" $bval] .sample configure -background \ [format "#%.2x%.2x%.2x" $rval $gval $bval] if {$rval+$gval+$bval < 1.5*255} { .sample configure -foreground white } else { .sample configure -foreground black } } table . \ 0,0 .sample -columnspan 2 -pady {0 4} \ 1,0 .color -columnspan 2 -padx 4 -pady 4 \ 2,0 .redScale \ 2,1 .redSample \ 3,0 .greenScale \ 3,1 .greenSample \ 4,0 .blueScale \ 4,1 .blueSample eval table configure . [winfo children .] -fill both blt-2.4z.orig/demos/eps.tcl0100755000175000017500000001543707240160070014357 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl bltdebug watch ResizeEpsItem proc MoveEpsItem { canvas tagName x y } { global lastX lastY $canvas move $tagName [expr $x - $lastX] [expr $y - $lastY] set lastX $x; set lastY $y } proc GetEpsBBox { canvas tagName } { global left top right bottom set anchor [$canvas coords $tagName-image] set left [lindex $anchor 0] set top [lindex $anchor 1] set width [$canvas itemcget $tagName-image -width] set height [$canvas itemcget $tagName-image -height] set right [expr $left + $width] set bottom [expr $top + $height] } proc SaveImageCoords { canvas x y } { global lastX lastY set lastX $x set lastY $y $canvas configure -cursor sb_h_double_arrow } array set cursors { sw bottom_left_corner ne top_right_corner se bottom_right_corner nw top_left_corner } proc StartResize { canvas tagName x y anchor } { global left top right bottom image GetEpsBBox $canvas $tagName $canvas itemconfigure $tagName-image -quick yes $canvas itemconfigure $tagName-grip -fill red $canvas create line $left $top $right $bottom \ -tags "$tagName $tagName-cross $tagName-l1" \ -fill red -width 2 $canvas create line $left $bottom $right $top \ -tags "$tagName $tagName-cross $tagName-l2" \ -fill red -width 2 $canvas raise $tagName-grip global cursors $canvas configure -cursor $cursors($anchor) global lastX lastY set lastX $x set lastY $y } proc EndResize { canvas tagName x y anchor } { $canvas itemconfigure $tagName-image -quick no \ -showimage yes ResizeEpsItem $canvas $anchor $tagName $x $y $canvas itemconfigure $tagName-grip -fill green $canvas delete $tagName-cross $canvas configure -cursor "" } proc ResetGrips { canvas tagName } { global gripSize global left top right bottom GetEpsBBox $canvas $tagName $canvas coords $tagName-nw \ $left $top [expr $left + $gripSize] [expr $top + $gripSize] $canvas coords $tagName-se \ [expr $right - $gripSize] [expr $bottom - $gripSize] $right $bottom $canvas coords $tagName-ne \ [expr $right - $gripSize] [expr $top + $gripSize] $right $top $canvas coords $tagName-sw \ $left $bottom [expr $left + $gripSize] [expr $bottom - $gripSize] $canvas coords $tagName-l1 $left $top $right $bottom $canvas coords $tagName-l2 $left $bottom $right $top } proc ResizeEpsItem { canvas anchor tagName x y } { global lastX lastY left top right bottom GetEpsBBox $canvas $tagName switch $anchor { sw { set left $x ; set bottom $y set cursor bottom_left_corner } ne { set right $x ; set top $y set cursor top_right_corner } se { set right $x ; set bottom $y set cursor bottom_right_corner } nw { set left $x ; set top $y set cursor top_left_corner } default { error "anchor can't be $anchor" } } set w [expr $right - $left] set h [expr $bottom - $top] set options "" if { $w > 1 } { append options "-width $w " } if { $h > 1 } { append options "-height $h " } $canvas coords $tagName-image $left $top eval $canvas itemconfigure $tagName-image $options GetEpsBBox $canvas $tagName ResetGrips $canvas $tagName } set numGroups 0 set id 0 proc MakeEps { canvas {epsFile ""} {imageFile ""} } { global numGroups id gripSize image # set image [image create photo -width 200 -height 200] # if { $imageFile != "" } { # $image configure -file $imageFile # } set tagName "epsGroup[incr numGroups]" $canvas create eps 20 20 \ -anchor nw \ -borderwidth 4 \ -tags "$tagName $tagName-image" \ -titlecolor white \ -titlerotate 90 \ -titleanchor nw \ -font *helvetica*24* \ -stipple BLT \ -outline orange4 \ -fill orange \ -file $epsFile \ # -image $image set gripSize 8 GetEpsBBox $canvas $tagName global left top right bottom $canvas create rectangle \ $left $top [expr $left + $gripSize] [expr $top + $gripSize] \ -tags "$tagName $tagName-grip $tagName-nw" \ -fill red -outline "" $canvas create rectangle \ [expr $right - $gripSize] [expr $bottom - $gripSize] $right $bottom \ -tags "$tagName $tagName-grip $tagName-se" \ -fill red -outline "" $canvas create rectangle \ [expr $right - $gripSize] [expr $top + $gripSize] $right $top \ -tags "$tagName $tagName-grip $tagName-ne" \ -fill red -outline "" $canvas create rectangle \ $left $bottom [expr $left + $gripSize] [expr $bottom - $gripSize] \ -tags "$tagName $tagName-grip $tagName-sw" \ -fill red -outline "" $canvas bind $tagName \ "$canvas configure -cursor {}" $canvas bind $tagName-image \ "SaveImageCoords $canvas %x %y" $canvas bind $tagName-image \ "MoveEpsItem $canvas $tagName %x %y" foreach grip { sw ne se nw } { $canvas bind $tagName-$grip \ "StartResize $canvas $tagName %x %y $grip" $canvas bind $tagName-$grip \ "ResizeEpsItem $canvas $grip $tagName %x %y" $canvas bind $tagName-$grip \ "EndResize $canvas $tagName %x %y $grip" $canvas raise $tagName-$grip } } source scripts/stipples.tcl # # Script to test the BLT "eps" canvas item. # canvas .layout -bg white button .print -text "Print" -command { wm iconify . update .layout postscript -file eps.ps wm deiconify . update } button .quit -text "Quit" -command { exit 0 } table . \ 0,0 .layout -fill both -cspan 2 \ 1,0 .print \ 1,1 .quit \ table configure . r1 -resize none foreach file { ./images/out.ps xy.ps test.ps } { if { [file exists $file] } { MakeEps .layout $file } } .layout create rectangle 10 10 50 50 -fill blue -outline white .layout create text 200 200 \ -text "This is a text item" \ -fill yellow \ -anchor w \ -font *helvetica*24* .layout create rectangle 50 50 150 150 -fill green -outline red wm colormapwindows . .layout .layout configure -scrollregion [.layout bbox all] blt-2.4z.orig/demos/graph1.tcl0100755000175000017500000001005007543540145014747 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl if { [winfo screenvisual .] != "staticgray" } { option add *print.background yellow option add *quit.background red set image [image create photo -file ./images/rain.gif] option add *Graph.Tile $image option add *Label.Tile $image option add *Frame.Tile $image option add *Htext.Tile $image option add *TileOffset 0 } set graph [graph .g] htext .header \ -text {\ This is an example of the graph widget. It displays two-variable data with assorted line attributes and symbols. To create a postscript file "xy.ps", press the %% button $htext(widget).print -text print -command { puts stderr [time { blt::busy hold . update .g postscript output demo1.eps update blt::busy release . update }] } $htext(widget) append $htext(widget).print %% button.} source scripts/graph1.tcl htext .footer \ -text {Hit the %% button $htext(widget).quit -text quit -command { exit } $htext(widget) append $htext(widget).quit %% button when you've seen enough.%% label $htext(widget).logo -bitmap BLT $htext(widget) append $htext(widget).logo -padx 20 %%} proc MultiplexView { args } { eval .g axis view y $args eval .g axis view y2 $args } scrollbar .xbar \ -command { .g axis view x } \ -orient horizontal -relief flat \ -highlightthickness 0 -elementborderwidth 2 -bd 0 scrollbar .ybar \ -command MultiplexView \ -orient vertical -relief flat -highlightthickness 0 -elementborderwidth 2 table . \ 0,0 .header -cspan 3 -fill x \ 1,0 .g -fill both -cspan 3 -rspan 3 \ 2,3 .ybar -fill y -padx 0 -pady 0 \ 4,1 .xbar -fill x \ 5,0 .footer -cspan 3 -fill x table configure . c3 r0 r4 r5 -resize none .g postscript configure \ -center yes \ -maxpect yes \ -landscape no \ -preview yes .g axis configure x \ -scrollcommand { .xbar set } \ -scrollmax 10 \ -scrollmin 2 .g axis configure y \ -scrollcommand { .ybar set } .g axis configure y2 \ -scrollmin 0.0 -scrollmax 1.0 \ -hide no \ -title "Y2" .g legend configure \ -activerelief flat \ -activeborderwidth 1 \ -position top -anchor ne .g pen configure "activeLine" \ -showvalues y .g element bind all { %W legend activate [%W element get current] } .g configure -plotpady { 1i 0 } .g element bind all { %W legend deactivate [%W element get current] } .g axis bind all { set axis [%W axis get current] %W axis configure $axis -background lightblue2 } .g axis bind all { set axis [%W axis get current] %W axis configure $axis -background "" } .g configure -leftvariable left trace variable left w "UpdateTable .g" proc UpdateTable { graph p1 p2 how } { table configure . c0 -width [$graph extents leftmargin] table configure . c2 -width [$graph extents rightmargin] table configure . r1 -height [$graph extents topmargin] table configure . r3 -height [$graph extents bottommargin] } set image2 [image create photo -file images/blt98.gif] .g element configure line2 -areapattern @bitmaps/sharky.xbm \ # -areaforeground blue -areabackground "" .g element configure line3 -areatile $image2 .g configure -title [pwd] blt-2.4z.orig/demos/graph2.tcl0100755000175000017500000000770007536461660014766 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl source scripts/stipples.tcl if { ![string match "*gray*" [winfo screenvisual .]] } { option add *Button.Background red option add *TextMarker.Foreground black option add *TextMarker.Background yellow option add *LineMarker.Foreground black option add *LineMarker.Background yellow option add *PolyMarker.Fill yellow2 option add *PolyMarker.Outline "" option add *PolyMarker.Stipple bdiagonal1 option add *activeLine.Color red4 option add *activeLine.Fill red2 option add *Element.Color purple } set data { R0lGODlhEAANAMIAAAAAAH9/f///////AL+/vwAA/wAAAAAAACH5BAEAAAUALAAAAAAQAA0A AAM8WBrM+rAEQWmIb5KxiWjNInCkV32AJHRlGQBgDA7vdN4vUa8tC78qlrCWmvRKsJTquHkp ZTKAsiCtWq0JADs= } set data { R0lGODlhEAANAMIAAAAAAH9/f///////AL+/vwAA/wAAAAAAACH5BAEAAAUALAAAAAAQAA0A AAM1WBrM+rAEMigJ8c3Kb3OSII6kGABhp1JnaK1VGwjwKwtvHqNzzd263M3H4n2OH1QBwGw6 nQkAOw== } set image [image create photo -format gif -data $data] set graph [graph .g] table . \ 0,0 $graph -fill both source scripts/graph2.tcl $graph postscript configure \ -maxpect yes \ -landscape yes $graph configure \ -width 5i \ -height 5i $graph axis configure x \ -title "X Axis" if 1 { $graph element configure line1 \ -areapattern solid -areaforeground green # -areatile $image $graph element configure line3 \ -areapattern @bitmaps/sharky.xbm \ -areaforeground red \ -areabackground "" -areapattern solid } set fileName testImg.jpg if { [file exists $fileName] } { set image [image create photo] winop readjpeg $fileName $image if 1 { puts stderr [time { $graph marker create image -image $image \ -coords "-360.0 -1.0 360.0 1.0" \ -under yes \ -mapx degrees \ -name $fileName }] } } bind $graph { MakeSnapshot } bind $graph { %W postscript output demo2.ps %W snap -format emf demo2.emf } set unique 0 proc MakeSnapshot {} { update idletasks global unique set top ".snapshot[incr unique]" set im [image create photo] $graph snap $im 210 150 toplevel $top wm title $top "Snapshot \#$unique of \"[$graph cget -title]\"" label $top.lab -image $im button $top.but -text "Dismiss" -command "DestroySnapshot $top" table $top $top.lab table $top $top.but -pady 4 focus $top.but } proc DestroySnapshot { win } { set im [$win.lab cget -image] $im write test.ppm image delete $im destroy $win exit } if { $tcl_platform(platform) == "windows" } { if 0 { set name [lindex [blt::printer names] 0] set printer {Lexmark Optra E310} blt::printer open $printer blt::printer getattrs $printer attrs puts $attrs(Orientation) set attrs(Orientation) Landscape set attrs(DocumentName) "This is my print job" blt::printer setattrs $printer attrs blt::printer getattrs $printer attrs puts $attrs(Orientation) after 5000 { $graph print2 $printer blt::printer close $printer } } else { after 5000 { $graph print2 } } if 1 { after 2000 {$graph snap -format emf CLIPBOARD} } } blt-2.4z.orig/demos/graph3.tcl0100755000175000017500000000561207526141335014760 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl source scripts/stipples.tcl set visual [winfo screenvisual .] if { $visual != "staticgray" && $visual != "grayscale" } { option add *Button.Background red option add *TextMarker.Foreground black option add *TextMarker.Background yellow option add *LineMarker.Foreground black option add *LineMarker.Background yellow option add *PolyMarker.Fill yellow2 option add *PolyMarker.Outline "" option add *PolyMarker.Stipple fdiagonal1 option add *activeLine.Color red4 option add *activeLine.Fill red2 option add *Element.Color purple } image create photo bgTexture \ -file ./images/chalk.gif option add *Tile bgTexture option add *Button.Tile "" option add *Text.font -*-times*-bold-r-*-*-18-*-* option add *header.font -*-times*-medium-r-*-*-18-*-* option add *footer.font -*-times*-medium-r-*-*-18-*-* option add *HighlightThickness 0 set graph [graph .g] source scripts/graph3.tcl text .header \ -wrap word \ -width 0 \ -height 3 set text { This is an example of a bitmap marker. Try zooming in on a region by clicking the left button, moving the pointer, and clicking again. Notice that the bitmap scales too. To restore the last view, click on the right button. } regsub -all "\n" $text "" text .header insert end "$text\n" .header configure -state disabled htext .footer -text {Hit the %% set im [image create photo -file ./images/stopsign.gif] button $htext(widget).quit -image $im -command { exit } $htext(widget) append $htext(widget).quit %% button when you've seen enough. %% label $htext(widget).logo -bitmap BLT $htext(widget) append $htext(widget).logo %%} table . \ .header 0,0 -fill x -padx 4 -pady 4\ $graph 1,0 -fill both \ .footer 2,0 -fill x -padx 4 -pady 4 table configure . r0 r2 -resize none source scripts/ps.tcl bind $graph { MakePsLayout $graph } if 0 { set printer [printer open [lindex [printer names] 0]] after 2000 { $graph print2 $printer } } #after 2000 { # PsDialog $graph #} blt-2.4z.orig/demos/graph4.tcl0100755000175000017500000040530507454237612014770 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl set tcl_precision 15 set graph .graph image create photo bgTexture -file ./images/chalk.gif option add *default normal option add *Button.tile bgTexture option add *Htext.font -*-times*-bold-r-*-*-18-*-* option add *Text.font -*-times*-bold-r-*-*-18-*-* option add *header.font -*-times*-medium-r-*-*-18-*-* option add *footer.font -*-times*-medium-r-*-*-18-*-* option add *Graph.relief raised #option add *Graph.borderWidth 2 option add *Graph.Legend.activeBackground white option add *Graph.height 5i option add *Graph.plotBackground black option add *Graph.width 7i option add *Graph.tile bgTexture option add *Graph.halo 0 option add *Graph.title "s27.out" option add *Graph.font -*-helvetica-bold-r-*-*-18-* option add *Axis.tickFont -*-courier-medium-r-*-*-12-* option add *Axis.titleFont -*-helvetica-bold-r-*-*-14-* option add *Axis.titleColor red2 option add *x.title "Time" option add *y.title "Signals" option add *Crosshairs.Color white option add *activeLine.Fill navyblue option add *activeLine.LineWidth 2 option add *Element.ScaleSymbols yes option add *Element.Smooth natural option add *Symbol square option add *Element.LineWidth 1 option add *Pen.LineWidth 1 option add *Pixels 1 option add *Grid.color grey50 option add *Grid.dashes "2 4" option add *Grid.hide no option add *Legend.ActiveRelief sunken option add *Legend.Position right option add *Legend.Relief flat option add *Legend.font -*-lucida-medium-r-*-*-12-*-*-*-*-*-*-* option add *Legend.Pad 0 option add *Legend.hide no option add *LineMarker.Dashes 5 option add *LineMarker.Foreground white option add *zoomOutline.outline yellow option add *TextMarker.Background {} option add *TextMarker.Foreground white vector create x -variable "" for { set i 1 } { $i <= 39 } { incr i } { vector create "v$i" -variable "" } x set { 0 1e-10 2e-10 3e-10 4e-10 5e-10 6e-10 7e-10 8e-10 9e-10 1e-09 1.1e-09 1.2e-09 1.3e-09 1.4e-09 1.5e-09 1.6e-09 1.7e-09 1.8e-09 1.9e-09 2e-09 2.1e-09 2.2e-09 2.3e-09 2.4e-09 2.5e-09 2.6e-09 2.7e-09 2.8e-09 2.9e-09 3e-09 3.1e-09 3.2e-09 3.3e-09 3.4e-09 3.5e-09 3.6e-09 3.7e-09 3.8e-09 3.9e-09 4e-09 4.1e-09 4.2e-09 4.3e-09 4.4e-09 4.5e-09 4.6e-09 4.7e-09 4.8e-09 4.9e-09 5e-09 5.1e-09 5.2e-09 5.3e-09 5.4e-09 5.5e-09 5.6e-09 5.7e-09 5.8e-09 5.9e-09 6e-09 6.1e-09 6.2e-09 6.3e-09 6.4e-09 6.5e-09 6.6e-09 6.7e-09 6.8e-09 6.9e-09 7e-09 7.1e-09 7.2e-09 7.3e-09 7.4e-09 7.5e-09 7.6e-09 7.7e-09 7.8e-09 7.9e-09 8e-09 8.1e-09 8.2e-09 8.3e-09 8.4e-09 8.5e-09 8.6e-09 8.7e-09 8.8e-09 8.9e-09 9e-09 9.1e-09 9.2e-09 9.3e-09 9.4e-09 9.5e-09 9.6e-09 9.7e-09 9.8e-09 9.9e-09 1e-08 1.01e-08 1.02e-08 1.03e-08 1.04e-08 1.05e-08 1.06e-08 1.07e-08 1.08e-08 1.09e-08 1.1e-08 1.11e-08 1.12e-08 1.13e-08 1.14e-08 1.15e-08 1.16e-08 1.17e-08 1.18e-08 1.19e-08 1.2e-08 1.21e-08 1.22e-08 1.23e-08 1.24e-08 1.25e-08 1.26e-08 1.27e-08 1.28e-08 1.29e-08 1.3e-08 1.31e-08 1.32e-08 1.33e-08 1.34e-08 1.35e-08 1.36e-08 1.37e-08 1.38e-08 1.39e-08 1.4e-08 1.41e-08 1.42e-08 1.43e-08 1.44e-08 1.45e-08 1.46e-08 1.47e-08 1.48e-08 1.49e-08 1.5e-08 1.51e-08 1.52e-08 1.53e-08 1.54e-08 1.55e-08 1.56e-08 1.57e-08 1.58e-08 1.59e-08 1.6e-08 1.61e-08 1.62e-08 1.63e-08 1.64e-08 1.65e-08 1.66e-08 1.67e-08 1.68e-08 1.69e-08 1.7e-08 1.71e-08 1.72e-08 1.73e-08 1.74e-08 1.75e-08 1.76e-08 1.77e-08 1.78e-08 1.79e-08 1.8e-08 1.81e-08 1.82e-08 1.83e-08 1.84e-08 1.85e-08 1.86e-08 1.87e-08 1.88e-08 1.89e-08 1.9e-08 1.91e-08 1.92e-08 1.93e-08 1.94e-08 1.95e-08 1.96e-08 1.97e-08 1.98e-08 1.99e-08 2e-08 2.01e-08 2.02e-08 2.03e-08 2.04e-08 2.05e-08 2.06e-08 2.07e-08 2.08e-08 2.09e-08 2.1e-08 2.11e-08 2.12e-08 2.13e-08 2.14e-08 2.15e-08 2.16e-08 2.17e-08 2.18e-08 2.19e-08 2.2e-08 2.21e-08 2.22e-08 2.23e-08 2.24e-08 2.25e-08 2.26e-08 2.27e-08 2.28e-08 2.29e-08 2.3e-08 2.31e-08 2.32e-08 2.33e-08 2.34e-08 2.35e-08 2.36e-08 2.37e-08 2.38e-08 2.39e-08 2.4e-08 2.41e-08 2.42e-08 2.43e-08 2.44e-08 2.45e-08 2.46e-08 2.47e-08 2.48e-08 2.49e-08 2.5e-08 2.51e-08 2.52e-08 2.53e-08 2.54e-08 2.55e-08 2.56e-08 2.57e-08 2.58e-08 2.59e-08 2.6e-08 2.61e-08 2.62e-08 2.63e-08 2.64e-08 2.65e-08 2.66e-08 2.67e-08 2.68e-08 2.69e-08 2.7e-08 2.71e-08 2.72e-08 2.73e-08 2.74e-08 2.75e-08 2.76e-08 2.77e-08 2.78e-08 2.79e-08 2.8e-08 2.81e-08 2.82e-08 2.83e-08 2.84e-08 2.85e-08 2.86e-08 2.87e-08 2.88e-08 2.89e-08 2.9e-08 2.91e-08 2.92e-08 2.93e-08 2.94e-08 2.95e-08 2.96e-08 2.97e-08 2.98e-08 2.99e-08 3e-08 3.01e-08 3.02e-08 3.03e-08 3.04e-08 3.05e-08 3.06e-08 3.07e-08 3.08e-08 3.09e-08 3.1e-08 3.11e-08 3.12e-08 3.13e-08 3.14e-08 3.15e-08 3.16e-08 3.17e-08 3.18e-08 3.19e-08 3.2e-08 3.21e-08 3.22e-08 3.23e-08 3.24e-08 3.25e-08 3.26e-08 3.27e-08 3.28e-08 3.29e-08 3.3e-08 3.31e-08 3.32e-08 3.33e-08 3.34e-08 3.35e-08 3.36e-08 3.37e-08 3.38e-08 3.39e-08 3.4e-08 3.41e-08 3.42e-08 3.43e-08 3.44e-08 3.45e-08 3.46e-08 3.47e-08 3.48e-08 3.49e-08 3.5e-08 3.51e-08 3.52e-08 3.53e-08 3.54e-08 3.55e-08 3.56e-08 3.57e-08 3.58e-08 3.59e-08 3.6e-08 } v1 set { 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 } v2 set { 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 5.32907e-15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 } v3 set { 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 8.88178e-16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 2.13718e-14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 } v4 set { 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 } v5 set { 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 } v6 set { 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 8.88178e-16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 2.13718e-14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 } v7 set { 5 5.16904 4.84159 3.34542 0.317102 0.103304 0.0275721 0.0221534 0.017689 0.0142639 0.0113974 0.00918238 0.00742541 0.00616602 0.00481195 0.00397049 -0.0659889 -0.025671 0.165495 0.986891 3.05229 4.55511 4.91611 4.98192 4.99428 4.99833 4.99095 4.97295 4.95493 4.93428 4.90723 4.94799 4.98584 4.99566 4.99813 4.99907 4.99947 4.99965 4.99976 4.99984 4.99989 4.99992 4.99994 4.99996 4.99998 5.00002 5.00006 5.00002 4.99996 4.99994 4.99999 5.00003 5.00002 5 4.99997 4.99997 4.99997 4.99997 4.99997 4.99996 4.99997 4.99997 4.99998 4.99998 4.99999 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5.16575 4.69986 2.43862 0.0230224 0.035229 -0.0210607 -0.0292766 -0.0172693 -0.00271479 -0.000912251 -0.000349106 -0.000116866 -4.24733e-05 -1.39536e-05 -3.01179e-05 -0.0657192 -0.0204835 0.183378 1.07181 3.118 4.46472 4.84158 4.94795 4.98173 4.99236 4.99762 5.01939 5.0433 5.05332 5.04959 5.03955 5.02851 5.02052 5.01422 5.00965 5.00631 5.00405 5.00248 5.00083 5.00012 5.00209 5.00387 5.00347 4.99917 4.99213 4.98411 4.97521 4.96332 4.94601 4.9304 4.94633 4.97936 4.99264 4.99685 4.99857 4.99925 4.99954 4.9997 4.99973 4.9997 4.99973 4.99979 4.99983 4.99986 4.99988 4.9999 4.9999 4.99992 4.99993 4.99994 4.99995 4.99996 4.99996 4.99997 4.99997 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5.14242 4.76101 3.16003 0.299374 0.0645506 -0.000498424 -2.45108e-05 -2.27986e-05 -5.24401e-05 -4.9884e-05 -4.92491e-05 -2.93354e-05 -3.21402e-05 -2.11851e-05 -3.37925e-05 -0.0657892 -0.020563 0.182582 1.06058 3.12484 4.46552 4.84146 4.95102 4.98556 4.99472 4.99806 4.99909 4.99955 4.99976 4.99994 4.99992 5.00029 4.99967 4.99849 4.99736 4.99884 5.00099 5.00377 5.00215 4.99994 4.99893 4.99788 4.99862 5.00055 5.00134 5.00127 5.00073 5.00039 5.00018 5.00006 5.00001 4.99985 5.00026 5.00018 5.00003 4.99981 4.99985 4.99987 4.99985 4.99982 4.99982 4.99982 4.99983 4.99985 4.99987 4.99989 4.99991 4.99992 4.99994 4.99995 4.99995 4.99994 4.99994 4.99996 4.99999 5.00002 5.00008 5.00009 5.00006 5.00001 5 4.99999 4.99998 4.99997 4.99996 4.99997 4.99997 4.99998 4.99998 4.99999 4.99999 4.99999 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 } v8 set { 5 5.03758 5.04711 4.96911 4.20882 3.96295 4.01117 4.15521 4.2967 4.42274 4.5295 4.6176 4.69014 4.74831 4.7966 4.83537 4.80526 4.787 4.79295 4.88588 5.08978 5.15615 5.10778 5.07718 5.06652 5.08225 4.9744 4.52977 3.77452 2.69426 1.15294 0.245509 0.0981544 0.0567527 0.0367487 0.0252578 0.0180599 0.0133837 0.0101497 0.0078616 0.00620186 0.00499056 0.0041027 0.00344223 0.00295808 0.00260089 0.00229887 0.00200817 0.00176397 0.00160116 0.00147381 0.00134645 0.00125029 0.00116043 0.00107371 0.00101981 0.000965921 0.000912028 0.000858135 0.000804242 0.000761669 0.00072672 0.000691771 0.000656823 0.000621874 0.000588722 0.00057041 0.000552098 0.000533785 0.000515473 0.000497162 0.00047885 0.000460537 0.000442226 0.000423914 0.000405601 0.000388399 0.000378694 0.000368989 0.000359284 0.00034958 0.000339875 0.00033017 0.000320465 0.00031076 0.000301055 0.00029135 0.000282207 0.000276247 0.000270287 0.000264327 0.000258367 0.000252407 0.000246447 0.000240487 0.000234527 0.000228567 0.000222607 0.000217086 0.000213696 0.000210307 0.000206918 0.000203528 0.000200139 0.00019675 0.00019336 0.000189971 0.000186582 0.000183192 0.000179803 0.000176414 0.000173025 0.000169635 0.000166246 0.000162857 0.000159467 0.000156078 0.000152689 0.000149299 0.00014591 0.00014255 0.0316021 0.163272 0.348732 0.603651 0.35745 0.135965 0.0707354 0.0314595 0.0201047 0.00994945 0.00389601 0.00138839 0.00060778 0.000329648 0.000492396 -0.0732035 -0.0844077 -0.0789062 -0.0390837 0.0197559 0.0183094 -0.00180099 -0.0189565 -0.0424144 -0.0735904 -0.0892423 0.285039 1.13702 2.10809 2.95826 3.60164 4.0435 4.35771 4.57254 4.71769 4.81329 4.87534 4.91487 4.94264 4.97375 5.01526 5.06517 5.10154 5.06259 4.89005 4.5787 4.12226 3.46151 2.49023 1.2586 0.32725 0.116753 0.0701865 0.0455509 0.0286914 0.0178176 0.0117599 0.00902715 0.00760583 0.00637745 0.00543811 0.00439377 0.00352448 0.0030151 0.00285771 0.002465 0.00203114 0.00173004 0.0014839 0.00125177 0.00105327 0.000894905 0.000766372 0.000658894 0.000569105 0.000492114 0.000427938 0.000370217 0.000314758 0.000266569 0.000233726 0.000209048 0.000191957 0.000177169 0.000166604 0.000161 0.000157314 0.000143828 0.000130342 0.000116857 0.000103371 8.98855e-05 7.63998e-05 6.29141e-05 5.76583e-05 5.30027e-05 4.8347e-05 4.36913e-05 3.90357e-05 3.438e-05 2.97243e-05 2.72507e-05 2.59083e-05 2.45659e-05 2.32235e-05 2.18811e-05 2.05387e-05 1.91963e-05 1.78539e-05 1.65115e-05 1.51691e-05 1.38267e-05 1.24843e-05 1.11419e-05 9.79954e-06 8.51574e-06 7.69807e-06 6.8804e-06 6.06273e-06 5.24506e-06 0.0287318 0.0317111 -0.0320087 -0.103609 0.0369639 0.0121128 0.00961197 0.00934971 0.00820853 0.00699769 0.00607002 0.00535541 0.00476552 0.00427601 0.00376357 -0.073012 -0.0866964 -0.0809538 -0.038005 0.0277001 0.0188906 0.00614597 0.00373629 0.00489787 0.0146573 0.0191052 0.0151708 0.0124224 0.0105859 0.00879272 0.00729464 0.0070047 0.00449575 -0.00626652 -0.0252417 -0.0147287 0.022538 0.0822905 0.0947372 0.0657516 0.0445506 0.0316753 0.0220971 0.0158101 0.0140971 0.0161498 0.0139876 0.0122447 0.0106994 0.009397 0.00822236 0.00686509 0.00797431 0.00751269 0.00671173 0.00595243 0.00524633 0.00459528 0.00401688 0.00350109 0.00303954 0.00260569 0.00222792 0.00191033 0.00163917 0.00140949 0.00121464 0.0010471 0.000900638 0.000768847 0.000645236 0.000524807 0.000460275 0.000442237 0.000446775 0.000397026 0.000301585 0.000228994 0.000190894 0.000166569 0.000152261 0.000137953 0.000123644 0.000109336 9.50281e-05 8.56557e-05 7.78437e-05 7.00318e-05 6.22198e-05 5.44079e-05 4.87539e-05 4.57761e-05 4.27982e-05 3.98203e-05 3.68425e-05 3.38646e-05 3.08868e-05 2.79089e-05 2.4931e-05 2.19532e-05 1.89753e-05 1.75244e-05 1.64095e-05 1.52946e-05 1.41797e-05 1.30648e-05 1.19499e-05 1.0835e-05 9.72011e-06 8.60521e-06 7.4903e-06 6.5117e-06 6.10334e-06 5.69497e-06 5.2866e-06 4.87824e-06 4.46987e-06 4.06151e-06 3.65314e-06 3.24477e-06 } v9 set { 1.86175 1.99708 2.07867 2.01211 2.43309 3.27194 3.63896 3.90426 4.11074 4.27932 4.41496 4.52543 4.61491 4.68862 4.7479 4.79666 4.72895 4.68886 4.70354 4.81353 5.01568 5.14184 5.10482 5.07362 5.05143 5.03638 5.02323 5.01465 5.00853 5.00383 4.99985 5.00454 5.00652 5.00546 5.00411 5.003 5.00214 5.00151 5.00106 5.00073 5.0005 5.00034 5.00023 5.00015 5.0001 5.00005 5 5.00001 5.00005 5.00005 5.00003 5 4.99998 4.99996 4.99994 4.99995 4.99997 4.99998 5 5.00001 5.00002 5.00002 5.00003 5.00003 5.00003 5.00003 5.00003 5.00003 5.00002 5.00002 5.00001 5.00001 5.00001 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.17392 4.94828 3.78491 1.52079 0.608874 0.244031 0.127087 0.0552995 0.0361032 0.0169025 0.006364 0.00217624 0.000921391 0.000457305 0.000786754 -0.120016 -0.148054 -0.15898 -0.0801463 0.16463 0.174017 0.0799249 0.0318788 0.0129696 0.00483397 0.0025677 0.0042079 0.00350003 0.00178404 -8.72902e-05 -0.00128497 -0.00142213 -0.00130018 -0.00106874 -0.000789207 -0.000824335 -0.00104518 -0.00136799 -0.004366 -0.0102621 -0.0109254 -0.00649259 -0.00194842 0.00029793 0.00148673 0.00221085 0.00228291 0.00185261 0.00139687 0.00148183 0.00562266 0.00844119 0.00754627 0.00657396 0.00591212 0.00539269 0.0049282 0.00448417 0.0040572 0.00363719 0.00320392 0.00279607 0.00243938 0.00211505 0.00182302 0.00156254 0.0013341 0.00113834 0.000971865 0.00082776 0.000706193 0.000602499 0.000515059 0.000441401 0.00037897 0.000325459 0.00028083 0.000242096 0.000207274 0.000176444 0.000150372 0.000126407 0.000103373 9.05522e-05 8.53555e-05 8.63685e-05 9.02593e-05 8.37346e-05 7.72099e-05 7.06852e-05 6.41605e-05 5.76358e-05 5.11112e-05 4.45865e-05 4.08176e-05 3.72497e-05 3.36818e-05 3.01138e-05 2.65459e-05 2.2978e-05 1.94101e-05 1.76154e-05 1.67399e-05 1.58645e-05 1.4989e-05 1.41136e-05 1.32381e-05 1.23626e-05 1.14872e-05 1.06117e-05 9.73629e-06 8.86083e-06 7.98538e-06 7.10993e-06 6.23447e-06 5.44363e-06 5.32578e-06 5.20792e-06 5.09007e-06 4.97222e-06 0.0784323 0.0474527 -0.0764232 -0.151146 0.0615785 0.0144489 0.00974161 0.00947176 0.00849005 0.00728201 0.00630581 0.00554032 0.00487809 0.00441504 0.00384139 -0.118943 -0.149894 -0.161173 -0.0825299 0.171686 0.176912 0.0816085 0.0335236 0.013791 0.0056976 0.00238833 0.00105348 0.000526199 0.00025969 0.000396026 0.000837835 0.00170131 0.00196699 -0.000553314 -0.0061621 -0.0111895 -0.0142698 -0.0124608 -0.00795847 -0.00467822 -0.0043058 -0.00874449 -0.0118584 -0.00871386 -0.00377892 1.95244e-05 0.00218952 0.00325486 0.00386497 0.00422837 0.00446883 0.00447065 0.00486647 0.00547838 0.00565398 0.00559092 0.00538752 0.00507015 0.00466305 0.00420756 0.00373465 0.00328404 0.00287059 0.00250057 0.00216124 0.00184861 0.00156815 0.00134624 0.00117857 0.00103412 0.0008948 0.000761012 0.000619853 0.000462614 0.000319965 0.000287666 0.000356415 0.000379946 0.000339183 0.00027972 0.000252982 0.000226244 0.000199507 0.000172769 0.000146031 0.000130097 0.000117578 0.000105059 9.25401e-05 8.00213e-05 7.11204e-05 6.67061e-05 6.22918e-05 5.78775e-05 5.34632e-05 4.90489e-05 4.46346e-05 4.02203e-05 3.5806e-05 3.13916e-05 2.69773e-05 2.4827e-05 2.31747e-05 2.15225e-05 1.98702e-05 1.8218e-05 1.65658e-05 1.49135e-05 1.32613e-05 1.1609e-05 9.95678e-06 8.50108e-06 7.86765e-06 7.23422e-06 6.60079e-06 5.96736e-06 5.33393e-06 4.7005e-06 4.06707e-06 3.43363e-06 } v10 set { 1.86175 1.99308 2.16619 2.46661 3.09359 3.76864 4.31299 4.65564 4.83425 4.92153 4.96157 4.98063 4.98649 4.99039 4.9945 4.9972 4.96206 4.89882 4.83865 4.83202 4.91016 5.04479 5.06078 5.04827 5.03474 5.0246 5.01639 5.00996 5.00569 5.00239 5.00043 5.00296 5.00437 5.00382 5.00287 5.00208 5.00148 5.00104 5.00073 5.0005 5.00034 5.00023 5.00016 5.00011 5.00008 5.00007 5.00007 5.00004 5 4.99998 4.99998 4.99997 4.99998 4.99999 5 5 5.00001 5.00001 5.00001 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5 5.10081 5.10949 4.98359 5.00733 5.15145 4.37298 2.36126 0.470759 0.0577238 0.0115884 0.00262611 0.000671499 0.000389038 0.000291291 0.000317347 -0.0167823 -0.0158344 -0.0140559 0.0104849 0.0865874 0.107813 0.0524688 0.0214369 0.00876443 0.00341595 0.00170778 0.00259042 0.0022241 0.00118519 1.10217e-06 -0.000784506 -0.000948169 -0.000856256 -0.000696719 -0.000485987 -0.000724787 -0.000981491 -0.001454 -0.00552498 -0.0114992 -0.0105266 -0.00543527 -0.000982798 0.00127356 0.00224212 0.00275439 0.00281098 0.0025471 0.00230368 0.00222576 0.00485522 0.00729453 0.00691796 0.0062615 0.00573987 0.0052688 0.00481185 0.00436934 0.00394326 0.00352712 0.00309978 0.00270038 0.00235335 0.00203742 0.00175256 0.00150067 0.00128126 0.00109323 0.000933619 0.000795113 0.000678182 0.00057843 0.000494345 0.000423609 0.000363821 0.000312766 0.000269856 0.000232389 0.000198382 0.000168126 0.00014267 0.000119293 9.69034e-05 8.5669e-05 8.26828e-05 8.64066e-05 9.26665e-05 8.5454e-05 7.82416e-05 7.10291e-05 6.38167e-05 5.66043e-05 4.93918e-05 4.21794e-05 3.86073e-05 3.53007e-05 3.19941e-05 2.86876e-05 2.5381e-05 2.20744e-05 1.87678e-05 1.70933e-05 1.62648e-05 1.54363e-05 1.46079e-05 1.37794e-05 1.2951e-05 1.21225e-05 1.12941e-05 1.04656e-05 9.63716e-06 8.80871e-06 7.98026e-06 7.1518e-06 6.32335e-06 5.5374e-06 5.08959e-06 4.64178e-06 4.19397e-06 3.74616e-06 0.0438026 0.0242078 -0.0602019 -0.0840866 0.00148461 -0.00292489 0.000442098 0.00219489 0.00281478 0.00290756 0.00277945 0.00263896 0.00240099 0.00223283 0.001947 -0.0153629 -0.0148815 -0.0128673 0.0126017 0.0905161 0.11051 0.0538958 0.022562 0.00935726 0.00397422 0.00172534 0.000790207 0.000416322 0.000191632 0.000469721 0.0009779 0.00192566 0.00200688 -0.0016502 -0.00733932 -0.0128113 -0.0147608 -0.0115456 -0.00668995 -0.00401368 -0.00463908 -0.0101197 -0.0118993 -0.0076276 -0.00262656 0.000813059 0.00264455 0.00350796 0.00399494 0.0043049 0.00451658 0.00444739 0.00503842 0.00559516 0.00568213 0.00556459 0.0053176 0.00496654 0.00454337 0.00408592 0.00362171 0.00317793 0.00277001 0.00240394 0.00207009 0.00176575 0.00149725 0.00129045 0.00114257 0.00101135 0.000871672 0.000723764 0.000580438 0.000427507 0.000296956 0.000281834 0.000376628 0.000412266 0.000367547 0.000295305 0.000264513 0.000233721 0.000202929 0.000172137 0.000141345 0.000124721 0.000112577 0.000100433 8.82893e-05 7.61453e-05 6.75517e-05 6.33609e-05 5.91701e-05 5.49792e-05 5.07884e-05 4.65976e-05 4.24067e-05 3.82159e-05 3.40251e-05 2.98342e-05 2.56434e-05 2.36401e-05 2.21181e-05 2.05961e-05 1.90741e-05 1.75521e-05 1.60301e-05 1.45081e-05 1.29861e-05 1.14641e-05 9.94208e-06 8.59252e-06 7.96439e-06 7.33626e-06 6.70813e-06 6.07999e-06 5.45186e-06 4.82373e-06 4.1956e-06 3.56747e-06 } v11 set { 1.86175 1.73419 1.42874 1.04055 0.943004 0.268275 0.0826455 0.0388346 0.0214104 0.0135431 0.00961322 0.00712846 0.00588262 0.00432397 0.00377774 0.00270134 -0.00393731 -0.00542187 -0.00126596 0.0113777 0.0134522 0.00477056 -0.00211067 -0.00229253 -0.00173355 -0.00122404 -0.00113426 -0.000744931 -0.000520112 -0.000410048 -0.000220439 0.000508104 5.15856e-05 -0.000112593 -0.000118917 -9.57394e-05 -7.15727e-05 -5.11847e-05 -3.58275e-05 -2.47166e-05 -1.68866e-05 -1.14082e-05 -7.66646e-06 -5.12139e-06 -3.63426e-06 -3.01815e-06 -2.64862e-06 -1.4947e-06 -1.91403e-07 -2.5763e-08 -7.73699e-07 -1.52164e-06 -1.07268e-06 -3.81696e-07 2.6727e-07 4.75489e-07 6.83708e-07 8.91926e-07 1.10014e-06 1.30836e-06 1.2482e-06 1.00726e-06 7.66311e-07 5.25364e-07 2.84417e-07 6.27857e-08 7.43904e-10 -6.12979e-08 -1.2334e-07 -1.85382e-07 -2.47423e-07 -3.09465e-07 -3.71507e-07 -4.33549e-07 -4.95591e-07 -5.57633e-07 -6.04571e-07 -5.4944e-07 -4.9431e-07 -4.3918e-07 -3.84049e-07 -3.28919e-07 -2.73789e-07 -2.18659e-07 -1.63528e-07 -1.08398e-07 -5.32678e-08 1.062e-09 5.08502e-08 1.00638e-07 1.50427e-07 2.00215e-07 2.50003e-07 2.99791e-07 3.4958e-07 3.99368e-07 4.49156e-07 4.98944e-07 5.34512e-07 5.01032e-07 4.67553e-07 4.34073e-07 4.00593e-07 3.67113e-07 3.33633e-07 3.00153e-07 2.66674e-07 2.33194e-07 1.99714e-07 1.66234e-07 1.32754e-07 9.92744e-08 6.57945e-08 3.23147e-08 -1.16513e-09 -3.4645e-08 -6.81248e-08 -1.01605e-07 -1.35084e-07 -1.68564e-07 -2.18729e-07 0.0114926 -0.0245378 -0.111828 0.0964775 1.61491 3.22668 4.22041 4.54492 4.82845 4.94868 4.98588 4.99609 4.9981 4.99908 4.99788 4.98395 4.99294 4.99724 5.01939 5.0471 5.00902 4.98194 4.98496 4.99188 4.99623 4.99862 5.00025 4.99974 4.99953 4.99946 4.99958 5.00012 4.99997 4.99992 4.99988 4.99985 4.9998 4.9997 4.9988 4.99806 4.99982 5.00143 5.00159 5.00098 5.00053 5.00028 5.00007 4.99977 4.99992 5.00005 5.00133 5.0009 4.99993 4.99972 4.99975 4.9998 4.99982 4.99983 4.99983 4.99983 4.99983 4.99984 4.99986 4.99987 4.99989 4.9999 4.99991 4.99992 4.99994 4.99995 4.99995 4.99996 4.99997 4.99997 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5.00001 5.00001 5.00001 5.00002 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5.01457 4.99482 4.96561 4.99326 5.03452 5.00424 5.00101 5.00045 5.00004 4.99965 4.99997 4.99994 4.99958 4.99999 4.99936 4.9839 4.99248 4.99717 5.01976 5.04869 5.0087 4.98143 4.98488 4.99199 4.99622 4.9983 4.99928 4.99971 4.99986 5.00031 5.00022 5.00035 5.0001 4.99884 4.99811 4.99803 4.99887 5.00078 5.00151 5.00116 5.00007 4.99843 4.99915 5.00107 5.00168 5.00141 5.00092 5.00055 5.0003 5.00016 5.0001 5.00001 5.00016 5.0002 5.00009 4.99993 4.99975 4.99984 4.99991 4.99991 4.99982 4.99974 4.99974 4.99985 4.99995 4.99999 4.99998 5.00004 5.00013 5.00015 5.00007 4.99988 4.99982 4.99985 4.99995 5.00006 5.0002 5.00025 5.0002 5.00009 5.00006 5.00004 5.00002 5 4.99998 4.99997 4.99998 4.99998 4.99999 4.99999 4.99999 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 } v12 set { 5 5.16975 4.78685 2.94241 0.126698 0.0487004 -0.00422591 -0.00130689 -0.000486756 -0.000195875 -0.000108988 -6.66736e-05 -7.26005e-05 -5.63608e-05 -3.81859e-05 -2.123e-05 -0.0646846 -0.0184474 0.182248 1.06731 3.10988 4.46133 4.84133 4.95113 4.98364 4.99455 4.99694 4.99727 4.9994 4.99975 5.0001 5.00132 5.00089 5.00039 5.00019 5.00011 5.00006 5.00005 5.00004 5.00001 4.99992 4.99992 5.00002 5.00013 5.00017 5.00009 4.99992 4.99991 4.99994 4.99996 4.99998 4.99999 5.00001 5.00004 5.00006 5.00005 5.00004 5.00003 5.00002 5.00001 5 4.99999 4.99999 4.99998 4.99998 4.99997 4.99997 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5.14699 4.78074 3.19424 0.305663 0.0611255 -0.00179951 -0.0012032 0.000405978 0.000989399 0.000445194 0.000191447 8.30476e-05 3.96236e-05 1.91866e-05 1.70665e-05 -0.0655239 -0.0210234 0.1827 1.06848 3.11554 4.46518 4.84212 4.94853 4.98244 4.99434 4.9997 5.00081 5.00009 4.99972 4.99985 4.99974 4.9995 4.99949 4.99958 4.99973 4.99948 4.99914 4.99874 4.99946 5.00309 5.0091 5.01576 5.01835 5.01852 5.0176 5.01625 5.01479 5.01345 5.01264 5.011 5.01092 5.01344 5.01363 5.01289 5.01184 5.01071 5.00956 5.00848 5.00751 5.00663 5.00577 5.00497 5.00427 5.00365 5.0031 5.00264 5.00224 5.00191 5.00163 5.00138 5.00117 5.00099 5.00083 5.00071 5.00061 5.00053 5.00045 5.00037 5.00029 5.00022 5.00019 5.0002 5.00023 5.00024 5.00023 5.00023 5.00022 5.0002 5.00018 5.00016 5.00014 5.00011 5.00009 5.00007 5.00006 5.00005 5.00005 5.00004 5.00003 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5.14298 4.79809 3.32704 0.498385 0.105773 0.0160646 0.0319912 0.0299434 0.0240102 0.0185844 0.0130411 0.0106532 0.00864871 0.00744519 0.00660887 -0.0612913 -0.0203719 0.174998 0.991787 3.06292 4.60005 4.93058 4.98917 5.00033 4.9999 4.99909 4.9966 4.9955 4.99488 4.99374 4.9943 5.00131 5.00506 4.99311 4.96288 4.93567 4.92439 4.94236 4.9732 4.98864 4.99458 5.00031 5.00694 5.01525 5.01945 5.01998 5.01953 5.01874 5.01766 5.0164 5.01509 5.01326 5.01423 5.01455 5.01361 5.01245 5.01122 5.01002 5.00888 5.00783 5.00687 5.00596 5.00514 5.00442 5.00379 5.00325 5.00279 5.0024 5.00208 5.0018 5.00153 5.00126 5.00107 5.00094 5.00085 5.00078 5.00072 5.00063 5.00053 5.00042 5.00038 5.00034 5.0003 5.00027 5.00023 5.00021 5.00019 5.00017 5.00015 5.00013 5.00012 5.00011 5.0001 5.0001 5.00009 5.00008 5.00007 5.00007 5.00006 5.00005 5.00005 5.00004 5.00004 5.00003 5.00003 5.00002 5.00002 5.00002 5.00001 5.00001 5 5 5 5.00001 5.00001 5.00001 5.00002 5.00002 5.00002 5.00002 } v13 set { 9.73784e-10 0.0189926 0.0926769 0.206309 0.111533 0.0953491 0.0426966 0.0214177 0.0117943 0.00741442 0.00528816 0.00398417 0.0032967 0.00266499 0.00206647 0.00158788 -0.0371391 -0.0439528 -0.0408653 -0.0188706 0.0150241 0.0126852 0.00209817 -0.000239206 -5.31488e-05 0.000876324 -0.00451221 -0.0165223 -0.0284127 -0.0427584 -0.0502453 -0.0257366 -0.00903938 -0.00376456 -0.00233385 -0.00169922 -0.00130397 -0.00102542 -0.000811435 -0.000648115 -0.000529266 -0.00043795 -0.00036574 -0.00030716 -0.00026221 -0.000229662 -0.000205112 -0.000181038 -0.000162045 -0.000148988 -0.000137633 -0.000126278 -0.000115562 -0.000104976 -9.49324e-05 -9.0585e-05 -8.62375e-05 -8.18901e-05 -7.75426e-05 -7.31952e-05 -6.93752e-05 -6.59106e-05 -6.24461e-05 -5.89815e-05 -5.55169e-05 -5.22412e-05 -5.05263e-05 -4.88114e-05 -4.70966e-05 -4.53817e-05 -4.36668e-05 -4.19519e-05 -4.0237e-05 -3.85222e-05 -3.68073e-05 -3.50924e-05 -3.34782e-05 -3.25442e-05 -3.16102e-05 -3.06763e-05 -2.97423e-05 -2.88083e-05 -2.78744e-05 -2.69404e-05 -2.60064e-05 -2.50725e-05 -2.41385e-05 -2.32635e-05 -2.27232e-05 -2.21829e-05 -2.16426e-05 -2.11023e-05 -2.0562e-05 -2.00217e-05 -1.94814e-05 -1.89411e-05 -1.84007e-05 -1.78604e-05 -1.73647e-05 -1.70853e-05 -1.68059e-05 -1.65265e-05 -1.62471e-05 -1.59677e-05 -1.56883e-05 -1.54089e-05 -1.51295e-05 -1.48501e-05 -1.45707e-05 -1.42913e-05 -1.40119e-05 -1.37325e-05 -1.34531e-05 -1.31737e-05 -1.28943e-05 -1.26149e-05 -1.23355e-05 -1.20561e-05 -1.17767e-05 -1.14973e-05 -1.10954e-05 0.0152675 0.0228237 -0.00460678 -0.0341525 0.0232109 -0.0138039 -0.0416538 -0.0458764 -0.0201967 -0.00878316 -0.00379173 -0.00164621 -0.000785131 -0.00037575 -0.000352375 -0.0545586 -0.0746881 -0.0771865 -0.05386 -0.0022199 0.0136703 0.00633526 0.00138826 -0.00108934 0.0038886 0.0298077 0.0475776 0.0481003 0.0464167 0.047818 0.042789 0.035207 0.0264423 0.0193959 0.0151614 0.00624257 -0.00913057 -0.0310696 -0.0430238 0.016426 0.189762 0.49025 0.820116 1.13919 1.43549 1.70658 1.95183 2.17414 2.38506 2.5657 2.73958 2.97905 3.21403 3.43025 3.62645 3.8028 3.96002 4.09996 4.22443 4.33427 4.42886 4.51097 4.5817 4.64326 4.6957 4.74132 4.7797 4.81298 4.84102 4.86512 4.88523 4.90224 4.91649 4.92846 4.93868 4.94755 4.95483 4.96114 4.96682 4.97161 4.97502 4.9776 4.97944 4.98141 4.98319 4.98467 4.98585 4.9869 4.98796 4.98902 4.99008 4.99114 4.9922 4.99326 4.9938 4.99429 4.99479 4.99528 4.99578 4.99628 4.99677 4.99704 4.99718 4.99733 4.99747 4.99762 4.99777 4.99791 4.99806 4.9982 4.99835 4.9985 4.99864 4.99879 4.99893 4.99907 4.99916 4.99925 4.99934 4.99943 5.01473 4.92293 4.61974 4.0316 3.7835 3.74195 3.78344 3.87272 3.97386 4.07319 4.16686 4.25256 4.33126 4.40264 4.46697 4.49249 4.51807 4.55803 4.64055 4.78574 4.86074 4.88334 4.8999 4.91455 4.92814 4.93926 4.94761 4.95433 4.95907 4.9654 4.98317 5.0208 5.05134 4.85852 4.16041 3.00077 1.68376 0.672707 0.240838 0.0794725 -0.0106347 -0.00879443 0.107196 0.368163 0.701424 1.03581 1.3601 1.6678 1.95731 2.22701 2.47544 2.69099 2.92327 3.16648 3.3877 3.59067 3.77344 3.93584 4.08066 4.20863 4.32065 4.41791 4.50211 4.57423 4.63614 4.68888 4.73377 4.7721 4.80519 4.83338 4.85732 4.87815 4.89514 4.90927 4.92108 4.93122 4.94014 4.94845 4.95601 4.96251 4.96576 4.969 4.97225 4.9755 4.97874 4.98087 4.98265 4.98442 4.9862 4.98797 4.98924 4.9899 4.99055 4.9912 4.99186 4.99251 4.99316 4.99381 4.99447 4.99512 4.99577 4.99609 4.99634 4.99659 4.99683 4.99708 4.99732 4.99757 4.99782 4.99806 4.99831 4.99853 4.99863 4.99873 4.99883 4.99893 4.99903 4.99913 4.99923 4.99933 } v14 set { 1.86175 2.00147 1.85141 1.0654 0.275481 0.205547 0.0712627 0.0313387 0.0151431 0.00864531 0.00593861 0.00438111 0.0037479 0.00305857 0.00221221 0.0017081 -0.0896128 -0.109079 -0.121356 -0.0542001 0.175821 0.177442 0.0814591 0.0333042 0.0134909 0.00625777 0.00100092 -0.00552776 -0.00411139 -0.00150395 -0.000564784 3.48169e-05 -0.000287014 -0.000538515 -0.000456537 -0.000325677 -0.000275468 -0.000166452 -8.27481e-05 -8.28704e-05 -7.47644e-05 -4.60552e-05 -2.61481e-06 2.26359e-05 2.53852e-05 -1.39853e-06 -4.23456e-05 -4.0907e-05 -2.8501e-05 -1.5945e-05 -9.01122e-06 -2.07747e-06 1.49328e-06 4.38398e-06 6.84248e-06 4.76711e-06 2.69173e-06 6.16362e-07 -1.45901e-06 -3.53438e-06 -4.14256e-06 -3.76238e-06 -3.3822e-06 -3.00202e-06 -2.62184e-06 -2.24878e-06 -1.93456e-06 -1.62033e-06 -1.3061e-06 -9.91867e-07 -6.77638e-07 -3.63409e-07 -4.91792e-08 2.6505e-07 5.7928e-07 8.93509e-07 1.16076e-06 1.11055e-06 1.06034e-06 1.01014e-06 9.59927e-07 9.09719e-07 8.59511e-07 8.09302e-07 7.59094e-07 7.08886e-07 6.58678e-07 5.99251e-07 4.87523e-07 3.75795e-07 2.64068e-07 1.5234e-07 4.06119e-08 -7.1116e-08 -1.82844e-07 -2.94572e-07 -4.063e-07 -5.18027e-07 -6.08517e-07 -5.95879e-07 -5.83241e-07 -5.70604e-07 -5.57966e-07 -5.45328e-07 -5.3269e-07 -5.20053e-07 -5.07415e-07 -4.94777e-07 -4.8214e-07 -4.69502e-07 -4.56864e-07 -4.44226e-07 -4.31589e-07 -4.18951e-07 -4.06313e-07 -3.93676e-07 -3.81038e-07 -3.684e-07 -3.55762e-07 -3.43125e-07 1.06736e-05 0.0797407 0.0437947 -0.0645098 -0.0877312 0.0653203 -0.00621184 -0.0353188 -0.0491378 -0.0251957 -0.0110996 -0.00481123 -0.0020941 -0.000998038 -0.000478747 -0.000445332 -0.102046 -0.135753 -0.154351 -0.0827509 0.163348 0.174012 0.0794822 0.0310624 0.0112213 0.00249061 0.00130764 0.00181315 0.00163875 0.00101454 0.000497435 0.000195258 5.31901e-05 2.4607e-05 6.62736e-05 7.90718e-05 4.0372e-05 -0.000141184 -0.000280623 5.5608e-05 0.000799565 0.000920189 0.000931616 0.000494527 0.000162303 -8.24884e-05 -0.000183938 -0.000203899 -0.000144788 -9.87063e-05 -0.000227929 2.93932e-05 0.000208563 1.88958e-06 -7.6335e-05 -0.000172472 -0.000165656 -0.000145889 -0.000177311 -0.000191058 -0.000168287 -0.00015755 -0.00013142 -8.10488e-05 -6.36115e-05 -7.8699e-05 -8.11282e-05 -7.98625e-05 -5.98807e-05 -3.40879e-05 -1.95464e-05 -1.79247e-05 -4.45514e-05 -7.47995e-05 -8.7682e-05 -7.50806e-05 -3.25561e-05 -4.34114e-05 -7.69099e-05 -0.000141101 -0.00018743 -0.000148471 -5.06546e-05 0.000120195 0.000177635 0.000177052 0.000146344 9.75126e-05 8.31233e-05 6.8734e-05 5.43447e-05 3.99554e-05 2.55661e-05 1.11768e-05 -3.21253e-06 -3.88937e-06 -3.56628e-06 -3.24318e-06 -2.92008e-06 -2.59699e-06 -2.27389e-06 -1.9508e-06 -1.73227e-06 -1.56796e-06 -1.40365e-06 -1.23934e-06 -1.07503e-06 -9.10722e-07 -7.46412e-07 -5.82101e-07 -4.1779e-07 -2.5348e-07 -8.91694e-08 7.51412e-08 2.39452e-07 4.03762e-07 5.95733e-07 1.00771e-06 1.41969e-06 1.83167e-06 2.24365e-06 0.0828257 0.231038 0.465438 1.54516 2.8461 3.19221 3.40395 3.6382 3.80758 3.93848 4.04882 4.15428 4.247 4.32917 4.40235 4.36941 4.397 4.48862 4.64552 4.86595 5.03475 5.0348 5.02627 5.01967 5.01542 5.00925 4.98613 4.9519 4.91581 4.87357 4.82302 4.80403 4.82565 4.86102 4.89483 4.92253 4.94428 4.96257 4.97608 4.98373 4.98823 4.99182 4.99437 4.99635 4.99745 4.99802 4.99843 4.99873 4.99895 4.99912 4.99925 4.99931 4.99962 4.99973 4.99972 4.99971 4.9997 4.99969 4.9997 4.99971 4.99973 4.99974 4.99976 4.99978 4.9998 4.99982 4.99985 4.99987 4.99989 4.9999 4.99991 4.99991 4.99993 4.99994 4.99997 5.00001 5.00006 5.00008 5.00006 5.00002 5 4.99999 4.99998 4.99997 4.99995 4.99995 4.99995 4.99995 4.99995 4.99995 4.99995 4.99996 4.99997 4.99997 4.99998 4.99999 5 5 5.00001 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 4.99999 4.99999 4.99999 } v15 set { 1.86175 2.00199 2.08919 1.84314 1.08254 0.214737 0.0377351 0.00952455 0.00232763 0.000563614 0.000263477 0.000148642 0.000285086 0.000242592 7.34699e-05 -1.53467e-05 -0.0161874 -0.0157876 -0.0141194 0.0132576 0.0903272 0.109938 0.0535295 0.0224216 0.00940945 0.00466825 -0.000649972 -0.00654752 -0.00333248 -0.00103671 -0.000508276 -5.8896e-05 -0.00043938 -0.000544704 -0.00044444 -0.000307093 -0.00024517 -0.000154538 -8.78602e-05 -7.10461e-05 -6.06485e-05 -3.91039e-05 -8.45988e-06 9.43442e-06 1.28351e-05 -2.16734e-06 -2.6142e-05 -2.54768e-05 -1.88997e-05 -1.17906e-05 -7.3808e-06 -2.97101e-06 1.19146e-07 2.94246e-06 5.38942e-06 3.88851e-06 2.38761e-06 8.86704e-07 -6.14201e-07 -2.11511e-06 -2.59565e-06 -2.38885e-06 -2.18205e-06 -1.97525e-06 -1.76845e-06 -1.56241e-06 -1.36258e-06 -1.16276e-06 -9.62939e-07 -7.63116e-07 -5.63293e-07 -3.6347e-07 -1.63647e-07 3.61756e-08 2.35999e-07 4.35822e-07 6.07653e-07 5.90323e-07 5.72994e-07 5.55665e-07 5.38336e-07 5.21007e-07 5.03678e-07 4.86349e-07 4.6902e-07 4.51691e-07 4.34361e-07 4.11899e-07 3.60315e-07 3.08731e-07 2.57146e-07 2.05562e-07 1.53977e-07 1.02393e-07 5.08082e-08 -7.76222e-10 -5.23607e-08 -1.03945e-07 -1.47815e-07 -1.54225e-07 -1.60635e-07 -1.67045e-07 -1.73455e-07 -1.79864e-07 -1.86274e-07 -1.92684e-07 -1.99094e-07 -2.05504e-07 -2.11914e-07 -2.18324e-07 -2.24734e-07 -2.31144e-07 -2.37554e-07 -2.43964e-07 -2.50373e-07 -2.56783e-07 -2.63193e-07 -2.69603e-07 -2.76013e-07 -2.82423e-07 2.92534e-06 0.0446777 0.024278 -0.0518987 -0.0636547 0.00983929 -0.000518204 -0.000265194 0.000154772 0.000299538 3.12715e-05 -3.18225e-05 -2.48268e-05 -1.16701e-05 -6.05117e-06 7.61116e-06 -0.0163668 -0.0158244 -0.0141177 0.0100085 0.0857144 0.107784 0.051862 0.0204448 0.00629858 0.000967736 0.00121674 0.00190276 0.00154009 0.000860922 0.000410386 0.000164585 3.99493e-05 1.93797e-05 5.67594e-05 0.000110126 2.49925e-05 -7.17815e-05 -0.000142299 -1.63109e-05 0.000439529 0.000562489 0.000594599 0.000326164 0.000126423 -4.26063e-05 -0.000122927 -0.000114152 -6.72706e-05 -6.41242e-05 -0.000135588 2.61507e-05 0.000134036 6.43734e-06 -4.6223e-05 -0.000112047 -0.000101388 -8.67847e-05 -0.000117664 -0.000133957 -0.000116558 -0.000100873 -7.65448e-05 -4.44964e-05 -3.6677e-05 -5.26632e-05 -5.45172e-05 -5.13545e-05 -3.73869e-05 -1.99732e-05 -1.0907e-05 -1.10081e-05 -3.02609e-05 -5.18517e-05 -6.13597e-05 -5.30706e-05 -2.39572e-05 -3.24146e-05 -5.70062e-05 -0.000103448 -0.000135376 -0.0001024 -2.39007e-05 0.000110929 0.000151226 0.000142044 0.000105922 5.62834e-05 4.78476e-05 3.94117e-05 3.09759e-05 2.25401e-05 1.41042e-05 5.66837e-06 -2.76747e-06 -3.08639e-06 -2.81341e-06 -2.54043e-06 -2.26745e-06 -1.99447e-06 -1.72149e-06 -1.44851e-06 -1.26226e-06 -1.12096e-06 -9.79661e-07 -8.38363e-07 -6.97065e-07 -5.55768e-07 -4.1447e-07 -2.73173e-07 -1.31875e-07 9.42259e-09 1.5072e-07 2.92018e-07 4.33315e-07 5.74613e-07 7.10363e-07 8.01984e-07 8.93604e-07 9.85225e-07 1.07685e-06 0.04474 0.0928765 0.141327 0.0176048 -0.071675 -0.0124613 0.989022 2.28104 3.40619 4.21417 4.67173 4.87438 4.96044 4.98996 4.99858 4.96672 4.89502 4.79391 4.76433 4.8387 4.98612 5.0161 5.01722 5.01437 5.01256 4.99827 4.95807 4.9209 4.88217 4.83006 4.78461 4.80759 4.85548 4.89604 4.9254 4.94617 4.96126 4.97374 4.98255 4.98792 4.99126 4.99361 4.99554 4.99699 4.99792 4.99846 4.99881 4.99905 4.99924 4.99938 4.99949 4.99955 4.9997 4.9998 4.99982 4.99982 4.99982 4.99982 4.99982 4.99983 4.99984 4.99985 4.99986 4.99987 4.99988 4.99989 4.9999 4.99992 4.99993 4.99994 4.99995 4.99995 4.99996 4.99996 4.99998 4.99999 5.00001 5.00002 5.00002 5.00001 5.00001 5 4.99999 4.99999 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 } v16 set { 1.86175 1.73073 1.50572 1.89001 3.39004 4.36034 4.79012 4.93798 4.98305 4.99539 4.9979 4.99904 4.99772 4.9983 4.99935 4.99975 4.98837 4.99456 4.99728 5.01838 5.04568 5.00759 4.98112 4.98479 4.99197 4.99641 4.99747 4.99775 5.00043 5.0007 5.00035 5.00023 4.99976 5.00002 5.00007 5.0002 4.99993 5.00003 5.00021 5.00006 4.99993 4.99992 5.00002 5.00013 5.00017 5.00009 4.99992 4.99991 4.99993 4.99996 4.99998 4.99999 5.00001 5.00003 5.00005 5.00004 5.00004 5.00003 5.00002 5.00001 5 4.99999 4.99999 4.99998 4.99998 4.99997 4.99997 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5.01498 4.99342 4.96899 5.00301 5.02627 4.9977 4.99548 4.99757 5.00277 5.00245 5.0014 5.00069 5.00032 5.00014 5.00009 4.9867 4.99262 4.99607 5.01805 5.04713 5.00927 4.98184 4.98483 4.9914 4.99616 4.99902 4.9999 4.99987 4.99979 4.99981 4.99989 4.99994 4.99998 5.0002 5.00001 5.00008 5.00008 5.0001 5.00021 5.00032 5.00025 5.00019 5.00006 5.00007 4.99994 4.99997 4.99999 5.00023 5.00008 4.99993 4.99998 4.99986 4.99982 5.00003 4.99985 4.99996 5.00014 5 4.99984 4.99979 4.99982 4.99993 5.00008 5.00011 5.00002 4.99996 4.9999 4.99994 5.00001 5.00007 5.00009 4.99995 4.99978 4.99971 4.99976 4.99997 4.99996 4.99989 4.99972 4.99955 4.99953 4.99959 4.99976 4.9999 5.00005 5.00023 5.00039 5.00034 5.00029 5.00024 5.00019 5.00014 5.00009 5.00004 5.00003 5.00002 5.00001 5 5 4.99999 4.99998 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5.00001 5.00002 5.00003 5.00004 5.01564 5.03395 5.04932 5.11868 3.92502 1.31888 0.163888 0.0946876 0.0789578 0.0565084 0.0260333 0.0156986 0.00907667 0.00613629 0.00468417 -0.00174008 -0.0021422 0.000586962 0.0124937 0.0147977 0.00838454 0.00039383 -0.000522021 -0.000426598 -0.000290214 -0.00173713 -0.00384132 -0.00382945 -0.00429219 -0.00580193 -0.00393246 0.0017543 0.00423045 0.00408931 0.0031976 0.00245457 0.00187293 0.00159068 0.00105697 0.000609902 0.000358825 0.000334125 0.000212708 0.000168116 8.97349e-05 5.21578e-05 3.84527e-05 2.93033e-05 2.10067e-05 1.59954e-05 1.13917e-05 5.49738e-06 2.77217e-05 6.51259e-06 -6.65468e-06 2.09837e-06 -6.617e-06 -4.80187e-06 1.55031e-06 4.26536e-06 7.69457e-07 -1.46213e-06 -7.25202e-07 3.26501e-06 6.55807e-06 7.524e-06 6.07209e-06 6.00701e-06 5.41166e-06 3.86573e-06 1.10651e-06 -2.74603e-06 -2.18566e-06 2.3658e-06 8.59956e-06 8.35046e-06 2.90621e-06 -8.75982e-07 -1.87189e-06 -2.1528e-06 -1.94875e-06 -1.74471e-06 -1.54067e-06 -1.33662e-06 -1.13258e-06 -8.40567e-07 -5.20743e-07 -2.00918e-07 1.18906e-07 4.38731e-07 6.11382e-07 6.01529e-07 5.91675e-07 5.81822e-07 5.71968e-07 5.62115e-07 5.52261e-07 5.42407e-07 5.32554e-07 5.227e-07 5.12847e-07 4.72812e-07 4.26137e-07 3.79462e-07 3.32786e-07 2.86111e-07 2.39436e-07 1.92761e-07 1.46086e-07 9.94107e-08 5.27356e-08 -2.77779e-10 -7.98079e-08 -1.59338e-07 -2.38868e-07 -3.18398e-07 -3.97928e-07 -4.77458e-07 -5.56988e-07 -6.36519e-07 } v17 set { 5 5.16963 4.84136 3.33754 0.316206 0.103113 0.0273341 0.0221102 0.0177008 0.0143758 0.0115203 0.00929231 0.00752716 0.00625439 0.00489872 0.00403656 -0.0657317 -0.0256467 0.165394 0.985963 3.05067 4.55799 4.89728 4.92464 4.8882 4.90592 4.97315 4.99241 4.99694 4.99845 4.99905 4.99939 4.99959 4.99971 4.9998 4.99986 4.9999 4.99993 4.99995 4.99996 4.99997 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 5 5.00001 5.00003 5.00005 5.00004 5.00002 5 4.99999 4.99999 4.99998 4.99998 4.99997 4.99997 4.99998 4.99998 4.99999 4.99999 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5.00025 5.1657 4.69981 2.43895 0.0229743 0.0351406 -0.0211974 -0.0312063 -0.0160331 -0.0021718 -0.000766597 -0.000251052 -5.49363e-05 -3.36364e-06 -2.01983e-06 -9.70575e-06 -0.0657007 -0.0205247 0.183332 1.07163 3.11839 4.46213 4.84163 4.95195 4.99159 5.02084 5.04029 5.04138 5.0271 5.00445 4.97957 4.95702 4.95231 4.97819 4.99191 4.9963 4.99822 4.99878 4.99903 4.99925 4.99942 4.9995 4.99954 4.99957 4.99961 4.99966 4.9997 4.99974 4.99977 4.99981 4.99983 4.99986 4.99988 4.9999 4.99991 4.99992 4.99994 4.99995 4.99995 4.99996 4.99997 4.99997 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 4.99999 4.99998 4.99997 4.99996 5.14239 4.76219 3.16574 0.299969 0.0631609 -0.00118611 -0.00026052 -5.96333e-05 -1.44904e-05 -4.3859e-06 -2.99454e-06 1.10547e-06 4.84662e-06 1.30971e-05 2.23082e-05 -0.0655844 -0.0204818 0.182507 1.05954 3.12277 4.46735 4.83915 4.94512 4.97679 4.98654 4.9966 5.00833 5.00776 5.00432 5.00199 5.00086 5.00033 5.00008 5 5.00001 5 5.00005 5.00002 4.99981 4.99991 4.99998 4.99979 4.99979 4.99984 4.9998 4.9998 5.00006 5.00002 5.00001 5 5 4.99992 4.99998 4.99999 5.00002 5.00014 4.99999 4.99987 4.99993 5.00003 5.00011 5.00005 4.99996 4.99987 4.99985 4.99994 5.00009 5.0001 5 4.99993 4.99997 5.00008 5.00015 5.00021 5.00021 5.00007 4.99978 4.99965 4.99973 4.9999 4.99992 4.99995 4.99997 4.99999 5.00001 5.00002 5.00001 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5.00001 5.00001 5.00001 5.00002 5.00002 5.00002 } v18 set { 5 5.0333 5.02472 4.92559 4.18383 3.93923 3.9961 4.14293 4.28591 4.41336 4.52157 4.61101 4.68472 4.7439 4.79294 4.83239 4.80697 4.78808 4.79322 4.8838 5.08529 5.21863 4.88852 3.90198 2.14586 0.383977 0.101103 0.0525711 0.0318287 0.020895 0.0146908 0.010831 0.00830272 0.00656377 0.00532066 0.00440078 0.00369956 0.00315713 0.00272614 0.00237965 0.00209659 0.00186339 0.00167014 0.0015081 0.00137172 0.00125607 0.00115393 0.00106076 0.000980166 0.000918015 0.000862837 0.00080766 0.000763488 0.000721541 0.000680825 0.000653026 0.000625226 0.000597426 0.000569627 0.000541827 0.000519087 0.000499756 0.000480424 0.000461093 0.000441761 0.000423291 0.000411941 0.00040059 0.00038924 0.000377889 0.000366539 0.000355188 0.000343838 0.000332487 0.000321137 0.000309786 0.000299055 0.000292509 0.000285963 0.000279417 0.000272871 0.000266325 0.000259779 0.000253233 0.000246686 0.00024014 0.000233594 0.000227387 0.0002231 0.000218813 0.000214526 0.00021024 0.000205953 0.000201666 0.000197379 0.000193092 0.000188805 0.000184519 0.000180526 0.000177963 0.0001754 0.000172837 0.000170274 0.000167711 0.000165148 0.000162585 0.000160022 0.000157459 0.000154895 0.000152332 0.000149769 0.000147206 0.000144643 0.00014208 0.000139517 0.000136954 0.000134391 0.000131828 0.000129265 0.000126702 0.000132838 0.0311184 0.163151 0.34986 0.604501 0.357125 0.136137 0.0711304 0.0346959 0.0212674 0.00872193 0.00252206 0.000455269 7.59332e-05 2.91532e-05 0.000320562 -0.0720911 -0.0840491 -0.0791345 -0.0404143 0.0182035 -0.0235871 -0.0426072 -0.0597501 0.00824773 0.481404 1.32496 2.11949 2.57317 2.58202 2.15054 1.33786 0.45702 0.153772 0.0913584 0.0604989 0.0421591 0.0271456 0.0170021 0.0115815 0.00907886 0.00742466 0.00626096 0.00531127 0.00450501 0.00381927 0.00323718 0.00274374 0.00232494 0.00196885 0.00166686 0.00141134 0.00119437 0.0010109 0.000855534 0.000723378 0.000611408 0.000516704 0.000436769 0.000369523 0.000313026 0.00026526 0.000223976 0.000188972 0.000159042 0.000134148 0.000112688 9.49738e-05 7.97877e-05 6.721e-05 5.65115e-05 4.77194e-05 4.03591e-05 3.42848e-05 2.92627e-05 2.50435e-05 2.1412e-05 1.84532e-05 1.58624e-05 1.34673e-05 1.14461e-05 1.00935e-05 9.12375e-06 8.50202e-06 7.81431e-06 7.20729e-06 6.73936e-06 6.3702e-06 5.90049e-06 5.43077e-06 4.96105e-06 4.49133e-06 4.02162e-06 3.5519e-06 3.08218e-06 2.79099e-06 2.51281e-06 2.23463e-06 1.95645e-06 1.67827e-06 1.40009e-06 1.12191e-06 1.01376e-06 9.9375e-07 9.73741e-07 9.53733e-07 9.33724e-07 9.13715e-07 8.93707e-07 8.73698e-07 8.5369e-07 8.33681e-07 8.13673e-07 7.93664e-07 7.73655e-07 7.53647e-07 7.21781e-07 5.956e-07 4.69419e-07 3.43239e-07 2.17058e-07 0.0284032 0.0374438 -0.0157543 -0.0680497 0.0504768 0.0100294 0.00222261 0.000528697 0.000132929 3.99489e-05 2.46066e-05 4.56327e-06 -6.54853e-06 1.33783e-05 -3.68221e-05 -0.0724498 -0.0843663 -0.0792935 -0.0406426 0.0200019 0.0426259 0.0220753 0.00668555 -0.000968483 0.024662 0.0383437 0.0911513 0.087848 0.0602076 0.0390559 0.0260573 0.0180444 0.012974 0.00985409 0.00788132 0.0064228 0.005545 0.00453571 0.00364245 0.00310278 0.00270523 0.00236439 0.0020945 0.00186808 0.00167493 0.00151731 0.00138594 0.00126945 0.00116695 0.0010762 0.000996366 0.000928387 0.000864414 0.000808258 0.000759574 0.000713865 0.000666712 0.000632716 0.000601262 0.000572163 0.000543986 0.000515253 0.0004897 0.000468112 0.000449313 0.000432981 0.000417911 0.000401307 0.000382712 0.000366678 0.000355736 0.000349171 0.000335727 0.000317091 0.000296086 0.000283543 0.000277366 0.000272233 0.000267001 0.000263147 0.000256699 0.000250251 0.000243803 0.000237355 0.000230907 0.000225424 0.000220247 0.000215069 0.000209892 0.000204714 0.000200213 0.000196548 0.000192884 0.00018922 0.000185556 0.000181892 0.000178228 0.000174564 0.0001709 0.000167236 0.000163572 0.000160824 0.000158279 0.000155733 0.000153187 0.000150641 0.000148095 0.000145549 0.000143003 0.000140457 0.000137911 0.000135457 0.000133386 0.000131315 0.000129245 0.000127174 0.000125103 0.000123032 0.000120961 0.000118891 } v19 set { 1.86175 1.99994 2.0833 2.01627 2.42503 3.25769 3.62134 3.88827 4.09688 4.26773 4.40529 4.51734 4.60827 4.68313 4.74346 4.79302 4.72815 4.68959 4.70421 4.81316 5.01375 5.14493 5.10305 5.0699 5.04484 5.03751 5.03348 5.02504 5.01799 5.01271 5.00895 5.00628 5.0044 5.00309 5.00216 5.00151 5.00105 5.00073 5.00051 5.00034 5.00023 5.00015 5.0001 5.00007 5.00003 4.99998 4.99993 4.99993 4.99995 4.99999 5.00001 5.00003 5.00002 5.00001 5 5 5 5 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5.00017 5.17398 4.94779 3.78508 1.52302 0.608808 0.244311 0.126053 0.0597175 0.038422 0.0158174 0.00481338 0.00107847 0.000301256 0.000114861 0.00059489 -0.118904 -0.147478 -0.158986 -0.080544 0.165361 0.171378 0.0776087 0.0435738 0.0428235 0.0423755 0.0347695 0.0225061 0.0155539 0.0121357 0.0107997 0.0103976 0.0124406 0.016814 0.0167556 0.0149852 0.01459 0.0141182 0.0131934 0.0120286 0.0108692 0.0097184 0.00855881 0.00744912 0.00643877 0.00554044 0.00475165 0.00406535 0.00347158 0.00295981 0.00251995 0.00214318 0.00182101 0.00154613 0.00131196 0.0011119 0.000941587 0.000796999 0.000674582 0.000571283 0.000484276 0.000410649 0.000347005 0.000292984 0.000246715 0.000208143 0.00017489 0.000147412 0.000123854 0.000104332 8.77229e-05 7.40686e-05 6.2637e-05 5.32e-05 4.53946e-05 3.88343e-05 3.31864e-05 2.85905e-05 2.45725e-05 2.08671e-05 1.77301e-05 1.55911e-05 1.40153e-05 1.29421e-05 1.18693e-05 1.09815e-05 1.03484e-05 9.87664e-06 9.14446e-06 8.41228e-06 7.68011e-06 6.94793e-06 6.21575e-06 5.48357e-06 4.7514e-06 4.38454e-06 4.04432e-06 3.7041e-06 3.36388e-06 3.02366e-06 2.68344e-06 2.34322e-06 2.15196e-06 2.03791e-06 1.92386e-06 1.80982e-06 1.69577e-06 1.58173e-06 1.46768e-06 1.35363e-06 1.23959e-06 1.12554e-06 1.0115e-06 8.9745e-07 7.83404e-07 6.69358e-07 4.76113e-07 -3.47071e-07 -1.17025e-06 -1.99344e-06 -2.81662e-06 0.0783754 0.0500262 -0.0659563 -0.120914 0.0815957 0.0154255 0.00347177 0.000840357 0.000214582 6.54655e-05 3.91709e-05 8.07396e-06 -4.44265e-07 1.74384e-05 -4.52725e-05 -0.119379 -0.147984 -0.159247 -0.0824604 0.169014 0.177628 0.0758742 0.010558 -0.0346506 -0.0710288 -0.0838952 -0.0599521 -0.034568 -0.0181615 -0.00968034 -0.00547115 -0.00333511 -0.00232468 -0.00181159 -0.00143841 -0.00116601 -0.000839755 -0.000569764 -0.000578683 -0.000490551 -0.000411712 -0.000437859 -0.000408185 -0.000356644 -0.000311332 -0.000269006 -0.000221396 -0.000210054 -0.0001923 -0.000175122 -0.000161039 -0.0001428 -0.000126123 -0.000127893 -8.14516e-05 -0.000120166 -0.000154909 -0.000112733 -8.40377e-05 -7.11342e-05 -8.09538e-05 -9.77789e-05 -9.82402e-05 -7.73531e-05 -5.28255e-05 -3.1096e-05 -1.87967e-05 -1.96552e-05 -4.16655e-05 -5.77185e-05 -5.24142e-05 -2.83153e-05 -1.90012e-05 -1.54415e-05 -2.52569e-05 -6.23747e-05 -0.000130543 -0.000149394 -0.000110886 -4.35517e-05 -4.17084e-05 -3.98651e-05 -3.80218e-05 -3.61785e-05 -3.43352e-05 -3.36249e-05 -3.32729e-05 -3.29208e-05 -3.25687e-05 -3.22166e-05 -3.17143e-05 -3.10258e-05 -3.03372e-05 -2.96486e-05 -2.89601e-05 -2.82715e-05 -2.75829e-05 -2.68944e-05 -2.62058e-05 -2.55173e-05 -2.48287e-05 -2.43043e-05 -2.38159e-05 -2.33276e-05 -2.28393e-05 -2.2351e-05 -2.18626e-05 -2.13743e-05 -2.0886e-05 -2.03977e-05 -1.99093e-05 -1.945e-05 -1.91122e-05 -1.87744e-05 -1.84366e-05 -1.80987e-05 -1.77609e-05 -1.74231e-05 -1.70853e-05 -1.67474e-05 } v20 set { 1.86175 1.99724 2.17266 2.48439 3.15933 3.85231 4.38091 4.69033 4.85034 4.92851 4.96453 4.98188 4.98736 4.991 4.99482 4.9973 4.96422 4.89989 4.83907 4.83151 4.90868 5.04854 5.06104 5.04571 5.03219 5.03025 5.02273 5.01707 5.0123 5.0087 5.00611 5.00429 5.00301 5.00211 5.00148 5.00103 5.00072 5.0005 5.00035 5.00024 5.00016 5.00011 5.00007 5.00005 5.00003 5.00001 4.99999 4.99998 4.99998 4.99998 4.99998 4.99998 4.99999 5 5 5.00001 5.00001 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 4.99981 5.10081 5.10903 4.98404 5.00999 5.14946 4.36501 2.23938 0.325144 0.00660272 -0.0102186 -0.0082401 -0.00556785 -0.00374178 -0.00264763 -0.00202823 -0.0182241 -0.0169551 -0.0150395 0.0103736 0.0877592 0.104382 0.0515938 0.0373818 0.0411547 0.0397009 0.0308946 0.0205793 0.0154037 0.0129191 0.0119327 0.011527 0.0124295 0.0161152 0.0161076 0.0145391 0.0144541 0.0139287 0.0129215 0.0117239 0.0105795 0.00942983 0.00827423 0.00718354 0.00619954 0.00532868 0.00456631 0.00390448 0.00333254 0.00284003 0.00241714 0.00205524 0.0017458 0.00148202 0.00125739 0.0010655 0.000902213 0.000763611 0.000646279 0.000547291 0.000463934 0.000393401 0.000332424 0.000280655 0.000236328 0.000199386 0.000167536 0.000141218 0.000118654 9.99559e-05 8.40479e-05 7.09694e-05 6.00188e-05 5.09786e-05 4.3502e-05 3.72191e-05 3.18114e-05 2.74071e-05 2.35539e-05 1.99967e-05 1.69871e-05 1.49449e-05 1.3451e-05 1.24492e-05 1.14256e-05 1.05669e-05 9.94487e-06 9.47514e-06 8.77318e-06 8.07123e-06 7.36927e-06 6.66731e-06 5.96536e-06 5.2634e-06 4.56144e-06 4.23044e-06 3.92649e-06 3.62254e-06 3.31858e-06 3.01463e-06 2.71068e-06 2.40673e-06 2.23063e-06 2.12082e-06 2.01102e-06 1.90121e-06 1.7914e-06 1.68159e-06 1.57178e-06 1.46197e-06 1.35216e-06 1.24235e-06 1.13255e-06 1.02274e-06 9.12929e-07 8.0312e-07 6.33171e-07 -1.51288e-08 -6.63428e-07 -1.31173e-06 -1.96003e-06 0.0437517 0.0265689 -0.0515377 -0.0658688 0.010727 -0.000511921 -8.36924e-05 2.13278e-05 1.45207e-05 4.54862e-06 -6.14726e-06 2.0062e-06 1.02709e-06 1.4152e-05 -3.08225e-05 -0.0166501 -0.0157139 -0.013957 0.0107537 0.0873717 0.111302 0.0454129 -0.00530142 -0.0468336 -0.0790063 -0.0826944 -0.0534753 -0.0288705 -0.0149009 -0.00801592 -0.0046342 -0.00291835 -0.00213019 -0.00170055 -0.001352 -0.00110593 -0.000742655 -0.000532042 -0.000544742 -0.000479206 -0.000407307 -0.000403575 -0.000366209 -0.000324161 -0.000286183 -0.000247579 -0.000214281 -0.000203435 -0.000186896 -0.000171033 -0.00015779 -0.000145259 -0.000128069 -0.000122647 -9.89398e-05 -0.000114926 -0.000132195 -0.000107872 -8.91015e-05 -7.87996e-05 -8.14061e-05 -8.9098e-05 -8.83368e-05 -7.6122e-05 -6.14668e-05 -4.75402e-05 -3.81855e-05 -3.69696e-05 -4.78656e-05 -5.61346e-05 -5.35007e-05 -4.1459e-05 -3.35411e-05 -2.52374e-05 -2.37479e-05 -4.6406e-05 -9.41884e-05 -0.000109222 -8.52676e-05 -4.25166e-05 -4.10125e-05 -3.95085e-05 -3.80045e-05 -3.65004e-05 -3.49964e-05 -3.41627e-05 -3.3541e-05 -3.29193e-05 -3.22976e-05 -3.16758e-05 -3.10334e-05 -3.03653e-05 -2.96971e-05 -2.9029e-05 -2.83609e-05 -2.76928e-05 -2.70246e-05 -2.63565e-05 -2.56884e-05 -2.50203e-05 -2.43521e-05 -2.38716e-05 -2.34324e-05 -2.29932e-05 -2.25539e-05 -2.21147e-05 -2.16755e-05 -2.12362e-05 -2.0797e-05 -2.03578e-05 -1.99186e-05 -1.95079e-05 -1.9217e-05 -1.8926e-05 -1.8635e-05 -1.8344e-05 -1.8053e-05 -1.7762e-05 -1.74711e-05 -1.71801e-05 } v21 set { 1.86175 1.73273 1.42016 1.02483 0.944013 0.274107 0.0823742 0.0379366 0.020816 0.0132952 0.00955525 0.00717008 0.00592286 0.00437379 0.00383557 0.00273694 -0.0037467 -0.0054191 -0.00131454 0.0112179 0.0133918 0.00519747 -0.00260113 -0.00252847 -0.00181292 0.000183398 -0.000667607 -0.000750747 -0.000594314 -0.000433904 -0.000308985 -0.000217858 -0.000152926 -0.000107454 -7.54076e-05 -5.2675e-05 -3.66299e-05 -2.54341e-05 -1.75095e-05 -1.18848e-05 -7.97289e-06 -5.30239e-06 -3.53615e-06 -2.38504e-06 -2.40158e-06 -3.84485e-06 -5.29435e-06 -2.57099e-06 1.95189e-06 3.55083e-06 2.06179e-06 5.72753e-07 3.30469e-07 3.40296e-07 3.60221e-07 4.86081e-07 6.1194e-07 7.37799e-07 8.63659e-07 9.89518e-07 9.21274e-07 7.22275e-07 5.23276e-07 3.24277e-07 1.25278e-07 -5.59467e-08 -9.03265e-08 -1.24706e-07 -1.59086e-07 -1.93466e-07 -2.27846e-07 -2.62226e-07 -2.96605e-07 -3.30985e-07 -3.65365e-07 -3.99745e-07 -4.24266e-07 -3.82163e-07 -3.40061e-07 -2.97959e-07 -2.55857e-07 -2.13755e-07 -1.71652e-07 -1.2955e-07 -8.7448e-08 -4.53457e-08 -3.24353e-09 3.76901e-08 7.19937e-08 1.06297e-07 1.40601e-07 1.74904e-07 2.09208e-07 2.43512e-07 2.77815e-07 3.12119e-07 3.46422e-07 3.80726e-07 4.04507e-07 3.77191e-07 3.49876e-07 3.22561e-07 2.95246e-07 2.67931e-07 2.40616e-07 2.13301e-07 1.85986e-07 1.58671e-07 1.31356e-07 1.04041e-07 7.67256e-08 4.94105e-08 2.20955e-08 -5.21962e-09 -3.25347e-08 -5.98498e-08 -8.71649e-08 -1.1448e-07 -1.41795e-07 -1.6911e-07 7.87893e-06 0.0114592 -0.0245712 -0.111637 0.0961324 1.61168 3.22343 4.20442 4.53535 4.83834 4.95464 4.98874 4.99746 4.99883 4.99948 4.99815 4.98431 4.99298 4.99718 5.01948 5.04749 5.008 4.98243 4.98985 4.99781 4.99887 4.99679 4.99616 4.99743 4.99859 4.99936 4.99972 5.00058 5.00123 5.0002 4.99945 4.99983 4.9998 4.99966 4.99958 4.99956 4.99956 4.99956 4.99958 4.99961 4.99965 4.99969 4.99973 4.99977 4.9998 4.99983 4.99985 4.99987 4.99989 4.99991 4.99992 4.99993 4.99994 4.99995 4.99996 4.99997 4.99997 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 4.99999 4.99998 4.99997 4.99996 5.01454 4.99566 4.96796 4.99819 5.03232 5.00034 4.99867 4.99937 4.99977 4.99992 4.99997 4.99999 5.00001 5.00021 4.99974 4.98462 4.99301 4.99723 5.01936 5.04807 5.00929 4.9789 4.97876 4.98244 4.9863 4.99575 5.0069 5.00863 5.00624 5.00357 5.0019 5.00098 5.00048 5.00025 5.00016 5.00011 5.00013 5.00009 4.99982 4.99994 5.00005 4.99994 4.99988 4.99989 4.99997 5.00003 5.00005 5.00002 5.00001 5.00001 5.00001 4.99993 4.99999 5 5.00021 4.99997 4.99981 5 5.00009 5.0001 5.00001 4.99991 4.9999 5 5.00011 5.00017 5.00018 5.00018 5.00014 5.00007 4.99999 4.9999 4.9999 5.00001 5.00016 5.00014 4.99999 4.99993 4.99999 5.00009 5.00007 5.00006 5.00004 5.00003 5.00001 5.00001 5 4.99999 4.99998 4.99997 4.99997 4.99997 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 } v22 set { 7.10441e-10 0.00107105 0.000637109 -0.00236346 -0.018079 -0.0120077 -0.00217059 0.00266679 0.00403383 0.00403836 0.00356705 0.00303303 0.00244716 0.00198586 0.0016855 0.00136497 -3.96022e-05 -0.000367409 -3.77079e-05 0.00194085 0.00506964 -0.0400214 -0.0402572 0.0524434 0.286234 0.803011 1.44795 2.02473 2.54768 3.02748 3.4415 3.78287 4.09667 4.35152 4.53987 4.67614 4.77407 4.84319 4.89227 4.92702 4.95119 4.96764 4.97846 4.98557 4.98982 4.99209 4.99371 4.99569 4.99727 4.99802 4.99834 4.99867 4.99892 4.99915 4.99936 4.99939 4.99943 4.99946 4.9995 4.99953 4.99957 4.9996 4.99963 4.99967 4.9997 4.99973 4.99974 4.99975 4.99976 4.99977 4.99978 4.9998 4.99981 4.99982 4.99983 4.99984 4.99985 4.99986 4.99986 4.99986 4.99987 4.99987 4.99988 4.99988 4.99989 4.99989 4.9999 4.9999 4.9999 4.9999 4.99991 4.99991 4.99991 4.99991 4.99992 4.99992 4.99992 4.99992 4.99993 4.99993 4.99993 4.99993 4.99993 4.99993 4.99993 4.99993 4.99994 4.99994 4.99994 4.99994 4.99994 4.99994 4.99994 4.99994 4.99995 4.99995 4.99995 4.99995 4.99995 4.99995 4.99995 5.00145 5.00659 5.01209 5.01931 5.00279 4.99273 4.99217 4.99295 4.99471 4.99594 4.99696 4.9978 4.99844 4.99891 4.99924 4.99635 4.99699 4.99813 5.00068 5.00307 5.0588 4.96365 4.54012 3.6307 2.35176 1.0322 0.354379 0.115986 0.0435668 0.0245112 0.020786 0.0164656 0.0118409 0.00849698 0.00597078 0.0040105 0.0026076 0.0016597 0.00118185 0.00121067 0.00153587 0.00174836 0.00136519 -0.000189116 -0.00315555 -0.00646603 -0.00898042 -0.010203 -0.0110896 -0.0123764 -0.00953841 -0.00225795 0.000818314 0.00152252 0.00150269 0.00119025 0.000767068 0.000308852 -3.79272e-05 -0.00019691 -0.000186642 -9.73653e-05 -8.49784e-06 2.04147e-05 -9.91086e-06 -1.55959e-05 -1.80499e-05 -1.77097e-05 -1.51548e-05 -1.1978e-05 -9.84916e-06 -1.29728e-05 -1.67235e-05 -1.74153e-05 -1.39958e-05 -5.92272e-06 -8.08216e-06 -1.53077e-05 -2.92531e-05 -3.91049e-05 -2.98935e-05 -7.32122e-06 3.18534e-05 4.39134e-05 4.18753e-05 3.22759e-05 1.86766e-05 1.58432e-05 1.30098e-05 1.01765e-05 7.34312e-06 4.50975e-06 1.67639e-06 -1.15697e-06 -1.23877e-06 -1.11991e-06 -1.00106e-06 -8.82208e-07 -7.63355e-07 -6.44502e-07 -5.2565e-07 -4.29318e-07 -3.44661e-07 -2.60004e-07 -1.75347e-07 -9.06904e-08 -6.03349e-09 7.86234e-08 1.6328e-07 2.47937e-07 3.32594e-07 4.17251e-07 5.01908e-07 5.86565e-07 6.71222e-07 7.36123e-07 6.43886e-07 5.5165e-07 4.59414e-07 3.67178e-07 0.000334759 -4.60833e-05 -0.00106139 -0.00166624 0.000859563 0.00102606 0.00410037 0.00419931 0.00518997 0.00459791 0.00503125 0.00523877 0.00452158 0.00339924 0.00233399 0.000876915 0.000546439 0.000444299 0.000983968 0.00119304 -0.0429422 -0.0403983 0.0534896 0.288013 0.807345 1.44247 2.03448 2.57021 3.05049 3.47332 3.8131 4.1009 4.34677 4.53512 4.67127 4.76531 4.82526 4.86593 4.89586 4.91904 4.93806 4.95348 4.96597 4.97629 4.9843 4.98983 4.99335 4.9957 4.99741 4.99864 4.99946 4.99994 5.00047 5.00073 5.00086 5.00092 5.00094 5.00091 5.00087 5.00081 5.00074 5.00067 5.00059 5.00052 5.00046 5.0004 5.00034 5.0003 5.00026 5.00022 5.00019 5.00016 5.00014 5.00012 5.0001 5.00009 5.00007 5.00006 5.00006 5.00005 5.00004 5.00004 5.00004 5.00003 5.00003 5.00003 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 } v23 set { 5 5.00284 5.01266 5.01895 4.98936 4.99575 4.99217 4.99545 4.99775 4.99894 4.99946 4.99968 4.99975 4.99977 4.99986 4.9999 4.99528 4.99808 5.00039 5.00392 5.00512 4.99985 4.99863 4.99942 4.99992 5.00017 4.99897 4.99803 4.99784 4.99739 4.99883 5.00365 5.00298 5.00133 5.00048 5.00019 5.00008 5.00005 5.00004 5.00003 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 4.99999 4.99997 4.99995 4.99996 4.99998 5 5.00001 5.00001 5.00002 5.00002 5.00003 5.00003 5.00002 5.00002 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5.00217 5.00108 4.99547 4.99658 5.00667 4.99641 4.99532 4.99938 5.00328 5.00222 5.00114 5.00052 5.00024 5.00011 5.00009 4.99285 4.99591 4.99897 5.00403 5.00786 5.00318 4.99942 4.9992 4.99949 5.001 5.00408 5.00319 5.00063 4.99995 5.00014 4.99982 4.99832 4.99838 4.99865 4.99912 4.99836 4.99735 4.99606 4.99814 5.00958 5.02973 5.05293 5.06103 4.99342 4.80726 4.50744 4.07509 3.41358 2.37924 1.03194 0.261552 0.142392 0.0904482 0.0555071 0.0322869 0.018289 0.0113802 0.00875182 0.00757055 0.00629906 0.00523 0.00403349 0.0031953 0.00280864 0.00286119 0.00250389 0.00202815 0.001723 0.00147312 0.0012411 0.00104401 0.000886204 0.000758277 0.000651915 0.00056348 0.000487966 0.000424048 0.000365613 0.000308178 0.000258725 0.000228061 0.000207976 0.000198491 0.00018518 0.000172716 0.000163197 0.000155007 0.000141734 0.000128461 0.000115188 0.000101915 8.86417e-05 7.53686e-05 6.20956e-05 5.69164e-05 5.23275e-05 4.77385e-05 4.31495e-05 3.85605e-05 3.39716e-05 2.93826e-05 2.69449e-05 2.56224e-05 2.42999e-05 2.29774e-05 2.16549e-05 2.03324e-05 1.90099e-05 1.76873e-05 1.63648e-05 1.50423e-05 1.37198e-05 1.23973e-05 1.10748e-05 9.75232e-06 8.48447e-06 7.65129e-06 6.81811e-06 5.98494e-06 5.15176e-06 0.00056893 -0.00787906 -0.0217381 -0.0370066 -0.00770505 0.00659312 0.00975477 0.00949456 0.00777552 0.00655645 0.00568776 0.00508782 0.00458121 0.00410187 0.00365665 0.0015121 0.00160863 0.00263181 0.00638941 0.00772607 0.00225583 0.0010843 0.000882939 0.000801563 0.00075632 0.000554992 0.000435131 0.0003474 0.000217667 0.000491602 0.0012267 0.00250446 0.000212058 -0.0174972 -0.0527527 -0.0479071 0.194908 1.45838 3.40677 4.49242 4.86894 4.97215 5.01218 5.04342 5.06228 5.03069 4.87169 4.57056 4.11523 3.38264 2.19691 0.715839 0.172818 0.102162 0.0627162 0.0363388 0.020289 0.0119414 0.00826608 0.0066417 0.00549092 0.00492505 0.00439443 0.0037156 0.00306471 0.00247451 0.00195965 0.0014822 0.0010815 0.000904464 0.0010514 0.00152308 0.00120752 0.000228447 -0.00102833 -0.00116644 -0.00042067 4.78758e-05 5.09599e-05 -4.45756e-05 -3.22966e-06 3.81163e-05 7.94622e-05 0.000120808 0.000162154 0.000161895 0.000148481 0.000135068 0.000121654 0.000108241 9.81453e-05 9.2164e-05 8.61827e-05 8.02014e-05 7.42201e-05 6.82388e-05 6.22576e-05 5.62763e-05 5.0295e-05 4.43137e-05 3.83324e-05 3.54323e-05 3.321e-05 3.09877e-05 2.87654e-05 2.65431e-05 2.43209e-05 2.20986e-05 1.98763e-05 1.7654e-05 1.54317e-05 1.34612e-05 1.25441e-05 1.1627e-05 1.07099e-05 9.79276e-06 8.87564e-06 7.95851e-06 7.04139e-06 6.12427e-06 } v24 set { 5 5.01099 5.00866 4.97845 4.92369 4.9273 4.97413 4.9929 4.99826 4.99958 4.99978 5.00005 4.99968 4.99959 5.00014 4.99979 4.99914 4.99982 5.00023 5.00295 5.00664 4.99854 4.99647 5.00438 5.01722 5.03681 5.04766 5.04799 5.04867 5.04873 5.04685 5.04413 5.0367 5.02505 5.01726 5.01183 5.00806 5.00549 5.00371 5.00246 5.00162 5.00105 5.00069 5.00045 5.00031 5.00024 5.00019 5.00012 5.00007 5.00004 5.00001 4.99998 4.99999 4.99999 5 5.00001 5.00001 5.00002 5.00002 5.00003 5.00003 5.00003 5.00002 5.00002 5.00001 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5.00418 4.99953 4.99152 4.99807 5.00497 5.00112 5.00055 5.00038 5.00018 5.00006 5.00006 5.00007 5.00006 5.00004 5.00004 4.99853 4.99945 4.99998 5.00304 5.00935 5.00742 4.99181 4.97421 4.93603 4.8853 4.8927 4.93984 4.97458 4.99039 4.99614 4.99801 4.99851 4.99869 4.99924 5.00108 5.00181 5.00119 5.00059 5.00031 5.00022 5.00018 5.00011 5.00001 5.00006 4.99981 4.99977 4.99982 5.00012 4.99993 5.00008 5.00043 5.00048 5.00024 5.00008 4.99984 4.99993 5.00011 4.99996 4.9998 4.99977 4.9998 4.99993 5.00008 5.00011 5.00002 4.99995 4.99989 4.99993 5 5.00007 5.00009 4.99994 4.99977 4.9997 4.99975 4.99996 4.99996 4.99988 4.9997 4.99952 4.9995 4.99956 4.99973 4.99988 5.00005 5.00025 5.00042 5.00036 5.00031 5.00025 5.0002 5.00014 5.00009 5.00003 5.00002 5.00001 5.00001 5 4.99999 4.99998 4.99998 4.99997 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5.00284 5.00442 5.00381 4.98997 4.99092 5.00733 5.07791 4.98237 4.86434 4.76835 4.74067 4.79278 4.85094 4.90068 4.93603 4.95698 4.96984 4.97856 4.98869 4.99904 5.0005 4.99524 5.00181 5.01878 5.05177 5.07986 4.98917 4.56217 3.68 2.3539 1.18541 0.505772 0.221044 0.115287 0.0760938 0.0589194 0.0476784 0.0457213 0.0412911 0.033889 0.0259741 0.0191452 0.0139018 0.0100235 0.00711788 0.00497657 0.00349368 0.00250021 0.00176179 0.00121843 0.000838368 0.000582711 0.000423458 0.000294608 0.000201251 0.000133748 8.6227e-05 5.44252e-05 3.30514e-05 1.93926e-05 1.09814e-05 5.29857e-06 1.92247e-06 3.08708e-07 -3.74311e-07 -6.11121e-07 -7.27807e-07 -4.87604e-07 -4.80493e-07 -9.15925e-07 -2.03774e-06 -4.01128e-06 -2.46644e-06 2.10626e-06 8.22422e-06 1.04922e-05 9.83047e-06 7.27106e-06 3.29654e-06 -2.06736e-06 -2.18019e-06 -2.29303e-06 -2.40586e-06 -2.51869e-06 -2.63153e-06 -2.24615e-06 -1.70325e-06 -1.16036e-06 -6.17468e-07 -7.45754e-08 2.45198e-07 2.88285e-07 3.31373e-07 3.7446e-07 4.17548e-07 4.60635e-07 5.03723e-07 5.4681e-07 5.89898e-07 6.32985e-07 6.76073e-07 6.19054e-07 5.4001e-07 4.60967e-07 3.81923e-07 3.02879e-07 2.23836e-07 1.44792e-07 6.57488e-08 -1.32948e-08 -9.23383e-08 -1.6698e-07 -2.23206e-07 -2.79432e-07 -3.35658e-07 -3.91884e-07 -4.48109e-07 -5.04335e-07 -5.60561e-07 -6.16787e-07 } v25 set { 1.34824 1.35838 1.36465 1.34675 1.29167 1.23161 1.2201 1.2185 1.2181 1.21798 1.21793 1.21788 1.21785 1.21782 1.21779 1.21776 1.21655 1.21656 1.21669 1.21871 1.22421 1.22247 1.21858 1.2228 1.23803 1.27737 1.10647 0.395248 0.0600669 0.027687 0.0192374 0.015425 0.0130881 0.00977445 0.00696598 0.00491122 0.00341952 0.00237078 0.00162339 0.00109178 0.000726647 0.000478886 0.00031568 0.000207902 0.000143494 0.000109768 8.62987e-05 5.69775e-05 3.36547e-05 2.30356e-05 1.86108e-05 1.41861e-05 1.08293e-05 7.68835e-06 4.79593e-06 4.51019e-06 4.22444e-06 3.9387e-06 3.65295e-06 3.36721e-06 3.04559e-06 2.69981e-06 2.35403e-06 2.00825e-06 1.66247e-06 1.34508e-06 1.26225e-06 1.17941e-06 1.09657e-06 1.01373e-06 9.30893e-07 8.48054e-07 7.65216e-07 6.82378e-07 5.9954e-07 5.16702e-07 4.37489e-07 3.82774e-07 3.2806e-07 2.73346e-07 2.18632e-07 1.63917e-07 1.09203e-07 5.4489e-08 -2.2523e-10 -5.49395e-08 -1.09654e-07 -1.52862e-07 -1.3079e-07 -1.08718e-07 -8.6646e-08 -6.45739e-08 -4.25019e-08 -2.04298e-08 1.64229e-09 2.37144e-08 4.57864e-08 6.78585e-08 8.71693e-08 9.30725e-08 9.89758e-08 1.04879e-07 1.10782e-07 1.16685e-07 1.22589e-07 1.28492e-07 1.34395e-07 1.40298e-07 1.46201e-07 1.52105e-07 1.58008e-07 1.63911e-07 1.69814e-07 1.75718e-07 1.81621e-07 1.87524e-07 1.93427e-07 1.9933e-07 2.05234e-07 2.11137e-07 2.19788e-07 0.000393944 -0.000218983 -0.00105784 0.00172403 -0.00027134 -0.000204147 8.79968e-06 5.93762e-05 5.83554e-05 4.13815e-05 3.71369e-05 3.03372e-05 2.25336e-05 1.5986e-05 1.07284e-05 -7.5239e-05 5.60593e-05 6.97571e-05 0.000667617 0.000960856 0.00131749 -0.00759564 -0.0217897 -0.0450321 -0.076646 -0.128569 -0.186391 -0.202175 -0.206953 -0.2082 -0.208416 -0.208669 -0.208934 -0.209111 -0.209234 -0.209329 -0.209389 -0.209416 -0.2094 -0.209329 -0.20926 -0.209204 -0.209208 -0.209285 -0.209454 -0.209641 -0.20977 -0.209811 -0.209833 -0.209887 -0.209653 -0.209127 -0.208893 -0.208811 -0.208777 -0.208758 -0.208747 -0.20874 -0.208726 -0.208697 -0.208657 -0.208611 -0.208565 -0.208524 -0.208488 -0.208451 -0.208412 -0.208373 -0.208333 -0.208294 -0.208256 -0.208219 -0.208183 -0.208145 -0.208107 -0.208066 -0.208029 -0.207993 -0.207959 -0.207923 -0.207883 -0.207838 -0.207789 -0.207747 -0.20771 -0.207675 -0.207642 -0.207605 -0.207568 -0.207531 -0.207494 -0.207457 -0.20742 -0.207383 -0.207346 -0.207308 -0.207271 -0.207233 -0.207196 -0.207158 -0.207121 -0.207084 -0.207046 -0.207009 -0.206972 -0.206935 -0.206898 -0.206861 -0.206823 -0.206786 -0.206749 -0.206712 -0.206675 -0.206638 -0.2066 -0.206563 -0.206526 -0.206489 -0.206452 -0.206415 -0.203384 -0.20015 -0.196872 -0.205024 -0.210727 -0.206779 -0.0685263 0.586138 1.4665 2.22945 2.77554 3.076 3.24926 3.34515 3.40164 3.43006 3.43713 3.43075 3.42886 3.4384 3.46567 3.49025 3.51287 3.53821 3.57841 3.39846 2.80753 2.22947 1.7549 1.30429 0.707786 0.303206 0.131352 0.0671706 0.0429955 0.032461 0.0257161 0.0239521 0.0217397 0.0179705 0.0138745 0.0102813 0.00749643 0.0054328 0.00386817 0.0027004 0.00189442 0.00135552 0.000954715 0.000659981 0.000453435 0.000313993 0.000231347 0.000159665 0.000108122 7.10528e-05 4.50233e-05 2.77892e-05 1.62765e-05 8.9893e-06 4.5471e-06 1.54614e-06 -1.6542e-07 -8.68508e-07 -1.04369e-06 -9.63086e-07 -8.44294e-07 -6.57339e-07 -7.35885e-07 -9.80056e-07 -1.39772e-06 -2.10199e-06 -1.37474e-06 6.13269e-07 3.3028e-06 4.60941e-06 4.91053e-06 4.14186e-06 2.45258e-06 -8.7388e-09 -3.59647e-07 -7.10554e-07 -1.06146e-06 -1.41237e-06 -1.76328e-06 -1.63073e-06 -1.34534e-06 -1.05995e-06 -7.74561e-07 -4.8917e-07 -2.95733e-07 -2.16326e-07 -1.3692e-07 -5.75135e-08 2.18929e-08 1.01299e-07 1.80706e-07 2.60112e-07 3.39519e-07 4.18925e-07 4.98332e-07 4.83984e-07 4.4901e-07 4.14035e-07 3.79061e-07 3.44087e-07 3.09112e-07 2.74138e-07 2.39163e-07 2.04189e-07 1.69215e-07 1.26002e-07 4.83213e-08 -2.9359e-08 -1.07039e-07 -1.8472e-07 -2.624e-07 -3.4008e-07 -4.1776e-07 -4.95441e-07 } v26 set { 7.10441e-10 0.000309731 -0.000308186 -0.001694 -0.00360784 8.40909e-05 0.00203175 0.0012896 0.000596548 0.000277191 0.000161134 0.000120439 8.4915e-05 9.49929e-05 6.18812e-05 1.65433e-05 1.89682e-05 3.97578e-05 4.95446e-05 0.000225325 0.000214579 -0.00230134 -0.000451102 0.00997237 0.0341443 0.0449314 0.0424411 0.0341996 0.0315315 0.0308892 0.0291614 0.024365 0.0190282 0.0188976 0.017238 0.0138526 0.0105645 0.00778548 0.00561753 0.0039871 0.00279554 0.00194075 0.0013468 0.000934775 0.000664723 0.000498911 0.000377384 0.000254183 0.000163421 0.000120773 9.65058e-05 7.22384e-05 5.60316e-05 4.14549e-05 2.79516e-05 2.57096e-05 2.34677e-05 2.12257e-05 1.89837e-05 1.67417e-05 1.46737e-05 1.27228e-05 1.07719e-05 8.82099e-06 6.87009e-06 5.0896e-06 4.71705e-06 4.34451e-06 3.97196e-06 3.59941e-06 3.22686e-06 2.85431e-06 2.48176e-06 2.10921e-06 1.73666e-06 1.36411e-06 1.02855e-06 9.42931e-07 8.57316e-07 7.71701e-07 6.86086e-07 6.00471e-07 5.14856e-07 4.29241e-07 3.43626e-07 2.58011e-07 1.72396e-07 9.85409e-08 9.14091e-08 8.42773e-08 7.71456e-08 7.00138e-08 6.2882e-08 5.57503e-08 4.86185e-08 4.14867e-08 3.4355e-08 2.72232e-08 2.05821e-08 1.63235e-08 1.2065e-08 7.80643e-09 3.54786e-09 -7.10696e-10 -4.96926e-09 -9.22782e-09 -1.34864e-08 -1.77449e-08 -2.20035e-08 -2.62621e-08 -3.05206e-08 -3.47792e-08 -3.90378e-08 -4.32963e-08 -4.75549e-08 -5.18134e-08 -5.6072e-08 -6.03306e-08 -6.45891e-08 -6.88477e-08 -8.76373e-06 0.000131607 -0.00021685 -0.000433027 0.00047234 0.000211593 -0.000189601 3.2492e-05 0.000575955 7.72235e-05 -0.000285172 -0.000242061 -0.000135112 -3.50117e-05 -2.75868e-05 5.48974e-05 1.80604e-07 5.48911e-05 3.97478e-05 0.000192909 0.000297932 0.00402253 -0.0122366 -0.047853 -0.0963082 -0.108071 -0.0567275 -0.0239271 -0.0178628 -0.0233027 -0.031853 -0.0400843 -0.0482725 -0.0576154 -0.0627218 -0.0511236 -0.0279524 -0.0150986 -0.00931091 -0.00652876 -0.00479286 -0.00344346 -0.00249578 -0.0019532 -0.00157977 -0.00131848 -0.00111251 -0.000939229 -0.000797445 -0.000708384 -0.000630452 -0.000539722 -0.000508862 -0.000480596 -0.000439484 -0.000407217 -0.000363866 -0.000329506 -0.000318642 -0.000307362 -0.000286511 -0.000266253 -0.000242943 -0.000218107 -0.000204661 -0.00020241 -0.000194435 -0.000185062 -0.000173042 -0.000160549 -0.000151407 -0.000145626 -0.000145976 -0.000147342 -0.000145288 -0.000137979 -0.000124481 -0.000123218 -0.000127453 -0.000139006 -0.000145486 -0.000129764 -9.82749e-05 -4.72596e-05 -3.08671e-05 -3.28834e-05 -4.52254e-05 -6.25389e-05 -6.32516e-05 -6.39643e-05 -6.4677e-05 -6.53897e-05 -6.61023e-05 -6.6815e-05 -6.75277e-05 -6.61005e-05 -6.45173e-05 -6.29341e-05 -6.13509e-05 -5.97676e-05 -5.81844e-05 -5.66012e-05 -5.54231e-05 -5.4455e-05 -5.3487e-05 -5.25189e-05 -5.15508e-05 -5.05828e-05 -4.96147e-05 -4.86466e-05 -4.76785e-05 -4.67105e-05 -4.57424e-05 -4.47743e-05 -4.38063e-05 -4.28382e-05 -4.18821e-05 -4.10211e-05 -4.016e-05 -3.9299e-05 -3.8438e-05 4.29885e-05 5.14113e-05 -0.000127986 -0.000611463 -0.000149428 0.000882394 0.00297059 -0.00405825 -0.00591067 -0.00546997 -0.00158744 0.00190677 0.00298403 0.00268595 0.00196161 0.00130289 0.000783347 0.000520683 0.000565306 0.00053419 -0.00224696 -0.000920818 0.0132755 0.0322504 0.0442808 0.0638615 0.0701007 0.0539356 0.0247771 0.056244 0.294266 0.831368 1.45424 2.02898 2.54559 2.9937 3.35333 3.72609 4.06363 4.32789 4.52413 4.66504 4.7652 4.83637 4.88631 4.92109 4.94464 4.96046 4.97218 4.98079 4.98679 4.99076 4.99361 4.99555 4.99686 4.99783 4.99853 4.99902 4.99936 4.99959 4.99973 4.99983 4.9999 4.99993 4.99996 4.99998 5 5.00001 5 4.99999 4.99997 4.99994 4.99993 4.99994 4.99996 4.99999 5.00004 5.00006 5.00005 5.00003 5.00002 5.00001 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99998 } v27 set { 5 4.99984 4.99796 4.99478 4.9889 4.98738 4.98896 4.99087 4.99262 4.99419 4.99552 4.99659 4.99743 4.99807 4.99855 4.9989 4.99894 4.99908 4.99935 5.00001 5.0007 5.00132 5.00032 4.99976 5.00134 5.00339 5.00315 5.00157 5.00091 5.00058 5.00012 4.99944 4.99886 4.9994 4.99934 4.99899 4.99876 4.99868 4.99872 4.99883 4.99898 4.99914 4.9993 4.99944 4.99956 4.99967 4.99976 4.99982 4.99986 4.9999 4.99993 4.99997 4.99997 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5.00009 5.00028 5.00015 4.99983 5.00036 4.99996 4.99834 4.99783 5.00383 5.00734 5.00387 5.00058 4.99893 4.99836 4.99832 4.99854 4.99873 4.99905 4.99927 4.99952 4.99969 4.99834 4.99536 4.99163 4.99073 5.0053 5.03631 5.03103 4.9008 4.62503 4.21887 3.70902 3.09967 2.35791 1.41912 0.519675 0.210458 0.131362 0.0980819 0.0708209 0.0471701 0.0323272 0.0253535 0.0199144 0.0152615 0.0117228 0.00917696 0.00738117 0.00609292 0.00512664 0.00436184 0.0037961 0.00331639 0.00289006 0.0025477 0.00226529 0.00202925 0.00182793 0.00165474 0.00150531 0.00137529 0.00125983 0.00115603 0.00106455 0.000982977 0.000911255 0.000846819 0.000790092 0.000738698 0.000692816 0.00065107 0.000613595 0.000579642 0.000548935 0.00052106 0.000495598 0.000472174 0.000450849 0.000431118 0.000412667 0.000395868 0.000381319 0.000368487 0.000357327 0.000344212 0.000330334 0.00031622 0.000303298 0.000295809 0.00028832 0.000280831 0.000273342 0.000265853 0.000258364 0.000250875 0.000245118 0.000239488 0.000233857 0.000228227 0.000222596 0.000216966 0.000211336 0.000207047 0.000203455 0.000199863 0.00019627 0.000192678 0.000189085 0.000185493 0.0001819 0.000178308 0.000174716 0.000171123 0.000167531 0.000163938 0.000160346 0.000156835 0.000153973 0.00015111 0.000148248 0.000145385 0.000296579 -3.96718e-05 -0.000449085 0.000323433 0.000750086 0.000268264 0.000149028 -0.000100249 7.00956e-05 0.00012605 0.00022592 0.000193036 0.000120453 8.07865e-05 7.65771e-05 -3.27828e-05 0.000116759 0.000169498 0.000409804 0.000414965 0.00092323 -0.00590633 -0.0175477 -0.032433 -0.0559842 -0.0820373 0.0688484 0.626629 1.32929 2.01657 2.60925 3.12329 3.38952 3.14128 2.38463 1.23802 0.316019 0.107832 0.0694707 0.051837 0.035247 0.0209999 0.0116618 0.00967674 0.00789182 0.00574566 0.00386872 0.00258612 0.00167126 0.00104169 0.000641093 0.000401246 0.000277928 0.000171775 0.000102266 5.89376e-05 3.29258e-05 1.80463e-05 1.0057e-05 6.4571e-06 5.10093e-06 4.06791e-06 3.62716e-06 3.63321e-06 3.99625e-06 4.64368e-06 5.20886e-06 4.77728e-06 3.23919e-06 1.14113e-06 -1.29416e-06 -4.15607e-06 -1.88532e-06 5.24411e-06 1.38678e-05 1.28823e-05 3.6758e-06 -2.52285e-06 -3.97133e-06 -4.03071e-06 -3.37154e-06 -2.71238e-06 -2.05321e-06 -1.39404e-06 -7.34872e-07 -3.73325e-07 -1.05873e-07 1.61578e-07 4.2903e-07 6.96482e-07 8.18468e-07 7.60065e-07 7.01662e-07 6.43258e-07 5.84855e-07 5.26452e-07 4.68049e-07 4.09646e-07 3.51243e-07 2.9284e-07 2.34437e-07 1.71213e-07 1.06928e-07 4.2644e-08 -2.16403e-08 -8.59247e-08 -1.50209e-07 -2.14493e-07 -2.78778e-07 -3.43062e-07 -4.07346e-07 -4.55065e-07 -4.3348e-07 -4.11896e-07 -3.90311e-07 -3.68726e-07 -3.47141e-07 -3.25556e-07 -3.03971e-07 -2.82386e-07 } v28 set { 0.368163 0.361756 0.327463 0.269513 0.149476 0.0805716 0.0501146 0.03403 0.0230886 0.0160474 0.0116071 0.00870013 0.00679614 0.00542384 0.00432512 0.00340653 -0.00129719 -0.00399429 -0.00318719 0.00443085 0.0150156 0.0334147 0.0132288 -0.0189751 -0.0508377 -0.0252174 -0.0142489 -0.00675908 -0.0038653 -0.00243423 -0.00168891 -0.00120901 -0.000900426 -0.000685575 -0.000557595 -0.000457268 -0.000377427 -0.000315269 -0.000266613 -0.000228397 -0.000198283 -0.000174248 -0.000154886 -0.00013892 -0.000125864 -0.000115189 -0.000105841 -9.66611e-05 -8.84262e-05 -8.23872e-05 -7.74668e-05 -7.25463e-05 -6.79992e-05 -6.35276e-05 -5.92413e-05 -5.68994e-05 -5.45574e-05 -5.22154e-05 -4.98735e-05 -4.75315e-05 -4.54981e-05 -4.36726e-05 -4.18471e-05 -4.00216e-05 -3.81961e-05 -3.64559e-05 -3.54209e-05 -3.43858e-05 -3.33508e-05 -3.23157e-05 -3.12807e-05 -3.02456e-05 -2.92105e-05 -2.81755e-05 -2.71404e-05 -2.61054e-05 -2.51232e-05 -2.44984e-05 -2.38736e-05 -2.32487e-05 -2.26239e-05 -2.19991e-05 -2.13742e-05 -2.07494e-05 -2.01246e-05 -1.94998e-05 -1.88749e-05 -1.82865e-05 -1.79044e-05 -1.75224e-05 -1.71403e-05 -1.67582e-05 -1.63762e-05 -1.59941e-05 -1.56121e-05 -1.523e-05 -1.4848e-05 -1.44659e-05 -1.41138e-05 -1.39075e-05 -1.37011e-05 -1.34947e-05 -1.32883e-05 -1.30819e-05 -1.28755e-05 -1.26691e-05 -1.24627e-05 -1.22563e-05 -1.205e-05 -1.18436e-05 -1.16372e-05 -1.14308e-05 -1.12244e-05 -1.1018e-05 -1.08116e-05 -1.06052e-05 -1.03988e-05 -1.01924e-05 -9.98605e-06 -9.77966e-06 -2.85319e-05 0.00281092 0.00180106 -0.000981083 0.00551926 -0.00119763 -0.0295069 -0.0367677 0.064749 0.119022 0.0882007 0.0552062 0.03418 0.0223243 0.015545 0.011949 0.00757134 0.00667655 0.00583243 0.00644443 0.00650959 -0.0302575 -0.0437806 -0.0355466 0.0381776 0.282109 0.674178 1.07582 1.45189 1.789 2.08649 2.34663 2.57245 2.81211 3.04778 3.2523 3.45877 3.65593 3.83396 3.9923 4.13368 4.25864 4.36719 4.46064 4.54086 4.60962 4.66835 4.71838 4.76094 4.79716 4.82796 4.85413 4.87634 4.89518 4.91116 4.92476 4.93631 4.94608 4.95434 4.9613 4.96715 4.97211 4.97638 4.98001 4.98312 4.98571 4.98795 4.98979 4.99138 4.99269 4.99381 4.99474 4.99551 4.99615 4.99668 4.99713 4.99752 4.99783 4.99811 4.99836 4.99858 4.99873 4.99884 4.99892 4.999 4.99907 4.99912 4.99916 4.99921 4.99926 4.99932 4.99937 4.99942 4.99948 4.99953 4.99956 4.99958 4.99961 4.99963 4.99966 4.99968 4.99971 4.99972 4.99973 4.99974 4.99975 4.99976 4.99977 4.99978 4.99979 4.9998 4.9998 4.99981 4.99982 4.99983 4.99984 4.99985 4.99986 4.99986 4.99987 4.99987 5.00498 5.00354 4.99359 4.98981 5.00498 5.00099 5.00041 5.00022 5.00015 5.00012 5.0001 5.00008 5.00005 5.00003 5 4.99431 4.99459 4.99591 5.00087 5.01029 5.03935 4.92784 4.51643 3.78356 2.68745 1.43417 0.583128 0.205094 0.0777337 0.0391566 0.02723 0.023883 0.018808 0.010165 0.00254623 -0.00377463 -0.0038097 0.00144145 0.00267231 0.00193045 0.00144538 0.00121758 0.00112893 0.00109424 0.0010226 0.000948072 0.000882573 0.000826996 0.000776391 0.000729719 0.000686499 0.000647333 0.000610108 0.000575631 0.000545069 0.000515485 0.000488514 0.000465316 0.000443215 0.000422454 0.00040292 0.00038488 0.000368472 0.000353628 0.000339643 0.000326197 0.000313483 0.000302884 0.000294038 0.000284003 0.000270941 0.000254925 0.000246511 0.000244089 0.000245538 0.000242099 0.000235728 0.000227482 0.000218001 0.000207257 0.000202127 0.000196997 0.000191868 0.000186738 0.000181608 0.00017758 0.000173899 0.000170219 0.000166538 0.000162857 0.000159576 0.00015679 0.000154005 0.000151219 0.000148433 0.000145647 0.000142861 0.000140076 0.00013729 0.000134504 0.000131718 0.000129603 0.000127635 0.000125668 0.0001237 0.000121732 0.000119765 0.000117797 0.000115829 0.000113862 0.000111894 0.000109993 0.000108372 0.000106751 0.00010513 0.000103509 0.000101887 0.000100266 9.86449e-05 9.70237e-05 } v29 set { 5 4.99899 4.99654 4.99327 4.9863 4.98954 4.99212 4.99378 4.9951 4.99624 4.99715 4.99786 4.99839 4.99879 4.99909 4.99931 4.99922 4.99933 4.99971 5.00064 5.00084 5.00123 4.99865 4.99853 4.99983 5.00457 5.00242 5.00105 5.00062 5.00042 4.99971 4.9994 4.9992 4.9996 4.99955 4.99932 4.99918 4.99915 4.99919 4.99927 4.99937 4.99948 4.99957 4.99966 4.99974 4.9998 4.99985 4.99989 4.99992 4.99993 4.99994 4.99994 4.99996 4.99998 5 5 5.00001 5.00001 5.00001 5.00002 5.00002 5.00001 5.00001 5.00001 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 4.9997 4.99998 4.99954 4.99963 5.00059 4.99945 4.99732 4.99957 5.00919 5.00558 5.00033 4.99851 4.9983 4.99854 4.99871 4.99928 4.99914 4.99939 4.99952 4.9998 4.99976 4.99744 4.99598 4.99478 4.99806 5.01911 5.04602 5.05469 5.01317 4.89484 4.69655 4.42036 4.06069 3.60793 3.12531 2.72975 2.45187 2.25081 2.09841 1.98509 1.90211 1.84084 1.79411 1.7574 1.72763 1.70283 1.68188 1.66389 1.64823 1.63438 1.62201 1.61088 1.60081 1.59163 1.58323 1.57549 1.56835 1.56173 1.55558 1.54985 1.54451 1.53951 1.53479 1.53035 1.52615 1.5222 1.51845 1.5149 1.51153 1.50834 1.50529 1.5024 1.49964 1.497 1.49449 1.49208 1.48977 1.48755 1.48542 1.48336 1.48138 1.47948 1.47765 1.4759 1.47419 1.47255 1.47096 1.46949 1.46823 1.46696 1.4657 1.46444 1.46317 1.46191 1.46065 1.45956 1.4585 1.45743 1.45636 1.45529 1.45422 1.45315 1.45226 1.45145 1.45064 1.44983 1.44902 1.44821 1.4474 1.44659 1.44579 1.44498 1.44417 1.44336 1.44255 1.44174 1.44094 1.44019 1.43944 1.43868 1.43793 1.43765 1.43679 1.43515 1.43405 1.43478 1.43387 1.43345 1.43184 1.43086 1.43021 1.43003 1.42988 1.42944 1.42883 1.42818 1.42702 1.42642 1.42595 1.42586 1.42616 1.42783 1.41733 1.38106 1.30738 1.3877 2.09819 3.05285 3.58059 3.77601 3.87609 4.02557 4.24887 4.4608 4.60411 4.72109 4.8255 4.90465 4.97379 5.01253 5.01532 5.01239 5.0092 5.00665 5.00474 5.00333 5.00232 5.00163 5.00117 5.00082 5.00057 5.00039 5.00027 5.00019 5.00013 5.00009 5.00006 5.00004 5.00003 5.00002 5.00001 5.00001 5 5 5 4.99998 4.99995 4.99992 4.99996 5.00005 5.00012 5.00008 4.99996 4.9999 4.99985 4.99986 4.99997 5.00021 5.0003 5.00024 5.00009 5.00007 5.00005 5.00003 5.00001 4.99998 4.99998 4.99998 4.99999 4.99999 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 } v30 set { 7.10441e-10 5.70385e-05 0.000226143 0.000131916 -0.000887764 -8.01837e-05 -3.49653e-05 9.40039e-05 0.000118663 0.000108025 8.6059e-05 6.33268e-05 4.99295e-05 3.16843e-05 3.60692e-05 2.07572e-05 -8.6375e-05 3.44583e-05 8.07397e-05 0.000196296 0.000115615 -7.12768e-05 -0.000129812 -4.18679e-05 7.94364e-05 0.000182034 -5.41226e-05 -0.000451819 -0.000713937 -0.00129863 -0.00262186 -0.00213417 -0.00133767 0.000775698 0.000969902 0.000549281 0.000280946 0.000140321 8.6919e-05 7.22446e-05 6.5631e-05 6.45263e-05 6.63087e-05 7.17391e-05 7.59042e-05 7.59172e-05 7.03353e-05 6.33558e-05 5.31136e-05 4.64278e-05 4.40594e-05 4.16909e-05 4.05674e-05 3.96957e-05 3.87875e-05 3.74977e-05 3.62079e-05 3.49181e-05 3.36283e-05 3.23385e-05 3.12427e-05 3.02775e-05 2.93124e-05 2.83472e-05 2.7382e-05 2.64613e-05 2.59077e-05 2.5354e-05 2.48004e-05 2.42468e-05 2.36931e-05 2.31395e-05 2.25859e-05 2.20322e-05 2.14786e-05 2.0925e-05 2.03916e-05 1.9995e-05 1.95984e-05 1.92019e-05 1.88053e-05 1.84087e-05 1.80122e-05 1.76156e-05 1.7219e-05 1.68225e-05 1.64259e-05 1.6051e-05 1.57991e-05 1.55471e-05 1.52952e-05 1.50433e-05 1.47913e-05 1.45394e-05 1.42875e-05 1.40356e-05 1.37836e-05 1.35317e-05 1.32978e-05 1.31513e-05 1.30048e-05 1.28583e-05 1.27118e-05 1.25653e-05 1.24188e-05 1.22724e-05 1.21259e-05 1.19794e-05 1.18329e-05 1.16864e-05 1.15399e-05 1.13934e-05 1.12469e-05 1.11005e-05 1.0954e-05 1.08075e-05 1.0661e-05 1.05145e-05 1.0368e-05 1.02215e-05 1.76447e-05 7.21516e-05 -3.59786e-05 -0.000159618 0.000156236 0.000135106 -0.000336402 -0.000302283 0.000699323 0.000473866 -0.000156146 -0.000225625 -0.000123592 -3.78116e-05 8.47472e-06 2.43387e-06 -7.44762e-05 7.80111e-05 9.43608e-05 0.000170159 8.83919e-05 -0.00018802 -0.000373512 -0.000390597 0.000156875 0.0032343 0.00776304 -0.000566905 -0.00760695 -0.0159226 -0.0245989 -0.0331402 -0.0100902 0.067837 0.266702 0.910818 1.82282 2.69714 3.43247 3.98325 4.32893 4.51529 4.67087 4.79288 4.87574 4.92797 4.95902 4.97655 4.98622 4.99195 4.99526 4.99735 4.9991 4.99974 4.99982 4.99974 4.99961 4.9995 4.99943 4.9994 4.9994 4.99942 4.99944 4.99948 4.99952 4.99956 4.99961 4.99965 4.9997 4.99974 4.99977 4.99981 4.99983 4.99986 4.99988 4.9999 4.99991 4.99992 4.99993 4.99994 4.99995 4.99995 4.99996 4.99997 4.99997 4.99998 4.99998 4.99999 4.99999 4.99999 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5.00019 4.99888 4.99663 4.99457 4.99902 5.00229 5.00323 5.00302 5.0023 5.0015 5.00085 5.00041 5.00013 4.99993 4.99979 4.99948 4.99954 4.99983 5.00055 5.00109 5.00009 4.9987 4.998 4.99755 4.99676 4.99618 5.01091 5.05272 5.04156 4.80112 4.27692 3.42343 2.23953 0.967179 0.429813 0.540757 1.32991 2.32147 3.14903 3.78143 4.22325 4.47978 4.59448 4.69875 4.79798 4.87419 4.92339 4.95249 4.97174 4.98408 4.99124 4.99478 4.99729 4.99868 4.9992 4.99941 4.99947 4.99946 4.99943 4.9994 4.99939 4.9994 4.99942 4.99946 4.99951 4.99956 4.99961 4.99967 4.99973 4.99977 4.9998 4.99981 4.99983 4.99984 4.99987 4.99992 5.00001 5.00005 5.00001 4.99994 4.99995 4.99995 4.99996 4.99996 4.99996 4.99997 4.99997 4.99997 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 } v31 set { 1.8179e-09 -5.28841e-06 -1.44913e-05 -3.62932e-05 -9.75719e-05 0.000141781 3.73396e-05 -1.65603e-05 -1.5271e-05 -6.73884e-06 4.40157e-06 -4.85345e-06 -1.02964e-05 2.03126e-05 -1.89457e-05 -8.75564e-06 7.67422e-06 4.71103e-06 1.29798e-05 6.13469e-06 -1.14363e-05 -0.0394563 -0.0477298 -0.0622012 -0.0519225 0.262499 0.943611 1.67052 2.31017 2.84028 3.28467 3.61582 3.85887 4.13011 4.36511 4.54063 4.67013 4.76408 4.83263 4.8825 4.91837 4.94373 4.96117 4.97318 4.98093 4.98562 4.98906 4.99267 4.99539 4.99666 4.99731 4.99797 4.99844 4.99887 4.99927 4.99933 4.99938 4.99944 4.99949 4.99955 4.9996 4.99965 4.9997 4.99975 4.9998 4.99985 4.99986 4.99987 4.99989 4.9999 4.99991 4.99992 4.99993 4.99995 4.99996 4.99997 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5.00001 5.00001 5.00001 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99997 5.00002 5.00004 5.0001 5.0001 4.99987 5.00009 5.00021 5.00002 5.00004 4.99988 5.00013 4.99993 5.00026 4.99973 5 5.00006 5.00009 5.00004 5.00004 5.04854 4.82711 4.04208 2.64155 0.838902 0.19014 0.0982549 0.0723197 0.0576863 0.0427644 0.0301979 0.020146 0.0135728 0.00980358 0.00774482 0.00586604 0.0036687 0.00211511 0.00121906 0.000647581 0.000828436 0.00190938 0.00224254 0.00199956 0.00165488 0.00135612 0.00113715 0.000984181 0.000877175 0.000789973 0.000741139 0.000689338 0.000625676 0.000586082 0.000550152 0.000529573 0.000505606 0.000482117 0.000460574 0.000441649 0.000424674 0.000408398 0.000391914 0.000376272 0.000361487 0.000348181 0.000336045 0.000324466 0.000313545 0.000303046 0.000293056 0.00028356 0.000274586 0.000266155 0.000258279 0.000250938 0.000243789 0.000236912 0.000230244 0.000224186 0.000219291 0.000215346 0.000212468 0.000207291 0.000200862 0.00019368 0.000186767 0.000183515 0.000180263 0.00017701 0.000173758 0.000170506 0.000167253 0.000164001 0.000161164 0.000158357 0.00015555 0.000152743 0.000149936 0.000147129 0.000144322 0.000142066 0.000140096 0.000138127 0.000136157 0.000134187 0.000132218 0.000130248 0.000128278 0.000126308 0.000124339 0.000122369 0.000120399 0.000118429 0.00011646 0.000114527 0.000112892 0.000111258 0.000109623 0.000107988 0.000103598 6.86052e-05 3.337e-05 7.00783e-05 0.000218764 0.000221318 0.000118593 -0.000113962 5.78552e-05 9.42068e-05 0.000237037 0.000171302 0.0001033 6.16066e-05 5.52908e-05 6.30233e-05 7.01897e-05 8.48573e-05 0.000106859 8.37213e-05 -0.0391541 -0.047722 -0.0618454 -0.0169804 0.345725 1.03426 1.74825 2.37152 2.88737 3.32173 3.66761 3.9707 4.17762 3.98832 3.30483 2.09737 0.710892 0.148159 0.0707463 0.0555808 0.045618 0.0319116 0.0199589 0.0133357 0.00898528 0.00586075 0.00375478 0.00245443 0.00156038 0.000962344 0.000590953 0.000375107 0.000250243 0.00015882 0.000100203 6.18122e-05 3.7372e-05 2.23009e-05 1.32569e-05 8.29437e-06 5.72457e-06 3.96832e-06 2.98935e-06 2.59699e-06 2.75024e-06 3.38689e-06 4.0453e-06 3.50095e-06 1.64988e-06 -3.84371e-07 -2.03828e-06 -3.46401e-06 -1.24301e-06 4.63458e-06 1.14104e-05 1.02619e-05 2.15487e-06 -2.98487e-06 -3.67221e-06 -2.94279e-06 -2.58649e-06 -2.23019e-06 -1.87389e-06 -1.5176e-06 -1.1613e-06 -7.92127e-07 -4.18889e-07 -4.56502e-08 3.27588e-07 7.00827e-07 8.79539e-07 8.17025e-07 7.5451e-07 6.91996e-07 6.29481e-07 5.66966e-07 5.04452e-07 4.41937e-07 3.79422e-07 3.16908e-07 2.54393e-07 1.90078e-07 1.25366e-07 6.0654e-08 -4.05776e-09 -6.87696e-08 -1.33481e-07 -1.98193e-07 -2.62905e-07 -3.27617e-07 -3.92329e-07 -4.40392e-07 -4.18802e-07 -3.97213e-07 -3.75624e-07 -3.54035e-07 -3.32446e-07 -3.10856e-07 -2.89267e-07 -2.67678e-07 } v32 set { 1.10294 1.10297 1.10291 1.10277 1.10259 1.10294 1.10313 1.10306 1.10299 1.10296 1.10295 1.10295 1.10294 1.10294 1.10294 1.10294 1.10294 1.10294 1.10294 1.10296 1.10296 1.00547 0.998599 1.5201 2.49297 3.31258 3.73162 3.84757 3.92505 4.02965 4.16599 4.30294 4.41541 4.52886 4.64414 4.73865 4.81065 4.86391 4.90315 4.93188 4.95258 4.96726 4.97738 4.98436 4.98888 4.99162 4.99363 4.99573 4.99731 4.99804 4.99843 4.99881 4.99909 4.99934 4.99957 4.9996 4.99964 4.99967 4.9997 4.99973 4.99977 4.9998 4.99983 4.99986 4.99988 4.99991 4.99992 4.99992 4.99993 4.99994 4.99994 4.99995 4.99996 4.99996 4.99997 4.99997 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5.00028 4.99988 4.99968 5.00019 4.99987 5.00021 4.99973 4.99977 4.99996 4.99997 5.0002 4.99957 5.00026 4.99947 5.00074 5.00003 4.99987 4.99979 5.00008 4.99997 5.08794 5.05993 4.76875 3.99197 3.10174 2.5197 2.21771 2.04 1.92235 1.83874 1.77592 1.72665 1.686 1.65276 1.6286 1.61299 1.60039 1.58934 1.57954 1.57083 1.56306 1.55604 1.54963 1.54375 1.53832 1.53331 1.52865 1.52432 1.52026 1.51645 1.51287 1.50949 1.50629 1.50327 1.50039 1.49766 1.49505 1.49257 1.49019 1.48792 1.48574 1.48365 1.48164 1.47971 1.47784 1.47604 1.47431 1.47264 1.47102 1.46945 1.46794 1.46647 1.46505 1.46367 1.46233 1.46103 1.45976 1.45853 1.45733 1.45616 1.45502 1.45392 1.45284 1.45179 1.45076 1.44975 1.4488 1.44795 1.44711 1.44626 1.44541 1.44457 1.44372 1.44287 1.44212 1.44138 1.44063 1.43989 1.43914 1.4384 1.43766 1.43701 1.43641 1.43581 1.43522 1.43462 1.43402 1.43342 1.43282 1.43223 1.43163 1.43103 1.43043 1.42984 1.42924 1.42865 1.42808 1.42752 1.42695 1.42639 1.42584 1.42529 1.42472 1.42412 1.42365 1.42326 1.42304 1.42162 1.42082 1.42032 1.42029 1.42026 1.41995 1.41947 1.41894 1.41841 1.4179 1.41742 1.41699 1.41656 1.32097 1.30963 1.78765 2.64656 3.35764 3.747 3.86589 3.94217 4.04185 4.18453 4.3561 4.53439 4.68621 4.74905 4.77848 4.84629 4.91261 4.97541 5.01284 5.01548 5.01248 5.00924 5.00666 5.00475 5.00334 5.00234 5.00164 5.00118 5.00083 5.00058 5.0004 5.00028 5.00019 5.00013 5.00009 5.00007 5.00004 5.00003 5.00002 5.00001 5.00001 5.00001 5 5 4.99999 4.99995 4.99992 4.99996 5.00006 5.00012 5.00009 4.99997 4.9999 4.99985 4.99986 4.99997 5.00021 5.00031 5.00024 5.0001 5.00007 5.00005 5.00003 5.00001 4.99998 4.99998 4.99999 4.99999 4.99999 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 } v33 set { 5 5.00012 5.00023 5.0003 4.99972 4.99988 4.99984 4.99991 4.99996 4.99999 5.00008 5.00009 4.99986 5.00003 5.00007 4.99995 4.9999 4.99997 5.00013 5.00014 5.00013 4.99701 4.99763 4.99742 4.99998 5.02836 5.07262 4.96856 4.57267 3.85637 2.79544 1.45942 0.408016 0.084885 0.0271375 0.0119294 0.00707546 0.0051087 0.00373035 0.00264737 0.00186477 0.00130379 0.000915857 0.000653121 0.000483893 0.000380852 0.000302362 0.000219498 0.000154435 0.000121928 0.000104026 8.61242e-05 7.48526e-05 6.49216e-05 5.56238e-05 5.29689e-05 5.03139e-05 4.7659e-05 4.5004e-05 4.23491e-05 4.00356e-05 3.79522e-05 3.58687e-05 3.37852e-05 3.17018e-05 2.97592e-05 2.89804e-05 2.82016e-05 2.74228e-05 2.66441e-05 2.58653e-05 2.50865e-05 2.43077e-05 2.35289e-05 2.27501e-05 2.19714e-05 2.12346e-05 2.07821e-05 2.03295e-05 1.98769e-05 1.94244e-05 1.89718e-05 1.85192e-05 1.80667e-05 1.76141e-05 1.71615e-05 1.6709e-05 1.62828e-05 1.60061e-05 1.57294e-05 1.54527e-05 1.5176e-05 1.48993e-05 1.46226e-05 1.43459e-05 1.40692e-05 1.37925e-05 1.35158e-05 1.3262e-05 1.31191e-05 1.29761e-05 1.28332e-05 1.26903e-05 1.25474e-05 1.24045e-05 1.22615e-05 1.21186e-05 1.19757e-05 1.18328e-05 1.16898e-05 1.15469e-05 1.1404e-05 1.12611e-05 1.11182e-05 1.09752e-05 1.08323e-05 1.06894e-05 1.05465e-05 1.04036e-05 1.02606e-05 1.00185e-05 3.8343e-05 -3.06781e-05 -0.000111758 0.000111673 0.000130815 -0.000210491 -0.000231304 0.000310226 0.000265303 3.0878e-05 -4.48405e-05 -1.2852e-05 -7.84469e-06 3.29986e-05 -1.23286e-05 -6.07871e-05 5.35082e-05 7.69194e-05 0.000126221 6.57178e-05 0.00223349 -0.0148854 -0.0476636 -0.0491447 0.220125 1.11174 2.03988 2.90209 3.61069 4.13554 4.50679 4.71501 4.83916 4.91027 4.95284 4.98086 4.99151 4.98651 4.97113 4.95075 4.93102 4.93683 4.95457 4.97071 4.98212 4.98948 4.99386 4.99636 4.99785 4.9987 4.99927 4.99989 5.00014 5.00007 4.99988 4.99982 4.99976 4.99973 4.99972 4.99972 4.99973 4.99974 4.99975 4.99977 4.99979 4.99981 4.99984 4.99986 4.99988 4.99989 4.99991 4.99992 4.99993 4.99994 4.99995 4.99996 4.99996 4.99997 4.99997 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5.00001 5.00001 5.00001 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5.00012 4.99946 4.99839 4.99733 4.99948 5.00114 5.00158 5.00147 5.00113 5.00073 5.00043 5.0002 5.00006 4.99995 4.99986 4.99973 4.99976 4.9999 5.00029 5.00055 4.99704 4.99734 4.9972 5.00278 5.03354 5.07184 4.94057 4.51936 3.75638 2.60982 1.23803 0.315016 0.0796102 0.0252894 0.0165723 0.0827785 0.491298 1.40686 2.33436 3.1251 3.7691 4.22201 4.49976 4.68115 4.80513 4.88509 4.93208 4.95861 4.97579 4.98655 4.99268 4.99571 4.99771 4.99881 4.99929 4.99954 4.99965 4.9997 4.99971 4.99971 4.99971 4.99971 4.99972 4.99974 4.99976 4.99978 4.99981 4.99984 4.99987 4.99989 4.99991 4.99991 4.99992 4.99992 4.99993 4.99997 5.00003 5.00006 5.00004 5.00001 5 4.99999 4.99998 4.99998 4.99997 4.99997 4.99997 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 } v34 set { 5 5.00207 5.00813 5.01486 5.00156 5.0018 4.99861 4.99844 4.99888 4.9993 4.99956 4.99971 4.99979 4.99983 4.99987 4.99989 4.99671 4.9974 4.99864 5.00131 5.00377 5.0021 5.00039 4.99993 5.00004 5.0009 5.00109 4.99636 4.98617 4.96778 4.92047 4.89528 4.91112 4.9559 4.98286 4.99369 4.99812 4.99951 4.99994 5.00014 5.00008 4.99994 4.99984 4.99989 4.99998 5.00004 5.00004 5.00006 5.00005 5.00001 4.99997 4.99992 4.99993 4.99994 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 5.00131 5.00072 4.9977 4.99811 5.00325 4.99647 4.98948 4.99459 5.00262 5.00276 5.00156 5.00072 5.0003 5.00013 4.99995 4.99668 4.99775 4.99917 5.00173 5.00386 5.00188 4.99888 4.99757 4.99951 5.01712 5.0557 5.07088 5.07704 5.07758 5.06958 5.04223 5.03331 5.0279 5.03408 5.07611 5.01911 4.68594 3.99152 2.92195 1.69878 0.809 0.344091 0.154663 0.0788717 0.0467212 0.0336168 0.0280514 0.0254947 0.024173 0.0223567 0.0220555 0.0271514 0.0295872 0.0296052 0.0283971 0.0264726 0.0241813 0.0218244 0.0195349 0.017368 0.0152495 0.013295 0.0115444 0.00996982 0.00857091 0.00733891 0.00627261 0.0053494 0.00456316 0.00388373 0.00331073 0.00282181 0.00240991 0.00206389 0.00177187 0.00152283 0.00131167 0.00112558 0.000954373 0.000805726 0.00069326 0.000600991 0.000525743 0.00047355 0.00044359 0.000434815 0.000436053 0.000402511 0.000368969 0.000335427 0.000301886 0.000268344 0.000234802 0.00020126 0.000184967 0.000169932 0.000154896 0.000139861 0.000124825 0.00010979 9.47546e-05 8.67896e-05 8.24901e-05 7.81906e-05 7.38911e-05 6.95915e-05 6.5292e-05 6.09925e-05 5.66929e-05 5.23934e-05 4.80939e-05 4.37943e-05 3.94948e-05 3.51953e-05 3.08957e-05 2.67968e-05 2.42936e-05 2.17904e-05 1.92872e-05 1.6784e-05 0.00125927 -0.00794344 -0.0305499 -0.0621697 -0.0463796 -0.0224608 -0.00538381 0.00546086 0.0108675 0.012883 0.0131787 0.0127271 0.0119702 0.0110398 0.0100635 0.00649617 0.00489388 0.00545863 0.0098351 0.0167428 0.0126563 0.00697542 0.00427027 0.00330002 0.00390774 0.00408999 -0.00259143 -0.0160578 -0.0451849 -0.0409651 0.1301 0.597429 1.3848 2.63426 3.81272 4.51373 4.8412 4.98731 4.88165 4.37165 3.40034 2.17681 1.12217 0.505129 0.219703 0.104992 0.0622333 0.0448317 0.0355782 0.0311867 0.0293529 0.0274615 0.0288739 0.0307845 0.0304909 0.029245 0.0273602 0.0251006 0.022697 0.0202765 0.0179357 0.0157106 0.0136562 0.0117951 0.0101273 0.00865784 0.00739394 0.00634364 0.00551356 0.00480538 0.00415747 0.00356084 0.00297585 0.00236711 0.00181853 0.00160713 0.00169822 0.00166542 0.00145504 0.00120252 0.00109259 0.000982658 0.00087273 0.000762802 0.000652874 0.000584068 0.000528263 0.000472458 0.000416653 0.000360848 0.000321155 0.000301442 0.000281729 0.000262016 0.000242303 0.00022259 0.000202877 0.000183164 0.000163451 0.000143738 0.000124025 0.000114582 0.000107399 0.000100216 9.30332e-05 8.58502e-05 7.86672e-05 7.14841e-05 6.43011e-05 5.7118e-05 4.9935e-05 4.35378e-05 4.04281e-05 3.73184e-05 3.42088e-05 3.10991e-05 2.79894e-05 2.48798e-05 2.17701e-05 1.86604e-05 } v35 set { 7.24585e-12 2.21843e-05 3.20014e-05 1.25076e-05 -2.44947e-05 1.8425e-05 5.50546e-06 3.53025e-05 -1.07551e-05 -3.94383e-06 -2.27848e-06 -9.04789e-05 7.44215e-05 -2.7662e-05 0.000200038 -2.11998e-05 -2.09011e-05 2.37098e-05 2.18751e-05 -2.28422e-05 -6.23659e-05 3.58241e-05 1.76386e-05 -4.28311e-05 0.000355626 0.00156903 0.00100999 -0.0085304 -0.02067 -0.0389485 -0.0651568 -0.128475 -0.314362 -0.406837 -0.421558 -0.421277 -0.418176 -0.414481 -0.410845 -0.407348 -0.403971 -0.400716 -0.397582 -0.394563 -0.391658 -0.388866 -0.386178 -0.383585 -0.381094 -0.378789 -0.376569 -0.37435 -0.372256 -0.370188 -0.36815 -0.366422 -0.364694 -0.362967 -0.361239 -0.359511 -0.357888 -0.356334 -0.354781 -0.353227 -0.351674 -0.350152 -0.348888 -0.347625 -0.346361 -0.345098 -0.343834 -0.342571 -0.341307 -0.340044 -0.33878 -0.337517 -0.336279 -0.335215 -0.334152 -0.333088 -0.332024 -0.330961 -0.329897 -0.328833 -0.32777 -0.326706 -0.325642 -0.324601 -0.323683 -0.322766 -0.321849 -0.320932 -0.320014 -0.319097 -0.31818 -0.317263 -0.316345 -0.315428 -0.314545 -0.313825 -0.313106 -0.312387 -0.311667 -0.310948 -0.310228 -0.309509 -0.308789 -0.30807 -0.307351 -0.306631 -0.305912 -0.305192 -0.304473 -0.303754 -0.303034 -0.302315 -0.301595 -0.300876 -0.300157 -0.299437 -0.298716 -0.29798 -0.297329 -0.296691 -0.295837 -0.29516 -0.294725 -0.294044 -0.292917 -0.292351 -0.291965 -0.291365 -0.290687 -0.290027 -0.289376 -0.288772 -0.288193 -0.287505 -0.286892 -0.28626 -0.285714 -0.284545 -0.289246 -0.298717 -0.298492 -0.214163 0.181451 0.0749974 0.0454707 0.0292987 0.0196837 0.0124119 0.00884715 0.00527181 0.00585821 0.0296361 0.169856 0.361207 0.538856 0.67469 0.685933 0.392802 0.17772 0.0813085 0.0424601 0.0246654 0.0175258 0.0144256 0.0129859 0.012205 0.0112846 0.010933 0.0134813 0.0147254 0.0147981 0.0142156 0.0132732 0.0121355 0.0109587 0.00981238 0.00872731 0.00767007 0.00669346 0.00581341 0.00502167 0.00431819 0.00369842 0.00316168 0.00269663 0.00230035 0.00195801 0.00166928 0.00142286 0.00121522 0.00104072 0.000893384 0.000767675 0.000661268 0.000567659 0.000481766 0.000407101 0.000350044 0.000302721 0.000263424 0.000236813 0.00022199 0.000218182 0.000219548 0.0002027 0.000185853 0.000169006 0.000152158 0.000135311 0.000118463 0.000101616 9.33782e-05 8.57685e-05 7.81588e-05 7.0549e-05 6.29393e-05 5.53296e-05 4.77199e-05 4.36954e-05 4.15296e-05 3.93637e-05 3.71978e-05 3.50319e-05 3.28661e-05 3.07002e-05 2.85343e-05 2.63685e-05 2.42026e-05 2.20367e-05 1.98709e-05 1.7705e-05 1.55391e-05 1.34772e-05 1.22416e-05 1.10061e-05 9.77055e-06 8.535e-06 0.000631271 -0.00362586 -0.0146235 -0.0308486 -0.0237466 -0.0117522 -0.00304171 0.00251033 0.00531986 0.0063897 0.00657351 0.00636494 0.00599705 0.00553442 0.00505994 0.00330925 0.00246671 0.0027006 0.00473161 0.00830333 0.00649147 0.00356815 0.00217448 0.00187579 0.00270447 0.00219543 -0.00546118 -0.0179576 -0.0445306 -0.0649309 0.0197935 0.473629 0.87268 0.269542 0.0086094 0.0844602 0.606456 1.04929 0.906014 0.916205 0.919425 0.872867 0.556244 0.262457 0.11838 0.0571226 0.0333451 0.0237133 0.0185096 0.0159617 0.0148663 0.0138683 0.0144081 0.0153797 0.0152551 0.0146487 0.0137192 0.0125973 0.0113996 0.0101903 0.00901851 0.00790495 0.00687502 0.00593994 0.00510092 0.00436111 0.00372439 0.0031945 0.00277537 0.00241888 0.002095 0.00179943 0.00150419 0.00119264 0.00090934 0.000802394 0.000852816 0.000838368 0.000730842 0.000601028 0.000546616 0.000492205 0.000437793 0.000383381 0.000328969 0.00029454 0.000266428 0.000238317 0.000210205 0.000182093 0.000162091 0.000152145 0.000142198 0.000132252 0.000122306 0.000112359 0.000102413 9.24665e-05 8.25201e-05 7.25738e-05 6.26274e-05 5.78553e-05 5.42216e-05 5.05878e-05 4.69541e-05 4.33204e-05 3.96867e-05 3.60529e-05 3.24192e-05 2.87855e-05 2.51518e-05 2.19153e-05 2.03406e-05 1.8766e-05 1.71913e-05 1.56167e-05 1.4042e-05 1.24674e-05 1.08927e-05 9.31806e-06 } v36 set { 5 5.01426 5.02852 5.01923 4.77685 4.56471 4.52338 4.56813 4.63122 4.693 4.74776 4.79385 4.83258 4.86358 4.88918 4.91021 4.90553 4.89733 4.89554 4.91953 5.00757 5.07101 5.06318 5.05241 5.05535 5.08042 5.07251 4.90973 4.56136 3.98637 3.237 2.67216 2.33678 2.13529 2.00544 1.91429 1.84638 1.79461 1.75338 1.71958 1.69175 1.6686 1.64918 1.63258 1.61836 1.60607 1.59506 1.58483 1.57575 1.56847 1.56193 1.55538 1.54968 1.54416 1.5388 1.53523 1.53165 1.52807 1.52449 1.52091 1.51771 1.51477 1.51182 1.50888 1.50593 1.50309 1.50113 1.49917 1.4972 1.49524 1.49328 1.49132 1.48935 1.48739 1.48543 1.48346 1.48157 1.48012 1.47868 1.47724 1.47579 1.47435 1.47291 1.47146 1.47002 1.46857 1.46713 1.46574 1.46462 1.4635 1.46238 1.46126 1.46014 1.45902 1.4579 1.45678 1.45567 1.45455 1.45349 1.45275 1.45201 1.45127 1.45053 1.44979 1.44905 1.44831 1.44757 1.44683 1.44609 1.44535 1.44461 1.44387 1.44313 1.44239 1.44165 1.44091 1.44017 1.43943 1.43869 1.43795 1.43721 1.43874 1.43976 1.43619 1.43182 1.43726 1.43084 1.42587 1.42383 1.42642 1.42728 1.42736 1.4271 1.42669 1.42621 1.42569 1.41703 1.41244 1.41019 1.41199 1.41833 1.42502 1.41504 1.37535 1.28381 1.44779 2.33713 3.25835 3.67554 3.84975 4.01125 4.2253 4.45433 4.62215 4.74478 4.82998 4.8868 4.92396 4.94768 4.96498 4.98537 5.0128 5.04467 5.06722 5.06535 5.01475 4.91956 4.80647 4.7242 4.7059 4.73552 4.76379 4.81684 4.87376 4.92276 4.96112 4.9884 5.0045 5.00999 5.00933 5.00619 5.00384 5.00342 5.00373 5.00362 5.00309 5.00272 5.00239 5.00204 5.00172 5.00146 5.00124 5.00105 5.00089 5.00076 5.00065 5.00057 5.00048 5.00041 5.00034 5.00028 5.00023 5.00019 5.00015 5.00015 5.00016 5.0002 5.00023 5.00021 5.00019 5.00017 5.00015 5.00012 5.0001 5.00008 5.00007 5.00006 5.00005 5.00004 5.00003 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5.00062 4.99506 4.9835 4.96726 4.9728 4.97877 4.98675 4.9966 5.00406 5.00679 5.00629 5.00561 5.00487 5.00429 5.00384 5.002 5.00164 5.00229 5.00484 5.00769 5.00019 5.00242 5.01319 5.0335 5.07265 5.10129 5.11485 5.12551 5.13953 5.16048 5.18862 5.22811 5.25656 5.25627 5.19975 4.9139 4.24745 3.43732 2.8202 2.43224 2.17409 2.01333 1.93951 1.94622 1.98861 2.02217 2.05383 2.08376 2.11184 2.13793 2.16191 2.18267 2.20502 2.22837 2.24958 2.26901 2.28648 2.302 2.31582 2.32802 2.33869 2.34795 2.35596 2.36282 2.3687 2.37371 2.37797 2.38161 2.38476 2.38743 2.3897 2.39168 2.39329 2.39463 2.39575 2.39671 2.39756 2.39835 2.39907 2.39968 2.39999 2.4003 2.40061 2.40091 2.40122 2.40142 2.40159 2.40176 2.40193 2.4021 2.40222 2.40228 2.40234 2.4024 2.40247 2.40253 2.40259 2.40265 2.40271 2.40277 2.40284 2.40287 2.40289 2.40291 2.40294 2.40296 2.40298 2.40301 2.40303 2.40305 2.40308 2.4031 2.40311 2.40312 2.40313 2.40314 2.40315 2.40316 2.40317 2.40318 } v37 set { 5 5.01732 5.03181 5.05944 5.12686 5.20725 5.28103 5.31254 5.32901 5.33709 5.3408 5.34257 5.34311 5.34347 5.34386 5.34411 5.3406 5.33484 5.32942 5.32904 5.33644 5.34869 5.35001 5.34882 5.34758 5.34672 5.34599 5.34496 5.34364 5.34165 5.33712 5.33502 5.3366 5.34067 5.34306 5.34398 5.34434 5.34442 5.34443 5.34443 5.34441 5.34439 5.34437 5.34437 5.34438 5.34438 5.34438 5.34438 5.34438 5.34437 5.34437 5.34436 5.34436 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.35377 5.35451 5.34265 5.34488 5.35861 5.28622 4.90033 4.75027 4.89731 4.97098 4.99293 4.99832 4.99909 4.99956 4.99858 4.99829 4.9998 5.00035 5.0038 5.00989 5.00251 4.99438 4.9953 4.99761 4.99985 5.00152 5.0011 5.00046 4.99996 4.99925 4.99862 4.99919 4.99961 5.00048 5.00234 4.99654 4.98235 4.95936 4.83738 4.53021 4.21004 4.00593 3.91207 3.88059 3.87822 3.89117 3.91278 3.94044 3.97376 4.01152 4.05052 4.10679 4.17908 4.25673 4.33414 4.40875 4.47879 4.54342 4.60258 4.65595 4.70291 4.74414 4.78018 4.81185 4.83915 4.86291 4.88301 4.90048 4.91528 4.92802 4.9387 4.94777 4.95539 4.9618 4.96725 4.97195 4.97588 4.97932 4.98247 4.98512 4.98697 4.98831 4.98919 4.99015 4.99101 4.99169 4.99222 4.99282 4.99341 4.994 4.9946 4.99519 4.99578 4.99638 4.99667 4.99693 4.9972 4.99747 4.99773 4.998 4.99827 4.99841 4.99849 4.99856 4.99864 4.99872 4.9988 4.99888 4.99896 4.99904 4.99911 4.99919 4.99927 4.99935 4.99943 4.9995 4.99955 4.9996 4.99965 4.9997 5.00736 4.98252 4.87516 4.66727 4.49142 4.43103 4.4301 4.4571 4.49729 4.5407 4.5835 4.62363 4.66114 4.69577 4.72738 4.74632 4.75971 4.77576 4.80671 4.87073 4.91665 4.93252 4.94418 4.95331 4.96094 4.96727 4.97148 4.97471 4.97612 4.98276 5.00247 5.04086 5.08628 5.10673 5.08887 5.0564 5.02767 5.01336 4.99685 4.97422 4.90866 4.67035 4.33117 4.07888 3.94432 3.89105 3.88174 3.89292 3.91442 3.94564 3.98708 4.0355 4.09134 4.16315 4.24088 4.31918 4.39527 4.46693 4.53337 4.59405 4.6486 4.69693 4.73938 4.77617 4.80809 4.83551 4.85895 4.87894 4.89596 4.91081 4.92417 4.93651 4.94552 4.95198 4.9565 4.96096 4.96523 4.96972 4.97428 4.97868 4.98064 4.9826 4.98455 4.98651 4.98847 4.98967 4.99064 4.9916 4.99257 4.99353 4.99422 4.99457 4.99493 4.99528 4.99563 4.99598 4.99633 4.99668 4.99703 4.99738 4.99773 4.9979 4.99804 4.99817 4.9983 4.99843 4.99856 4.99869 4.99883 4.99896 4.99909 4.99921 4.99926 4.99931 4.99937 4.99942 4.99948 4.99953 4.99959 4.99964 } v38 set { 4.49849 4.53282 4.58329 4.66625 4.83345 4.97823 5.0207 5.01816 5.01116 5.00595 5.00296 5.00148 5.00073 5.00062 5.00033 5.0003 4.99864 4.99661 4.99652 4.99928 5.00361 5.12573 5.17251 5.22612 5.33479 5.44503 5.44432 5.44379 5.44334 5.443 5.44276 5.44258 5.44246 5.44238 5.44232 5.44228 5.44225 5.44223 5.44221 5.4422 5.44219 5.44219 5.44218 5.44218 5.44218 5.44218 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44214 5.44214 5.44214 5.44214 5.44214 5.44214 5.44214 5.44214 5.44214 5.44214 5.44214 5.44212 5.45159 5.45236 5.44064 5.44307 5.45616 5.38122 4.77163 3.53297 2.74466 2.34448 2.11802 1.9783 1.88656 1.82001 1.77389 1.72955 1.69632 1.66971 1.6526 1.65236 1.56034 1.53764 1.97139 2.75096 3.39212 3.74042 3.82345 3.85696 3.88547 3.91862 3.9585 4.00467 4.05903 4.1254 4.19533 4.26791 4.34517 4.42112 4.49238 4.55807 4.6179 4.6713 4.71815 4.75889 4.79418 4.82456 4.85062 4.87291 4.89196 4.90823 4.92209 4.93388 4.9439 4.95242 4.95968 4.96585 4.97108 4.9755 4.97923 4.98237 4.98503 4.98732 4.98927 4.99094 4.99233 4.99353 4.99452 4.99538 4.99608 4.99668 4.99718 4.9976 4.99794 4.99822 4.99847 4.99867 4.99884 4.99899 4.99913 4.99924 4.99932 4.99938 4.99943 4.99947 4.99951 4.99953 4.99955 4.99958 4.99961 4.99964 4.99967 4.99969 4.99972 4.99975 4.99977 4.99978 4.99979 4.99981 4.99982 4.99983 4.99985 4.99986 4.99986 4.99987 4.99987 4.99988 4.99988 4.99988 4.99989 4.99989 4.9999 4.9999 4.99991 4.99991 4.99992 4.99992 4.99993 4.99993 4.99993 4.99994 5.00381 5.00064 4.99246 4.99823 5.00349 5.00076 5.00033 5.00015 5.00009 5.00007 5.00005 5.00004 5.00003 5.00002 4.99988 4.99732 4.99728 4.9978 5.00187 5.00927 5.08712 5.07654 4.92855 4.4863 3.76162 3.00049 2.49834 2.20883 2.03492 1.92384 1.84676 1.79021 1.74716 1.7132 1.68576 1.66309 1.64406 1.62785 1.61383 1.60162 1.59081 1.58117 1.57253 1.56473 1.55765 1.55117 1.54527 1.53988 1.53485 1.53012 1.5257 1.5216 1.51773 1.51411 1.51071 1.50746 1.50438 1.50146 1.49868 1.49603 1.4935 1.49109 1.48878 1.48657 1.48445 1.48242 1.48046 1.47858 1.47677 1.47502 1.47333 1.4717 1.47012 1.46859 1.46711 1.46568 1.46428 1.46292 1.4616 1.46034 1.45923 1.45812 1.45701 1.4559 1.45479 1.45378 1.45279 1.45181 1.45082 1.44983 1.44893 1.44813 1.44732 1.44652 1.44571 1.44491 1.4441 1.4433 1.44249 1.44169 1.44089 1.44019 1.43951 1.43883 1.43815 1.43747 1.4368 1.43612 1.43544 1.43476 1.43408 1.43342 1.43283 1.43223 1.43163 1.43104 1.43044 1.42984 1.42924 1.42865 } v39 set { 5 5.01048 5.01221 4.98887 4.76261 4.54943 4.51564 4.56249 4.62621 4.68843 4.74374 4.79044 4.82972 4.86127 4.88724 4.90862 4.90791 4.89858 4.89589 4.91767 5.00405 5.16956 5.12391 4.7557 3.87953 3.01124 2.48482 2.20424 2.03812 1.92679 1.84956 1.79256 1.74907 1.71487 1.68724 1.6644 1.64513 1.6287 1.61446 1.60197 1.59095 1.58117 1.57245 1.5646 1.55752 1.55109 1.54516 1.53958 1.53444 1.53008 1.52606 1.52205 1.51843 1.5149 1.51146 1.50893 1.50639 1.50387 1.50133 1.4988 1.49651 1.49436 1.49222 1.49007 1.48793 1.48585 1.48433 1.4828 1.48128 1.47975 1.47823 1.4767 1.47518 1.47365 1.47213 1.4706 1.46912 1.46795 1.46678 1.46561 1.46444 1.46327 1.4621 1.46093 1.45976 1.45859 1.45741 1.45628 1.45534 1.45441 1.45347 1.45254 1.4516 1.45067 1.44973 1.4488 1.44786 1.44693 1.44604 1.44539 1.44475 1.4441 1.44345 1.44281 1.44216 1.44151 1.44086 1.44022 1.43957 1.43892 1.43828 1.43763 1.43698 1.43633 1.43569 1.43504 1.43439 1.43375 1.4331 1.43245 1.4318 1.43157 1.43089 1.43001 1.43042 1.42899 1.42439 1.42216 1.43447 1.44048 1.43705 1.43314 1.43039 1.42861 1.42739 1.42651 1.42548 1.42488 1.4243 1.42392 1.4235 1.32443 1.31149 1.78169 2.64844 3.43211 3.95252 4.20231 4.3746 4.49948 4.58929 4.65742 4.71183 4.77057 4.83196 4.88354 4.92894 4.96625 4.99235 5.00651 5.00941 5.00813 5.00689 5.00588 5.00504 5.00431 5.00368 5.00314 5.00268 5.00228 5.00194 5.00165 5.0014 5.00118 5.001 5.00085 5.00072 5.00061 5.00052 5.00044 5.00037 5.00031 5.00027 5.00022 5.00019 5.00016 5.00013 5.00011 5.00009 5.00008 5.00007 5.00006 5.00005 5.00004 5.00003 5.00003 5.00003 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5.00001 5.00002 5.00003 5.00004 5.00022 4.99974 4.99942 4.99997 5.00063 5.00002 5.00003 4.99994 4.99998 4.99999 5 5 5 5 5 4.99981 4.99998 5.00004 5.00036 5.00049 5.12012 5.16315 5.19712 5.21835 4.87874 4.10151 3.31555 2.74207 2.38075 2.15872 2.01614 1.91886 1.84852 1.79401 1.75052 1.71508 1.68672 1.66467 1.64602 1.62985 1.61576 1.60343 1.59256 1.58287 1.57418 1.56632 1.55922 1.55282 1.54687 1.54132 1.53618 1.53143 1.52698 1.52282 1.51895 1.51527 1.5118 1.50851 1.5054 1.50244 1.49963 1.49695 1.4944 1.49196 1.48963 1.4874 1.48527 1.48322 1.48124 1.47934 1.47751 1.47574 1.47403 1.47239 1.4708 1.46926 1.46777 1.46632 1.46491 1.46355 1.46237 1.4612 1.46002 1.45884 1.45766 1.45659 1.45555 1.45451 1.45346 1.45242 1.45147 1.45062 1.44978 1.44894 1.44809 1.44725 1.4464 1.44556 1.44472 1.44387 1.44303 1.4423 1.44159 1.44088 1.44017 1.43947 1.43876 1.43805 1.43734 1.43664 1.43593 1.43524 1.43462 1.434 1.43338 1.43276 1.43213 1.43151 1.43089 1.43027 } set attributes { V1 v1 red red V2 v2 green red V3 v3 blue red V4 v4 yellow red V5 v5 magenta red V6 v6 cyan red V7 v7 white red V8 v8 red green V9 v9 green green V10 v10 blue green V11 v11 yellow green V12 v12 magenta green V13 v13 cyan green V14 v14 red red V15 v15 green red V16 v16 blue red V17 v17 yellow red V18 v18 magenta red V19 v19 cyan red V20 v20 white red V21 v21 red green V22 v22 green green V23 v23 blue green V24 v24 yellow green V25 v25 magenta green V26 v26 cyan green V27 v27 red red V28 v28 green red V29 v29 blue red V30 v30 yellow red V31 v31 magenta red V32 v32 cyan red V33 v33 white red V34 v34 red green V35 v35 green green V36 v36 blue green V37 v37 yellow green V38 v38 magenta green V39 v39 cyan green } text .header -wrap word -width 0 -height 6 set text { To zoom in on a region of the graph, simply click once on the left mouse button to pick one corner of the area to be zoomed. Move the mouse to the other corner and click again. } regsub -all "\n" $text "" text .header insert end "$text\n" .header insert end { You can click on the } set im [image create photo -file ./images/qv100.t.gif] button .header.snap -image $im -command { MakeSnapshot } .header window create end -window .header.snap .header insert end { button to see a photo image snapshot.} .header configure -state disabled graph $graph htext .footer -text {Hit the %% set im [image create photo -file ./images/stopsign.gif] button $htext(widget).quit -image $im -command { exit } $htext(widget) append $htext(widget).quit %% button when you've seen enough. %% label $htext(widget).logo -bitmap BLT $htext(widget) append $htext(widget).logo %%} foreach {label yData outline color} $attributes { .graph element create $label -x x -y $yData -outline $outline -color $color } set unique 0 proc Sharpen { photo } { #set kernel { -1 -1 -1 -1 16 -1 -1 -1 -1 } set kernel { 0 -1 0 -1 4.9 -1 0 -1 0 } winop convolve $photo $photo $kernel } proc MakeSnapshot {} { update idletasks global unique set top ".snapshot[incr unique]" set im1 [image create photo] set im2 [image create photo] .graph snap $im1 blt::winop snap .graph $im2 set thumb1 [image create photo -width 210 -height 150 -gamma 1.8] winop resample $im1 $thumb1 sinc set thumb2 [image create photo -width 210 -height 150 -gamma 1.8] winop resample $im2 $thumb2 sinc #Sharpen $thumb image delete $im1 image delete $im2 toplevel $top wm title $top "Snapshot \#$unique of \"[.graph cget -title]\"" label $top.l1 -image $thumb1 label $top.l2 -image $thumb2 button $top.but -text "Dismiss" -command "DestroySnapshot $top" table $top 0,0 $top.l1 0,1 $top.l2 table $top $top.but -pady 4 focus $top.but } proc DestroySnapshot { win } { set im [$win.l1 cget -image] $im write -format ppm test.ppm image delete $im destroy $win } table . \ .header 0,0 -fill x \ .graph 1,0 -fill both \ .footer 2,0 -fill x table configure . r0 r2 -resize none Blt_ZoomStack $graph Blt_Crosshairs $graph Blt_ActiveLegend $graph Blt_ClosestPoint $graph Blt_PrintKey $graph $graph element bind all { %W legend activate [%W element get current] } $graph element bind all { %W legend deactivate [%W element get current] } blt-2.4z.orig/demos/graph5.tcl0100755000175000017500000000511507340644044014757 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* #namespace import -force blt::tile::* } source scripts/demo.tcl option add *Element.ScaleSymbols true option add *Axis.loose true option add *Pixels .8c option add *Element.lineWidth 0 option add *Legend.ActiveRelief raised option add *Legend.padY 0 option add *Button*Font { Courier 14 } widgetDefault option add *Legend*Font { Courier 14 bold } widgetDefault option add *Graph.Font { Courier 18 bold } widgetDefault option add *Graph.title "Element Symbol Types" option add *Graph.width 8i option add *Graph.height 6i option add *Graph.plotPadY .25i option add *Graph.plotPadX .25i set graph .graph graph $graph vector x -variable "" x set { 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 } for { set i 0 } { $i < 11 } { incr i } { set vecName "y${i}" vector ${vecName} $vecName length 11 $vecName variable y set y(:) [expr $i*100.0] } set attributes { none "None" red red4 y0 arrow "Arrow" brown brown4 y10 circle "Circle" yellow yellow4 y2 cross "Cross" cyan cyan4 y6 diamond "Diamond" green green4 y3 plus "Plus" magenta magenta4 y9 splus "Splus" Purple purple4 y7 scross "Scross" red red4 y8 square "Square" orange orange4 y1 triangle "Triangle" blue blue4 y4 "@bitmaps/hobbes.xbm @bitmaps/hobbes_mask.xbm" "Bitmap" yellow black y5 } set count 0 foreach {symbol label fill color yVec} $attributes { $graph element create line${count} \ -label $label -symbol $symbol -color $color -fill $fill -x x -y $yVec incr count } $graph element configure line0 -dashes { 2 4 2 } -linewidth 2 button .quit -text Quit -command exit table . \ $graph 0,0 -fill both \ .quit 1,0 -fill x Blt_ZoomStack $graph Blt_Crosshairs $graph Blt_ActiveLegend $graph Blt_ClosestPoint $graph Blt_PrintKey $graph blt-2.4z.orig/demos/graph6.tcl0100755000175000017500000040663207503171013014761 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl set tcl_precision 15 set graph .graph option add *Graph.Width 10i option add *Graph.leftMargin .75i option add *Graph.Height 6i option add *Graph.plotBackground black option add *LineMarker.color white option add *LineMarker.Dashes 5 option add *TextMarker.foreground white option add *TextMarker.Background {} option add *Graph.x.hide yes option add *Graph.x.title "" option add *Graph.y.rotate 90 #option add *Graph.y.stepSize 2.0 option add *Graph.title "" option add *graph.Title "Example s27" option add *graph.x.hide no option add *graph.topMargin 0 option add *graph.bottomMargin 0 option add *x.Title Time option add *y.Title Signals option add *Pixels 1 option add *Reduce 0.5 option add *bufferElements no option add *Element.color green4 option add *Element.ScaleSymbols true option add *Element.Color grey70 option add *Element.Symbol none option add *Element.LineWidth 1 #option add *Element.Smooth natural option add *Element.Smooth catrom option add *activeLine.LineWidth 2 option add *activeLine.Color white option add *activeLine.Color green1 #option add *Legend.Hide yes option add *Legend.Position right option add *Legend.Relief flat option add *Legend.activeRelief sunken option add *Legend.borderWidth 2 option add *Legend.Font -*-helvetica-medium-r-*-*-10-*-*-*-*-*-*-* option add *Grid.hide no option add *Grid.dashes "1 5" #option add *foreground white option add *zoomOutline.outline yellow graph .graph vector x -variable "" for { set i 1 } { $i <= 39 } { incr i } { vector create v${i} -variable "" } x set { 0 1e-10 2e-10 3e-10 4e-10 5e-10 6e-10 7e-10 8e-10 9e-10 1e-09 1.1e-09 1.2e-09 1.3e-09 1.4e-09 1.5e-09 1.6e-09 1.7e-09 1.8e-09 1.9e-09 2e-09 2.1e-09 2.2e-09 2.3e-09 2.4e-09 2.5e-09 2.6e-09 2.7e-09 2.8e-09 2.9e-09 3e-09 3.1e-09 3.2e-09 3.3e-09 3.4e-09 3.5e-09 3.6e-09 3.7e-09 3.8e-09 3.9e-09 4e-09 4.1e-09 4.2e-09 4.3e-09 4.4e-09 4.5e-09 4.6e-09 4.7e-09 4.8e-09 4.9e-09 5e-09 5.1e-09 5.2e-09 5.3e-09 5.4e-09 5.5e-09 5.6e-09 5.7e-09 5.8e-09 5.9e-09 6e-09 6.1e-09 6.2e-09 6.3e-09 6.4e-09 6.5e-09 6.6e-09 6.7e-09 6.8e-09 6.9e-09 7e-09 7.1e-09 7.2e-09 7.3e-09 7.4e-09 7.5e-09 7.6e-09 7.7e-09 7.8e-09 7.9e-09 8e-09 8.1e-09 8.2e-09 8.3e-09 8.4e-09 8.5e-09 8.6e-09 8.7e-09 8.8e-09 8.9e-09 9e-09 9.1e-09 9.2e-09 9.3e-09 9.4e-09 9.5e-09 9.6e-09 9.7e-09 9.8e-09 9.9e-09 1e-08 1.01e-08 1.02e-08 1.03e-08 1.04e-08 1.05e-08 1.06e-08 1.07e-08 1.08e-08 1.09e-08 1.1e-08 1.11e-08 1.12e-08 1.13e-08 1.14e-08 1.15e-08 1.16e-08 1.17e-08 1.18e-08 1.19e-08 1.2e-08 1.21e-08 1.22e-08 1.23e-08 1.24e-08 1.25e-08 1.26e-08 1.27e-08 1.28e-08 1.29e-08 1.3e-08 1.31e-08 1.32e-08 1.33e-08 1.34e-08 1.35e-08 1.36e-08 1.37e-08 1.38e-08 1.39e-08 1.4e-08 1.41e-08 1.42e-08 1.43e-08 1.44e-08 1.45e-08 1.46e-08 1.47e-08 1.48e-08 1.49e-08 1.5e-08 1.51e-08 1.52e-08 1.53e-08 1.54e-08 1.55e-08 1.56e-08 1.57e-08 1.58e-08 1.59e-08 1.6e-08 1.61e-08 1.62e-08 1.63e-08 1.64e-08 1.65e-08 1.66e-08 1.67e-08 1.68e-08 1.69e-08 1.7e-08 1.71e-08 1.72e-08 1.73e-08 1.74e-08 1.75e-08 1.76e-08 1.77e-08 1.78e-08 1.79e-08 1.8e-08 1.81e-08 1.82e-08 1.83e-08 1.84e-08 1.85e-08 1.86e-08 1.87e-08 1.88e-08 1.89e-08 1.9e-08 1.91e-08 1.92e-08 1.93e-08 1.94e-08 1.95e-08 1.96e-08 1.97e-08 1.98e-08 1.99e-08 2e-08 2.01e-08 2.02e-08 2.03e-08 2.04e-08 2.05e-08 2.06e-08 2.07e-08 2.08e-08 2.09e-08 2.1e-08 2.11e-08 2.12e-08 2.13e-08 2.14e-08 2.15e-08 2.16e-08 2.17e-08 2.18e-08 2.19e-08 2.2e-08 2.21e-08 2.22e-08 2.23e-08 2.24e-08 2.25e-08 2.26e-08 2.27e-08 2.28e-08 2.29e-08 2.3e-08 2.31e-08 2.32e-08 2.33e-08 2.34e-08 2.35e-08 2.36e-08 2.37e-08 2.38e-08 2.39e-08 2.4e-08 2.41e-08 2.42e-08 2.43e-08 2.44e-08 2.45e-08 2.46e-08 2.47e-08 2.48e-08 2.49e-08 2.5e-08 2.51e-08 2.52e-08 2.53e-08 2.54e-08 2.55e-08 2.56e-08 2.57e-08 2.58e-08 2.59e-08 2.6e-08 2.61e-08 2.62e-08 2.63e-08 2.64e-08 2.65e-08 2.66e-08 2.67e-08 2.68e-08 2.69e-08 2.7e-08 2.71e-08 2.72e-08 2.73e-08 2.74e-08 2.75e-08 2.76e-08 2.77e-08 2.78e-08 2.79e-08 2.8e-08 2.81e-08 2.82e-08 2.83e-08 2.84e-08 2.85e-08 2.86e-08 2.87e-08 2.88e-08 2.89e-08 2.9e-08 2.91e-08 2.92e-08 2.93e-08 2.94e-08 2.95e-08 2.96e-08 2.97e-08 2.98e-08 2.99e-08 3e-08 3.01e-08 3.02e-08 3.03e-08 3.04e-08 3.05e-08 3.06e-08 3.07e-08 3.08e-08 3.09e-08 3.1e-08 3.11e-08 3.12e-08 3.13e-08 3.14e-08 3.15e-08 3.16e-08 3.17e-08 3.18e-08 3.19e-08 3.2e-08 3.21e-08 3.22e-08 3.23e-08 3.24e-08 3.25e-08 3.26e-08 3.27e-08 3.28e-08 3.29e-08 3.3e-08 3.31e-08 3.32e-08 3.33e-08 3.34e-08 3.35e-08 3.36e-08 3.37e-08 3.38e-08 3.39e-08 3.4e-08 3.41e-08 3.42e-08 3.43e-08 3.44e-08 3.45e-08 3.46e-08 3.47e-08 3.48e-08 3.49e-08 3.5e-08 3.51e-08 3.52e-08 3.53e-08 3.54e-08 3.55e-08 3.56e-08 3.57e-08 3.58e-08 3.59e-08 3.6e-08 } wm min . 0 0 v1 set { 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 } .graph element create V1 -x x -y v1 v2 set { 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 5.32907e-15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 } .graph element create V2 -x x -y v2 v3 set { 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 8.88178e-16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 2.13718e-14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 } .graph element create V3 -x x -y v3 v4 set { 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 } .graph element create V4 -x x -y v4 v5 set { 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 } .graph element create V5 -x x -y v5 v6 set { 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 8.88178e-16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 2.13718e-14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 } .graph element create V6 -x x -y v6 v7 set { 5 5.16904 4.84159 3.34542 0.317102 0.103304 0.0275721 0.0221534 0.017689 0.0142639 0.0113974 0.00918238 0.00742541 0.00616602 0.00481195 0.00397049 -0.0659889 -0.025671 0.165495 0.986891 3.05229 4.55511 4.91611 4.98192 4.99428 4.99833 4.99095 4.97295 4.95493 4.93428 4.90723 4.94799 4.98584 4.99566 4.99813 4.99907 4.99947 4.99965 4.99976 4.99984 4.99989 4.99992 4.99994 4.99996 4.99998 5.00002 5.00006 5.00002 4.99996 4.99994 4.99999 5.00003 5.00002 5 4.99997 4.99997 4.99997 4.99997 4.99997 4.99996 4.99997 4.99997 4.99998 4.99998 4.99999 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5.16575 4.69986 2.43862 0.0230224 0.035229 -0.0210607 -0.0292766 -0.0172693 -0.00271479 -0.000912251 -0.000349106 -0.000116866 -4.24733e-05 -1.39536e-05 -3.01179e-05 -0.0657192 -0.0204835 0.183378 1.07181 3.118 4.46472 4.84158 4.94795 4.98173 4.99236 4.99762 5.01939 5.0433 5.05332 5.04959 5.03955 5.02851 5.02052 5.01422 5.00965 5.00631 5.00405 5.00248 5.00083 5.00012 5.00209 5.00387 5.00347 4.99917 4.99213 4.98411 4.97521 4.96332 4.94601 4.9304 4.94633 4.97936 4.99264 4.99685 4.99857 4.99925 4.99954 4.9997 4.99973 4.9997 4.99973 4.99979 4.99983 4.99986 4.99988 4.9999 4.9999 4.99992 4.99993 4.99994 4.99995 4.99996 4.99996 4.99997 4.99997 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5.14242 4.76101 3.16003 0.299374 0.0645506 -0.000498424 -2.45108e-05 -2.27986e-05 -5.24401e-05 -4.9884e-05 -4.92491e-05 -2.93354e-05 -3.21402e-05 -2.11851e-05 -3.37925e-05 -0.0657892 -0.020563 0.182582 1.06058 3.12484 4.46552 4.84146 4.95102 4.98556 4.99472 4.99806 4.99909 4.99955 4.99976 4.99994 4.99992 5.00029 4.99967 4.99849 4.99736 4.99884 5.00099 5.00377 5.00215 4.99994 4.99893 4.99788 4.99862 5.00055 5.00134 5.00127 5.00073 5.00039 5.00018 5.00006 5.00001 4.99985 5.00026 5.00018 5.00003 4.99981 4.99985 4.99987 4.99985 4.99982 4.99982 4.99982 4.99983 4.99985 4.99987 4.99989 4.99991 4.99992 4.99994 4.99995 4.99995 4.99994 4.99994 4.99996 4.99999 5.00002 5.00008 5.00009 5.00006 5.00001 5 4.99999 4.99998 4.99997 4.99996 4.99997 4.99997 4.99998 4.99998 4.99999 4.99999 4.99999 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 } .graph element create V7 -x x -y v7 v8 set { 5 5.03758 5.04711 4.96911 4.20882 3.96295 4.01117 4.15521 4.2967 4.42274 4.5295 4.6176 4.69014 4.74831 4.7966 4.83537 4.80526 4.787 4.79295 4.88588 5.08978 5.15615 5.10778 5.07718 5.06652 5.08225 4.9744 4.52977 3.77452 2.69426 1.15294 0.245509 0.0981544 0.0567527 0.0367487 0.0252578 0.0180599 0.0133837 0.0101497 0.0078616 0.00620186 0.00499056 0.0041027 0.00344223 0.00295808 0.00260089 0.00229887 0.00200817 0.00176397 0.00160116 0.00147381 0.00134645 0.00125029 0.00116043 0.00107371 0.00101981 0.000965921 0.000912028 0.000858135 0.000804242 0.000761669 0.00072672 0.000691771 0.000656823 0.000621874 0.000588722 0.00057041 0.000552098 0.000533785 0.000515473 0.000497162 0.00047885 0.000460537 0.000442226 0.000423914 0.000405601 0.000388399 0.000378694 0.000368989 0.000359284 0.00034958 0.000339875 0.00033017 0.000320465 0.00031076 0.000301055 0.00029135 0.000282207 0.000276247 0.000270287 0.000264327 0.000258367 0.000252407 0.000246447 0.000240487 0.000234527 0.000228567 0.000222607 0.000217086 0.000213696 0.000210307 0.000206918 0.000203528 0.000200139 0.00019675 0.00019336 0.000189971 0.000186582 0.000183192 0.000179803 0.000176414 0.000173025 0.000169635 0.000166246 0.000162857 0.000159467 0.000156078 0.000152689 0.000149299 0.00014591 0.00014255 0.0316021 0.163272 0.348732 0.603651 0.35745 0.135965 0.0707354 0.0314595 0.0201047 0.00994945 0.00389601 0.00138839 0.00060778 0.000329648 0.000492396 -0.0732035 -0.0844077 -0.0789062 -0.0390837 0.0197559 0.0183094 -0.00180099 -0.0189565 -0.0424144 -0.0735904 -0.0892423 0.285039 1.13702 2.10809 2.95826 3.60164 4.0435 4.35771 4.57254 4.71769 4.81329 4.87534 4.91487 4.94264 4.97375 5.01526 5.06517 5.10154 5.06259 4.89005 4.5787 4.12226 3.46151 2.49023 1.2586 0.32725 0.116753 0.0701865 0.0455509 0.0286914 0.0178176 0.0117599 0.00902715 0.00760583 0.00637745 0.00543811 0.00439377 0.00352448 0.0030151 0.00285771 0.002465 0.00203114 0.00173004 0.0014839 0.00125177 0.00105327 0.000894905 0.000766372 0.000658894 0.000569105 0.000492114 0.000427938 0.000370217 0.000314758 0.000266569 0.000233726 0.000209048 0.000191957 0.000177169 0.000166604 0.000161 0.000157314 0.000143828 0.000130342 0.000116857 0.000103371 8.98855e-05 7.63998e-05 6.29141e-05 5.76583e-05 5.30027e-05 4.8347e-05 4.36913e-05 3.90357e-05 3.438e-05 2.97243e-05 2.72507e-05 2.59083e-05 2.45659e-05 2.32235e-05 2.18811e-05 2.05387e-05 1.91963e-05 1.78539e-05 1.65115e-05 1.51691e-05 1.38267e-05 1.24843e-05 1.11419e-05 9.79954e-06 8.51574e-06 7.69807e-06 6.8804e-06 6.06273e-06 5.24506e-06 0.0287318 0.0317111 -0.0320087 -0.103609 0.0369639 0.0121128 0.00961197 0.00934971 0.00820853 0.00699769 0.00607002 0.00535541 0.00476552 0.00427601 0.00376357 -0.073012 -0.0866964 -0.0809538 -0.038005 0.0277001 0.0188906 0.00614597 0.00373629 0.00489787 0.0146573 0.0191052 0.0151708 0.0124224 0.0105859 0.00879272 0.00729464 0.0070047 0.00449575 -0.00626652 -0.0252417 -0.0147287 0.022538 0.0822905 0.0947372 0.0657516 0.0445506 0.0316753 0.0220971 0.0158101 0.0140971 0.0161498 0.0139876 0.0122447 0.0106994 0.009397 0.00822236 0.00686509 0.00797431 0.00751269 0.00671173 0.00595243 0.00524633 0.00459528 0.00401688 0.00350109 0.00303954 0.00260569 0.00222792 0.00191033 0.00163917 0.00140949 0.00121464 0.0010471 0.000900638 0.000768847 0.000645236 0.000524807 0.000460275 0.000442237 0.000446775 0.000397026 0.000301585 0.000228994 0.000190894 0.000166569 0.000152261 0.000137953 0.000123644 0.000109336 9.50281e-05 8.56557e-05 7.78437e-05 7.00318e-05 6.22198e-05 5.44079e-05 4.87539e-05 4.57761e-05 4.27982e-05 3.98203e-05 3.68425e-05 3.38646e-05 3.08868e-05 2.79089e-05 2.4931e-05 2.19532e-05 1.89753e-05 1.75244e-05 1.64095e-05 1.52946e-05 1.41797e-05 1.30648e-05 1.19499e-05 1.0835e-05 9.72011e-06 8.60521e-06 7.4903e-06 6.5117e-06 6.10334e-06 5.69497e-06 5.2866e-06 4.87824e-06 4.46987e-06 4.06151e-06 3.65314e-06 3.24477e-06 } .graph element create V8 -x x -y v8 v9 set { 1.86175 1.99708 2.07867 2.01211 2.43309 3.27194 3.63896 3.90426 4.11074 4.27932 4.41496 4.52543 4.61491 4.68862 4.7479 4.79666 4.72895 4.68886 4.70354 4.81353 5.01568 5.14184 5.10482 5.07362 5.05143 5.03638 5.02323 5.01465 5.00853 5.00383 4.99985 5.00454 5.00652 5.00546 5.00411 5.003 5.00214 5.00151 5.00106 5.00073 5.0005 5.00034 5.00023 5.00015 5.0001 5.00005 5 5.00001 5.00005 5.00005 5.00003 5 4.99998 4.99996 4.99994 4.99995 4.99997 4.99998 5 5.00001 5.00002 5.00002 5.00003 5.00003 5.00003 5.00003 5.00003 5.00003 5.00002 5.00002 5.00001 5.00001 5.00001 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.17392 4.94828 3.78491 1.52079 0.608874 0.244031 0.127087 0.0552995 0.0361032 0.0169025 0.006364 0.00217624 0.000921391 0.000457305 0.000786754 -0.120016 -0.148054 -0.15898 -0.0801463 0.16463 0.174017 0.0799249 0.0318788 0.0129696 0.00483397 0.0025677 0.0042079 0.00350003 0.00178404 -8.72902e-05 -0.00128497 -0.00142213 -0.00130018 -0.00106874 -0.000789207 -0.000824335 -0.00104518 -0.00136799 -0.004366 -0.0102621 -0.0109254 -0.00649259 -0.00194842 0.00029793 0.00148673 0.00221085 0.00228291 0.00185261 0.00139687 0.00148183 0.00562266 0.00844119 0.00754627 0.00657396 0.00591212 0.00539269 0.0049282 0.00448417 0.0040572 0.00363719 0.00320392 0.00279607 0.00243938 0.00211505 0.00182302 0.00156254 0.0013341 0.00113834 0.000971865 0.00082776 0.000706193 0.000602499 0.000515059 0.000441401 0.00037897 0.000325459 0.00028083 0.000242096 0.000207274 0.000176444 0.000150372 0.000126407 0.000103373 9.05522e-05 8.53555e-05 8.63685e-05 9.02593e-05 8.37346e-05 7.72099e-05 7.06852e-05 6.41605e-05 5.76358e-05 5.11112e-05 4.45865e-05 4.08176e-05 3.72497e-05 3.36818e-05 3.01138e-05 2.65459e-05 2.2978e-05 1.94101e-05 1.76154e-05 1.67399e-05 1.58645e-05 1.4989e-05 1.41136e-05 1.32381e-05 1.23626e-05 1.14872e-05 1.06117e-05 9.73629e-06 8.86083e-06 7.98538e-06 7.10993e-06 6.23447e-06 5.44363e-06 5.32578e-06 5.20792e-06 5.09007e-06 4.97222e-06 0.0784323 0.0474527 -0.0764232 -0.151146 0.0615785 0.0144489 0.00974161 0.00947176 0.00849005 0.00728201 0.00630581 0.00554032 0.00487809 0.00441504 0.00384139 -0.118943 -0.149894 -0.161173 -0.0825299 0.171686 0.176912 0.0816085 0.0335236 0.013791 0.0056976 0.00238833 0.00105348 0.000526199 0.00025969 0.000396026 0.000837835 0.00170131 0.00196699 -0.000553314 -0.0061621 -0.0111895 -0.0142698 -0.0124608 -0.00795847 -0.00467822 -0.0043058 -0.00874449 -0.0118584 -0.00871386 -0.00377892 1.95244e-05 0.00218952 0.00325486 0.00386497 0.00422837 0.00446883 0.00447065 0.00486647 0.00547838 0.00565398 0.00559092 0.00538752 0.00507015 0.00466305 0.00420756 0.00373465 0.00328404 0.00287059 0.00250057 0.00216124 0.00184861 0.00156815 0.00134624 0.00117857 0.00103412 0.0008948 0.000761012 0.000619853 0.000462614 0.000319965 0.000287666 0.000356415 0.000379946 0.000339183 0.00027972 0.000252982 0.000226244 0.000199507 0.000172769 0.000146031 0.000130097 0.000117578 0.000105059 9.25401e-05 8.00213e-05 7.11204e-05 6.67061e-05 6.22918e-05 5.78775e-05 5.34632e-05 4.90489e-05 4.46346e-05 4.02203e-05 3.5806e-05 3.13916e-05 2.69773e-05 2.4827e-05 2.31747e-05 2.15225e-05 1.98702e-05 1.8218e-05 1.65658e-05 1.49135e-05 1.32613e-05 1.1609e-05 9.95678e-06 8.50108e-06 7.86765e-06 7.23422e-06 6.60079e-06 5.96736e-06 5.33393e-06 4.7005e-06 4.06707e-06 3.43363e-06 } .graph element create V9 -x x -y v9 v10 set { 1.86175 1.99308 2.16619 2.46661 3.09359 3.76864 4.31299 4.65564 4.83425 4.92153 4.96157 4.98063 4.98649 4.99039 4.9945 4.9972 4.96206 4.89882 4.83865 4.83202 4.91016 5.04479 5.06078 5.04827 5.03474 5.0246 5.01639 5.00996 5.00569 5.00239 5.00043 5.00296 5.00437 5.00382 5.00287 5.00208 5.00148 5.00104 5.00073 5.0005 5.00034 5.00023 5.00016 5.00011 5.00008 5.00007 5.00007 5.00004 5 4.99998 4.99998 4.99997 4.99998 4.99999 5 5 5.00001 5.00001 5.00001 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5 5.10081 5.10949 4.98359 5.00733 5.15145 4.37298 2.36126 0.470759 0.0577238 0.0115884 0.00262611 0.000671499 0.000389038 0.000291291 0.000317347 -0.0167823 -0.0158344 -0.0140559 0.0104849 0.0865874 0.107813 0.0524688 0.0214369 0.00876443 0.00341595 0.00170778 0.00259042 0.0022241 0.00118519 1.10217e-06 -0.000784506 -0.000948169 -0.000856256 -0.000696719 -0.000485987 -0.000724787 -0.000981491 -0.001454 -0.00552498 -0.0114992 -0.0105266 -0.00543527 -0.000982798 0.00127356 0.00224212 0.00275439 0.00281098 0.0025471 0.00230368 0.00222576 0.00485522 0.00729453 0.00691796 0.0062615 0.00573987 0.0052688 0.00481185 0.00436934 0.00394326 0.00352712 0.00309978 0.00270038 0.00235335 0.00203742 0.00175256 0.00150067 0.00128126 0.00109323 0.000933619 0.000795113 0.000678182 0.00057843 0.000494345 0.000423609 0.000363821 0.000312766 0.000269856 0.000232389 0.000198382 0.000168126 0.00014267 0.000119293 9.69034e-05 8.5669e-05 8.26828e-05 8.64066e-05 9.26665e-05 8.5454e-05 7.82416e-05 7.10291e-05 6.38167e-05 5.66043e-05 4.93918e-05 4.21794e-05 3.86073e-05 3.53007e-05 3.19941e-05 2.86876e-05 2.5381e-05 2.20744e-05 1.87678e-05 1.70933e-05 1.62648e-05 1.54363e-05 1.46079e-05 1.37794e-05 1.2951e-05 1.21225e-05 1.12941e-05 1.04656e-05 9.63716e-06 8.80871e-06 7.98026e-06 7.1518e-06 6.32335e-06 5.5374e-06 5.08959e-06 4.64178e-06 4.19397e-06 3.74616e-06 0.0438026 0.0242078 -0.0602019 -0.0840866 0.00148461 -0.00292489 0.000442098 0.00219489 0.00281478 0.00290756 0.00277945 0.00263896 0.00240099 0.00223283 0.001947 -0.0153629 -0.0148815 -0.0128673 0.0126017 0.0905161 0.11051 0.0538958 0.022562 0.00935726 0.00397422 0.00172534 0.000790207 0.000416322 0.000191632 0.000469721 0.0009779 0.00192566 0.00200688 -0.0016502 -0.00733932 -0.0128113 -0.0147608 -0.0115456 -0.00668995 -0.00401368 -0.00463908 -0.0101197 -0.0118993 -0.0076276 -0.00262656 0.000813059 0.00264455 0.00350796 0.00399494 0.0043049 0.00451658 0.00444739 0.00503842 0.00559516 0.00568213 0.00556459 0.0053176 0.00496654 0.00454337 0.00408592 0.00362171 0.00317793 0.00277001 0.00240394 0.00207009 0.00176575 0.00149725 0.00129045 0.00114257 0.00101135 0.000871672 0.000723764 0.000580438 0.000427507 0.000296956 0.000281834 0.000376628 0.000412266 0.000367547 0.000295305 0.000264513 0.000233721 0.000202929 0.000172137 0.000141345 0.000124721 0.000112577 0.000100433 8.82893e-05 7.61453e-05 6.75517e-05 6.33609e-05 5.91701e-05 5.49792e-05 5.07884e-05 4.65976e-05 4.24067e-05 3.82159e-05 3.40251e-05 2.98342e-05 2.56434e-05 2.36401e-05 2.21181e-05 2.05961e-05 1.90741e-05 1.75521e-05 1.60301e-05 1.45081e-05 1.29861e-05 1.14641e-05 9.94208e-06 8.59252e-06 7.96439e-06 7.33626e-06 6.70813e-06 6.07999e-06 5.45186e-06 4.82373e-06 4.1956e-06 3.56747e-06 } .graph element create V10 -x x -y v10 v11 set { 1.86175 1.73419 1.42874 1.04055 0.943004 0.268275 0.0826455 0.0388346 0.0214104 0.0135431 0.00961322 0.00712846 0.00588262 0.00432397 0.00377774 0.00270134 -0.00393731 -0.00542187 -0.00126596 0.0113777 0.0134522 0.00477056 -0.00211067 -0.00229253 -0.00173355 -0.00122404 -0.00113426 -0.000744931 -0.000520112 -0.000410048 -0.000220439 0.000508104 5.15856e-05 -0.000112593 -0.000118917 -9.57394e-05 -7.15727e-05 -5.11847e-05 -3.58275e-05 -2.47166e-05 -1.68866e-05 -1.14082e-05 -7.66646e-06 -5.12139e-06 -3.63426e-06 -3.01815e-06 -2.64862e-06 -1.4947e-06 -1.91403e-07 -2.5763e-08 -7.73699e-07 -1.52164e-06 -1.07268e-06 -3.81696e-07 2.6727e-07 4.75489e-07 6.83708e-07 8.91926e-07 1.10014e-06 1.30836e-06 1.2482e-06 1.00726e-06 7.66311e-07 5.25364e-07 2.84417e-07 6.27857e-08 7.43904e-10 -6.12979e-08 -1.2334e-07 -1.85382e-07 -2.47423e-07 -3.09465e-07 -3.71507e-07 -4.33549e-07 -4.95591e-07 -5.57633e-07 -6.04571e-07 -5.4944e-07 -4.9431e-07 -4.3918e-07 -3.84049e-07 -3.28919e-07 -2.73789e-07 -2.18659e-07 -1.63528e-07 -1.08398e-07 -5.32678e-08 1.062e-09 5.08502e-08 1.00638e-07 1.50427e-07 2.00215e-07 2.50003e-07 2.99791e-07 3.4958e-07 3.99368e-07 4.49156e-07 4.98944e-07 5.34512e-07 5.01032e-07 4.67553e-07 4.34073e-07 4.00593e-07 3.67113e-07 3.33633e-07 3.00153e-07 2.66674e-07 2.33194e-07 1.99714e-07 1.66234e-07 1.32754e-07 9.92744e-08 6.57945e-08 3.23147e-08 -1.16513e-09 -3.4645e-08 -6.81248e-08 -1.01605e-07 -1.35084e-07 -1.68564e-07 -2.18729e-07 0.0114926 -0.0245378 -0.111828 0.0964775 1.61491 3.22668 4.22041 4.54492 4.82845 4.94868 4.98588 4.99609 4.9981 4.99908 4.99788 4.98395 4.99294 4.99724 5.01939 5.0471 5.00902 4.98194 4.98496 4.99188 4.99623 4.99862 5.00025 4.99974 4.99953 4.99946 4.99958 5.00012 4.99997 4.99992 4.99988 4.99985 4.9998 4.9997 4.9988 4.99806 4.99982 5.00143 5.00159 5.00098 5.00053 5.00028 5.00007 4.99977 4.99992 5.00005 5.00133 5.0009 4.99993 4.99972 4.99975 4.9998 4.99982 4.99983 4.99983 4.99983 4.99983 4.99984 4.99986 4.99987 4.99989 4.9999 4.99991 4.99992 4.99994 4.99995 4.99995 4.99996 4.99997 4.99997 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5.00001 5.00001 5.00001 5.00002 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5.01457 4.99482 4.96561 4.99326 5.03452 5.00424 5.00101 5.00045 5.00004 4.99965 4.99997 4.99994 4.99958 4.99999 4.99936 4.9839 4.99248 4.99717 5.01976 5.04869 5.0087 4.98143 4.98488 4.99199 4.99622 4.9983 4.99928 4.99971 4.99986 5.00031 5.00022 5.00035 5.0001 4.99884 4.99811 4.99803 4.99887 5.00078 5.00151 5.00116 5.00007 4.99843 4.99915 5.00107 5.00168 5.00141 5.00092 5.00055 5.0003 5.00016 5.0001 5.00001 5.00016 5.0002 5.00009 4.99993 4.99975 4.99984 4.99991 4.99991 4.99982 4.99974 4.99974 4.99985 4.99995 4.99999 4.99998 5.00004 5.00013 5.00015 5.00007 4.99988 4.99982 4.99985 4.99995 5.00006 5.0002 5.00025 5.0002 5.00009 5.00006 5.00004 5.00002 5 4.99998 4.99997 4.99998 4.99998 4.99999 4.99999 4.99999 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 } .graph element create V11 -x x -y v11 v12 set { 5 5.16975 4.78685 2.94241 0.126698 0.0487004 -0.00422591 -0.00130689 -0.000486756 -0.000195875 -0.000108988 -6.66736e-05 -7.26005e-05 -5.63608e-05 -3.81859e-05 -2.123e-05 -0.0646846 -0.0184474 0.182248 1.06731 3.10988 4.46133 4.84133 4.95113 4.98364 4.99455 4.99694 4.99727 4.9994 4.99975 5.0001 5.00132 5.00089 5.00039 5.00019 5.00011 5.00006 5.00005 5.00004 5.00001 4.99992 4.99992 5.00002 5.00013 5.00017 5.00009 4.99992 4.99991 4.99994 4.99996 4.99998 4.99999 5.00001 5.00004 5.00006 5.00005 5.00004 5.00003 5.00002 5.00001 5 4.99999 4.99999 4.99998 4.99998 4.99997 4.99997 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5.14699 4.78074 3.19424 0.305663 0.0611255 -0.00179951 -0.0012032 0.000405978 0.000989399 0.000445194 0.000191447 8.30476e-05 3.96236e-05 1.91866e-05 1.70665e-05 -0.0655239 -0.0210234 0.1827 1.06848 3.11554 4.46518 4.84212 4.94853 4.98244 4.99434 4.9997 5.00081 5.00009 4.99972 4.99985 4.99974 4.9995 4.99949 4.99958 4.99973 4.99948 4.99914 4.99874 4.99946 5.00309 5.0091 5.01576 5.01835 5.01852 5.0176 5.01625 5.01479 5.01345 5.01264 5.011 5.01092 5.01344 5.01363 5.01289 5.01184 5.01071 5.00956 5.00848 5.00751 5.00663 5.00577 5.00497 5.00427 5.00365 5.0031 5.00264 5.00224 5.00191 5.00163 5.00138 5.00117 5.00099 5.00083 5.00071 5.00061 5.00053 5.00045 5.00037 5.00029 5.00022 5.00019 5.0002 5.00023 5.00024 5.00023 5.00023 5.00022 5.0002 5.00018 5.00016 5.00014 5.00011 5.00009 5.00007 5.00006 5.00005 5.00005 5.00004 5.00003 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5.14298 4.79809 3.32704 0.498385 0.105773 0.0160646 0.0319912 0.0299434 0.0240102 0.0185844 0.0130411 0.0106532 0.00864871 0.00744519 0.00660887 -0.0612913 -0.0203719 0.174998 0.991787 3.06292 4.60005 4.93058 4.98917 5.00033 4.9999 4.99909 4.9966 4.9955 4.99488 4.99374 4.9943 5.00131 5.00506 4.99311 4.96288 4.93567 4.92439 4.94236 4.9732 4.98864 4.99458 5.00031 5.00694 5.01525 5.01945 5.01998 5.01953 5.01874 5.01766 5.0164 5.01509 5.01326 5.01423 5.01455 5.01361 5.01245 5.01122 5.01002 5.00888 5.00783 5.00687 5.00596 5.00514 5.00442 5.00379 5.00325 5.00279 5.0024 5.00208 5.0018 5.00153 5.00126 5.00107 5.00094 5.00085 5.00078 5.00072 5.00063 5.00053 5.00042 5.00038 5.00034 5.0003 5.00027 5.00023 5.00021 5.00019 5.00017 5.00015 5.00013 5.00012 5.00011 5.0001 5.0001 5.00009 5.00008 5.00007 5.00007 5.00006 5.00005 5.00005 5.00004 5.00004 5.00003 5.00003 5.00002 5.00002 5.00002 5.00001 5.00001 5 5 5 5.00001 5.00001 5.00001 5.00002 5.00002 5.00002 5.00002 } .graph element create V12 -x x -y v12 v13 set { 9.73784e-10 0.0189926 0.0926769 0.206309 0.111533 0.0953491 0.0426966 0.0214177 0.0117943 0.00741442 0.00528816 0.00398417 0.0032967 0.00266499 0.00206647 0.00158788 -0.0371391 -0.0439528 -0.0408653 -0.0188706 0.0150241 0.0126852 0.00209817 -0.000239206 -5.31488e-05 0.000876324 -0.00451221 -0.0165223 -0.0284127 -0.0427584 -0.0502453 -0.0257366 -0.00903938 -0.00376456 -0.00233385 -0.00169922 -0.00130397 -0.00102542 -0.000811435 -0.000648115 -0.000529266 -0.00043795 -0.00036574 -0.00030716 -0.00026221 -0.000229662 -0.000205112 -0.000181038 -0.000162045 -0.000148988 -0.000137633 -0.000126278 -0.000115562 -0.000104976 -9.49324e-05 -9.0585e-05 -8.62375e-05 -8.18901e-05 -7.75426e-05 -7.31952e-05 -6.93752e-05 -6.59106e-05 -6.24461e-05 -5.89815e-05 -5.55169e-05 -5.22412e-05 -5.05263e-05 -4.88114e-05 -4.70966e-05 -4.53817e-05 -4.36668e-05 -4.19519e-05 -4.0237e-05 -3.85222e-05 -3.68073e-05 -3.50924e-05 -3.34782e-05 -3.25442e-05 -3.16102e-05 -3.06763e-05 -2.97423e-05 -2.88083e-05 -2.78744e-05 -2.69404e-05 -2.60064e-05 -2.50725e-05 -2.41385e-05 -2.32635e-05 -2.27232e-05 -2.21829e-05 -2.16426e-05 -2.11023e-05 -2.0562e-05 -2.00217e-05 -1.94814e-05 -1.89411e-05 -1.84007e-05 -1.78604e-05 -1.73647e-05 -1.70853e-05 -1.68059e-05 -1.65265e-05 -1.62471e-05 -1.59677e-05 -1.56883e-05 -1.54089e-05 -1.51295e-05 -1.48501e-05 -1.45707e-05 -1.42913e-05 -1.40119e-05 -1.37325e-05 -1.34531e-05 -1.31737e-05 -1.28943e-05 -1.26149e-05 -1.23355e-05 -1.20561e-05 -1.17767e-05 -1.14973e-05 -1.10954e-05 0.0152675 0.0228237 -0.00460678 -0.0341525 0.0232109 -0.0138039 -0.0416538 -0.0458764 -0.0201967 -0.00878316 -0.00379173 -0.00164621 -0.000785131 -0.00037575 -0.000352375 -0.0545586 -0.0746881 -0.0771865 -0.05386 -0.0022199 0.0136703 0.00633526 0.00138826 -0.00108934 0.0038886 0.0298077 0.0475776 0.0481003 0.0464167 0.047818 0.042789 0.035207 0.0264423 0.0193959 0.0151614 0.00624257 -0.00913057 -0.0310696 -0.0430238 0.016426 0.189762 0.49025 0.820116 1.13919 1.43549 1.70658 1.95183 2.17414 2.38506 2.5657 2.73958 2.97905 3.21403 3.43025 3.62645 3.8028 3.96002 4.09996 4.22443 4.33427 4.42886 4.51097 4.5817 4.64326 4.6957 4.74132 4.7797 4.81298 4.84102 4.86512 4.88523 4.90224 4.91649 4.92846 4.93868 4.94755 4.95483 4.96114 4.96682 4.97161 4.97502 4.9776 4.97944 4.98141 4.98319 4.98467 4.98585 4.9869 4.98796 4.98902 4.99008 4.99114 4.9922 4.99326 4.9938 4.99429 4.99479 4.99528 4.99578 4.99628 4.99677 4.99704 4.99718 4.99733 4.99747 4.99762 4.99777 4.99791 4.99806 4.9982 4.99835 4.9985 4.99864 4.99879 4.99893 4.99907 4.99916 4.99925 4.99934 4.99943 5.01473 4.92293 4.61974 4.0316 3.7835 3.74195 3.78344 3.87272 3.97386 4.07319 4.16686 4.25256 4.33126 4.40264 4.46697 4.49249 4.51807 4.55803 4.64055 4.78574 4.86074 4.88334 4.8999 4.91455 4.92814 4.93926 4.94761 4.95433 4.95907 4.9654 4.98317 5.0208 5.05134 4.85852 4.16041 3.00077 1.68376 0.672707 0.240838 0.0794725 -0.0106347 -0.00879443 0.107196 0.368163 0.701424 1.03581 1.3601 1.6678 1.95731 2.22701 2.47544 2.69099 2.92327 3.16648 3.3877 3.59067 3.77344 3.93584 4.08066 4.20863 4.32065 4.41791 4.50211 4.57423 4.63614 4.68888 4.73377 4.7721 4.80519 4.83338 4.85732 4.87815 4.89514 4.90927 4.92108 4.93122 4.94014 4.94845 4.95601 4.96251 4.96576 4.969 4.97225 4.9755 4.97874 4.98087 4.98265 4.98442 4.9862 4.98797 4.98924 4.9899 4.99055 4.9912 4.99186 4.99251 4.99316 4.99381 4.99447 4.99512 4.99577 4.99609 4.99634 4.99659 4.99683 4.99708 4.99732 4.99757 4.99782 4.99806 4.99831 4.99853 4.99863 4.99873 4.99883 4.99893 4.99903 4.99913 4.99923 4.99933 } .graph element create V13 -x x -y v13 v14 set { 1.86175 2.00147 1.85141 1.0654 0.275481 0.205547 0.0712627 0.0313387 0.0151431 0.00864531 0.00593861 0.00438111 0.0037479 0.00305857 0.00221221 0.0017081 -0.0896128 -0.109079 -0.121356 -0.0542001 0.175821 0.177442 0.0814591 0.0333042 0.0134909 0.00625777 0.00100092 -0.00552776 -0.00411139 -0.00150395 -0.000564784 3.48169e-05 -0.000287014 -0.000538515 -0.000456537 -0.000325677 -0.000275468 -0.000166452 -8.27481e-05 -8.28704e-05 -7.47644e-05 -4.60552e-05 -2.61481e-06 2.26359e-05 2.53852e-05 -1.39853e-06 -4.23456e-05 -4.0907e-05 -2.8501e-05 -1.5945e-05 -9.01122e-06 -2.07747e-06 1.49328e-06 4.38398e-06 6.84248e-06 4.76711e-06 2.69173e-06 6.16362e-07 -1.45901e-06 -3.53438e-06 -4.14256e-06 -3.76238e-06 -3.3822e-06 -3.00202e-06 -2.62184e-06 -2.24878e-06 -1.93456e-06 -1.62033e-06 -1.3061e-06 -9.91867e-07 -6.77638e-07 -3.63409e-07 -4.91792e-08 2.6505e-07 5.7928e-07 8.93509e-07 1.16076e-06 1.11055e-06 1.06034e-06 1.01014e-06 9.59927e-07 9.09719e-07 8.59511e-07 8.09302e-07 7.59094e-07 7.08886e-07 6.58678e-07 5.99251e-07 4.87523e-07 3.75795e-07 2.64068e-07 1.5234e-07 4.06119e-08 -7.1116e-08 -1.82844e-07 -2.94572e-07 -4.063e-07 -5.18027e-07 -6.08517e-07 -5.95879e-07 -5.83241e-07 -5.70604e-07 -5.57966e-07 -5.45328e-07 -5.3269e-07 -5.20053e-07 -5.07415e-07 -4.94777e-07 -4.8214e-07 -4.69502e-07 -4.56864e-07 -4.44226e-07 -4.31589e-07 -4.18951e-07 -4.06313e-07 -3.93676e-07 -3.81038e-07 -3.684e-07 -3.55762e-07 -3.43125e-07 1.06736e-05 0.0797407 0.0437947 -0.0645098 -0.0877312 0.0653203 -0.00621184 -0.0353188 -0.0491378 -0.0251957 -0.0110996 -0.00481123 -0.0020941 -0.000998038 -0.000478747 -0.000445332 -0.102046 -0.135753 -0.154351 -0.0827509 0.163348 0.174012 0.0794822 0.0310624 0.0112213 0.00249061 0.00130764 0.00181315 0.00163875 0.00101454 0.000497435 0.000195258 5.31901e-05 2.4607e-05 6.62736e-05 7.90718e-05 4.0372e-05 -0.000141184 -0.000280623 5.5608e-05 0.000799565 0.000920189 0.000931616 0.000494527 0.000162303 -8.24884e-05 -0.000183938 -0.000203899 -0.000144788 -9.87063e-05 -0.000227929 2.93932e-05 0.000208563 1.88958e-06 -7.6335e-05 -0.000172472 -0.000165656 -0.000145889 -0.000177311 -0.000191058 -0.000168287 -0.00015755 -0.00013142 -8.10488e-05 -6.36115e-05 -7.8699e-05 -8.11282e-05 -7.98625e-05 -5.98807e-05 -3.40879e-05 -1.95464e-05 -1.79247e-05 -4.45514e-05 -7.47995e-05 -8.7682e-05 -7.50806e-05 -3.25561e-05 -4.34114e-05 -7.69099e-05 -0.000141101 -0.00018743 -0.000148471 -5.06546e-05 0.000120195 0.000177635 0.000177052 0.000146344 9.75126e-05 8.31233e-05 6.8734e-05 5.43447e-05 3.99554e-05 2.55661e-05 1.11768e-05 -3.21253e-06 -3.88937e-06 -3.56628e-06 -3.24318e-06 -2.92008e-06 -2.59699e-06 -2.27389e-06 -1.9508e-06 -1.73227e-06 -1.56796e-06 -1.40365e-06 -1.23934e-06 -1.07503e-06 -9.10722e-07 -7.46412e-07 -5.82101e-07 -4.1779e-07 -2.5348e-07 -8.91694e-08 7.51412e-08 2.39452e-07 4.03762e-07 5.95733e-07 1.00771e-06 1.41969e-06 1.83167e-06 2.24365e-06 0.0828257 0.231038 0.465438 1.54516 2.8461 3.19221 3.40395 3.6382 3.80758 3.93848 4.04882 4.15428 4.247 4.32917 4.40235 4.36941 4.397 4.48862 4.64552 4.86595 5.03475 5.0348 5.02627 5.01967 5.01542 5.00925 4.98613 4.9519 4.91581 4.87357 4.82302 4.80403 4.82565 4.86102 4.89483 4.92253 4.94428 4.96257 4.97608 4.98373 4.98823 4.99182 4.99437 4.99635 4.99745 4.99802 4.99843 4.99873 4.99895 4.99912 4.99925 4.99931 4.99962 4.99973 4.99972 4.99971 4.9997 4.99969 4.9997 4.99971 4.99973 4.99974 4.99976 4.99978 4.9998 4.99982 4.99985 4.99987 4.99989 4.9999 4.99991 4.99991 4.99993 4.99994 4.99997 5.00001 5.00006 5.00008 5.00006 5.00002 5 4.99999 4.99998 4.99997 4.99995 4.99995 4.99995 4.99995 4.99995 4.99995 4.99995 4.99996 4.99997 4.99997 4.99998 4.99999 5 5 5.00001 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 4.99999 4.99999 4.99999 } .graph element create V14 -x x -y v14 v15 set { 1.86175 2.00199 2.08919 1.84314 1.08254 0.214737 0.0377351 0.00952455 0.00232763 0.000563614 0.000263477 0.000148642 0.000285086 0.000242592 7.34699e-05 -1.53467e-05 -0.0161874 -0.0157876 -0.0141194 0.0132576 0.0903272 0.109938 0.0535295 0.0224216 0.00940945 0.00466825 -0.000649972 -0.00654752 -0.00333248 -0.00103671 -0.000508276 -5.8896e-05 -0.00043938 -0.000544704 -0.00044444 -0.000307093 -0.00024517 -0.000154538 -8.78602e-05 -7.10461e-05 -6.06485e-05 -3.91039e-05 -8.45988e-06 9.43442e-06 1.28351e-05 -2.16734e-06 -2.6142e-05 -2.54768e-05 -1.88997e-05 -1.17906e-05 -7.3808e-06 -2.97101e-06 1.19146e-07 2.94246e-06 5.38942e-06 3.88851e-06 2.38761e-06 8.86704e-07 -6.14201e-07 -2.11511e-06 -2.59565e-06 -2.38885e-06 -2.18205e-06 -1.97525e-06 -1.76845e-06 -1.56241e-06 -1.36258e-06 -1.16276e-06 -9.62939e-07 -7.63116e-07 -5.63293e-07 -3.6347e-07 -1.63647e-07 3.61756e-08 2.35999e-07 4.35822e-07 6.07653e-07 5.90323e-07 5.72994e-07 5.55665e-07 5.38336e-07 5.21007e-07 5.03678e-07 4.86349e-07 4.6902e-07 4.51691e-07 4.34361e-07 4.11899e-07 3.60315e-07 3.08731e-07 2.57146e-07 2.05562e-07 1.53977e-07 1.02393e-07 5.08082e-08 -7.76222e-10 -5.23607e-08 -1.03945e-07 -1.47815e-07 -1.54225e-07 -1.60635e-07 -1.67045e-07 -1.73455e-07 -1.79864e-07 -1.86274e-07 -1.92684e-07 -1.99094e-07 -2.05504e-07 -2.11914e-07 -2.18324e-07 -2.24734e-07 -2.31144e-07 -2.37554e-07 -2.43964e-07 -2.50373e-07 -2.56783e-07 -2.63193e-07 -2.69603e-07 -2.76013e-07 -2.82423e-07 2.92534e-06 0.0446777 0.024278 -0.0518987 -0.0636547 0.00983929 -0.000518204 -0.000265194 0.000154772 0.000299538 3.12715e-05 -3.18225e-05 -2.48268e-05 -1.16701e-05 -6.05117e-06 7.61116e-06 -0.0163668 -0.0158244 -0.0141177 0.0100085 0.0857144 0.107784 0.051862 0.0204448 0.00629858 0.000967736 0.00121674 0.00190276 0.00154009 0.000860922 0.000410386 0.000164585 3.99493e-05 1.93797e-05 5.67594e-05 0.000110126 2.49925e-05 -7.17815e-05 -0.000142299 -1.63109e-05 0.000439529 0.000562489 0.000594599 0.000326164 0.000126423 -4.26063e-05 -0.000122927 -0.000114152 -6.72706e-05 -6.41242e-05 -0.000135588 2.61507e-05 0.000134036 6.43734e-06 -4.6223e-05 -0.000112047 -0.000101388 -8.67847e-05 -0.000117664 -0.000133957 -0.000116558 -0.000100873 -7.65448e-05 -4.44964e-05 -3.6677e-05 -5.26632e-05 -5.45172e-05 -5.13545e-05 -3.73869e-05 -1.99732e-05 -1.0907e-05 -1.10081e-05 -3.02609e-05 -5.18517e-05 -6.13597e-05 -5.30706e-05 -2.39572e-05 -3.24146e-05 -5.70062e-05 -0.000103448 -0.000135376 -0.0001024 -2.39007e-05 0.000110929 0.000151226 0.000142044 0.000105922 5.62834e-05 4.78476e-05 3.94117e-05 3.09759e-05 2.25401e-05 1.41042e-05 5.66837e-06 -2.76747e-06 -3.08639e-06 -2.81341e-06 -2.54043e-06 -2.26745e-06 -1.99447e-06 -1.72149e-06 -1.44851e-06 -1.26226e-06 -1.12096e-06 -9.79661e-07 -8.38363e-07 -6.97065e-07 -5.55768e-07 -4.1447e-07 -2.73173e-07 -1.31875e-07 9.42259e-09 1.5072e-07 2.92018e-07 4.33315e-07 5.74613e-07 7.10363e-07 8.01984e-07 8.93604e-07 9.85225e-07 1.07685e-06 0.04474 0.0928765 0.141327 0.0176048 -0.071675 -0.0124613 0.989022 2.28104 3.40619 4.21417 4.67173 4.87438 4.96044 4.98996 4.99858 4.96672 4.89502 4.79391 4.76433 4.8387 4.98612 5.0161 5.01722 5.01437 5.01256 4.99827 4.95807 4.9209 4.88217 4.83006 4.78461 4.80759 4.85548 4.89604 4.9254 4.94617 4.96126 4.97374 4.98255 4.98792 4.99126 4.99361 4.99554 4.99699 4.99792 4.99846 4.99881 4.99905 4.99924 4.99938 4.99949 4.99955 4.9997 4.9998 4.99982 4.99982 4.99982 4.99982 4.99982 4.99983 4.99984 4.99985 4.99986 4.99987 4.99988 4.99989 4.9999 4.99992 4.99993 4.99994 4.99995 4.99995 4.99996 4.99996 4.99998 4.99999 5.00001 5.00002 5.00002 5.00001 5.00001 5 4.99999 4.99999 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 } .graph element create V15 -x x -y v15 v16 set { 1.86175 1.73073 1.50572 1.89001 3.39004 4.36034 4.79012 4.93798 4.98305 4.99539 4.9979 4.99904 4.99772 4.9983 4.99935 4.99975 4.98837 4.99456 4.99728 5.01838 5.04568 5.00759 4.98112 4.98479 4.99197 4.99641 4.99747 4.99775 5.00043 5.0007 5.00035 5.00023 4.99976 5.00002 5.00007 5.0002 4.99993 5.00003 5.00021 5.00006 4.99993 4.99992 5.00002 5.00013 5.00017 5.00009 4.99992 4.99991 4.99993 4.99996 4.99998 4.99999 5.00001 5.00003 5.00005 5.00004 5.00004 5.00003 5.00002 5.00001 5 4.99999 4.99999 4.99998 4.99998 4.99997 4.99997 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5.01498 4.99342 4.96899 5.00301 5.02627 4.9977 4.99548 4.99757 5.00277 5.00245 5.0014 5.00069 5.00032 5.00014 5.00009 4.9867 4.99262 4.99607 5.01805 5.04713 5.00927 4.98184 4.98483 4.9914 4.99616 4.99902 4.9999 4.99987 4.99979 4.99981 4.99989 4.99994 4.99998 5.0002 5.00001 5.00008 5.00008 5.0001 5.00021 5.00032 5.00025 5.00019 5.00006 5.00007 4.99994 4.99997 4.99999 5.00023 5.00008 4.99993 4.99998 4.99986 4.99982 5.00003 4.99985 4.99996 5.00014 5 4.99984 4.99979 4.99982 4.99993 5.00008 5.00011 5.00002 4.99996 4.9999 4.99994 5.00001 5.00007 5.00009 4.99995 4.99978 4.99971 4.99976 4.99997 4.99996 4.99989 4.99972 4.99955 4.99953 4.99959 4.99976 4.9999 5.00005 5.00023 5.00039 5.00034 5.00029 5.00024 5.00019 5.00014 5.00009 5.00004 5.00003 5.00002 5.00001 5 5 4.99999 4.99998 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5.00001 5.00002 5.00003 5.00004 5.01564 5.03395 5.04932 5.11868 3.92502 1.31888 0.163888 0.0946876 0.0789578 0.0565084 0.0260333 0.0156986 0.00907667 0.00613629 0.00468417 -0.00174008 -0.0021422 0.000586962 0.0124937 0.0147977 0.00838454 0.00039383 -0.000522021 -0.000426598 -0.000290214 -0.00173713 -0.00384132 -0.00382945 -0.00429219 -0.00580193 -0.00393246 0.0017543 0.00423045 0.00408931 0.0031976 0.00245457 0.00187293 0.00159068 0.00105697 0.000609902 0.000358825 0.000334125 0.000212708 0.000168116 8.97349e-05 5.21578e-05 3.84527e-05 2.93033e-05 2.10067e-05 1.59954e-05 1.13917e-05 5.49738e-06 2.77217e-05 6.51259e-06 -6.65468e-06 2.09837e-06 -6.617e-06 -4.80187e-06 1.55031e-06 4.26536e-06 7.69457e-07 -1.46213e-06 -7.25202e-07 3.26501e-06 6.55807e-06 7.524e-06 6.07209e-06 6.00701e-06 5.41166e-06 3.86573e-06 1.10651e-06 -2.74603e-06 -2.18566e-06 2.3658e-06 8.59956e-06 8.35046e-06 2.90621e-06 -8.75982e-07 -1.87189e-06 -2.1528e-06 -1.94875e-06 -1.74471e-06 -1.54067e-06 -1.33662e-06 -1.13258e-06 -8.40567e-07 -5.20743e-07 -2.00918e-07 1.18906e-07 4.38731e-07 6.11382e-07 6.01529e-07 5.91675e-07 5.81822e-07 5.71968e-07 5.62115e-07 5.52261e-07 5.42407e-07 5.32554e-07 5.227e-07 5.12847e-07 4.72812e-07 4.26137e-07 3.79462e-07 3.32786e-07 2.86111e-07 2.39436e-07 1.92761e-07 1.46086e-07 9.94107e-08 5.27356e-08 -2.77779e-10 -7.98079e-08 -1.59338e-07 -2.38868e-07 -3.18398e-07 -3.97928e-07 -4.77458e-07 -5.56988e-07 -6.36519e-07 } .graph element create V16 -x x -y v16 v17 set { 5 5.16963 4.84136 3.33754 0.316206 0.103113 0.0273341 0.0221102 0.0177008 0.0143758 0.0115203 0.00929231 0.00752716 0.00625439 0.00489872 0.00403656 -0.0657317 -0.0256467 0.165394 0.985963 3.05067 4.55799 4.89728 4.92464 4.8882 4.90592 4.97315 4.99241 4.99694 4.99845 4.99905 4.99939 4.99959 4.99971 4.9998 4.99986 4.9999 4.99993 4.99995 4.99996 4.99997 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 5 5.00001 5.00003 5.00005 5.00004 5.00002 5 4.99999 4.99999 4.99998 4.99998 4.99997 4.99997 4.99998 4.99998 4.99999 4.99999 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5.00025 5.1657 4.69981 2.43895 0.0229743 0.0351406 -0.0211974 -0.0312063 -0.0160331 -0.0021718 -0.000766597 -0.000251052 -5.49363e-05 -3.36364e-06 -2.01983e-06 -9.70575e-06 -0.0657007 -0.0205247 0.183332 1.07163 3.11839 4.46213 4.84163 4.95195 4.99159 5.02084 5.04029 5.04138 5.0271 5.00445 4.97957 4.95702 4.95231 4.97819 4.99191 4.9963 4.99822 4.99878 4.99903 4.99925 4.99942 4.9995 4.99954 4.99957 4.99961 4.99966 4.9997 4.99974 4.99977 4.99981 4.99983 4.99986 4.99988 4.9999 4.99991 4.99992 4.99994 4.99995 4.99995 4.99996 4.99997 4.99997 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 4.99999 4.99998 4.99997 4.99996 5.14239 4.76219 3.16574 0.299969 0.0631609 -0.00118611 -0.00026052 -5.96333e-05 -1.44904e-05 -4.3859e-06 -2.99454e-06 1.10547e-06 4.84662e-06 1.30971e-05 2.23082e-05 -0.0655844 -0.0204818 0.182507 1.05954 3.12277 4.46735 4.83915 4.94512 4.97679 4.98654 4.9966 5.00833 5.00776 5.00432 5.00199 5.00086 5.00033 5.00008 5 5.00001 5 5.00005 5.00002 4.99981 4.99991 4.99998 4.99979 4.99979 4.99984 4.9998 4.9998 5.00006 5.00002 5.00001 5 5 4.99992 4.99998 4.99999 5.00002 5.00014 4.99999 4.99987 4.99993 5.00003 5.00011 5.00005 4.99996 4.99987 4.99985 4.99994 5.00009 5.0001 5 4.99993 4.99997 5.00008 5.00015 5.00021 5.00021 5.00007 4.99978 4.99965 4.99973 4.9999 4.99992 4.99995 4.99997 4.99999 5.00001 5.00002 5.00001 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5.00001 5.00001 5.00001 5.00002 5.00002 5.00002 } .graph element create V17 -x x -y v17 v18 set { 5 5.0333 5.02472 4.92559 4.18383 3.93923 3.9961 4.14293 4.28591 4.41336 4.52157 4.61101 4.68472 4.7439 4.79294 4.83239 4.80697 4.78808 4.79322 4.8838 5.08529 5.21863 4.88852 3.90198 2.14586 0.383977 0.101103 0.0525711 0.0318287 0.020895 0.0146908 0.010831 0.00830272 0.00656377 0.00532066 0.00440078 0.00369956 0.00315713 0.00272614 0.00237965 0.00209659 0.00186339 0.00167014 0.0015081 0.00137172 0.00125607 0.00115393 0.00106076 0.000980166 0.000918015 0.000862837 0.00080766 0.000763488 0.000721541 0.000680825 0.000653026 0.000625226 0.000597426 0.000569627 0.000541827 0.000519087 0.000499756 0.000480424 0.000461093 0.000441761 0.000423291 0.000411941 0.00040059 0.00038924 0.000377889 0.000366539 0.000355188 0.000343838 0.000332487 0.000321137 0.000309786 0.000299055 0.000292509 0.000285963 0.000279417 0.000272871 0.000266325 0.000259779 0.000253233 0.000246686 0.00024014 0.000233594 0.000227387 0.0002231 0.000218813 0.000214526 0.00021024 0.000205953 0.000201666 0.000197379 0.000193092 0.000188805 0.000184519 0.000180526 0.000177963 0.0001754 0.000172837 0.000170274 0.000167711 0.000165148 0.000162585 0.000160022 0.000157459 0.000154895 0.000152332 0.000149769 0.000147206 0.000144643 0.00014208 0.000139517 0.000136954 0.000134391 0.000131828 0.000129265 0.000126702 0.000132838 0.0311184 0.163151 0.34986 0.604501 0.357125 0.136137 0.0711304 0.0346959 0.0212674 0.00872193 0.00252206 0.000455269 7.59332e-05 2.91532e-05 0.000320562 -0.0720911 -0.0840491 -0.0791345 -0.0404143 0.0182035 -0.0235871 -0.0426072 -0.0597501 0.00824773 0.481404 1.32496 2.11949 2.57317 2.58202 2.15054 1.33786 0.45702 0.153772 0.0913584 0.0604989 0.0421591 0.0271456 0.0170021 0.0115815 0.00907886 0.00742466 0.00626096 0.00531127 0.00450501 0.00381927 0.00323718 0.00274374 0.00232494 0.00196885 0.00166686 0.00141134 0.00119437 0.0010109 0.000855534 0.000723378 0.000611408 0.000516704 0.000436769 0.000369523 0.000313026 0.00026526 0.000223976 0.000188972 0.000159042 0.000134148 0.000112688 9.49738e-05 7.97877e-05 6.721e-05 5.65115e-05 4.77194e-05 4.03591e-05 3.42848e-05 2.92627e-05 2.50435e-05 2.1412e-05 1.84532e-05 1.58624e-05 1.34673e-05 1.14461e-05 1.00935e-05 9.12375e-06 8.50202e-06 7.81431e-06 7.20729e-06 6.73936e-06 6.3702e-06 5.90049e-06 5.43077e-06 4.96105e-06 4.49133e-06 4.02162e-06 3.5519e-06 3.08218e-06 2.79099e-06 2.51281e-06 2.23463e-06 1.95645e-06 1.67827e-06 1.40009e-06 1.12191e-06 1.01376e-06 9.9375e-07 9.73741e-07 9.53733e-07 9.33724e-07 9.13715e-07 8.93707e-07 8.73698e-07 8.5369e-07 8.33681e-07 8.13673e-07 7.93664e-07 7.73655e-07 7.53647e-07 7.21781e-07 5.956e-07 4.69419e-07 3.43239e-07 2.17058e-07 0.0284032 0.0374438 -0.0157543 -0.0680497 0.0504768 0.0100294 0.00222261 0.000528697 0.000132929 3.99489e-05 2.46066e-05 4.56327e-06 -6.54853e-06 1.33783e-05 -3.68221e-05 -0.0724498 -0.0843663 -0.0792935 -0.0406426 0.0200019 0.0426259 0.0220753 0.00668555 -0.000968483 0.024662 0.0383437 0.0911513 0.087848 0.0602076 0.0390559 0.0260573 0.0180444 0.012974 0.00985409 0.00788132 0.0064228 0.005545 0.00453571 0.00364245 0.00310278 0.00270523 0.00236439 0.0020945 0.00186808 0.00167493 0.00151731 0.00138594 0.00126945 0.00116695 0.0010762 0.000996366 0.000928387 0.000864414 0.000808258 0.000759574 0.000713865 0.000666712 0.000632716 0.000601262 0.000572163 0.000543986 0.000515253 0.0004897 0.000468112 0.000449313 0.000432981 0.000417911 0.000401307 0.000382712 0.000366678 0.000355736 0.000349171 0.000335727 0.000317091 0.000296086 0.000283543 0.000277366 0.000272233 0.000267001 0.000263147 0.000256699 0.000250251 0.000243803 0.000237355 0.000230907 0.000225424 0.000220247 0.000215069 0.000209892 0.000204714 0.000200213 0.000196548 0.000192884 0.00018922 0.000185556 0.000181892 0.000178228 0.000174564 0.0001709 0.000167236 0.000163572 0.000160824 0.000158279 0.000155733 0.000153187 0.000150641 0.000148095 0.000145549 0.000143003 0.000140457 0.000137911 0.000135457 0.000133386 0.000131315 0.000129245 0.000127174 0.000125103 0.000123032 0.000120961 0.000118891 } .graph element create V18 -x x -y v18 v19 set { 1.86175 1.99994 2.0833 2.01627 2.42503 3.25769 3.62134 3.88827 4.09688 4.26773 4.40529 4.51734 4.60827 4.68313 4.74346 4.79302 4.72815 4.68959 4.70421 4.81316 5.01375 5.14493 5.10305 5.0699 5.04484 5.03751 5.03348 5.02504 5.01799 5.01271 5.00895 5.00628 5.0044 5.00309 5.00216 5.00151 5.00105 5.00073 5.00051 5.00034 5.00023 5.00015 5.0001 5.00007 5.00003 4.99998 4.99993 4.99993 4.99995 4.99999 5.00001 5.00003 5.00002 5.00001 5 5 5 5 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5.00017 5.17398 4.94779 3.78508 1.52302 0.608808 0.244311 0.126053 0.0597175 0.038422 0.0158174 0.00481338 0.00107847 0.000301256 0.000114861 0.00059489 -0.118904 -0.147478 -0.158986 -0.080544 0.165361 0.171378 0.0776087 0.0435738 0.0428235 0.0423755 0.0347695 0.0225061 0.0155539 0.0121357 0.0107997 0.0103976 0.0124406 0.016814 0.0167556 0.0149852 0.01459 0.0141182 0.0131934 0.0120286 0.0108692 0.0097184 0.00855881 0.00744912 0.00643877 0.00554044 0.00475165 0.00406535 0.00347158 0.00295981 0.00251995 0.00214318 0.00182101 0.00154613 0.00131196 0.0011119 0.000941587 0.000796999 0.000674582 0.000571283 0.000484276 0.000410649 0.000347005 0.000292984 0.000246715 0.000208143 0.00017489 0.000147412 0.000123854 0.000104332 8.77229e-05 7.40686e-05 6.2637e-05 5.32e-05 4.53946e-05 3.88343e-05 3.31864e-05 2.85905e-05 2.45725e-05 2.08671e-05 1.77301e-05 1.55911e-05 1.40153e-05 1.29421e-05 1.18693e-05 1.09815e-05 1.03484e-05 9.87664e-06 9.14446e-06 8.41228e-06 7.68011e-06 6.94793e-06 6.21575e-06 5.48357e-06 4.7514e-06 4.38454e-06 4.04432e-06 3.7041e-06 3.36388e-06 3.02366e-06 2.68344e-06 2.34322e-06 2.15196e-06 2.03791e-06 1.92386e-06 1.80982e-06 1.69577e-06 1.58173e-06 1.46768e-06 1.35363e-06 1.23959e-06 1.12554e-06 1.0115e-06 8.9745e-07 7.83404e-07 6.69358e-07 4.76113e-07 -3.47071e-07 -1.17025e-06 -1.99344e-06 -2.81662e-06 0.0783754 0.0500262 -0.0659563 -0.120914 0.0815957 0.0154255 0.00347177 0.000840357 0.000214582 6.54655e-05 3.91709e-05 8.07396e-06 -4.44265e-07 1.74384e-05 -4.52725e-05 -0.119379 -0.147984 -0.159247 -0.0824604 0.169014 0.177628 0.0758742 0.010558 -0.0346506 -0.0710288 -0.0838952 -0.0599521 -0.034568 -0.0181615 -0.00968034 -0.00547115 -0.00333511 -0.00232468 -0.00181159 -0.00143841 -0.00116601 -0.000839755 -0.000569764 -0.000578683 -0.000490551 -0.000411712 -0.000437859 -0.000408185 -0.000356644 -0.000311332 -0.000269006 -0.000221396 -0.000210054 -0.0001923 -0.000175122 -0.000161039 -0.0001428 -0.000126123 -0.000127893 -8.14516e-05 -0.000120166 -0.000154909 -0.000112733 -8.40377e-05 -7.11342e-05 -8.09538e-05 -9.77789e-05 -9.82402e-05 -7.73531e-05 -5.28255e-05 -3.1096e-05 -1.87967e-05 -1.96552e-05 -4.16655e-05 -5.77185e-05 -5.24142e-05 -2.83153e-05 -1.90012e-05 -1.54415e-05 -2.52569e-05 -6.23747e-05 -0.000130543 -0.000149394 -0.000110886 -4.35517e-05 -4.17084e-05 -3.98651e-05 -3.80218e-05 -3.61785e-05 -3.43352e-05 -3.36249e-05 -3.32729e-05 -3.29208e-05 -3.25687e-05 -3.22166e-05 -3.17143e-05 -3.10258e-05 -3.03372e-05 -2.96486e-05 -2.89601e-05 -2.82715e-05 -2.75829e-05 -2.68944e-05 -2.62058e-05 -2.55173e-05 -2.48287e-05 -2.43043e-05 -2.38159e-05 -2.33276e-05 -2.28393e-05 -2.2351e-05 -2.18626e-05 -2.13743e-05 -2.0886e-05 -2.03977e-05 -1.99093e-05 -1.945e-05 -1.91122e-05 -1.87744e-05 -1.84366e-05 -1.80987e-05 -1.77609e-05 -1.74231e-05 -1.70853e-05 -1.67474e-05 } .graph element create V19 -x x -y v19 v20 set { 1.86175 1.99724 2.17266 2.48439 3.15933 3.85231 4.38091 4.69033 4.85034 4.92851 4.96453 4.98188 4.98736 4.991 4.99482 4.9973 4.96422 4.89989 4.83907 4.83151 4.90868 5.04854 5.06104 5.04571 5.03219 5.03025 5.02273 5.01707 5.0123 5.0087 5.00611 5.00429 5.00301 5.00211 5.00148 5.00103 5.00072 5.0005 5.00035 5.00024 5.00016 5.00011 5.00007 5.00005 5.00003 5.00001 4.99999 4.99998 4.99998 4.99998 4.99998 4.99998 4.99999 5 5 5.00001 5.00001 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 4.99981 5.10081 5.10903 4.98404 5.00999 5.14946 4.36501 2.23938 0.325144 0.00660272 -0.0102186 -0.0082401 -0.00556785 -0.00374178 -0.00264763 -0.00202823 -0.0182241 -0.0169551 -0.0150395 0.0103736 0.0877592 0.104382 0.0515938 0.0373818 0.0411547 0.0397009 0.0308946 0.0205793 0.0154037 0.0129191 0.0119327 0.011527 0.0124295 0.0161152 0.0161076 0.0145391 0.0144541 0.0139287 0.0129215 0.0117239 0.0105795 0.00942983 0.00827423 0.00718354 0.00619954 0.00532868 0.00456631 0.00390448 0.00333254 0.00284003 0.00241714 0.00205524 0.0017458 0.00148202 0.00125739 0.0010655 0.000902213 0.000763611 0.000646279 0.000547291 0.000463934 0.000393401 0.000332424 0.000280655 0.000236328 0.000199386 0.000167536 0.000141218 0.000118654 9.99559e-05 8.40479e-05 7.09694e-05 6.00188e-05 5.09786e-05 4.3502e-05 3.72191e-05 3.18114e-05 2.74071e-05 2.35539e-05 1.99967e-05 1.69871e-05 1.49449e-05 1.3451e-05 1.24492e-05 1.14256e-05 1.05669e-05 9.94487e-06 9.47514e-06 8.77318e-06 8.07123e-06 7.36927e-06 6.66731e-06 5.96536e-06 5.2634e-06 4.56144e-06 4.23044e-06 3.92649e-06 3.62254e-06 3.31858e-06 3.01463e-06 2.71068e-06 2.40673e-06 2.23063e-06 2.12082e-06 2.01102e-06 1.90121e-06 1.7914e-06 1.68159e-06 1.57178e-06 1.46197e-06 1.35216e-06 1.24235e-06 1.13255e-06 1.02274e-06 9.12929e-07 8.0312e-07 6.33171e-07 -1.51288e-08 -6.63428e-07 -1.31173e-06 -1.96003e-06 0.0437517 0.0265689 -0.0515377 -0.0658688 0.010727 -0.000511921 -8.36924e-05 2.13278e-05 1.45207e-05 4.54862e-06 -6.14726e-06 2.0062e-06 1.02709e-06 1.4152e-05 -3.08225e-05 -0.0166501 -0.0157139 -0.013957 0.0107537 0.0873717 0.111302 0.0454129 -0.00530142 -0.0468336 -0.0790063 -0.0826944 -0.0534753 -0.0288705 -0.0149009 -0.00801592 -0.0046342 -0.00291835 -0.00213019 -0.00170055 -0.001352 -0.00110593 -0.000742655 -0.000532042 -0.000544742 -0.000479206 -0.000407307 -0.000403575 -0.000366209 -0.000324161 -0.000286183 -0.000247579 -0.000214281 -0.000203435 -0.000186896 -0.000171033 -0.00015779 -0.000145259 -0.000128069 -0.000122647 -9.89398e-05 -0.000114926 -0.000132195 -0.000107872 -8.91015e-05 -7.87996e-05 -8.14061e-05 -8.9098e-05 -8.83368e-05 -7.6122e-05 -6.14668e-05 -4.75402e-05 -3.81855e-05 -3.69696e-05 -4.78656e-05 -5.61346e-05 -5.35007e-05 -4.1459e-05 -3.35411e-05 -2.52374e-05 -2.37479e-05 -4.6406e-05 -9.41884e-05 -0.000109222 -8.52676e-05 -4.25166e-05 -4.10125e-05 -3.95085e-05 -3.80045e-05 -3.65004e-05 -3.49964e-05 -3.41627e-05 -3.3541e-05 -3.29193e-05 -3.22976e-05 -3.16758e-05 -3.10334e-05 -3.03653e-05 -2.96971e-05 -2.9029e-05 -2.83609e-05 -2.76928e-05 -2.70246e-05 -2.63565e-05 -2.56884e-05 -2.50203e-05 -2.43521e-05 -2.38716e-05 -2.34324e-05 -2.29932e-05 -2.25539e-05 -2.21147e-05 -2.16755e-05 -2.12362e-05 -2.0797e-05 -2.03578e-05 -1.99186e-05 -1.95079e-05 -1.9217e-05 -1.8926e-05 -1.8635e-05 -1.8344e-05 -1.8053e-05 -1.7762e-05 -1.74711e-05 -1.71801e-05 } .graph element create V20 -x x -y v20 v21 set { 1.86175 1.73273 1.42016 1.02483 0.944013 0.274107 0.0823742 0.0379366 0.020816 0.0132952 0.00955525 0.00717008 0.00592286 0.00437379 0.00383557 0.00273694 -0.0037467 -0.0054191 -0.00131454 0.0112179 0.0133918 0.00519747 -0.00260113 -0.00252847 -0.00181292 0.000183398 -0.000667607 -0.000750747 -0.000594314 -0.000433904 -0.000308985 -0.000217858 -0.000152926 -0.000107454 -7.54076e-05 -5.2675e-05 -3.66299e-05 -2.54341e-05 -1.75095e-05 -1.18848e-05 -7.97289e-06 -5.30239e-06 -3.53615e-06 -2.38504e-06 -2.40158e-06 -3.84485e-06 -5.29435e-06 -2.57099e-06 1.95189e-06 3.55083e-06 2.06179e-06 5.72753e-07 3.30469e-07 3.40296e-07 3.60221e-07 4.86081e-07 6.1194e-07 7.37799e-07 8.63659e-07 9.89518e-07 9.21274e-07 7.22275e-07 5.23276e-07 3.24277e-07 1.25278e-07 -5.59467e-08 -9.03265e-08 -1.24706e-07 -1.59086e-07 -1.93466e-07 -2.27846e-07 -2.62226e-07 -2.96605e-07 -3.30985e-07 -3.65365e-07 -3.99745e-07 -4.24266e-07 -3.82163e-07 -3.40061e-07 -2.97959e-07 -2.55857e-07 -2.13755e-07 -1.71652e-07 -1.2955e-07 -8.7448e-08 -4.53457e-08 -3.24353e-09 3.76901e-08 7.19937e-08 1.06297e-07 1.40601e-07 1.74904e-07 2.09208e-07 2.43512e-07 2.77815e-07 3.12119e-07 3.46422e-07 3.80726e-07 4.04507e-07 3.77191e-07 3.49876e-07 3.22561e-07 2.95246e-07 2.67931e-07 2.40616e-07 2.13301e-07 1.85986e-07 1.58671e-07 1.31356e-07 1.04041e-07 7.67256e-08 4.94105e-08 2.20955e-08 -5.21962e-09 -3.25347e-08 -5.98498e-08 -8.71649e-08 -1.1448e-07 -1.41795e-07 -1.6911e-07 7.87893e-06 0.0114592 -0.0245712 -0.111637 0.0961324 1.61168 3.22343 4.20442 4.53535 4.83834 4.95464 4.98874 4.99746 4.99883 4.99948 4.99815 4.98431 4.99298 4.99718 5.01948 5.04749 5.008 4.98243 4.98985 4.99781 4.99887 4.99679 4.99616 4.99743 4.99859 4.99936 4.99972 5.00058 5.00123 5.0002 4.99945 4.99983 4.9998 4.99966 4.99958 4.99956 4.99956 4.99956 4.99958 4.99961 4.99965 4.99969 4.99973 4.99977 4.9998 4.99983 4.99985 4.99987 4.99989 4.99991 4.99992 4.99993 4.99994 4.99995 4.99996 4.99997 4.99997 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 4.99999 4.99998 4.99997 4.99996 5.01454 4.99566 4.96796 4.99819 5.03232 5.00034 4.99867 4.99937 4.99977 4.99992 4.99997 4.99999 5.00001 5.00021 4.99974 4.98462 4.99301 4.99723 5.01936 5.04807 5.00929 4.9789 4.97876 4.98244 4.9863 4.99575 5.0069 5.00863 5.00624 5.00357 5.0019 5.00098 5.00048 5.00025 5.00016 5.00011 5.00013 5.00009 4.99982 4.99994 5.00005 4.99994 4.99988 4.99989 4.99997 5.00003 5.00005 5.00002 5.00001 5.00001 5.00001 4.99993 4.99999 5 5.00021 4.99997 4.99981 5 5.00009 5.0001 5.00001 4.99991 4.9999 5 5.00011 5.00017 5.00018 5.00018 5.00014 5.00007 4.99999 4.9999 4.9999 5.00001 5.00016 5.00014 4.99999 4.99993 4.99999 5.00009 5.00007 5.00006 5.00004 5.00003 5.00001 5.00001 5 4.99999 4.99998 4.99997 4.99997 4.99997 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 } .graph element create V21 -x x -y v21 v22 set { 7.10441e-10 0.00107105 0.000637109 -0.00236346 -0.018079 -0.0120077 -0.00217059 0.00266679 0.00403383 0.00403836 0.00356705 0.00303303 0.00244716 0.00198586 0.0016855 0.00136497 -3.96022e-05 -0.000367409 -3.77079e-05 0.00194085 0.00506964 -0.0400214 -0.0402572 0.0524434 0.286234 0.803011 1.44795 2.02473 2.54768 3.02748 3.4415 3.78287 4.09667 4.35152 4.53987 4.67614 4.77407 4.84319 4.89227 4.92702 4.95119 4.96764 4.97846 4.98557 4.98982 4.99209 4.99371 4.99569 4.99727 4.99802 4.99834 4.99867 4.99892 4.99915 4.99936 4.99939 4.99943 4.99946 4.9995 4.99953 4.99957 4.9996 4.99963 4.99967 4.9997 4.99973 4.99974 4.99975 4.99976 4.99977 4.99978 4.9998 4.99981 4.99982 4.99983 4.99984 4.99985 4.99986 4.99986 4.99986 4.99987 4.99987 4.99988 4.99988 4.99989 4.99989 4.9999 4.9999 4.9999 4.9999 4.99991 4.99991 4.99991 4.99991 4.99992 4.99992 4.99992 4.99992 4.99993 4.99993 4.99993 4.99993 4.99993 4.99993 4.99993 4.99993 4.99994 4.99994 4.99994 4.99994 4.99994 4.99994 4.99994 4.99994 4.99995 4.99995 4.99995 4.99995 4.99995 4.99995 4.99995 5.00145 5.00659 5.01209 5.01931 5.00279 4.99273 4.99217 4.99295 4.99471 4.99594 4.99696 4.9978 4.99844 4.99891 4.99924 4.99635 4.99699 4.99813 5.00068 5.00307 5.0588 4.96365 4.54012 3.6307 2.35176 1.0322 0.354379 0.115986 0.0435668 0.0245112 0.020786 0.0164656 0.0118409 0.00849698 0.00597078 0.0040105 0.0026076 0.0016597 0.00118185 0.00121067 0.00153587 0.00174836 0.00136519 -0.000189116 -0.00315555 -0.00646603 -0.00898042 -0.010203 -0.0110896 -0.0123764 -0.00953841 -0.00225795 0.000818314 0.00152252 0.00150269 0.00119025 0.000767068 0.000308852 -3.79272e-05 -0.00019691 -0.000186642 -9.73653e-05 -8.49784e-06 2.04147e-05 -9.91086e-06 -1.55959e-05 -1.80499e-05 -1.77097e-05 -1.51548e-05 -1.1978e-05 -9.84916e-06 -1.29728e-05 -1.67235e-05 -1.74153e-05 -1.39958e-05 -5.92272e-06 -8.08216e-06 -1.53077e-05 -2.92531e-05 -3.91049e-05 -2.98935e-05 -7.32122e-06 3.18534e-05 4.39134e-05 4.18753e-05 3.22759e-05 1.86766e-05 1.58432e-05 1.30098e-05 1.01765e-05 7.34312e-06 4.50975e-06 1.67639e-06 -1.15697e-06 -1.23877e-06 -1.11991e-06 -1.00106e-06 -8.82208e-07 -7.63355e-07 -6.44502e-07 -5.2565e-07 -4.29318e-07 -3.44661e-07 -2.60004e-07 -1.75347e-07 -9.06904e-08 -6.03349e-09 7.86234e-08 1.6328e-07 2.47937e-07 3.32594e-07 4.17251e-07 5.01908e-07 5.86565e-07 6.71222e-07 7.36123e-07 6.43886e-07 5.5165e-07 4.59414e-07 3.67178e-07 0.000334759 -4.60833e-05 -0.00106139 -0.00166624 0.000859563 0.00102606 0.00410037 0.00419931 0.00518997 0.00459791 0.00503125 0.00523877 0.00452158 0.00339924 0.00233399 0.000876915 0.000546439 0.000444299 0.000983968 0.00119304 -0.0429422 -0.0403983 0.0534896 0.288013 0.807345 1.44247 2.03448 2.57021 3.05049 3.47332 3.8131 4.1009 4.34677 4.53512 4.67127 4.76531 4.82526 4.86593 4.89586 4.91904 4.93806 4.95348 4.96597 4.97629 4.9843 4.98983 4.99335 4.9957 4.99741 4.99864 4.99946 4.99994 5.00047 5.00073 5.00086 5.00092 5.00094 5.00091 5.00087 5.00081 5.00074 5.00067 5.00059 5.00052 5.00046 5.0004 5.00034 5.0003 5.00026 5.00022 5.00019 5.00016 5.00014 5.00012 5.0001 5.00009 5.00007 5.00006 5.00006 5.00005 5.00004 5.00004 5.00004 5.00003 5.00003 5.00003 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 } .graph element create V22 -x x -y v22 v23 set { 5 5.00284 5.01266 5.01895 4.98936 4.99575 4.99217 4.99545 4.99775 4.99894 4.99946 4.99968 4.99975 4.99977 4.99986 4.9999 4.99528 4.99808 5.00039 5.00392 5.00512 4.99985 4.99863 4.99942 4.99992 5.00017 4.99897 4.99803 4.99784 4.99739 4.99883 5.00365 5.00298 5.00133 5.00048 5.00019 5.00008 5.00005 5.00004 5.00003 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 4.99999 4.99997 4.99995 4.99996 4.99998 5 5.00001 5.00001 5.00002 5.00002 5.00003 5.00003 5.00002 5.00002 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5.00217 5.00108 4.99547 4.99658 5.00667 4.99641 4.99532 4.99938 5.00328 5.00222 5.00114 5.00052 5.00024 5.00011 5.00009 4.99285 4.99591 4.99897 5.00403 5.00786 5.00318 4.99942 4.9992 4.99949 5.001 5.00408 5.00319 5.00063 4.99995 5.00014 4.99982 4.99832 4.99838 4.99865 4.99912 4.99836 4.99735 4.99606 4.99814 5.00958 5.02973 5.05293 5.06103 4.99342 4.80726 4.50744 4.07509 3.41358 2.37924 1.03194 0.261552 0.142392 0.0904482 0.0555071 0.0322869 0.018289 0.0113802 0.00875182 0.00757055 0.00629906 0.00523 0.00403349 0.0031953 0.00280864 0.00286119 0.00250389 0.00202815 0.001723 0.00147312 0.0012411 0.00104401 0.000886204 0.000758277 0.000651915 0.00056348 0.000487966 0.000424048 0.000365613 0.000308178 0.000258725 0.000228061 0.000207976 0.000198491 0.00018518 0.000172716 0.000163197 0.000155007 0.000141734 0.000128461 0.000115188 0.000101915 8.86417e-05 7.53686e-05 6.20956e-05 5.69164e-05 5.23275e-05 4.77385e-05 4.31495e-05 3.85605e-05 3.39716e-05 2.93826e-05 2.69449e-05 2.56224e-05 2.42999e-05 2.29774e-05 2.16549e-05 2.03324e-05 1.90099e-05 1.76873e-05 1.63648e-05 1.50423e-05 1.37198e-05 1.23973e-05 1.10748e-05 9.75232e-06 8.48447e-06 7.65129e-06 6.81811e-06 5.98494e-06 5.15176e-06 0.00056893 -0.00787906 -0.0217381 -0.0370066 -0.00770505 0.00659312 0.00975477 0.00949456 0.00777552 0.00655645 0.00568776 0.00508782 0.00458121 0.00410187 0.00365665 0.0015121 0.00160863 0.00263181 0.00638941 0.00772607 0.00225583 0.0010843 0.000882939 0.000801563 0.00075632 0.000554992 0.000435131 0.0003474 0.000217667 0.000491602 0.0012267 0.00250446 0.000212058 -0.0174972 -0.0527527 -0.0479071 0.194908 1.45838 3.40677 4.49242 4.86894 4.97215 5.01218 5.04342 5.06228 5.03069 4.87169 4.57056 4.11523 3.38264 2.19691 0.715839 0.172818 0.102162 0.0627162 0.0363388 0.020289 0.0119414 0.00826608 0.0066417 0.00549092 0.00492505 0.00439443 0.0037156 0.00306471 0.00247451 0.00195965 0.0014822 0.0010815 0.000904464 0.0010514 0.00152308 0.00120752 0.000228447 -0.00102833 -0.00116644 -0.00042067 4.78758e-05 5.09599e-05 -4.45756e-05 -3.22966e-06 3.81163e-05 7.94622e-05 0.000120808 0.000162154 0.000161895 0.000148481 0.000135068 0.000121654 0.000108241 9.81453e-05 9.2164e-05 8.61827e-05 8.02014e-05 7.42201e-05 6.82388e-05 6.22576e-05 5.62763e-05 5.0295e-05 4.43137e-05 3.83324e-05 3.54323e-05 3.321e-05 3.09877e-05 2.87654e-05 2.65431e-05 2.43209e-05 2.20986e-05 1.98763e-05 1.7654e-05 1.54317e-05 1.34612e-05 1.25441e-05 1.1627e-05 1.07099e-05 9.79276e-06 8.87564e-06 7.95851e-06 7.04139e-06 6.12427e-06 } .graph element create V23 -x x -y v23 v24 set { 5 5.01099 5.00866 4.97845 4.92369 4.9273 4.97413 4.9929 4.99826 4.99958 4.99978 5.00005 4.99968 4.99959 5.00014 4.99979 4.99914 4.99982 5.00023 5.00295 5.00664 4.99854 4.99647 5.00438 5.01722 5.03681 5.04766 5.04799 5.04867 5.04873 5.04685 5.04413 5.0367 5.02505 5.01726 5.01183 5.00806 5.00549 5.00371 5.00246 5.00162 5.00105 5.00069 5.00045 5.00031 5.00024 5.00019 5.00012 5.00007 5.00004 5.00001 4.99998 4.99999 4.99999 5 5.00001 5.00001 5.00002 5.00002 5.00003 5.00003 5.00003 5.00002 5.00002 5.00001 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5.00418 4.99953 4.99152 4.99807 5.00497 5.00112 5.00055 5.00038 5.00018 5.00006 5.00006 5.00007 5.00006 5.00004 5.00004 4.99853 4.99945 4.99998 5.00304 5.00935 5.00742 4.99181 4.97421 4.93603 4.8853 4.8927 4.93984 4.97458 4.99039 4.99614 4.99801 4.99851 4.99869 4.99924 5.00108 5.00181 5.00119 5.00059 5.00031 5.00022 5.00018 5.00011 5.00001 5.00006 4.99981 4.99977 4.99982 5.00012 4.99993 5.00008 5.00043 5.00048 5.00024 5.00008 4.99984 4.99993 5.00011 4.99996 4.9998 4.99977 4.9998 4.99993 5.00008 5.00011 5.00002 4.99995 4.99989 4.99993 5 5.00007 5.00009 4.99994 4.99977 4.9997 4.99975 4.99996 4.99996 4.99988 4.9997 4.99952 4.9995 4.99956 4.99973 4.99988 5.00005 5.00025 5.00042 5.00036 5.00031 5.00025 5.0002 5.00014 5.00009 5.00003 5.00002 5.00001 5.00001 5 4.99999 4.99998 4.99998 4.99997 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5.00284 5.00442 5.00381 4.98997 4.99092 5.00733 5.07791 4.98237 4.86434 4.76835 4.74067 4.79278 4.85094 4.90068 4.93603 4.95698 4.96984 4.97856 4.98869 4.99904 5.0005 4.99524 5.00181 5.01878 5.05177 5.07986 4.98917 4.56217 3.68 2.3539 1.18541 0.505772 0.221044 0.115287 0.0760938 0.0589194 0.0476784 0.0457213 0.0412911 0.033889 0.0259741 0.0191452 0.0139018 0.0100235 0.00711788 0.00497657 0.00349368 0.00250021 0.00176179 0.00121843 0.000838368 0.000582711 0.000423458 0.000294608 0.000201251 0.000133748 8.6227e-05 5.44252e-05 3.30514e-05 1.93926e-05 1.09814e-05 5.29857e-06 1.92247e-06 3.08708e-07 -3.74311e-07 -6.11121e-07 -7.27807e-07 -4.87604e-07 -4.80493e-07 -9.15925e-07 -2.03774e-06 -4.01128e-06 -2.46644e-06 2.10626e-06 8.22422e-06 1.04922e-05 9.83047e-06 7.27106e-06 3.29654e-06 -2.06736e-06 -2.18019e-06 -2.29303e-06 -2.40586e-06 -2.51869e-06 -2.63153e-06 -2.24615e-06 -1.70325e-06 -1.16036e-06 -6.17468e-07 -7.45754e-08 2.45198e-07 2.88285e-07 3.31373e-07 3.7446e-07 4.17548e-07 4.60635e-07 5.03723e-07 5.4681e-07 5.89898e-07 6.32985e-07 6.76073e-07 6.19054e-07 5.4001e-07 4.60967e-07 3.81923e-07 3.02879e-07 2.23836e-07 1.44792e-07 6.57488e-08 -1.32948e-08 -9.23383e-08 -1.6698e-07 -2.23206e-07 -2.79432e-07 -3.35658e-07 -3.91884e-07 -4.48109e-07 -5.04335e-07 -5.60561e-07 -6.16787e-07 } .graph element create V24 -x x -y v24 v25 set { 1.34824 1.35838 1.36465 1.34675 1.29167 1.23161 1.2201 1.2185 1.2181 1.21798 1.21793 1.21788 1.21785 1.21782 1.21779 1.21776 1.21655 1.21656 1.21669 1.21871 1.22421 1.22247 1.21858 1.2228 1.23803 1.27737 1.10647 0.395248 0.0600669 0.027687 0.0192374 0.015425 0.0130881 0.00977445 0.00696598 0.00491122 0.00341952 0.00237078 0.00162339 0.00109178 0.000726647 0.000478886 0.00031568 0.000207902 0.000143494 0.000109768 8.62987e-05 5.69775e-05 3.36547e-05 2.30356e-05 1.86108e-05 1.41861e-05 1.08293e-05 7.68835e-06 4.79593e-06 4.51019e-06 4.22444e-06 3.9387e-06 3.65295e-06 3.36721e-06 3.04559e-06 2.69981e-06 2.35403e-06 2.00825e-06 1.66247e-06 1.34508e-06 1.26225e-06 1.17941e-06 1.09657e-06 1.01373e-06 9.30893e-07 8.48054e-07 7.65216e-07 6.82378e-07 5.9954e-07 5.16702e-07 4.37489e-07 3.82774e-07 3.2806e-07 2.73346e-07 2.18632e-07 1.63917e-07 1.09203e-07 5.4489e-08 -2.2523e-10 -5.49395e-08 -1.09654e-07 -1.52862e-07 -1.3079e-07 -1.08718e-07 -8.6646e-08 -6.45739e-08 -4.25019e-08 -2.04298e-08 1.64229e-09 2.37144e-08 4.57864e-08 6.78585e-08 8.71693e-08 9.30725e-08 9.89758e-08 1.04879e-07 1.10782e-07 1.16685e-07 1.22589e-07 1.28492e-07 1.34395e-07 1.40298e-07 1.46201e-07 1.52105e-07 1.58008e-07 1.63911e-07 1.69814e-07 1.75718e-07 1.81621e-07 1.87524e-07 1.93427e-07 1.9933e-07 2.05234e-07 2.11137e-07 2.19788e-07 0.000393944 -0.000218983 -0.00105784 0.00172403 -0.00027134 -0.000204147 8.79968e-06 5.93762e-05 5.83554e-05 4.13815e-05 3.71369e-05 3.03372e-05 2.25336e-05 1.5986e-05 1.07284e-05 -7.5239e-05 5.60593e-05 6.97571e-05 0.000667617 0.000960856 0.00131749 -0.00759564 -0.0217897 -0.0450321 -0.076646 -0.128569 -0.186391 -0.202175 -0.206953 -0.2082 -0.208416 -0.208669 -0.208934 -0.209111 -0.209234 -0.209329 -0.209389 -0.209416 -0.2094 -0.209329 -0.20926 -0.209204 -0.209208 -0.209285 -0.209454 -0.209641 -0.20977 -0.209811 -0.209833 -0.209887 -0.209653 -0.209127 -0.208893 -0.208811 -0.208777 -0.208758 -0.208747 -0.20874 -0.208726 -0.208697 -0.208657 -0.208611 -0.208565 -0.208524 -0.208488 -0.208451 -0.208412 -0.208373 -0.208333 -0.208294 -0.208256 -0.208219 -0.208183 -0.208145 -0.208107 -0.208066 -0.208029 -0.207993 -0.207959 -0.207923 -0.207883 -0.207838 -0.207789 -0.207747 -0.20771 -0.207675 -0.207642 -0.207605 -0.207568 -0.207531 -0.207494 -0.207457 -0.20742 -0.207383 -0.207346 -0.207308 -0.207271 -0.207233 -0.207196 -0.207158 -0.207121 -0.207084 -0.207046 -0.207009 -0.206972 -0.206935 -0.206898 -0.206861 -0.206823 -0.206786 -0.206749 -0.206712 -0.206675 -0.206638 -0.2066 -0.206563 -0.206526 -0.206489 -0.206452 -0.206415 -0.203384 -0.20015 -0.196872 -0.205024 -0.210727 -0.206779 -0.0685263 0.586138 1.4665 2.22945 2.77554 3.076 3.24926 3.34515 3.40164 3.43006 3.43713 3.43075 3.42886 3.4384 3.46567 3.49025 3.51287 3.53821 3.57841 3.39846 2.80753 2.22947 1.7549 1.30429 0.707786 0.303206 0.131352 0.0671706 0.0429955 0.032461 0.0257161 0.0239521 0.0217397 0.0179705 0.0138745 0.0102813 0.00749643 0.0054328 0.00386817 0.0027004 0.00189442 0.00135552 0.000954715 0.000659981 0.000453435 0.000313993 0.000231347 0.000159665 0.000108122 7.10528e-05 4.50233e-05 2.77892e-05 1.62765e-05 8.9893e-06 4.5471e-06 1.54614e-06 -1.6542e-07 -8.68508e-07 -1.04369e-06 -9.63086e-07 -8.44294e-07 -6.57339e-07 -7.35885e-07 -9.80056e-07 -1.39772e-06 -2.10199e-06 -1.37474e-06 6.13269e-07 3.3028e-06 4.60941e-06 4.91053e-06 4.14186e-06 2.45258e-06 -8.7388e-09 -3.59647e-07 -7.10554e-07 -1.06146e-06 -1.41237e-06 -1.76328e-06 -1.63073e-06 -1.34534e-06 -1.05995e-06 -7.74561e-07 -4.8917e-07 -2.95733e-07 -2.16326e-07 -1.3692e-07 -5.75135e-08 2.18929e-08 1.01299e-07 1.80706e-07 2.60112e-07 3.39519e-07 4.18925e-07 4.98332e-07 4.83984e-07 4.4901e-07 4.14035e-07 3.79061e-07 3.44087e-07 3.09112e-07 2.74138e-07 2.39163e-07 2.04189e-07 1.69215e-07 1.26002e-07 4.83213e-08 -2.9359e-08 -1.07039e-07 -1.8472e-07 -2.624e-07 -3.4008e-07 -4.1776e-07 -4.95441e-07 } .graph element create V25 -x x -y v25 v26 set { 7.10441e-10 0.000309731 -0.000308186 -0.001694 -0.00360784 8.40909e-05 0.00203175 0.0012896 0.000596548 0.000277191 0.000161134 0.000120439 8.4915e-05 9.49929e-05 6.18812e-05 1.65433e-05 1.89682e-05 3.97578e-05 4.95446e-05 0.000225325 0.000214579 -0.00230134 -0.000451102 0.00997237 0.0341443 0.0449314 0.0424411 0.0341996 0.0315315 0.0308892 0.0291614 0.024365 0.0190282 0.0188976 0.017238 0.0138526 0.0105645 0.00778548 0.00561753 0.0039871 0.00279554 0.00194075 0.0013468 0.000934775 0.000664723 0.000498911 0.000377384 0.000254183 0.000163421 0.000120773 9.65058e-05 7.22384e-05 5.60316e-05 4.14549e-05 2.79516e-05 2.57096e-05 2.34677e-05 2.12257e-05 1.89837e-05 1.67417e-05 1.46737e-05 1.27228e-05 1.07719e-05 8.82099e-06 6.87009e-06 5.0896e-06 4.71705e-06 4.34451e-06 3.97196e-06 3.59941e-06 3.22686e-06 2.85431e-06 2.48176e-06 2.10921e-06 1.73666e-06 1.36411e-06 1.02855e-06 9.42931e-07 8.57316e-07 7.71701e-07 6.86086e-07 6.00471e-07 5.14856e-07 4.29241e-07 3.43626e-07 2.58011e-07 1.72396e-07 9.85409e-08 9.14091e-08 8.42773e-08 7.71456e-08 7.00138e-08 6.2882e-08 5.57503e-08 4.86185e-08 4.14867e-08 3.4355e-08 2.72232e-08 2.05821e-08 1.63235e-08 1.2065e-08 7.80643e-09 3.54786e-09 -7.10696e-10 -4.96926e-09 -9.22782e-09 -1.34864e-08 -1.77449e-08 -2.20035e-08 -2.62621e-08 -3.05206e-08 -3.47792e-08 -3.90378e-08 -4.32963e-08 -4.75549e-08 -5.18134e-08 -5.6072e-08 -6.03306e-08 -6.45891e-08 -6.88477e-08 -8.76373e-06 0.000131607 -0.00021685 -0.000433027 0.00047234 0.000211593 -0.000189601 3.2492e-05 0.000575955 7.72235e-05 -0.000285172 -0.000242061 -0.000135112 -3.50117e-05 -2.75868e-05 5.48974e-05 1.80604e-07 5.48911e-05 3.97478e-05 0.000192909 0.000297932 0.00402253 -0.0122366 -0.047853 -0.0963082 -0.108071 -0.0567275 -0.0239271 -0.0178628 -0.0233027 -0.031853 -0.0400843 -0.0482725 -0.0576154 -0.0627218 -0.0511236 -0.0279524 -0.0150986 -0.00931091 -0.00652876 -0.00479286 -0.00344346 -0.00249578 -0.0019532 -0.00157977 -0.00131848 -0.00111251 -0.000939229 -0.000797445 -0.000708384 -0.000630452 -0.000539722 -0.000508862 -0.000480596 -0.000439484 -0.000407217 -0.000363866 -0.000329506 -0.000318642 -0.000307362 -0.000286511 -0.000266253 -0.000242943 -0.000218107 -0.000204661 -0.00020241 -0.000194435 -0.000185062 -0.000173042 -0.000160549 -0.000151407 -0.000145626 -0.000145976 -0.000147342 -0.000145288 -0.000137979 -0.000124481 -0.000123218 -0.000127453 -0.000139006 -0.000145486 -0.000129764 -9.82749e-05 -4.72596e-05 -3.08671e-05 -3.28834e-05 -4.52254e-05 -6.25389e-05 -6.32516e-05 -6.39643e-05 -6.4677e-05 -6.53897e-05 -6.61023e-05 -6.6815e-05 -6.75277e-05 -6.61005e-05 -6.45173e-05 -6.29341e-05 -6.13509e-05 -5.97676e-05 -5.81844e-05 -5.66012e-05 -5.54231e-05 -5.4455e-05 -5.3487e-05 -5.25189e-05 -5.15508e-05 -5.05828e-05 -4.96147e-05 -4.86466e-05 -4.76785e-05 -4.67105e-05 -4.57424e-05 -4.47743e-05 -4.38063e-05 -4.28382e-05 -4.18821e-05 -4.10211e-05 -4.016e-05 -3.9299e-05 -3.8438e-05 4.29885e-05 5.14113e-05 -0.000127986 -0.000611463 -0.000149428 0.000882394 0.00297059 -0.00405825 -0.00591067 -0.00546997 -0.00158744 0.00190677 0.00298403 0.00268595 0.00196161 0.00130289 0.000783347 0.000520683 0.000565306 0.00053419 -0.00224696 -0.000920818 0.0132755 0.0322504 0.0442808 0.0638615 0.0701007 0.0539356 0.0247771 0.056244 0.294266 0.831368 1.45424 2.02898 2.54559 2.9937 3.35333 3.72609 4.06363 4.32789 4.52413 4.66504 4.7652 4.83637 4.88631 4.92109 4.94464 4.96046 4.97218 4.98079 4.98679 4.99076 4.99361 4.99555 4.99686 4.99783 4.99853 4.99902 4.99936 4.99959 4.99973 4.99983 4.9999 4.99993 4.99996 4.99998 5 5.00001 5 4.99999 4.99997 4.99994 4.99993 4.99994 4.99996 4.99999 5.00004 5.00006 5.00005 5.00003 5.00002 5.00001 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99998 } .graph element create V26 -x x -y v26 v27 set { 5 4.99984 4.99796 4.99478 4.9889 4.98738 4.98896 4.99087 4.99262 4.99419 4.99552 4.99659 4.99743 4.99807 4.99855 4.9989 4.99894 4.99908 4.99935 5.00001 5.0007 5.00132 5.00032 4.99976 5.00134 5.00339 5.00315 5.00157 5.00091 5.00058 5.00012 4.99944 4.99886 4.9994 4.99934 4.99899 4.99876 4.99868 4.99872 4.99883 4.99898 4.99914 4.9993 4.99944 4.99956 4.99967 4.99976 4.99982 4.99986 4.9999 4.99993 4.99997 4.99997 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5.00009 5.00028 5.00015 4.99983 5.00036 4.99996 4.99834 4.99783 5.00383 5.00734 5.00387 5.00058 4.99893 4.99836 4.99832 4.99854 4.99873 4.99905 4.99927 4.99952 4.99969 4.99834 4.99536 4.99163 4.99073 5.0053 5.03631 5.03103 4.9008 4.62503 4.21887 3.70902 3.09967 2.35791 1.41912 0.519675 0.210458 0.131362 0.0980819 0.0708209 0.0471701 0.0323272 0.0253535 0.0199144 0.0152615 0.0117228 0.00917696 0.00738117 0.00609292 0.00512664 0.00436184 0.0037961 0.00331639 0.00289006 0.0025477 0.00226529 0.00202925 0.00182793 0.00165474 0.00150531 0.00137529 0.00125983 0.00115603 0.00106455 0.000982977 0.000911255 0.000846819 0.000790092 0.000738698 0.000692816 0.00065107 0.000613595 0.000579642 0.000548935 0.00052106 0.000495598 0.000472174 0.000450849 0.000431118 0.000412667 0.000395868 0.000381319 0.000368487 0.000357327 0.000344212 0.000330334 0.00031622 0.000303298 0.000295809 0.00028832 0.000280831 0.000273342 0.000265853 0.000258364 0.000250875 0.000245118 0.000239488 0.000233857 0.000228227 0.000222596 0.000216966 0.000211336 0.000207047 0.000203455 0.000199863 0.00019627 0.000192678 0.000189085 0.000185493 0.0001819 0.000178308 0.000174716 0.000171123 0.000167531 0.000163938 0.000160346 0.000156835 0.000153973 0.00015111 0.000148248 0.000145385 0.000296579 -3.96718e-05 -0.000449085 0.000323433 0.000750086 0.000268264 0.000149028 -0.000100249 7.00956e-05 0.00012605 0.00022592 0.000193036 0.000120453 8.07865e-05 7.65771e-05 -3.27828e-05 0.000116759 0.000169498 0.000409804 0.000414965 0.00092323 -0.00590633 -0.0175477 -0.032433 -0.0559842 -0.0820373 0.0688484 0.626629 1.32929 2.01657 2.60925 3.12329 3.38952 3.14128 2.38463 1.23802 0.316019 0.107832 0.0694707 0.051837 0.035247 0.0209999 0.0116618 0.00967674 0.00789182 0.00574566 0.00386872 0.00258612 0.00167126 0.00104169 0.000641093 0.000401246 0.000277928 0.000171775 0.000102266 5.89376e-05 3.29258e-05 1.80463e-05 1.0057e-05 6.4571e-06 5.10093e-06 4.06791e-06 3.62716e-06 3.63321e-06 3.99625e-06 4.64368e-06 5.20886e-06 4.77728e-06 3.23919e-06 1.14113e-06 -1.29416e-06 -4.15607e-06 -1.88532e-06 5.24411e-06 1.38678e-05 1.28823e-05 3.6758e-06 -2.52285e-06 -3.97133e-06 -4.03071e-06 -3.37154e-06 -2.71238e-06 -2.05321e-06 -1.39404e-06 -7.34872e-07 -3.73325e-07 -1.05873e-07 1.61578e-07 4.2903e-07 6.96482e-07 8.18468e-07 7.60065e-07 7.01662e-07 6.43258e-07 5.84855e-07 5.26452e-07 4.68049e-07 4.09646e-07 3.51243e-07 2.9284e-07 2.34437e-07 1.71213e-07 1.06928e-07 4.2644e-08 -2.16403e-08 -8.59247e-08 -1.50209e-07 -2.14493e-07 -2.78778e-07 -3.43062e-07 -4.07346e-07 -4.55065e-07 -4.3348e-07 -4.11896e-07 -3.90311e-07 -3.68726e-07 -3.47141e-07 -3.25556e-07 -3.03971e-07 -2.82386e-07 } .graph element create V27 -x x -y v27 v28 set { 0.368163 0.361756 0.327463 0.269513 0.149476 0.0805716 0.0501146 0.03403 0.0230886 0.0160474 0.0116071 0.00870013 0.00679614 0.00542384 0.00432512 0.00340653 -0.00129719 -0.00399429 -0.00318719 0.00443085 0.0150156 0.0334147 0.0132288 -0.0189751 -0.0508377 -0.0252174 -0.0142489 -0.00675908 -0.0038653 -0.00243423 -0.00168891 -0.00120901 -0.000900426 -0.000685575 -0.000557595 -0.000457268 -0.000377427 -0.000315269 -0.000266613 -0.000228397 -0.000198283 -0.000174248 -0.000154886 -0.00013892 -0.000125864 -0.000115189 -0.000105841 -9.66611e-05 -8.84262e-05 -8.23872e-05 -7.74668e-05 -7.25463e-05 -6.79992e-05 -6.35276e-05 -5.92413e-05 -5.68994e-05 -5.45574e-05 -5.22154e-05 -4.98735e-05 -4.75315e-05 -4.54981e-05 -4.36726e-05 -4.18471e-05 -4.00216e-05 -3.81961e-05 -3.64559e-05 -3.54209e-05 -3.43858e-05 -3.33508e-05 -3.23157e-05 -3.12807e-05 -3.02456e-05 -2.92105e-05 -2.81755e-05 -2.71404e-05 -2.61054e-05 -2.51232e-05 -2.44984e-05 -2.38736e-05 -2.32487e-05 -2.26239e-05 -2.19991e-05 -2.13742e-05 -2.07494e-05 -2.01246e-05 -1.94998e-05 -1.88749e-05 -1.82865e-05 -1.79044e-05 -1.75224e-05 -1.71403e-05 -1.67582e-05 -1.63762e-05 -1.59941e-05 -1.56121e-05 -1.523e-05 -1.4848e-05 -1.44659e-05 -1.41138e-05 -1.39075e-05 -1.37011e-05 -1.34947e-05 -1.32883e-05 -1.30819e-05 -1.28755e-05 -1.26691e-05 -1.24627e-05 -1.22563e-05 -1.205e-05 -1.18436e-05 -1.16372e-05 -1.14308e-05 -1.12244e-05 -1.1018e-05 -1.08116e-05 -1.06052e-05 -1.03988e-05 -1.01924e-05 -9.98605e-06 -9.77966e-06 -2.85319e-05 0.00281092 0.00180106 -0.000981083 0.00551926 -0.00119763 -0.0295069 -0.0367677 0.064749 0.119022 0.0882007 0.0552062 0.03418 0.0223243 0.015545 0.011949 0.00757134 0.00667655 0.00583243 0.00644443 0.00650959 -0.0302575 -0.0437806 -0.0355466 0.0381776 0.282109 0.674178 1.07582 1.45189 1.789 2.08649 2.34663 2.57245 2.81211 3.04778 3.2523 3.45877 3.65593 3.83396 3.9923 4.13368 4.25864 4.36719 4.46064 4.54086 4.60962 4.66835 4.71838 4.76094 4.79716 4.82796 4.85413 4.87634 4.89518 4.91116 4.92476 4.93631 4.94608 4.95434 4.9613 4.96715 4.97211 4.97638 4.98001 4.98312 4.98571 4.98795 4.98979 4.99138 4.99269 4.99381 4.99474 4.99551 4.99615 4.99668 4.99713 4.99752 4.99783 4.99811 4.99836 4.99858 4.99873 4.99884 4.99892 4.999 4.99907 4.99912 4.99916 4.99921 4.99926 4.99932 4.99937 4.99942 4.99948 4.99953 4.99956 4.99958 4.99961 4.99963 4.99966 4.99968 4.99971 4.99972 4.99973 4.99974 4.99975 4.99976 4.99977 4.99978 4.99979 4.9998 4.9998 4.99981 4.99982 4.99983 4.99984 4.99985 4.99986 4.99986 4.99987 4.99987 5.00498 5.00354 4.99359 4.98981 5.00498 5.00099 5.00041 5.00022 5.00015 5.00012 5.0001 5.00008 5.00005 5.00003 5 4.99431 4.99459 4.99591 5.00087 5.01029 5.03935 4.92784 4.51643 3.78356 2.68745 1.43417 0.583128 0.205094 0.0777337 0.0391566 0.02723 0.023883 0.018808 0.010165 0.00254623 -0.00377463 -0.0038097 0.00144145 0.00267231 0.00193045 0.00144538 0.00121758 0.00112893 0.00109424 0.0010226 0.000948072 0.000882573 0.000826996 0.000776391 0.000729719 0.000686499 0.000647333 0.000610108 0.000575631 0.000545069 0.000515485 0.000488514 0.000465316 0.000443215 0.000422454 0.00040292 0.00038488 0.000368472 0.000353628 0.000339643 0.000326197 0.000313483 0.000302884 0.000294038 0.000284003 0.000270941 0.000254925 0.000246511 0.000244089 0.000245538 0.000242099 0.000235728 0.000227482 0.000218001 0.000207257 0.000202127 0.000196997 0.000191868 0.000186738 0.000181608 0.00017758 0.000173899 0.000170219 0.000166538 0.000162857 0.000159576 0.00015679 0.000154005 0.000151219 0.000148433 0.000145647 0.000142861 0.000140076 0.00013729 0.000134504 0.000131718 0.000129603 0.000127635 0.000125668 0.0001237 0.000121732 0.000119765 0.000117797 0.000115829 0.000113862 0.000111894 0.000109993 0.000108372 0.000106751 0.00010513 0.000103509 0.000101887 0.000100266 9.86449e-05 9.70237e-05 } .graph element create V28 -x x -y v28 v29 set { 5 4.99899 4.99654 4.99327 4.9863 4.98954 4.99212 4.99378 4.9951 4.99624 4.99715 4.99786 4.99839 4.99879 4.99909 4.99931 4.99922 4.99933 4.99971 5.00064 5.00084 5.00123 4.99865 4.99853 4.99983 5.00457 5.00242 5.00105 5.00062 5.00042 4.99971 4.9994 4.9992 4.9996 4.99955 4.99932 4.99918 4.99915 4.99919 4.99927 4.99937 4.99948 4.99957 4.99966 4.99974 4.9998 4.99985 4.99989 4.99992 4.99993 4.99994 4.99994 4.99996 4.99998 5 5 5.00001 5.00001 5.00001 5.00002 5.00002 5.00001 5.00001 5.00001 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 4.9997 4.99998 4.99954 4.99963 5.00059 4.99945 4.99732 4.99957 5.00919 5.00558 5.00033 4.99851 4.9983 4.99854 4.99871 4.99928 4.99914 4.99939 4.99952 4.9998 4.99976 4.99744 4.99598 4.99478 4.99806 5.01911 5.04602 5.05469 5.01317 4.89484 4.69655 4.42036 4.06069 3.60793 3.12531 2.72975 2.45187 2.25081 2.09841 1.98509 1.90211 1.84084 1.79411 1.7574 1.72763 1.70283 1.68188 1.66389 1.64823 1.63438 1.62201 1.61088 1.60081 1.59163 1.58323 1.57549 1.56835 1.56173 1.55558 1.54985 1.54451 1.53951 1.53479 1.53035 1.52615 1.5222 1.51845 1.5149 1.51153 1.50834 1.50529 1.5024 1.49964 1.497 1.49449 1.49208 1.48977 1.48755 1.48542 1.48336 1.48138 1.47948 1.47765 1.4759 1.47419 1.47255 1.47096 1.46949 1.46823 1.46696 1.4657 1.46444 1.46317 1.46191 1.46065 1.45956 1.4585 1.45743 1.45636 1.45529 1.45422 1.45315 1.45226 1.45145 1.45064 1.44983 1.44902 1.44821 1.4474 1.44659 1.44579 1.44498 1.44417 1.44336 1.44255 1.44174 1.44094 1.44019 1.43944 1.43868 1.43793 1.43765 1.43679 1.43515 1.43405 1.43478 1.43387 1.43345 1.43184 1.43086 1.43021 1.43003 1.42988 1.42944 1.42883 1.42818 1.42702 1.42642 1.42595 1.42586 1.42616 1.42783 1.41733 1.38106 1.30738 1.3877 2.09819 3.05285 3.58059 3.77601 3.87609 4.02557 4.24887 4.4608 4.60411 4.72109 4.8255 4.90465 4.97379 5.01253 5.01532 5.01239 5.0092 5.00665 5.00474 5.00333 5.00232 5.00163 5.00117 5.00082 5.00057 5.00039 5.00027 5.00019 5.00013 5.00009 5.00006 5.00004 5.00003 5.00002 5.00001 5.00001 5 5 5 4.99998 4.99995 4.99992 4.99996 5.00005 5.00012 5.00008 4.99996 4.9999 4.99985 4.99986 4.99997 5.00021 5.0003 5.00024 5.00009 5.00007 5.00005 5.00003 5.00001 4.99998 4.99998 4.99998 4.99999 4.99999 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 } .graph element create V29 -x x -y v29 v30 set { 7.10441e-10 5.70385e-05 0.000226143 0.000131916 -0.000887764 -8.01837e-05 -3.49653e-05 9.40039e-05 0.000118663 0.000108025 8.6059e-05 6.33268e-05 4.99295e-05 3.16843e-05 3.60692e-05 2.07572e-05 -8.6375e-05 3.44583e-05 8.07397e-05 0.000196296 0.000115615 -7.12768e-05 -0.000129812 -4.18679e-05 7.94364e-05 0.000182034 -5.41226e-05 -0.000451819 -0.000713937 -0.00129863 -0.00262186 -0.00213417 -0.00133767 0.000775698 0.000969902 0.000549281 0.000280946 0.000140321 8.6919e-05 7.22446e-05 6.5631e-05 6.45263e-05 6.63087e-05 7.17391e-05 7.59042e-05 7.59172e-05 7.03353e-05 6.33558e-05 5.31136e-05 4.64278e-05 4.40594e-05 4.16909e-05 4.05674e-05 3.96957e-05 3.87875e-05 3.74977e-05 3.62079e-05 3.49181e-05 3.36283e-05 3.23385e-05 3.12427e-05 3.02775e-05 2.93124e-05 2.83472e-05 2.7382e-05 2.64613e-05 2.59077e-05 2.5354e-05 2.48004e-05 2.42468e-05 2.36931e-05 2.31395e-05 2.25859e-05 2.20322e-05 2.14786e-05 2.0925e-05 2.03916e-05 1.9995e-05 1.95984e-05 1.92019e-05 1.88053e-05 1.84087e-05 1.80122e-05 1.76156e-05 1.7219e-05 1.68225e-05 1.64259e-05 1.6051e-05 1.57991e-05 1.55471e-05 1.52952e-05 1.50433e-05 1.47913e-05 1.45394e-05 1.42875e-05 1.40356e-05 1.37836e-05 1.35317e-05 1.32978e-05 1.31513e-05 1.30048e-05 1.28583e-05 1.27118e-05 1.25653e-05 1.24188e-05 1.22724e-05 1.21259e-05 1.19794e-05 1.18329e-05 1.16864e-05 1.15399e-05 1.13934e-05 1.12469e-05 1.11005e-05 1.0954e-05 1.08075e-05 1.0661e-05 1.05145e-05 1.0368e-05 1.02215e-05 1.76447e-05 7.21516e-05 -3.59786e-05 -0.000159618 0.000156236 0.000135106 -0.000336402 -0.000302283 0.000699323 0.000473866 -0.000156146 -0.000225625 -0.000123592 -3.78116e-05 8.47472e-06 2.43387e-06 -7.44762e-05 7.80111e-05 9.43608e-05 0.000170159 8.83919e-05 -0.00018802 -0.000373512 -0.000390597 0.000156875 0.0032343 0.00776304 -0.000566905 -0.00760695 -0.0159226 -0.0245989 -0.0331402 -0.0100902 0.067837 0.266702 0.910818 1.82282 2.69714 3.43247 3.98325 4.32893 4.51529 4.67087 4.79288 4.87574 4.92797 4.95902 4.97655 4.98622 4.99195 4.99526 4.99735 4.9991 4.99974 4.99982 4.99974 4.99961 4.9995 4.99943 4.9994 4.9994 4.99942 4.99944 4.99948 4.99952 4.99956 4.99961 4.99965 4.9997 4.99974 4.99977 4.99981 4.99983 4.99986 4.99988 4.9999 4.99991 4.99992 4.99993 4.99994 4.99995 4.99995 4.99996 4.99997 4.99997 4.99998 4.99998 4.99999 4.99999 4.99999 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5.00019 4.99888 4.99663 4.99457 4.99902 5.00229 5.00323 5.00302 5.0023 5.0015 5.00085 5.00041 5.00013 4.99993 4.99979 4.99948 4.99954 4.99983 5.00055 5.00109 5.00009 4.9987 4.998 4.99755 4.99676 4.99618 5.01091 5.05272 5.04156 4.80112 4.27692 3.42343 2.23953 0.967179 0.429813 0.540757 1.32991 2.32147 3.14903 3.78143 4.22325 4.47978 4.59448 4.69875 4.79798 4.87419 4.92339 4.95249 4.97174 4.98408 4.99124 4.99478 4.99729 4.99868 4.9992 4.99941 4.99947 4.99946 4.99943 4.9994 4.99939 4.9994 4.99942 4.99946 4.99951 4.99956 4.99961 4.99967 4.99973 4.99977 4.9998 4.99981 4.99983 4.99984 4.99987 4.99992 5.00001 5.00005 5.00001 4.99994 4.99995 4.99995 4.99996 4.99996 4.99996 4.99997 4.99997 4.99997 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 } .graph element create V30 -x x -y v30 v31 set { 1.8179e-09 -5.28841e-06 -1.44913e-05 -3.62932e-05 -9.75719e-05 0.000141781 3.73396e-05 -1.65603e-05 -1.5271e-05 -6.73884e-06 4.40157e-06 -4.85345e-06 -1.02964e-05 2.03126e-05 -1.89457e-05 -8.75564e-06 7.67422e-06 4.71103e-06 1.29798e-05 6.13469e-06 -1.14363e-05 -0.0394563 -0.0477298 -0.0622012 -0.0519225 0.262499 0.943611 1.67052 2.31017 2.84028 3.28467 3.61582 3.85887 4.13011 4.36511 4.54063 4.67013 4.76408 4.83263 4.8825 4.91837 4.94373 4.96117 4.97318 4.98093 4.98562 4.98906 4.99267 4.99539 4.99666 4.99731 4.99797 4.99844 4.99887 4.99927 4.99933 4.99938 4.99944 4.99949 4.99955 4.9996 4.99965 4.9997 4.99975 4.9998 4.99985 4.99986 4.99987 4.99989 4.9999 4.99991 4.99992 4.99993 4.99995 4.99996 4.99997 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5.00001 5.00001 5.00001 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99997 5.00002 5.00004 5.0001 5.0001 4.99987 5.00009 5.00021 5.00002 5.00004 4.99988 5.00013 4.99993 5.00026 4.99973 5 5.00006 5.00009 5.00004 5.00004 5.04854 4.82711 4.04208 2.64155 0.838902 0.19014 0.0982549 0.0723197 0.0576863 0.0427644 0.0301979 0.020146 0.0135728 0.00980358 0.00774482 0.00586604 0.0036687 0.00211511 0.00121906 0.000647581 0.000828436 0.00190938 0.00224254 0.00199956 0.00165488 0.00135612 0.00113715 0.000984181 0.000877175 0.000789973 0.000741139 0.000689338 0.000625676 0.000586082 0.000550152 0.000529573 0.000505606 0.000482117 0.000460574 0.000441649 0.000424674 0.000408398 0.000391914 0.000376272 0.000361487 0.000348181 0.000336045 0.000324466 0.000313545 0.000303046 0.000293056 0.00028356 0.000274586 0.000266155 0.000258279 0.000250938 0.000243789 0.000236912 0.000230244 0.000224186 0.000219291 0.000215346 0.000212468 0.000207291 0.000200862 0.00019368 0.000186767 0.000183515 0.000180263 0.00017701 0.000173758 0.000170506 0.000167253 0.000164001 0.000161164 0.000158357 0.00015555 0.000152743 0.000149936 0.000147129 0.000144322 0.000142066 0.000140096 0.000138127 0.000136157 0.000134187 0.000132218 0.000130248 0.000128278 0.000126308 0.000124339 0.000122369 0.000120399 0.000118429 0.00011646 0.000114527 0.000112892 0.000111258 0.000109623 0.000107988 0.000103598 6.86052e-05 3.337e-05 7.00783e-05 0.000218764 0.000221318 0.000118593 -0.000113962 5.78552e-05 9.42068e-05 0.000237037 0.000171302 0.0001033 6.16066e-05 5.52908e-05 6.30233e-05 7.01897e-05 8.48573e-05 0.000106859 8.37213e-05 -0.0391541 -0.047722 -0.0618454 -0.0169804 0.345725 1.03426 1.74825 2.37152 2.88737 3.32173 3.66761 3.9707 4.17762 3.98832 3.30483 2.09737 0.710892 0.148159 0.0707463 0.0555808 0.045618 0.0319116 0.0199589 0.0133357 0.00898528 0.00586075 0.00375478 0.00245443 0.00156038 0.000962344 0.000590953 0.000375107 0.000250243 0.00015882 0.000100203 6.18122e-05 3.7372e-05 2.23009e-05 1.32569e-05 8.29437e-06 5.72457e-06 3.96832e-06 2.98935e-06 2.59699e-06 2.75024e-06 3.38689e-06 4.0453e-06 3.50095e-06 1.64988e-06 -3.84371e-07 -2.03828e-06 -3.46401e-06 -1.24301e-06 4.63458e-06 1.14104e-05 1.02619e-05 2.15487e-06 -2.98487e-06 -3.67221e-06 -2.94279e-06 -2.58649e-06 -2.23019e-06 -1.87389e-06 -1.5176e-06 -1.1613e-06 -7.92127e-07 -4.18889e-07 -4.56502e-08 3.27588e-07 7.00827e-07 8.79539e-07 8.17025e-07 7.5451e-07 6.91996e-07 6.29481e-07 5.66966e-07 5.04452e-07 4.41937e-07 3.79422e-07 3.16908e-07 2.54393e-07 1.90078e-07 1.25366e-07 6.0654e-08 -4.05776e-09 -6.87696e-08 -1.33481e-07 -1.98193e-07 -2.62905e-07 -3.27617e-07 -3.92329e-07 -4.40392e-07 -4.18802e-07 -3.97213e-07 -3.75624e-07 -3.54035e-07 -3.32446e-07 -3.10856e-07 -2.89267e-07 -2.67678e-07 } .graph element create V31 -x x -y v31 v32 set { 1.10294 1.10297 1.10291 1.10277 1.10259 1.10294 1.10313 1.10306 1.10299 1.10296 1.10295 1.10295 1.10294 1.10294 1.10294 1.10294 1.10294 1.10294 1.10294 1.10296 1.10296 1.00547 0.998599 1.5201 2.49297 3.31258 3.73162 3.84757 3.92505 4.02965 4.16599 4.30294 4.41541 4.52886 4.64414 4.73865 4.81065 4.86391 4.90315 4.93188 4.95258 4.96726 4.97738 4.98436 4.98888 4.99162 4.99363 4.99573 4.99731 4.99804 4.99843 4.99881 4.99909 4.99934 4.99957 4.9996 4.99964 4.99967 4.9997 4.99973 4.99977 4.9998 4.99983 4.99986 4.99988 4.99991 4.99992 4.99992 4.99993 4.99994 4.99994 4.99995 4.99996 4.99996 4.99997 4.99997 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5.00028 4.99988 4.99968 5.00019 4.99987 5.00021 4.99973 4.99977 4.99996 4.99997 5.0002 4.99957 5.00026 4.99947 5.00074 5.00003 4.99987 4.99979 5.00008 4.99997 5.08794 5.05993 4.76875 3.99197 3.10174 2.5197 2.21771 2.04 1.92235 1.83874 1.77592 1.72665 1.686 1.65276 1.6286 1.61299 1.60039 1.58934 1.57954 1.57083 1.56306 1.55604 1.54963 1.54375 1.53832 1.53331 1.52865 1.52432 1.52026 1.51645 1.51287 1.50949 1.50629 1.50327 1.50039 1.49766 1.49505 1.49257 1.49019 1.48792 1.48574 1.48365 1.48164 1.47971 1.47784 1.47604 1.47431 1.47264 1.47102 1.46945 1.46794 1.46647 1.46505 1.46367 1.46233 1.46103 1.45976 1.45853 1.45733 1.45616 1.45502 1.45392 1.45284 1.45179 1.45076 1.44975 1.4488 1.44795 1.44711 1.44626 1.44541 1.44457 1.44372 1.44287 1.44212 1.44138 1.44063 1.43989 1.43914 1.4384 1.43766 1.43701 1.43641 1.43581 1.43522 1.43462 1.43402 1.43342 1.43282 1.43223 1.43163 1.43103 1.43043 1.42984 1.42924 1.42865 1.42808 1.42752 1.42695 1.42639 1.42584 1.42529 1.42472 1.42412 1.42365 1.42326 1.42304 1.42162 1.42082 1.42032 1.42029 1.42026 1.41995 1.41947 1.41894 1.41841 1.4179 1.41742 1.41699 1.41656 1.32097 1.30963 1.78765 2.64656 3.35764 3.747 3.86589 3.94217 4.04185 4.18453 4.3561 4.53439 4.68621 4.74905 4.77848 4.84629 4.91261 4.97541 5.01284 5.01548 5.01248 5.00924 5.00666 5.00475 5.00334 5.00234 5.00164 5.00118 5.00083 5.00058 5.0004 5.00028 5.00019 5.00013 5.00009 5.00007 5.00004 5.00003 5.00002 5.00001 5.00001 5.00001 5 5 4.99999 4.99995 4.99992 4.99996 5.00006 5.00012 5.00009 4.99997 4.9999 4.99985 4.99986 4.99997 5.00021 5.00031 5.00024 5.0001 5.00007 5.00005 5.00003 5.00001 4.99998 4.99998 4.99999 4.99999 4.99999 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 } .graph element create V32 -x x -y v32 v33 set { 5 5.00012 5.00023 5.0003 4.99972 4.99988 4.99984 4.99991 4.99996 4.99999 5.00008 5.00009 4.99986 5.00003 5.00007 4.99995 4.9999 4.99997 5.00013 5.00014 5.00013 4.99701 4.99763 4.99742 4.99998 5.02836 5.07262 4.96856 4.57267 3.85637 2.79544 1.45942 0.408016 0.084885 0.0271375 0.0119294 0.00707546 0.0051087 0.00373035 0.00264737 0.00186477 0.00130379 0.000915857 0.000653121 0.000483893 0.000380852 0.000302362 0.000219498 0.000154435 0.000121928 0.000104026 8.61242e-05 7.48526e-05 6.49216e-05 5.56238e-05 5.29689e-05 5.03139e-05 4.7659e-05 4.5004e-05 4.23491e-05 4.00356e-05 3.79522e-05 3.58687e-05 3.37852e-05 3.17018e-05 2.97592e-05 2.89804e-05 2.82016e-05 2.74228e-05 2.66441e-05 2.58653e-05 2.50865e-05 2.43077e-05 2.35289e-05 2.27501e-05 2.19714e-05 2.12346e-05 2.07821e-05 2.03295e-05 1.98769e-05 1.94244e-05 1.89718e-05 1.85192e-05 1.80667e-05 1.76141e-05 1.71615e-05 1.6709e-05 1.62828e-05 1.60061e-05 1.57294e-05 1.54527e-05 1.5176e-05 1.48993e-05 1.46226e-05 1.43459e-05 1.40692e-05 1.37925e-05 1.35158e-05 1.3262e-05 1.31191e-05 1.29761e-05 1.28332e-05 1.26903e-05 1.25474e-05 1.24045e-05 1.22615e-05 1.21186e-05 1.19757e-05 1.18328e-05 1.16898e-05 1.15469e-05 1.1404e-05 1.12611e-05 1.11182e-05 1.09752e-05 1.08323e-05 1.06894e-05 1.05465e-05 1.04036e-05 1.02606e-05 1.00185e-05 3.8343e-05 -3.06781e-05 -0.000111758 0.000111673 0.000130815 -0.000210491 -0.000231304 0.000310226 0.000265303 3.0878e-05 -4.48405e-05 -1.2852e-05 -7.84469e-06 3.29986e-05 -1.23286e-05 -6.07871e-05 5.35082e-05 7.69194e-05 0.000126221 6.57178e-05 0.00223349 -0.0148854 -0.0476636 -0.0491447 0.220125 1.11174 2.03988 2.90209 3.61069 4.13554 4.50679 4.71501 4.83916 4.91027 4.95284 4.98086 4.99151 4.98651 4.97113 4.95075 4.93102 4.93683 4.95457 4.97071 4.98212 4.98948 4.99386 4.99636 4.99785 4.9987 4.99927 4.99989 5.00014 5.00007 4.99988 4.99982 4.99976 4.99973 4.99972 4.99972 4.99973 4.99974 4.99975 4.99977 4.99979 4.99981 4.99984 4.99986 4.99988 4.99989 4.99991 4.99992 4.99993 4.99994 4.99995 4.99996 4.99996 4.99997 4.99997 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5.00001 5.00001 5.00001 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5.00012 4.99946 4.99839 4.99733 4.99948 5.00114 5.00158 5.00147 5.00113 5.00073 5.00043 5.0002 5.00006 4.99995 4.99986 4.99973 4.99976 4.9999 5.00029 5.00055 4.99704 4.99734 4.9972 5.00278 5.03354 5.07184 4.94057 4.51936 3.75638 2.60982 1.23803 0.315016 0.0796102 0.0252894 0.0165723 0.0827785 0.491298 1.40686 2.33436 3.1251 3.7691 4.22201 4.49976 4.68115 4.80513 4.88509 4.93208 4.95861 4.97579 4.98655 4.99268 4.99571 4.99771 4.99881 4.99929 4.99954 4.99965 4.9997 4.99971 4.99971 4.99971 4.99971 4.99972 4.99974 4.99976 4.99978 4.99981 4.99984 4.99987 4.99989 4.99991 4.99991 4.99992 4.99992 4.99993 4.99997 5.00003 5.00006 5.00004 5.00001 5 4.99999 4.99998 4.99998 4.99997 4.99997 4.99997 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 } .graph element create V33 -x x -y v33 v34 set { 5 5.00207 5.00813 5.01486 5.00156 5.0018 4.99861 4.99844 4.99888 4.9993 4.99956 4.99971 4.99979 4.99983 4.99987 4.99989 4.99671 4.9974 4.99864 5.00131 5.00377 5.0021 5.00039 4.99993 5.00004 5.0009 5.00109 4.99636 4.98617 4.96778 4.92047 4.89528 4.91112 4.9559 4.98286 4.99369 4.99812 4.99951 4.99994 5.00014 5.00008 4.99994 4.99984 4.99989 4.99998 5.00004 5.00004 5.00006 5.00005 5.00001 4.99997 4.99992 4.99993 4.99994 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 5.00131 5.00072 4.9977 4.99811 5.00325 4.99647 4.98948 4.99459 5.00262 5.00276 5.00156 5.00072 5.0003 5.00013 4.99995 4.99668 4.99775 4.99917 5.00173 5.00386 5.00188 4.99888 4.99757 4.99951 5.01712 5.0557 5.07088 5.07704 5.07758 5.06958 5.04223 5.03331 5.0279 5.03408 5.07611 5.01911 4.68594 3.99152 2.92195 1.69878 0.809 0.344091 0.154663 0.0788717 0.0467212 0.0336168 0.0280514 0.0254947 0.024173 0.0223567 0.0220555 0.0271514 0.0295872 0.0296052 0.0283971 0.0264726 0.0241813 0.0218244 0.0195349 0.017368 0.0152495 0.013295 0.0115444 0.00996982 0.00857091 0.00733891 0.00627261 0.0053494 0.00456316 0.00388373 0.00331073 0.00282181 0.00240991 0.00206389 0.00177187 0.00152283 0.00131167 0.00112558 0.000954373 0.000805726 0.00069326 0.000600991 0.000525743 0.00047355 0.00044359 0.000434815 0.000436053 0.000402511 0.000368969 0.000335427 0.000301886 0.000268344 0.000234802 0.00020126 0.000184967 0.000169932 0.000154896 0.000139861 0.000124825 0.00010979 9.47546e-05 8.67896e-05 8.24901e-05 7.81906e-05 7.38911e-05 6.95915e-05 6.5292e-05 6.09925e-05 5.66929e-05 5.23934e-05 4.80939e-05 4.37943e-05 3.94948e-05 3.51953e-05 3.08957e-05 2.67968e-05 2.42936e-05 2.17904e-05 1.92872e-05 1.6784e-05 0.00125927 -0.00794344 -0.0305499 -0.0621697 -0.0463796 -0.0224608 -0.00538381 0.00546086 0.0108675 0.012883 0.0131787 0.0127271 0.0119702 0.0110398 0.0100635 0.00649617 0.00489388 0.00545863 0.0098351 0.0167428 0.0126563 0.00697542 0.00427027 0.00330002 0.00390774 0.00408999 -0.00259143 -0.0160578 -0.0451849 -0.0409651 0.1301 0.597429 1.3848 2.63426 3.81272 4.51373 4.8412 4.98731 4.88165 4.37165 3.40034 2.17681 1.12217 0.505129 0.219703 0.104992 0.0622333 0.0448317 0.0355782 0.0311867 0.0293529 0.0274615 0.0288739 0.0307845 0.0304909 0.029245 0.0273602 0.0251006 0.022697 0.0202765 0.0179357 0.0157106 0.0136562 0.0117951 0.0101273 0.00865784 0.00739394 0.00634364 0.00551356 0.00480538 0.00415747 0.00356084 0.00297585 0.00236711 0.00181853 0.00160713 0.00169822 0.00166542 0.00145504 0.00120252 0.00109259 0.000982658 0.00087273 0.000762802 0.000652874 0.000584068 0.000528263 0.000472458 0.000416653 0.000360848 0.000321155 0.000301442 0.000281729 0.000262016 0.000242303 0.00022259 0.000202877 0.000183164 0.000163451 0.000143738 0.000124025 0.000114582 0.000107399 0.000100216 9.30332e-05 8.58502e-05 7.86672e-05 7.14841e-05 6.43011e-05 5.7118e-05 4.9935e-05 4.35378e-05 4.04281e-05 3.73184e-05 3.42088e-05 3.10991e-05 2.79894e-05 2.48798e-05 2.17701e-05 1.86604e-05 } .graph element create V34 -x x -y v34 v35 set { 7.24585e-12 2.21843e-05 3.20014e-05 1.25076e-05 -2.44947e-05 1.8425e-05 5.50546e-06 3.53025e-05 -1.07551e-05 -3.94383e-06 -2.27848e-06 -9.04789e-05 7.44215e-05 -2.7662e-05 0.000200038 -2.11998e-05 -2.09011e-05 2.37098e-05 2.18751e-05 -2.28422e-05 -6.23659e-05 3.58241e-05 1.76386e-05 -4.28311e-05 0.000355626 0.00156903 0.00100999 -0.0085304 -0.02067 -0.0389485 -0.0651568 -0.128475 -0.314362 -0.406837 -0.421558 -0.421277 -0.418176 -0.414481 -0.410845 -0.407348 -0.403971 -0.400716 -0.397582 -0.394563 -0.391658 -0.388866 -0.386178 -0.383585 -0.381094 -0.378789 -0.376569 -0.37435 -0.372256 -0.370188 -0.36815 -0.366422 -0.364694 -0.362967 -0.361239 -0.359511 -0.357888 -0.356334 -0.354781 -0.353227 -0.351674 -0.350152 -0.348888 -0.347625 -0.346361 -0.345098 -0.343834 -0.342571 -0.341307 -0.340044 -0.33878 -0.337517 -0.336279 -0.335215 -0.334152 -0.333088 -0.332024 -0.330961 -0.329897 -0.328833 -0.32777 -0.326706 -0.325642 -0.324601 -0.323683 -0.322766 -0.321849 -0.320932 -0.320014 -0.319097 -0.31818 -0.317263 -0.316345 -0.315428 -0.314545 -0.313825 -0.313106 -0.312387 -0.311667 -0.310948 -0.310228 -0.309509 -0.308789 -0.30807 -0.307351 -0.306631 -0.305912 -0.305192 -0.304473 -0.303754 -0.303034 -0.302315 -0.301595 -0.300876 -0.300157 -0.299437 -0.298716 -0.29798 -0.297329 -0.296691 -0.295837 -0.29516 -0.294725 -0.294044 -0.292917 -0.292351 -0.291965 -0.291365 -0.290687 -0.290027 -0.289376 -0.288772 -0.288193 -0.287505 -0.286892 -0.28626 -0.285714 -0.284545 -0.289246 -0.298717 -0.298492 -0.214163 0.181451 0.0749974 0.0454707 0.0292987 0.0196837 0.0124119 0.00884715 0.00527181 0.00585821 0.0296361 0.169856 0.361207 0.538856 0.67469 0.685933 0.392802 0.17772 0.0813085 0.0424601 0.0246654 0.0175258 0.0144256 0.0129859 0.012205 0.0112846 0.010933 0.0134813 0.0147254 0.0147981 0.0142156 0.0132732 0.0121355 0.0109587 0.00981238 0.00872731 0.00767007 0.00669346 0.00581341 0.00502167 0.00431819 0.00369842 0.00316168 0.00269663 0.00230035 0.00195801 0.00166928 0.00142286 0.00121522 0.00104072 0.000893384 0.000767675 0.000661268 0.000567659 0.000481766 0.000407101 0.000350044 0.000302721 0.000263424 0.000236813 0.00022199 0.000218182 0.000219548 0.0002027 0.000185853 0.000169006 0.000152158 0.000135311 0.000118463 0.000101616 9.33782e-05 8.57685e-05 7.81588e-05 7.0549e-05 6.29393e-05 5.53296e-05 4.77199e-05 4.36954e-05 4.15296e-05 3.93637e-05 3.71978e-05 3.50319e-05 3.28661e-05 3.07002e-05 2.85343e-05 2.63685e-05 2.42026e-05 2.20367e-05 1.98709e-05 1.7705e-05 1.55391e-05 1.34772e-05 1.22416e-05 1.10061e-05 9.77055e-06 8.535e-06 0.000631271 -0.00362586 -0.0146235 -0.0308486 -0.0237466 -0.0117522 -0.00304171 0.00251033 0.00531986 0.0063897 0.00657351 0.00636494 0.00599705 0.00553442 0.00505994 0.00330925 0.00246671 0.0027006 0.00473161 0.00830333 0.00649147 0.00356815 0.00217448 0.00187579 0.00270447 0.00219543 -0.00546118 -0.0179576 -0.0445306 -0.0649309 0.0197935 0.473629 0.87268 0.269542 0.0086094 0.0844602 0.606456 1.04929 0.906014 0.916205 0.919425 0.872867 0.556244 0.262457 0.11838 0.0571226 0.0333451 0.0237133 0.0185096 0.0159617 0.0148663 0.0138683 0.0144081 0.0153797 0.0152551 0.0146487 0.0137192 0.0125973 0.0113996 0.0101903 0.00901851 0.00790495 0.00687502 0.00593994 0.00510092 0.00436111 0.00372439 0.0031945 0.00277537 0.00241888 0.002095 0.00179943 0.00150419 0.00119264 0.00090934 0.000802394 0.000852816 0.000838368 0.000730842 0.000601028 0.000546616 0.000492205 0.000437793 0.000383381 0.000328969 0.00029454 0.000266428 0.000238317 0.000210205 0.000182093 0.000162091 0.000152145 0.000142198 0.000132252 0.000122306 0.000112359 0.000102413 9.24665e-05 8.25201e-05 7.25738e-05 6.26274e-05 5.78553e-05 5.42216e-05 5.05878e-05 4.69541e-05 4.33204e-05 3.96867e-05 3.60529e-05 3.24192e-05 2.87855e-05 2.51518e-05 2.19153e-05 2.03406e-05 1.8766e-05 1.71913e-05 1.56167e-05 1.4042e-05 1.24674e-05 1.08927e-05 9.31806e-06 } .graph element create V35 -x x -y v35 v36 set { 5 5.01426 5.02852 5.01923 4.77685 4.56471 4.52338 4.56813 4.63122 4.693 4.74776 4.79385 4.83258 4.86358 4.88918 4.91021 4.90553 4.89733 4.89554 4.91953 5.00757 5.07101 5.06318 5.05241 5.05535 5.08042 5.07251 4.90973 4.56136 3.98637 3.237 2.67216 2.33678 2.13529 2.00544 1.91429 1.84638 1.79461 1.75338 1.71958 1.69175 1.6686 1.64918 1.63258 1.61836 1.60607 1.59506 1.58483 1.57575 1.56847 1.56193 1.55538 1.54968 1.54416 1.5388 1.53523 1.53165 1.52807 1.52449 1.52091 1.51771 1.51477 1.51182 1.50888 1.50593 1.50309 1.50113 1.49917 1.4972 1.49524 1.49328 1.49132 1.48935 1.48739 1.48543 1.48346 1.48157 1.48012 1.47868 1.47724 1.47579 1.47435 1.47291 1.47146 1.47002 1.46857 1.46713 1.46574 1.46462 1.4635 1.46238 1.46126 1.46014 1.45902 1.4579 1.45678 1.45567 1.45455 1.45349 1.45275 1.45201 1.45127 1.45053 1.44979 1.44905 1.44831 1.44757 1.44683 1.44609 1.44535 1.44461 1.44387 1.44313 1.44239 1.44165 1.44091 1.44017 1.43943 1.43869 1.43795 1.43721 1.43874 1.43976 1.43619 1.43182 1.43726 1.43084 1.42587 1.42383 1.42642 1.42728 1.42736 1.4271 1.42669 1.42621 1.42569 1.41703 1.41244 1.41019 1.41199 1.41833 1.42502 1.41504 1.37535 1.28381 1.44779 2.33713 3.25835 3.67554 3.84975 4.01125 4.2253 4.45433 4.62215 4.74478 4.82998 4.8868 4.92396 4.94768 4.96498 4.98537 5.0128 5.04467 5.06722 5.06535 5.01475 4.91956 4.80647 4.7242 4.7059 4.73552 4.76379 4.81684 4.87376 4.92276 4.96112 4.9884 5.0045 5.00999 5.00933 5.00619 5.00384 5.00342 5.00373 5.00362 5.00309 5.00272 5.00239 5.00204 5.00172 5.00146 5.00124 5.00105 5.00089 5.00076 5.00065 5.00057 5.00048 5.00041 5.00034 5.00028 5.00023 5.00019 5.00015 5.00015 5.00016 5.0002 5.00023 5.00021 5.00019 5.00017 5.00015 5.00012 5.0001 5.00008 5.00007 5.00006 5.00005 5.00004 5.00003 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5.00062 4.99506 4.9835 4.96726 4.9728 4.97877 4.98675 4.9966 5.00406 5.00679 5.00629 5.00561 5.00487 5.00429 5.00384 5.002 5.00164 5.00229 5.00484 5.00769 5.00019 5.00242 5.01319 5.0335 5.07265 5.10129 5.11485 5.12551 5.13953 5.16048 5.18862 5.22811 5.25656 5.25627 5.19975 4.9139 4.24745 3.43732 2.8202 2.43224 2.17409 2.01333 1.93951 1.94622 1.98861 2.02217 2.05383 2.08376 2.11184 2.13793 2.16191 2.18267 2.20502 2.22837 2.24958 2.26901 2.28648 2.302 2.31582 2.32802 2.33869 2.34795 2.35596 2.36282 2.3687 2.37371 2.37797 2.38161 2.38476 2.38743 2.3897 2.39168 2.39329 2.39463 2.39575 2.39671 2.39756 2.39835 2.39907 2.39968 2.39999 2.4003 2.40061 2.40091 2.40122 2.40142 2.40159 2.40176 2.40193 2.4021 2.40222 2.40228 2.40234 2.4024 2.40247 2.40253 2.40259 2.40265 2.40271 2.40277 2.40284 2.40287 2.40289 2.40291 2.40294 2.40296 2.40298 2.40301 2.40303 2.40305 2.40308 2.4031 2.40311 2.40312 2.40313 2.40314 2.40315 2.40316 2.40317 2.40318 } .graph element create V36 -x x -y v36 v37 set { 5 5.01732 5.03181 5.05944 5.12686 5.20725 5.28103 5.31254 5.32901 5.33709 5.3408 5.34257 5.34311 5.34347 5.34386 5.34411 5.3406 5.33484 5.32942 5.32904 5.33644 5.34869 5.35001 5.34882 5.34758 5.34672 5.34599 5.34496 5.34364 5.34165 5.33712 5.33502 5.3366 5.34067 5.34306 5.34398 5.34434 5.34442 5.34443 5.34443 5.34441 5.34439 5.34437 5.34437 5.34438 5.34438 5.34438 5.34438 5.34438 5.34437 5.34437 5.34436 5.34436 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.35377 5.35451 5.34265 5.34488 5.35861 5.28622 4.90033 4.75027 4.89731 4.97098 4.99293 4.99832 4.99909 4.99956 4.99858 4.99829 4.9998 5.00035 5.0038 5.00989 5.00251 4.99438 4.9953 4.99761 4.99985 5.00152 5.0011 5.00046 4.99996 4.99925 4.99862 4.99919 4.99961 5.00048 5.00234 4.99654 4.98235 4.95936 4.83738 4.53021 4.21004 4.00593 3.91207 3.88059 3.87822 3.89117 3.91278 3.94044 3.97376 4.01152 4.05052 4.10679 4.17908 4.25673 4.33414 4.40875 4.47879 4.54342 4.60258 4.65595 4.70291 4.74414 4.78018 4.81185 4.83915 4.86291 4.88301 4.90048 4.91528 4.92802 4.9387 4.94777 4.95539 4.9618 4.96725 4.97195 4.97588 4.97932 4.98247 4.98512 4.98697 4.98831 4.98919 4.99015 4.99101 4.99169 4.99222 4.99282 4.99341 4.994 4.9946 4.99519 4.99578 4.99638 4.99667 4.99693 4.9972 4.99747 4.99773 4.998 4.99827 4.99841 4.99849 4.99856 4.99864 4.99872 4.9988 4.99888 4.99896 4.99904 4.99911 4.99919 4.99927 4.99935 4.99943 4.9995 4.99955 4.9996 4.99965 4.9997 5.00736 4.98252 4.87516 4.66727 4.49142 4.43103 4.4301 4.4571 4.49729 4.5407 4.5835 4.62363 4.66114 4.69577 4.72738 4.74632 4.75971 4.77576 4.80671 4.87073 4.91665 4.93252 4.94418 4.95331 4.96094 4.96727 4.97148 4.97471 4.97612 4.98276 5.00247 5.04086 5.08628 5.10673 5.08887 5.0564 5.02767 5.01336 4.99685 4.97422 4.90866 4.67035 4.33117 4.07888 3.94432 3.89105 3.88174 3.89292 3.91442 3.94564 3.98708 4.0355 4.09134 4.16315 4.24088 4.31918 4.39527 4.46693 4.53337 4.59405 4.6486 4.69693 4.73938 4.77617 4.80809 4.83551 4.85895 4.87894 4.89596 4.91081 4.92417 4.93651 4.94552 4.95198 4.9565 4.96096 4.96523 4.96972 4.97428 4.97868 4.98064 4.9826 4.98455 4.98651 4.98847 4.98967 4.99064 4.9916 4.99257 4.99353 4.99422 4.99457 4.99493 4.99528 4.99563 4.99598 4.99633 4.99668 4.99703 4.99738 4.99773 4.9979 4.99804 4.99817 4.9983 4.99843 4.99856 4.99869 4.99883 4.99896 4.99909 4.99921 4.99926 4.99931 4.99937 4.99942 4.99948 4.99953 4.99959 4.99964 } .graph element create V37 -x x -y v37 v38 set { 4.49849 4.53282 4.58329 4.66625 4.83345 4.97823 5.0207 5.01816 5.01116 5.00595 5.00296 5.00148 5.00073 5.00062 5.00033 5.0003 4.99864 4.99661 4.99652 4.99928 5.00361 5.12573 5.17251 5.22612 5.33479 5.44503 5.44432 5.44379 5.44334 5.443 5.44276 5.44258 5.44246 5.44238 5.44232 5.44228 5.44225 5.44223 5.44221 5.4422 5.44219 5.44219 5.44218 5.44218 5.44218 5.44218 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44214 5.44214 5.44214 5.44214 5.44214 5.44214 5.44214 5.44214 5.44214 5.44214 5.44214 5.44212 5.45159 5.45236 5.44064 5.44307 5.45616 5.38122 4.77163 3.53297 2.74466 2.34448 2.11802 1.9783 1.88656 1.82001 1.77389 1.72955 1.69632 1.66971 1.6526 1.65236 1.56034 1.53764 1.97139 2.75096 3.39212 3.74042 3.82345 3.85696 3.88547 3.91862 3.9585 4.00467 4.05903 4.1254 4.19533 4.26791 4.34517 4.42112 4.49238 4.55807 4.6179 4.6713 4.71815 4.75889 4.79418 4.82456 4.85062 4.87291 4.89196 4.90823 4.92209 4.93388 4.9439 4.95242 4.95968 4.96585 4.97108 4.9755 4.97923 4.98237 4.98503 4.98732 4.98927 4.99094 4.99233 4.99353 4.99452 4.99538 4.99608 4.99668 4.99718 4.9976 4.99794 4.99822 4.99847 4.99867 4.99884 4.99899 4.99913 4.99924 4.99932 4.99938 4.99943 4.99947 4.99951 4.99953 4.99955 4.99958 4.99961 4.99964 4.99967 4.99969 4.99972 4.99975 4.99977 4.99978 4.99979 4.99981 4.99982 4.99983 4.99985 4.99986 4.99986 4.99987 4.99987 4.99988 4.99988 4.99988 4.99989 4.99989 4.9999 4.9999 4.99991 4.99991 4.99992 4.99992 4.99993 4.99993 4.99993 4.99994 5.00381 5.00064 4.99246 4.99823 5.00349 5.00076 5.00033 5.00015 5.00009 5.00007 5.00005 5.00004 5.00003 5.00002 4.99988 4.99732 4.99728 4.9978 5.00187 5.00927 5.08712 5.07654 4.92855 4.4863 3.76162 3.00049 2.49834 2.20883 2.03492 1.92384 1.84676 1.79021 1.74716 1.7132 1.68576 1.66309 1.64406 1.62785 1.61383 1.60162 1.59081 1.58117 1.57253 1.56473 1.55765 1.55117 1.54527 1.53988 1.53485 1.53012 1.5257 1.5216 1.51773 1.51411 1.51071 1.50746 1.50438 1.50146 1.49868 1.49603 1.4935 1.49109 1.48878 1.48657 1.48445 1.48242 1.48046 1.47858 1.47677 1.47502 1.47333 1.4717 1.47012 1.46859 1.46711 1.46568 1.46428 1.46292 1.4616 1.46034 1.45923 1.45812 1.45701 1.4559 1.45479 1.45378 1.45279 1.45181 1.45082 1.44983 1.44893 1.44813 1.44732 1.44652 1.44571 1.44491 1.4441 1.4433 1.44249 1.44169 1.44089 1.44019 1.43951 1.43883 1.43815 1.43747 1.4368 1.43612 1.43544 1.43476 1.43408 1.43342 1.43283 1.43223 1.43163 1.43104 1.43044 1.42984 1.42924 1.42865 } .graph element create V38 -x x -y v38 v39 set { 5 5.01048 5.01221 4.98887 4.76261 4.54943 4.51564 4.56249 4.62621 4.68843 4.74374 4.79044 4.82972 4.86127 4.88724 4.90862 4.90791 4.89858 4.89589 4.91767 5.00405 5.16956 5.12391 4.7557 3.87953 3.01124 2.48482 2.20424 2.03812 1.92679 1.84956 1.79256 1.74907 1.71487 1.68724 1.6644 1.64513 1.6287 1.61446 1.60197 1.59095 1.58117 1.57245 1.5646 1.55752 1.55109 1.54516 1.53958 1.53444 1.53008 1.52606 1.52205 1.51843 1.5149 1.51146 1.50893 1.50639 1.50387 1.50133 1.4988 1.49651 1.49436 1.49222 1.49007 1.48793 1.48585 1.48433 1.4828 1.48128 1.47975 1.47823 1.4767 1.47518 1.47365 1.47213 1.4706 1.46912 1.46795 1.46678 1.46561 1.46444 1.46327 1.4621 1.46093 1.45976 1.45859 1.45741 1.45628 1.45534 1.45441 1.45347 1.45254 1.4516 1.45067 1.44973 1.4488 1.44786 1.44693 1.44604 1.44539 1.44475 1.4441 1.44345 1.44281 1.44216 1.44151 1.44086 1.44022 1.43957 1.43892 1.43828 1.43763 1.43698 1.43633 1.43569 1.43504 1.43439 1.43375 1.4331 1.43245 1.4318 1.43157 1.43089 1.43001 1.43042 1.42899 1.42439 1.42216 1.43447 1.44048 1.43705 1.43314 1.43039 1.42861 1.42739 1.42651 1.42548 1.42488 1.4243 1.42392 1.4235 1.32443 1.31149 1.78169 2.64844 3.43211 3.95252 4.20231 4.3746 4.49948 4.58929 4.65742 4.71183 4.77057 4.83196 4.88354 4.92894 4.96625 4.99235 5.00651 5.00941 5.00813 5.00689 5.00588 5.00504 5.00431 5.00368 5.00314 5.00268 5.00228 5.00194 5.00165 5.0014 5.00118 5.001 5.00085 5.00072 5.00061 5.00052 5.00044 5.00037 5.00031 5.00027 5.00022 5.00019 5.00016 5.00013 5.00011 5.00009 5.00008 5.00007 5.00006 5.00005 5.00004 5.00003 5.00003 5.00003 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5.00001 5.00002 5.00003 5.00004 5.00022 4.99974 4.99942 4.99997 5.00063 5.00002 5.00003 4.99994 4.99998 4.99999 5 5 5 5 5 4.99981 4.99998 5.00004 5.00036 5.00049 5.12012 5.16315 5.19712 5.21835 4.87874 4.10151 3.31555 2.74207 2.38075 2.15872 2.01614 1.91886 1.84852 1.79401 1.75052 1.71508 1.68672 1.66467 1.64602 1.62985 1.61576 1.60343 1.59256 1.58287 1.57418 1.56632 1.55922 1.55282 1.54687 1.54132 1.53618 1.53143 1.52698 1.52282 1.51895 1.51527 1.5118 1.50851 1.5054 1.50244 1.49963 1.49695 1.4944 1.49196 1.48963 1.4874 1.48527 1.48322 1.48124 1.47934 1.47751 1.47574 1.47403 1.47239 1.4708 1.46926 1.46777 1.46632 1.46491 1.46355 1.46237 1.4612 1.46002 1.45884 1.45766 1.45659 1.45555 1.45451 1.45346 1.45242 1.45147 1.45062 1.44978 1.44894 1.44809 1.44725 1.4464 1.44556 1.44472 1.44387 1.44303 1.4423 1.44159 1.44088 1.44017 1.43947 1.43876 1.43805 1.43734 1.43664 1.43593 1.43524 1.43462 1.434 1.43338 1.43276 1.43213 1.43151 1.43089 1.43027 } .graph element create V39 -x x -y v39 toplevel .top .graph legend configure -position .top.legend pack .top.legend -fill both -expand yes button .quit -text "quit" -bg "red" -command "exit" table . \ .graph 0,0 -fill both \ Blt_ZoomStack $graph Blt_Crosshairs $graph Blt_ClosestPoint $graph Blt_PrintKey $graph $graph legend bind all { HighlightTrace %W } $graph legend bind all { %W legend deactivate * eval %W element deactivate [%W element activate] } proc HighlightTrace { graph } { set entry [$graph legend get current] set active [$graph legend activate] if { [lsearch $active $entry] < 0 } { $graph legend activate $entry $graph element activate $entry } else { $graph legend deactivate $entry $graph element deactivate $entry } } set lastRow 0 set logicPlots {} set leftMargin 0 set rightMargin 0 proc LogicPlot { from graph signal args } { if { ![winfo exists $graph] } { global rightMargin leftMargin graph $graph -title "" -topmargin 1 -bottommargin 1 -height 0.75i \ -plotpadx 4 -plotpady 8 -bd 0 \ -leftmargin $leftMargin -rightmargin $rightMargin $graph grid off set xMin [$from axis cget x -min] set xMax [$from axis cget x -max] set yLim [$from axis limits y] set yMin [lindex $yLim 0] set yMax [lindex $yLim 1] $graph axis configure x -title "" -hide yes -min $xMin -max $xMax $graph axis configure y -title $signal -min $yMin -max $yMax $graph legend configure -anchor nw global lastRow incr lastRow table . $graph $lastRow,0 -fill both global logicPlots lappend logicPlots $graph } set list [linsert $args 0 $signal ] foreach i [$graph element names] { if { [lsearch $list $i] < 0 } { $graph element delete $i } } foreach i $list { if { ![$graph element exists $i] } { $graph element create $i } set pen [$from element cget $i -pen] set xData [$from element cget $i -x] set yData [$from element cget $i -y] $graph element configure $i -x $xData -y $yData -pen $pen } } set changePending "no" proc EventuallyChangePlots { p1 p2 how } { global changePending if { $changePending == "no" } { after idle ChangePlots } set changePending "yes" } proc ChangePlots { } { global changePending global logicPlots global leftMargin rightMargin set from .graph set xMin [$from axis cget x -min] set xMax [$from axis cget x -max] set yLim [$from axis limits y] set yMin [lindex $yLim 0] set yMax [lindex $yLim 1] foreach g ".graph .g2 .g3" { $g configure -leftmargin $leftMargin -rightmargin $rightMargin $g axis configure x -min $xMin -max $xMax #$g axis configure y -min $yMin -max $yMax } set changePending "no" } #LogicPlot .graph .g1 V1 #LogicPlot .graph .g2 V5 #LogicPlot .graph .g3 V9 # LogicPlot .graph .g4 V13 # LogicPlot .graph .g5 V17 # LogicPlot .graph .g6 V22 # LogicPlot .graph .g7 V26 #.g1 configure -leftvariable leftMargin -rightvariable rightMargin trace variable leftMargin w EventuallyChangePlots trace variable rightMargin w EventuallyChangePlots blt-2.4z.orig/demos/graph7.tcl0100755000175000017500000000451107240160071014750 0ustar dokodoko#!../src/bltwish set blt_library ../library package require BLT set blt_library ../library set auto_path [linsert $auto_path 0 ../library] # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl image create photo bgTexture -file ./images/buckskin.gif option add *Graph.Tile bgTexture option add *Label.Tile bgTexture option add *Frame.Tile bgTexture option add *Htext.Tile bgTexture option add *TileOffset 0 option add *HighlightThickness 0 option add *Element.ScaleSymbols no option add *Element.Smooth linear option add *activeLine.Color yellow4 option add *activeLine.Fill yellow option add *activeLine.LineWidth 0 option add *Element.Pixels 3 option add *Graph.halo 7i set visual [winfo screenvisual .] if { $visual != "staticgray" } { option add *print.background yellow option add *quit.background red } proc FormatLabel { w value } { return $value } set graph .graph set length 250000 graph $graph -title "Scatter Plot\n$length points" $graph xaxis configure \ -loose no \ -title "X Axis Label" $graph yaxis configure \ -title "Y Axis Label" $graph legend configure \ -activerelief sunken \ -background "" $graph element create line3 -symbol square -color green4 -fill green2 \ -linewidth 0 -outlinewidth 1 -pixels 4 table . .graph 0,0 -fill both update vector x($length) y($length) x expr random(x) y expr random(y) x sort y $graph element configure line3 -x x -y y wm min . 0 0 Blt_ZoomStack $graph Blt_Crosshairs $graph Blt_ActiveLegend $graph Blt_ClosestPoint $graph busy hold $graph update busy release $graph blt-2.4z.orig/demos/hierbox1.tcl0100755000175000017500000000605507240160071015306 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl set saved [pwd] #blt::bltdebug 100 image create photo bgTexture -file ./images/rain.gif set imageList {} foreach f [glob ./images/mini-*.gif] { lappend imageList [image create photo -file $f] } #option add *Hierbox.Tile bgTexture option add *Hierbox.ScrollTile yes option add *xHierbox.openCommand { set path /home/gah/src/blt/%P if { [file isdirectory $path] } { cd $path set files [glob -nocomplain * */. ] if { $files != "" } { eval %W insert -at %n end $files } } } option add *xHierbox.closeCommand { eval %W delete %n 0 end } image create photo openFolder -file images/open.gif image create photo closeFolder -file images/close.gif option add *Hierbox.icons "closeFolder openFolder" image create photo openFolder2 -file images/open2.gif image create photo closeFolder2 -file images/close2.gif option add *Hierbox.activeIcons "closeFolder2 openFolder2" hierbox .h \ -activebackground blue \ -yscrollcommand { .vs set } \ -xscrollcommand { .hs set } scrollbar .vs -orient vertical -command { .h yview } scrollbar .hs -orient horizontal -command { .h xview } table . \ 0,0 .h -fill both \ 0,1 .vs -fill y \ 1,0 .hs -fill x table configure . c1 r1 -resize none proc DoFind { dir path } { global fileList set saved [pwd] cd $dir lappend fileList $path foreach f [lsort [glob -nocomplain *]] { set entry [file join $path $f] lappend fileList $entry if { [file isdirectory $f] } { DoFind $f $entry } } cd $saved } proc Find { dir } { global fileList set fileList {} DoFind $dir $dir return $fileList } set top .. set trim "$top" .h configure -separator "/" -autocreate yes proc GetAbsolutePath { dir } { set saved [pwd] cd $dir set path [pwd] cd $saved return $path } .h entry configure root -label [file tail [GetAbsolutePath $top]] .h configure -bg grey90 update regsub -all {\.\./*} [Find $top] {} fileList eval .h insert end $fileList .h configure -bg white .h find -glob -name *.gif -exec { %W entry configure %n -image [image create photo -file $top/%P] } focus .h set nodes [.h find -glob -name *.c] eval .h entry configure $nodes -labelcolor red cd $saved blt-2.4z.orig/demos/hierbox2.tcl0100755000175000017500000000514507240160071015306 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl proc AddDirEntries { w dir } { if { [file isdirectory $dir] } { set files [glob -nocomplain $dir/*] eval $w insert end [lsort $files] set subdirs [glob -nocomplain $dir/*/] eval $w entry configure [lsort $subdirs] -button yes } } set imageList {} foreach f [glob ./images/mini-*.gif] { lappend imageList [image create photo -file $f] } set top ../ #option add *Hierbox.Tile bgTexture option add *Hierbox.TileOffset yes option add *forceGadgets no option add *Hierbox.openCommand { AddDirEntries %W "$top/%P" } option add *Hierbox.closeCommand { eval %W delete %n 0 end } image create photo openFolder -file images/open.gif image create photo closeFolder -file images/close.gif option add *Hierbox.icons "closeFolder openFolder" #option add *Hierbox.Button.activeForeground red #option add *Hierbox.bindTags "Label all" hierbox .h \ -selectmode multiple \ -hideroot yes \ -yscrollcommand { .vs set } \ -xscrollcommand { .hs set } .h button configure -activebackground grey92 scrollbar .vs -orient vertical -command { .h yview } scrollbar .hs -orient horizontal -command { .h xview } button .test -text Test -command { set index [.h curselection] set names [eval .h get -full $index] puts "selected names are $names" } button .quit -text Quit -command { exit 0 } table . \ 0,0 .h -fill both \ 2,0 .quit \ 0,1 .vs -fill y 1,0 .hs -fill x \ 3,0 .test table configure . c1 r1 r2 r3 -resize none .h configure -separator "/" -trim $top \ -allowduplicates no #.h entry configure 0 -label [file tail $top] AddDirEntries .h $top focus .h set nodes [.h find -glob -name *.c] eval .h entry configure $nodes -labelcolor red wm protocol . WM_DELETE_WINDOW { destroy . } #blt::bltdebug 100blt-2.4z.orig/demos/hierbox3.tcl0100755000175000017500000000436107240160071015306 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl proc AddDirEntries { w dir } { if { [file isdirectory $dir] } { set files [glob -nocomplain $dir/*] eval $w insert end [lsort $files] set subdirs [glob -nocomplain $dir/*/] eval $w entry configure [lsort $subdirs] -button yes } } set imageList {} foreach f [glob ./images/mini-*.gif] { lappend imageList [image create photo -file $f] } image create photo openFolder -file images/open.gif image create photo closeFolder -file images/close.gif option add *Hierbox.icons "closeFolder openFolder" #option add *Hierbox.openCommand { AddDirEntries %W "$top/%P" } #option add *Hierbox.closeCommand { eval %W delete %n 0 end } hierbox .h \ -allowduplicates no \ -hideroot yes \ -yscrollcommand { .vs set } \ -xscrollcommand { .hs set } scrollbar .vs -orient vertical -command { .h yview } scrollbar .hs -orient horizontal -command { .h xview } button .test -text Test -command { set index [.h curselection] set names [eval .h get -full $index] puts "selected names are $names" } table . \ 0,0 .h -fill both \ 0,1 .vs -fill y \ 1,0 .hs -fill x \ table configure . c1 r1 r2 -resize none set top ../ .h configure -separator "/" -trim $top -autocreate yes #.h entry configure 0 -label [file tail $top] catch { exec du $top } files foreach f [split $files \n ] { .h insert end [lindex $f 1] -text [lindex $f 0] -button auto } focus .h blt-2.4z.orig/demos/hierbox4.tcl0100755000175000017500000000434507240160071015311 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl proc AddDirEntries { w dir } { if { [file isdirectory $dir] } { set files [glob -nocomplain $dir/*] eval $w insert end [lsort $files] set subdirs [glob -nocomplain $dir/*/] eval $w entry configure [lsort $subdirs] -gadget yes } } #blt::bltdebug 100 image create photo openFolder -file images/open.gif image create photo closeFolder -file images/close.gif option add *Hierbox.icons "closeFolder openFolder" option add *Hierbox.cursor crosshair option add *Hierbox.Button.Relief solid option add *Hierbox.Button.ActiveBackground white option add *Hierbox.Button.Background white hierbox .h \ -yscrollcommand { .vs set } \ -xscrollcommand { .hs set } \ -activebackground lightskyblue1 \ -selectbackground lightskyblue2 scrollbar .vs -orient vertical -command { .h yview } scrollbar .hs -orient horizontal -command { .h xview } button .test -text Test -command { set index [.h curselection] set names [eval .h get -full $index] puts "selected names are $names" } table . \ 0,0 .h -fill both \ 0,1 .vs -fill y \ 1,0 .hs -fill x \ 2,0 .test table configure . c1 r1 -resize none .h configure -autocreate yes -font { Helvetica 34 } focus .h .h insert end { The Quick Brown Fox Jumped Over the } .h entry configure root -label {[Root]} .h insert end { The\nQuick\nBrown\nFox\nJumped\nOver\nthe } .h configure -focusedit yes blt-2.4z.orig/demos/hiertable1.tcl0100755000175000017500000001340607470301614015610 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl set saved [pwd] #blt::bltdebug 100 image create photo bgTexture -file ./images/rain.gif set imageList {} foreach f [glob ./images/mini-*.gif] { lappend imageList [image create photo -file $f] } #option add *Hiertable.Tile bgTexture #option add *Hiertable.Column.background grey90 option add *Hiertable.ScrollTile yes option add *Hiertable.titleShadow { grey80 } option add *Hiertable.titleFont {*-helvetica-bold-r-*-*-11-*-*-*-*-*-*-*} option add *xHiertable.openCommand { set path /home/gah/src/blt/%P if { [file isdirectory $path] } { cd $path set files [glob -nocomplain * */. ] if { $files != "" } { eval %W insert -at %n end $files } } } option add *xHiertable.closeCommand { eval %W delete %n 0 end } hiertable .h -hideroot no -width 0 \ -yscrollcommand { .vs set } \ -xscrollcommand { .hs set } \ -selectmode single -hideleaves false .h column configure treeView -text View .h column insert 0 mtime atime gid .h column insert end nlink mode type ctime uid ino size dev .h column configure uid -background \#eaeaff -relief raised -bd 1 .h column configure mtime -hide no -bg \#ffeaea -relief raised -bd 1 .h column configure size gid nlink uid ino dev -justify right -edit yes .h column configure treeView -hide no -edit no scrollbar .vs -orient vertical -command { .h yview } scrollbar .hs -orient horizontal -command { .h xview } table . \ 0,0 .h -fill both \ 0,1 .vs -fill y \ 1,0 .hs -fill x proc FormatSize { size } { set string "" while { $size > 0 } { set rem [expr $size % 1000] set size [expr $size / 1000] if { $size > 0 } { set rem [format "%03d" $rem] } if { $string != "" } { set string "$rem,$string" } else { set string "$rem" } } return $string } array set modes { 0 --- 1 --x 2 -w- 3 -wx 4 r-- 5 r-x 6 rw- 7 rwx } proc FormatMode { mode } { global modes set mode [format %o [expr $mode & 07777]] set owner $modes([string index $mode 0]) set group $modes([string index $mode 1]) set world $modes([string index $mode 2]) return "${owner}${group}${world}" } table configure . c1 r1 -resize none image create photo fileImage -file images/stopsign.gif proc DoFind { dir path } { global fileList count set saved [pwd] cd $dir foreach f [lsort [glob -nocomplain *]] { set entry [file join $path $f] if { [catch { file stat $entry info }] != 0 } { lappend fileList $entry } else { if 0 { if { $info(type) == "file" } { set info(type) @fileImage } else { set info(type) "" } } set info(mtime) [clock format $info(mtime) -format "%b %d, %Y"] set info(atime) [clock format $info(atime) -format "%b %d, %Y"] set info(ctime) [clock format $info(ctime) -format "%b %d, %Y"] set info(size) [FormatSize $info(size)] set info(mode) [FormatMode $info(mode)] lappend fileList $entry -data [array get info] } incr count if { [file type $f] == "directory" } { DoFind $f $entry } } cd $saved } proc Find { dir } { global fileList count set fileList {} catch { file stat $dir info } incr count lappend fileList $dir -data [array get info] DoFind $dir $dir return $fileList } proc GetAbsolutePath { dir } { set saved [pwd] cd $dir set path [pwd] cd $saved return $path } set top [GetAbsolutePath ..] set trim "$top" .h configure -separator "/" -trim $trim set count 0 .h entry configure root -label [file tail [GetAbsolutePath $top]] .h configure -bg grey90 regsub -all {\.\./*} [Find $top] {} fileList puts "$count entries" eval .h insert end $fileList .h configure -bg white focus .h set nodes [.h find -glob -name *.c] eval .h entry configure $nodes -foreground green4 set nodes [.h find -glob -name *.h] eval .h entry configure $nodes -foreground cyan4 set nodes [.h find -glob -name *.o] eval .h entry configure $nodes -foreground red4 cd $saved #bltdebug 100 toplevel .top hiertable .top.h2 -tree .h -yscrollcommand { .top.sbar set } scrollbar .top.sbar -command { .top.h2 yview } pack .top.h2 -side left -expand yes -fill both pack .top.sbar -side right -fill y .h column bind all { %W configure -flat no } proc SortColumn { column } { set old [.h sort cget -column] set decreasing 0 if { "$old" == "$column" } { set decreasing [.h sort cget -decreasing] set decreasing [expr !$decreasing] } .h sort configure -decreasing $decreasing -column $column -mode integer .h configure -flat yes .h sort auto yes blt::busy hold .h update blt::busy release .h } foreach column [.h column names] { .h column configure $column -command [list SortColumn $column] } scale .s -from 0 -to 300 -orient horizontal -length 300 table . \ 3,0 .s update .s set 20 if 1 { .s configure -command { .h entry configure 0 -height } } blt-2.4z.orig/demos/hiertable2.tcl0100755000175000017500000001246107470301615015612 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl set saved [pwd] #blt::bltdebug 100 image create photo bgTexture -file ./images/rain.gif set imageList {} foreach f [glob ./images/mini-*.gif] { lappend imageList [image create photo -file $f] } #option add *Hiertable.Tile bgTexture option add *Hiertable.ScrollTile yes #option add *Hiertable.Column.background grey90 option add *Hiertable.titleShadow { grey80 } option add *Hiertable.titleFont {*-helvetica-bold-r-*-*-11-*-*-*-*-*-*-*} option add *xHiertable.openCommand { set path /home/gah/src/blt/%P if { [file isdirectory $path] } { cd $path set files [glob -nocomplain * */. ] if { $files != "" } { eval %W insert -at %n end $files } } } option add *xHiertable.closeCommand { eval %W delete %n 0 end } hiertable .h -width 0\ -yscrollcommand { .vs set } \ -xscrollcommand { .hs set } \ -selectmode multiple .h column configure treeView -text "View" .h column insert 0 mtime atime gid .h column insert end nlink mode type ctime uid ino size dev .h column configure uid -background \#eaeaff .h column configure mtime -hide no -bg \#ffeaea .h column configure size gid nlink uid ino dev -justify right .h column configure treeView -hide no -edit no scrollbar .vs -orient vertical -command { .h yview } scrollbar .hs -orient horizontal -command { .h xview } table . \ 0,0 .h -fill both \ 0,1 .vs -fill y \ 1,0 .hs -fill x proc FormatSize { size } { set string "" while { $size > 0 } { set rem [expr $size % 1000] set size [expr $size / 1000] if { $size > 0 } { set rem [format "%03d" $rem] } if { $string != "" } { set string "$rem,$string" } else { set string "$rem" } } return $string } array set modes { 0 --- 1 --x 2 -w- 3 -wx 4 r-- 5 r-x 6 rw- 7 rwx } proc FormatMode { mode } { global modes set mode [format %o [expr $mode & 07777]] set owner $modes([string index $mode 0]) set group $modes([string index $mode 1]) set world $modes([string index $mode 2]) return "${owner}${group}${world}" } table configure . c1 r1 -resize none image create photo fileImage -file images/stopsign.gif proc DoFind { dir path } { global fileList count set saved [pwd] cd $dir foreach f [lsort [glob -nocomplain *]] { set entry [file join $path $f] if { [catch { file stat $entry info }] != 0 } { lappend fileList $entry } else { if 0 { if { $info(type) == "file" } { set info(type) @fileImage } else { set info(type) "" } } set info(mtime) [clock format $info(mtime) -format "%b %d, %Y"] set info(atime) [clock format $info(atime) -format "%b %d, %Y"] set info(ctime) [clock format $info(ctime) -format "%b %d, %Y"] set info(size) [FormatSize $info(size)] set info(mode) [FormatMode $info(mode)] lappend fileList $entry -data [array get info] } incr count if { [file isdirectory $f] } { DoFind $f $entry } } cd $saved } proc Find { dir } { global fileList count set fileList {} catch { file stat $dir info } incr count lappend fileList $dir -data [array get info] DoFind $dir $dir return $fileList } proc GetAbsolutePath { dir } { set saved [pwd] cd $dir set path [pwd] cd $saved return $path } set top [GetAbsolutePath ..] set trim "$top" .h configure -separator "/" -trim $trim set count 0 #.h entry configure root -label [file tail [GetAbsolutePath $top]] .h configure -bg grey90 regsub -all {\.\./*} [Find $top] {} fileList puts "$count entries" eval .h insert end $fileList .h configure -bg white focus .h set nodes [.h find -glob -name *.c] eval .h entry configure $nodes -foreground green4 set nodes [.h find -glob -name *.h] eval .h entry configure $nodes -foreground cyan4 set nodes [.h find -glob -name *.o] eval .h entry configure $nodes -foreground red4 cd $saved #bltdebug 100 .h column bind all { %W configure -flat no } proc SortColumn { column } { set old [.h sort cget -column] set decreasing 0 if { "$old" == "$column" } { set decreasing [.h sort cget -decreasing] set decreasing [expr !$decreasing] } .h sort configure -decreasing $decreasing -column $column .h configure -flat yes .h sort auto yes blt::busy hold .h update blt::busy release .h } foreach column [.h column names] { .h column configure $column -command [list SortColumn $column] } blt-2.4z.orig/demos/hiertable3.tcl0100755000175000017500000001157207476002124015614 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl set saved [pwd] #blt::bltdebug 100 image create photo bgTexture -file ./images/rain.gif set imageList {} foreach f [glob ./images/mini-*.gif] { lappend imageList [image create photo -file $f] } #option add *Hiertable.Tile bgTexture option add *Hiertable.ScrollTile yes #option add *Hiertable.Column.background grey90 option add *Hiertable.titleShadow { grey80 } option add *Hiertable.titleFont {*-helvetica-bold-r-*-*-11-*-*-*-*-*-*-*} hiertable .h -width 0\ -yscrollcommand { .vs set } \ -xscrollcommand { .hs set } \ -selectmode multiple \ -hideroot yes #.h configure -icons "" -activeicons "" .h column configure treeView -text "View" .h column insert 0 mtime atime gid .h column insert end nlink mode type ctime uid ino size dev .h column configure uid -background \#eaeaff -style text .h column configure mtime -hide no -bg \#ffeaea -style text .h column configure size gid nlink uid ino dev -justify right -style text .h column configure treeView -hide no -edit no -style text scrollbar .vs -orient vertical -command { .h yview } scrollbar .hs -orient horizontal -command { .h xview } table . \ 0,0 .h -fill both \ 0,1 .vs -fill y \ 1,0 .hs -fill x proc FormatSize { size } { set string "" while { $size > 0 } { set rem [expr $size % 1000] set size [expr $size / 1000] if { $size > 0 } { set rem [format "%03d" $rem] } if { $string != "" } { set string "$rem,$string" } else { set string "$rem" } } return $string } array set modes { 0 --- 1 --x 2 -w- 3 -wx 4 r-- 5 r-x 6 rw- 7 rwx } proc FormatMode { mode } { global modes set mode [format %o [expr $mode & 07777]] set owner $modes([string index $mode 0]) set group $modes([string index $mode 1]) set world $modes([string index $mode 2]) return "${owner}${group}${world}" } table configure . c1 r1 -resize none image create photo fileImage -file images/stopsign.gif proc DoFind { dir parent } { global count set saved [pwd] cd $dir foreach f [lsort [glob -nocomplain *]] { set node [tree0 insert $parent -label $f] if { [catch { file stat $f info }] == 0 } { if 0 { if { $info(type) == "file" } { set info(type) @fileImage } else { set info(type) "" } } set info(mtime) [clock format $info(mtime) -format "%b %d, %Y"] set info(atime) [clock format $info(atime) -format "%b %d, %Y"] set info(ctime) [clock format $info(ctime) -format "%b %d, %Y"] set info(size) [FormatSize $info(size)] set info(mode) [FormatMode $info(mode)] eval tree0 set $node [array get info] } incr count if { [file isdirectory $f] } { DoFind $f $node } } cd $saved } proc Find { dir } { global count set count 0 catch { file stat $dir info } incr count tree create tree0 tree0 label root [file tail $dir] eval tree0 set root [array get info] DoFind $dir root puts "$count entries" } proc GetAbsolutePath { dir } { set saved [pwd] cd $dir set path [pwd] cd $saved return $path } set top [GetAbsolutePath ..] Find $top focus .h .h configure -tree tree0 -separator / set nodes [.h find -glob -name *.c] eval .h entry configure $nodes -foreground green4 set nodes [.h find -glob -name *.h] eval .h entry configure $nodes -foreground cyan4 set nodes [.h find -glob -name *.o] eval .h entry configure $nodes -foreground red4 cd $saved .h column bind all { %W configure -flat no } proc SortColumn { column } { set old [.h sort cget -column] set decreasing 0 if { "$old" == "$column" } { set decreasing [.h sort cget -decreasing] set decreasing [expr !$decreasing] } .h sort configure -decreasing $decreasing -column $column .h configure -flat yes .h sort auto yes blt::busy hold .h update blt::busy release .h } foreach column [.h column names] { .h column configure $column -command [list SortColumn $column] } blt-2.4z.orig/demos/htext.txt0100644000175000017500000005232007240160072014750 0ustar dokodoko This is a (for lack of a better name) hypertext widget. This widget combines text and other Tk widgets in the same window. It is sort of a cross between a read-only text widget and the pack command. Any widget can be attached to the hypertext window by the %% set this $htext(widget) label $this.lab -text "append " -relief sunken \ -font *-Courier-Bold-R-Normal-*-12-120-* $this append $this.lab %% command. For example, %% message $this.msg -relief sunken -bd 2 -aspect 10000 -font \ *-Courier-Medium-R-Normal-*-12-* -text {set w $htext(widget) label $w.face -bitmap @bitmaps/face.xbm \ -relief sunken -borderwidth 2 $w append $w.face -padx 2 -pady 0.25i} $this append $this.msg \ -fill both %% added this %% global tk_library label $this.face \ -bitmap @bitmaps/face.xbm \ -relief sunken -borderwidth 2 $this append $this.face -padx 2 -pady 0.25i %%. There can be many types of widgets in the same document. For example, this is a simple %% button $this.but -bg pink -text { button } \ -command { puts stderr { a stupid message } } $this append $this.but %%. If you click on the button, it prints a stupid message. Any Tk widget can be used, including %% set whichTile 0 proc ChangeTile { w } { global whichTile if { $whichTile } { $w configure -tile bgTexture2 } else { $w configure -tile bgTexture1 } } checkbutton $this.ckbut -bg lightblue -text { check buttons } \ -variable whichTile -command "ChangeTile $this" $this append $this.ckbut -justify top %%, %% radiobutton $this.rdbut -bg mediumseagreen -text { radio buttons } \ -command { puts stderr { radio button pressed } } $this append $this.rdbut -justify bottom %%, and scales %% # -sliderforeground scale $this.sc -showvalue true \ -length 100 \ -foreground powderblue \ -sliderlength 10 \ -orient horizontal $this append $this.sc %%. Widget trees can be also be included. The following example is *borrowed* from the widget demo. It is a couple of frames surrounding a listbox, a message, and a button widget. %% set w $this.frame frame $w message $w.msg -font *times-medium-r-normal--*-12-120-* -aspect 300 \ -text "A listbox containing the 50 states is displayed below, along with a scrollbar. You can scan the list either using the scrollbar or by dragging in the listbox window with button 3 pressed. Click the \"OK\" button when you've seen enough." -bg lightsteelblue -relief sunken frame $w.frame -borderwidth 10 pack append $w.frame \ [scrollbar $w.frame.scroll -relief sunken \ -command "$w.frame.list yview"] {right expand filly frame w} \ [listbox $w.frame.list -yscroll "$w.frame.scroll set" -relief sunken] \ {left expand filly frame e} $w.frame.list insert 0 Alabama Alaska Arizona Arkansas California \ Colorado Connecticut Delaware Florida Georgia Hawaii Idaho Illinois \ Indiana Iowa Kansas Kentucky Louisiana Maine Maryland \ Massachusetts Michigan Minnesota Mississippi Missouri \ Montana Nebraska Nevada "New Hampshire" "New Jersey" "New Mexico" \ "New York" "North Carolina" "North Dakota" \ Ohio Oklahoma Oregon Pennsylvania "Rhode Island" \ "South Carolina" "South Dakota" \ Tennessee Texas Utah Vermont Virginia Washington \ "West Virginia" Wisconsin Wyoming button $w.ok -text OK -command "puts stderr $w; destroy $w" pack append $w $w.msg {top fill} $w.frame {top expand fill} \ $w.ok {bottom fill} $w config -bg lightsteelblue -relief sunken $this append $w -pady 0.25i %% You can add you own home-grown widgets. Here's the graph widget. Beside it is the "color" demo. Moving the scales, adjusts the background color of the graph. %% # # Simple script to change colors of a window. # global xlabel ylabel red green blue graph set red 255 set green 215 set blue 0 option add *Scale.sliderForeground "#cdb79e" option add *Scale.activeForeground "#ffe4c4" set w $this.colorFrame frame $w scale $w.red -command "color red" -label "Red Intensity" \ -from 0 -to 255 -orient horizontal -bg "#ffaeb9" -length 250 scale $w.green -command "color green" -label "Green Intensity" \ -from 0 -to 255 -orient horizontal -bg "#43cd80" scale $w.blue -command "color blue" -label "Blue Intensity" \ -from 0 -to 255 -orient horizontal -bg "#7ec0ee" $w.blue set $blue $w.green set $green $w.red set $red pack append $w $w.red {top expand fill} pack append $w $w.green {top expand fill} pack append $w $w.blue {top expand fill} proc color {which intensity} { global red green blue graph xlabel ylabel set $which $intensity set rgb [format #%02x%02x%02x $red $green $blue] $graph config -bg $rgb $xlabel config -bg $rgb $ylabel config -bg $rgb } $this append $w %% %% proc makeplot { widget } { graph $widget set X { 2.00000e-01 4.00000e-01 6.00000e-01 8.00000e-01 1.00000e+00 1.20000e+00 1.40000e+00 1.60000e+00 1.80000e+00 2.00000e+00 2.20000e+00 2.40000e+00 2.60000e+00 2.80000e+00 3.00000e+00 3.20000e+00 3.40000e+00 3.60000e+00 3.80000e+00 4.00000e+00 4.20000e+00 4.40000e+00 4.60000e+00 4.80000e+00 5.00000e+00 } $widget element create Y1 -x $X -y { 1.14471e+01 2.09373e+01 2.84608e+01 3.40080e+01 3.75691e+01 3.91345e+01 3.92706e+01 3.93474e+01 3.94242e+01 3.95010e+01 3.95778e+01 3.96545e+01 3.97313e+01 3.98081e+01 3.98849e+01 3.99617e+01 4.00384e+01 4.01152e+01 4.01920e+01 4.02688e+01 4.03455e+01 4.04223e+01 4.04990e+01 4.05758e+01 4.06526e+01 } -symbol circle -label VGS=2.0 -color blue4 -fill blue $widget element create Y2 -x $X -y { 2.61825e+01 5.04696e+01 7.28517e+01 9.33192e+01 1.11863e+02 1.28473e+02 1.43140e+02 1.55854e+02 1.66606e+02 1.75386e+02 1.82185e+02 1.86994e+02 1.89802e+02 1.90683e+02 1.91047e+02 1.91411e+02 1.91775e+02 1.92139e+02 1.92503e+02 1.92867e+02 1.93231e+02 1.93595e+02 1.93958e+02 1.94322e+02 1.94686e+02 } -symbol diamond -label VGS=3.5 -color green4 -fill green $widget element create Y3 -x $X -y { 4.07008e+01 7.95658e+01 1.16585e+02 1.51750e+02 1.85051e+02 2.16479e+02 2.46024e+02 2.73676e+02 2.99427e+02 3.23267e+02 3.45187e+02 3.65177e+02 3.83228e+02 3.99331e+02 4.13476e+02 4.25655e+02 4.35856e+02 4.44073e+02 4.50294e+02 4.54512e+02 4.56716e+02 4.57596e+02 4.58448e+02 4.59299e+02 4.60151e+02 } -symbol triangle -label VGS=5.0 -color red4 -fill red } option add *graph.title "Plot Title" option add *graph.xTitle "X Axis Label" option add *graph.yTitle "Y Axis Label" #option add *graph.legendMapped false option add *graph.elemPixels 8 option add *graph.relief ridge option add *graph.borderWidth 2 set graph $this.graph set xlabel $this.xlab set ylabel $this.ylab makeplot $graph $this append $graph -padx 0.25i -pady 0.25i %% If you click on any button in the graph, you will get the coordinate values at the pointer location. The current coordinate values are %% label $xlabel -text { ??? ??? } -relief sunken label $ylabel -text { ??? ??? } -relief sunken bind $graph {labelxy [ %W invtransform %x %y ]} proc labelxy { values } { global xlabel ylabel scan $values "%e %e" x y $xlabel config -text $x $ylabel config -text $y } $this append $this.xlab -width 100 -fill x %% and %% $this append $this.ylab -width 100 -fill x %%. There are four global variables automatically created when a hypertext file is read. They are: %% button $this.l1 -text " \$htext(widget) " \ -command "puts $this" -bg orange $this append $this.l1 -width 200 -pady 4 %%the pathname of the hypertext widget. %% button $this.l2 -text " \$htext(file) " \ -command "puts $htext(file)" -bg orange $this append $this.l2 -width 200 -pady 4 %%the file being read. %% button $this.l3 -text " \$htext(line) " \ -command "puts $htext(line)" -bg orange $this append $this.l3 -width 200 -pady 4 %%the current line number. %% button $this.l4 -text " \$htext(index) " \ -command "puts $htext(index)" -bg orange $this append $this.l4 -width 200 -pady 4 %%the current index in the text. Click on any button and the current value is printed on standard output. The hypertext widget works with plain text too. If you don't want to read it, click on the %% button $this.goto -text button -fg purple -bg white \ -command "global endOfText; $this gotoline \$endOfText" $this append $this.goto %% to jump to the end of the plain text. ------------------------------------------------------ [This is a pre-release version of BLT. It's basically the latest snapshot of BLT, as it moves towards a full release. What this means is that the documentation and demos still need work. Let me know about any configuration/compiler/installation goofs so I make sure they're fixed for the next release.] This is version 2.4 of the BLT library. It's an extension to the Tcl/Tk toolkit. You simply compile and link with the Tcl/Tk libraries. It does not require the Tcl or Tk source files. BLT is available from ftp.tcltk.com in the "pub/blt" directory. The URL is ftp://ftp.tcltk.com/pub/blt/BLT2.4.tar.gz This release has been compiled and tested with versions: Tcl 7.5 / Tk 4.1 Tcl 7.6 / Tk 4.2 Tcl/Tk 8.0 Tcl/Tk 8.1a2 What is BLT? BLT is an extension to Tk. It adds plotting widgets (X-Y graph, barchart, stripchart), a powerful geometry manager, a new canvas item, and several new commands to Tk. Plotting widgets: graph, barchart, stripchart BLT has X-Y graph, barchart, and stripchart widgets that are both easy to use and customize. All the widgets work with BLT vector data objects, which makes it easy to manage data. Hierarchical list box: hierbox Displays a general ordered tree which may be built on-the-fly or all at once. Tab set: tabset Can be used either as a tab notebook or simple tabset. Multi-tiered and/or scrolled tabsets are available. Notebook pages can be torn-off into separate windows and later put back. Geometry Manager: table A table-based geometry manager. Lets you specify widget layouts by row and column positions in the table. Unlike the packer or grid, you can finely control and constrain window sizes. Vector Data Object: vector Lets you manage a vector of floating point values in a high-level fashion. Vectors inter-operate seamlessly with the plotting widgets. The graphs will automatically redraw themselves when the vector data changes. Vector's components can be managed through a Tcl array variable, a Tcl command, or the using its own C API. Background Program Execution: bgexec Like Tcl's "exec ... &", but collects the output, error, and status of the detached UNIX subprocesses. Sets a Tcl variable upon completion. Busy Command: busy For preventing user-interactions when the application is busy. Manages an invisible "busy" window which prevents further user interactions (keyboard, mouse, button, etc.). Also you can provide a busy cursor that temporarily overrides those of the Tk widgets. New Canvas Item: eps An new item is added to the Tk canvas for handling encapsulated PostScript. It lets you embed an EPS file into the canvas displaying either an EPS preview image found in the file, or a Tk image that you provide. When you print the canvas the EPS item will automatically include the EPS file, translating and scaling the PostScript. For example, you could use "eps" items to tile several PostScript pages into single page. The "eps" item can also be used as a replacement for "image" canvas items. Unlike "image" canvas items, the image of an eps item can be printed and scaled arbitrarily. Drag & Drop Facility: drag&drop Adds drag-n-drop capabilities to Tk. It uses "send"-style communication between drag-drop sources and targets. The result is a much more powerful drag-and-drop mechanism than is available with OpenLook or Motif. Bitmap Command: bitmap Lets you read and write bitmaps from Tcl. You can define bitmaps from ordinary text strings. Bitmaps can also be scaled and rotated. For example, you can create a button with rotated text by defining a bitmap from a text string and rotating it. You can then use the bitmap in the button widget. Miscellaneous Commands: winop Basic window operations. You can raise, lower, map, or, unmap windows. Other operations let you move the pointer or take photo image snapshots of Tk widgets. bltdebug Lets you trace the execution of Tcl commands and procedures. Prints out each Tcl command before it's executed. watch Lets you specify Tcl procedures to be run before and/or after every Tcl command. May be used for logging, tracing, profiling, or debugging or Tcl code. spline Computes a spline fitting a set of data points (x and y vectors) and produces a vector of the interpolated images (y-coordinates) at a given set of x-coordinates. htext A simple hypertext widget. Allows text and Tk widgets to be combined in a scroll-able text window. Any Tk widget can be embedded and used to form hyper-links. Other options allow for selections and text searches. What's new in 2.4? 1. "eps" canvas item. An encapsulated PostScript canvas item lets you embed an EPS file into the canvas. The "eps" item displays either a EPS preview image found in the file, or a Tk image that you provide. 2. "hierbox" widget. Hierarchical listbox widget. Displays a general ordered tree which may be built on-the-fly or all at once. 3. "tabset" widget. Can be used either as a tab notebook or simple tabset. Tabs can be arranged in a variety of ways: multi-tiered, scrolled, and attached to any of the four sides. Tab labels can contain both images and text (text can be arbitrarily rotated). Notebook pages can be torn-off into separate windows and replaced later. 4. Changes to vectors. New features: o Vector expressions. The vector now has an "expr" operation that lets you perform math (including math library functions) on vectors. There are several new functions (such as "max", "min", "mean" "median", "q1", "q3", "prod", "sum", "adev", "sdev", "skew", ...) vector expr { sin(x)^2 + cos(x)^2 } y expr { log(x) * $value } o New syntax to create and destroy vectors: vector create x vector destroy x The old syntax for creating vectors still works. vector x o Vectors are *not* automatically deleted when their Tcl variable is unset anymore. This means that you can temporarily map vectors to variables and use them as you would an ordinary Tcl array (kind of like "upvar"). proc AddValue { vecName value } { $vecName variable x set x(++end) $value } There's an "-watchunset" flag to restore the old behavior if you need it. vector create x -watchunset yes o Vectors still automatically create Tcl variables by default. I'd like to change this, but it silently breaks lots of code, so it will stay. Bug fixes: o Vector reallocation failed when shrinking the vector. o Vector "destroy" callback made after vector was already freed. 5. Changes to Graph, Barchart, Stripchart widgets. New features: o Drop shadows for text (titles, markers, etc). Drop shadows improve contrast when displaying text over a background with similar color intensities. o Postscript "-preview" option to generate a EPS PostScript preview image that can be read and displayed by the EPS canvas item. o New "-topvariable", "-bottomvariable", "-leftvariable", and "-rightvariable" options. They specify variables to contain the current margin sizes. These variables are updated whenever the graph is redrawn. o New "-aspect" option. Let's you maintain a particular aspect ratio for the the graph. o Image markers can now be stretched and zoomed like bitmap markers. o Bind operation for legend entries, markers, and elements. Much thanks to Julian Loaring for the suggestions. o New "-xor" option for line markers, lets you draw the line by rubberbanded by XOR-ing without requiring the graph to be redrawn. This can be used, for example, to select regions like in zooming. Thanks to Johannes Zellner (joze@krisal.physik.uni-karlsruhe.de) for the suggestion. Bug fixes: o Closest line (point) broken when using pens styles. o Marker elastic coordinates were wrong. o PostScript bounding box included the border of the page. o Bad PostScript generated for barchart symbols with stipples. o Wrong dimensions computed with postscript " -maxpect" option. o Text markers fixed. Thanks to De Clarke for the bug report and fix. o Renamed axis configuration from "-range" to "-autorange" to match the documentation. Thanks to Brian Smith for the correction. o Fixed polygon marker pick routine. o Fixed active tab labels overlapping the selected tab. What's incompatible with releases prior to BLT 2.4? 1. Vector names must start with a letter and contain letters, digits, or underscores. Namespace Issues: Vector names are still global. If Tcl provides an API, vectors may in the future be created on a per-namespace basis. Right now, there's no mechanism for detecting when a namespace has been destroyed. Which is why you can't currently prefix a vector name with a namespace qualifier. [Ok, there is... Thanks to Michael McLennan for pointing this out to me. So maybe soon there will be vectors on a per namespace basis.] 2. The "-mapped" options throughout the graph have been replaced by the "-hide" option. The many usages of the word "map" was getting confusing. # No longer works. .graph legend configure -mapped no # Instead use this. .graph legend configure -hide yes How to compile and test BLT? See the file "INSTALL" for instructions. When will the so-called "official" BLT work with Windows? It currently compiles and runs with MS VC++ and EGCS 1.1 under Windows 95/NT (loadable binary versions will be forthcoming). Everything pretty much works: graphs, bgexec, busy, drag&drop etc. When will...? In general, I can't answer the "When will" questions, mostly out of embarrassment. My estimates of when new features and releases will occur usually turn out to be way way off. What does BLT stand for? Whatever you want it to. --gah %% global endOfText set endOfText [expr $htext(line)-1 ] global updateInterval count barchart global Red Green Blue set updateInterval 200 set count 0 set Red bb set Green 00 set Blue 33 option add *barchart.title "Bar Chart" option add *barchart.x.title "X" option add *barchart.y.title "Y" option add *barchart.y2.title "Y" option add *barchart.Axis.subTicks 0 option add *barchart.x.stepSize 0 option add *barchart.x.Ticks 0 option add *barchart.legend.hide yes option add *barchart.Axis.Font *-Courier-Bold-R-Normal-*-8-80-* option add *barchart.y2.hide yes set barchart $this.barchart barchart $barchart -bd 2 -relief raised -tile bgTexture2 $barchart y2axis use y $this append $barchart -fill both -padx 10 -pady 10 -relwidth 0.8 proc AnimateBarchart { } { global updateInterval global barchart count Red Blue Green if { [info commands $barchart] != $barchart } { return } incr count if { $count > 100 } { $barchart element delete [lindex [$barchart element show] end] } set color [format "%x" [expr $count%16]] set Green ${color}${color} $barchart element create $count -data { $count sin($count*0.1)} \ -fg #${Red}${Green}${Blue} -bg brown after $updateInterval AnimateBarchart } AnimateBarchart %% Press %% button $this.quit -command { exit } -text {Quit} -bg pink $this append $this.quit %% to remove the window. blt-2.4z.orig/demos/htext1.tcl0100755000175000017500000001053007240160072014774 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl set visual [winfo screenvisual .] if { $visual == "staticgray" || $visual == "grayscale" } { set activeBg black set normalBg white set bitmapFg black set bitmapBg white option add *top.background white } else { option add *htext.foreground navyblue if { $tk_version >= 4.0 } { set file1 ./images/clouds.gif set file2 ./images/chalk.gif image create photo bgTexture1 -file $file1 image create photo bgTexture2 -file $file2 # option add *htext.tile bgTexture1 option add *htext.foreground black option add *htext.background white option add *htext.selectBackground gold1 } } option add *highlightThickness 0 proc Blt_FindPattern { htext } { toplevel .search wm title .search "Text search" label .search.label1 -text "Enter Pattern" entry .search.entry -relief sunken button .search.clear -text "Clear" \ -command ".search.entry delete 0 end" button .search.cancel -text "Cancel" \ -command "destroy .search; focus $htext" button .search.search -text "Search" -command "Blt_Search&Move $htext" bind .search.entry "Blt_Search&Move $htext" table .search \ .search.label1 0,0 -padx 4 \ .search.entry 0,1 -cspan 2 -pady 4 -padx 4 -reqwidth 3i \ .search.search 3,0 -reqwidth .75i -anchor w -padx 10 -pady 5 \ .search.clear 3,1 -reqwidth .75i -anchor center -padx 10 -pady 5 \ .search.cancel 3,2 -reqwidth .75i -anchor e -padx 10 -pady 5 focus .search.entry bind .search { raise .search } } set last 0 set lastPattern {} proc Blt_Search&Move { h } { global last global lastPattern set pattern [.search.entry get] if { [string compare $pattern $lastPattern] != 0 } { set last 0 set lastPattern $pattern } if { $pattern == "" } { return } set indices [$h search $pattern $last end] if { $indices == "" } { bell } else { set first [lindex $indices 0] set last [lindex $indices 1] $h selection range $first $last $h gotoline $first incr last } } # Create horizonatal and vertical scrollbars scrollbar .vscroll -command { .htext yview } -orient vertical scrollbar .hscroll -command { .htext xview } -orient horizontal # Create the hypertext widget htext .htext -file ./htext.txt \ -yscrollcommand { .vscroll set } \ -xscrollcommand { .hscroll set } \ -yscrollunits 10m -xscrollunits .25i \ -height 6i table . \ .htext 0,0 -fill both \ .vscroll 0,1 -fill y \ .hscroll 1,0 -fill x table configure . r1 c1 -resize none bind .htext { %W select to @%x,%y } bind .htext <1> { %W select from @%x,%y %W select to @%x,%y } bind .htext { %W select word @%x,%y } bind .htext { %W select line @%x,%y } bind .htext { puts stderr [%W select index @%x,%y] } bind .htext { %W scan dragto @%x,%y } bind .htext <2> { %W scan mark @%x,%y } bind .htext <3> { %W select adjust @%x,%y } bind .htext { set line [%W gotoline] if { $line == 0 } { bell } else { set line [expr $line-1] %W gotoline $line.0 } } bind .htext { set line [%W gotoline] incr line if { [%W gotoline $line.0] != $line } { bell } } bind .htext { %W yview [expr [%W yview]+10] } bind .htext { %W yview [expr [%W yview]-10] } bind .htext { %W yview [expr [%W yview]-10] } bind .htext { exit 0 } bind .htext { Blt_FindPattern %W } wm min . 0 0 focus .htext blt-2.4z.orig/demos/spline.tcl0100755000175000017500000000362307344534201015062 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl option add *graph.Element.ScaleSymbols true # test to show spline over-shooting set tcl_precision 15 # Make and fill small vectors vector x y x seq 10 0 -0.5 y expr sin(x^3) x expr x*x x sort y vector x2 y1 y2 y3 # make and fill (x only) large vectors x populate x2 10 # natural spline interpolation spline natural x y x2 y1 # quadratic spline interpolation spline quadratic x y x2 y2 # make plot graph .graph .graph xaxis configure -title "x^2" .graph yaxis configure -title "sin(y^3)" .graph pen configure activeLine -pixels 5 .graph element create Original -x x -y y \ -color red4 \ -fill red \ -pixels 5 \ -symbol circle .graph element create Natural -x x2 -y y1 \ -color green4 \ -fill green \ -pixels 3 \ -symbol triangle .graph element create Quadratic -x x2 -y y2 \ -color blue4 \ -fill orange2 \ -pixels 3 \ -symbol arrow table . .graph -fill both Blt_ZoomStack .graph Blt_Crosshairs .graph Blt_ActiveLegend .graph Blt_ClosestPoint .graph Blt_PrintKey .graph .graph grid on blt-2.4z.orig/demos/stripchart1.tcl0100755000175000017500000003030107530630501016022 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl # ---------------------------------------------------------------------- # EXAMPLE: simple driver for stripchart widget # ---------------------------------------------------------------------- # Michael J. McLennan # mmclennan@lucent.com # Bell Labs Innovations for Lucent Technologies # ====================================================================== # Copyright (c) 1996 Lucent Technologies # ====================================================================== option add *x.range 20.0 option add *x.shiftBy 15.0 option add *bufferElements no option add *bufferGraph yes option add *symbol triangle option add *Axis.lineWidth 1 option add *Axis*Rotate 90 option add *pixels 1.25m #option add *PlotPad 25 option add *Stripchart.width 6i #option add *Smooth quadratic #option add *Stripchart.invertXY yes #option add *x.descending yes # ---------------------------------------------------------------------- # USAGE: random ?? ?? # # Returns a random number in the range to . # If is not specified, the default is 0; if max is not # specified, the default is 1. # ---------------------------------------------------------------------- proc random {{max 1.0} {min 0.0}} { global randomSeed set randomSeed [expr (7141*$randomSeed+54773) % 259200] set num [expr $randomSeed/259200.0*($max-$min)+$min] return $num } set randomSeed 14823 # ---------------------------------------------------------------------- toplevel .addSource wm title .addSource "Add Source" wm group .addSource . wm withdraw .addSource wm protocol .addSource WM_DELETE_WINDOW {.addSource.controls.cancel invoke} frame .addSource.info pack .addSource.info -expand yes -fill both -padx 4 -pady 4 label .addSource.info.namel -text "Name:" entry .addSource.info.name label .addSource.info.maxl -text "Maximum:" entry .addSource.info.max label .addSource.info.minl -text "Minimum:" entry .addSource.info.min table .addSource.info \ .addSource.info.namel 0,0 -anchor e \ .addSource.info.name 0,1 -fill x \ .addSource.info.maxl 1,0 -anchor e \ .addSource.info.max 1,1 -fill x \ .addSource.info.minl 2,0 -anchor e \ .addSource.info.min 2,1 -fill x frame .addSource.color pack .addSource.color -padx 8 -pady 4 frame .addSource.color.sample -width 30 -height 30 -borderwidth 2 -relief raised pack .addSource.color.sample -side top -fill both scale .addSource.color.r -label "Red" -orient vertical \ -from 100 -to 0 -command source_color pack .addSource.color.r -side left -fill y scale .addSource.color.g -label "Green" -orient vertical \ -from 100 -to 0 -command source_color pack .addSource.color.g -side left -fill y scale .addSource.color.b -label "Blue" -orient vertical \ -from 100 -to 0 -command source_color pack .addSource.color.b -side left -fill y proc source_color {args} { set r [expr round(2.55*[.addSource.color.r get])] set g [expr round(2.55*[.addSource.color.g get])] set b [expr round(2.55*[.addSource.color.b get])] set color [format "#%2.2x%2.2x%2.2x" $r $g $b] .addSource.color.sample configure -background $color } source_color frame .addSource.sep -borderwidth 1 -height 2 -relief sunken pack .addSource.sep -fill x -pady 4 frame .addSource.controls pack .addSource.controls -fill x -padx 4 -pady 4 button .addSource.controls.ok -text "OK" -command { wm withdraw .addSource set name [.addSource.info.name get] set color [.addSource.color.sample cget -background] set max [.addSource.info.max get] set min [.addSource.info.min get] if {[catch {source_create $name $color $min $max} err] != 0} { puts "error: $err" } } pack .addSource.controls.ok -side left -expand yes -padx 4 button .addSource.controls.cancel -text "Cancel" -command { wm withdraw .addSource } pack .addSource.controls.cancel -side left -expand yes -padx 4 set useAxes y proc source_create {name color min max} { global sources if {[info exists sources($name-controls)]} { error "source \"$name\" already exists" } if {$max <= $min} { error "bad range: $min - $max" } set unique 0 set win ".sources.nb.s[incr unique]" while {[winfo exists $win]} { set win ".sources.nb.s[incr unique]" } set xvname "xvector$unique" set yvname "yvector$unique" set wvname "wvector$unique" global $xvname $yvname $wvname # catch { $xvname delete } # catch { $yvname delete } # catch { $wvname delete } vector $xvname $yvname $wvname if {$xvname == "xvector1"} { $xvname append 0 } else { xvector1 variable thisVec $xvname append $thisVec(end) } $yvname append [random $max $min] $wvname append 0 catch {.sc element delete $name} .sc element create $name -x $xvname -y $yvname -color $color if { $name != "default" } { .sc axis create $name -title $name \ -limitscolor $color -limitsformat "%4.4g" -titlecolor ${color} .sc element configure $name -mapy $name global useAxes lappend useAxes $name set count 0 if 1 { set yUse {} set y2Use {} foreach axis $useAxes { if { $count & 1 } { lappend yUse $axis .sc axis configure $axis -rotate 90 } else { lappend y2Use $axis .sc axis configure $axis -rotate -90 } incr count } .sc y2axis use $y2Use .sc yaxis use $yUse } else { .sc yaxis use $useAxes } } set cwin .sources.choices.rb$unique radiobutton $cwin -text $name \ -variable choices -value $win -command " foreach w \[pack slaves .sources.nb\] { pack forget \$w } pack $win -fill both " pack $cwin -anchor w frame $win pack $win -fill x label $win.limsl -text "Limits:" entry $win.lims bind $win.lims " .sc yaxis configure -limits {%%g} " label $win.smoothl -text "Smooth:" frame $win.smooth radiobutton $win.smooth.linear -text "Linear" \ -variable smooth -value linear -command " .sc element configure $name -smooth linear " pack $win.smooth.linear -side left radiobutton $win.smooth.step -text "Step" \ -variable smooth -value step -command " .sc element configure $name -smooth step " pack $win.smooth.step -side left radiobutton $win.smooth.natural -text "Natural" \ -variable smooth -value natural -command " .sc element configure $name -smooth natural " pack $win.smooth.natural -side left label $win.ratel -text "Sampling Rate:" scale $win.rate -orient horizontal -from 10 -to 1000 table $win \ $win.smoothl 0,0 -anchor e \ $win.smooth 0,1 -fill x -padx 4 \ $win.limsl 1,0 -anchor e \ $win.lims 1,1 -fill x -padx 4 \ $win.ratel 2,0 -anchor e \ $win.rate 2,1 -fill x -padx 2 if {$unique != 1} { button $win.del -text "Delete" -command [list source_delete $name] pack $win.del -anchor w table $win $win.del 3,1 -anchor e -padx 4 -pady 4 } $win.rate set 100 catch {$win.smooth.[.sc element cget $name -smooth] invoke} mesg set sources($name-choice) $cwin set sources($name-controls) $win set sources($name-stream) [after 100 [list source_event $name 100]] set sources($name-x) $xvname set sources($name-y) $yvname set sources($name-w) $wvname set sources($name-max) $max set sources($name-min) $min set sources($name-steady) [random $max $min] $cwin invoke } proc source_delete {name} { global sources after cancel $sources($name-stream) destroy $sources($name-choice) destroy $sources($name-controls) unset sources($name-controls) set first [lindex [pack slaves .sources.choices] 0] $first invoke } proc source_event {name delay} { global sources set xv $sources($name-x) set yv $sources($name-y) set wv $sources($name-w) global $xv $yv $wv $xv variable x set x(++end) [expr $x(end) + 0.001 * $delay] $yv variable y if {[random] > 0.97} { set y(++end) [random $sources($name-max) $sources($name-min)] } else { set y(++end) [expr $y(end)+0.1*($sources($name-steady)-$y(end))] } set val [random] if {$val > 0.95} { $wv append 2 } elseif {$val > 0.8} { $wv append 1 } else { $wv append 0 } #$wv notify now if { [$xv length] > 100 } { $xv delete 0 $yv delete 0 $wv delete 0 } update set win $sources($name-controls) set delay [$win.rate get] set sources($name-stream) [after $delay [list source_event $name $delay]] } # ---------------------------------------------------------------------- frame .mbar -borderwidth 2 -relief raised pack .mbar -fill x menubutton .mbar.main -text "Main" -menu .mbar.main.m pack .mbar.main -side left -padx 4 menu .mbar.main.m .mbar.main.m add command -label "Add Source..." -command { set x [expr [winfo rootx .]+50] set y [expr [winfo rooty .]+50] wm geometry .addSource +$x+$y wm deiconify .addSource } .mbar.main.m add separator .mbar.main.m add command -label "Quit" -command exit menubutton .mbar.prefs -text "Preferences" -menu .mbar.prefs.m pack .mbar.prefs -side left -padx 4 menu .mbar.prefs.m .mbar.prefs.m add cascade -label "Warning Symbol" -menu .mbar.prefs.m.wm menu .mbar.prefs.m.wm .mbar.prefs.m add cascade -label "Error Symbol" -menu .mbar.prefs.m.em menu .mbar.prefs.m.em foreach sym {square circle diamond plus cross triangle} { .mbar.prefs.m.wm add radiobutton -label $sym \ -variable warningsym -value $sym \ -command {.sc pen configure "warning" -symbol $warningsym} .mbar.prefs.m.em add radiobutton -label $sym \ -variable errorsym -value $sym \ -command {.sc pen configure "error" -symbol $errorsym} } catch {.mbar.prefs.m.wm invoke "circle"} catch {.mbar.prefs.m.em invoke "cross"} # ---------------------------------------------------------------------- stripchart .sc -title "Stripchart" pack .sc -expand yes -fill both .sc xaxis configure -title "Time (s)" -autorange 2.0 -shiftby 0.5 .sc yaxis configure -title "Samples" frame .sources frame .sources.nb -borderwidth 2 -relief sunken label .sources.title -text "Sources:" frame .sources.choices -borderwidth 2 -relief groove if 0 { pack .sources -fill x -padx 10 -pady 4 pack .sources.nb -side right -expand yes -fill both -padx 4 -pady 4 pack .sources.title -side top -anchor w -padx 4 pack .sources.choices -expand yes -fill both -padx 4 -pady 4 } source_create default red 0 10 source_create temp blue3 0 10 source_create pressure green3 0 200 source_create volume orange3 0 1020 source_create power yellow3 0 0.01999 source_create work magenta3 0 10 Blt_ZoomStack .sc .sc axis bind Y { set axis [%W axis get current] set detail [%W axis get detail] if { $detail == "line" } { %W axis configure $axis -background grey } } .sc axis bind Y { set axis [%W axis get current] %W axis configure $axis -background "" } .sc axis bind Y { set axis [%W axis get current] # scan [%W axis limits $axis] "%%g %%g" min max # set min [expr $min + (($max - $min) * 0.1)] # set max [expr $max - (($max - $min) * 0.1)] # %W axis configure $axis -min $min -max $max %W axis configure $axis -logscale yes } .sc axis bind Y { set axis [%W axis get current] # %W axis configure $axis -min {} -max {} %W axis configure $axis -logscale no } blt-2.4z.orig/demos/tabnotebook1.tcl0100755000175000017500000000473707240160072016163 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl # Create a tabnotebook widget. tabnotebook .tnb # The notebook is initially empty. Insert tabs (pages) into the notebook. foreach label { First Second Third Fourth } { .tnb insert end -text $label } # Tabs are referred to by their index. Tab indices can be one of the # following: # # number Position of tab the notebook's list of tabs. # @x,y Tab closest to the specified X-Y screen coordinates. # "active" Tab currently under the mouse pointer. # "focus" Tab that has focus. # "select" The currently selected tab. # "right" Next tab from "focus". # "left" Previous tab from "focus". # "up" Next tab from "focus". # "down" Previous tab from "focus". # "end" Last tab in list. # string Tab identifier. The "insert" operation returns # a unique identifier for the new tab (e.g. "tab0"). # This ID is valid for the life of the tab, even if # the tabs are moved or reordered. # Each tab has a text label and an optional Tk image. set image [image create photo -file ./images/mini-book1.gif] .tnb tab configure 0 -image $image # # How to embed a widget into a page. # # 1. The widget must be a child of the tabnotebook. set image [image create photo -file ./images/blt98.gif] label .tnb.label -image $image -relief sunken -bd 2 # 2. Use the -window option to embed the widget. .tnb tab configure 0 -window .tnb.label # The tearoff perforation, displayed on the selected tab, is # controlled by the tabnotebook's -tearoff option. # # If you don't want tearoff pages, configure -tearoff to "no". .tnb configure -tearoff yes table . \ 0,0 .tnb -fill both focus .tnb blt-2.4z.orig/demos/tabnotebook2.tcl0100755000175000017500000000417007433613270016162 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl image create photo bgTile -file ./images/smblue_rock.gif image create photo label1 -file ./images/mini-book1.gif image create photo label2 -file ./images/mini-book2.gif image create photo testImage -file ./images/txtrflag.gif scrollbar .s -command { .t view } -orient horizontal tabnotebook .t \ -relief sunken -bd 2 \ -textside right \ -samewidth yes -tiers 2 -slant right \ -scrollcommand { .s set } \ -tile bgTile label .t.l -image testImage set attributes { graph1 "Graph \#1" red .t.graph1 graph2 "Graph \#2" green .t.graph2 graph3 "Graph \#3" cyan .t.graph3 graph5 "Graph \#5" yellow .t.graph5 graph6 one orange .t.l } foreach { entry label color window } $attributes { .t insert end -text $label -fill both } foreach label { there bunky another test of a widget } { set id [.t insert end -text $label] } set img [image create photo -file ./images/blt98.gif] .t tab configure $id -image label2 -tile $img table . \ .t 0,0 -fill both \ .s 1,0 -fill x table configure . r1 -resize none set index 0 foreach file { graph1 graph2 graph3 graph5 } { namespace eval $file { set graph [graph .t.$file] source scripts/$file.tcl .t tab configure $index -window $graph incr index } } blt-2.4z.orig/demos/tabnotebook3.tcl0100755000175000017500000002000307433613270016154 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl #bltdebug 100 image create photo label1 -file ./images/mini-book1.gif image create photo label2 -file ./images/mini-book2.gif image create photo testImage -file ./images/txtrflag.gif tabnotebook .tnb \ -textside right \ -slant both \ -side right \ -samewidth yes \ -highlightcolor yellow \ -tiers 5 \ -scrollcommand { .s set } \ -scrollincrement 1 label .tnb.l -image testImage set attributes { "Graph \#1" pink "Graph \#2" lightblue "Graph \#3" orange "Graph \#5" yellow "Barchart \#2" green } foreach { label color } $attributes { .tnb insert end -text $label \ -selectbackground ${color}3 \ -background ${color}3 \ -activebackground ${color}2 } .tnb insert end -selectbackground salmon2 -background salmon3 \ -selectbackground salmon3 -activebackground salmon2 -window .tnb.l set tabLabels { Aarhus Aaron Ababa aback abaft abandon abandoned abandoning abandonment abandons abase abased abasement abasements abases abash abashed abashes abashing abasing abate abated abatement abatements abater abates abating Abba abbe abbey abbeys abbot abbots Abbott abbreviate abbreviated abbreviates abbreviating abbreviation abbreviations Abby abdomen abdomens abdominal abduct abducted abduction abductions abductor abductors abducts Abe abed Abel Abelian Abelson Aberdeen Abernathy aberrant aberration aberrations abet abets abetted abetter abetting abeyance abhor abhorred abhorrent abhorrer abhorring abhors abide abided abides abiding Abidjan Abigail Abilene abilities ability abject abjection abjections abjectly abjectness abjure abjured abjures abjuring ablate ablated ablates ablating ablation ablative ablaze able abler ablest ably Abner abnormal abnormalities abnormality abnormally Abo aboard abode abodes abolish abolished abolisher abolishers abolishes abolishing abolishment abolishments abolition abolitionist abolitionists abominable abominate aboriginal aborigine aborigines abort aborted aborting abortion abortions abortive abortively aborts Abos abound abounded abounding abounds about above aboveboard aboveground abovementioned abrade abraded abrades abrading Abraham Abram Abrams Abramson abrasion abrasions abrasive abreaction abreactions abreast abridge abridged abridges abridging abridgment abroad abrogate abrogated abrogates abrogating abrupt abruptly abruptness abscess abscessed abscesses abscissa abscissas abscond absconded absconding absconds absence absences absent absented absentee absenteeism absentees absentia absenting absently absentminded absents absinthe absolute absolutely absoluteness absolutes absolution absolve absolved absolves absolving absorb absorbed absorbency absorbent absorber absorbing absorbs absorption absorptions absorptive abstain abstained abstainer abstaining abstains abstention abstentions abstinence abstract abstracted abstracting abstraction abstractionism abstractionist abstractions abstractly abstractness abstractor abstractors abstracts abstruse abstruseness absurd absurdities absurdity absurdly Abu abundance abundant abundantly abuse abused abuses abusing abusive abut abutment abuts abutted abutter abutters abutting abysmal abysmally abyss abysses Abyssinia Abyssinian Abyssinians acacia academia academic academically academics academies academy Acadia Acapulco accede acceded accedes accelerate accelerated accelerates accelerating acceleration accelerations accelerator accelerators accelerometer accelerometers accent accented accenting accents accentual accentuate accentuated accentuates accentuating accentuation accept acceptability acceptable acceptably acceptance acceptances accepted accepter accepters accepting acceptor acceptors accepts access accessed accesses accessibility accessible accessibly accessing accession accessions accessories accessors accessory accident accidental accidentally accidently accidents acclaim acclaimed acclaiming acclaims acclamation acclimate acclimated acclimates acclimating acclimatization acclimatized accolade accolades accommodate accommodated accommodates accommodating accommodation accommodations accompanied accompanies accompaniment accompaniments accompanist accompanists accompany accompanying accomplice accomplices accomplish accomplished accomplisher accomplishers accomplishes accomplishing accomplishment accomplishments accord accordance accorded accorder accorders according accordingly accordion accordions accords accost accosted accosting accosts account accountability accountable accountably accountancy accountant accountants accounted accounting accounts Accra accredit accreditation accreditations accredited accretion accretions accrue accrued accrues accruing acculturate acculturated acculturates acculturating acculturation accumulate accumulated accumulates accumulating accumulation accumulations accumulator accumulators accuracies accuracy accurate accurately accurateness accursed accusal accusation accusations accusative accuse accused accuser accuses accusing accusingly accustom accustomed accustoming accustoms ace aces acetate acetone acetylene Achaean Achaeans ache ached aches achievable achieve achieved achievement achievements achiever achievers achieves achieving Achilles aching acid acidic acidities acidity acidly acids acidulous Ackerman Ackley acknowledge acknowledgeable acknowledged acknowledgement acknowledgements acknowledger acknowledgers acknowledges acknowledging acknowledgment acknowledgments acme acne acolyte acolytes acorn acorns acoustic acoustical acoustically acoustician acoustics acquaint acquaintance acquaintances acquainted acquainting acquaints acquiesce acquiesced acquiescence acquiescent acquiesces acquiescing acquirable acquire acquired acquires acquiring acquisition acquisitions } for { set i 0 } { $i < 500 } { incr i } { .tnb insert end -text [lindex $tabLabels $i] -state normal } scrollbar .s -command { .tnb view } -orient horizontal radiobutton .left -text "Left" -variable side -value "left" \ -command { .tnb configure -side $side -rotate 90 } radiobutton .right -text "Right" -variable side -value "right" \ -command { .tnb configure -side $side -rotate 270 } radiobutton .top -text "Top" -variable side -value "top" \ -command { .tnb configure -side $side -rotate 0 } radiobutton .bottom -text "Bottom" -variable side -value "bottom" \ -command { .tnb configure -side $side -rotate 0 } table . \ .tnb 0,0 -fill both -cspan 2 \ .s 1,0 -fill x -cspan 2 \ .top 2,0 -cspan 2 \ .left 3,0 \ .right 3,1 \ .bottom 4,0 -cspan 2 table configure . r1 r3 r4 r2 -resize none focus .tnb .tnb focus 0 set filecount 0 foreach file { graph1 graph2 graph3 graph5 barchart2 } { namespace eval $file { if { [string match graph* $file] } { set graph [graph .tnb.$file] } else { set graph [barchart .tnb.$file] } source scripts/$file.tcl .tnb tab configure $filecount -window $graph -fill both incr filecount } } .top invoke blt-2.4z.orig/demos/tabset1.tcl0100755000175000017500000000304607240160072015126 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl image create photo bgTile -file ./images/chalk.gif image create photo label1 -file ./images/mini-book1.gif image create photo label2 -file ./images/mini-book2.gif tabset .t -relief raised \ -activebackground yellow \ -bg red -borderwidth 0 -highlightthickness 0 \ -scrollcommand { .s set } \ -width 3i #option add *iPadX 4 #option add *iPadY 2 .t insert end First \ -image label1 \ -anchor center \ -selectbackground darkolivegreen2 \ Again Next another test of \ a -image label2 widget scrollbar .s -command { .t view } -orient horizontal table . \ .t 0,0 -fill both \ .s 1,0 -fill x table configure . r1 -resize none focus .t blt-2.4z.orig/demos/tabset2.tcl0100755000175000017500000000404707433613270015140 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl image create photo bgTile -file ./images/smblue_rock.gif image create photo label1 -file ./images/mini-book1.gif image create photo label2 -file ./images/mini-book2.gif image create photo testImage -file ./images/txtrflag.gif scrollbar .s -command { .t view } -orient horizontal tabset .t \ -relief flat \ -bd 2 \ -textside right \ -samewidth yes \ -tiers 2 \ -slant right \ -scrollcommand { .s set } \ -tile bgTile \ -scrollincrement 1 -selectforeground green2 label .t.l -image testImage set attributes { graph1 "Graph \#1" red .t.graph1 graph2 "Graph \#2" green .t.graph2 graph3 "Graph \#3" cyan .t.graph3 graph5 "Graph \#5" yellow .t.graph5 graph6 one orange .t.l } foreach { entry label color window } $attributes { .t insert end $entry -text $label -fill both } .t insert end \ there bunky another test of \ a -image label2 widget table . \ .t 0,0 -fill both \ .s 1,0 -fill x table configure . r1 -resize none foreach file { graph1 graph2 graph3 graph5 } { namespace eval $file { set graph [graph .t.$file] source scripts/$file.tcl .t tab configure $file -window $graph } } blt-2.4z.orig/demos/tabset3.tcl0100755000175000017500000002024207433613270015134 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl #bltdebug 100 image create photo label1 -file ./images/mini-book1.gif image create photo label2 -file ./images/mini-book2.gif image create photo testImage -file ./images/txtrflag.gif tabset .t \ -textside right \ -slant both \ -side right \ -samewidth yes \ -highlightcolor yellow \ -tiers 5 \ -scrollcommand { .s set } \ -scrollincrement 1 label .t.l -image testImage #option add *Tabset.Tab.font -*-helvetica-bold-r-*-*-12-*-*-*-*-*-*-* #option add *Tabset.Tab.fill both set attributes { graph1 "Graph \#1" pink graph2 "Graph \#2" lightblue graph3 "Graph \#3" orange graph5 "Graph \#5" yellow barchart2 "Barchart \#2" green } foreach { name label color } $attributes { .t insert end $name -text $label \ -selectbackground ${color}3 \ -background ${color}3 \ -activebackground ${color}2 } .t insert end Image -selectbackground salmon2 -background salmon3 \ -selectbackground salmon3 -activebackground salmon2 -window .t.l set tabLabels { Aarhus Aaron Ababa aback abaft abandon abandoned abandoning abandonment abandons abase abased abasement abasements abases abash abashed abashes abashing abasing abate abated abatement abatements abater abates abating Abba abbe abbey abbeys abbot abbots Abbott abbreviate abbreviated abbreviates abbreviating abbreviation abbreviations Abby abdomen abdomens abdominal abduct abducted abduction abductions abductor abductors abducts Abe abed Abel Abelian Abelson Aberdeen Abernathy aberrant aberration aberrations abet abets abetted abetter abetting abeyance abhor abhorred abhorrent abhorrer abhorring abhors abide abided abides abiding Abidjan Abigail Abilene abilities ability abject abjection abjections abjectly abjectness abjure abjured abjures abjuring ablate ablated ablates ablating ablation ablative ablaze able abler ablest ably Abner abnormal abnormalities abnormality abnormally Abo aboard abode abodes abolish abolished abolisher abolishers abolishes abolishing abolishment abolishments abolition abolitionist abolitionists abominable abominate aboriginal aborigine aborigines abort aborted aborting abortion abortions abortive abortively aborts Abos abound abounded abounding abounds about above aboveboard aboveground abovementioned abrade abraded abrades abrading Abraham Abram Abrams Abramson abrasion abrasions abrasive abreaction abreactions abreast abridge abridged abridges abridging abridgment abroad abrogate abrogated abrogates abrogating abrupt abruptly abruptness abscess abscessed abscesses abscissa abscissas abscond absconded absconding absconds absence absences absent absented absentee absenteeism absentees absentia absenting absently absentminded absents absinthe absolute absolutely absoluteness absolutes absolution absolve absolved absolves absolving absorb absorbed absorbency absorbent absorber absorbing absorbs absorption absorptions absorptive abstain abstained abstainer abstaining abstains abstention abstentions abstinence abstract abstracted abstracting abstraction abstractionism abstractionist abstractions abstractly abstractness abstractor abstractors abstracts abstruse abstruseness absurd absurdities absurdity absurdly Abu abundance abundant abundantly abuse abused abuses abusing abusive abut abutment abuts abutted abutter abutters abutting abysmal abysmally abyss abysses Abyssinia Abyssinian Abyssinians acacia academia academic academically academics academies academy Acadia Acapulco accede acceded accedes accelerate accelerated accelerates accelerating acceleration accelerations accelerator accelerators accelerometer accelerometers accent accented accenting accents accentual accentuate accentuated accentuates accentuating accentuation accept acceptability acceptable acceptably acceptance acceptances accepted accepter accepters accepting acceptor acceptors accepts access accessed accesses accessibility accessible accessibly accessing accession accessions accessories accessors accessory accident accidental accidentally accidently accidents acclaim acclaimed acclaiming acclaims acclamation acclimate acclimated acclimates acclimating acclimatization acclimatized accolade accolades accommodate accommodated accommodates accommodating accommodation accommodations accompanied accompanies accompaniment accompaniments accompanist accompanists accompany accompanying accomplice accomplices accomplish accomplished accomplisher accomplishers accomplishes accomplishing accomplishment accomplishments accord accordance accorded accorder accorders according accordingly accordion accordions accords accost accosted accosting accosts account accountability accountable accountably accountancy accountant accountants accounted accounting accounts Accra accredit accreditation accreditations accredited accretion accretions accrue accrued accrues accruing acculturate acculturated acculturates acculturating acculturation accumulate accumulated accumulates accumulating accumulation accumulations accumulator accumulators accuracies accuracy accurate accurately accurateness accursed accusal accusation accusations accusative accuse accused accuser accuses accusing accusingly accustom accustomed accustoming accustoms ace aces acetate acetone acetylene Achaean Achaeans ache ached aches achievable achieve achieved achievement achievements achiever achievers achieves achieving Achilles aching acid acidic acidities acidity acidly acids acidulous Ackerman Ackley acknowledge acknowledgeable acknowledged acknowledgement acknowledgements acknowledger acknowledgers acknowledges acknowledging acknowledgment acknowledgments acme acne acolyte acolytes acorn acorns acoustic acoustical acoustically acoustician acoustics acquaint acquaintance acquaintances acquainted acquainting acquaints acquiesce acquiesced acquiescence acquiescent acquiesces acquiescing acquirable acquire acquired acquires acquiring acquisition acquisitions } for { set i 0 } { $i < 500 } { incr i } { .t insert end [lindex $tabLabels $i] -state normal } scrollbar .s -command { .t view } -orient horizontal radiobutton .left -text "Left" -variable side -value "left" \ -command { .t configure -side $side -rotate 90 } radiobutton .right -text "Right" -variable side -value "right" \ -command { .t configure -side $side -rotate 270 } radiobutton .top -text "Top" -variable side -value "top" \ -command { .t configure -side $side -rotate 0 } radiobutton .bottom -text "Bottom" -variable side -value "bottom" \ -command { .t configure -side $side -rotate 0 } table . \ .t 0,0 -fill both -cspan 2 \ .s 1,0 -fill x -cspan 2 \ .top 2,0 -cspan 2 \ .left 3,0 \ .right 3,1 \ .bottom 4,0 -cspan 2 table configure . r1 r3 r4 r2 -resize none focus .t .t focus 0 after 3000 { .t move 0 after 3 .t tab configure [.t get 3] -state disabled } foreach file { graph1 graph2 graph3 graph5 barchart2 } { namespace eval $file { if { [string match graph* $file] } { set graph [graph .t.$file] } else { set graph [barchart .t.$file] } source scripts/$file.tcl .t tab configure $file -window $graph -fill both } } .top invoke blt-2.4z.orig/demos/tabset4.tcl0100755000175000017500000000516307446744102015145 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl #bltdebug 100 source scripts/stipples.tcl tabset .t \ -samewidth yes \ -side left \ -textside bottom \ -textside top \ -bg red \ -tiers 1 \ -scrollincrement 10 \ -scrollcommand { .s set } \ -rotate 0 \ -selectcommand { MakePhoto %W %n } scrollbar .s -command { .t view } -orient horizontal option clear option add *Tabset.Tab.font -*-helvetica-bold-r-*-*-10-*-*-*-*-*-*-* set files [glob ./images/*.gif] set files [lsort $files] #set vertFilter sinc #set horzFilter sinc set vertFilter none set horzFilter none proc ResizePhoto { src dest maxSize } { set maxSize [winfo fpixels . $maxSize] set w [image width $src] set h [image height $src] set sw [expr double($maxSize) / $w] set sh [expr double($maxSize) / $h] set s [expr min($sw, $sh)] set w [expr round($s * $w)] set h [expr round($s * $h)] $dest configure -width $w -height $h global horzFilter vertFilter winop resample $src $dest $horzFilter $vertFilter } image create photo src image create photo dest label .t.label -image dest -bg purple proc MakePhoto { w name } { set file ./images/$name.gif src configure -file $file set width [$w tab pagewidth] set height [$w tab pageheight] if { $width < $height } { ResizePhoto src dest $width } else { ResizePhoto src dest $height } .t tab dockall .t tab configure $name -window .t.label -padx 4m -pady 4m -fill both } table . \ .t 0,0 -fill both \ .s 1,0 -fill x table configure . r1 -resize none focus .t foreach f $files { src configure -file $f set f [file tail [file root $f]] set thumb [image create photo] ResizePhoto src $thumb 0.5i .t insert end $f -image $thumb -fill both } .t focus 0 .t invoke 0 blt-2.4z.orig/demos/tour.tcl0100755000175000017500000001164307240160072014556 0ustar dokodoko#!../src/bltwish #package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl option add *Scrollbar.relief flat set oldLabel "dummy" proc RunDemo { program } { if { ![file executable $program] } { return } set cmd [list $program -name "demo:$program" -geom -4000-4000] global programInfo if { [info exists programInfo(lastProgram)] } { set programInfo($programInfo(lastProgram)) 0 } eval bgexec programInfo($program) $cmd & set programInfo(lastProgram) $program puts stderr [.top.tab.f1 search -name demo:$program] .top.tab.f1 configure -name demo:$program } frame .top hierbox .top.hier -separator "." -xscrollincrement 1 \ -yscrollcommand { .top.yscroll set } -xscrollcommand { .top.xscroll set } \ -selectcommand { set index [.top.hier curselection] set label [.top.hier entry cget $index -label] .top.title configure -text $label .top.tab tab configure Example -window .top.tab.f1 if { $label != $oldLabel } { RunDemo $label } } scrollbar .top.yscroll -command { .top.hier yview } scrollbar .top.xscroll -command { .top.hier xview } -orient horizontal label .top.mesg -relief groove -borderwidth 2 label .top.title -text "Synopsis" -highlightthickness 0 tabset .top.tab -side bottom -relief flat -bd 0 -highlightthickness 0 \ -pageheight 4i .top.tab insert end \ "Example" \ "See Code" \ "Manual" set pics /DOS/f/gah/Pics set pics /home/gah/Pics image create photo dummy -file $pics/Ex1.gif image create photo graph.img -width 50 -height 50 winop resample dummy graph.img box box image create photo dummy -file $pics/Ex11.gif image create photo barchart.img -width 50 -height 50 winop resample dummy barchart.img box box .top.hier entry configure root -label "BLT" .top.hier insert end \ "Plotting" \ "Plotting.graph" \ "Plotting.graph.graph" \ "Plotting.graph.graph2" \ "Plotting.graph.graph3" \ "Plotting.graph.graph4" \ "Plotting.graph.graph5" \ "Plotting.graph.graph6" \ "Plotting.barchart" \ "Plotting.barchart.barchart1" \ "Plotting.barchart.barchart2" \ "Plotting.barchart.barchart3" \ "Plotting.barchart.barchart4" \ "Plotting.barchart.barchart5" \ "Plotting.stripchart" \ "Plotting.vector" \ "Composition" \ "Composition.htext" \ "Composition.table" \ "Composition.tabset" \ "Composition.hierbox" \ "Miscellaneous" \ "Miscellaneous.busy" \ "Miscellaneous.bgexec" \ "Miscellaneous.watch" \ "Miscellaneous.bltdebug" .top.hier open -r root .top.hier entry configure root -labelfont *-helvetica*-bold-r-*-18-* \ -labelcolor red -labelshadow red3 .top.hier entry configure "Plotting" "Composition" "Miscellaneous" \ -labelfont *-helvetica*-bold-r-*-14-* \ -labelcolor blue4 -labelshadow blue2 .top.hier entry configure "Plotting.graph" \ -labelfont *-helvetica*-bold-r-*-14-* -label "X-Y Graph" .top.hier entry configure "Plotting.barchart" \ -labelfont *-helvetica*-bold-r-*-14-* -label "Bar Chart" .top.hier entry configure "Plotting.stripchart" \ -labelfont *-helvetica*-bold-r-*-14-* -label "X-Y Graph" .top.hier entry configure "Plotting.stripchart" \ -labelfont *-helvetica*-bold-r-*-14-* -label "Strip Chart" .top.hier entry configure "Plotting.graph" -icon graph.img .top.hier entry configure "Plotting.barchart" -icon barchart.img table .top \ 0,0 .top.hier -fill both -rspan 2 \ 0,1 .top.yscroll -fill y -rspan 2 \ 0,2 .top.mesg -padx 2 -pady { 8 2 } -fill both \ 0,2 .top.title -anchor nw -padx { 8 8 } \ 1,2 .top.tab -fill both -rspan 2 \ 2,0 .top.xscroll -fill x table configure .top c1 r2 -resize none table configure .top c0 -width { 3i {} } table configure .top c2 -width { 4i {} } table . \ .top -fill both proc DoExit { code } { global progStatus set progStatus 1 exit $code } container .top.tab.f1 -relief raised -bd 2 -takefocus 0 .top.tab tab configure Example -window .top.tab.f1 if 1 { set cmd "xterm -fn fixed -geom +4000+4000" eval bgexec programInfo(xterm) $cmd & set programInfo(lastProgram) xterm .top.tab.f1 configure -command $cmd } wm protocol . WM_DELETE_WINDOW { destroy . } blt-2.4z.orig/demos/treeview1.tcl0100755000175000017500000001304407515130066015502 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl proc SortColumn { column } { set old [.t sort cget -column] set decreasing 0 if { "$old" == "$column" } { set decreasing [.t sort cget -decreasing] set decreasing [expr !$decreasing] } .t sort configure -decreasing $decreasing -column $column -mode integer if { ![.t cget -flat] } { .t configure -flat yes } .t sort auto yes blt::busy hold .t update blt::busy release .t } proc FormatSize { size } { set string "" while { $size > 0 } { set rem [expr $size % 1000] set size [expr $size / 1000] if { $size > 0 } { set rem [format "%03d" $rem] } if { $string != "" } { set string "$rem,$string" } else { set string "$rem" } } return $string } array set modes { 0 --- 1 --x 2 -w- 3 -wx 4 r-- 5 r-x 6 rw- 7 rwx } proc FormatMode { mode } { global modes set mode [format %o [expr $mode & 07777]] set owner $modes([string index $mode 0]) set group $modes([string index $mode 1]) set world $modes([string index $mode 2]) return "${owner}${group}${world}" } proc Find { tree parent dir } { global count set saved [pwd] cd $dir foreach f [glob -nocomplain *] { set name [file tail $f] if { [catch { file stat $f info }] != 0 } { set node [$tree insert $parent -label $name] } else { if { $info(type) == "file" } { set info(type) [list @blt::tv::normalOpenFolder $name] } else { set info(type) "" } set info(mtime) [clock format $info(mtime) -format "%b %d, %Y"] set info(atime) [clock format $info(atime) -format "%b %d, %Y"] set info(ctime) [clock format $info(ctime) -format "%b %d, %Y"] set info(size) [FormatSize $info(size)] set info(mode) [FormatMode $info(mode)] set node [$tree insert $parent -label $name -data [array get info]] } incr count if { [file type $f] == "directory" } { Find $tree $node $f } } cd $saved } proc GetAbsolutePath { dir } { set saved [pwd] cd $dir set path [pwd] cd $saved return $path } option add *TreeView.focusOutSelectForeground white option add *TreeView.focusOutSelectBackground grey80 #option add *TreeView.Button.activeBackground pink option add *TreeView.Button.activeForeground red2 option add *TreeView.Button.background grey95 option add *TreeView.Column.background grey90 option add *TreeView.CheckBoxStyle.activeBackground white if 0 { option add *TreeView.Column.titleFont { Helvetica 12 bold } option add *TreeView.text.font { Helvetica 12 } option add *TreeView.CheckBoxStyle.font { Courier 10 } option add *TreeView.ComboBoxStyle.font { Helvetica 20 } option add *TreeView.TextBoxStyle.font { Times 34 } } set top [GetAbsolutePath ..] #set top [GetAbsolutePath /home/gah] set trim "$top" set tree [tree create] treeview .t \ -width 0 \ -yscrollcommand { .vs set } \ -xscrollcommand { .hs set } \ -selectmode single \ -tree $tree .t column configure treeView -text "" #file .t column insert 0 mtime atime gid .t column insert end nlink mode type ctime uid ino size dev .t column configure uid -background \#eaeaff -relief raised .t column configure mtime -hide no -bg \#ffeaea -relief raised .t column configure size gid nlink uid ino dev -justify left -edit yes .t column configure size type -justify left -edit yes .t column configure treeView -hide no -edit no -icon blt::tv::normalOpenFolder focus .t scrollbar .vs -orient vertical -command { .t yview } scrollbar .hs -orient horizontal -command { .t xview } table . \ 0,0 .t -fill both \ 0,1 .vs -fill y \ 1,0 .hs -fill x table configure . c1 r1 -resize none set count 0 Find $tree root $top puts "$count entries" $tree find root -glob *.c -addtag "c_files" $tree find root -glob *.h -addtag "header_files" $tree find root -glob *.tcl -addtag "tcl_files" .t entry configure "c_files" -foreground green4 .t entry configure "header_files" -foreground cyan4 .t entry configure "tcl_files" -foreground red4 .t column bind all { %W configure -flat no } foreach column [.t column names] { .t column configure $column -command [list SortColumn $column] } # Create a second treeview that shares the same tree. if 0 { toplevel .top treeview .top.t2 -tree $tree -yscrollcommand { .top.sbar set } scrollbar .top.sbar -command { .top.t2 yview } pack .top.t2 -side left -expand yes -fill both pack .top.sbar -side right -fill y } #.t configure -bg #ffffed .t style checkbox check \ -onvalue 30 -offvalue "50" \ -showvalue yes .t style combobox combo \ -icon blt::tv::normalOpenFolder .t column configure uid -style combo .t column configure gid -style check blt-2.4z.orig/demos/winop1.tcl0100755000175000017500000000324107451271403015002 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl if { [ file exists ./images/sample.gif] } { set src [image create photo -file ./images/sample.gif] } else { puts stderr "no image file" exit 0 } set width [image width $src] set height [image height $src] option add *Label.font *helvetica*10* option add *Label.background white label .l0 -image $src label .header0 -text "$width x $height" label .footer0 -text "100%" . configure -bg white for { set i 2 } { $i <= 10 } { incr i } { set iw [expr $width / $i] set ih [expr $height / $i] set r [format %6g [expr 100.0 / $i]] image create photo r$i -width $iw -height $ih winop resample $src r$i sinc label .header$i -text "$iw x $ih" label .footer$i -text "$r%" label .l$i -image r$i table . \ 0,$i .header$i \ 1,$i .l$i \ 2,$i .footer$i update } blt-2.4z.orig/demos/winop2.tcl0100755000175000017500000000263507434307126015014 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl set file images/qv100.t.gif if { [file exists $file] } { set src [image create photo -file $file] } else { puts stderr "no image file" exit 0 } set width [image width $src] set height [image height $src] option add *Label.font *helvetica*10* option add *Label.background white set i 0 foreach r { 0 90 180 270 360 45 } { set dest [image create photo] winop image rotate $src $dest $r label .footer$i -text "$r degrees" label .l$i -image $dest table . \ 0,$i .l$i \ 1,$i .footer$i update incr i } blt-2.4z.orig/demos/images/0042755000175000017500000000000007553201213014323 5ustar dokodokoblt-2.4z.orig/demos/images/blt98.gif0100644000175000017500000010755707240160072015766 0ustar dokodokoGIF87aòT÷TLN´¬±  D!Š•ŠÄÌÄ´¼´ÌÔÌäìäÜäÜÔ×Ô&euc¬´«ìôëYeW+6)9E5£¥¢IY?PVLsuq‹ŒŠÀÄ»+7´¶¬ŠŽxlnX«®ŽƒlÅȦ«¬¡ÔÕËõöëäåÛìíã'(›}·¹˜–—‰`b1{}UWX@ÖØ«vwaßợ¤Ž¶·¤Íκ¸¹QQR'¢£V‹ŒX½¾y¬­oÉʆ“”lÖÕ½¼‰‡dc›š XWwwHG88¬«((¾¾*44 „„"XXcc3 qp)DD88ƒƒ?OO2mmF77(EE3aaSLLF¼¼²ÜÜÓÌÌÄ$$#,,+mk )( MLA> TL!4,4, ”ŒŠ4,+ ļ¼¼´´ÜÔÔìäääÜÜìììäääÜÜܼ¼¼´´´888 ,òTþˆHP‰Aƒ((\Ȱ!Ã.D±¢Å‹3jÌHÄJHˆ©£ DüÈr¢Â%¢\Ér%Ê3•Ìt“çÌ– &¤ðçD1:’&%Q’à@ƒ&Å ¤ $¨˜Ã˜Ô ”bG˜`5Jܱ,W bHpX ÌZ¥Nœ)5åÂ=F•üÁ+ñbC½ ó>l4.T1 +‰‹.ãÇu¡ê”:)S1ou¨Õñ ©\Ä‹…:(ŠRL˜‘$`ó'!i¢U†íWáž ÿå©w4ïÝ:€ÞÖ±Ö‰ý[ïrž owŒNT·kŸÐ©’vZš2bîÈþ> ©Y|òÏá§I©æµÜƇ»Ú{\”tß'Ù/qkŸg5Dm¶©ÔQ õ¤Sv¤Å?ü \|`,•šj¦=àh:馛t¼å5Ú]Òá•WUØ-· U âÇÓ@ì­&]‹9 RSŽ¥õ]b™#I7î7ðK÷ÄS3 „Ðbïq°_ñ1‰ ±±8 I0Q SxÈ U,¡Ä€I‡` ªØÜmJ„„â \[ZHAª©¶bEýwbuUÁI“J¤9ÇS ±5YZZí)Òx"DYbœé0_Rãw!ŸäiFÂ~ò­EÂp@láktÁÁþ`t¡ƒ[°bPA†N±£>8E_Qd…J,ñÇ< 8T1SÒDGJ$áš^1´œº‡GJ€Å 3D(á„Å]µg¤§iˆjEAN¶V.‚ÔmŽ"„Õiå-ÆÂ“’ ^R`¹)\î­§ž£‚1e‘v&ñ:ñÅi¤ÁAn‘ÐE$˜±†eè…m‘A%ÄFAmdà@Fk„‘ÅM$¡ÄIü±DQ0ÔD_,^$1ÝKa}.‰-UÔí €àîÇÄ”:Ž'•nyHUU²Í5‹r3TwPÉÝxcþRëMJic Ç–[y*ñZTRù ÇrÀn»î >øÅ†“‘†{nÙÙîæDjU…N $¢kuµå· øíDçÊ–Ñ×_ˆín»‚èãžÆvL U]Qc}Äöîí¦£í"nøRšþ®‘¥–zäpvrõ?<Ž»`ƒ½ùóËWa[G‚œýæ3à@B=:Õ_n¼¡ä¦–ÔõÅûGÒÍÖí aÇ6äâ@VꃘŸÔOxÂW¢“?­y¥5!iOߨ¢)!• uBUàÖ"1#ÙÉ|×»—>°+lc‹ªŒ¾øçz$4aú<³ž¬ˆ wtÀ æºßT%Kþª+]Kn³:ŒP  [ØŠ»ìI X™QZ°R£v$_jª›šbÂ;.Â$Aê™—S"¯Áƒu ?h='ÒécNŒÐ㢶|¡²‹\úª'1"=èƒç#!‘Få„Óè-X`ÊÂÄð1ô ø(Áž2ž`é‡ÚYr"Òð†M[š×HG%òOlbÃAIö¤žÅ?À×eYDÔuÑ+Ùv %’3Ú©H,ìžØˆFጄÈäÞ)‹€Æ WÈB¶ …Pá K˜¬ðƒ%4SØB€Ð+Ì  [X¸ð„(IU° ®@…2h! Lþà@òI†%dAW@C>PP \A ZIO˜`&pa4S¨Ê¦ ›±ç;Až0 åŸ@À…&Dè ìÊB„®„%Ì©L˜Á¦0&€LJ`Ђ¨P…'¬Å×ã@Ö²@bƒ ÃÄ 1˜M iÝhÓš(,66ÂÝû£—”Œ£IØ^ì@ºÄ"Ì{šÑb°"ÉÂÏE…ýCò•º«½Ô³_Q o¢©íÑÎNi\æÿ¾7;9Š ªÊ þ$ “ T-4ZX‚°U4¡ ?˜Â¬¹(lá YAY½ù„&XJK˜ÂD³`d ÕÂ d ƒèA%èp'LÒ [P‚Π„'„ ä!•‚šÊÞÇ,•ig`Gÿ} IžªoêR'AM˜Ü¬Km³Ñ—8ø~'²QÄ|ZÔÆŠr*»¢€Öz8±8;a@ŠÇ¯–]\Å0÷Dh=Ž g _ØÞù¢PLœ!Àƒfhº8$$ˆöf¡¾…¡4ë;Íi@œLvá DZ˜R¤TÈÀrQT‰sÜäw tÈ^mÄï¡/ÙSbþìüÇ?¨uÅ ›Rbå 2„p] øc•Èçaž¶Ù£“õøˆÚ¬k]È<ß`ñŒüÃ9 o°¢àN=ë¹YÇH58Ÿf= ÉÍíä¯.)ÒCÜò,Ãç,h%…eSa–;GåD@Cɨ"ô¿7óš$îsH›Xj)M©¾IU²éâ:~4Ï!¶°aKBEË–¨ó_Øp`g,£Gp• 7àïf¨ÊiZ$ç$h¦Ý‰ƒá¿:d$á‚é>|8E@&¹h'p3Jnˆ˜Dù$XŒ+Ò<AÏJDª³?ŠGí騉!<%!¤Án¸þGÌØ¢¶¶ÉÉ4¥5Òƒ´ |ËÛñÞ‚¤¹(DÈædÓé ÄÁGÓßËé„×sêmÔ’ªlŒ:iA 2¤»ékp³Ó‘y’Om<"õë{–¸ ç-%«/Œ}(9ûÂâêýxØ`ûžOœá›ÏÛÃòþBPs5R0Ù1¿ØƒMÂuÁ‘l¬ÞC̽@WoƒŠWwµå¨óÌ”gO:¿;Ãî¶$Û=—·ºAÄ(ê žRìHåoÜÿ÷´~^Éø…ÈÕó«lÆÇät/üâÓêGxoÏrT¡ää#ø¢ží’a'ßzœ†>áP¯Óºk¿§l¼ðþ@|Î\å8Äté?îž'ŽÜ@Òx/Aö¸Ûƒ½ŽÈÿ*fo—¿üPöµßoÜõœÌ_ÞŸ'`nÇ?"UÝ9²AlÁAo7gB(4v±Ex›CjÈ7vŽ·_r„>ÂÆz´s's©#õòngôB&%?§1,H*rflo÷Qî÷u«%ë 6.…LÖ~¹wwr†gwj—ëòLy†GfG+4htT ·gÇf¦Äz²Åut·|)×.xtG"52Ê@ðAnœzLÁAíT·{ú¦‚B>ˆL_Ç_ó1Ÿg+AD:¶KÖ€s¸a!$ggçC¨Wþ!±dngZ48l¦|‚†FdÓ~Œ%qxGçfÙ·f'ql†r‹5…•hG åS’ƒ$ˆ#jAV|¦§=Ø|BׄÆaB5ƒq'ˆƒTÄC À^qKÀ~5G®‡qìƒvOò‹ëC6b¦õl}–[0xmË·zö~¨÷lb|–z·7m÷£ø~#36¤AÒsÀôŒ¦TmäS8csˆ&[2XG·8ŒÅæn7¡‡à‚F“dZàNÈ„V3€q7^pu_'O jÎ}áX"|ZHxïÈ_2HƒáŠ·è~ã8w¨…q'r²óX’ÓB.”xço¦þLÌW‡¨a1 zr^T††ɦC.±Ñ\aP ¶í¤[ßÄIöJa4 a[Q@U™«ëÄ.Z€TMðQˆ[]†«åk<Õk2ˆ“è~;Ù‘ii‹3ˆ“ÝÈXL”’LxŠF÷Œa×fh[߃r[(—¸GÉvBY\PUP^0ZÀ$ÀP8àMH‹é0G¦ŸCL05¡'$0L¢e2^À^ \Lv¢)mÀÇS§´f©§zné~’¹éL‰›Üx“¸Y€þ•Bϧx/©¸×?c¹‘€ih5˜é#%h÷`‡éø§lN¹0Ÿþ¤:Å'ÎHjΖzøŽ}¦mK4Œ·¨zÀ¦îÇ.q —À —»©œy”BAµ(—¹9wÞxb拇rÅX)§SÖɃ¢g@äÞ)oûi‹Irïw&‰›ð —tè‘Îô›$ŽìÙ&¦„Ê7“Ù“Ù÷›ÚH‡®ˆwθ{!æNeW) a ¡&Êxƒy¸ ±6Â4”(CoŸä¹›–vGu¤rI‰FÚ›«'¤áx¡rIruiBJˆ|È÷’·“JƒÊôŠ€Ç¢—¶$”@^ã†Ø?AD_q1Ý9*x¶Ÿr©¥E*v4@žàøž[Úž8éž}Z¤þ”¨é‘¨f½¦„ œI ¡Ãô>™HØno˜P:z˜M &X LMUaQH0{Ðd€Zp&€0d-T1*pw“ÿó¤íFr3ps؈ꙖIª¤µù§l©¬ëyç9mh‹xº2ä¥ó§v†„lûá‘0±A£©óîåK°X@b‚b‚4©™_©3QP­ &1 o ·J[!©«ø(ƒ^ ˜HEr- y—û§Òç›b§žê9¬ƒÚã)wÙx{Z‰¶Yƒq€j—ˆ@vv£Bø@„pñà .¢”° ±°þ„ èBJîÙ~É‘ºz40* Mj›y*¨µ‰¬@Ûžýº›Óª¬ rÚ¬H»z˜VN)£ì³ŒJ¶v©P°p®p²\[ãPÿÀî:Õœ*Ú¡9+Ðhñï9´Ìš«ðÉ›ñi¨2´À±¶É¤¸—¢j¥õUÆ–qP9„×` ÎÐhÿP ]˵ð­` Ö:ÝrgŒ÷œÉœ2PmÀÏ`°q§¥C›rÉš¢èI±`w´Fº¥ l*z³êL(_5©A8¦ë` µ <@иÑ4§ëÐ Þbv¶{îD‹M6vDÀ0¸éþy°²{“Ȉƒú¨7+¨ÙÛ´ŽÊ½ û§Ê¥uH˜“jlN™¹à ²€!е†6&O±¼®b’rQà^$ð ƒÀÛ³*8Ð1‡Îù첓'ôAÐa#Áq÷L¥¥2Ȫ\дÊ“B+q3+´ «½+Ÿw›¬­{¨¹Ç†Ÿwçrpz²èº¿X §Ìý›h «ñAÜÿÊä NS²*Îø«RªQà5\1àÀ_7ÂXàÀZ –Œ5½j¨Ãš}P8´/Œ´g‹|ai˜›L8³†ƒÈ> „K K€P€À¤ºþ@Ì@l@\a0H€]RªîÅOÐTîZ¡9š‹,gU àÔÀ“ÙÃŒÇÁMÅÅXÅ<M°¨+Æ[Ú° ‹¤‚ ¸é™¬4‹¶ÍŠÂ€‰¹Ñ*žrlq# /Syܵl·d‹qðö -Ê~dòQ]i‰²››lU`§Úë°…Š›pk¥°K´røŽ¸.ì·†˜{T}fÆrœvì`¢T ¿|²oƒ–Jtsæ“æœp ¥Ýë°ð™¡¤«««,·ÓüÏ⹯ú(H.:‹h‹n–ŸQH@ÄÅãËëŒ&ùZÐx÷Ÿ(…>‹Ï¹ZÏ,\Æh‹¡¥+¾,œÆr µ`ºˆ xþz( ©·Ð»ÜIôÓ`®ãË)ÑÌ{=ÿÙaÿ9Gg¶ÚK¤Üë¤@ °Ërè¨oÜÊ-‡u뜼§ªèÎwöÑ:‡êƒ¿#??!72J«SÓ_TK³qD‰EÏŒ—>†ÓfÛd}›·ýÊ×ûÖ! ¸P˜ÊBq¥gƒkuf7BbIÔKš>I Ÿ´!þ‘Ò¡·¡ƒ]}?®Ãa'gMÑó|wÛ3½ž ;q žýqÙ °JÕƒ9ˆ¯Ge‘vي҈ƽYƒý±!aÄJýFqXY¤&œuÑÕ.U¦7íè“aŠÙòF³{ÖÂj³¨›ŸnþɤoLÂ?jqƒ«™ÉCøÕv‰õqƒ­=‰td?’q‹¢(¯† &D ¶/SÑÞ¶ ·ªÚ'­‚ÇL$ ½þ¼zÞØÆ›T,C%i¤«%¾‡Üì±ÝY{¯ÝƒÏL×î4d˜#74`¡“ŒèÍ"(ÂRôFÂ!rÇí`!‘±Q+€ÊfßÇæ{-ú£¥{·`l°IÍÖP:Ëåè´„ù“P©(ÀÕÔˆŠh{M–V&*G2@ùßÁ$¢Óws¨‘;eÑ2.ÀÝ-Q[µÇø”ÃÌû±."1™ðÈ4v3ŽšJz…çœ9-àIÅÙ<ƒ2£îæ0¡A¨P¿þb±&mwÖmž>Fxž·€‚;u¡r ‘;h¡‡lªIð Ák ª¹¹$0Y!]@«Jðí%^à^î*æO`ΠJp“Jà›^5¬qOcÈaª3À"Q=@[´•3ÀUÌ.ÃÞÙÓ]ÕÍÊíq´8àMj×{T!7”¼H¿ø‡5Û“iHo>÷Æiá~çM1‚é¡[ÐDópÛ¢M`_Ð2:@¾V)•®šV ‹9U©ÄïSÀ>O€”O€d`ªÀÒ-³g&î%É Cîš„bªéMU€ÌÀ8€—MYÕ“»wÜ<þ»§Û·(ŠÑ=i*qò­fªuTb¥Då„ð‘‚{­™“S¢0ïA` Z –³˜@&QÐU3T0%IÑVÀY + ’<ôXpëY¿Ÿs¡:$P™–iïK [Á–þ9dBîep$PgN†fõ^@®ÁØ3“Œ\¿.L 'Ýnò¬—ÑKã×L˜8 ÖBi·uøS6hˆ£±R¡,¦t¢¢6â¡ZQ#ÙA¹P¢1úF*,ÈÊ6ñ­ ylŸ3ðjb5o Úpu iµË¾Ló‚÷}»„ë×=hÂk¹µg•âòÕ©hsé›Aúþ&íëS`d&‰à³tgƒy#!##"ß,‰×í*ždê}:Þ£Û©øá²”¶ÿÐg iìûû½1ÙyˆDˆD‹ˆgý—ÖœÖú ¸$”8 ÐB† >Da%“$Á1ãÇ /&)X0LŠRp†5þÀ:tˆ¹ù@Œ;ž|¨„Â%aH€á„ÃJ —)ÆE¡)0¬ˆ$‰0SB|8è_(@\à00äÚ‘m’y®È©)¶ W`”– ZFÁpGÂ…ómÉQ+È‚…ì0á]£ '“„ΉžR þUH¡hF ~œ> „ƒ!Å<€Ý5Œ˜ƒ“^ez*Κhª–;ò3è«€¢`E ²+ñÈEëbQärªEIµnT¸×áTµ_Ø7qËÂ?‚Oxà¤"A7‡ïpè»J“Êå®Õ„‘“ö 5ÕÀ¸© Øvz- %¸P‰(”H‚‹)yB‰(¦Ø#‰ˆþ0鮣îÓ‚„)”˜¢‰0(x‚‹(’ð‚Â'ªªÚŠ‹O2óº®:z+Gþ& 颤2šÁ/ò [ê<%Ï+,$’$ª1J«€¼o«;é!¢È*J"Šh5z ãPA1¼`BŒ%ZÄ‹ K$þQ‰â" ÑÖX‚.HXãB½ `Š(˜£‰Ü¸hB @¸,È?®¢Qʈ( i¸þú#Ž>ªNÚT´·Ò#²H#=Âo«µV…«Êý³4JLWãÊN˜q¦LšãR * ¤MÍ`;{¢Ñ'ÌØ#/Z\–Â0ZÄ3‰=h" š MÑ?`ÐÏ'˜Œg½ãQ'«Šìžæ&#i*Ðö˜¯¿xÓÞùÍ"Ëo#_—‚+‰ÝIº¸¢ÖXk•.%žag–~6á5`­Æ´ Á:4É`Åø‚ ¢*e1>ú–óÂч¼8ΡŠÜ«¢}ìY×+æ]WÞ=•T~þK L+¹"©èì >wç…—§’¢#¾—­ü4Ma?Þé­¡\x2…ᣀh¡v޹¡{ôA€¡JXáù=)¿Æ7«ðÆ3,Iü ÂÎÝŠ¨"Z8•—fúÇ·‹2hªþ´.i'‰êñ?î• Èžh92Q;mΖYPÙÇò« }Û9£J=Ò©óœl‹ï·p$œ$¥gÚ±²-·.á)QšŠq„(ÚZ(-mˆe2b ƒŒ$^œÁ É«¸“!$4 c‰…*L^r/f$y™ãË¢ÅðY‡k9ä82$ @¸ Bì8\%M0ž˜„RãÈÖ¿L!zv’ÍþT•)Ê\v U^w»„ dRC ðèç=ýMo ãDª`†0á #L‚ô¦ð,\M0‘žš@&8ä8å’^›0T A •ÄB–ÀöByå‚_C @0¡r 1 –Ð(’ ù Ì_p À¸pE âZ"‰Nè… …A)§³‹à ¸F†ÑgvøÂÙ¦Èà(%4¡E5„¤§…6Q3€¡눕@.A áò£b…D™ˆ aa±þöG%LQ‡‰âüª`¢*2„K¨d£V…2ä dáƒ.ù-„È2¾JB¦C‘F9   C ½Ð„¼R K˜ÞþÈFbNi‚`éO”ªÃÛ4ñNp ]1¥ÙL½2 LeWL„%$ÓefüÈ/íâMoNSšå4§sðE£aJ&4é4§‡&¶`niuJˆÀ€²©u¶ž²ª?›ÉÆ€jÉŸ’]q ÙƒRS°k˜ª–óÈ`gTæáJ¨ø)Ì…þ³¢É¤”@߉Î"B¤\ôÞ{®B«Àè¤*{–Dâqí_0ÂJE9ø(FÑCid&ä“6 a jÂþѸ«2iA˜Fª~zlR—TCz› UÊŒ€˜"ä2´pYÏ:Qh”¼zav¤€ô2¯¦L $A‚5þ-¡\ÇÔ! 69B&x/ w­Â¦¸‡*¯yÉMCž°÷åÆN[p@n´É'"s2ŸiÞ:•‘e•ªVÍY¨”pA­JÕˆ ½J¹ k”ë­ðzJ¤ÑȨ¢À¶H£ð{¤^ó˜Är…!‰‘©Â$WXG=²E† a‡úÂ6RÌ£h`¨,ÄUE'Í™wŒBƒ…(3ÚÔ¼LK)ÔºÓS«åÔj'¥5xyM4ýIYHC(ì¡xÀ»Þ˜˜=2<&|K$!¹6z&6ø"ÆÑЊÀkÒ„tiERP¸ŒHG 5¤eϺ”þfJµ®A`U8Ž`æØFúÌ…†;¯I|rßþ¡ÀW«ì¨sP¢5Æ}Æ]öEÉOhs…’sÉe¶õÌsí)±gÆWjqqT*R&ŸH%XœîôÓ;Ä*Æ7ýa;àwæ„{7¥#™L4¿’|[ü&#yá ÿh«þßù¦<ÐsΕ‘SDìl1ˆO ž& ¤ ÊÀÍKwΧ¾ë 4j_Í·‹òÀVâÍDrÃËYq–sšZUñûÐöØéIÎÁ£ù˜5?P øe’ñé$Û¼&=ÕÓ²XVü"ûÓÈé ‰;ÝÌø‡7NÀrÄUú‚ñ¢ rs-M+¦˜a/q€š ¯v5ƒ#:É>ð˜®x Ã#ºVù—ÓC#'é‚x 8 l ÌAÌAñ{Š}öžðºµH‹Àh ¬+Ó·š¶Ã ŒQAop%xÐ:ë6ÐØ½MÙ²û‘`¢43ƒ§œéë "D ´ ¹Î°þ óÓ˜ìCP ˆË»ºî[Œ*Q’§ 8Ä( ¿XÃÒàÓH ÕÈ·ÕÐ7ú³  c¿ ÃCŸÛ7{C‹¥Ð¼™è¼¥°·!P4±@7k¹#BÆA9ù"¸©b¨»#(ƒú¬Ï¸;8ë©è `£·šˆ8›@ –x‰¼ºl 2@ ¥0ûè~1•Òø‚\üð3’0$ 0ƒ-*Ø‚,Ð+0ƒ5(ø‚.ø0Ø ¡õÈ<0 !¡>Ã?|³A‘H¼Rû²ªécãƒ/t#³àË;°¹Äs§Ù㸾ÓAŒ ‰;|A—ø‹4„ >lŠü 4þ/H\ÌÅø‚ÒÀ"pC˜+Ø ØèÈ‚-Ð,p‚¥ð‚/˜›Ä`‚ÄØ˜H0ùÀ´ˆA˜(Aœ ¡;s¾73‰KµŸpÄÚø1yÁ»ÖÒÄ\㙲© ¯P»”@‹{ º £¾SÄÇñI¾ ÁÉ}l ò"È‚Œ«$H (‚"ø¿ØÅ5‰/üÂÎ[žû À¼ƒtC\¤›‘´Ã£À¯ûÄDK5s·û?Mœ+Lûê tžà<|C Š“ ðJ7LÊ\ÊÜÇ~™\ÄÊ\\C¬ŒØÅ5ü>•ä>ÍKÂ\ÃþªìÅŒØG/ù˜à ÌsCÉ|‰AL’¼èŒ¦#¼D;5¡Iùê6ú¨³tS­Ã±1g³*ú aÑÒÜ<Ë#Áñ0’ÉêœKñ°J«ÄÊ«„LÍ^M0lŠ4œµÜN[üÊÔ×Hž`CÎ\ÃÚÜ<òƒ¿µxЫO`“ÀD󌘔5€Ã ûò7¯˜/%D§lªQó4¿UtP") ZTC7TK5,’ ]K«ÌÌ–ØÎ( H…<ù>òdÏ"¹ÊÌ$È‚¼E#)ÁêtC&(-ÀÊ­+Ø'¸œC(€SdÆ/ÐÁÓ#`™ ½éwQ»r¼¯rt»-ÃÉ'%À5ºþ3™ä h|ÊÕˆ_2Wš–¨J mÃìÜÎÕÌ1HÑ5,‚%Ià‚-¤ôÅ–à#@â¥P¤m-ø‚=- -0 ÍL+8Ï…Ï8\ 3°ÕˆH{3¤X“”‰5°‚& ƒ/ÈàS2x+0Ø‚/Øã±‚?X>’ˆ™49ÿœµ<'Ò 30Êð°L-R‹%ñ¥.5•B%ÓÄàN¬äЂôÐíTH ÊÒÐGÙd‚4Ø`¥_e‚X‚‚|‚@‚)rV £ÒÀÊ<åÎ…LOÓ@ÖÔøBÐIBˆ‚¥ÈÈ+HƒCB.€H°H0ƒ,2p0þp“’[ùn1BÜé8·ãJ§¹R8IÁ‰´°Î—0_" Ö@Q3Ý΋µØ1aS.¨[ô -(ƒ"X¦ÌÌ.MºJ,à‚`Ù‚¬—å‚<­.¸Å«l‚)’V$àÎÈ‚% S'(’dÝ4B¨4à-È‚4‚M¼ø+p‚4° ­Hh+8ž(°1XÐ+P‚*Ø$Ö¢3À$ЭùOM«9“ Á—Ø84Á= ]ÝØ1EQ5’MÓo5Vc-Ö05Hn\ŒÅÊh5Üóô[‚ì ªÝÅ=AØJ?è4Ìc†äº5p"þÖ(‹ ‚ ü¸Fü Ä Þù3Z›¦ÃA /QS6ܾ½NnuÜÞEM`E2ÓÎÌÅ"(S‚~`Çb˜½J.ÐaW>ÏÒNß‚±L^Ù¸ÓÆÊ%˜‚ „}påÅJ•:PÒ@ƒ6±/þÀÙBÍ’…ÓdÅñ»:1é@{£A”8ÖC¼#tÄë×C;+Â"£‘¢`fÞÕÌ\âþa>†ÏnÖèi&àÞíÝŒÞÌþ…Ϲ¼¥ÌÅŽ3è}@âí,>ˆ?ȈƒbÝJƒ<ââ5 |”˸ŒA{#jt »±7_öŒ$mÝs•å ¶ÙˆGn{݈æ½àPw.Ó‚\6$SîáŽæ îݰkeAMý Ý•Nn…Zp0#hâÐ(‚¤!€‘Ž­<ÈïÅ\†œÃÃæ9´„Êñã:odÄ’k>Þq*Vá‰Ðk:RSß3#Òqf>Žàþlþ®¦\Œ­fÇ5QþU–áeÑÒáýÐÌTeÀ•X"àá\Àn蕎èÜn¾]ÜõUˆ¼: íˆùü4ó[¶­€yÅ3á‰Ùˆ Eã´ÊÈÄðÝ‹.é ÝØÙÜØÓ.iæãÒ^ÞjÍÌ—kàU ʹŒÖÞ[-…`0­ÞNp†gø‡°0.…XðƒoUJb5^{^m M/OµîܤEt€¢óÍŠ0ÊR²k<áŠ}ñn¿Íj)ÎjµžK>Vq¬¬æ‰FY>b^o•Üõ Œ&ø»9FÎU¾¨Séœ\#(P"`YÀ•¿þÖ_5%Èè4AmÑïdQð]I4ð2´3½å–Á|²% %QVm&¿Î¦Tóí‚b(âMÏÅ)roåM TI,X•¸È!! ÊYk ­ëYh0"¹dÊFŸPê}X)tÄ­b+ï<ƒÎ‰ÓÝ7|ÁÁ°ÆãÎÀ§ÀAó "±XUb¥,uú Zôèoâ̬‚žuV,à%ÊÅÝNEV h,/¸í Y"/p¥XУÂXZìãݾXuVÇN{¶á¾ÈcUÑ'·ôгÃD æˆ}„J/ÿtÃäðNâS·qÂÀÕpšØà%í@þÞê´FñÁÀ‘HÀêð ¼°ˆ¤­0Œ×þÛ7ŒôH ‰tSñÒZä]âMÍeÅ£4D|‹‰»UÏ/μD äþ>5ÖHÜ 9j˜%‰Pï6SÝЕvàßEq­X@£¹Ž”xaß !ÁÕ‰å4o÷ËØyR!÷äÖŽþÖ’VH ÑÎe ¢¦8A$ÚœZ ö—|ü‹VÏ¢^qͤ-½› ˜ûˆw÷$\æeC ¦ÌzXš%þؑҾµÈyxú¿èõÅs°OjTë6ÌYŒ­bquðߨÆçœ›®ÔL¥—zGñ_%qè%y0W· š¸?ùŽô[íLŸgíþºŠ“+Î`®š£A¹'õ¬ wŸ'¶ðw} 0av•ŽäÌÌÎíP‰/MÓtOïMÓ ÎßZlk¢Þ­?-ÅM¿) öwR‘wáÕç´W}lô‡›fÒªÑ_ÕÖ ’{Œ~‰B˜Â}ñGú{B|q•Ì6­ÆïÛë”âíýÍùÇ÷ì^o„yû£;×ÏzÉôPΈFÁaG’„IH0T¨„%þìdñ" 2n´G£ÆˆD,I’$C >Læe’%K†!QSe„wî<E`Œ3@-Z´È?b€P:ãÇP¥‚xÇÏZ&5þJ”hQ¢3‚Ž- ”iÕ« †) ’ž¸q)ˆ¤Ys%McDªw`AƒS.LR#Æ‹-.V ò#È™J^6l³íäºvS*ä`¹0çœ9õ[¶tŒ"ª‹€øòåGÓ§¡FÕzõv^­U¿z ë;ìi´±ýÎ0ȃM1n?bܸ2ÝÍI8ä.ƒøŒÀ‚²}9fÛ¶ˆ;Nl>qÇÈ4q®…)qfä›;¦O9´Á¡dc›öZ)¬55`S´ä™Nxå…ÕO»‘X¨ùg”YÅÇVD‘w\½7™JX Bnm·VwÉQLmMä‡émx^soXŸdþp”Ñdw}æ][­§ Pc5œX_E(`j±EõÃÔr˜Ed£|®&¼§[zº(¨þþK©Õ+JF/NiÚpv¡f…vÆaæÄíAðÁW±O„áEºdpñ±Q1C.5á§D ÑÄFOx¡H1PP9Md» ƒL.4É= ëEâ€xáÆ>Nx‘àB_ÅO+öÀ>$ˆ!µ[:jtw½jÄï¾[Q(Õv—™Ô{tdÞ˜þubW)*nÕo‡Óuß üÁ¢±çR[°_½£ ½koè•Ô}8+’Ñ ÚÓE Hò]ÙÓõ}ÂÆsú?–¸f¤´$/&uù\~w¶»dJmÖ{à‰Örµó¡Š.Y;NÚc6uÑ("¡ y$q÷/Ý@E'( lüâ@ÈwàQ© kë)DÀ-Äj¿#sX’¼a‚“Òq$1¦J"0QÉMf>=)áTLÄH,x:ííÂÖxÆ?6¡½p¬cÖøG#"°?lD}‰Hev¶E,û ¤üÂÃ$ˆáKÙÛžªð¦µQJ !”ÿxʼnþ¤&=RÂäèò6*ò"S ê.³‰ÍÂŒhÄ7´w?äcÀYÝ$€@œ@ ˆÃ)PÁŠ|$F"—© ^àÖ ®é°S CÜÂÄ»9@!Ûg@ÓúI]t[$zà"™L!dUø˜ç¦†k2Ë"Kð ’ð¸pËsÓšØ2Tyä#Ь›`td¤ãÿˆ„cÜöÌq(eù –üùK€ùš Jö¨LCݤG†âà;Ï—¿‰&adÀÂKÈ…5[š¦Elq fçTLD¡9Æ,悸Çú NÅHQYËÉÚV¡ªøË3Ø{f• †c²‰þ-B²šY†R-1¥òcÌÝ&Ã#$QhŒÏ|æ’žI,iÍÉ“S™HQdd„„ +jÈ÷ /lûA6äµn<ÀØ2’³->aujwT׿þ5ÃP>$ñ‡œà"´l×GîF™¼ä,b?¦—4ΩˆªŒòÆ÷–¹P`¯,aõô¶+µ½Ç2œáX± Æ4J=qäC'#ÂHêñ0NMèdOö%2§9Yíœ\+Ñçd„1bB­tQÕŠ\„â@-¬aiüƒ Ø¡ðÖ=‡7„æ_÷$“ÃD=Ðamví ÝJ6¿þ€µ2‚祘FVd)•àÒ!ÄÌa¤«žx¢v<õõoªðë\ÁqLÖ/cþ`×m.&Y°2yÒ¦ ú÷-vqu?|Ýç4Wµ?LOu÷[I ¯6Æ\-»óÄDÑ'´2¾âhsÌÒ#«µ¾7¾¯ŽuÌR »FT.qt`! ÅØcò#XƒùƉ %C"æý:Ówеaçte‰ÒĦ ]þÀüÔçz¤FzÓ)ð‘˜ö-“í ³¬æÕ2GÎÖ…3ƒÝë.4¾õ™sÿ|]>—‡ÌÙ•QY*’?œȇ>ôIF2èÆM’ÑQ5§w¼äøzȉ…þñ¡"ç\æÑö—ÓUžrkC¼×½º:¹¤ªPGbZB»Í¤õsßmÔîv˜wÖŠr½_MZ̪Í4’§íç|Nd"‰63ªIRª>F„ݦ=É )lfç@çÜi&Ÿ e}XDWŒjLè;#^Ö€}u9ìcìšz.9OoUtÀ5k¤Ùº[·²S­n:úEJ äáóñ4;óÙQNL$æáŠJ ‘VU¨%m(ûºÉL›ôu=4Q‚ÿ’‘½¹~›×æWƒI&÷æù$ÿÐGܯË3­ô!‘Adˆ‘ÑÝH½êAD€.T¿Ú}i~V䢙ˆŸ(€‘VÈÏŠåaþm mß^çè¡x&0¥ÜÝÉHðgŠúÈÇP—¾nˆ\£˜@ †JønÚ!Qº(^ ‰H¡‚ÄDö¾sçüáX(8‘X¨#Ö¸Å;Ä“G{Öž¾{”…žºä˜9Ó{”›[hÈáíª­–Ž”¬½Å|IÄ8P‚ö‰ÁRe ”€3¨ƒ;”ÀHHB%þ4ÞcDÛÇm/pÃ/TB”ßLÂYí•j>ÐÒ àCÜÃ,X;üƒ%¸î¨áŽ-ÐÑîåß}ÜÕ àa^öàB š•U£yß¶aʼn„$°Ã:„‘Š  < Ð B€ÂˆA>tB+h¡‚Ä4<Ã3Ì–P@>@%œÀ°i†™%+èƒ>àC!¤’H¤Y£ýžþdÚœÝß¡ÙÈ%—œ\Ý’SM¡Ä)[¢­Ú›ÖšA†)ò_ŒýN¼Q-”C!¼ ”ó“<ÀŒ<€($ô€>”Û 1àDI!ÜAD€D€6<Ã1ìÀþd„hQ&°‘’Åà1›ñ…ž¼5¢þe!ŒeD\€ d àDóZâ1_ö)4¦_ÒEc**E„ž0Ö ÁùÎHD•ö •ô±#ó‘@°Ã2(ÃxSQXš)ˆ¨Ë3¼Â,ôƒ%”Vå­Zã ‚l„ýÄÙ  Ñ¡šoiÝ&˜Z˜þd›‘œàD&ªããeŸ¹µÚ’¡ ‰£Éۣͱ̈́»©›:*Á5ã›E€$À  ø6pC%ôÁt‘¤ŠÄ[ÇQ!;2„¬gr¤£ÆI'$Ò èI ¤mH#âfbjàK”Šî faFbÍÛ ¢T» ç3*º)§–=ÀR¥æJB§ÖÉÛ¸õVï½ZbÈ–3üƒ¸\éX¼9æÓþ)[éÀq‡1]»1_y’\Rba‚½4Ò'ŽIcþf~ªã^\gÙÜ«õ݌֦òùV‚Š%?nà{¬æª[Þ˜(î]ÒéH´¥B'àÃÜÂ>(Üõ% ZúœiÆÓ ñ'A‰6çPÝ%Æ%Ý“r£JŽfú•Öï=œÂ}DÇ©£M´›:‰ñ(ÂÕª¸ÜqDïe\á%fá&¡5Ž}Þ§öéŽP5écgGX‹éÃûÀE«¥à8*¡Úˆ-)™rÀQŽh¾!?2ÕFFr†å°Užº@‡êä`"Lž*»íh·©KBZ¨…%Æûèƒy@Y©•Ö‘¦$Dý]þ‚ä±™[êØ«V\D d÷yÞ$MŠ&æ‘Úð Œé…¬'¹’€즊:a4~è»)åaPd[ÒŒ„Þ‡ú£'*Ûq„‡|h V'›þ\”å€&úNè©$Ô¢àC'8ÁN›–&t~Itº+¦RR%²0(ƒ9lC ôÌ ‚LÂ*HF’Š¢‚+€¨®'©žk-ªæ£ö«Ž„)ªr ¼ui—¦—¹œ²I\ÅbÞ6î^iµfM**|äÏ)úØ=èƒ$,\“‰ÜªýlyŠýhD%Ф)PÅŤ)L–&Qm¢IŒ:0Ã2ØS!(Á TÂPBÉVhlFþêþ”(¹žèÒ‘JnîíÐj„¾áJ.'0ªÄz¥_ÚÈ;V¹©š#šº‚d¼y%E¾HLêÈý‚4|l Etcªi,`C5Ü ‘Ð H kbáªQ,^6fª…d*ðð€d€HèƒænGj†Õ)N˜ëÅéâæ©£*‡è©e˜~\'òcI¨iºÖ”fð]ï5+›+¡`«"ei:¯I8ëŠôl$X3äè ž€RÂ3¬Ã+üÃ"B%ÜC>H‚©|Ÿh¶šäƒPMBbL-’À>Nï̱ê-ƒ1ÀÁ-!Rá&Ô©çR©#-Vpزcvo.þJßB§­ºä­Rá&B.Fóáìmºäƒr¯c–&YIÀüÞ}ÙcʼnÜ<À ÔµÆÂ>àƒÖºh Î>€,VÂ>Æìn¢kŠÁ>ÄÁ¨ÑÁ>®ÃhCø@#AJÓ‰2hß%Þägnöº>À>ú¤ªyaþ¤ŸêÎ×é·1š²c6FèL<©3â±¥(ç-“-âle#4§úQÔϽQÄ\,bÔI¨ë%j„èÃ$ÜOÞ¾!ñž¡4¹›àC8\i&ˆ‚ ‘À@ä@¸@B€AÜí­%‡‹$nYFÄ?ï^¥¥«±+š"• 0©Øea²cþ¢&åï¡­›¤f?Ö„1±,°,˜iž*%XªÇj…ì ôªE#ÜCü$Ù/ÜÁ>dÀ'œ€6»*2h!äƒnîƒöU©¢!© a[Ã9$Ã:øè,[O‰Nó+ƒBÇ2 Ts[ø\ÑæÄ¦°W¦1t‰\Æ ³‘"¥Šúd¹²›ÖÕâÏ8JÞÜ{ª'K3¨Ns5ëÀ~ºq:.—cžÛ>€¥¢_Xž Âùþ°"Æ »KÅa,H¨Â:! ÜÂ3¤­ô!p(%h­÷Qš­C9HAŽ.̲4‰²4Ëþ@2¸Ã2L€„ T!þ¼ü8ü !¨‚-æÃ <->@œ6æ‡&œtfܺUp»á©zç¨Ëž+ƒÊ::›‹îp%z‹«¸†k¸Nüz³t^ sÞ2Õ¬:€Ôéf1e™9‚‰äÝà B8Lƒ6t‚t),LÂ-dŒ'à5{£&¬ôq6Ђ7ð(`± ìFmC3¤Ã4ðƒ¨H@9@`‚x‚úL$l‘¶zèáò¨6î£îpn6R"¨‚3ƒ’ñ™¦Ä]~å«!J5»9¨ ùUÌm9bSÊY_7šÚ*¡ÉgºÑ4bäa†vƒ’ §Ž9 Ô%o®w-ö˜Šºð|€þ EGUXƒ38C9üC"ÐüÂ4Xƒ4\@!ÄO(@†C%`ò$àŒ¼Z.”¾¯­î^?§æ0;ó^Ý}Ù’1á‘ × $…R\ø‘ƒ÷T;¨Q…1m`nún¶­é xÀtðu#:Š0ƒ’hXCI‘×F5Åð €À  Á”Q:ƒ2tƒê¥Âô@%H‚LM‚¿磡"Ké::*L ¯ÿãÅõ§sjðìž–XGÁ¯ãF©×ÆS„5B—è`Dß.{v¢D{®åÅÁ&)h k³FçP=^),``$#5P„€À3Bf Ž"%Ž÷*Ftˆ4bÐ_GéV·†’ƒ"À"Dtr)†ÂJ(&•ùâI[\Bo@cÀDþ'Øñ uücåÛ ŸöÊ¿8kƒü©ÓžD²; $E9)"ÕÜi¡É(q[¢_z`^Ê2ŠyÆ3üñ! ã´ˆ€{ö¾ië2ý.†0ˆé¬g~N2In”¶‡æÜ0<áãJ#4¢x±•pWJUG¨'1ŒèŒE,dá ZR˜(!Ì0:º±Z8ã©û‡'8p–Ôg°*éKG4ê–?Ø/‰º× ÿâÅbëªG¼šbfº¼«Ñ´˜šýV¹T@ÔÀì°Æ?DЕ½M%DaJdr`ŽtðC¼ gD¨Y xUíɃÐ!lÃ͸&þöƒ{äê0(TSp"wÐW¦Ÿ9Ý%9õSB:¶ÑmhÀ A”Pˆ€ŒÜÍd k?(­äsþÑW€H/üH9{e3õ®^ ˜c g³v™qqs,°Á™ôÖ·UxÀ] ˆƒ #„EàÁyS73 1jÎÙC÷…4Q1( ÅnºŒ¸Ã9 D/ÀQ LÀ¢¨„ žq„­@%*“+í¤ÄA/Ÿ’­RsN˜ ë¹Ö8.9 WþT–ÿèëPyIò€¶RYêxÖ—¿Ü,0»E™ÆtzLQ x~ â—ê  ã@> @‰6¿rõPw£3°°´5Ì~*Aí¥/¶E‰˜ÂªemµÉ`VÀ}„ö¥ '®lVÑ;à™A/œÁˆÅµar9Ų™Î0gˆŠ¶–oµÒƒRà€(x9\×8CéXF9t g$ƒÿ@ôBµ¦È+¨dÙîÊ4¨Ì z€P }èc×ÜÕ½ò¥2®lé'é¶ÁêpŒý§Rг´³ÌmÍ|[ï|Ì‚ÁtþçÄ¥& XNŠ Ô]´†¸[Ñ'Îcr± kœãC˜ð ~8ãŸD ÈÑâ=ð€ ÑPXéAbê6bäDFB©Œ?aÌ )hu.Œ€[áf>Bu%KKѳPûFÅ% }„9f&ÄfÈg (Š×*Q$ÐáÜ–™ùÛÍõ&PÃÇ(‡»ÒôiB÷¸ >˜N%b造¸ÀÁˆÍî,÷ðƒà@|´»?*A¶¢¨s­>(¿&³J@@€„1ž „Ïša”û²i>×:¥oSkÂßadáZ’’ÙÒï;o+ÜÐA´% `þ¡vÀJ‹ÀþáfàlžhŠÐM;ã#€tª„èCG’?P•3UoZÓ9Záôa.B@Ⓤ³ ÔanÀ'$e3”ä;#–á¹Â3lÕ†ï!ìaðA @;štéÜ [•äš0 R,AŒ¡àád€Ù^å²aq.a``j Ú2ÊŠBÄ ÿÚj>ЦS™®·PÌOŸ-þ°ó þ P §„˜¡àúÁðcøô·¤\v ò@€ Öƒ#ýHÒÕ9œ¡faqà”!PÁHµ3íÁ+éÁ&þ€î¡"¡ZAÇ“·ŠÓOcH2-ñg™’¡0ÀîÀ' L€T¾`›@ h > ~`á¢@ à”,µ¢%¸•ToÂ鬪å4Ö{B;×MÑTááVÕ¦$€ÑB×K‹€=TÀ{¤àéÀPIJLpLÎaÀ–Tm¡ò!PÌ!T?—XAt–WÒ¿°" $ OEH`J@ \ 8ùè)' @þ @`(a¤áv!sÅï¶Tx<·9@×’äoÌÐÒNdâzK ²ákáCÙÒKÉéÖ ghi¢[›ú€`ÂÓÝš4`QÈA½°Áþ¡j‚TÝ­Jö(c´Â,!2h†' ‹DE(APðV#¨á´zᦠÎn ÒäR“N#©Åö(hU/"5J€í `VAÄ…–=Ž. °¡h¡áìD #',–İð¦ëÜ¡,a¸2( àAHMð³QÍ!‘ŽeÎi#(—\aè¡ò¡‚6ÿ˜ð¦þþÁ&Ýh f` X`˜°;# xªF* ‘G†ç(85b”qâ霰 IÀÂçÉU'zGJ6¢Y,ÖŠ÷…)÷ð¤–aÀ&J‹§êábybñô–.±Ý( d2aP ö¡”òqÏÂk€Ž@2£µrÌ:—•q¢·dâ½WIª…õ·ªF” ;t%–Cª|i”EVy7˜ƒJa™Ù<^AKÁ!X¡< Axàb{Bcù-¶SH¦ä„¡:a¨2  2€8Ö™’€ ®éxW[‰–žÙØYF¸UidÚZnCDKw†þYTE€§wjˆX¦D9—i¢˜aÉ&Zèà0¡fµÝð—‰ùàÈ,K€ßa–A|`Ø!dðx $H1¥_9hIÒŽr:j~äxrvžãZ®Mª–C´wvº®Aâ8V¢8Šå–´v•Å¡(¤Qâ€ì˜Ö8‚3bÑ ÌKo«%|·h¯áø& ÁJ ·í‹3ôºúj㮟ø–¶V¶›n-¡ˆÐ‰#ô‚tæ+–kZàÂHðA=+¡W.b(÷^›xž#j<£MR‚—Î2/`Îa(Àõ>é~Î’µí$µÑR r#æsþÄÁ¶IYkÕÛ×)gñ·•Ó)\ï¢~æÊT DEæ‚B¶¹îA(@ŽahLšDòaXnÙŠOJKx—¸•ºobTÛY­»ó.‡0ùV fS Lí2𰽟ÅÝ{*—sB ¡“TCüãmðK£ñ¤eXÅ#$A ØT^aUA²9¡& $ÆD|éž&¯0¿fÂÂ[˜;Ѳ5‰.S AðRÒÇ aêVÅÑülñ{ xâ@‚a6a|*J@ŒÂHaæŠ-œ$¼áúA,! ¡ðàØH:@ "€ú$á7`þ)r⢑ÎO<¤ÅY™g%²ˆvQŸ\,.Ö!š¡V5ÍQ½Ädn§ñt²ÁÖ¡úÁ–×þÎ@¨äG°èc®:ªî$ Öa™ÐaHaX@v;å+8‹² ™?rÖZîadrQ£¦H„³?†0N€”ΰ°áÐaq¡™S}Þo×B%û‡4"$`B¡È4ô¨L®,èd>ôÂ<|€€rw 4œ Æ"vààáPèã.×Â>Î$W/j4îLï(!ïv–Ñ´Ü-a<–éN 6^àþè}çkÂJaz v)@–Æh~Ähà]•àa}ðLNü„×½ Ðë¾ÁÜ2@ ` D ¢Œ’’àâ@"™Ì»u±$¬¼ß!*taø0öFê~ µZÔ3úÀlµbyžÞ[a Ž¢† ÿ@ÜxT:&@–Šù´+@x"_N¥3^Â%,ÞèÔÆ! ü’ ÎceÌnÜ ß$Üí®>AÚAš¡˜×½×ÉP¡2_-ÑÔ»3¡x€1Eáüy#|#Î:ÉDo¼‚P nT¸«x¢êþDŒR,\‚ÂbPXñs:«aœad¬<þ6qдŽ5Ïü£—QÁD,bÄ è(ƒÌG€°Í2ìôóÏFÙ€C$ˆÁYþXU )D‚1ddC5ê3H2È£Œu­’X¢F$QCHžÔ"ª™evª¤"ôL›ÿ”C$àã¤ýq9€_|!à˜½â@‹1Ì$cG‘Á5,Rà 1Ä cÆÐB6ðlóÏ?+a 5´ñ qè“$LÞ«¯ÙJ®®DZªx¨*A0ê0Ó ´ô²Í4>ÄÈ'™´‡e®&yåa”6J„¥ÄÄøþ/{ë½ç# qx@Á7ùhó‹¹¢‡åXl9C3ÀH 7v˜"ˆ?ŒÈE>…à@‡ ÒJq´1Ç0à Ӛ`B¯„®ÌPˆ6¤°2þ‰Dj>RR"Š*€L2½Ú¡j±Ï8óÏ›ñDrÇ ( àÇ'ß{êƒJgFf\q£NŒ±‚·èÅ—ñ ’A鬓Î?pÍu{c¡”„˽ B_1àhF8‹ ÂAHù C¢ a4F-­ É´£Œ ?ðàŒ5縣‡“¶×ñ$J‘½K(ñš؉·¨µ(’A¯èà\‹žêHWÊj‘ˆ_øÄ‰KìbúŒ&Îh‹…ã[ñàwL¹ äó‰˜ñMyB(y iÍ.fž˜Æ$“¨¥À1–± !x@vÓ¢àÑŒÆnL ÿH„ ¢Àþ2„`˜”‘ŠÔ8BäB»àÅ+|ú0Oa‰{Ÿá&F8 bX”~ÄômÏE„ØüŒ$?TQ Aüá~h¸æp¦‰@dÔýV8à 3&i÷2–ÄóŒÍ=ùŸg'  ‚®s4ë)@Àe¬ãÖAñ LKZ^Ø£g‚4mPN …!„åû؇‘ðÑ £Ë F7ÒÁޏCf•óg>É’‰@á ü 1¬U$¢ã'DF=€+>LIðæ0ŠœYÔOxbÊ@щϫ¡Ä¾¸^¶2paчîQ6â¡ E Pì,x@þÐi〃*j ƒŒAQÁ L0ÀÙm΂1Ö ò8(a«-¶/ ŒäÞøF-ÐÁô€œ(ÁÆþ‚2’H,”ÍÉžü\4K” D%è@ ?ìÒ¡Q¼âú8“K¬d%\ùIJLêC1̲”`HL™’ Š’{Ï»ØI ·Ò^q—Zƒ&Q &ŠgžÞcY¯d‡Ô4þ  3 ÔÑŽYB1XÁ `€´vfu€›K§°¢@ e´£‘ ;˜Á küãÑaH $ ôÁxˆ£Ü³”)Œoñ;™˜¸›Þƒ` D%†P‚pX´]YÔ_›SEþŠá' rirF ”RÂô'-u©MnbJ fÏ9ë»âûzxRZr…QèpF3È%$hžƒ€Þ–4×UÚÑá§E˜Ý À±ƒø ¢ÒyÆ=ªs8(…3²áŒÞäáA€€.ðŒ¿j/b.º×ü׸Êyp„ÏùÐwDŒ@â¨Ä.ðPä§&E-Jp)Z+ªE4‘ rXrE‘ ŸYIK­R“Ïžt–ΦGw)¸898ÉlJT!Lø @! |²[¢·¹9¦„ š²;B((‘Ù­‚1 &˜\4þ±WJB\p„#ÄáàLlI€ËÄÝþC.Ê,Æ=ï!qxŒs_[ꨅÆÏ0«(D(Hq køÃ (cu ÌE9͸|ÀOf©ƒˤ&þ5 È0a [eY2ÍKÙÌœ0q¥ÞeJP$2 ç²+ Hpüb¹„jUr/ñx¨Ø7àáœcs¢*aƒiƒÐ;/èUiõªK JIÓ+‚À‡(äÑ òp§Î©aGò]dkooªB¶x’HT<#Ũ…)îÐ ÜÁ hÄ À`J ¶¤¨©^“(ÐÙ(.iÉ¢¯ân ¸¬4@h)0éÀ.%äˆø}NœÝix¿›þ¤$Â1tÔpe¤RqYcÀkÉà+hƒÑ¼Ð;eÜÀÓ&J0hu«$S‡e£¤Špr$ú‹Þ¡÷¸Ç°¡WLf>ûÙØŸÅÒÇ=Œ é$S® ÚöŒcüƒ4C ~°‚x‚Â¥$º4{è伤WâqË\BïþJÅ%dBUê Z¾¸bln3-up•–½&qø»“ •¡ H„\ç=oÚh%B!ƒ3š`ÝøÄ?¡A˜€ƒ ^ kÙ•Ç]J”-¥HÚ|HžãàA%BÁ Óâ¾2ý(gúÐ!õ2×í‹N¥àw’ìâþB8‚†ËáÐ`Y3Ü)Œ—‚GV×cÂcш¦K¤P€ô‘ ,‹®È®Ø^õpËúÑ/Ð…0„ÿ Ar€¨=û—ÇØÅÄႬZ2 C `à ¯° ݲ ^§y×¢y1ƒr\’~@±>7T1~p Å  Ò ³ðÊÐmúFìaPtCbJBä©ÅXdC Ô"tm@6Ð ¹:söYêrƒ-•`^ ÍW~^Ïg}2á5ƒp3á÷ ãpZÁ 8q|Z§iä„3 × Ô 8à3Á~à_ Gb°Úà ¿€GÓþ?@ °6k,ædBh€ÒâNu¦(â?ÍA®@ ìÀËð&ÿÐ ¢Ðä°€¥S=Ä>ØP 5En¶¿¤`L­T{¦ù°ø@ ­@&1a@@£è4ñ|Q@b=,\G~@„w00á}ì"ÖY-Ñ_›×н"ÛPœðÝPp0öp<6…ôçNF£ Ì0ˆÑ„ ø`šÇy³Öy"†¸%3@ÈnyHD#iU #À³9lã²l‰¨õCŽY¥>‡¦(ÌñÙÓ(«ÕX¶DKJ0€ «A3ÒWñ&vA8!aÈ+Uhr'þ, ö ’0/0÷° •@ ù°,£(Ð,íÔƒ½B+€5úà•PE–‚(Y@TJÐaESmãVR0•ú &R,_ & É¢ñ%é_#µóg“Ö$3i,”°@l(™@6@ð ö6ÙN$™E€VØÀQP‘4é2«ÐQà.0k*06@ “€x@2 ¢@ WÁ—±é_$æ…;A5?W =þPðø~€ÐU”fÈÉ+ÕB$1”2“eYÓI`q€VÿÀ P"°F5H wI‡FÁ Š"`±™i¼âƒw43I%€)P ™€ ø°Œ31gÕgr5)˜ÖDš > ð2á8k³ rC0P’'Ð “0 Ö° 0±X#‰RY±‰¡‰")`í3tÉf™ ÷À• ’ÀCç3YˆKâF‰<±>àƒ${ðD: h6Á~ìF`Ã7Ð`}_`’3îôâ)`´búˆhèyT HAnàÄ€ ݰ §à‘ìb®8®ÈŒ\¢ŠH;b5þ&pr_*R ´ €  ‰R ÍP ‚à ‹ð `# ¿À„p±¹_ªUž|™rÌe‚0«"<2 } ÂC•  LË=<¡(8±a`tšÑÿ³,uæR1|7à%XÝy@8 ,ç6ž¶$8ܳ¤ûÕ¤¹er1pšB ÿ  tz}àk4}0@0”-Cjht4œ‘+ÎAÏàA@Ðì Þ‰ ‚p1ൡÿ ˜Ë¡®µªÍyPVbø0Ð ¢€€ °¥]VDZÀd|jö"•! ñ??2}Í(¦€)  ãþ%âÉ &@‡©ëj«ÿñGH Å ÿ€ Ȱ0ÿàR}]úš,ѤF¡9È…4šr±©B@P–P« ?pA0Cp'0R?0ypVAR'Ø몮‡–­0ÃÐ Ó •P Ëp ë° ð s^„ch0¥5¢(q—5Ù+(Ð+­9; ƒhµ¶.¢EÌæ•ÛäèI;}ð9Éð&þîÐ6‡}G:žg¨š¦\¤¦‰‚YëÊ.~°¢ð RÀ à Öp / P Ã7³¶¤М´ê®ˆa ÙÀ ‚þÈåÐ «@ûPå` RÀ]~C>Q„¨Fòà½26@0 T P ­à˜c\‡"'EÑÑ*²G«^Ñ—‚Û+A ÏP®É0€„Ò-Š qªÈn—uiú¨±Ì³Þè´¶¤®q›arÓ°ÒH>¶ìàoR'·—±úUëÐQ±Ž‚½ Ñ çðýx'àß 5OT>%pD|Xl«,³ 0à Ô«¥©@]uF,Û5)Úa-²¤ˆ–[Hp½bN§hÝ"yÎp(âÀ]q‚Y¾Å¥N^'±Iº·ÚŸ°ŒGŒ›@¾þ+.ö 'G R`|ù›*ˆÑ ~ úÀ𠪜÷ 1íIžødè#JF÷ñ”0Cà «0k¢0‘@ [ ·cÒ%*Q‰¢ô.g#{³7bÉ5&dð3P/á~ ßà CðËÖ‰C¾Bl· (¿™»]Ø÷ ì` È pðJ'˜P“š))³a¹Šr8*,•À é`Ì úpƒ°%:“p ܰ ¬CålI$#ä;¢ø Í•Ì` ¡ ]¢9K9,*áXw“™ÁËÑ—ËÚ+F@#€".ày)±•ûŒ©þ›u‹þy(Wk­e^# ~t šzÀJ[¡~P„ Gi‡ÈœÌa˜Ý“ö0 …À‰ % ×°­Pšé ϰ î2Œƒ'± Ñ  å ®@IÀo ìa¦2›‚ø’01‚*äë¤_:R+µn¼l¨"Å §±8fM:ž^!E‚€Í÷€˜ptðŒƒ žT%°úð”‹TšÉ~z‹/zUûÁ 3mš€€Ð€+a ψÿ À t 7À /{C—Aí lÃÏG¼€W9ë~*†)‡m$Eµ_.ë2{þ™¤)¼*œ\¾/»\{û‹›bq Ì  0¬  · eÇ }¢ìÀ¾ÿ -@±3k è´°kµlKðÇ”ª ™@ ÎL• ;ð ¡PÑÓóDÃ$Ù!t°AvÀvƒZ×Ê—ã‰Ò(¡EèP-’±jLp[œ¨˜!˜#Öô—N´ã+Ñ>r¦Ð ¦ðP £ÝÔ@¥ð  ðxµRÐG Ð¤æ¬ ÞÆ{[%¯R ¤`šºÀù CoaÍ€ C«±-0ЀGžÚ—-›(¯Éüq/ÂŒ¹OëÕ¬’%^’OZ¹4,WÇ(þôS×!ÁI…° jQ×esí)‘Õ×ÝœÛÝ%) ‘ ¼ „p ËP ;`Í®Û3Û¬=³ç‘§.°ÝI÷ÒK >>=¬{à. ·<Ü)—Ï)è€@AØkҲ݋¹RŒ85%M€Àl£ ð ÞÀ Ý‚ â…2¥2Ÿ>¢‚?ñ‰¬ÍäPr÷ä‘R®,«©äÑMŠ[ª¸Šù«Æ›NFˆ1€ûЭa@€‡”€äSýÕž½ÛS ð® –P€Pù “b¶®$ !€@ „Ps‘“0”*¦ J޹P­þé­LØ3zs8³ì¥¢Áž¬Êª¿:Øž•Ð'€Æ °@| Òp ®P «üJ3zÚDRPdJ O_ÉÆ?žnÍ•PO• ûÊû.ø %÷p ! ¤P ùà O¨#µÌÝû¿.Âð¯=è[bð?íUûÝ0’¢ µP ÓÐ-'°ë ­ÿ0¨Ž8ô³Ão° TA‡Â¡1ó3§"ôq’€ …`ùn9A}P ô¢ …PÌ)/ÅSÛ®‚ `>õu¾7Aí†*›ï݃ )˜ ¾)p>À@ m  ݹÚsWþ2)BÐ hfXãà`Q4>fû=6_Д ¾@ ÙP pÐ#[#á@8M'À/×p ™àJ:µµzÛœQÕ—?Ÿ`Þì—¦ä¦.`˜¬ñ ÉÀ Û±Q%0BDàýÃϱø0ÿƒò‘ ñà„b”8P¨äÏCˆ”L¤P‘0d‚M"µŽ»u þ‰±¸Ç" \ÈnÂ' 3gÏÒýƒ§GG‚a”ÌƧO>PTÔèQ¤I•.eÚ´èÉ¢JpâäY•g¬XƒR$êÔi.Uïü[Äj©D%bÑ©˜i•R‹ð£ þ­"¡Ãï_Ndñ”T¤ôl;käÚâqP¡N +¦ðç¥:dì–•ëa”G‡!îhÒ ”„$NÔ¹ØëmܹáF*´çO×9)ênŠP=@º½7IWøÄ Û÷‡’g@]-ZTD„qØœ-óuôèý8mB„ Å8ÞÄ ›¤H¤@ÇÁƒ´£O‰Szå;þIä’=Ò £¬:H‚ƒ¬’¨Ê§Ù¤R‚8;Ü-;‰r JÄßz£o9uëÁ”{ðiÅg’¡æAžÚn»?ö¨ÅœŒqG“u¢ù矒âH ÔÓ¡ öJK>Äþ£H‰ ²#‰‚Ä*ê0ÄæS¢)t …0è#!«ª,¼JM)HñM+ŠêL­¬Ž0ÙP„Ó«TÒq'rÀg•BÂY ‘ @¤À¤)ÈŽ6n@f¨Ar~˜á$9£/PáKˆ>Á\l»ÅNí¯³VbÈ'vîŸ켳¢=öÔ•Ãè¬ð‰‚•sW¯î¡`ŸAÈa¤¨{i–­Š®4i’Š&"!’¨Á†h˜!ŠÂýSôÀàà/ƒDU¾ÿX׊&ù£91&‘KÚ¦"HJDœ 1¢$¬6“ˆ5ø¶}­Í`m;Ø«| Ä9£Ü•3ŸA*ŸAþâ°6$È!\’7Ýt\N0 0ÖKÈ 0Ú›/¾Î,¢‡1ð‡19 J¸˜L˜Ä vÀ¥6©aõ|8N©¨ÂŠB4§|zêÜ(ĹI Aá˜lŒ¹Ã@J „œ ɇŽMqqQ·SO[^ï/¿j;|D!¤q2¡e˜\Zé¡ &iE¢0èЂIÉðï…·`¤äÔNj®9D‹Î¹ç¶p1γ3 ôЙuæ•d”Ë%”vʲŒÃ±¼BD¹újºÃe$L¯\–—to>w‹bÅU<Àu”y&Òx`…’UHš„A ‘¤® r ÅþFÓ?I»ÖÏ·¶ôÒ-P@¿ÀÃ; ‘@LƒêpÆ2°§9$.{,Éà4D¦`) äaÉf€ƒ$(ä]}\Q<×>|¼ÀYIÁ…1ŽaŠmƒCòħ¨x¦¹ìþ 0ÙÝ’¤·QÑ'u€ÃŠ¢pã(ì(îXA  üàÇ>âäÈùM1[HÍ(Ä*êsË!¸ yÈÓYlQQßvêçÂÐ=†þø#„€Á9zp„Oo1“™Cš§"ž€àF)¼A!ýCŠBÛ;EG“$f]iˆ«4L‡ÈÐF~|Š2ýøÈ†&e8 bpÑ@30!Ì–â.ˆÄp† >ܦ‹}Tℸƒ$P`•è¤V’Û‘ˆg¡ùЇ!:Å&S’Ø }"žýegº´/—¹J©ëB C™¾¹-2l¤RzE7‹b””QþÀ)bbª‚b‰˜N3‰B­É:ú3)•Ð$4ˆTèãP„ê4¢ZÉ\è9Ë(%õT)pV'\Ž|dÂ%ºŠK{¨B!‚Ì…'}`3WMŬ+>‰Q•H«¢ÎYͨFkóÍÆ«:mêD¤ Äô©Î‘B¬á5Åq‚Bd,´@†^PW­üjDjºŠ§&HˆDÉ|ð,M>Dá¬pt"} Ä$kÇD ~ÄHв¾,i³z-ª¸#ª 7§lØPÊP>3\ˆdCØÀˆ@¢"GõRî ˜T¥jEPq ~Tã}„>:Qˆxèá8¡þ"…°ö+vR¥LœM æ–›BìCƒ „-aŠ@¢“ Ä®P•žµ+-Ó›SPb*F§eH{öÅ“ ¶g" ÉRƒßgò¼>þqò‚¬®'é"R­ˆ4Ëú.)-MUÑEX4" ÀANà«!<sCÏéf1nY°F*Ñ»dƒ͘8*±X<Å$„©V{X^¾=¹!œYÚ_¢ƒô̸Æ}Á‰du¢ß†àDÆÁ#Yü$È·½²ç5ó¹ñ{Úô^-IÕ]„™YCØÛ‡Â…¸ƒ*¨±Œ` ´:8$¾:ùlm™r htƒwÐþ+<òu0ÃIdlDi˜–¾$äÆsAˆÓr˜ÌŽ ÛåÄÎsÆÎôé}¡×wP ° x@ ¨„H^œB†-)gPw9/r™N xÀD"ñº¡á2óÆç”=ð Œëw¾‚p¥eÊ8_S¨ ½t%»âЋŽ2·Ê\ʹ`Põþ 7®kzó⢕l ƒ8(¢€@P‚U8B@¨#ch‡6 ŒŠæÓ(9S¨\Ñ»¥ð޹‡o˜§ÙZÁ³øƒu¹1öˆ©Ú@¯DcB’/M þ6a;§âÙÁ“1Qj:›š$‰¦™=}Ó·'q¼÷àĺ¼1(›¢ fx†fà!p!¸ À€ ð†( ­‹"%ú:4<+µZZ¢¢€„AÀŽìηªˆ¼Që¶8 ã6Ns&CÒM)¥šÚÁó ›ùÃAœ¯óh™ £!ÅX~Û·V‹!{’Çã Qˆ. N„¨U؇ø†°„#À8À˜Ò­30C7ó/w¢&kZ¨Ø* B àf¹¡¤h¼!ë1/é9 ȇ3(žqÁ|Ї¹á¡E——C<…©7C<ú:.ÌYRQb̲öþ"•…¸‰Ó2€SFÑ»àƒËpù —/ „¶‰²=/Gú(¯ô±Å:ÜÐ?оÙJ<û£¨âÄÊÚ© ± ½F¤AСPÂÇ’Äѳ«»Jà¶ÓQ$¸À’RÁ¶ñ* 17W &aÙ#ŽÁ§xªè+¢ƒqÀ„jx\¨â! )“À²”´¦Ñ:wY‹?p:¨b ‡\˜B¸ÅbƒŠÃóŠT –RY—…€ÊNƒB乃A"aÃGºÑyS“Þ˜•*úÙø¢‘„5¦)(…pÁÆó7ÔyaÑœ+;ȑ̗RøM8ƒU°Ñ8;rè6c’þ ‘‚â°öZˆT(„?Àn`f8†x˜~°!¹2‹!³ªJ¨©2°‚2QAø.tŠ0}…ßA$‹œ¿A”›…¹ rª «ÔÖÚ)W¦ÄਇAA»»îƒÉ¿Ü½uX‡tp~H‚(X6°„«ÑG¤ªŠÙØ6‚*•!…@ЇJ@hàЀMx@>ª²š©29s(Ña”âŒÄ;–I(„ºRÄ?‡;0D`›»eÄÍŽÔÄ­èßÄýÓ1ùˆ½¦šOk‹(:Ü @!°„¹Ys:7Û³Š˜i/üJ4¿˜ g0c@|`-Èþ p/C ‰ SA‹è[îђ¯+wé;õÛ”U „xpyRN{¦Ñ¢?ÓÉMžØpå¨tü—õGƒÙú‚0ø­x: ¡7Mô‰~ƒ5>½s àSx…³ë˜ 庚2‰ð¯i*jêËÛ¾†BŸ=: Bè€D“„0$Œœ»øçCħËM¥A+O݃ÃÀ®;=b¨ƒ4ÚàÃÒi3åÑ.ÖBàAÒKÓã €€ x†8²†hš•4&¦É2€\¤úY¨bM«ÕÑœ?èB‚$% ¨„J˜„IEÄJ}Fæ›Òpq¦47þ*‰‘dNI•bB iBÒ|,¤5«vrÙ „,É£X¥âQ’%Í " ×’’¯2ŒUÓ#Të>PÍF)06<Š{¨„}è$—|èƒJ°-K@ä@CÚT­x/6¬¦Òd¬Oûœ31ð1%hFc”8K{ h…8à›It=) "ÓÊ`ѺÀò/õÉalÉ‘2¶{˜„&¥Î(JÈI°ØU5P@-=¤Ñ£Í_ùÑÅ׳p¨Î×tý#úX’K}P‚(¾JFÊx­¨e@|¨ãjÕ Ð4øPžKÜ×~t-£âŠS "‰°Äþ†áŽÏ‡Õ‡ŠIØ|‡¬¸°k,K,ÊÚs[Pø8©ô¬îSAF¢`|À‰ðƒ4j E¨Œší¤¦3Aü|*¾ˆ °û´%é. ³ Qq§ÙPI®Ã²÷Ø[^åD‹ÄÉ‹€€ È€ˆH`…‡]P[©PÊTUËààÚ£ ÝÒMA‰€ƒ„J@†eH‡fèƒ{yª˜|À‡!ÀTRÊLȇP¿SÂ×O±A¾Ê[Z•Âø8I,Ý´X iÕßåÄ[ŒB(b@†i€†3ÀÊÁ„ ™Ú[ªXê4ÚôΆažj)Õ‘Ê¿ÄÐðÍ q`oJ þƒ[…W’ðƒ¥PB¨/8i† „Ap?ý-OéC¼I%‰,päU¥"•0@º¬4žÚèd8kPxPuhƒˆIÈàØÇ|Ù[²œ¯6ÓÄÈL‹?5Œ-ו- ]á¤X‡{H" (@˜X8RŠ=hF}„Èêa†l¨!U¾JIVFEäÁ{ &!(OL¥qk3 k³ySa(†Mòb¸†bhbÀ„V(…%Q_Çኆ©ÐjÙ©)s<¡5/é{¨§IáðmÛ}8¢_$Wà_ÐL€ƒ0‚¨€!áEt¿âQÆ@þÄfô¨ n ƒOûZ’} *Ý«¼!ˆO¹cøf0†fhs`†d@x‡ÄÅ•Ïl´Ð)²„¬¤ÑRút'ö '98›J:F˜±Í èƽaÀ P hàùXE2üC'YE’éÀÙu?'S`ƒpL £F”HÍÛ\лƒ:b,T‡‹°šCÎõQ cUo{§Ï‘Pô¹@ˆÆÛ1þË’UÛŽ£ÊYûqëb…í¹PˆF¸„+’€XDQª›iÜ”Ñ*‚"(%#.ÝÕ”® HC$´fÄÌc³BL‚r˜%¿r‡~øà¾JU»Š•þù)MlàMV/4æ±€åa%)\\Ñ|êƒiIXWðƒAÎ8@»¸)8¨)ˆ7 $¥"™AÄT­QÚ¼9—“Vѽ":ç Dqù–mõC¢û‡ Ø 8nòœ®fÑ‘ :9Ѩ9TY­T˜È*¸wuµàuÂrųҜŽ:&È~“zh–| ,µBJ¨Š} ƒJP̹éŒ-RÒVWl>måæ$Fg¤;§x»T’ž;Œ›° ø6ðkPhP@˜€x+MÙ Ž“à¨øÔ’ÈC?剼F­­Kê¸\&ñb Ûåî|Ðþ¾{Èi(†l„Bp‘£ƒ|x`h~èJˆ7§‹ëAœï —(û¾m"ä"&^ý½"¬•oúR*Ïmá™ ƒ ø@„uH@(@d¦ª±;õNúd$k´5ËÛus5Ä}Õ.°æ¦2’jè£T‚\˜`†X„Á1ŠjPeÐè4‡ B¶Eôaá¡_LÅ¢2$7k»Yò{]3$PˆR"ÿ‚" _ùžpQ ‚¸J*ƒD`1O”C5“yUÖj¹8KX@8ŒÝ%Ñ85¿onÈ(A¨>ÚnÀ*2æ½ð„L zX‡dþx…a`… „aà%Mx«{P‡e8†h€WÀ†˜<€ògšòK-C«­Övm×–FØÎfÍá‰ÞwDMñáѲô/Ȩ°”#h ™¥Aˆp Œã6Ú_þõÅ …Pgýþp‚ª¯~ã1ŠX5p¸e'&É6ÕÛ˜…vHvðhgÉ^ PÐ>@°S!È;ØØ–g¨Ú’x"/à ”w4ëá™ÒNç”N7¤è¥Z—ˆu÷ €Ø@ Á3¢Ãj4ìn‘¾Ðïî,¿%2p+êá¤:_]v® ªkºÅkê¸h„äHk0P€qè %‚þSoñyááÀ 4|«=|­ºtûVmkç³ÈÊ­ÜjÜÁ$ð‡)Ö®Å@8ŠÁ£ËZŸ$|:šMâsYQñà(II„`§ñÒO¯ ¸ùìî§ÙÒp“a0…oPF¸ƒ9Á*Å/~Œªo¢¿(W,~M/ë/FèB’áªÍU“:¹ÜÒ!!àY*D‘A0b!ù eˆ 3S`vY¯•/uAܳW•ˆh”ƒ-2„Ž-:@€Np›JøÏå'z€c`Œ "$8CàA‚ c€ˆ¢ˆ/~ù1I>’)r¤È&“Pâ`¥ .)Š)s&Íš6þmÂäRfΛ5)üq F‡0`8€ ù@ŒP%NY2uàT!Å„$ªƒ„P1bT‚e©äY§^:ešö«Ô–Nî”è^p’"Å “ÇBˆ „X0pCÀ7ŒHâ—‹ŽÿþàØ$I‘aÂŒD 2LË—ž=û -z4iNÓÕêu©W¯JÔ®ÕHU¤HÁl%õµT×c”=­„Âë«!Ã|uÝ–Ž}~ðéä L¢”èå{8°Á‡~Î/>ü_†Æ ˆñ—ðIpäð3 úõ/ÓÇϹ§N˜{ø— €¢¹ôX­1¥–rOu ÌálFá–ÛþKõöÕk2ˆUnD‰„f8P‰>ôAI>× “6¡‚Ý^QÞ`E4žŽ;Ú8bè­'Dîq ™|(‘„gNá÷Oýá4 ”SRð_YBu… l+œ˜ñÅÑ@à0RD]˜ n®!øZq$õ…æF>·SÈ$±8£N2(ðO.Ùá@ã_< ÄcxQ0Ê莇飤5æÞQ™Ä‘I '€1Á”S¨:MYj€U6¸[É=e pAIEÕ ?ЊØ´Uµ•®p–gMyE‚{qDÕ†%´P3KÒðƒBð B?>ø&G4ŽÇmâÑ(þ™¸|1Ê×x‰6P`¹·ÑFãVuR}ÂíáÓN¦â;àgO©ÕVXžE–ÙGë­¸fõ@}Z’páDíEæ¸â†áŒ1ë˜3Aÿ4r‡U7t0„ &Mü®£à¾+n‘‹Ë­`ì:ôc ™Ëò±ñ¢†p÷æÛsÏ/§YA Ý`Àhae«F´ÎĘÉ~¨pà c…•GE–+!™[{ƒ3ÿÐFm¼€’z]mó¸ÞN|äI-o+žwëù8d)Û\Õ±))ñß½£ú¸¾RœTø\Äa¶ò¬›‰«UZQ®œEj$ž­áE&Y,àÐGhʱ+ÇAˆÊÄŠþ›òI&…ôúG-Ÿ{wêŠÇú±&¹Íû¼€ƒ¥€<÷G¼àöþg¥gà ç’ߡʸ—ÁÓGxTUÖ…”¦z¡(ç™óuƒ­I Ä8”I’"ûÛâÊ[I(»­¡¶¶cý°Ë_JÃA)T;yÉððx3qž“g¼=(!$ErÚB˜v°Ý&Y¢` ã½Í…Qø%zÐ}œ`(¨Œf…¬ã܇I:ÓO}*qIlcΰF?‚pGì8%3÷©O]ò–A:H‚8\Të4'8ó–2lɘ§É·”–°Xs^§>%‘gʇ,ך®¸I ²(—Іœ®f¶;‹hi G¨ª=® äÎȤ„¢2gªõ®cÓA¢x`N’R‡…bC½˜•#1wYµ_¾%µX1а,¢ó²ÉM]r‹Þ;’`!gÉK<p%íÎ!3v$h°ãɼ Ier“!šK°(Wg„Æ Ð<Äc‰ WÖÃÃf{[þ’'®~Ö…rUÞ†ÍÖ¼ûUUâwfhfTª=öª}NG™åªõd]¸¬Ú(Ú²¢Ž4“AýÊÕ%ÎPà”åPJÆL“»J›ëx8¡ l´—È%gæ5¹Æ«Öö²¬½Í´¤£\]ô“ž \ÊG­6MW¦2‘Ð's½å@†š¬¡Þôœ]grÐöø€š œU«ƒaOhv“mmåË!BÇMÂL¼” ze+ÜÚ“ݤ؀×Õ$ ü1Ô“£\“I(NÓd‡(ŸùÉ'`}×{ 3Áy½ èh®š¾TUk¬8ÊÈÅÌXºeT¬&Þ þÒÊL N ˆBD’£´ÍãÇQíWƒg*_6€æ3—ÉÆ†º—\¦*2;Ê}€ïž¢ÞJˆ‰ê]¯0Ð{óú©@À}a%bÊ® I´DÛ¥P-G=J„Žn½ëUDŒ—˜d’–A;¥øRB؇ʀtþäˆÉN~v H0 kgûPÝN“zóA&pÇ»tz§aï¹^`ô<®eŠc{%\AóRˆ²›:¾ÉŠNCºmÎÔéªéH›Ò"›ç·Þ&ðë¡GóP^Ž˜”ý;Ð ˜´LˆóGåç'DQ¸ß~߀ ½Þã/‡Ýš8"‘–°”°$ÈÅÖòd\öðÕþiÐ].Ü\µÔõLèÝÁYÊ]é™ùýÙÍ Ê‰üÅü… „ ½þOHYZ¨E…›ŒÖ‰AÖ© œL(i‘„ÄGa=–ÀQ’­›”„Þ”C9¤Ùe | )š†F½• ýÍDàÜÜ©`®‰UoÄÙñÁ ‚DŧH”‡Lm ™Œ‰­üÓ¯ˆÓ†i^¾ Ûa@°a ÙÑå8¡OÐ Ž €Ö òÜîžß8›yiˆSÁF„µÕx‘aQdÌK[[“…Ûøe N 4í¡O|ÎQáýAÜÕb“U׆ÀoÌØX$þ^yXÄÌJ-ÚT­$A6á_öÍDþC!È„8á;lâ3­ÄN|âù]ä[PÀ¼‘b½Ý[Lä)¦¢*®•«(ò±Ä1’±5Î(eŽxtαìÇCíbMøb(ÈD Ü=Bø_ŸžÜO´!ÝÕË(ÚÀ â5æFÖŒÑK€T fÒ&m™côA—¢]¡oÅÄöÉ„  \%Äc1¨$ãßùìÉŸÜÉÄ?d@®Õo¬IBþÖ›ü*!˜…ñ¢I$ ø"è5@?Œ]F²?x†J˜gäÝÑÛ4¥ê‹JU">NXiœÔp´ÄÐðÝ©€Õ•íT‘] þUNå%ŠÝ÷ñ$ÛùäK Üß°ÔKè[5ʨè4Ö^R.Ѩä£e”ÏDÒõñÙ×…”’,I"Ý•A GŽÓT ëýÃèÅD˱ÞüäÉ…`ºe½}Fðœ3.¥N\_¯%N¥itæÏ€ÖLâ‹Dy `ÎUAiTV àì¯H Ñ$’€Á¬AÜWQ@ÁÁ‚AàíKF1PlŠ\7}dI–ŠD6PDù¢T8Iç“$'•ôD™Õ] ä[¹ŠzùqJ’ùVtª•SH7ÉÕ¦ðp˜h$K’Óz¡ÅŒq#%¦oy“Rþårb´¹â‚)“¸½æjàq'l§ÈÊW¹ H¡Õ3Á H!’nª§tÏzš¥r‚¢9•\Å`”!_lÒEM`ލ°1ѵ¢7rgr0Å‚¦ Þ‘SYTF¥Ú!=[Ú–|‰Õа„$e”iFgj!!›Xù±-ÌQ!Hoªe>­f>¬i?°g=²i>µk>²l?µl?¸k>¹l?«f@­gA®iA¯lA¯kD²jAµkA²mA¶nB°kD²mEµoE¹nB¼oC¹oD¶pC¶qE·tG¹pC½qCºqE½rE¹tG¾tF¶rH½sHºvI¾vI»wM»xJ½xK¾zMÀsEÁuGÄwGÁvIÄwIÃxJÅyJÆ|KÁzMÆzLÂ|NÆ}NÈzKÉ{MÉ~NÌOÆ{PÃ}PÅ~PÊ~PÍQÊ€OÌOÇ€QÊ€QÍQÏ„RʃT΂UÊ„TÏ„TЃSÐ…SцUÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ,^rþ¡@QR¤`Á;\Ĉ‘℈ hx°Ã'P °ÁãG B¤ˆ”„ɑ#}ðÈ¡’‡ 'O2)DH¼6b|MÐGE÷é€C~ûùÔ]…8 -¸ÔrT9ÕÔR 1DgÆmT…à±0ZYH˜÷¢ˆ$²D[/]y%m#6ááyLÜ—C~(ÔØ•D† 1à ÃÌ-äm.tä#(aW] 9l˜„—/z‰)Âöž¢A¼ö^NQhHø†ƒ 'ð)¡îÈ# 8´ 'AN9§„©VÉYžz¥Õÿàý¹!§å6Eˆ‡¾äᇪÄ}FñNqënbæ Â~l UgzîȦB8ôÀà© "xVEE”VAUfiI iåÒŠå[íéú’iåz«—”ö–CFUX”„D!†›Ê!Xcb&öÜî»/à‚ ¥AšÛÄñ21ì¡#"¡¯¿Æ+ï¹¼‘æB™#t%³ '·ÐÁ²ëf³ÙBvœ*ܰÀú_¡¹Õ‹DkÄ»bƇá³¹-Ú§’ ˜–°Í&+ÀWµ¬„¶+_åBCšü¥Ô•¨}èån½Åµ„ÐC¨Äˆ™å%¡Q¸ÆÃ6`xòÓþ"pWÔ¿Y/fíà+÷p0·g>½ä#œ`Ã<ñ„‹ô‰øQ䯽Ý6‰®aij”¯w7¦{2Ü7E"$Ʀ 0³N]UVƒf=$ Ó|‚§Täex—åJÎ!‰šk¾lñÙå{]FŒ^&Ÿ|w•äQ«cv W_M'‰Ñ¼é«|:ü8E<1yè‡ÈmOøîKÇ3ÏÖˆô¡…ùÍ'„)ô(ó:WqÝcdp¸àiyÃø†;Ý-å5æ+ úâ³¾×PÉoÑAŠFä# á#LþŒ@$3Õ®B |À[°2„DÁ FУ’E„;KÚ¬Bp<.X­þ™œ|Þƒ¹æ¹'W*"Ë“<Ôà¯$´ x+>ù-" a Nð0‡=p \`@ËIz–°«êÆÒ ìAÔi¯+…¸¢«73*nV$ôÞ`à± °ÀmËÛEŦ׽í}lp;?¹àO9ûœfS[’”TWªM®°„•<ær“7ÛÅ hàÚ¾—òÀKCŶ`»­€Ý[‘=m¾*°ÁŒ"†—™lV-ìÑ– ÒI)¿ë$§Ñ¯n>2¦ÅÀµ þ€+á X@ÈåònWþpf3›™¶šòðŒ–,bÔ–¸QºÂ t™Rݽë#(YnIt“„ÏY É”ô¤'a TÀÁ#ð#-ä!7zO³¬ f¤ä² 6Ë%M'ãæÜ·P‡ÔN} [ì|´‘FÉ—zíü# :º·¦ÀÒ äT`•r|{‚·Ó¤±¯Hlrg¿„ŽÎ!ß[–€ç#Æmœµ iºl×&î?X@°ÍkÆ^àܨc+Ò'‡eɤBMÔÒRQR'r‰Âà[Fû. ê[g´sMJ@͘Ê,Ҥ݌íõÃ/@!_ +á% \ð8œÄ;B·Ž0ÿ4]Âb×ãßÈanKBÈ…àqœàíRSôE8Pés«»¼gõ¹' ë1ÿçB?€@šÈ$r;y¥·Üm3bŒKú½A\ÛLW:Ú•Ÿ`€â¶Å {Ñ ¨ý×»n€E|²„ï'ÖdzÈãöTv a¥¬N—Û„·oë‰:[öÎô˜H6 AAÙ…Ò€¸=ÝjŸ°¯ÓÎùsË=|ïö¸lJúà¥dëJŸs l@xÈÈ-ª¶é™öà-8|ÊÀÙÝÎyr3ö×H@Ú…_ óI,ÏJfÐ%® ïw+øÃTðá9ãàn.ÙºI‘8û•þð8åá ·Å@‚_€òØ hX¦ÉYÞ`ô¤wz±”ƒ¬ä7}1}¼D}7gÛ¶] ÕLZòx9!S5’ðõkP~èkêFX`|±bY6p&PFð$ˆDìÂ8Kݶ,â'®ks¦ZÇ}$ètÜ÷}³ôZÏ3~`~øh € 0„ 'cI*ð$?pŽ·t9À$È€]6#4öZX˜®E4°d€âxOH‚M¸tK(†4†K[ñD„8„B†å7„•&°…5°m7`"yxP¸m'c3f…à„ø™”„\h€ÿW†7pß·„9P\¨ÃUjȆXi˜Ø†pd•Å…5À‡ŽXŠ~HâÑ]Åt‡L&`YI8c_ˆ‡¥øÖ´„\Hc”•K‡ n¾˜ Ð^\!&pŒ(@LH8XŠ8…ˆ”Uv_1%ðŠˆ(‹ÌøøŒÑ؈5@»8!° ŒÁH„hI¯8¡˜‹³Š8LÈiÅEYãt`AIu¸…â1µØŒ*87 ‰Ç[_C¨Ž p‡C¨V®øŽ3ðÉx‘õX‹J6‰*°‹P!ýáÝAS%‹¹(cÞøâ14€“ é4ÿ ™Ž‘ P°“ €“éøy!p’Èø¯¸cÁ„ã1K [–Ôð”$ÙàŽÿÈ…öDŽؒäh3pŒÇX#f“=Ù“ “‘ `ÂHÆ` 0‰‘IŠàGcU’N •R9••…’ʸ’~¡”A &—=±a`“pP@:IÀ– €r—bA—1IQâ~JY\¸$•Où—ÜA•ô¥‚JÉ4:h‘]‰†¨{r—Ž@—I™Ĺ™ Pž¸é•äXš'›èZ¯hIàšR‰#€KÿH}Ðù’ÿ¥é•È8—€¡›AØ›¾œ”y ™™À`‘0—r©˜P&¥Y˜LS…”Ø”®Ù594¥Å;›s©˜s™Ÿ!ð ‡;IiyÀ™ž ‘Йט PŸ ú¡ú¹·ù¸šÖù Õy#4µ4àˆé3 P'ð¡ Š£Ï“ € `¡p–0íyžP=ªœ°Ò °‚LÁI8IÖ]ÿYÝ¡@Ý‘–Ô,8ô¢°˜„2j…°õ¤ jˆã¹p €Åyð¦gù¦pšy@= špYŸ*Z°r’(¦[•¥ @žØUÿàAKÅÕ¨V(O* À§†ø ñù˜½9§0C Eš¡  p{ +­‰L¯å¨ª.Ý1‹š±U¨%‰K(Y\õPyªºC×(ª¡œz–`¤ì™?JªºpªPÉP«Ú¨»øR9˜–t:RÉQÙȪuhL³ö”§*Ìš›_q ™í §ÄJœi‰¡ú˜`qt·a жjþ™^ª@÷ ˜ªÈ7D B¹…ªÙP`¯òÐ ð˜ðš–ÄI¬™9§vª Ÿ yO¹a àÈ‹ÉتÔZ¨7ä,Ú” é¢Hè¨Lé4 »aÿÀÇ»¦û›Äú¦ÇŠ® ¬Íª¢¨ú”¢…#Û]úO´Ú²®•K´Š¯Ùh 4fY®pªAk®±@ê¦éI¤û®¢Jª{*f •hªI5úVH ­“(O7B Gè‚–ŒW&Í"®åú º'ªéZ¡Ãê©Æúžê–ƒ…MÚ§“jˆ€ä÷’MÛ¥ÜAIˆx¥skIFû‚#£PE®ÍÚ«X¨›¢Ú›Aº©º©íIœª+ j¶OJO>äŒÔ×]/[²G˜²NóšI}ÎèŒ:Á3õ¤½:ž<ú˜mʺÀ œI§l¹pÅš Ú ¤¶*è‘ÿW’:Ä´»ˆ¥ßkLTÛm²™ |š£*>Ú›ªžêižꙋ 9н±IÛ‹´•€é•nK­Áû‚²‰‘z» ¯(¢Á£ ™;9™”©“š™™ü‹É¹Š “A—¥©‘I”¸‹ËUÈ4傱h³T£ßyŒD ¥+w幓ũž;Y™*ŒÅG‘¸Y—œ¿§y·ç‘áÛ,Z“*©,:ÀV (¨éœ¶)—¸Iy>º–¾‰Ã7Ü~‘Y~¢úy®µ1éÁõ8T˜„:ˆKþû¤Z«-ÈŒÀ!:!“ŠÙ¥Ákùí‡Ã:Ùžl)Œ `|TéÂ( šÿækŠÀ‘ù’P-ê§®h°A¼’7àCÍÙ• ³ –j™–IùÇÃX„ÿË•a “/ùÀÑY…L +Aáý1¾u¨—ÊhxY—>ì’3) ‰j©Žn8]A•4ŠÄëÐXŠùÁ½Óêôú§‚ ˆËüw‰á &l)–¿aF8È¡øß·ÊÐè‡26‰Ô—Öˆ(œ‹O‚•é‡ À¶#èˆ6ًىE!OÉÈ…Û&x¹ŒèÜ̺»>aˆZØÄ³ǯæˆÛ–‹Ô¸`ìõËXi¾(‡äTËÇü„Éöˆ …ÿ×eê|…Q´ôÕ…³(|‡ÿ'2Ñ“hL‚ÑmÓk¨Vß{˜ Í„E†`¸]ש¹>uÔ–%Ǩ'P5¸tåÜ9àõ—¸‰Ç‰fÐ~çGð±€”|ø‡D5HzÙy H›‰†!9K€9®Gu58M7K …ÒÆ{ìW~Øî·Õò§C™4KM­%Ü·.*áz7G›ËB\Üùsx)Âx7¸мɿÆÕå‡~?|½lÖb!›ÿÇ|ÍôobÇœöaÃq¶'X…"ªf׳‡à72UtÇnw~¡½kŒE¥}nsש=Kú×|£¤o±qx'c3#¯xÿ«Ä|?à}D-Eâç™—vÆ lÄÍsPqé­nÆ7w=4×açÎ7<TJ'÷O-á ®WJ4ì­uÓä}j HÐ#w–§vPq7õUéViæ½p ·i£8á6aIîñÒ}’}ÍcD>"(¡7v'yжp·FtGÜ»åk.dÐ}‚p›(ÿÇ Q#Çãá)bbQáq“r%Nm»äB`MÉfݘ"~àk÷à7ãB÷sEæ,’ÍÜ_¸tBÀ5qG J±ÑE@mûV}æ9%Ÿv!WÒÖíZ[Än7åkqåfÇéhC\ö“ôƦ10&Ûö9$ÑRìÑá´ÑˆGjÏumRP32øa*P!çnÖfh¦f”Vim&TÁ0°h}e1æºÑY(.eÐm§–Ö™>hÛ‡†hâk;·vkâæ#Ðk+À^o&ab&!HFx€W„–±nmoÁríÒáé©%0‚söaù"=…ñXnff+ ijÆçföXà•$HÆê ¤™^³Þá(Fø çFtNbVõ‡+f1îä~f¼æc…kë5Æ7G‹€"(¶¢_eYò_1ëÖä"a`12x•k;ñYä~Næõþ!ãÅŠ,XX`pAƒ„Dˆ(¡"… 6pø’¤ *S¦Ha’äˆ A|`,é£ÈÊ“%M"ñ„‰)5¥LáØ$‰I6TüTñpà TР!¡ V¼øbD‡I&m aè%"Å‘#fœm†Db²¥ÚkÕ¢LbófÙ&0sà ñ3…‰"´]ðÀjÒ¦Oe¬Êô*a B‡zEB…< !;%IÜ)!]¶rrG[@Ô^F’„Iç8ëšÌá…‰}!8A”0SƒF@•ábĈ #<$ñ‡ÜC?œ€… C|0¡%ófî;KþDGiðFt”LÍ Ù&Ú™áÁà èô?|*â„S‘{á„s¡…ãšBî1¯Œ.2ªb íš °;ïà+Ï—Ê Â´ô¸£Â(–bˆæ;!„ûò*7 Òà@NpA†dh8ßüËÏ«ÚJ¸ï9\ˆ/ˆ%˜XÂ6“©C“8 ¢¼ÐJZ¢»$™ˆ‚‰#à“¾îó±¶Üüªª âÜ!Írn¸Æ¸‚È+çês!MÓŽ@2ÄÔRs  4Të;?¿K"½‘4MìÃoƒE€ ·†#h„5Ó¼qÍ5Ûl ‚ÛZÜà¾"sÁ†¾[≠™i ‹þøÓˆøtÐ!4Œ€5ˆ-Ñšð‰÷†âÄEéÒ¡Ún‹´±á4ma4"vXÇÜl.N9K:l Ž‡ Œ"Ü=£¯YgÍ¡²(£ôACV“Ìò½ø¸uºÚz4R¢†Çf‰ ¢‚KÓpë롵ÔM5Ëx]-7<xÀèâvq o‰#Ãâ ðnÝÁ [øƒzßH!b€¡"Šx‡Rà™„ ”ky+çJÕTŽUÍÒWKŠÕˆµ`¨¼\@\*D6WØ/J_8ØRžcèÁæ"”8µ[ „¯ÁVáFiL¼'žh\$þIÜØ5Ï /$>Fòn‘Ðzè á~à!`P;VZ©*ç9…‡FØ1ë¼Uqì¨Øû;#D^ú$˜8} 7c£ŸÚd`3%d®r›S›òš£H} "t‹ v9ßµ@~ þ$[Tr¼ÊÑLm*pYÆ2…%…™Y e8ô¡æ…¨™IZRE(²*9pA½N°D¡Dn"EbÙ”p’ãP~¿#cÂ6@§tŽ=ìéNZ gÅ% ¦$ݹc…¾ÆzU‹Œ"^‹X¶“ø€xeëA f¶³‚ùÅ’¶ RPG™„(Š—IBë2f’·`„U… äÓ•úlew®ŒY ÒX¶€d%LSph³Üh røš rp™¬g JK»Ì•!fâ #œN’‰FåÇ!„Îä$Y§›ÝÒ›˜–Úàè—ÆüÅ9!ØÖ0˜™¼yLp2Ä•KÈž%ˆ(НÑÿÁ]Z)´r¾,f”ÃAšŠ7PpÚHm³$ÿ69në90\ª7¥AÉ[%ñ–iÊs¤õ ðzé¢ÁÉö³•_:d$hÚê´Ìuð›8ë¦ÖÄK_ú’+  *òÐz” [Ú16¥(9Áoë ¤°“tÙ€(Az›ƒL1»¦Vr³rÏxÆ#‚#¡¥<·5§ª\É@B°Sˆ RèH´„'¾acßù)žÞ W`ôÜ A×~F«"2>Í#ÃJîyOˆÝ X$úråpÀÖjƒ‡zË­©Úø(Ÿ‹mh GЫg2ȿΠ°h²ƒ~vU ’ͽ­Çœ—bΑœ«äÁ4€ 4€¡EëVIhR&ˆµ€:‰X¢†Ú#øÊ&[â·Z‰ pW+<¬mÙª(ì ŽÅ\L'™‚1þì/ÄÍätŠT>æ" µÅX|PB]$Ù„$ÙLŠ6ߢ„íÁ“ähìw¶%@ ;blt-2.4z.orig/demos/images/chalk.gif0100644000175000017500000001043207240160072016067 0ustar dokodokoGIF87a``÷ÞÝâßÞãàßäáàåâáæãâçäãèåäéæåêçæëèçìéèíêéîëêïìëðíìñîíòïîóðïôñðõòñöóò÷ôóøõôùP 0L©Â Pà à8ò ¶ÿ¿ÁàP.©¶ à¸kðÿ¿É3 Àñ ÿP¿Äðÿ¿Tår ² PTÌrñªÿ¿WDlð€ò HL©ÂP  PLàÂñ ÿXåò²àÿ¿P4È/¨`ñÿ¿¨LLÂPL¼Â ðÿP¿täL(àÂPPÀ¶L¨ÂL€ ðÿ¿L4Âò/ÿP¿P娲PÀüÃò¨«ÿ¿=óñÿ¿èLyÂL ÂðÿP¿4ó ¶ÿ¿P¨` ðÿ¿4óà¶` ¶àPðÜò ©L)àÂP8.`ªÁLRÂ`.`Áª`Rà¼àªðÁàP8èVóñªÿÿ¿¿4ÁPóñÿÿ¿P¿ð² òªLXn)ò¿ P`ñÿ`n[ñ¿`X òc¾ò¾ÿ¿PàøPõññÿÿÿ¿¿¿¶ò ÿ¿,``þ PÐàA„ƒ B€à Á‚ ,XÀ ¢ƒ‹/"Øxà€@T |À€d‚—#2X ‘Á >ìØ‘¦L…t&ðX€@H”btèräĉ4¨èó%Ç")Î,ÙÀJ†7„ÚõÁƒ¦*@ÐqcL‰@¨ek€@ ´B¥º«Ø‘kkÎ\KÕ'IŠR¥Ît`Ë¡mkvU9„—Ä:ò%DŒÊ¥YR`ÞÂ#–ØV$ÄÏ[&X:5jWÚ ;X`R  ÍJ.,I¶m_oÌÚ5‚î©>7Ô|õ#Ï¿ÀË*:hÃÛ‰oþ‹ÎÜ×4ðÐ0·ŒÉÑ7DžX³wŸž°ìtÞtÝ/‡ñ÷‹þ4ßw3!VÐv¤‰UcfíVÒi›„H¦QäŸwµÕ]„Ü…EžEôC릒sŽy·•XÝg˜D^ôTTŒg@‡|„cHÑVÛS4™”#Žæ”V61Y6 ˜âE6†tÑ!©a¿¥Azy#vá˜ão(%V‘máIõhþIõÖ[Ì]ø€eÅe– |"‰X_l@ÆdPe¨·V]Ø’G"pf¥i¦†¾ùJ-4AzA ¶… 榤 g™z›u¨¢œÅäÙKe„à[þ‹ÆZЖáÅS‰ÙQˆ">´ªg^Ñ Z%)˜Z±á·Ür­b4ÚX±.ŠÞ¥˜fJZ:‚™cHûyÖšk³™åœN1‘e§K5­úV³2—WWÑZ$nzÎýx\oEÊí²t%7€Û1ªƒ| 6ãm™Å»\ G[Öx ¨zUGºâer%· *u!Ÿ“ÎDcc@™gj$*™bA.‡gomTÕf×jH5¦Ó±É>$Yh*3S0–Ÿ˜å…R+qm6¨´Ž¨Ì6šIÞYærøŒí1r@ö¼" Ì…BD¹ÜÉÀC“Þ &"Bº‹DŠV¬“©-^ÚQ…•¦3eiЏ”Zy—DöM/‡)YEšò®Ý”l"4kâMjå$’t Lv‰›¶ã: ¥¤Å‘KKòƒ—6î-•<]Θ¢Wî®G —.dË|‰9 rå3í7®Ê=(Y}i I°_b*CæŽ ÃËjâÒC§¡Ê¯b0ÿÈhˆ]þ!vÞGG!Ì‘oƒòVG¥°|iGàŠ%¸úyÿt©\ !¯X‘i2%TþË^¼àb–íŒG3H‰klT€kI&7¼\O‹¢I!êi,bŸTåbÆÙÙÞÜH“Hø@1OÇñȽ²w³Ø)åD˜¹(p”Ô³úX«W3„%²`$vUG>•`è212õ I“Ù’KѵJàYD©Y$à.Ç›A­vYíVÏ‚Š(¶¯¡¢š†i,œI3cA¦gʆJ<.m&ñפR“"‰¤¡'*N4/…S9³d™K–blùÒ§>+’ëKXC8ƒ]ÕTœÉ Z¨ˆ–ÇüŽ"©‰þaã›ÖQÇ#xýŽ*7ÓˆXG£{)#¥¤€"^è£ÇÙ­lXv­ºqÑ £ÌÅK Eê·’±RXhëÇ'eÈ¥VñyÀ\—(ήvUÊ 7“§àtE÷Yj¼¶V lé p%Yu/ü²7;²} vžò®JuɾwÉȶdÈʹä²U½ÏPÈ—OE¬)üj/cfÔ>ªUjŽ˜¾†P³`È G»³ØŠ8O`ß,^(µ L.þ|Ø“èB¿É*-°•u²:c… H™ #‘»°å Î8›S ¸¼[‰f*ã‹ÏÃâø~‰B‚ ò¦dO‡ð‘˜»àþ«ªz?v’«ŸŒ¹Ï²²gÙhöou1 ˜;Kgù'`¾Ó*`àb¦°@¶ÍJ¦ËO¨ÄŸñÆŽ‰ˆõ¼gjfeQy¤`p¶TÒÄ$y­%O× €(¦&¸ÒK™Mp"Ä¡ÈFƒ¡Y#˜ÐàÎÁA]êR—˜d@.v¥e‚°ÀÆÕ’[F±/‚µÊéÄ¥ï¥Ö’éâ@1ÉÓ/Šm Ÿ– _m•%‘´´3¬¢*égþùÙYºó±¶yûÛ'£kiœ¢gýE*ÂK¨Þ,¨© z;õXG Kƒ©Pø¶Š)SÅÌè nWÖ´‡ð$íÎ*T=`µþ_¥e‹wC­_ÚÓä3¥é¯_‰‹œbˆ{¤4ô&óÀÚËòlë¼#òr2—§€í®ª{ŒhþO¨)À²º«ÚÛT¡=‹4êDžzWjêdëÓjT&à‘¢ºd•„kVß4@TaQÕq¯›9Ë#_ÑÙ,*súK ÕDÆ’ÿ{ÉuöƒYßZóÛ‘A!ƒÅÎ`1}fŠ\žîÀ2ÝvA•BËÆr"_g<¾pnr)†2”JTŸž.bÑÄÙ¿¡érDˆL{zoX†uðñ?B5ìCy¤þ.—ÁdaO$„!Œ±%˜ø%=$—¯DuÑ©Ke!7JÕOQItúãa/&ý–#s++ò9âÕ<‘Uy\8©žZDX”Sa"ÓžÀˆ(CghàéD‘)* ›ÔúYÃù ˜–½ò0͈!Mƒ>—%]†aTÔØâyŠ”r @ÛaA°”~ ÑŒô1\@µq郔 @FªW0ꂉ)úö3É<³R'X?§fdˆ&„‡E–(ˆ]áBÃr-ômñ”kšu¼Ó*j± !ØŒT¸øÒ!œ¡}ÒÓ=6‘q†ÁAbÚiM± CD,‘2»0Ãâ¢þ^Zœ•¥³Ñ§±tWF­dCX‡d a]§¦uùÅ.êT ^–- CÔ-ƽ»d'XG&á7G ç»•&gqN¤H[÷&%§''/ àPÜ#@‡!bÓp Â>ñ‚R˳,!µ‹iÇ/Lg<80¿'F¤p€F†ØC“@rež“ŽÃå/SÉF‚ÑÔehgy~ja­B+êoÅÃ>…s“üT«ÙE˜bgƒ+§sÞ“_ÔÉo“)ò91–.1>x¬ ¶Z'æ¦ZúJí“LMU­e2|ççm‡8 #X™° ÉÆ‰œ¨|aòt–„Æã—ÿQ pvWšÝV!PãeE;blt-2.4z.orig/demos/images/close.gif0100644000175000017500000000021607240160072016111 0ustar dokodokoGIF89a ò¿¿¿ÿÿÿÿÿ!þ$File written by Adobe Photoshop¨ 5.0, 3HÌú1¨ñÍÊosR–@ØZh¥b-ûlí–°-ãt|›:ÎëCü”€¤r¹L;blt-2.4z.orig/demos/images/close2.gif0100644000175000017500000000021607240160072016173 0ustar dokodokoGIF89a ò¿¿¿ÿ¿ÿÿÿ!þ$File written by Adobe Photoshop¨ 5.0, 3HÌú1¨ñÍÊosR–@ØZh¥b-ûlí–°-ãt|›:ÎëCü”€¤r¹L;blt-2.4z.orig/demos/images/clouds.gif0100644000175000017500000001441607240160073016305 0ustar dokodokoGIF87aPP÷ÿÿÿ÷ÿÿïÿÿçÿÿÞ÷ÿç÷ÿµÖçÖïÿÎç÷½Öç­ÎçœÆç­Ö÷ÞïÿÖç÷ÎçÿÎÞïÆÖç¥ÆçŒµÞœ½ç”µÞŒµçÖçÿ½Ö÷­Æç¥½ÞœµÖ½Î电猭ÞÎÞ÷œµÞÎÞÿÆÖ÷½ÎïµÆçœµç”­ÞŒ¥Ö”­çŒ¥Þ{”ÎÆÖÿ½Î÷­½ç¥µÞœ­Ö”­ï„œÖŒ¥ç{”ÖsŒÎZsµ½ÆÞµÆ÷œ­Þ”¥Ö„œÞZs½RkµJc­¥µçµÆÿœ­ç”¥Þ{ŒÆJcµ9R¥)B”1„½Æç­½÷œ­ïŒœÖ”¥ç„”Î{ŒÎs„ÆBZ­!9ŒÎÖ÷œ­÷ŒœÞ”¥ï„”Ö{ŒÖk{½s„ÎcsµZkµRc­1”!„{ÆÎ÷­µÞk{Æcs½Zk½RcµJZ­BR¥9Jœ9J¥1B”1Bœ)9Œ!1„)„œ¥ÞJZµBR­BRµ9J­1B¥)9”)9œ!1Œ!1”!„{s”œÖŒ”Μ¥ç{„Æ)9¥!1œ{”œÞŒ”Ö„ŒÎ„ŒÖs{½{„Îs{Æks½ckµck½Zc­ZcµRZ­JR¥BJœ9B”JR­JRµBJ­9B¥)1Œ)1”!)Œ!„{s„sÞÞÿÖÖ÷ÆÆçÖÖÿÎÎ÷½½çµµÞµµç­­Þ­­ç¥¥ÞœœÖ””Îkk½ccµcc½ZZ­ZZµRR¥JJœRRµJJ¥BB”JJ­BBœJJµBB¥99”BB­99œ99¥11”11œ))Œ))”!!„{„Œs{„ks{skcZRJB9scZµB9”µ­Þƽç,PPÿÃĈQ¥ ™* ¸’#‡VÆ|õzv K S`1q!âˆ) ; S¥$F&3œÄÐñfJÉ)~¾àB A%8¦0ääJŠ¬ÄˆÉŠ Æ)­ø(1XRE$ %Dˆ Eb1ƒå¤ÊSVL@ ˆ‚CÈ+Í®\i2e‰l“!BT¥—§4iÂd¯Q üøñ™¢«“ÃL”€œâ³îÞ&)5‹JÀ©ª†±ò…«ÉÅJ˜ÂBH#:MÂhI1åi ,aX "’d•0Ÿ«üÊW”~ •„uÖIÅO™¯b‘GÍ¢9{¦ä(‡ 5 Æf“ÏÖ%«¸ÿ9ríŠàdlgÿð!(ÿ£A›špˆ½,PH (¦„5a„ d Ä £*üa Bž,e†>å`*Ibî‚•L&Y¡v…5V©§RÁ_§êåæ&·yi ÀàF*T›ú‚EøP UØ„#l•7%9$IDذ`A€è"à Â^°ÇÚ18Áœ/™pÀ£ÞÈBAD“‹;²ànhJ Dg„ðÃ!<0…XÁV(×64'ݤ TºÑ#ˆÐ!@X A®@ˆd56«Âk9@Ö\` ޼ ’v…ì †G(À¸¼’ÞZA]A€A,@â’9áÿd†ÃI]Ö ©®Ÿ‡ƒZÐ`Ï„j -¸˜&ÕfˆYðI%!"ëÏüÀ‡ADc± Ç| ²’¬y `F-Â6¶bì០A Ò¶6?p‰x£[ nÁ „¨H©ip²¢ýA~G™‚!^ᇞâJdœšJ¼rµ¬)Âyˆ…3œá0AcèV@¥ÀC¸BشͺBÒM`fp–‚NMN Æ¡¼‚A´G NÀÇ8Çí* "šœ!žÔ_8mŽÞ¨Ç‡ëí§ LåŠÄ¢ˆjAÒU÷6gP¢ôm8«ðÙ«X4… ¶dú€†W¼'#Oy ÿÁA@€…’x Ž„ò°°2†5‰XøqðâÀU<¥g„«B™dHQ¸~«‘ØÒ„ ¤ÚŸ°('¡ pŠ·Á‚¬LDX(B `ˆDìå¬x„as‘Ô˜ë)®!b˜IC 1hh V1³Ÿå`} !ˆbà„.GS$ü~qTÁM€ëɇfpáNªÆ#zqŒD¬™ ‚Zr’ß}"*.EÍUˆT•D WxƒõL-´±/—ÊU~+¡ ÈpÆ.|1ÒfÁ á ÐŒ.ìå0ƒÇ1]=‚Á†+ó 0µñ|Lÿ(½Ò„U¨ÑK¨T ÚK±¶i°ävÁ fà Ið@êé‚P@SßÔ ä!z‚h€Ãå %M  8¡b±*a $t@áD.dN Aë䊠 Y ®1&n RºD‚RK2É $nÂá¡*PJòå|$a1àdX ‹åDNNS1I„À‰ k X`¤Z MX•€ÃäY°@>*`AÐ »&MÀPô—bàqB°9NÐ1–£VPÍ€Rñ .ÐdW€ ¿°šÐx‘.@%Œ%èÿá!¬Qca`BÑP94eVù‘VýÑVC@$WðPsTE6Mà³™£p‚aÈ !Â"t´ P$P ã7)*\d#3R#1€|y£#aóYÄŸ)Ð {Ñ;N€Uo ÂPÂ{p%z`ª¡\â%`â%à_€¤‚_Qƒð?–ƒ¬àCt ˆ€'„@]Ö…]†`3À¬ [%@¹V§¤¯Ðð @A@%V¢bP¿à S Ò °b-V\ˆõ?‡Qfü¤µ‰Ð[6 ¶`V`A1 ÐqË”Bÿ`:³t°ŽA ƒ´—² Y€LÀtW P£P:ÐOÑLüCO‘OÑ:òÒc?dù²/¼`.%€:·ñˆp΂Ñâl€!XP ÂÐ&@$ºF1år1U}¡ÇA%¡ $Cxo–) g"@g1Óm­DõáðS ã{ppc»""Ó i N5RUj3,Ϧ5¸Ð5?6Ï6 žj£¥I¦f-jÑ% ¡S0 ½À>V4.0TdÐlmVg!†C ó¶8x´+`%a¬af0V@ Óñœ£ËÿÀ‘¡ ÖæMrW,»¢VSð’t#,@n:°ž ÁKÓf@…'ˆ’$r#‡jìDY ˆÒ<Ïp†j#=ÆP=)bà47†A U@%!®Æ_°("à.º±E>S©S@7pèCüã?ʲ(CA@×ö!’pÀÊã@6·VŒAà¬CxÍ´Ns"V"L¸؃B1@iÐD°&~G;9õ!]Id Cvsè!Y`¬ vcDqD‡à¸@gŠ  >V [6Ã^âVÓDBØÑ%6ft»2‹@<¶ç!%¡D† )ÿÀeZ2uV÷G“G LÐ w°½Ð pkÁgÛ!zWP–-*_àEÐ2µ¶p不“¦”~Ÿê4°!Y±4KµÔ dK»d©”çÌ LX ° pA}s‘χà"—„,¸I`U!”­@ݺUb§.´AMÀP °pÁ Å`KÍp ó4üÇ,ÎøMúÔ&V0ê#^ zqÒjUQqJà’âÇŠYxŠHhNJð %Á U%5"U<‚éõ¹O¤N€äV ¡ENÂrP‡P‡/}Z3@ŒÁ Šÿž â„0ÃÀâ– mšQf€$ !n€  ‡À(¨ƒÐ–Sà`53€Ä™†Kò ÿ RQo£]…Zc Ãð › ,p Ðd~Ð lÐ v‚(¢9@  ð?B° ˆ0•Äy‚V:I3ðA¨€ g冠ü3BBDb$‰ ¡¬‡ BoN & ‹Ôà•Ÿ™ UÁŽ Xð#.1•®S >ŒáQˆ ²ŒSÌ€Yš•:b[íxnRºAGñ1J0 Yð {‘6¦ Ö¡ñ?†€†@qœVpR @"0­9ÿàq4ã#õfr2w2]M`˜Ð“€!L€‚Bí²Ë„,å%Š]q¯%1EQKsôs¸¢Á`nP $À80­A $%1α’ZWzmÁʲ+ž$¨àfП2iãdÿƒPdÞwo~p)·`FÈTŒµS`{ Ðrئf§mƒ ìB ’#i<)Ï@%šÄË£3"7£–9F±X°£y† ¾KvL<¥à%s¤aJÐ ‡-åBå"%12®F¾ÄëcrÀ2$0TYlà66œ²P "n¢v1°JàÒq‹AC£Áaaÿã rÂ23Su¬` ]3_6І ›ðiŸànpmpš@§0æâ¸t#±äÆãÅ`o8ïò‹B<¦0½ø8b@$xs•Óß)á9ž+ÕV$”ºlà=­a+…!b®&Ÿr8sבR•“ ?‘Ÿ<Л5ƒX¦ÔAÁ¯ šÓqÑ“›ð ‡=K¡¤ i°Ê.¨{‘õŠb  It_€“’@‹?Q G€ b3š$Y€$=c@ºsvÂ%{‘ I¤$s0ÁEuVƒP Ñ•zCd±’Å5o‘q¥Áÿ  Eå#eUÀ O±–D¦°0`÷0vÍÀÏP'l` xºsÛqEWÐW:@ ç”$ 6: aTÓwh´ckQ|o®õF¦Þ£6z„.•@ÿÙ‘–J¬Âäǰ©VK}Ëä¬pàÒjIê9à ”ºÑ1ƒ§´:9°ÊZ®K²¤´ô ñ«ºD ÉצÀSÐ û'¡Á¯@åà~7ÁNº†!BÑ >M™âêBC€‚줮Aó$CQà80™+¥»ã}1OT5UTBY‡À2®="‚ ÿ{G8F“@N‘RÑUKD±3+ ,ðÉz!ɉÂ"]5µUë#릵„ð½nX² Äã`Ó¨w¨3 Aõc~Xo+´¬ rÐDr´„îÓ¹ Ó 5Y¼ŒVñ‰?¡‰b3Ó‰‘[ÂEÒ‡ñªø ƒàGÁ±l0 UãâÁ  @\&Á"UŒ1#»[<šuœ•ŒXË(¹Ò •»Óøl\â•!ƒ°†° Ò •°!ªÛOæ² b-@¤ &4ÓZºE'Ð%]z²¾˜ðJ_êkâ¨s†w‰¢pÿú)rD à42ÁØ%;Æ•:Pâ¦b$ ¨²Ao!°‚2`ÁÒ¥†p=¾à ¿bzAœ7)´ŽÀ“Âò¦J±b@šR‘WŽ‘ð 8@;Õv@r¤àh¶0°”9/UÐlÌ àˆ‰i&pÏ*’A!$R¢ r v¹½P”ëòÜ’é“@$ã‡2¶ dä«(ÓlO@í# P°Ä&dÍË—ê3 ù8@°YÓ05X™zâ% ¼â¶2lT ]jŠ ÊÌP˜|e  ©à ží¦ 6uÿ¼ùÑlS s0iÿò39–9±kt@cJ@$æ2Õ Nú Q_²ÍŽi*¿ÊÆl8À9h€ /<#€RàN аL£¬"Jà3C7vÞc`nh‚êFœ|ÉÐé¤`D¬E<á|¢†R¤P2CÇ^AR˜™Q¥É• ²ðñ@¨‰1„(Q‚£Š˜2XªƒHF•’š0x@ (UÅÒ4땦¬^XœX˜0A d¿ž$ºbkŠ,¢¸ùЀC %N¦iĉ•*„”LÙ*F –2µ¦LñÐDÌ•+|R½P‚ÈU %=65ãd‰Q£cM@‘P%XÍŠõêU¬Y°-Á*ô¹‚ÈÉiš|±bÒ„LäbH$DÇM¦4É¢c¬WÎ;blt-2.4z.orig/demos/images/corrugated_metal.gif0100644000175000017500000001703407240160073020334 0ustar dokodokoGIF87aKK÷ÿÿÿçççÞÞÞÎÎÎÆÆÆ½½½µµµ­­­œœœ”””ŒŒŒkkk999)))!!!„{{ŒssZJJŒkk„cc{RRk99”cZsRJkRJ„RB1œ„{{cZZB9ŒcR„skkRB{cR„cJkJ1„sc{skRB1J1­¥œkcZJB9kZBscJ{scZRBkcR„{cJB)kcBÞÞÖ½½­ccZ„„sZZJ{{cRRBZZBZZ9{{JZZ1ksBs{RksJ„ŒkksRRZ9k{9RZB{„kJc!ZkB„Œ{ckZcsRkscZkJZsBJc1Jk9ÎÞÆk{cZ{J1R!RkJRsJR{J{„{kskckcRZRJRJBJBs„sc{c9J9kŒkc„cJcJBZBRsRZ­cR„ZZŒcBcJ9ZBR”cRkZ)B1JsZR{cJ„c1ZB1B9cskJkZJ{c1kRZ„sBkZ!ZBJscJŒsc{s1JBc„{Rsk9ZRR{s1cZs{{cssRccBRRc„„BZZRsscŒŒ9RR9cc1cc1kk))BZcBcsJcs1JZZs„Jc{cksJRZRk„1Jc19BRc{BRk)9Rs{ŒJRcksŒRZsJRkBJcks”ckŒJRsÖÖÞss{kk{ccscc{BBRcc„99ZBBk)skŒZRsJBcB1k”Œ¥{sŒZJ{J9kZJscR{½µÆZRcRBcZBs­¥µJBRkZ{„{ŒsZ„R9ckZskB{„kŒJ1RB)J{Z„k1{kJsk)s{s{ZRZcZcJBJB9BkZk{c{ZBZkJkR9RcBcJ1JkBkk9kk9ckBc„Z{œ{”{ZskJck)ZR9Jc9Rs9ZœBsνƄBcc1J)ŒRk„ZkkBR{ckZBJ„kskRZ„cksRZkJR{RZsJRkBJ„RZs9B,KKÿ¹å0 aè´Q©Å 8æHa²dãÕ(ø,dAå…Ó¦$ʆh"…èU}^|ÉÊhÛ¬j›°i 6£Gµ1€˜B&†M9r›Q Px rkÐ eBüœÒGÍ”xŒ$ì@§K¢D°¾hÖ)ƒ ¼j•ˆ¦/­\ú(‘(¾´ÁØv„Ú¦Øæ¤áV-̼MÙ"YûbáK—P›¶ÝÄhÁ"Eâ>6Ñ Û° ¢ÅÔŽ|ºiÊ÷i œpòÝr’%  /ó(+‘åßsuQYÿ°÷åŽ$%‡°¥QÖÍËŒV›Äd©§ÀU¡¯fxáóe†«AèèPF OÌáG<òE#-#&s¤G­€07{Ps‡QlRÎ&€xaA  üÀ 쓈,i”ÅØÐ)FÌ0È6–àã|hC‰ ô`C‰ úÌÌ)ß´È5ÞÓB:x@ -P@ÕT#Å==|Qͱ\1‚1ÁpL/Ø0¡‰:ƒ@b‰,üÓ† šqG‰`óEY`CM 5òqE:ØX!Ã+?|‚>ƒÜ"Q¼ÂE…Nðr5¯œ±ÉØÄâktc h@D ¦â"f QÆ ¿äÿÈ•&.ðOšâ ,ö´ Íõ|¢Ì)Ù|ß-ÛPã`óÉ3!|1ˆLx³ -ü`L"QPAM9ØdsA5nÔà ,ÚäC ž€¢I0ùÌsÇå”âË!s\Å  Hÿx‚29TCÍ*ˆAÕì@J|̳ÆË(RD'Å\°…šàƒß^ ÑE5xxÑ‚ ¥h³Ã•ÌPÄ)ClòÊ ÅsȧäÐJ*æà‚>=ÄûψÀ?Óðpƒ€QO$0ˆ)-”£ä-``“b2ˆthâÊ&ilBÍ7öP0Ûtcl$²M5¼lS#Æ´Ð _2hÿÇ õdâÇ+€X‘ƒ6& 0ÿlr6ŠT“O_@‘ˆ&]¤óJ5`¸BÍ)¥MsÇ<9dÃÍ'u)ó4 –t¡ 5NÌÇ& PÅÝØðE”3P“‚ Û¨òEÝ4‡úA(¢L@;èòó¼ÂGKJàÈçX€Çs´@Â@ì@C>Ül2ÏFDц6¶´ñE"4P“Æ+ˆäiŠ'3Жˆ‚6üp‡+0B38Á ÄðŠfØ@ ÈF,þa€â¦pÀ?$Ыuä#è˜C„¡7´#s°À ±mlÂ’ðÂ6ñ{|£¯ B4AnX]˜Áÿò‘Ù$BûL òÑ #, ˆ @3|pd, v0Q®P Aàš¸Æ N±(”Àéè‹>”Q‡=løË6À°˜B kD °Ñj<Á¤HB%B `C ðB7À ‰j8¡€è)ŽÐ‹[œÆ eЄ´ñ €ÁèÆð|Á ö`)®q+$â±%ŽAŠ.lâwèÂñîPŒn !8œÃx8¤c‚A"8ð…WÀ!^ß>Œð md͉hAðЂ[`CEHÐ lÌàìø‡ ´á«'¼è«Æ1r ƒ'˜ õø†Tÿ lˆ‰h'¨¡ŽyB¶0Æ,Ð Ml£ðB¡`UäJ€C5à`lä ÕhÅ(`ˆüƒ°F?HA‹FÜj©HŒ†RX@X˜ƒ'ìñ (¤ a0i‘Œ`„…x…XÓ*ÌàÜðC0àŒb¤b. €hMp1àð:j„Á­§Øé…4 !]èÂ(  SÌA ƒB+ô†`Æ1²A +Ø cÄÃ^Áˆ| ƒ@5°ñ„a­HC~°+ÌÁ¨ãP†6Á ßhMzL„0‡äi_<\1²‘‡ÿìÀ¸Æ0¨Á Dã Ŭ¡¼B©:ø‚+ pXMÜÁ¡iÐF#‘(¤`æ„Á¢±€PÃgà†&6` h Ø2L4€5^ …ô¬± EÜAæX@5(Q‚#H 3°ÂrVm”A2ÍÆ#´ƒtâV°†)87à#Ÿ Å,1„g(ã _F28a+tõÀdpe˜èMôp ?`ø˜Ê1†ÏÚ£5ÓC"ŠÁ cÜc>ð‚ Na(¸¡KíÂ2âÈ…áèƒ&>œotƒˆM6¼P@Á‡hê&tpŠAÂÿP@œð }ŒàÝø¢b¾*,Ç–ˆE)Ô+´uSÈG¦a†Gø¢GàÆ }€¡¯`:à‘~”A ‚1v€‡3à tÀ‡2¬Q oæçÇ@@p·‰x¬¢ø¢,ª±$â6°B1Ê@ tœÁÛð5, ƒih¢`Ƙà.˜Ld©Æ@À4çM´B{IÀÔñfÔÃW(ÇÚ0›iB«0ƒ‰æ‘ kˆ‚'áŠ{|=ØÄ&œÐ‡kÀ÷ÐÆÐë9ì( \ö&°¹œC#ðŰ D€^È‚910Ñð Bv9ð@]p ÿÐìò Ì€ LÐ 3 Àƒñ  ¿€ ø 0Ö°Ÿu9¯ tå±áÝ È09ð ’ð  ®ÿ€ 4ÑOåØÐ€°®  €ð° ™Ð § Õ@ (mPò@sã Ô¡ G °ðƒàЃðA€¶ð `›0¤0C𔿠õàÚ`æð€ WÊ –à Cd)ÀÈøªP¬'sÆc Øà ‚àÁà  I€ ¤ m0Ü`3`€Õ€2€ ør)—MÛЃ'ið:šr3  ›`¶ Z@ ù` .ð4i°kРÁì p^°æ  ^àæÐ À ¥€VP ÿ€!‰ð \  ¾¨ g  X€P D0P@ =ɰ Oà• ”`š  6`§ðEÿ` N]¡ ØP W  ð G  X€³ˆ]`)  * D Œ`ˆ‡‡30ø `0ìä t¾¨3ÂàNð 3P›P¨wA&¢ šz¶ƒÔ@V3ð _(Ù}¹ ¯9mÙ mFp  ¯ùd %ð%¤ /bðiwp9øÀ‡ DW¦ð ö  Ý  Ÿ`"U0ØÐ !&Ÿð áB Ð1°G|ÿ ÅðW¾° ~Q `` A€öpF0   Q±`Fà~`¾:`á›ûÝÐÊ0ŠpKe ƒpc &ÅOµyà›)°Z`?° ° †` mpO ‚P  ŽØ;` 1˜` ÖpP0á7 à€­°JàÚÀ `0NÐ ù  p F`K‰ `R‹É W   šðtÔª  bFLb€³ ]Ð L÷àm@ŸÐ *‰à p"ÿà Cð Q Œ`?‰_ ƒ€ƒÐ ;° 0 qÿ 9 6ð Ø «ÿ0èà;`W0Úp9`]@ˆP ¨€ Û  (Ð P]@ 0pÀ ÇÐVP Æ€ pðÿpðEõ`yC0‘wÀûà¶pàm†ƒC‰Û`_×P 98]°I  ^iÓ_@ ¤ðdÑw@ iТB6-ÀÞà ÜЙÀpùº_„XÑÀ Pڦ΀ ` k ${€ bƒhÀ Q.9P ó` ÝðÔCð›Ð ¥0Æ0ðÐ-P ÁP P ‘à´Ð ¯P «P - ‹ÿ`i hp4Psß× Oð¼ w€Ü·„ pT` · Üàð°¥0«4*Èü0‎0ËF P` _Pð ‰`Q0 I0 .° Ñk+¬Àç‹ÿ‰öð ŠÎbÐü' P4€›Õϰ P5Œà ù°\Ðø K¡æ% Pаc`G° ’æºó@ ¤˜p 2ðˆ sð¶"Ê0 p4C°šù /ÐÖq Y¤ g IæŒà«p´`¯à i€ H0Óð¸p óûÿ` Vð Ô0Õp·p,< §pÚ6›pøð 0ðÜp >ðCCx GÓ9`Ìa È07òã0 z°ÀI /9 {  ;ö¿Ð«À{Àø‡!Ö]ι õØMp›O DxZ3 Ö`:Ðæ° x Õ0,(üpP§0P€Ð¤0ó°P° b«½¹Ô _p?_@ À±P »°(ѸŒd$çèÜP 9Ð^À š¿€©Ðgà­pºØ`ÆPp4b`i`(Y ·w€ »¤ÿc ‹0N°ÔÕà­ Âð € {¯að-@ ºtx@9*àư^ Ø`¶7·À_Ѓ@ &r¨iû-fÏnà›Õ°,ƒ€¦¤°ûpâPY`Àe§à­ˆš0z bÐ pð_  ±ã%®° ƒ0À‡Ì$dÛ0?›à Œ° €'U{å`  |9`†ù9Ðä À i0 ‘8}Ú QÐ-0mú›2[Pé 9 æ`PP Ûñ °ƒ ¥¶¿p ÷`ÑP ÏFDq­AðM£@ žôE  òÿP ãÙ_À°p †àiR—Õ`iPEMpÀ0ɪˆøp e`’€Ì™Ð]@E^p àØ0Ö  )À¾Q€Cð MI° ¼€ gœq0ð‘…ðŽàHÐw0ñpu9õ`%õ0¤ðc€pÊ%;à ™ /²0@ ‰°Ü@ÞãYÒm­< Kó {À g`à° YÐ =‘wzR -€ÔÀ¾90–dÀC–¨U ó€úa€øÐm=0Þàóð eñ e0F)÷L…ì¼ÆB¶pî`È ÿÿP­` Y€—W #`¨P æ€V>à øÀ 蕯¹¥a8iPƒ§àР àqª@Ú0`ÐLSذŠ6pà (‰ 倓° ‚pKåôö`R ° ã¬ýòm Y@)›€ Å?   ²`wð64ØàÊPÊ0 Ô  ‹p­c ­€¬ù5× %6º›W`Ï3À½P †@fPðqð—€ >` ¸ð pÕ0Ûð 1 Wè@oû LðÚ`±9×9p]0 à)®¥€éÀÔ`Ÿ ` „ÌÉÿ€Væ¼0W ÜP epÓ° æðÝ pp >`éóEØP5 Ø ˆ°Ø éP 𘂠Dg ‘<«ra@(`MŠÐ›°Ô„0\ðY°~Ð ù°§­p·%p ÁP'•%–á“Âp4›° p°Ã`,^ àÚ@ ða^@ Ê` ±ÍVPN¯   ŸÐ ` úeÍDËú€ ^ò}2@fD` xP ØP ù@;C°úg,0-W kÐ ’Ï Rà Á0 p@^’6°kð:@eàƒ s0Õ¥ÿ /€C;MOP €s0Ù N ®€Ñ¿pû>?¦à£9°N&å7Ö„)Ûg¯@_Ì ³ñ…B"Êü ‹–(Ú³kÚŒõ–Â> ÔÄ´˜BYjÊ\}Á¤ÉW38-¾tƒS J—ƒf8ùEQŠØzå@5‡[qþý À§(8õjÆ«IZ{´Í—'ÔÚÜúRcÎ ­à CAÓ¯/PòÑÚô…T R?š`Ó¦ÃÉŒ½fQã¶©ÚNw éƒZ‹_ÍØÁcéØR!$àß½A)Z´š¬‘˜[¿Ê é"¡‰·'¯rP0%C[ÿˆ0¾TS2Ï $N41º5U5D݈ˆÙ¶gF¢`%”©ƒÃ+Ì+ ¨bl¢Æá‹ÿ8.Ķÿ´åKH Tš¨•¹âîT"›Q³§?›¥.y%s6ÁgL88…š,pŽn¾¸edÂðcl或'àhŽ”Ñp–pMX*1TI\À†.J‰Æ„'æ¡KPP”mÊè&ŠV´ùâ‡`܈ ÅàØMÌØ›‚É"2|ËðxEšy„ØdžÀ0% {&(¶ÉÊHY* Z¹F€iV©FŸr˜C0àÐÁaŒÜ¡¹l´yÿacf ç M°i¡|ªÁ†‚pFI¤ 'R¸£ž;*8barxÂ^îI„šê)ç ´¸ƒ1ª¹ ‘"‡¡æŸ„ô¢@%‘2v`ä‹y¼Ù%;¶ÁÆÉ+ yŠ;há "*a¢MÀ˜á z,ø‚/m4)lÙÒg/bnu' ^¶™ 8hãÍjàHä DôöÐ$N°i–D⣾ù‹y¾€Š9Zé—'D\ ‡G‹'\±`‡QZ™©šm¹#Š|Ð!EM|—-¾8lPðe7(HB–( €Ba‡hàð“`8˜£ 1°qÿ¥…6FØf–l61¦šjÖ F‘A\ñ…(.)G2(ÚðD‰.rð‚šyîX„‹´9E\c˜Ñä‹mZdb©©†8>XªØ1 ƒO‚ùb‡ˆ8ÁžD^¡$Ÿm´ÁeŸ`äˆLé›oŒ‰A·(^‰«Tæ€Á‰2¸A¸žNÉÇkÀ ba b†¦ “’è‡l¬(G›Mæ°æ ¾ˆ&J,ÝA–¬IÄ M†®&|îA$²/‚I£\v™§‹|Z0bj2ɇ+69á‘.¤ÁbHÄ6>/4#`ÀFÖ S â>H:Àp 1DƒFXŠ€ÿ€Ãi"_ÈÁ'H€,(ØðÃÅ’@ '*N¸C  ðƒD¤Ã¿€ ‚±MNÄ¡ 8 b rÐÇ/‚Á…]|¢øðE †4 BJpE5>Mü¡ƒøÂ4@ ˆSh‚SÊp‚0~°†[ÌÀ_0FÒ‘ø¢ò Æ ,?,cI°Fëî€ Ü¢‚P5¨ÑŠyÈíP`D,à1WìàÁ°G=‚!“,l 2x„8þõk¤À.ôˆÁ>(Œ6$" ¿ØD¾Àz|¡˜Õ 1¾_˜‚ 0Ã`Ñ YÈD?;ðI6Rà„hbmÀD5`Ð…+ÿ˜£ ¸À>± ø!ƒ0C ¦q l\A#ˆÀ?ÈýÑÙ€Ç'Œ`„ 4B‰Ð›êA/ºaùP7ºô¤a;3ÀƒªñŒ.|! `hÁÚrÜAb¨„9ˆ€T㟮C²MðÚ†b kXÀ–ðÂ'Ê  ™lã`bPF+4Q1Ãt[Ý„fp/Àöè†9z=´  ;blt-2.4z.orig/demos/images/folder.gif0100644000175000017500000000013007240160073016253 0ustar dokodokoGIF87añÿÿÿ‚‚‚ÿÁ% ,1„yÁ¬„”á8gÛצ0TÙ¨…I‚"š©'[®°àΔiÓ¸]óტñˆ,;blt-2.4z.orig/demos/images/jan25_palm3x_L.jpg0100644000175000017500000000772007240160073017505 0ustar dokodokoÿØÿàJFIFHHÿÛC       ÿÛC ÿÀdI"ÿÄ ÿÄD !1A "Qaq2Ñ‘#$&3BSbr±%6CR„’“¤ÁÂÒðÿÄÿÄ2 !1AQq"23ab‘±ÁCr‚ðñÿÚ ?4½(½#ïœ «Û–늊á5í*¦•ê‹òÆ‘À Œ’dó=1õÖQ¶}38ݽ¹öÇlõþíXš¥!Y  ‘ùT…ñ2FAÎAÔôÓoX©þql0;ûÇ¿oÇO î¿‰»Û…T Ÿwª¤–àå‹S ,’Æ ¯õI9¶úß,ê΢kpïCfѳUéUéCm¬ºWpºÝMéO?‹ ˆêî@P±—æpr0À{ƒV$ôôâzmXÓ§örõ¡ }-8¿p2¢o:ùä” ¤þ!ذ\¨b= 2;u5³î;Ó~Ü¢µíšZz‰êiÞ²¨ÓDð  βJФ9ïÛ'¶€b01´ºbÑ]Здhÿ.'6²Y@Çsã?ókçðê⛹HívlޤAûô!µ³‰ÍI lû}MJ«ÁSÊ&‚U`YY_ €H9뎚…²Ý7Ö㞢’ÃOI[-'/Õ„qÌYT€Ê £vÏm/Æet]¨PL$FÒúnqr¢d§¦³ÛY"$pó33„*÷bO@ž¯¼[ãoxGn³\¯]§Z·£ (¢(ªÄ?: ~ :y膇ôó$´V’ÆÈct¯@ÊH,Œê2 ö8é©c¹ø½{­8‰w¨š’)8½’°$ÁT¼l£¬N¡*@È öÆ”XŒ¿+Y ÚON©Äz]è±Ç ÁÆÍ·~ªÜ–úZzËÍ(¼JlòLr‚AìÜƒŽºkpÐêïŸÅÚÛõ2Kü?ðpþš.uÀÉ\ÑÁ6ßX¿úű1åEqÏÛžÓBÎÝÚ›|nŠ >è’®:(¨*k|JZ·¦’7ŒÆCó©È3dgh£õʱî-ŒXüŠáŒüüH4.lºº8·½ªj‘;r[ëü8áˆJò9ERƒ…,qôü´9›žÜšS£[|Âã1!¦º'5|$átûuÞZ+Œ×ºŠI-"o‰ÁFgunÌ”9éÌ{v°í]©Ãëµ¾·ní[õ%DT2ï8!I£¤qHyyß“%GO–q«|íêh%—rÙáLB%± Qä%Ç %Ï( (Î9ÒŽñÂSQ,ƒbr ªp\`³ˆóÐç*BçË:ÌÎ*pÒ×jpîkä8t¥Qª6ShéèíÄ[(vµÖz fQL°_¨Äq a &,r<›"LÆ>JØÈÜË’€(Ç1-ôï¨+UÞ¹&Z;m¡Ç‚Þ%eª:PÕAËøŽH%OAËç©qîj*?hâWÊÆ¢•L|KƒÉœ’2’O\çÈ d2¾"iú|u_¡WÙ7×*›¹ ½}ãrŒã1g¾AÏßJKïù˜®Î…Ê€z×F Œy01×Ï_¾˜{Ÿw¸+ûF·‡RKzŒŒäg®@#¾0~š›´ÁYGnX¯· uub³x•ó¬ ’€ È)àõ#:‰+¢ °ÖwæBbG¹HP×ß'¢Š{­ ]YË B)‘OE|.r=‡ŸßYo$–Iöø˜Tç3àË)' Ôr÷ÿ÷}iR{c'Ú¹éçùgY?¤ƒšÂajr›&&cŽ‹Œç¶®üß:‹j—/„¢ƒÚOú³‰÷_“Òåo=~´íúhÙÐ;êÅ5¿‰i“‘]lcùÃ/飋Z¦/iœ­™Á³e*¼>˜c9¹¯_>”ú ø}E_vÌHQ}šè$å$Sr#$ƒßËF¬á3oáÛ€Iö‹˜éþ4_6$Í`¥¯ÜçoRPÃSYQp´†(Ô.G(*Hò ¶t8æ r™cq«]]oÓš ¨ˆÈv,UÆXoöæXƒFñ= ÆC+HªÊrº 1Ætâ‹fmúJôõ[åê«%ÔÉøS…2Û·LƒÛT¢Û~¾Ýj¦·]æškE=,‘û¸ÓÖH›–b¯ åçä|µc£²KK4nMÔ@dð—à ‚ ƒ)ä òZÈ%‡Ò[¬ö£÷<Ô3'BŸ>ÃÙÄÁšðL«¼wU‰Ê+3b®2 9$¿-;M¡¶hÚ£%ã HŒ×@ñ°ç,O+ÈUˆf$ 1ØW$°4tÒB‘Þ<"§áˆÆ¤Œ’@ldƒ×Ëí© ­rH°†¼K eˆð†pOÊlà䃓’zäh xŽÍxôî—™õ]ááÞÌ»ÐÒÝœ ®`º’=ÀĘQÛ:«qáåw±,§#Æå3'8\ã—¯ß:±ÑfØÐVÝo"âZSqÓFy V1âz+ {ãTŽ'n«Vú¶Ø¯6s2Ä’OO,s Ib”%X@8#±#W¾LÊüÞÉe¢÷?´¢dOkÁwUú°3ì¹}c;‚i[j…%îÑES$±­<ąÎ|B]@2|tÂŽ¤õÖ…O¿-ëø•Ìá@fñ°Žçðþ~z𸜗_èFâ;#°­ ¤Hì>Gë×IŽ˜)=ñ޾X韮«¿-âx¥¤2 ò¨ ë€H ~ZýÿiðÈièó嚣ô臮##ÌG蟒}—-Ój°]!­‡sUGKIõÒfX3+J«·E8$uÈÁ#T=ûo°ÙvõŠ ·2ÍI,ÓÔ{@”JgršFqÑŽ‚@Æ1Ó]·Å—|XkmwÛG ­<TÃøÉ"爿*H)(Kg”à}sV¼ÒClÛ4t-º¢¾Ü²¢²ºt„À¢IŽXãìcÏï«ü›+Åa±1É l¯Ÿø…ûŠG7ªý¶—jÛý­â‘ûSgÿm\ãätz³hšŸ„;ŠàGJýÉ(SóÓÀ£L“¢ÿ•õ}‰73»¤ÞôêÛÍôw¾Nf¶ÔÑWŒy‰ú‘å¯.k­Ó]ÑŠóÉ4PC’"VyU',yFOSœ kÙ¾-mx÷¯ ÷.Õ’>quµÔÒªÿ}£!1õæÆ¼z¨Üà¹\„³TA$nDl!’7‰X/ÂÁ†A àŽ£Sð2B0ïk¯]Šé\þÜ”)YŠ8¸ÜÂ<Ηjïm$mÜÇŠo»¶…ßaî%Û·–†wzT«Š¦Ÿ›Ãq’A=È`AÔ}Κ®Õi·]« >Í ôÊ®]ÌBFˆ¹ rŒ:0*NqƒMn›…Ãt_g¾Üëk«jfè%«‘YÂùU@%P5ö®x_l¦Û¥žåì~ÑímA7†ÔñÏæñ±ø†{•|‰`º]©šUp½RÛ®5k3øôΫI*˜œ|=%cñ‚r@)Œ~!œYögwG¤¹E¶(¢—Ýp¥ç”Ï‚R5RrY‚œ`c#ëÒµ§uJ×%ôwà9ýšZ~ÂAØ‹N!à'" ì½1ø¢fò3¥¥¢sqJÓØx+ÂHˆðêÂ>ôjÏR´<+á­4Ê`ØV*AèèOÓýÝ--£ctàì¶{Ž—ÄB <ÈN$¢¡ÆH2©H;blt-2.4z.orig/demos/images/mini-doc.gif0100644000175000017500000000013307240160073016502 0ustar dokodokoGIF87añ¿¿¿ÿÿÿ,4„ƒÆ!jNŒ+Þ¢àÅœpÏ…]Á@yŸ„V$™µŒºž©õñ½²w®³Uz;‡â(c_†;blt-2.4z.orig/demos/images/mini-filemgr.gif0100644000175000017500000000015207240160073017363 0ustar dokodokoGIF87aò¿¿¿ÿÿÿÙÙÙ,7ºÜ0F†½<É5 B(Ù#¨EÞ^jù ð°¶ ‹î·)†½Ù.Æ2ÕH¸ †rx } imagemask grestore 0.500008 0.500008 0.500008 SetBgColor 421 154 121 2 Box Fill 540 86 2 70 Box Fill 0.750011 0.750011 0.750011 SetBgColor newpath 421 156 moveto 421 86 lineto 542 86 lineto 540 88 lineto 423 88 lineto 423 154 lineto 421 156 lineto 421 156 lineto closepath Fill 0 setlinejoin 0 setlinecap 0 0 0 SetFgColor 3 setlinewidth [ ] 0 setdash 448 102 42 Li 1 setlinewidth [ ] 0 setdash /DrawSymbolProc { gsave 0.996109 0.644541 0 SetBgColor Fill 0 0 0 SetFgColor stroke grestore } def 448 102 21 Ci 58 27 0 502 104 BeginText 14 /Helvetica SetFont 0 0 0 SetFgColor (sin\(x\)) 58 0 21 DrawAdjText EndText 0 setlinejoin 0 setlinecap 0.542977 0.542977 0 SetFgColor 3 setlinewidth [ ] 0 setdash 448 135 42 Li 1 setlinewidth [ ] 0 setdash /DrawSymbolProc { gsave 0.996109 0.996109 0 SetBgColor Fill 0.542977 0.542977 0 SetFgColor stroke grestore } def 448 135 21 Ci 64 27 0 505 137 BeginText 14 /Helvetica SetFont 0 0 0 SetFgColor (cos\(x\)) 64 0 21 DrawAdjText EndText 24 16 90 537 388 BeginText 8 /CourierNewBold-Bold SetFont 0 0 0 SetFgColor (360) 24 0 12 DrawAdjText EndText 32 16 90 79 384 BeginText 8 /CourierNewBold-Bold SetFont 0 0 0 SetFgColor (-360) 32 0 12 DrawAdjText EndText 8 16 0 85 90 BeginText 8 /CourierNewBold-Bold SetFont 0.566415 0.171878 0.929702 SetFgColor (1) 8 0 12 DrawAdjText EndText 16 16 0 89 402 BeginText 8 /CourierNewBold-Bold SetFont 0.566415 0.171878 0.929702 SetFgColor (-1) 16 0 12 DrawAdjText EndText 8 16 90 537 364 BeginText 8 /CourierNewBold-Bold SetFont 0 0 0 SetFgColor (1) 8 0 12 DrawAdjText EndText 8 16 90 79 356 BeginText 8 /CourierNewBold-Bold SetFont 0 0 0 SetFgColor (0) 8 0 12 DrawAdjText EndText 8 16 0 101 90 BeginText 8 /CourierNewBold-Bold SetFont 0 0 0 SetFgColor (1) 8 0 12 DrawAdjText EndText 8 16 0 109 402 BeginText 8 /CourierNewBold-Bold SetFont 0 0 0 SetFgColor (0) 8 0 12 DrawAdjText EndText % Element "line2" 0 setlinejoin 0 setlinecap 0.542977 0.542977 0 SetFgColor 1 setlinewidth [ ] 0 setdash /DashesProc {} def newpath 79 90 moveto 82 90 lineto 85 92 lineto 88 95 lineto 91 99 lineto 94 104 lineto 98 110 lineto 101 118 lineto 104 126 lineto 107 135 lineto 110 145 lineto 114 156 lineto 117 168 lineto 120 180 lineto 123 192 lineto 126 205 lineto 130 219 lineto 133 232 lineto 136 246 lineto 139 260 lineto 142 273 lineto 145 287 lineto 149 300 lineto 152 312 lineto 155 324 lineto 158 336 lineto 161 347 lineto 165 357 lineto 168 366 lineto 171 374 lineto 174 382 lineto 177 388 lineto 181 393 lineto 184 397 lineto 187 400 lineto 190 402 lineto 193 403 lineto 196 402 lineto 200 400 lineto 203 397 lineto 206 393 lineto 209 388 lineto 212 382 lineto 216 374 lineto 219 366 lineto 222 357 lineto 225 347 lineto 228 336 lineto 232 324 lineto 235 312 lineto 238 300 lineto 241 287 lineto 244 273 lineto 247 260 lineto 251 246 lineto 254 232 lineto 257 219 lineto 260 205 lineto 263 192 lineto 267 180 lineto 270 168 lineto 273 156 lineto 276 145 lineto 279 135 lineto 283 126 lineto 286 118 lineto 289 110 lineto 292 104 lineto 295 99 lineto 298 95 lineto 302 92 lineto 305 90 lineto 308 90 lineto 311 90 lineto 314 92 lineto 318 95 lineto 321 99 lineto 324 104 lineto 327 110 lineto 330 118 lineto 334 126 lineto 337 135 lineto 340 145 lineto 343 156 lineto 346 168 lineto 349 180 lineto 353 192 lineto 356 205 lineto 359 219 lineto 362 232 lineto 365 246 lineto 369 260 lineto 372 273 lineto 375 287 lineto 378 300 lineto 381 312 lineto 385 324 lineto 388 336 lineto 391 347 lineto 394 357 lineto 397 366 lineto 400 374 lineto 404 382 lineto 407 388 lineto 410 393 lineto 413 397 lineto 416 400 lineto 420 402 lineto 423 403 lineto 426 402 lineto 429 400 lineto 432 397 lineto 436 393 lineto 439 388 lineto 442 382 lineto 445 374 lineto 448 366 lineto 451 357 lineto 455 347 lineto 458 336 lineto 461 324 lineto 464 312 lineto 467 300 lineto 471 287 lineto 474 273 lineto 477 260 lineto 480 246 lineto 483 232 lineto 487 219 lineto 490 205 lineto 493 192 lineto 496 180 lineto 499 168 lineto 502 156 lineto 506 145 lineto 509 135 lineto 512 126 lineto 515 118 lineto 518 110 lineto 522 104 lineto 525 99 lineto 528 95 lineto 531 92 lineto 534 90 lineto 538 90 lineto DashesProc stroke 1 setlinewidth [ ] 0 setdash /DrawSymbolProc { gsave 0.996109 0.996109 0 SetBgColor Fill 0.542977 0.542977 0 SetFgColor stroke grestore } def 79 90 9 Ci 82 90 9 Ci 85 92 9 Ci 88 95 9 Ci 91 99 9 Ci 94 104 9 Ci 98 110 9 Ci 101 118 9 Ci 104 126 9 Ci 107 135 9 Ci 110 145 9 Ci 114 156 9 Ci 117 168 9 Ci 120 180 9 Ci 123 192 9 Ci 126 205 9 Ci 130 219 9 Ci 133 232 9 Ci 136 246 9 Ci 139 260 9 Ci 142 273 9 Ci 145 287 9 Ci 149 300 9 Ci 152 312 9 Ci 155 324 9 Ci 158 336 9 Ci 161 347 9 Ci 165 357 9 Ci 168 366 9 Ci 171 374 9 Ci 174 382 9 Ci 177 388 9 Ci 181 393 9 Ci 184 397 9 Ci 187 400 9 Ci 190 402 9 Ci 193 403 9 Ci 196 402 9 Ci 200 400 9 Ci 203 397 9 Ci 206 393 9 Ci 209 388 9 Ci 212 382 9 Ci 216 374 9 Ci 219 366 9 Ci 222 357 9 Ci 225 347 9 Ci 228 336 9 Ci 232 324 9 Ci 235 312 9 Ci 238 300 9 Ci 241 287 9 Ci 244 273 9 Ci 247 260 9 Ci 251 246 9 Ci 254 232 9 Ci 257 219 9 Ci 260 205 9 Ci 263 192 9 Ci 267 180 9 Ci 270 168 9 Ci 273 156 9 Ci 276 145 9 Ci 279 135 9 Ci 283 126 9 Ci 286 118 9 Ci 289 110 9 Ci 292 104 9 Ci 295 99 9 Ci 298 95 9 Ci 302 92 9 Ci 305 90 9 Ci 308 90 9 Ci 311 90 9 Ci 314 92 9 Ci 318 95 9 Ci 321 99 9 Ci 324 104 9 Ci 327 110 9 Ci 330 118 9 Ci 334 126 9 Ci 337 135 9 Ci 340 145 9 Ci 343 156 9 Ci 346 168 9 Ci 349 180 9 Ci 353 192 9 Ci 356 205 9 Ci 359 219 9 Ci 362 232 9 Ci 365 246 9 Ci 369 260 9 Ci 372 273 9 Ci 375 287 9 Ci 378 300 9 Ci 381 312 9 Ci 385 324 9 Ci 388 336 9 Ci 391 347 9 Ci 394 357 9 Ci 397 366 9 Ci 400 374 9 Ci 404 382 9 Ci 407 388 9 Ci 410 393 9 Ci 413 397 9 Ci 416 400 9 Ci 420 402 9 Ci 423 403 9 Ci 426 402 9 Ci 429 400 9 Ci 432 397 9 Ci 436 393 9 Ci 439 388 9 Ci 442 382 9 Ci 445 374 9 Ci 448 366 9 Ci 451 357 9 Ci 455 347 9 Ci 458 336 9 Ci 461 324 9 Ci 464 312 9 Ci 467 300 9 Ci 471 287 9 Ci 474 273 9 Ci 477 260 9 Ci 480 246 9 Ci 483 232 9 Ci 487 219 9 Ci 490 205 9 Ci 493 192 9 Ci 496 180 9 Ci 499 168 9 Ci 502 156 9 Ci 506 145 9 Ci 509 135 9 Ci 512 126 9 Ci 515 118 9 Ci 518 110 9 Ci 522 104 9 Ci 525 99 9 Ci 528 95 9 Ci 531 92 9 Ci 534 90 9 Ci 538 90 9 Ci % Element "line1" 0 setlinejoin 0 setlinecap 0 0 0 SetFgColor 1 setlinewidth [ ] 0 setdash /DashesProc {} def newpath 79 246 moveto 82 232 lineto 85 219 lineto 88 205 lineto 91 192 lineto 94 180 lineto 98 168 lineto 101 156 lineto 104 145 lineto 107 135 lineto 110 126 lineto 114 118 lineto 117 110 lineto 120 104 lineto 123 99 lineto 126 95 lineto 130 92 lineto 133 90 lineto 136 90 lineto 139 90 lineto 142 92 lineto 145 95 lineto 149 99 lineto 152 104 lineto 155 110 lineto 158 118 lineto 161 126 lineto 165 135 lineto 168 145 lineto 171 156 lineto 174 168 lineto 177 180 lineto 181 192 lineto 184 205 lineto 187 219 lineto 190 232 lineto 193 246 lineto 196 260 lineto 200 273 lineto 203 287 lineto 206 300 lineto 209 312 lineto 212 324 lineto 216 336 lineto 219 347 lineto 222 357 lineto 225 366 lineto 228 374 lineto 232 382 lineto 235 388 lineto 238 393 lineto 241 397 lineto 244 400 lineto 247 402 lineto 251 403 lineto 254 402 lineto 257 400 lineto 260 397 lineto 263 393 lineto 267 388 lineto 270 382 lineto 273 374 lineto 276 366 lineto 279 357 lineto 283 347 lineto 286 336 lineto 289 324 lineto 292 312 lineto 295 300 lineto 298 287 lineto 302 273 lineto 305 260 lineto 308 246 lineto 311 232 lineto 314 219 lineto 318 205 lineto 321 192 lineto 324 180 lineto 327 168 lineto 330 156 lineto 334 145 lineto 337 135 lineto 340 126 lineto 343 118 lineto 346 110 lineto 349 104 lineto 353 99 lineto 356 95 lineto 359 92 lineto 362 90 lineto 365 90 lineto 369 90 lineto 372 92 lineto 375 95 lineto 378 99 lineto 381 104 lineto 385 110 lineto 388 118 lineto 391 126 lineto 394 135 lineto 397 145 lineto 400 156 lineto 404 168 lineto 407 180 lineto 410 192 lineto 413 205 lineto 416 219 lineto 420 232 lineto 423 246 lineto 426 260 lineto 429 273 lineto 432 287 lineto 436 300 lineto 439 312 lineto 442 324 lineto 445 336 lineto 448 347 lineto 451 357 lineto 455 366 lineto 458 374 lineto 461 382 lineto 464 388 lineto 467 393 lineto 471 397 lineto 474 400 lineto 477 402 lineto 480 403 lineto 483 402 lineto 487 400 lineto 490 397 lineto 493 393 lineto 496 388 lineto 499 382 lineto 502 374 lineto 506 366 lineto 509 357 lineto 512 347 lineto 515 336 lineto 518 324 lineto 522 312 lineto 525 300 lineto 528 287 lineto 531 273 lineto 534 260 lineto 538 246 lineto DashesProc stroke 1 setlinewidth [ ] 0 setdash /DrawSymbolProc { gsave 0.996109 0.644541 0 SetBgColor Fill 0 0 0 SetFgColor stroke grestore } def 79 246 9 Ci 82 232 9 Ci 85 219 9 Ci 88 205 9 Ci 91 192 9 Ci 94 180 9 Ci 98 168 9 Ci 101 156 9 Ci 104 145 9 Ci 107 135 9 Ci 110 126 9 Ci 114 118 9 Ci 117 110 9 Ci 120 104 9 Ci 123 99 9 Ci 126 95 9 Ci 130 92 9 Ci 133 90 9 Ci 136 90 9 Ci 139 90 9 Ci 142 92 9 Ci 145 95 9 Ci 149 99 9 Ci 152 104 9 Ci 155 110 9 Ci 158 118 9 Ci 161 126 9 Ci 165 135 9 Ci 168 145 9 Ci 171 156 9 Ci 174 168 9 Ci 177 180 9 Ci 181 192 9 Ci 184 205 9 Ci 187 219 9 Ci 190 232 9 Ci 193 246 9 Ci 196 260 9 Ci 200 273 9 Ci 203 287 9 Ci 206 300 9 Ci 209 312 9 Ci 212 324 9 Ci 216 336 9 Ci 219 347 9 Ci 222 357 9 Ci 225 366 9 Ci 228 374 9 Ci 232 382 9 Ci 235 388 9 Ci 238 393 9 Ci 241 397 9 Ci 244 400 9 Ci 247 402 9 Ci 251 403 9 Ci 254 402 9 Ci 257 400 9 Ci 260 397 9 Ci 263 393 9 Ci 267 388 9 Ci 270 382 9 Ci 273 374 9 Ci 276 366 9 Ci 279 357 9 Ci 283 347 9 Ci 286 336 9 Ci 289 324 9 Ci 292 312 9 Ci 295 300 9 Ci 298 287 9 Ci 302 273 9 Ci 305 260 9 Ci 308 246 9 Ci 311 232 9 Ci 314 219 9 Ci 318 205 9 Ci 321 192 9 Ci 324 180 9 Ci 327 168 9 Ci 330 156 9 Ci 334 145 9 Ci 337 135 9 Ci 340 126 9 Ci 343 118 9 Ci 346 110 9 Ci 349 104 9 Ci 353 99 9 Ci 356 95 9 Ci 359 92 9 Ci 362 90 9 Ci 365 90 9 Ci 369 90 9 Ci 372 92 9 Ci 375 95 9 Ci 378 99 9 Ci 381 104 9 Ci 385 110 9 Ci 388 118 9 Ci 391 126 9 Ci 394 135 9 Ci 397 145 9 Ci 400 156 9 Ci 404 168 9 Ci 407 180 9 Ci 410 192 9 Ci 413 205 9 Ci 416 219 9 Ci 420 232 9 Ci 423 246 9 Ci 426 260 9 Ci 429 273 9 Ci 432 287 9 Ci 436 300 9 Ci 439 312 9 Ci 442 324 9 Ci 445 336 9 Ci 448 347 9 Ci 451 357 9 Ci 455 366 9 Ci 458 374 9 Ci 461 382 9 Ci 464 388 9 Ci 467 393 9 Ci 471 397 9 Ci 474 400 9 Ci 477 402 9 Ci 480 403 9 Ci 483 402 9 Ci 487 400 9 Ci 490 397 9 Ci 493 393 9 Ci 496 388 9 Ci 499 382 9 Ci 502 374 9 Ci 506 366 9 Ci 509 357 9 Ci 512 347 9 Ci 515 336 9 Ci 518 324 9 Ci 522 312 9 Ci 525 300 9 Ci 528 287 9 Ci 531 273 9 Ci 534 260 9 Ci 538 246 9 Ci % Unset clipping grestore 0.750011 0.750011 0.750011 SetBgColor 0 0 598 82 Box Fill 0 82 70 329 Box Fill 546 82 52 329 Box Fill 0 411 598 68 Box Fill 0.500008 0.500008 0.500008 SetBgColor 69 410 478 2 Box Fill 545 80 2 332 Box Fill 0.750011 0.750011 0.750011 SetBgColor newpath 69 412 moveto 69 80 lineto 547 80 lineto 545 82 lineto 71 82 lineto 71 410 lineto 69 412 lineto 69 412 lineto closepath Fill 311 29 0 308 20 BeginText 14 /Helvetica-Bold SetFont 0 0 0 SetFgColor (Sine and Cosine Functions) 311 0 23 DrawAdjText EndText 7 16 0 308 463 BeginText 8 /Helvetica SetFont 0 0 0 SetFgColor (X) 7 0 13 DrawAdjText EndText 40 16 0 79 441 BeginText 8 /CourierNewBold-Bold SetFont 0 0 0 SetFgColor (-360°) 40 0 12 DrawAdjText EndText 40 16 0 136 441 BeginText 8 /CourierNewBold-Bold SetFont 0 0 0 SetFgColor (-270°) 40 0 12 DrawAdjText EndText 40 16 0 193 441 BeginText 8 /CourierNewBold-Bold SetFont 0 0 0 SetFgColor (-180°) 40 0 12 DrawAdjText EndText 32 16 0 251 441 BeginText 8 /CourierNewBold-Bold SetFont 0 0 0 SetFgColor (-90°) 32 0 12 DrawAdjText EndText 16 16 0 308 441 BeginText 8 /CourierNewBold-Bold SetFont 0 0 0 SetFgColor (0°) 16 0 12 DrawAdjText EndText 24 16 0 365 441 BeginText 8 /CourierNewBold-Bold SetFont 0 0 0 SetFgColor (90°) 24 0 12 DrawAdjText EndText 32 16 0 423 441 BeginText 8 /CourierNewBold-Bold SetFont 0 0 0 SetFgColor (180°) 32 0 12 DrawAdjText EndText 32 16 0 480 441 BeginText 8 /CourierNewBold-Bold SetFont 0 0 0 SetFgColor (270°) 32 0 12 DrawAdjText EndText 32 16 0 538 441 BeginText 8 /CourierNewBold-Bold SetFont 0 0 0 SetFgColor (360°) 32 0 12 DrawAdjText EndText 0 setlinejoin 0 setlinecap 0 0 0 SetFgColor 1 setlinewidth [ ] 0 setdash 79 416 538 416 LS 79 416 79 428 LS 136 416 136 428 LS 193 416 193 428 LS 251 416 251 428 LS 308 416 308 428 LS 365 416 365 428 LS 423 416 423 428 LS 480 416 480 428 LS 538 416 538 428 LS 9 16 90 18 246 BeginText 8 /Helvetica SetFont 0.566415 0.171878 0.929702 SetFgColor (Y) 9 0 13 DrawAdjText EndText 16 16 90 40 403 BeginText 8 /CourierNewBold-Bold SetFont 0.566415 0.171878 0.929702 SetFgColor (-1) 16 0 12 DrawAdjText EndText 32 16 90 40 324 BeginText 8 /CourierNewBold-Bold SetFont 0.566415 0.171878 0.929702 SetFgColor (-0.5) 32 0 12 DrawAdjText EndText 8 16 90 40 246 BeginText 8 /CourierNewBold-Bold SetFont 0.566415 0.171878 0.929702 SetFgColor (0) 8 0 12 DrawAdjText EndText 24 16 90 40 168 BeginText 8 /CourierNewBold-Bold SetFont 0.566415 0.171878 0.929702 SetFgColor (0.5) 24 0 12 DrawAdjText EndText 8 16 90 40 90 BeginText 8 /CourierNewBold-Bold SetFont 0.566415 0.171878 0.929702 SetFgColor (1) 8 0 12 DrawAdjText EndText 0 setlinejoin 0 setlinecap 0.566415 0.171878 0.929702 SetFgColor 1 setlinewidth [ ] 0 setdash 65 403 65 90 LS 65 363 59 363 LS 65 403 53 403 LS 65 285 59 285 LS 65 324 53 324 LS 65 207 59 207 LS 65 246 53 246 LS 65 129 59 129 LS 65 168 53 168 LS 65 90 53 90 LS 8 16 0 79 51 BeginText 8 /CourierNewBold-Bold SetFont 0 0 0 SetFgColor (0) 8 0 12 DrawAdjText EndText 24 16 0 170 51 BeginText 8 /CourierNewBold-Bold SetFont 0 0 0 SetFgColor (0.2) 24 0 12 DrawAdjText EndText 24 16 0 262 51 BeginText 8 /CourierNewBold-Bold SetFont 0 0 0 SetFgColor (0.4) 24 0 12 DrawAdjText EndText 24 16 0 354 51 BeginText 8 /CourierNewBold-Bold SetFont 0 0 0 SetFgColor (0.6) 24 0 12 DrawAdjText EndText 24 16 0 446 51 BeginText 8 /CourierNewBold-Bold SetFont 0 0 0 SetFgColor (0.8) 24 0 12 DrawAdjText EndText 8 16 0 538 51 BeginText 8 /CourierNewBold-Bold SetFont 0 0 0 SetFgColor (1) 8 0 12 DrawAdjText EndText 0 setlinejoin 0 setlinecap 0 0 0 SetFgColor 1 setlinewidth [ ] 0 setdash 79 76 538 76 LS 124 76 124 70 LS 79 76 79 64 LS 216 76 216 70 LS 170 76 170 64 LS 308 76 308 70 LS 262 76 262 64 LS 400 76 400 70 LS 354 76 354 64 LS 492 76 492 70 LS 446 76 446 64 LS 538 76 538 64 LS 8 16 0 572 403 BeginText 8 /CourierNewBold-Bold SetFont 0.800793 0 0.800793 SetFgColor (0) 8 0 12 DrawAdjText EndText 24 16 0 580 340 BeginText 8 /CourierNewBold-Bold SetFont 0.800793 0 0.800793 SetFgColor (0.2) 24 0 12 DrawAdjText EndText 24 16 0 580 277 BeginText 8 /CourierNewBold-Bold SetFont 0.800793 0 0.800793 SetFgColor (0.4) 24 0 12 DrawAdjText EndText 24 16 0 580 215 BeginText 8 /CourierNewBold-Bold SetFont 0.800793 0 0.800793 SetFgColor (0.6) 24 0 12 DrawAdjText EndText 24 16 0 580 152 BeginText 8 /CourierNewBold-Bold SetFont 0.800793 0 0.800793 SetFgColor (0.8) 24 0 12 DrawAdjText EndText 8 16 0 572 90 BeginText 8 /CourierNewBold-Bold SetFont 0.800793 0 0.800793 SetFgColor (1) 8 0 12 DrawAdjText EndText 0 setlinejoin 0 setlinecap 0.800793 0 0.800793 SetFgColor 1 setlinewidth [ ] 0 setdash 551 403 551 90 LS 551 371 557 371 LS 551 403 563 403 LS 551 309 557 309 LS 551 340 563 340 LS 551 246 557 246 LS 551 277 563 277 LS 551 183 557 183 LS 551 215 563 215 LS 551 121 557 121 LS 551 152 563 152 LS 551 90 563 90 LS showpage %Trailer grestore end %EOF blt-2.4z.orig/demos/images/qv100.t.gif0100644000175000017500000000520607240160074016123 0ustar dokodokoGIF87aD&÷ÿÿÿ÷÷÷ïïïçççÞÞÞÖÖÖ¥¥¥”””„„„{{{sssZZZJJJBBB999111)))!!!çÞÞÞÖÖÖÎÎÆ½½­¥¥œ””Œ„„skkƵµRJJïÖÖµœœ911­””1)))!!!­{{¥sssJJZ99Þ„„R11)ŒJJZ!!kZB9)!½cZ­RJŒ91cçcRŒZRœcZ„JB{B9½RBR)!÷{cB÷­œÎ„sïsZέ¥Ö”„÷{Z1ÿŒkÆZ9Þ”{ï„cÞ{ZÞsRÎkJc1!„ZJ„B)s1ŒcRÿœs”ZBŒ{sÿÆ­J91ÿ¥{R1!!Æ”{ÿ½”{cR1)!÷çÎ1!Þ¥1)!ç¥Î¥)Þµ!Ö­Æœÿ÷ÎskBµœ)ïç­Æµ1εÿ÷µRRJJJBBB999111)ïï½199B!BRÎÞµJs1ZŒ9Bc1k{ckœZZ”J„­{{­sÞ÷ÞŒµŒÆÖÎ!1)cŒ{ÎïçÖÞÞŒ””Zcc!!)ZcŒ¥1RZ)k{)cs!sŒ)Rcs„Œ1BJÖïÿŒµÎ{”¥)Z{½Þ÷œ½Ö9c„¥Î­9BJ!9­½ÎBJR)19ŒµÞ)B!sƵ½Æ”œ¥s{„19BJRc!k!{÷÷ÿÖÖÞÎÎÖµµ½½½Æ¥¥­œœ¥””œŒŒ”„„Œss{{{„kksÖÖçcck½½ÎRRZZZcJJRBBJ{{Œkk{99B119ÞÖçÎÆÖ”Œœÿ÷ÿ÷ï÷ïçïÞÖÞÖÎÖÎÆÎ½µ½Æ½Æµ­µ­¥­„{„sksRJRçÎç„s„÷çïÖÆÎ½­µZJRsRcƵ½„s{!祽œ„Œ¥Œ”ÿÆÖÿ¥½Æ¥­Þœ­ÿµÆ÷Œ¥Þµ½µŒ”ŒcksJR½k{¥Rcï½ÆçŒœÆcs÷­µ­ckÎs{,D&þH° Áƒ*\Ȱ¡Ã‡#JœàY‹(ð ¶^¿zõÒåà#¯^wíJ°‹—.] TÛÕ˶.uaË¥ëšO]ÛèJ´Z­[̘ÝÚ5,BixåšÊ,×kIJٲUÍšWkО [¡›4¯]«Ù²f 1^Ö¶Ú¢e­Ö4i¤á’“ 3€%PppÐÚƒaÛx)^Ìì…kHvì)SÙÛlØæc˜ÕZ¦¬Wâ]Ì~5Vyš·Å5p+Á} 6"ÑkÖ2iË¢E“&-›>\˜™cv@.¸(a€ÙsÀÐ(à ŽWqþ@»nÀVù ^¾ÌåÀ΃%z5C¨K€fÍbáß/¿þùûÍÇ0ÀàŒ0¿ü¢K4ÎÜ7ß@ÿÝ÷Ì/p`/ÕT@4@0ú(Ü2$’ ‰²Wâo%ÐÈ/<@Ì1ÃãK-ЬH"0Ë@3 ¡8€A@À¡@0 /ÀHC ).Ã#WS‹–Z>£26À1¶Ì"ËŽQc,Í0£ 3¬äA6MãL,ÓdH 5ÒdÈ „›5ÓPSK-{î)¥¢Ò˜E\£R^Í,Ò$Ù¥—6P¹dcÇšÙ7Ï8c 5FI#Ü4ÌL lþ (“q‡$Êç£ÒPšk”^ðè- Ó 4[± SB¶Dð¢ dÎ3Ê|ÍXҰꪼ8pL±Äƒ¬¸à{ì°È6 .˜8°@0çjF ô2à,ˆÕ"Ö\D£2µ0cËŽ8Ð-H ð¸Úð®N qÄŒ#—4F¬¹Æ>P/ÎfCA¤Ê’A5ÌJ 3ÂØB °ÒÀ0K@ÔÍ8ç,ñœöÒû 2°-Y@ÀJ{ÃŒ<5Ï,cËI , Ì7¿Üò²0Â0à Ñ‚Ê)™DJ,±,9>,2ìÂÀ0ÐáîÐTœ ÄD@þÓÑ`Í.)ð -V;òK0`&s ‰'§ÀªÄÍÙ‚¬„´À³ #,híÁ1TÍzU“g†yâòr#bF q´4€"FJSÀ!p BMLÅÈÄh¬d ]º¨us¾·2Ë0“!-Ӽދ«¿8À€#· ÌÍh$FXA]\°À5åt `À]´f˜ mlòíê½´2+K‹5èbíI@ ÆÄìS8 a~Èä Œlăú 5Ú6 D`uƒþò‡©ÔáYþH5¨ Y£+tù“²!,‰%ƒjHC A>àþs Rà… ´#hK†#ìd4Oh—â_ÑŽ‘Âô0e_qá-$–.P n¸ƒ" ‡=`zÐC¸ 0!ŒÀ Њå‘P2È8aŒPE°°*‹_¹Eô¦@‰a0 8ØB(‡<èp9îqzÔƒIü àDL‰îRíŠQÿTZàâ+¨\Å(¦9LŒ+ØAœpƒ? ˆ@€<Ôu¨ãèà ñ"À®v…Ž„@å(2hP㔨ôŠ )@ d£a·IœPƒ/˜@YàÂ1„àpl0G>:„í1Ét@¤ˆ:‚P#ÀþÐÀ-öy ìLÓXy£À#ô¡…)a 9ÈÂ;¬0GD B … š1„tPF›,á1©Ìv£¹À2Vf«D1£a€âôá.Ü óž…ièÃ10‡|p\”hïÐŽùIQzK0€½j`/{·pÄ`¸µÛÀâœ`@”€ÈC¡€9Ð Ta~ÉèXŒB`‡OEo¨¡‹Є‘: GÖ{]W¬ÁŒPÀ‰šI(ð4c\â›8lœŠQ Vl"Â(F(Ð&bÔ“˜…$ðèIN*ðq˜¡××E•! ¶J} VŽ€þÀ#&GŒ@0ƒ¬«ðÂ@B &Z‰R´‚“—õ^#¨1gP£z.ÌSo „aË®0†1ŒR`2Ùߊ%Ê@–€%&ÁÞÍÖbj@A¨Ñ[dkvÉ.ªJP1v1¼`…1DB·„ÞáE1@ù€”â˜M.%¨Ëã(È4fa Üâ9ý¤Mu/#˜Xmj3±Š‘Å€Ì!¾sè(2BÀÖ G1z BF, ¢ hÈb-ÖÈ›5c^HN2½ŽìšM"ù“áhžÏ¢ÍÁ ·J ì@‡.w¹«dÀ1ò8Tþ…@®D­Ãr„üÞ¸^*¬eXœ#s „ ÈYXIÐâbm&]€V ÉE.p= HaDUp‘‹çТ³¨3E °€@R{Q6ÆÄ€l # F0¢&ê #j ÐÀÊq€làÕâ@®‘”CCɵ®;blt-2.4z.orig/demos/images/rain.gif0100644000175000017500000000731107240160074015742 0ustar dokodokoGIF87allãÿÿÿÄæÿ”Ëÿ¼àÿ³Úÿ©ÓÿˆÄÿw¼ÿŸËÿ”Äÿˆ¼ÿw³ÿŸÿf©ÿ?Ÿÿ,ll@ÿP™„’º) Äy¦ÕVp1vee`–‚…®Ê×Nš½Uv¦@ç°¸(ŠÜëd¬Y‡æb«yž5Úg‚µ|Ó&¦ó [ËÈ/(Áå5#–š¦Œ2]֢јNùP~@|…†|Dˆ|Œƒ}Q6†EN~T^x2;"0¡Î4ôÓo–üpA[¯­ÂuZ\é;è¡:jeS>’…‘LÝCåTx™¨ÐsÒ6Vf %Ðþ¤WGÍíÓÑ=ù8§Z%ª–jL:µFÚJ5–XÜIP¡ª‰€6YJ^OQEUQ²U­:ÿ@´šg°Äåd¤ï¡S¤í¡ÀÞ¦ZÑ€JkÒj2Ñ€éÄp DYWŒ…î¤ö'ֈè·«±† B HFlcÅפäv…w,(¶ ‘}cÊa/ö8F*žè´ar6ø Ä·k„N°0k¾®9F~apƒÖ‚7(DØ »1.MÐqÀþ í¾vá“€³òZ­¿<ídŠQÀG^ùgÜ­Ac¤Ít@HªÁD=òxÕPOÝq–£'€Z~‡!5,oæqÁˆý‘Ë«CQÝÉÖªR¹Ë¢ˆ^Q êŒüE"¡Z\üƒ!ßµ,êŠWÔjiÀ›µ@*^ÿסiš­)Dÿe”h¸"h!á•jgÐÆ/T±9Ne[yWIèy†æ*¯ÁÅ0z¾(¸eДØÃ‘+–¡è7Ù–5Í%%Æ–€%‘ÈðdíæJ½W(/×'ÞH ÷¡cDü–‹÷]~ þ-} ÿ ¶RÉb6 S}mvî´´£XÖø^v ¦˜‡ S¦[$p˜ûàÄ$u¡_@Ó„â »0,O+ˆ…~Æç½?„‰|T#±#àõGz‚øF8•÷¤Ç[d‘èp×96Œ/u&̈ I?oÝ3œÐe lÐÁ¦Ô•Ôd„C qE¤·ŸÚªG Ǻl°vÿ@$YÑš²`µ£´ËVë ¸î@ ý}j]òr3¦Ê”ŠGsàñªÈŠYvQ ¥LC6žLTT’Rqî4Š(玒òãûF¬åZi¬È+Ä®Ä.K#_¶¬Õ#ŒJ|N¦ÀG5…DÍxîØ,$RëTÝåМ’U²Iy–Hx6*ˆÔch£r ¶Ò•D\½ðn()Gi®3Ë3V¼t [¨5ž°'SM©T3½R«Xƒ3¥‘YWŠY_ü$› 2Þ¾H«¯(3kщÝZI†b¾ä.úòÄkÖ™³¹9Ãt8Ø+CH¥á¬ © ‘u s”ÿ’DAT´ƒ¼.Õ¾Dš³íê-p)€¢3ÇEþI KË ¯™Óí ‘ _Ú.èƒ'9f1l†½ôE FhwR»×[83†Åm 2˜“7˜ö,‘!GlÊ!p”º¡rf4«Ü œ€ÐBK; Ì ,6›hh¬%RLi½«ž9åÛ¼N7™©UãÓ:Îo¡¡À+3ÅŒµ:%8¹ ÐAwÑnÃ?`ø¢LÚi¥†ÖrÖ÷¯ºå]¾ªÕ1Œ¶&K´5afxX7¤f’lMË’êg¦ZuL–p =Ty js嬺h0lêV¶g!ª5+SÚÿJ×ÖsFžð‚™ÈdMÁ±ªBH"R$Ü0°NâüäŸ\\$+‹ÅÏÚøê4E‹v Å´‰u@y±ùîCû†.^–à - ËvÁ­ +-ÔÏÚ ÃUÕtJ3BR'U-n¨¯Vüjîu¯þîè$ô9—–aZpª|XgµÇ¹¦eİÎTq`£€ê`E^ï žG ÄË½Ø csÖÍ žá’pŒk}ÅE‰åBOSvïž<Û ÁX³ÙØDÉ4xZë(þÃd°žæ0³‹òÍp…÷H­lPBëŽÖ9X„Œ7æYI}ái¶;tr…P ƒ$ òYÊAÞ±ÿöÆZ¸ˆÏ»Hê  ¥gp¼Ùx²ëDkÇðh(hàzsm²Ú$9ÙF¦ƒ^‘¨À‹-( É=0`}@H16êÒZûiñ¶T3rŽZèX3Š+pL±`òܤA7!„ExEI_M$ÈðšÁ‰å a×d#dô ¼¡Â¤ÀôµÂ€³ˆ¶÷VëjOÚÓ€é+…‡#6CJÁ¡Ü$ø‡lŠI€Eh@ ¨îHÃéK ªçdÏ¢iå6”v†Ì·\ô»Ü³ Å«®ñ9ŒÚ œ´œ² ÷ Ë5¤¸"¾·ä?{éƒæ¡ÎqZǼ¯`ÚwfJ¶l…e`$ªP…ÿÄÁ@t°H̸r³€òA‡Áè„ÈÂÇšóe^S)JÒµT»kè«Ù—ØiX¢Lϳ8¬—›e›Ùët t‰­Àù ^ꀚîÂz$¼ŸNˆx5ó¨àTeFnù{¾ØL¯ÍŠá4A å"c 0˜zw@:MÒBÍÇ«Å0ã©´ÆG˜V›ÿT–½> lÖm®»7Œ, °ò9Ô©ûrÊ©>.«"µA"ŠÍ¥µYAŸbF¹³¬£:Áªo}¦WÁ$#G<?l?–&xCÛ2õ˜Œ­cX`ÝŒÕc×^å*æ ŠYÔÈdEnü‚û­‘7pµŽ¡1ÿ~œÿ›’´~”„pÞdÑJÜöפ1ï„ãxDéç{¨¤, ˆ)õQÃÁYQ‚1YÌôæRþ‡ª"HH)ÏR1*Ø7zõ"*Ä% ÂåB¿d)yËR]Ñ!]cD„æ,d“O¸b"*ÁQµtZ¢%%g5ØÆ‚}ð÷K@ˆ*IXKM¨uUósÇ,á/·TO¤r'À¥Lž±PÖ4Gˆ€tZ_x]`Ô[A³MÑ$76PQÇ"­‡Öõ\UèE=ÃŒ—D‘.h x„!6¨§ññXìÔKÅ’{˜¤[=S)¯d½‰fó ›Qÿâ°ÿB7Õ†›fèç5XhF-ˆ£(X† §¨.£ÂÉY댂~=/î Á7æÄ3jåIÂ…Ž8NêB‚bXwÈØKòÁŒ/áŒN ÿáI¹Ò)À)ø×Yçõ…Ä õ„O#GKwõIí@8Ü%cÃveX9aì‚Y`F‰¡$a®óP¥X %.™HSw*xhsy7¸Y_:Vo‰¬­ßšŽRš¶x8D©ØêÖYj9‘©ŠËÚŒ'0ô©«Š:+ÀÅ¿¸œ§,A<þÓH° Áƒ*\È —ãTQiÂ€ŠˆC ¶jõp`ÇŒ%0hrˆÎ8…\ª´J“²JJUÒÄT©r£Ë†)¢  'Q¦L‰sÛ¶¢G[vŒù‘` Z´W%èÀ*.¶2šeã¶%Kü‰ÚÆAÔÖm;>Äjðc :t0:3+N¶*³l“YÅhÝPà¤8PE*Ö”Y²Ä …ugO*‡*ÑÉÂïÙ®9,á`´,Í ;oÎ"ÊŸiK\.f`ˆJʼn”±zÝJÓ¦ÊmXsë–]»UÍš¾ƒ÷-§q̉·— jræÌ“'Ö;]zõmY8Lÿü9»wíà¹þsð'¾¼øX²ÉéCJŽ”N¢ô9Q ;tN¬°°R •(ïÉÒ€8 J#¾@cˆ•d¤VTÕ[‡0PI-°UYeuå¢l©ÄGY%”…*ª0E… ÝÄÒŒ3¶“L4„•U'äae\H`RœquÖJ7ÎÔÔUXÑ1Q9†øÔ!“wÅYL­è"TAUå£R§p[(-„"Y\ ÀEÇn¹y›(EçgKœrTKèEy›XU(t@Ó„&M4¡J„¹ ÙJq¼¥¤œj/)¥Û]ðÆè¢Ä·¨rPa TÛ„¢œrzBg”‰EvÕ±Šþ¬fÇÝvÞÉÊ*䉗+yþ¨Ò 8"H TÐI °@ɲ”4ÐE²È2( öŽØf«- îÉДcRC7¸dAU„’C\S…ˆ®‡º}ÈæP. ¥-fÑB0"”ä8–{ZÜÕãU0AÚ×6» hÔQ¿-*0L½›‘Ä“Ø=œewXbæn7R…ÛF]YÖ˜’‰á!lÌæ]X=Lr¨[%72‘FÙø–Th‚±OitxäÉ4ÉF2^‡QET•ÖÖ)ÔÆ)*¤¡l”õÕØiÊt­|]_›:ª­Ö*ëvæµÍëg»Žg^,T EVÈŸþ, D ( €ÐÅ<„Ï# $r8ÅlëøãUrÆåhôTãô ¹ŽE›™&¢34±è#œ–@§/´âOSñk`¹£—~ÐI¡džùZ8^•Ö‰¾Ù¯¹Ëî:ÅU0PEÆWÇz1&ê• Œmw6V+¥‰R3ɶ«Ù¡»l†Ï—o¿%~KãH%BE…ŠðâmU(qp2ÑF|K%–¨ÒÔPWŠSÖSN®–%œåìQ¤jN¨Æöœê$<­ŠUÛ¸ó¶ñàªW¼ÂUw8€ž  íÁ± !‡ÄÉA”äPŒ>ôa,Ð)6GÃò«dG%^S‘‘t¨8þ©úÞn6 Àå]*H—’Ä9‚¡Î! y‹²­ÐÅDs9êH™ÀÛ=ñ‰La Ô;˜àÎGÄ ^° h¸f_Vá ùx£4´´¢a[ ÎQβ‹mŒN~aÓ8Œø“9†OaÀÃÒ!Ù’4ìPqÙÃb“µ=2Æ|û Q› &MÑ„9K³d•…µ(ªˆ¢$[–І*¬1P:Úy¥­¾ó@¸™çmä€É“ô€£XÅþ± # b ÀÞ Ì#ÜáÖXÅ*, ØðšÚ Š*Q‰Ì Ç+4 &UB± C%¤B&2‰(›¶ÉëXR¯1Ö¨@Rþ¬„†—- …áW“TÑ„Jañ\KQBKÆâE th‚ÊDªx$tO´’‚“1rÄ6'bØQü±¥¥P§ ÃSª’’qpa­€©K›6F?ÑQD½ÑÆ‘*l¢"D؃èÀ—âì1§ Ëʉd‚¿˜â¦ûÛÈL9iL…Í8‹ rx5QMlYbXX«Q¥­;µ¤ Z5¨K Ê­Wà¡['TAa:ÀÁ˜À Þp `L%˜B¦p‰b ÀB°ÉXléP*:I9Ê!ÊÒPh‚6+ ¨"ªÐ€D; ® Mµ»¢EÆ#ÌQsX¼þf漇9ö«#{Kf3:Üät ]ËC1ªÔ†¦K¢$Ù^NG0¥šˆ#ôbªjz·Gt”MO‰Ë!cÑ›ÔÔ¥.}éëȚŒÑ.å£ÉCZÀ€ž0@ÅCˆj2P‘ï¾ðÑazSµM%Ê”îïÖöÈœ¬nj••\”uÈà®U¶t›ZsõVîÐ DˆæÐðBRx8š«˜Á ,` ArXE4Ëb .“gk&×E¹Mä 9D° l‚o`9À¡ ˆÀ¯ ‚ÂQ‰p¨¢²"ÈÂá$ŠÀ%¥´µ–ck÷Ä(\–mÂBÁ’TÅB !#þ˜‹.($.È(Iæ˜Òæ~Äžö¼hð†ÂgáÖň 8„O8Ð]zÝd%çMtZ|COÕÔëÐõ*Zñ\ M@ª˜óþöê1ÚÑ1UI |wSÿEUkZâ(³&*Qi­k§ëך¯R'mg• \·R˜—™8²ARXã…«h@1@ÑJœà„Ê– ‹b°CÚh±¶ò–‰\Äx†È*Y×P¯Ð„Ô‡WšÐ4ȱ‰+¸A Ý„~ì‹ ôØÈäp+š€1pjb„”ðd‚s3¯qÍ:¥²Ímn™írU2ÇÏ̅⇨m˜þ‚Ð…ôˆCT!ÓJ¶•gÎAD‰8EÈ9žæ¶¸zhC ÂÚ«l¼uéãøÈR..ßn¦éÛ¡øŸÒºá&I2gñ÷'¢s¸qqë„Cò§q#sfES÷rˆ€¡  ÇNÇ:væ3GBrúÅR²!^µ±‚¦)^Ñ)ªÖ)•dTÀñØ!6¦¢* $Aµ²kâ!+¿&7ãÁyÇ+Y@þPp8,À}à C’‡b p ÊàÊ •÷…ì&ÁS€Ö $Vd Ð @pšÕÖ€²Y†@ `Рbx¾ " àB b{°Tþ¯°bd•° ´g9šÐ àIàðBS@¯ÀBðMAãÈ0¾Wë6|¯A9`&8´€jr&°fOú$O¡eüB€(PMwåW[G bQ|1%/Wð—9ÙíTÐÝÄŒS~:ä×#Ëx!€²q .³>±Nù‡9tÌéÓ9R!Jt€ ’ í5|å ˆ$á‚Ãáhkq¢ƒH ‚- QCaÇIšÂi•2=g7`Y3V:#*1³@ ö@taÜ&½¦Vz·AÚ!W‡p,ÌV V@ Q€Xh€8 Ày RPþÙ `X“_PiPÀ(/•‡à“Á Àþ ±,†%(=anÐP@‡ÖðÒF›`à †Tá   dõ–‡¾à ~Ð^{0|D ŠÆƒ<GB àDÓgnŸÓÕ7†³hÝ×29  ã— úG&ê„Z€B˜+…"%‘&9$>w<š%@£YšàsT€&r© “}1öà„‰{ð W@{@¬ààÐàÃç$áÄcmDÐ,6 ÿ6Z>F†ˆÐo†`9FÖYøS Çpq}Á€pa8¶ Ðc°›Ð >°cÐçSþ'T  ›ÀÃáà-’"„(áR(„Â,1G‘5‡1l?†áR43v.8Vuœ6P‘ÅÑ¡¢)˜J³ÖUCi‘¶‚VÚkleA´+uƒM¨ €BðQ7Æ¢YvS7‚!^h“&ÊrÑ#\2Hüg~2xîA±@† ’GQ"šÐO7@Ó› p } ódÅà r  T¯€1DZ†X Ñ ·>qApè(h1Ž ×E[&´He’aŽé#‹yDib0r99¶Ga#ᆛ¥ Î7Y 0ð 0}ðЕX› nþå JædLÖ€pYp€|D: !}À ÿ °¬0Š84ênð ‚â{u.š)”Õ‘a;ܤNåàGà 6°  {o0O {@W@bp A¶ ²yo\I6°3ðoTké-Ä ­¡!xÙŽJSUéU@¹Ó&†S—⦦¹¥”G›"‘£3UµJ°v5 ª6=H+î*wi5A©}ç¡àð+Lh,*“Ù 0Ù…,¹':° Qræ²3QQf!™+§ƒÆrÑ›²˜E‚—™êÔ^rIr‘&†ð … ¬‹>ª°.â$¿Éþ˜™ zR1ê„C妞çt›Õ}xù…‚—rÑœ"TÐ"PD0 ‡1" Š‘‘íå ÈC›° •€< P h Ügž:Kå_v L¡ž4¬šN’!„ø A3(wÀÀc{à?f Ö R0p"À Ö Â…Xµ"ð­a{PàEàFM ˆ“E(áô^Hzc·‚Iã(ŸÆ/qSƱ‚.˜Æ©K568ã°›@Š¢`©»þÕ‘Ôá¡‘À&„‰YaŸñKÆ[7ýš ‘ 2 “Í›¼Ê É+I½š¼É&7…±e÷'ŒTºQSÇ.%PâH6í{¥=q&#Q¤Z˜ZªÃåG†€·q!M }*¥&%¡RQ1¹,€¢ rp™cz~¨Y»¬¯ 6¶Ë…'~ ÷s `7ªh{B"˜÷‡~›!‡pËQr§(»œ™›Âߢ™‡  ‰c9š– 0ÁéôÌ }`¿íÜÅ  !nr0zt¸YwÆëÓ•ÑP Ö M°<}ѶQ¸A<31j¢†?›Ô­TE5P%þ@Áá?þéIViwk×±®m7wIÈdKÀû±@¼ÂÿЯR Ô”ì¼R°]¸•ìœÜÔN½90’§|R&QÁ%gêÍbx„?›‹ƒT(%1qÌ:=G6í²/Rd;-?ÌTàAÓ‡™‡PšU˜>÷sd“˜öˉásðËB)V„Öj§)Ep¡/âømùˬì^%ë©¥œ²0s×ȰB$!hó²2rUx§À—rÑ…R9žj ]5C>O?»ñÆûµu/•ÆÛ:DzñY2@Ë!‘¥4VdW®¹Û`<Aê»™Kã¡ãA×=íÈCþM¢Ï“2‰¼‚¡ [øÔÜÝÝ›ü/®³#gf;ç%xftŸJ$^üSÅñRl^32H÷‡:'‡‚®ÃÞöͧ|ÕM‡?jS…E à•)Pѽ@á´fDa5Yp §à?AØ?ñe¾ þ`(¼%ºô‰u•")§«†ÑiiÜisL»«„ÇáJ@¤„jfµ`€L+;ˆ‘³â‘ˆajE7Hù+"j7ÖMÝvÓ¯ÿÊ…RàÝLÞäNþä6t.£ó#L4 Ûëèßà•.Å“Þ OQD`ÎDÓ*Ÿ£H#ÒH޶æù#G\U)Í1fJkW®ê:V:HÓ ÊþÈ=µw>~K4¼HùKðKýêÈ/I¢2i7‹¾ÝPé’>éó8YAVîÉ8òmæh§L\mF7ÒaÄ$ ãhfd'hE Âitäç>øµâcgœ†b÷ŸxVYBk]Ñ1 „6Ô» a®ÇîܺèN¼C¢DíC “($ÔÚMéØžíÜMæó/3;nÞ©“©óV„;E·~Ãe‚ûµ\ß¾éö2]‘òw¡æu¡_%®›dvÎ5/æCÒ+Þ5ó£âbg_¹ æjV Ô  †Vº¶6ñºì¶”}× ±ðw˜<äÉ› † Ô!*®í$_þòËbîþEþ<¿U:Àµévîrïj)7Ñî†æ'†¦IÑÕóä>6á;$Mj³qS]có§>]pÌuÀáôEv6!vª®}Q`Eq5ÍÑ2­q'w<ölãõB+åáK==lu3n"Êè×ÍñÒkòr?÷5©òï^ê¡^1zOt¤ƒ÷çŽská[O1;¯^µôí~âô²óâ:G6ECß&—´uÓ >;b#†ÔT\f~U…šâ‚\óæW…®IØ/wccÓÆ¾ã¾{wÑ-äÖÝè1iݘüKÒNÉt¿ûso½c÷/ïòïî/9¢#F·_1ßHk¶f£ÒJþ±éˆté5RSþ>)Xj“‚IûHîHÇ(¨ƒSLñuãƒIWÅ_TcuFã¯æ? ìªÆ)àºûJ€^õ¯Êž+½„ñ…n,Âæ¡‘MJ… 6© KŠYÒ<„QâDŠ-^ĘQãFŽ=~ò#‘«l<™2âÉ•Yj$é² É—i¦‰ù°fš)iV:(Ož)OÆ<9Ž(—*­Zú´•„mA‹JeZThT§UŸB­²­•N£`£6E›V¨S©MÙ†ýÚ*”[§¡ØÊm•…j(±z·Ù¥šw*Õm~³>•EqaÅ7ÎÂA1ʉ%S¦ìóeUàÀuþWa h)¥ žÎfˆtÊJ¾†[ölÚµ/î´íq(n—Duú–ø8E¤¿sδIôhrœ6Ëe”iÖ¬8­FWnÖìW»sƒ~5}«X»w£fyª|ºÚèq›¶ˆ.Á½T»n¹âµ?ujX è÷o“@¹\Œ*½ „,ÁÅ&‹L²ÈÄ,²S(ƒP±X:i¢‰NNM!+5Ñ(Í×rC1EWd±ÅÚx“¨'à^’¢˜rÊI&šÊÑ"ä¬++;«vÏ7•Ðï;íÎÚjÈïÌë)ô´Ò*-õÆ¡É) ÚƒŠ­ª¼“ê®´” °©tª¿þôBï°¼+ Á/£þÁ,&„ð²<#¼  Á)m!GK-¤È¦e”‘£Q…4RI'}ôHëŒD颬Tú͹¡šã´·%‹¢ÒÒç–«<¨¢É&ñz ;ýXÂN(œ°tR-$•ìò+Ý’¯ÌV¤JX¼ V@ÕTð09›­ÓÎÌŒBk)‹%4)òРCKkhQK£´\sÏE×E'bÉÒá4ýí¥‘Sé&#ºiSRQ=ÒTŸ ª²W-w#‹Õ¦ª„²ª-ÓØF,€ûír»´´ä2.-‡%óL¼ûK¿ºòê¯cņeÎ9„e;éÔó2üAˆ4Ófæv!qea-›twæ¹gŸmþ µ¤­J®Çñ±ÊVMU®i"#ŽØ;í~Ú-‡›L#”)ã]zb´˜j«­]ósKU±Ù’¯©«bS¾Á–ëÙÆTîɨ62Íìæ ƒ ´!…gÈÑÀ‰¡Ÿg¼ñHi䈺N›ÛèhH²œ8Šhüôa{™ö—j~w“®ôíV‹§aL×&·jïl²/S­0ÓÞËmój˜ãªÔŒÓ¯5,Œn:ïΓŽO¡C2 舥´DO tÐ 6< ¡—³u¼{ᅦTF¦Cº8옫¨:²dªrß}rúý®Gï+ñê{˦²h·Õ¢¸”ØÙ,F»ò¼Å)cÊÛþä×2éå.Ëd'Æ$È2(»àe”·™æÕ©00 h®Gšny¦ ‰»P,úÖ ðµÐ…/Ì”FÚu9˜dd9ÃáOîÕ9–*‡ñƒØèPÕ5ƒ½å;YAOçv•]ÅnUg1 }¨’Àý¸­LLSð@¶ •©XŠ‘Û‚¤u7XO›‘L(ú6½Ïø©º^,ä(GUtB}k õ¸Çï­ËGMk‰æà$|ÝІ“kXôÅ:Ðe'IüâÉzžV«  ®HUÙåžhºG~ÍkOÑíèã¶PHXô"•õÅ`F@Í‚eƒ ÓAÈTFƒ“‰™Aüäl&['<Ä…ÀþáÄùC±àc2•™LÜüP74 dp&RœênSÄ&éLÇÈ!­Çi½:ØYxrKµÊœœD‹ Ø æ.s¹]šÚ¹:ŽÝežý± ½øÅ ¦nYXBe‰¼ r€e4žß ÒF^v"D(Œ…*xyÂr€—ËÄhF¿'9Ìõ$EåÐw¯HŠ*^î#]ImµœzIçÐyüþ¥?° LuAÑKÿƱ°×¥DaŠKÚ.ÆŸ§ÀS*¦ Ð`º2 ‰cN•‹?V fõ³eÓÒÓdü±åeAyà€Aƒ¡9VqˆÅË8PÇĽì¢%\åJ›ò­Ä¥‘+$årÔþÑÌa~¥JÚæÞw’¶Üï‰Þì)½¦3°û¥w3DÎNy¥¿GBI¨g*`ØêSÙbA³ËÊ'œø"Ú†… ZÆè´&„'”U˜'ôl¯·ÖˆRHŽ{ëÛ\?âGÝö#G«+Ž2R×–Rš!]äJ…$$%)¥Uëæsfƒ%viI¤×úª€+I–<@·•­+ TÆ"È&Æt6–#Ë‹ƒÎ¸²®Nˆnm¨B†Ù„ÏÌQ…Y¨#f`æ[Žð–RZ‹…¬"Ë/¤»mÎ^G*ÒŠ´”¹ï¦ºÖ>È1’ôšI+®I/±@D)%]Â6¹N&2*êüd¯¾ä¥þîÓ„½ùM…ØZ0·Á p Ê•ûh5ãבÌñF¸™"Ø¿&4@^ê(?$KaÇêÀU<ÐQä¼] •ŰŠÄU+Æ6>gLÁ²qyÕ«Þ¸½Édí…S`ÐÓÏ Ê÷Aöµdˆùä,ø­s‡é•úœ[—+³0(üû‰x\Gõ-þ¾K®e~Ô rÅ©VsÛÈAF ƼéÚ#cL‘éãÍB´ä4§Ó*Q›o:ðãE(ÆÑ‚q4ÿïËw~ó[7À?¤úMÐ ;ÝÒÂTºL>et ×ÛñVw¾¥fíÜÙ‡PŸ ›yªÍ©I…>Ézz(ßþaÛÎØ3ù8h£‹ò*º€§ŽY;X1­‘iŒ|Ú‹”sŒ•±Œ»³@½Y7#>‰º£Ûz7zä ¡*`*‡$‡+¸hè*(ÐM( Á¤A¤‚¨„PØAæ»>ì󈬺éøA:[À"˜gò$æ ®uñ—$T"Q Šõã<¢™þšÇó¡‡ëºïP§@¤ƒS8&Ñ™Ø3±›¦0*Œ ¾X*²ó¹™®hŒ*КÒ#y;ä‘ „z4uÛ›&ëÜÚ4 ¼à ‚b&Ѐp ‚ (‚K *Ѐ$‚"8A9`hh‚C`€&€7˜hÐU €A  ƒhŒ>ë‹& ¼5뀎¢,ñ(Âú 1Pá°NyB$!©ô±7öÁ·˜š ² Ã¹h*Ü—có¹©ñ ûI6ýq¤ÿቴᚢÆ#¢—ùØ.±á:^á‚9¨š¢j‹ìÕ› p3 ª2™9©@¾(4ړ೨;þ²¨€\·ÀÃ$*"xÁ XÅ`pV°°ÈMˆƒYP:È*…¤Q4„7؃< D* ‡x_Ð øƒMø‚OÔȘÐÈpÐÁ|ÅXŒÆž,%åÓ Àƒœxk°ÉA,a3.@m@¸¥ü”“Ú2ˆH’{3ósF©d—¨T޹…`8Êáœo""•Ž[¬3PFu²¾ê0Pé:ð¨©2Œ˜ª·) Àà û@“¿ˆ“°ð ­qÀ÷’—ãGûúü“¨´Â-T‚¤ƒ&p„W`Å=hHCÐh*@DÄȯlh˜Aþ:(‡JÐ؃¤Drxƒ'HJÔ„?ØV ‡Ð$AMüÔÉJ°ÁJˆF⤃PxÅçqËÍ“¾#¼ç£ˆ0—âPF@K6Û©Á…S˜7£xŠ¡©‰»rÆðœ¦ã¡Çû+QY'ùNç ! ˘r‰$©)mü5,)³4‹c‹­È$±ì$Có »]I³aÃPÊ"ô¿Ä§¸™|/¼c€Ú»[+AüGD‚d9°€C0„bP€>Ñ,9pƒ& ƒS`:¨ÌhM MxrØQ"Ѐ&(‡=N M"P…\Ř|… :€M"ðþ…7˜A¬„=`=øÍ‚S hËå‹FX‡J€R5Ó¤UÈpäJéó™¾’·ÊH]+.«D.Rñ],šY áJ•"’ôй[Joº$TÛ?€‘¤Å’8ýÓö9Ç6sŽþ\ `Û’Vø¸Õ[=…¢ý4Œ)%¦‚@’A¥CËÕcɘ%ð=jQ7?”(lÙPÍÀ>p€>èd8å€CÅ^¥ÑCè„N8å,m!ØA ˜7x…M¸I(%7ƒJXDЄOÁM(ÒMð…M`€M€Q`7€Í=P…&xC¸ÑôÒq8ÎåëÁ˜Q¤+MSrþxVMU ˜VØ`â4Ó|e€,ÓÍkXt‡lñ‡æá°L>°ä¹ÈXòôÓ.$‰?+Ô{á«3+¸Ä·Fu8ÇrK˜ú \Ï…‘¬363ÐN5À( “, ±ð¬´‹@91L šŠ¼‘» ´¥X·Xå¥C˜UÍø@Ü®8Å¥äºåk§¯D¾*€EX¤h@ƒMR7ðkp‚"@ƒ 8ÅM kxÔÉMp1XRqÕ„>EH¯Ý)ªíRª=X{e€q`€C¨R`µIr ‡¬ÄM˜kPIMtÄ~=„„QUØ)XD:X* ƒ¬„Ñ ‡þp`VÒ¥‚?Єå¤«- Uˆƒ>¨'éþg–æh¾fѦfÓžæ'°†¸a*ZüA“ª}ädÖ^ÅNDY8Vª¥ƒpƒ}†Mr X*Xê¥fVÐá•ÖM¸h"ð"Ø·]M0„MðH°†&èD°ftp‚ké6ïóŽf'x`o–``éxƒU,ê݃r(êCèfßE~¾Ã~>ä4SG‡ ¹AõØ‚r ‡Ö]É=è×WhAM n_ðƒ/P]Æý‚7xƒ/èç×íW ï…~Ö‚WðƒWøÙÍrp…+ÐrÐ#ŽA§Ýu3K}ˆaéêGVÁ8dÛÂZrºX_y:òxJþh# Õ Å6Ì•Sl乌3j™ÈôǼ[7âË­B,¥W¼Z¿ÊX…íÓo‘mgoò>ïÒv‚UˆCJÙˆ¾q¦QÎlçk=€ëC@·W¤Q*€Høá|m)x[D—pQPC0„†_P"€4x‚òFïOõÐVoñFã~à"@H*¨„õÈUXáÌŒüZ(-Ü¿ó܃âZ{íoAwWNÜ„ì×}Ži¸Lçîj7àð/+øƒ?ЀˆMøƒ¯Ö„+(nÆÁ&]A|rP ð}.dxH€CÀÜ`¡ä•î¤k•Â[þÁ5!¤¤ïÜ&$_O’¶44 Û’c@,B;ƒ?8Á“†¡È^‚YíÇÉÖд"È¿õAâh ꔈ,ˆN?sñv‚í5íOsPWim(†8`€ëíÉ’NÁ²‘aS щ-æSÐ pWbMˆ?Æ*h‚=ƒ³å6õ¤WzÒ.'øhg~‚#Èj ƒ×ÌóçE €õ<ßÁPøss†Å4õʯÌ×<VƒjCXW_(V´~×¢7×7èƒf…éþkxƒ‡M€„ÖÞhÐÑW˜t~®a*H7(ÁÓD9x…}–AC€UxíLEŽôp,ÍW©þâ@ºpl?ó÷¦˜Ù*#Ÿ+‚5Qýÿ@lÃ8‰/h‰»åáG‹jLxxíÿ%ÈéÓìà˜7§p°†ÑFóñFz”7oÐ^ú®xícž I ^´>t.“}žS+eC(‡>xú¥7ÿP`Ò&éÀê=HÐÌlck^mç‰ÅÆEHÎW\¾gô*ˆqã*jÂá`Múø¡i“*Áܬš`È4 ¬ô‘"ÚÃ=<Š@3D…Ц>VÜ4aHÄ!H ^6©pèH Ê9)Y¹rn m2Ä Jš4U–rAÚ*i•VK“rQŠôêÒ¬Uš:MþÓ´i+©\ÆqJv©T±U$D *-Ú¨kѲÝ&ABØm­BÙí‹7”»­ìf)l8 _ò,>œå ‡Ç!KŽ ™C¬Ëýùƒœ93䤢G“.mú4êÔªW³=.Í8¤¥«rá¶U–¼UÓdyçpÀÑ9ùòäÇ—'WŽüxóæË—(f¨5ö¤¯§fïîZû¸MDžnþ<úôÏ—/ñdd •*Ñ‘Ýt´ì©Ubïo!P`V¡À6ŽÒq tHÐ ì!GKTø°IoøÒ4T $h¸!‡†Tà€nÄQAŒR"„;ÑÑ‚!tÒÄ‹t4â!þ;1#Fš”³9{@K Pme$Ta‰v•RMîvd“ZÉ%¥R\à•ÕX[]u›\aµ%Õ\R±ÕJ`nÝ–o †Û6|ýµfbz%–Å6ŒvÐ)wJ–gd…Y¦Ygš´fràw‰*º(vûí÷ÚiZ>•†XdƒÅpÂ焦çAçitŸzzÈQ$£®½ÖB l%º[m^µš ôÁ\yêéºk§Åýö°ïiÛ~»}wš± U“(û_SãdÑ}T|ôJF ¨àbwµB [wå¶Ô]ÞXÅ‹Бź ¶ÀîA;6MI†É±8mVYµM“H2«Ÿþ~^i9%We©¥åYä’Ù%™£Ù^{¥uÛ[z™yÙY§a¸9vctNö¡”© YÊ„zP,œš*Í53êhvHqpB5¿­wÜÅ•w§EK‡œÑ¼>×)R@Êè8 &ÈA ²e÷4jüA [ïàª4غNG°%(@‡€£ešÕ¥=ÍdÀ¯íöt µ”°egl²S½†5~6Håœä*Z{e•T?iU\ee¥˜÷!5˜û ¹–cjÞe˜­´À%™¹áUqÄ·u[˜›„ÖXÉ#–çd$û¹YŸ©r*)cv?ªØ<<ñª9Ê*à‘&µ3§ëé!þœÏ¤PtóÍ#öÑÏéQŒ©ÆJ(tpPŸ¢.UuÕK¶rŸv½ñÐ)öñ«7p<È!ÂÓÛažZ²oãgÖX–¥4Ô-!5r–kÆR›Ê*V 4–ù(5)Êieq°‘À|¨@‡J° )_¡V¼T%«°ï>’;¡”°¹)1¥\¨Zåºö€®.ŒqÓ^rc±¿tl/mòac@;:å®d§ ™ejw'ÊwÀÛÝÌŠ'Å)j§ €É[k²P ëM<ÄÉÕÐ8õÅóp{ÇáÁ;š@³*¼kjûñNÛ¬ ‚y n¡ð¨ä§Ç£Ñï D‡lþÆÆo1‹4JÖÀŒÄ”CBþŠAd ›Y-®_TÛâ˜â¯ªhò.ÌÚòä§<%.‰ÌO•°2•õA.a—;˜\¾‚90Á%+•Á2:4iìLdÒcóC_v%듟øT?Õî2ðÔfz3*R“xkiPÚR#:8¹#q>µœ¤íqTH³†Àѽ›E]ôÎú¸>¸µ-)±p@5†VÎ}ê8NèD¬Ô½q6¤‰Ui¢"„&…A;¢Bšp:lÇr  YÈbÁÚ…“ ¥Ü’æÆ:Â(•˜Öä`YJ¹,)J§„RVäV,[Ò”,RÑÄr˸ÔÑKi¹™*榻ô%þ7B´“a@æ:=Én‰•A柠‰;àU³ª4#;“·¤\«ø¦¯¦çœMù*üëЀò%êiá«'U:šÚ¬/sVKiTBav˜õ¬z'qˆª„p_aáO„ÚfkPˆÔ”ñQPJoI[ÁÒÀË]Å„Gê×Ñ• ÄÆ_x…%*ÛÆIÓ2¥µœ“àÁ¢þt+bú\X0g4“– /¨¦&coyÈpÃeÞN2L½ÝËœx(™]&V½.ÔzHÁiðÁÒ¦W½èiÊW>ó+z–¬lÀ•5lüÛèPE˜rG4aá‚#¸° ½´M*þs¬B°àôî38˹ƒæÚŠ]lƒÁƒÑ‹ÆÞ©`/Õf¿û]Ø6é „Á%¨@›\ÀL[ÈÖ6‘V뺲0ŠVž •×R2©‚RÊ-WØBc,%·´¬¥OS‡&Œ¥E0‹ðÇL˜ßf©±‹ ŸŽ8ñ)ñ1ªxÙ¡ È+s»^*:H R(†¡'Þæ Ç8}=«—œÄ¡|$`{Ñ•¹6pñ4Ræ8R½â@5¤`Ûør÷­ëE“T½`U°°äÒP èˆh+Á\ʬd’Ô5Ø‘^É*.¦ÅxýðæâêRȉš³bþ¡5èRXǸHJ,ºE]—ó%¢ ù.|ù¡1Y'2Ö%õ¹ÌŒ*ž4“'º¬wÒäŒð¾¬mÖü-5YPE ªQCǼÉùMœÁ¨Ç2ž[ÎÀ™eÅÿÄ&yQÑØŤÕ¶-uÊ Ø]è#ç ï8E%û@(1HÅ2µå~ódaþ6é5 ’¬§;ÈÚYŸÚÆ#T%ˆ ©”¿%(…±Udß`×Κ¼”Œ£¥M]K úz·h¹mT`–] UNƒ0^ÚÔÀ˜ì¨C„22—(åñ-÷2Òuúîµí©›&b†Ê­†öÅ/²ÙŸŽÑΛœ'Ä!ÛÝ_ BQµÒþO)†eþ ‘fáh s\¨[¡ 4üëüD)ÔØg *…U•…‚rÿü'¯B¼a)¹ð„F¡àÏ)´8VF)³2>¨ [5ŽP0€XR$wà’Èùfþ´4Ւ´ò„ñçL‹Xè¬l¹t|ùeÆ“ìÃ$ñÙH<&Ÿ¤ <Ð<‘êÎW[ÔÒÞѬ‚ÜkÚõÃûfì‘ózéFÐ0ý¬%èÓüߢQŠ`´CöPÁ0Øàg.Ö°ßÿ€T@ßø©ÛIäÁ#<‚xA9¼H€Ï½¿À’Åuu›Èu–¬l”ÇZ&eÔ|–DQTJ%EãHë±\ëþe’â€ÅRü+5 NnÝêÙ]Œ· F·Æ’ Óo•Ç0íL†”-SM• tF3IÝó9_«ÜEiÓý! º•ÕôlÊöí‘ÐÓ8™dSkHË´¬šÞ´ÔA-Ið ¢!ØÀ‰]E'Ô@yåŸJÇT€|ù lTBô‚3< hA ,2QË- ‰íÙå„BãÁ•U ¿Ñª}G¨m´ìˆxšÞˆ’Ee³XjI*œGy”V4Œ\x V̰ ™¸pÉ’YÌ/ñbàFë´N0õàð=›2QTM™TJgtF>Ÿè «œHþ¦øÓ–UqT¡_I»G5Àѧa‘òÈU0$8®C¬Ã:P”†ˆ€6Èa¡¡ƒ5€C^–Ã+,€0Â(,€ b%„hPˆí³äÍŠyÚ剡¬í†Ë†L ¿<Ö~„”ü×kÑÓ­ÍX ^ŽÁ¢Éí”\ôØííÒmÝÖ•ØÒ˜ÆèÅ_ø… #:F/ÝaЕ‘Œø4]T=]ðtÙ1R]løGú˜F+àÑtLcY…SV5X%°Cß9AÐlßÖµzÇ8 äå±À PÐ0À÷p@Ð&¸Á¬¥0†±TÀ;<;Ú*øÃWˆþá@PÄ€ Á(ÀÀ@%ä@8”C"C¸ÚÖ@±ˆ‚Ü•BŠœhÞ9"KÀ$ËÜìÄDaȹT¬ŽkÕ˜äPIlÁ’+ÙÜÍdkM -Ù’êœÉ[” bUð Q› RßS a´ÙŽ ,—q¥¶¥ ΘF,t„“x±°Ð¨¸øÂ¼Â+ø‚5ðÀp”€{(@…(p§y0‡¨p‘‚„!Rid‹ M½e^”B LÀEF»°‹B0€³€I,€¼Ï\Ú ¨‚ÁÕ8P\€+ \@ä„Â#ü€øH6Eâ]ÎJ«Üx˜&±Oˆþ‘†­èH˜iÀJÃ$E(‚álP‹™VY€`}9Žã¸˜©bH O•fjžÅ]¸àkp¡Ž‘¹ŽlÞàbˆLÒ1SÇeÓTA4qNiÄ‘qðèÁt¤°<<¼Â@ü+ø‚Áø‚…ˆ+°‚¼XÃô•Ø•:TÃu`GÝ,Ȫ䙬q€8€*„4¸D‚¨ ÈIˆ]€Vã%4A(Ì‚é-P·1@?”À´@*(Á\ÁßôÂ5¼ÂÊœŠVX2ˆ*$Ä´´BÕX Ã;$ ÁuBXr$å¾i”!Ù Bþ%xÜÉ("=N¥šˆñ˜,ÉÒúìÖ·< çÜœkšäëäÆˆËe †›Ól–ë’âfü`ҭ̵)UUé¶½QG•ƘyUƒ6ð€›©[r¸Ç\¸Â¬+˜iú$–AøA Ä€<À›‘™ \©§v ¤Ì(²dÁ–ºÌQ·}EÏ XÃpSˆ—?´ÈÁ*TC¼ETxlìˆ&b¤¥ÞŒº˜"vg¥WÄFæpþÅŰ ‰íRj~ ¸’/Í"Sëäàë8Û³éÉø¬kNá¡\F1¥¼~½É ipÀ (õð@5Ty¨UNÁ¸‚8\+,é–Á+8¬ê^ƒôC?Ä0Œ›§Ty8A1 VŽ7ÊÕ\yRäÀ?d¤ú^pÀ&Ü5¾,Ø@Ç\‚/ Ã,4ÐhhÀ +¤AŒc0üÍ+€ìäÖŠ6”º$È‹¶aÛ„‚*ä©5ÄB1À¡XºÜÁ ‡ãn‡â¸TÝ0}”Cxb+Q\¥Öž¥’æi’YNlŒ&]üXåèÖŨÉÎÉ"-î¢K†œˆŒ›þ̉ºÝÉ®Uµ`´—¼O¹Ç{|išÕî{XC ˜A\8ì€8 Áh|8|+8ì5\ƒàÀħžb_iƒài´(½èj´À&Á„ƒW´Â)¤¬h8‹øêò2oØ@wNd&Ex‚@ äÀ¬Ã1°‚$<¬ƒh¬¥`<^Љþ’"¦Á6ÄÂr8(';(€Pìr Vi¡’FÉÆù¶ ÀÍž•ÐG…hˆÂÒKL­MYpXdŽùTèΗ˜$ÆðbǨIÝ’)™M6•áò&)_ã¢0va~ªØgþ¯N¡RR¥pш՘(ì5ˆî|ÁûðèŽn\Ã6ÀÃÁ”‰Õx:2Pqi”‚H j,E(ø@;„A@ ^Õlj#ë¯[öÀ%˜^i¼1 À=ˆÀ¬Ã\ÀXÁ €h€|YŸ’§)Ž˜"Ù \q¸G Ü9Cˆe–~ÔJÂ!h*Pªyl(‹ª– …&æž+Ls«ÅD…ç| `üÐ0QR•k-ãæ’c3-®´!0cW%ȉFr–‡yMU.çr Ç<À˜7ó‚ïÀññè’@ q?,þq Xôlí²ØÉv¬èN€Új,Å,´C;ø€@(Rä?ЃôÁæî3 Í%(Tä@%0Àì Á+Á|µ°$ „„OKéoÜ Èù¦‰ä¾ÖnHÀ)œx=Áž~ŠÔèeZ I4\d­ ¤’€&g!ð޹m” PláÔÜÒ”.]ŒÞò´ÞW nðÐ…L¹öbáþ n:SÃ+pÊS§0¹¨‹ôMxs’º]O{tõÀ8ûÁ‹Ãû°ô‚ Áç÷ÀÀ[Ã÷hç§Íö¡îÊ&Dyšiφ±ä@\À5\ lÐIþl.؃ Ü9û+cMØ€ÃåÀ,° L áÄvTv4 P  §€üW=­X«œÚrÎ¾ÐÆ.€@TVêt^Á xqôî¦Ôj1 ƒäHAh*”W C®­(‚d"½mç™\–¼…±Pä¬+£‰šð´ Qñt0_“æò2mwû&´¥ 1 ‡w0kVØŠF3×͸aßÑ”À€.@p³+°YŸ5= Á¤u~Ó÷ç‚ø¬¥ì‚tFÇ*BkH(e“z>PR¨¬ (Ä ˜A#\Bpç·£9ó9ñ€‰g84òþ*°À¬%(À,4@Àô”8 @‚HÁ,ÜÇ²Šø(!9S‹È‚J‹5ÌÀ ÜAœ;°‚`”‰å”§•ƒ`VÁÜUò.Gn9®²iîèjªÅJ¢àO‘NŜΤýEÏÑKÞàa÷ì̹N–1nÔ9.ŸHi‡‰~ízˆ‘R¦:L7¿}Ó·5Ÿµ€°8ðÂ63¦ç<$ô\ŸWXÍpyTC‚õulæÕ‰Z@Cx‚3ô €cHO5‚Ýžº‡x)Œ3ùÿp<ˆ,@‚X³sg LÁ­—XÂ{<@$(;'C><ÊðÔtJ@ÆXªh¡jH*!¦˜bB+˜»@ tYçHè¢ :ꨱqÆaࢸZ€ê(.`„ê;‘D‡…NÊ£K$H£Ÿ\‡):9¤…&Dh!¡–$ª¨Æ êi¼'¬‡²âÂJ¡®Ä «­¸8Ë«³´: (¡Äì*  Ì” ”²¶yÓÍ·ÎLk›,àŠ“®¿þ"¬°Á ë 1¾8Pe B;l°ËmÔÑG+G0øR¢ ViO5Ѥ{)Üé'—Ùj»†q\‡‚ãM·Ý¾§ â»æš1úÁá‚)òKºÐÞƒ„È@Jƒ:*þA±AbCE šh€_ ¬¶ºéxІ‡’ÞãÁkîxCŒ~à1ã"x(ÁÚuACG © L›B‰ Ü¡pŠ"˜]P 9Å.1¼"¥#K_ô(¦Z¨F%JN‘ €è´éq¦ì®š’*ᮉ±2ªÄ²¢IâÇxŠ ¨«´ê£.5úª!ÁêL­Z䢕½ *#¶¸¢s´ÎbëÍ<æÓ/BQÂüYlP²îšHÁ[lÊÔ¤cª4Zx‡Û•j—$ø*á#ú1 &l¡¸SsÛ­Õ!X•ሻæ“\rÁ¡Ÿ .ÈoíÕŸnþ,Ë¢ :œ•ÊÆZ¨$ øÉ•0ܦ„çØ=°]ü€m?`€' Âðà 3b¸¤ˆS‡»mt´¥ ÆÙdŒIÖI`ùç™/¢X„_N#”&qØašL”¬‚ÕÈÆXÚq£5«ÊCà‰¨£Âšž~œD ç&{vÊÿª¼”•q´¬LI#à™Š6':EMo¡ íä&ºÜÉ/4L^¬&Di00ƒñ㵬„%|”QÂ3£4Ä‚ú}"wŸ)Äà ¹°Õ5zð\”!U¹G«b«°Á…«raÀ£BáÖh"§#õXF"Èþij¹¥„Da`ž–×¼ôNu!ˆ€÷;¹!b` \ÁÌŠbPÀÞFF÷”ä ìhB4ÐŽ}c^Ö°0®c UPa÷|2ŽPBš!ž µ8ˆ@,`2L4Œ ÕSJ”´ÂN\®EKR™S r¦)i2f SŠÍlÆ%œ=E*YŠÎX1\1à\BÁ=Á¥.r±Ÿâ"µ,ìE0Š! ¡¬ÉA¾œB1þP×¾fBqŽ32&úŠBÒ‚XŒ@*1c ã&·7ÄÀ ~È…®†2œÊo¼q•8®À†X‘à†¶Bb”¨«)8±=QTÉþH%ú„MðÎÃ6Éð< mÿØí€!†(u÷1c žðÿ¼Á§séÚÈŠkÀ‘¨"+ÊÀ _ì.õ”§ž † „APÂ:ê{#‘ÐS Bb%ˆÄhIÖÃZ€2ˆ‰Å‚ˆ,° YtÂD§€K(¡°¤4%d¡àÀEVÔ”ŒÒäl››eþ˜ÔUÿ‘E#àV¬t¦^åM\i–º24vE˜‰¦âT–¸ Å/•K4¥)5BQóOzŒbNÁ€¬ j/ª` 9Q›Ú:"ª(Æã¸Õº†¢t ¸À%àñxÐsV_`ƒ?µ@Tøæ Ð ªþô6‚™ÁcX¢;xÕ6ýÔ O dhB¤J m,é^ÌÂC‡XL€ír§U‚Rð€WO˜Û’ÀŠ/¼â oP@îà‡2\¿exiÊŠ0Ô1 I×»è ‘Ïk^|!p¼ŒÐÃCÂÓ¤P@dÃi€Vö²Ð¢¨P#(›Þ)N#Çœ" ¨@Lª –£´«ÉÞ†—2¿°d¸X2ÑñÄ8ò£«´Ì*^ò’WøŠäœ…É‹ÝJÑ´É2-‚É4K2ÝäL+_Vš~ ©æÁ­3k^Uí™O81 k[0°¦ƒöÚöÌé—m/á‡8W Zè=ˆþ «"Ϊ ÈQbBݱ+éžwîl‚D³Ãc˜30ƒ1x8 kt ½ãÁ¬ Û! ~`Å4ñœx¿®pÅ=hB—vµ{Ãø¥®Ô½YBHmÞ:JðˆüãMMäò³†„¢» G (yÅѤ~)ó®dó£©ÒO#[ZiÜ¢¬•~gK S¸­?ýQû)C¹ /á-!µ ˜¬vbBo£I¥hl²“œì$Ìmü{àq1xœ2ÛA¹€› 's¢cÚE¡™â%dmDÞq‡Áy5§{‚Hû¥¯Oè×Gpµð‡^¬œäØȪY çIÄÁpÀþÄ…ú>pLÊxB‡aÔÚvO ¡‡÷äq×<ð+ î?”zûÍ ® ›Wœz¿ºqÅ\±›+ ' aÈÅrÑ1˜ë f—ëN7! iÀDY ;ÂH!1ü•ÉÂE@ˆQIB+J‰ ©Qoÿ¸JϦB¾¦üù¤®’çR.«z3‡°Ýa¡Ù’)×Å2¹±[Ù÷›ØÄÀ³¬éNvì›öÔ̹X°Ë‚ªš\NQÍ1?¼â½›•Z‘(ý‰ãxzó÷)ü§¾¶{< ß“ÿÆÏè…߀ãêT19À½óµñ\%}˜LC¸s,â™9ÃÛæˆúšþ·Q+u%°‚ þ ý·ú ÁñMÖ¿``íUb%ë‚Cl§°öAëëÒ…Œ` &ä paX`¤x(`–ö@ ¦ ó") ü!ĈnJ„ÆÉ`$±|„ –¦TŒ#VægîG)ÀHa»ªj­xâlÆ-ÝdB¯`°¯„°ót)Kx†LŒÉôÒD°ë»²H 3õBa.0ëM.P®éË´‰´¬i´Å÷Ȱ2¾‹ÙF, À¡FŠÓ€å d¡*$üƒ¡¿HÀ Ê%U~#apÆÀxáâáÚÁÈÜk+ÍZªÁÌPhˆYˆ®ÇbBa þ‚b¡X æ…:í î@ ÌàˆÖH€~k¸tcÈÈá ú,å¬öà ÐHBò£B€¡9RŠü¬e½f`”$³@&à&«„ñôŠ!ÌBI¬^¤( hÌd`Ðëbà¶Á) H ip¢BHš€ 0b~bŒ!*§ ¯>""¸M÷ªKhÉŒ‰ H±èdLRoL†°¢ii,ë.’Ë2 ÷njòâ0Ž/¬Éƒ$® 1’2À- C¡Íâ r-4ž@níFÍ ÄÙà H€Ø@rATÂ@zR`†ƒxáì±ÂÂè^‡WÆèíNk£þL„Æ.ç"‚<€$Ò¢ä@ ä€|Ð ?@êÚ!Р€ l€4@ÊAzAÆ’ òàsXáŽÏ‘:o¯°‚Lˆ -POõËôK˜.±²²ÐþËÌÂö2( &21CQa*·Lr_VêéžÎ .À®à¡A ^¡p'  þAÜÀ ìã\ê 8ŽüV!"ØO’$ zB®ÚO~¤ ,`Zª¥.€Óè9â.ŽÀ4`Â!4tò@Xóàd@ à¡üë¾àlÀö€ú@@ÌHBC@Ûd,$ºç;¢ä6 “~x¦œHÔ ÞÔ­ *{„àXŒ2d¢®~]·ÈuIHAo_¹¤5PLG¯˜ºbi˜ (*S _¯,Î qsM1¦&k¸i8cN-mbÁD@¨à "Q¶ÜAæ¦P%Aâd!¡ÂýÀèé A=ðvü@ R€ zSE Êòत‹þ€@“¾CU×Ïò.IC¢”Œ\J xà XEÝÀ vª*Ä H@ò€4àþ€Céá  °ô©[R7®ÀÄï.Ñ üa[¿•U¯Ä©±aÆ“x¬™Ò(Ù*oÃc; g A°èf<]4¡dÜ~ä–à­rëÇgHo¯²¢+¤€¢ßKÊ‚‰L¥â¦ ˘†² r m8kᶆ8 åbÉP£ÊBèrÀtí§>ÒŒö¥9œãdOª¨ "Üà Ê@Õb  †®¡e™£ž¼òÔÜ–^ÄàDhÛ£M2Üd)%£h¥ "Šá.Ýéd§ÀþÔ¾`þ ÕRô ¤®ž¾2åÄöèäèycÒnt’nμ’ÖŽT¹7>ú`q¯Äf¦q~´­£íÑ[gäœ8¢\×ínwÉKâzpBÊAIúJòbéq—–x°(xF—øÑݺ¤*~¦(ô±ö­L–¦°(õ^s, 7ãBOÔäiˆáV—O@8Á¬"E1:«kŒŽv+®|«€^ˆÓ6Å…ÐþãÀ?Dêtâ ˆ@èà^\Á®axÁ p äü×ü@ à!}! ÚávbÀBP*rž–>f@ T¤F E€óƒÙQ¾CЗ:‹à "`®þ`ëö«%sávÌàyË€Uòw’¯€8òxÓ. 0T.ÀLÍâ¶*ß! ÒµNë18±#ÊBP¶b75»çc.ï”6X,²)×±¨ »^—}Ì„)w—ïñ…Gø”Š,†ìÞz©Ú@H?·ß¤P ×ä Ž-n¹/h¯ö 0lokÄŠ}¯—£* |Ñ6ÎmžàÀ3 ô¯Ž(€_€á jë  A>]!ÄATxáÜÁàÞà ’àaö@¤€qxSªwðccÁÁú`’²¢*ÀŠ8@1TD˜­a&íÙTzFÎ} b X!Ê v¤NŸŠc”p‡|HVˆ# þÌ B…\d@CG2äºsw"‘ŒVAf‰[wÐ2*X+†ý úcLÄ—‚eFˆIˆÐ•í݈‰¯¾ÂÞ:"#º”ßFOLÌd‡Ý‚‡#+(ðÄNZà†¥&öúäËŽjÚt÷Â‰Ï ’4q¸×ͪ äwYÅá¦Âà 졘ãÌ€p‡4€ Ю÷P î‹ Y ¦ nîóŠà€á¨£7ATkå I 4áÊ!9|@ÈáYD@.çaèOUAúà‘ÏÈ%k®A“W^ãûp 8íymGw‹\€BîS_‚qþ³çs©{§Àá\=Âo!“€¦‚õ¶Qد–¯ è"Elâ”ÆVæ35‘Jæ'd´úP‰…‰ìÞLS+¶dg|fKÛ$(Æß’FUS·®o8²®œ×ôœ½°Ó¹8 c/»â8‘'BTóó¼ð#T6{7fºv²2+Í ª›R­ Ì€>Á”]á¡D‰6¼„$äa.ëƒé|G,ÜDÂaÜ€ 2ÔË©`&`Ær,‰ ˆÀ¢T *Nô¹¡û® aîE ¦`W쥞°\n'¡ _ à ( ¾J`¶Eµ%Ï¥Z«RXþ„Ù&s6C’$ ‚Q:«åX*Áa:½Ó¯Ó%3Ur@èÖœ | ·YýÔ‘EÓåQ³ªæa6ƒÖ™ x¶d¦m„§D<¤d™É­K&w¿ýç+4×Kª"#\Ù7—­K+æâŤ2Â,Ë5Õ„öbO/ ’j‚S÷4Èšöb"OÅÁ‹þÓÊH:PJ úa“Ë æœ+í,tXÁvÂà Õ¶ „`L­¾vg%j¤î@„RÉ×+?‹a@ A„ ÂXÌ© ã£•Ì7a¨à|AÖqcE€ Á´Á=þnJàæìtL§:׎þÈúܘËM³ÛhëbÞ€ƒw¢Í¥}Iáb!¨` a|àW3S Ô23Ëaö€C·ÞúÔR:^*ù€ È’ Œ·q–àxY¡Êî_Á Ä€ÐR4á RÒúβ`l5€Ì5ÁË“ô&â§@c*²BJä”\ØÞZfÈØúKX˜¯ÔºÈêG*Zd°V²¶”™œ¥ ˆÒË8ó‚‰ÑùšÄŒàûÜQ+‹| J XP*T À<‘ xÜ òWàá~‹³éÉTâàÁò@ ¾û\@@CnXÔ€@”n]ŠÁèÀ ᪎Åþ^A2“ÂAc©` Aðtc›@äÀ¶Å¥Kà ò© A 'höPxÓÏwJÌ\ËåÇ… îÌñEb”'%С{S¢D‚)ðÞ鈀ʕ,[º|bƒ&D|½Ù£ •^¯’ÁI%97¾È‰ÂàQ/hT„Py”‡ «$GˆèµiÀƒIz9%ÇêȽ4”ûòf «/ZÈ ‰ñ$ÆräÊ„QæËr{þQ©Té&hMªTI“¦ —q†WiÅñáÄ’¹žl8³fí8oî¬øq ­:w–ÙtæÅ–3ýºjÏ£—¾-{[¨þÜ­¶IÈ’û·îmÀwÿ΂œòåÌ—+OžE9‡SÒ£s˜N'ºuþT!þ>¼øñäË›?½eÊi* ÒeË”=>!‰#†™2WÄé½ÂJeP†+lháŠý˜‘Ë'ñ|J¤BÏA¬„áÇ%E°PÄ@¡ÀÝ”fÚ-MÓ z-ð9¼×@ êçPÐ`þØ"7# ßø–§Õ ªTáS'd¬4«Cx1„TX ¦Ç\a€‰Àg®xŇƒ™^€ „à„¾€!6…!úÙ¨äÄ'’B Y”L´Yž‰¶‚jD^Çß7\@1`ÅPÊ>v5¬`5@â6¸BˆmŒÛD”pB°ºþcA~œ’ƒÅ½X%NèÓ  &2ßlš{¿IÅ·µÜ›øF6ÇñÍw¸Of¡ Ì×6ªSP ´_"Ø¢|_ Q‡~§QÐoá“1Ž„Ä 4­ˆÊ -p")àG*ØÀ‹®*A pÀÁú(Ž•òX 0*è¡-´PÜ&ï [Ò hV³~[Eq]&2Kå‚–•1e• ã Tk 2Ä™Al\P ýÀBnãmþÁ¿.ƒÀG4 ñ×a¢”ãí„r3l1ã‘õ‰aÝÔ?'&Îq΂‰ùÜM­5µ|ê~'ŸebŨ¦œüÍþ¶üÜÛØ¦Ñœöôÿ¤‹xg8ÈÑ»d“XíîKÔ ŒàzW-°/D ãLŸøÒ)cQûŠmÞúÕØ. &Y;¨€ë ™P | 7äE¶µÀ„Ù¹^1 ¸(ßd|Â4f¢Æ9GjCvâÇó™èÀLÙ «ðÎÅU¾ˆ‡ðÐbV6“•Í+f“ðþOînŧÛ4ü¶1[dLb®…ÍÄlCÌëžVÈ[Cq Š&F¤Áºã>÷Õ¯åÜRôÿ€C.-gá1úÜÆmº[ß^ü[λŠþ@ús‚Ü„«_ßôü£§ 6àAãèC"!4R€ã #5^w a • À €A=°y`‚e0Úöà ’Dý 0"N`oÀ Œ#u*Gµ[“5¸'fæ3ƒ±—_oVr¬ dxc›bc{ l°87ýð {AU|Sô )ÐB6@zw>EfP°‚.QH.¸MLEEÒÂn¼EµnÚÔ|þ”±rã“&&\«1ÄW>|f.ÝDx‡+'K3T@àð q — 09ð†àNÖ7O§-Ý¢NœfOÖµ?÷ô–f@ü3D'^¢†jÒPêÔq_púçŠõ{4 %`HTç1Kæ èVpe¹pCSýЀfpZBZà3ð`aåþ‘mC0WÀG×0A5Op ¬° w zð‘Q,HeE/Hrâs’]˜'VòH rW „Ð`œ`3uÔ8pŒ½Pu!Df`$pmôCšàBW@nåm—À…ñþÊà,ÜÄA7rçÓ[ëè|\Ù‘TC†wø†v-L…,Ã7‡Ó#›ÑãÐ`¾PFh%U‚ ¶6o £Ów³v.¤A”ð$?¸¡}èT”ñ’~ý¤eï"ò/•6/á%ŠÌ‘ø¢/¨Aëõ cöŠa‰EßÁ3àŽ-a"Vb%Oî0fÐ}´€‘ @—]õm¼@œ@Äp36Ôo l¨°Cà #Pñ°vë 6O $ E€'…ÄÚ€I•’Ýôgn¸ŽŽ1y%o@n7 õ¸ŒR))ÀŒÿ¸ ¯ÀšÉøW DÎlŸ— {þñ*u7¾e†THÊà‘/(>!§œL•œëØ‘t|Âe>æó={–’è#.̲|ìF>oˆ,³  ÿ°hðÕ kƒžèYz° }€r "0g!§‰.‡”2×?îÃhË•HÉŸÔ@¹@7¢ViW‰tF— à 1‹bùŠ÷Àp–“%ú•1¹Ø7Ó LŒL0ƒ™ dç¡° 9”CŸ0+:0.ó l` $µ ˜ xð&Y%>`  N@ æ¶œ‰,ljj˜þ‡xSà â $à zQ*A‘áÀ)`B¤Fe€½À ψAC@þy ðmR~„7é£òáÙ°béø™²÷,瓎•A¤âƒ‘Ñ’N¡}zŠ,…¨ÁU-rh~F5,f{i 9° ¾p fƒž¸Fœùu3 >#’±±i›hO¨‘}3—ŸôÔ6'•ß•XáU[þ¢]¡öO¢j>’^þ2Aþ°«P³Ð ¡eHE³ðúDw‡1¼Ö7pÉ¡º¢`C¹p ŸàS=u V8ÐF¿Œ× £È‚cp<©6¦¤a³WÁÇ™}ꑞ™’`™ÿ7o(¥Rª½áÀ¯)@®€7kel@ÆÜÚ­ñÀ ܦ¬Ù °þ¦_À lbw@œ,a |Mj¤4HƒÐÙœz¤ÌÇ‘p8›9²*‡xÈ’äÓA 'P N¤zô!Žac³¸f%—>Ðwœñ”ö‰fÜ]Où]Ý¥i77@ë²|AîW«æ0¢–ÖÑ«—Õ/W@Ý#¬š0U° ïq³ê*Bè°W}Óiû¹P¢, Œ7d Ö78'VcÀLàRoe nUŸ`Àb  Ub@‹8k¶Û¨ ²îzY@‘°6ö ¢BBüZ ®‰l¿ÈC!ú ¼ Ɇm ­ÏV&õBeÑ vI4F™'`t"Úд÷,}þú‚%ù™¹›œ#wMÞ¹‘# ’$ûqâ¢>éw{ËR>¡ ¤P1bs1c;½òž<€ "€»!î„\ú³-ù³ië"?˜V/¥ ûtW¹ Uû´Zi^³^×a›€]ûjeè,½>j¶´ˆ1$±|Ä×ðc!ú¶ °DøBy  ðº»(¦pùd9Ä pµ€ýða"ñQ!f1f V}Zh‰,Úà…Od%5ÆtQMÁhú_@ 4pº&ª (­ÀØ&®lày­« 9¦Dd4eìpF€§$¼qHM½¥†ŽªTnṙœ…ºœêȼÍ7>ñS¤ þàóJ‘"$oõqqð³™Q”ÞRN—ȽÀa~ì2@æÇ½7gNÃщâ—^Ç1PÌjYIP¸Ú/ªj×1f`®†¿úçP9@ x§ÈZO°¡{$ V“BÕÊÀ)Ð ¶€ úQY€n•C=Ðë0€:%cq #Ü™íZ{%ì{ip+F%°ƒaÀB¥R»©-”cÁYz¿v!~ðcl¦‰Rùšm¡ç3o´ü£ì€²4Sì®Wüˆ˜1²Í©Ž(lÂ_ü®' >ðJ¨‹ú®†Á¡à«ÂQÕ…ñÁÏ?ÚRÀ𱯑¨×gNØ×£J¾”þŸÿãŽõ~=Ç@žFtùr^F'¿ ðÀwÜtŠaqÁÏ!,¹x’m—®`s`rcB`²dyC‚m²˜› (Ô€IÐÃ:Ôào’7ö »Ô{_è ExÚMÁ‹ŽDZ>±`Æ!\Öà3'¥  lÊm_P&}„D7ö›UhÃ:F­m¥'µ¦ÿŠ!ÙœzÄɲРÀq{è“>ó ìœ>ÏÇÅÐ…*ØjØÎð 1­’ç²|êȪàыԵÙLR¤0z¶]?vüNzÜŸ¶Ñ]ÆQ@TÙª^¢È§˜^ÐaÑëU0©@¹9àÑbihþŽÄ™³Vâb}$7KÖhU&¹À¨€Ü¨0ºŸP­]õQ)„ÀÈFå*E@U5‘f;ÙÓkËJ¥»wš²Ê‚Y0ÕSE`zÔØ )°ÞUÈ$µ€Â, lñØf`B  {Y l¡të3I0•¬Äþ°beXÎÉ‘Ã5¤¦§„m²ïlÎ蜧êF¨y-¨©¡[—QbUP} o‘›W)ñð’ÑÉr¥ŠOƒ†¾¤ZO­@Kã¥Ýþ´OÊ0Èá¾µ Ylp¬ ¸³Ít“>ÀÕ+½6ÛÏO๠Z@©p3eôà7vCÔ&Úþ3ÓlmàQÒŠ°§kC!jG‚¬ bŽ,ŒÝœTÔ»IMàÑ 9ˆw4a ZðyZP&»¸˜q ®%E°þAC0Gp…Àlyzñt+dtÛ3áÌ(œ¼™unnjxçÈ{΂íâÍAÉkሺ|Í»4"@ 'ÒÏܹNP › Ûšñªî†y¬â÷ t²1ÐêçÐÂj|Œ ¬­•º:AÉ!0e0bÀµD_G*ÿ0´⌓ð宀 „ ‡„ ʄ¯9RØxÁ}d…ÀH&uÙFݾ 6P¾@‹²¾Ý,±ÔٔŇœŽª¿²ðþ£/†lzè¶ùcmU7„¢¡°ñÀxóQƒ¹€ÌM ¿–R»‹A”‹s¸(r"X ádð»ìÝñ¼¸w’|Ú,OÌ™KU¼,¶¶·g:æ§4Ø} nŽ#âpÕ@ ö›5nŒ”,ǽR)] ]æw~ÖÕsž¦e€Üî»ìH§öãð ¡@í°öˆª0'ÿ☳*Qq4 RÎèfp8rAyP 2é‡\Ôá 5\ö庻]:€DaHv§Í6q qJ`8ðΧ7¤‘Á  #ŽÉ¥Ç  ÃGügîp…¹ (©þ¯úð0Ñ(dQªRt{ *s3° fì ÀyÈwþ^PMM¹Ë¸¿ Õ-„Í×^¼É]›Ñêæ¦ fâóñïGÔ5 š¡?O£}ùÃÙ ˆ¾Ü5Oúó‰AW«µÎNŠ^O ºPÖQöWp¿iA'V Ú% $XÐàAè –pg¦Œ«T©v”¹æ.A‚ ý®DRi\šq!A†l‘#Å6ðÜõc3„œ¸OƘǃǪ;èxXQÀ :'>TX!ÍÑ4UŽrQª©R.G›&š†©U©G—@bÇnhÁ  K¼ñãç+â\ù s-Œ¸xcÜ)QÒ°Ÿ3þnÙˆ#Á‹â…uû•w…–!W(–õ“¤È"D ªÌŸT.L«læœÔsSР¯:JÚéçÑTEw.½ùjÔ«ª“–ž½¹U•Û·«h®’¥óQhÿZÜøñ„Ñ G“#T‹Þ­ZI¨²M‚éÓ¥[ÏÞ*”ô*²lû.|«,泬ÿN~ý{øñãs¿ž~ùýÑçŸ?™ ö) 4ð@TpA‘ª* pJ¹‚ˆë© .0ƒ•2R¡GVz€ç‚Œ6ôã -Ê¡ã: ZhŽpòȃH0£26éå/®i3.x¢„áxxG›°ˆúj¸l ¤4¬<þÓ,+Ò2#P‚S”Iò«°žˆÁ ³®q…+®)Ã3ÌÀ °uà)㨇!è¨Dˆÿã%Pp§Œ+Ä‚ž!@ìÁ¬²Žx…x¸° ¶i¶¦¢ªô³Ù0e©ÔZËôÉO-•m7PK m3Ì8Ó3.лí£PX…%)´õV„´q ‹4r›Ž êÀË­é¾û.»ï²È.=IÕ EÒé¬Ûæ½iã»>:죃¿ùôãÖ?ÿö”ã#'4÷\tÓÅå§ZqM®Â)Ì£ zRqåLx”X§¡xÂ`ã?æd€ *Ðd/¾°± ü aˆ?zà™Ì8b9¢Ø!eËGþRH ¡Üí)Ϩ,³ØG–jC§„'ŽÈ‹-@Å)ƒŠp¸…)²!…pèhÅ*Xƒ2úÑÍ!¾ ±2ËZàš$Ž`e‚ &Ë5 Ø(5UÔX£JÓ”ÅFUJMiÓÔª©ØM³UQå 7ºgC¯©‘‚‡ :Æ•8w‹sâUBQ»î°C¼»ì°ÃM<ìBñíYÉ­‹|= žÍ\¼ôä»ï¾õ²Íö[ÿð×??.pà´t[w}Á Œ=& |Éu¬.cˆ!p#—~è Ÿ\®‰çá/†Ð‚G?ìé'ø>áI‹-z¹ÂÌÈÅŒ;NÒoƒÐq€äµE6«þ‘)e½+ŽsŠ7޹Œ0ü´iÞÙègŠ Üƒ„?,• 5À#6°Â ýÐ8þ …|ˆ×À^YÌ0…#ÜÁDÚZ+žB*L• *¥áÔ“ÎFª‘¹æd!! U#7KÁ°6–Š¡°æÆïl£)t˜À*¸ÛQ9щ2ÒcÅM§<:dQn’¹mœ'qçI–x¬³i½‡sð¡z@güpÑ?§0Ý)bp‡=ëukd£‚b—†8pðozQ0âV¸.׸F. Ð ŒpÃÂ@‚~µe €¤K`.†1iA’¯˜Ú5.¾v …8Êp¡ØjóÉf%5þ‡6Žc…8l‚GÀ£+ÎòIöB’×LFÞ1PÀ $ G fÔwÈ2P‰üKM<í^<‹$´œ …%(Nà[õÂ)•ªS$;§¤d6QPœµ™Û g3šrjn¼)VRšàmXHˆóÜ** ŠðàFRÏÒŽwZÁšÇŸJü'v˜…,N =ã‘|ÔF0‚®tö!]üs„Èumä¨ëôÆ4Ìcô _ Šà ûM¹($ð‰ƒ~€ $hÇ á 8¸cMJ€‡Ã`Ù‹/ŒÀLbˆÁü&Íîràæ§>37OÊÍ›Gi‚)£ C0`2þCKÊðÓ§ ¡ I H4…ðï N»Â.²Ž´¶) ûB/†àŠ00L¬( ‘ 9v`ç©êÜT9Q¶±f…O-ߺºñÆ5S¹dɉ›ÊVÇpih Ðð ’T´©†:ñÍÐaЍ%¨t̃¸(â¦<”ƒœ´BÁ¹ÚÂÇ=ž[OLQ‹J”ûɈ5vT¹­‚ü:Z ãðpÈJ ð&\ã¹=ø‘6°t ‹pàÕ/Po™ˆ²ÇŽM:ö,T7c8û:…7Hé„)8t<`6ÃäµÅì€)x ïz€‚‹$ ˜éþÇÓD¢‹ðïöK˜òîJA –å -Ž2b!»r~ê†ùmá ókºyj²/!©xS¯J78\yÒ Š>ä“Ð%ivU…qØæq˜VâÊZr'е2÷ž‚rñ=Üê-E…{:¬b³'› H—ÛÑ”Áæ(-Å êHä—= ƒá£vµË W¸"P°Øx“Ú{Už3TºÀ7LaÈÙ Ò€Dª¬™t7OU…Íž- ¡C£•Íã"öxÈLíŠhá â`CÌ ¯²Ú£gq‹8…uð/M$Ð3ï ÕÇCùA ¾¸Ø¢28^u¦„“u’þqÌ©´Ñ<’Ý/«RÎ'½-²—j•m$Õ”P.x»ˆ|n‚° ÉÂ4ãèfÃ(·'‰ÿláÞSï‡*k:˜«yªÑÒ<ŒÞ²„â3'Ü@}JTá(t¥<˜BOë,Ôð"-®HÀ´€ 6¼€ÚÍ…^³·;-جf(Âmìä c‘faÛôû›ßÓ*“"Mâ©Ô—-ç bÈóôÜ  fäð@Á:.ê.òy*)æJ6äU^4íécY|ñ†É(ÄÓŒ–ùefÈl¹ó°PqÛAIé¹evÆd»48QÕmÚF7ÿ¼MRZáUˆÁ ¶‹8‘þ«±+Õ§XÚ!–t¯hQîˆ}–¾“e-W™ßZ¾Ï6òãåŠò‡uiWxé³B¾40`…—ø 3³Ä£Î^J¾ðz C0/^ÀG3œ<wmKìAq˜=¾«øHr]8¶AUvKqû6N$O÷DèD”bªW¨<“àÖN÷ ìÃë_ ‡¼j¿B áL`¡ry £.§ÑS7Øv£›ËÊ›¬ÌÀ1ès¥ð;ðH;ûzªmË;"¬Ó§^Ñ¡Î7îy3z‚9!r‚PßËaœ~r­fA+ª­cqº¢Ûb¨Ò-†b»AãþýèÓ[.Mc‚U ±s[ Á ê*ƒíÂ3ºRž§Y5µXŒ\¶)L“æ™Z´iRª¨†, —$kÚ¹Š’£¨€X’O+_˜—=sIê‘÷;‹ú!ž\8†vÈ…~Á£›Vµªh +£r=à ŸjÈsÀ(é¶Ócª +ù¨ÝÈÄÿ£ü"3h™ÌB'k“>rŠÜ P9È œ'œ'ˆƒuÓœÛèœ`9(„j}z­ÌƒœÎ±_¬ùø·ñ j ½Ïü¨¹JüÁ6½7‣ º¨8?ànÄ3^‡ÚKþX5¯*¡ª33¡ƒa#äÁQHpÈœp‡H26Û£ †3³é³ŠCF ƒètØ0‡1 ="Gœ9H¯?Çó0?ó*3a…WØÈ±49D4ªÐvŠ’Ì• €±Ðx J±¬°ý·AÁ, d1Ã2¬súŒ¸™@Ûà±ì¨‚ ‚F ­ÀѾ¤b='X…(à€cÙŒf‰–%jÁÌ¡7hAi±­Ì‰"~"Fb4Æ-ó²%`ÆÓA=š„FŽÚ(Ö)ÊW-PKÂ~ØFWxH¯Z«„1º@콤 ^¸‚¶PwÐBÂ3å‹/Ÿ°z¤ƒ&þ=x"U`€ ØpÌJ7-² 5b¸^9…öÙì ‹—1 (µ/˜K£S ³(6èûr°å!”½¸—2XÝ\€²8“tÇ-Ÿpå[@=ÏüÁä|¾l¡Ç’ Ѐ7ïÀ:€î)wy™'à'xî´‰'OâŒ8=èƒøîÀ ^Œœí×*(׺œ­ŒAhIbËúø"ÒSð4p©/´T®Ñ+Žb=˜‘H+xDc5-Ð*èrX ¼0>òFšŒ°Fä(ÌìÓ`( 0Ø P½Ç|Q¡ £9þ: 80*¨¡)š­Î …w(LŸt˜‚x´`ƒ¹¤ˆy©K(< Iª—ÝûF6ð‹>À³°µ x€-L’j`s3RP…qp¡ 7ÃI2’(šXS6«„9Sq‘‰=¥¹ùˆ©H2ûj>›èÈ/ì»RˆEMÚΰ†7H”ò1p_ðPîÄ>ƒ¢UpÃ"ÌZœbÏóHUyƒëH–†Šó¸¼Û­¸Ï30sF]ÐÖiɆŸc½cÛÎmÐx!ˆzèêí*ƒxàÆxh‡À¼Õ¤9" +€‚&þ0„;0„&PoU…&‚ÈðQ5š…7x…©*ØVp" PU€í;âlTPãªr1ûÉ3µà¸Sû‚@¹ß¹O¸†uŒË\h„ ˜‚ðÔ?ýs‚bèƒ` +ƒÈìVM ‡%@-Ø„?и‚W  ˜…<`Ù=° Ð˜ ø Ð h‚)˜uW¢ÌMÚÈT…¥%Z:…e€e³6•œÈJÈU¤Æ1êtWtÔO O9“Ÿ²ƒ¼‚=X["ÀT+pG±-ˆ‚XÈØÄ©ñŽñPA̹ €Í™½å[Ä¢þ­d€û"0šÍé^M—ä<›ˆ÷ŠÛ£\Ä!iP¹â…äQž<`Ö¢ŸhíÆkX׃[8# tèƒ&ÀÑ‚1„b¨€‚9„U ˆ]Zs%:(*€W"`¥‚M`_Ø*h €GiÄÿÒ­åàê¢Æp º¼Vƒ(ÅÈ2à…yq‹ª°à™´2ª„(7Ÿ@HhÔ‚m€†ß¥C€hHZp€ÈØ•r ‡åÞá]rð<`€p РZ€†EqÞ‚YÛ=žÕQ) ‚MhÞàM0ZUxÚÛb€Þ}Ž$£ÑÀQþÚX¨¦VÑ7e€wp¯ì²}€ 8‚~H‚Þ4µ="V°ëT£tm@˜aPÅ99_,­L\Å™„U-2Æ+r\Ø2Ê2"#/;ãã4K´™\t!½¶Q…"VåOדõ ”TH²MqàÆk V´J€'°X˜{#"¨9˜Ó¡ƒC8„SX¾õ‡Cà€kÉ‚J>*ÀÑWæÕà&ØHXÞÅp°OF.­-)9û Œôƒ\È‹\Àº¶0“úÙå~°‡}(?ÐÂ-·žN Rx³jІbU×áu€`jþæ€ `ÐuU×xhÞq•‚=xL‚iQMxðÊÔ ‚L`hÐ7èƒ (‡¦‚r ؃& ‡1"x…&(P6¡å-šÈÚ&@†=‡2ÎŒÈSŠPpWŽ[tèáðáéҚѳ»tÙ23ˆ"°Øç "@Ãß:U}:ÁXm–(Ê¡ÎÑ<õðâÝê·ÊÜ*ËJ.³UÒK%\,8®D_]êÔÃÜwÑ\\ Îð,Ö´Ò?“äá6`Tˆ€–°{p«}‚ hiª¦ "²N ..àǸ¶ êø¿¸¾Ž PÌ M^Eƒ†þ)ðÖæõ!t`‡ñ¬–Á8‚†˜J“(•½kH _6¨šx´â`Ïgzá4=І“<6v€Hƒ&øV –"€†Ål‚C€H MðÖ&ÐèÚ6lCCèY¡¥ÌW(YÀFe7€„u€&pƒ$€„݆Þƒ" mn5˜W€~m:(‡ý˜Ø%o­Ú7pmÕ ÍH<˜3¥åHd.‚§Ë^>”=;5œ¡ •Æ(1}G\q‚Xè ®EA%*\äÛ,hA©ôŽù¼é,~-fiÌ5fÜàZFúpƪ覦.—f3Kp@P;V Iä}þ«Œp˜11ž¯f… ÈLõ½Ða8뉅ëƒs>ë –ëø<ü¨Yp€lh ä>è c °"€ì§³‡/¹l¬K XÒ‚Üûƒ¤iéçêÂÑ$aß„ NH°îrxmCÈgH¨P6„WèVM`€&Àíé¦PþÖ7·óÅßÇÄÝ•ƒ|vƒU.‡>P7àÑâF"ØÖ˜sV8Uhx}í„.hÚ6„á.FwôëØ¹û´ØÀ¿™´&¨£.>òCp4º¾¤·  7Hk×ÃÎÀ9±¾…¢ëø6Ã5\eñbTE¨‚’2ÄÕé¾õ0Ú"cþÔO\YÎïAÒ“ _¨†µÎN$ Oõ=䬦®09‹‡•SÅ íq GKˆb€qð ,™|Éè³ #G•q Y(†€PhÁ)!†,: ˜—´~Ùï""øP¹¿ú/:*m8Ü¥ä×.‡N0y:Ù×–Ú½]¥äJ~òmèJÎÑMì½dÙVhÊÌße(šC(‘ÚM—ƒrxQܽm×®är /€d°Q®ñIÀ…–[íT_9w€‡ Ë…(“îÇ{i‹4éÈöl ¢”lœÆ–O §7¾ã·þ©Ü^L–fÙiÇí–2ƱDj‹ #gd3ãö3S›µ‘м_së…DN+õU‚ϯ wÀƒjµÖ50?€l`¸Ösë:Hƒ"g³Hk›æ[ 5{ŠIH¹^ŠSè„N¨ „ÅÞ?c´xøpNà„°¶qŸjê/åxbâ>„æãÇ~¯ýæ«ëQ£¨p¾¡YSÈ‚9¥9rŽ8åÓH“h0„‘;Ý÷Éù¡Óõˆƒ?„„¶m€ð—…K«P«äp³ª€†Blˆ“'<.`„ÏL?3f®]+sE›‘_®°qUæšG{ðŽLIPbbÄš6þ•q©R¥U–V·I°³UÐ*@[m+øSBÁ,²@Ý5‹T @ŸFý9u+ש§²|åÀ¡k±bӤɉ6M´m×›v®ÜºvﺅÛ6ç[·¡.Ñ´)x0áOf¢+‘àI‚˜S”<¸0eÊ%ë¦\ž¬ù‚V=Ž–€0éÁèZk2®,­Ùêl+öÚ*\¸°ÅMwNŸky§}*á”'6Ññ8âŠÕµÏŽP`劯\—L ñ´i‰Æ:é#‡ApcãêÖ øî¹·yK3ΩÓºq#wÜÛk[ôáVXáF'ñ­ÅŸ|-TŸƒòéTI •RŽþ?ÔŠzÿÜñDiÛ¡óÄ”i¤‘G=øQ†ŠâŒtÅe¸òÊ‹aô`ðØ£bFô[>õäQI1eUF†âSCúÊ6Iõ$TVaÕ}da9ÖTZB%VYþpf^³Ù¦W]ºá•&^e¾5Û}}¥aÐB<Ò)˜N V‚žmö˜Ÿ’ñÉçð¤hÆ’íX'èhÓÄ‘tŒŠ[êÉFimrá[BÞ·ÖS_Ñ¡ ;ÇMQ„J×$!ÙØóF.²AÁ:2ÑÄ]D¶ÒÙGä‹*ýÖæz¼½‡{iÝæ–•L!˜ šl­Õ ‚tôÁ;V°Ð‡jv¥“òqÁþ -´À@þlÃÅ6U0˜†!âJÚDŠ=qÁ%Æ`€(¦(Ò_ìàâ+®ÄX†Áã 2)êP°U$•B%¥R?ý •H=uOSm£e(TQ ²U]qÉå–e…y֘В m]pÒe¬ÌqÑ|©™7— Wyqh×°¢!Τ爚aFÙîÀƒÃIF¢*šÏ‡Å+ôv=!GãDÜWÌ0ß¼©†ÐrjÛPiÙö^+h`Åqõ²rÒrG`§'‘!–]w‚eíwH‘ƒXëÄ[l•^ª“O‰ßö6~mÑi H v+ƧÞÍþŒ^¨Ölm‹/Þ‚Oä^þ•OIUa3xMó–À0ƒâ/IøáÇ5 ¨x…+_ oü+¯”±€ôô 3EÐt>ÉS÷PB•äÊTaIVÊeuiËfÁ¶—Ú<ãõìofêÌo)NXk¥5:MÄ ‰Ï"5¨1 1ˆÁK¬F™ô`%€ vjg»Ö®v«8„|r¿úÍ…¨SZlã‚ì¤-¡Ð‰X”Á‚¹=€°bÅ%ž~ph ¼]Ìö¼ )j[!ƒ4µBÅ. hÂwò£JiˆqÐ’Å 1:P Hb´ÃØÜF'ãˆÏSþL¨“h@!,ͼD4…á1àÍ Xš`9( S`"q؆Ùjþ›üìÄ •hMR²˜ƒMÁCtLÌlê™hfD‡„:„! Ï'y Y¼ôcPG¨v‚hv° <áREY¤«ðD8Ÿ”0&«òIÄÂKO:™S°B2®Œ%Ä(+ ÚJ?5‰ =*Ö\í’Â6Õ-üñÁ*càÛÖ* Ô« hw8ÍNcfæŠp‹•㎟kX)Ï 8·^¡5N^β/ý³«Í^ ýµ @0kžÍ­qÇ Ô†€v C&j)d"äVC(;<;<íq Ã*‚|”ÞŽC%ÃÒ5øÁ¯m44üH†PW —Z,ZpµÀB±hÖ8ÕþÙ$É‚ÔrÇw$€  ë Èvv‡íZ²Earg A$˜…£ D@hŠ 0èAä@ƒHëæœQÐ4dÁã¦Á?Ô–µÙÃäÂÁ,âãÍE¸AL9Þ¸ƒ>ò‚ÁXÍuP† ¼ã/,8Áo&ª—lEÇœLUðiÅê žž‡/ȬOÎêlÊÔiË´ÒÖÌÑ*¼áédʳþ”¥ÑNÊ©©B¨‚,ï·ÄÅ8ˆÀ\‚AíqH!NÄaèÔÒŒêÕ Ùô@.„„+ˆÃŒÀôdùçòÔ€&²x€à°ãûàl)œB»=n P°9Ãì@A%„‚&€Ã•ò‡¦Ñ\ðƒPAä~+Í"¯zÇõ“M<á £Ã:tnç¾:¥Ó©àâÄk|äðºÂÆë´¯jÉX0a箃.¬Ã:<†6ˆ4nV)‰*¸ E(¨šFˆ`,Þ…„èKô °€°À(2¡õú/„A˜‚ìN-0pòa2(ƒ$ªb›&uXU`UþTŒÒYqX–LEÏŠØü´L¹©›ÉÿšIDm¥±d²šQ0€?4A,0)*ð~üƒ ÜG°ÿN e(`môE_DÓðÂ|,@ô!"÷Al¢6X†_5<‚ÎÔ èv A–á ¹Œøm«L·€T@–Éæ,I .šnðÇ ª0õ_Æ=ó:Ç ‚P ¶-«¡Ctñ:|q8# ꈻ¬âë0TÀŽ#¤ (A?À ¬ƒ°40œMÃPâP”TÎ!0À)¼«ª…¯ ·™aDÆÝ®Š`­/8²Xƒ5A$Aª`ÄG¼H€ÁþcL†bÃð¦åî“2èYiÉUl¡&E¤Tj&ÌÈœUé!ËÌ©ù¦Ò[—X˜¸ HÒ00@¤Ö éž^ŒL¯ˆ€HÁ8ÀýÁ+ÔÍIP÷éIø’l›µ°Ö3+†ÒÙp-ª~Bð‚8ˆÃ”pÓÀ »m5lâ÷YÌ9Á“QÄ.šíÖ4tvð@1Ø€bÆN8ÌB’+ 2+Â)¸_‘å¢5q쨂¬1w6±çœ6?(~rÛrˆ\€=$TÀ+º°B”g®Ô¸œ+q™Ð²+Z°Açºt{£€5,—aºPäÜFaVŽûG PÀþÉ‹aHóÂŒ”?†+!ŽÀ*cõÃ5ø£ÄÆ”­ ßI+Š”)‘ÏÉ`ÒSd›é¥ûR…Ì®rGz$Ê4×G†d¹=-wXÃüƒX6Îʽ–Œe*øŠ§e4!lÂø„Ó£ž4vßÐí O¥^.sOí¼ðÉc8MP@ª^à Œ@8MAä=¥Ô:i¯st߉µèˆ9ƒ ù%¸A0ƒhpB*ÐC;ÄÀ£~Ñ)®±ˆ16¥œ8@18t>¹Y™Ktk¿³O·®hC”À*4¶È<§ ™´†|ÿ %ZÐÃwqþßAì°E¼6)“ ÅjL 0@LÌí+ldt„„ €ÞypÞÕ¦GTÆÒàÝö-†CÙ"¹VÛ„ˆ t:$úF$kM؇aEW-g‰»ÏFºÆü¦ž@P'pjœ…ˆ6AºµÛ‹áÆåÄ‚@ƒø§·F¨°ø XCñòwºD󜹙ŽÍËd»;`€5ƒH¬ê5øÎ0A<˜'ë ÁSê9“Ûbb&ú“÷­(˜×݃ÆcîM.P{þÛ„A8¬FˆÑBýÁÜuè®®âN£ÑF8À %lnA6šË°?Í:Õà;ú˜“‚ì!PP@þH¼ªÓ~ ðq ©.ëq“¨Ç8¤ÀOA©£À¨ïnP<®AÔG(hÀ˜¶cî\G0o¡˜ÁôÃ<Ï1pÁ=xGÄDÜ¡ÜÔ …k,ÈÁÛ´òX}”lØË^‰XÁ/®ÞGNþ,§¸XÖ`à$ôÁìo³Èˆ>Øp€È!¼»±Ò!ˆ€!8À¾/XÃài"Ÿ¡Ód¡ }vÊÞÛgÂk³+0Ácá€f³ÂÕ ;¨ €’„gâjƒààTC ”¹¢{‡ˆµ<Á& 튬a0ø‡MSÁ,ðC<4‚üDÝÚ9‰· ×/þGAÅ(®@v Î $èANtòäIH¬‚Ù° cFŒÿ|ä¨2. È4U²dñØ¢ÊÈPURriÕjÌm1WŠDµnÝœ(pNH9’eÐ*­‚†’€²…:G[lš’]B…Ñ•àñà<3ü„¹f&—™1¹ú( ÏÝwî0àhg¦Ÿ»§è¸Qð$*º'<Nõ;õD1 i$”4\¸¤„m`†Z¼-T–VY;N\r›á’t4wö\’‡,¢9píj£OqhÍáÁ¾R j»S‡•U¾ÐìQÅ@(Ëq)[dñ!e“páòhñgÓ¦=6&¼Yþu/Ú &”º{ø¿ÞóFuR¢j‚):§(1p­Ì5&¹®¹×#LÊðºré6RúXEHY¥¬@!=œp‚ªÑ£š,¬¦RH™ð žpBk¬±¢>ØDR.©á «´)4¬qâ"l0äŠvÂ0à!Œ/T ¥…V¸pé%$CYi(–Ò £…ú¢j<ÚŠJ;íÌÒ¯-ňÁ„Jxâ'¦x"ÆT³ª½jð%˜rð¤qZ@)8–¸`i2Q²…±mÒ4Pà §uPp‡ƒA¬"¦=YZÒ¨BÉN¡£’`¦@Oª) ŠÊL¬þúëšTýÈ¥\5VàÁÁZû)+®uHà7((âÓ½²û’»j,áRÄ23ì1Å S,‹Å(Ë ±h5‹lÙÎDí³ÐHãÖÛm9ˆ%\PÖšK¬p*mV‘"ˆ˜NhD°tÉJ.e€ ¨PEp£ ìéç{îH³¼ñ´DèAðˆ˜ÊïH5³Å]ŸÊ©øX5€¿ûôÃ>^^±n•N¨Ä µáA¾>|‚RШF›jÞ­ ,Xe•uŸÐc/ IáƒKÑ£fmÔCYN9¥P´)˜=T€CცpäȲ‡je¥m‚))þˆIån¡¹ˆ!„üU ½Ê4s=†%îÛo †™N‘Æ®ŠP`Ò³ $%ç‚Ðq<ézk8¡!–Ÿ†Ú“¨ÐG›Uš ‚èÈÁ `J ¶ªŠÐ Ö1®ñêöküH¾2ü0ž[ xË%Wâxì9¢ˆèFïm…¢ŠÅq˜(“iZÇ Ë–ÙjK2ê3ϾݖÛòÉ'íüpQ í‚)Žpc4ÐÃJú`Am¸ã`äÕÃŰ40N€(ÆnÓ"65Ì;wëNyJ ·è]JZš›€1…"ø¢y<˜‚ÊÀ üà ep…bxôà p€†úЀ>þ8è!`™j 'àì 5¸ÏÞaž‘"g€ØáC !hiÚ`‡X0E@8}ØDJ$‰ŒimkŠR‚”“.ŒãH/‰\S’P8`X¤Š—°4&khñΕò70IŠþa{˜€5hÃJôá~Ö8)®‘óXexÃ@¦ýegpËR Iõaƒ´¡àÞÐàFà\`J Ò¯î ¤Ì Z-Ö@)\aö€ r`¬:íR~â%îþ€BOÕ4(Š# ¡ üÔ(ÞèH«KzÈÄ’éiwx§wr«_Mô - š0U45¹Ü ž•XÀO‚ï›:ã» E» ­E4Z4²@rÅå[´…4Ö«Àmp¨h`Ê¥ZŠDlƒ¨Ì/.‘*øÆóÔOg¡U;Ëã *ªÞÀ–¤Ô˜$O΢ X N T ©,€ôÀDª¤ ÞaþBcæ,R½‚Hà+ú!žë¹´‚|)>ÄbÏtpÅC›€xZLÕ0À§q³çY$ƒœŽq7'w|ÂþEsSãÛ¤Ä] ¤Ì/DRÄ P̣͡!š˜<œUÙÊu#ŠT.¡ /á “)‰Iôp$8€ °@ ´ÁøàhŒ×ÀÐ@Þ!â,Ä<@#O`D0@@¥à¤@` °€¢€y+ €h4äŽÀ¦ñºD $B‚ˆà.TyÖ¡~`-žk=êÊ:Ûö€%C×£I‹TèáG1¥` UG4 Èá ÌôXáB§`À¾®Ž@?ÚÒFFa``æÎui.²ÊØ0r¡ ’àžàþ!áƒÑM&¸€ÑvA/&d‚&þ'&0c&32Œ‚32%áÒ ³1%Hû¡•×¼,vÇ Röxá ²Ø¶$uôz€²˜è#¹PøŒÅƒí3£‹Øø¶kUÙéÚÒ§žÏr›18CC!|h®‘g¬  ¤üöèCP·K¤1“Õmù‚¢³àFˆDbó48e"a.F_‹ˆ¨!å, °àâ9â`ä6jª,@¤àä ¸?ßad޳‹° °€å 0BŒèޤˆ ! Ó 6ádZØön¯™ž"š¢I…w¥<äF­Â…é ÌÀB»4 Äà è!sTþn' †Úôx!•Š¡Vz'UÈBp¡"©ÃCD㻀¯©—¼æxÅ‹~“£O7â¥dœ3D„Õ9›J >¤‚r6n*ÄÝš¥‡ì4ê $¹qžòØ4 ¶!f€Àãä.®V¡°…Y”¡{.AŒYC° 4 âÀâ WáŠaÔ<bþî_?7ædθaÎÕãœGÝ áB 4Ö"?z€ ˜àÔ²™Ë,uWo¾° äåúŽÛ_4ÀL‰À^á þ@¨`¹5à´€ŠûÕ ‰oÁŽp«âÉÔ„G`ÔFA ®dã)ÚCWd j'BIbàSJ@†!áH•¬ÖT(%tꛈû»Ñ‚˜ðÓN`óОÄ&®ÞVŠáCõz Æ@ôÆ‚ŠÃ€¨ÅŽKÃçp1 ‘@Ü'Æ :A^“»dÓ›²uY†1|¼‡Å» 4ž5^#úZCܸú ªl´¯£Æ™“nòÂéÂqTòYÈþ;ÞÞ´ƒž@êúRü!tÒˆ(%nf0†60ùÀÌã {´à<ˆàA1 `£ ê ”"[¹âÄuä0°@Ï‹aääœC¤‚úÀ"r¡-0àFà~ J?!îÐB ŽÉRÍnFe‘ ´€R@‚›c‚{A¾à ´à2ŒLÝöà ^¡ öà 4Až¯@€+„b=*våÆË ÁwtB=râ)øÇà)ü€ Ì ÙŸà[.8öDlóDO—Üqˆ13[‰£wLbàmS…5õ-úÁxPyð@ àa lg¦ÉâþVnå-©¸ÆÀSÍxÁÂL H7Ï©½+Z­6m1ê8)×ÇGáa¼5°z}‚\*éÄpÆ ¶‰ÎzY¹°‰¿T_ÚãÓÞÞè&Ž@ .%4> ¸´’P%MšPhj8цæÒ¥U—f8$ÌÂŒ 2¢A3ÃBŸzœT«¦ Ë»ܰD‘’-8qÞe‹S¬Ø„(ïb{)ç],@…ˆ¢Œ”OJ sìˆ;8JJ}øñÃËX?À¡C©kö.(E ¬Ù²dÏ@‡îÉWè ¹"†‚˜7bü\Ñ2¤o¹< Â¥Øôå 9MÐ4P Ž _ü\˜ÌþC©ÚËfÙ¢+QbŠçuS.)#ŽMwëÖ¡˜˜µU3|MI ¤k¿2¾p.‘WÁ*UZTW¥ð‚\ª$Ožæ¸ñâÇ£%AB:èdi%wJ.äw×Ï<ó~äbÀ¸óÀ–…§àeà¥å@YpK„YdQ…V¸uYl“ᇂ("ˆ§ÐÁÁ‰žÈ‰§¨˜¡Š0žx; ôÑ@}°`6VðÀC ,(P l9ÁVfh%Ix 6‰¤“PF© “™=ÁÃ5ø’ªp \+­$WP9\R zP´þ )wÜáP OÌ0.qì¡ÌF}BÊ™TóD (óNžXœðŽÙà.ªH‹¡‹(ã*dã@1}X@J7@¡L6Ô8ñ„OlöD|]IE•U/ €` ×Äã0 ªEåYqÍsQpàlê%Îü±X8 ñ… Cüñ‡y„“C%9„óÇfáÙ‘Qn¶Y䯗ÀG\ñ…8 €}žMq‰/¾¼A®;ø™A‚= lÆÙ%¿ŠtÀ‰Y0Áa ÜsÖ1pÈŠRׂ»NYBy~\FWˆã ¹` Ÿ|ñ¹ÓŽø½›Údð¸cF;¹ŒÃ}³-þ¹–”˜9¡V±øã3K€èá‡Cƒ¨Ýˆ#ž2â‰&F㊴ˆ"úÌ€?˜åÄk8ö¡À*<ò 6 ÂB5F’eäÍ7Û\1Îg¹ .ÜtOÉ6¯<×K—T —:‰°Ð–D zÈ& øè|/zÀæ•‚@ÑÂ4ãHG¢{e)ŠÀ V¸Â ç:P ð²‡=Tâ~ðƒ³¦%q”Aca0C {¸¢0eðC '-i€šùÞ÷€áŽ˜¥CppÇdŽà‹\€6¹€ X«ÎHî Ê0Ètš.ì¦5…N(Z :œ‚t0dØ„>H‰-À¸@?Úq {vŒñh<.€r515 eèÄ÷ŒaX'$éöH4"ØFÔ¢–¥!- ¡#þˆ¨F×¹Uik­^éºF3bÍi=›ã&‡ê²8á}Ðã*»Šm“~Ò™ÛÚ¦™EJ²Ž´l“0+É™êPEP³ÓãTÀPx.”A„wÈá'gr‚äq‚¨’@Ã*HYÄ!Fjót€à¥’)\ðÒhxÇî0ƒ=øRxÇb-PmÄâ¤à;X`¹àø”‡€ož_“9©f6×NCŽå2ÕP€/®à Va z#ÒèÉŠ^# ×(Ca¾àŠx˜Á =`ƒBs>à\=h ¼µ”µÅ­mkYÊE¿'®øäb!Àþã{á¸#ÂZˆ@¦€`ÔàDª "Óßð8Í‘©Á¤“†!Wa`-H²P¶¢*P,\%àýÚu™æ‡$ƒ;ÊÅe.¯ðhÄÇüU•àI›ÕÆ”töÇ´¶ÂEz}ë†Âˆ43z1gÌ3œS£Iù­[lÖ »¹UìQÖd,·Ç…D‘ ®,ˆ É´8€iÓ¬‚Ú©éËTR‡œÉ†¢3°¹ ¨.¸q 4ÈÂRŠÃ‚6A eÈ¢g±@ƒ6ôä„8Üö0Þá‹\ºVqГþ¡ÌLÀ“³lV)Áà0ž0ä3¨;œþ` ˜c@/´‚Y7ó½Y} x+D;¸Â ³‡`¼ÂÒ"Çî ?W°A_0t…$@oE˜À|Q‚~\¡ bØpR|½”Í!é¢GÒYR°qÞ$  `@à€xøï¿SPBâ1„~ Gh(ÆšxY¹eZÒQGó‡ðþvRóRºô¸Ëɳ%¹9 áNyzê™L`rúíM¢Ð°ã±È½2gÀƒ;ò×@áÈFâÀ HÊ&»…æKb2ƒD·#¤@C0`)ØÜÀFë?pa K8AÑGx `XáàÃ⌸&bIëÊÞ¯ ‡Aå¬gEK š+zP†Æcñ &í>2pbpI£Á 5¥OlC%iá ³±îÀ :P òñ5îp ¼@)ÀÀ@rÀÐ;lÁb@Ô‘tt 5Ô9 =•dÕ1ÕÑ ãd¥U„+RƒS0Iá±$þ%p 2P?×@âeåó \ÇuaX…U¡q1°1Z×ý‘‚¸Y«@%‡´6Õ°  ä!{"2W_T‡/"xlÄwuÕVs„x‡7GWSx@#˜â5†yÅ€CRV%*bkáa8Ó xk“yôufèÀ‹HzM¸y”dzq¡ BÛ9¸0 ÃÀ Q  Õà9À>0 p !ñ†6 )qr 8Q«@]Qà' ‹ÁÄKÙ:Á´lÿð×犠 ÿ@ bÐcHRð` Ð1>  :â#’È cÖàê ǂ gþ0là>Z$(ë¼Ð£.Á@¯@Wào…G°s»rQq#Yn gð ¼°ê…8Jà³R©p‚ ÅPJáHEà '@%"@MTŽ!“}ãA%GhÒSp…Õ‘‡p ðB“ðiGYnQOäå?eàTWà,C2fP îÐröðfÀ ðcýÐ=ë”yláv9³9%P QW¡ g{(F}w‡w!¢"Y O³W*"5s˜‡7)Yc]ÃG8ò††)”÷qEâkôf3žx=ì‡Oˆ3†D*†%^ŸÇHoþ× èP RÁÛ Á«¦ZbðK%09X`z`Ù˜‹° pRz<ãyŒ ¡•"Á0”µ:Ñç¹7Áæ¼TÿàÜ@ Á`Á0 Å€9”ÇSöPIÐnP n°G~DW¤+ {pqTè>eð Cæ#P'C¬@)   …qqM%–¬ð4Æq×#Y 2E¯°.Y¼ sÀn82`®@y2 ’la%ŰçA P 3y"`”EiÐ M@Ey <Š;T&¤@J‡ÐF¹ p¹tþ†Ä$©H%Ppü‘ V•õ ó, Ê 0Ód s ±VýòŽMrˆz@ši¥ƒEg­w#‡A#F-r ¢‡’—kµVrt§X#5‚VxQãWs …Å €)y8¢f¦÷N‘‰íhQM"b ¸ g´H©Ös©wSV¢ bN@mY`ËQÉ$\ÜðŒïŒÂ8M2aLÐEO@:Ä}¤°°æqPK‹ºŒ:a)¾Ä Éx ‡¼XªÕH  }€}°›èžeoŽ,`ìÀ=„”É+„¡åsp\g_` )ð¥þ v àŸ\G†ñZ@½ðŸ¬p »AzW©fÑõC : 6ð"Àš  ?PNÏ£îÀZ@WV)È€"ä'e{@yðäÐ Ðt@)›“AåÁ%9¨ƒ9@ƒ9X •àЪ00Æ‘­`{fúNN 7“U'•VÚ® ÆufwveÙcàÇÐEt_™ª O  sH€w‡¤tÆV§Ð  904qi‡G£h¤>•‡BÅWCx'Ò%]¢"ª ›tL…•ˆ °X]ƒ#É(¡ï”•iI{E”x=+@GHzФ“™$iþª5jè¸ñÔ†=×b² >ðïP9' ‹ÝY[®ÙymÁrÀ3àma›‚›{/Aq€ÜðȆ Æ” ½n3^½Å ¸`H€–³ Q(ïP ¤@Q›ñö@o€cHQ*¢²¹MÂÄuåà Aô  å£Bš?ô÷pnÀ È@äŸ÷«.…¡ Êu ª~ û© Rx ñ @ 6€£†  p ÌS ð„À b +¨ó¯^ë@_À%3é²TP 2«³  y@ᓱ× Ø¢Iá ÃŽÑ7C{BKgîdQwPþþƒ/f°1b(°Zª¯×Ud‰µí@¹Ð"Ó/˜x3½W™ha àE³!x×!f449жi[FvëSAU"%1m 5L£"4x"2ô7}‹Çƒ5¸ìP ž†æºÅŸ—E‚y‘ºpc® .šÆÙ„Žl¹CÜqZŠ•¤« >¦”P9kB Å`\Ê  ,!Q`ïЪ¤RªPR  °LÙ¸Ä4¬2!Æl'ð> ÿpœÜ@» 9€ ¨ƒT( pŒï`&’•7¸o‘„Eà uåc>ìk  • M𯰽yðô`Î Fþ ½€ D€¥¯€p_°âp¿~ð_gfXg¨Cñ!íàÀÄ@ äà åÀWÑ<00â` nBJH0Ë$а!{/ ³5K"´6K @³@E>kÒTP“6ù³‡@¤0noÇ ysö€ã¨ÄDW@YxèX;¥à c $ŒÅV„ƒt†ìÀ–  ÛÁ¶’ÕÛ° x7FY]Fd´Fzy*"Tyû4€[xƒåg~ö7X «°¨]Ê~B™F’Y‰ÜYjÓN’ÛqšeȾö#A$ÖÜž†uך5Ä›3*«§Êcþ ¼Ã¤B Àˈþ²Ê» !±ï QpXð|’ƒ ±À8¸€º©üÆtLÖ™)D à6Ð9à '®ŒÜ Ú} ØJ½Ó„:àuHYØ’„ÖÀU¬eAôô@³P-ñ›ä0Èà¾T¿&õüê“ ä°`âo®Ð_%‘ ÷6D*@þxZŒp?€ÔL°£Ð f9’S ²  60µQ Q5 \p ° .­€¨þÀ£QãSEù£lÜÆ‡¤§0DzHªƒG ,°+kIG`1P ýÐbØ1C…Ýê´pAjW=¡øµW´ ¾0Ye¡TÝþ±ÀÕ»§y¹—ÂÕ"B5oKWÛÐäe­·RŽ"|ë"yü·W¸~¦ 5ñÇ'P}À”hyãñÏOݽF™–5IE2*5€¤ 9–l7ö׌˜M”CŠ2åwB‹<° 6 Ô'3°‚wpÚp,  㕜áV'Q 'Í7(¸ >  ÙÀ }@¬0ˬæ¼ ›À8½}à€œ«P¤@ÁÚšsØY¬Cðè‘lð)0 ³ày¿T@EZÐ á]βÃy@&°êA•ÅφLY‘H¹¼9$WRîÀŒà€^sà0þEðGwP K_ ç ÐJ  ãPd\0Á-À&Õ—4ÔC)”2( n!…q1Pó•휋` @ –@S€ýà ;ÀÎà ʳ0ðÖ`%ð¢ô2ƒÐ<à.îàáƒÃaƒAt"~jð_BNò `Òïiàðrn1zóÆO˜~îàõ㊄8ql\±áEâÚ53ý๛2åÉtè|éÄ#H’%IZë3$:=«¢@ò—%‹™Ûdʤ™Å¦„]Yvñ<5󧨠>³ˆ’ JÔ¶m¢8=ª3þéQ›§‚žZ**‹U«»NIèzìØS U =UéHŽoMÞÅ ×mÇŽ"KÚÍ ·o '%ªÍ(ÆÖ-Þ·€ïÊuBÒ‰žjwÐü«R% ¸(Qм›° W k܆­%EjÆ0nÙâ é£Ôªr¤(³ÐYJ¬86&\²€ë„²8¸ü‡¶¶bqXhcËÂA,q,²Àíƒwb”£©AªÆ%ÕN̳°¦ÀÊ¿÷ê]YâÉxoÌ<ü£J:áèP¡BƒG´ G -þ8ž!¾âŠ/®HAƒ<&ÌC-¾G¢2ÊJI$ÀÀ ,!€4|¹dwþ®)ƒùa‰¡ˆ"xP]Ñ„AŒ#×&”42c’É4Òh%”ÌB‘²É)« ’J,«Ø¦ 2{ÌqÒà‚=æR‰/ùžx?Þ¤¨ ~Ì(ƒ 62Œˆ^Âȇ~.˜"@$Ñ=“X²"M'Øaá8¨B¼œ‰¦,³lÁK ¸ S/Çi¥.8íT‚P=•`›T»4• /_5õTT«§ÓJK¥©ÔJûh HÞ)†…È+Q°½ž`§PCIê‹/gå2vYfEô¨% ´VÚÈ ý(Ûh%I¾.ÁåUlà&×চÃÐà<`°S.˜ jX…þšÈÆ4¬a' 9bña“î÷„HA"8îNX™ ¢x' >,¸‚lÞ¹Ž jHw˜Kô¸c•w¸)æ„UØ@7Þ( +>ì+¯¸BBç"¦8¢ŸvÄ"…< ‡¢Ñ —^6)G?*訄h þ(pˆüô+ºÂ Åèš0Þ°gŠŽ¸£à[¸ >|Q@Ç$v`„‘9\`†bˆ!$ Ä@^â9¦%PPb°ÇZ—”RÊP¹hRÉÌZ™2ÔË­sI,C©$‡$wà†Eç‰;xà žcðà ?6ôã"x ðãx)cðkâ1ƒ@݈þ=µÛ@L„@ùe‘À 4à qZ½ ìµoÖ̺{*ů„ÊЉ>?‡Î':z4H!œˆg–<ìŸÿ?6ù†+‚!+( †Š¾+ìñ²ö¡|  ÓÁ4f#æ‘–Í:¹¥0©ó‹²˜µ˜±}DÚÐF5¼u(øpk.Ù’K³p¦ò HP[ ,0ƒr9 XàtÐ0`˜ÇðâÆ ú@ 4Ø9PÅ?®cYL‡:¸ˆCqN`8œÌ4ïÀ¢2²Ñ„N€ã:¤à$–(p£Hèv&ð`T#ehÐâà€”X# ¬pCþ·Ö=áPc³‹¬Á _dvWB/öCa?ÐÀ&œµJ´ BÈC/dµ -úÂâ1‘Š\℺C5D(™KP ÀÐȬÐ7( ^¸Û(`àŒü Ex2`S° fp ‡¸u¬ÃðA"ç9(êJ—ÛçÄù¤%å€Ã.@a # ÂÀB `ž"Xã Sx@F.ÙÍ® $ðàŠ˜!a€Q.ú!ÍuLá¬{¡ø¢<>L‚eÇ<Ó¶tTƒ¾‚† ° ’ŠÀ˜üƒ|°?Ø`Áèß‚Œ+L b°G Ž ƒþ#,ð ýˆ=èc#¨óG€<Œú@e„©YÜâ%(ªFumk‹*z¥–>T.“áÁJ¶åAvp$ƒ,ô‹HÔÊó8ÁxcÕ–Zç€'hƒ `Ç 5¨Öná,.ÛÒÃd´±ŠÔàH0á†,œ [\E Q"Jl@²xG5jŒP@1h0^ Xpˆ€—ØŽkÀѯ8L`;R¨8V n`'5ÜÀÀ‡7‚ÙÀÅ%PâYHá«@ƒˆP7•a^ðÂpp„ÖýEDwá4qu£®8@Éa²JÁ#öS!÷ÁZx/=ò“þä!ïBâ3ÕªëƒY¥¥ @4CAŽàË@&aêÅ(ÔñWô ^Å#` ¸#q‹Ædp] ÃDp˜DåÍ͹ªKdê9eŠYã–‹Sˆ2al –І=ß@ÝŒð¬¹ëXá qPä"AÜ‘)¬ãJ€G ”:¼:Á“5øà檃º._¾š¦Ž€hPòáŒàó `. ‘=÷Ùu‹T‘χæ3#wÆó¡ñ\ÕE—@ÐXÕÈT©êºb¸ÁW}P@XçÂ𤭅Òë_â⺸5ÍO¬C´—ˆþD<@¡¼Ê˜ FuŪ Dá’W'° ñJ¡yô€…(œ èdQ PX€æ%P e`A5ˆƒ*|ŒaÌà­Aÿ±‰ÔL/ÙˆE6þá\¼VÝ*âà1ì`Ú€#àjT — ,:!HôaqCˆûÁ‹Œ€ =øÓ:(™¼¬ÐD öi†+hA’yP€èAQÒƒ ú9¤ò‘ÿˆ~@ |w¡.ˆœÀk\wYO¸D;hà‰sŒÁˆA`a/0‚4Á®ÑƒWhá }Rg•ñ¬3¼¡5†ª*ˆªþ \xåÈ´v´“‰ c;¥²0 D€ÇÀÃ:”`1„¡26PPb°oðÅCJ,€oêA®PŠà@ ð(ªQ“ꧤJPD7¨AjL‚€xsT?¿‰ªín.^Dßiܹ†Îg>y€ÏÚGšu»w]åÌ:â#3÷­ýÖñÉ×Ma÷r~5Â|×Åù ¼*Æ­Q·ë1g ©A(׸¼yvAd 碇̅«p[øKô×C¹õ•ckkKŠñŽ8œ@ß@bƒc³)peh€U2 8hÀç ×ê¶K»H &r°¡pþpP…(Z-îè¢ èƒ¡ °¸¬(K8#è„>¨]ê„ ¨)>ˆ_`›k`‡Ãh” \‰'(0?8ÙùMø¹©Q;Ù3h‡0V¸©0€¤!‚‘{BLWà?¹¿Ž¨ ´¡µÔ¹ƒƒ0ƒØ›H‚XrØ/èX/€È‘)@)P‚B*öÛ±;˜È.á€XðUà€,¸Ä*‘±0¡8*r€†—úŸ0 {]ÀƒF6Ø‚-ˆ‡¿£€ÎÀ†  „UXÈ'@¡$€‘(V(W@CÊþ ƒˆ$€‡$x“Çó…xÂØ­0›2K`<À†j(`À%.»„ °GÃ¥934AcCs>|ú=ç;¾é#¾w|‚8#¾ç»Çyܽ5y{lëëG9¾>{¬G·AHX…;h tàè±7œ¥•€ ãq–àYû*f‰¡4‹Ed?6$_˜³9¤zDRR†z!v0™b`7"m ,Peð È@)06l€(…>HA À‚ù: Ì"åØ?¬†<ªxÙêí˜ (†™ú‡xAARÀXÆB@P†SX4°=°‚”‚MøþR ‚ ˜kø&ø€8œ ¾[;bÐ!Ø)ƒ=ð8§ ?Hˆ‡U2x01ˆ~ Là…g`Txz¹ I-`ÊÓ©ûŒz'°„jˆ³#Ðð_x1€†Çã› ›xA™`¸ƒHµÂ@½ pÈ (@ŽƒñU'»žpȤ/x¨Ê€#AsˆbØNà0 s \ˆeP„ ]\6a¾e=â©Gê«ÇâAQý½8‹3RPZ…õHj°‚P!ô;+¹b«—«ºJœé–îó¨Hmà;Іz$7Xˆô 4é–½¤«'˜1ž#$,4˜4Ð>PA^©Ø‡Yee8@9x…eˆ öÓ€Û pˆp¨î°€>ø \‡ê¨Ž¬¢!:­jp º¬l‚8¨€Xè„ X…Ô‘)©Ïª4ƒŒP‚»¼KŒ˜¸´aȤhœ'Ôñš$z`ƒ»6ˆz‡Ðá‡+þà/È…LÈ„èUL*¯G@/ॊ¨¯* â–¼XÀ·aÃ<XZ$¾YgØ3ø<kÀ nà€à†@$0™²u3@؃}݃Wx?Hà'3ÀÛ%€8€6 bàbPcÈÈ„0°‡„3þy,Èé›Q}°ä¥°ê“5"U?#uÈ@jq+¶ú*ÕL?’Òq+¾PÒ …ÖуÀÅK°i10ՋȨÇK¸„o«ÇláK˜ °€'˜3Š‚lµø 8P†`h·wxex‡ð*'ð¨äKœÄB•ƒÕh‚ax4P m˜à† ˆKnˆ$8¸PµA×(]Uh‚|HÕà¢Ýƒ‡»d¸½œH·à4pƒ7Ðø|BIª/ˆ^ƒc臘Ññ¤©ù6 U"0TVLJš!4„‡|∠ŠÜ½­Çʰ†ª…˜Z+˜8þT—Q:g ‘$ø<=@‚Ù¨†œ¥!@à`\à€m …¶à`ìØ!áM"4 €ò…73ˆÊÌwØ HØhƒ6Èb€Øc„x¼óV(P„fsM*Ù¹UÙ ™ˆ”% ÆûŒhœZ±%@#*%[e>x¼ÇK¦>êC _(†U㌔ ðû–ˆìÛ¾¥–²"п…HS‹ ¸ ¾ ÔÀEö«Gk®.MR[‰Êþm+®%Hm(3'ªT“ ˆÙ 4h§@ƒ`€f_\ãpŸäm`zJHÀ°ÄX¨€NˆU‡Ó˜D-ì€ælU)hTA]T\àðp€† x½j¸×µÀ†Á4é$¸€Vý‹¢H7›{`…¡!UHð.wðÂ/Ѐ¢!šKÒ‚p«IQ¯Á^¸†¤J_˜æS³½•©j¥‹õ@ m]…$x€ès=à·`S£Þ-y0.†õ¨Ú±/®`À³}7˜Lè568P8RØþã+HƒÈçóÇÖ©=|G­ÒáãÚE._Y…B25RžHhQ3RCû`™Ž!½ÀÅ2¿gyÅ®øÛ¤Q«‹›ù*Q.QBYħdp{JRhµk‹,ñH]Ùí¢Ô˜f\"˜7è É>0¼<ŠÄGðGi…`4ˆËwƒêè¢w®g)` &ŠþäX­8† è@) x–À\ßDÙ@ƒU¸3˜º#ÐeZ#!¾H€#`…õ¥¤¬¡‚ƒHœ÷ä“ËÖB>©xˆ P¢‚^ØÑ4ƒÐ`=›‰|€KP(-ÄèÂC¸„ÛjWØèhA!f@ð€É‚å„ Ȇ%¨ƒbÃxBAàp6$ ЫB‡xð»~hƒ5Þƒc€¶nƒT”‡Õw`cc@ôuà1Ph—qø¼†ùôWÕ¯2ø„Jÿ§à—Ìm`H>ǼÓ]`c8@€Ëöƒ\ÈÂFØ#AØ}h„\PÃQ·V‚"Aþ±Œ±Ô[Ø[ÖÞP`‡ízB&{äíÇ …>­Qï>QßäÝdà&ÈØ‹Ûb˜€O®C*åˆô¾7Ô‹Áý´¯R8;“÷€ âýÍXæ·zJö" ­?¾ú‹*ýÚ*}=JfR †U8Ôaö(¢Ì `­Y¯„T8ÊUJ0.†U˜UPŸGÉ‚P`,Žã‡†…O™ê …Ž2·‘ï—6zUÈÀwHùŽ:ápËÈ ð{¢á Wî’x‚&ü‚ü¯¢Ù?`ƒŠ0D=F6ÎuW‡?øûùqûr ¨FˆÐh(G—tC“ðÑ“þbògp`„+¸†‚˜²\¸–þ€è0/f¼ðl0lˆ'Æb,£œ{“¥ ³$§-<‡6k°bÐ_%0 ÈscPgà@|ÈW‚<£l€ÂS€8º–Íb*ÞOˆ‡O¸t¸( ?€F_8‚GƱÊÞì,m ‰hÎ\‡Îƒ\ÈÎ&…uu8æEC¦;(ä"¨ò ]G0>ئäe¯ë8Û‘€ômÝöcå~lwÑ­Qò·¦Ô†ÆØÛ_!ñ–¡q/vRÄ­«ŒÜNë–»m3Ä55ªÈɈ€î`Á‚èª]ºsg†þ¯<œ t‚D[7 ¨õ‰GNœU¤Xp;‘ÃUÙ4Z¸ˆÄB”hªU gÕ e¢ éS#Ž \¸€[ªJ•ÿHYC3TŠUÿÞUÓÃâƒb¤j¬šQŒ®w¤4ÆÉæÀÁ; 8©A ‰ž—Z)r‰º„yó&ì[°ÄƒKW´ü¡Â@Tè ¹B⚟¹ÌŒÁG rùù“'q8*4ôÒòå‹+?J$xãëÎA¾eÿe%¦ ›!~ðÀˆÐx0`P2¦TåÌ0$ˆ„”¶ªNÐQȃ0|` ˆ" $|T-ìÉOÞ„¡a,.þ*2ñóÁ pÚìkƒ û¨î4bÏ%hpE1¾˜aÆd~„á/׌°À+®P/e”Á ˆa„a\Š(®£‹rcsÌJ€B:p xd–ÆŒ±O? Â1# ˜) ÀÜqDwDiÍU>ðÄX¢‡%èñP%]>pÇ]f‰^–_^‰æa¢WÂ%È)'›^¶ù¥av‰u±Í†_³TQwÑ6(uÓ4Ý^lQDEÌP ^±1JÝŸQWMžO(ºW˜N<á§BŠ2#†/«¤g“zÒÇ  EYàH«tþ¤JHU€†ÜhîÙô¡M¬TƒF'ªP‘ͤ”h¬€èaAÁÄÁM ©ÃÍ;ÁHÇ z<›,·B’ 85ÐD Ü(“MÙdó7HÔà„¬'ôŠN Öh3§@‡hw¡óÄa ¡I/T –h ññ®ÄӃ׼ü0Nb¢‘Ö˯°:ŵèÔ¼—à p‰ ý|pÍ ¼9³ÃC0QÜ‘(`€ÃýȈA? P§n5ìd«- × cÄdMwh—ÍÀs-öP ‚~ðíC$D@ýc ô×aèð 2Cá˜áâþ"îG×ðâJ $¢~ˆñ† ëh¾N’(袋1žxrÌ>xìócé(Ï[ì³£xŸ. méb˜Ù¹JL¡ÄÀ—$%¸Ã Þàц~´Ã¾xC ŽÀ¼)LsùQÂet±è u:hÆ $}âG4ð„Ú†1¨@þwëd’ „6È EÒ6• vfi ×{€5Œg%+)àÊ«R]”w<^{kBO™ÊD½”N/RÕ“Þžâd'+Xc”ZK5´QRí/ícãlè—Sy }…BÔ^Ö(FqŠ&V{”ýJ ª.©ë‘RÕK_Ø÷„8dTÑÞñŽp£Xü‰€™È-R`â;€B´ôaïà β 4!,.œ¼ôµ/ªåÕÁ!.âðŽ Äa}XE ¢cxeº!7àP+¬7¬Ê>B`¤X‹”4C!*g}AŸÍbð ÄQt,G ©*Ì"¾þÅX ³[ F6`…=¼šÆSùå ¬9‚L¶€tÆ ;A  ]^ˆZ Ú+ÐÿéaT;ÍÚ4’a,X H;ÞëÞÄåŒ×*AÏð€5Ü *1®ù d¢ ÆØ‡ Žá þÓ™  ˆÁ ~4BJ؇eŒ‘<Èà2ÊŒæÚ™ß1)?m(D?2—ØCÂ>`Ö¡·cä¢íPºOÐàF:¬œüÈ (àœ’v´Í)$À¢Ox€§¼•^i Ê“RŒ—Q2E£wpSóÂD½1«©MwzžÈT½•ºÉSwê.ЉULÄ <8þík­PRa PkÜéx"ÀÉÆOÿ›N ô³²c¼ô  ¨Êû?J•Ç Oˆ¡R›Ô¤ZJªpêC6*°/p£'[YŘ² "Ä¢ Z¹7|ñH%_Ê?ÎòÔ 5ɇ¡/&:€«X¬TÁ ‹x‡¼´QE TãZz€ó?š@ëlüCÔq .f0¢8@] ↜Àî<‹²Ç•ÐÈZ×6Ã+® 1:’†ŸAÌ,ð™p`l4xdGóˆŽ]á  $רFçNÁ ®x…äb €xa (CàáŽ~˜Wp ñ ²%ÝREÇþwn˜ÀF8ØAF@À`»¬ïA wónû0F#81‹Ylaw Ez&tà‰}Ì( ÀC<ˆA S4A:Ú6@CB;e¬õãðD!Αâ0€Z·ÁÜ䙵£Æ*ˆ¦èhP Òefìu’Žð{(G¡¼û;p„#\¢f¾õº¤<1UïÉc*ÓH=Úe’йóTv¾|fòm‰{}€Ä;Ša2$§€î;Ha…KJ}oØ@<Cúy:‡6ÔBª±ŠG µ©n®6Àâ”Ò=·§ÍÔ•@›%PÅÐZDH,RÜ¡¦{}‡ þžR¬B$q ¡!Ð"‡l4àøÇ,Ð’bñÄï?‹(Ö ôAXI·¡K±@›6Œ7à Ø:ÜA·ü:€ üà ø.ØZ¸Å]Y@º}‘ÚÄI?àÀ\ÀÜ _¬mìÔAL/ÀÃôQ/ô‚ÅèVbäÁ,Øq’RA¥@/DÀÈÀjÚNÝ^s±<¸ÂixA(@Ä€Çy\:]€;\À(À¸À(@ƒ@8  GºaÊ@Ì6ALCÎq‡ÂÜ.ÙÌÙŒÐið— ìÃ1(Ý,dB~(”éC“.ÈÀèœCÐÀ gôéÈ‹ˆNÜ H.ç>ˆA0Ô? ´%â> B!¨Á»¶C4B.„â  ƒ×C;0,'\°¨ BÜØ‘ ÐÀƒ~xB)œÃ‹ünΈ?é(Ú $è¨Á‰õbxVðè¬ÃÙÜþã Ž Hç9¨A!ÄOCX;üˆ1,G#@Xôƒ‡U:çøBƒ< SÕC4ìÙ\”h™ñ¨Ù÷€Ùå½”•PY•c{ ™}±—I—À‰ž@Ù÷XÁHXƒhC±Ï½¡ ­¯< `ŸBèÁD J5èl£4CFá¥@:VMNpµÛí.5Äp; ³8q‡Éé¶­r •Oåi‹Þ5l•-çZŸ®X‰q[À“æ$d±_I\F ·™ÅNÄA-ÈA¾DQøC6(Ö;,-‚‚ƒ{sƒW‘IÁ¤ÔÀ0€C“êÊ ,à8<ü5»…ä€Ð;0‹º\þÐDXC0–ÞЗÕÀÌÁͼ=<ÐŒÊ `öŰÂx+,+”Á—øÖ[þ¡ª&h °‚ÀC ˆ/ñ޽`–b@)¬sÐ})`†~<qp|‚)˜A<;ë¯Q7¤×`³ÃO‡ŒÎ‰<ƒ->¢€ì"¨À @˜Y˜'<Õ  "„E,‘Xñ&âA;ìƒk¦¹Äö4Áð1Ę–W ŒE $@+>ºšïb¨ÀP0èHfC´ƒT¾.¼Á\‘A”Þö’hŽð¬l–•Ô˜EÏI­”šñúç•ßGYÁÌJÏþ¨Ù“÷„ôX‚³§ðAtÜž d,{XôñVŢЄNå?ÖÀ«¸¡÷A Ô@°X¥­Z5m€HÕx‚®Ú=NÐ9q²ŠCO>ˆN#:éä kO€{s牕U¤8ˆóî]±b3ßY¨áäΪ}~ê1ا6v5ú¼S¥êŸ™q”µT•Sš¸Åɶ\¬ Ùb:à†eÆŒ8à¤P¬ñîßRàÞ!ÑCªÚ pd®ª¦Ç‡N-ÜÙ[OµÖf¼# ¯K—.¬òóƒòˆ/˜`Æq!A`—€¡ó(’tÈÒI4}w…Õ51eþþüÉ“'íÚ³5ÐûÓKÓŸ/_®\3Ó/†½…£K“V¾|9ºS”ÀÁ`àà ÌL0(‰Žv Ý•à`bÊL‚èô”x(š4  PÖ¬ÁÆGO}‰êñ—Ðï<Á:€Ã˜}4Ƙs¡AAOÔ€†x2!†Ÿ-Ù¢kCÁFtPaþtÑEPh„ bˆ £‘1r9Ç“Aœâ‚)î¸ãŠx£’æ|b ¦Àˆ‡7‹ˆÏ=‹¸£þk}ó";ÿÌ“‡E÷Ü“ÎE뜓' ²BX胈”c§HúP 4NjN9’ªÙH"NZ¥=˜‹HU”q ¦«‘ «æUÑœ(á#œx€šô¼D‹¤U5ªáîpLŸ{' [Áiª˜wœr`†„jXe•K’Bƒm£x'¶ÙæŸ â@ã üñ'‹ÀÁE¬Wù¨%e¶…&¦l∃4¾qk ÅTñ¡âlÞÁÅRÂu Wgà×Ð@Ob \]åbˆàÆšKf¸ä‰;bøagÔQÇ”>aÂx:K`ŠØCn$K,±¢š® gþˆ!¾p…•2^¹â‹?4Ð òÈí-~»Â•+X3Ãl?’X69‘<à#E ˆ9ÒJHw¸Ã &|Æ!K´O»u”ã“~Ìí!ˆtDlÖ0ᄃÖ;¤ýœ«û¹ãŽÀ}Ρ 0â¹rÀAˆyFâ!fõhhhPñ˜kA…cÔH'À6Òi„†\ÚiçŽñü™xt1OI¼‰;€ÁãIQ˜ö‘ÑÆ8Ç%<‰€ ,\ (hçÆ¿¹Ã°;) _gŠº}Nÿßd§'ê*`£öd XcP…zÓü¨‹ð ÈÒÓþEµH‹éà @•*åT ° $Ü`…­4ì°ÂâšE†"€(D´)4åGBé7,P,èa!œ’³ôP.k4‹ÚÐFGb8“\bG¸„/&@„,΄ˆÃ?ˆ‡ àB ¸â ² 4L ªÈF,Ð\@%ª˜E6Àá€w`!RˆœB. ¼ë+Q˜@6D ‚ü# ÜXIáÅ`ãz@ƒ *àƒíõqâSŸ ø'ŒÜÉ{ÔEÜþ´¨‚s²Âµ(+è©$q;VŠ(È`*ìT16 H ¡"ásôàDœö#<@Ù*ôv°c9uñ$)ÜE m XXAØ¡#bâ¢Ájâ¸7ª>S"Èqfð†K°ÉØ„Ĉí¾rà8âP 4Nª^”ÂWäðŽœÀ^¸ð|ÀER\bPEY’H $d£yÆ;X‹1&¦Q@ƒ6 ë rzÉ;Ðp‚Dˆ-)¢…  øUœ+%Rƒè!|¨HAŸ)¸c øJQ ê|(F˜ã„(œ"™\àB$ðþ ?|a½ Â#¨5ij¯`żYΪ]a{ ‡Ê!MhÑ #À—i„]8ÂÇ$ó.ì@ ¹yD?GC;Æ0†û“ŸJ¨3† z&%¸ÃÎcø-P\bµçq‹8A7êó†:'XûÑ0” unLÆh‚ð¡ƒØ-i|JÐ… j‡"˜nm@ÒÒ ˆnt NÆwB ¡cÌšç)à¨Ä{„øE=ò o—nSpß>Æð ÒÑ@JD!BÖAc !õR–öq%wpÑ!Q€Ìä>%Ch8‚5Ž Ý#À©¯ ”5{+0ÐMÈS¤Å'þ9Ý»²xª¤$Y Šä ,€„8 ‰UØ4ìèÃÁE»Šfq9a)Øá¬`Kƒíeg[ vÀ*"ûyBÌ\éÈ8D "7ÌHœÐJ>„¸\OøHy!̬’„Ä…“5‰y€ ìa}(`û„,&a—µñU¼ËV`©×n]Å ÌÀ‘¼F (Ðòj`¡hB6˜²`˜zàƒÑ°1R<à% ŽÃË̵ n`C'XD°0áZ4À¢«8Fã¸Ô +~‡6ÐÑr$ÈÐùN:¤ÃÏRÄ™ ®xEx@šL5 ð3$†røá;Ð’© þÌ^t‚Žœ‡ÜÏž÷M`A‡St¢  PD2€ G¬àÌ»¸ó±‹œBʰ€ÍÑ¡&ï„mÀ÷³óí|O;Ñ(p0´@:V† ! $Œ|#ø!ñyðiµLp©ïŽAÀ Ú¡Ftt€ˆ!ŽA ö'vÄX­.!|<BâábDÒá@$ †áª ×Èà꡾aäÁ>ÂNöl¥„ÚÁ}P Ô@ ˆyðMÂ$ŽaÛ¦àLæª~²D†‚úäÜ⯤K¯äíèÝÜÄ ìí¯ÜÄä„Þ ±JBN"þ%£.耥4~h³â€lŽ4ž °k´J ……ˆeµÃ9fæÆa  (ÌE'HL$§.†Áp*ô$"µ,@¼ŠÈ!±¬ –‹–¬á"8âHÄ€VÁ]ä`”¡^ö"a`Ibâ‚ø ˆ,ÉÀÀ¥[e梓´åæÏÀBàbpáþ@NIXÍå!‚à xk1v î j`üå|`‡,cä ”áâÀÂÜΕHÉl`Þ`Ä€ áH¸*Ïø  üÉ>av` " ê`váǪ€ ZaÒ  þÈ© Èš¨ "©€ö*¡"+Â*òà~o NA² vaDÌP’ÌV`Daî¡%Eá$àZaø áðÄL´#Já§¾çBº§LþF ¦À9€Á!®¹‚iGÇäÁ¢ˆHG?Öã#@;>ç¨ ¤@taL ŒÚB<¡a¶` 2a Ç d@Xa €Ã ‚öo !F'J@Æ À ‚¡È #ÁˆK¾a1¡àHB¨D¾ ÌÀ®d tÀDÊÎ JºƒD¢ãLŽ¡~rü€r®® : 3d îà¥ÝüGP¥þÞôª ¥Þ…"«‚,ƒäD?þNZBNJƒŒnå`ëT. @¥´J@„榹JCI‰¸af Pæ¶<)¶ˆ+ЪHb†Ç¥B/"ž ’âbqnçƒÅ‚#¢#à!x ´¶EÆeêÆÑ\$ ¬Ñ, ]’»À!îTú ï¸á°€& SX 6Á†a‚akòºÁ¨!`2lrìE1pÁU·Ø|ÀþAÀ& ¤ö ˆd‹€¾‚!ØñFÔ Š¶A^ÍJ:ziÆ2ãF (áîþ¡$á !ÇaL…@ÈZO ŒŒ !"àönÏöf¯6"r–@ìÔNK2OK%KÒ^Ò$³`$ÀôbAÎé ÖÄ;JŸfäLº£QÍî„*ØB‚…<ààÏ,J?À2véJáz€õä@0¡OÝIHr$€ ²Àä o›àütá`MQWöxo)~ÏNWÀþ$a×ùb7OïôNßIP;·Uü!ú–øŒU¿¯›-;ÊO'ÝAQ€¡XØïR…‰m°!œrˆ+˜°÷#žCIð¦@€j@ d¥tDªI2¡[í!¤Æ'¤ÂJ@ à0ÅódÀØ€ad H¡¾Ž'vÚ®nAó † <ÀZÎ À ¡ÀŠ\'2! h`Ôà{Ĥ3÷!®Pà;Îd àÌQR«’ŠÐØìõÜh øµ_ýĸ€`x±î7/‚ß®%a•#"H¢˜ŒNEƒ<ËT.õ²ªA¶FŽDNÙ¸fk¶´á²\þ‘øàhbŒ†  2¬p–ì%\eµF{&Î ¬á‰èP0bKâ¹Ì.D‰ ' ä!ð¸áb†”ÖÅ]ôH²¿T¡PÕ °àa¤ ºÅ{¤€‘à VáGcᤵa]¢@bø@¨¨áœ"‚!páP ÞEÑA žV'zd’±àR F¶ªƒræÆ>  ¾àôÔ%íô%«Ù$ïá´ù@ò–$ýaöTaöò@t²àâEOKò%ÿTvo×N·¡æ¹ª€$IRN!œEÀú!@ÐÏŸf þá@JqÊoMZs/Q¸H£L ržRnt–ÍfÝú¡ÐUIB *MÎ!u Î;Î!†! f T@XA†¤yTíËŠÁ>5s®ò̤{Áž˜  !À€mˆáJ DF$”58AÓ´rD $¤Æ’;º ÈÊQwÚ~Héõ ¦à3Þ N˜°€ ˆ` ÈÞ`ü €&hOK±ìú€ˆ³²Ö´x ˆ ´¡ˆY€a@OOž(Çt¤Fî ¤Øª¸4ŠË‰Û \1µ¾å ê`vcŠÁH(Œ1¸Ø“xà<6N&¥?Ýþ#^fÑ ðˆ 6aˆ H!ð°Á‘6€¡©IåaÊÂ]´À!þ(¹Æð¨oóÀ|f@N N š@®Ú.þaºeFk€“Æ1C¹X,ÀEiÂŒä¶îÀˆf ?IØáNeù`* yË1àð¦Ê@vr € ¾@²€ Vr%aòùDÁš­yXÒKíô¼y üaœÙ” šÀ’ Ir›/<žåY8@sç¹ h|&%`ö™Tá Ì`F·'û7 ¦£hìŒ| ¬ÈaeÐŒÆ ºa’ÁædÈ(gþÀÂÀV„Ï0ÀF¶ò@vGWU T`Pº„¤øE AbË<À$#°×rp<úoòM>ä¬6!H"èÝüJÞà X¸_ím€ ¨MæÍ ²x@7nNÅQPËàŠ¡~Ø…¬a¬ˆf}‰•ã¢‚É ”StK¶äqGžËèûäâ#ôà^æ•ÆEbЀŒPñ \é6N"Ø!Y*È´Ðc…žà ¯h$®X(÷øfû ¿Ft \D Á)–`Vnþ»+bA–`&$”ã Z  \ÎË Á‚€aÜËþa–³a^A&”¨Á±'/ÅÒ=’[J«¾xÑ€&CbÄQï@cìÆsŽ :è@ƒ1ûìÓÆ9žÄþƒd&4ÐàI!j¨aLgHL‰á†VjˆNë  D?Ó0DcK3¿LÓL3dြéD (á /ƒ „¸3F#ÇÓOCÞ¨ †¢€Ž6šç¡p4z(—\®Cã:S!ÃSŒ¡ `C¿hà2–„[t#‚Ýè†<‚@ $<ðÀ†„<äi„JÈQŽ¥„}¸#…ûˆÔ¡tqBŠQ”ÚT¨¦ «"€ê´âAp¥*Y…ŠU?´•j«S=àb¯võDšH‘&ÑÊI¿Xp¬ ¹äZ,¨‰¾jb¥aU‹¤87ì‚â[i—VAŠ’X¨!XðÊ*ªá„;`¡ʈe2c™ŒÐäŽ/yˆLlÂÄU€‹]‡,A ¬á‹ <€a3ØU ¬Q’þÜá hð‹8Ð )œÄ]^›€ËÚòŽ”‘L ï°@ÞQ'ô¡3èÓ‡£ ÁXàFW汆ø)†ÁKàâI“ËV8V K`ÁN€c ,#3·Èl¸p€þÑU€CÙˆ.¸Ñ #l“A„WT Fˆ…8#eœQHF P¿n €»ÁˆÓœÏqn:ÐÙ…#¶!É…¢]ÒÎu.8ÁŽ(Q¹] ¥t¦ƒ{TwŠ%ÐÁuà8l€†7X/ I°ÇîÂ0-Œ¢?(…)8aƒaÈ,YÌÓ ‚ðêñ Jè!LÀŽ”€‡n)R#d ˜ÙºKpp!fi„JY Æ¥îp„#A´²†lpXÃo°†h¥ÃZÅJ`B<~[+)nÄWOpds•kiYÁ –à X@¢u¡Cn@ƒÀ\B­JËZ¤€„2Þ!‡wä²2.™e^'Ô€2X@C*cQN XB«PÆ"²•AÌ4D™•|IuÿŃÝ>þÑÆºJ &~dÀ MVòÆKpãg>ÐÀ?ˆ`šœ‹ÀEHÌôam©Á*¬‡M8`zD¢°-m4`¾pñÁIB2´EáH€þ˜´aÔà†_|A +Tã• ¼bɃ>pc%Ð p6²8@d܆6Sƒ'$a¯ Ç&šp Q¡Kà@w¶±YÔÙèD,D‘Òâô8÷NqŠ3žÌ©§à©œå¸ Ÿ,´‡>­h…(²° I/¡¨C,Œàç%¨®èÄ6L‡ºJ‡.¥§8E©;QÎ>$Á IˆÁb`¶ùá .øÂLA+\‚þÊ+†¤ç¿ € sìÃÊñ*ô G®Õk„ÁJ˜u„‡s#ƒ8F&8ñ ¨`hÍÄ3îG‚F¸Cš’ï­!9Qj…ðD&ÚQã ÈãÞðÆb×ô|dÀP„%\2'Cá¡~¹páf9‹îC£À£J©ÒêâPëHÀ6õ„ 0ј²Uop‰7À\«â”5h‹«U÷T¤.°t•ª ý } ´Ñ‡(€ÚX:žÀަ¢(4r*ñæ•Äï‚XÜ–‰U¾ÕÐZ/äJû’1ÙˆE”Áþ6 ¨Ày- ´Œ( wþ¼;ôÕåXÀª„Iôç^¢‡¦‚˜±Ü2 4 ƒ¸J¤Tƒ•8í)c&…HŒ† üC R©±-HÈ! c¶€ 0;_ðD3’YŽ{9$ƒ¤À$Hˆ0_¼’í21.ø^ ˆ ¡¤$Í@9X£xo‹ˆ\b>-F 0#,áÔòáBüáéßÄ™ÑP¢¥ã鸧 v4¤å#U,!iðŠÑ .Åháøà³àKPp:Xó§:í×~ÊQÆâ `k²)10Cp¼à ¯p [#@€à|Ð e†þ<ñ°—T ) _`m0¹`ýÐ]•(0yr@ppI¨žÀ Ïp'í ` `€ñ@öðqBg‡o]ˆSÐø€ƒ0æ?€ g° ß` ¶ ‘@ à%'(` ø4PZ2Z†"Zx0$£…YxàBº'¥5C–²)Àð¾ðo°x'W—°*L”[–(\Öp ¶•`´%\°+SD¡,>÷+ÉÕV |$'ÀŠR½b¤@DÐÎâ[#¢!ÕÐh`_LJw©TàKfÃzR‘O'°- EÓMQÁJÙâJP*ƒÜÀþ"b""1,¢bq‚*Õ`/ÔâOWw€¬p ¿….z5Ðe—° —ðç$.q`_Ê€èR X` +± ï0NÙ° ï 3Õ@ rPw†Dp ša•i¦ÝpQÐ:£Uщ,q öHü¨OzÅ FQ}Ú@"–Ñ5€ }€r ïPN|À! Ð t Uà}\pà¢@…Qô± p£C9”öPŒvR•sñ”EVû YPP nÐ R° 6 iôÄ@ à §Pþ@~¨CRóq9\  ei±@V  àIþðV10®¬ HUÄ!€À| Ïhf  Á`ôÀ–CÀ $cà0)•¢°û¦;r =BÏ@m°À ³‰%çHLÇ”@ ÒÓ…øÆs ƒà$ç `¶PÓ@ ìN–ÀÔ@%°º û g(m0m0C-”Bc`ˆ£u> Ç(x‚Š˜ZŒ8»µ[E@*kfC6Ç*=*7w ŸòŽO`ŠJ„*µ"ЏâH%`\pDÌe,Iá }@l¬ØT×u\4¹ öÒ«ÀÚpª´ y¸M°eù(±PþªGGA4¸@zÿÀ '© & lA3+Ã23€Ÿñþ_suÅ„Žˆ¤P ˆ'î2°¾P‰3`KVdG63:#4Õ@2©DKÕ0ïðoT d!fÓD ' ?CGLÊ*c¥R5ÐÚˆÁ°¤sZvàMq O`ãŒÖP#úðU-wŒ@DÀ2ª óP9u9egÝq•W æáàg :X¹ þP±°ª±0—¢¨&—3ª  -p‡Ð"ð¦{€ b@0 $`Ä Ä gK@”äg:URYéhæñÊ sPþå0˜ù6?PoƒlZÄH€Ó0™ô-öÐñÀ VØ+4îÀmS@„pfà¦ùYâf m VP(O@ Pà_“Ù@P Š@ ÔP‡½Ù›_nÆñÀ Äw@-` th%o !›ûÐ(3Ä%62 ×Bpp ZœCœ¥x"B†2 *œ¢‰©‚³óÙ)µ¢Cò©.EðC»"a¦*£ˆ*¾+*E§² ¿ ²à¦ ]ÄV`]³d,« WgÎ"-Ÿ'1hz° *ƒ1³ð7¡ܰ4Ù McG¦«`¥­Ä` æ4ó#þvq 2ßKPGla Fö8ë ïð,ŽÕ¢6«à {pbà `¥f“Q€c"’ša¥h@/053Z&€¤q“vÁ'NÐa¯0 ‘‡ Ta6|wIq!ƒÌFV1*>01 òHcë2,‘!€ b:Ìë ÔD Qp Ÿ¡  9P: j•¦³ ±À¢ödª’–•°¾•@0O ¡P wy9xf¾‡@úKÃôËgy¬Ã•Gwþàj°Xi@YRõaæ±”ª ³æ×Z0ðåPewpxW¢ŠE þÙùžg8$@$`ð~#]•BžÀ¯  ž@ÐZ¿k¿`Uõ ”yå›]º‚e(¹0$ BÁ<÷ÆÕâZîàÅ$k('4²xq„(B…²Y…‚'ˆ˜'§ir•¨Cº%I*G´:¤C¸Ÿ¶ÅrCÛD=›D *04A*Ê´ ÊØ2KrÐ3-ºŠ§r-SGÂg/O·.ãÅo3<@$ãMÿPKÀp.&Zcv3KFb©ûF¤À+Ñ{@Kma}hp’-‘ZóÒ\èPÅÀ‰3à w”Lõì¸Dà˜ 3#s.‹'GÅ þ¤[½ñe"ãJUv^Qð' ¤Ð q»T° šk¥Ü}¤ ¸`QÃzš"Ó|§Ü||@4⌠&b¥ˆG•afÇQ¨Özñ„R° â 9À9ñ–ƒQ¨Svf¾æËMÀáÐÑBP •À:æ›`Ñ¥³ ôÁpì“pö4¡À”â$ÙÐ3› u u–ÒvYR©Ó ãÐ ó  ^àq0ÁZ0opÅÆ!Ñë¡H%< pr0gx†ñn@bð@he@@#ê£jк` ž ý ¤&ð Âþ°&Ëð ßð ò` Kì°â¥uG&ЇôC ôðö  ä¤û&Éw2в( ’Â%ç‰YXB¥å3³$g³¹5[¼µ*u,Ÿ°ýÚóI+Op‰>´[Gd\?tš G$\ˆ\ r Ê ^W qÇQ  zÅÐú’ŽRšº5@lèB,6_ ÌMFó¾§2Oá1' Ú`6áJð¼hÐ »t2‚ƒ!ÕÀwPù"Ú03ðbÖ@z`/qB ¢x D°ÁÀLVZ ;Úq€ÝpxG““Lhàq0ˆÑvA}'âõ¥¢"àþ{0SB4]!f$H@ ¤ efû.öU·zÀ.1½ 1¢öíJ+fH€Gß âÒŸÉÇHѨc—¡ö‹I‰”¸”þ  "ÀåÐ ÑÒ˜s ±°ó¤ “Ðjûw @óÄI:űÕ ó ° <}•SR©Vi0QF}Ô†ð Ià. ÁMÝ ZÀ S;᱓N50A.1,7ñÏVI0I„î`¯o`P„:r…p:B×íÐ50 t A@Ó€ëA`Õ{oõ(¬ñ 2°%)t ™IýyoÔbdH0 “@þ 'ÉÙ`ìÙj,íÒþ(ÕŽˆ’ž%—œ(+¼u°x*Çr9[Ǭ²D:”`«²[Iô\&R+¾%ŠP„*Z[ï4ÁØ23ÜÊ h0]£zrà ¡¸"^zðοX3ïÝ–1%ZZcGFäÚpI¯äpÔ5yÊ  Ø=]ÁÖ‡rÃB}}àVÁ,¶š š\.c*©|G©ô‚{fÔ·»|°e‘2k±|¼k pM7YeÙA»„©$‘2P"2àâ,%™LzÞ®¤HÚ|9Aö/Z' çtMú¢8‘¤@—õçøþw9§£©Sž”z”•–oΫ"@UÀ)ÕiF P€ É ²MÐÒäq ¤ÚÒõ”ÒªViâ!ã£gPO¢PiïaÑy_úwi °Öã .à; ûâÐp Ñ=à’QA%lò°Gsê.}ð}àÐÀ{ðÈ eà€ö*ýî€>–ÕP²q@Ò%A° &{- ºÎ¼Žoz0›*Ðñ@ 'r 1Žä°N ±Ô 1(*ÐÙ†òÙ  ëP P2p hÙ‘ÇL,aºŒie•‚>AûÌ(&ÇA1+zЃdTŽ4VZ¢à’>ܤD‰ó®X5t%ôŒõÀ h £ª§ÏH Íxƒԉ8Ù*€ç Ú“KÀù˶Á ïâÌàQ‰ÚVͰö„mL=Õô8yR¢îH•w,£sûΪ>¤&Ké[ŒT m¤¨™EÒ€š 6Àýs§·h,`Árâ„2Üô `§›(pyí4ÌCüQæ)²éœl‚±@δF™4ßFƒˆJÐÛLSõÀB¸'ªA㓳¶>°¨o»j#Îmx°ê½ÐÎæ°jøÀùKj ÁP4þÁϬÐÂ'-<]Á 7ä@„N¢Ydžd¤©cAD9E‚*P„N²…‹m88%– *бGEwPu·‰¥Ž ŒØ1Èq¤2ÃÏ)l¾x yÅ gñÒ€~ú¹õL4Õnø…ià„bˆ ‡M´Ðà-¾ ‡ž^ðo©ÐÂÊ03ô#8‚H,C‚(8Ç𰀨…<ÎÄ`XFW#LÕc°ÀAÝ*®2f*\é 2€è†Ä‚G) Yaˆ@ªu à¡Xѱ B,Š$à Ö —5.a pá —5P!4ãBIž0…—l«æþB‰¸\R®ºÄä&1a6Øážj°5'hJ1XÐH@‚D ÏxP*'‚™!.nÓ‡U@Î*ìàƒ,À‡±˜i:}`‡|…hÃLè¨Ëøâ\pÇ=È y²‘8X†U‰äf„=Ô€š©ÆZ.“ì,g†Msä™Ð Uƒ™›Í'n85PF6.”†HA {qY6fàŸ¬I ƒÍFÞILâ œÍÜ…p}È×ÓjÐ â—¨A5´Ñ€Ô€g]1Ð,0'>ȆXX…,¤¥hB£{¦BÚÐ5´ È  (Ôb Ò(þÑŠ`ØÅƒT…mœ‚hÒC/„ õ( ,¥’“DW¥mˆÂGRòš0¨9Ì î˜‚=BXà a8ÞäÆ4n3ƒ @›øÃþüôAÐOZ GË@xÀã‹2CÜ1f5 ``C;žp*XC ¸DEØb*‡‘P†ÖP ÇtW½¦ŠTx= ¨At”:ë'ÒCƒ0ËQÅrVA⬈X«"é Idð‘Žh¤ZdIC2’"XÁðLHj¢€'ªË]&YWgØU¯>4 ©É×u9(€LiÊûÀ³‡¡>òAÃ*9Mf |häþÆI Rhã1›Ó0±k&\üc7äAC8I\(ÆœX EÓ¬âÞǨŒ-9±€Ú CtÄ$;Õ` Øq¦z¤ˆƒÊ‹ÿX “F6¸1G.…ª`h aiþ•Øåƒ6¨!Œ á¼É<Ìf<€vb\9ç*b2x³š‰Í×°,¤æïÀE° žì"Øð„%°°ˆ:è´ ¡“Ð3S—Ð 59¢ÏÌD¹pƒ5Ô¢]˜G’ƒ$ QøCG&…ñ¶‘æMù™¦kªì$˜òhF`>óN)zM à/øÀÖqyG4¸± ¯ØÄ?þªÚ§^h¡_‚´ðLJa8TX/@Ö\àA º0tp‚SËìb´Ã¨¯ ¬^ïÓˆF¨`z‹á=ØT¶H0Ü1)ËXJÀC‚c ™È©ø×‘´d$ßòˆ¥¢Úz¥D´âº¢g4.•¬6Œó²ÉÕ(¯T`rh@v%“Û¦X¡ €Dä04X°,0JP  Å¦_õԤœ^\(·½l±'Ъ1îT£âý‡@9ñX:ò6ŽÔ €ÐáVކ“«XJ`S[–<†5ê‰]G:€7.fIK4r¨€i’þ‰†»4›°lqRâiÔ°Ùy œö:¡ÃgÁ‚yÎ)ÊXv¸iÚ¨†wìY ã¼³Æ>åP'Pcœ¡Î;°` ,4kè„(Äd);”J5Ðé*$:';èóXƒ,ŒP€,Oh¦PD!œÉ¥/uò”>g *(C`^éb#™2 WðÂúœ€ cXئ„Ñ C cpâF0ªš‡^@š‚#¨!°!†‚‡;>}x˜ÁëÈ«”¥ƒYD =S "ÀØc4§êu­ÀàzÖÀ6ÿ SÕ+$ ºH&Ký!ºc@CÒúþCp–x”j9–kA0Š 0Â0Jzñˆm9-z¢'RÀœx‰Žx‚ÒÒ¶œ¨wÙ–›è áeh€UÈ}+†lèŸ(’Ñ«8•wè ø‹³†åÐ.=`RÈ 4àÂy°Ü.=ؘ¨$‹’‰¸K4@©'ZBBm(•qh¶ÀÂU … ø‡xR,—P R˜Þ€³ð °'39 @H ÈC’“9AƒÐy¦‰±{‡hvh,8¥(‹i¤§á†8°™ã e ™xù‹‡‰Ç:=à†K&²[\†@‰ãƒUp¥Ì›(þ·5E0‚mx2'« h*‡(k2—’ÓQ ™©%È‚SÈ `Õ)2Ô"b,Æ)s))¼' ’œâQ FãYæÉ‚*  p&è ¸– nð¦è9aàa°_˜€!@BHBˆGfH…!àS^(ƒO`‚\0€æ«°Š>?èŠ@hCS£ì»ƒbàNh‡KšU2?Uqkh¸< µŠ¡òC•é‚ Å"ˆfqä¡uP‚}0ƒ1è?’c15‰€Ë"êCвŽ-‘øpوؗ;P€D¡‰ìì##t‰þz‰—'¨ ƒ&)Jh'èC8Ÿ@¤ÈYŽ\Y…izR@‚X…w¸˜¨! j@:«˜ã" «˜“úhœˆÉ Ë(ZËé˜Í€Gz«±@°;08íP€%"\˜;°¥µÀB ”§)Ø„T2 Rèåª',ðC 4™hºlx9a™gÊ9!G:)0‚ ˆÛDظ# H¯·9·¬Þè åÒØÐèA4`{Ò$êÈ®j`Oœz¢Šj †;=ˆƒX’]X‚yP† ¸–‚ÅiVÆX„2ˆrˆºô”€Á{&[<“g,<Î3þFcäž„ª¼*’mY#ð‡(™E ‚Çk1 ½r$ÛÛ&§â`ƒ|ä…KÉ…è3ø´ Px0éÃw0Wø‚+ðƒ½”À}ØbX0 ˆ/á …;x "@ƒÐÐ ¡q [e; †`Øè(ˆº×hK\P†³‰ÝØ]8–[D"è„PP…w08ŸC²³€NàU‚ax ìzeð¸+ †ÅøŽ‰Y ç‚Ãt 샃¤'82yŒPŒa€Ô (Hm ȆX(›~¥Æé‰… =)X € IƒúLƒÁÛ<ÔYFøLO†ZØÖaf´ÏíɈµOûÔhüO}žV8…NpE]²J ‡WÇH€ ±nÍѽi˜\øDYi‡F°wP¬Š`9_˜«±Z”0ð?(?€‡gþhÓeÁ #(¶"•]c¿\RòK)º„·BR]éƒåô@ØÂ†¡€`È„˜ˆ}PIê?‚؃Œ¬i‹¬‡@¤>™3Óq1‰qQ©ÐÀuy‰7e—Õ£)P#ÑH#v©‹Úª –pÜ' ™‘‘‚™ª±ä ²åŒU(†`N‡Aƒ´IŽÍˆ‰X±Þ Ö±à¤¦zšŽU­@\ø$òPt¸nH/˜ ÄøAÖ”#²•‚XˆƒaB‡Ó Ôµº=¸ƒŠT#þÚR½„7À"è¸b³à §{Ëxš "؃ p€`˜L²u.ÔP.r=§ìÒ“Ù "À®þƒQHø‡MÈ]Bâ ‚8ð…CWm׈N²SÞa^J¯'¤ ÅH&&×òÈ‹–Ñ©PÌCô”OŠÅÅ÷D)b<Ù†¨‚uXÑÑX‡5^'ï,Xãɼ&¸‚"¸–U¥Q!… h*›\ €"õÙW"N"Š p_ {ˆ¾$` ¤½‚F¨–R;"ÐhY®U­åZòÓ›)E%E•¼Z%'pCkx UA_  …(5ޤ8 àŠŸ#Øã†R4“áxt-Â'|šˆŽ›Ã8ˆ™·!œT² $pËa˜“Ä.ˆ…óÐŒs}Έ«9æŒj°‚–eꎀ«kð…»™€œ‹£8 Î$ÎÃ"˜€=xË€°ŠZŸƒœÔm:°`¸š©9‚ô †RDè"ð ïŠ'ìâ†b0²Ë—ïX…³hRx°k’sÂ,`ë:š10¬p„]˜ Q³ Q؇-Øy)æÉá]ÜE‰‡1<ÁÛžÒq2c|Ðë‘Sð‡þCà€(¡&ÙVrX…ŠH€;ˆ'³ ®š†l@âz®=н© iÇ+xðƒ7p +¸‚b 5Ëš6ˆ€µ‡[a 4câkí¨¥Z³Š'0"ІSyŒŒA{†x8†6ƒ~(ä¢>8d†ðãd Àc©¤Ò]†Î’ ,‰Î*‚7¸„q1JŸLÜÕºzùŒ¥„Àv #©\#—ƒbpƒU#Ô…A­Ýú ÑMì;j¯VUÕ¦"ܳÐB¾>÷±†Ä×´Ù0$œóE¥2ÙË#_€ RÈ Ö¦¹ƒ¿pŒÀ)Å ¶­ «ôJ8þBþ ñfÃèƒ`(ߦ“ÓÀWÜЙ \+†{æŽXÒK`(nxºaX×>8åCÀ»¼g)”]_ k`9á`k]~£É.!Û˜3l›ET. øV ÃY`›%pGȨ†aúäžì©iöŒ²V˜)a YÎc³]´i›n(–F1c© ¹<ü”âFè„ÝÉ‚(‰…%XaLO˜kЛ«^K3™±™MÇEä°¡†ùóp€MÐ@Ù2ƒ7ð…?Vxðƒ0è%H€Â,%8†cp‡Â±õk[Ê/Ajã’Wh°ìÀ+'൨ è«c ؇›þŒ[%°Òþ»,…ÀÛ.MäœD)P‚¸“èˆG‰qaõ;`õG6m‘°¢Ñ*#. °ÊMš/*­Ne7hÝb ;rhm¡Ä€ˆ‰¿«ˆKÎÈŒh¤GÊ ùj‹K"NÛ½Ù›}B;œÅÀÍ8¯8P† `Mne±6´Î¶—U°'KXŽ'íK˜Czšq.{{>˜xÎïõЧxJ»>à1áx‡((ÇḘ·áŽÝ}0«¹gCø‡ &9X€Ã¹9±ÚÛP®Æ1ÕÃÔœÅ8ëŠ%™E‚a6§8@(U˜…šŸÈm–®2‹EŸ¦ÅÑÑÅÍ þ"¡qŸÏz¢.ò Ï‚+Ϲ؛©_¤ƒS`:È‚­gØâ¹+ç*—ˆ/¯ö2‘ıH›Ì¥Ø'>Ú  ‚²4F@…9ð 0-V¸01˜¾P?@HðCGôU¡èý Fוjƒ  8°€žÊôxàô”Ûup‡cè‡ÌV«!@…tý1á>“ø•x‘Ð 1ª}›X‰“øÛÂÅ¢mù d—›ØJ@9€„Š;ˆÍÈHž#»´ë†É'ˆ {òmàƒj(t±8Ci²%/KfïTx*÷ÁyK_8AIŒþ1DN¨'ÔÀ®Óƒ„¤ñÉ&„°÷˜ €x‡k»bïÐX@b¡˜¯b3Ðôáf!ˆnÜ´éQØÇÂ*mH‘âó.[”lʸéq’ñãADâ|7a)«‘Š‚†:t«Šq;AJ:$5´ñ¨†ó]3¸¡ÁR ÔZ…F&\"r„ •C•ªPÛÒ åÂ%Ë6µUÐÂ…[enܹoÓpÁ›¶ —V\øÆ›o•VvßÞMs8ðÝ*Û–øãЖpcÅŠ·qàÐJ:Y:K(ܪæXK–œÊÂÁ‡tzjèa—Ò‰@»UœpåK„?©RôÒòå‹BZ´ aÄlþÈ‹01Þ„!‡ãˆ?~.$X‡B %P °Î :æÏ£?ï$=ûöéiëѦm½y@ökë Ä“;Ê›ÇÇ$|`e02ôsL.Çtžài§Äí<¨wx|žwàq¸B¸N%óÀ—<`MEøgÅ.òÀÃV¨x‹<ñÄ;î˜cŽü=!ãŽ1> #AcކH!GrÈ"$}PÉÎø;NTƒ‘ù@:*uä|€4UO®MõN,à45ƒRÌ0ƒOÅa QÕ¬bÁTQ¡è CÑVÔ Hˆ©M Z¡1ÃOœ™wÔ`ÍQS)DŠþ8à@0%ÄÎ3¬rœ |œ¢ÍFè&ÚœPAdc µiƒ…Ê ¡ )}Ôy £hÄ'[qpSMO¡!TJJYŠSEï€dYÀŽÚPÂG˜¤ø² §e‰5VY­Äµ(¢lSY`÷εM½÷¦Vãð+—bU„µZˆÙ×`iV½ð L×eY|šY0JàÅÅc²Åô¦—´•0&  ‰Æ6üA=œbÜ®ôbÜZ¤2„:e„=1,pľ”!†ë¬Ãpp<¹WµÕîeÉ% Òš§)zZAJkX–òyþÝ Ñ+ëAb#4Їv†¨D#¹<(5PsX¡‡ÛmâÒ"–0Åw¼QćÁC‘-Îx¸ŒþáXxŽŽó0Åü‰ùåGêˆ$ÈAz1}”y5¬ÆÎ›±X€…ÊD)ë©D›m_ª„h5ï¼ÃMDàâÔ;ÿüóÎ Šöè QJÊ%¤À†D5Ü8ÐzÕ ± Tƒê;)€ £ÔQ5yt‚°ïÄA7à1«qœ°J5|`q‚úDNšrCʈšÐ¦,ÈÂPFòÃ2JP¢ `Ÿ†aÁ®pêùÑö` dC ñ»•j@½;‚T}B gþ€ 4ðì°Ä ¢ ‡ýðà›PXÂ2 ¨b¡Ð D±QøÅ2 i¶‘D¹üe‰üš‹ÆÂ|Í%ŠJ¬‹é2ºä+3`@g*A Œ-oQË à‘e¡ըͯÊ :V _ G/€óˆâ gCøÃ® W𢠸#áÁ W9a˜Ó” ‹½eHöxB–TçIOÞ¡A‡Šqºb8 }xBÊ:ÙWê§|@G ”pŒ1ÈnÚN.â±´½íƒoáéß æ·uCD ¸Ã‰¬Á8=à™{@jMÿ‰GŽ;\ç†ô¨it˜+Ò‹xÐþ‡jÜð“]ëà ¨¤¥(Ä"ïÂIaGò`É Þ“^ ¤å„SÁv)¼²á¿wð€6òù¢ÞY `¼æ#úŠ~Þi¥Ë"³À*ú$«(œ (vz‡l` £@üžþ6 ËU`!>ðIâðQrc¸àˆpˆ&8 |¸U¢‚h`ãy°Cƒƒ1`ŠàPÆ 5RhC)J!Å*ìD 4XoP50á;8bù`A '(%rË,®Ø—]ø£KHbb¶Ø1É+Åõ¢Ä…I±0õ² ÄFË ö0ALß² UütÇ8ªÐ‚þΆÂRˆÅ_þrŠÓœfQ`ǘ°äZóÔ&_°z‘3䈃 +ü@{¸ƒ‘J¸<àáò apÓºÓïXWê¤:«kž{b³wXÈC q:"•çAº¡A?%ØN0;Ä¡µƒ(X‡10€an¿(Ð……*¤¦•`™Õ¼„¸ù€ a ˜‚ Š ƒUSG(Â.a ;N›EÒæ(7Î#Îºæ©ÆJÏ©‡Uô“Ü`Ê Y°ž1ÍæK°)ðÊZ¾.½{¸^f0”Çk5 Kˆ H„Ty•JÐù%‡Î€àF¢Ð€þÈB Q  p‘lü#~:SLÿQ“Da¨'p@þä;õ€>0B6‚‚JC8@yK­2H€…†š3† õ€†“ ¡£^¥Õ—tŒâjôó€&¼D޲%Bà°Æúd!bÌL S˜]ìâóBlÀƒÚ%Äâ’éë ›Øf4öcÃúª˜É2Vb‰…26A‡P´ tðGdqHtÂ_£9í³P,Ч'ù¤ã$f †`°A:ÈD.r1`ÀJH»×1`\Àfè‡Xq{A2ˆÐÞ§ `hÛjÔ1zÐQƒé]bzÑ´Æ ŠA„™ìþ!‚€–ÑüÂìØÏ:tÑ7÷ÎW;cxÜcàwC ŠC4…#Â-*ÂŽîÀikpúà Α‚W`ŸK®ÃÑ„Q*Çʼ}^´x0$¨˜}:YÒ]Ó6øÌ¸Æe;΄`/xïÇ?¤mWÀCëQ‚”äy’O˜Þ™’(å è”2•­¼fCÄ¡O3ˆ˜Í¾<%s£dÏÆ"Òœ) ÏQ±H‹d#P¨Ì†NG*4Ävú[:MÈT øâPx3œ£úä°[ KCM¸:ƒK(E?¤pÀ¦;meW"Ô9PMs½ UK€þÕ÷òØ«amš'. 1 ÂæÒ0¹€Ø=e²èýUØ_!X(²Àìy@ ËhDqZU`|°}-œ>ôA l /xñ &ŒA)à¨[v°›‚W?ôÃ5\Ô+ì01à…è‚@Áq –¬%ÝÁ%ô+L@1XC0}@@7Ã-è ðQPÒÊ}È5M#ăvìMƒDÍÊõ…|œ2•È%(@©HŠXA5Y4Q08NèHÍ=Î9Ó†‘SúÇÉ£øÒœ'}UAXÀèÁ%èÁÔIåÙ*Ü:XC£€—PÏëÌÑþ;±Ãë É;Õ.HAžÕÀüÊ*tJ§dÃpÃSHAiíTùÀ‡¦pÄ|¤LFÔÐÉÁœÐX’iJG…$8€çÕŽ·T6à‚¶’ÕXœ6Ì@pЏY§œ$YC] œ×lB|K1¸".ØŽ×(ñh[ÕÆ¬ šò¼“˜¨¼4A%([ùÑdÆ8ªµÂ.ø‹á…ыǑfø‹­-L^(_ÀDÑ__bFeH–ÁXFø›Y‘¨ÅB't‚,tÂ) F^´‚U„a>ÁÊ™ÃÈÀ,à€|ä‚Àƒ°‚8|Á\þA”A\+\GŽ$smÇ}Uˆ%É@5¨ÎÀq - „=\‚ ÔMà:¼Á ” L¤—x€Úì0¨À>Ž{=HÓôC.ä×}¥\†¸Wƒü2HŽ5ÄTS5©È PŽxŽøˆ`N[úȆýHzÈ${KíQÚP”ÌðÌ€´ Ãpld—ÔÀS(™|ÀÔ•)ÙšhC ¬BŒ(EA .ô¥[}™ä±ÃW ù¸ÆBpC1ø |àOHµŠ@CìAŒ÷È8¨8ÏF(Eà£põIU.x ŠÙÜ ¼Â‘™.àBÌ€°þÈFÜ<‘ôõô‰ÄBÐ yTÄ9éG˜@gWAE bAôA Pc@B9PA²…E²…†Z¤ùË8.Q_4ÃèKAJ ÷ñË8TB8A8„C%´éK®ÕE=6FÂÆÀ E+p@,¨üÐpj¸_+ô=FЋB^Wz؇m¬ -%€°Á Bm}$iRøÁH ŒŽd;Ì S:T à ÀJV—‰ÁN9ƒ/°Òš<Á°ÂzÜ‚@€7L5` 0à;Ó Þ`Ó€4B?h‡;ÀÁ>\%à“ߎ2Iá‰3­Hþ†ÙÈŠÔ)奆% ˆ‡ýˆ’tŽˆq Q¼F ÍÀX} 0 A+ÑÒ—˜ lé¥@›ÍÀ ,B6œY§€„àl@* ”DY@O¬^DÄ`„JÔe1 Á±CÄAíÔ€,ƒˆ@0ÈÄõÙþTD0Q8ÄT¬B@Bh Ø"ïÕeö“ø.€.\0P϶X lkj;B¤©Dø¨§R…×pC ¬;ˆ¤!Ëôœz‡\BP@t­Zð€ üƒ=hWˆÀ&l‚X+=Á%L@‘¾S7L‚•Ri×¢C<åpñ¨D‚¸CÉ1eÓÜWrȇx\‡tˆdeÓ°ÛCæé á8Î䜾\~áçD“’\nÑñ€u5"~|ÉCXD} VÈ%>yEDÁA D PöxŠHÁ;Åsr yø®6€”uŽ )gYþqUªJ­à©XC@‚ج‚pÞ ˜,zŠ5\2`ê™ñ Zà‚ èj,r4@Mª JˆY€Cñ0¤5æ¡ÂƤ¹bD7Pƒp«(€íxÄ·ffåQ…)+q‰—°Ž“Yƒà‚WR§¬'gM_+dÉç;ä6(¸£{Ö'ÃÔg(„=ˆÃºÂ¨02”Ã!P0À Áð‚Ã&ø@½ŒÆè‹)(öñ…®éÅfdmƒ?dƒ˜Æ`ÍË ì)ˆ£¼œ†ª–(X@{„¨~Œ(-Q@D= *˜B<|Â5$Ò5€ä‚„Á„Áþu` ÀA#ÊÝ×~C°¸Ê ë‚mz¬.m0\Â2Ã&ü"Û€“¾ÁœÈ@TmÜm×’‰–Í%gö peÔjÇ>Ó†äZÒÊù$»=¹ˆ3•4qÓ6q¡æø[f“ã<æ ‰ž~eu ü™“]ÏœUÌàvÖŸmø.œ€öVîž%Ô@%â0àÂód”2p ï¨DìÊ;]‚EÄÏk¸¢Ì€ÞÁC̼ƒ5|•ˆ¢ä¥Ã] qCªn¯™¥"0 'eÆNxžÀ$hÔaA @CÚŠ€áYÚ|)p ¢†7p^6Ìþª²@T;¬ 5`<4b|Ä­8pªN@2B ˆ-¤ñN­ì¥²ÄÂ) L(pã€â…ˆB@9ª…(t°A’FiL\°¿´@ÐøI‡”C/P„C¤ A.\Á&À&|¶læ'Ìh†jðt/8t‚iˆ‚¿úkèËÎË9¶B6lÖØQOƒ/\ÿé@<|@¹•›@?¤±uÌÓ4 C#À1PöÕÊ@VAé«ü1z‚QpC0Ø1€ ƒ5®þÁ&|A0\/¼ÁÄ€ ÜÁ¤D(3-­I>X8Ó¼ÛÒ €1þ´x|~-.BÈ %±Û„IF4“6å2åF·Ðe’ì)Ÿ†Î•¨“3ƒ”0 •´Ê X@tZ‚~ÐÑ·ÂØ°Ä› O±ÌÞ¹~‰$Ò 5T‹ð:a”¦T¤ÉvŠu–6ìâ@ ŠºdC›eƒ¤Ë%(ºîf,¢WÇ‚d«ŠuÊ¢E6X€<”VÄ ªà|K$ï6UÌ@6ÄMuJüôt~Váù>3НB*"¢ÁX5œ‰ÅŠP*¦dl4pÌ_Ül¬ãÅ6XÛY¤¾„ö=h܃Hä›&ÃØ–ô‘Å2ÀUWþV R€l‚øƒZ„õNSŒ¯‰,_Ì…ù½‘\p@¸uËz°«EªéË.ôp|nC,l€2 -å2u$¶  ¨±¥÷ƒ—cóèƒ PöÉé ÜÐvjñfs‰· 2 ÜàÎÙþAØÀlA,+¼Á„=J¤÷{`ɘôuÙð¶oÇÛ¾ñèsy›ŽöM„„œˆ°ÈáàÜŠ¼ÁjNtK7Ðá6¥5шZòèä²’€á'±CŽ×ˆŠ°Hb5pm¨D ®ÌŒ9@˜ Dêao ÀÎ’Õ ˆ}|]÷ÜI#f•¢8°î–ô*œJª /NpD‚™rh=X¬™ïÄúÁ+œf_Ü,¢cFd9#ìhdA,„ ¼ƃV(½¼õ.HÀÍR9û…_¨EAV5¬Ì¥©Ç¯÷„Ž$uX‡Ò²B( 'ó¶ìC#4Â9€2eïÍv ®}üñ=UÃ%XP  4e«€2=À·± Ð:9þø>H¢ˆÞñ%iñןì:§®ÉnOÁ–6B;PíâöMq_ÈÝ(„·ˆÀ›FûÜÁj-·%‹4¡5aŒØ‘H‡y.‘(IuPPäfmÅGhîo1}° \‚/LÀÊšwª­²À­RH´ñáƒD$¤fXPX£†=OªãfCmÕôê…”“‚¤´‘ZÕ§OeÙ²É)¶ŠGUR&Ô@Ãí]”wÁ¤‹3á·‡|ºa†ÅªUhd«€M =ZkX@Cê]¶8q }ÅrâD…|H)s°iB1`w.͘F!Þ‡¤¢ÄÁ%pÆ*RZ«¡Á'jþ ’*‘8”¨‡ puN‰ÕŠKšÌ­¶µª’4èÌ¡I“æÂÁG,¡¸pæòt•*­–,iÕDÊz©z ùòEÜŽ/äþüI¡¹–W1ŽøáC–²œwµnu=K–mŸCs×|½U–%þ8Hض-‡Xª8ˆê|}WË﫼nÍe¶f.Û”QküÔH›;¬¸ãŽ"ŽˆÁŒÍðÃŒ7ìç‚ Ö¹p%dPá˜sÎQa<ŒÁC%.Là v PÀ]|FÑ)á ºf  FdÀ]ÖÑ…G%¦æì ãŠ/lfˆlhçŽ'Lblj*!ˆ¤@GJ@þL0KH B%Ü9†wð€C P6•XÓÍ:ít3Ã:×I`Š­IðŽ¬™âBŸ(ôŽ)žàáþ,ÁFy˜ôŽIµ¢Ðe4SKŸˆT´9!) ÐHˆ¢â¡„-Ñ‘Ñ ‰j¤¼d\g …‡'t¤j±è#Š,Ø•”j ó‰]kÐF'aGV$R‰”dõX…›U¢pÜwÞ™!UR¤Pk,¡ ƒ—bfpà>œ`‡,¢À¯Þùg“&ˆ‹>ªq‚”ƒx"°ÉšwäP&а0èþº¤†KHAƒ‚qgàf®†Áe_fPÀR¬Ñþ¦†°¬šÅ,€–±è¤6ËNÙeû:­´ ƒ®5fá Š÷€NC6Q8¸ š+´Ðbˆ^(Õ/´(§*Èãë?®ÀÁ7Zhƒ:–Øå²ê^K: Ïb+­¾ë¶9…ƒ¼9HO•Xbɳ]ZE¾Ÿñï¾ú˜Ö̈ø°„jØrQ|yãݹÀÎÝÇž ¦˜"ÒÈpÆhÄ“FÚØÇ˜ÓA˜ÀÔƒÅPuoqFnlÄz,]—t‘AÇ#H] ®¸‚6"ˆ€‚ €Y y´dž $ÿL^¿¦¸P‰}tC 8ìl_9ñDa;QþhSúQ(}È"4}E˜T(HMê‡úS¥,5À)XáP•Bþ„)¡WOÐàî\ä„>dÊx‡HRƒ˜Ä¡zÑä4¢Y¡c  SªRukã_Å [ðnàå<ØØ®Œ F°—œPmôA…%L5&  nÄ! høJ¶¢ npƒ_´FîнC޳ÀÒ¯!ý‚F€‚ , ÁH°8B± ˆa¾GÝ’zeq–K´X ¿ cŒHàÆÐp‰è„z(L,ðÀZzñ€‚ û´†gîÙÆe037¡y‡þ4UP8Tápà‚4 #$ÎV@Ű;HqeÈ5D®¤ e`‹|`“ùâªÈ^ߦj¨,Ê"‰”(òŽ8€+v 0œp‰êÁ ,@zŸ°$ñˆà6° ÑØgpµYlèæMÙT¡ŸñNþaÿãK¨LϺƒ™Vâ Iø‚&Š£ ô" B%8Ü‚J„#yþBüÐ|³7ÅT|žÿÊæœ« Úk“P„Bªá*ÏÓJ¦)NÀAfÚiŒà"@T‰FExƒä?ä¢A›C¨éêwíÃCÇPA";c¸E^j+KP©`C4ˆG&Úa“^Õb`+Ä`Ið•ÀðÅÀç"P£8…?öªY­H|OH€—ÆÔvè v*Q‰šj¿6ù£ß¢À©BiAE°FDMê"h0¬“ X'e fPƒ±þªùx0f=`¡*àŠÃ®.kTƒ…}ÕR5jº­wL€´ïÀ ô`‘( Ê%¸CG•œÀ \%d: þ­Û%‚YÀ±pÈ,&îZãÖv{*ðŽla²¸ˆÅ ¦k c„ƒQÆz* 4¼¶XàF¬í _Ä;Û÷´Áj¬b(ÜèµmpÚì:Y窱6„ø¬Uƒ(Ê .j0ƒKt 5@;ØHDY.!…GLKÀ>÷åÂ.·´Ð„"ì E+†^…Pl#âF0þàƒ,àGp°Œ ’p #§Є¨á^ S äHÁ\ád ˆ4Y(À=n _¹½8«‘zhZ!5·ìgÀ›ÿþøÅŸ§€[a ÄêU`z@@';9 ’ÁþèL7¦ú]yðÐæc8äo2 oOÇ #t\ö:‡'h04â`… ÈaƒMøtfEzÅèthÀ"–‡X„ÂÝãƒÀò·T‚ Ø£o€‡®‘ ¤ÞÓ•Žê›ÜtéíïoÑÿãA5@Z‡5A‹2+¬¹Ê(kxú ŠÊÔ¢B©¶ª ßMJ%U††(¥J‰dA-úÊ  ec& .Ž-¬å‡f$U\H“>fV¡+À¨*fÞ¡¾¤±èè¤âvLîò/²á´pÁTHwš­X B¾Þk!ŽH66V!‰2)U°à.ÆâÖc Ä‚¤þ @¦~m&ÀÞ®Í0â `*æ&bK‰²E·f ´¬ÁˆÆKŠØá ÞÊú Œ¬A0Ž([ªN6|n6¶Apø‹nˆî3®cèÄ©r@là|`vLIƒ’  )2LÂî ®ÀÄÉZêl@À†;¶¡Œ`ŒÀ6úkðdcqBƒ ÆAˆîÆrÀ*þf à32#ðÞðþË3®# X`@f¤%Â|ÁÄÀHÌ djt¦@¥ÀMðÀR§CÎË *Ø$ó(€¬¡ÏJF€†¡DDÔÀtAì$ñ¾@ÊÑØ€ ~à àUþVᬠjaæ¡æ¡þFVãf`rlØAÐát€l Äú¡}ºÏ}*M ®ÏÒðç 8͆@í ÊOÔ%S"R*Å«T ý*åOÂ*ÕÔoRÚ ªáŠ”Á# Bc.ÁVT³aõàáFÂ$&€þA&”´hª¡U–-@†ÒŠá£¾B³ÀŒ¾D#bb’våv,W+bÁ¢`4i`4‰Â$ B"º‰, þAþ!ï`ŠR‰Ð ”!Õ)‚¡`„^«ä&àF’¢\b¢&F‹A‹b!€aWÈ+[¨ää@úÀþ ”å¬¡ÌØ¢À¾Ç48ã=„†i:ñßãè| Àø!>Ã:„fXÁ ñ2ìѾÀš, X¡ &AÂ!3Z£2ñoê©;dãîþ.h$ òðÆÀá²’V3„L3^,eÃ3ZCl‘§fäŽà |! ü€Î@ Þ€9Dç ítPàÊÎá:Ä=äËà DŽ¡<ÊvÆÇ]¤ı¾ÑË`ìÁ¥þ 6á6aÔqÙ€¬A@(,º@æ Ö@—`ÝB¡Ä,A Ú!F àa!ïì‡Òš ©.­!ÏÇKîþà jà„TRlÈÌJS¨R¥Óˆþ˜PÌjÔºêPz%£œÀ"b‹½6â ,ð 4«¸TƒàV$b¦JxÀr⊪ÁZLB\ºò¯.ʯСÌ‹„J€$’!ìm†²1ÁDå& Ž¯P ¸d$bŽ˜Mdâ^,â!f`ˆâe´ae Æ"@ ú€@®|//!‘´p!, Šá&“´¡TŽeŠT¢Nà&XÂ%*âJŒà ´A²8Ó°ª!eÊ(ࢠDcqLç4£¿<ñÇ®cY¡Óo <'h4Àñp3*aÊAžG†€¨f8H@ ö@-þMã  *`* ¸#ÀïïBQ%€:[ ;rh–€ï5q~LœŽN6¸`Þb…|¥b 2' ¤FE‡tªûð óûX³Ú½óèD 0v‡îà÷ÊZ@hd.ìÁžàþ! Œ*‹@aV“’¨( -ûpÔ)Úˆ Bôþa* xJC.d 졲9×ï„Ò>›~B»ª 媪€^[ÔÜ6AŒý«l¨QX;¨µã¶ÖB…V2 ¢ ¿¡Â!Nàà!"[Î0ÿJ µ>‚-ÞíHf ,88Aªš6 ÅVéAW‚šUÀJ<™R,ø"¥Ç n¸pÅц€I'w°DY…„Ô; Új²`›2p V{÷ÍŒÅâ(sPŒ”¶þƒ²a³ÀNŸbRÀmÚä`†…Ÿ3xƒä Ö?q.YC,ްÊ"é¦G…wÜ´!'ŠÈ8ø´äÈIÇ'ì8.üx Ÿ…€LšÔ.ã,KêH®scI+.\ZµªÂ¥J•4\‹ná/G ǘ5kÞÕj×®{+wì]ªúôcæ M„òT WIH*þ ÙA¢LV¾‚ù z3õ*­Òp®j›gëµ·h1.T%:8ø;ÅaI,ËŸÃk÷LŸóåËU¶é×¼M3vÿ#²¯DŠi®¹0»Þ9èÖZDÖ èÿ3Tø”¨'LÁ …‚TŸȃ"4 €ÇâAìœÀ$  FÀ 7°@ j+ hÐ7^2µÊ_ÂÖBj$9a¤F,Ð|e‹F<¨F­x  4ìʨK[ZTƒoIK5àEð¬Äárq!)¸²ÅÁ¸¸ÄHq‰*C ¨€2d¡ŒEÝÉ5ç“…80äq‹œ‚(G&Ë9(BSÀÃøöq HtQˆð&wœ£ ºˆÐ*6 ÉMÊî¡&¢~ƒšÛ8ô³Sôg`?8 Š&ü#¶ †Àt<àPÅ!þ:AÆ;Xãö¸€„¦ „\̉M0ôÉ>]ĉBò‹ŸŠÀCʰéMý§@Hå©R‚ ¢úD@¬Rê~Q ¦œ€ ’Bì%XÀB à„Ô ˆ—@C^r˜`ÑäïH×F9¬â"ÉËFÆjtФ)D)†’(XÐ/4A çø üË*hx‡™â—jŒUÚpÀ?ÎòŽ=âb—(b^e‘%ÖÂ…—ÐÆ*ä <Œ‰>éªÀRð¡eÚ胤` mH‹CQ†^2ƒa„äp±À_£  MEeh£_ôÐ $ðA¾E‚I„± ž&3˜ÁŒ)QþiÞ4d!qãÚ.šV˦‰b¾LsÄ)d±€W”!jÏÖŒ£e&Ó˜ÊLÄ€*´7¾š‘OzçÃÏØ>‰kE,ê°„shóÑŽv4 î”8êìÏ…«Ð„j`Ë@y’œäxzÏ¥î*ª‰4Ô†ND¦£ÆpŽ}C$D—QKœàбÈA~ZÑ;¶ïÔô¨G©IåÀ¤ˆIî Þ­2Ö°‡ tê  )¡F]“1L´ö±ïMtB*šÌD?•€Q€ÆÿòǨ<á)PÖèŸV)U©ECJ"†rj¬À¿Ùu„F0GE•±‘Z%¤ Gd«þŒ06AÓ‹ÀÆ žLeL Ũ†&+8®'ÐÈ$z˜×;ø@»jðáŠü²Š^ºñ+Ž0ÄK Ãí;¤À¯w¬àFÿ~âØ,Ùõ‰LÞ9ж'íƒ.q@hÀIµðR W â¶wõ¢‡jp£MñK¦¢ ‡,aÑÃj 6°¹öÁešìˆgÛ:Gmðá Hë š…]˜2h9ËÎßÚšùH ¼¨y¥|Wp´ÛÐ76MC\Xá_\Á9eÐÂØ‘‚GÂ8)èE/ȱ‡`@­ šy;33Ït¼œsóŒ$áVøÃðùp}Æ)¸øÀ Pü³ þ»QSäf<&Ë]sƒ茡"s( ºè@GtãáxX…%¼äP&Ë QØ]PLÍÞ!.Å'†›:#,…´p £ídÁ²&ÀXýbz^æP08µD'‚ƒ1Ƨϣ"•NgœŸï„@B-*‘TŒا¨Æø©…¾½íï7(C] #+7Àñl´ë­oQ†Ör•™¨ªrõQ6ÀQl0/Y…hÓe\’¡ %P ;”áepC²€ Q®¯¨ «Ô€Á7ã'€+»3`ìg€†bpcO‚Ð Q@}E H€Î7 D`JB/¦bDX;þ"QQÀ¢± 9¡À “à%ƒåkG"ÃÅn$Ó PÙE} /R1ìp«~Úb£¢0ÊpŽ!7:ó`À3± hÀVÔkÅA°/1/`Q‹ ŠP µ€Ö°OPX‹ñ,õò‚,B Â ì  3ÀoFÐq&bGGk³ÒÄ®þAK+€r´±–°±\p Zð®@l0ð_ðZð_0äð {°  ¬4‡'„Æ—tùAM¡@bÝTŠkø7ô± y¨iÿð6àvCR@byY-0B&ˆ!rcŒ(z¤#Œ˜ÈOm0‰q"Œšƒž@€À0Ú Ÿ¨%QŠá%PEM[§N°Ø–göp ar ôpbqP 'œïµDà"<àg4â‹j‚Tï#PqGPE5"?¥&ëP»"úc‡†'dS€ò(ò)UŒ¢(ŽæTw`Ö0NE(—ÒžXí‚:¤[ÄŽ¤Àþ.Q05°”Ö0nÌr h\s´ 3iߢ²ƒè`nÔ•Õ Y.âüWZÕ`k.ñ1:¤C%á[¾Õ¤0}©Uh@|D@¤°EÖÀ3]Ê  †¡/Á@;J*ªfq€ ¯Â YÁm¢•¢ñÜàY;,}°1ï æÕ† '@]‹  ¸PÕpÕ~J–`7!x£X€HYJ \ _Úñ6'M±uEW–#w_±L¸¨M#§@rI®@…x9š <÷SuwXMit"&„oƒMA‹Ú± ¼Óuƒ—NÖá•Fga$uu>  W7 ¯¨þ#>e×JU à©"¦Ù ª'!À€>æc¢GgEv:JP#¢9mÐOº wÀ¦)$œLœäh@ Šp üñx¥8x¯h7³ `¡2 ç/ª N§ÈÙ0 ùh á‹™Ó&è)Œº@!Â8>x†žy¦T2Oh ë@ûÓ@oðù31†'6Õ(øóŸ€Ò(~‚(‹ŸU‡ްcÕ`I¼Ö"H}†Á.3Ð.R.oõ¢ÖúVäR KY-má[4a,;Á 9éYQDŽh^‚Öð@ %¢+ á"| ÿ,æbyÙàlce}À«°Èþ“1Ü€%3€2Ä& '‹P|qp©"“XrÚáOÒ–À–À”Qp$¤ 5p ¸`ÿðYQm· Üêé·§é–nq €ØG*Ð-Ðtªñ!–ë…ÕÁ$–ªÕñQ±t4i™–´±¨²8y@Wà W°x© x¹_ð Àt°br“aù`#7óÑÞAxŽ™9`™ý‘˜ññV§iQf7W—ž© ªš%V>pcÃú ª7¥Y!'Bg"s6'¢>B¥"æ:À`­a+Úê%¥­$c  °•¬ñxúц°huD ÁåWw0|U  Ùþª Zw‡ y(â+!á9"F%ŒþªÁüJ"¬C')r°Ôxó¨°ú©3à ‰æ'7%);(‡æ'­W…" Ûz…†( ;Á™2ßÂVZ =q¸ö¸0{:B<áC$ üçÐ'oz¡1S‹kÆÕo‘-R+AD  |-‘V‡1EóW.ÚWÀ/' CXXðEÊÅH¸V5gšA±P}B»Gh ¡¤ðA“¢ås} pjR[«hDŠ ™yR¸ :DŽŽKŽ€ÙЪ x% ,Ë[ü‚¹¡JT·˜ƒJeÈSF€ed)3­àþµK󕺬»–¬Áå@_pð äÀsÌÓ€bó¡Êˆi^pÓuˆù¡ª•Ç•7x“ùúÁ>@|>À¡‡WgÍ9 Ök½â1 v b+%P›&Òc "PêÃOç€E>èCPì¿Ö*»rk ø"N@ ó€8üÑàœQ° ³ÐW¾àr0r`¯hÀ/hPGÓ<3@±àš"ú*!r‚:ÿú¯Ïª>*:ÀØ&e Í(’b )»wÔ±Œ’h @±òÙ{˱w0iYµh¸h)1Ò"Ž Y&Ô¸Ðop+„*xµn„Ô³3À [Ñ#`þ]¨2€,´$Z‘Y/‘, á"%àð›ðh`y!YðgQPmh,©2IØå*¡ , ,²° †Æk Ê ÖlÍM D 6@¥ê"\0×f³Ñr ïæl)ŒG5p­3` „½xd]+ ¤€ Ù`G~t§}PMà›ó13sÁ›åÇ ¥–©Ñ·<_¹¬ºk™4»À9@°s¯p,Ƙ bôq^âÝÌÎü¿^÷†ª #ER8ÍöƒæÎÕ«ÚÛ«U0Ùáä¯ ¾O@?"L¿ñŒ¬±ù!Ïꈲþ’"B…:ûp =¶2 Àp @`À` ¶ö‰NÀól33€¸xv£ rÐo@X"Õ‰/NpÙàª*<ý^†ð¦.uO¦©OˆŒÏZàoÂÁ¦W>lrvÛ(ƒÖÓwÐ'Œ" ²whôT‚"UO¥öUïÜ”áØÀ§×&drÐ.ò†m±Õh $sB= OôÝb}42>ÜÖÕkÚéHæ:”-Ö°F› ÎáU1Ý0Ôå ªG¢V.^‹'àC²…R0RM ¦ D‹ °$ZG™%G| HÕ èwhÔ$Ћ$0}P “þCp4jF1Ïfk´ƒ*W1_º²ü›pE <Í”9ª›kJÃótO'®ƒjEKEƒrªKr¬+ T–u  аr › 1%§´¹©LÞã_åÜþ;3î$0 –IbÂt…ca90 ³pb°Xwˆ®“ý76@#š7 âËB™c:£"B5gtf"Ï*P#"À!pá 2`aÐ@QÒR~ÇPÀ©¬îMeû.ͳÑÌã€D€xÄ ᄜäŠbó󬥗ŒÃh:ï°ãó¯D.?*rˆâ;‰fS7Ͱ†v’'vŸ ${Ö° “rÔþêT\¯Ô3RoH ¡ÔE|PÐ'´T*ÖÊEß"1–äAgz—{E·|má]za¿$»H¢2±Vd^DÏZ2ù5™”I^=wÚšügÞ‚³.±‡½ý¯EÕ’% %«à`1 «Òèx„}Bm¡ÀðÎõmÏ{ä‘’Õ÷x=£xT,'«`0jÄA¸§1qßN嵞‹Jœ!<ïÅÛ ^2J¬ñìg©–³¡–7SYuåÐȼ[ЧMžkîsXbÆîíáîÛ ±`F éwßþ u¿;7á ‹­Êµ á/‡,þÒTÙƒN!º .,L Æ,^ÜwÑ8 PŽJŒ €£bŸŒ)xd´Ë¦] öJ ÓIΜ yZÔ©ÊÐVÛŒ-ªU:ªŠ¡ACÄÁ„&¼›@$NµUqüµÊ’Å_XtZˆ ’õº €á™W€.%u¡üHdȉ(ÖùEáغ¶èxܹcåâ‹?xÂã'OJTn™ÇæÃÖ&–üyq МyðDíPµj¤”e‹òŽO5=ÚHÕ¨öĉ“58ÑãZ }°X fAØ;e 9ˆýÝŒzÐ!!¥‡œ»ù¬B¢©ÙÕœþpåöN›ðÛæ‚Ik\ ÏX5#ý‰hf¼³/›af p‰C \V郕&ÊÁ)ˆè›«Ð(f9Ò‹ƒ4,èƒm´YųV©N=f°@>à# ø@C)²™>³ ;=j@CD=rÒƒF4jQ¾ш#»È"[E U8ئ•4Zᢠ.Òàr˃ŠÚ†‹¢Ú†K3s.va³Í]îYa…{îySÎ9E1j‰Xb9å”3ÿjK/ÿ$”Ë*Z eB ¥ C¹T´ŽX–e‰::©Ãˆ bá ‡,T§UýÒÊP8ða–BÉa›%V­Â(¥NÝþF©,Zî¸{'†xÈ¢sÚ0&£Œ,ꈣP"©ÙJÂãÖ¡¶‘xŽQÁ<ð˜¢;@Pó)'@"9¥ÊZÏÝ&,F­Â9xƒˆ`ܸd7ü[¥˜b|©¦)B!‹ƒ²8`€›;K „þ ‰®@Ò%0àˆ˜.$Vb¾þ¢‡žXl³Å"CìàÆNmŠÐ({BeÎ4»£³ƒ­8ø0+8{5ÔV«‹ *ˆƒ pCB›ê²­šËô¨D,Ð8n<,Þ F èpyçUD‚…ùèÉ òXÓÆ Ð`­6 øq¾Ðaš=xÄ‚7Ç—Û¦æ†ERÐþ柂™@Š`ppnVÑPƒEؤ˜ÞV1DûŠÁ¢¾éD`xè=J„<ÕლäаÁ‡„Æ‹°àC$V9¡G>pb‡”³µ¹CÅjøà&Á>ÖRȉK²Q…mbí²P.ÒŲŠS–8K3åBÌVÜdS6W¥ü9åÄdÎm*õÇ5Ï4î ¥ûD¦²Qîru ì ÀÔ)*°(ŠàÈF6bA*1 e fÁQŒQæjE+Z•Á*1`<áU¸Ð2`\À"…(İőÀa^FR’ºÈ@ ,ùK#TpŽD %€% þíÄ kè^­e”,¤+]U`Ô?X‘Ÿ ÄaV`JÔ¨<¡+ŒÊÂ@ð)< ! S˜ÆB‚‹ÅE ƒÃŶFÀü0ShKCž` >®ìd‹™Œcþ(L¡2"{e¬Q„ÄÄL2VxÂÁ©3ž c7ï8 ³¸Ù¨(\ç1šÑªQ<)„*AëÛ;â U6‡ò!€â °€e5Êv‚pƒ6L«¸£ÉÇXˆú`64LÀ§›‹†CŸ8¼ãÆ0.ŒÛ ¡344 MH CBˆªñ!ß½>êà Р‡88ÓQ@;€yþ¨ŽÝÐQsÀ nÔ`m±#EÑHA9ã°`'¨³@Ö¸‹4 Ù‡*þ‡¡®P…þª§%ù•ôJÛÈÞ¡²p >êPlúž›ä$Š{ÐtN7Mž(¸ Gį¤^òiý¶w”L©UûëÒúšè¿JÉb  ’¢B‹*%KÛðFSu”Z¥zÓkTCÁkè '=‰ 0ÔjŒ6Â…hƒ Ô ­biDY%‰cIh-%\@ pÉHG*¢Ü„,˜Ä‹H‹S$Q`Y RX²@‡,@ñ3àA3‰PŒj¼ƒ`ilC3RÌ  SÅ@r 4œ±! ÀƒD"Lj½þ1ŽÍ¢X^$æ—Œí¶cë8ã.¡kÜÁ—(®hs˜"L&fË Í"¹²ÍH21Ÿ¡ŒÈ(YI' ¡>‚­£8,8›Xs"E!ÊàÏ*Ѐ5 p#=ÜðЧŒ8ôá7»aÍjH5÷àr'=Q×n‡ÌèTE5€Œ6ªa OØw¤ÜXƒ„Kôæ›þ±Š~¹qy Á3ÀE‚t¶B—fk@Fÿ¡ÉW²ƒQˆ‚2^£Œ‰Z->zQ| ß ñÁwð*OD  Æ ª1=Üá_i(S–â(.c9 YêXNÁ황{brDLÝDÓðÑÔþNwÂOç'(¡Öy{C‰RÌ<¿CIM•’8–P¦*,ªhbcY ÖÊ{ Ó¡… šÝÉpO ó†KÜa (ØÇ9R¨‘TdAµ õŠ<¸#¶7ì‹.àÀÖ}¬9€<"A† xàÀNð“÷˜˜®Sda FÇn"† øÇ t+ü!‡Èm3à¨UHCáeßá hËø±‘¼Q$p©ËÅ܆iL„9ãa&ó„"$·H.¾Ÿ+™ƒ!Æœ^…ɪ{Èy“ŒEÈîf¶‹R€£¨ÿ°¦Bö™@hƒ‹þ±’fÀE³OkÕ苸± Eþÿ‰ÎÖp²#¢;–<«yõœ„ÚHQp@6>œ'Œ2 ¨èŒð-'P™D}Èšfp P`7I²0°q¡¸ÙMˆc×nÜhÆ´´D7¨¡Œ €C>ˆ² >§‡'˜èuë%æÓ³„"yG5€›^“IpH¿¾3Ï*pÙ-“TPZRT%pˆ tb,°üvS5‹ïM»_œâTS¤h)‰H)³ëGª44ªQ&=È–â%ø£þ؆¤`?”DAö(\ÊPRŸ¥<ãŠHGž “aŽÐÃþ²­6´a®.¬«JP­­‘ z†$q‡JP€‡~ ëßþ7Æ_)@„KädAGúmÉê÷éZ©d!ûË<Á3°Æ¥°È6²qà p¨ ˆØ3b6 †P7qk¢ ºÀƒ’ˆÀ¸`7%ø4Œ<#ãòŒÅ(F*>ò·|ã#@ú·U`$š9$Ê™CŠ™üC¤…㉘€9›(ÀjލˆhPb`ºÎ™‘šã±÷²€™ýˆƒw:óÒ%Síb‡c2>Ð…²€ú§Û°ñÐyz‡S†w vÀ%ó"»lƒ¤ó0$€›¹A‚na¸/URC,°¯‹ƒØ9Øà†`†IŽœK 8þ Žèܰ°a£@ ÿú%=@&j˜@à8j„UøD*xÿ¹ $PªZ ùá2"³,p¼S…bNsé’VH³]p™º<:©©ó©W,)ù{Ñ=Ýã’Ó3³;‹•Nh<#è„Ö3ªj”sY•&‚Åíé’-Q ’(B”4à ‚9œxmðV8‚) ’ÀˆZû¾s¨5ê;µdq!¼5•؇ºÈG‹p5°6°(/K¤Kp9†  Pýi>ó¿ÉšÃ¸„7À¬À,)Š,h°óp(R¢€)˜1  ·¿’ÀmÑ þºX·¾ÀÉÀȘ‰àÞJ˜†àHkÀŒ;¸„zc$A’®Í¨·yC$æJìÒ Ó0 Ì0t¸VÀ? lÅñX…ûë´K¸_€ 40Žñ³Ñ 膑{‡§‰‚ X…K@ƒé› c÷0/JB¸ëƒÚáŽÑ¥`Ò4ˆU [ùŠ‚(mÐŽjhEØ(üè_±ʩ¯ m(2ÿ¸°ÝÁ%=àø@2A¯nP2R8°¶ì†’Ó‘Ó§3¬—kË&´¤!bx=°·d;ÚX#xÃã='ª‚XP†N8…NC ”%(c«’0[5Û…Í{þb\GXùù“,‘dÆ3é²XQŠX$=@I½VØ“XØ=´¤àªˆ< Ú=ÞÃ3WÁgd€›¸ Kâ>x_xƒ~‰‚¾Œh¾sPB؇z¡º ‰»P‚}h„}@8h>5À€Yë— †Yà„0XÀ¾ä‰j°¸ c°Y˜v9ˆ‚€PÈ(*3œˆ‚ Z2ƒ"èƒ>x€H­` ‚ä; Vhw@‰€ ”‰6²I›Ôɇ Œ¿ø4ŽQ`À#†x‚7èƒük8‚;(`8Fb¤B:Œš4.‘¹™ÏÀ –ÑŒ°ôþPPkk˜èÀ‚.†ƒAÓH%JüxÂez?D¡é¥·l¦»ƒ°õJ@P‘Ý80óz¨j0ŽiC'XݨôPÅýp'­Á è ˆ…Sz‡}YLð …÷:DR †„b¹¡†d:¦ã($˜È'ieÍÙ” ‡ãˆƒPÜ =˜ÍðØ‘UžÛÑáû=ºÒ\…(£œw8ã0ÍjàmȆÊâ³/±½VYà8„C ƒS`<(¶ìä‚_ËòGè)/yO b€NyO—ROc˜+by!‹ØÇލ h6Ú‡1Ø”R(5(M>Àž &qþ±à¬;ˆ×!¬Àùz/®Ä‚ºû@€KØ€5Ȇ 8lˆ‚Cœø†n= À0lØß©û…iø…þyp‚ÞÙB®a’¬!·ƒÖØ àŠ;¥(Xà ž8ˆ…2# øk#À†E0‚S  €ƒm‚N€>…3kØïñҵ<ò¤ŸSQP…eLÏÂcÏÜ£½÷ŒÅ-ëëL #Ȇ:¨’êÉ 0óí¢èÙ½XÉaA+“4°…p‚(‚íµ‡ °£¹‰c™µYc+¤-µ»¢ˆˆÁ€cˆZ8(¸úˆ}ˆb x°‡LИ˜]†Fh„cþÀGcH‡10†( h28*(¢  $$PbüQ¢8`ˆ›˜à,)ˆV 2Ø,7Š`Ú¬˜s›¸)ÓÇ]4M˜LF ʘǘSñÀã*.{«| [݌ʓ©Œá3«˜Ë°ð{€‡ €æy«ÊLž‚ (x0€p‡ °V ‚(†wœðr'P†ËÌ?'¸Kª Qt^`Ñb ˆ‚bh€ßÈ jÀv€ã§éK>8¢Ó¥óhàÀ×8œ8†é9øP¡¥n¸¥[„I (˜i0EXƒdÀ† è†Zøè^ƒEH†DH„þdHéEø…aÿmBàeJ¨á˜á°Ë"‘Uv8+|Õ†â©&¡žàᆠ¨ùÙÅ#%³E86Øqh: ƒ‚ X), 36 F`d“õÙÈC=BŠ¢òšÝXÑ#YöÜ2dŒY"þXƨªrâ3Ó’ ªH@L®ˆƒ=°@œ`š(³€k=?aX†eøEø†d„hX”5‚dØ€ZP„Z€X€‚Zˆéfˆ†høX†iØ_äèƒ(bbÀêø›èhŽl¸i³‘{5^t(ýþ²€pn€ŒÑÑ»N“.áNy lø…*_³¨„J°êq°ô>)³îQ“7ùÿÙ).Ï?I”V …öa%ÙtÑŸSÿ’5‰Î²Ë# ’W„aò \Y—Cáë-ó X¨ … ¸‰'`{øY7(ênc’, ­µ68µJ–0†=† Q ˜cbA‰cÐxˆÓæ„- †kg+Oˆ‡vP{h`Ð' ƒH€ßCÔƒlàU€<È)Ø ¿² ¢®7ðY¥Qˆ"ðVî¾ ‰)`–‰@ÓXÆn l\VŒÁØ-ðN€'Xz»ƒUà´7 €7Ð\|3JþÏ`óvABõ@è7k¸mÀ.É™ÊPæLËù »å#0ƒ~€‡x0£Ëàâ#è‡ð&È…úE"…*rwšÙ,ª¯b8dVˆ;°%˜š€MKªô²KˆaØ(ØÕyqv VÇltê,x/n’ø¦â†ñ¬#±cRsþ53ÿ;(€hH†:¸:((P(€Z¨…5PZ˜(h†iø†høl˜5߀ÙX…Ï¡¥ hÓüP%®¤%@D`²ÏŽÖ¨KU¢ $àѹ4€aú„½X8i aƒ‚å_þ°jÊŠ<§vþ“ïé„X ƒ¶.ÏùY—UÇ~Xì@ÑT§=2Ññï ؆X¨®Ä÷HËbT_—ÉS4sŒ…¨Y©¡âp 1IÞ¼ñud %pPP¢ ±ˆûöµ™hqŸ18pèÒˆNP`€Ó椺TÄ#¡ƒ†blh(A±Oxñ©ÈUhŸ®ÝÈ[&L˜‡EY–.õW@Xa&Dmã°$:>È)ÈÊ×tèJX3æ%5Õ h g­.rçÊÀ0! `S€­£»nJ‚è”x¢íµÄ—±ö€Çƒ;’¹3åÉÈ0óÐ\¤ñV¬Üþé\­3ê›Åhíú5ì±w̰2ãK +1¦L¹p^3=®]cr­ßÞÖмCCjšï&Ä)¦G5mÕ8 Ç xÚ°(«Ð$[±jà°³ a¨Ed߃}úò£p£†€HEïpCŠ…cA zˆ€ÔœPË"ÉQGÉ$c ÉR‡ Öq!Øl°0¿$£ÈÓüòË7&Dó¢0ÓÃxzœ¦ h|·Ê;ÚUCJÜH )hD‘3h·JÅ¢)àòÎs¤ÔPè8ñ7RdÁEt"KKÔÅ/ѬK9å¸àÌ®8£þ"BG}öÉE\J‡!†ˆ@Å¡ ÐAG~¦A¦ŸUH:)¥\´"¨§p°é6’^Úg£i*ª¨Û`ÅA(“¶²j£­lã*,ΫU¬ºÍ.Ûફ®’Ššê«»HÐJ(Xm³Ä6Hw°ŠÑú’AI\pÁGm)ݤB#…ÛÆ9e´rÁAC.¨¥£„xdBL:€K 5rL;$Äã‰'çd„B qÆ2ÍD2ÉÛH@´âH`²kUYä@Å+1L‘„¹ÙÖ42Æ>ôjÛ–[Æp 3GvÕe3 }õEWÎ…Ng˜…öØþc©AÙÖ”6…jšíV4Ñ™ñPj C=ÂÛ”ž –Á8¯aA'hØ„,0JT8Á*äalÎuAØÀ/ @‹ ÁyѨEô¢¡ˆý‚ “€LaŠºÔ¥nHXŠl1;¬a º4´ˆh$b 7€‚Öȃ&Ц„6YH‰°Å/ŽÂQ=¸ÆK­ÑÑ`ô`ðBfíR V±ŠK°ÏGiµ€ ³Šj\2}3pR ¸s‡K\"MÀþà)æE€"xk¨$^Q¹À1ˆÞ@‚=P!á¨D $uÂqäÎp…뇔½¨à E•Ã>…¢Š¶Š…2äpà ÈB Ȩõ(ÝFª‡z”«–Šá¶BRK¨À ¶ÁG삉KXÂ=žÈÄ]P·¸¢jÅ.–ÂÔ¡¹êÄÞ0îô¡¯pæE­ ¬%fy£ (2G:ž£ w$æBlV“ò4èÇ1Ø@N´cJÿÙŽx„¤`jJ á Xl² …%b!©P0@>à@¨b+SU!68BhCYÄ oˆ=r¶_g2¸„þ=fpKwàA¸ì%0’3ë,.º´¤`DÃ+,91NN ÒT™ÄPó3ž¡fb¤¼™)œLʘi÷´ÖÎvŽ¥E À†0²Âs‹A?úÑ~’–ðHÀÄ…wŒoÑy—4¸×èÁ N`A1 qˆá†Bh°€66  Eˆ®€R„ ¾1º DB¿P„§¡ð‘Z¥¥ ÂçL`‹ED ª–¬o y$¢7øð!çbãB0Á(Éc32¦g‹d|ãzp(ôÀU/¡ƒ|àÑFøpVîym3Ð7Àá4Ü¡|5pB5¸ñíTãzp7Wþ‡t jΠUÀ!@‰NO£X(Æ+v°ƒ/8CZ4¾°(›øÃ4arhày9>q¸Â =5‡´@·UÈ‚(Z‘†mÄb€8ykEµCÞòvR©ºnv…¨« 7 Xu›kTÝàÔ.Гè«pÀÃFÇ .•…X¸Á­IìßЂôf vˆà  cЋ^pˆˆ1Ô@®;âåÊcMtI—zíãoèÃ*F—õ ™L8ðŽrõ°Â´FÁÄ%„XƒÅF„ÍPR:<£1@D¨5âAË Ó.!“ºÐK]tË 8JÒ9¨€14 B<´ƒ ð<üB=ÔÃ74CÃ,@À4(— ÀŠ?$NªÌBz)À+lÂLþ+œE„AZ<Ó3ÙÃ0pC(à Ã-xEÖN7tÃ-ÈÃðÇ \“C$SΔ¡`$†‚5tFd¬‚8Fg7ÆÐ„†“ñõé0„Æè;`‡60Ù—<`À`ŽöußX+Œ_9Ü¡ô9|AÄ@ô@øÁ+˜ÁnÜÁsÚwpÇ`lw¸Æ Ð80ÄADA,B6Dõ¼È,,C›,`ô˜¦ý6üBJEƒaÖ ò ô„”¦­4`ÈböŽ &†,Á"ÄB ¢¸`-D‚0Dƒ¸6Ü 4Á \ˆ0‚Ž(TàP –€Ï;þ`ÁãèôüœtüÍ€8€6Èá^B¨…;ìƒ0mÌÜ ¹‹¦ƒ1” À d‚ ÈÀ"Ø“ÖCš<"‚7t ™ØÜþ(ùhÝÃ0Ü€+Ì1(Á3¡CàÁ °¥õXŽ7xEN$EÚÇêtƒ0¼Ã0Ì^ŒâÌ\è3ùÌ’±¤MÒ´¤Ò6,ßd”=òmF<0ìd èAg°¥JÛB¹“6_K%;żÐdguö‚&˜_$ÁùÁnìd !; Zk°C0h‚ˆ4ìf6dÃ`€Î°’èÀH¦½HŒ¼H¦±‰›ˆ ðÐ`20 TYÈÁ7°‰ $C¦­‰HPeöZ$6ȃ ,‚°Š6˜€´ª …,B°ƒ;q@Ç I•ĦzdG þa¸Z Oüt )¼CÄ2ð )ÜA]aA\G Tl  üA ÌÂ,l 8€&0€4ÁtRAôBö!”*0€øA@?ÀC;È’YÐÓÃmÏJÁdƒH€mƒÝŠÐ2ÒZ~îÖŸŠÉJ&®ÊR-VxLkY…?Üš è+Ââ+Òâ=¬À=¨Ü8 ÜíN,äA8°A^‘Á+ŒAP@؃׽K¶¨ÅŽšÝ١軜h¼\£ŒÙ·ìÃÙñ(32DC!|„x -d€9˜ƒ4d“FVýÂ2xC ÇÎ?  £þF +@ƒÁ‘ß\/ð@Q&À:Ã0ôå4Ef,ô®ïÂ"ÜP$ĨJØL3‘$: ñíÓ$54Ò_h¨¤óJ/|;t/8Õ(Ôz„ek8@‰ôxêö¼†X”€hB©r§Åõ‚+¼Âøù‘ÈPà%4zŸtAÜF=€ <@` |2¹WE´1´Á3μ¶Å€?#Ìà-Ï8„̈ÏØEP<5\‚ø™‘¸+æ^n‚"P%LÀ?ØÀ?pÂ3€è@< túÂíPQ–9×À\.Ã$й:åð%Äx&Á)A ƒX‰z]Ÿö^ó¦dd\Æ|Õ@ÍdLd(8•†j¨ ÓÍ”§/$+Äíþ~ly÷¥™ÞAü?|Ady,ùÁŠ™=þÆP³G÷²C5йÖCV08HA¸GóxŽçàN‹X _¦”ô U²MÏ\òÅ•_¤Ô©“ÈV2[æêܸþwo…E K:E)vI†»Ví¹ÂÊW_n|½¹3åM‘%LQ‚‚0 tá1&CE#{©P±ÏX:Ãxà0,Ìxö¹Ã£dpẔàQ=X³€uëOyøÁÜL¬±eËμ_'&ü#ŒÄŒa3f"%Lž°iØ6t„„]xdœG º¿Ox<ù^ŸnÞЧ÷F Ë%`SP(Y7e°¿èÐñÿ Èƒ)P?àáŽ"ôãÏš"îHp?Ÿ˜‚À"úpƒˆWXÁë>bP †Ž8â7ŽÀÄQLQEñC'Kˆ¡ç?̨‘F¦ÄFE'œ°þ„Ç« ÒG'Lìƒ:Bi°pnši"Ù a¤&Êi øEK(²ÌmhYd5æYCÌE’YÈ5’©Ãˆhj‰S–dÂÄæl²1¢“::1­¶237:噤›I%cƒ °©3 aø¨"ІÐC@ô …mªÑ€NI±À‚¨¡mH©a4`µ€vœÀO›nåÁ =f@ƒPyÄﯞ ÔDx´Ð"*¨`ÀY!Ê™ë‹i©Õ¤-† Á "²pdGvqä"Œ²Èƒ–@ i›%Lò³v·ÉA^UÀñÒ*£òí—ß›rJ¨Œ@jáC®þxåŠ+Ê(ãƒÆødˆT\1ã ˆ¨ Ïݤ1GiD¹G”]Ò°(‹:¢@ð(>ˆ á•$6D#¯#xCüfÒ ƒÃÕd{f àèFŠÆ`tÑå° =Í}0€èuNSMµÌPC3¸&¬l]€¡ 1“¡“›aˆkç$¨9ï2¦Y¦™h°i&‚ð ÕìACV—ç“-ÖùKS ºñà­Áùûß"L€i éO|jàV¦¶­!:d8”ä! 4jØà†©¼‡"i åABwa>Tà D*a©H‘©j¨ª5 rf€ ðaRN Å*X *'TV+ –°ã2±€I‚A…<ä!B ‚ö…!È(!ÐÀ¾À†vÀ+×.Æ•¯,¨„% E¶qƒ“$‚LuˆÎŠY€C± I*¢“ž Ò'JÆ‘†PP #+þÆ„1àÀ/`Cüƒ7 ÁyòJl!d,a÷ØNª ŠX@ —8Â\¦ ‰¡C pÈŽp{Á;% Oi“˜}4ÆÇÆ1‡ÑŽv£h@Mk@Î(a^ë Д ´¡É€2Æ@:¦F¶Â¼¦>À†0(pÃhÄ%jp>€A ƒ³Œi–¨0Šv‰z6šÂâþ²+$¢“ó†<@ 4Üf[\Šg+ðÀ ðOmJððà? ]x7:Õî¹ ‘=hv„ LáußOìJ0<ªHXS¸ò®@ŽGPeƒ/¦—þ"'p¯þüÑôÀަÀ R ½ä€>yhÉ߈Loh騀6'(DB‘øEX5ÈbL@Ó˜Ö„?!‚µ +›:ø¤0Õ¡Zi`2XlÈÃ…zh"‡b!RÚ ÔRÙmtã„€àCŠÁ |H(á¦J ©Þ É)•6µPPé¡XwèÃ*,ðϯE<²BDЇh ðb³¬¨rl"Sd@8ŽÄ/þ! /È4l£\èjÉbqÂJÃ]1Âß ˜Ë&óÁzÂ/7¶±'ã…VWˆcZèA p`†þ9ðâýˆŠ…E|, ´EÆ" Ф! x‡/Ž Œ¾ /GPÀ†ú0¢7\â ðÎ|ƵÖCí À0¸Áœ@ÜpÎÛ†ÑZ<”M3Ù$ i´ ¬‘B£ŒuaŒ}¤áZÙ̆‚žw¨<5¥a“VƒÛ;¡¦ª±P$Ô 0D{m@ŸÞÍ¡?bGCÓȃÀМ”Ú"=XC£}±øS ‘èª3ÀÓ Ù‹X<(N]ä² KX-Úé¥Yä'¼¡y ‚÷À ½¬H{Ý’›ke$Ñ¡ïÐá4Š?¤UfFZMP‹hþÀ©¿€ŸúÂj è»¶]w½†DøÉÅ–ë²À¾·ª PFHSé´Ø‡ Q캱NRÔ*T]¶)´ÁŽU`€x‚±€†x€(m5Сt<W~Ç0.Q `ˆy¡ìÐ÷¨œ`Ã;hƒ£:8õP'XÃ>p+z¡¡2ëŠCmÈ…à,:H@•l 6Zd'ƒÄcKÌ¥ñ ¢Ҙǰ°–x·&AÁH¿öß|Á1 iE²@‡Pá a(ƒÓ¿ …^”cnèxAà1ÀC b@CÖ [€²m7Å6ÄÅü£—˜M‹úÀ 1$þÁIH‚ðâ‹KXC<Ä Œ¦ÉâFSÂXÆ2Î@†»ÝM‹ˆ.f ƒuHíÇÑ̦.‚l 8¸Ck‡CÖà€ù}´a¥W.Le‹æ¦I`^ÿz×÷,öZÇç„ØÑTqI€î÷MU$Q“3Þ N)ßgßÝcÁ¬p ñü‡@ˆPôù¾D7Hâ.CQ­ .BÏáG·øá¥1þ¿y¬ÐÂ7qÔ†¯GÝ V°Ld š„ °Àî'L Èצ¬Kܧº`×víh}AØì`Lv-7Œm×’!Ä+ð'ì¶‚¬t-ÜÅM"è¾ääþ&Aê„áo¨Æô ?VÝ,T€VA Z Ø­V†ÈŠ0ßR…f¶Â UêàF¥î`,k„¬€¾¯îà l@–ˆ«¸8Ž þ€¸ò`¨!ºè LŽ 6AþeèÒ…`8@T!Ô+bA+:A @ÄÄTa½V¢çHîà0ƒ® Î%#¶¡Tþ€r!âØ€‚®à°î’ráªÂŠALÆÎ+’AV`dpB a½âŠX.|á.f‘ŽÀDЦìÌ0ƒbl˜ƒ ˆQñîæžî'îgzŒ4žIÒ!þŒaÁÆÆ0” 38£ ¨Qð`j®ñ5,ê¢bÕlq`ãiç=6gqb‡@bã.*vhE„œÀ<<`<Àr(€l¸†ùœ€X £FÊÐA ädw$<Âc·XäûôÀXÆï ´xÒ/##nÓàá.€è!4@ Ž §„g©´Øzx„xJ`^áƒø€Åž£Q¸´D'}í×6 ­¾JL€ Ø†m º`Ö°{-˜-¢ál!Ä®« D°hê@ Ö $žC  ŠPj Wú V®µHA·‚¤¢àj áV¡ÞAÐþômWj€bHªÁŠÁE…xÎÐ`ÂÃDdÁŠ¡% XžÀp‘„@ò€a3;3!þ€R 39Ž23þÁ&ä èöE‘è0®Š°k vAN¡Œðp T%‚¢¶ÁçZ® ÞÈè‘ü!€3²€À&€â¡à®á R€R@ xá Ø€ ÄÌÄ)Xá”a+»"ôÁŒvÁ"¨@ <§ÞˆÄˆàBfñ|A 4DcÇöŠL1!¸!„ Îà 5Ȃ΀d 1ïÇOjã0¾¦32”j2T ŒáÔà$þÛ®QùC>üñ¢~¦¢Pà™c5|ê”À¤ä. fЦLê?ƒ…,A)ç$ïÉ$­ùî@sBTª6PJABªwhKÒ0’Ô²§%í‘z´´J5òÒ¼ã Ìh´ èá 2 â†Ç ´ˆðî l ¬  ~äÁ / EÕ­ hÖȪ¬„MMÒÄÊÄL&Lˆ}LÀÄ‹€LàÁ8tMÙu+—íNðIL êjÚMõ@ô 0 1£ïÜ€¡ö£vgt÷«vbÇ $.ü†9½ÕÛDÈï|!™½OrÙA¨ÁŸLd©(!@á(¹ä­¼jÖ6`¬„J°dvc ›µä«àd­åt M8p¯°Ê*L:¨€äùOb!òþ¯Œ`Ùæ¡°! ¢ Ý¨çT•¡ò0â Þá²Ád!}"EžÀUN…U|¶&Rä ÈÒ¼w¥Z¥UX¥WªÁD ¡É‘Aˆ€ˆ©|á l€È¡ ¿P¦(2έɵ D@ˆK¦EŠŽ(ŒÂŒZ%8@&ñ¨O’Î4 í0ƒ{¸š_Vb ŠS†o" áƒÁ¾ö4€ `ÚúÓfA4Aô˘à:ƒa¬€"5,vAnj¥ÞôqÁ§Wjñ.æ®/àx‡qHfêa`/È€­˜#"¡þ:àNÅWÅ6#E-Ô0œÝ4~Lœ0Cš¤IõŠ j;Cón¤1Ôà¡öÇ.Ì Ú!Ì`><>'nãv6¦€e-f¦\¦¨ ¡H ¤@ þÂÑDŠ€£Þ`Aø£AôC„¸t½^½½£Ê¬a ÐO#—ÊzZ({B½N°«ví À§ÄJö4P{M'¯YÁŸ’~¸DØKÖ‚7Ší~Š-¾*4Pn­Í|fìfÈ# bÁþ!Ƴ&£qÁÅ- N ÆŒSh W ª°àˆó½øRâ¦^V”£TYÀ@ ÝÑ÷`ˆ@/¬að‚¤(þRÀ‹ò ä2ÓYDŽèÀY®Hè ŠbªÙï‹Îq½Ba$é²Àš ¨  ê]|nÂZø_ˆN†c˜xBT¡rà àaqìAœ¥á¦z¡Ë·ó ^avÀ¯†‚u46“Úf|@r êdà‡ê®i&Bç $ÄgìL tA.al¡ná`ØåaØŠ´Ÿ¡(A”£¢Æii˜Rol®ñ0YœÈ©ljÇ&ôÀé=¯É”àÜ¡ôÝûaFíÁbݺ)Sy0%Á”0~ü¸– A‰ ¢#å@V'CNJðxÀþcÊ“#­Í°Æƒ‡ž'OJ8A ¦Ì™4kÚ¼‰3§ÎœèÐM,s§N'ì¬èqÀ‰¥‹Ö‰f┩TýÂU¶ª&™0Qëj´hkÖDÃ6m”_@€8…j"Z²dkâ–k²DFnÔ©s#› )‹N`±P­š6˜=«!Áâ 7\*ljó 7 3¸IQf; «T;ŠNϪͤHñ±@ ÉK'Oª•¨¶Šl=zjXAŠÎ¡=ÈÊiAnFË'GÞ NH*yQ R%ìÚCµU)*Yªd¡ãïY$HÈÒ*˶m¡ªl˪թ÷qPÕ„*þ±¨ÂA(ÛT`+ "˜FƒÚÇ÷qC}Uä BxW‘/T¤1N%T0Â_<"]ä|ñ#Zðr+lLàK5}±Ä=­4ØzÄ„D7x €$e…/n¸ñF“ XSÄ <<10Sà‚.ÆÈ€‹-ŠÀòȉ0XPÂiZ }¬bÍ( pìƒJL¡§p  €*sÎ) ] Äz^€Ç>*¨Ðˆ 2샇 xà¡© Ÿæ©'ŒÃý¨ÚÏðôcF#TÄE$ta´JDèD”À%lÃ…("°ôDJÉ‚ôÀþw´ÔcBMKmµÖÆÄXOu-Mè8AŠ<8A'l…<Ó°åÔSn•UÖW¿|µ•UR­…YOÙ;ÖX@HÍ<‰˜€MS‹`sUYùuC"cQ RØÆä„§µ¦3`±HaX²J1DDá@gºÆÍh,Fn ÚðÁoG¹”˜QßžV ¼õR h¢I9½ˆ  9¯XÔ ¬@Cty<­åhðÈtÖ á4Ô¨BÇÊ×B{ïÉg ¡´§_YpÀ@Ûª¨BÅÛæ·‚¡äW…ƒ V_(sx7›„“GDDAwW¢A.cø!νÐ3ChAþ×Äcy—‡(­p¡_9«h Hx`d‘EPM1¯Ð¨@“EÜñFKsÄ:º¤£ G"f™”œîlEX±ü—¼AÁ:J¤C}:н.pDºý§Ÿ:j¬fPàGb”AB0l\ABûÄÿ0í‡ñ>ÃØ?Œú»Ã' î¨ê ÀÃp”ÚÑx ä18‚Ž€+3˜ÁšÂ¬-Ÿ‰‚ \ØF90%$ëYÑ·º…¦0('T!xp: 8¡ÔÀÂN ì¥]@ØK¤a„§ŒÅ*PØ@-&• làk0B2¢a/¬´ÅPÐáMÐÁœþk.FˆÅ np FÁ Rˆò2m¢ß"E7”±ˆwœ@Ö ‚ ‘ Ã`A¤À‚°ŠoÍ7ÚÚÖ ­‘›qEËb‰9 Lx MDRjDÛ„Zò"a:y \z¡ Pö"j“#„>I üakrS[~$° XŠÍ•-Ç8ÔF:0@³ NÜ|àpø@ó9ÐÝêV.8¨ b@èS¡*Ìâ³H—{ø ÜœE?ÜÑWã_¸¾@ˆÃ ¼@EqÞ:<.)cþA‚0@Š8= |­‚Ç Ò$`èbÖ»ž¢²(áS+U‚ ÜñÒKØã b¸‚ÈAŽMüa§>à‡þð5D-ªQqñŽËÄ$€à@à0†<ðSXG?ú‘‹0P@"EH‚’ÃáÁð +BŠðø¤±ØÆ.¶a,_á (™;^"­|¶Ð…|í«P$f-Æ8áìàÖc p.¬ Ñ‹Uû•~!q˜V  u™à-¿˜Æ4¾—Æbe ‹øJSLàÙl0»¸Á °(XB5¨FRÈE.v°@ ž° vÑ6!p þÚ@‚"ã4èÁ%'LM5j° ,äFÜÄ‹Žbˆ@_À)4ö€^"¼á% ë6A-hB¾,ª/0„!¤"¿å ÆÖ¢y7ùD(BtP[ܳ¶C¨Â"øé6?DX6™º!úXHoyãÙò–†*„#-ø<€å¼wc>(C  `@ $`‘+HPT bö¨R1*ƒ†ßD«'ýLŠLÁ”@`’/Þ €X Oh($ˆp„, xr´%¨¡ gðQà¼jw%è"¥Šªˆ@€Q@{4¢a ‚q_A¨Ð€†b •Ãþ˜À0†‹`$Œft= `¡hXÅ%2FaîXGB2…~\£ÎýÊ|Ñ~pHo€‡Žp"(àÉ$yB,–€ë,PÁ eÉÄüšBÀ{ØÕú>eâjÌföT¨¨Ä´<6´ÛŠ©RDµÌ *ÓX‹d㲈dì´žMÆjq½ QÔ Pc¬ðvð€–°B½µa>ôAXP†2p‹lhãøÇ&DŽ8˜ÆQȆúp”Ùë[¼Q )ªˆ—lË»…Å žp\rìaÐ Çö I"\< Â8wº¢újá âøÂL!Sà˜¨ªàþf} t¶ ÁY8E,š0ÞÛà çÂ"°t9@BóEß&9H™-@P‡« ~„ÇØL@ f€h`CR8D 袲‚âB\áŽ<á‘FB•‡Œ@G"¼àK@ V ÁO²†³úÀÐUHaÖ`óH)€R ©)àO¥*xÜáÆð  ‘x† ì{ д¸ B04I„8øùÏvQãpûÚ×þÑqp@¢p|̼c35œô*îðG}“Ó¸ÃG¬fõ@y@C®Ñx”àý°Ç«ð€#˜Áy,Ô¦kHXã[ù$¶þýïœL"UŒÆÁ°¡DJ$ ÂP&ÚVmô²PàYX( Ló²YOññbZT$K 7° Y`hÀÕ€HÖ` '¨ú¶ +h Ö0ðÿ¡ àxï T”a+ˆIõ«0€PH€z x¸e„DH„FbxH  Õ Ðp¯p{ @åP}y%°ä5;õ`QCQC½0eà ¬pÙàuSøÑ5BÇ Ò àw ° 6°6À>í³>Wpšäþ& þ@L;²7!æuŽ T@@ow°¸|Ù À§°þ69°`›€^¬0,R—à+1=ÁPÔE.3!xèpJòP".< dN@ ·(€ ÐÚÐ^™®f*¡wÐ÷¤p p ÕXÒ8h0 Å0ð@{àâèÿ · ÿ •ÁŽíxQ€|Ø8„õØ[’†}p Ö'gà{r ¬P oP Pfððw Ð>à'%À;G”iýàf¥7=— àV ’ö'1€Ð  ¶pØYê’m €XÑYÌ&ΖXô/‘Ó0¨e@kà¶ ÿ¢C<™÷ Kþ0ÿÐ(aPb ÍÑ$oà ¾ð&ãrðÿ°`>€ —P|h`ÿà ÃÀ ïÜÀF†¤0„¿ÖOŠ¡ ¢qFþÄÚð} IQ8šð ¯ Æ¡ rÐ^ï5T@³À‹“ÑÑ ® …Ðàó± m£KªÀu3:  ±`Ù 60ŽÁ0jXTÃ'‡xˆðÙð~Ìô ¡`6^ 9ð@V¢wÁ% Y¤ZKà§ŠªÐ '5cÀ`B±È?ÁŠÜRF> 3ð3p;)1%ÛR ²àï`PoRcõ9x•~1€¦‚1ðþâ« i÷I öiÜP ï r q 0y†`Žo—Ž"€\ÈUŽ•‘ þ6ð `&÷ˆ @ MyÐýÐ2@3{np+àäìÕo@®ð .k)S`aÐ~p%p ”ðn™W(tF!’@ k`?ù èYž¥/MAZqÁl³ž€Wzq1&›e T”0ó@¶ú°¶ ^±u°­° 9@¦'eÖ×$fðW²'d3|à0 O —05p Ü@ÕøjY2¤@[z@ Üp|ܰOF’q·•q­óOAþè° ›`äI¯@rÈ ('6pJž$ t "°"@þ \° »Ð pMàhS èkЉ¢0nÿ`ãXŽ  › Éʉ²À‰°èŒ˜ññ5"Š6   DðKKPÐEÆÙj“]“G·Žp U6`1×^ܵWÑ’,E` Oo«P =aàÐ -p  „‚p « V%ð1ÐI` gIà ô/sùf.IU|R "P§²æhp“§[ɉÿ ­ ÜÐ7´ P7t=Û'|b>žBU˜þˆ0°6@{{Ù×`ÖÑ—I@USàÇÐfàJo`?ê V°WÃ6¤FжCA1ÉѶP¿ ØDF`·C¹gန¥D6d&è€ÝæY•e@ iÊ c¥AÐ ¤pÊ=÷÷sö@vÊQí¢WµµMÒ Pi«0}À Ò¹C—o¸ðÑÕ„zð=»¶e©þ|ð“& UQ– Ðà  _ЅЀ ¢Zr¬ð¬@³")P5B T@4È0;€ ¾š» -   €÷Q7‡Ê€ Ê€#°þŸˆkÐ Kp ¢”ï!  š•éu– b` a b0‡¢PP·&:ñîñª9€œ ˜” ¯wµ-®øw2-¯øÌÓ,OV0qR0i Lº”^»‰Ê¯EÀ ^à €Ðp í`T¥Ÿ”ÐÅpì ŽÇÄ[¹ÄàŽ&»ŽR­`۸p” XÜ F ®_œ Ô o·Á0wÅpþ6­F8@UM{GðMSP@~ÐìÀ° *ñ›P D@ "\¶i‹Èi Xyû ßÉ–¥ Äz0E”YÔ þljQX {ÔÉÓ@»šY64 eÒ¶g‚gd„7à2úCý@>~Ь€£T‘)A—Ðl÷Gq„|$ÜÐ|€d, –Æ ë¨ƒ¤Ý »–ŠÔРʶGõX€c"|Poð {p¬à¤J8EWCïÜ „ ϰ }†^;@‡pîÁÀ† MP­` j³ Ð ‡ˆ q€#ÆZLó± ¤C‡¤SLnª6§°þšmõˆz“9° n× °À ¼ÀÝKÑŸŠø‘j#K «ÛÐ¿Ñ ÔPx×Ðrdkå+,‘SÀwþ VÑR ¶jKå@f+éCe=¡¤Z ~ý€`8 2 …X&ëpÀWhP–›°‡éø²õlÙðR ³¡ù6G׉­™RMP#Ý MÐÁ¤ š{ZÃp@¨ÐðN,r8u|Ç=°£Ñ²(š=Q @Ö Â‰ÌÙMxݰl¿° Ë0 @PN„ Xà¸5ÔÉ•¡|ɯ=€iAYÜ, |›ÌF '¤„…—Úо€Dð¾ ŸbÀÀäÄ 4ö ¾°~ë'¾0Æ÷±‘3‘z&cÈü{‡Å@ /q€àÀ©òþ{tÛL ”€s câÕ eb AIÀ ˜0ˆ12Ð×Pâ`à¼Pb0q Î(GÐ5ºV4T@õÑÒ–©¸æÀ¦ÎLóäÑD:4:2­Ñ¡ •¹ !ö ÷& ð7‡íqL<’tÓð'i° §Ð: xAq$Ñ^@Ñ^º$ኴ(v8å¾@R  6`%ÐWð¯Paå*Wµ4ÜQpeK¥TÆG ¾|† 2‰&T[ùGn=¹rL2»Åþk²‘‘¬àð×@·GÝݘ?í ýP­B%®—¹­¢þwä2@\<ðŠ Œg P š}Èø'lž{E.ò@D¿à¶¤™…¡±>&õ·ˆ¡cbC¨Úì=€WŠ µ.¾Í0&”` g «€´. 1Pfpš@á@Ï_@Rè Q‘OfG°AH ±¨:+gÄØU¹¥|¤°ÞA@ è Ûï”0&e"ñÎy(Ü$~À PÎe˜@ áû€¹p ¹`„ÀGÜ0L ²*®ZÐ} ð«ýá^b"ÎŽ ò ² îš~.! ¢L.þ°0=ds7B!_Ù|sòñöþq7àYp§ u! C8d;úÊq2%Ô‰Õຊ)ˆ~à" ÊÀF à ^~âÐÊhá‡J`ПW G ]ÆwIÕá= DçEŽq M°K±à±ð0ØÖÿ0ÆyHÅn=^çhÖ{ÀT ÷CºðÐdAև߈Íwup€ªö±ø+°öwVЬЖõgê©’ë. µÐÑ@YœÜìÉ,€‘PD¸Þë¨ûxÛjÁl'ÀC Êð³  o}ðŸA#íeÇbà…ð˜c¨ ý sW>Ä kŸoï`šØïP2H:HÆþL˜3Z½k&êÉë- }€Éè­Úò ” ¡ÜÅìiÜI ?oJ”H`A(”, Í"Áö€S•eà8´ µ#‡³pØ(¡ÕÉ]UNVQY%T•mOr¡É¥UM›1ce«Àa[ iX^ô—…æÉ—¡:rPÅ4GH¤ÛBµòhr›ÊŽÛLÞÔº­ŽƒzŒë¤,º'OJ ÀãN5µ ×& 5Ãצ/{^½ãëʰ%xøy5d›kî”\p‡A†»u5f y7!N0ÌqlŽóîšbh¸óìY  o.‘ZÕ‡H,Uªš€g(›¡"²®B…þN¾g‹ñσ8r&à¢0£† `Ñ/Lᘽ0bìL[bÊâ)Ñ™xáÍth7¡¹CÖý{øñåϧ_ßþ}üùõ­Ö Aa¨™¤› „Fž ÄB˜ Ä¢Aa4pƒÄBy(±Ã€,Ämœp¢+ † 5Ð`?Ì`åŠ?X¤ƒT¡B„^4à VÌ0 ĘÀn¢8Á刘 4 ¨ "+)aÐÀ IJ› -°€š ±“’ ±à€´Â{à‚"à¼à"蠃괳„;f˜àŠ=bñg‰mD‰Eªb’Š)Øbã€%•Zþ©Â&J§ÚÆ"Q8eÓmvéÔ¦“BÝ&#–È¢• `â`¤mŽrI©Prˆ-8PŠ¥PsÕuד.ª#RØ"ˬ±Ð(=tô0Ѭ)ì™ÂØÒºšrÙã‹xÆhž)¢õK6Øà‡ ”p§ÇðÆÏpÁ%\Þq7^nêÅ{OàV!¥†K.¹ƒ‡jªAãŸXš€¶ã¤¡‚Ù~3¤“C:ñÇŸ„;iB)”éÑ,¨˜´ž¨³ (hä‚“Râ»)H€ô²çˆµÐÙcöóùg ƒÚçñô`‡š ƒ $ ‘æ²Á äapƒ§Þ’j©ÑiyþŒ„)‰„`¾Å^z¡‡1® G XÄG[üÕ!í‰á’¬!Å4”éÌ 4H Ô’jƹŒpƒ´Ë ̤L ° „L­…±Ÿp“êê4yŠ)€1hƒ*H;.!bHÊB”‹N:% Þsˆ%T‰eÕP„¢)(.ÒàÒ¥DYbUQx?EÑPmÊãA«P¾£¬r½hUb'–‘fñ(Ò]Ñßu«ëŇ‚±œj° ʼnšÙÂ_ÿb@/g'XÁ/¯¸ÂX†0P [OðÃ\Á\ƒ[ë0ÊuшfÍi¿fðA1Y€¤àþ µQ°jü­_«XE1¤Ð 4A6Ç‘ƒ*ÐB ÙøÇl¨àlÂÿ°4là€!"±35ЃÔ²–h=€O@–±Žp{¤ŠÐš‚5 E”`hc$cÍ(a•Å’Z×(§¹©a­rFgÇÈãrZãC™(á¶K}X…/ÈA…<´ha(9â¦Èmn ˜EfA…=ø¡ýxÃ.Q  RʘÀ îG3>ðC‘€ÚXI¡+%è@AG™äA ­i[£%5à-·áèV´P7…u#™ªK@t’Y48àl« õrY/6>ˆEþX”I%yà JL²p Üb ÑK”L<â©‹ùCR0‘ ¤r¢Š% o ÀÑÈH”*ôá*RÊÕ©H¾ 4€jTF”cÍ &Š–ŠÀ™…ÕxC àáVˆáZ¬¸€ÉXQ’`ŠÙb€Ñ'®âÓd>8  ìÐ Áv ¡IúL1â ÆFRˆ¤Ž&4¡ÿØ„¾`ü!C 1l@°’ ›øGYã`’k-ËÂYØ¡3#gÅHÐ3Q"¬åŒ{åk_ƒ6‰¨ˆVZ%Ôä .IMLÃB$.d 6Nîr”Ø;þ!ÑjôÁ ŽLAÚ4 …+\ƒ q£‚‹‚:Њˆ Ç,Rp?Ä 53 Øï…ÄÏ“P+ «G0umrX¨Ür¹¹\’i|À‚6îð„¬BG(ÂE¡ Œðc1I]Ì” ƒK ÃP]ÂîbґԆÛ€†*r>pdA{Ê£Ê8•÷ÍT±¤&¡ ®bÒ paU¦Zïæ “‘j|Ë6sPIE¸%,y‰„O"˜ø$ÃÎ+¯?”· )@KXìàA`+( N<8ú ºu˜á f¸ƒÄp„L¡mdÃXV '€Öð×WSd"¡‰ÉÒƒ’…þZB> ÁÊøÆšðЍ›À…Š1»&DrË6pÒHÀ nã?>Yt¬Q&ª¥Šs}Þð Yt=Vz¬ñ†4«¯f!±æ3¿&úgìðZ„؈¡,¨AxŒD$€XG?ÚŽj†¥IH‰, `ÅRzÐã W(Ãþ·&G È*£<ð#]µîükLf„cB ú…ȹ2Ž :ƒºÖÆZ"HièFrÉ„… Y¢QІ²žÐ‡7œx Ð&1§àŽv\# WT X—Y9T æ•JB¡ üÁˆ›ˆ–cQ<\­Q@6™þ“y¦)øUINþÛŠ‘„YhöZÁ%¡¥ZBÇcq•˜R#ù­"Ü+êõªWËp ²èÆ 1PÀÖ%‚C0@åRB;úA"È¡tR#¿ …»á¸ ær‡ îp8×à_5€‹‰| Ÿv£¤N‘P*,XÖ€| "ôÅF²Tqv'ÝÁÖxØAh÷˜(hS¼ƒ^É’?tTC,t ùª÷@ Ñy7´¢olIKÚ†ªfGÓŽ~¬c…‹ ZbI@†®ÉATha_ 8þ@º‰ ìyHm(ÂAX2ßf©'­á‹þ}ÙoH˜„Ô y96èø\ZЂhú1ù’dªœ/ùp ÜÝ èCuI÷€+®ùÜÃàa%¬wÀ‚¤PÞI%VÐ^ˆ°‡MPAG Up§.‡* ‰PhŠ …‰›'IÉ‚—Ðôy¸ “8¥ ˆ[‚N0‚Nè¸|Z”›'–#9pšŠ¤ (Ž˜ „óç9Ÿ;×A»²?H‹Š`€hx3`Œ~°Mh køŽk@)-Ðr0 Ã{XÂè¥jˆ=eñ)*Aꆈ²¯C‚Rxr€nø _˜$C8÷þ¨†U€4` b‡¼«3ý1rƒ)+0<š¡@ÄÆC4ai«¿k¼Ç[Äø°Iš+y4-Y¬-a%Jã<Ê´gëJ˜ØrÐTت+ƒWˆ HGêÙc€p¨„JH¤Jʃ?Xµ½`…#è$?‰ê$ a@6È©#«ñ-;J¬ ¹J5ëK%­Á¥>2+0®"x‚;‚7)sé‡\’0øwCKh€x£·XÉú#‡´#²zŠ QØ…,Šà€•P Þ‘€* È ¨8íI.¸”“:ÀƒŠVȧX¨ƒŽ³HþXH¼Šë/’ãž9I™ ÿ»ˆá‘¯,˜¹z9‚8‚W˜¹# r†úƒ!¸€# ‚&¨Cxƒu¸-è-ðƒ‚Xh{¸’q¢&*¨l¢$«Êª†j`¢d¦Ëà ñ Ј͈ƒað—jP–jÀn $k(CûeÉ-Ê;(*†(E|AD£¼ü;AË»Cl¼¾dD„n šf½Hd£d¤Äò-ä›´ZÒ ™œÏq+9Є^@^(ƒ0¸†yµDbÅW£‚p õŠ›<ð[|°/ð_kX=ð€*ÙlÀ† 8¾ Ø´®1þfƒ,YF/ÙšTâKàƒj‹²®Ñ ‹¦þ¹"*—Æ0?à…\@ð"8˜‡C8…S ð؃¯zVh/nj‹ø/™8‰4x ðÇà—`@X•oš”DQ‰ïa€É9„Ì‚|ºŽcÐŒÀ“”å!9 »îáHX¡ QÙ†Žó‰*Èb¸c1‚xVˆ­øÁ7#0ƒu˜‚ ¸*¸C°†‚è3p…"ÔWˆ™“I*b²&ŠB=È)F¢J8¡‘²(Ќϓz9~aRÖ!R–ñ$=(÷ðJØ€Z(€e%QKþˆa‘(>„¢ ð›@„6 ¤¿´SDÛ4bSbI <LÂL4*a%aXLÐã4ǤÄK‹£ãóÍÞœ†ßô¥ (“BÕÅ^ø,q(3ÀQ”úƒrp‘]+ÍJ‡Dr)M؃Ò„ø‚/ð¤Â)ƒÔiÀ†ã\MÆa<[=9’´ NÎÓ#æÔ)J%l+†¨6áê|€"8‚2P è0ƒhïôV€H(•èÁˆÐpøØ?ùU0ÚžS™”œÉV ¥Ø†¸&|u‰ë©'„ƒ”‚ô‡C `„,”XpP܉ '‚ºþ|•?’S9E ¹X„`½z78PŽ9yfRY`€C#‚8·2P=z¸x (J!-Ò¨«mH²äL¥a!ÛŠeˆ,È)$À)BZ~¡º¿aR1éR4(³H#áƒ(ž‹`€Mp€w˜ŸËÂÓ*¢™Âs õË=©4I#ýqSÀ¤‚©3'¸»@eDàƒ øM±#Ë£š¿eLk%dÛMƪÁ4á´1¹»U8¤G Wؤ!dЄP zȃ<È<ø,M ‡!‡+pÑ$+8‚#°)Â[5ÝĆ(àÍ¡Fýi€T¨¹þ]ÁZ=â£I¨ŸZ“>¢Ã¶(±8a]wÀ2ð ÀV¸†à…17h°˜LQ…ð§ Œ ð ¥@sâ‘x¯§`À|õÇäP‰äH¬È!Ch‚~ÀBáÐ%pЛ€üMv‰KáÏ<Ÿþ2AQ™×‹‹’4°€³}Eh؃K€Ñ7H37ØHØ)˜€'2çýÃH%RÊ©(#¡>Ò(K¥b>X…8P°ùq‚' …'åÚUH ‚w(† 胺(†Fnè6÷HˆÊ2p°wx.:ÓK:¥Óh9–¿þ4;ÝSýÑ»³øK©}[²u‚èœ(8œãbqèhÛ»M4¨6(ðMÈz¬9ÆÞ„LÞÝÍ@FF=ZFl£ÀŸ>xµÍåÔ~°Ü?pEȃ(¿#`rHQü-Ð-("rÈ!ȃ^ð1x€>ñŒÚ•]Ef6 N(¨]lh¶\†büåÊ4V½1áƒJ;jw0€kèh x2øR(…WC(€Aa ÷Êpp€lx‡>‚ó –óžòzžƒ‚ßXIú¥8Ô¯'‡¬h0Ü+@\9 Œ‹Bát@TŠœß‹U9[ÀþMƒ&(€áá)¨bQhCØ3 ¦°‡arU€)pÇ7€®  ØWX="xÁcÒT¢º;ø:©0*_І¦–;(Fƒ˜ª¶Xªvm(†là€øâˆÚ"¸õË›(º2™:ÙKA¼Ã@J<¶xCKc²xšÑ¿qëaAh4Ðãžéã½r^J¸ÕãcšG[¬i€‚ÄæÝÞôÍFõåe[F©Á¶ àPzWÓ‚(u³zÈÔÒÒ€ìŠ00e¤ë…?ÐMx…/èÏ̓£ô….šwˆƒÝ4þ¨]P@ÜVšÝÂ…š˜]\6FÉ™>_j°Ñ»KðX3xð(h6€ÆÀR`‚èRP8À€ˆ·ô}à¡•ˆ%9lð‡˜Xúº‰^QPþ”ßWÉWoJŠ SÀ€"¨Ì!˜ÑÔÂ0QéÐû¦ uÀù•Žhޏˆ« 0C¸ €„&8øË‚Xj=@=À…;; ð…Öýß :lìÄÑZ51X¿!¡ð—Õ ²>™ÌêvÐRÀ‚bh'•j*âU(²}+°¢¾ž±&‡q‚цe©³U˜€rž½š´¦·vÁîØÃ´þ%IJ -¥Dü;¹ê¸°S#¶‚Òmð뽄I %aÀUÀÁ’ß äÜõ-H#_n6Æ-.1™»0pqp…2 !XÅDʃ&¸‚˜Y Ôùz(J Píù‚GȃGøƒÕ=‚!»meØmÚÅUl˜#¨™†(Ðí^Þ€_ýÙm¶[ŪYÆ=bm >Пoë¤7qxÀ¸êÆø€°VÀjwƒxžôÕ²ðH°€9R‚¾‰ ¨ä8I A—˜oL÷uhh’“€CðÁ~¼‘UÑPO±KH¡è÷¯Ð¥P…zºØ–(@:Ø„=¨pt"‰þX@ŽoS €‡KŠ·_@U ¤MVk81ç¹k W`_°†"Ð8Cƒaè‹»_¸q4@'èÒÖH¡‹ç=9£Úñ0b#v"üÙ6æÃaA‚°€U32 “Z4>ã:årø ´-+è´Xs4¦";U¨FýáC'Hj;/£nÐ<©±#Ī4J\¬Ãu%¸W6a%ÜdÊ¡I%…jH€" xP·/ÐÏ SÝ/ª™'¸NOD"å+x…Cú¬! )kx4ˆXõÚ­Ýi%;ºUEžÝÐdžÝîãÎÊö>²€=F°‚;‹“5ÃmµþVxHvkÅ݃RÀ/ÈLpðði” VYÈ‹lqR8q =ûbwu÷Gä (÷ S…¢ƒqx¯› “‰$'„Fh…¸ùð C¸‚r8$*` ¦-{± ¸„%|1Ø‹7 hèG€ÈíÁ r›ˆ8bƒž*T4hºÂFCzC®%¹cmÕ»(µL(;Ší((Þ¡X>Q› ä±aû~|lTËÃ"¬µj|øÈ[•ò‰µ7G\pÄðÄ;ð ˆ<8Ð ôðŠ{üóªÄR8,ÒɶÂE#¦ÁE+­ŒÈ…(ÈÒÉ)UÀc(0¶2c¡àhciTqbˆ!VÁEŒUÐÑD,t´ÒBK.ÉAÛ ãˆ;NÉ£þ•;ÞØ ”BŠ8N1n3c -PA2šˆ  úcäZ% †œo°âË›l¢›¼Œ/hpÐS$PèfäÒÎ\•àÄV<ÜLB\e¥•Kˆâ“@M”ÄGš"Št¡H-]¬Ñ…kØÑª9vòê<‚aDtRGó¬! ²È’]'œ š?±0 ˜ðÔ˜¥/ Ë\œÀ˜<Á V(‰XžÀ_ ¡çºé¥Ð1Tk¬ÈÒâÁ*ÐpÔ/™Š1Áfø ,yhFg‘á d¦Ã_DÆ;W<@C0ȨpažÂÂ%Š€x„A šh‚èŠ *Z1AC ŠB!$Ð4ð…7¢‚ÍÎÌL€Æ3.r¤lÂ6PÆ«šZ²-ÄÂ~Ù c|hÀ Þñ–áE0m× °€GîÀŒ°-k°HŽÀ P@Š!‹%\4þá Òß‚YÜ‹>ôGêe/ŒhÞùHp@êvU„" Ð%ßj¤ÝðRwHÃÝ‘yÓ‹^òF© .¦ƒq@‡m@ó¾þPK f¾A+o „l`+RP‰pT‚áBBÖiÜãu‰I\¢’ˆ ã8oÆÌ„£­³ Í#@Œ! çahGüÐŽv4èÄk Â0¢½è9'Á‚A DàôHf‘ƒ«‡âêXSŒ61ŒBÅÈ*‹V±:Æd+¢U@^xðX ÅX)¬Pj±Cvé²fåi…¥}p˜ /¨º™2þhŒT@T¨9/xñh`h Å Æèi¡a§ƒ=cq†C9ofæ™azܳ™zgâiÀ{–Å,«Õ ÉtÍë-Ò 8€:v ì¸âØ¿þÁ²›- î±mK)²Ò'ƒt¢ŠB ”#wjÄâŒBUAA¥AˆXÎ1q80@+䀓´ÀŠy×ãœÜ.áýaÉàä·µX8d“\‚°V܉ˆ@•€=ÀD@„ °Á5ô‚TB%\JXþÈB" ˆÂ.dÁ. Wə؈ŒÃŽÉ˜Œƒ‹Á\8ðÃ,ð'¤'lA*D€@<ă ÎF.ŒÁŽáÄä‚'Ѐ' À Ð  Ãı1D@p?èá,X]j]Ž„‚‹i€ôXaUÀD˜XPEÁ•Ä(@1ôۉܡ¬‚ÀÔµŒ—¹$ž!ž…ô—Þ)ºKÁ4,ƒ0l PFÁLgèÌåEÆU]UÀÐâI†E <À:ÀÃäÁ#D@;\€¥¤ :‚!p<šà•+0‡\A”Õ‚Ä ÿÇ"DCypÚ Éþâf<^.ZWí%Ð"‰G…i¼Ã hCÁuŸi}€|ÀüÀøãô€´Öô@üÀÄÈA@ø„ÉåP/…×@™HE%”+‰·ÍHx 0Ià€ädÁ†¨0ÉÝ(Γ µE—–´äyE×É]É“tˆw5Î64à…¨‚*BœÓòL€q@ +ƒØÃØÃXCLA ¼BUî!ÈB2äŸ? WàLd‰ƒG>á˜\Ü,(c0ˆP€;¸¸ƒ( À\Îå:Ø%;±Ó:Ù% Üe]Þå_J`ê%_Î¥Àƒ;àÁ>ÀC?˜ þF 4¡´Ó_8A5Ü’‘‚„âYT :ð€L@Xƒ3>Á¬B1¨&gF‘XBÙ‰/xKLÁD¹$ ân@AÀx€x€¾„†U‡08Õšmà -\h„G-ZTQƒ6ÜÁ„+¤@s @ØaE58”0€ý+€éõ9lD,B6ôL{(Ãa–§IVaÃfô"›d”‘eœZi`5ÈCDÁ;ôÁHÆìÚ0„ŽÀ#yAàƒ¼‚+ŒüÀ˜ÂC4AšÈ´IÜPÜXäEÂä¸e GVI–—E†—Þ€ƒl]þÐ-µÛ0Qdz‰Ï+aÎz­—MâdBbãˆB6`,4œ@ ¢CA|A<ƒôB/`œ8€!€$8€@$t_1X(Î?ùS()!ŽÀ\s¬^4B#àÐe]æé:ä)aîå]&@^‰`ª`O¡®S **^"ª¢jº´E–í]1S`XKó¤Ä'Ö”E£ˆÐT¨ºÁöõÅ*”é@Bn@BM=;"$Láñf­Î XÂgÃý ÁE§rêŒz´Ytn†tŽÇ©Ñ`­ X„Á ÀôÂêiEóÄ ƒÌîõÂþÀ+ˆ=¼BRâB}.BÄa™@4|óEÃ}bŒ¾ô iäçóYÒ$‚"è ì[LÁà@0ôÀl-€…²e8èƒ:˜Â ŒÀØt‚?lÔ¸Íý}RÊY¤–° NúҷͤýµMäIŽÐT€éü¤€ƒ¨BlÃÝ´äLr‰‰t”èlt‘rAFúÈE=‰“ð$H”B TÃeŽÓ À¸B Ä€ìAB,8,‰£9À?ØÀìAŒÈ.Ld‰H|mB´Ã[ê_þ%`ÎmŸÚmŸj5jðð-¡öåßò)Ý:*¢F‹`™Û½„àM@1þ0·Ì…[4º4ºXƒ/ø+ 0™@|¢°è²Â+Ħ¬v.ªN€­ª.L°5HÃüB,º¯ÖYtþ‚f¸Ù9žÇ/ÄyìÌÍ$'iŒXB´š;˜/°A<`IÍÄhÝ,,Ó ÀZá\L€ºvèçÍ@Æ/Ìk4¯dÍiä e!LWÝ‘}L ħipCÀ†h,ƒì£Œ@xMƒ|À8!Â\èè*ƒ,ÄÂEuÒR䔘×É©(NNÎÆ¨Êš\Ež×ãNœN6lÂ?üÁ?œÛ“d$‹ÑŸ¸‰,ŠÑd”“+ùÈ.H€lÃþ“Øl:@4$4@5èÝð+üÁÔ² @ƒ&LÀlúåÀÅ@˜·Â)^Á@ ¸Ã( æåÿ%a¢žÞmžÊåïi^ê­¡˜q¡þížê©Ünñ¢æ-º¼„XL…E TÃ*ô5X…@«–ýX¼A1„nøÂ"¢ƒ/ÈÁâ²Â¼+Ã+t®P2«B+èæêÚjëú‹<ücA7°†æaÆ9ú®z¸Ùϼ™óEVª†xð0ÅôÃ>@&˜Âd"L¬B6PAÖ…C,“B9ˆpo8À"¬Á"DaÙL-äîøfÕwäçÎä"¾ˆFi¨Çbõþ"t;`A4d±œ€ÔÀ#RM?8È×øï5|Â'\Ã0Ã0Á@²Á SÊÉ$½%!@Tà€ ÿ’ʺ践\爀dC'ÄBØúÀDÿä’Èð‰èÈü©0ѦW‘²×ÚÀp+Ð0 íš4,4@1P‚ð6BV¸Á¼¼‚DL±øÁÔ¡ÞèPÁ¹51 „Á14Â[Ò-£Î-Ÿ¢À|±aÂ%Kõ\ÊeTÃ¥8uæ:d±j_NAg±ÿéÜ.ª£þ:À:J)žÝW`Ë ‡®¸(º ç†.+„.è’nlJ2&þ ¶&×* ¨UéjeM‚R•Î4ò者,î§ÁPÖ¾ÔP4 ])ÄC.@ à•Àø[TBh9@ƒ!4Á#Ì).ÈaÝaÅÙwÌÑåEVñ•Q I–zŒÇ²º‡p›ÀP;ðÁ °QR¬Â•Ô€ôÃ…2HÄ@x(/ À”ôÃ\À ‹2€{Õdåxìü¥è'í,Nµ•¬øP›,á8ÐAË¢*|J2THÕÕì’ÐpKRàEÆ—,ÎmB5Éšä@,t‚S X`&:\BnJ2éXŒÉˆÄ&”C„ˆ“,Xnê‹Ãñþc±Yá&TŸ\µŽó8ž^uãåRÛeŒ¯1Ÿ:5a:5 ù³‰“yŒ]Ц/ë*@@\XÅ;)èºö¬*€°‚çz¹øaWå%¿Â„î+(6oŠó¾ÈâëJšíge,Cd@§›ý‚ ¬²œÉQÁ Úe…Ì ðà ¨Á>8ù_ Cˆ€¿…Ã#hÁ00Àð.°k-–Ì”ÿì ¥‡"øni”Ç8úL4¸:4“ÇÏÌ¿$ë|Ejœ@  ËÜÁX·iÅÀ€+|”Bà(0pÌDCü¨”<ð/lŠô‰¢þì kΗGC%B9AC{ .„íO:‰ _‹É›¸lüµ;»WŒõÞäÈÍJ.qÀÅ@(¨Xº<+4A9¸Aäæ0ä!ä74Hï|Ax÷+¸A9 d%t›æVl¡4yS£0|qÛø>æ>°|Ã.ÀÁß)\ê‚ëBàvñε‹uàŽ5ϽRîoH®¶nk1|¢¤Æj«rê–?P0²`ïµ`7òaöÖWeUÁèŽ.œÇù)&•h4Œ,^žd1L+ÊÃ2\ÕžC-¼™yø.ЈïUY3;r7¼è@4Ø2þ”À¤Ç¥_=äA8XÚ¤k-Ìk-Ä ºªÏë"«æÏk3Aç‹£8âçyHÖ¬;ß{ÈPÈ­5ÿôSpŃ;‚Hv_ƒ`³_ HlÀ"Á  ÛX zK {ÿ³KÚ[û$4ŒŒ‰0ËÁ^K‹K)âB6ü{(Ô°»Ë[zmûܤÈþVédA¾{¿Í†‰âÄ_ã°?œ‚,€@-$ Ì)p…582ZADŒ# b$ùBNÃzôø‰óãçK¹&tNIh‘ÃÇ‘%$˜’`]Ç릠X§D %pPÂAá…3i*€RW̘ºþPÊ\÷ó§. !‡®3‰¢äQ¤JŒ2eZô'ÈŽÑ•(ñtY¹:±6•kZ¬r㦘›>OœpÍêÄR9¯Ü°zÅŠ•ŸW{φÅËjÞ»vñ&±æë·‹7vüräÆ(a‰„š¼ P~m®5-H· òä ƒ2mÚ2a‘6üúeÂõ/lØL̆rzëÛPýº½a·w¸…Vbkã'{¨<ÒЋœ–/yfÍú£c¶h]jÕŠbâÄ4(µ±-Z³&Y¢D²¢_Äýy ÑÚÏ7a¢;6(À…mÀ¶y̱dƒ Œâ„>X 剦˜âà9€ÜIÂ3ÆþÀµ±À‚i’e—4ÒçD«¨‚‹*TtÑDCi%Æ4X4±ÅW´1 .z¬¢• ƒÜf QÌqÅ*y7|‰ꈂRøàF™m8Ø& .»Ì¢•"wä"Ì%–؆ÌVXä" Q–ˆÅL-·”Sr 2<³ørÏS²(@ P°8An,¸£*€‘¡£.€ž0Ê S¶xæ7^©àŠü %‡Y(°*`@êT£JÂÉ&t€¦Xcåé%hí ØÁ‚4.¹ÄªdÀ‚ƒ‚ /9bŠ`]š"9:=å”C` ‡P4(â£F•=)&”tz_Öšt’‰~”€Qâ‚§B6¤TB&ÑÅrò?£ €GYVÿB‚Ž<NØÁmùâ E@ÇV‘®t‰Á VÀŠ[ر Ha.¬ð…üÀŠ+\á [ë]²—¿@bD ËJÀƒ±ä ˆA¼—%¨A Œ† ëOÀ6@ yl4ËN$„!*F5Æl¶8±…m [¬EgJãŸòàâ,€€¾Åkíþy ‡CÊÀ†<ð#ÄhG1~Q.D# ³1Ám¦ÑEúÐ'g¿†"ºÆœ!í=µð™|Ö ýØ?ÂÐOäÑ ¨@XÀ%´µ\À8¨ÐbÄ ~ Á¤ …E$£Ž€›ßæÖ#..O9èR(ˆÉ»Åˆp~#œ‹˜£©Nt¤Ò6Z@*ü! S8À1¹:t¢'Ed±†Edƒ@’À6Nñ9-‰BKgêD Úµ uK8`·„ìLwkÈíˆä».É) À)dA‰d˜=d€kBUàÀ)(>?ÀžuHDŒÀ;¨‚ ³þàÇÁ zÌÂŒB•ÿbr@¥Èʦ4¹ÉMZ–¨D&PIÿŒ5pX8= R¨¬©8ë<€V[´qÁ7\¢PŠAN`VЃµÐá„;¸n XÊõŠ+øâ%°Æ&`Ã+Ü¥.wÙ94h-!þ°‹D¿¨Ñ JŒf5ÂÀÂf¾h6¸áLiƒ Õ,5ýan‰±*ÊæÙX°` K´‘+ÕðAR0‡à ôà…d€e˜  ¿¨ÙljܲgIÛ"X3EÓ,íbO[ƒ à³Ü›‰GÑF7&‘àl`± j@²¶µ P(þ›;.0!3 „ˆÆ7 ðË*ˆIG¿ü¥ßZŠ,p¿^âÀÞ’¹L¿ÙHp:¢¯Ž¦¹ Tš¸Âà†MT ²Gæ!‹(x ˆB'¶áºV€o øåÀ›tWQœb ˆÂ< pŠèS¡KèD¶±‹SÜ ó˜ÇîX× ä) ¡ØRB³á:eƒöè‡=´‚üw;ê‘/¹àˆµ"Yž…’ xP oð wWñè>£Ž~þ+ aÃW®èàˆ° †D˜€&ö°k5°±þ+;H# „†Š=,c ¹0ÔÔæ>´yÒ~kÔ܆`_ü"g)qï€B:@ Â-èð…†À‹\\C–lhïðŽdØb·Ý©Å~V‡Áœ[sùãÍ/ÈКÖhg7„üí&Áð!‚ÛŠ´T§ì—˜0ÊàèÆòÅHõÍ“–|ª=¼¡¬Øƒ¤àet¢MȆ,”Š$1`BS˜ð+ŠwÂ7H]+þ °b#HA EèÀ`¡ŽxÝ?×0#øCÓ:g¾'ï¢èä8†±ä}X!+Ö(YX›‚GôBÐhNÑÃW¢9 NZàƒbÌ€O¸CGJ0æd Í'™BPÝW“5Õ§*ٌџD¥© šg¢ž$5) ä_ê§R•²F>9eéÃÞ €#¼aw°†¤ß _¸ ŽÎ–Zf€†²õ_¸Â^Q„g•ào˜Àˆ ïÁÖx4^ñ,YŸ?ˆ€í­qýY€Œ×%ö}ÚcÎù+Œ«A p ™3ýð'"¡¦á €(á´²M èþH r! H€ Ì€Á`ÝÐ-bzk ¡:°âí>ê­ àãÞèCº¨V£3tËØ˜†¡ ¢ <`œÆ@0G”,@kJ Ž@ ÀÅ*îš`O>°ÞFH@G¦ Iîë¤ö+ÈFg™˜ •I™‡tî†H>'¡B¡öàJ@ à²ÁäàvG²A®¦ 8 L€dO–@ö0Ç^¬Ê:adÂÖ ºNú`ÈdþIÇŒÀÄÖI¡ˆd„ŒK*Âðë€ÞÌ ¶Bï„€FqSA  F!¯„ñòÀ«@ ¡þ,á n‘T‚"ÏþÇÏjâ~êç}VBÝ Ú¬Íö%xâôP¥(ZO~œ‘X2oö¢B*6Â*¬‚$è-XÀV! 2È0î@f ]’„|áÑ–ÑB]TÈ.ö`úˆ  «Â ¬¸öà 䮊aŠAªÐO ï…ܯ°2#, &`´cþc¸(g†‘ðã¾Á5†a)gÁ¢ 7–! ~# à-žà t 0ÀÌà €á ø æÁnCÞæÁyfæí·r'wä Çz²hì#7r‹6 ?2Æ‘°º¡?N  úk¬¡A þ–6ÏÜ¡‚Á$àÄNámvAÂDLäkÊø†äjF^ŽGgå®pp¬ðnˆ©K8ž¨© r€<ÂlठŠá²Âda”ÀÓŒ) fnêIÜíLj, Ö@ Àd¡9 áÊrLX¬ºDŠÕN:A Ta|€aúAªœ |A ÊÀ0€~pÀ†@:v`Žà~ðÀ*Eª ª@pa(ÀT~e¢~xJ&b¯~zV€n‚VüŒ(Š"w‚XâSXnª((Ï‘£‡®Ï 8,0(à ‚ŽÏΑ÷ŽO…¢þêf@­>èZí Ä ®l‹`Zèê6ÈÌo‚’Cݰ ŠBcr4F£4„á·’AnM‰B>êÍœr&hL 7‰b6CnæºN€n(aPò  <¡àÆ àᬡ°Áä Ìq¬’èc¢îºT¤8°n L‹R¤ÞÃ76C·ø8tò?Hƒ&J pá, Hd ~°â.`. &úÁDA—v¡‚¤MÜ$NT‡oîr yDET$Àºp™ÔDH„dOè@˜à)HÒ 4 Cg 1Õ[ªaäÀ¤ b!@î:áþ| |¸¤þÄÊiæá6³%äÀ``$ÂÁÁæN²`D‡Kž5˜.QüÁb!þh h HAªâ øþ`¶0À%ûáÈËý Å`þ Â"€R€;Õ§ýÌõ`Vx1%\Ï&r‚ÏÒ3&xj~E H&rÂ&fâV ¨õ6¯$²g¦®WÁúnÑ+œÏÄÀøžÅ+Ô "-ÑÞÀ@Ægણ^aÄ`že+ÈŠ¬¬"ª$HÔhvC;”Ci4BC4’J±àDic<à4±¦ÿ˜+lA>€ ¹€@¾¨? ¦!þ|£„~£LË ¦à@ Œs ô ¢ >° °Ág:0º€ÝÚ-æm6,£5Ö@ºô¡o –ë4î~A`p7€0`˜r±„¡ˆ°€,@DÈAŽÝ!{¥†á²À½bŽLÌÝê`i$ ±pQ¥¬™^IÈ$æFGMÔ.è€P‡D:ÌF|ᦀD Àˆ ž â€yOU@üau:Á1'¬n dìVÊì΄êb¡ Ê¡ € çP5ˆävíkOò„˜¼DíbAbÁ ¯ ÐàÞÁ04ɲÇΤ¢Yöþ³A8‚$”ÀÂÞ }¤;i*=QVhÂ(ŠÑ‚s^ÅV\V”ÑùÇÎVE~¢‘~F˜)*Öµ¬Š¡€"ï ì‘Ââ ÈʬÃú¬âu9¬¥‡®‡u–fÉ‚ªá…“£¬xV‰³Bý,ÀÖ ×‰KÃD…!#»_øÏŠ˜Ö‘Ì jm¡¹" Ù®Ò×¢@aÞA8¸¡ (Áá.!À@ bâ#x€`;– »¶4wæá˜‚måÛL“ñ&bÂQ¨¦ñTܧ„m‚X*z„ƒe×ÁT‚Ø+úùŸEZ& c_­É ˆ+g6ˆ›Œ¦­%‚tx ܨÉ6è Øa„²bg—øüœà_níg«¨almàωÈàØ–š4˜–6©þÞ¦ö*é>PÃ@æ¸!k_°‰¦ & èO¯ÑXêc?LÀgüØñ<‰ÙîÃ5@a3zãÖÀ¥A¤Š°è†$à6l­ôV”Hƒhí´¬‚Áœó#Š`ä ›ôp3CL³;NNÇ¥L¾^NÀ`™ )•uj™R*¡ÔN 9€š0 r ü. Æõl ^ˆ.ÁÞÀ(@ ìb A  GØÉÀ©¡YÙÉLüÁ²áœ ³À 4@DÀ^”!U/³eŽïK s€²€"š  ¡Žw‚<A¡-œ¶Æ#¢Ó…£ê þèD¤€9‚#Ï:~n"ô±ô^¢%¸`WB$šV "aãÓ¢%`õì}.ïÏ”`#Øu?õ@‡mÚV!f¡Å†aM+‚ˆªagÙ(¨‡š¨Ñ¯~¶DAëg†Šac4ÙP£Ö0C3ôÏ7„í<|¦hzf½ÈãÂZaÄ@a'àÄ $à àÔ†í>p)=6n€?þÏÃì!Á’>c<’°EªMŒÉ7‚`º!ŒpÔ6«œxø`¼ºB¦€ˆ@HׯœÎL¼W—äKNŠR}ipuÀj¾š0q\ûRý¡ á:$ofþºæü@ÄÂÀád€¼Æ²—¬b@ 䀪³ ²àTAb»V·›eLAlÉ AÀ¡ ¤¦ý wç2ÝY6On—9§º@âÀx} ~R;NÀÀ xÀ…‡ôÚ}H­à¿ý¿Sú È7¨ ‚õ0Ï(xÂŒY"=CÏŒ1ƒ–%ij€þl=O¢'<¸aÛ§¦nª©¶Ü¯Ð§­…€ÙõÅ·‚-+‰#ä…ÚÆo<°úågŸØÖž8"3zëp`N#DCãÖ 3–¨Éa¦Á‘oãÐ`p¡¤KÝ©ažÖÌ¿¼þ“µçÁ·jaqu«gÚmذ>7¦ÝÈô±¦®Í &a_ À’NÃ*´¨ÁN9ÙZºæ¿@š`M¶¤Fl :NäÕ鈤o|$ Õ½TGHÐD¾µ¾$àäè ¥ a¬³/sÀàÁ#à!üàra Ü¡£I,øQ.à 4 ª Ê@¥:¯ö«"DAã* ˆN@ Žè”AÊ© íjñÝ ¿D]NàŠÜÁáÈÖ ­£AÞBÝ:«^ø\Xѯ?¥aø ܨð5Ïø má`F& :ýÓƒ'|'X"ÿ§'ö_Y§hBßþ3V@œòh œ C` Áƒ D“„#JœHqâÄ+jÜȱ£Ç„A°l'/ˆ<,%ƒt»eRØ4(¿L@ eÙ4Z¦-‹$,Òȓ„¡6óÄ/lØ©“̈´¦É™ÀöëL¤QNC¬º€Äį5FŒ,J†vZ@’ÍKÆvÞšhµ¢-²&Ùh2±1rãF:7’™˜v–­¢ ,™02õÄ´ÂäY Æ‡5mÕØ}-Áƒ°>q²piu¯@'Y²ìâÂEÔ).il/Ù&j›ï*i€§ >\8î*\ª´Z¾švÚÉÓ´âФ‚¡"4ØþFdÂ&U9fý co]8 p‡Å:÷ïßãH¿Ž1î”Ø3C‚?Á„1³d ±ea[ úãO,É(S (P`J-‹ÈÒÉKˆÒ¡( î"Á6YøÆ±H¡LÄr¢°¸Á/ÑLã8ñÄ¥=À#wð8Å¥=aäO ™@ 4¹Î“P>麸§„x p‡í¡ €Æìcæ>pl  `®y%›íEy¥”lb©„.`†©Ä–yJ_œP.éF>!Ð@ 4¢O(ªÐG9$PA9饘f 5òD’’P¨E>‘ÀÍŽOe”í]‰'žWz™¥˜bâQ¦™[ri¹žu ß:JP¾'{Â!@{°¾¥{qÖþ|À,9Ðà…iÐï):)¢i:øà‹jªüòñAIf&ZRf$A”-îªDÀ®ÚÒ—÷‰$Bm"‚Ü HÒ|»¶”,Ól°APD!ÅëL¶baNâÁ²PxÖÚ¢²¥,¥0ÒÖ ƒäo &B4è²qkm÷X [ Ð)SÁOµø…06p‚ùa ž!…,À‚‹$¤Q8 (2¸-·q€þ Ã)þ* œ¢Ò˜ÇÆZ±ÝŒl" ™rZ±šm0§ÈYâ8Z!:4ÁÅXÅ%fp‰xå+¿+êöt%iŸÀÒÔ8(i#(ÅÐRG»u\À‹8ÈH1ƒl0€k8Dšpì‚C®Yƒ,ŒàˆBb±X‚*8àØp- ò ‰Ø›P¨B>°Á0ÞQ,Œ«´°ÄCˆ¤¸›ùˆ…,‡¤Ç=nÀ@.&§'0]‰Lž+ÓšÚˆ‡3áuaJ¦2õô'(UspÀ“žø´ÌÛÕ1PºcÁœP‚mO"ŠrH7¹™#G1O".<§:/ÕaP¢$ ¢Ÿ0ÈþP’Uý".ÑèT$hd‹ðI#vøg"¤Ñ0‚´|‚â@ÿ¹;´o1A™†KZU l@! P85P Š0Aøê0•EdƒZ óV¨…¶¸Š/êb µ*È—¨ˆ+K¸G·¢„ Lƒ,o¡–EIˆ’ò›©Dœ@($°0÷˜ÍjªÈ*Ò h€#¶b$È”¸É“11Š!Ç8Æ€ ¡Úh¢N`¸cÀÀ—à×1¨cr–J´|Àøè¨xt…x‰zÂ;þáƒMc8røÈ%€ƒE.*Ñ6N„·ä€ª ‚&þŠPH`9”ÜUŒbøB°ÕŒ@¡Jð H¢e’w³ñÀ–‘›‚€19Ÿ]®=\ÚkžÆTÌ3 v™Ë¤ãíüäÌ;å)L±ûR•¾û]eR­j_é]7yÀ# Î!ÅÃÈî¥= yë̯~!5‰ x žŠŸ¨â7#8‚é⪺ʶbë|è‹°ù*A¨¯€¿ˆß¹*„lœ@€À$(ñ‹Š‚k1Â\¬õ-•ª ‚eV‰ù²>Ô.}‘  Ø"Q$¢$¿0B2𠡤¨|@Rµ¡‡„X P o<$ ©®“Ue:1yÜ÷˜!XEÑHþ(*1N4«s„3Öø€ €)ä s.µÈkôz%wŒÜ-¶5 ˆ¯°é2T˜&X„P&vþì3/í“J6ž–00-áƒ`U°!.‚ßÅÆØPÄ´ØÂÜ`†kèÉ©dEB!3Eõ øÀm„ …jhÛ]8Ý9T¤ „JÄ"l:eàÍ9ä¶å„B‰i¦X•Ø‚*ä  q ‚VÁ;W<8 ùª„Å^ u€þ ¯„1$ÖLÁÐxàÑíà#IQ ppà“ªè´¤° Êj µ 6¿yp˜6½^»MÖà†Þ²á¢ DÁ+Šƒ¥,‘d8WIŽ[ÇšûË7±Éuنݞ¼”¦dsNMÈfÓ{¦`¥kÆÇ—Ê$5·K»ê'þSÜU#·‘ºÙ(Þyÿ½¿sû{]˜Ny›?¿ÎƒgKt;*a,C~ŠL4¾¡ˆH˜@€ÒèÖ…œÄÄÂá‡ñWå£p€1 /ÑaRñaAB§RA—Ýbr˜"K p³‚²Ò>T '}ájSC‰‘oÓbc² óCÔ@ Ô`|a ‹À$Ãt\° Э uyÀ•€"…qÿDٲآIfÅÏQ2e×Z9 oP3_ñhu—Wîà=S'{çî`FN#x?0^pt¶Žò;NðqÀ€Z> { {°yÁ°yWð‡@þY>`ZY€7 €7Pã §p"à{P Áð"¡J‘8%ð¾V8¶w$¯ °ô8S À\ªÃ:›Ó%cò:̦ u%ÌÖFÜf Üæ{•£|§cMØå9\r}ud;§³KT“3…bŒ…r(Ýä“r~ÎøŒÁÕ3*ò#?µ ™¡sÔ"A"ôo÷D!·Ø&Ø7- u°Y R˜`‰ ÞÓ€q¿‚ #D(.G-ôØ@ðX¢pF0+Ê ó`ŠÐOç3{G.M‹€=…‘Tq*,µµ ” ?Ô€«@ “# àƒÐñ´þ±ÆAEª 0 ª òHs²Ò6 CÛ° LÔ’$3…¡@ÿ° Yh—RÀЋ5&0yò&s²P J4?°~Pƒ¢<1ÐJÿàp…¬ äðÛ± à³0 0Òiq Ž—- SVä>@j›Py…ˆfk½ã‰Âö8²÷‰´7»(P ц¢S%ØE™°Ã:š³ÈÆ:¨Ã&ÌG}ñљ˔&‘Œ¦émO’;U³$³Œè&lÜt(î´éŒ|`”Ï3?#„€ñã)ÂP tq€dÐ6±ò QA˜Ñ Ý€Â`ù†qêHþ C#(.,7ßð Ͱd0 “ Ð’KQ÷A˜°@ØržN‘ ùww‘!ÉÐ-æ9dVzá+}щ0ÿÙe@”@ &1ƒšÁ!¿P*ó ÁEQXYZà± 9À!Bf óXFPˆá$“D¡`Z·ÖvËSÀ”…mÐìAFí‘gøh4=pr…x¢nDr30wp5à "w` CÊ 'pq0BX°KÐ5$B'š7‡J6pa Áà–9Õ@˜Œék´ô‰Ib{´ôJ À˜ »×˜WÂ:º&°;zÊ9Æf:R þ'¾Ä‹¦)¨É^ååmÁšîÑ3Ùw˜“Fn:“3:r_‡òhµy©çĺÙSA+3ÁPÐ ˜&0œ2! ´0B8Qx'QÝÀ©&!?–qkPl1SÃySõ ¶2*gá-çc7ž…Á0 —:• Ù`«KaPv VÁrE–qÁ6ß">xÁAòàõF ›Á?NÀ°1JV_G¸‘ y³€7( ÒPañVÀ0ÂD%Z' Rà *º<\È”ZÂW0 X­S£y4ŸÀL`0_”_»ózÀöÅÕ°E—pÀP5Ð ¹ ìB"Yþ9  Ÿ”6À f0$`«õ5kÁõ¢˜$I¢3P¤SÀ¦¾&§ŒyŠº§{xpu2L³8^Ò4‹}Š]æU}²Kyb™]‚Rk™Âȋؔ}M9½£^:ãMÇ3›˜º¶˜Ò ¹éœ7¦U?Þ¸w!­Ç+¿ð,t€ÀÉ ’† hc¿BtAÛhQ,7-çy„7`r Ò0ĺ@ĺ-ï¹0Å`éSAyQA¶‚.ksrwQ ø3žqAÀ–Ý0Ê’SfVêf| ÚUaö“­€¢°% > «  –ª)è ðÐ_²Fþ!0c°'8°XT‰=Àeð°M´y“Z ÉÂÝ@ÔðSu@7€¡°Q¡±`Z9`ð`j”õÅKC2´e;\Aòk¬d < <»{=óKx’%Ìö:W½¾$MÓ–LÁ§KÀHm¹xm¶˜]p‚:I›¨Q"¶Žó¿$<©îu_ݤ…Q~lûŒÚ` Ô€¾ò`*¿Â·!d*É>‰à=€1‚}! ¶0¿`ßpeñ d>v°Þ#A@ @ˆwd@6·.’›RÒ@ˆqž‡áOI.MaŸyë¸å’K1d¨›€Ó€&B“` Ô°úºf!óZY 2Ïaþ¢YÀ—0’jÓ!+Ð Žð“CeNT-p¢"€z°¼+:2m£×[•׫8Ð=Ðf\ÀÓÂ!‘PÊ P@ëë¾+ ‘'¿› ¸ð3™ˆ•U >â³Fr\%ﬤ8­$ÖphzŠSð¦¸d9]{™¾g4wBÁ•S|²óKˆ S[%]ÒÌìµíñ™R²K»h83¶…K& 9„i(g+l†b(ÜÂîœÿS/«›o-Ç+!%­gažõxS÷>¶ð :±OìÓPý4¯g¶Ä|±Ðâèa'`R'µ s@‡@“[6©-6IrÞ"P(+k $d{þa+ÑО(µR 8­3A=: Ô@ 2;Ø’DD2c•Dyã–w"½ñƒ«át‡´þÀ¯‡¨ ûo: ìa°yeF0fdŸÜ£ï ,€6 °ÕØÐ'ÐÙоª†¡) ÿðyÿ0 {€Z+‹7ª° E K#ì¿ýkŒs$<@À¶g{Fûg˜£KRËmv ¨ÉdÍxò%Ñ¥&ÞuÁ¥“'Ç4L„=ÍlµaÎ#×e«}gÛ(Úg± YWíÎì` 08  R!ãÝi¶` ±Â>Iß®ELpáCójúP¬’{„鉭 ³ò¬Ý-“ ¢à`±IþˆÆJ¸-7@¾=ÛéâÛݲØ€S…‘ Öùr?óÓ¬K å ëš2Áᄸ2} à |ÓH,É1="§àU Ð o¨_ñLm:Oé°«£G¡ OP ,€ïà”À`.¢j9@"ðÿð–âáàP“ª`‡ À>0hà:3EÊ#À€×C[×{-{¾VŠŒÉ\ÜlEMQ)Ál2&²¨±ØmD^^¦ÀkBšÊd™Ò¼{‰ qºšL2Ι^Ǩ}¹œÙã£èÔàúå@ çû<÷è*|‹Ä~ñ+âÒ¹}Ø0 S1Ai‘Ã:ìþŸ9|ÜGˆi.%äæÔ6ÇÚ@Hr”‘)Së¢pMņAÐ íè´º·B=à ]°1v,O”Þ9 v'’7à Û ´± ]ã“=IIšæl‡”æ7 pwWF€7LÐ#à†í iµ¹;5° ÐEÇQ €´áY`Ö>>ÐÜM ÕŽZƒÔD‡£3㸷×húEð[·œ$<£\Àp¨Ð]ÂçÀBŽØ=ÍÎ\l’¹Ø(` ¥Ùlv"•Ö(Œ9L¢Î½£#E¦˜Ë¥!×:²ŒçfN^æçÄ0È)AQ!|k«}¿²6Þ".þ¹6ü'ÛŽNC¶‰ÑÐMlQ@±"é?ìp{^ÑTœ €ia‘âb4´@25‚C†qGx*˜Ûú%”  àéKEŽ˜Ç¡DTEÄÛÒ¶±С,ÛÊÀX”E©+KYZpx(*K«Vۆ嫇¢Êª¡C÷¤H‘#ÖŠÜyöÁÖ;GŽÄxp¤)ly\xvÊë” À+8ºò PGÉ]¼…×á=œ¸îbÅë+ÑE¸0^]P( þx°`¼ƒW¢ ;eÝ\Ð ¯K:õ“OxXyâå”%Z·å‘û'½ÐžM»wìNœ`€Î €åÍ™ë„]zH'P ²¡¶h&L|ón"î&°‰-Y2 &%ºQ'™‘õFºÿšök¼#uê( ?ÿø[cd ˆDê&‘5ô[0¾:ŒÐ¿5¼¿ˆâÛ°Ž úP”ø’IˆE¤p lä "øóð†DŒp0šE¢©Š 6 y,8ÁˆXDÙF!Šª"”Cš`€*ÆAò #)Ú†ƒmv¹r›"9 ž@¤šjš®ÌäJ˜ë. ÀÁ þJÓL9¥„(bY‚ª¢²På=s*”,rhâþ ¡X¸£7k"àÚ곎¸ Ê†­)IJS`Hó /ÁtÌ2Ì ëk2Ã{•±É«ë°É*à Àà@AË\l¥•P›"bUCv8Þz›m¶Ö\+·Üb®ÚÞxã͸'Ø1®&ã¾%sNqËj @˜_j1ϼòÒCy¹+p‘ðh\ˆ5Y›_~¡7™ÿb”‘àùCØC!/ ®Ã»÷8TxÈîùðˆê`øÆhÖðãh6 $ˆh&ÔpBúòíw,^ÆÂa¢g -â"!þƒølâE¨ V(¢È.šÒËVB åŸdx ÎqåD' .p‡ÚŒzj¯o2΂©–Èâ¢ô|* ¦sPåŸ`&¡PTgkžˆ+·±È´ˆP¹ºƒ«#ø”︶:bÔºüªŒW^-ÛU0^%s51Âlm¬VÌ S•¯U+ó5ô^+«<´ÑEÖ64ÙR¶¶ЄVÚe_¯ö·à–ÕöÛÜ¿ýº÷›±„jºQ÷óÎ /=î¢ñW˜iLXƒ¼_ €âc€åÅ ãAÖðÃ#q‰ŠoÀ¸B»¿ÆøŒ8Â9Θà†6¦¯»ôö/(XY` <Ðr´yþ`!2;2ê ¥ƒ$ä Di“² $!$ i8ÚA´D%¹c X‰S¸|w¬àífèA 08‰p„¾³D6²'+é‰*9Å6rà¼ã>HR(8"¬¢7HIYîP–Á¡,—¸@¨îpÀM‘oP¼€h&Ã]uF/z e*'™ÌÙJV§Ù"ö¢«»øªWœÖbtqÓuª±ÍRr›jÍÕšVqúH›ßä†Ãù "‰sœ6$N°D„'(ø«]âÁ^%M0 y8â~ò“ä± dËX|±ÊD¬§>ó Y÷ê` øäBFXóŒ€1¥þ |[ßz&Äž|È@É0O-¸×Ê9Ș‹8Ë`ÈÐJÛÐY+08:Ä›jKˆ@‚-‘3Kج‚¸B:’„%xÀX3< …î|a„R¦(>‡‚!¨"8ü8äШ”°eŠT$0p‰7\âN´”=Þð•­@‡Ù‹ùÒ+Vc/(Ug:c¹X&1Š) Œ¡6бqtUJO³Ó;Þf.žbÍpôˆ-Üð&+(‘ !©ÈÞ°cZNÈ–Gð9B'Tƒ“ Æ´‡<ïøË_ƒB~$–Ë5̃DÆ{z”©Ò@Ñ#¼ÒSÌc†¬þ•Ë\Pìõ±EHcuxÈ=TJcúgú:f‚rY¢:ì"}«ŒÞ3±q‚ Ù ž¬$´VAP"N$å‡aJ•ÀŽ€IjSµ VJ`©"ëµ°—”Q%E‡TiÛ?À¡ âª"â@&Àƒ×EŠo“ K¦ú¦–L]Ê™ºD Þpψôs|ïe‚™`e®r°êŒHCÊ™¼Pî¼8ÕÅwŠšžÎE³i‹P§5-á(kv³1ä²9Üö®N,à5„¡=ã…Ç«µ`׿ܳ¯шDä᪠ô•ŒUûZ„1T G/İ´Ðš‰0A@þy½C>ÄVúÓÃ!3Â<ú3cŽ'=1†È|˜ŒlDCG/;Á :¡Ùk2ÅÉHÊŠBAŠŒ3hLÈиP¥làBŒ,pNJèš{†ùk܈üa¥,8…(¼UE,0(ªTé¸TG´”å’*ÂX¸¢©¸Xê j¹ƒvq<¬‘Ai`$½Þ`ÍʽqÌœ÷"iÍ´W¼ó­U¨1]+ùšÆÔª)Öžåk¹f¨­Æ—%-ß(‹ÕO0snµ±ëàa!¬àé*õžb &p}L aï^..ÐýòÊ èÙȘӎÈzViáºòšŸÊp¹©¬Cþ°kŽ dž:`l–:æ±,ö5YEgƒÆÙVH€HRˆÎ¢T‚¼ Ùè;rv¶sáfrf½¹§*JØF(˜Òf!V<*Ù€„5xÃÄ‹R·+jAypQCÛ2LfP^™‚·¨Zã`ZzÏÜes—‘ܤYUÏ4˜£b\JGÕÐW5£ *™…’üòà²ÖÛ¬¯uukñ·77S5X@ h#Á¾Ö$óDY s'7ZðÉ@tƒw8AâÙ¹‡yí:‚|jeDcõg±³,0Q9¡l¬!ýÁS|Ð-"T>ìíê ™ø3× QXþD6¶¡MpöHrk Îrv¤RD›UàÀ;–vÚçÚ'ÙȆPÞì”Ñ/­Kù}SZ¡§X´K"O‹É¹òæSÔ˜œZŠ`0xØÇÕ«iUÍüú§ò y{Žº(ÝŒ=£d$“Rš‚F ¢ùÌ|sjúÓŸê ëð¯7®çÿÖвµ®ë =µڃ'`>;³c_ã*™†i  Ü{Ù€_XòQ¥ûYÈâ°fŠ%úذd¸wÛ¶ ™ô¡Y„õ¸‘ij˜:ˆ…•iÁXø]‘Êûˆá±}y€7–©P¨  Ê;š ª œþ¹ ÕK¢q„ ªUè䩪 mH lðQ8"a š¡8…~=-9…%ˆ…N)p_H€°•;84`>_Ð(x84³x® xƒ~ À¾}Øc0™jDÏ!ÉÑ45Š ô#ŒËA/œ–K«ÄË8 ј‹ÑÅb!Å=B5;Bµ«SŰ*±X¢«+ªûJ [Ó£Öпà?*À., 㨆j¸+ÐØ5>‡óøQÊé±$›lX„yX1‚öP;@i¨¼%Ðn”VBÿÀ6U2ÍArcñ˜ ¡õˆiœ;œ±òÙtó0úбþ ±‘r;…Ñ«2&t Ôª ,ܦ r2#¹ 4ø4˜½‘p8^¤H†c e¨-AC.À84”¢8³Y30IUhp€b°†Zœ‚  ¨7ð…Cã íª>_ð1_0F˾š[D“jÄ.¢ŒÀÀƒžÓŒð¯Y5`1#•úË`¿O» •Eû2Ö0–Ô #ÊŠWŒ‹¸‹«³º¸°‚8ËXSE¼!œ²D¢¶$@±ŠÔ倪j°`=p ¨K¨_‹ÀiØ(€°é‰0lxÆOò¿Jï°…UšiKA Ÿøhq±‰¥ ¡¥©¥}QþˆA|ˆ Á¦)€50Ì£‘5 ˜‡ZØ€E(€i¾Õ;š â= Bƒ§ÕkÈ kˆÈŠtÎÞál¨€%#7 …q¨8~²!Ðk¨¯`¾K!Ï#xƒç«>æ;Ï«q‡}h„ìkDF„ÄTé I£©Í@¢óÄ3bŒ£ËÄ–zŒ1Ø^aJ»XºS£ú¢=rÅ%Ê¡²:¼K±8K´Ì¿ü³ºUK K'8¤o!ÆjàK¨Ú'ÐmØaˆ„ +ï«­’ñøZb˜os%[ c¢rs¥¼ÚÌ1‚pÄ1\r%qìLXÚ¶¼*7Áã°þ1c¼^â¶l­"·rL†"4‚€Ü…VøR'cŠlª8p² €kÂäˆ*ˆ€;¸­ç„S9al˜Æ8\-pŠ¢ εђ*q³¢8®7 º7ðƒíšÁí2ÏKÙ.<PE4† „U (ÊŒQƒ•Íy©—´)÷B©V©œÕœÖxa ˰W}”iÁиxU«»ƒWK±à¶È/t ^„*§ÒKjq*néKPŽ‹ä‘e %Ø ä*~ÁŸ-†ùÌB,û‰«ñèÌðÕ¶é;à0з·Ê+ih{«Èz«º‘ðÀ; 1ñ°þÅÄÑ*~!·y¸[‚0mB#Ñ,”Œ;XƒhH)lÈDùƒx7Ó‰>0¦XÜ› UÀ=UÀ&¦É!¢Ú: @ã_`…$p¹7ˆê+‚˜õ…$€Ù@4 {0ƒìS‚ì[ÄE̹Jô LÊñzŒ2úTùC£Wù¹_©T”Š/`ˆ¯øZù’•9J ÚqZÝVeP°[•忲ÌÐ PÞ°E`ýªÊ–¤z¼ŒµØpR(Ìeë*cqùØ}‰¥ÎÌ¥ðÈ—h¸oÕŲtRîá˜hû˜´eÓÑacš)íe°á1þi¸Ò àŽbâgņ5X¦N5%-ãDˆäâ€*è= ÂB"†ˆŠåÝ2€h¼(Àaˆƒi¬€lXpÐ+ ÙŒk37ã "ð+Ð.˜…‡#€3¨>³H3˜É#Pó´‡~ €~Øw˜T8Z5ºTšŒ÷}£ùµ´ºx?ÍÑPs^9Êëà ðª ]¸¾Gµ‡a  0àa°°ZÈؔð°†7°†Wõ›°¸U ¾º®Å`¶ « 4UdPX|`ÅŠÜA‡â0ÙÉ ãàa(ÂÅžZèܽí`š…9xAxIžñ×ä$ Ür G\jþé°VGtM„XCá×ij—_à‘c«—þ9#È7,¡Â3`àáòØÞ 8¦ù#b§Þ•cépj… j8Š…5˜N=iCl⽊£ª C >L_ˆò½Þ˜Y_ðV`ä#ÐÙ~°‡÷”GdDET/I‹ HÃŒ¥dZóS ¥…Àð_IË ™rT%˜nà†˜nÈåÀ…w˜K˜£R9Œ ÜðŠ ¶ŽòŠ@S"†Wähæ ¾P¶ÌÐ.ÜÝ¡DJ$«ËKÍŽ_©$[W3Ýabïh°ô° øÀi\þÉQ[˜«VÍÜ—éž·Ò—#q”†oƒô×ô° ÒùxÒ‚E˜è1Y0¶EXãђ`và(¨"yCX‚1ĸ‘I–^P7˜É¤þ阅Ù$p1H‚ëj pk28X ƒnX v2@„) ǃÏZ%a¿vÕ¹ök«£¨Á¡ñ7`fþëݰU33Žþ8lãp*+8$vÈKa­ÜA$tR½{ÕѰv”MìP…)+VW;Ì hö(}Éa‘b¶ÊïH<Âb³ R»²þ¨øˆ@·Uâ1ïèxþÌÁÚYx»(í\eX„ *I-ƒÔ¦&”›ŒÓ¦,ÈÍêÑ;:X®I'z‘@m@eèK°„ ùR…äÈQuŒknS—ÞBbð…’;‚ž°ÈK–…Ë®V)·e‘Ðr›Ë,­bf¡“…C–›7¥ÈIòæÈ‘ŸGйðàH {oÞøñÃŒ½5Ú§þÏ%pŒé 1¸½‹%Î"qâàz‡kØ»a3ìɶî.^xï¢èÛWIßu~Qè’1ƒ›°ÄgÈ,&C&H2°!º…ˆÀ­[‚ºs7A‰À.=x0åÁko¬y@ô§µÒ®SËæñÀJkÛ<ŠÄ¶rGö;;:)ÎvvK7·xãÍÜÕð`íµwuÁÞþvÚwœf[¸ñ6o¿ÝFQ¿…ûÀÛú]œÄ·0mXѱ†ûà‹>( ~ÖPÀÛÅ›2Ç ,Ðî åðMÔØ€:¥Ç=kÐ}„2 égU«ƒl…HL#C4º¡ÑEÔbEóŽ„Á2A(k0AV”ˆh +bOd„8Í=J}$Š%ˆÂkØ68¦±dÜ Ê𒜄6²‘Mq‹kC¡¶4øC“`‡% '<€ 'R@ü1†œþs¬¡X ‘““år’…:Q²“œdå$©“qdb`ÔçŽà“7Ä toøä‚RÊ#\¢SHì|…‚F ÃÉHÆ7~±Œi4ƒ—¾;ƒ$`q†eHâ ‹‘Ç4°WQÀäC¯–§+]†¸àå`™nDF2Õóff‚à½ïM€¨V®@îàLá[§aÎåšù™ï5ócMjèœØ4L8e*ÎwšCŠ æS:¾1 Öâ7øÂoP€Vƒšˆ6T>qÚóÀ;èë ô² ˆ¶ž_`#?c¢(à³®9Mið7± ‚ ðÅ%vã­vÙ¦S½þ²Ã° VÃ7Óa˜j¤ãšéD´¼uèõ††ú‚¬ðC_á _b³BxØQ YhØH¡Æš hãºÓ0¢Ëni’-Sƒ!Ê °iü"T ¼x¡­&¨gHCZˆÏÓT¨•¨DVËØÕ@ä"÷Œ¨h7(@’=lc/bLHi`ë“̦$³‰lEÒ6– œ€ YÊÐWÀÆ+€É ›ÿ ;P¼AXC-ú=XP”Ö‚ùB1\$Xå¸A14”Ã+ÀŸ”–\À-…C%ÜCYà ¼CÈB¸Ø‡ØAˆüÂ7(‚-P ‚ˆÂÕp zV•‰  @Á‡Õp ÏÜQ9äË`R}Ü "ÍÓXQ ™AÍŠxš2t¤Í„ÜŠ„X-ÔBpÀ¾dn"¡ÕÑ8LR<ŠC™þPN¡t†¾¸KsDa‡¦ €á¨ÜqÀèD$A’<Ö%…BÚD(H€ßY” g‘£øÁ+4Eh‘RóΣ½ XC ÃîЖ© çÓ[ÒV]Óï¨ZtÁB<tC ÔÀÃixa´d$K÷0 " Ktu@$`%@5% ‚xCdêi”À0 ‚ÅÆ·=ÔjDŸ¤­O¹U_àÆ-ºo´ºf­£ôAHÇ*dªtãqrc`”-X1|Ry5š/ø¦B-§ƒ5Ô4–_ƒ}cs†ÖB£ƒÜþ-…ÀXC€ DMˆA¨Š"¼þT‡HMlj !™ ¸ÇËU¤‘!«}<„ì”-ŒçË%ÕËI Hšœ>fd|,B@>•Í Ф Ä£Óaä`CÄB¬Õ6 áÚ°‘½…Ɖ%©‚@‚™V.”6Ì ‰–èE|„˜uðÀ‰Âb„„ÄtZƒ/¬è)øÃ)ȉSZRS6åcUÎ6H%K¬á&8…çJ82J 4 °Bhíè¡Ä@<…==,â©9©"òðª|ƒl9b#ø°C \‚µ W®¡Z¢Ô©8öhFÈC$hm°hC5 6ð5t5 Â$h—%èÁ^*/þâ›Q0,šÏ,’Fià›½}QØ[/Ž °€à̦†*\*„-£ Á‚…*+Dã§¼B1Àí{Ýߥ*9CMî LÀB-gCù¡¼ÂË>.\£-X|ñÀ*DÁ"¤È ˆ (üB4¸Å”ȸ‡‘iL‚ˆàÒë4¤>ÞRÏD«ƒÌ‡‘ÐPÌzR¤ÕU‘ R̓ÎëÀTYÕ»nÀ˜‡§íÇDƒ2@ÛÐ+ÕeYZMKÂeAH¡ä&+<ã*@lÄJ„°ƒ… {±ƒþî/E€½í­p€p€?p€(°9%ÈVA ÐÝæþR†hÂO”’OÌá£Ä!éRš.‘*€nžŽYÎ@ôô,”ò’°ìR3ìN3UÆe\.™«S€Ï95›µ”†%†©ÔrSdŒž8á)%ôV±°@d: ‚6PLŸvÇ^&0´ot öɆ·ågÝÁ»ýĘ£f¾Ag®ÆifGüÔ&)X©²Â2>£/¼±$`Ô{œ„1T£µªC=îÜêýM€&øÀÁÀŸƒ‰Á¿5ç4^ ó›ÁX€ÀŠÈÂ"tÁ§‰œ-HÈÆ «<.•‘ÅG-à.R%US¹HˆpÌ~ ddH‰H"¸n ´Z¤Õ÷ºþL"ÔøˆÐÉœHGÀ¼" üáåëJ^]p€ìãjeª²À,W„XÁXõ†vÐË7kD8G”ºXƒ*´ûCRJ°åPΞ`’$ñ] 0€„ã+iiÝßý1…/˜V†–ÀjåBÕl?à¬5X±ôìÏö’“öÐÂ4¨Ì/ GÏÖtÀD‹C èBL0Å+q10 C±T÷Xmžv%X hÃ÷-‡¿<Tàé*î¥})Ÿ·¤—ò-߈eÆÆj¨c,²ÒºÐÙi¼fÀ@”jHcCÜqXý9ãú ÈüíÁ@'´ß4îÁ#þ¿B$¿4ø9¾Yû[“äfÁ‰#߯ Ä®ˆ-D Q2£T‘Ù Ê8k,w+õ:ï‡aÃ7œÐïNHõB/ y y}”ˆõöLF¢ˆE«ÒÊíÌÒ Å9Q-ÈBâ´ïƒ¢ÝëÕa+p@@‚Cñ[ƒ¹Ah_:0 nØÅOš ppïÑõå€Ãûƒ?ˆBN<åfÒ% Ú$]ó~9.VZ¤-ØŠÁüsËŸxN‚ÈnùÐ.â4Ð-4@$Ô´X)L pK,"ø8Û%ÎST‹.¬Ã0exÏè]þ"ä7 €Ç»…ˆéNÿ’í$‚„†lôex¥×õ-_PDŸµ¥W´ñÆi´†ÁÌ»<йqq.Å+t.¼=ƒ1²¿\CÃ|Á#_AêBƒ ì9Ü?[Ú?s.69ˆ€]ƒnù¹9@Ó—_„DdƒdƒSm0ãÜz0•‹yvаò‰P ”½{¬Ø|Ô‡± ›;Õxz6Rµ ­‡X•õº‡O ¨CÊàœGƒ,hGRY¬Aú–aJfÙÆIø+|jü¥*¼aárO„¬‚÷=s¨ƒsüvó¥ÆÜ„t'¥åÐ&VßU‚!¼Â)±þBÌ¡üÁ¬Ì:^h‘.þ[ÀÅõWLÃ7•êpç™Z$DB kD›ÁÜA )È%LûëàŠ¤…Î$5]„cF—~OD (Ǹ•†QEiøK¢¡ƒ¸wCˆ£ZŠ‹»ìežKŒñi’F;Ö ÆØ8÷øoòæoNXÁájƒí6û ¹ZCÃ8Ø@Ã&l‚¿!99ù!¿[C2]Ç_êªõìlÂ[¿Âp4ˆÀ?Ã#æ*ƒ,tB/»ØšÛL'Xà¹&¯JíT4hë ˆ.äœÀdÜ+]C={ìT¨ø˜AvFÞÈ ÒÇ‹ÀÖ³þºÇÒD6Ô‚T€‡IXIÙ°¥g™Ö¹äÈ2À!œµX3gçjƒ7‡::¬[1,#ߘøKªWÄà³q¢ð%ë­—ác¡á­ï>‹¼ã™x7…à‰­’Àž’o’ã^êjRê¹0nY8)ˆf耎l´O \I$ 5èœ4PØ¢=”5Õ€<ài´\—7È5Bh<¤EäåÆzFÝPƒðÀ%Ô“Á| v”ÀQ‡‹¢¨F(q¿Áƒuß>Tä[nBØ6"¥•–ÿÀɼ#ü4ç¨õ#“@ÓDŽÕ› ¬^%¼ò¦+Väö¼Ú³‡þ+7¬&B{Eä9h{äá(š&9 A²BÓ'ЬNÙ€$K¶†f²Dk­©cD§™‰ÍŒmM"iuÕQz´Ž5&~™ˆö‹ê/lØL,úÓH"[RY#S©ÌdK•ÞäsMØEµji…dQ2ò„mÀ¶Æˆ¬E}Mœ0adQYYÒ¤á¢Xq•*­·’ì˜2e.’[eá  «bD(¾rÈJN1tP§V½šukׯa³®¶Ê¯Ú¾9bíR§c>\8:+Ö¹pçÎ *Y4oÛ–ez–PÛBY¯žCÂôìÖ[{u„|Œ#oÞIâP +1~|™‰Q0F {þýì]BŸÄ‚$V´aAže,°™f6 „+ްb€ò.x`Šœ`‡H"¡DtJÆ—7b@ï &&!‘[`Œ ˜¢Â p¦Âxxâ‰J@@‚°Ä Vy€¹#ŠÐ/½" ,"9)§àAÉx«²„)°„’K(èÒš"¬y%Šm‚W&pã ŽFôe7¯XS$Žö€Æ‡$*È—(zS´ŽÈÑ@<‚æ#ö@ˆ•Š8rà ‰öÐd"Ð"E£˜¤Èi¦šƒ¢ Œ( #|ú4š°’‘æ†¥ŒBË' ¨ŠÆ„«°™ a"™Æ„Sg2¡–þ¡rˈP5ë,¥”ºi¬d€¶lË„i&™D¾Š]› é$mNˆe±4ª@· .ƒL²m «"ÊZ¹¬•m8à€ŠbŠ™€ˆõ£bH!ÎàƒƒsÂ4Üè—•¸Dkú°æ „1θµ'V™Á—#îóŽ²Ëº“±³.”Pr8ùd:B'‡W|Q޼#ü`EÔcÅ1ÄHâç‹ÜZ 3Þð% þècbmøæ—eÎX¦E°`Ák.€§à‰A¾°%”á`¦p y@©…@J`Ê#°œ`žÐ j‚ÂÈ'¨1o 3L.RþH «A‡”; óŽóp#¹ˆ­y·#vFî +瑇;Jx"Ì*°“1&˜À=&(Æ99Jâ<Ñ.B(ÏM4Ù¢IÓt¨$M,h9ö^4ù´x÷C¢8båŠÝ¨û‡m+&ŠEªm‹/ž°©Å¦:d¢‰&¢Œ­£€£Aê†ûë ø—ÊVª–!Œeè$ü‹JNP…ª ¥}3IÆ«^Å÷Õä-ü#Š ú&¬˜`,8Á†2²q= !ÛHLº,Ó®Èe," ,Ф  ¦‹]a½*ãÂÈh&œM¥ö@½èsVЃ±º1RÔî E´/(¶³f•¬­q‚(÷€a‚ÌÿP\¶Eë  ^Ò EXähõÑM”´œ-E€O€†<,i]íÃØA a4cÐxP{xMB8°G„Òx„ ¸cG%@d)+A`fHz>²;Ô€H膋"Ñ !î”\J%y¨´ÉÂþ NØ›jÏ3L$·7E@O› Ý´*àr—@N˜Æd ¨.‰wØ$+Öt‘(*O M!¢‰BxÍÛD9‚ÎrL„‰ž¢ð»lâ#¯TT‰(ìE„PHyGÑb4 4i¼µˆ›Ì„.æ3iC‚af¡´Ò¸‰­ Â¿oLMA€BWf S±D£¤9aq…ú—S+Ãk˜Ç<Ú˜š@&·ªé4´ÂbóԤ胚ÐÇœ°¨‹q×c*ã®{A'"pHT ,Š7¢"äÎH|–ÔšÝ() i¸|ƒ•x0Gð:4Ш/¦æD߈€Æ†€žò…â ”2'¯y's^ªRÉ{… ¿@`G]“"˜ê>£pÿ¹ÏŸ|Yƒ-ÚB>÷9°+49èœÐdÙ ¿øñ4„Qâ_°oÍIX&˜Ð '£Z3yèNN5– eþ(kà8ÿlÎ⑞ }x‡À%£]G½L»â…ôí´à’RlÍ*€lv";Ðp'ðÍv¾ ­aõ/£ƒÚå¶³û0p¨â:xv;uîUP´ tðCr|1k̉á qTf¹œk¶øÀvþŠ D4 q€ö:QK|5, ’kbR‰ÖÎcsŠ/9îàì2ëø¶&b(G.!9à(çúî ¦ê©à)Ý6á¾D¢yæ‹Å#0#®iöKÊáú†ÒâI 4ê™éMHàþònP|a¢°6 œ uNi.@2ï,—ã ´Þ.a9ЦšoÒ&m˜HH¡2-”Ðau,mN ó”B:M»€ër’ËD$SŠ.!ÍœD2ÁŠÛ$Fú¨+dÜÉþìêäQÊ/x6Á¼ê+!<‚QûK¿â›ê+55Aþ` bûþmîP,"Þà"^! Ýþ@"@AØQ àY*Þgá~âSªE+p…¦šóÑQW,ˆ*¸S¡ bƒø§.DŠ|è¢ÂŒ¥¥lþÂYÄ‚A̦¥úÇÉGûàþäàÑE1bð… l2"#3ppTaØh©G±N$ä Æê&  S¦’:.‚_xàA!4cž@» ñv¬mD`eª@‹²¨(‹²;$€î@ö@‘’ëîÌ!Ü`ühæ"®É!ŠÇ©ïÜ(ë4°àGJ F‚ qp¤ßRl"ÄŽ@޶D­ò®ˆ(à6ŽÀ¬‹´aƒÐfuz‹0{ë|¤‡ØÁØ.™äºxF7@ÔDÀJJ€O—fÀ·¦f¬‹ÛÆDJÂdPbýÄo:£†€Gðm˘{¢n"Êa¼þ‚4 ‚Q5¡ü2âÝxó´©ÎH"g 5O@5ÀF‚N€ "¦Ô§+êb(ü1ÇleZn¥ãN`njBîWó⦾áZ6`¦VÁ±B%(l®:W¥Å&¨¢Æb*úç*äÁöb¦:ÎVˆÂ/Nà3Z“¨@É#*]Sè2Œ’ª€¢n†þá#>¢¬ C#4ë>ƒOFã"Ä ÜÔŒ_3†l‘Û’`L$‰6Á‹NFn:n0^莮À ü`i~&¹šPî¯ï’æF9‚!ÈC`Ä °Â!ü ë|¡° f`;qt$•زA>Ëþ<ÞRJe¨ô ¸M`oÒ&qbªÁM[¯¸œà ‚Íóz«0¹d“Nà ¨Á®ÐD”IJd¹’K»Guz‰—§IŸmNG"æ0Ýö ¾DsªÊ ö "Åw® `Ì æM ¾È¡ÄOÞúî ¢$‚ ÞàÑâmOóR^!$ ájAj –5’EžbXMà ÈãjŠWM×W}U çq–AX9Žu¯‚ÅdbVfîÅÜå:H(´b>u¬oN  ÉgLŸD`è£1T3f:r  4À_â–œ.En‰è –Cö5ª¡îdªô©w$ERúþ »axàúÑìµÎã faîV†(öΨ r ,Â~!f ±."{®L4H„DTlàgÖcn§‰€$L ³óΆ-áá³ú¡>F ‚Öl.$LúÀ" ˜¸”ÛÔȧøÀ,œ ÖBjG“Ö¶•Ôæ…³D@GJJB±¤s6»ÆK2JzƒG”¤æpûàV7ïO$¯ ‚Rª×ܾÈáyNq5áÍP3ýæä ‡$â7ã¶œ$ ¡r£@2—Ų¢s) ‡¢¬Ât…!ù¦¶3än**’õ¦te :Ž­b,þæ!YlN*‚ÌSpBç:£4™æBn²a¦üøV¦….”!Qï0èüì„èE]^H2¸`$À‹v‹‘G!"à¯"k~#}aã f€$愆*bÌ܃`ÝÀ¦Ð—…c6à=bàµÒè ¾€ Â!²~+¡BШ`n&š€Àémd…Ô#ˆÈQêЮÀz,¢ oV¡ªáiG‡KÀ0u¤-)l6«ÜABÂHÖw& ~!q‚{m,÷ÙG$ÚG.„·6)HÐái·†rJ-Î|i©h‰©rè¸-ù¢èr˜Ã0µìMìšðiÞiP&âQ¨‡¾:¢þ–óÄP¢qS“O@%  Eà«QÔm¶çû¶ÇžE*w!ã‚(þ¯.ÀmÎÁWmŠW™]Õt­Â¦hÁ¡` ¦¬BsË1 òg¤°:+žåY;ˆ|ˆ….<Åš“!½¥ãüXáAl‡ôs¨’*2b–!Cf !šVÓœ4"À,BR¢P™—™™SCÀfçH€B_™}¡¬{5û5Ô  ¹f-|Á4 b¦Zи9rÀoß ~+¬‡wþÍÀ¾¾@ÞB!FD ŒÓ=í "ý ûˆÃ´¡XÀHUçûù6k³êãÜþ!„Ý!L´û b𝰶T f ´AmŠëH 'uìû×|÷ôûØ&7tãMdÀ$ŠøT»x#LôCP¯‹q°köxÜè BP á67¡Þ&å© áë+zÞmûμrTr—h^qÛ8ÞÈ záP BzpuQJ‚žÈ ¤@¢@°aWq. >¥-€ÀÖ3çZuYm*/j(0Ò:É™W£.B™<Ù'ä:çø‚wè’±z,ÒríWä1}jЀÛLÀaî(C]–L%ƒÊ² @nå–kˆà&¨.µeÃ늨A‚†–©A™HÐþ_Ã8²ða^k=~FGÂI4€ |àöhŠ÷ÊChàˆÜ°ïnG{ï+B#6¢På  ûy‡Ü`y 6”ò jÑÆỖl©lI9>ò`ÇeéyÚ N{¾Sç×€$Ú£ýרýGŽíCq ͶôH3yƒ7lñ|Ĥ¥Lp©ˆû™tx4§1{€Tó¤Pà+yVó-¥=—¾æIì]¥‹;ܨI5"&%4ˆzp ÁìXf7ÀVæúSÄ¢ èS ¦hŠ«££ø‡9›39‘G…bjXŽXj.¡TpÌ|0ù)ð\hBþ®;£ ˜ýðõú6Ár …éÄ0 À®—¤7·ß2âúØK V’ÑQƒú€všé‹¿Or¡i_©Þ5FDKæÃexÖòÉ È# Fn>ï .À?ÌŽ’ ü£w ÂwêKÞ,bN`4Ëm  ®hŠF nêzD†«¤·.àì£>6KB&ƒÓ£7 ¦`DdDìáÛ I¢õ[¢ƒäô¥]Ú »Šo—”Ïr’¨¦MùȤJ*‡9¨+‰j·!ިݨh>“ëkl€Öϼ$üÂSüeûþzþÞ¿fSx,EŠ Õwî¶¼4þAÇ!!,i5tQ®åZ%( ÈVj*¨âVª"ãANuEþ£þM~ o¢w+ð' ²ƒb 5 $¸(R7a‹ŒY­6lP6D™ØçŽr{ö#B„•& áBU9™¦Ê¶“\²H £J´ {®¹Òq‘WDt|Ô#4CTäT€4©Ò¥L›:}Úk†ˆL mç+œ³Þ 6¬Ø±OVùò¥À/1o’°bå'‰_~ŽÄhk÷ÈxoÞØ{à…7¾b¹ëçí«2¬èŠóö­˜#÷¸ã†P"_l|yõ&2+·£Y]馕¬ŸLáìÂÞ7fþÞÀã /¼#öb˜ñõûÒ”è.¼Mâ‹p_{†?áÁÃÊ×O”x‚ý ëè¶o×ŽŽ‡5_3¬1¯àÍ%x¹ôÆÚ¥"wÜ9RDÁ‘'Ú÷ïÏÃÏÝ1Þc4é4?i†Óg¬ˆ‘ØVíñ +™½ò9äüQÎ&½lBΚÝôŠ/nì 4šPÔ+{øÄ‘&+v¤ 9¼µ“‚šP!Â+bøò 4ÈÅEó¬ñM4Ñ$Ðó$bDÒ‘L"VÚ2-X~ƒÍ/^*ò ¿|#æ/ÓÈD7ÝÈ &Ô"f-µ˜„CaBžK&³†CVòéä"Lò¹ˆA‹ðþù 5 ˜M6k(3'LƒM‘VÜáKA”8mBE¡„’F©U”:N("@ŠN@ó4B£SP6nÖ‘"8`ÅX¾þêÔÖl¢SH(†ÄS§@²ŠÀ> íR<ô¡–5oÑå‹…jùáF\kÅõF?ºqÁÜMaM_—è•íbBÙW¼ $+ŸµÔƒ?>¨Ø²†x-$ù±‰Û%0ÅEØcW_ýØö†]1ÄÀ0oGÌ7: ÀÃpr_ð€l~ ;§vN<xÜ•°2wè k}Eô§ÝôY£}aÍ{ ÌôyEǧ€|E§ g½BSVšþµ¨Yi[Ac“h.f"9 Rxa…k9-BM<ù4o5Ö¤áZ ì¿{D&$‘ʘ`žÑØâ$ UJSGF$x"Ù±†-Ñ$iÂ7^z)¦˜&L#LÔDÓ¼é%6s®QåC™ É$38•L®^PéJ „0˜€6'@!éÊÔrB5Ö¸!G6Î{Åšˆ * ˜tê8-dÁ€!¬r¦ ñvä“‚^‹¸Š2‘âl´âCõœÍ{ìU5MÐ*}„?~üañàK1hqVþ™–ÄeI˜3Üe7øywžpݬíÚJd*¤HF^ZÉš… ó\Eþ . ¸ÅAéÄ,»Îb£—¾üF\1HáÄdÃ1“• !c ~ŠPÀ£ýHB ôS®æ 'ÙÉÎudÖ=\§e"qF k$ð„YEÍ´¤- ‡<‹bÏ€f¹ˆÁ_Ä 4ˆ5µ΋\ÉNäÕ=â1æ $ÀWcÜ$¯ÑJA8aÅȱ¶/ä$CÐp[GräyAÃr°Û"ê [HJ‘’C¦4%)%KÉ0ˆ’€À¸o˜àÍÀÝ/F 4QƒòØ6LðJ=¡®J@X„뀀º>AòH‰†,"‹Et!zê’硌E˜ "Ó˜”0*e=ôþM@†GÈñd|á›’‚T‘ƒ„‚à0Ä܈ !-(&Có’…¹¢«ÑÊrè ä‡O¤Hå ´ª•‚^Ǭcr˜ò‰P¦Ü¡VÉ–/®R¡\È ¤‹^Hv„”P;¬™BÂ(ðÈÀ«Žo™€ˆÞ² f0—€Úƒ¶ò.?@F2 Úƒ/î`$€²9ÂæR›7ÜŇ;‚ ÈU®ýät ohâúá‡v,ÀfÐËÅdP®é\GeOX™Ø2ðV¸„5x†Ã¾”‡gÐÎSŸ¡ÑÇ>x ï k`†(Ò 9 XÍ­{À 6ƒr>ÐÈt¦oþAßõB2"Á“)rOp"«œ¨¨#”ýÈF¢ Xi‚TÆn ¤dÜ pFȤàQ¥ÀîtÉ– ’§_,c’ûE—(' ÙQÊs&PÄçf¹Aä!kHÄ‘(%AW É]Ã27`:eV*¸ÁµHï¬ r”£/Ò¦†zÚ~BCì¥,4Ü È?hb‚toWp¢‰Mpeæœ@žÐø­Ì‡ìûXa”ê„èpBѱ ð$6Fû(4¯Ç¼E¦>, XK ' £;×9rÞ †"¼!G ‚ dB$"îA¬€O×¢™šÐ%‰Ì\䋌’x Äþ\(@±‰ ÕªMlî0œí\ño @ü@¦ÉzáX6ŽbgÄHtX*§g=6~gð#’™'DîKÒv×`ñfššV*ä–]sÆ…‰Oöø…›H& r¡hüŸ Z²2J¯£«ÍKyÑ+4Q ”Cx¬ˆƒ’[Q®¡‚«%UºKBÄüd4<Ù¥Š”IN¾…Â4~=‘Q.sPh.¬›:d—.ÙÒîtM°yÌÃóX| \nœàÚx‚:2êWXöED5¨ËÑ“œp³²Ê/ŠTdÊæ›Ø#Hˆ° ¼¢«p°þøZ&$³ù„'4!$ AP›ÔßøD‡LÁ ¦‘_ù‘Ø'†$Ìõ«^…Yu¨Ì øÂl‘aKbîõSg<k†H}ü-Ú¸¥.„ñXkÆ›SŒc»iáEÉU!jµ;<-B?|q2  oðèx±ºöçËGä(XÍ<âçøb]{±jFö7\B tO_‚¦0ôH±â)‚ó5—¸p°Bœ•ˆàvÎv$IÀŒ¼2þÓWLÈ&øJwŠ&DŽÂËk^-¢¯N®0Ykr rPAÌ5tBpAáryJêMI¤W,Ã4Îå •ºîRž°ñk(\~p)Ôtþ ò:*‘º„*j!y¡ólÇݰ€OèŒq6Æ ^må@!¹‰rÌwдêþPη“=˜óX 9$ÐÐ`†«er P ï"d%G ‚ÄÂÕ?¾"2mi‹‰®å1Ñ„qÉ‘feà‘ÂGyW`cc"Õö >å I€bê!SÁ }q1dÿà µ±Xg¡QÓv2E1MÆ0»A@@'tS°Dó1`e¬bBtw‘QÓ1øAƒ[ÅQ#¶OYG?o z124o0E5v@4g4:s sV ”.,g!ŒFS³6þ7rC_]³Fó²>Ô?o‘˜/—/‚A0ò’cpt>’Åà‹ðKÄ” u°y°Õ'T(«CL¤skµ6´{¸K°T¼õJ]&žÓ'PÂ'µ{¢ˆ #8kP(ŽH:°$ÂàÑ ¸s;Ü X€z€V°å Yäi[±Mèã"Å£ ½ 3’YpÓ}Ú·G""~›`Äb› õ–o÷‡¾ÒrP![q µ¬`é—ÐÂn€,T!Á}¡ïH3åfwàU

Õ:±Gr oDà ý–ª¿B?jáP„Ñ%§ö)ìãf8”øhãÁzR©?…`mS&lÄ}ÇÈqfð v¦.ûáæáSUtNØeJ.·a S.PŸq );h;é~@Ip42bfuH8bf–46–õ4Vpõ¡3ãÁ„lþ¦0ÿ¡ ÔTüa ùLqÎZU©£M)¤:ê±rè•p”‡@_£Fr|uXët#,#·™an!©W ÙÀZÉKjª'1'‚¹¦‡ùˆP ©ç[fÒ]n"'µpJ@Ày“8{¬3ЇB(eŠŸ¹AÀÈd¶3 ï )X bÖpx+#3¶Z""Ž÷G—jXÂ"("Œï¦"5â6¡ @· Ráæô F:wbœD ¡µ}` ~ë+wð‘-Œ–£ûdàIqa˜EÅŠEé2€èEÐ?ûƒ}¨qkRÄr(–ÀÑíÒþ>Åûa¡$3ðp##ãºóžcT.Úªtp‘aPWP~ SÐ:ø?G°“—Ь0G8bHIc JtVV˜°Ö<Ãfk[W3g…-3…!›•Œñ¼ý $qÄ• ðŒÆAUI nA<ð"Sð'H>áxÄã1Mù ÷‹7ó6{0D’J™ˆ7‚3)¸S ¾'lxkaKÑð[ ¸ãkÁ ®”[¾µ$®˜Õå7´•й$]±f]‰Ú 'Q ·#ÄïpX`©y"‘j_0#ô ~!£! ,/5qM×ÓWXœ!’Zþ#‡çâ?ŽË%5cI,ÕCQÉ¢ÉiÆ`áÓ„,ZÓŽÂ>@B‡õuùžÕp¬E`g¡@eBú- dUêsáS5g}!Sg1j)4M§g²Q  2¡½Ásýðžö /ò~pXvlp MRýpðP‚ö0`æÐ`ÏQ322nVW:#£E43 “vó ü Ÿ;SŒEr—ÁŽ1•sá¬Rœ¿oAùë.ª­Q<u´iÕÃ=ù?â›bÀc«!B qð µ%‰PKÊ´´rò:Á8·fK þc ‹ð ÄFlaò *, 5{´®×\‚“ '\˜ (´V:½gâ3Z¶ƒ*;'°Ñ„}ÐA€´Åøâw3¦ {¸xÝøœÒ#ïwM)ò‡}5OÕÇKRPo¯J!å ÷6ÅÀoAý<° yœ-×¢†Ëx½ê1G„EcÆ3«À„A5)vOùa¹¬ÿ©¹?B‘|¡bZ=€!'6è _&£E. #’æÊsº1¼(¯<Z d$à âða Ð×peŠËl Aùš²QW2ƒÑÑLh»<ƒV 4¬ bg¥¾Ä¬QØaþA#6ù¬ûÀ³!S“µ;Õÿ#T8ÖÍSÙXtñ?Vm€8Ò"&U5xd#Çvô5ŒA)}’ µ  Ãg]yÂ¥·l#LÂ&,˜œ8amÁåkn’'¸Äˆµö:´u¶W{ÕÕKy’¨Ñ\¶È À P€ÚàˆFY¡Å‹T3·…!ØSÅ676a6=Ñ=Ò)ÂS² ààN½ .wš!–‚G#ÂÀáM¡ êè#jéѽJÕm]é¡é1f<°…kícÕkbr×ú~&ÒFÖìúÈA»:»&ótëQ s¿+ ãþ·Áå=xÑÛÎ+/lð® @Jǰ|Ðeð¼fpËÎ{eð°“?•QHN°ž0¾u³°54Æl OðuÀ€E=Ó°ÓáDw`ž¡Qä³ëÖèJ‰bâ  q!öŠq'Sh9»­Â -Ô.—Ë Å€#l@¶?Î <±R  QP%‹ ¨ÍÕIKR¦µä{ÖuJ¦§˜¶ž è[yr& ;pº$PâI…²z¸ÔˆM(…R:‚²Ÿù™¥ÓL‰*§  ìO#>A#3"·ˆÅYœB².Ò²;1&+hOš`Mh#·{ M –â¾ü~ÀÔ=/ÿ´?¤þ¥ïûŽÕ° Åp!àù ¤»/2ÎrÈrÈ¡Q-ƒT”-?…”‘—þªï?¤bÈ %£«~` n¬.km6uØû~}°ÉsÌ:të ÙÏÛY‚ðÐW CÀ¹Ðíp K'ŰØÏë s21¬Ñ`HȤ` ÚPWîQ£¬½3R¤Q ôö“EPÉUwϼQ µA@<æç 3C¥BtÑä"5 pä3µ—G5Yp!1±»/SÅÖMˆ=Œ ² §»N]¾‡¦iºŠ{"«wJ¿ÅÂLJ;°DЍXÂÊdÎ&ŠþÉFß¶¤LX‹ B´%ÒXÐ!V Ü}¡Åþ’À×j9‘xÅsM™ªnvÕ²"iùI†P"pOߦQ×"A¦NnðÞK j™A¤¡/!}qbÚcFf€cj!vá±kÑ܃GbЄ6  ŽˆñU°Á7G¾)R¡¯7—ŠL9räÁŒwŠÜ¹pሽ#ðBÂë(ò‚’ ýÚõƒÃÌ53.˰a3äš;3eH”ñcà‚Ÿ2¬Â˜éCŒ™7öJ”@‡€Ó',läñ H‘7 ¬)à¡ñ’Àw¾Z»sç5OŠX+RÕÚÛŠGŒþ²¢PaÅá½É{äB‘#Ebùë±âƒÂqñòel&É3¾’øñãÆ+VI|se“=ÐÈíÙCäJi?%ÇH¢Ð eÊ DS¶!Ê"#k€D²¨÷îEÑ|¯1a"Úq »‹óRÜį_P¦AÙ LØ4lP~Õ*$YîÝÂu_´fp k’%[S>Ù"çÙ7@Y”Ìĉ X„m‡‹'Є MÈ!C4Ù<M ,GƒÑà7^¹bÒ0Ë0´ÑH{å•®@f_1í ÒöÐd7œ`Fk´ñFsÔ‘Ftx°Æ 7Xy31† ÒVˆ2Éþ>vtòI(qDçG‚¢ =|Ìì‚è _*c艥–Bç _ŠaE 1ÖdI‚X©LÎ0‹4ªµÀÊJ Ž(¨µƒ|,+_S¨K‚ ‹°'.æŽôŠÁ¿: ž)P2ž~Ì  NÍp…^Vº†q`2CT6`‚žUý w`ªÆ'¬¸¤,«¬yÀ—KØzÀг‚}+"²ÌºcŠªÌzÀÇ;|½àÅ %̪Š<*ì"Œ:B¬£Ž˜".ºÈ0 ±Š’ˆ!ÊøRÈ—WHûB 6aQÅ+z²#{'Š(6Xdl°I¦ŽÜ„sØ8ã¢i﹈ûÆþ9ŒMnšêä bƒ„±q.=Ý‚C®½ãÌÓ=”Ë;¸¸kQf YjñO¿ü 'ØÑD„^"|p"ʉ°ÒÈ™°œЄÅ=*K‘ÄÛt1èѾ â@M.ÜEI3Ä9ôp"J´Ó®;6RC!Åp£MV®r"X‘Qm¾Ó^EÉ7Y™{î"éý7/Í’#0*â‰FxbŠÞ³W ïkÞ¬ŽhÐ@ì 1Þxc ³¾ÔÓ 74³êªrb Ò ÈL *ÊÙ‰$p_}£ŸLSòô^®éÇú!ášžú‰•†2#žx釥vÊãx”—©½€þ¶¬µž`««g›Õê-ÌjÖ¬FŸà¡ª®ºbZo;Â#n¹ÅHÜnáoZû#`·s¿ PnìòkbðÁhè4 iÞæ‹ËÉÉŸõ`CF¨C"ˆsøˆŒ<ÉBt.ŒAì0Ät°ajÈCX {s g7êqyŠ£²bc:å1‚2¢Ðaø'аϬ`£}á 'B‘‹ DŽ|Ð@9öe =\¨nCQÝ2! |QAšZ_ñ…+äq_€Fhˆ`…'ôM;B‡°™7$©M—›€†ØH„b4e“ÔÑ*H“7 3˜1Ícþ§Å™N”E(WW6b ˆ ©jWÈÖUîR.‹ÜO”A%+L7Rd–n VLW.R¾ÎGÐH¹žùå.1Ú²TH\r¿)ÄŠW(pÒƒR]£ý(CPA‚\´ƒ¨ˆÇúx°Çp Öa+IΨh±ŠYJЖ°ëYØ)}5¿aýSrôë ¸.àƒv„0´¥(U’Wá 8è®Ñ3 £}Õ¤(õ*ÁéJèþÈšËøAqEºB›4dšW\Æïƒ2°‘5Ø”„,Ćp|ß°'ÑŽvxÃ_g7߀‚v¤c¨rÇ*K|þ–2–é&9,+Î{Rh‚ PCK6ôƒ…þì瀀5 M¤ÑŽ{„9´ˆ™¯Ù-¦mŒ)+J”GÌ àmp»Ì® ¤!ɰvÝ¡bXƒ’“¥Q ¬a:P P®ådÚ”·>첓lŠ5ˆ€Ø!A"K@ÂŒ .Á8ͤÆväŠEºaHpfÃâ’lU$-‡Dˆ@d—•K`ë—xCåR:»ˆRu€áÁJpLÊñàìTHô×¾á )ñCFhNOëÃBÂÇÁ1A q±Œç9Ñ©N$6À±iÀpªêYÏxÔœÔòG8F0{ê31„A¡c=XüE Xà P  -#,úB‰^”˜.@CZÔâðHM!ÆÒW¨›œ‚"§$ÜÑ‘¬X€e’ÌTf¬pÀcC;ZÒöh¦“ G`á¿(€ ‘„õdÑ¡ 7¤òM’IRjÄ ™þ7\Fqrb“ébi&¦,¥Q—¸D\|AàV„!°Ã `2Ì[odZžË `¾‚Z'E”±ä®;¹°Äå/ð°GKD"ÞE3 âh/*x¸bçõƒpp[-%áŸ0Æe+xJRFOÐÆ[.á \–žw¨Šä¬Ñ¨fÏÝ“»nZä‡ «¸½F\îaÿ˜ =`Â:Lóà@ç;ß¹4ªákØ<è h9Ž]‘ã2¸âK¯ñ›ÞƒIÆ™ï’ËBbbº È!ÃF~¦Úˆ¹¬Ë¿ÈŽ Õ<¤ª¹‡]æØ~¢3Uz‰4„Ä€hœõäÆe@E˜0"Ÿ(þ`¡'¢0N ž) ƒU¶c\B™½øaB*ƒÝ$¿Ax]†eˆi3MW,ZÑ"šçcê ©Èn¨†h{­6 ¯e¹~r6^j‡Ì(Àõ¯WÛ”X1ÁŽÈE(ZæÄ@žÐ†ö„§9[K¸d.C¶ÝÜ«8‹¹¾ LsÁK«üÅ"ˆQ>øGw‡cJ»\â—AZà¾K¼'Ç5j‚Þxô¸p}#þ”¦l ,@0eA¥· ¥ k@|šŸ;°‚²°­R2&É9‰þË@3€»(§«9c‚šÁø€Ü@Ÿ›(Ó9lAŸó±û  :—þ{¥sWð±2ð‚#±Ä ºÅ`ˆ@\«ü†Ûâ:‘ù…êXŠI0ƒ!æ³2“‡À-K‰QÝP;òªðP™ˆá2㨅ih€_(jà† àaà†j’\1ÉpŒËp <ô3 Oñ—£ >Œ~H‰º·><©WT‹)Ë`WР@5 H°†Ýã=(™0s%Rº —ˆ–P(M춽 !!c‚œ{‹BŸƒ0cª |¬¯ ¬/3”±ƒŒ¹»&± ÁœëŸ[1žsAìÀšë± 3:W°ÁÄ1”±ò Q|Àp Ê)H«iˆ"l”Q! ™iˆa°˜„1Žo¢h¨¡ °ÉëÐB&ó0™.Û2¾û!"2-;ùh*,°€¨,À(°P‹¬p±[€$ðK‚!+1<žx1Ö(±’¤”$°Q<34É{…$˜œ £ºZ¿ÿ8Œ¨.ëJ8Ñ,ÆÎLM`(`.–`²Š.Ñ d‹'øÅfIŒŽJ €Ì0&qi¨“ÐÌIM€ux>…{Fèt _MGyNë$`€Î’{°É19ä|Ìj@¿ÐóHj­H0Á†DÈþ†¤¹|H“HãψbA†¼Ïƒ„ÈúÔÁPºˆ¹2ÐËŠaèyhI-l³ÉÐìÐŽ ÝP¤ÊÉzê°(PEÈŽ£ä:ç8*äd0¡ô0‚Dø¡†U"y@ÑZ(˜(™Ý=@X#ÕH…(u†/p•%$u&ERè-p^` Y-`„øFpœÕ‚(ÕR•Ý[€.õ‚Sµt  SäÓ(yÆo Ž@ ŒËR+¨Úû±/ÍÔL[üÚÍÜŸ\5( c¨ö‰ ›Åõ#)CK¾ ÀˆTâ^LÖŽ[@¶x +H‹jÄ5j!þD{ØÌ 8Šs) å$‰ÿ¹TÄX–XÎGéT]e ™0w|N“{7ÉÙÎùÙÎ’ÃÇùùÛÏ%“aý€‰dõ9À€Öí¿ý»0×µ¦ ü€lmȇ º™ÛÝ™[€™Ó°™sÁŠÌ9dAA :ÄÁ%5VÐipB…áª}Õé˜1ÃlØI0”¡_ˆy03lÈ©Z„­ó)mØ“)y0‚hàŽh€3É!Y(? ›œÅJtx£uºKP§‹¹hW›ƒ8€@`-ÝÐÒ@R˜ÍY •à/ÐÒ YgÈR,}`t¹ÉS€³qÓ­‘¥€&±]xþ(±" á6aŒPΓ8‰\ÍÕ)(Û® ïy'±Ma\ýa†Û" qb[D‡Ïd¾2™'Ý_üNü1€‚ÛsL€ƒª¯ @%؇mÂÿB¸ 08c?¸„‡+Ô †\¹2‘‘BúÜ3±N?õ\2©cùÑ[2YGÌ}‚j(EÖ½V&°Ýûä@Ôå9wHÏ ³¯EV1dÈråVšSÈë0o×AN±Öå9ø€‚œHà9³¼†ÌÀ¦l ¢-ëI˜ ™&„Ž´3‹1¦‚ŽÝ€,Äó­3®ú4K»äˆ6[ƒì¨¢Â†ÝÀj ®C+ýP«(àƒ sƒþÈA¤Õ±˜c¦{Èô¹J~HçsqøWp`Kç!Z ÅA¡=Y ŽRW¸àUS€&¤¸€ZÔÌä,[R‚á>“û¹0Py Ûb†îˆ´}•sc\]‡õÌ‚&ý1â¦T[ÝŸ#ÞhqÁ®ÓäÅ»ÅÔ2áÊý–dsÕ~ƒ0ðƒqQax ؇ à PûÊ\…ËQ¹ ˆa|Æ;x”"6]<“ÍÝÎT%@¦fÇh;“¥XÇçdÇ´Nî 3ÎD] ûâÝ9×eäGå #Á†,Ë1‹1›Û]CÝDN±MÖ9;õÏ ƒOAdüØ€ê˜þ†™á»øPѤRÑ…³óˆ˜æ8²{Ž`>¦Š†:¨iH„š†iXíH_‰ùó¨…ZPŠ l,@Pˆ"y˜J]>Ö{£=Pvuà¥û9¨m¦Û]VHþ¤9Ln×™{HtNà‡£s>€!8€/8€‚(ƒ‰‘|Α¦ÎKH €ÎUï9hx(‚³¹î‰ÓƒRh°ö¯‡Vè“øŸ²M(ù.©ÞL–>ûùnÍìÌâcÛ[4©ƒî‡s$/Ê/ÿr‡~°‡ëA(üš ³w€ðé Çȵ•FqU‹–>’öUaÅÍ<ÆÜ_ìÕ ^ çþ\GNÞ@&0€\HÌ…ßë×¹±¦•ýóä‰4„¹ºäÁß-AëLÁÿtO㨉êT»¡ð]íÙPQÊl Q²[ÑìMWö“Iª¥Ž‚•Ž_H„öØýÀŽ.³r¤\:Sdí_íâ‚ÃC+(ò> ¸ô`n`Cw®m-Åmà–H„¾È'dwuHé‡éžnã¾Á¸ÙSò.ï{úJiO‰Ò¹öƒ#¤O_›' ž©ˆrÏþ‰„f¨ùf¦[whƒB \ÿîŒ. s±Ÿ"þn>¸ôëÌYµƒ[XyévП2öþžnQž0`3øâ1(…6˜éï!Ê1j#–°lj÷Óë:wËÅܨV\ÁÙ½VQöj¹æOO¶qxÀ€|ïdÞCHøœÁ`kàõ]CApF1ÖeA{—(Lj‚ È¡ê0*ß×ùm(Xs˜©˜.+ Âe1oªÈ6‚EØsÿ+ í»ÍÉú0‚ pßhmE Ž+çeÞ|3ÝœéÞ¹`úI‰ ¦LyÝ/L.wJ”ˆÇ‹×§x(P`ˆ÷‰M½?*m_ôšûøòÛ»”æþþû1¸3ÖOý0•Kfôp ‚ &u &þõÓR6`”QLõdaO=(•Ä X$ô‹0¬±Æ"‹˜`B4@Å/µ`³ÁßDc66¦øK4‹ÔX£ˆ‘°H‘0ØÁ H5U7ï`ƒ 6 ÑMALƒ 6'Q‡óÔ’â4C.bDµœÐa±|<ÀWìàŠG&Í1‚Nðà /ŒðÂJê¨s€ .Í¡§‚šÂŸ¥—;@ñä‘ÕõS‚#\óJ NÄÕ©§WMQ„ ‘ ƒZ¦*ÕC m}Ú*\Y7 Á¶N¬8vA GÖ+a„íêÎb†<“…Æh~šh£Á¦Zitl¯Y›-lÀþ$0^lÖÁc/$à×°ñŒ)8×O.×Ô¶Î:îäRï °Îo¶ZçšiØqÇ]¬e„¤xè!ŒNÂä1ŒžÂæ9Ìž¤üM_¤LèÓ{8è÷“~c5V€_Q 2ÅD˜Ú9BS.7•2†©ÕÔ…*°À VÂ(5%F4Œ,bób4PTiÂ7&7Fc%ŠPÈ8-®QG=‘,ÓL3Ë("4ÉØò A@ Ý@¡ CÉd“Ì<@tqÐFÄ’šX40Ñ™Xè‘‘ä0rÀ;„¤’JyÞÉ“Í|¦Ò /µl¨…vòÙg…LàÐ^ž?¨Ü<¢ãÄþœºšúVEÛ×¼ÆT?fØóê·[¥ð È ›SðkÝkÏRFšb•íU]‡=À¯¼‚ÆiœÕzm¬ÂÇö­ð»Ö}·ý‚?^uOdß l0†îŒa@[|¬£Âó{àqÕšµÛïN^’ç)L|ãy˜ hÀñzéÜÆìÃ! I dÓOÈøC“‘f}%c } °”©ŒCK ÛÓ¥ø(fCv¶£ ÈcɈF-j5ªÝE{QŠá´¥jµ‘<°ˆZD¡uXÂ=î±G@q\€â ì;üb`CN&#$c @b6Àˆ ,þXÀÂHÓC,à„Œ°ÂZØáæ@GqüÀ?@ÜrV¡;- eyÒcIúx§?^î…:‰Nn’ a¨8P‹R:×ð I¸Û$’JÐ`üÎZ| ËÚÄÉM’ï¿ó õ¶çÊë¹2{û‹U´#Êê½2—®ìž÷À÷=ïUç€þSØö.`ð" ý¸ÍP¸µK„¹¦Ë1]s=ïxç9`ùKñu‹5l;—BDŠCõÙM$èvŠŽd$Of“kDÒq#| Qîc2b# P£Z2’a£ÁèP¸€˜¢9ô &h‘0(! #¡þ؆(ZÑ .|þ” "é.DQÒ:H£FXÄú Œ0-±D_TE,@ J4`X`‡xÊp…BÚI%‡êáòH’t$g×`YËyHC 2¨sp…8Êà <%îülŠã€ÉSâ< HÍÖ<ß­#”o«êÐñÑLïÛë%¶´—K³ê2¯áûf/­iÍï¹²{ýë7»%ÀÁÆfƒö!Wô é* Oz¸ÒMj³<ã™kaƒ¹;Ávç³ÝŸ„úãOKæ¢>õñ@FN¥ŒA)¥¨$kqcÁ#>=X€MʺÍÙäf6»PG˜„EÄ•¸ô +a£‹(Ñ‚–£ˆÞ(þG …B,(,a »hÅx[Q…*˜÷¼UiF:RQ,aÝ@;@‘,áK¨ÜLð!3ñ­¦+5ÊÈ–1¡$TÝÁ†êŠü`r’SröA›Eõsw²‰â©²¥Duevò‚Mrb§2ˆƒ1Ð$[]…ޱ‹2‡ae Zœ:·*ï6£–]¹GËlñî•Áó1`_£×íÉÒÈ» lö¬óYà œ§ø´×c·„+NØrùªMƒaØô«/½·dÖDù{TF`kÚñý¬Rh1ƒ¤à) Ä¶èØžûó(±<*,ûáræLñÖN2ÃÙ…4–ªøAþW;0䱈DÔb¡VÚ‘‰€P£!¦hiAbÑ"`øÝFy?Z…PT¡½!u¯#FÞEX€8Á"nßXÔ!'úЙЀ œÀ +B UW U Ž“œ~P=º¢ÂbÊÙÇ>Ѝ›ãÐå I¡¨–x;X@XlcO-;ƪ\Þf0Ùww <ØÌi€Üclc7«­zgð\Ö®OFr]æd'7y ä{Í’K°ä¥ÙâÄøîªeØ‚M…²YyU¶¼eÌÞ[³Ø¼¸½iq5GÍ£JÀ1x²s)©µX9ýã Æ6¶¢ ©³Ï”ÀÀFþáíRc¦²§«-J‚°‘\yP"”0A"ªÜZXÑx®¨#ú\èBAAÀÂ"–°·¿½p7ozÏ›†õšW¤­E'Ö€ˆð:0Âz£P‚oÆ~ Þˆ1ä¬Ä}ô-…­í;q;ÃO*‚dzÏ-*eçf\å8Ï„ÄY{Å7¼Ññ€#$Á„JdÜñ€³>.áÁëã™âÍ2–Ö2kµªuÖ)ãxÍö̪- s±×ºøÄü|kUü—Ú—¸a±òl›œ¹8±)qîwo=_ùµï}výÂ&z:‡N 2ÐþÅ¥­Ïñüf ÍVÏÝþ€Ì0…{d^Ê,„ȌӡEª¤J4@Œ5Tà/T×sÝ)T—X‰Š‘,Ã4(ÄDm€mìÜmƒG¹š Þz©W rÁ6,(hI2ÈÂÛpC7)´ E˜ÉâaA5ÀŠ,@¢•D† ×pŃ8„ Ò øp攣¤Dä I¸Ì¬DäQ¸[î­ŽÂ<€Äž„ü„©)™á[èÛd0`Ð…ý\ß¬È ïЊó™U(’e ´ü˜ ٷ쎵˜Æ´,¢¶ÄJ"^Ÿõ “zŒþ$"ù _&nÇv\"Äß%jœwHÜÊ=Ü^É\(Ð÷­xøþœk)Ð;½Ç{ŒEkÝ\|ÌÖlÁ†m ÚÉ<SࣅÐÚ }HÝ‚¨!7¼ƒ0PÃD°ÈdšØ-Bˆ§=T4ØBÐØ‚ ˆ ÚH %CxÁ—(tHµàzá] ¾:ªÞÉÝ),A°‘ ¬ÍΘI$²YBà¼Õ+TaäLžœ@’…,Õ|Â5D¡S’Ë$ZFæ‘dRê^ %µ!P$Á´I‚$W¼ )"-ñ î˜*iËïŒFÁY‡óYôYŸ¶ õÔd¿]‹,E¢ÀGdi’[‘iŸ•a"&%¶$þF%ûqÏ™µ7%Ì*‚™TàŸä‡ýMlõŸÉt •Sí |¼Ì0ÆÌ¥ã:ƒô„n1…øÁC¨]@A2 QtEˆÑŽMÐL—§Í/` š@ÖŒãÛqÀxµ Ý©— ¢×Ýqzy” :ÂÛÕA›=®ÍDÁ(œ€¼Ñ˜ÁµáQžàååÉš›‡ýÑR1Ê}ÛUoHNVAdæ¼À”Á¬ä«xŘÁ;]ÒZ5gV±ìcX†MþágÜ!e(Ïfü^ñ(ö„’­Ÿ ÞR¶àäŽá$õe¶à•$B–T¼Ñ–aGSbÁ%ô¡'þbqâ'žßÉ“öAf©â*®G€Ì"|Ø_O˜L=ý‡ií‡~Ü˼ä_¼å£á‰Ê8ŽãÜe†àˆ~˜R˜0Å  D´Mæ"`ƒ"˜@—œˆ@”Š &ýÂÙEf,øƒ(p€(lC©G±#f¶c º HT,A'6L 5PͱQM°ÀTˆ$+”ùÉLXPa[¡èQ† RN0J‚¥DPR¡ì‰NìDçm¡ž…@•渂à^ujÒY9ÅÀuú©U<ÁKd¬ŒñÅï˜Uc(‹cK`ü…ŒYÆ ÒJ|¶ŽPzêxÂçyj "Àå'baþÓ¨ªi4OfËÔ•«b"Æq\I“=Ì*v¥®f„mñG€ÀǬ.Z(;5h€LkébXŠÉÌ%ƒlÎ$Å:! ¢W™(‚ˆ”I,Ã`C¬A2 ÈBXŠ@×sé(²« |ùé)\¦‘â+Þ¡#¤AÝ}ÔgÊÔA¨ @@8²5@™è’<Àx˜ªDæ\C™é ¸Æ:$ãHäJU¡Ò-N…ìÄNXHÉꄜ:ŽË0ÊËøÁêªd)L ”Å}ôÆìU$*©°%ñDËYQÆ`€†óÆ^FcÌyzgMJÏŽÁgñÀÕðþijð¥µÌ +ßÓò›«^ÅÅFU†S÷øP‚îjW~4m ÈèÈXPP^ºÇÄ„Œ;‹Èô¬ïUƠŇ(ä]2J¤Ì„}ÜáZŒ˜AqD‚Ž(`2¬”ñˆ¤¥HB•ÚŽbƒ¨E6(Cd,Á)p@‘Â`gf¦gÆ`fæfÊ],`ƒ=À$A-PÄ ›tE@l!ml…R‰H`›”D…iÎÒáé…¡@nᢘ¬œª“Å`$Y/_NJæ¬ÂÜÁ‰F<@Îê¬¢ŠŽÐ®­œoMfç_`§¥ŽÆx6íÒÊïghm®D- ®çTögþ$ædþNOÖúÛþ4™VvŸÙ–­úå*Ù*041ŒiuÐ]P²b¨ŸÙ†<í"|ÄS,àÌЙ=mH|Ä.é™ÐE-Â$4(Ñ4X€ ÄBÁ͹íPvéè•tÂÄB,pÀfÁÛ¡î¾¶c;v¦‘®“±(dÖyC3ÖÂ>>dÄøAœä‘!ÒœdÙɈƒÙc[Ææ r*N›vèÉŠÞÓ•¨nYØËï¼ÂЉ¯ÌNÁø>5E ØÛSž¥Å¤­üþü^€òÔ½1F(Íï#{ç¥(I+ÅϨröð!J2fàJ#.¢jø¯ªþLð(\­êª*6ÌÙ SÏŸÍ)«X,ë•ÌÛ6+£â–iãCCàpEJçÙ:ÕÖÝÖÈLJ1@‚2|ÕlÀKñ—¹ªë¦ñHØåD)6d °-ÁËÝgê«Ýñk{±ãyÁ8Ÿ×ÛÁ×J5@3^iG¼ÂQµ Ÿ˜HJà„!ÎH¶Ý³ž˜ÛšºñæÄñ’|ŽBX 5›‚ýæµ½BörîLI&EøV´¾Á$2±LFc¼çüVêúîüÂog@2%ãÊÏBË:@ þÞ$QZ×hUJò¿pÆ$“r'wrO;¢’i`pÄ|‡fIYgußÇ mþ¹å¤Ø[ž´*ÙÆ¼ \®“ÍÌ †,HtvÎÓ)d?½"[02 ÈRÔ‡2G ! þQÐÞ?)Ð~“%†îâUÃåbH³id1L@üB$Pƒ”lÁ¨¦]ãŽ0faÖB©H'ðõ±¤ À"öyuæ»ã šcoC,¦ÈÕÐ(téÝspìM€„@;HQ%9K$ù¸{[›B’=y¨cÛ ÀªÔö¡êŽ®ÀC·hyÈžÐó(ILWFs†Þ²R(çHS÷¦žo$Ò’#K÷!ÃÆ¬0|ÃçÕ¹RïèáY‰*^="¶ÔUÃqŸÀܪ+ º‚"°ÚZ°XÐÓþ%nâVR§óm%uÑр𢱜e=ý¢Bcsˆ/¸îÊC7îþN׃K ©E¦aÖp K—Ø«yýº{‰a»z ±Õ{f )‡‹nVä[°ƒã=&a¸‘^!ʼn’Xñ3µ%yHÐÑJБ?€ek,>‡ñ"‰1Ȧ©›Ue[ Íɼ‚/A•SzèÊÜO•ópWª³<*fà$!¼JkPtojwŠ'ún*©B*f¼µ(|L?êaö 'Üž?ÈÓ¹O­ûñ’ÿ ­¯ªGÂŒÎèÀ¼RÜ…¼üË?HâîÇ¥{úYºe[²%º“ƒêVÓõ2†ìqâþâùÁZ¸Á;ÀДø×BÀhÓÛhÑ&Š8&©U‰2TÀþeŽ3HÉ °sa·#’‚ýi‡m­DU8aˉ>è C÷`Á«2#Fü°xñâŽs4îð2ÂË«®\uÜáÌ™Æ+çÌ9Ð’åˆkL˜¼7ÇÕ‹#^´üñ‚ɇL(–yñbÄ‹8]É,ãeÁˆ^XakV­[¹võú•«Ãð mZµ yÜï‚» Gä^xpá½yñš1C/Š)J¦ ÀWIÞu„§¬k<rä)y †œ`JÍŽ1kö옱c½£3;MZs Õ JxvúµçÌ®×iά÷É”ÜSèåy÷mÒ¸oçÖü$µjÕè”›5ëþ¹CçÐÍ0c»u38pÀ㎣ŸïîÜáÀþywÒ«'¯Ä½zxå¿cïa€¦Ð¡=øàßã:ëz¸ÆŒû΃G¼îp8ž"|9áyä&› „‰f Ù0Ãh°Á&°ù…Ä_Lñl²Y‚‹*Zt‘‹4Òà"F«°ÑÅVªÐ‘Ç[Ùf›CÉ"‹%b²a´Á¢v°bÎJÚᇬìh¥•Ä1å‡h¢©¢9trÅ”Liɧ¥”šƒ§¾¤ÈÍ Fø$N&îûO;ß”jkø‰$z€'‰#ž8k­DÕ 'Þ8¬E%M´· ãk2É /«Mþ´Ä*#Í4R7]¯Ñb[U¶×8k¬3Vg{¢9嘫u5[•£µ^iõ5äZ 6ØÖ3n7ÌTµ­³aAî¸×Z›–µik…Î<îÞZO.øæKÏRõ¸ë§½÷ð"=q¿ûÀv ï¼vÿû`¦ý²;/[îêrGàîƒO˜p(/é<ê˼$ÊN©ìÄŽ]0yúM:±¦)8™XÀN´ý þ‰¿’XÀ «”î¯J¸Cîºõ~R«Ü@…U¶ÆJ}L¯L[çï¼"[ÌUćU/PY}m¶á*wÍÚæXcMØåp­ÖVéDÇÕ׿xÝœXc=ƒvuÝ’SnsÕ]ïuó'ŽW÷âÚ=±øÈ‹K¾ôÊÅ€<ïÐãî^þ¼d7AóÌÈ…‰ý»Ó¼~qˆ¡»·º+/`ñbø¯‡Ñ8á„7°‡“‘¸áE<ñbOTf‘N¶iñEi9d¹Ðñd,cÙ`¶ ˜q@±à€AXÀŽ1¤~¸I6¢Œ¸b'iÊ5Üd¬qÐMIEàT‘¸©„=ˆ Q€Â°ýäkJþщQ¾¶“”a"$á$ƒHí ˆŒâ0æĺñà„ÜàH£Ä nS9Uá0#š*Žæ4©²Ü¹X¸ÛÀ&W¹ª®ÂHF2ÞŠŒ¼*ãç`g-bËŒÔBÎmG,ÛÑJ7¿êÕaÜßÅÇ;î0Þñªw¯{mÍ?Ù¹O€¸ÃžìäK[ÚC¼ iŸ¡H¥ X€’ð i@!aØ6ÖŒ5l¨bÑûB”¢lÔÁei¸ÑÇPæ"‘Ũd>š¥Ž€$ Á fª …2*‹â yÀ+¤RB8" °ÈG¼0/\DšÉHT‹E,aúÈØÊV —%[YÊ ¤,´¯,‡´¡ ®âI¶cÅŠòW°“$âØ6)8¥–(ƒ81,;-˜ARĆ™çÙþ󧨔á áþŸå'š\c&_.P‚QŸ¯M:¬a3Ï;oÑ­ u«[„Â¥  ªËîR…0H€ BŠ—#<÷ŠëâF·h—éNF£ÃÆd¶ëÒð@/Ý}@¥4z;j7v+eN?EöFÇ9ÏyN{§_tTï]Í[ªSiµìôxäÕµTüª©ŸA®UïÁðX b€ 7pã`ÓP†(£à°5DĵÀF-D„ PBáPH_Â?’ÝR–;zQ\qIJ^†b ¡ÅË*à8dA }àÙ%ŠÐÅÎaK/Qlо@A-™é&h2 R^À‹£¼€Nþõžþz§.¥?MU¡gùfð¥?v2Ð"á1Ù¾ÎjAÇ*Ž`†~\'v¦joùÌ ÞÊ…·þR.] ê–#7¡Éu®¢EêÒÜN7–ÔFÇËÞØEº˜º06=…îzÔŒ¹,UPÈ@ŒÕŠîpG—Ú×½±~õ«y6kàÕÅÄuñÞC`¤Žg=KM^"û ¨7}ikÕûó·êÃMZǪSñÍ6ÐU—xb&F˜0>dQÄõÅ{±ò ²qßx Y`Y+†¬pÈ iÄÐä—Xd²â˜’9+¢”ƒlCöL½'0µ(à¬È9iÑFÓ™a~ôþ´'!Î×øV¬Q‰~ä C3…šÉyÑ3ÔBqÞȺΌFqš.9^îbòWÕæäÊê¨åÀËsÂ&ufÄK—#ë—6¤ÖÔ1 aDõ;tqk’û…×SõÄ.wy)ÌL$:u|)Èëý*}%(ë¼aäƒäÁa˜ FÈÅÒg(ìF¸Áýô7W”‰;Ü-j¸cÜŠ,)¯Ì‚*[ "p hà™/|A^xù2YðDúÔÌdz)E™Q<’’˜l;XIGthzŽü$ƒ /[Îeš  ?ø±Sƒ“Ûÿ>ˆàEÜ_eUŽŠ›1\ápþÆÕ}Uè-©ª¡%»/zå­òèy…>¬a1ëû«:–H‘åó¶|s®;)÷Õ[_‡èK’I ;¾ô›­æ}à‰W!Å\uÝs¹y°ì¦gzî£b`|šaH¨ÛânîP¬b>)}Da­Ïïd‰–Ìí–j‰dväð$€HDr€š  ”¡b! °¢|A ÚÉ'(‚)pb±âI±nÂß4Ï™(âÀƒ6"žFÈ™ ßhÂiÚ¥]fÂêü#¨¬yÆ _æ € ÿé!Š¡$Ê¢ª »¥T”è1bEç¸èvHjúÐ+sP'6ÂÏ£†®ÚÏsp4'ŽäsþPªVNçXhêvŽ¥W‘]ªÔÔcwÄEÀŒj>Éþ˜ð<„O¬¦]‚‚ P íä: Ì©ò¯zë¶LÍü€)Ñ ÜàR¬ƒ€6 îNéD@ Ä~¡dïh$¯¨–v1dâ 8ÐðfD0r@þAÐa˜ZP&O Ài"ŒÂÄAIbLt‚M~âábk¬Žô(îñD±Fl¾OÄÑÈ…;ÆÀrÁ¨¨xŽÇé” ¬`g²Põ¦¬¢, xr«\Ч<æc[É=àÂè¡<.¸æÂ!1í..Àãô"£,Òu†cŽÒsÜ0úÐOXä0¾êþè¦#t<çaŠ$ã ¾J’Œ@‡Õ®…9| ]<1þâ¥þ§’ra(ü£@–^ „‘ì#¨èï@x+< ä>’ ;Ø1Þà@©¨&aFB¤C€ÀC¢¡b¤Fl¤EbÌÜTÆFÂ,˲®$€KPÀµ°@D¡dg(À Fï Ë€šB´Œb" Él˜€©°&(¬Ù˜'OmNò#¨r]pÀ¨¬(¿n 2A¢Êx`?sRîF‹ò\tçâB!ñ\ò\Š`!›ë0"Ò¹(Ó¬ëŽ ®Àž`¼²+8"Í Íät.YÔou’£X‚E7hg¥Xþò$uå¥LÒ¾¤³9eò¥Q{Êã×òO·„M[„­ë²íÃ’ÄÓ]ðƒy¼3{¸îz  {Ú’  †º!&áB6 D+?  ` 6pM†­Òe/ ÊM–~„-³€² }`и´`ðÐ0ë´Œ0ðá¾äCÅlÚä½ÌkNköÎKP+ÙÌc/oO…Âì:%"\ápô 4{4-˜#ù†42%1fn"ù¢¸BNI мP¹üà†@ç² #¥ 5®‹‹ÎÐ"µ”JçH ;‡úb*¦ZJ$ψ:¥Óèf ãC§éx{*ìzòï‘î…þ‡<Ãóêö/<ïEP®C“ î®‚@¼áí$Ƭø3c²a<&eVæE2GÆ ¯,u, N8€T€ª @¡DÁ7‹)2h$Ê ž®)´`•$2ƒrµ$@Oß VMWµÉUA+šÞE“Ž">B“ÂÇF•uX! hÅ÷|ÔGK`»„³ø.G¤Â/Šp.Š®TLC ƵH/Å¡Ãìa¤®4Koã4^å‹^.6„ãåö‚^¯/íhÿÐŽŽÃûV­sˆîVî°e é¶å-x ©‘Èã;øltÒï¯O#q( 3yĬ^úÃ/Þñ(¬þ@á¦2¨a8d ºàD¡ê`ðÒ AaFer1ev,]LFtäc‚±SUf!v °`êàDÁIÐá ìv@ ì°\áK#˦6uðiõmWëé°¶Ö$œ–J\Á â©j+è…¨„°Š•)ÿc'¢b›ÊŒ)¿çO˜2 bÀv¦•ZA³6MºÎ6 %`UÎpVpb#\#Vç]G ã°^ƒSr'GpepãU[7uÞvB÷593GWFrt_Ê  =Ôq\Ä;´®§îe2¡P1ƒBé®c‘ž;† ÿÈ%b·§¹ÐÅ_ú`  #þ!ä Dì”AÄáxëàcØñzäyDR ´­>ÐcdiH²€ÁSU €¨’da ü!ÑaÞ€°Žžæi›¦±žBË›‚ÅAßxA‰³þmáÞ)³4'”b‡2H*À‰+B´Ô¬m(|ŽÀ\ko3øIú‘¢h®<®zÓ6T**8 ×U wrØ0&ݰ EwĆQ9Ù°Ò«¦Hg†Í¨ŸN—`Ít½œ#!ÛCxÖ£ø[¶yˆÇ¨¢.c÷þ$–uÙƒ\š˜>€W á¡ì;Ð<Þ àø€¦AB¦ÁÄFlÄL`!fÄð¶! þd¯tÖG¨–p ø'e>f:•è@bÁÀ°€, N•°Â¬ÁÞ$‡¶)´vƒ^@0á„ÊrMZ‚Ê4¹MâdöPˆƒŽ‚'r‚'RmJ´öêE‘Àlkîö üIƒ©õ  /Šà¹v™6ï¢"ÇË.€9¡8­ä–erÞPÕ¦e òýªS¥Ò‹™›Ù™§y%öŒÐ¡‡M’½\tKŒ&íaqêÏë ì)IÀ ̧ Dª°#@ µd„6 O€º¡6  ¦¬jC `.g„Hvde´·f'µf¹w–ÖŠÅ×ýÁ”¡jA(þ f†°‚žà'±cO çi>¥¦àž…XúÊFàjVº1—ð [Tâìd™ðýë¨p Îñ‘g?f× üÀ €GkÙG™#ºø¢¹˜Ë¹í·æâ5­ €k.L-£.r4XG†Uc9c²9Ñ(%»ùL]ÒšëK¾èk:cÍýf ®çkÖÖÚýäštØøx” þÂëþµûxÒ¤/v?h"yôg[±OKâ4o÷ঠ °@Ä@ fCÖ@jÁÒÊðî*ñJò*µÍ2¯Ê­,cLEfTAšXà£-aj¢`E8` ú@ù æþ£¨˜† Ká—›k|JýË@ØQ¹£k丗*=s’Â9xƒ =º{Ž ”zoK 70#äš´Ô@6¯«Ûû@ø¢¨´Kõâû€X\‡¤B²~Ž…™3™÷Z–:Óô­£®\Á\®<·´çuå9@Üq‘¤§¨žIÑ®! ,ŽÁpˆÁ®PË PËr¡±c-©ÁeÃû§¤?)Ï|Á ¢ ° j!Åjáa&€@F› 䨀ˆäðîŠÝê˜ÉË­Ütñµs–¶ÁÁØÁX´– OŠ¡úÀŽ`"ä_¾ƒÇÍ )ŠïåM„2þl ÃY_èQ>ޏ±wêB·â⨞ëPÈ»Zæê-%2Ö;¡&¢>.¾›¡† Ó°Ë!©ÈÒº(8”û*7¿scX’…å\øšÛšÀÜ­I}ÁœÁ£ããÀ1DåÖ˜4›Ô4»%\àÃòü}'Ï -e\}}1üh¸æ£V¡¢à¢a LÌÇ× æAèÇ8É«]¶áÚSµWû@äïTg¯T! œÀ ,– þçÅðjH¨  DÀÁ Ü@“ÊVFà’¢"*øD“HkYó+;Ü ¤> )êø!÷…;˜açƒ.p 6BoþÎx¢*ò1P@ <~\U êR.E䨫¸HÓI÷b»RÞåMæ, £¸ˆ£x£ÒH£¼F‰¦¼êh#‰# Q`aÍÔ]-MGçèm /N£äƒé=U”`P`ꃨþê±¾ê?E0º2~]0˜Np<2¨>\ ½w£wz+Ïì! Ƈ =Ä`8dC¢!:a ‚Ú|›Üïu —Ì­@ ¤ d¡Ýiäf/ÕÜh$ ¡daöá œá Xo«Éø×V-®"k'œê>Vèß+Ùh0"›N*üd\Aµ~ “,îü´ÆMú# ã?þójNÑ#‡‰œ^/ÌõÐj0j>S*4FCìÉ1¨ 9ÍR†”p˜>ù‹y‹´´r€Þ‹vc7ê;7Ñv"Mœš×è½\4Ã2ªÿ0ÌuT¬4¡îü\P3’ Rx\ pÀÃÃ@A‚ 4À°!CðܹCÈ0Ã#ðÞ‹R yò-Z#RŠ‘X§²pØ–ET–mÛZIتJ•V7kÞ¼)¡•Oœ\ÒØšFèPª8Ø,Z4(S¡MÓ8eÚ‚•r䮸º2à‹+qWĉsEÖÕ²gË–ÝáªÌ‚=˜,`òÃÕWuñþ(S÷GÝ#~xA»àZaÃ=ÊœU¼à­þ#ü@–Ü®\¸=Ä$y‚€çÏ C‹Mº´éÓ¨S‹~ð`J‚)®]'˜M{lØ´¬Ó={wïܵy×½{qܳ§Ø¾}{ù%°/0·ýöòå¯_ïF^ö“Øß<É^={ìÜãÅOI?þ6{ñãÇ—x2_|‚÷ã?‰/¾„ÿñÍ÷_ èX :ˆÎ4è ƒJ(Ñ <Jäà…<àà`ä!‡Âs„I¤„;H$@ „ƒEQ(cA`—=|À\I±´”š4«iTšO¡¹TQaeeÍ9¨¢Á&6¼†ð ú¦L0±'eZÆÒ×0áÐA42´ç5ŸpÊuÕqAýôž/”ñɦ0Êt¢R|jÓ{ö`\~°g°æ­÷Þª›Üm´YkŸ}‚ kx¶³m[®€æ¦—m³×JKß·ôÈx´éè쀹=žùçãš.èéšKúä™HàêN|«s÷Îûœ½Ìuˆ" ëD(á‰'ºÓ»…÷æ{pD»Xa‹ìðŠ¢Îm€ÐCÏöôI˜ƒ…}D5ÝP#Ï&ŒTA'þd‘ÅOèûd˜m^y“úæ¿„T;¥æTQ¡ÉTþP4ÓoÿP¡š°‰$!pùAÓšÆ6S1ð $ˆ ºC.$ˆƒ}``yÄšÃDA@°„€ A$¨Â9Ä! CžÀ·Úo Ïk¾SnI‹pâ*×°´õ,qqŽtéBݹ0‡DÒ­K]BPÿ³.Õ­Šª{¢¤ÈÅtYqŠ©3‚4 Ø8g_ÍÁ f—/x1ˆ#Š£‰¶ã.I(:ù†P40 ±h ƃG *Ôƒ¸ðzJ@ÁX ½nh#߃’ȷ˜µ‚ èsßPØg—±„= “Qb²>6EELFÙŸÍxö?¢Ô¬ ãȈðþªéˆ Q”Ž®‘‚|Ê JD"4»Ø)²D¾S^Cttµ ³DTH‹$ƒ²º¡6·šlzßAäÚc« áWáÜxx@¸vÞg=‰ë\;$ Ê… žž[«¨Ï(>1‹óጂ®¸ÅU‘‹cBÊÐ†Š‘Œm(Ca÷Æè¼î8Îa…b#¡}í1޶q¼ìÕ lxÀK‘‹X´¼ ’B!¤3#tmlŒ¤À‚0°0EÔa 2{ß%Ù¤¾*¹Ï~YŠ_¼Ä3R®OLéŸ(é÷ÊVVµ- ‚$Òƒ=¡í4ú@Êð1@.f¸Û¶"þ¤ÈŽÏ)NI•I¸\ÃN~hñ|7"œèzĘ¿@ nö°ŸáÁ¬Á¡7öKCýº@¿úe+ Y¶A–m k$kNÖÜ 6ž­–z>;vêG=¥-­z¾“ÎÅ…n\M¤âî@X*ޱŸ }¨Dw €Ýú–Œ ímo jQ yïbпâ5°áɈð‚UÚGâÄ ":XCF˜µ‚@¦ 1À ["Ì ¤°@$6À¬Á+i™Oøw%£þ¬gC¡‰ùâU-õªQýïTj&”ö-eK°, ^Ñ ŒÕNM;!ÔÊ(¶1dnyBˆÃ*‘ùF¥‘›!ãb–þäÕ3шÜ“ÂvÇfèMÄÚ¸†w°†=àq„÷¸C@Ž,ˆÄY~qÖV z,f9ëYÌæŠ5H¾fA{Y\ehÊëÉr–»•8|Š®ˆÀ¸Ã%°O*êóŸgfèp *Üo~¦3¿5Йu»f8 ÷zcì2Ú¦¤s}¦…Šë = /°(äõ„™h¹5Ì!1ÈSRMuè '°6p‚`#@¥‰Ö÷32aÉ•HÅ KâW“¦.e*øcå*y†jMªI}AG  qù!j¼¨Cv4 #jGwÚQ‘[T7þ’±¤iÄÀÄ »ÄQïpcƒ™þ(˜x»±¸ùö€#\‚C?²qÑHdièA·ar†œœ«î¼‘´á¼ 0ŒÏ^`ßòÂÕkö+ÖŠÖq›B˜…-&fÎt^ü­D‡+\ßê–Íp¶óq/„ç\Å»ÇÌÍ# ›Ëñ™`€Vžwݪ„¤9ïz*2$C Ù1˜µ1ÀqpÅ 8Á¢ðtB0QÙM0ÙÉS_r},«Â–$Šm˜ŒÖó3SÎþ+Êû¥a´Æo›ª4j5QÁ÷)B¼BáŠJ­&ìªÜe>È ÉøBwœ×…Ù¬1JÙ ±Ÿ‹!Yˆ°5·âUó üÊÅ­¨ÇkEžê˜þ´˜÷Nµ&Ï |ònôŽçGÿy{kÞZ x|ÀÂÑŠµû¡'ëyE…nñ¡bÄ­BZqÀ‘ãÑ}N¼ñ× ¬çv/;:Wo“7i1~^¢‹—´Å CÛÄË0ä[ C‚2@½˜ŒZeFº­;ù“O:镳ÎÙSâ•úÃß}2ñ‰PBA„è Z1sð/`5 1¿tHÓ5]rFâR8'1)Ža =×aò.ÁÔk4´x ˜ R,8Êò+ä¡,òA‚†.ñÄZ‘C,Ñ-(X,²¡8?$9¸±z«·Cæ"zá!zê!Dí$•s:²—þDJt{_dff&QWx²p#5!Õ|v§Â·næ|*•LËóhضR!A:‡m1€",tâÇ$åw>ês%œ´2t8‡8Ñ%*a>G±&æ?ÿ3vB3CáEÐ[Sà e ` ?À6=Â0#t15ÂKÉ#<#¶"±áG ñ P^ð‘X! 2oð¶;Rþ‚°+:Ä‚O¿b‚+OF[_–8çâ‚·8¢ƒàÂEh<°<ô,Ý¢Œð´9A”„KD{´·„ì:Ò:]„­£ºE ÉEdq$|ÑQ…DÛ!Žx7rk´…$õVʇ"½þÓQÈD†X##Õ§XƒRGÀš¶$à H§%qXkRÑtY‚ZBÐ÷U~8)Uþsê7"0 ò1 C ^0lSB•H’~p'óGi(¶|û¢]“Á6Ñl3âGug\=FX±ø“ݤ+ТyCÙ¨8ÇŒÂò8ÁxD±FO•MèE³‡E…„…ÛXÚHFÞÈO«“F¶/vdrfyޝƒ/í†GãÈF ˆ<.R"/æG,¢"tya(–—¢2B½DG` òðÙPK°òCJO×>ÿÓ2+“~4!u ÉÉJòG™õgö'UøGþ ßTP;p;ð°W@*Ÿ"16r s“ yÂaÓ óVxô"n•/mUs*´añ¨<ƒ"ïÖŠØ”Æ NåQ‹B¤8Þ‚pβ9ÖX.+[ê"Eµw•HDfsÆPivPçPßžQ·P¸\Âç.[È€!âø:îè|3]²¹"Õç#€eILƒ› SMI°’8P TG=² ðu Y­T`4÷E‡­`>ðµ«D[‘€Èuyî3UÀ"qÙfQlx/à)8R5fa>"H–md)X'R &”²k!ÏKÆ–°þ*Æ‹¢CÌÁe±ÇŒÕ¯E9PJ•“OHÔ„õEZD¥5PÞÙ噥¹%ždŠ kVg Õq™ÈGÂG–ïÒ ËA–S@0 øQtÚ;q=-†Ø¥r|œYC““BÄc1 ²@>I'T›d?8ÃuP‡_Ub>I¡•‘c¡šú¡šÙt£–tÀNð™Gà“¯Plu±4ÖF’Õ6=«)£˜›òXR"¢¶áKep_0¼Pyœ0énï&Ž2Pdv¤°X S€W„7ÈŒ¾¥ŒS˜q΢ӈE]´­NôGˆ¥¸%gÿ´•hæ¥ÛÈOÀ¦¿Uqþg¦ êI/"Â|ey!˱q2eI§"’§+µ á›ÐwRV#=àv)¤BÒDÐ(QTêçJ‘Ú&M©j>Kà$y©€8‘—i3ÿå?¦ö&  £*EEЌœªÕVl€¡q¡ju1†b{Õž•4‰¡n±fp@ÜÇYÄ$/P¦Ž0ªÊ‚wN¢åz+ØÓi:÷‹M :ÖˆŸÓµû±¥³7•LH®êgbJ®f \e ¯ ‚¦ 5…Jðnlš\öj…rºqïø–*ç"½Ô’=muH¹ woára€aŠ{À3~@ñTøu%7£Iþú3ûõ +‘ø³ºÿÓJã *û™`…A³^Ã@¡4k'4«°€»l0Ru„h%7r“ ‰Xù¢W!0Q¦wrMfú´ãNµÉhŒV{Œ›CŒÔ:­ß* `‰¥¥¶·Ç½hvŸs¶Yj¶×æÙ¶è‹ [!{tr)híF–»#;wä.õX3/´]~û<úh°is±] }ý¬°‡Kö‡m’&3c?¦±c y¨¡—Z²ªt&÷C²aG`W"K²‚ y®@€œò¼0)™²›£|i}·+GÑ'yÅm,–L@z"6lÄþcFöБ¯Íj¤Ê{cà”Nù¦NZÖŒ®µD£³‹“s„S$E““•¦sÖ½^lZŒß›{bj®ëº{é«fn ·‘g–qÄ|'…r#Ò¦ë&!îÒQw+—ùë0…ä‰Ï4¼òH—&BQªÐ  -Ð>2±IÜ3Ê©Ê2ªY‡©²Æ¡J™i±°KV±²½uo05¤2³Kê4ÛUÈ6qm-5öI# ‹',G*†ð !ŠDSR>c˜¶I¬Äíñ+0(ƒ@xN\&ƒ@ÔC^¤DdÛDæJž]š[ãZf_ü„×L¾h¬{eܶ½Ç{ðZqW8ÇJðgÆGÀþ/Á4Ç)rrµ0†53‡Ë6SÏ¡"ÑÄ]‹Ö!¬Ðt@k‰Œj‘¬É¨dkL7ܹž‹™º™&ì#¢tP¢ß„à`$yVLÐ5^c*2º¿HK#{bvbu;!*†ñ’û’HËÑ/ÿ2<˜Õ8̇żÖƒÍêƒ~µ’­@4ÅOØ­_Ô:^«®eû½f|Y9¶Ú¼¶eÜOìgìJqokga¸R!|EìÂñÉ¥‰ÅÁ¾´#L~º;xLR>L"e½‰dAù‹"à"PlÒt%«±• ÁôuÁ‘J‘LU©ÔÉjÂЀÄþ r xK 4•¢(¢²}±@Õv ec5§bU‚„@ñ c•ª…‘µÜq'·GPMop‰ÇÓ5”C²p¢5N¢½ŽãCL áë„L= _9®NH¶`ùÔe{ÍÙ»Oã‹ÆÜY¦Ò•í:ΟŸ?ŠQähâ;û|Ça¯'u¯y”]»]דŸz—u)G!TÚ·]¯Ð ˜Dˆã ˜ü“±—ܨîc`4ÓÐÜ¡gÒà—9ày™Y%#¬Ñ1À) dm¨<·#Mã@psÂ/°5¹€}1âQŸØU^Š)y'Ö#MuKdÿbÛ PXº­Mê«CÜbþ-~ƒ8á‘­Í2ƒÔkÅœ£:œAPéÔXݽâJÕM.ÝUÍjë·E¦_™Pp»ÆpFRíf\nZRýà° sËó<¼k=€„0¿;mîMWÓLrnB)t °Y´¬° À» t›ZUªIsHj!ü~` Nk|(Ñm?` › Î1@~!)?°4(,f¡)ˆfqªÅÆ)ÆmÜf]b7r#fð)m‰ð`aÎã;Eö`á–ã7d­Bý8–ÃeøTOûÑÒÈDMصTMåN ÕçÕÍýìVζޜÕhû\½Psh8ÙàþVÐs Gþ=y’î]Eær£æ|7x(Èq>¸+‚a0QHc`=1àW ñ5¡;ãÈëuŽüèìwBq2‰.²–ìÁ;vøu»VÙ¤ÑG5}³Õ¦x»sáÂHÊÆ4×°<±§€$‰5rL07ÄK‰&AûÀ)™WlÚ¼I†xmæëz“¤Å\- Ç”B È.Iݱ5Õܺͺ·Í_Ý[jÝ»UåéªÆÛ.q[¾P =—Š<Éqc™"@ª<&Íaý0]÷rÞæ;olË™XR2-&GÖbò~ ‡@1–k¹Žý¹Guq˜/Ó Ï©—iþ8Ãè3ój_—¯PœßÄ‘ «¼Û6ge’œ5q00Æb‚œ5Ql&ÖÇ3;œê1ÀЃ]ædƒS¼@¿7I:”ËöÒoœ*B!‚Õ*áˆÄÉhŽ\)£Œxy¡Œk˜xá$“8ÒèW^0Éþ•Tò äBW\™Cœ~ñšüà G?~²*7«”긤’Z*¨u‚:ž$cÐÍž Žxà ³¦¤²J+Ǻ ®µÔò+-µðZ‹.Á˜¢-À[,MÃ0ƒl4ÂÚ|Œ2Òâ„Ó²É$£³Í7ítm+'ð´LÏÌ6ë³PÓRkíɪª²ªÑ¢‚*Ó*܈Œ-(£.@A©¡€djŠ#|t)¤r£.(P›³®9špI&‘fŠa:$àb½úړϾ÷È<_ÓÃØ[ý#ö½^=O×cq­• Pâ;o|ÑŠ!‡ž(¦—BúÀ€1> éƒÄ¦“>ü(&˜`te„vm,CÝV[þ(£ª“Nº¢Ü!Ž& Š*3R¦’´GIªàêJ…f˜¡¸ƒ+´ÖªK0Å&^,«ºÜŠX´‡½´XÎ;錳ä9 í1@+댳9ù49Ð;˜ìO‘á\¹ÐÕXólµ‡ ¸Ìu.’Ò"‘BzŠê¸‹­Tê.Í ä¤Vµ¹ãfêÁŒW]5ÀŒxò:—krñƒVšE¼õruoY“=°=ç#>üŠå¯W¸ÍÏØl%Zòž-è¼4¸äÁ†ž€'‰rÅå­”‘x3&˜ÄE‰ÞÊG¸†'Íi’É'ãžV‚ßâ–ë·8‘ ’î^H‡|RÒ;¤l¸vÛÉÚê‰2)îxLKþÀª-Œß¢Ø.yM‹sfÙ3—í|Ù´èI†ùææEÆOí £ù3æ å9ü†‚ÚÓ2‘zôÞI÷Í-_Ô©ƒç¹~åŽëpè‡rÐyê|õ®CÒš×Ì:3ôƒäÐ@( ‚žÀµ > oU·ù´Â‚ôÁ±ÜÓŸüØjXÍ"O ÔcÄá CKü "&, ]%—ån2¢̰\<©\åp8“Öý†‡¦C•ªD‚Ãn ±Ž vh´¶\àHGpÐí¤8Ek=l ÀxÀŠ÷&Á<ÀP Þ—8f<̰ìa›ÀgƘáÌ1-ƒÞåÈÆéÍñN„ÑÙdâçGµïþ6ðèšÖ€Ó›üÅ/­CN?ܱ?â+_ÛyÚÓšâ4~EjCz…r°@?ò[Ü|Ê¿éí>t£Û'3ÁÁ­W}càk5Âd-˜ÖBº‚Ž$A;ÈÈJ*R¢Žtdø…’É‘|„#eh¦3ï×>šð¤ˆžËaåȅͯñ&k"dTt#5«Llh(ͨ¸N†E&0Åû’]ƽLl£Ó„˜‘i&\ ™]ãÏ祬NÞèóp&Pš}Ï4~ðƒ”Ô¨$ýq610Ãl ƒ~tÔf0uð ÉMeS›RÊ2•)¤¨Ô¥JXGL‡Æ©L­C þ(HJ °(ðoÔO(ýËd!kWðÁɳÊü4µ•{Oß–Ÿõ®–U Â Ô¹šˆc¡ˆE^Ä Wˆã ÌÐEÄqWü  r׋.´qÀµ†R[N®a£žDD8üZ.(wMÞ/ IìÍŠ© -‹'dgd¯¤22.fKb’KeÃT<Šé®KjtÓ˜Þ¹<î9tŽu#ÉJS=9vïd…£ôZSÇ ÈàuÀnS ´"uj)3M©L…Ó¶¬Ãœ5®9c*ª˜6v¥.•iIME” ‰ª@~ŠJ¢îM”€C–Þ¶KAº15@¢%(¥ª ë þpÀPX‚$”᫚Ëô«ßiá«eæ[Ë×Õ''òCL´YM&\ÃC×hë‡`hÍjÓ%7쀣ž`çîèT™²"Y›e1~žh„•·üS3£µ¢îÒR±ÐÜq4—áSCÿtÐ’o{ýÍ:ÛìyÈ®™Øq“¼d&7¶ÉÈEnrKÜ¡¬ƒ¥¢¢N©‰HչꇲAªàpˆpYÜÕ®Pª]\ÕÇoö©[xÄûW¾m‚ºjEj+¤pƒ.»21ø!C(*ɈlT#v}äE®á0ü‘»âCàœ3kh€ó•ê0ð€-×à—\X¯œûþÿàzØ$±7ByÀxÀƒj•ØÖ_q²ø€«$YOw Óî EµÌ³wnºL>ñ¨Y2Ý‹#@×ø2Ø^zGö§ÌzdÊ<™ÉÉM²”eå™%H§« ¬h"Èçä/€][¿ùM/ 4ÉEþ@‡Œw©¾Zå(!HÊÖg­x–Œz繡Yªlž`ÂÓŠMôAq¼4ƒ´fÉ 1‡Y+—«JÒ¹¯‘|¯"¹†á & ¸pðx‘!ºz¨†_ë´È-—j¯é5C’ö“„Îljò%Š·Fújž€NÛ^ ‹,(™.á 1‹]"SÖLjcï©XŸe„ãþÊÄn䄦ld”ÙYÏ:!>1Ûfe­õZ“ö$ oÊÊ®pS Ór I}·iGû•J%€^ƒ·ÿòç?àDe&ýCÆ7ŠóDu‚E=¯)óg§õ“uà ^Kö`P»*³lY…c(ĸ־U¿­QN& «œ‚sMNǨ†{Åaåöº×·ò‚s0A¼^rå3aãdÓë^ýÐ`çIB _$“t[+†ètºÓwç±'á—ˆ’¬Ó¥.avOÖ š¼˜Ì¾Qîª5Zí³óÌg”¡™ëÒ0-çŸó O)ŸFÙ;KÁ>¢8$RÜ &©¼Óþ$)‘xëx¯éëð¡~0rè·¹ù<¹53ei³†³‘€ìÚ<†Y⼶Ѻ¡¼™kðŠÂ¸Þ ‰1ÀТ1¸½‘@ÂÚË…’à à{9ÛãÎÉkðšÎ1ƒ—@¼Ä»†%̯¨<š¢ø0ðã‹)@ î“¬Ê Ü‚¬øÁH€]›Ë’±0ú Ðb-Í8Œ›¿eû…ú›‘-Åè¿DdĵC;9)¬#6RÄÏH;fsÄÚÈ—ŒšU!Žâˆ "¼@úDKrŠŠ’T$Ÿ &?Â­Š )Š›Ê1ð).†Ë36/¸¯ø˜ªþda‚؆ z³OBÆ[1½ÀI=C¥~Ë4x€ œxà‰RÀ1(…"âšU9Â#lH¢ŽèÈV "Ññ&A" Þ©wã@çãÀÛs7©x &©ŠŒ"¨57Œ¬Ìà{º´¨,t€‹dÓÃΘÞQ™{­ÑÚú{?Ù:ık™ãº"kD;â1B”ðé G±})ŽüÁ(Úƒ·³(&Ñ4d«`ŠF ©¨&Þó‰ðƒš#0€$¨Ø¨8,3pÏaµØm$*Ž•‰<ŽL)“ Õ—]'˜5Y›§ ³,-©,±›?…„LºXHâ!­•ÖÇàÐÐBÓÌ Å8“»ˆ?§ý¿-ÚyÑ5ê^tØÖJùÑMdoJÝê '©ŠØñK¤XŸQÙËiý»| Š?xƒ°¼¼J6Ë B¦L=q×,È‚^‘W‚È.5þœí4àZÊ׊Óéä‚qU(Ojôƒh ¿J—€q¬ŸûA %ž&®¥8~GíÈFxÂ\ø¨è#¢Ìµf®`b‡ë×GþüpUü‚çÑ»5síÚûü Â,¸¶ÀÏW_áàzfÐe÷™ÁÖyýà¥U?qùÅSI=PaSh¸szø!ˆ!Š8⇠ñ áÀ$ÌI¥„QB:ÁˆD™dÒ@OP4’C2å´ÒŒ7Þ8ÐŽ9âÈÓ39‘äL9I‘/½IuePG¡£åPBµå–LAá˜|Q(•S¬£Tš(¨Ø:J(!—œ¹uFaZ¹U_íôàGähAÎeœ–z\ Z†{#PÇDuñ%+¬ìñYì¶ni6*e¥•d¥ŽS‡Tà8„™l¡¼ÖJ²HpÛ§¾Iö¯§I° ®¢Ñ‘C8³lrI 51§Ð8È¥ÔZ×ÃÕýP+â ^L¼¶äö€Ÿ{à^“Ä‚…áƒZki%ŸÜåYowÚa•Ts¸À|!ÆW™REuÄ\ð¸cÕ¾Öðà%‰K<±‡ ˜À DåB‹DP% i£•M‚”SŽU–$²O&gä#Á̱Ê4“¤‘9ã ‘E0³f—4… ´³Ì;blt-2.4z.orig/demos/images/smblue_rock.gif0100644000175000017500000000735407240160076017327 0ustar dokodokoGIF87aPPÕÿÿÿRcZZkcs{{kssckkRZZZccJRRBJJk{{cssZkkRccJZZBRRZssRkkJccZksRck1BJcs{BRZk{„JZc{„ŒZck9BJks{cksJRZBJRRZc19BZcsck{s{ŒRZkJRckkscckRRZZZcJJRccsZZkRRc,PPÿÀÐæSØ„>MÁ y ¡B4„Ú0ϧéøxèñ³é¶BÃÆð9¬Â!´ ©¥ÍgñãP‹…SFn jM '‡_Gsbs*kJB*! sRDtF˜ks+R+h•O Mdk+lŸa•œm*¼lœ ›! Çk)·up*‡[Ì* )[{Y[°—BƒSB•”‚·PudskÈÊMM+÷ò}+Vj+,H$¤C“)„0ùðÀÈ&IÞ1BL¿„cºÙé×€ !C€Ø2 Qu¤@³#Ï@ Šœ9àñˆ ³è¤S ‰ÿ7+Šè7‡@~}²ÓmÐ[Ô ûÐá 5Ÿ(£…S%,C@‡Y•¸Û¦æ ¨(°aƒ ìÕ˜ÿdSÈðÊ‘:â20àPäP‰”‘…„áÍ#qäÛ`†cE!wî˜@  ÃÛ˜#"B3AÆf@…ìJ7²3‡ †/§ •Ø•õœ@),@9§HˆËÆA b…`u "¡jE“,~d.¸Õ„ò…´ &ðF â0xíé#!@z”3‘#À, )â!(…†•$nÝ¡¯R±)(K’X˜ÜÄ'N<É 'PdÈÖw'8ÜBŒ§PØ4S³´Ùì*"æÐ DÈx bÊò€˜Â¬´áBúCÃ$Â055ikd`¤ƒ'¬L7íbeâh ¯Û›…`¾)22z´)"å¤àWd™úQUò•* Æ™tx ¢ú·œH¡  ”œE[ìK%@É9Í [˜7yÉ+¬G‘ØÕ^¢„. Â+ !j‚/ ¶¬ +@†N^PM8 r"zZ™oSæÐ½$Fh¹D0b¥“¸ñ­~eIXTüQ—iR”N)×ÔÈHÀJ°nºAŠf•8„$&˜@ÓëüD†ëV¶– EM!ÁR%ÿ˜¥³ëÕYh9C’ ²2Ží1aè.ùÈ–Êe÷#šÅÕ¸|T4÷e©¢Úã˜À:iÒ„ÄrÇöl#8Àè„s’© Ð.Ïèúˆ;Y.Œ(ƒ¨þ Fæ»"-p*t<œÌ vƒ¦Ú¸óxj˜¶óKeêr @o±0üvº08M° :áUcà$`ñó¢@à¡¥yª^^`˜Ñ'+#M<Ó O"_©ÓSù#÷@´›Ð <š‚sq¡"á"ÛÐnù8#FNkèå?â÷\r!Òça;¶¢›á¹=öðnB C¿ IâA;blt-2.4z.orig/demos/images/stopsign.gif0100644000175000017500000000040307240160076016654 0ustar dokodokoGIF87aóÿÿÿÿïïÿÏÏÿ¿¿ÿ¯¯ÿúþÿ˜˜ÿÿppÿ``ÿPPÿ@@ÿ00ÿ ÿÿ,¸°ÈYž½ÓM³ÏÜöW(‘覩ȶçËVŽÌÖ6Š;Èp<‹ƒðx8 >KcˆÈPà <Ôß‚ °^†‡‚a™ZÂ, ْΘÅîöbû~äË`8ww~{yqs€s„lt[Y[^Žgn[ Švw y[ |o€˜jXz“ƒO ° ‘ ½} ‚92Ç#Ê.Í*Ð&É9Ô1Èר0;blt-2.4z.orig/demos/images/tan_paper.gif0100644000175000017500000004473007240160077016773 0ustar dokodokoGIF87a  æÿÿÿçÞÎÞÖ½ÖεƽœÞÖµÎÆ¥Æ½”ÖÎ¥ÎÆœ½µŒµ­„ÎÆ”ƽŒ½µ„µ­{ƽ„­¥s¥œk¥œc½µ{µ­s­¥kççÞççÖÞÞÎïïÖççÎÞÞÆÖÖ½ÎεççÆÞÞ½ÖÖµÎÎ­ÆÆ¥½½œçç½ÞÞµÖÖ­ÎÎ¥ÆÆœççµ½½”ÞÞ­µµŒÖÖ¥ïïµÎΜçç­ÆÆ”ÞÞ¥½½ŒÖÖœµµ„ÎΔç祭­{ÆÆŒÞÞœ½½„¥¥sÖÖ”ÎÎŒµµ{ççœÞÞ”ÆÆ„­­sÖÖŒ½½{¥¥kçç”Î΄µµsœœcÞÞŒÆÆ{­­kÖÖ„½½s¥¥cÎÎ{µµkÆÆsÖÞŒÎÖ„ÖÞ„çï­ÖÞœÎÖ”ÆÎŒÞçœÖÞ”ÎÖŒµ½{Þç”ÆÎ„­µs½Æ{µ½sÖÞ¥ÎÖœÆÎ”Þ祵½„­µ{½Æ„çï½ÖÞ­ÎÖ¥ÆÎœÞ筽ƌÖÞµÎÖ­ÆÎ¥Þ絽ƔÞç½ÖÞ½,  ÿ€<‚<77g:4<:)+2(0+<4202ƒ@<@F:™C0::FCœ2@J:5f)4D@k70‡:007„:_‰_CJš@¿š™ˆ%CZKy#SDJT° 3 :Àƒ„‚3™Ì% 9[زÆÂöËFqÄJÁP4 :hqC"qPD‹ 6ôrÎÿËlQCÓHfKdã,'É,g €‚ÿQDM:ñÖŒÀÙ±¥ ‘<ó`2úÐ@KM„ÌÔ5’Øð&™ðÙÒ/jaÉ)'ˆ¿ 2D!xò ßCðó F ªR+4£È‰4üB@è§%†­2Di¤PH :Äaà ’Ù•Y…‚«Ð'M:6ÑЂkžðN  Cg>–ÐÏ7•4ƒ"A’Ø„ˆ±Ö4œôòâ>|òjbq‚¬ŽÐ §p"Mìª Ì@Ć 2sÃ#‰(a’8éÐ2¸å³ &ØqÀ*n°D È4cS:ÍT¥ŽlÚ±ÂÿÁXmÈ"&kXç% oX–$-(Éx*]ö’L‚<°é }^UIŸádBÍ ÊÍe Ž‚x† Ÿî)âÂ!à´µáD³Ä 5Ö™F>­âÈ -¨“L ¼É9îXýQ´’Œ6¤M2€æ;vD³é,9èð$(psLC-GÄžŠ´¶ï 'µX”l/ e8µ”‰{ørD¾(L;:4òÈ f4ËÍ;ä5£¹ pFÃD2$±$)Hhâ—2p)Ù4H(1'[Ó²GWqòMa4(àL´S½…É&e"èräX¼òæB ò“ òÊGÍÁÏ8CÔv&ÿ޲`­¤áÈÿT(ÀR>›4òC™8ðùDç¤@1‰/-¥À_jLò†g.5ɸŠß䯒cl_‹G´ÂB/j¬!i”Ddã0…6âÒ-Gj HOKÀ1‰„[`@F™¼ Áù£FlànTî:š{Ã'ÂJ8ì .pA:P°¸Äˆá „1Ä© äùšð :%¦kp†3%¨Dn¬À”¦Æ ¹]¦H ¨fØ­åñ-EúÜ;¦h(â>—‰›Ë†Ì6â“Á4öÄ ˆeE'`Á `à‘Ô€'Ðê6äV­@£F  ”Ö¸íÿ ‚ @IILã”ð@F*p€á PC ºµBþI ÌÆhD™#D`9€1‚c´à)âkÛ—H¶‘¸@ya€–Rp‚Tbl:PCZLjUŒãsnX$ ²Hù… šp[#hñˆ-åŠ-x€kbD|Øá_i(¤~‹!mAy3D>„RŒm:ïXW`ZÅ^þÅ TÉ€´Kš°$¿`ÅÔ ~Íæ‰9ƒ­h±‚] BÉAÜg&p†9³øì¾q4t—i :``‡|ÐÇ3ì[d $p,8áA˜Ô¼é¢Ø‚À=¼%< ¤íÜÿx`^$¸¾¥!G ŠZùÀM]F3ÑW/,Ñ69"‰Ð  ;ºÒ€Iny .GI͉¬ˆ2‘Ñ• B¿«Ð@uOŒØrq¿QVÂ5ûzÄ(„‹Íe<›O`à‚¸Ù.LÖy¢>rÌ09p×`tàEBÑ@ „âØa6E#aÈà°Ý:f•|È`s€ÁšÀ‚"†A’£â07(2йbšQˆœà õ¡a¡h¢0'ZÜØ×C¦b‰80€zûT@þ5‹С_–ðœ_2—xá ™¥o„¡#mä&Þ‰x.šñ )eÅqV‡jd\ëSÿ‘À!H-V"áD’:V±´YÀÀ „Hn"·¼ÃÇü P¼ˆä23bõ |f' Wp-àfqGÔu(>ý¢ XÈ/ŒÇèèN&(þƒ7˜ÈÇaZÁa€à€þý†Ű–z ¡¡f ¢4›Jy”aˆiìðÌh‰pdB 8!ðw¼ª/Ég&œé3°6q8ÊR”JP:@AgßЀDYf%0’´q€ÅÜ‹A¨"ÈÍN‰1 FÐ'êCËã[ BÔP4 ÕJg´A‰g¢¢Š{æ1'‚ú+$’`Mÿ!yD aƒ´ý˜‚ìlÆ/X›2Xd3§h{Ji ÕŒá‰ÌLü—_(¡ M@FÜÒ ˜A:HCdPj–°28`¶;…@*u—‚ˆB¢Èûþ(`D+(¨æ[6‘H¤¶TªÌl¬óƒll  E¶3Ìbß×9t簞‚…•žÏTò=5jMXÞða˜ ÉÀ5@Ú#÷åÌ!7ÀØ6gCài 8ûqPt 2ŽéÌ.0@ B¸8/Z£ÔöUêH€?–'+xÁ}ÞXF[Á$›(öMÆ L‚i8š!‚* ÿt`vx€ølà.qxKn†s„r‡‚$à'ð—c¶ ƒ7PP‘ÑA64`&­ƒAf†ê‘xš µ€‚¢0 %)„ŠvŽú`ù¦,(†‘¤.å Åó@F@›F\CSY 鱈à4QRËŽÒP°‘ HÁMRâPÊ4»1€ÑÔ‡DÒ1´Y: ð† X3``Ї2Ÿ!–©£~Úp¥ÓnÈ0 ~ô ¡ #gp¸wÔ† úq‚t3(@;B‘gã0Õ7ÞÂ5aÁ "àßÔL\ƒ·B1!DЖ‘$7Vòc D4‘ÿr/‚”»'p¯ïP$†× @DÓРEbuãä¤" S\K R¸Ç «LR7`,°{5=æ/ Â)@Ô°œ“‹C5!DqD4 b1¡eb:Nè`$àR­á*i)5(íÖ` /¢Å ÝÁY>0.@0\„ç'zvr )À|üð0 cgT£a×*Ÿ0Ý À5€« ÅQ’´ éT Ÿ3;D$•¦o„² ˰4I2T x.°BWšÂÀ9°:²š!3(ÿ Í4Ð(x(€T‡j}Aq7 )@„Ž !@-à!(Á XM3!48PR<ƒ7PçSZAf®B¡e¼± jÀã.7ETR1Ö`\‚4‚Éà·µO~·0EÉG"€J’À0,ƒ‚f@=e}ÒgðH .pÁ ÛDq -°) R‚Âeµ!@Ðx[éa•àÿ 9pãÔ+޲.–™ñ[‘òw‚²Ô0.ó €B,2)€{8‘4"H7ðKÆ?âŸH #1.ÀIãÄ­y(p^Ø&)p+lâ?Þ îp760 ãq¥`Ž7 DÄB>²0z2)¸ °j q *E ÀfQe2°³0$*c†±š(°…Æ"‚dhÉ!–ŠÀ [ÀMwŒ”pNG‚½Á¶¶” :P˜géivP qÓs< 1h&gpP{D“°[ :âx(`'°H° EÐÑxÀÉ|{òÿI§{Â=0.p>P"aoà?p:<‰d$a*P~W©M`[Y)V!/Q2å|³rn( 9 Zð Š@¢´X{­–„) À¹=Ð “á³ ®E›!`Ÿ¢kqB•ó—(à)  á‚È0'p¡úÆfà£X 7À%Ð)B ìX]ã6”ð-ð+Í“ ÉPÂ’!Ÿø[Ã*Jà'Àø(¨#@Øà+¿ñD1C³´#ã&çhó'…0 "€ôÿ=òHaÔ“ût‹œqð/çDõ  ¦ CG92C€;§,5Àt¨EiÐg$YZ`\ÂZŒÀ’&sȰCR¡ë8(¥¦Ng2ЉÇDT³É#@-àœå>à0Jº#20tU‘ f°H>cß‘§19. É bjð7;#ˆP ЌèkŠð/_¢%•P tqò£¨¹ÃVÛS¨F?ã”+õ:Ó á„Eqº"`#@Õ<Ñ¢HÑ›"SŽ’,=šqS930E01pm ]*™­Ðÿ6@&îr‹6 h¦pŠ`\¿@Œ&Â$Ž1¥B2ÐÔSá.I'jòeÔd6B¢L/÷)®­¶^„· °'À„ptP¼AÞé»–;wK¹)¢¦f‚6rXýA ` (à§©5  D±a‘VMœ¹<ÙËYYài 1\Ž÷ œàcÞæ®ÒÀ*p¦YP"2ç”â¥%[Ò`‘½sI‰@‘µ .+ñK¡)˜`}К ç°h÷Hñ*-@AÆ—N sÁ|Ž–wb mØi sò!0¦E ŽÐ,¢0sÿ †v.6P2Û†'7——‚B5¥€B40Äx^û’+Ë7¤’w1(`ÁF¯2à?f‚ý±%(x}Œ°XQ>ÅcK!Àb¬ …Ø žZ–:Ð 165,C*,îppÀ° ‰ü€w4ùPa ›ð¾(àôanv^û4,0,0 ÿ÷+ó¸À¡IZâ2à:‘·6  ÁlçP ’0@ØV `•+ Ûô¹‚Ò±$Ð<ë’ ±±É@1>A„Ow+ã’q"p0P² ñ[´` 8¶Hê’,/‘×Ñ'F°>IŸ ÿ­ò[ÀOŽšÊ N‘6pG 2Ò­”ËC¡w€ÑJea(°°H!€¬óh z¨\¨ö[û2? Çð ;¢‡ËPqã‚{>¦xÉ5â@I¢b±¬¬™ ¶a õÌéÁenÀP•‘©òC!äˆÿ©ÏEÊu\“½k Ëá†lºMj1Ù®@QeƒrX¸R¡q‹+µ‡vCš­v­&ÙèZƒB(Ì„Í0z—¸´Ìp+¡1I¨ >Ú<çˆmµ°aí¼ÈÈ?˜­°/q ­‹' )ódzà¹^l"‡5æ>N‘žçgÿ‘¤p‰9™‰»t6 R¬ pjpW ßZË-<·Šg3.1)ÒJ“H M5XW˜ ÐQ JP€ÐDà ¼¨ý iàîÐYïP )š@§Õ,¥‹$ß‘ÃF* vðšâ1«‡Í9¿¢¿Vñ(Hq6 ýéi)³ït/GX:ðêP> ‡Ü¢=¶*‘êðGÐ i D(û¸gÒA;ˆ†tð†¶Ô¯¤”Fà„î (xŽH1ô§ñÁï ;à#Âtãð)¦t”š¨%\â9Ôà`ôàDµëÿ €¡=ö 1RÁ?+àúR•à!ßÕÙ š H'D5y‚@(!`ÍÄyE20†÷ò­@Ž¡:ù¦L’àUJp#6;§e5@ŒµàV ÙÓGÃÉÐ ‚òbŠ œ+ oñ+Ä1 ƒâ¢>F Œð=Ê *²_œÁU*Å..ƒ%´ Ø'Pºq3N ,—a\!Ô\æ;ÖÑ 7À7ÛÐÆ'C=5°<Ùà ñßö/ ù©Ð:É‹j —Ä|;¹)ÚëžÐc„ æFñ€Ö S×4+ƒR“ºõD­CW—E‘àø¨¶°ž5ÿXz¢‹tf@„b6¢*IÚ ̓"Y> ŸÒÛWÄTºêP>pÔ~3x'J2°{lÂ5üÀ¼ñÉÈP)Ô)U‘¤m’,¸©6ñ™¼(… •é´p‰fQé'0è *NJR ªEÀ*1z‡þšä!¬bdà³/œàHœ%5Ÿ@CW$ý±aóq$Ôy«o³‹À ¦²k…¸Z€!‰ü!E7£mÚ0Kw›Û˜À¦ùT«HC]íÁØfX𧻢E²s†$øZ];P4† œåCàYÐh/3:Bœ°>€o0»÷ÿ„Xœô?fæ/˜ó9ËgÜ6°RÌÌDPH-5ž§­@Ø0÷è âo€fMZ6bÐeZb8×Q µ‹|,ÐÚ0î¼Ê ”«8·Å;1–! p¨ø•i  `ŠP¦³„9ßë”Tãó"H›E,‘ÑBìq6C’É §1É버™¿ô!Ćˢ)Ø2LoÏg…¯^{IÿÂEP÷ 4(074<::g)@@‚@i)6FD@:e,&(†4COU55>:0?<ŒŒ—G62 4+69š9D=”6@<À42g:4o22i6Â4@ÿË+È0Ì4Å_ºG˜2<¾bÀDGKD”ŒDÎD²4ë:)…¿È@JŒ:2?È #)2ˆ5'(ìÐø‘%U$ül´ð¥ÃitLâñ£Q³J ` p$‡Ž-? ùaäF‘‡‡0²¡‰[ÂüúRaœCK2RÄQ°Â™ŸÚÔd!M›°–”üÌÁôP gJ†\Š@d›"bx‰â2DIê DÍ•/‡ixÆ!. œàwC P²`hüTã†FqXÉúå B`)L4Cäw‹"ˆX9ûÆÃn³2„-3´Œ¤³{24ݬm3ËbiCeF&y…-6mÀðI3Aã–%9ÃÃ?àc× úI‡ 74RZ|šÜÒ6¤±Â-¤¡ÆÔh €Ú°?É1Ò=ë¼´Ž<.vÄT†¯9”f±Iq^¡ý¸éC|ÄnÁØ`AycW –ÚSÃ|°–£É UYbȈƒ4i#"ÍOÅæ&C™ˆ $ÂO:ÔðW |&ûH%ÚÁèO9ã±£(YX+–æO®µ € 8é°~J„”ƒ4P ©«`‚œu]ö`­ ð¶á 5 Pè ÀÆ[.°åGö¼ÿê:áŽ( sŒ ' £0ƒ;ø%‘£I„uƒ[¿ÔU¶’áWN+\’&SÛ™Ž@!COÍ“CD†±œ Äa™ .9@T`®[2Ð(%#Ò@Î9Ð|Ä‹©"Ô¯4-¤²ê .Ô áÚ45ˆØƒ‚0tÄJ††TÅCp±`FŽ#ày#š‚B?~ñpíBJj³ÅX»,ð’Ç, ¦™ýV-b,¹‹.=èR[æþÌØØî×ETÔ•ª‡¬’µ%^XÚ03´ÿáÉp"VR–|7Â8z`½hÖ°É%ódUÀiU`s„V<@ @øaÔà‹pHà<ø‚%Œà…bâ5¨ˆƒå—‰§D娄ÖFˆØ‰Ðj°DDà'™&A5x–ÒÆŠ!„g8@΀œÀÀÆMrú2°ŽôÂàZ€ïî„ œ¡°ÇÆñ€nÃ.iT wñ€B6`!¿Hƒàn±‹#Ìc@x£F©…¿H¥°º„FÃh' †%Ð'„Ðã9z„¦~Ãý±. :xÂDñìÀ «!“T° $€à£ Îóu¤ ú+Ï!jp‰°é5(IÂnì‘@ü`yâdÅ:E œv  a¸ŠˆŸìsy‰÷7âá!óµò{‹%k©Á¥€F3œëY”0 Mµˆ[˜ÉrãD¡  3°¯â\ƒG»E?¡`‚2œ„µA¨±Ù<¯*t‘M€ Æ/7öepH eKhòØ‘ ¢Ö ¼Ägmf°3„ Åxz´V:Î= "ÔÒÅCâ|ÿ>\’ä 8‚`p&’ñÀ ¶Y vpJõÔÀ¾í‡] ‚¤ùöh mVƒ§ s扬7 €šbLކ€>.7âSHUB ’‚ͮɴ „NÏðÜU¥à©ZÑCtQ²n#M9A1‹Úá€8¡ÈÁaåHcy“P\ ¤wÂ/>‰²à¿Z#GÉŠ‘‚ºÂ™¡Á´-…Δ\E@Å VP—1x?`B| „4ƒbEkFÜòÀÆ´–³ aš­07Î\hÝú´ó‚:0ƒN¡áÿÄ™.Àxïш'!#’­EÝaÔË€ÛÊLÀî„øµÉàF™±C¢¨©Er?‹Þƒ)"2Á  ƒ“üÂzyC$*SÏ44À\ÁX‰‘âCÙ¬LE3D|ïá Ó÷~û58j¤vôpˆ°Y±?gp.à&À ÐÕ¡i(À|†–°!Æ(rb~ ‰440_0]ù´J®óQšÂ8 TuÓ@+ ?9‚v€Yàj,ƒ\ùõ‰´U¬°UˆpO#e6Ð)Ð+• «P"‡k.B!P3&æÒ ”P<4àõ€wE5`ÿ $tÀ"à÷q?Pa;…$ ¦Ò|4 ±+k0\Ç2Ô1”0†¡id<) MrR•~öÐ7p›0CÐW4`_?09"Ç€!D # @ †@v+ 5[1WcÑC&dàñ0B^Q<#Âqˆ¾•$ VÚÐ$`l!  ‡GâBü[=ÂÃ&"7§@$Ãt¡â]o0&E?ñæ²FZÚ ( è3Q ~áx<t6Ï¢V' À‘!à†e’ua!¿1"ð†<ðÕA…? D£ç1\†EVÐä&aÑK30ð§L…èôy0K¥dXF@(¸'X+†d*¡ØDð‰ð5¦+d¡4kãiRÿsΰ6Ʀ€9‚ñѵ4b !Å20 ) }£ÿÌ iÔ¨ƒ?`‚K¹qõÐ*q€Rã ©`ß1 ½yýðÀð4×– Â(ôð aHzñ0vd6e$I ÄeG 4Kußñ ÔäyB d† pHÄsopoð5á-A‘ÂðÖ50ÒpðÓ4°%±ã2”–‚¹Ä/< 1‚PK†xÃô.ãi¨”o02–C“-Aã&¶‡Ëµ ¡'¶P 40— šòs•! TLZÉÔµ}•“’,A™J2l]°6Å ΈA\ 8r¡¬ð¡"—ÿ# `ôprÌ ð†0\ÍÿB2Óâ æ@ #`¨op£V ¼Ø(?ÄX2F!Ñäb ø€5¿ $B" Õ$©Ð - ~3d’WA.q€fÀiÒÀ+ð­Ã†tSaH\Œ 2Ëðíàš,)à^“^w(r37±Õ@`’Oà æâ% âS#à êÅ,ÖD­Y aŠ €Ÿ+Õt•wŸ‚ ­x[ÀT÷±:²pkÔùµD]Z,›#•/|v$]@+]B k2bÁ÷0•ÑÌZö -4{7¤)Wç°sK * ÑÿYæÔ(w²ƒœ‘:Ô@r¸€ x± ?ÐIp&¤Õ`Zù‘фɀ5àÚ #Å©/¿ÀJc#à$ç1PXo¡?Èp) ² 4CZã(û:/Q7ùÔ,+°:i@q çÀÛ…­ ° -pYA4GvP[±C %Dp#Ó’:°6"h[jé—¯zHÁ‘]M2 åñDQ<çA# Œe+µ-Œ@F ‘Ñ´u‡*`4ÉP xHäÈ2¥¤Š™V CÏrÚ¤iiP@Ä2[0\Äåš‚P¢Å P”bù"ð,°ÿ0ê’¡€R¢¥”ÉVJä6Ž W©¤zfÔ:­S´h6A¸…âñb! NÄEÇ7'F1‡¥Ö•©£ wòei«ÃV„+£$"eé @! ªøÐâ ñIÎtÇ=sæ #°“! ðÂ?  ö`À}E@†àÛ°rX¯•¡j:ÐkìÁg€x‡Hó*ùBnàV¥„?u#°9”}íªwv@—ËO4 '›€Hòyƒ °œ’#`4@$‡ b“‡j%)6ðŒ8L³k¦¸Ö@qH½©\)X gP:ÉGÿQCÀ`àB0rð\öE/Q^!µ¤¸ÃTˆFS:Ó5qûóÉ‘°‡ÐD£wì— OL(ù~ªѲ&-08A‡º€# o  € -dÌTl4·ið+#C¡JR‘L9¢š3¡jà2  A:3èA! `9ų¤8B(çi’Yâi¦Øýà! Žy>™kñµ_# 7Üë úõi¢/Ç· „¡a @Ð¤Îøyb9Èе® l!6 G#±8kÐ¥da"çð4[°L}!Icpkðî“)Øzÿnà[ ¨¡ØA¬ðMšF†rDÐiމê( ¯ øÂ!³“•Ñ#J¤«²Õ•XÚ3nAM@ÉK¦ÿ¢¿1¶b ‡ ©‚¥Â$¡¶.Æ^u& 5gºcc,Ð _°`‡ðޱSv,ñ:}q R™ÜÐëµø!à~¸2ë$ͤë]nt,²°&Âà¿–1id uÚ“‰ŒpÔ/‡­í+Ð)& Ä ›”Cà‰ŒÎ@p4- [ [pê«J¦$´ò @ o° ôÁ`U  ?}Õ°¤ÿ4:ÀL´E12`!0¹U &… iºKv‘Ìq víp²T€­'¤¥e`³ âK„ V7¡q;P9}‚ñ¯6PPИ'àÀíEd§ "-v’Í ç À†7 lDcñF"¦€ q–¤ÅYZ0,`+ct`#@¤U»¾ßð C)2Àä µ“±Æ-!â 9 '‰L0•±zÆÂ7ã@.ªÃC¾)C¡Ë3dbD¼ xÁÆC;=¡P0P¨!$OvfiÏ @+¬3ZÈ€¸S"*ké?¾¥ @0tà k¤€RÝñÿŽç ÀKh$2¼HDAì }ËT)Ð$êl6*Á£ýš¹µ°ù…ðÂ;M±¼öü@”=Á³‚>+(À±ÃÀD!èHÑËS5á5<ªÖ¤†$$Hs\F²6ª2)(@ °”~+@¾u+®3Ã3 y!!ŒR3¡². š0ŽÙ§€4z‰û,zyçx´å›^×ÿåWáx$“wñ=AT 14@Už¶dÃÓãèI̸»“oáuž°S#¬ yÔüW¼”_r$Y¾1Y3°;•^9ÁNq£ ú.€$Ïå§šq÷H¤{ÿ,e’ðÓ(@~0à!‘DãðŒ/qÔµ 1P …"ð†¦Ñv0< » ê5A¢ávò~…R5(2ÂpdËkÐ$¹^±E+ðJ:@D¤#ÐpÉÜE¤3¥ éeÇ&j² 6¾ù´€t $D›œR²” +Òr!p(³w*á&%‚'ÒLÎ AƒW],À˜·$ÝÝùiäѯš"0ãñ5»ÃÓs$û“—.€ÉQç!ð†‹N‚"ÎÞªœ¶ì¿QL–Mz!œ íÆÝ‚ 4á…À®€€Ýõr.’ " òtØ yH•0ÿ\f@bËІ! ! ŽI$o` ¶µ_ nÀãˆ5Â8)SÚñ&YÁ‡g(€i_?ª¨ 6‰Vkñ#†PáåiÊÒ›¾):0jvæuû¤©@“K ŽFJk::(+!"(6NG@@:@G[7:702<@7"!('"-6((!Ї)422…F?72­q:20·0Y?…5™7.0 ''&,2)šo"+4Ð(q$Ðv"")):$!Ú664:6@<+o<v@’‡Ðüé&ÿ?” É n”ÃÃ<¬qCB <äðà@CG`ƃåijI8~Ú@ ˜“†9$øùE!áÅ%i2vD$ÁcÃ>v´ÒBá€6øB°Ô”‚ (0Œ…*aS iŒTÎÚa& ¶ÂS–Ó @C6(ð$jä † ðŽÃP(Œs€ø]²‚6D6Ù~DD$ƒ*K b)PŠhqªsN8€ói4Ô`n‘& G˲q$p‚>È gÐà€¼+Tóð s̬ ˜£ô•4ˆ0O+1ÇLÒ Ä%B’6ر‚@€±òrí$§D+ÏJb8 C$áƒÿLlÑ´ó4JÀkDIfàº<Œ ƒ$Úá,`<  "Øñ^;+ªçËáOiæ&q´ÎÀvV48]$köL^5Œ4¬ôÀ?Ô#ä°$|¬ÈP±vÔrΘ^"IJ㠄“&Z‰”ØEx1Ä?¬¨Ã±“‰c„:Q…F0‚@ƒh%J:0'Ì„•€hÅÆ8 !º`+³Á²@Ýi…@ƒ/,!éÐ Ž¨£"ñØ €‚9èespF)ö…°VÐAJ@À’fö1eÈÀO±Š Öuèಀ޵_Ì"ÿÁËÅ…Qƒ£ü ùÁ¶HwT‘/ ´PaÄ…•´dX éŠ`äÒ‡0 tÝ1±8 óHŽ9| h™c0 ŽÑ€5SРÚèx¼h"}:¨Œ@R \˜eP ŒC ©h=$R!äÈjbøæJY“/Òp‰¾˜Ã‘ø¶Ð "Ú .aÈZÐ' Á»žhVPŠ:¤Î ˆïðSˆè4`øáˆD`•NèÀø (‰´¡+-€¦é̃T)áÓD(ùr'DB” &AüÀIš}¹D!~!üÄò>QÊ&*&#$ÁÿIÔôú•£îK@Êr<Ť³/ÐàP €°Ù nˆ2³iŽHäâ ¤Lƒ@b>0AÔ@6WØ¡v4Hi 3’uµ"fqA@‘ÀBé åo S¦±“ãÐåA"‘‘¨ZP¨Dˆ „Žb“"QGÀr+í(bIB °±Ï†d=~êç`zð€à†ex1@šH”¾,€TZ'(À 1 D¤9X@¦L¦¹€$ïj8¾ô¬ZØÀ< ´³ð9c/ýLgMx²§ÔÐÒ&„¢’X:Ãkfîeƒ5 !´0è‚ShB)ºÿ>8B¥ÐvK9‘Ö ÂáCðÅ0Ñš°‚ PHçZ@µ±åœ Œö(†]­ 4ƒÓЍ7ŸxÀÈ¬à‹ŸTŠ–v‰$H‘A ¨#ƒ!ÀÀ†Òä.1„/1é ~ ðƒ!´€.5hì0… tœ(K¸8D×r¡pleÿÔ±Œñx¥h‚]ZhC.èB;žá'¬Ô‚v(€.<t¨+¸ÁõÞ`;ëAðømøRèI‰^ äBÀT2ÄÁ(0*‚pãHüçîTZ.8a„5ŒDS#«Àn8AܯÿYp$‹‰ÑB"1¢Ë̳DÑˆÒ -àx6áÔHrƒüg Kå ^!\4 ŸºàÐ=˜ùŒVüm”ˆ@»´å ä=0fÉô…»È¥©<ƒ :ñ ¾lÒ›C24<«&ð0O‡v~T1 @ZÁfø< ð1 a ó0¸ 6¥.´P¡À@rƒ34„oQZ<µ?@Šq @:·ð6C#<0?`OìQ@åÐ: =`2p(B8É÷[¡ð+@{Œa&ŽsT5RÁ- B<@`‚AHá£m‘ Xq0EÁy@2e'­´9‰"+7g ;›E0r0`1(ÿ<$áS;˜6ý33‹Â` ÇbÒ¡n擸b€A<µ-N0á3• }òK”ða Š½çFàD¥F€/ëµ2OׂGN%‡„-®“TU;Ñòiµ ¹ð:01*zâ*pv€I7P~K€Bè<ò[t‘i5Eqº)–ˆ ]Då ÓכğÃñ¦'!òv!‡Ðâç|!S¡ã +p ÐMài Q;‘(1âfÚÒ q`Z‰ƒAðMU•" ' ûðä0…Ý£e 4½PO$05È´Ÿ'ÿ‘ódvFe™ wq„ñGþp¸4òjà€9LîA€¹Ðî!| ¥76]HC×Mæs'cs-œð¤-ØÔ^òJÓ&(>?0Ž¿!>/ÔJŠa3ðA ÐEf`eNáB eô-ð°t´ÐIeƒ(Ð@¥ ’„sbÜr…ky¥Xó 8¶“[D |ñyêðEÞ±Á@O@1ÒR¾I zÂÚÒI¸€…'zÆÈ4ÂY2'3Ãfpͳv™‡/”„ð-ã@Ð3CPNăsQÒ“2Éq*äG K€b Pÿ–DŽÃP‰øÑ@@5(а¤ÔÕÿ wÉ2]´J /)Î&t˜p¡·‘YZQ<à$Á8lfx/âN33CQ >Ô‚è(yZOЯáDqŸ B6 ~jpQ€b°ÖñùyoTB‘@?ð¢9hO6ðyÀ2¼+ Ñ ‹´|‘ 5ñpnpsìQ_ÐUA$‹BçŒyÿÀ‘¿ÅŒ%Ù`“åP%…‡…!ƒÙà4 6 .tê0iÈ>’#$Fø1 Q°G°€âÒsX–D:R2bê €˧ÿ@?p¡9vø s }*.…ð¶D;oæ }JM;øŠó4 гÊ @ ~q; vPŠ.¹·E&Pu0‡Q'-x€ ÅŒâ0ìÑ(vjW0iÐóYâšQã!ÊïÐUJ‘ˆ1òD €‚i°Ï0 úD…ð[¡t žúBa fàzpaƒc#a2#?Áb` uÀP‡L$ñ°|ѰÀ§%Иm6 ®“+8´ÀðXAÙsƒ`(Fuœ@  DGàXOS /’ˆþôlYÅb𤑮 ’:p=†7ä@a»T@×D'0. €Ì©(Â….äÀÛ&ñ«0PÃ!¬6ªá2õ0 ? Ÿ×{N!ÄGਠñyÙiðY ½÷ê [°DéSN O¸¿B 0ZA£~ä*[blË6u-·µšp pe À¬G¡ð 0@%JA>ð—à þñQ=r-`‰1¹à0ðHUfCVç@²i>ý@Vk *¤^† @PïáFJá,ýs~z¢)öHŠÁ‘Ø¢1l…<ÙôOéó-eÒªÁÓKs0 ’f]TÿgìNÊ_`ã¸ôD?0B ,¬@Za{xc2/Be›€ÄÔÚpthî@÷0ž Q›4s<š³fÑg­”«5ª9ŒUG8A“ÔÔ²µ~âà¢4  ºH¾ 4:0¶– ›³‡&p ©ù0)^À”U`*ë8Ø Æ3NFDgxA¥Ë ©Ýo"ç¦ib*™e-Ѭ4ì1}2p `sßò„qW‘«$¹(â@6‹Í÷ÀM@¯ãð[†w…p@êAu ðtÃ"Ñ …'IüIͶ¿÷*°9º÷cbËÎ<ÿiàtñ]BJiИáSäz¨’)}5êBê@Z û’„ýÔïðý"˜-ÐÐ\· [jx¾ *!>›¥ õÑ:Cð¾Ñ/)P³hB-˜¡•JÀþkJ#)ö4y§šñBj•(ÆA¡8¡Åײ%6+#h!rÒÁÍOô[Ð œ•M/´¾ –>çÉt˜Ä«jlj 9 `Á+3(Iv-b£„ð[Î)µ5µ¦Ù¿U i€ yÐÐq@5ˆ\£MSprBýs ¡ä¯GÍ¡=ÎøØ]U´1“›ý©@ðÎê&­jÒíÏ…ÿ T™£Y¡nÊlwúå|ÛUÿà b'~y" p P1)C­“ÖGR¥Å‡1œñ+MÕ™a'6ðÓnPÐ&0Pa!šÒëkF…¹Œ´Z`ÎB8!ÕW‘}¡;Ø¢4!$Eq Ç^Îв£ œÒ¸ƒÊ4RE…€}—§{3^bÏàÿÀž»iPøÙ}µH™I(<5DVø(ÕCÜi°8îÔKŠU¨«`âG‚i»f8†¢ `:ƒGÈ?pÉ6A.5•.„Mš ÂߣA¹à=6õ6¥“_Öªz2¥ D;1 žå/݇ŽPÿÜdvB“ta8@’š{ÙO$¡½ d QGË" Ø,À%íF…I>д¬0p êp kªªE0ã¶,íB{vsCÑê-Ý« °y&Ô ¶ø #+à'#QXøh;xå±iHd.>R~R÷ÛRAÏ:a³)^EOM…ÆŽ×%7÷¢ÿ&ì2r%Z1}pÂkÙ¬âC¥-¹¿XÕ 4­ 67¬…€·A –sÖY§o†OñeJcñœ/òö 1Ù{*¼-ÝòX^&ù· öÆ&ÒêÙ÷•bFZ±00ò+ôäãÙ.ÉÜ‚ºÓW@²ˆÓSñMÛ°³ÿëãOàgì¼FM*9Þ[ƒkr2þ)wKÄZÐiìa ÁRV3›øÑµ³‡ÂA”¨{,añe0ð-¥jx A86´b¯7£"QG‚ñ¡ä aåÌvQ 7&>ø~tÀ­îëfdk B×ó]ýª|þ€Ia פ›´]øUÞÆ˜zi’‹j‘åQ1‘ö‚KŠ~­8kБnA•›ºaœ$™á§ÜÄSoƼ›* Û7*0ƒÍ87¡Úpkí ×$P—Л›¡þÙ:ųïjÅa2.& ïe¡¥b幨øÑ~ Z¨ÿ– 'I'nFå9’o<ÜÔO¸)(49@0.(2 2´25Z:@6”C:ŒFa@2:k:>7:ë g?ˆ:7êE?^‰’̇@“Íj‡CF$µj Œ ¦5ÊDéË>I•t¤€câ*+z]< ƒ5I4˜zcª† Ož’ IÔQQêd4;XäÆ)M’âÈdœn<Ö(Ä4³cÏ}q‚*2²†Ð!ît(²æ$7?"Ý8ãÀPÿ0Lêh )RGŒ'[¥J ’U>_š*ÉXqL‡)Š(*êX±ÂΊMoPˆZµâ@Šg”aýq#¨<ï¡°©# y¼Œt„Ä ˆeÎ$SDÄHUe<(ˆÙ§„Ȧ¤‡Ö5ƒ@ÉA@#tliLIŸ¯6'UP‰â1Si|åÑ"%_ 2ÓÄÐÆ_°gdO!†™‰‚xäq’F "HæEÖ’]Pë‚5ëã [’„9$‰¬çk¨EZi4¼ÚI<Øñ%L„CHÇ [„UKëœdJ>½tô•$[”W H½8‡ #ŠÐàH7ÏáÔ‘]‡q‡•$-¬°—Z6cÿ ÁI2„…C´NØ(± gÀÀ@ vP”&ŸPÈÃbQ6>¡ÃóÅDBÀÜQÇ4㉠:£È7Ôp ÷1ȃl5°Âc’œ 3&òp%—´â‰]q·IqvÑ\Î=æÀ ôòç–=áP2“¬3ç6FL<20sß’lÍ £H2õC_¸ÆC½Å&T/:|µ ÔäO|ÔÁùæa>ü0ÄCÈp#£D’FÜ!ÇŠu%gÃ\Ù ‰CC0PQ y ‰vÜaÔœ$פa E¢H<‰üÂC”ØA« 9lRŒuËTÂå6 Ä‘Û ö¤6ÿ„JÓ$b&X´õDÞe7ÜLŒù0¤@¥$0H^îdå Y· ¯rEcÐT]miòÊ!gˆ@ÊH(üup˜\+ƒ!š(Áà qdeC@©É r«TbI*¾A[RãÃCnÓxš7ÜÅC nÌɃÏýÐ<ÆRÚ)28"É((,i nÐbŽ ®ìÃÝa§¦& ;ŽûH­˜ ƒÜÂɰ†/#‚+IE )¢ –Lƒš'bR?©ŒcD3›kÙ¯"òJŠüäÜ'„”®×<0F%¦PB߯ŒK ¸G{!‹ÔbGYò"ŽØ°“Ýu¦tYo¬@Nàð»ÿIE7ôÍÐ/+]¥ Êh™k¨ó4ÊäpÍ8é`C@ÞÌ” Cš~ç¹""Ô#7piÄŸð#¤ °ÒàFиBU"1²3Åd2W4À›€ŽßWŠäÝâÐ"E+0²6„DF:³Ë1ˆd¤x0`Kr‘J0×=…å@GÞLT„*ÁH6XC¼n/lÎqðY<Ð&U‘gixÀ%ŽA5ð ") [:"’Hô'yqÀ\²‰‡ˆÇ~™@d‡$Sä…$z²Y)6æ1Ñ&‹DV¾5 È[€&x´3qc” Ï\æ€C€ÃJÈâAR€ø _("ÿ:€‰ HbƒøD.Ê™]””%î Üá A4Eª¤2G¡ÚR¨4DÇÑšäaÄ3Šî À>IÃÙ‹t`%³BßðD3(p ^¬Ãwí&ÐG5©7žÊ jz" 8ikP'ò8@(]t‹¤&®ÕWª<´Ddƃ°#¦è#$áˆåTp0qÀoÄ3—xò…03»Úý¦iZZXwèFFØÅLž•XÑšk˜ÏD¨@k´¤ƒbXŽ*ب ì¨¡)My*­¢D²3 ;8A¿K(@‹æ¬ fÙGZ )o8 ´ªîì‘ü(f4ÿê¸z‘‚/šç «„ìÅÄ E,T¡[ÃÌ0_(cäP†Ž@'ôÀ'GH«8´ÊÕŠ·$ N¸Ç*D¬„½ãQwNð†€± åÊwH²M4‡i#R“Ùd ÍSDK'ŒÛ dæX:À °@P$¡Ùx° µÔ9½ÁƒÄtÏ?@‘xfšE~J( ŽÐƒ³R V9xÀ6’¡ªHøç_IUG¸ô20ÃÊ8:‰‘žÒ(Õ^< Qs©Ï\–7 ¶lÒ–ÐÏ7•4ƒ"A’Ø„Ml±Ö4œôòâ>|âjbfR¬ŽÀ §p"Mì† Ì<ÀÆ 23Ã#‰!’8ÙÀ2¸å³ &¬aÀ*d°Æƒ È4cS:ÍT¥Îlþ®ÂÁXmÈ"&bXçe eX–$-(Éx*]ö’L‚8°é }^UIŸádBÍ ÊÍe Ž‚x† Ÿî)²Â!à´µáD³Ä 5Ö >­â *¨“Œ ¼É9îXýQ´’Œ6¤M.„€æ;kD³é,9èð$%psLC-ÄžŠ´¶ï 'µX”l/ %8µ”‰{øòD¾(L;64òÈ ^4ËÍ;ä5£ù pÃD. ±$&Hhâ—.p)Ù0H(1'[òGWqòMa0$àL´S½… &e"èräX ¼²Ã¦B ²“ òÊGÍÁÏ8?Ôv&ÿŽ"`þ­€áÈT%ÀR>›4²™4ðùDç˜@1‰/-•À_aLò†g.5‰¸Š䯒cl_‹G´ÂB/jˆ!`”Ddã0…6âÒ-Gj HOKÀ1‰TX€F™¼ü ù£dÐnTî:š+Ã'ÂJ8¬ +XA:J°¸Äˆá „1Ä© äùšð :%†bp†3储Dn¬À”¦Æ ¹]¦H ¨fØ­åñ-EúÜ;¦h(â>—‰›Ë~ 6âsÁ4öÄ ˆeÅ$H Xà‘Ä€$Ðê6äV¡@£† þ ”ָ͠‚ @9ILã”ð@†(0€ ƒ ºµBþi ÌÆhD™!@`9€‚c¦à)âkÛ—H¶‘¬ÀyY€–L@‚Tbl6C ZLjUŒãsdX$ ²Hùy š p[#hñˆ-åŠ*p€kbD|¬á_`(¤ v‹!QAy3D>„RŒm:oXW`Zµ^þ% TÉ€´Kš°$¿`… ~͆‰ù‚­h‚] B©A Üg¦p†9³Øì¾q´h€—i :X°†|ÐÇ3ì[\ $p,8Á˜Ô¼é¢ØzÀ=¼%þ<¤íÜx`^$¸¾C JZùÀM]F3ÑW/*Ñ69‰ÐF  ;ºÂ€Iny .GI͉¬ˆ2‘ÑÕ <¿«À@uOŒØrq¿QVÂ5ûzÄ(„‹Íe<›X°‚¸Ù.LÖy¢>2ƒÌ05p×`làEBÁ` „âØa6E#a¸`°Ý:f•|¸h`šÁÀ‚"†A’£Ìð2(2ЙbšQˆ  õ¡a¡h"0'ZÜØ×C¦b 3,€zûT@þ5 ¤¡_–ðœ_2—\á ™¥o„¡#mä&Þax.jñ )eÅqVb†þj\ëS‘À!H-VáD’:V±´Y°À „Hn"·¼c ÇüÊP¼‘ˆä.3bõ |f$Qp-àfqÔu(>ý¢ XÈ/„@ÇèhI&(þÅ‚2˜ÈÇaBÁaxЀþýŰ–z ¡¡f ¢4›Jy”aˆiìðÌh‰p`†d" 8!àw¼ª/Ég&œ¹/°6f8ÊRdJP6(AgËÀ€DYf%0r´q€ÅÜ‹A¨ ÈMN‰1 @ 'êCËã[ BÂ@0 ÕJg´A‰g¢¢Š{æ1'‚þú+$’`M!y$ ac¦ý˜ìlÆ/X›2Xd3§h{Ja ÕŒðà‰ÌLü—_ H@FÜÀ xá6C \j–°.øÂ`¶;yÀ*u—‚ˆB¢Èûþ(XàD+%¨æ[6‘H¤¶TªÌl¬³ƒll  E¨3 bß×9t簞‚…•žTò=5jHXða˜ ¹`1@Ú#÷厠!7ÀØ6g=ài8ûqPt 2ŽéL+,` >˜8/Z£ÔöUê@€?–'+xÁ}ÞXF[Á$›(ãöM Fài8þš!‚* œh`kp€ødà.qxKn†sDj`†‚ €$ð—c¨à‚2Pð‘±0p0`&­cÁf†ê‘xš §P‚¢, %)„ŠvŽê`ù¦,(†‘¤. Åó@@@›F\CS é|à4QRËŽÀ@°‘ HÁMRÌPÊ4»1€ÑÔ‡DÒ±´Y: ð† X‚ XÐÇ2Ÿ!–©£~Úð¥ÓnÈ0 ~ô a #_@¸7Ô† úq‚t3%@;B‘gã0Õ7ÞÂ5aÁ àßÔL\S·B1á@–Q!7Vþòc @4‘r/‚”»Ç$p¯âïP$†§@DÓ Ebuã´¤" S\K ¸Ç «`L30)°{1=æ/ Â&Ô€œ‹C5!DqD4 b1¡eb6NèP!àR­á*i)5(íÖ` /bÅPÝÁY>Q0.<\„ç$zvr &À|ü°,pcgTca×*ŸðÝÃ1P« µQ’´ éT Ÿó;!`•¦o„² ˰4I2T x.ç°BWšÂÀ5 þ:²š!3( Í0Ð(x%`T‡j}Aq7 &„Žð*à!( XM3!44<ƒ3ÐçSZAf®¡e¼± aÀã.3ETR1Ö²0z)¸ €aPq *ÀfQe.°³0$*c†±š%p…Æ"‚dhÉ!–ŠÀ TÀMwŒ”pNGR½Á¶&” 6P˜géikP qÓs8 1h&_`P{@“°[ :’x%0$аH° AþСlÉ|{²Ig{Â90.p:ae ;ð:Á<‰d$1' ~WiH[)V!/Q‚å|³rn( 9 S° ŠÈ@¢´X{­–„&ÐÀ‰9Ð “á³ ®E›°Ÿ¢kq•ó—%°& á‚È€$p¡ú†^@£X 3À%Ð)BÅcK!Àb¬ …Ø žZF6  65,C*,îppÀ° ‰ü€w4ùPa ›ð¾%@ô!nv^ûô)ð)0 ÿ÷+ó¸À¡IZB.à:‘·2  ÁlçP ’0@Øp0•( Ûô¹‚Ò±!Ð<ë’ ±±É@1>A„×Ow+ã’q`,P² ñ[´` 8¶Hê’,þ/Q×Ñ'Bp>IŸÀ ­òTÀOŽšÊ N‘6pG 2Ò­”ËC¡w€ÑJea%€°H€¬óh z¨\¨ö[û?ËÇð ;¢‡›Pqã‚{>¦xÉ5²@I¢b±¬¬™ ¶a õ¼éÁedÀP•‘©ò!äˆÿYÏEÊu\m“½k Ëá†lºMj1Ù® QeƒrX¸R¡q‹+µ‡vCj­v­æÙèZƒB(Ì„Í0z—¸´Ìp+¡ñI¨ >Ú<çˆmµpa½¼ÈÈ?­°/f ­‹' )³Ç³ þ¹^l"‡5æ>N‘žçgБ¤ `‰9™‰»t6 R¬`a`W ßZË- à·Šg3.1¹Ò “H M5XW˜ ÐQ E€Ð@ ¼¨ý `àîÐYïP )j<§Õ,¥‹$ß‘ÃF* kðšâ1«‡Í9¿¢¿Vñ(Hq6 ýéi)³ïtà/GX6PêP> ‡Ü¢=¶*ê€CÐ ` @(û¸gÒA;ˆ†tð†¶Ô¯¤”Bp„î (xŽH1T§ñÁï07`à#Âôãð)¦þt”š¨%\â9Ôà`ôàDµë €¡=ö 1RÁ?+àúR•à!ßÕÙ š H'D1y‚@(àÍÄyE2,†÷ò­0Ža:ù¦L’àUEp 6;§e1@Œµ PÐÙÓGÃÉÐ ‚òbŠ œ( oñ+Ä1 ƒâ¢>F Œð=Ê *²_œÁU*Å..ƒ%´ Ø$Pºq3N ,—a\!Ô\æ;ÖÑ 3P7«ÐÆ'C=1°<Ùà áßö/ ù©À:É‹j —Ä|;¹)ÚëžÐc„ æFñ€Ö S×4+ƒRSþºõD­CW—E‘àø¨¶€ž5Xú¢‹t^@„ ²6¢*DÚ ̓": ŸÒÃÛWÄTºêÐ:pÔ~3x'J.°{lÂ5üÀ¼ñÉÈP)Ô)U‘¤m’,¸©6ñ™¼(… •é´èp‰fQé$0è *NJR ªAÀ*1z‡þšäá¬bdà³/œàHœ%5Ÿ0CW$ý±aSq$Ôy«o³‹À ¦²k…¸Z€!‰ü!E7£mÚ0Kw›Û˜À¦ùT«HC]íÁØ6X𧻢E²s†$øZ]7P4† œ¥?pþRÐh/Ã:œ@:pe0»÷„¢Xœô?fæ/˜ó9ËgÜ2 RÌÌ@@H-5ž§­@Ø0÷è ¢e€fMZ6Á[ÐeZb8×Q µ‹|)ÐÚ0î¼Ê ”«8·U71–! p¨ø•i  `Цo³„9ßë”Tãó"H›E,‘¡Bìq6C’É §1É버™¿ô!Ćˢ)Ø2LoÏg…¯^{Iÿ‚AÐ÷;N€ÖŸ€ðeÂÃSÂf"#ÄcƒÔ€ƒ£Ó•2RB ó£ô£còƒCH9ä ã’ƒ"S3Yþ”Ó(ã ãòeSæâ&à ÃSŒ"Ìb ó‹E;邃»E¡ 4dÔHä€ Ä Snc2sŒ#ÌSÔ@hã²#ÜbâbcCR²³#e”"÷d¨ÀeC`l0±£Ð1G X”XÁ£† *;òùØ!dF…’1ÉŒX¼äÂB¡›ÂG.L˜I€™ŒÔÂHÁŒ/Šì¬‡ ÈŠü€Hµ"@¶ØÚÂ# aùˆ,´ÑÈ*\ ÂØðÁ ¥.V qo†‹šX±°˜)Æ „̘b• Ù-ºLŒ8–o/Aò™B–m¦Œ.x£T $2y.&þÍðKí2Ê_f7Uö,2e8PQ£HÆX<„ˆÁSH;äf‚Dk93v+Är …µ‰_Œ ñ¡ÜWã4”`ÓáÄ [&œsÁ¬j`~ìq‚¯ ó.fL™¿œ ¾Ö1ÓVé qìýR`P‚C*Tæ ²­ƒŒ ”Ô„Ò=Õ¬Tƒk¹ìÄT!k$’?ذƒ„„a[>Â𠲡‹l¹¸€€%¨`‚RëuTLX•±¶Õí• ¦¬“O@Õè‚L 3AÂJã§W[k™a@0•í0C QÃ?ÅR ‘ð™¤S … pf8˜—‹&*¨fÎ#¿þìD*À ÀQR1`F.;D!„ rñD ÔèÂn¹à MCáÁ@‚ZM2C BÐ9NZÑ=–,dr AʬõH ºàðÅóÌ5ƒ}š±Â …„ÖÞ$±ä `  € `„á€3þ=Â_…2ˆqOq„àO9+•ÓŽŠ!Uáj ™)¬CMŒ'(>kîÅÃXðpÛ.2TÀ„]¿Ìe¤ñÄð^«ßL‚‚TPòa ¥óXJ1³“°µ¹ÐEexH_”°“>|©§±ˆ82á‰î”2/JÒ#~’q`f È@“ bL0 §@$ш,x×nQJ$ÄI§eþÓÊÐî+°C ‚~Á `°µB MnÏzž–ãí‡íÀ€oÂ`q /èpÃ^-J„W3¬•‹\ßTû{Õ„$f"ðœã¬Á“0ïÄ Y7@T¸ÊÈ<V™ß[xÃã åŠ6ò! ðÑ\ÌC¬h*Aúê ƒ £ :à 18x6 ,|æL>ñ”@ ™R!%RáÀ@[)xÑÅÝø7Þ‡ ”€Ï^8P{БÔPV- ¬¤1JY–>~IËÃHÖBK´ÄF¢5tÿ²4³ïõCiuªRbt¤ƒ¬@0ÑÈJ!/$°0 #´çÅseð2¯ÅŠP²™?%þ„0x㌠‚\BWj€…;Ð~€„xa $Æšòq±Ô ˜Áº‘Ü…Èx„L ˜…‹2¢Âš!œÂaàk\l#CÀ!„+üB)3ˆADä§½ðÈ;!ú†#Èp¶Ó¹îƒ¸Ã#Ò¾Ç A.ˆ³lP6SüÀ+ùø‚Ìðâø…5kRŠp €eä”è–vG'iÀà éh@<ÄÐ À°sá‹¢dX ’Éü‹Z ~ãuÊ)ðå)ðh$ð±:«% /Q>ÌàJ±".µà/uZ°~À‰þ…Ìà^À °£™Â1»1Õ^Jd `á  x¥É@¦)–M@âb+(Áß„¥ Èæœf°.Â!8 9P %ÚáLA àN8¬Acfp $g…ðœó †/õúÙxéàÁŒ†.‘€ .‚@(í…Cc 43 ²m¦ò!è3%-Q[1Á¯ôåÖä T” É1N(É.‰RÊsƒDHáÁ]~`½ÆÃRÚ(”t ”Ù` 1‘JxºåBÿ„.!ŽXÁFYp?TØè, ƒÀ`†|@‰làsþˆB+pAŸºD¿R¸NÛMÌ4g¸@Èx‡  (¾8à4ÀCRƒVÒ€mþCPepI¸Z$\¼B9(5:$\\ŠEÔÌBÈõøˆZ¦ €÷ÄÃå4@]J/€ÏiÀ³¤`VÕ„§´'i5‚€ð1à 7§ßˆ/¨„#z¬=>0EePð C&°ÀV‚2Ù Õèˆ ÄžšƒŽ8Öc@H©ðàˆ *Bœ@„˜$Qù /ƒá Ž˜¡­è€H +2t_àO<*ÃÈÕ †XSŠñ1(‡Ä<“yš…\þ•øÐÆ‚ø¢ "!ÎàÈÀð0¸€¨±öº ˜á4©U¤ ìÁƒ¬‚d'Œ[Œ«"Ô”°„ËQ…EÀåR7§!B"tGŒg!å0î¥Ä HÓjHB„ÛÄÀ+Øò¾i tr¢_`Á`­æc'zî\VòAü…x H|§…ƒûÆIü¡šBb@)žÁìäš| „"0âR)²Ú,Ñ?%è èk8Ç Ñk±OgXÐŒ  #ÁGegˆÁ5Ì“ 2äˆB±À« }ÜAͲ™;އ"‚˜1| þ.í9›â‘Ì`dÞ§5º "shH´h±8“¯– ÁB†  d•P°ÌbpRš'+à->æR·C€l=€‚, ˜åÇ"@¤`¡8¸Tblôƒòm¹œ2jˆ dM2pE#pú…æ¢Êá0Õ‰B‹Ù°fªÉ‰QtŽä 9€@ ÈØ*…˜€ÈcDÚ" "¬ët{ÑG| …ý}˜ÐJuÒð ̵•ʨ €m4¦á ‚(f€‚ø¨LÁ?ØÁ¬ ƒÇäàY‹ˆð‰ Ñ¡ïa´0è%!»Û‘)3ᆇ5þ¤•\<úT!À …µY&‰=»ÆÞÀG´l¢ 3Î)XAÅÍ(B0I&€ì+äÞ:”Þ!ÀVeüE§ÂŸÍ4ªÌàÄK}È‘ÅàÑWlPÀG qH`Œ$ñ¸K±y‚ãÚÅI†ÔÉšàd&‚að׃ ÐÇ~ùõ7gdsT ùY ?_@+@#0Ñi%{F€–(o"{! †„:Ý€ÑeO¨´:eàDZp)ˆSH7…°i€÷c#± ¬†2Æu_X`HYe Yå/~‘±4Q&`*R5aÊP þ!¢·¦"0à1 c1.§ÐÂdÐW HM#Ð&8ñ+03°–Se0*Ê‘¸2½!“u(cAÓ_¨S`FÃc $%µÝ©1_Yþò{ôµþb#. .rüÁÊ@ °­2Vƒq:$?Ö=8° ´ÂàƒÈ[&hE *2.ÐÔ ~A$+”¯¥#‰lBsS0a2Iç)ÜUÀ³d,Ð0\q;ð+ã´_THUC!f°KT z!;`&!`CbpþV„à/ãúR*ˆ f& ѼÐWÄ‹Œ€²…%ðwaJà 8!6 D.(SiSFáHôZØà ¬1ªe(€?­Ô\^ eÀ[c„²ME@ D²ÃZ¹À'Ñ*ã7< !.ˆ³æCRN´0.h4,pMüQSP>`¡¿°‹‡\Ã,hEüÐéjØW")²ân\ˆeP¸GôŽ1ÁEXbÕLkâºôpÑ~6 T%PN+awþ’TIF5f B<@‚²2H£Ò‰¹›Ø>M ­Fs6ªa&þpO-‡ gClh#DÑV K!&’Q(Ã`ï—7a £`F…P:D±²A µTãªb&Õ O1 ^°½°k‡e  KSm`p ‰òÉpƒt 3GsASCR„» \B0>“T_°+1aMI`'àÑAs!½±„<3P$PL:‘É ˆ f/À 3Ð>çbT1*#i0`/|+á8`1RPJVxÀÄ.Àƒi¤A”eà/1fC‰3)àÓ%³WÅÐ~¯`q'°à0Ç`*ªÉsëàÿ#LViÒu{å‘S’þ(•AGlVp6¿`ÊH|!\Œ§ 52¡¦Àa"BÊ" °ï@rÆÀÀÀ”\ÇÐ÷2Ђ à Ð"]Ò§e0¡ ¸¨(<¤X/êEáòó@5»¹ "u ÂŒ£p *p~1`Bæ `@ábàšÆ 8€L¡:¸1Hta1ñÑ…Â…˜S ˆp+0 ½b 55±u„â6oóZ Ô%ö„¸0.[R <¨€^É2-=”šŽà¥4Áô™R WvÇ) *~GJ5$Æ $€F p_H¤¥Âr5²í²gDb±¢%€&!æþ{ ³ø€ á'‘eûÐAÜ¡Bh€w@jo8§d›`«ÐŒŽ5NŠB'7ˆ¦ã !' ÂP” ;€D@&¢¥°VÉŽ§ÓÃ@5Þz !u}y/¹J#  !§10Xlq?Â0&²CV³(ù /7ö¤,(@b`0fàá@Ùe­ P *PY>CsQPXA@Ú$@@#Ðb:®ö!g;jæW­JH½q]JÒ ¥þÀD ÑP8@ã Ôе)…-„Bà²õJá) 4Ãàtàˆ2¢dŠ— Ì¢×þ„i`@=„2T\Âu—RCS]ò šÐr)2<‘;ñ7àþr.ã° &åS JDpl¢$nߨpë`J§7Fª£:D»b“ƒ+(+.¼°DYD|úBfto8j “ xC_”Fbj5¸/ "Q6ÿã‹`ŠeÐ, aО@±L$P\fàÖ#gÈÀ5BXY ‚eàíüWD WP (Lj󺨶iÅè‘_PxƒØGžÊ*öÓAdÀV¢T?q°6d}ëzwk—ÅÐN#í“TÂy£ 0™b Pþ0!' ^S‡hõ(2°ŒL³;¦¶–ðgÐ\ôu:+[á²dµ£TùÀB#:Ñqø³‰‘p‡ÌèCÿrwé ÐNJÕœ$É{Z΂&*ð7JÁŽ´@ ðeð~ *4É4l1W`à(ÀŽqJOaL6bš/Qa€.`á@Ÿê åã@QÐ 9ƒ¤5(ã)’VÒ`ÀŽ¢¨ø Á ŠI>˜+ï•_à 6Ìåpøåfr/ÄW QZÐ  ¤ÊÈy"þ9ÂÀµ¨Ð ,!2ðFq8b ¥a!"á°4T€LzñH\0bàëc)ÖªdÀ[h¡Öê@¦€JjEVr@À`€ŠYæè¯¸¾ñ°3ë ¤¨r•ŽàWÔÀ2kH0ÉJv÷d»!¶[ÀJa¦B¢’$a²á-Ãó]tÆ 1ðf·#™3,Ы X`J±Ž®#v(Á:z1 pR˜¬ é…ôi°zx2åà#ÇУË]kD,¬€&¼à¿ú©fôrªþR‰„`Ô,g­¦£ 0&`& Ö9 °™Õ“?pˆ|Î<`3þÍ X¤ T0êKIv$à€±² à eP ð OàÑ>{…­d46L²1.0·õ $% fÒœºëJsÌfð~uÍp’T}'¢•e\S²K± S÷ŒA78mѯ2@ Ìh'Ú€ë5d¡`",6’ê`¨¬°h8À4^ðn  ÂgR:ü@Ü5/kp22AJµ’‘ ¹à/‘â ~›ð ååPÜb!¸Pw‚ȳ¨7,xÓ 0°§ <ä[2Š‚ásÂ~‚1Ð'.ÂmTËbÀý¹[E(ÀJ6D¡sÊ0Ȭ¤± ~ñèb—&gR 2€º¹®Pip$þÒCš|R¯4 '¢r@$ƒw&±&!R'Ñ<Î1€ZÁ)–Æg#ÙÙi౯ Z ³ï5»À3rí#øS—+pÅ1ç°†‰‚˾ªš†ì»þAKVJ:!˜‘ë¶Ý†`4ß…À¨P€ÛÅr*2 À ÂtÒPuøŽ\^ bņà ¢ Š$e °`²ÿ dßH5¾)žJÚïY¾wg%`i\Ñ>¦h² 2iVh±!f0ááI ÄÐ~’›ºù9ˆju¶uöУ¦ÃŒŠ„QC2¤ÛA ”ÐÍ ùÅ÷ˆʰXcô± SHX**p•@'œ©IN8Û4 Í!ž9pÐ= dI…˜%¥kɘ 6èÀ"<|Cë¢ð Â( Á2þ1Ynr×TÀðA;¦¨¬²G $°ÖBʰ üèÅÉÅ3\¦ «Èß0ü@„:AÉŽƒÊ‘®HØäâ‚ Bt¸Æ±záð",|°Ff@8з륌.o…9DY–“˜aúX¼ùßnuLY2sÅЯd°Xìƒ „@P‘é•â‚à ¬ñJ8\^)Pɇ3 L’PÅÑ`?qÅJì@¢ À6ÆW¬òDB†00@•’6ð%¾$•}PÅ™  !·„$“ú1ÀÍ 1E ,D ûÈ` ‹ã!ë¨ P4þÐ¥h@F'è0S¤aI<ˆeêÑ b¸àN Š È•Ø`¬`ÐE\´"º›Åyƒ ì ‡Ùµ:4Ñ.|Ð_¶%œ„W¹ _Ør„F<Ý!A4 í8t ‰dc,pŽ Ä`ˆÁ‘RFÓÊÀƈÈEâ³ÁcŠ ‘WÈ,|B„_â¿D)+!ŠÊ E¾ðpØ7ù ™p†GÜBHÄt@SðP9@‰A $W<Ðô8ƒ‚NÌ!÷8Ö>nU,‡݈EÒ¨TÂ#ÀX0DÌ` WQA2?ÄþÀI&О$4i8Ù`9,PP \° Ä'M˼Ë#T±ÅG•À Q&á°-Bˆ v0{´í8WöñàFœwQF…TÀLìU ƒÊ‚)Mp$beè$„ ‘ïÙ@w%¸À̆®b ®ƒÈ<ó—ŽËË öt$.Ÿ&só/1€‡–ìÆ,²…t„,˜Â@„"\D”ä9À X‘BõT zÄ#乓=û’èî/%“KÄÔ!ØE¥h (1Jl¡­$õ1’°E#&HO·%d½B:ÀA¿&@ dþu±§8ÛèA!õŸ#H– $Á’¨ò¨%à)$/ˆášu€ æi|BDi„äa‘&iÖZĹȲf° |ŒÂ. PÉÔ P`‚93"H ç<€€_¦×0Ì ›áUÐ<ö¬#Eà(…]îd N˜ÔJŠ bàü€.\&¼ðˆŽØ@{XÉ]âó€ü@n‰ÁR)Pt@© ÄW´U¡¶~ƒ9@£)WAŽbp+“:Ü¢Œ€.XΑŒ;Iå!XÎá~(ÀBß@Á  W†¬XRnµg3<`NB¼R ’%-À þ@IQ¼°'?±8çÐfA !ˆ¡#“ÂA(\ÀQÁ–dÿ{ì±P°:.íEÁ4!×:²7t 9@A: )z^*ð.  çb¨%™¥Øem‚ØGT¡ˆ4“ÙÔ=SHgãHz¤‰ç9Ge*¨Áҫ€ ÌU‰ ÜƒŽ A讀Á_@ð•BAè¤p´–ô [² Ü€@ÚăX•!‡…"En¢BWòj°ÝˆÇø8“LC¸N× ,ÍX" &ä+×0³VHÒK܈A > ob4©B8rÅŽ” )ÅòL™ìpCH8@' ÄA„@uÐþªÖ_²¬àJ<üÄx ù„íðFÞqoÍ­%‡*²”™U‘€,  <@yµÂ"Q\ˆŠ ’ˆ¶ô|e—õÉ´pàSL!Æ7€ ™æ‘¼?\ º*áìoÉ‚ö¤E…âQÌd˜odìk¥zü§ÏÁ/=6/Ä…-FÅ„ð&Ûi’’  \•qÙáA"••¨?£¥&ÚàДK—ò.¾-!l=)|Oº)\p@(LàB¦ˆ’ÍÇÃs€ <¡!KÇ6.ÝWôÃ.$³çE<Á\ƒ¢ŠåÓ{4‰Ô=âÉ6Àˆ]†fû!P û³þ¥@ÀPM£&&à Cfa¦Êpz(‚âå…f‘„¨E¸¤à/ÀAŠ„Z„0C,qæ‘„XÈÒfaø  ÍC(­:UX1waí°`|ó`à` j¢iÓ´+  f b¢ìhQaGoaýÀi@eº³ù­  Ñý ÊðRä°sá îä  ç/Bñ:˜žUSűDÀùC$À h³C)‚\°k0éTýó waaBà"}#|¸• ¹@²g_r8ÑTU8 "„þ!%¡ƒ0 =Ó–ƒe?ð8 'ù³RobJ”#(«s,ð«CY.‘"qÁ#Ð-PºÓqê =® Z³ ?Ð/ @(ñÿ,kÀãö=;¦îPSÔ’NÁR‘`'¸Ä ¡£h{I çÑSä ñB è*ì-ptTñGÑr:ÃÑT®£,é VÅ0 Iah°™2'+p$°‘4ÞGtù·ƒ+P#¸å5 VK´qA‰òˆ²p@ô À|AIv9¡nE. !h§qñ‘,1qa+¥9È€_Àw—f®ã‚¢"g6-þbB@‰è0±<0X`Tªà(¼@gPeà Lh=ÑSpA?p ApD>ÀJLôy¡8;Ðe_À_M .£àw„3Kíp ‡IðRQ¹tý7 p»—QT1bc%xÄsÖô=pÂ5ÐB X?ÓM÷p%ù04ñÛ³ܘÛsB¦D#ðÄUäO†&Ä ©ÐEØ¢Dç –ä5¢ ~Ñ Ù7 V-Cð©&WƒÕEc49Ef[`˜GWtõ€'ê° í„¡"&u›®0'õ7-–$ B¡ r2gL?°›±rþ|Á2 àa±` “ó†ÉÀ¦ê`§Û¢ ¹ñJ­ƒfj§ÍDƒ¨x1e›Èª8°®€3pº°Ÿ!Ú"{Åñr1" /ª@R`‚q¡Ê€QÅÈ ýPbC0vþ9Àž±­ƒ¡4B VU`‚¨"Xû·—à`õ Ü‘¡G¤ ¸¥I±p©XÀŽà§§/È5. 5›±2ë㱞 )tÁäk÷ æ`q' †if­p:“þ‚ã Qˆe@ =0èBbMG ŒP[L0‡…4¯€"‚xOÈ&U8°HŠr`‚ Q`Ó{3PKã¶Z©ð `U‘Pˆ)¢„D¤”Ýð¸ð±?fp…Ù>ðd!%9‘«åMÞ`-‰0{±ä'çV$u×*NwU|#”ÀC 1 G[`QR&ð³‡)µ‡Ñ3Cr"«„,0 1ý3 ^#(;: PIÆ%«²ŒÃ_–” gF™_0:@9fÐ"´ðQš'tD1€ Ž0k< 'DA9)²,“p ™Ë…þ “£ç^G Z£ç‰yÁÒE:ðnÍô5Õwt'9ŠD°Y¢ `N¥1 !’yOûGrr8Zsq:‰ÀraÐ3aqã FKýM0@/°ûWœƒÂ JhBd»f¸Ê]ÐPjœº "ó­°E€y¶çâ”A80‡ª˜÷; Ó / A.@C$>‘”„ô» =A-jGxq «V¶öðRÐ I+ ŸVÀ;¹D¡,ÁMB0 øñ¸p;€Γ¡-1 HÁˆädP‘/]¼šßs]5þFˆ BãùÁ€fDDz à7'“xD-CF ¨ º#Mø$>Øâ%¦ª;¶„½ÀYVE]ÆçD ò•5WKG´/àˆPÂD¯7ƒ"M6 ñ×K‘¨F€†nÜ©ß@ImÁÆì19ƒvfJ²ê¢“SXm$-ÙL÷°Zõp' -C“¹<🃄 äà?Ý`\ûH©@9ÅayB1$`ä@‘cÙ…EùŸò°‡“¦ *sdŽÑs§S³ ‹jMê¶q†ð™6’“á%Ê¢ÌCSÌç_°/‡-H¸j•²Ú‘„ 0ð²ÑþÕÔíÚ ¸õwq¡ ÿ øðM‡eÐ6Á 0Pq"ÄX@D`lô ¯ ñ”óŸÅ?FlÙŒçáa%þ0”ÿ,ø°D 0‡#)Òðá¢&Di0µ©@/BhOw‘Øi/t™Ê¢ Æ 6@¥‡ ³@ÛCY´à¦óe€öbÁŠd‚D°SY†q¯ª64ŠÜÆzÙ»£œ² ƒÊ  €°+S³!dв5ä@H¸uœ ¡ IëRdŠ—w[þ¯òq¡ `MÈ.ªÏ-•&´ ± I÷ ÔjcÚymU>«2²iŸtÁè<.Ybª}ê¼P²Ð”2:ã6ÌoGâáÍA]Ï‘¸P o‚b!'.€_€“*d:b $áYu¨Â`€¸b4U9o"8<°f¦¡"M¾^ä—ÄØªþu,}£Qâq³-C“AŒñ,éq%ÙÜ °:ÔP)†Ë§Ñ"ªI˜×p º0s%‘ ˜‘q¹õ/‰í0<`Wƒ$™}RSmbtç<½ „sN¶4Xªº‘%+$‘Fþkó'„ŸÃw}¼ „tRLiBÑ$ Œ=4 ×óRéðR3‰e¦:'L:@Q½pYçqBÉ èaªPMPñ&-éCí±¨²§—öäÓ;@ÿamD,ŠfUbn0à—Ý“LõP }±@±@¦£ÚCùÂmõPÒ&Dg0צnÒ¶ºT 'êàAbi•Ï)‚wÒ~`AƒP®šPDPqâu'¿&…¬ ƺŠrUídTa|xVs(Šo»¾"PBÌ—&µ&Í”±=Mj’ôU¦ÐÒ’ðr¼ª %®ð8`-utfñ‘X64¡Îòþ²n¢’¶7ÂÔb-ˆ…è^"µðne¢ ¦.};à(^D“"¸ÒN7.-Ù"Ì&˜/šË|ý³ŠÁ<o´w‘:´Þ é”}¿^kÍ4’ÜM*H& sO‰‹1D 0–VððŸ, +^Ų“á:t¸+‘C&º3À¿ æXÆØ‚X£&ªƒ\Ó?b°õT3ÁmÄê æÍv¯cÛ/Ù— `ê·îEB@Ö=Øe¯Ã‡‘´2€,ME@IÔJuM<ðKz9—I¨é£(Zñ.±4èaŠ? ‰MII™«ÅB2wZM5…fÅKùþ™’¹v“(™Â*h\z„A °fN©Mûô¶Y…Ôj¾CïceZÂ-†è’dš5bÞYшÑwÊSHŽ0'D 'g†EÞÉ‘hÜÕdO±äŒÖS÷Š=…H(Q~ °€ð5c‚bãâb"Ã##†#£Ã²Râ"è‚é3eÃ#ƒƒóc)¤5Áãb#fƒÆÃƒÃðe3::KÄS#++” ¶è „cƒ;ª£3c#½ðµCj3´sõƒC,‹Ãƒ+6û#þÈðêc£’;Ú0›‹EþmcÂÂÒߊP ¸p4î8ˆÊ ŠábÙ2"?¼þfA4²à™‘H83.JñHVD1ó`;ä² 3+Ç ¡Â‚åj6ŠüQ˜Ìf|iðËŒ m0Çì ÀˆÑ·.V¨Q¢¡`e‘¿ÿl @±Ť2%5BaÀ„‰/¯†î˜±2› k³J€´€E6PBRa¶¨È«_\"è+¶+dÍYÒd= §NÈTðê'C)H\.y$øæ"}3_©XÄGƒw±$Ù“¤vé«M¸`á¥_[qD„aâÇd[18V4S²Ž³(ÃÂ"Zf-t‰™Çd§!Ã(39"Ž5 ›ÝÄþ93³ÌÌ ÒÎPI"Z…rRàPñLà„‚›K‘ŒC-å6ÉAaÉeÜP਀‚YUÉ Ì0¬Îþ4üÕPê|ÁÂ&¬1J’Ø 88°…z?t·QBó”2ƒ>`°"NX$±23Äð á"ŒW1€‚^àDwK,â`À(`8" f°6ÉBfÈ jÍ¢W($Jš6™ >®à" BÈ(„¥`ãB,½4PÌ“0L+㸒ÎJ;Ef´èÂK¡Ø ”4,$46Ûù¦e–ré°ÃTüà‚‘ 7›Ä §ÃµÏþo?,ð cqÆ t8½€Á é036ތ⣬Á€$5L¢Š (ÀòÍ‘22`Æh3tCÙåâM”,|v’s‚Í^)ZÜ¥ƒ‹ë‚€ %U Q+ –¹œúM"X­…Vî„….ø†ÃÒP jÁÚK2 ò‹$Eà0ƒDÉ@JT 3[# Á²ˆ(<|FS2§à0Z.ŠzÓåc³˜@†¡8¬ ÏÇeë(‹%â‚…àR‚±±@&Í8 9ÆÉ5é+4ƒ‰Íf7±18°à5k.ˆÑÕAÊ‚óVãó.J$u“ËD#M9‹$s¨Œ²¼2!Ì‚þà<¤„%4k­Ò8ܵÍ(ˆŒCš‘Ä)ñÁm!2Ãå<¬9™(õãw>ãX(ƒY7çˆy—ÂS"c®HÿÌ öoÜV$Ô,¼¢Q<ˆM1ͼRC/Éäcƒ ê„CŽ=¿ŠÅê-CÓO£”v¤XðXN‹.0 $Ü èýæ7tŽH|óÝâ @2 QìæÌ#‡X CÂÈÕX0©L6¬àOŒ°±€?E¬'0óêUƒq Av©‚„É@ ÛšÁ°p¨½5`eØ`À•,åi€Ákb Âð6¹Œâ*a3‚»u4ÀNë˜D>˜#ƒ´„nþ ƒÁp6ñD|ld‡0X V°!‚„_Ì ŠR †ÆÑÂGÎqÉ‰Ä aLb,I™$ÀPßȈ4Þ ‰ óíüùÃqCdà”Dl& ûŠ|hÒC¸•Á8§‚Áve3ðIúÚ›2ö&<‚j ‘ s qœ€Çf%Ó „$µY$ ËÅX§f¼âZÍ‘Äõ"†éBQD™ÌINÁƒåB ôY†œ"ýL˵[€$NƆÌï ˆ8H$Àa!¥D,g9HRÃ;•ó,oYx¨¦ÙP35:SO”ŽCM D",âXFä„äÌô¢zþ¿Ò# U îOp¬Á(A—BJQ>ÊÔ(0œK¬ÁBòÉM"&‰LÜ"»Ó¤TP(b4À áúÆÁÂb¹hhˆh˳ @:eà×7@÷ˆº_zœvà…´ ÉPÆ+Š0 $!(‚W‹p Ë T0Pek„× Vä‘X8@”]+ÅO¡c‡œK·ÉL¨$543¼"IÞÌR‚6 ,8Âp@VÔ'¨–!®D‚.̳Ðfõ¢YDÆXR Ã!䀫èT  #WXŠO9 ”‚;b é,\à…@š‚ÃHÂ!2‘é\†sÀœì”EæÒïŽ„Ž H’X¯‘S°áÊ£/OD’E‚¡KÌÃÇ@ˆH=Fagš$„p #Üaõ’`=õâ·-ªëf°Ш÷C–@1 /¬ <0éƒdA«ú¡àhˆk ®" µ|ƒ¯³9"š¨©’;blt-2.4z.orig/demos/images/txtrflag.gif0100644000175000017500000004135707240160077016657 0ustar dokodokoGIF87a xöÿÿRƵ½ÿÞ­ÿ½¥)œÿç”ÿçŒÿ½Œï½ŒÿŒŒZ9„ÿç{÷µ{Þœ{÷„{ÿ{{ÞB{ŒsÿcsÞ1sÿçk÷ÞkÿÆk½kçµkï­k­”k÷{kçZkÆ1k”1k{kÞœc÷Zc¥9c”1c­)cœ)cÞZZ½)Zœ)Z½!ZÿÞRç”RÎŒR¥ŒR­{Rc9RÞ1R÷ÖJïÎJÖ½JÆ{JscJïJJÖJJ„9JZ9Jœ!J­„B”{B¥sB„kB”cBscB¥BBR9B„!B{Z9kR9{99R99k19R19÷Î1­„1¥k1ÖB1ç½)Ö„)½„)”s)„k)”Z)¥R)sR)Þ))Æ))ε!¥Œ!¥c!½Z!cB!J9!k)!J)!œ!!”s{Z¥R”R„J9)½”)½­”¥Z”ZœBcBÿÿ¥{”{{Z{BZ9ÿœ„, xþ€x‚ƒyl\Pe7xyy‹uŒQ,5QP5‚j˜e-->>PxjxuXx/z!«!ltnon,lhKmkk\otd\\nKOYK3¾\+q[KYLkZYÂY++O3[cgv=H> )**11WçW71#*)&#Xç7ô7(ø$õ8N'<,¡Â„‰„t¨ƒTž:u…pò‹‹ FyôÔ Ó„E“-‘Lad„‡E *-Þ´`±èâF=vj€BŇ..t̸‘ñdΜ'M̘aæÍ7Qž†æÉŠ%2–1K>eÎ0ˆ1¡aÅ‹wïI<AA"E ,anÈ“7Â|])Â8q‚‹ˆ)JP(á—+Xp@Q÷”` c&ä@DBT†uÐñ[¸¡P´‡˜±!ZB(Ò…E4ÔñFul±¨ÇI@´PzÔXÇuxˆFJÍa‡YHhñ†Èe‘År þ³ÄJÍðDWµˆaÝYˆÅxQ]1ÆYcAÄ$P€ TÔwEl¢pŽ 8 GŸ<|…a&=Äð_àà†"DPÂ÷L@:(¡Ä±qA†t€‘†tè±…‡”á Qn˜± «‘AÇ&\Ä1‡t¤J!° Ô@mz€±GÃ(¹dcLáÅ^¼Ñ.V%)Ç\,Á n`(UX`@XPr†u¬ÀÀ 30@ÀòÆB(øÅžéè•f a`1çÄÐA|á zŒ:ÃóâÁ "ì ÄI aȵt$SvxgGf˾âuþ˜áh ‡h †[4a¼8!Säá±vÔúp©JòF—Ed!CIf!×É‘ËÁÕú’·ØÑp1PdÖ1\1°ƒ›è¨QîJœû…éÐI›÷î…êˆplb!„äÆ0Á'  ÀI$FÛl`v)ÛAcxÔ€aѯÐÑF æQE%¤±QsÐ"‰E¡¸˜GÊ5jн4KTẔÆE7ÑÄf´Ì0TÒÀ eT±*T-óDçºñÒÆ c„eòÜq…k~‘D`(qFó pµ|ôá@Î ˆ0U8¼B@Ab~Q B"ñEþ¼Ýpvlƒr{àF(ŒcÈ j¸Ñ d´±"-„@Å ¢ˆÒˆ·©Á*€€€VPá2eˆƒë Q´8Ä lx•¨×¢ qKVX¬òø¢9rà ¦p†Ð V8ê<0ÔáaB'” =zqÂÒ €Ä&‹â¢ÊàÏŒä,x!‡‡ Aa tˆ‚N?—@Ä Q nã á›=è¬0†)Ñ@ޤ( aÌ€J8[Ã’´†ihÁ®ªÁ ¼€²$‚RÁ(O9,ä‡.㠤ǟ¶(!eº„(Q!Ô’‡É˜´¤2Í„@ñ—<Cr#ÂP(ÐÁ5[àðÀP&"_<Âù  ¥ÄA ژ„ô¦yA ó-:n½ÝB ™P-,Uf?Yd 6Da S±¨zh¬Ø5®@‚õ$€á?ñ€ö’€âŸA Ùr ­Ý;PÁ:T@¯Ýõ)Ðö"<€‰'èÀEZ"Å®ªÞ D@E'¨Q}'E†X@ÏÕ@$Œð ^Ð 4 /`Xð:ÁK€Zlgð° bð 3 µ h€{2°K!W!%ˆOò p`ðLJk!·;àÅV¤4wáçÀþõ5%@àwé•=åÑD/óB/p! Ìò c”E,R5°ŽC“£b,ÐMÀ§Ñx€Bá]PqD Gõ™UI¾â”Ö!{›n°bܲ$TEk`3€UnÀÍR4âô(Ôa°£´c;€òîpŠA'7p;`ƒ ð;\D"P^‡800æ‚jÀR“µ!³ð>Xäës,Py„PÀ¼…³x°yàM +{ðE72f:×µ0†^à+ÕÁ€Ç±Qp$40ÊbD¡YRcp-†Ð TÀ70r°þ<€iÒÇ*0&DP5èàå¨t‚ÚS Eó!½ /  8° DˆB@Gð•á4åR9RÀ„h0c™áQ‘*sÐEG1L?5°wCZ”ò50×Ò3>±sðGe!>0LT"ŠV-ÿ5c\ÐA)–S04dÐán¸·\ƒâåp¤æ.X°cAøð'XÀCmDpX@qÂ&õ‚K GH Cp#G`3F [° `p`ð¢ls“*l l‘`5pc@Rh?v2‘‡s`¸g–»˜#å tàŒPÃþ#Tðš×œ>Ð[’`4= To0¢)¼‘TO' Z0IOÐ SF¢P üôoé?ò è!Â7(¥éùa %ýÀ@ÄVÌÊ­dLd²°6¾T yà_‡Àhuб!“ªF§zs,àN‹§ñQ«áð!ŸpTÍ ZÐ0Ä“ÆÁ m O'@3 ƒ¤< Qµ°pYð2AP^@UË¥(ypç°wQ àJ²)®dVÍ5þ؈XPKlÁm1ú}ŠÕÀ!‡Pnlp …z ‘³&sn> ¨¡LùõB_Pf8ŒÈÑso°F¢Wg$LÀZ ÍQ¥h{SGB …Æn–°Q`S` %ðÚƒ‹j`&lq*€zšÚ“*ÀÎS‰®Ä”á§ 9@6B`64WRx0R”S-Ë”,M’¥¹…¥¤Q¹o°à P5°g5’uðÐUê@TNc`v€"‰»o¸Nçd-KW-`$s¸ia uÔ @U›É-# V)@® pqøþA%À|kE" | ' (ü"Bt)@J€ƒ)‡’•"3–LÕ²„±_›Rss+áˆ#…¼…sM  9G°IÐuÐ/° 4¥!™b{€kÐ,ï-©$PÐ…¦’ÐñnwH¾7å¶U ŸÑÂ-3ÐgâÑÇ4üƒ1ppëþÉiô0Qê1wJÖˆwïu“(:€kô8—"æ–c€!šrf‡Ðo 8ªa¦åq°‘É* à¿3)i x›Z‰å‡`$Èq»KLŽ’A¸{0ÄÕ’^±PER™pì +pÝ‚eàVþ<©jEj,w/ô CW”ó šN€]œ1W°j" ^b5J`à~›[-AQæöEÈäRiY4"JF!ÐcPf—bÐ>Ð i€·"À4¢]`N°­Nq€JQ NÐ1_`8oA³+ÀŒ4€3€@ÝYÂ! ÀSt°=Ô§ì2lò=Gð™õqyr(@(l"GpT"AdkJ gºK"Íb!zàzPt`+²)²ÀoÀL@M@i€“Ú/ÀTX7c ?@ seä£Ç‰6n=ƒ:ŽYbNËhÐþ»ÀÏ"{4 2ÀF`ÀÑ+b°Òè°n€œ>P”#1Gu,KA9”óMäS"3Ê¢b‚–ÍïÆ ?Àugñc àµrÿéBJÀu?¤N&ë±V8$šÿà.ôàÂ'âR)y'e¼Ù,5 :µa7†ªXhX¯’±Bôa„>€ºV=»>/¢y¡Ë1Eat¯аNèt¬Ü é TÅÖþÁ$-3 7¶âVÞAÛƒ+H=uÐÎ_àjqÂê¸Ùãp²X04Ü~¡¼B w P¡à"' 7X@é1I„ÉR_óƒTÐ*•Ð .â?‚ÐLtðMÐPr"á&…ä”$V $O Ï  9AµaUÂç:#3P$ýnc°oÀáK`Ç{a”(¡Ài¹”)À·é0ápßÖà÷ïPhÃjsï§>ƒÀËÂ!NP„?0Ç*#!NÀ!°²Âr™0_xPaà¶áBv ,qðzÁ°Àb>ÀñªëT3þbÐk 3°ÛØ2`»Yð|2Ðâf3°ÐÖ-LàVhÍ& ]å8#;‚w"`CƒR#`Ôg}—XK!»cüA6¥^,å x@¼ñ_Œ m¹Uƒ R,ÀnÊ9 Ñ?1GJ°H€7ÚqàHW1Œ­U¤ƒˆ’=ÇÏ 4è=sZÀôv\ L4`Ítqé%qÐ QDpƒûDÛ3J‚Aêsw‚{­dï&€KY9’‘£”@u\6ðEü>qð¸6êypÄMÀY¤ÍôݺRmgðMÇ‘TÀ¢þu¾Â$½5bI"hµànÕò|$hÃàÏÄ[ðgW÷ÁÑba0&@z½swz:k;"Np*ðDP8Pˆ|qFLù8`6(Hp›`PëГ3\±…–„ Ó_‘¥Æ;W» 2§¼  ;'fzzYLnOÀ ?¡@>cÏh\À-Ññ N`P@ØFR®Ê­­vǰh-ØagVÊ—"ð“XW0&àå&£ÆŽlwúâfp/€`†vs"r‚3!âD„¥“4t†—‡·•ÅÕVgçVVWêÆÆÆEÅBUSåFWÇþVÖ¶5×Äá„§†ã†g§— ÷¢gŒÉFÆ•µ„–õäÌV寥ÌõíÄFçÄõ½D³´”•µÂ²åV ¥,C“!v0gÑ¢‚‚us&ôutôE–+©F '7n8q‡5aè`r$ŒÄPPø˜âˆ’3H”pÁóŠ »7Æô¼±C¦)7t̰qcfN*,¸”aÁ¢3tèÄá´ Bž;¼Ô¼°ããE _ìpQ÷e›'Í¢=±æ¦M“QP¾®€U…L+Pâ@‹2c\k\jRY1cŠ/]z¨!ø— –$`ÔI >'ŒsQÃñ (†q¢Ë„ Tþt¦àÁÄ¿ ¹@™É… K;t¬œICå›6mÔÑ©ãF ”(\8¨ÉStKeP^¨Á3)Oƒ,4 1p ‘5$Q àÁxA <0ȸ _¤aL0{´Á7ѱE(²ÃqMáQT5´À5$‡Gy¨á@-ÔðBW‘QFt|AtDãL]qÐá†[\³6ã˜CÎZÐ ‡ O\° ÌðžFþØqÆ^`ø7‚B„_|QEùôƒŒ)æA ¡¥ðádBœC"tð¡ %˜ < À `²N(vØÁÆ'eXqNБ[D¡Òoy™Ç(µÀ,h ÈMòÉ$!h€€M„€@h414Œ¡…L˜ùe4åÈA4Yı„ KÀ¹F¸ð}‹œDÁ oxá‚o ‡‚ø(x„B ©aQ Ý &¨ða¢@ÀHÔ™9$JD “rÊÁi—aq\Q©•! %a §nKêX‡£¢ÄBN´”Q j(pÜuø3ó&q¡F6Yt‘ÆþRèW^4kÈ¡]ϬÑ]¸+Xàí rhÁD´YÌpšJ©A!Ç3H!jÜ€B 7Ä@!©P‚ )¤­¯ŒíA #PðÁ)¨p(Œáð!ß›öÅ `!Ä ÇyœillQaÌ:ëo¥°ÁB _@N+³u´q[•t„àCP Ô±‡1þèa ÙhÇÕvH!Çz­1ÎÐZd¡bÈW\­ÀEr,±Æ k}7°|ã$ ïÐpž¥ °ùäsņ)±ÃÜŠ\Q(¤í¡1`AEƒUêÄ 7(€C"C(ñb¼ ¹â¡Ì:‰zÌJŠÉå\NªFQþ‡ôØ‚\’.@;lB,ƒÐ‡œi'sxƒì°.;4ãhƒ ç.X¨$T⇸òP(£ Qˆ‚ ²ð&D¬Û‹ u5x 3*H ˆ 6.8Ä;ØL p°E@1 UHp ‚àà Dèt ä@ÎHahÁP¤Z9î¤h¤ (4!¸ÒÄ–:‚ TAa¨ƒJH¸puÃÖÐ…2Á-2pƒî²ñŒÌÊXÂí2@ƒ5œIß0C5¾aЀ(R Cl˜„(* làìMš`‡.|â6ßðÁXéS‡Æ‰ÑdGÂB0”¼à xÀBl‹ ÔÀ h^Ѐt¤F%lh†3žP2@‰ ¬àNvÖPÚ¸AWࢶ„Ã>µ€Æp†"Á nÈLr„=}a!¹Á S…Ì€Æ3QÁÛ$‘8A`”@ˆ¾pE<àþ´MN‘@3˜ ¼ pTá²YÉ?x¨ÁšÀ‚Ô`"“‘J&‚&´€"^7®¦ nµçIU¨BQÊQŽ%¸þ!wO;àSŽhIË+ˆ‚D)…:ìeHH/Àˆ‹Dàõ†¨6±aAh vðD@‹ÜF0EqH|588à€¦ÜácNð#éœþá¡.,ÀÁã>f¤:`¡ >€B  ð1æáq³ò¬À n@êˆRXtöÞ¸7h¨Âñrvé®xu8ÎÐô†\ Q¨€ó~Þ:QÁ 1ØÁ”U@!Ô! \¬iÜBÓ¯<|؈J@"¨`%-„ ®ü¡˜ ~è€ÎÌ‹8×A `8ƒÊ ‡CîcP> A¥CAÆÐhK€ Zàv°=à×qÊEVO0` ÊeCq%Ù23+˜€ Dá+¢45°(pJj³D é5/ùXPµE„°0!%eÀUPþpõCC )Ð*©ò [ S ä…d+êÀ9³  LðgPP•±Gs°9ÀÀ /°up{n˜B\¤&eàcÐ^5c€z>1 Ä Ca Uð/ qAwÖ@m0obu`QLP  Wð]ð„1 Aë…°¸ø Á´>—A‰üÄ  IÐE PQ@˜p ¡õi`wå'ÐèAu`@a=±+5s@o!@þASÅ#WãXðœd#E Qòr|ãrC7* y LÈñ ˜*¼¡m¿2T°”A‰YÕÁ%Èñ8ËÑy PÇ¢ ðM,sO R0V@o0Ð@°Â=L„6øð/‰ ()ð–âÀlœ‚9ü“S‰ \€ 9 Jz,ŸnV°þ@&a ƒ!à²õ@Ï bÙeüñAv&CƒC“‡äB 4Q.^¹ °Üq.œqÀ Е P~²”;@ R l%P~ý¨î%SÆ(7Êr‹à>àÒ$ð0ô7W$Føc9™O‘sœ§MßäÊ,”@QðtK¸z“PVš0Ÿ> ]ºRÐ]`Lp5&ðQ¦ ú 2à,ÞQûä< O[°•C5àP2€(7&`IÐ=á­x%ð0b3‘*ârwƒ.J­þ•˜rø'€[ü'A ÄupiDþª‹Se€“yáDÑÈUËæöª£ÓÁp~Ò$kÀ%DÂ÷ s0ÞØ-Ü¡-\Ñ ¤`Úæ 3@3@W1GlPw` `4 w}:QÝ j€6§d0'‡"°—Ôº `(\p` 7@'PS#@sõI¤°•X o€¯[@yK˜A" °âF X 22­à®ç`ðG~ÄŒd4¦P h`åà-O MôÆÅÅièò‚¯r3¸¡kðv>%þÔ/›C ;Šq$z‚D =rp=îÕ —®B`š¹4)îþsHPsg€LVS|diàGoÀNR5œÃ%°ÀM0޼!†ÿ‡R`n!ÐÇ z@:{°uVtà¯ê@ #Ô‚×€"qú ¨b¥ µ¹ I°’Ÿ´ ÎîäJADDG}”'Wp‘ÁppvEúû°'\¶’gÁ†LEfO¯O,ò©uëH\"w>Ñ ö>€t¨`À9/Po VeGà"{À"LpÉ]&¡Ð½ŸÔ-5†¶ MP+`6}ß@ ˜038WñâJùàéÕ–†Ã®†;ŒP¤‘aê?þðRWˆLI [¸ ©Œ`¸§Öq¶qOý*Gà±8˜ZÝÈpÁà¥óÄKÁûP2T@Îð ¥@ ò±`Ƴg¡ °mP›Z@îáP4I^ð,tàM ~ò:P´äJû°úð´40_€¼TŠ… ž'€€ó3;p5b¥ÔSŸP M)3á7UÐ*¡l!Ь`N0$Aô+ÐG`Uó§QÛòc0Oô©, «óq DÿF¸"kj ‚¹ŠV` ™'ñš7 —q(ƒ †‚þÐùƒ 0ÄtÔ*Œ1 / E7áwM ©P@)±8¥þ!g” ‡êäDmáM°!ðleÁ:ÎÐA"XoÀ¥Ç–ÄjR9ãÐÀq%]ÉLÀÙ‘-éAt€÷Œ Dðà÷‘ë{ lÛ3fMÜKïã„J˜'Ððs9 sŒ˜À¬ÇÁK*áš0$†9ÞÔií£ª7•xõâ 9S¦Î o0c`s .p<ÝvO IÍÀ;S 8ƒ;&5á§uJ]ðop–^àQ„*Q€—‘ðëûþ¥Ùç³ &7rƒDBö°Ö=B= óðB +Êa$ƒ ô}9°Agªx`- àh¾L€ÆŸØÚH›ã ô=àiQ‰;å0ãb²`Ia7W40k@Íxq}mÒ_+p±u°=ÒSÚ'ÇÃ`xB˜W˜€kÖº=ñó>0L”$àr1PR' @žAG¼4áS:‡9jШp[Ÿ d$tpÁ?Ò`“pLåuàfŸ€3«óŽs€¡]P'ª±e:Ó:©qÛ·.ÑðÑwPÐãªþÝe°}Je`®–'Ï)l—²&`!"9¨Ôsx»ø‰*–20ó!±6(kŽChqÖ|P0á˜#$Q€R€]ç6ùg®b ÅÈk­¤2ãG_@¡À-âí€]Á‰= ´³,ø ê° + LpCÀâmÇh$[w3p07;  Q˜ 1K©´6¸t'§"@êœá>,õв gpx§Hài„ 2‚ ß`ª?š Û€.Û$ ­'#SAÇÒÀëGÆ‹:Ï|Ì; 8ã-…¾UCÄZ /¸Nà¢øÀpM D:#µK0 IàC ºÕ€@T¢NB2 MP$\bÛôMÆrÄFsàF¨ÐGP9-`@ÀÁÆC E \ïÖòý\à4œt¯BiUW‚;5ëÀ5¿\à&}ŒpÌ)ÔaÐQš !ð 0îãJhœ½0ÄÔæÛEC€©±ô³  / `À@ÑÈ%žt#ø ºÂ!éuðQrKÒ‰6¼HR*é¬âIOô Õ ¥À¨7ßÐV#[Lþó j‘šl c4 ú˜!é[+¡õRx ¿~‘'ò_  ÄTë[tCð#Á³ìQÀg€µ¬Qò7_5áèP9ÍcÐz› ,p5‘at€:z2·ÑgÌ'éf•ÑÐFPRŠlà…ÞV‘¶& §Kи‹`‹,Z»ê^ADGÐE_—¶jWX„B8@B"7U7"W7BnNaa_aNU"8a;a  l\P\lPuozvz{¯tPµtmlnl»f5MP¿-,us,-QUyyUUXj!t/M/ 4tnqh\¨hhOKO§ªdþdÞKYY+PKZZKãkckbñYPY44RÒØè!EJ—:W*üòåÈ‘3gn8Ár… –*”„`¡€e‚“8a¡‚% N(PøTB%…'„œP Š.(§êÀ²cç.NØTT£Æ 25ÔÔÀ†¨3>j°`¢E5yðä¹¢K  ¨ñBƒƒ%rž`ÒåvR æBÈûÉÜ1¦n˜Á eø Éá:TSd°‚'È€.äÂÕ|gC1Р`‚š@«„èËUB¨Bd¹¾„¨a"„Èeu, Âaà‚I°š(à(¸_t@"ØyÿÛƒ¬Ð à´á'Úè\6SAd¹hCư5’þa 8ÐDÀè- BZ@†r,qbGZÀqú„âÊ@†/LÎ ÜÓà‡5¬Ä« xp†"Ø¡q¸^/Q K€á @¤!œ05¤ I¹ ‘à ñ;"0ÓD@š‘‰)x 6ðäÆê s¡ 7ÖB xàÀ+Ø 4¡Uà.C”ÊM)*£;g¸`†2Ta Üj‹¸¸°ÕŸ¬â p8…¸<˜ùÐ@Në ÁVÀ8Í€ xà ò,ˆPBðBˆð!(! X4Â`·0\! Š@"(€E¦0J‹8Á†( !D þBPÀ:À:Ð f˜Ù+ w+¤â x¸ƒÐà <J+Hå+˜¹´ŒH—aŠZ°*¼ÀÂáȰ‹¢ÍÕƒrXBÖŽ,È.yO}´€&ˆa Rc;œGƒ(Ø {Rš0 IøBêw¨€¤;@>²‘Ø´„#H*Ì* SŠÀ'Nð˜ àl¸NèP80èÁÏ8ưPƒÄÝ@+¯2μéƒ/ìŠ:ÎëD l  _˜#6&1Äq˜]¶Â±³,Ü…-b’» -0¡<èZà ¤µŒÁ Vð¦P…[2*þy£>z…#|BE*ÚE2+(zµÄèÄ âçLÌø€œ)pÌCÁ8ŒËƒ0ÃÊ<î8†£ È€eøê8(CšÀ„&h`d®µfìp*8€'ÌGÞð† xá sØ'8î!‡8ha㈂|ÔT­%Ð [êx xØ-¼ýxW® í@¥H)¨?¥à÷Ңơpöì¼TW–ì@ ͤ/p-c2TЂЧR±² Ic&5hA-à˜n©Á AŽ ‹=ÌŒq€C[x|†7LAZo@5_¸Eƒ»ˆNÃ{áfà.ð®`É þÐBzºŠTРÿ°À÷Ž­"Ü {û5g E‰€%#H&‘ÜF ÁF› äp6÷ç×NN*Ë3¢@…,£çth·ÀªÏma*àB Ìð‚=afÐCÔ MKa ]øÎ`‡È± ¼wi]xІuCaíL Á Û¡ª2p®Î „Ыz§A$°‘Žï R(`Š"ìÒˆàÁû%i/%’X^9¨ßši*ÃݪeþûšPÑ„ÜäÂQ XÖ&ƒsSÀQŽ2ð Ý33,dQq©å G~ChäZì‚€YšþÑ‘ŠZÙr¨(Kïs4arýX2ªwøaRÀb \Š\Að" „}×í6‹  8h,å1¿^ gð˜ó*"mAލ•9T [àt°Pp eàd éÆ 9Ò>ÀNP À °Z6 °\ ]K`s h]Kà\p}5`o·G¡ ¾“ áòxW€ GQBÞPNS Ðb3œQ!•p öƒX€EM±_·ÔK©u€Bp-00 I0XðÉÄ8\P«€Œñ`öÞTZntMlP{7B%Gu þGv0Ä[ –p{ñ6ǧ ¤3¿Âa\@aðK0h¢$J%â.ì dE 3Ðfði]P^@$xö%i@BÀ]! ±X¡ ðRX,eî¥`ÔfSJpЦ h¤ …£fði ËS œc€{Æg”8U0uPÀg4M°fÀËÀ#ZÑÚQ/Ða%TP’3hcˆx çð¦Õ‹dC?A“kb¢Pz²Z`sp^°_p†¢X uÀGà@Q XQ6.T@R„'à!Ÿ°!–61ˆ¥þUÒrŒ{ð v¨ w¸FnÐ#ÂpzQ:_a€TC†CC¢ƒ»²ˆe@Pè maÉÕSà!$dp•w­³xõ¸Æ0`.à‚eKfS „g ‚DáÑN`yÁ(¶f¶_8p‘œ(0 p58Q >à Ç6Qn@xÞä »a$Çá7RPaf€Æñ#yc d0OÂIdøvjwÁ¨PaÅáÁë & w.ðð!$KQJY0ÁV ?‘q— –ðD€E\±K –‚ÒBYþì#*ò/$p‘;  Ç×|e`l@©0$ÔTHUC\E‘+5ðhÀJ'°b'ÀWP/p,f`>`B„l°cpj44 ];Ç›´Oôsoàš09ëtàsð`IÔx Ñ W¤#DhÃ@XðE‘B‘b*ÐrW€RžÅ``SGÐk³ÇA5@ èà ,ó*çFPàUiÙÀbð9Qu@A hhi !n!b°S0z5{BðæR3òP^ëàõ°¹PC'þýp°}8pX%áW@½ö 4U"qÇÙL‚ò"µ\p~ D ”ªHp>+Z‘ T0n­’?§²¢ XHE$-0szÔÇÀZ±€A7ó{wÁ-bÿf ^PšoUÔõºp2^ x±Q Þ $\ðlÀR@'ÿ"œÁ/÷Õ‚ !2')óR“ºÈ)B¨N 5€ $µ>Nð8pC H€_ytDRvhT†BWaPq“Pd #…$l` DcOÅ$B@«± â]Í"]úov°¥¦µ£-mþq2ËÅ*P ÷ñM£©p}^å .äf 6€¨)0x Q=(2s)ÂK(‡ç ¡AGP‘X€qIi g?·‚ÔFvg*zt@µzySQAePg”oÀ™fAÃ¥t€Aö©?ðàc :hpkˆømwBæÈ‚‹è « wKÀ t=e€À`r'Z@ÓƒB9ðD ÁY²_( 1€‚ØóBC+´La uP†@'J_J€©ÀEVìh€dÐ2‚ %ÄGºÀm·ƒ MÀV(C:d™‘d- ÇõƒÂAˆþNpvââŽeÌåá2€‚EÈ#x¥ãà\p§æ]°œöü’_€z_ cWÄ„¸$´øBRé'`Š@1B€TIØžI  ‰‡´*Âq3]P8Ãm@“G™ã>àQW8’2àT_PÃ9zBð@à-@ p2ã aB‰jÁÎÚ ŠÔ.Äã ð¸\{‘uµp°pÿ›CÐ^‡ù׃P7Ж‘ ÇQMA–©ì#wévã~NPlhöYÀû‹7‘8ä8 “€º0BwXW€ ŒC «ÇeÀü+/Ðþ//Ž»ðź3m1PUPO¨Esµ©Pt µ@5z"4G&Q=4p?0Xy–!\ñÕ’ »É¨TH»4S2ñ#À0G!‘ò_ïÚ0á‘å7@½?e3{ÐÁoÐऻ¶ð¦Š1œ9ÓÁ-S¸ da:dÉE½>9a%äŒn`‚bPq ²îð¢ÿ‘=°b¡V€ÃX9tpKáÇ›y0º_H0]±>~)±:) q®™•§,A!4E02* ±›HM?BÁ„N59*¶ 1Fµê!à0þmÇáV@@àCÌ…PÜ ;OGy„&s`jn2jQœÄarð@ÿJ203 Ypq`»ÖÃFp]*RŒB§1´7Ð"úãŠÐ´_ö'$ððx9×q[:F©`XáZDZ&&º]4ÀÚLÈãÂÍ@B°Yв¹>x "ö5s*! °)@s;ða@ïj3Å0!Id”™š-…dݧŠT˜¡z©@2þ>¿PLR'€ ¼8xð6Ò¤TP¬h ç¸zµW]p&8ÛÜ%òÑ4àB9v‡ÁM¦ƒÙq p")")À–= á( À!r®¢ñ "!9°8QÔœ/¡E·¡¸h¨J{t¹©8” áªeðÔ‘f gUÆú“]4Ç M°Å²`i1m€œ6\S0šV ÄK€5»ÀÅ3^€‰PðU“;LÀC@ ?”"ß³Q냸üò²öÜNp(ðœ=œ=ÌÛK1!0¢Cp`0Cýw+†£gÍËþ8™á}MhÉ@T‚ƒmФMÐ$!´* v ŒTLÀic×á›´prjså&ÄÂizàÌÂ\ ×ÜY;ÄØL09Ævx?üXAdT~x9PAϾ$¡1‘1` –›~SŒD`9 s^p¸9y‚LuPCjÜ ÷´\hL@m­m 0O¥âÜÇb¦³ 8^Bl ª:û { set coords [%W invtransform %x %y] catch { %W marker configure [%W marker get current] -coords $coords } } $graph marker bind all { set marker [%W marker get current] catch { %W marker configure $marker -bg green} } $graph marker bind all { set marker [%W marker get current] catch { %W marker configure $marker -bg ""} } blt-2.4z.orig/demos/scripts/bgtest.tcl0100644000175000017500000000104307374404237016546 0ustar dokodoko set fid [open "../README" "r"] set data [read $fid] close $fid regsub -all "\r|\n|\t" $data " " data set data [split $data " "] set count 0 set maxWords 500 foreach word $data { if { $word == "" } { continue } if { $count & 0x1 } { puts -nonewline stderr "($word)" flush stderr } else { puts -nonewline stdout "($word)" flush stdout } incr count if { ($count % 10) == 0 } { puts stdout "" puts stderr "" flush stdout flush stderr } if { $count > $maxWords } { break } after 500 } exit 0 blt-2.4z.orig/demos/scripts/clone.tcl0100644000175000017500000000437307240160077016360 0ustar dokodoko proc CopyOptions { cmd orig new } { set all [eval $orig $cmd] set configLine $new foreach arg $cmd { lappend configLine $arg } foreach option $all { if { [llength $option] != 5 } { continue } set switch [lindex $option 0] set initial [lindex $option 3] set current [lindex $option 4] if { [string compare $initial $current] == 0 } { continue } lappend configLine $switch $current } eval $configLine } proc CopyBindings { oper orig new args } { set tags [$orig $oper bind] if { [llength $args] > 0 } { lappend tags [lindex $args 0] } foreach tag $tags { foreach binding [$orig $oper bind $tag] { set cmd [$orig $oper bind $tag $binding] $new $oper bind $tag $binding $cmd } } } proc CloneGraph { orig new } { graph $new CopyOptions "configure" $orig $new # Axis component foreach axis [$orig axis names] { if { [$new axis name $axis] == "" } { $new axis create $axis } CopyOptions [list axis configure $axis] $orig $new } foreach axis { x y x2 y2 } { $new ${axis}axis use [$orig ${axis}axis use] } # Pen component foreach pen [$orig pen names] { if { [$new pen name $pen] == "" } { $new pen create $pen } CopyOptions [list pen configure $pen] $orig $new } # Marker component foreach marker [$orig marker names] { $new marker create [$orig marker type $marker] -name $marker CopyBindings marker $orig $new $marker CopyOptions [list marker configure $marker] $orig $new } # Element component foreach elem [$orig element names] { $new element create $elem CopyBindings element $orig $new $elem CopyOptions [list element configure $elem] $orig $new } # Fix element display list $new element show [$orig element show] # Legend component CopyOptions {legend configure} $orig $new CopyBindings legend $orig $new # Postscript component CopyOptions {postscript configure} $orig $new # Grid component CopyOptions {grid configure} $orig $new # Grid component CopyOptions {crosshairs configure} $orig $new # Graph bindings foreach binding [bind $orig] { set cmd [bind $orig $binding] bind $new $binding $cmd } return $new } toplevel .top pack [CloneGraph $graph .top.graph] blt-2.4z.orig/demos/scripts/demo.tcl0100644000175000017500000000146607461125075016210 0ustar dokodoko# ---------------------------------------------------------------------------- # # The following code is solely a convenience so that you can test the # BLT distribution without first installing it. # # ---------------------------------------------------------------------------- # If we're in the ./demos directory, we can simply specify # "../library" as the library directory without having to install the # files. if { [file exists ../library/bltGraph.pro] } { global blt_library set blt_library ../library set auto_path [linsert $auto_path 0 $blt_library] auto_reset } # Add a binding for convenience to let you exit with pressing the # "quit" button. wm protocol . WM_DELETE_WINDOW { DoExit 0 } bind all { DoExit 0 } proc DoExit { code } { destroy . #exit $code } blt-2.4z.orig/demos/scripts/globe.tcl0100644000175000017500000006623707240160077016357 0ustar dokodokoblt::bitmap define globe.0 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0x40, 0x02, 0x00, 0x00, 0x1c, 0x3c, 0x00, 0x00, 0x01, 0xfe, 0x00, 0x80, 0x80, 0xfe, 0x03, 0x60, 0x00, 0xff, 0x07, 0x10, 0xc0, 0xf1, 0x0f, 0x00, 0x80, 0xc0, 0x1f, 0x00, 0xc0, 0x07, 0x3f, 0x00, 0xc0, 0xff, 0x3f, 0x00, 0xf0, 0xff, 0x4f, 0x02, 0xf0, 0xff, 0x5d, 0x00, 0xf0, 0xff, 0x1b, 0x00, 0xf0, 0xff, 0x8f, 0x02, 0xf0, 0xff, 0x0f, 0x06, 0xe0, 0xfc, 0x0f, 0x0e, 0x00, 0xf8, 0x0f, 0x0f, 0x00, 0xf8, 0x07, 0x3f, 0x00, 0xf8, 0x03, 0x7e, 0x00, 0xf0, 0x03, 0x7e, 0x00, 0xf0, 0x03, 0x3e, 0x00, 0xf0, 0x0b, 0x3c, 0x00, 0xf0, 0x09, 0x3c, 0x00, 0xf0, 0x01, 0x18, 0x00, 0xf0, 0x00, 0x18, 0x00, 0x70, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00}; } blt::bitmap define globe.1 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0xc0, 0x00, 0x00, 0x00, 0x34, 0x38, 0x00, 0x00, 0x02, 0xe8, 0x00, 0x80, 0x01, 0xfa, 0x03, 0xe0, 0x00, 0xfc, 0x07, 0x30, 0x00, 0xe6, 0x0f, 0x10, 0x00, 0x86, 0x1f, 0x08, 0x00, 0x3e, 0x3c, 0x04, 0x00, 0xff, 0x3f, 0x04, 0x80, 0xff, 0x5f, 0x02, 0x80, 0xff, 0x3f, 0x00, 0x80, 0xff, 0x2f, 0x00, 0x80, 0xff, 0x3f, 0x0c, 0x00, 0xff, 0x3f, 0x1c, 0x00, 0xee, 0x3f, 0x3c, 0x00, 0xc0, 0x3f, 0x7e, 0x00, 0xc0, 0x1f, 0xfe, 0x01, 0x80, 0x1f, 0xfc, 0x03, 0x80, 0x1f, 0xfc, 0x01, 0x80, 0x1f, 0xfc, 0x01, 0x80, 0x2f, 0xf8, 0x01, 0x80, 0x0f, 0xf0, 0x00, 0x80, 0x17, 0xf0, 0x00, 0x80, 0x03, 0xf0, 0x00, 0x80, 0x03, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00}; } blt::bitmap define globe.2 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0xc0, 0x01, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0x04, 0xf0, 0x00, 0x80, 0x07, 0xe0, 0x03, 0xe0, 0x01, 0xf0, 0x07, 0xf0, 0x00, 0x38, 0x0f, 0x30, 0x00, 0x10, 0x1e, 0x18, 0x00, 0xf0, 0x30, 0x04, 0x00, 0xf8, 0x3f, 0x10, 0x00, 0xf8, 0x7f, 0x12, 0x00, 0xfc, 0x7f, 0x02, 0x00, 0xfc, 0x7f, 0x04, 0x00, 0xfc, 0x7f, 0x74, 0x00, 0xf8, 0x7f, 0xf0, 0x00, 0x70, 0x7f, 0xf8, 0x01, 0x00, 0x7e, 0xf8, 0x03, 0x00, 0x7e, 0xf8, 0x0f, 0x00, 0x7c, 0xf8, 0x1f, 0x00, 0x3c, 0xf0, 0x1f, 0x00, 0x3c, 0xf0, 0x0f, 0x00, 0x3e, 0xe0, 0x0f, 0x00, 0x5e, 0xc0, 0x07, 0x00, 0x1c, 0xc0, 0x03, 0x00, 0x0e, 0xc0, 0x03, 0x00, 0x04, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x1c, 0x00}; } blt::bitmap define globe.3 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0xc0, 0x01, 0x00, 0x00, 0xdc, 0x20, 0x00, 0x00, 0x09, 0xc0, 0x00, 0x80, 0x1f, 0xa0, 0x03, 0xe0, 0x07, 0xc0, 0x07, 0xf0, 0x01, 0xc0, 0x0c, 0xf8, 0x00, 0x40, 0x18, 0x78, 0x00, 0xc0, 0x23, 0x08, 0x00, 0xc0, 0x3f, 0x04, 0x00, 0xe0, 0x7f, 0x54, 0x00, 0xe0, 0x7f, 0x0c, 0x00, 0xc0, 0x7f, 0x10, 0x00, 0xc0, 0xff, 0xd0, 0x01, 0xc0, 0xff, 0xc0, 0x03, 0x80, 0xfb, 0xe0, 0x0f, 0x00, 0xf0, 0xe0, 0x1f, 0x00, 0xf0, 0xe0, 0xff, 0x00, 0xf0, 0xe0, 0xff, 0x00, 0x70, 0xc0, 0xff, 0x00, 0x70, 0xc0, 0x7f, 0x00, 0x70, 0x00, 0x7f, 0x00, 0x70, 0x00, 0x3f, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x38, 0x00, 0x1f, 0x00, 0x18, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x18, 0x00}; } blt::bitmap define globe.4 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0xc0, 0x03, 0x00, 0x00, 0x7c, 0x03, 0x00, 0x00, 0x13, 0x00, 0x00, 0x80, 0x7f, 0xc0, 0x03, 0xc0, 0x1f, 0x00, 0x07, 0xe0, 0x0f, 0x00, 0x0d, 0xf0, 0x03, 0x00, 0x10, 0xf0, 0x01, 0x00, 0x0e, 0x38, 0x01, 0x00, 0x3e, 0x10, 0x00, 0x00, 0x7f, 0x50, 0x00, 0x00, 0x7f, 0x30, 0x00, 0x00, 0x7f, 0x40, 0x00, 0x00, 0xff, 0x00, 0x1e, 0x00, 0xfe, 0x00, 0x3f, 0x00, 0xec, 0x00, 0x7f, 0x00, 0xc0, 0x00, 0xff, 0x00, 0xc0, 0x00, 0xff, 0x07, 0xc0, 0x00, 0xff, 0x0f, 0xc0, 0x00, 0xfe, 0x07, 0xc0, 0x00, 0xfe, 0x07, 0xc0, 0x00, 0xf8, 0x03, 0x40, 0x00, 0xf8, 0x01, 0x60, 0x00, 0xf8, 0x00, 0x20, 0x00, 0xf8, 0x00, 0x20, 0x00, 0x38, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x00}; } blt::bitmap define globe.5 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0xc0, 0x03, 0x00, 0x00, 0xbc, 0x06, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x80, 0xff, 0x01, 0x02, 0xc0, 0x7f, 0x00, 0x06, 0xc0, 0x3f, 0x00, 0x0e, 0xe0, 0x1f, 0x00, 0x14, 0xe0, 0x0f, 0x00, 0x18, 0xe0, 0x00, 0x00, 0x38, 0x60, 0x00, 0x00, 0x78, 0x40, 0x08, 0x00, 0x78, 0xc0, 0x01, 0x00, 0x78, 0x00, 0x02, 0x00, 0xf8, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x01, 0xb0, 0x00, 0xf8, 0x07, 0x80, 0x00, 0xf8, 0x0f, 0x80, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0xf0, 0x3f, 0x80, 0x00, 0xf0, 0x3f, 0x80, 0x00, 0xc0, 0x1f, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0xc0, 0x07, 0x40, 0x00, 0xc0, 0x07, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 0x00}; } blt::bitmap define globe.6 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0x80, 0x07, 0x00, 0x00, 0x7c, 0x0d, 0x00, 0x00, 0x9f, 0x03, 0x00, 0x00, 0xff, 0x07, 0x02, 0x00, 0xff, 0x03, 0x04, 0x80, 0xff, 0x00, 0x08, 0xc0, 0x7f, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x30, 0x80, 0x07, 0x00, 0x20, 0x00, 0x03, 0x00, 0x60, 0x00, 0x03, 0x00, 0x60, 0x00, 0x0e, 0x00, 0x60, 0x00, 0x10, 0x00, 0xe0, 0x00, 0x80, 0x07, 0xc0, 0x00, 0x80, 0x0f, 0xc0, 0x00, 0x80, 0x3f, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, 0xc0, 0xff, 0x03, 0x00, 0x80, 0xff, 0x01, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00}; } blt::bitmap define globe.7 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0x80, 0x07, 0x00, 0x00, 0xfc, 0x1a, 0x00, 0x00, 0x7d, 0x02, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xfe, 0x01, 0x20, 0x00, 0x1c, 0x01, 0x00, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x18, 0x00, 0x40, 0x00, 0x70, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x39, 0x80, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xf0, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00}; } blt::bitmap define globe.8 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0x00, 0x07, 0x00, 0x00, 0xfc, 0x25, 0x00, 0x00, 0xf8, 0x19, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x08, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0xc0, 0x04, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0xc0, 0x1f, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00}; } blt::bitmap define globe.9 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0x00, 0x03, 0x00, 0x00, 0xfc, 0x27, 0x00, 0x00, 0xf0, 0x13, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0xe0, 0xff, 0x01, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x80, 0x47, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x40, 0x0e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00}; } blt::bitmap define globe.10 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0x00, 0x06, 0x00, 0x00, 0xf4, 0x2f, 0x00, 0x00, 0xc8, 0x4f, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x80, 0xff, 0x01, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x30, 0x04, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00}; } blt::bitmap define globe.11 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0x00, 0x06, 0x00, 0x00, 0xec, 0x1f, 0x00, 0x00, 0x91, 0x9f, 0x00, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xf0, 0x01, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x80, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00}; } blt::bitmap define globe.12 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0x00, 0x04, 0x00, 0x00, 0xdc, 0x3f, 0x00, 0x00, 0x42, 0x7e, 0x00, 0x00, 0x00, 0xf8, 0x03, 0x20, 0x00, 0xf0, 0x07, 0x10, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x04, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; } blt::bitmap define globe.13 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0x00, 0x04, 0x00, 0x00, 0xbc, 0x3f, 0x00, 0x00, 0x01, 0x79, 0x00, 0x80, 0x00, 0xe0, 0x03, 0x60, 0x00, 0xc0, 0x07, 0x10, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x80, 0x1f, 0x08, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00}; } blt::bitmap define globe.14 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0x03, 0xe6, 0x00, 0x80, 0x01, 0xc0, 0x03, 0x60, 0x00, 0x00, 0x07, 0x30, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x38, 0x04, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00}; } blt::bitmap define globe.15 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3d, 0x00, 0x00, 0x27, 0xc8, 0x00, 0x80, 0x13, 0x00, 0x03, 0xe0, 0x01, 0x00, 0x06, 0x70, 0x00, 0x00, 0x0c, 0x10, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00, 0x20, 0x0c, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0xf8, 0x03, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00}; } blt::bitmap define globe.16 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3b, 0x00, 0x00, 0x9f, 0xa0, 0x00, 0x80, 0x4f, 0x00, 0x02, 0xe0, 0x0f, 0x00, 0x04, 0xf0, 0x01, 0x00, 0x08, 0x70, 0x00, 0x00, 0x10, 0x38, 0x00, 0x00, 0x20, 0x3c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x28, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x02, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00}; } blt::bitmap define globe.17 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x37, 0x00, 0x00, 0x3f, 0x42, 0x00, 0x80, 0x3f, 0x01, 0x02, 0xe0, 0x1f, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xf0, 0x11, 0x00, 0x00, 0xf8, 0x04, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x08, 0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00}; } blt::bitmap define globe.18 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x2f, 0x00, 0x00, 0xff, 0x84, 0x00, 0x80, 0xff, 0x04, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0xf0, 0x9f, 0x00, 0x00, 0xf0, 0x97, 0x00, 0x00, 0xf8, 0x27, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x60, 0x04, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0xa0, 0x01, 0x00, 0x00, 0x00, 0xc0, 0x05, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03, 0x00}; } blt::bitmap define globe.19 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0x40, 0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xff, 0x13, 0x00, 0x80, 0xff, 0x13, 0x00, 0xe0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf0, 0x9f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xba, 0x07, 0x00, 0x00, 0x98, 0x23, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x09, 0x00, 0x00, 0x00, 0x0d, 0x01, 0x00, 0x00, 0x21, 0x0e, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x09, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x07, 0x00}; } blt::bitmap define globe.20 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x80, 0xff, 0x0f, 0x00, 0xe0, 0xff, 0x0f, 0x00, 0xf0, 0xff, 0x13, 0x00, 0xf0, 0xff, 0x10, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xf4, 0xff, 0x00, 0x00, 0xe6, 0x1e, 0x00, 0x00, 0x62, 0x1c, 0x01, 0x00, 0x20, 0x18, 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0xcc, 0x00, 0x00, 0x01, 0x68, 0x08, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00}; } blt::bitmap define globe.21 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0x80, 0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x80, 0xff, 0xbf, 0x00, 0xe0, 0xff, 0x3f, 0x00, 0xf0, 0xff, 0x1f, 0x00, 0xf8, 0xff, 0x17, 0x00, 0xf8, 0xff, 0x27, 0x00, 0xec, 0xff, 0x0f, 0x00, 0x8c, 0xff, 0x07, 0x00, 0x9e, 0xf7, 0x00, 0x00, 0x0e, 0xe3, 0x00, 0x00, 0x06, 0xc1, 0x00, 0x00, 0x06, 0x81, 0x10, 0x00, 0x03, 0x40, 0x04, 0x00, 0x03, 0x20, 0x06, 0x00, 0x03, 0x40, 0x06, 0x00, 0x01, 0x80, 0x00, 0x03, 0x01, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xe0, 0x02, 0x02, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x1f, 0x00}; } blt::bitmap define globe.22 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0x00, 0x01, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xf0, 0xff, 0x7f, 0x00, 0xf0, 0xff, 0x1f, 0x00, 0xe0, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0x34, 0xfe, 0x3f, 0x00, 0x76, 0xbc, 0x07, 0x00, 0x36, 0x1c, 0x07, 0x00, 0x0e, 0x08, 0x0e, 0x00, 0x1e, 0x08, 0x80, 0x00, 0x0f, 0x00, 0x02, 0x00, 0x0f, 0x00, 0x20, 0x00, 0x07, 0x00, 0x36, 0x00, 0x07, 0x00, 0x04, 0x08, 0x07, 0x00, 0x00, 0x18, 0x06, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x0b, 0x16, 0x00, 0x80, 0x0f, 0x04, 0x00, 0xe0, 0x0f, 0x04, 0x00, 0xe0, 0x0f, 0x08, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x1f, 0x00}; } blt::bitmap define globe.23 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x80, 0xff, 0xff, 0x01, 0xe0, 0xff, 0xff, 0x01, 0xe0, 0xff, 0xff, 0x01, 0xe8, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xfc, 0xfe, 0xff, 0x01, 0xdc, 0xf2, 0xff, 0x01, 0xde, 0xe3, 0x3d, 0x00, 0xde, 0xe1, 0x38, 0x02, 0x7e, 0x40, 0x70, 0x00, 0xfe, 0x40, 0x00, 0x04, 0x7f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x30, 0x01, 0x3e, 0x00, 0xa0, 0x01, 0x1e, 0x00, 0x20, 0x20, 0x1e, 0x00, 0x00, 0x20, 0x1c, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x3c, 0x1c, 0x00, 0x00, 0x3e, 0x1c, 0x00, 0x00, 0x3f, 0x18, 0x00, 0x80, 0x3f, 0x10, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x1f, 0x00}; } blt::bitmap define globe.24 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0x00, 0x02, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x80, 0xff, 0xff, 0x01, 0xc0, 0xff, 0xff, 0x03, 0x80, 0xff, 0xff, 0x03, 0xe0, 0xff, 0xff, 0x03, 0x18, 0xff, 0xff, 0x03, 0xfc, 0xff, 0xff, 0x07, 0x7c, 0x87, 0xff, 0x07, 0xfe, 0x1f, 0xef, 0x01, 0xfe, 0x0e, 0xc6, 0x01, 0xfe, 0x01, 0x82, 0x03, 0xfe, 0x03, 0x02, 0x00, 0xff, 0x03, 0x00, 0x08, 0xfc, 0x01, 0x80, 0x09, 0xfc, 0x00, 0x00, 0x0d, 0xfc, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x80, 0xf8, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x20, 0x78, 0x02, 0x00, 0x70, 0x70, 0x02, 0x00, 0x7c, 0x70, 0x00, 0x00, 0x3c, 0x60, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x1f, 0x00}; } blt::bitmap define globe.25 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x80, 0xff, 0xff, 0x03, 0x80, 0xff, 0xff, 0x07, 0xa0, 0xff, 0xff, 0x07, 0x10, 0xff, 0xff, 0x07, 0x30, 0xf8, 0xff, 0x0f, 0xf8, 0xdf, 0xff, 0x1f, 0xfc, 0x3b, 0xfc, 0x1f, 0xfc, 0xfb, 0x78, 0x07, 0xfe, 0x77, 0x30, 0x0e, 0xfe, 0x1f, 0x30, 0x0c, 0xfe, 0x3f, 0x00, 0x48, 0xfe, 0x1f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x24, 0xf0, 0x07, 0x00, 0xa0, 0xf0, 0x07, 0x00, 0x08, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x27, 0x00, 0xc0, 0xe0, 0x13, 0x00, 0x40, 0xc0, 0x13, 0x00, 0x70, 0xc0, 0x03, 0x00, 0x70, 0x80, 0x01, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x1f, 0x00}; } blt::bitmap define globe.26 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0x40, 0x00, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0xe8, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xff, 0xff, 0x07, 0xc0, 0xfe, 0xff, 0x0f, 0x40, 0xf0, 0xff, 0x1f, 0xe0, 0xe0, 0xff, 0x1f, 0xf0, 0xff, 0xfe, 0x3f, 0xf8, 0xdf, 0xe1, 0x3f, 0xf8, 0xdf, 0xc7, 0x1b, 0xfc, 0xbf, 0x83, 0x19, 0xfc, 0xff, 0x80, 0x30, 0xfc, 0xff, 0x01, 0x20, 0xf8, 0xff, 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0xe0, 0x80, 0x3f, 0x00, 0x20, 0x80, 0x3f, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x80, 0x3f, 0x01, 0x80, 0x80, 0x9f, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x40, 0x00, 0x0f, 0x00, 0x60, 0x00, 0x0e, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x1f, 0x00}; } blt::bitmap define globe.27 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0x80, 0x00, 0x00, 0x00, 0xc4, 0x3f, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xeb, 0xff, 0x0f, 0x80, 0xc9, 0xff, 0x1f, 0x80, 0x07, 0xff, 0x3f, 0xc0, 0xff, 0xf7, 0x3f, 0xe0, 0xff, 0x0e, 0x7f, 0xf0, 0xff, 0x3e, 0x6e, 0xf0, 0xff, 0x1d, 0x64, 0xf0, 0xff, 0x07, 0x44, 0xf0, 0xff, 0x0f, 0x00, 0x60, 0xff, 0x0f, 0x00, 0x00, 0xfe, 0x07, 0x40, 0x00, 0xfe, 0x03, 0x00, 0x01, 0xfc, 0x01, 0x00, 0x01, 0xfc, 0x01, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0xfc, 0x09, 0x00, 0x02, 0xfc, 0x08, 0x00, 0x00, 0xf8, 0x04, 0x00, 0x00, 0x78, 0x00, 0x40, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f, 0x00}; } blt::bitmap define globe.28 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x3f, 0x00, 0x00, 0x40, 0xff, 0x00, 0x00, 0xe8, 0xff, 0x03, 0x00, 0xf8, 0xff, 0x07, 0x00, 0x8c, 0xff, 0x0f, 0x00, 0x06, 0xfe, 0x1f, 0x00, 0x1e, 0xf8, 0x3f, 0x00, 0xff, 0xbf, 0x3f, 0x80, 0xff, 0x77, 0x7c, 0x80, 0xff, 0xff, 0x79, 0xc0, 0xff, 0xef, 0x10, 0xc0, 0xff, 0x3f, 0x90, 0xc0, 0xff, 0x7f, 0x00, 0x81, 0xfb, 0x7f, 0x00, 0x01, 0xf0, 0x3f, 0x00, 0x01, 0xf0, 0x1f, 0x00, 0x03, 0xe0, 0x1f, 0x00, 0x07, 0xe0, 0x0f, 0x00, 0x02, 0xc0, 0x1f, 0x00, 0x02, 0xe0, 0x5f, 0x00, 0x06, 0xe0, 0x47, 0x00, 0x04, 0xc0, 0x27, 0x00, 0x04, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x1f, 0x00}; } blt::bitmap define globe.29 { #define globe_width 32 #define globe_height 32 static char globe_bits[] = { 0x00, 0x40, 0x01, 0x00, 0x00, 0x0c, 0x3f, 0x00, 0x00, 0x80, 0xfd, 0x00, 0x00, 0xa0, 0xff, 0x03, 0x20, 0xe0, 0xff, 0x07, 0x00, 0x30, 0xfd, 0x0f, 0x00, 0x10, 0xf4, 0x1f, 0x00, 0xf8, 0xc0, 0x3f, 0x00, 0xf8, 0xff, 0x3f, 0x00, 0xfc, 0xbf, 0x73, 0x00, 0xfe, 0xff, 0x67, 0x00, 0xfe, 0x7f, 0x47, 0x00, 0xfe, 0xff, 0x41, 0x00, 0xfe, 0xff, 0x03, 0x01, 0xdc, 0xff, 0x03, 0x03, 0x00, 0xff, 0x01, 0x07, 0x80, 0xff, 0x00, 0x0f, 0x00, 0xff, 0x00, 0x1f, 0x00, 0x7e, 0x00, 0x0e, 0x00, 0xfe, 0x00, 0x0e, 0x00, 0xff, 0x02, 0x0e, 0x00, 0x3f, 0x01, 0x0c, 0x00, 0x3e, 0x01, 0x0c, 0x00, 0x1e, 0x00, 0x08, 0x00, 0x1c, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, 0x00}; } blt-2.4z.orig/demos/scripts/graph1.tcl0100644000175000017500000000445307433350451016442 0ustar dokodoko set X { 2.00000e-01 4.00000e-01 6.00000e-01 8.00000e-01 1.00000e+00 1.20000e+00 1.40000e+00 1.60000e+00 1.80000e+00 2.00000e+00 2.20000e+00 2.40000e+00 2.60000e+00 2.80000e+00 3.00000e+00 3.20000e+00 3.40000e+00 3.60000e+00 3.80000e+00 4.00000e+00 4.20000e+00 4.40000e+00 4.60000e+00 4.80000e+00 5.00000e+00 } set Y1 { 4.07008e+01 7.95658e+01 1.16585e+02 1.51750e+02 1.85051e+02 2.16479e+02 2.46024e+02 2.73676e+02 2.99427e+02 3.23267e+02 3.45187e+02 3.65177e+02 3.83228e+02 3.99331e+02 4.13476e+02 4.25655e+02 4.35856e+02 4.44073e+02 4.50294e+02 4.54512e+02 4.56716e+02 4.57596e+02 4.58448e+02 4.59299e+02 4.60151e+02 } set Y2 { 5.14471e-00 2.09373e+01 2.84608e+01 3.40080e+01 3.75691e+01 3.91345e+01 3.92706e+01 3.93474e+01 3.94242e+01 3.95010e+01 3.95778e+01 3.96545e+01 3.97313e+01 3.98081e+01 3.98849e+01 3.99617e+01 4.00384e+01 4.01152e+01 4.01920e+01 4.02688e+01 4.03455e+01 4.04223e+01 4.04990e+01 4.05758e+01 4.06526e+01 } set Y3 { 2.61825e+01 5.04696e+01 7.28517e+01 9.33192e+01 1.11863e+02 1.28473e+02 1.43140e+02 1.55854e+02 1.66606e+02 1.75386e+02 1.82185e+02 1.86994e+02 1.89802e+02 1.90683e+02 1.91047e+02 1.91411e+02 1.91775e+02 1.92139e+02 1.92503e+02 1.92867e+02 1.93231e+02 1.93595e+02 1.93958e+02 1.94322e+02 1.94686e+02 } set configOptions { Axis.TitleFont {Times 18 bold} Element.Pixels 6 Element.Smooth catrom Legend.ActiveBackground khaki2 Legend.ActiveRelief sunken Legend.Background "" Title "A Simple X-Y Graph" activeLine.Color yellow4 activeLine.Fill yellow background khaki3 line1.Color red4 line1.Fill red1 line1.Symbol circle line2.Color purple4 line2.Fill purple1 line2.Symbol arrow line3.Color green4 line3.Fill green1 line3.Symbol triangle x.Descending no x.Loose no x.Title "X Axis Label" y.Rotate 90 y.Title "Y Axis Label" } set resource [string trimleft $graph .] foreach { option value } $configOptions { option add *$resource.$option $value } $graph element create line1 -x $X -y $Y2 $graph element create line2 -x $X -y $Y3 $graph element create line3 -x $X -y $Y1 Blt_ZoomStack $graph Blt_Crosshairs $graph Blt_ActiveLegend $graph Blt_ClosestPoint $graph blt-2.4z.orig/demos/scripts/graph2.tcl0100644000175000017500000000624507433613270016445 0ustar dokodokooption add *HighlightThickness 0 option add *Tile bgTexture option add *Button.Tile "" image create photo bgTexture -file ./images/chalk.gif set configOptions [subst { InvertXY no Axis.TickFont { Helvetica 14 bold } Axis.TitleFont { Helvetica 12 bold } BorderWidth 2 Element.Pixels 8 Element.ScaleSymbols true Element.Smooth cubic Font { Helvetica 18 bold } Foreground white Legend.ActiveBorderWidth 2 Legend.ActiveRelief raised Legend.Anchor ne Legend.BorderWidth 0 Legend.Font { Helvetica 34 } Legend.Foreground orange #Legend.Position plotarea Legend.Hide yes Legend.Relief flat Postscript.Preview yes Relief raised Shadow { navyblue 2 } Title "Bitmap Symbols" degrees.Command [namespace current]::FormatAxisLabel degrees.LimitsFormat "Deg=%g" degrees.Subdivisions 0 degrees.Title "Degrees" degrees.stepSize 90 temp.LimitsFormat "Temp=%g" temp.Title "Temperature" y.Color purple2 y.LimitsFormat "Y=%g" y.Rotate 90 y.Title "Y" y.loose no y2.Color magenta3 y2.Hide no xy2.Rotate 270 y2.Rotate 0 y2.Title "Y2" y2.LimitsFormat "Y2=%g" x2.LimitsFormat "x2=%g" }] set resource [string trimleft $graph .] foreach { option value } $configOptions { option add *$resource.$option $value } proc FormatAxisLabel {graph x} { format "%d%c" [expr int($x)] 0xB0 } set max -1.0 set step 0.2 set letters { A B C D E F G H I J K L } set count 0 for { set level 30 } { $level <= 100 } { incr level 10 } { set color [format "#dd0d%0.2x" [expr round($level*2.55)]] set pen "pen$count" set symbol "symbol$count" bitmap compose $symbol [lindex $letters $count] \ -font -*-helvetica-medium-r-*-*-34-*-*-*-*-*-*-* $graph pen create $pen \ -color $color \ -symbol $symbol \ -fill "" \ -pixels 13 set min $max set max [expr $max + $step] lappend styles "$pen $min $max" incr count } $graph axis create temp \ -color lightgreen \ -title Temp $graph axis create degrees \ -rotate 90 $graph xaxis use degrees set tcl_precision 15 set pi1_2 [expr 3.14159265358979323846/180.0] vector create w x sinX cosX radians x seq -360.0 360.0 10.0 #x seq -360.0 -180.0 30.0 radians expr { x * $pi1_2 } sinX expr sin(radians) cosX expr cos(radians) cosX dup w vector destroy radians vector create xh xl yh yl set pct [expr ($cosX(max) - $cosX(min)) * 0.025] yh expr {cosX + $pct} yl expr {cosX - $pct} set pct [expr ($x(max) - $x(min)) * 0.025] xh expr {x + $pct} xl expr {x - $pct} $graph element create line3 \ -color green4 \ -fill green \ -label "cos(x)" \ -mapx degrees \ -styles $styles \ -weights w \ -x x \ -y cosX \ -yhigh yh -ylow yl $graph element create line1 \ -color orange \ -outline black \ -fill orange \ -fill yellow \ -label "sin(x)" \ -linewidth 3 \ -mapx degrees \ -pixels 6m \ -symbol "@bitmaps/hobbes.xbm @bitmaps/hobbes_mask.xbm" \ -x x \ -y sinX Blt_ZoomStack $graph Blt_Crosshairs $graph #Blt_ActiveLegend $graph Blt_ClosestPoint $graph Blt_PrintKey $graph blt-2.4z.orig/demos/scripts/graph3.tcl0100644000175000017500000000332207526260714016443 0ustar dokodokoproc FormatAxisLabel {graph x} { return "[expr int($x)]\260" } set configOptions [subst { Axis.Hide no Axis.Limits "%g" Axis.TickFont { helvetica 12 bold } Axis.TitleFont { helvetica 12 bold } BorderWidth 1 Element.Pixels 1.75m Element.ScaleSymbols yes Font { helvetica 23 bold } Legend.ActiveBorderWidth 2 Legend.ActiveRelief raised Legend.Anchor ne Legend.BorderWidth 0 Legend.Font { Helvetica 24 } Legend.Position plotarea Relief sunken Title "Sine and Cosine Functions" x.Command [namespace current]::FormatAxisLabel x.StepSize 90 x.Subdivisions 0 x.Title "X" y.Color purple2 y.Loose no y.Title "Y" y.rotate 90 y2.color magenta3 }] set resName [string trimleft $graph .] foreach { option value } $configOptions { option add *$resName.$option $value } $graph configure -leftvar changed set tcl_precision 15 set pi1_2 [expr 3.14159265358979323846/180.0] vector create x sinX cosX -variable "" x seq -360 360 5 sinX expr { sin(x*$pi1_2) } cosX expr { cos(x*$pi1_2) } $graph element create line1 \ -label "sin(x)" \ -fill orange \ -color black \ -x x \ -y sinX $graph element create line2 \ -label "cos(x)" \ -color yellow4 \ -fill yellow \ -x x \ -y cosX Blt_ZoomStack $graph Blt_Crosshairs $graph Blt_ActiveLegend $graph Blt_ClosestPoint $graph #Blt_PrintKey $graph $graph marker create bitmap \ -name bg \ -coords "-360 -1 360 1" \ -bitmap @bitmaps/greenback.xbm \ -bg darkseagreen1 \ -fg darkseagreen3 \ -under yes \ -rotate 45 # -rotate 45 $graph postscript configure \ -maxpect yes \ -landscape yes blt-2.4z.orig/demos/scripts/graph5.tcl0100644000175000017500000000270007433613270016440 0ustar dokodoko set configOptions { Element.LineWidth 0 Element.Pixels 0.7c Element.ScaleSymbols true Font { Courier 18 bold} Height 4i Legend.ActiveRelief raised Legend.Font { Courier 14 } Legend.padY 0 Title "Element Symbol Types" Width 5i } set resName [string trimleft $graph .] foreach { option value } $configOptions { option add *$resName.$option $value } vector xValues xValues set { 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 } for { set i 0 } { $i < 10 } { incr i } { set vecName "y${i}" vector ${vecName}(10) $vecName variable x set x(:) [expr $i*50.0+10.0] } set attributes { none "None" red red4 y0 circle "Circle" yellow yellow4 y2 cross "Cross" cyan cyan4 y6 diamond "Diamond" green green4 y3 plus "Plus" magenta magenta4 y9 splus "Splus" Purple purple4 y7 scross "Scross" red red4 y8 square "Square" orange orange4 y1 triangle "Triangle" blue blue4 y4 "@bitmaps/hobbes.xbm @bitmaps/hobbes_mask.xbm" "Bitmap" yellow black y5 } set count 0 foreach { symbol label fill color yVec } $attributes { $graph element create line${count} \ -label $label \ -symbol $symbol \ -color $color \ -fill $fill \ -x xValues \ -y $yVec incr count } $graph element configure line0 \ -dashes { 2 4 2 } \ -linewidth 2 Blt_ZoomStack $graph Blt_Crosshairs $graph Blt_ActiveLegend $graph Blt_ClosestPoint $graph Blt_PrintKey $graph blt-2.4z.orig/demos/scripts/graph8.tcl0100644000175000017500000000526407433613270016453 0ustar dokodoko set X { 2.00000e-01 4.00000e-01 6.00000e-01 8.00000e-01 1.00000e+00 1.20000e+00 1.40000e+00 1.60000e+00 1.80000e+00 2.00000e+00 2.20000e+00 2.40000e+00 2.60000e+00 2.80000e+00 3.00000e+00 3.20000e+00 3.40000e+00 3.60000e+00 3.80000e+00 4.00000e+00 4.20000e+00 4.40000e+00 4.60000e+00 4.80000e+00 5.00000e+00 } set Y1 { 1.14471e+01 2.09373e+01 2.84608e+01 3.40080e+01 3.75691e+01 3.91345e+01 3.92706e+01 3.93474e+01 3.94242e+01 3.95010e+01 3.95778e+01 3.96545e+01 3.97313e+01 3.98081e+01 3.98849e+01 3.99617e+01 4.00384e+01 4.01152e+01 4.01920e+01 4.02688e+01 4.03455e+01 4.04223e+01 4.04990e+01 4.05758e+01 4.06526e+01 } set Y2 { 2.61825e+01 5.04696e+01 7.28517e+01 9.33192e+01 1.11863e+02 1.28473e+02 1.43140e+02 1.55854e+02 1.66606e+02 1.75386e+02 1.82185e+02 1.86994e+02 1.89802e+02 1.90683e+02 1.91047e+02 1.91411e+02 1.91775e+02 1.92139e+02 1.92503e+02 1.92867e+02 1.93231e+02 1.93595e+02 1.93958e+02 1.94322e+02 1.94686e+02 } set Y3 { 4.07008e+01 7.95658e+01 1.16585e+02 1.51750e+02 1.85051e+02 2.16479e+02 2.46024e+02 2.73676e+02 2.99427e+02 3.23267e+02 3.45187e+02 3.65177e+02 3.83228e+02 3.99331e+02 4.13476e+02 4.25655e+02 4.35856e+02 4.44073e+02 4.50294e+02 4.54512e+02 4.56716e+02 4.57596e+02 4.58448e+02 4.59299e+02 4.60151e+02 } proc FormatLabel { w value } { return $value } #option add *Graph.aspect 1.25 option add *Graph.title "A Simple X-Y Graph" option add *Graph.x.loose yes option add *Graph.x.title "X Axis Label" option add *Graph.y.title "Y Axis Label" option add *Graph.y.rotate 90 option add *Graph.y.logScale yes option add *Graph.y.loose no option add *Graph.Axis.titleFont {Times 18 bold} option add *Legend.activeRelief sunken option add *Legend.background "" option add *Legend.activeBackground khaki2 option add *Graph.background brown option add *Element.xData $X option add *activeLine.Color yellow4 option add *activeLine.Fill yellow option add *Element.smooth natural option add *Element.pixels 6 option add *Element.scaleSymbols yes option add *Graph.line1.symbol circle option add *Graph.line1.color red4 option add *Graph.line1.fill red1 option add *Graph.line2.symbol square option add *Graph.line2.color purple4 option add *Graph.line2.fill purple1 option add *Graph.line3.symbol triangle option add *Graph.line3.color green4 option add *Graph.line3.fill green1 $graph configure \ -width 4i \ -height 5i $graph element create line1 \ -ydata $Y2 $graph element create line2 \ -ydata $Y3 $graph element create line3 \ -ydata $Y1 Blt_ZoomStack $graph Blt_Crosshairs $graph Blt_ActiveLegend $graph Blt_ClosestPoint $graph blt-2.4z.orig/demos/scripts/page.tcl0100755000175000017500000000555607240160077016203 0ustar dokodoko#!/usr/local/bin/tclsh array set page " rows 2 columns 2 padx 0.5 pady 0.5 width 8.5 height 11 gutter 0.25 " proc Pica { dist } { expr $dist * 72.0 } # ------------------------------------------------------------------ # # TileFiles # # Tiles graph postscript files together in a pre-defined # grid. # # Arguments: # outFile -- Resulting tiled PostScript output file. # args -- Names of input graph PostScript files. # # ------------------------------------------------------------------ proc TileFiles { outFile args } { global page set row 0 set column 0 set padx [Pica $page(padx)] set pady [Pica $page(padx)] set width [Pica $page(width)] set height [Pica $page(height)] set gutter [Pica $page(gutter)] set totalGutters [expr $gutter * ($page(columns) - 1)] set w [expr $width - (2 * $padx) - $totalGutters] set totalGutters [expr $gutter * ($page(rows) - 1)] set h [expr $height - (2 * $pady) - $totalGutters] set cellWidth [expr double($w) / $page(columns)] set cellHeight [expr double($h) / $page(rows)] set out [open $outFile "w"] puts $out "%!PS-Adobe-3.0 EPSF-3.0" puts $out "%%Pages: 1" puts $out "%%Title: (Graph tiler)" puts $out "%%DocumentNeededResources: font Helvetica Courier" puts $out "%%CreationDate: [clock format [clock seconds]]" puts $out "%%EndComments" puts $out "/showsheet { showpage } bind def" puts $out "/showpage { } def" puts $out "$padx $pady translate" set first {} foreach inFile $args { set in [open $inFile "r"] # Warning, this is assuming that the BoundingBox is in the first # twenty lines of the graph's PostScript. for { set count 0 } { $count < 20 } { incr count } { gets $in line if { [string match "%%BoundingBox:*" $line] } { set bbox $line break; } append first "$line\n" if { [eof $in] } { break } } if { ![info exists bbox] } { error "can't find \"%%BoundingBox:\" line" } set n [scan $bbox "%%%%BoundingBox: %d %d %d %d" x1 y1 x2 y2] if { $n != 4} { error "Bad bounding box line \"$bbox\"" } set rest [read $in] close $in set x [expr ($cellWidth + $gutter) * $column] set y [expr ($cellHeight + $gutter) * $row] set w [expr abs($x2 - $x1)] set h [expr abs($y2 - $y1)] set scaleX [expr $cellWidth / $w] set scaleY [expr $cellHeight / $h] if { $scaleX > $scaleY } { set scale $scaleY } else { set scale $scaleX } puts $out "% " puts $out "% Tiling \"$inFile\" at ($row,$column)" puts $out "% " puts $out "gsave" puts $out "$x $y translate" puts $out "$scale $scale scale" puts $out "-$x1 -$y1 translate" puts $out $first puts $out $rest puts $out "grestore" incr column if { $column >= $page(columns) } { set column 0 incr row } } puts $out "showsheet" close $out } eval TileFiles $argv blt-2.4z.orig/demos/scripts/patterns.tcl0100644000175000017500000000146207240160077017114 0ustar dokodokoblt::bitmap define pattern1 { {4 4} {01 02 04 08} } blt::bitmap define pattern2 { {4 4} {08 04 02 01} } blt::bitmap define pattern3 { {2 2} {01 02 } } blt::bitmap define pattern4 { {4 4} {0f 00 00 00} } blt::bitmap define pattern5 { {4 4} {01 01 01 01} } blt::bitmap define pattern6 { {2 2} {01 00 } } blt::bitmap define pattern7 { {4 4} {0f 01 01 01} } blt::bitmap define pattern8 { {8 8} {ff 00 ff 00 ff 00 ff 00 } } blt::bitmap define pattern9 { {4 4} {03 03 0c 0c} } blt::bitmap define hobbes { {25 25} { 00 00 00 00 00 00 00 00 00 c0 03 00 78 e0 07 00 fc f8 07 00 cc 07 04 00 0c f0 0b 00 7c 1c 06 00 38 00 00 00 e0 03 10 00 e0 41 11 00 20 40 11 00 e0 07 10 00 e0 c1 17 00 10 e0 2f 00 20 e0 6f 00 18 e0 2f 00 20 c6 67 00 18 84 2b 00 20 08 64 00 70 f0 13 00 80 01 08 00 00 fe 07 00 00 00 00 00 00 00 00 00 } } blt-2.4z.orig/demos/scripts/ps.tcl0100644000175000017500000005362507433641503015710 0ustar dokodoko#bltdebug 100 array set cursors { w left_side e right_side n top_side s bottom_side sw bottom_left_corner ne top_right_corner se bottom_right_corner nw top_left_corner } array set pageInfo { gripSize 8 scale 0.25 radioFont -*-helvetica-medium-r-*-*-11-120-*-*-*-*-*-* labelFont -*-helvetica-bold-r-*-*-12-120-*-*-*-*-*-* printCmd "nlp -d2a211" printFile "out.ps" } proc SetUnits { units } { global pageInfo switch -glob $units { "i*" { set pageInfo(uscale) [winfo fpixels . 1i] } "c*" { set pageInfo(uscale) [winfo fpixels . 1c] } default { error "unknown unit \"$units\"" } } set pageInfo(units) [string index $units 0] } proc ConvertUnits { value } { global pageInfo set value [expr double($value) / $pageInfo(uscale)] return [format "%.1f%s" $value $pageInfo(units)] } proc SetPaperSize { unit } { global pageInfo SetUnits $unit set pageInfo(-paperwidth) [lindex $pageInfo(paperSize) 0] set pageInfo(-paperheight) [lindex $pageInfo(paperSize) 1] ApplyPs } proc SetCanvasSize { canvas width height } { global pageInfo set width [winfo pixels . $width] set height [winfo pixels . $height] $canvas configure -width $width -height $height } proc SetCanvasOrientation { canvas } { global pageInfo set width $pageInfo(paperWidth) set height $pageInfo(paperHeight) SetCanvasSize $canvas $width $height } proc GetPsOptions { graph } { global pageInfo foreach opt [$graph postscript configure] { set pageInfo([lindex $opt 0]) [lindex $opt 4] } } proc SetOutline { canvas } { global pageInfo foreach var { gripSize xMin yMin xMax yMax } { set $var $pageInfo($var) } set xMid [expr ($xMax + $xMin - $gripSize) * 0.5] set yMid [expr ($yMax + $yMin - $gripSize) * 0.5] $canvas coords image $xMin $yMin $canvas itemconfigure image \ -width [expr $xMax - $xMin] -height [expr $yMax - $yMin] $canvas coords nw \ $xMin $yMin [expr $xMin + $gripSize] [expr $yMin + $gripSize] $canvas coords se \ [expr $xMax - $gripSize] [expr $yMax - $gripSize] $xMax $yMax $canvas coords ne \ [expr $xMax - $gripSize] [expr $yMin + $gripSize] $xMax $yMin $canvas coords sw \ $xMin $yMax [expr $xMin + $gripSize] [expr $yMax - $gripSize] SetCanvasOrientation $canvas $canvas coords n \ $xMid $yMin [expr $xMid + $gripSize] [expr $yMin + $gripSize] $canvas coords s \ $xMid [expr $yMax - $gripSize] [expr $xMid + $gripSize] $yMax $canvas coords e \ [expr $xMax - $gripSize] $yMid $xMax [expr $yMid + $gripSize] $canvas coords w \ $xMin $yMid [expr $xMin + $gripSize] [expr $yMid + $gripSize] } proc CreateOutline { canvas } { global pageInfo foreach var { gripSize xMin yMin xMax yMax } { set $var $pageInfo($var) } if { ![bitmap exists pattern8] } { bitmap define pattern8 { {8 8} {ff 00 ff 00 ff 00 ff 00 } } } $canvas create eps $xMin $yMin \ -tags "outline image" \ -width [expr $xMax - $xMin] \ -height [expr $yMax - $yMin] $canvas bind image "StartMove $canvas %x %y" $canvas bind image "MoveOutline $canvas %x %y" $canvas bind image "EndMove $canvas" $canvas bind image "ConstrainMoveOutline $canvas %x %y" $canvas bind image "EnterImage $canvas" $canvas bind image "LeaveImage $canvas" focus $canvas $canvas create rectangle \ $xMin $yMin [expr $xMin + $gripSize] [expr $yMin + $gripSize] \ -tags "outline grip nw" $canvas create rectangle \ [expr $xMax - $gripSize] [expr $yMax - $gripSize] $xMax $yMax \ -tags "outline grip se" $canvas create rectangle \ [expr $xMax - $gripSize] [expr $yMin + $gripSize] $xMax $yMin \ -tags "outline grip ne" $canvas create rectangle \ $xMin $yMax [expr $xMin + $gripSize] [expr $yMax - $gripSize] \ -tags "outline grip sw" set xMid [expr ($xMax + $xMin - $gripSize) * 0.5] set yMid [expr ($yMax + $yMin - $gripSize) * 0.5] $canvas create rectangle \ $xMid $yMin [expr $xMid + $gripSize] [expr $yMin + $gripSize] \ -tags "outline grip n" $canvas create rectangle \ $xMid [expr $yMax - $gripSize] [expr $xMid + $gripSize] $yMax \ -tags "outline grip s" $canvas create rectangle \ [expr $xMax - $gripSize] $yMid $xMax [expr $yMid + $gripSize] \ -tags "outline grip e" $canvas create rectangle \ $xMin $yMid [expr $xMin + $gripSize] [expr $yMid + $gripSize] \ -tags "outline grip w" foreach grip { e w s n sw ne se nw } { $canvas bind $grip "StartResize %W $grip %x %y" $canvas bind $grip "ResizeOutline %W %x %y" $canvas bind $grip "EndResize %W $grip %x %y" $canvas bind $grip "EnterGrip %W $grip %x %y" $canvas bind $grip "LeaveGrip %W $grip" } $canvas raise grip $canvas itemconfigure grip -fill red -outline black set pageInfo(image) [image create photo] $pageInfo(graph) snap $pageInfo(image) $canvas itemconfigure image -image $pageInfo(image) } proc EnterImage { canvas } { global cursors global pageInfo bind $canvas { MoveOutline %W [expr $pageInfo(lastX) - 1] $pageInfo(lastY) } bind $canvas { MoveOutline %W [expr $pageInfo(lastX) + 1] $pageInfo(lastY) } bind $canvas { MoveOutline %W $pageInfo(lastX) [expr $pageInfo(lastY) - 1] } bind $canvas { MoveOutline %W $pageInfo(lastX) [expr $pageInfo(lastY) + 1] } focus $canvas $canvas configure -cursor fleur set pageInfo(lastX) 0 set pageInfo(lastY) 0 } proc LeaveImage { canvas } { bind $canvas "" bind $canvas "" bind $canvas "" bind $canvas "" $canvas configure -cursor "" } proc EnterGrip { canvas grip x y } { global pageInfo $canvas itemconfigure $grip -fill blue -outline black set pageInfo(grip) $grip global cursors bind $canvas { ResizeOutline %W [expr $pageInfo(lastX) - 1] $pageInfo(lastY) } bind $canvas { ResizeOutline %W [expr $pageInfo(lastX) + 1] $pageInfo(lastY) } bind $canvas { ResizeOutline %W $pageInfo(lastX) [expr $pageInfo(lastY) - 1] } bind $canvas { ResizeOutline %W $pageInfo(lastX) [expr $pageInfo(lastY) + 1] } focus $canvas $canvas configure -cursor $cursors($grip) set pageInfo(lastX) $x set pageInfo(lastY) $y } proc LeaveGrip { canvas grip } { $canvas itemconfigure $grip -fill red -outline black bind $canvas "" bind $canvas "" bind $canvas "" bind $canvas "" $canvas configure -cursor "" } proc StartMove { canvas x y } { global pageInfo set pageInfo(lastX) $x set pageInfo(lastY) $y set pageInfo(direction) "undecided" $canvas configure -cursor fleur } proc MoveOutline { canvas x y } { global pageInfo $canvas move outline [expr $x - $pageInfo(lastX)] [expr $y - $pageInfo(lastY)] set pageInfo(lastX) $x set pageInfo(lastY) $y } proc ConstrainMoveOutline { canvas x y } { global pageInfo set dx [expr $x - $pageInfo(lastX)] set dy [expr $y - $pageInfo(lastY)] if { $pageInfo(direction) == "undecided" } { if { abs($dx) > abs($dy) } { set pageInfo(direction) x $canvas configure -cursor sb_h_double_arrow } else { set pageInfo(direction) y $canvas configure -cursor sb_v_double_arrow } } switch $pageInfo(direction) { x { set dy 0 ; set pageInfo(lastX) $x } y { set dx 0 ; set pageInfo(lastY) $y } } $canvas move outline $dx $dy } proc EndMove { canvas } { $canvas configure -cursor "" set coords [$canvas coords image] set x [lindex $coords 0] set y [lindex $coords 1] set w [$canvas itemcget image -width] set h [$canvas itemcget image -height] global pageInfo set pageInfo(xMin) $x set pageInfo(xMin) $y set pageInfo(xMax) [expr $x + $w] set pageInfo(yMax) [expr $y + $h] global pageInfo set pageInfo(-padx) [list $pageInfo(xMin) [expr $pageInfo(paperWidth) - $pageInfo(xMax)]] set pageInfo(-pady) [list $pageInfo(yMin) [expr $pageInfo(paperHeight) - $pageInfo(yMax)]] } proc StartResize { canvas grip x y } { global pageInfo $canvas itemconfigure image -quick yes set pageInfo(grip) $grip $canvas itemconfigure $grip -fill red -outline black $canvas raise grip global cursors $canvas configure -cursor $cursors($grip) set pageInfo(lastX) $x set pageInfo(lastY) $y } proc EndResize { canvas grip x y } { $canvas itemconfigure image -quick no ResizeOutline $canvas $x $y $canvas itemconfigure $grip -fill "" -outline "" $canvas configure -cursor "" } proc ResizeOutline { canvas x y } { global pageInfo foreach var { gripSize xMin yMin xMax yMax } { set $var $pageInfo($var) } switch $pageInfo(grip) { n { set yMin $y } s { set yMax $y } e { set xMax $x } w { set xMin $x } sw { set xMin $x ; set yMax $y } ne { set xMax $x ; set yMin $y } se { set xMax $x ; set yMax $y } nw { set xMin $x ; set yMin $y } } set width [expr $xMax - $xMin] set height [expr $yMax - $yMin] if { ($width < 1) || ($height < 1) } { return } SetOutline $canvas foreach var { xMin yMin xMax yMax } { set pageInfo($var) [set $var] } } proc ComputePlotGeometry { graph } { global pageInfo GetPsOptions $graph set width [winfo width $graph] set height [winfo height $graph] if { $pageInfo(-width) > 0 } { set width $pageInfo(-width) } if { $pageInfo(-height) > 0 } { set height $pageInfo(-height) } set left [lindex $pageInfo(-padx) 0] set right [lindex $pageInfo(-padx) 1] set top [lindex $pageInfo(-pady) 0] set bottom [lindex $pageInfo(-pady) 1] set padx [expr $left + $right] set pady [expr $top + $bottom] if { $pageInfo(-paperwidth) > 0 } { set paperWidth $pageInfo(-paperwidth) } else { set paperWidth [expr $width + $padx] } if { $pageInfo(-paperheight) > 0 } { set paperHeight $pageInfo(-paperheight) } else { set paperHeight [expr $height + $pady] } if { $pageInfo(-landscape) } { set temp $paperWidth set paperWidth $paperHeight set paperHeight $temp } set scale 1.0 if { $pageInfo(-maxpect) } { set xScale [expr ($paperWidth - $padx) / double($width)] set yScale [expr ($paperHeight - $pady) / double($height)] set scale [expr min($xScale,$yScale)] set bboxWidth [expr round($width * $scale)] set bboxHeight [expr round($height * $scale)] } else { if { ($width + $padx) > $paperWidth } { set width [expr $paperWidth - $padx] } if { ($height + $pady) > $paperHeight } { set height [expr $paperHeight - $pady] } set bboxWidth $width set bboxHeight $height } set x $left set y $top if { $pageInfo(-center) } { if { $paperWidth > $bboxWidth } { set x [expr ($paperWidth - $bboxWidth) / 2] } if { $paperHeight > $bboxHeight } { set y [expr ($paperHeight - $bboxHeight) / 2] } } set pageInfo(xMin) [expr $x * $pageInfo(scale)] set pageInfo(yMin) [expr $y * $pageInfo(scale)] set pageInfo(xMax) [expr ($x + $bboxWidth) * $pageInfo(scale)] set pageInfo(yMax) [expr ($y + $bboxHeight) * $pageInfo(scale)] set pageInfo(paperHeight) [expr $paperHeight * $pageInfo(scale)] set pageInfo(paperWidth) [expr $paperWidth * $pageInfo(scale)] } proc PsDialog { graph } { global pageInfo set pageInfo(graph) $graph set top $graph.top toplevel $top option add *graph.top*Radiobutton.font $pageInfo(radioFont) GetPsOptions $graph ComputePlotGeometry $graph set canvas $top.layout canvas $canvas -confine yes \ -width $pageInfo(paperWidth) -height $pageInfo(paperHeight) -bg gray \ -bd 2 -relief sunken CreateOutline $canvas SetCanvasOrientation $canvas label $top.titleLabel -text "PostScript Options" table $top \ 0,0 $top.titleLabel -cspan 7 \ 1,0 $canvas -cspan 7 set row 2 set col 0 label $top.paperLabel -text "Paper" radiobutton $top.letter -text "Letter 8 1/2 x 11 in." -value "8.5i 11i" \ -variable pageInfo(paperSize) \ -command "SetPaperSize i" radiobutton $top.a3 -text "A3 29.7 x 42 cm." -value "28.7c 41c" \ -variable pageInfo(paperSize) \ -command "SetPaperSize c" radiobutton $top.a4 -text "A4 21 x 29.7 cm." -value "21c 29.7c" \ -variable pageInfo(paperSize) \ -command "SetPaperSize c" radiobutton $top.a5 -text "A5 14.85 x 21 cm." -value "14.85c 21c" \ -variable pageInfo(paperSize) \ -command "SetPaperSize c" radiobutton $top.legal -text "Legal 8 1/2 x 14 in." -value "8.5i 14i" \ -variable pageInfo(paperSize) \ -command "SetPaperSize i" radiobutton $top.large -text "Large 11 x 17 in." -value "11i 17i" \ -variable pageInfo(paperSize) \ -command "SetPaperSize i" table configure $top r$row -pady { 4 0 } table $top \ $row,$col $top.paperLabel -anchor e \ $row+0,$col+1 $top.letter -anchor w \ $row+1,$col+1 $top.legal -anchor w \ $row+2,$col+1 $top.large -anchor w \ $row+0,$col+2 $top.a3 -anchor w \ $row+1,$col+2 $top.a4 -anchor w \ $row+2,$col+2 $top.a5 -anchor w incr row 3 label $top.orientLabel -text "Orientation" radiobutton $top.portrait -text "Portrait" -value "0" \ -variable pageInfo(-landscape) -command "ApplyPs" radiobutton $top.landscape -text "Landscape" -value "1" \ -variable pageInfo(-landscape) -command "ApplyPs" table configure $top r$row -pady { 4 0 } table $top \ $row,$col+0 $top.orientLabel -anchor e \ $row,$col+1 $top.portrait -anchor w \ $row,$col+2 $top.landscape -anchor w incr row 6 set col 0 label $top.plotLabel -text "Plot Options" table $top \ $row,$col $top.plotLabel -cspan 3 incr row label $top.sizeLabel -text "Size" radiobutton $top.default -text "Default" -value "default" \ -variable pageInfo(plotSize) \ -command "SetPlotSize" radiobutton $top.maxpect -text "Max Aspect" -value "maxpect" \ -variable pageInfo(plotSize) \ -command "SetPlotSize" radiobutton $top.resize -text "Resize" -value "resize" \ -variable pageInfo(plotSize) \ -command "SizeDialog $graph {Adjust Plot Size}" table configure $top r$row -pady { 4 0 } table $top \ $row,$col $top.sizeLabel -anchor e \ $row,$col+1 $top.default -anchor w \ $row+1,$col+1 $top.maxpect -anchor w \ $row+2,$col+1 $top.resize -anchor w #incr row 4 set pageInfo(oldPadX) $pageInfo(-padx) set pageInfo(oldPadY) $pageInfo(-pady) label $top.posLabel -text "Position" set pageInfo(position) $pageInfo(-center) radiobutton $top.center -text "Center" -value "1" \ -variable pageInfo(position) -command { set pageInfo(-center) 1 CenterPlot } radiobutton $top.origin -text "Origin" -value "0" \ -variable pageInfo(position) -command { set pageInfo(-center) 0 ApplyPs } radiobutton $top.move -text "Move" -value "move" \ -variable pageInfo(position) -command { set pageInfo(-center) 0 MoveDialog } table configure $top r$row -pady { 4 0 } table $top \ $row,$col+2 $top.posLabel -anchor e \ $row,$col+3 $top.center -anchor w \ $row+1,$col+3 $top.origin -anchor w \ $row+2,$col+3 $top.move -anchor w incr row 4 label $top.printLabel -text "Print To" radiobutton $top.toFile -text "File" -value "printFile" \ -variable pageInfo(printTo) -command " $top.fileEntry configure -textvariable pageInfo(printFile) " radiobutton $top.toCmd -text "Command" -value "printCmd" \ -variable pageInfo(printTo) -command " $top.fileEntry configure -textvariable pageInfo(printCmd) " entry $top.fileEntry table configure $top r$row -pady { 4 0 } table configure $top r[expr $row+1] -pady { 4 0 } table configure $top r[expr $row+2] -pady { 4 0 } table $top \ $row,0 $top.printLabel -anchor e \ $row,1 $top.toFile -anchor w \ $row+1,1 $top.toCmd -anchor w \ $row+2,1 $top.fileEntry -anchor w -fill x -cspan 3 $top.toFile invoke incr row 3 #table configure $top c4 -width .125i button $top.cancel -text "Cancel" -command "destroy $top" button $top.print -text "Done" -command "PrintPs $graph" button $top.advanced -text "Options" -command "MarginDialog $graph" table $top \ $row,1 $top.print -width 1i -pady 2 \ $row,2 $top.advanced -width 1i -pady 2 \ $row,3 $top.cancel -width 1i -pady 2 -anchor w SetUnits "inches" foreach label [info commands $top.*Label] { $label configure -font $pageInfo(labelFont) -padx 4 } } proc PrintPs { graph } { $graph postscript output "out.ps" puts stdout "wrote file \"out.ps\"." flush stdout } proc ApplyPs { } { global pageInfo set graph $pageInfo(graph) foreach option [$graph postscript configure] { set var [lindex $option 0] set old [lindex $option 4] if { [catch {$graph postscript configure $var $pageInfo($var)}] != 0 } { $graph postscript configure $var $old set pageInfo($var) $old } } ComputePlotGeometry $graph foreach var { -paperheight -paperwidth -width -height } { set pageInfo($var) [ConvertUnits $pageInfo($var)] } SetOutline $graph.top.layout } proc StartChange { w delta } { ChangeSize $w $delta global pageInfo set pageInfo(afterId) [after 300 RepeatChange $w $delta] } proc RepeatChange { w delta } { ChangeSize $w $delta global pageInfo set pageInfo(afterId) [after 100 RepeatChange $w $delta] } proc EndChange { w } { global pageInfo after cancel $pageInfo(afterId) } proc ChangeSize { w delta } { set f [winfo parent $w] set value [$f.entry get] set value [expr $value + $delta] if { $value < 0 } { set value 1 } $f.entry delete 0 end $f.entry insert 0 $value } proc MakeSizeAdjustor { w label var } { frame $w label $w.label -text $label button $w.plus -text "+" -padx 1 -pady 0 -font \*symbol\* entry $w.entry -width 6 -textvariable "pageInfo($var)" button $w.minus -text "-" -padx 1 -pady 0 -font \*symbol\* label $w.units -text "in" bind $w.plus { StartChange %W 0.1} bind $w.plus { EndChange %W } bind $w.minus { StartChange %W -0.1} bind $w.minus { EndChange %W } table $w \ 0,1 $w.label \ 1,1 $w.entry -rspan 2 -fill y \ 1,0 $w.minus -padx 2 -pady 2 \ 2,0 $w.plus -padx 2 -pady { 0 2 } \ 1,2 $w.units -rspan 2 -fill y } proc SizeDialog { graph title } { global pageInfo set top .plotSize if { [winfo exists $top] } { return } toplevel $top label $top.title -text $title button $top.cancel -text "Cancel" -command "destroy $top" button $top.ok -text "Ok" -command "ApplyPs; destroy $top" MakeSizeAdjustor $top.plotWidth "Width" -width MakeSizeAdjustor $top.plotHeight "Height" -height table $top \ 0,0 $top.title -cspan 2 \ 1,0 $top.plotWidth \ 1,1 $top.plotHeight \ 2,0 $top.cancel -pady 4 -padx 4 -width 1i \ 2,1 $top.ok -pady 4 -padx 4 -width 1i set width [winfo fpixels . $pageInfo(-width)] set height [winfo fpixels . $pageInfo(-height)] if { $width == 0 } { set width [expr ($pageInfo(xMax) - $pageInfo(xMin)) / $pageInfo(scale)] set pageInfo(-width) [ConvertUnits $width] } if { $height == 0 } { set height [expr ($pageInfo(yMax) - $pageInfo(yMin)) / $pageInfo(scale)] set pageInfo(-height) [ConvertUnits $height] } set pageInfo(-maxpect) 0 } proc SetPlotSize { } { global pageInfo set graph $pageInfo(graph) switch $pageInfo(plotSize) { default { set pageInfo(-width) 0 set pageInfo(-height) 0 set pageInfo(-maxpect) 0 set pageInfo(-padx) $pageInfo(oldPadX) set pageInfo(-pady) $pageInfo(oldPadY) } maxpect { set pageInfo(-width) 0 set pageInfo(-height) 0 set pageInfo(-maxpect) 1 set pageInfo(-padx) $pageInfo(oldPadX) set pageInfo(-pady) $pageInfo(oldPadY) } resize { set pageInfo(-maxpect) 0 } } ApplyPs } proc PaperSizeDialog { title } { set top .paperSize if { [winfo exists $top] } { return } toplevel $top label $top.title -text $title MakeSizeAdjustor $top.width "Width" -paperwidth MakeSizeAdjustor $top.height "Height" -paperheight button $top.cancel -text "Cancel" -command "destroy $top" button $top.ok -text "Ok" -command "ApplyPs; destroy $top" table $top \ 0,0 $top.title -cspan 2 \ 1,0 $top.width \ 1,1 $top.height \ 2,0 $top.cancel -pady 4 -padx 4 -width 1i \ 2,1 $top.ok -pady 4 -padx 4 -width 1i } proc MarginDialog { graph } { set top $graph.top.options if { [winfo exists $top] } { return } toplevel $top set row 0 set col 0 label $top.modeLabel -text "Printer" radiobutton $top.color -text "Color" -value "color" \ -variable pageInfo(-colormode) -command "ApplyPs" radiobutton $top.greyscale -text "Greyscale" -value "greyscale" \ -variable pageInfo(-colormode) -command "ApplyPs" table $top \ $row,$col $top.modeLabel -anchor e \ $row,$col+1 $top.color -anchor w \ $row+1,$col+1 $top.greyscale -anchor w table configure $top r$row -pady { 4 0 } label $top.previewLabel -text "Preview" radiobutton $top.previewYes -text "Yes" -value "1" \ -variable pageInfo(-preview) -command "ApplyPs" radiobutton $top.previewNo -text "No" -value "0" \ -variable pageInfo(-preview) -command "ApplyPs" set col 2 table $top \ $row,$col $top.previewLabel -anchor e \ $row,$col+1 $top.previewYes -anchor w \ $row+1,$col+1 $top.previewNo -anchor w incr row 2 button $top.cancel -text "Cancel" -command "destroy $top" button $top.ok -text "Done" -command "PrintPs $graph" table $top \ $row,0 $top.cancel -pady 4 -padx 4 -width 1i \ $row,1 $top.ok -pady 4 -padx 4 -width 1i } proc CenterPlot { } { global pageInfo set pageInfo(-padx) $pageInfo(oldPadX) set pageInfo(-pady) $pageInfo(oldPadY) ApplyPs } blt-2.4z.orig/demos/scripts/send.tcl0100644000175000017500000000636207240160077016211 0ustar dokodoko # -------------------------------------------------------------------------- # # SendInit -- # # Creates a "send" proc to replace the former Tk send command. # Uses DDE services to simulate the transfer. This must be # called before any drag&drop targets are registered. Otherwise # they will pick up the wrong application name. # # The first trick is to determine a unique application name. This # is what other applications will use to send to us. Tk used to # do this for us. # # Note that we can generate the same name for two different Tk # applications. This can happen if two Tk applications picking # names at exactly the same time. [In the future, we should # probably generate a name based upon a global system value, such # as the handle of the main window ".".] The proc "SendVerify" # below will verify that you have only one DDE server registered # with this application's name. # # Arguments: # myInterp Sets the application name explicitly to this # string. If the argument isn't given, or is the # empty string, then the routine picks a name for # us. # # Results: # Returns the name of the application. # # Side Effects: # Sets the name of our application. You can call "tk appname" to # get the name. A DDE topic using the same name is also created. # A send proc is also automatically created. Be careful that you # don't overwrite an existing send command. # # -------------------------------------------------------------------------- proc SendInit { {myInterp ""} } { # Load the DDE package. package require dde if { $myInterp == "" } { # Pick a unique application name, replicating what Tk used to do. # This is what other applications will use to "send" to us. We'll # use DDE topics to represent interpreters. set appName [tk appname] set count 0 set suffix {} # Keep generating interpreter names by suffix-ing the original # application name with " #number". Sooner of later we'll find # one that's not currently use. while { 1 } { set myInterp "${appName}${suffix}" set myServer [list TclEval $myInterp] if { [lsearch [dde services TclEval {}] $myServer] < 0 } { break } incr count set suffix " \#$count" } } tk appname $myInterp dde servername $myInterp proc send { interp args } { dde eval $interp $args } return $myInterp } # -------------------------------------------------------------------------- # # SendVerify -- # # Verifies that application name picked is uniquely registered # as a DDE server. This checks that two Tk applications don't # accidently use the same name. # # Arguments: # None Used the current application name. # # Results: # Generates an error if either a server can't be found or more # than one server is registered. # # -------------------------------------------------------------------------- proc SendVerify {} { # Load the DDE package. package require dde set count 0 set appName [tk appname] foreach server [dde services TclEval {}] { set topic [lindex $server 1] if { [string compare $topic $appName] == 0 } { incr count } } if {$count == 0} { error "Service not found: wrong name registered???" } if { $count > 1 } { error "Duplicate names found for \"[tk appname]\"" } } blt-2.4z.orig/demos/scripts/stipples.tcl0100644000175000017500000000731707240160077017124 0ustar dokodokoblt::bitmap define bdiagonal1 { #define bdiagonal1_width 8 #define bdiagonal1_height 8 static unsigned char bdiagonal1_bits[] = { 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11}; } blt::bitmap define bdiagonal2 { #define bdiagonal2_width 8 #define bdiagonal2_height 8 static unsigned char bdiagonal2_bits[] = { 0x08, 0x04, 0x02, 0x01, 0x80, 0x40, 0x20, 0x10}; } blt::bitmap define checker2 { #define checker2_width 8 #define checker2_height 8 static unsigned char checker2_bits[] = { 0x33, 0x33, 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc}; } blt::bitmap define checker3 { #define checker3_width 8 #define checker3_height 8 static unsigned char checker3_bits[] = { 0x0f, 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, 0xf0}; } blt::bitmap define cross1 { #define cross1_width 8 #define cross1_height 8 static unsigned char cross_bits[] = { 0xff, 0xaa, 0xff, 0xaa, 0xff, 0xaa, 0xff, 0xaa}; } blt::bitmap define cross2 { #define cross2_width 8 #define cross2_height 8 static unsigned char cross2_bits[] = { 0xff, 0x88, 0x88, 0x88, 0xff, 0x88, 0x88, 0x88}; } blt::bitmap define cross3 { #define cross3_width 8 #define cross3_height 8 static unsigned char cross3_bits[] = { 0xff, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; } blt::bitmap define crossdiag { #define crossdiag_width 8 #define crossdiag_height 8 static unsigned char crossdiag2_bits[] = { 0x18, 0x24, 0x42, 0x81, 0x81, 0x42, 0x24, 0x18}; } blt::bitmap define dot1 { #define dot1_width 8 #define dot1_height 8 static unsigned char dot1_bits[] = { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa}; } blt::bitmap define dot2 { #define dot2_width 8 #define dot2_height 8 static unsigned char dot2_bits[] = { 0x55, 0x00, 0x55, 0x00, 0x55, 0x00, 0x55, 0x00}; } blt::bitmap define dot3 { #define dot3_width 8 #define dot3_height 8 static unsigned char dot3_bits[] = { 0x11, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00}; } blt::bitmap define dot4 { #define dot4_width 8 #define dot4_height 8 static unsigned char dot4_bits[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; } blt::bitmap define fdiagonal1 { #define fdiagonal1_width 8 #define fdiagonal1_height 8 static unsigned char fdiagonal1_bits[] = { 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88}; } blt::bitmap define fdiagonal2 { #define fdiagonal2_width 8 #define fdiagonal2_height 8 static unsigned char fdiagonal2_bits[] = { 0x10, 0x20, 0x40, 0x80, 0x01, 0x02, 0x04, 0x08}; } blt::bitmap define hline1 { #define hline1_width 8 #define hline1_height 8 static unsigned char hline1_bits[] = { 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00}; } blt::bitmap define hline2 { #define hline2_width 8 #define hline2_height 8 static unsigned char hline2_bits[] = { 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00}; } blt::bitmap define lbottom { #define lbottom_width 8 #define lbottom_height 8 static unsigned char lbottom_bits[] = { 0x00, 0x11, 0x11, 0x77, 0x00, 0x11, 0x11, 0x77}; } blt::bitmap define ltop { #define ltop_width 8 #define ltop_height 8 static unsigned char ltop_bits[] = { 0xee, 0x88, 0x88, 0x00, 0xee, 0x88, 0x88, 0x00}; } blt::bitmap define rbottom { #define rbottom_width 8 #define rbottom_height 8 static unsigned char rbottom_bits[] = { 0x00, 0x88, 0x88, 0xee, 0x00, 0x88, 0x88, 0xee}; } blt::bitmap define rtop { #define rtop_width 8 #define rtop_height 8 static unsigned char rtop_bits[] = { 0x77, 0x11, 0x11, 0x00, 0x77, 0x11, 0x11, 0x00}; } blt::bitmap define vline1 { #define vline1_width 8 #define vline1_height 8 static unsigned char vline1_bits[] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55}; } blt::bitmap define vline2 { #define vline2_width 8 #define vline2_height 8 static unsigned char vline2_bits[] = { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33}; } blt-2.4z.orig/demos/scripts/xcolors.tcl0100755000175000017500000001444207374067720016763 0ustar dokodoko#!../bltwish # # Tk version of xcolors # package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } source scripts/demo.tcl set numCols 0 set numRows 0 set maxCols 15 set cellWidth 40 set cellHeight 20 set numCells 0 set lastCount 0 set beginInput(0) 0 set map 0 set entryCount 0 set lastTagId {} scrollbar .xscroll -command { .canvas xview } -orient horizontal scrollbar .yscroll -command { .canvas yview } label .sample \ -font -*-new*century*schoolbook*-bold-r-*-*-24-*-*-*-*-*-*-* \ -text {"Bisque is Beautiful".} button .name -font -*-helvetica-medium-r-*-*-18-*-*-*-*-*-*-* \ -command "AddSelection name" button .rgb -font -*-courier-medium-r-*-*-18-*-*-*-*-*-*-* \ -command "AddSelection rgb" canvas .canvas \ -confine 1 \ -yscrollcommand { .yscroll set } \ -width [expr 16*$cellWidth] -height 400 \ -scrollregion [list 0 0 [expr 16*$cellWidth] 800] frame .border -bd 2 -relief raised label .status \ -anchor w \ -font -*-helvetica-medium-r-*-*-14-*-*-*-*-*-*-* button .quit -text "Quit" -command "exit" button .next -text "Next" -command "DisplayColors next" button .prev -text "Previous" -command "DisplayColors last" selection handle .name GetColor selection handle .rgb GetValue bind .name { .status config -text \ "Press button to write color name into primary selection" } bind .rgb { .status config -text \ "Press button to write RGB value into primary selection" } bind .name { .status config -text "" } bind .rgb { .status config -text "" } bind .canvas { .status config -text \ "Press button 1 to change background; Button 2 changes foreground" } table . \ .sample 0,0 -cspan 2 -fill both -reqheight 1i \ .name 1,0 -fill both -anchor w \ .rgb 1,1 -fill both -anchor w \ .canvas 2,0 -cspan 2 -fill both \ .yscroll 2,2 -fill y \ .border 3,0 -cspan 2 -fill x -reqheight 8 \ .status 4,0 -cspan 2 -fill both \ .quit 4,1 -anchor e -reqwidth 1i -fill y -padx 10 -pady 4 \ .prev 5,0 -anchor e -reqwidth 1i -fill y -padx 10 -pady 4 \ .next 5,1 -anchor e -reqwidth 1i -fill y -padx 10 -pady 4 proc AddSelection { what } { selection own .$what if {$what == "name" } { set mesg "Color name written into primary selection" } else { set mesg "RGB value written into primary selection" } .status config -text $mesg } proc GetColor { args } { return [lindex [.name config -text] 4] } proc GetValue { args } { return [lindex [.rgb config -text] 4] } proc ShowInfo { tagId what info } { global lastTagId if { $lastTagId != {} } { .canvas itemconfig $lastTagId -width 1 } .canvas itemconfig $tagId -width 3 set lastTagId $tagId set name [lindex $info 3] .name config -text $name set value [format "#%0.2x%0.2x%0.2x" \ [lindex $info 0] [lindex $info 1] [lindex $info 2]] .rgb config -text $value .sample config $what $name .status config -bg $name } proc MakeCell { info } { global numCols numRows maxCols cellWidth cellHeight numCells set x [expr $numCols*$cellWidth] set y [expr $numRows*$cellHeight] set color [lindex $info 3] if [catch {winfo rgb . $color}] { return "ok" } # if { [tk colormodel .] != "color" } { # bind . { # .status config -text "Color table full after $numCells entries." # } # .status config -text "Color table full after $numCells entries." # return "out of colors" # } set id [.canvas create rectangle \ $x $y [expr $x+$cellWidth] [expr $y+$cellHeight] \ -fill $color -outline black] if { $color == "white" } { global whiteTagId set whiteTagId $id } .canvas bind $id <1> [list ShowInfo $id -bg $info] .canvas bind $id <2> [list ShowInfo $id -fg $info] incr numCols if { $numCols > $maxCols } { set numCols 0 incr numRows } return "ok" } proc DisplayColors { how } { global lastCount numCells cellHeight numRows numCols rgbText global map beginInput # tk colormodel . color set initialized no if { $how == "last" } { if { $map == 0 } { return } set map [expr $map-1] } else { incr map if ![info exists beginInput($map)] { set beginInput($map) $lastCount } } set start $beginInput($map) if { $numCells > 0 } { .canvas delete all set numRows 0 set numCols 0 set initialized yes } set input [lrange $rgbText $start end] set lineCount $start set entryCount 0 foreach i $input { incr lineCount if { [llength $i] == 4 } { if { [MakeCell $i] == "out of colors" } { break } incr entryCount } } if { $entryCount == 0 } { bind . { .status config -text "No more entries in RGB database" } .status config -text "No more entries in RGB database" } set lastCount $lineCount proc tkerror {args} { #dummy procedure } if { $initialized == "no" } { global cellWidth set height [expr $cellHeight*($numRows+1)] .canvas config -scrollregion [list 0 0 [expr 16*$cellWidth] $height] if { $height < 800 } { .canvas config -height $height } global whiteTagId if [info exists whiteTagId] { ShowInfo $whiteTagId -bg {255 255 255 white} } } update idletasks update rename tkerror {} } wm min . 0 0 foreach location { /usr/X11R6 /util/X11R6 /usr/openwin /usr/dt } { set file [file join $location lib X11 rgb.txt] if { [file exists $file] } { break } } set in [open $file "r"] set rgbText [read $in] close $in set rgbText [split $rgbText \n] DisplayColors next wm min . 0 0 blt-2.4z.orig/examples/0042755000175000017500000000000007553201214013566 5ustar dokodokoblt-2.4z.orig/examples/calendar.tcl0100755000175000017500000001001307514405672016047 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } #source scripts/demo.tcl set file ../demos/images/chalk.gif set active ../demos/images/rain.gif image create photo calendar.texture.1 -file $file image create photo calendar.texture.2 -file $active option add *Tile calendar.texture.1 option add *HighlightThickness 0 option add *calendar.weekframe*Tile calendar.texture.2 option add *Calendar.Label.borderWidth 0 option add *Calendar.Label.relief sunken option add *Calendar.Frame.borderWidth 2 option add *Calendar.Frame.relief raised option add *Calendar.Label.font { Helvetica 11 } option add *Calendar.Label.foreground navyblue option add *button.foreground navyblue option add *background grey85 #option add *button.activeForeground red #option add *button.activeBackground blue4 option add *Label.ipadX 200 array set monthInfo { Jan { January 31 } Feb { February 28 } Mar { March 31 } Apr { April 30 } May { May 31 } Jun { June 30 } Jul { July 31 } Aug { August 31 } Sep { September 30 } Oct { October 31 } Nov { November 30 } Dec { December 31 } } option add *tile calendar.texture.2 set abbrDays { Sun Mon Tue Wed Thu Fri Sat } proc Calendar { weekday day month year } { global monthInfo abbrDays set wkdayOffset [lsearch $abbrDays $weekday] if { $wkdayOffset < 0 } { error "Invalid week day \"$weekday\"" } set dayOffset [expr ($day-1)%7] if { $wkdayOffset < $dayOffset } { set wkdayOffset [expr $wkdayOffset+7] } set wkday [expr $wkdayOffset-$dayOffset-1] if { [info commands .calendar] == ".calendar" } { destroy .calendar } frame .calendar -class Calendar -width 3i -height 3i if ![info exists monthInfo($month)] { error "Invalid month \"$month\"" } set info $monthInfo($month) label .calendar.month \ -text "[lindex $info 0] $year" \ -font { Courier 14 bold } table .calendar .calendar.month 1,0 -cspan 7 -pady 10 set cnt 0 frame .calendar.weekframe -relief sunken -bd 1 table .calendar .calendar.weekframe 2,0 -columnspan 7 -fill both foreach dayName $abbrDays { set name [string tolower $dayName] label .calendar.$name \ -text $dayName \ -font { Helvetica 12 } table .calendar .calendar.$name 2,$cnt -pady 2 -padx 2 incr cnt } table configure .calendar c* r2 -pad 4 set week 0 set numDays [lindex $info 1] for { set cnt 1 } { $cnt <= $numDays } { incr cnt } { label .calendar.day${cnt} -text $cnt if { $cnt == $day } { .calendar.day${cnt} configure -relief sunken -bd 1 } incr wkday if { $wkday == 7 } { incr week set wkday 0 } table .calendar .calendar.day${cnt} $week+3,$wkday \ -fill both -ipadx 10 -ipady 4 } frame .calendar.quit -bd 1 -relief sunken button .calendar.quit.button -command { exit } -text {Quit} -bd 2 table .calendar.quit \ .calendar.quit.button -padx 4 -pady 4 table .calendar \ .calendar.quit $week+4,5 -cspan 2 -pady 4 table . \ .calendar -fill both table configure .calendar r0 -resize none table configure .calendar c0 c6 } set date [clock format [clock seconds] -format {%a %b %d %Y}] scan $date { %s %s %d %d } weekday month day year Calendar $weekday $day $month $year blt-2.4z.orig/examples/form.tcl0100755000175000017500000010716707240160077015253 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } #source scripts/demo.tcl option add *takeFocus 0 set file1 ../demos/images/chalk.gif set file2 ../demos/images/tan_paper.gif image create photo texture1 -file $file1 image create photo texture2 -file $file2 option add *Frame.Tile texture1 option add *Toplevel.Tile texture1 option add *Label.Tile texture1 option add *Scrollbar.tile texture1 #option add *Scrollbar.activeTile texture2 option add *Button.tile texture1 #option add *Button.activeTile texture2 option add *HighlightThickness 0 option add *Entry.highlightThickness 2 # # Initialization of global variables and Tk resource database # # # Resources available # # Tk.normalBgColor: # Tk.normalFgColor: # Tk.focusHighlightColor: # Tk.statusFont: # Tk.titleFont: # Tk.headingFont: # Tk.subheadingFont: # Tk.entryFont: # Tk.textFont: # #debug 50 bitmap define attlogo { { 60 30 } { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0xf8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x83, 0xf9, 0x87, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x80, 0xf9, 0x87, 0x7f, 0x00, 0x40, 0x00, 0xf0, 0xc7, 0xc3, 0x38, 0x0c, 0x00, 0xc0, 0xff, 0xff, 0xc7, 0xc3, 0x7c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x40, 0xc2, 0x6c, 0x0c, 0x00, 0x40, 0x00, 0xf8, 0x67, 0xc6, 0x9c, 0x0d, 0x00, 0xc0, 0xff, 0xff, 0xe7, 0xc7, 0xf8, 0x0d, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xc7, 0xec, 0x0c, 0x00, 0x80, 0x01, 0xfe, 0x33, 0xcc, 0xfc, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x33, 0xcc, 0xb8, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } bitmap define globe_00 { { 32 32 } { 00 40 02 00 00 1c 3c 00 00 01 fe 00 80 80 fe 03 60 00 ff 07 10 c0 f1 0f 00 80 c0 1f 00 c0 07 3f 00 c0 ff 3f 00 f0 ff 4f 02 f0 ff 5d 00 f0 ff 1b 00 f0 ff 8f 02 f0 ff 0f 06 e0 fc 0f 0e 00 f8 0f 0f 00 f8 07 3f 00 f8 03 7e 00 f0 03 7e 00 f0 03 3e 00 f0 0b 3c 00 f0 09 3c 00 f0 01 18 00 f0 00 18 00 70 00 10 00 00 00 10 00 00 00 20 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 1f 00 } } bitmap define globe_01 { { 32 32 } { 00 c0 00 00 00 34 38 00 00 02 e8 00 80 01 fa 03 e0 00 fc 07 30 00 e6 0f 10 00 86 1f 08 00 3e 3c 04 00 ff 3f 04 80 ff 5f 02 80 ff 3f 00 80 ff 2f 00 80 ff 3f 0c 00 ff 3f 1c 00 ee 3f 3c 00 c0 3f 7e 00 c0 1f fe 01 80 1f fc 03 80 1f fc 01 80 1f fc 01 80 2f f8 01 80 0f f0 00 80 17 f0 00 80 03 f0 00 80 03 60 00 00 00 60 00 00 00 40 00 00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 1e 00 } } bitmap define globe_02 { { 32 32 } { 00 c0 01 00 00 60 30 00 00 04 f0 00 80 07 e0 03 e0 01 f0 07 f0 00 38 0f 30 00 10 1e 18 00 f0 30 04 00 f8 3f 10 00 f8 7f 12 00 fc 7f 02 00 fc 7f 04 00 fc 7f 74 00 f8 7f f0 00 70 7f f8 01 00 7e f8 03 00 7e f8 0f 00 7c f8 1f 00 3c f0 1f 00 3c f0 0f 00 3e e0 0f 00 5e c0 07 00 1c c0 03 00 0e c0 03 00 04 80 01 00 00 80 01 00 00 80 01 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 10 1c 00 } } bitmap define globe_03 { { 32 32 } { 00 c0 01 00 00 dc 20 00 00 09 c0 00 80 1f a0 03 e0 07 c0 07 f0 01 c0 0c f8 00 40 18 78 00 c0 23 08 00 c0 3f 04 00 e0 7f 54 00 e0 7f 0c 00 c0 7f 10 00 c0 ff d0 01 c0 ff c0 03 80 fb e0 0f 00 f0 e0 1f 00 f0 e0 ff 00 f0 e0 ff 00 70 c0 ff 00 70 c0 7f 00 70 00 7f 00 70 00 3f 00 30 00 1f 00 38 00 1f 00 18 00 0e 00 00 00 06 00 00 00 02 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 20 18 00 } } bitmap define globe_04 { { 32 32 } { 00 c0 03 00 00 7c 03 00 00 13 00 00 80 7f c0 03 c0 1f 00 07 e0 0f 00 0d f0 03 00 10 f0 01 00 0e 38 01 00 3e 10 00 00 7f 50 00 00 7f 30 00 00 7f 40 00 00 ff 00 1e 00 fe 00 3f 00 ec 00 7f 00 c0 00 ff 00 c0 00 ff 07 c0 00 ff 0f c0 00 fe 07 c0 00 fe 07 c0 00 f8 03 40 00 f8 01 60 00 f8 00 20 00 f8 00 20 00 38 00 00 00 18 00 00 00 18 00 00 00 18 00 00 00 00 00 00 00 00 00 00 00 40 10 00 } } bitmap define globe_05 { { 32 32 } { 00 c0 03 00 00 bc 06 00 00 cf 00 00 80 ff 01 02 c0 7f 00 06 c0 3f 00 0e e0 1f 00 14 e0 0f 00 18 e0 00 00 38 60 00 00 78 40 08 00 78 c0 01 00 78 00 02 00 f8 00 f0 00 f0 00 f0 01 b0 00 f8 07 80 00 f8 0f 80 00 f8 3f 00 00 f8 7f 00 00 f0 3f 80 00 f0 3f 80 00 c0 1f 00 00 c0 0f 00 00 c0 07 40 00 c0 07 00 00 c0 01 00 00 e0 00 00 00 60 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 80 10 00 } } bitmap define globe_06 { { 32 32 } { 00 80 07 00 00 7c 0d 00 00 9f 03 00 00 ff 07 02 00 ff 03 04 80 ff 00 08 c0 7f 00 00 80 3f 00 30 80 07 00 20 00 03 00 60 00 03 00 60 00 0e 00 60 00 10 00 e0 00 80 07 c0 00 80 0f c0 00 80 3f 00 00 c0 7f 00 00 c0 ff 01 00 c0 ff 03 00 80 ff 01 00 80 ff 01 00 00 fe 00 00 00 7e 00 00 00 3e 00 00 00 1f 00 00 00 0f 00 00 00 03 00 00 00 03 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 01 00 } } bitmap define globe_07 { { 32 32 } { 00 80 07 00 00 fc 1a 00 00 7d 02 00 00 fe 1f 00 00 fe 0f 00 00 fe 07 00 00 ff 03 00 00 fe 01 20 00 1c 01 00 00 1c 00 40 00 18 00 40 00 70 00 00 00 80 00 80 00 00 39 80 00 00 7c 00 00 00 fc 01 00 00 fe 03 00 00 fe 0f 00 00 fc 0f 00 00 fc 0f 00 00 f8 07 00 00 f0 07 00 00 f0 03 00 00 f0 01 00 00 f8 00 00 00 38 00 00 00 18 00 00 00 0c 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 02 00 } } bitmap define globe_08 { { 32 32 } { 00 00 07 00 00 fc 25 00 00 f8 19 00 00 f8 7f 00 00 f8 3f 00 00 f8 1f 00 00 f8 1f 00 00 f8 0f 00 00 f0 08 00 00 f0 00 00 00 c0 04 00 00 80 03 00 00 00 0c 00 00 00 c8 01 00 00 e0 03 00 00 e0 0f 00 00 e0 0f 00 00 f0 3f 00 00 e0 3f 00 00 e0 3f 00 00 c0 1f 00 00 80 1f 00 00 80 0f 00 00 c0 07 00 00 c0 03 00 00 c0 01 00 00 60 00 00 00 30 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 04 00 } } bitmap define globe_09 { { 32 32 } { 00 00 03 00 00 fc 27 00 00 f0 13 00 00 e0 ff 00 00 e0 ff 01 00 e0 7f 00 00 e0 7f 00 00 c0 7f 00 00 80 47 00 00 80 07 00 00 00 26 00 00 00 1c 00 00 00 60 00 00 00 40 0e 00 00 00 1f 00 00 00 3f 00 00 00 3f 00 00 00 7f 00 00 00 7f 00 00 00 7f 00 00 00 7e 00 00 00 3c 00 00 00 3e 00 00 00 1e 00 00 00 0f 00 00 00 07 00 00 80 01 00 00 80 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 08 00 } } bitmap define globe_10 { { 32 32 } { 00 00 06 00 00 f4 2f 00 00 c8 4f 00 00 80 ff 01 00 80 ff 01 00 80 ff 01 00 00 ff 01 00 00 fe 01 00 00 3c 00 00 00 3c 00 00 00 30 04 00 00 e0 00 00 00 00 01 00 00 00 3a 00 00 00 38 00 00 00 78 00 00 00 f8 00 00 00 fc 00 00 00 f8 00 00 00 f8 00 00 00 f8 00 00 00 70 00 00 00 70 00 00 00 38 00 00 00 18 00 00 00 0c 00 00 00 06 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 } } bitmap define globe_11 { { 32 32 } { 00 00 06 00 00 ec 1f 00 00 91 9f 00 00 00 fe 03 00 00 fc 07 00 00 fc 07 00 00 fc 07 00 00 f0 07 00 00 f0 01 00 00 e0 00 00 00 80 05 00 00 00 07 00 00 00 08 00 00 00 60 00 00 00 e0 00 00 00 e0 00 00 00 e0 00 00 00 e0 01 00 00 e0 00 00 00 e0 00 00 00 e0 00 00 00 40 00 00 00 60 00 00 00 60 00 00 00 30 00 00 00 10 40 00 00 08 40 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 } } bitmap define globe_12 { { 32 32 } { 00 00 04 00 00 dc 3f 00 00 42 7e 00 00 00 f8 03 20 00 f0 07 10 00 f0 0f 00 00 e0 0f 00 00 c0 0f 00 00 00 07 00 00 00 06 00 00 00 14 00 00 00 18 00 00 00 20 00 00 00 80 00 00 00 80 00 00 00 80 00 00 00 80 01 00 00 80 00 00 00 80 00 00 00 80 02 00 00 80 02 00 00 00 04 00 00 40 04 00 00 40 08 00 00 20 08 00 00 00 00 00 00 10 00 00 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 } } bitmap define globe_13 { { 32 32 } { 00 00 04 00 00 bc 3f 00 00 01 79 00 80 00 e0 03 60 00 c0 07 10 00 80 0f 00 00 80 1f 08 00 00 1e 00 00 00 1c 00 00 00 58 00 00 00 10 00 00 00 20 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 06 00 00 00 04 00 00 00 00 00 00 00 02 00 00 00 0e 00 00 00 0c 00 00 00 1c 00 00 00 18 00 00 00 30 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 } } bitmap define globe_14 { { 32 32 } { 00 00 00 00 00 fc 3f 00 00 03 e6 00 80 01 c0 03 60 00 00 07 30 00 00 0f 00 00 00 1e 00 00 00 38 04 00 00 30 00 00 00 30 02 00 00 00 00 00 00 40 00 00 00 80 00 00 00 00 02 00 00 00 01 00 00 00 01 00 00 00 18 00 00 00 00 00 00 00 00 00 00 00 14 00 00 00 3c 00 00 00 3c 00 00 00 7c 00 00 00 78 00 00 00 60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30 00 00 } } bitmap define globe_15 { { 32 32 } { 00 00 00 00 00 fc 3d 00 00 27 c8 00 80 13 00 03 e0 01 00 06 70 00 00 0c 10 00 00 18 18 00 00 30 0c 00 00 20 0c 00 00 40 02 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 03 00 00 00 13 00 00 00 64 00 00 00 c0 00 00 00 00 00 00 00 30 00 00 00 f8 00 00 00 f8 01 00 00 f8 03 00 00 f0 03 00 00 80 03 00 00 00 80 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 70 00 00 } } bitmap define globe_16 { { 32 32 } { 00 00 00 00 00 fc 3b 00 00 9f a0 00 80 4f 00 02 e0 0f 00 04 f0 01 00 08 70 00 00 10 38 00 00 20 3c 00 00 00 1c 00 00 00 06 00 00 00 04 00 00 00 04 00 00 00 00 00 00 00 20 00 00 00 0a 00 00 00 0a 00 00 00 00 03 00 00 28 06 00 00 00 00 00 00 c0 02 00 00 e0 07 00 00 f0 0f 00 00 e0 1f 00 00 e0 1f 00 00 00 0c 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f0 00 00 } } bitmap define globe_17 { { 32 32 } { 00 00 00 00 00 fc 37 00 00 3f 42 00 80 3f 01 02 e0 1f 00 00 f0 07 00 00 f0 11 00 00 f8 04 00 00 fc 00 00 00 7c 00 00 00 1a 00 00 00 9a 00 00 00 18 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 28 00 00 00 08 18 00 00 00 30 00 00 00 10 00 00 00 17 00 00 00 3f 00 00 c0 7f 00 00 80 7f 00 00 80 7f 00 00 00 70 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f0 01 00 } } bitmap define globe_18 { { 32 32 } { 00 00 00 00 00 fc 2f 00 00 ff 84 00 80 ff 04 00 e0 7f 00 00 f0 9f 00 00 f0 97 00 00 f8 27 00 00 fc 07 00 00 fc 03 00 00 6c 00 00 00 64 00 00 00 60 04 00 00 40 00 00 00 20 00 00 00 20 01 00 00 a0 01 00 00 00 c0 05 00 00 88 00 00 00 00 00 00 00 38 01 00 00 fc 01 00 00 fe 03 00 00 fe 03 00 00 fc 03 00 00 80 03 00 00 00 00 00 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f0 03 00 } } bitmap define globe_19 { { 32 32 } { 00 40 00 00 00 fc 3f 00 00 ff 13 00 80 ff 13 00 e0 ff 03 00 f0 ff 00 00 f0 9f 00 00 f8 3f 00 00 fc 3f 00 00 f8 1f 00 00 ba 07 00 00 98 23 00 00 08 03 00 00 08 00 00 00 00 00 00 00 80 09 00 00 00 0d 01 00 00 21 0e 00 00 00 1c 00 00 00 00 00 00 c0 09 00 00 e0 0f 00 00 f0 1f 00 00 f0 1f 00 00 f0 1f 00 00 00 0e 00 00 00 00 00 00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f0 07 00 } } bitmap define globe_20 { { 32 32 } { 00 00 00 00 00 fc 3f 00 00 ff 07 00 80 ff 0f 00 e0 ff 0f 00 f0 ff 13 00 f0 ff 10 00 f8 ff 00 00 fc ff 01 00 f4 ff 00 00 e6 1e 00 00 62 1c 01 00 20 18 00 00 20 10 00 00 01 80 00 00 01 cc 00 00 01 68 08 00 00 00 60 00 00 00 c0 00 00 00 00 00 00 00 5c 00 00 00 7e 00 00 80 ff 00 00 80 ff 00 00 80 ff 00 00 00 70 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f0 0f 00 } } bitmap define globe_21 { { 32 32 } { 00 80 00 00 00 fc 3f 00 00 ff 1f 00 80 ff bf 00 e0 ff 3f 00 f0 ff 1f 00 f8 ff 17 00 f8 ff 27 00 ec ff 0f 00 8c ff 07 00 9e f7 00 00 0e e3 00 00 06 c1 00 00 06 81 10 00 03 40 04 00 03 20 06 00 03 40 06 00 01 80 00 03 01 00 00 02 02 00 00 00 02 00 e0 02 02 00 f0 03 00 00 fc 03 00 00 fc 03 00 00 fc 03 00 00 c0 01 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 f0 1f 00 } } bitmap define globe_22 { { 32 32 } { 00 00 01 00 00 fc 3f 00 00 ff 3f 00 80 ff 7f 00 e0 ff ff 00 f0 ff 7f 00 f0 ff 1f 00 e0 ff 3f 00 fc ff 3f 00 34 fe 3f 00 76 bc 07 00 36 1c 07 00 0e 08 0e 00 1e 08 80 00 0f 00 02 00 0f 00 20 00 07 00 36 00 07 00 04 08 07 00 00 18 06 00 00 00 16 00 00 0b 16 00 80 0f 04 00 e0 0f 04 00 e0 0f 08 00 e0 0f 00 00 00 06 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f0 1f 00 } } bitmap define globe_23 { { 32 32 } { 00 00 00 00 00 fc 3f 00 00 ff 7f 00 80 ff ff 01 e0 ff ff 01 e0 ff ff 01 e8 ff ff 00 c0 ff ff 00 fc fe ff 01 dc f2 ff 01 de e3 3d 00 de e1 38 02 7e 40 70 00 fe 40 00 04 7f 00 00 00 3e 00 30 01 3e 00 a0 01 1e 00 20 20 1e 00 00 20 1c 00 00 00 9c 00 00 3c 1c 00 00 3e 1c 00 00 3f 18 00 80 3f 10 00 00 1f 00 00 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f0 1f 00 } } bitmap define globe_24 { { 32 32 } { 00 00 02 00 00 fc 3f 00 00 fe ff 00 80 ff ff 01 c0 ff ff 03 80 ff ff 03 e0 ff ff 03 18 ff ff 03 fc ff ff 07 7c 87 ff 07 fe 1f ef 01 fe 0e c6 01 fe 01 82 03 fe 03 02 00 ff 03 00 08 fc 01 80 09 fc 00 00 0d fc 00 00 00 f8 00 00 80 f8 00 00 00 f8 00 00 20 78 02 00 70 70 02 00 7c 70 00 00 3c 60 00 00 3c 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f0 1f 00 } } bitmap define globe_25 { { 32 32 } { 00 00 00 00 00 f0 3f 00 00 fc ff 00 80 ff ff 03 80 ff ff 07 a0 ff ff 07 10 ff ff 07 30 f8 ff 0f f8 df ff 1f fc 3b fc 1f fc fb 78 07 fe 77 30 0e fe 1f 30 0c fe 3f 00 48 fe 1f 00 00 f0 0f 00 24 f0 07 00 a0 f0 07 00 08 e0 07 00 00 e0 07 00 00 e0 27 00 c0 e0 13 00 40 c0 13 00 70 c0 03 00 70 80 01 00 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f0 1f 00 } } bitmap define globe_26 { { 32 32 } { 00 40 00 00 00 e0 3f 00 00 e8 ff 00 00 fc ff 03 00 ff ff 07 c0 fe ff 0f 40 f0 ff 1f e0 e0 ff 1f f0 ff fe 3f f8 df e1 3f f8 df c7 1b fc bf 83 19 fc ff 80 30 fc ff 01 20 f8 ff 00 00 c0 ff 00 00 c0 7f 00 e0 80 3f 00 20 80 3f 00 00 80 3f 00 00 80 3f 01 80 80 9f 00 00 00 9f 00 40 00 0f 00 60 00 0e 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f0 1f 00 } } bitmap define globe_27 { { 32 32 } { 00 80 00 00 00 c4 3f 00 00 f0 ff 00 00 fe ff 03 00 fe ff 07 00 eb ff 0f 80 c9 ff 1f 80 07 ff 3f c0 ff f7 3f e0 ff 0e 7f f0 ff 3e 6e f0 ff 1d 64 f0 ff 07 44 f0 ff 0f 00 60 ff 0f 00 00 fe 07 40 00 fe 03 00 01 fc 01 00 01 fc 01 00 00 fc 01 00 00 fc 09 00 02 fc 08 00 00 f8 04 00 00 78 00 40 00 70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 e0 1f 00 } } bitmap define globe_28 { { 32 32 } { 00 00 00 00 00 88 3f 00 00 40 ff 00 00 e8 ff 03 00 f8 ff 07 00 8c ff 0f 00 06 fe 1f 00 1e f8 3f 00 ff bf 3f 80 ff 77 7c 80 ff ff 79 c0 ff ef 10 c0 ff 3f 90 c0 ff 7f 00 81 fb 7f 00 01 f0 3f 00 01 f0 1f 00 03 e0 1f 00 07 e0 0f 00 02 c0 1f 00 02 e0 5f 00 06 e0 47 00 04 c0 27 00 04 c0 03 00 00 80 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 c0 1f 00 } } bitmap define globe_29 { { 32 32 } { 00 40 01 00 00 0c 3f 00 00 80 fd 00 00 a0 ff 03 20 e0 ff 07 00 30 fd 0f 00 10 f4 1f 00 f8 c0 3f 00 f8 ff 3f 00 fc bf 73 00 fe ff 67 00 fe 7f 47 00 fe ff 41 00 fe ff 03 01 dc ff 03 03 00 ff 01 07 80 ff 00 0f 00 ff 00 1f 00 7e 00 0e 00 fe 00 0e 00 ff 02 0e 00 3f 01 0c 00 3e 01 0c 00 1e 00 08 00 1c 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 1f 00 } } # ---------------------------------------------------------------- # # SetOption -- # # Sets the option array associated with the resource. It # first check to see if the resource exists in the option # data base, otherwise it uses the default value given. # # # Arguments # name -- Name of the resource. Used as index into # the option array. # value -- default value given. # Globals # pq_dict -- Associative array where the option resources # are stored. # # ---------------------------------------------------------------- proc SetOption { name value } { global pq_dict set widgetOption [option get . $name Tk] if { $widgetOption != "" } { set value $widgetOption } set pq_dict($name) $value } set pq_dict(textIndex) {} set pq_dict(entryNames) { last first middle area exch ext com org tl room oldloc loc street city state zip ema } set pq_dict(numEntries) [llength $pq_dict(entryNames)] set pq_dict(index) 0 set pq_dict(defaults) {} set cnt 0 foreach name $pq_dict(entryNames) { if { $cnt > 0 } { set pq_dict(format) $pq_dict(format):%$name } else { set pq_dict(format) %$name } incr cnt } set visual [winfo screenvisual .] if { ($visual == "staticgray") || ($visual == "grayscale") } { option add *Entry.background white option add *Text.background white set pq_dict(visual) mono } else { set depth [winfo screendepth .] if { $depth < 8 } { SetOption normalBgColor grey SetOption normalFgColor black SetOption focusHighlightColor white } else { #fff4de SetOption normalBgColor grey90 SetOption normalFgColor #da5f5f SetOption normalFgColor navyblue SetOption focusHighlightColor #fffdf8 } option add *Entry.background $pq_dict(normalBgColor) widgetDefault option add *Text.background $pq_dict(normalBgColor) widgetDefault option add *Label.foreground $pq_dict(normalFgColor) widgetDefault option add *Button.foreground $pq_dict(normalFgColor) widgetDefault set pq_dict(visual) color } SetOption statusFont -*-Helvetica-Medium-R-*-*-14-*-*-*-*-*-*-* SetOption titleFont -*-Helvetica-Bold-R-*-*-14-*-*-*-*-*-*-* SetOption headingFont -*-Helvetica-Medium-R-*-*-14-*-*-*-*-*-*-* SetOption subheadingFont -*-Helvetica-Medium-R-*-*-12-*-*-*-*-*-*-* SetOption entryFont -*-Courier-Medium-R-*-*-12-*-*-*-*-*-*-* SetOption textFont -*-Courier-Bold-R-*-*-12-*-*-*-*-*-*-* #SetOption entryFont fixed #SetOption textFont fixed option add *Label.borderWidth 0 widgetDefault option add *Entry.relief sunken widgetDefault option add *Entry.width 11 widgetDefault option add *Entry.borderWidth 2 widgetDefault option add *Entry.font $pq_dict(entryFont) widgetDefault option add *Text.font $pq_dict(textFont) widgetDefault option add *Text.width 35 widgetDefault option add *Text.height 10 widgetDefault option add *Scrollbar.relief flat widgetDefault option add *Scrollbar.minSlider 10 widgetDefault option add *Button.padY 6 option add *Text.relief sunken widgetDefault option add *Text.borderWidth 2 widgetDefault foreach name $pq_dict(entryNames) { option add *${name}_label.font $pq_dict(subheadingFont) widgetDefault } option add *Label.Font $pq_dict(subheadingFont) option add *status_label.font $pq_dict(statusFont) widgetDefault option add *name_label.font $pq_dict(headingFont) widgetDefault option add *tel_label.font $pq_dict(headingFont) widgetDefault option add *office_label.font $pq_dict(headingFont) widgetDefault option add *addr_label.font $pq_dict(headingFont) widgetDefault option add *loc_title.font $pq_dict(headingFont) widgetDefault option add *org_title.font $pq_dict(headingFont) widgetDefault option add *overall_label.text "Customer Database" option add *name_label.text "Name" option add *tel_label.text "Telephone" option add *addr_label.text "Address" option add *last_label.text "last" option add *first_label.text "first" option add *middle_label.text "middle" option add *com_label.text "company" option add *org_label.text "organization" option add *tl_label.text "title" option add *ext_label.text "extension" option add *exch_label.text "exchange" option add *area_label.text "area code" option add *loc_label.text "extension" option add *oldloc_label.text "exchange" option add *room_label.text "area code" option add *street_label.text "street address" option add *ema_label.text "e-mail" option add *city_label.text "city" option add *state_label.text "state" option add *zip_label.text "zip code" option add *org_title.text "Organization" option add *loc_title.text "Fax" option add *clear_button.text "Clear" option add *quit_button.text "Quit" option add *cancel_button.text "Cancel" # -------------------------------------------------------------------------- # # Procedures to perform post queries # # ---------------------------------------------------------------- # # StopQuery -- # # Stops any current "pq" request by setting the variable # associated with the background subprocesses. # # Arguments # None. # # Globals # postOutput -- variable where collected output from # pq command will be stored # # ---------------------------------------------------------------- proc StopQuery {} { global postOutput set postOutput {} } # ---------------------------------------------------------------- # # PostQuery -- # # Collects the data from the entry widget fields and # executes a "pq" request. The "pq" command is executed # in the background and a "wait" is setup to wait for the # command to finish. This allows the animation routine # to operate and exposure events to be handled properly. # # Arguments # None. # # Globals # postOutput -- variable where collected output from # pq command will be stored # pq_dict(entryNames) -- list of entry widget names # pq_dict(textIndex) -- starting index of highlighted information # (a line in the text widget) # # ---------------------------------------------------------------- proc PostQuery {} { global pq_dict .status_label configure -text {} set cnt 0 foreach name $pq_dict(entryNames) { set value [.${name}_entry get] if { $value != "" } { set value [split $value "|"] foreach i $value { if { $cnt > 0 } { set query $query/$name=[list $i] } else { set query $name=[list $i] } incr cnt } } } if { $cnt == 0 } { return } set fmt {%^24pn\t%10org\t%6loc\t%area-%exch-%ext\t%ema} global postOutput postError set postOutput {} set postError {} bgexec postStatus -error postError -output postOutput \ pq -o $fmt $query & Animate on tkwait variable postStatus if { $postOutput != "" } { .text configure -state normal .text delete 0.0 end .text insert 0.0 $postOutput .text configure -state disabled .status_label configure -text "Post query successful" } else { .status_label configure -text "Post query failed" } set pq_dict(textIndex) {} Animate off if { $postError != "" } { tkerror $postError } } # ---------------------------------------------------------------- # # ClearFields -- # # Clears the all the entry fields. # # Arguments # None. # # Globals # pq_dict(entryNames) -- list of entry widget names # pq_dict(textIndex) -- starting index of highlighted information # (a line in the text widget) # # ---------------------------------------------------------------- proc ClearFields {} { global pq_dict busy hold . ; update foreach name $pq_dict(entryNames) { .${name}_entry delete 0 end } set pq_dict(textIndex) {} .status_label configure -text "Cleared query fields" busy release . } # ---------------------------------------------------------------- # # FillFields -- # # Makes a post query based upon the highlighted line in # the text widget to fill in all post entry fields. # # Arguments # x x screen coordinate # y y screen coordinate # # Globals # postOutput variable where collected output from pq # command will be stored # pq_dict(format) standard query format to collect data for # all entry fields # pq_dict(entryNames) list of entry widget names # # ---------------------------------------------------------------- proc FillFields { x y } { global pq_dict set info [.text get [list @$x,$y linestart] [list @$x,$y lineend]] set info [split $info \t] if { [llength $info] == 0 } { return } set name [string trim [lindex $info 0]] set name [split $name ,] set last [lindex $name 0] set name [split [lindex $name 1]] set first [lindex $name 0] set middle [lindex $name 1] set org [string trim [lindex $info 1]] set loc [string trim [lindex $info 2]] set tel [string trim [lindex $info 3]] set query last=$last/first=$first/middle=$middle/org=$org/loc=$loc/tel=[list $tel] global postOutput set postOutput {} bgexec postStatus -output postOutput \ pq -o $pq_dict(format) $query & Animate on tkwait variable postStatus if { $postOutput == "" } { # Try again with out the telephone number set query last=$last/first=$first/middle=$middle/org=$org/loc=$loc set postStatus {} bgexec postStatus -output postOutput \ pq -o $pq_dict(format) $query & tkwait variable postStatus } Animate off if { $postOutput == "" } { .status_label configure -text "Post query failed" } else { .status_label configure -text "Post database fields found" set postOutput [split $postOutput : ] set cnt 0 foreach name $pq_dict(entryNames) { .${name}_entry delete 0 end .${name}_entry insert 0 [lindex $postOutput $cnt] incr cnt } } } # ---------------------------------------------------------------- # # HighlightText -- # # Highlight the text under the current line (as based upon # the given screen coordinates. Only highlight the line if # pointer has been moved to the another line. # # Arguments # x x screen coordinate # y y screen coordinate # # Globals # pq_dict(visual) either "mono" or "color"; indicates if # color screen features can be used # pq_dict(textIndex) starting index of highlighted information # pq_dict(normalFgColor) color to use for highlighted region # # ---------------------------------------------------------------- proc HighlightText { x y } { global pq_dict set newIndex [.text index [list @$x,$y linestart]] if { $newIndex != $pq_dict(textIndex) } { catch { .text tag delete highlight } .text tag add highlight $newIndex [list $newIndex lineend] if { $pq_dict(visual) == "color" } { .text tag configure highlight \ -foreground $pq_dict(normalFgColor) -underline on } else { .text tag configure highlight -underline on } set pq_dict(textIndex) $newIndex } } # ---------------------------------------------------------------- # # ChangeFocus -- # # Change the keyboard focus to the next/last entry widget. # # Arguments # direction either "next" or "last"; indicates in # which direction to change focus # # Globals # pq_dict(entryNames) list of entry widget names # pq_dict(index) current index in list of entry widget # names of the keyboard focus. An index # of -1 indicates there is no focus. # pq_dict(numEntries) number of names in entry widget list # # ---------------------------------------------------------------- proc ChangeFocus direction { global pq_dict case $direction { next { incr pq_dict(index) if { $pq_dict(index) == $pq_dict(numEntries) } { set pq_dict(index) 0 } } last { set pq_dict(index) [expr $pq_dict(index)-1] if { $pq_dict(index) < 0 } { set pq_dict(index) [expr $pq_dict(numEntries)-1] } } } focus .[lindex $pq_dict(entryNames) $pq_dict(index)]_entry update idletasks update } # ---------------------------------------------------------------- # # ColorFocus -- # # Change background color of entry widget with active # keyboard focus # # Arguments # w name of entry widget to change # bool either "on" or "off"; indicates if # the focus highlight should turned on # or off. # # Globals # pq_dict(entryNames) list of entry widget names # pq_dict(index) current index in list of entry widget # names of the keyboard focus. An index # of -1 indicates there is no focus. # pq_dict(visual) either "mono" or "color"; indicates if # color screen features can be used # # ---------------------------------------------------------------- proc ColorFocus { w bool } { global pq_dict regexp {\.([a-z]+)_entry} $w dummy name if { $pq_dict(visual) == "color" && [info commands $w] == $w } { if { $bool == "on" } { set pq_dict(index) [lsearch $pq_dict(entryNames) $name] $w configure -background $pq_dict(focusHighlightColor) } else { $w configure -background $pq_dict(normalBgColor) } } } # ---------------------------------------------------------------- # # Animate -- # # Activates/deactivates an animated bitmap and busy window. # A cancel button is mapped and raised so that it is unaffected # by the busy window. # # Arguments # option either "on", "off", or "continue"; # indicates whether animation should # be started, stoped or continued. # # Globals # pq_dict(entryNames) list of entry widget names # pq_dict(index) current index in list of entry widget # names of the keyboard focus. An index # of -1 indicates there is no focus. # pq_dict(visual) either "mono" or "color"; indicates if # color screen features can be used # # ---------------------------------------------------------------- set pq_dict(curBitmap) 0 set pq_dict(lastBitmap) 0 proc Animate option { global pq_dict case $option { on { busy hold . .status_label configure -text "Searching..." global topLevel table $topLevel .cancel_button 18,8 -anchor e -reqwidth .70i winop raise .cancel_button .quit_button configure -state disabled .clear_button configure -state disabled winop raise .cancel_button set pq_dict(lastFocus) [focus] focus -force . set pq_dict(curBitmap) $pq_dict(lastBitmap) update } off { table forget .cancel_button .quit_button configure -state normal .clear_button configure -state normal .trademark configure -bitmap attlogo set pq_dict(lastBitmap) $pq_dict(curBitmap) set pq_dict(curBitmap) -1 focus $pq_dict(lastFocus) busy release . } } # # Continue with next bitmap # if { $pq_dict(curBitmap) >= 0 } { set bmap [format globe_%0.2d $pq_dict(curBitmap)] .trademark configure -bitmap $bmap incr pq_dict(curBitmap) if { $pq_dict(curBitmap) >= 29 } { set pq_dict(curBitmap) 0 } after 100 Animate continue } } # -------------------------------------------------------------------------- # # main body of program # frame .frame set topLevel .frame label .overall_label -font -*-Helvetica-Bold-R-*-*-18-*-*-*-*-*-*-* label .name_label -font $pq_dict(titleFont) label .tel_label -font $pq_dict(titleFont) label .addr_label -font $pq_dict(titleFont) label .org_title -font $pq_dict(titleFont) label .loc_title -font $pq_dict(titleFont) foreach name $pq_dict(entryNames) { label .${name}_label entry .${name}_entry } if [info exists env(POST_DEFAULTS)] { set pq_dict(defaults) [split $env(POST_DEFAULTS) ":"] } foreach i $pq_dict(defaults) { set i [split $i "="] if { [llength $i] == 2 } { set name [lindex $i 0] if { [lsearch $pq_dict(entryNames) $name] >= 0 } { .${name}_entry insert 0 [lindex $i 1] } } } label .orders_title -text "Current Orders" \ -font -*-Helvetica-Bold-R-*-*-16-*-*-*-*-*-*-* set font -*-Helvetica-Bold-R-*-*-14-*-*-*-*-*-*-* button .clear_button -command ClearFields -font $font button .quit_button -command { exit } -font $font button .search_button -text "Search" -font $font label .status_label button .cancel_button -command StopQuery #-relief raised label .trademark -bitmap attlogo text .text -yscrollcommand { .vscroll set } -state disabled scrollbar .vscroll -command { .text yview } table $topLevel \ .overall_label 0,1 -cspan 10 -pady 5 \ .name_label 1,2 \ .last_entry 2,2 -cspan 2 \ .first_entry 2,4 \ .middle_entry 2,5 \ .last_label 3,2 \ .first_label 3,4 \ .middle_label 3,5 \ .tel_label 1,7 \ .area_entry 2,7 \ .exch_entry 2,8 \ .ext_entry 2,9 \ .area_label 3,7 \ .exch_label 3,8 \ .ext_label 3,9 \ .org_title 4,2 \ .com_entry 5,2 \ .org_entry 5,3 \ .tl_entry 5,4 \ .com_label 6,2 \ .org_label 6,3 \ .tl_label 6,4 \ .loc_title 4,7 \ .room_entry 5,7 \ .oldloc_entry 5,8 \ .loc_entry 5,9 \ .room_label 6,7 \ .oldloc_label 6,8 \ .loc_label 6,9 \ .addr_label 8,2 \ .street_entry 9,2 \ .ema_entry 9,7 -cspan 2 \ .street_label 10,2 \ .city_entry 11,2 -cspan 2 \ .state_entry 11,4 \ .zip_entry 11,5 \ .ema_label 10,7 -cspan 2 \ .city_label 12,2 -cspan 2 \ .state_label 12,4 \ .zip_label 12,5 \ .orders_title 16,2 -pady { 4 0 } \ .text 17,2 -cspan 8 -fill both -padx 2 \ .vscroll 17,10 -anchor center -fill both \ .status_label 18,4 -cspan 6 -reqwidth {0 4i} \ .search_button 18,3 -reqwidth .9i -anchor center -pady 8\ .clear_button 18,5 -reqwidth .9i -anchor center \ .quit_button 18,8 -reqwidth .9i -anchor center eval table configure $topLevel \ [info command .*_label] [info commands .*_title] \ -anchor w -padx 2 -ipadx 2 eval table configure $topLevel [info command .*_entry] \ -fill both -padx 2 eval table configure $topLevel .name_label .tel_label .org_title \ .com_label .addr_label .street_entry .street_label \ -cspan 3 eval table configure $topLevel .last_entry .ema_entry .city_entry \ .ema_label .city_label -cspan 2 table configure $topLevel .overall_label -anchor center table configure $topLevel r16 -pady { 5 5 } -resize both table configure $topLevel c0 -width .vscroll table configure $topLevel c0 c10 -resize none table configure $topLevel r3 r6 r10 r12 -resize none table configure $topLevel r17 -height { 40 {} } table configure $topLevel r16 r18 -resize none table configure $topLevel c6 -pad { 5 5 } if { $topLevel == ".frame" } { table . \ $topLevel 0,0 -fill both } bind .text { FillFields %x %y continue } bind .text { HighlightText %x %y continue } bind .text { set pq_dict(textIndex) {} HighlightText %x %y set info [.text get [list 0.0 linestart] [list 0.0 lineend]] if { $info != "" } { .status_label configure -text "Query individual with button-2" } continue } bind .text { if { [busy isbusy .] != "." } { .text tag delete highlight .status_label configure -text "" } continue } bind EntryFocus { ChangeFocus next break } bind EntryFocus { ChangeFocus last break } if { $pq_dict(visual) == "color" } { bind EntryFocus { ColorFocus %W on } bind EntryFocus { ColorFocus %W off } } bind Entry PostQuery foreach name $pq_dict(entryNames) { set w .${name}_entry bindtags $w [list EntryFocus $w Entry all] } focus .last_entry blt-2.4z.orig/examples/pareto.tcl0100755000175000017500000000653107434101500015562 0ustar dokodoko#!../src/bltwish package require BLT # -------------------------------------------------------------------------- # Starting with Tcl 8.x, the BLT commands are stored in their own # namespace called "blt". The idea is to prevent name clashes with # Tcl commands and variables from other packages, such as a "table" # command in two different packages. # # You can access the BLT commands in a couple of ways. You can prefix # all the BLT commands with the namespace qualifier "blt::" # # blt::graph .g # blt::table . .g -resize both # # or you can import all the command into the global namespace. # # namespace import blt::* # graph .g # table . .g -resize both # # -------------------------------------------------------------------------- if { $tcl_version >= 8.0 } { namespace import blt::* namespace import -force blt::tile::* } # Example of a pareto chart. # # The pareto chart mixes line and bar elements in the same graph. # Each processing operating is represented by a bar element. The # total accumulated defects is displayed with a single line element. barchart .b \ -title "Defects Found During Inspection" \ -font {Helvetica 12} \ -plotpady { 12 4 } \ -width 6i \ -height 5i table . .b -fill both set data { "Spot Weld" 82 yellow "Lathe" 49 orange "Gear Cut" 38 green "Drill" 24 blue "Grind" 17 red "Lapping" 12 brown "Press" 8 purple "De-burr" 4 pink "Packaging" 3 cyan "Other" 12 magenta } # Create an X-Y graph line element to trace the accumulated defects. .b line create accum -label "" -symbol none -color red # Define a bitmap to be used to stipple the background of each bar. bitmap define pattern1 { {4 4} {01 02 04 08} } # For each process, create a bar element to display the magnitude. set count 0 set sum 0 set ydata 0 set xdata 0 foreach { label value color } $data { incr count .b element create $label \ -xdata $count \ -ydata $value \ -fg $color \ -relief solid \ -borderwidth 1 \ -stipple pattern1 \ -bg lightblue set labels($count) $label # Get the total number of defects. set sum [expr $value + $sum] lappend ydata $sum lappend xdata $count } # Configure the coordinates of the accumulated defects, # now that we know what they are. .b line configure accum -xdata $xdata -ydata $ydata # Add text markers to label the percentage of total at each point. foreach x $xdata y $ydata { set percent [expr ($y * 100.0) / $sum] if { $x == 0 } { set text " 0%" } else { set text [format %.1f $percent] } .b marker create text \ -coords "$x $y" \ -text $text \ -font {Helvetica 10} \ -fg red4 \ -anchor c \ -yoffset -5 } # Display an auxillary y-axis for percentages. .b axis configure y2 \ -hide no \ -min 0.0 \ -max 100.0 \ -title "Percentage" # Title the y-axis .b axis configure y -title "Defects" # Configure the x-axis to display the process names, instead of numbers. .b axis configure x \ -title "Process" \ -command FormatLabels \ -rotate 90 \ -subdivisions 0 proc FormatLabels { widget value } { global labels set value [expr round($value)] if {[info exists labels($value)] } { return $labels($value) } return $value } # No legend needed. .b legend configure -hide yes # Configure the grid lines. .b grid configure -mapx x -color lightblue blt-2.4z.orig/library/0042755000175000017500000000000007553201221013412 5ustar dokodokoblt-2.4z.orig/library/dd_protocols/0042755000175000017500000000000007553201221016105 5ustar dokodokoblt-2.4z.orig/library/dd_protocols/dd-color.tcl0100644000175000017500000000316307240160102020305 0ustar dokodoko# ---------------------------------------------------------------------- # PURPOSE: drag&drop send routine for "color" data # # Widgets that are to participate in drag&drop operations for # "color" data should be registered as follows: # # drag&drop .win source handler color dd_send_color # drag&drop .win target handler color my_color_handler # # proc my_color_handler {} { # global DragDrop # # set data $DragDrop(color) # . # . do something with $data # . # } # # AUTHOR: Michael J. McLennan Phone: (215)770-2842 # AT&T Bell Laboratories E-mail: aluxpo!mmc@att.com # # SCCS: %W% (%G%) # ---------------------------------------------------------------------- # Copyright (c) 1993 AT&T All Rights Reserved # ====================================================================== # ---------------------------------------------------------------------- # COMMAND: dd_send_color # # INPUTS # = interpreter for target application # = pathname for target drag&drop window # = data returned from -tokencmd # # RETURNS # "" # # SIDE-EFFECTS # Sends data to remote application DragDrop(color), and then # invokes the "color" handler for the drag&drop target. # ---------------------------------------------------------------------- proc dd_send_color {interp ddwin data} { send $interp " foreach color [list $data] { winfo rgb . \$color } global DragDrop set DragDrop(color) [list $data] " send $interp "drag&drop target $ddwin handle color" } blt-2.4z.orig/library/dd_protocols/dd-file.tcl0100644000175000017500000000322507240160102020105 0ustar dokodoko# ---------------------------------------------------------------------- # PURPOSE: drag&drop send routine for "file" data # # Widgets that are to participate in drag&drop operations for # "file" data should be registered as follows: # # drag&drop .win source handler text dd_send_file # drag&drop .win target handler text my_file_handler # # proc my_file_handler {} { # global DragDrop # # set data $DragDrop(file) # . # . do something with $data # . # } # # AUTHOR: Michael J. McLennan Phone: (215)770-2842 # AT&T Bell Laboratories E-mail: aluxpo!mmc@att.com # # SCCS: %W% (%G%) # ---------------------------------------------------------------------- # Copyright (c) 1993 AT&T All Rights Reserved # ====================================================================== # ---------------------------------------------------------------------- # COMMAND: dd_send_file # # INPUTS # = interpreter for target application # = pathname for target drag&drop window # = data returned from -tokencmd # # RETURNS # "" # # SIDE-EFFECTS # Sends data to remote application DragDrop(file), and then # invokes the "file" handler for the drag&drop target. # ---------------------------------------------------------------------- proc dd_send_file {interp ddwin data} { send $interp " foreach file [list $data] { if {!\[file exists \$file\]} { error \"not a file: \$file\" } } global DragDrop set DragDrop(file) [list $data] " send $interp "drag&drop target $ddwin handle file" } blt-2.4z.orig/library/dd_protocols/dd-number.tcl0100644000175000017500000000317307240160102020460 0ustar dokodoko# ---------------------------------------------------------------------- # PURPOSE: drag&drop send routine for "number" data # # Widgets that are to participate in drag&drop operations for # "number" data should be registered as follows: # # drag&drop .win source handler number dd_send_number # drag&drop .win target handler number my_number_handler # # proc my_number_handler {} { # global DragDrop # # set data $DragDrop(number) # . # . do something with $data # . # } # # AUTHOR: Michael J. McLennan Phone: (215)770-2842 # AT&T Bell Laboratories E-mail: aluxpo!mmc@att.com # # SCCS: %W% (%G%) # ---------------------------------------------------------------------- # Copyright (c) 1993 AT&T All Rights Reserved # ====================================================================== # ---------------------------------------------------------------------- # COMMAND: dd_send_number # # INPUTS # = interpreter for target application # = pathname for target drag&drop window # = data returned from -tokencmd # # RETURNS # "" # # SIDE-EFFECTS # Sends data to remote application DragDrop(number), and then # invokes the "number" handler for the drag&drop target. # ---------------------------------------------------------------------- proc dd_send_number {interp ddwin data} { send $interp " foreach num [list $data] { expr \$num*1 } global DragDrop set DragDrop(number) [list $data] " send $interp "drag&drop target $ddwin handle number" } blt-2.4z.orig/library/dd_protocols/dd-text.tcl0100644000175000017500000000305307240160102020151 0ustar dokodoko# ---------------------------------------------------------------------- # PURPOSE: drag&drop send routine for "text" data # # Widgets that are to participate in drag&drop operations for # "text" data should be registered as follows: # # drag&drop .win source handler text dd_send_text # drag&drop .win target handler text my_text_handler # # proc my_text_handler {} { # global DragDrop # # set data $DragDrop(text) # . # . do something with $data # . # } # # AUTHOR: Michael J. McLennan Phone: (215)770-2842 # AT&T Bell Laboratories E-mail: aluxpo!mmc@att.com # # SCCS: %W% (%G%) # ---------------------------------------------------------------------- # Copyright (c) 1993 AT&T All Rights Reserved # ====================================================================== # ---------------------------------------------------------------------- # COMMAND: dd_send_text # # INPUTS # = interpreter for target application # = pathname for target drag&drop window # = data returned from -tokencmd # # RETURNS # "" # # SIDE-EFFECTS # Sends data to remote application DragDrop(text), and then # invokes the "text" handler for the drag&drop target. # ---------------------------------------------------------------------- proc dd_send_text {interp ddwin data} { send $interp " global DragDrop set DragDrop(text) [list $data] " send $interp "drag&drop target $ddwin handle text" } blt-2.4z.orig/library/dd_protocols/tclIndex0100644000175000017500000000110207240160102017562 0ustar dokodoko# Tcl autoload index file, version 2.0 # This file is generated by the "auto_mkindex" command # and sourced to set up indexing information for one or # more commands. Typically each line is a command that # sets an element in the auto_index array, where the # element name is the name of a command and the value is # a script that loads the command. set auto_index(dd_send_file) "source $dir/dd-file.tcl" set auto_index(dd_send_text) "source $dir/dd-text.tcl" set auto_index(dd_send_number) "source $dir/dd-number.tcl" set auto_index(dd_send_color) "source $dir/dd-color.tcl" blt-2.4z.orig/library/Makefile.in0100644000175000017500000000343207514405104015457 0ustar dokodoko# ------------------------------------------------------------------------ # Makefile for library files and directories of BLT library # ------------------------------------------------------------------------ prefix = @prefix@ exec_prefix = @exec_prefix@ version = @BLT_VERSION@ lib_prefix = @BLT_LIB_PREFIX@ srcdir = @srcdir@ libdir = @libdir@ scriptdir = @BLT_LIBRARY@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_ROOT = RM = rm -f SHELL = /bin/sh cursors = treeview.xbm \ treeview_m.xbm miscFiles = \ bltCanvEps.pro \ bltGraph.pro \ dnd.tcl \ dragdrop.tcl \ graph.tcl \ hierbox.tcl \ tabnotebook.tcl \ tabset.tcl \ treeview.tcl \ tclIndex \ $(cursors) ddFiles = dd-color.tcl \ dd-file.tcl \ dd-number.tcl \ dd-text.tcl \ tclIndex instdirs = $(prefix) $(exec_prefix) \ $(libdir) $(prefix)/lib $(scriptdir) $(scriptdir)/dd_protocols all: pkgIndex pkgIndex: rm -f pkgIndex.tcl sed -e 's/%VERSION%/$(version)/' $(srcdir)/pkgIndex.tcl.in | \ sed -e 's/%LIB_PREFIX%/$(lib_prefix)/' | \ sed -e 's;%LIB_DIR%;$(libdir);' > pkgIndex.tcl install: mkdirs pkgIndex for i in $(ddFiles) ; do \ $(INSTALL_DATA) $(srcdir)/dd_protocols/$$i \ $(INSTALL_ROOT)$(scriptdir)/dd_protocols ; \ done for i in $(miscFiles) ; do \ $(INSTALL_DATA) $(srcdir)/$$i $(INSTALL_ROOT)$(scriptdir) ; \ done $(INSTALL_DATA) pkgIndex.tcl $(scriptdir) mkdirs: @for i in $(instdirs) ; do \ if test -d $(INSTALL_ROOT)$$i ; then \ : ; \ else \ echo " mkdir $(INSTALL_ROOT)$$i" ; \ mkdir $(INSTALL_ROOT)$$i ; \ fi ; \ done clean: $(RM) pkgIndex.tcl distclean: clean $(RM) $(srcdir)/*.bak $(srcdir)/*\~ $(srcdir)/"#"* Makefile blt-2.4z.orig/library/Makefile.vc0100644000175000017500000000321407530630503015460 0ustar dokodoko # ------------------------------------------------------------------------ # Makefile for library files and directories of BLT library # ------------------------------------------------------------------------ include ../win/makedefs version = $(BLT_MAJOR_VERSION).$(BLT_MINOR_VERSION) pkgdir = $(libdir)/tcl$(v1)/blt$(version) srcdir = . cursors = treeview.cur miscFiles = bltCanvEps.pro \ bltGraph.pro \ dnd.tcl \ dragdrop.tcl \ graph.tcl \ hierbox.tcl \ tabnotebook.tcl \ tabset.tcl \ treeview.tcl \ tclIndex \ $(cursors) ddFiles = dd-color.tcl \ dd-file.tcl \ dd-number.tcl \ dd-text.tcl \ tclIndex instdirs = $(prefix) $(exec_prefix) $(libdir) \ $(scriptdir) $(scriptdir)/dd_protocols $(libdir)/tcl$(v1) \ $(pkgdir) all: build-pkgindex install: install-dirs install-ddfiles install-files install-pkgindex install-dirs: @for i in $(instdirs) ; do \ if test -d "$$i" ; then : ; else mkdir "$$i" ; fi ; \ done install-ddfiles: install-dirs for i in $(ddFiles) ; do \ $(INSTALL_DATA) $(srcdir)/dd_protocols/$$i $(scriptdir)/dd_protocols ; \ done install-files: install-dirs for i in $(miscFiles) ; do \ $(INSTALL_DATA) $(srcdir)/$$i $(scriptdir) ; \ done pkgIndex.tcl: build-pkgindex build-pkgindex: rm -f pkgIndex.tcl sed -e 's/%VERSION%/$(version)/' $(srcdir)/pkgIndex.tcl.in | \ sed -e 's/%LIB_PREFIX%//' | \ sed -e 's;%LIB_DIR%;$(libdir);' > pkgIndex.tcl install-pkgindex: pkgIndex.tcl $(INSTALL_DATA) pkgIndex.tcl $(scriptdir) $(INSTALL_DATA) pkgIndex.tcl $(pkgdir) clean: $(RM) pkgIndex.tcl $(RM) $(srcdir)/*.bak $(srcdir)/*\~ $(srcdir)/"#"* distclean: clean $(RM) Makefile blt-2.4z.orig/library/ZoomStack.itcl0100644000175000017500000002316007240160102016171 0ustar dokodokoimport add itcl class ZoomStackGraph { # The name of graph (nee the namespace path) variable graph "" # Indicates which corner of the rectangular zoom region # is currently being choosen. variable corner "first" # Coordinates of the current zoom region. They represent the # two corners of a rectangular area. The two points are order # independent. variable x1 variable y1 variable x2 variable y2 # A list of axis configuration commmands. Acts as a stack to # unzoom the graph back to previous axis limits. variable stack {} constructor { args } { # This will need to change when we start using inheritance. set graph [info namespace tail $this] # What about collisions between the blt::graph instance # command and the ZoomStackGraph instance command? blt::graph $graph if { [llength $args] > 0 } { $graph configure $args } # Set up the bindings to select/deselect the zoom region bind $graph <1> [code $this SelectPoint %x %y] bind $graph <3> [code $this ClearZoom] # The particular mouse buttons should be configurable. } destructor { if { [winfo exists $graph] } { destroy $graph } } # These methods are used internally, within this class, to manage the # zoom stack. private method SaveCoords { x y } private method Zoom {} private method Unzoom {} private method Push { cmd } private method Pop {} private method MarkPoint { x y } private method SetTitle { title } private method DrawBox { } # These methods are called by "bind" and "after" from the Tk # event loop. Is there any way of hiding them, so that it # doesn't look to the user as part of the public interface? method ClearZoom {} method ClearTitle {} method UpdateOutline { x y } method SelectPoint { x y } } # ---------------------------------------------------------------------- # # SaveCoords -- # # Given a point on the screen, transforms the point into graph # coordinates and saves it as one of the points representing a # corner of the zoom region. # # ---------------------------------------------------------------------- body ZoomStackGraph::SaveCoords { x y } { set coords [$graph invtransform $x $y] set x [lindex $coords 0] set y [lindex $coords 1] scan [$graph xaxis limits] "%s %s" min max if { $x > $max } { set x $max } elseif { $x < $min } { set x $min } scan [$graph yaxis limits] "%s %s" min max if { $y > $max } { set y $max } elseif { $y < $min } { set y $min } if { $corner == "first" } { set x1 $x ; set y1 $y } else { set x2 $x ; set y2 $y } } # ---------------------------------------------------------------------- # # MarkPoint -- # # Adds text around one of the corners of the zoom region. # The text consists of the x,y graph coordinates of the # corner. # # ---------------------------------------------------------------------- body ZoomStackGraph::MarkPoint { x y } { set marker "bltZoom_text_$corner" set text [format "x=%.4g\ny=%.4g" $x $y] if [$graph marker exists $marker] { $graph marker configure $marker -coords { $x $y } -text $text } else { $graph marker create text -coords { $x $y } -name $marker \ -font *lucida*-r-*-10-* \ -text $text -anchor center -bg {} -justify left } } # ---------------------------------------------------------------------- # # Empty -- # # Indicates if the stack of axis configuration commands is # empty. # # ---------------------------------------------------------------------- body ZoomStackGraph::Empty { } { return [llength $stack] } # ---------------------------------------------------------------------- # # Push -- # # Appends a command on the list "stack" which can be used # to return to previous graph x and y axis ranges. # # ---------------------------------------------------------------------- body ZoomStackGraph::Push { cmd } { lappend stack $cmd } # ---------------------------------------------------------------------- # # Pop -- # # Remove the last item pushed onto the stack and returns it. # # ---------------------------------------------------------------------- body ZoomStackGraph::Pop { } { set cmd [lindex $stack end] set stack [lreplace $stack end end] return $cmd } # ---------------------------------------------------------------------- # # ClearTitle -- # # Clears the zoom title (displayed in the upper left corner # of the graph). This routine is called from the event queue # using "after". # # ---------------------------------------------------------------------- body ZoomStackGraph::ClearTitle {} { $graph marker delete "bltZoom_title" } # ---------------------------------------------------------------------- # # Unzoom -- # # Reverts to a previous zoom. Resets the x and y axis limits # back to a previous setting. First checks if there's anything # to pop back to. In addition, displays a title in the upper # left corner showing the current zoom level. # # ---------------------------------------------------------------------- body ZoomStackGraph::Unzoom { } { if ![Empty] { # Reset the x and y axis limits, by invoking the saved graph # command. eval [Pop] # Cheat: Using "Empty" to get the number of entries on the stack. set level [Empty] if { $level > 0 } { SetTitle "Zoom #$level" } blt::busy hold $graph update if { $corner == "first" } { # Remember to remove the zoom title in a couple of seconds after 2000 [code $this ClearTitle] } blt::busy release $graph } else { $graph marker delete "bltZoom_title" } } # ---------------------------------------------------------------------- # # Zoom -- # # Push the old axis limits on the stack and set them to the # zoom region. # # ---------------------------------------------------------------------- body ZoomStackGraph::Zoom { } { $graph marker delete "bltZoom_*" if { ($x1 == $x2) && ($y1 == $y2) } { # The first and last points of the zoom region are the same. # Revert back to the start. return } # Put a command on the stack that lets us revert back to the current # axis limits. set cmd [format { %s xaxis configure -min "%s" -max "%s" %s yaxis configure -min "%s" -max "%s" } $graph [$graph xaxis cget -min] [$graph xaxis cget -max] \ $graph [$graph yaxis cget -min] [$graph yaxis cget -max] ] Push $cmd # The first and last corners of the zoom region don't have to be # selected in ascending order. So consider their relative positions # when setting min and max axis limits. if { $x1 > $x2 } { $graph xaxis configure -min $x2 -max $x1 } elseif { $x1 < $x2 } { $graph xaxis configure -min $x1 -max $x2 } if { $y1 > $y2 } { $graph yaxis configure -min $y2 -max $y1 } elseif { $y1 < $y2 } { $graph yaxis configure -min $y1 -max $y2 } # Call "update" explicitly here after the graph is made busy. # This prevents the user from inadvertantly selecting another zoom # region when the graph is recalculating and redrawing itself. blt::busy hold $graph update blt::busy release $graph } # ---------------------------------------------------------------------- # # ClearZoom -- # # ---------------------------------------------------------------------- body ZoomStackGraph::ClearZoom { } { $graph marker delete "bltZoom_*" if { $corner == "first" } { # We're haven't started to select a zoom region, so assume # that we want to revert back to a previous zoom level. Unzoom } else { # Let the user re-pick the first corner again. So reset the # indicator "corner" and turn off the binding. set corner "first" bind $graph {} } } # ---------------------------------------------------------------------- # # SetTitle -- # # ---------------------------------------------------------------------- body ZoomStackGraph::SetTitle { title } { $graph marker create text -name "bltZoom_title" -text $title \ -coords {-Inf Inf} -anchor nw -bg {} } # ---------------------------------------------------------------------- # # UpdateOutline -- # # ---------------------------------------------------------------------- body ZoomStackGraph::UpdateOutline { x y } { SaveCoords $x $y MarkPoint $x2 $y2 DrawBox } # ---------------------------------------------------------------------- # # SelectPoint -- # # Invoked from the binding to ButtonPress-1 events. Saves # a corner of zoom region. # # # ---------------------------------------------------------------------- body ZoomStackGraph::SelectPoint { x y } { SaveCoords $x $y if { $corner == "first" } { MarkPoint $x1 $y1 # Display a new title indicating zoom pick is active set level [expr [llength $stack] + 1] SetTitle "Zoom #$level" # Start watching now for motion events, drawing an outline bind $graph [code $this UpdateOutline %x %y] # Indicate the next corner is the last set corner last } else { # Stop watching motion events bind $graph {} # Zoom into the new region defined by the outline Zoom # Reset to select the first corner, again set corner first } } # ---------------------------------------------------------------------- # # DrawBox -- # # ---------------------------------------------------------------------- body ZoomStackGraph::DrawBox { } { set coords { $x1 $y1 $x2 $y1 $x2 $y2 $x1 $y2 $x1 $y1 } if [$graph marker exists "bltZoom_outline"] { $graph marker configure "bltZoom_outline" -coords $coords } else { $graph marker create line -coords $coords -name "bltZoom_outline" \ -dashes { 4 2 } } $graph marker before "bltZoom_outline" } blt-2.4z.orig/library/bltCanvEps.pro0100644000175000017500000000434507240160102016171 0ustar dokodoko% % PostScript encapulator prolog file of the BLT "eps" canvas item. % % Copyright 1991-1997 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. % % % The definitions of the next two macros are from Appendix H of % Adobe's "PostScript Language Reference Manual" pp. 709-736. % % Prepare for EPS file /BeginEPSF { /beforeInclusionState save def /dictCount countdictstack def % Save the # objects in the dictionary /opCount count 1 sub def % Count object on operator stack userdict begin % Make "userdict" the current % dictionary /showpage {} def % Redefine showpage to be null 0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin 10 setmiterlimit [] 0 setdash newpath /languagellevel where { pop languagelevel 1 ne { false setstrokeadjust false setoverprint } if } if % note: no "end" } bind def /EndEPSF { %def count opCount sub { pop } repeat countdictstack dictCount sub { end % Clean up dictionary stack } repeat beforeInclusionState restore } bind def % % Set up a clip region based upon a bounding box (x1, y1, x2, y2). % /SetClipRegion { % Stack: x1 y1 x2 y2 newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto neg 0 rlineto closepath clip newpath } def blt-2.4z.orig/library/bltGraph.pro0100644000175000017500000003152307535300711015702 0ustar dokodoko%%BeginProlog % % PostScript prolog file of the BLT graph widget. % % Copyright 1989-1992 Regents of the University of California. % 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. The University of California % makes no representations about the suitability of this % software for any purpose. It is provided "as is" without % express or implied warranty. % % Copyright 1991-1997 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. % 200 dict begin /BaseRatio 1.3467736870885982 def % Ratio triangle base / symbol size /BgColorProc 0 def % Background color routine (symbols) /DrawSymbolProc 0 def % Routine to draw symbol outline/fill /StippleProc 0 def % Stipple routine (bar segments) /DashesProc 0 def % Dashes routine (line segments) % Define the array ISOLatin1Encoding (which specifies how characters are % encoded for ISO-8859-1 fonts), if it isn't already present (Postscript % level 2 is supposed to define it, but level 1 doesn't). systemdict /ISOLatin1Encoding known not { /ISOLatin1Encoding [ /space /space /space /space /space /space /space /space /space /space /space /space /space /space /space /space /space /space /space /space /space /space /space /space /space /space /space /space /space /space /space /space /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quoteright /parenleft /parenright /asterisk /plus /comma /minus /period /slash /zero /one /two /three /four /five /six /seven /eight /nine /colon /semicolon /less /equal /greater /question /at /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore /quoteleft /a /b /c /d /e /f /g /h /i /j /k /l /m /n /o /p /q /r /s /t /u /v /w /x /y /z /braceleft /bar /braceright /asciitilde /space /space /space /space /space /space /space /space /space /space /space /space /space /space /space /space /space /dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /space /ring /cedilla /space /hungarumlaut /ogonek /caron /space /exclamdown /cent /sterling /currency /yen /brokenbar /section /dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered /cedillar /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis ] def } if % font ISOEncode font % This procedure changes the encoding of a font from the default % Postscript encoding to ISOLatin1. It is typically invoked just % before invoking "setfont". The body of this procedure comes from % Section 5.6.1 of the Postscript book. /ISOEncode { dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding ISOLatin1Encoding def currentdict end % I'm not sure why it's necessary to use "definefont" on this new % font, but it seems to be important; just use the name "Temporary" % for the font. /Temporary exch definefont } bind def /Stroke { gsave stroke grestore } def /Fill { gsave fill grestore } def /SetFont { % Stack: pointSize fontName findfont exch scalefont ISOEncode setfont } def /Box { % Stack: x y width height newpath exch 4 2 roll moveto dup 0 rlineto exch 0 exch rlineto neg 0 rlineto closepath } def /SetFgColor { % Stack: red green blue CL 0 eq { pop pop pop 0 0 0 } if setrgbcolor CL 1 eq { currentgray setgray } if } def /SetBgColor { % Stack: red green blue CL 0 eq { pop pop pop 1 1 1 } if setrgbcolor CL 1 eq { currentgray setgray } if } def % The next two definitions are taken from "$tk_library/prolog.ps" % desiredSize EvenPixels closestSize % % The procedure below is used for stippling. Given the optimal size % of a dot in a stipple pattern in the current user coordinate system, % compute the closest size that is an exact multiple of the device's % pixel size. This allows stipple patterns to be displayed without % aliasing effects. /EvenPixels { % Compute exact number of device pixels per stipple dot. dup 0 matrix currentmatrix dtransform dup mul exch dup mul add sqrt % Round to an integer, make sure the number is at least 1, and compute % user coord distance corresponding to this. dup round dup 1 lt {pop 1} if exch div mul } bind def % width height string filled StippleFill -- % % Given a path and other graphics information already set up, this % procedure will fill the current path in a stippled fashion. "String" % contains a proper image description of the stipple pattern and % "width" and "height" give its dimensions. If "filled" is true then % it means that the area to be stippled is gotten by filling the % current path (e.g. the interior of a polygon); if it's false, the % area is gotten by stroking the current path (e.g. a wide line). % Each stipple dot is assumed to be about one unit across in the % current user coordinate system. % width height string StippleFill -- % % Given a path already set up and a clipping region generated from % it, this procedure will fill the clipping region with a stipple % pattern. "String" contains a proper image description of the % stipple pattern and "width" and "height" give its dimensions. Each % stipple dot is assumed to be about one unit across in the current % user coordinate system. This procedure trashes the graphics state. /StippleFill { % The following code is needed to work around a NeWSprint bug. /tmpstip 1 index def % Change the scaling so that one user unit in user coordinates % corresponds to the size of one stipple dot. 1 EvenPixels dup scale % Compute the bounding box occupied by the path (which is now % the clipping region), and round the lower coordinates down % to the nearest starting point for the stipple pattern. Be % careful about negative numbers, since the rounding works % differently on them. pathbbox 4 2 roll 5 index div dup 0 lt {1 sub} if cvi 5 index mul 4 1 roll 6 index div dup 0 lt {1 sub} if cvi 6 index mul 3 2 roll % Stack now: width height string y1 y2 x1 x2 % Below is a doubly-nested for loop to iterate across this area % in units of the stipple pattern size, going up columns then % across rows, blasting out a stipple-pattern-sized rectangle at % each position 6 index exch { 2 index 5 index 3 index { % Stack now: width height string y1 y2 x y gsave 1 index exch translate 5 index 5 index true matrix tmpstip imagemask grestore } for pop } for pop pop pop pop pop } bind def /LS { % Stack: x1 y1 x2 y2 newpath 4 2 roll moveto lineto stroke } def /EndText { %Stack : grestore } def /BeginText { %Stack : w h theta centerX centerY gsave % Translate the origin to the center of bounding box and rotate translate neg rotate % Translate back to the origin of the text region -0.5 mul exch -0.5 mul exch translate } def /DrawAdjText { %Stack : str strWidth x y moveto % Go to the text position exch dup dup 4 2 roll % Adjust character widths to get desired overall string width % adjust X = (desired width - real width)/#chars stringwidth pop sub exch length div 0 3 -1 roll % Flip back the scale so that the string is not drawn in reverse gsave 1 -1 scale ashow grestore } def /DrawBitmap { % Stack: ?bgColorProc? boolean centerX centerY width height theta imageStr gsave 6 -2 roll translate % Translate to center of bounding box 4 1 roll neg rotate % Rotate by theta % Find upperleft corner of bounding box 2 copy -.5 mul exch -.5 mul exch translate 2 copy scale % Make pixel unit scale newpath 0 0 moveto 0 1 lineto 1 1 lineto 1 0 lineto closepath % Fill rectangle with background color 4 -1 roll { gsave 4 -1 roll exec fill grestore } if % Paint the image string into the unit rectangle 2 copy true 3 -1 roll 0 0 5 -1 roll 0 0 6 array astore 5 -1 roll imagemask grestore } def % Symbols: % Skinny-cross /Sc { % Stack: x y symbolSize gsave 3 -2 roll translate 45 rotate 0 0 3 -1 roll Sp grestore } def % Skinny-plus /Sp { % Stack: x y symbolSize gsave 3 -2 roll translate 2 idiv dup 2 copy newpath neg 0 moveto 0 lineto DrawSymbolProc newpath neg 0 exch moveto 0 exch lineto DrawSymbolProc grestore } def % Cross /Cr { % Stack: x y symbolSize gsave 3 -2 roll translate 45 rotate 0 0 3 -1 roll Pl grestore } def % Plus /Pl { % Stack: x y symbolSize gsave 3 -2 roll translate dup 2 idiv exch 6 idiv % % 2 3 The plus/cross symbol is a % closed polygon of 12 points. % 0 1 4 5 The diagram to the left % x,y represents the positions of % 11 10 7 6 the points which are computed % below. % 9 8 % newpath 2 copy exch neg exch neg moveto dup neg dup lineto 2 copy neg exch neg lineto 2 copy exch neg lineto dup dup neg lineto 2 copy neg lineto 2 copy lineto dup dup lineto 2 copy exch lineto 2 copy neg exch lineto dup dup neg exch lineto exch neg exch lineto closepath DrawSymbolProc grestore } def % Circle /Ci { % Stack: x y symbolSize gsave 3 copy pop moveto newpath 2 div 0 360 arc closepath DrawSymbolProc grestore } def % Square /Sq { % Stack: x y symbolSize gsave dup dup 2 div dup 6 -1 roll exch sub exch 5 -1 roll exch sub 4 -2 roll Box DrawSymbolProc grestore } def % Line /Li { % Stack: x y symbolSize gsave 3 1 roll exch 3 -1 roll 2 div 3 copy newpath sub exch moveto add exch lineto stroke grestore } def % Diamond /Di { % Stack: x y symbolSize gsave 3 1 roll translate 45 rotate 0 0 3 -1 roll Sq grestore } def % Triangle /Tr { % Stack: x y symbolSize gsave 3 -2 roll translate BaseRatio mul 0.5 mul % Calculate 1/2 base dup 0 exch 30 cos mul % h1 = height above center point neg % b2 0 -h1 newpath moveto % point 1; b2 dup 30 sin 30 cos div mul % h2 = height below center point 2 copy lineto % point 2; b2 h2 exch neg exch lineto % closepath DrawSymbolProc grestore } def % Arrow /Ar { % Stack: x y symbolSize gsave 3 -2 roll translate BaseRatio mul 0.5 mul % Calculate 1/2 base dup 0 exch 30 cos mul % h1 = height above center point % b2 0 h1 newpath moveto % point 1; b2 dup 30 sin 30 cos div mul % h2 = height below center point neg % -h2 b2 2 copy lineto % point 2; b2 h2 exch neg exch lineto % closepath DrawSymbolProc grestore } def % Bitmap /Bm { % Stack: x y symbolSize gsave 3 1 roll translate pop DrawSymbolProc grestore } def %%EndProlog %%BeginSetup gsave % Save the graphics state % Default line/text style parameters 1 setlinewidth % width 1 setlinejoin % join 0 setlinecap % cap [] 0 setdash % dashes /CL 0 def % Set color level mode 0 0 0 setrgbcolor % color blt-2.4z.orig/library/dnd.tcl0100644000175000017500000000626207427313353014676 0ustar dokodoko# # dnd.tcl # # ---------------------------------------------------------------------- # Bindings for the BLT drag&drop command # ---------------------------------------------------------------------- # AUTHOR: George Howlett # Bell Labs Innovations for Lucent Technologies # gah@bell-labs.com # http://www.tcltk.com/blt # ---------------------------------------------------------------------- # Copyright (c) 1998 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 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. # # ====================================================================== if { $tcl_version >= 8.0 } { set cmd blt::dnd } else { set cmd dnd } for { set i 1 } { $i <= 5 } { incr i } { bind BltDndButton$i [list $cmd select %W %X %Y %t] bind BltDndButton$i [list $cmd drag %W %X %Y] bind BltDndButton$i [list $cmd drop %W %X %Y] } # ---------------------------------------------------------------------- # # DndInit -- # # Invoked from C whenever a new drag&drop source is created. # Sets up the default bindings for the drag&drop source. # # Starts the drag operation. # Updates the drag. # Drop the data on the target. # # Arguments: # widget source widget # button Mouse button used to activate drag. # cmd "dragdrop" or "blt::dragdrop" # # ---------------------------------------------------------------------- proc blt::DndInit { widget button } { set tagList {} if { $button > 0 } { lappend tagList BltDndButton$button } foreach tag [bindtags $widget] { if { ![string match BltDndButton* $tag] } { lappend tagList $tag } } bindtags $widget $tagList } proc blt::DndStdDrop { widget args } { array set info $args set fmt [lindex $info(formats) 0] dnd pull $widget $fmt return 0 } proc blt::PrintInfo { array } { upvar $array state parray state if { $info(state) & 0x01 } { puts "Shift-Drop" } if { $info(state) & 0x02 } { puts "CapsLock-Drop" } if { $info(state) & 0x04 } { puts "Control-Drop" } if { $info(state) & 0x08 } { puts "Alt-Drop" } if { $info(state) & 0x10 } { puts "NumLock-Drop" } }blt-2.4z.orig/library/dragdrop.tcl0100644000175000017500000000534607427313353015735 0ustar dokodoko# # dragdrop.tcl # # ---------------------------------------------------------------------- # Bindings for the BLT drag&drop command # ---------------------------------------------------------------------- # AUTHOR: George Howlett # Bell Labs Innovations for Lucent Technologies # gah@bell-labs.com # http://www.tcltk.com/blt # ---------------------------------------------------------------------- # Copyright (c) 1998 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 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. # # ====================================================================== if { $tcl_version >= 8.0 } { set cmd blt::drag&drop } else { set cmd drag&drop } for { set i 1 } { $i <= 5 } { incr i } { bind BltDrag&DropButton$i [list $cmd drag %W %X %Y] bind BltDrag&DropButton$i [list $cmd drag %W %X %Y] bind BltDrag&DropButton$i [list $cmd drop %W %X %Y] } # ---------------------------------------------------------------------- # # Drag&DropInit -- # # Invoked from C whenever a new drag&drop source is created. # Sets up the default bindings for the drag&drop source. # # Starts the drag operation. # Updates the drag. # Drop the data on the target. # # Arguments: # widget source widget # button Mouse button used to activate drag. # cmd "dragdrop" or "blt::dragdrop" # # ---------------------------------------------------------------------- proc blt::Drag&DropInit { widget button } { set tagList {} if { $button > 0 } { lappend tagList BltDrag&DropButton$button } foreach tag [bindtags $widget] { if { ![string match BltDrag&DropButton* $tag] } { lappend tagList $tag } } bindtags $widget $tagList } blt-2.4z.orig/library/graph.tcl0100644000175000017500000003352007503465645015236 0ustar dokodoko proc Blt_ActiveLegend { graph } { $graph legend bind all [list blt::ActivateLegend $graph ] $graph legend bind all [list blt::DeactivateLegend $graph] $graph legend bind all [list blt::HighlightLegend $graph] } proc Blt_Crosshairs { graph } { blt::Crosshairs $graph } proc Blt_ResetCrosshairs { graph state } { blt::Crosshairs $graph "Any-Motion" $state } proc Blt_ZoomStack { graph } { blt::ZoomStack $graph } proc Blt_PrintKey { graph } { blt::PrintKey $graph } proc Blt_ClosestPoint { graph } { blt::ClosestPoint $graph } # # The following procedures that reside in the "blt" namespace are # supposed to be private. # proc blt::ActivateLegend { graph } { set elem [$graph legend get current] $graph legend activate $elem } proc blt::DeactivateLegend { graph } { set elem [$graph legend get current] $graph legend deactivate $elem } proc blt::HighlightLegend { graph } { set elem [$graph legend get current] set relief [$graph element cget $elem -labelrelief] if { $relief == "flat" } { $graph element configure $elem -labelrelief raised $graph element activate $elem } else { $graph element configure $elem -labelrelief flat $graph element deactivate $elem } } proc blt::Crosshairs { graph {event "Any-Motion"} {state "on"}} { $graph crosshairs $state bind crosshairs-$graph <$event> { %W crosshairs configure -position @%x,%y } bind crosshairs-$graph { %W crosshairs off } bind crosshairs-$graph { %W crosshairs on } $graph crosshairs configure -color red if { $state == "on" } { blt::AddBindTag $graph crosshairs-$graph } elseif { $state == "off" } { blt::RemoveBindTag $graph crosshairs-$graph } } proc blt::InitStack { graph } { global zoomInfo set zoomInfo($graph,interval) 100 set zoomInfo($graph,afterId) 0 set zoomInfo($graph,A,x) {} set zoomInfo($graph,A,y) {} set zoomInfo($graph,B,x) {} set zoomInfo($graph,B,y) {} set zoomInfo($graph,stack) {} set zoomInfo($graph,corner) A } proc blt::ZoomStack { graph {start "ButtonPress-1"} {reset "ButtonPress-3"} } { global zoomInfo zoomMod blt::InitStack $graph if { [info exists zoomMod] } { set modifier $zoomMod } else { set modifier "" } bind zoom-$graph <${modifier}${start}> { blt::SetZoomPoint %W %x %y } bind zoom-$graph <${modifier}${reset}> { if { [%W inside %x %y] } { blt::ResetZoom %W } } blt::AddBindTag $graph zoom-$graph } proc blt::PrintKey { graph {event "Shift-ButtonRelease-3"} } { bind print-$graph <$event> { Blt_PostScriptDialog %W } blt::AddBindTag $graph print-$graph } proc blt::ClosestPoint { graph {event "Control-ButtonPress-2"} } { bind closest-point-$graph <$event> { blt::FindElement %W %x %y } blt::AddBindTag $graph closest-point-$graph } 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 { graph x y } { if ![$graph element closest $x $y info -interpolate yes] { 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 { $graph marker delete $markerName } $graph marker create text -coords { $info(x) $info(y) } \ -name $markerName \ -text "$info(name): $info(dist)\nindex $info(index)" \ -font *lucida*-r-*-10-* \ -anchor center -justify left \ -yoffset 0 -bg {} set coords [$graph invtransform $x $y] set nx [lindex $coords 0] set ny [lindex $coords 1] $graph marker create line -coords "$nx $ny $info(x) $info(y)" \ -name line.$markerName blt::FlashPoint $graph $info(name) $info(index) 10 blt::FlashPoint $graph $info(name) [expr $info(index) + 1] 10 } proc blt::FlashPoint { graph name index count } { if { $count & 1 } { $graph element deactivate $name } else { $graph element activate $name $index } incr count -1 if { $count > 0 } { after 200 blt::FlashPoint $graph $name $index $count update } else { eval $graph marker delete [$graph marker names "bltClosest_*"] } } proc blt::GetCoords { graph x y index } { global zoomInfo if { [$graph cget -invertxy] } { set zoomInfo($graph,$index,x) $y set zoomInfo($graph,$index,y) $x } else { set zoomInfo($graph,$index,x) $x set zoomInfo($graph,$index,y) $y } } proc blt::MarkPoint { graph index } { global zoomInfo set x [$graph xaxis invtransform $zoomInfo($graph,$index,x)] set y [$graph yaxis invtransform $zoomInfo($graph,$index,y)] set marker "zoomText_$index" set text [format "x=%.4g\ny=%.4g" $x $y] if [$graph marker exists $marker] { $graph marker configure $marker -coords { $x $y } -text $text } else { $graph marker create text -coords { $x $y } -name $marker \ -font *lucida*-r-*-10-* \ -text $text -anchor center -bg {} -justify left } } proc blt::DestroyZoomTitle { graph } { global zoomInfo if { $zoomInfo($graph,corner) == "A" } { catch { $graph marker delete "zoomTitle" } } } proc blt::PopZoom { graph } { global zoomInfo set zoomStack $zoomInfo($graph,stack) if { [llength $zoomStack] > 0 } { set cmd [lindex $zoomStack 0] set zoomInfo($graph,stack) [lrange $zoomStack 1 end] eval $cmd blt::ZoomTitleLast $graph busy hold $graph update busy release $graph after 2000 "blt::DestroyZoomTitle $graph" } else { catch { $graph marker delete "zoomTitle" } } } # Push the old axis limits on the stack and set the new ones proc blt::PushZoom { graph } { global zoomInfo eval $graph marker delete [$graph marker names "zoom*"] if { [info exists zoomInfo($graph,afterId)] } { after cancel $zoomInfo($graph,afterId) } set x1 $zoomInfo($graph,A,x) set y1 $zoomInfo($graph,A,y) set x2 $zoomInfo($graph,B,x) set y2 $zoomInfo($graph,B,y) if { ($x1 == $x2) || ($y1 == $y2) } { # No delta, revert to start return } set cmd {} foreach margin { xaxis yaxis x2axis y2axis } { foreach axis [$graph $margin use] { set min [$graph axis cget $axis -min] set max [$graph axis cget $axis -max] set c [list $graph axis configure $axis -min $min -max $max] append cmd "$c\n" } } set zoomInfo($graph,stack) [linsert $zoomInfo($graph,stack) 0 $cmd] foreach margin { xaxis x2axis } { foreach axis [$graph $margin use] { set min [$graph axis invtransform $axis $x1] set max [$graph axis invtransform $axis $x2] if { $min > $max } { $graph axis configure $axis -min $max -max $min } else { $graph axis configure $axis -min $min -max $max } } } foreach margin { yaxis y2axis } { foreach axis [$graph $margin use] { set min [$graph axis invtransform $axis $y1] set max [$graph axis invtransform $axis $y2] if { $min > $max } { $graph axis configure $axis -min $max -max $min } else { $graph axis configure $axis -min $min -max $max } } } busy hold $graph update; # This "update" redraws the graph busy release $graph } # # This routine terminates either an existing zoom, or pops back to # the previous zoom level (if no zoom is in progress). # proc blt::ResetZoom { graph } { global zoomInfo if { ![info exists zoomInfo($graph,corner)] } { blt::InitStack $graph } eval $graph marker delete [$graph marker names "zoom*"] if { $zoomInfo($graph,corner) == "A" } { # Reset the whole axis blt::PopZoom $graph } else { global zoomMod if { [info exists zoomMod] } { set modifier $zoomMod } else { set modifier "Any-" } set zoomInfo($graph,corner) A blt::RemoveBindTag $graph select-region-$graph } } option add *zoomTitle.font -*-helvetica-medium-R-*-*-18-*-*-*-*-*-*-* option add *zoomTitle.shadow yellow4 option add *zoomTitle.foreground yellow1 option add *zoomTitle.coords "-Inf Inf" proc blt::ZoomTitleNext { graph } { global zoomInfo set level [expr [llength $zoomInfo($graph,stack)] + 1] if { [$graph cget -invertxy] } { set coords "-Inf -Inf" } else { set coords "-Inf Inf" } $graph marker create text -name "zoomTitle" -text "Zoom #$level" \ -coords $coords -bindtags "" -anchor nw } proc blt::ZoomTitleLast { graph } { global zoomInfo set level [llength $zoomInfo($graph,stack)] if { $level > 0 } { $graph marker create text -name "zoomTitle" -anchor nw \ -text "Zoom #$level" } } proc blt::SetZoomPoint { graph x y } { global zoomInfo zoomMod if { ![info exists zoomInfo($graph,corner)] } { blt::InitStack $graph } blt::GetCoords $graph $x $y $zoomInfo($graph,corner) if { [info exists zoomMod] } { set modifier $zoomMod } else { set modifier "Any-" } bind select-region-$graph <${modifier}Motion> { blt::GetCoords %W %x %y B #blt::MarkPoint $graph B blt::Box %W } if { $zoomInfo($graph,corner) == "A" } { if { ![$graph inside $x $y] } { return } # First corner selected, start watching motion events #blt::MarkPoint $graph A blt::ZoomTitleNext $graph blt::AddBindTag $graph select-region-$graph set zoomInfo($graph,corner) B } else { # Delete the modal binding blt::RemoveBindTag $graph select-region-$graph blt::PushZoom $graph set zoomInfo($graph,corner) A } } option add *zoomOutline.dashes 4 option add *zoomTitle.anchor nw option add *zoomOutline.lineWidth 2 option add *zoomOutline.xor yes proc blt::MarchingAnts { graph offset } { global zoomInfo incr offset if { [$graph marker exists zoomOutline] } { $graph marker configure zoomOutline -dashoffset $offset set interval $zoomInfo($graph,interval) set id [after $interval [list blt::MarchingAnts $graph $offset]] set zoomInfo($graph,afterId) $id } } proc blt::Box { graph } { global zoomInfo if { $zoomInfo($graph,A,x) > $zoomInfo($graph,B,x) } { set x1 [$graph xaxis invtransform $zoomInfo($graph,B,x)] set y1 [$graph yaxis invtransform $zoomInfo($graph,B,y)] set x2 [$graph xaxis invtransform $zoomInfo($graph,A,x)] set y2 [$graph yaxis invtransform $zoomInfo($graph,A,y)] } else { set x1 [$graph xaxis invtransform $zoomInfo($graph,A,x)] set y1 [$graph yaxis invtransform $zoomInfo($graph,A,y)] set x2 [$graph xaxis invtransform $zoomInfo($graph,B,x)] set y2 [$graph yaxis invtransform $zoomInfo($graph,B,y)] } set coords { $x1 $y1 $x2 $y1 $x2 $y2 $x1 $y2 $x1 $y1 } if { [$graph marker exists "zoomOutline"] } { $graph marker configure "zoomOutline" -coords $coords } else { set X [lindex [$graph xaxis use] 0] set Y [lindex [$graph yaxis use] 0] $graph marker create line -coords $coords -name "zoomOutline" \ -mapx $X -mapy $Y set interval $zoomInfo($graph,interval) set id [after $interval [list blt::MarchingAnts $graph 0]] set zoomInfo($graph,afterId) $id } } proc Blt_PostScriptDialog { graph } { set top $graph.top toplevel $top foreach var { center landscape maxpect preview decorations padx pady paperwidth paperheight width height colormode } { global $graph.$var set $graph.$var [$graph postscript cget -$var] } set row 1 set col 0 label $top.title -text "PostScript Options" table $top $top.title -cspan 7 foreach bool { center landscape maxpect preview decorations } { set w $top.$bool-label label $w -text "-$bool" -font *courier*-r-*12* table $top $row,$col $w -anchor e -pady { 2 0 } -padx { 0 4 } set w $top.$bool-yes global $graph.$bool radiobutton $w -text "yes" -variable $graph.$bool -value 1 table $top $row,$col+1 $w -anchor w set w $top.$bool-no radiobutton $w -text "no" -variable $graph.$bool -value 0 table $top $row,$col+2 $w -anchor w incr row } label $top.modes -text "-colormode" -font *courier*-r-*12* table $top $row,0 $top.modes -anchor e -pady { 2 0 } -padx { 0 4 } set col 1 foreach m { color greyscale } { set w $top.$m radiobutton $w -text $m -variable $graph.colormode -value $m table $top $row,$col $w -anchor w incr col } set row 1 frame $top.sep -width 2 -bd 1 -relief sunken table $top $row,3 $top.sep -fill y -rspan 6 set col 4 foreach value { padx pady paperwidth paperheight width height } { set w $top.$value-label label $w -text "-$value" -font *courier*-r-*12* table $top $row,$col $w -anchor e -pady { 2 0 } -padx { 0 4 } set w $top.$value-entry global $graph.$value entry $w -textvariable $graph.$value -width 8 table $top $row,$col+1 $w -cspan 2 -anchor w -padx 8 incr row } table configure $top c3 -width .125i button $top.cancel -text "Cancel" -command "destroy $top" table $top $row,0 $top.cancel -width 1i -pady 2 -cspan 3 button $top.reset -text "Reset" -command "destroy $top" #table $top $row,1 $top.reset -width 1i button $top.print -text "Print" -command "blt::ResetPostScript $graph" table $top $row,4 $top.print -width 1i -pady 2 -cspan 2 } proc blt::ResetPostScript { graph } { foreach var { center landscape maxpect preview decorations padx pady paperwidth paperheight width height colormode } { global $graph.$var set old [$graph postscript cget -$var] if { [catch {$graph postscript configure -$var [set $graph.$var]}] != 0 } { $graph postscript configure -$var $old set $graph.$var $old } } $graph postscript output "out.ps" puts stdout "wrote file \"out.ps\"." flush stdout } blt-2.4z.orig/library/hierbox.tcl0100644000175000017500000003244707427313353015575 0ustar dokodoko# # hierbox.tcl # ---------------------------------------------------------------------- # Bindings for the BLT hierbox widget # ---------------------------------------------------------------------- # AUTHOR: George Howlett # Bell Labs Innovations for Lucent Technologies # gah@lucent.com # http://www.tcltk.com/blt # # RCS: $Id: hierbox.tcl,v 1.1 2002/02/03 20:00:43 ghowlett Exp $ # # ---------------------------------------------------------------------- # Copyright (c) 1998 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 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. # # ====================================================================== array set bltHierbox { afterId "" scroll 0 space off x 0 y 0 } catch { namespace eval blt::Hierbox {} } # # ButtonPress assignments # # B1-Enter start auto-scrolling # B1-Leave stop auto-scrolling # ButtonPress-2 start scan # B2-Motion adjust scan # ButtonRelease-2 stop scan # bind Hierbox { set bltHierbox(cursor) [%W cget -cursor] %W configure -cursor hand1 %W scan mark %x %y } bind Hierbox { %W scan dragto %x %y } bind Hierbox { %W configure -cursor $bltHierbox(cursor) } bind Hierbox { if { $bltHierbox(scroll) } { blt::Hierbox::AutoScroll %W } } bind Hierbox { after cancel $bltHierbox(afterId) } # # KeyPress assignments # # Up # Down # Shift-Up # Shift-Down # Prior (PageUp) # Next (PageDn) # Left # Right # space Start selection toggle of entry currently with focus. # Return Start selection toggle of entry currently with focus. # Home # End # F1 # F2 # ASCII char Go to next open entry starting with character. # # KeyRelease # # space Stop selection toggle of entry currently with focus. # Return Stop selection toggle of entry currently with focus. bind Hierbox { blt::Hierbox::MoveFocus %W up if { $bltHierbox(space) } { %W selection toggle focus } } bind Hierbox { blt::Hierbox::MoveFocus %W down if { $bltHierbox(space) } { %W selection toggle focus } } bind Hierbox { blt::Hierbox::MoveFocus %W prevsibling } bind Hierbox { blt::Hierbox::MoveFocus %W nextsibling } bind Hierbox { blt::Hierbox::MovePage %W top } bind Hierbox { blt::Hierbox::MovePage %W bottom } bind Hierbox { %W close focus } bind Hierbox { %W open focus %W see focus -anchor w } bind Hierbox { blt::HierboxToggle %W focus set bltHierbox(space) on } bind Hierbox { set bltHierbox(space) off } bind Hierbox { blt::HierboxToggle %W focus set bltHierbox(space) on } bind Hierbox { set bltHierbox(space) off } bind Hierbox { blt::Hierbox::NextMatchingEntry %W %A } bind Hierbox { blt::Hierbox::MoveFocus %W root } bind Hierbox { blt::Hierbox::MoveFocus %W end } bind Hierbox { %W open -r root } bind Hierbox { eval %W close -r [%W entry children root 0 end] } # ---------------------------------------------------------------------- # USAGE: blt::HierboxToggle # Arguments: hierbox hierarchy widget # # Invoked when the user presses the space bar. Toggles the selection # for the entry at . # ---------------------------------------------------------------------- proc blt::HierboxToggle { widget index } { switch -- [$widget cget -selectmode] { single { if { [$widget selection includes $index] } { $widget selection clearall } else { $widget selection set $index } } multiple { $widget selection toggle $index } } } # ---------------------------------------------------------------------- # USAGE: blt::Hierbox::MovePage # Arguments: hierbox hierarchy widget # # Invoked by KeyPress bindings. Pages the current view up or down. # The argument should be either "top" or "bottom". # ---------------------------------------------------------------------- proc blt::Hierbox::MovePage { widget where } { # If the focus is already at the top/bottom of the window, we want # to scroll a page. It's really one page minus an entry because we # want to see the last entry on the next/last page. if { [$widget index focus] == [$widget index view.$where] } { if {$where == "top"} { $widget yview scroll -1 pages $widget yview scroll 1 units } else { $widget yview scroll 1 pages $widget yview scroll -1 units } } update # Adjust the entry focus and the view. Also activate the entry. # just in case the mouse point is not in the widget. $widget entry highlight view.$where $widget focus view.$where $widget see view.$where if { [$widget cget -selectmode] == "single" } { $widget selection clearall $widget selection set focus } } # # Edit mode assignments # # ButtonPress-3 Enables/disables edit mode on entry. Sets focus to # entry. # # KeyPress # # Left Move insertion position to previous. # Right Move insertion position to next. # Up Move insertion position up one line. # Down Move insertion position down one line. # Return End edit mode. # Shift-Return Line feed. # Home Move to first position. # End Move to last position. # ASCII char Insert character left of insertion point. # Del Delete character right of insertion point. # Delete Delete character left of insertion point. # Ctrl-X Cut # Ctrl-V Copy # Ctrl-P Paste # # KeyRelease # # ButtonPress-1 Start selection if in entry, otherwise clear selection. # B1-Motion Extend/reduce selection. # ButtonRelease-1 End selection if in entry, otherwise use last selection. # B1-Enter Disabled. # B1-Leave Disabled. # ButtonPress-2 Same as above. # B2-Motion Same as above. # ButtonRelease-2 Same as above. # # All bindings in editting mode will "break" to override other bindings. # # bind Hierbox { set node [%W nearest %x %y] %W entry insert $node @%x,%y "" # %W entry insert $node 2 "" } proc blt::Hierbox::Init { widget } { # # Active entry bindings # $widget bind Entry { %W entry highlight current } $widget bind Entry { %W entry highlight "" } # # Button bindings # $widget button bind all { %W see -anchor nw current %W toggle current } $widget button bind all { %W button highlight current } $widget button bind all { %W button highlight "" } # # ButtonPress-1 # # Performs the following operations: # # 1. Clears the previous selection. # 2. Selects the current entry. # 3. Sets the focus to this entry. # 4. Scrolls the entry into view. # 5. Sets the selection anchor to this entry, just in case # this is "multiple" mode. # $widget bind Entry { blt::Hierbox::SetSelectionAnchor %W current set bltHierbox(scroll) 1 } $widget bin Entry { %W toggle current } # # B1-Motion # # For "multiple" mode only. Saves the current location of the # pointer for auto-scrolling. # $widget bind Entry { set bltHierbox(x) %x set bltHierbox(y) %y set index [%W nearest %x %y] if { [%W cget -selectmode] == "multiple" } { %W selection mark $index } else { blt::Hierbox::SetSelectionAnchor %W $index } } # # ButtonRelease-1 # # For "multiple" mode only. # $widget bind Entry { if { [%W cget -selectmode] == "multiple" } { %W selection anchor current } after cancel $bltHierbox(afterId) set bltHierbox(scroll) 0 } # # Shift-ButtonPress-1 # # For "multiple" mode only. # $widget bind Entry { if { [%W cget -selectmode] == "multiple" && [%W selection present] } { if { [%W index anchor] == "" } { %W selection anchor current } set index [%W index anchor] %W selection clearall %W selection set $index current } else { blt::Hierbox::SetSelectionAnchor %W current } } $widget bind Entry { # do nothing } $widget bind Entry { after cancel $bltHierbox(afterId) set bltHierbox(scroll) 0 } # # Control-ButtonPress-1 # # For "multiple" mode only. # $widget bind Entry { if { [%W cget -selectmode] == "multiple" } { set index [%W index current] %W selection toggle $index %W selection anchor $index } else { blt::Hierbox::SetSelectionAnchor %W current } } $widget bind Entry { # do nothing } $widget bind Entry { after cancel $bltHierbox(afterId) set bltHierbox(scroll) 0 } # # Control-Shift-ButtonPress-1 # # For "multiple" mode only. # $widget bind Entry { if { [%W cget -selectmode] == "multiple" && [%W selection present] } { if { [%W index anchor] == "" } { %W selection anchor current } if { [%W selection includes anchor] } { %W selection set anchor current } else { %W selection clear anchor current %W selection set current } } else { blt::Hierbox::SetSelectionAnchor %W current } } $widget bind Entry { # do nothing } } # ---------------------------------------------------------------------- # USAGE: blt::Hierbox::AutoScroll # # Invoked when the user is selecting elements in a hierbox widget # and drags the mouse pointer outside of the widget. Scrolls the # view in the direction of the pointer. # # Arguments: hierbox hierarchy widget # # ---------------------------------------------------------------------- proc blt::Hierbox::AutoScroll { widget } { global bltHierbox if { ![winfo exists $widget] } { return } set x $bltHierbox(x) set y $bltHierbox(y) set index [$widget nearest $x $y] if { $y >= [winfo height $widget] } { $widget yview scroll 1 units set neighbor down } elseif { $y < 0 } { $widget yview scroll -1 units set neighbor up } else { set neighbor $index } if { [$widget cget -selectmode] == "single" } { blt::Hierbox::SetSelectionAnchor $widget $neighbor } else { $widget selection mark $index } set bltHierbox(afterId) [after 10 blt::Hierbox::AutoScroll $widget] } proc blt::Hierbox::SetSelectionAnchor { widget index } { set index [$widget index $index] $widget selection clearall $widget see $index $widget focus $index $widget selection set $index $widget selection anchor $index } # ---------------------------------------------------------------------- # USAGE: blt::Hierbox::NextMatchingEntry # Arguments: hierbox hierarchy widget # # Invoked by KeyPress bindings. Searches for an entry that starts # with the letter and makes that entry active. # ---------------------------------------------------------------------- proc blt::Hierbox::NextMatchingEntry { widget key } { if {[string match {[ -~]} $key]} { set last [$widget index focus] set next [$widget index next] while { $next != $last } { set label [$widget entry cget $next -label] if { [string index $label 0] == $key } { break } set next [$widget index -at $next next] } $widget focus $next if {[$widget cget -selectmode] == "single"} { $widget selection clearall $widget selection set focus } $widget see focus } } # ---------------------------------------------------------------------- # USAGE: blt::Hierbox::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::Hierbox::MoveFocus { widget where } { catch {$widget focus $where} if { [$widget cget -selectmode] == "single" } { $widget selection clearall $widget selection set focus } $widget see focus } blt-2.4z.orig/library/hiertable.tcl0100644000175000017500000006016207427313353016067 0ustar dokodoko# hiertable.tcl # ---------------------------------------------------------------------- # Bindings for the BLT hiertable widget # ---------------------------------------------------------------------- # AUTHOR: George Howlett # Bell Labs Innovations for Lucent Technologies # gah@lucent.com # http://www.tcltk.com/blt # # RCS: $Id: hiertable.tcl,v 1.1 2002/02/03 20:00:43 ghowlett Exp $ # # ---------------------------------------------------------------------- # Copyright (c) 1998 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 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. # # ====================================================================== namespace eval blt::Hiertable { set afterId "" set scroll 0 set column "" set space off set x 0 set y 0 } # # ButtonPress assignments # # B1-Enter start auto-scrolling # B1-Leave stop auto-scrolling # ButtonPress-2 start scan # B2-Motion adjust scan # ButtonRelease-2 stop scan # bind Hiertable { set blt::Hiertable::cursor [%W cget -cursor] %W configure -cursor hand1 %W scan mark %x %y } bind Hiertable { %W scan dragto %x %y } bind Hiertable { %W configure -cursor $blt::Hiertable::cursor } bind Hiertable { if { $blt::Hiertable::scroll } { blt::Hiertable::AutoScroll %W } } bind Hiertable { after cancel $blt::Hiertable::afterId } # # KeyPress assignments # # Up # Down # Shift-Up # Shift-Down # Prior (PageUp) # Next (PageDn) # Left # Right # space Start selection toggle of entry currently with focus. # Return Start selection toggle of entry currently with focus. # Home # End # F1 # F2 # ASCII char Go to next open entry starting with character. # # KeyRelease # # space Stop selection toggle of entry currently with focus. # Return Stop selection toggle of entry currently with focus. bind Hiertable { blt::Hiertable::MoveFocus %W up if { $blt::Hiertable::space } { %W selection toggle focus } } bind Hiertable { blt::Hiertable::MoveFocus %W down if { $blt::Hiertable::space } { %W selection toggle focus } } bind Hiertable { blt::Hiertable::MoveFocus %W prevsibling } bind Hiertable { blt::Hiertable::MoveFocus %W nextsibling } bind Hiertable { blt::Hiertable::MovePage %W top } bind Hiertable { blt::Hiertable::MovePage %W bottom } bind Hiertable { %W close focus } bind Hiertable { %W open focus %W see focus -anchor w } bind Hiertable { if { [%W cget -selectmode] == "single" } { if { [%W selection includes focus] } { %W selection clearall } else { %W selection clearall %W selection set focus } } else { %W selection toggle focus } set blt::Hiertable::space on } bind Hiertable { set blt::Hiertable::space off } bind Hiertable { blt::Hiertable::MoveFocus %W focus set blt::Hiertable::space on } bind Hiertable { set blt::Hiertable::space off } bind Hiertable { blt::Hiertable::NextMatchingEntry %W %A } bind Hiertable { blt::Hiertable::MoveFocus %W top } bind Hiertable { blt::Hiertable::MoveFocus %W bottom } bind Hiertable { %W open -r root } bind Hiertable { eval %W close -r [%W entry children root] } # # Differences between "current" and nearest. # # set index [$widget index current] # set index [$widget nearest $x $y] # # o Nearest gives you the closest entry. # o current is "" if # 1) the pointer isn't over an entry. # 2) the pointer is over a open/close button. # 3) # # # ---------------------------------------------------------------------- # # USAGE: blt::Hiertable::Init # # Invoked by internally by Hiertable_Init routine. Initializes the # default bindings for the hiertable widget entries. These are local # to the widget, so they can't be set through the widget's class # bind tags. # # Arguments: hiertable hierarchy widget # # ---------------------------------------------------------------------- proc blt::Hiertable::Init { widget } { # # Active entry bindings # $widget bind Entry { %W entry highlight current } $widget bind Entry { %W entry highlight "" } # # Button bindings # $widget button bind all { %W see -anchor nw current %W toggle current } $widget button bind all { %W button highlight current } $widget button bind all { %W button highlight "" } # # ButtonPress-1 # # Performs the following operations: # # 1. Clears the previous selection. # 2. Selects the current entry. # 3. Sets the focus to this entry. # 4. Scrolls the entry into view. # 5. Sets the selection anchor to this entry, just in case # this is "multiple" mode. # $widget bind Entry { blt::Hiertable::SetSelectionAnchor %W current set blt::Hiertable::scroll 1 } $widget bind Entry { %W toggle current } # # B1-Motion # # For "multiple" mode only. Saves the current location of the # pointer for auto-scrolling. Resets the selection mark. # $widget bind Entry { set blt::Hiertable::x %x set blt::Hiertable::y %y set index [%W nearest %x %y] if { [%W cget -selectmode] == "multiple" } { %W selection mark $index } else { blt::Hiertable::SetSelectionAnchor %W $index } } # # ButtonRelease-1 # # For "multiple" mode only. # $widget bind Entry { if { [%W cget -selectmode] == "multiple" } { %W selection anchor current } after cancel $blt::Hiertable::afterId set blt::Hiertable::scroll 0 } # # Shift-ButtonPress-1 # # For "multiple" mode only. # $widget bind Entry { if { [%W cget -selectmode] == "multiple" && [%W selection present] } { if { [%W index anchor] == "" } { %W selection anchor current } set index [%W index anchor] %W selection clearall %W selection set $index current } else { blt::Hiertable::SetSelectionAnchor %W current } } $widget bind Entry { puts # do nothing } $widget bind Entry { # do nothing } $widget bind Entry { after cancel $blt::Hiertable::afterId set blt::Hiertable::scroll 0 } # # Control-ButtonPress-1 # # For "multiple" mode only. # $widget bind Entry { if { [%W cget -selectmode] == "multiple" } { set index [%W index current] %W selection toggle $index %W selection anchor $index } else { blt::Hiertable::SetSelectionAnchor %W current } } $widget bind Entry { puts # do nothing } $widget bind Entry { # do nothing } $widget bind Entry { after cancel $blt::Hiertable::afterId set blt::Hiertable::scroll 0 } $widget bind Entry { if { [%W cget -selectmode] == "multiple" && [%W selection present] } { if { [%W index anchor] == "" } { %W selection anchor current } if { [%W selection includes anchor] } { %W selection set anchor current } else { %W selection clear anchor current %W selection set current } } else { blt::Hiertable::SetSelectionAnchor %W current } } $widget bind Entry { puts # do nothing } $widget bind Entry { # do nothing } $widget column bind all { %W column highlight [%W column current] } $widget column bind all { %W column highlight "" } $widget column bind Rule { %W column highlight [%W column current] %W column resize activate [%W column current] } $widget column bind Rule { %W column highlight "" %W column resize activate "" } $widget column bind Rule { %W column resize anchor %x } $widget column bind Rule { %W column resize mark %x } $widget column bind Rule { %W column configure [%W column current] -width [%W column resize set] } $widget column bind all { set column [%W column nearest %x %y] if { $column != "" } { %W column invoke $column } } } # ---------------------------------------------------------------------- # USAGE: blt::Hiertable::AutoScroll # # Invoked when the user is selecting elements in a hiertable widget # and drags the mouse pointer outside of the widget. Scrolls the # view in the direction of the pointer. # # Arguments: hiertable hierarchy widget # # ---------------------------------------------------------------------- proc blt::Hiertable::AutoScroll { widget } { if { ![winfo exists $widget] } { return } set x $blt::Hiertable::x set y $blt::Hiertable::y set index [$widget nearest $x $y] if {$y >= [winfo height $widget]} { $widget yview scroll 1 units set neighbor down } elseif {$y < 0} { $widget yview scroll -1 units set neighbor up } else { set neighbor $index } if { [$widget cget -selectmode] == "single" } { blt::Hiertable::SetSelectionAnchor $widget $neighbor } else { $widget selection mark $index } set ::blt::Hiertable::afterId [after 10 blt::Hiertable::AutoScroll $widget] } proc blt::Hiertable::SetSelectionAnchor { widget index } { set index [$widget index $index] # If the anchor hasn't changed, don't do anything if { $index != [$widget index anchor] } { $widget selection clearall $widget see $index $widget focus $index $widget selection set $index $widget selection anchor $index } } # ---------------------------------------------------------------------- # USAGE: blt::Hiertable::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::Hiertable::MoveFocus { widget where } { catch {$widget focus $where} if { [$widget cget -selectmode] == "single" } { $widget selection clearall $widget selection set focus } $widget see focus } # ---------------------------------------------------------------------- # USAGE: blt::Hiertable::MovePage # Arguments: hiertable hierarchy widget # # Invoked by KeyPress bindings. Pages the current view up or down. # The argument should be either "top" or "bottom". # ---------------------------------------------------------------------- proc blt::Hiertable::MovePage { widget where } { # If the focus is already at the top/bottom of the window, we want # to scroll a page. It's really one page minus an entry because we # want to see the last entry on the next/last page. if { [$widget index focus] == [$widget index view.$where] } { if {$where == "top"} { $widget yview scroll -1 pages $widget yview scroll 1 units } else { $widget yview scroll 1 pages $widget yview scroll -1 units } } update # Adjust the entry focus and the view. Also activate the entry. # just in case the mouse point is not in the widget. $widget entry highlight view.$where $widget focus view.$where $widget see view.$where if { [$widget cget -selectmode] == "single" } { $widget selection clearall $widget selection set focus } } # ---------------------------------------------------------------------- # USAGE: blt::Hiertable::NextMatchingEntry # Arguments: hiertable hierarchy widget # # Invoked by KeyPress bindings. Searches for an entry that starts # with the letter and makes that entry active. # ---------------------------------------------------------------------- proc blt::Hiertable::NextMatchingEntry { widget key } { if {[string match {[ -~]} $key]} { set last [$widget index focus] set next [$widget index next] while { $next != $last } { set label [$widget entry cget $next -label] if { [string index $label 0] == $key } { break } set next [$widget index -at $next next] } $widget focus $next if {[$widget cget -selectmode] == "single"} { $widget selection clearall $widget selection set focus } $widget see focus } } # # Edit mode assignments # # ButtonPress-3 Enables/disables edit mode on entry. Sets focus to # entry. # # KeyPress # # Left Move insertion position to previous. # Right Move insertion position to next. # Up Move insertion position up one line. # Down Move insertion position down one line. # Return End edit mode. # Shift-Return Line feed. # Home Move to first position. # End Move to last position. # ASCII char Insert character left of insertion point. # Del Delete character right of insertion point. # Delete Delete character left of insertion point. # Ctrl-X Cut # Ctrl-V Copy # Ctrl-P Paste # # KeyRelease # # ButtonPress-1 Start selection if in entry, otherwise clear selection. # B1-Motion Extend/reduce selection. # ButtonRelease-1 End selection if in entry, otherwise use last selection. # B1-Enter Disabled. # B1-Leave Disabled. # ButtonPress-2 Same as above. # B2-Motion Same as above. # ButtonRelease-2 Same as above. # # All bindings in editting mode will "break" to override other bindings. # # bind xEditor { set node [%W nearest %x %y] %W entry insert $node @%x,%y "" # %W entry insert $node 2 "" } image create photo blt::Hiertable::CloseNormalFolder -format gif -data { R0lGODlhEAANAMIAAAAAAH9/f///////AL+/vwAA/wAAAAAAACH5BAEAAAUALAAAAAAQAA0A AAM8WBrM+rAEQWmIb5KxiWjNInCkV32AJHRlGQBgDA7vdN4vUa8tC78qlrCWmvRKsJTquHkp ZTKAsiCtWq0JADs= } image create photo blt::Hiertable::OpenNormalFolder -format gif -data { R0lGODlhEAANAMIAAAAAAH9/f///////AL+/vwAA/wAAAAAAACH5BAEAAAUALAAAAAAQAA0A AAM1WBrM+rAEMigJ8c3Kb3OSII6kGABhp1JnaK1VGwjwKwtvHqNzzd263M3H4n2OH1QBwGw6 nQkAOw== } image create photo blt::Hiertable::CloseActiveFolder -format gif -data { R0lGODlhEAANAMIAAAAAAH9/f/////+/AL+/vwAA/wAAAAAAACH5BAEAAAUALAAAAAAQAA0A AAM8WBrM+rAEQWmIb5KxiWjNInCkV32AJHRlGQBgDA7vdN4vUa8tC78qlrCWmvRKsJTquHkp ZTKAsiCtWq0JADs= } image create photo blt::Hiertable::OpenActiveFolder -format gif -data { R0lGODlhEAANAMIAAAAAAH9/f/////+/AL+/vwAA/wAAAAAAACH5BAEAAAUALAAAAAAQAA0A AAM1WBrM+rAEMigJ8c3Kb3OSII6kGABhp1JnaK1VGwjwKwtvHqNzzd263M3H4n2OH1QBwGw6 nQkAOw== } if { $tcl_platform(platform) == "windows" } { if { $tk_version >= 8.3 } { set cursor "@[file join $blt_library treeview.cur]" } else { set cursor "size_we" } option add *Hiertable.ResizeCursor [list $cursor] } else { option add *Hiertable.ResizeCursor \ "@$blt_library/treeview.xbm $blt_library/treeview_m.xbm black white" } # Standard Motif bindings: bind HiertableEditor { %W text icursor @%x,%y } bind HiertableEditor { %W text icursor last } bind HiertableEditor { %W text icursor next } bind HiertableEditor { set new [expr {[%W text index insert] - 1}] if {![%W text selection present]} { %W text selection from insert %W text selection to $new } else { %W text selection adjust $new } %W text icursor $new } bind HiertableEditor { set new [expr {[%W text index insert] + 1}] if {![%W text selection present]} { %W text selection from insert %W text selection to $new } else { %W text selection adjust $new } %W text icursor $new } bind HiertableEditor { %W text icursor 0 } bind HiertableEditor { set new 0 if {![%W text selection present]} { %W text selection from insert %W text selection to $new } else { %W text selection adjust $new } %W text icursor $new } bind HiertableEditor { %W text icursor end } bind HiertableEditor { set new end if {![%W text selection present]} { %W text selection from insert %W text selection to $new } else { %W text selection adjust $new } %W text icursor $new } bind HiertableEditor { if { [%W text selection present]} { %W text delete sel.first sel.last } else { %W text delete insert } } bind HiertableEditor { if { [%W text selection present] } { %W text delete sel.first sel.last } else { set index [expr [%W text index insert] - 1] if { $index >= 0 } { %W text delete $index $index } } } bind HiertableEditor { %W text selection from insert } bind HiertableEditor { %W selection from insert } bind ${className}Editor { %W selection adjust insert } bind ${className}Editor { %W selection adjust insert } bind ${className}Editor { %W selection range 0 end } bind ${className}Editor { %W selection clear } bind ${className}Editor { blt::tv::InsertText %W %A } # Ignore all Alt, Meta, and Control keypresses unless explicitly bound. # Otherwise, if a widget binding for one of these is defined, the # class binding will also fire and insert the character, # which is wrong. Ditto for Escape, Return, and Tab. bind ${className}Editor { # nothing } bind ${className}Editor { # nothing } bind ${className}Editor { # nothing } bind ${className}Editor { %W cancel } bind ${className}Editor { %W apply } bind ${className}Editor { blt::tv::InsertText %W "\n" } bind ${className}Editor { # nothing } bind ${className}Editor { # nothing } if {![string compare $tcl_platform(platform) "macintosh"]} { bind ${className}Editor { # nothing } } # On Windows, paste is done using Shift-Insert. Shift-Insert already # generates the <> event, so we don't need to do anything here. if { [string compare $tcl_platform(platform) "windows"] != 0 } { bind ${className}Editor { catch {blt::tv::InsertText %W [selection get -displayof %W]} } } # Additional emacs-like bindings: bind ${className}Editor { set parent [winfo parent %W] %W cancel after idle { blt::tv::EditColumn $parent %X %Y } } bind ${className}Editor { %W icursor 0 %W selection clear } bind ${className}Editor { %W icursor [expr {[%W index insert] - 1}] %W selection clear } bind ${className}Editor { %W delete insert } bind ${className}Editor { %W icursor end %W selection clear } bind ${className}Editor { %W icursor [expr {[%W index insert] + 1}] %W selection clear } bind ${className}Editor { if {[%W selection present]} { %W delete sel.first sel.last } else { set index [expr [%W index insert] - 1] if { $index >= 0 } { %W delete $index $index } } } bind ${className}Editor { %W delete insert end } if 0 { bind ${className}Editor { blt::tv::Transpose %W } bind ${className}Editor { %W icursor [blt::tv::PreviousWord %W insert] %W selection clear } bind ${className}Editor { %W delete insert [blt::tv::NextWord %W insert] } bind ${className}Editor { %W icursor [blt::tv::NextWord %W insert] %W selection clear } bind ${className}Editor { %W delete [blt::tv::PreviousWord %W insert] insert } bind ${className}Editor { %W delete [blt::tv::PreviousWord %W insert] insert } # tkEntryNextWord -- Returns the index of the next word position # after a given position in the entry. The next word is platform # dependent and may be either the next end-of-word position or the # next start-of-word position after the next end-of-word position. # # Arguments: # w - The entry window in which the cursor is to move. # start - Position at which to start search. if {![string compare $tcl_platform(platform) "windows"]} { proc blt::tv::NextWord {w start} { set pos [tcl_endOfWord [$w get] [$w index $start]] if {$pos >= 0} { set pos [tcl_startOfNextWord [$w get] $pos] } if {$pos < 0} { return end } return $pos } } else { proc blt::tv::NextWord {w start} { set pos [tcl_endOfWord [$w get] [$w index $start]] if {$pos < 0} { return end } return $pos } } # PreviousWord -- # # Returns the index of the previous word position before a given # position in the entry. # # Arguments: # w - The entry window in which the cursor is to move. # start - Position at which to start search. proc blt::tv::PreviousWord {w start} { set pos [tcl_startOfPreviousWord [$w get] [$w index $start]] if {$pos < 0} { return 0 } return $pos } } blt-2.4z.orig/library/treeview.xbm0100644000175000017500000000050607427313353015762 0ustar dokodoko#define test_width 16 #define test_height 16 #define test_x_hot 7 #define test_y_hot 7 static unsigned char test_bits[] = { 0x00, 0x00, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x64, 0x26, 0x66, 0x66, 0x7f, 0xfe, 0x66, 0x66, 0x64, 0x26, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x00, 0x00}; blt-2.4z.orig/library/treeview_m.xbm0100644000175000017500000000051307427313353016274 0ustar dokodoko#define testm_width 16 #define testm_height 16 #define testm_x_hot 7 #define testm_y_hot 7 static unsigned char testm_bits[] = { 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xfc, 0x3f, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfc, 0x3f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f}; blt-2.4z.orig/man/0042755000175000017500000000000007553201224012524 5ustar dokodokoblt-2.4z.orig/man/BLT.mann0100644000175000017500000001471307535436724014040 0ustar dokodoko'\" '\" 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. '\" .so man.macros .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 \fBtable\fR A table geometry manager for Tk. You specify window placements as table row,column positions and windows can also span multiple rows or columns. It also has many options for setting and/or bounding window sizes. .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. .TP \fBspline\fR Computes a spline fitting a set of data points (x and y vectors) and produces a vector of the interpolated images (y-coordinates) at a given set of x-coordinates. .TP 15 \fBbgexec\fR Like Tcl's \fBexec\fR command, \fBbgexec\fR runs a pipeline of Unix commands in the background. Unlike \fBexec\fR, the output of the last process is collected and a global Tcl variable is set upon its completion. \fBbgexec\fR can be used with \fBtkwait\fR to wait for Unix commands to finish while still handling expose events. Intermediate output is also available while the pipeline is active. .TP 15 \fBbusy\fR Creates a "busy window" which prevents user-interaction when an application is busy. The busy window also provides an easy way to have temporary busy cursors (such as a watch or hourglass). .TP 15 \fBbitmap\fR Reads and writes bitmaps from Tcl. New X bitmaps can be defined on-the-fly from Tcl, obviating the need to copy around bitmap files. Other options query loaded X bitmap's dimensions and data. .TP 15 \fBdrag&drop\fR Provides a drag-and-drop facility for Tk. Information (represented by a token window) can be dragged to and from any Tk window, including those of another Tk application. \fBdrag&drop\fR acts as a coordinator, directing Tk \fBsend\fR commands between (or within) TCL/Tk applications. .TP 15 \fBhtext\fR A simple hypertext widget. Combines text and Tk widgets into a single scroll-able window. Tcl commands can be embedded into text, which are invoked as the text is parsed. In addition, Tk widgets can be appended to the window at the current point in the text. \fBHtext\fR can be also used to create scrolled windows of Tk widgets. .TP 15 \fBwinop\fR Raise, lower, map, or, unmap any window. The raise and lower functions are useful for stacking windows above or below "busy windows". .TP 15 \fBwatch\fR Arranges for Tcl procedures to be called before and/or after the execution of every Tcl command. This command may be used in the logging, profiling, or tracing of Tcl code. .TP 15 \fBbltdebug\fR A simple Tcl command tracing facility useful for debugging Tcl code. Displays each Tcl command before and after substitution along its level in the interpreter on standard error. .SH VARIABLES .PP The following Tcl variables are either set or used by BLT at various times in its execution: .TP 15 \fBblt_library\fR This variable contains the name of a directory containing a library of Tcl scripts and other files related to BLT. Currently, this directory contains the \fBdrag&drop\fR protocol scripts and the PostScript prolog used by \fBgraph\fR and \fBbarchart\fR. The value of this variable is taken from the BLT_LIBRARY environment variable, if one exists, or else from a default value compiled into the \fBBLT\fR library. .TP 15 \fBblt_versions\fR This variable is set in the interpreter for each application. It is an array of the current version numbers for each of the BLT commands in the form \fImajor\fR.\fIminor\fR. \fIMajor\fR and \fIminor\fR are integers. The major version number increases in any command that includes changes that are not backward compatible (i.e. whenever existing applications and scripts may have to change to work with the new release). The minor version number increases with each new release of a command, except that it resets to zero whenever the major version number changes. The array is indexed by the individual command name. .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. .CS if (Blt_Init(interp) != TCL_OK) { return TCL_ERROR; } .CE Recompile and link with the BLT library (libBLT.a) and that's it. .PP Alternately, you can dynamically load BLT, simply by invoking the command .CS package require BLT .CE from your Tcl script. .SH BUGS Send bug reports, requests, suggestions, etc. to gah@siliconmetrics.com or ghowlett@grandecom.net .SH KEYWORDS BLT blt-2.4z.orig/man/Blt_Tree.man30100644000175000017500000001503207243426113015002 0ustar dokodoko'\" '\" Copyright (c) 1995-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" '\" RCS: @(#) $Id: Blt_Tree.man3,v 1.3 2001/02/17 07:46:19 ghowlett Exp $ '\" .so man.macros .TH Blt_Tree 3 BLT_VERSION BLT "Blt Library Procedures" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME Blt_Tree \- Tree data object. .SH SYNOPSIS .nf #include .sp struct Blt_Tree { \fBTcl_Alloc\fR(\fIsize\fR) .sp \fBTcl_Free\fR(\fIptr\fR) .sp char * \fBTcl_Realloc\fR(\fIptr, size\fR) .SH ARGUMENTS .AS char *size .AP int size in Size in bytes of the memory block to allocate. .AP char *ptr in Pointer to memory block to free or realloc. .BE .SH DESCRIPTION .PP These procedures provide a platform and compiler independent interface for memory allocation. Programs that need to transfer ownership of memory blocks between Tcl and other modules should use these routines rather than the native \fBmalloc()\fR and \fBfree()\fR routines provided by the C run-time library. .PP \fBTcl_Alloc\fR returns a pointer to a block of at least \fIsize\fR bytes suitably aligned for any use. .PP \fBTcl_Free\fR makes the space referred to by \fIptr\fR available for further allocation. .PP \fBTcl_Realloc\fR changes the size of the block pointed to by \fIptr\fR to \fIsize\fR bytes and returns a pointer to the new block. The contents will be unchanged up to the lesser of the new and old sizes. The returned location may be different from \fIptr\fR. .SH TREE OBJECT ROUTINES The following library routines allow you to create and destroy tree objects. Each tree object has a name that uniquely identifies it. Tree objects can also be shared. For example, the \fBtree\fR and \fBhiertable\fR commands may access the same tree data object. Each client grabs a token associated with the tree. When all tokens are released the tree data object is automatically destroyed. .TP 2.0i \fBBlt_TreeCreate\fR Create a tree data object and optionally obtains a token associated with it. .TP \fBBlt_TreeExists\fR Indicates if a tree by a given name exists. .TP \fBBlt_TreeGetToken\fR Obtains a token for an existing tree data object. .TP \fBBlt_TreeReleaseToken\fR Releases a token for a tree data object. The tree object is deleted when all outstanding tokens have been released. .TP \fBBlt_TreeName\fR Returns the name of the tree object. .TP \fBBlt_TreeChangeRoot\fR Specifies a node as the new root to a tree. .SH TREENODE ROUTINES Tree objects initially contain only a root node. You can add or delete nodes with the following routines. .TP 2i \fBBlt_TreeCreateNode\fR Creates a new child node for a given parent in the tree. .TP \fBBlt_TreeDeleteNode\fR Deletes a node and its children. .TP \fBBlt_TreeNodeId\fR Returns the unique node identifier for a node. .TP \fBBlt_TreeGetNode\fR Gets a node based upon its identifier. .TP \fBBlt_TreeFindChild\fR Searches for a child node given by its label in a parent node. .TP \fBBlt_TreeNodeLabel\fR Returns the current label for a node. .TP \fBBlt_TreeRelabelNode\fR Resets a node's label. .TP \fBBlt_TreeNodePath\fR Returns the fullpath to a node. .TP \fBBlt_TreeNodeDepth\fR Returns the depth of the node. .TP \fBBlt_TreeNodeDegree\fR Returns the number of children for a node. .TP \fBBlt_TreeIsLeaf\fR Indicates if a node has no children. .TP \fBBlt_TreeIsBefore\fR Indicates if a node is before another node in depth-first search order. .TP \fBBlt_TreeIsAncestor\fR Indicates if a node is an ancestor or another. .TP \fBBlt_TreeSortNode\fR Sorts the children of a node. .TP \fBBlt_TreeSize\fR Returns the number of nodes in a node and its descendants. .TP \fBBlt_TreeMoveNode\fR .SH NODE NAVIGATION Each node can have zero or more children nodes. These routines let you navigate the tree hierarchy. .TP 2i \fBBlt_TreeNodeParent\fR Returns the parent node. .TP \fBBlt_TreeFirstChild\fR Returns the first child of a parent node. .TP \fBBlt_TreeLastChild\fR Returns the last child of a parent node. .TP \fBBlt_TreeNextSibling\fR Returns the next sibling node in the parent's list of children. .TP \fBBlt_TreePrevSibling\fR Returns the previous sibling node in the parent's list of children. .TP \fBBlt_TreeRootNode\fR Returns the root node of the tree. .TP \fBBlt_TreeNextNode\fR Returns the next node in depth-first order. .TP \fBBlt_TreePrevNode\fR Returns the previous node in depth-first order. .TP \fBBlt_TreeEndNode\fR Returns the last node in the tree as determined by depth-first order. .TP \fBBlt_TreeApply\fR Walks through a node and all it descendants, applying a given callback procedure. .TP \fBBlt_TreeApplyDFS\fR Walks through a node and all it descendants in depth-first search order, applying a given callback procedure. .TP \fBBlt_TreeApplyBFS\fR Walks through a node and all it descendants in breadth-first search order, applying a given callback procedure. .SH NODE DATA VALUES Data values can be stored at any node. Values have by both a string key and a Tcl_Obj value. Data value keys do not have to be homogenous across all nodes (i.e. nodes do not have to contain the same keys). There is also a special node array data type. .TP 2i \fBBlt_TreeGetValue\fR Gets the node data value given by a key. .TP \fBBlt_TreeValueExists\fR Indicates if a node data value given by a key exists. .TP \fBBlt_TreeSetValue\fR Sets a node's value of a key. .TP \fBBlt_TreeUnsetValue\fR Remove the node data value and key. .TP \fBBlt_TreeGetArrayValue\fR Gets the node data array value given by a key and an array index. .TP \fBBlt_TreeSetArrayValue\fR Sets the node data array value given by a key and an array index. .TP \fBBlt_TreeUnsetArrayValue\fR Remove the node data array value. .TP \fBBlt_TreeArrayValueExists\fR Determines if an array element by a given index exists. .TP \fBBlt_TreeFirstKey\fR Returns the key of the first value in the node. .TP \fBBlt_TreeNextKey\fR Returns the key of the next value in the node. .TP \fBBlt_TreePrivateValue\fR Lock the value to current client, making it private. .TP \fBBlt_TreePublicValue\fR Unlock the value so that all clients can access it. .TP \fBBlt_TreeGetKey\fR .SH NODE TRACES .TP 2i \fBBlt_TreeCreateTrace\fR Sets up a trace callback to be invoked when the node value is read, set, or unset. .TP \fBBlt_TreeDeleteTrace\fR Deletes an existing trace. .SH NODE EVENTS .TP 2i \fBBlt_TreeCreateEventHandler\fR Sets up a callback to be invoked when events (create, delete, relabel, etc) take place on a node. .TP \fBBlt_TreeDeleteEventHandler\fR Deletes an existing node callback. .SH KEYWORDS alloc, allocation, free, malloc, memory, realloc blt-2.4z.orig/man/Blt_TreeCreate.man30100644000175000017500000000762207240160103016123 0ustar dokodoko'\" '\" 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. '\" '\" .so man.macros .TH Blt_TreeCreate 3 BLT_VERSION BLT "BLT Library Procedures" .BS .SH NAME Blt_TreeCreate \- Create tree data object. .SH SYNOPSIS .nf \fB#include \fR .sp int \fBBlt_TreeCreate\fR(\fIinterp\fR, \fIname\fR, \fItokenPtr\fR) .SH ARGUMENTS .AS Tcl_Interp *interp .AP Tcl_Interp *interp in Interpreter to report results back to. .AP "const char" *name in Name of the new tree. Can be qualified by a namespace. .AP Blt_Tree *tokenPtr out If not NULL, points to location to store the client tree token. .BE .SH DESCRIPTION .PP This procedure creates a C-based tree data object and optionally returns a token to it. The arguments are as follows: .TP 1i \fIinterp\fR Interpreter to report results back to. If an error occurs, then interp->result will contain an error message. .TP 1i \fIname\fR Name of the new tree object. You can think of \fIname\fR as the memory address of the object. It's a unique name that identifies the tree object. No tree object \fIname\fR can already exist. \fIName\fR can be qualified by a namespace such as \f(CWfred::myTree\fR. If no namespace qualifier is used, the tree will be created in the current namespace, not the global namespace. If a qualifier is present, the namespace must already exist. .TP 1i \fItokenPtr\fR Holds the returned token. \fITokenPtr\fR points to a location where it is stored. Tree tokens are used to work with the tree object. If NULL, no token is allocated. You can later use \fBTcl_TreeGetToken\fR to obtain a token. .PP The new tree data object created will initially contain only a root node. You can add new nodes with \fBBlt_TreeCreateNode\fR. .PP Optionally a token for the tree data object is returned. Tree data objects can be shared. For example, the \fBtree\fR and \fBhiertable\fR commands may be accessing the same tree data object. Each client grabs a token that is associated with the tree. When all tokens are released (see \fBBlt_TreeReleaseToken\fR) the tree data object is automatically destroyed. .PP .SH RETURNS A standard Tcl result is returned. If TCL_ERROR is returned, then \fIinterp->result\fR will contain an error message. The following errors may occur: .IP \(bu 3 There already exists a tree by the same name as \fIname\fR. You can use \fBTcl_TreeExists\fR to determine if a tree exists beforehand. .IP \(bu The tree name is prefixed by a namespace that doesn't exist. If you qualified the tree name with a namespace, the namespace must exist. Unlike Tcl procs and variables, the namespace is not automatically created for you. .IP \(bu Memory can't be allocated for the tree or token. .SH EXAMPLE The following example creates a new .CS Blt_Tree token; if (Blt_TreeCreate(interp, "myTree", &token) != TCL_OK) { return TCL_ERROR; } printf("tree is %s\\n", Blt_TreeName(token)); .CE .SH KEYWORDS Tcl_TreeGetToken, Tcl_TreeExists, Tcl_TreeReleaseToken blt-2.4z.orig/man/Blt_TreeCreateNode.man30100644000175000017500000000703007240160103016722 0ustar dokodoko'\" '\" 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. '\" '\" .so man.macros .TH Blt_TreeCreateNode 3 BLT_VERSION BLT "BLT Library Procedures" .BS .SH NAME Blt_TreeCreateNode \- Creates a node in a tree data object. .SH SYNOPSIS .nf #include .sp Blt_TreeNode \fBBlt_TreeCreateNode\fR(\fItree\fR, \fIparent\fR, \fIname\fR, \fIposition\fR) .SH ARGUMENTS .AS Blt_TreeNode parent .AP Blt_Tree tree in Tree containing the parent node. .AP Blt_TreeNode parent in Node in which to insert the new child. .AP "const char" *name in Node label. If NULL, a label will automatically be generated. .AP int position in Position in the parent's list of children to insert the new node. .BE .SH DESCRIPTION .PP This procedure creates a new node is a tree data object. The node is initially empty, but data values can be added with \fBBlt_TreeSetValue\fR. Each node has a serial number that identifies it within the tree. No two nodes in the same tree will ever have the same ID. You can find a node's ID with \fBBlt_TreeNodeId\fR. .PP The arguments are as follows: .TP 1i \fItree\fR The tree containing the parent node. .TP \fIparent\fR Node in which the new child will be inserted. .TP \fIname\fR Label of the new node. If \fIname\fR is NULL, a label in the form "\f(CWnode0\fR", "\f(CWnode1\fR", etc. will automatically be generated. \fIName\fR can be any string. Labels are non-unique. A parent can contain two nodes with the same label. Nodes can be relabeled using \fBBlt_TreeRelabelNode\fR. .TP \fIposition\fR Position the parent's list of children to insert the new node. For example, if \fIposition\fR is 0, then the new node is prepended to the beginning of the list. If \fIposition\fR is -1, then the node is appended onto the end of the parent's list. .PP .SH RETURNS The new node returned is of type \fBBlt_TreeNode\fR. It's a token that can be used with other routines to add/delete data values or children nodes. .SH EXAMPLE The following example creates a new node from the root node. .CS Blt_Tree token; Blt_TreeNode root, node; if (Blt_TreeGetToken(interp, "myTree", &token) != TCL_OK) { return TCL_ERROR; } root = Blt_TreeRootNode(token); node = Blt_TreeCreateNode(token, root, "myNode", -1); .CE .SH NOTIFICATIONS \fBBlt_TreeCreateNode\fR can trigger tree notify events. You can be notified whenever a node is created by using the \fBBlt_TreeCreateNotifyHandler\fR. A callback routine is registered that will be automatically invoked whenever a new node is added via \fBBlt_TreeCreateNode\fR to the tree. .SH KEYWORDS tree, token blt-2.4z.orig/man/Blt_TreeDeleteNode.man30100644000175000017500000000526007240160103016724 0ustar dokodoko'\" '\" 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. '\" '\" .so man.macros .TH Blt_TreeDeleteNode 3 BLT_VERSION BLT "BLT Library Procedures" .BS .SH NAME Blt_TreeDeleteNode \- Deletes a node and its descendants. .SH SYNOPSIS .nf #include .sp Blt_TreeNode \fBBlt_TreeDeleteNode\fR(\fItree\fR, \fInode\fR) .SH ARGUMENTS .AS Blt_TreeNode node .AP Blt_Tree tree in Tree containing the node. .AP Blt_TreeNode node in Node to be deleted. .BE .SH DESCRIPTION This procedure deletes a given node and all it descendants from a tree data object. .PP The arguments are as follows: .TP 1i \fItree\fR The tree containing the parent node. .TP \fInode\fR Node to be deleted. The node and its descendant nodes are deleted. Each node's data values are deleted also. The reference count of the Tcl_Obj is decremented. .PP Since all tree objects must contain at least a root node, the root node itself can't be deleted unless the tree is released and destroyed. Therefore you can clear a tree by deleting its root, but the root node will remain until the tree is destroyed. .SH RETURNS Always returns TCL_OK. Errors generated in a notification callbacks are backgrounded (see \fBTcl_TreeCreateNotifyHandler\fR). .SH EXAMPLE The following example deletes the root node. .CS Blt_TreeNode root; root = Blt_TreeRootNode(token); Blt_TreeDeleteNode(token, root); .CE .SH NOTIFICATIONS \fBBlt_TreeDeleteNode\fR can trigger tree notify events. You can be notified whenever a node is deleted by using the \fBBlt_TreeCreateNotifyHandler\fR. A callback routine is registered that will be automatically invoked whenever a node is deleted via \fBBlt_TreeDeleteNode\fR to the tree. .SH KEYWORDS tree, token blt-2.4z.orig/man/Blt_TreeExists.man30100644000175000017500000000443307240160103016174 0ustar dokodoko'\" '\" 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. '\" '\" .so man.macros .TH Blt_TreeExists 3 BLT_VERSION BLT "BLT Library Procedures" .BS .SH NAME Blt_TreeExists \- Indicates if a tree exists. .SH SYNOPSIS .nf \fB#include \fR .sp int \fBBlt_TreeExists\fR(\fIinterp\fR, \fIname\fR) .SH ARGUMENTS .AS Tcl_Interp *interp .AP Tcl_Interp *interp in Interpreter to determine current namespace context. .AP "const char" *name in Name of an existing tree data object. Can be qualified by a namespace. .BE .SH DESCRIPTION .PP This procedure determines if a C-based tree data object exists by a given name. The arguments are as follows: .TP 1i interp Used the determine the current namespace context. .TP 1i name Name of an existing tree data object. \fIName\fR can be qualified by a namespace such as \f(CWfred::myTree\fR. If no namespace qualifier is used, the current namespace is searched, then the global namespace. .PP .SH RETURNS A boolean result is returned. If the tree exists 1 is returned, 0 otherwise. .SH EXAMPLE The following example checks if a tree "myTree" exists. .CS .ft CW if (!Blt_TreeExists(interp, "myTree")) { fprintf(stderr, "can't find tree \\"myTree\\\\n"); } .ft R .CE .SH KEYWORDS tree, token Tcl_TreeCreate, Tcl_TreeGetToken, Tcl_TreeReleaseTokenblt-2.4z.orig/man/Blt_TreeGetNode.man30100644000175000017500000000444607240160103016246 0ustar dokodoko'\" '\" 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. '\" '\" .so man.macros .TH Blt_TreeGetNode 3 BLT_VERSION BLT "BLT Library Procedures" .BS .SH NAME Blt_TreeGetNode \- Finds the node from the ID. .SH SYNOPSIS .nf \fB#include \fR .sp Blt_TreeNode \fBBlt_TreeGetNode\fR(\fItree\fR, \fInumber\fR) .SH ARGUMENTS .AS "unsigned int" number .AP Blt_Tree tree in Tree containing the requested node. .AP "unsigned int" number in Serial number of the requested node. .BE .SH DESCRIPTION This procedure returns a node in a tree object based upon a give serial number. The node is searched using the serial number. .PP The arguments are as follows: .TP 1i \fItree\fR The tree containing the requested node. .TP 1i \fInumber\fR The serial number of the requested node. .SH RETURNS The node represented by the given serial number is returned. If no node with that ID exists in \fItree\fR then NULL is returned. .SH EXAMPLE The following example gets the node from a serial number. .CS unsigned int number; Blt_TreeNode node; Blt_TreeToken token; ... node = Blt_TreeGetNode(token, number); if (node == NULL) { printf("no node with ID %d exists\\n", number); } else { printf("node found: label is %s\\n", Blt_TreeNodeLabel(node)); } .CE .SH KEYWORDS Tcl_TreeCreateNode, Tcl_TreeDeleteNode blt-2.4z.orig/man/Blt_TreeGetToken.man30100644000175000017500000000641107240160103016433 0ustar dokodoko'\" '\" 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. '\" '\" .so man.macros .TH Blt_TreeGetToken 3 BLT_VERSION BLT "BLT Library Procedures" .BS .SH NAME Blt_TreeGetToken \- Grabs a token associated with existing tree data object. .SH SYNOPSIS .nf \fB#include \fR .sp int \fBBlt_TreeGetToken\fR(\fIinterp\fR, \fIname\fR, \fItokenPtr\fR) .SH ARGUMENTS .AS Tcl_Interp *interp .AP Tcl_Interp *interp in Interpreter to report results back to. .AP "const char" *name in Name of an existing tree data object. Can be qualified by a namespace. .AP Blt_Tree *tokenPtr out Points to location to store the client tree token. .BE .SH DESCRIPTION .PP This procedure obtains a token to a C-based tree data object. The arguments are as follows: .TP 1i \fIinterp\fR Interpreter to report results back to. If an error occurs, then interp->result will contain an error message. .TP 1i \fIname\fR Name of an existing tree data object. It's an error if a tree \fIname\fR doesn't already exist. \fIName\fR can be qualified by a namespace such as \f(CWfred::myTree\fR. If no namespace qualifier is used, the tree the current namespace is searched, then the global namespace. .TP 1i \fItokenPtr\fR Points to the location where the returned token is stored. A tree token is used to work with the tree object. .PP A token for the tree data object is returned. Tree data objects can be shared. For example, the \fBtree\fR and \fBhiertable\fR commands may be accessing the same tree data object. Each client grabs a token that is associated with the tree. When all tokens are released (see \fBBlt_TreeReleaseToken\fR) the tree data object is automatically destroyed. .PP .SH RETURNS A standard Tcl result is returned. If TCL_ERROR is returned, then \fIinterp->result\fR will contain an error message. The following errors may occur: .IP \(bu 3 No tree exists as \fIname\fR. You can use \fBTcl_TreeExists\fR to determine if a tree exists beforehand. .IP \(bu Memory can't be allocated for the token. .SH EXAMPLE The following example allocated a token for an existing tree. .CS Blt_Tree token; if (Blt_TreeGetToken(interp, "myTree", &token) != TCL_OK) { return TCL_ERROR; } printf("tree is %s\\n", Blt_TreeName(token)); .CE .SH SEE ALSO Tcl_TreeCreate, Tcl_TreeExists, Tcl_TreeReleaseToken blt-2.4z.orig/man/Blt_TreeName.man30100644000175000017500000000403307240160103015571 0ustar dokodoko'\" '\" 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. '\" '\" .so man.macros .TH Blt_TreeName 3 BLT_VERSION BLT "BLT Library Procedures" .BS .SH NAME Blt_TreeName \- Returns the name of the tree data object. .SH SYNOPSIS .nf \fB#include \fR .sp char * \fBBlt_TreeName\fR(\fItree\fR) .SH ARGUMENTS .AS Blt_Tree tree .AP Blt_Tree tree in Token for the tree object. .BE .SH DESCRIPTION .PP This procedure returns the name of the C-based tree data object. The arguments are as follows: .TP 1i \fItree\fR Token for the tree object. The token must have been previously obtained via \fBBlt_TreeGetToken\fR or \fBBlt_TreeCreate\fR. .SH RETURNS The name of the tree object is returned. The name will be fully qualified with a namespace context. .SH EXAMPLE The following example prints the name of the new tree. .CS Blt_Tree token; if (Blt_TreeCreate(interp, NULL, &token) != TCL_OK) { return TCL_ERROR; } printf("tree is %s\\n", Blt_TreeName(token)); .CE .SH KEYWORDS Tcl_TreeGetToken, Tcl_TreeExists, Tcl_TreeReleaseToken blt-2.4z.orig/man/Blt_TreeNodeId.man30100644000175000017500000000426507240160103016062 0ustar dokodoko'\" '\" 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. '\" '\" .so man.macros .TH Blt_TreeNodeId 3 BLT_VERSION BLT "BLT Library Procedures" .BS .SH NAME Blt_TreeNodeId \- Returns the node serial number. .SH SYNOPSIS .nf \fB#include \fR .sp unsigned int \fBBlt_TreeNodeId\fR(\fInode\fR) .SH ARGUMENTS .AS Blt_TreeNode node .AP Blt_TreeNode node in Node whose ID is to be returned. .BE .SH DESCRIPTION This procedure returns the node serial number. The node serial number is useful for programs that export the tree data object to the Tcl programming level. Since node labels (and therefore pathnames) are not unique, the ID can be used to uniquely identify a node. .PP The arguments are as follows: .TP 1i \fInode\fR The node whose serial number is returned. The serial number of the root node for example is always 0. .SH RETURNS The serial number of the node. Nodes are given a unique serial number when they are created. You can use the ID to later retrieve the node using \fBBlt_TreeGetNode\fR. .SH EXAMPLE The following example prints the ID of a node. .CS printf("root ID is %s\\n", Blt_TreeNodeId(node)); .CE .SH KEYWORDS Tcl_TreeCreateNode, Tcl_TreeDeleteNode blt-2.4z.orig/man/Blt_TreeReleaseToken.man30100644000175000017500000000423607240160103017277 0ustar dokodoko'\" '\" 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. '\" '\" .so man.macros .TH Blt_TreeReleaseToken 3 BLT_VERSION BLT "BLT Library Procedures" .BS .SH NAME Blt_TreeReleaseToken \- Releases token associated with tree object. .SH SYNOPSIS .nf \fB#include \fR .sp int \fBBlt_TreeReleaseToken\fR(\fItoken\fR) .SH ARGUMENTS .AS Blt_Tree token .AP Blt_Tree *token in Token of tree to be released. .BE .SH DESCRIPTION .PP This procedure releases the token associated with a C-based tree data object. When all outstanding tokens for a tree data object have been released, then the data object itself will be freed. The arguments are as follows: .TP 1i token Token of the tree data object to be released. This token was initialized either by \fBTcl_TreeGetToken\fI or \fIBlt_TreeCreate\fR earlier. .SH RETURNS Nothing. .SH EXAMPLE The following example creates and then releases a new token. .CS Blt_Tree token; if (Blt_TreeCreate(interp, "myTree", &token) != TCL_OK) { return TCL_ERROR; } printf("tree is %s\\n", Blt_TreeName(token)); /* Tree will be destroyed when the token is released. */ Blt_TreeReleaseToken(token); .CE .SH KEYWORDS tree, token blt-2.4z.orig/man/Makefile.in0100644000175000017500000000362107434314102014564 0ustar dokodoko# ------------------------------------------------------------------------ # Makefile for manual page files # ------------------------------------------------------------------------ prefix = @prefix@ mandir = @mandir@ sectiondir = $(mandir)/mann srcdir = @srcdir@ version = @BLT_VERSION@ instdirs = $(mandir) $(mandir)/mann $(mandir)/man3 MAN_N = BLT.n barchart.n beep.n bgexec.n bitmap.n \ bltdebug.n busy.n container.n cutbuffer.n \ dragdrop.n eps.n graph.n hierbox.n \ hiertable.n htext.n spline.n stripchart.n \ table.n tabset.n tile.n tree.n treeview.n vector.n \ watch.n winop.n MAN_3 = Blt_Tree.3 Blt_TreeGetNode.3 \ Blt_TreeCreate.3 Blt_TreeGetToken.3 \ Blt_TreeCreateNode.3 Blt_TreeName.3 \ Blt_TreeDeleteNode.3 Blt_TreeNodeId.3 \ Blt_TreeExists.3 Blt_TreeReleaseToken.3 MANPAGES = $(MAN_N) $(MAN_3) INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_ROOT = SHELL = /bin/sh RM = rm -rf VPATH = $(srcdir) all: man.macros $(MANPAGES) install: mkdirs install-mann install-man3 install-mann: $(MAN_N) for i in *.n ; do \ $(INSTALL_DATA) $$i $(INSTALL_ROOT)$(mandir)/mann; \ done install-man3: $(MAN_3) for i in *.3 ; do \ $(INSTALL_DATA) $$i $(INSTALL_ROOT)$(mandir)/man3; \ done mkdirs: @for i in $(instdirs) ; do \ if test -d $(INSTALL_ROOT)$$i ; then \ : ; \ else \ echo " mkdir $(INSTALL_ROOT)$$i" ; \ mkdir $(INSTALL_ROOT)$$i ; \ fi ; \ done .SUFFIXES: .n .mann .3 .man3 .man3.3: $(srcdir)/man.macros $(RM) $@ sed -e "/man\.macros/r $(srcdir)/man.macros" -e '/man\.macros/d' -e 's/BLT_VERSION/$(version)/' $< > $@ .mann.n: $(srcdir)/man.macros $(RM) $@ sed -e "/man\.macros/r $(srcdir)/man.macros" -e '/man\.macros/d' -e 's/BLT_VERSION/$(version)/' $< > $@ clean: $(RM) *.3 *.n distclean: clean $(RM) $(srcdir)/*.bak $(srcdir)/*\~ $(srcdir)/"#"* Makefile blt-2.4z.orig/man/barchart.mann0100644000175000017500000027320107435034423015171 0ustar dokodoko'\" '\" 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. '\" .so man.macros .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 displayed. If no elements are specified, then all displayed elements are searched. It returns a 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\-fdashes\R 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 blt-2.4z.orig/man/beep.mann0100644000175000017500000000336707240160103014307 0ustar dokodoko'\" '\" 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. '\" .so man.macros .TH beep n BLT_VERSION BLT "BLT Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME beep \- ring the bell .SH SYNOPSIS \fBbeep\fR ?\fIpercent\fR? .BE .SH DESCRIPTION The \fBbeep\fR command rings the keyboard bell. \fIPercent\fR is relative to the base volume of the keyboard bell and can range from -100 to 100 inclusive. .PP If \fIpercent\fR is nonnegative then the bell volume is: .CS base - [(base * \fIpercent\fR) / 100] + \fIpercent\fR .CE If \fIpercent\fR is negative then the bell volume is: .CS C base + [(base * \fIpercent\fR) / 100] .CE The default \fIpercent\fR is 50. .SH EXAMPLE .CS beep .CE .SH KEYWORDS bell, beep blt-2.4z.orig/man/bgexec.mann0100644000175000017500000003151307371150016014632 0ustar dokodoko'\" '\" 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. '\" '\" Bgexec command created by George Howlett. '\" .so man.macros .TH bgexec n BLT_VERSION BLT "BLT Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME bgexec \- Run programs in the background while handling Tk events. .SH SYNOPSIS \fBblt::bgexec \fIvarName\fR ?\fIoption value\fR?... \fIprogram\fR ?\fIarg\fR?... .BE .SH DESCRIPTION .PP The \fBbgexec\fR command executes programs in the background, allowing Tk to handle events. A global Tcl variable \fIvarName\fR is set when the program has completed. .SH INTRODUCTION Tcl's \fBexec\fR command is very useful for gathering information from the operating system. It runs a program and returns the output as its result. This works well for Tcl-only applications. But for Tk applications, a problem occurs when the program takes time to process. Let's say we want the get the disk usage of a directory. We'll use the Unix program \f(CWdu\fR to get the summary. .CS set out [exec du -s $dir] puts "Disk usage for $dir is $out" .CE While \f(CWdu\fR is running, scrollbars won't respond. None of the Tk widgets will be redrawn properly. The \fBsend\fR command won't work. And the worst part is that the application appears hung up or dead. The problem is that while \fBexec\fR is waiting for \fIdu\fR to finish, Tk is not able to handle X events. .PP The \fBbgexec\fR command performs the same functions as \fBexec\fR, but also allows Tk to handle events. You can execute a long-running program and the Tk widgets will behave normally. When the program finishes, its output and the exit status are written to Tcl variables. This makes it easy to monitor and save the output of a program. .SH EXAMPLE Here is the disk usage example again, this time using \fBbgexec\fR. The syntax to invoke "du" is exactly the same as the previous example, when we used \fBexec\fR. .CS global myStatus myOutput blt::bgexec myStatus -output myOutput du -s $dir puts "Disk usage for $dir is $myOutput" .CE Two global variables, \f(CWmyStatus\fR and \f(CWmyOutput\fR, will be set by \fBbgexec\fR when \f(CWdu\fR has completed. \f(CWMyStatus\fR will contain the program's exit status. \f(CWMyOutput\fR, specified by the \fB\-output\fR option, will store the output of the program. .PP You can also terminate the program by setting the variable \f(CWmyStatus\fR. If \f(CWmyStatus\fR is set before \f(CWdu\fR has completed, the process is killed. Under Unix, this is done sending by a configurable signal (by default it's SIGKILL). Under Win32, this is done by calling \fBTerminateProcess\fR. It makes no difference what \f(CWmyStatus\fR is set to. .CS set myStatus {} .CE There are several \fBbgexec\fR options to collect different types of information. .CS global myStatus myOutput myErrs blt::bgexec myStatus -output myOutput -error myErrs du -s $dir .CE The \fB\-error\fR option is similar to \fB\-output\fR. It sets a global variable when the program completes. The variable will contain any data written to stderr by the program. .PP The \fB\-output\fR and \fB\-error\fR variables are set only after the program completes. But if the program takes a long time, to run you may want to receive its partial output. You can gather data as it becomes available using the \fB\-onoutput\fR option. It specifies a Tcl command prefix. Whenever new data is available, this command is executed, with the data appended as an argument to the command. .CS proc GetInfo { data } { puts $data } blt::bgexec myStatus -onoutput GetInfo du -s $dir .CE When output is available, the procedure \f(CWGetInfo\fR is called. The \fB\-onerror\fR option performs a similar function for the stderr data stream. .PP Like \fBexec\fR, \fBbgexec\fR returns an error if the exit code of the program is not zero. If you think you may get a non-zero exit code, you might want to invoke \fBbgexec\fR from within a \fBcatch\fR. .CS catch { blt::bgexec myStatus -output myOutput du -s $dir } .CE By default, \fBbgexec\fR will wait for the program to finish. But you can detach the program making ampersand (&) the last argument on the command line. .CS global myStatus myOutput blt::bgexec myStatus -output myOutput du -s $dir & .CE \fBBgexec\fR will return immediately and its result will be a list of the spawned process ids. If at some point you need to wait for the program to finish up, you can use \fBtkwait\fR. When the program finishes, the variable \f(CWmyStatus\fR will be written to, breaking out the \fBtkwait\fR command. .CS global myStatus myOutput blt::bgexec myStatus -output myOutput du -s $dir & ... tkwait variable myStatus .CE .SH SYNTAX The \fBbgexec\fR command takes the following form: .sp \fB blt::bgexec \fIvarName\fR ?\fIoption value\fR?... \fIprogram\fR ?\fIarg\fR?... .sp \fIVarName\fR is the name of a global variable which is set when \fIprogram\fR has finished executing. The exit status of will be stored in \fIvarName\fR. The exit status is a list of a status token, the process-id of the program, the exit code, and a status message. You can also prematurely terminate the program by setting \fIvarName\fR. Under Unix, the program will be sent a signal to terminate it (by default the signal is a SIGKILL; see the \fB\-killsignal\fR option). .PP \fIProgram\fR is the name of the program to be executed and \fIargs\fR are any extra arguments for \fIprogram\fR. The syntax of \fIprogram\fR and \fIargs\fR is the same as the \fBexec\fR command. So you can redirect I/O, execute pipelines, etc. (see the \fBexec\fR manual for further information) just like \fBexec\fR. If the last argument is an ampersand (&), the program will be run detached, and \fBbgexec\fR will return immediately. \fIVarName\fR will still be set with the return status when \fIprogram\fR completes. .SH OPTIONS \fIOption\fR refers to the switch name always beginning with a dash (\-). \fIValue\fR is the value of the option. Option-value pairs are terminated either by the program name, or double dashes (\-\-). The following options are available for \fBbgexec\fR: .TP \fB\-decodeerror \fIencodingName\fR .br Specifies the encoding of the stderr channel. This affects only data returned to the Tcl interpreter. No translation is done on file redirection. .br For example if data is to be converted from Unicode for use in Tcl, you would use the "unicode" encoding. The default is that no tranlation is performed. .TP \fB\-decodeoutput \fIencodingName\fR .br Specifies the encoding of the stdout channels. This affects only data returned to the Tcl interpreter. No translation is done on file redirection. .br For example if data is to be converted from Unicode for use in Tcl, you would use the "unicode" encoding. The default is that no tranlation is performed. .TP \fB\-error \fIvarName\fR .br Specifies that a global variable \fIvarName\fR is to be set with the contents of stderr after the program has completed. .TP \fB\-keepnewline \fIboolean\fR Specifies that a trailing newline should be retained in the output. If \fIboolean\fR is true, the trailing newline is truncated from the output of the \fB\-onoutput\fR and \fB\-output\fR variables. The default value is \f(CWtrue\fR. .TP \fB\-killsignal \fIsignal\fR Specifies the signal to be sent to the program when terminating. This is available only under Unix. \fISignal\fR can either be a number (typically 1-32) or a mnemonic (such as SIGINT). If \fIsignal\fR is the empty string, then no signal is sent. The default signal is \f(CW9\fR (SIGKILL). .TP \fB\-lasterror \fIvarName\fR Specifies a variable \fIvarName\fR that is updated whenever data becomes available from standard error of the program. \fIVarName\fR is a global variable. Unlike the \fB\-error\fR option, data is available as soon as it arrives. .TP \fB\-lastoutput \fIvarName\fR Specifies a variable \fIvarName\fR that is updated whenever data becomes available from standard output of the program. \fIVarName\fR is a global variable. Unlike the \fB\-output\fR option, data is available as soon as it arrives. .TP \fB\-linebuffered \fIboolean\fR Specifies that updates should be made on a line-by-line basis. Normally when new data is available \fBbgexec\fR will set the variable (\fB\-lastoutput\fR and \fB\-lasterror\fR options) or invoke the command (\fB\-onoutput\fR and \fB\-onerror\fR options) delivering all the new data currently available. If \fIboolean\fR is true, only one line at a time will be delivered. This can be useful when you want to process the output on a line-by-line basis. The default value is \f(CWfalse\fR. .TP \fB\-output \fIvarName\fR .br Specifies that a global variable \fIvarName\fR is to be set with the output of the program, once it has completed. If this option is not set, no output will be accumulated. .TP \fB\-onerror \fIcommand\fR Specifies the start of a Tcl command that will be executed whenever new data is available from standard error. The data is appended to the command as an extra argument before it is executed. .TP \fB\-onoutput \fIcommand\fR Specifies the start of a Tcl command that will be executed whenever new data is available from standard output. The data is appended to the command as an extra argument before it is executed. .TP \fB\-update \fIvarName\fR Deprecated. This option is replaced by \fB\-lasterror\fR. .TP \fB\-\|\-\fR This marks the end of the options. The following argument will be considered the name of a program even if it starts with a dash (\fB\-\fR). .SH PREEMPTION Because \fBbgexec\fR allows Tk to handle events while a program is running, it's possible for an application to preempt itself with further user-interactions. Let's say your application has a button that runs the disk usage example. And while the \f(CWdu\fR program is running, the user accidently presses the button again. A second \fBbgexec\fR program will preempt the first. What this means is that the first program can not finish until the second program has completed. .PP Care must be taken to prevent an application from preempting itself by blocking further user-interactions (such as button clicks). The BLT \fBbusy\fR command is very useful for just these situations. See the \fBbusy\fR manual for details. .SH DIFFERENCES WITH FILEEVENT Since Tk 4.0, a subset of \fBbgexec\fR can be also achieved using the \fBfileevent\fR command. The steps for running a program in the background are: .PP Execute the program with the \fBopen\fR command (using the "|" syntax) and save the file handle. .CS global fileId set fileId [open "|du -s $dir" r] .CE Next register a Tcl code snippet with \fBfileevent\fR to be run whenever output is available on the file handle. The code snippet will read from the file handle and save the output in a variable. .CS fileevent fileId readable { if { [gets $fileId line] < 0 } { close $fileId set output $temp unset fileId temp } else { append temp $line } } .CE .PP The biggest advantage of \fBbgexec\fR is that, unlike \fBfileevent\fR, it requires no additional Tcl code to run a program. It's simpler and less error prone. You don't have to worry about non-blocking I/O. It's handled tranparently for you. .PP \fBBgexec\fR runs programs that \fBfileevent\fR can not. \fBFileevent\fR assumes that the when stdout is closed the program has completed. But some programs, like the Unix \f(CWcompress\fR program, reopen stdout, fooling \fBfileevent\fR into thinking the program has terminated. In the example above, we assume that the program will write and flush its output line-by-line. However running another program, your application may block in the \fBgets\fR command reading a partial line. .PP \fBBgexec\fR lets you get back the exit status of the program. It also allows you to collect data from both stdout and stderr simultaneously. Finally, since data collection is handled in C code, \fBbgexec\fR is faster. You get back to the Tk event loop more quickly, making your application seem more responsive. .SH SEE ALSO busy, exec, tkwait .SH KEYWORDS exec, background, busy blt-2.4z.orig/man/bitmap.mann0100644000175000017500000002062407371343261014660 0ustar dokodoko'\" '\" Copyright 1991-2001 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. '\" '\" Bitmap command created by George Howlett. '\" .so man.macros .TH bitmap n BLT_VERSION BLT "BLT Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME bitmap \- Define a new bitmap from a Tcl script .SH SYNOPSIS \fBbitmap define \fIbitmapName data\fR ?\fIoption value\fR?... .sp \fBbitmap compose \fIbitmapName text\fR ?\fIoption value\fR?... .sp \fBbitmap exists \fIbitmapName\fR .sp \fBbitmap source \fIbitmapName\fR .sp \fBbitmap data \fIbitmapName\fR .sp \fBbitmap height \fIbitmapName\fR .sp \fBbitmap width \fIbitmapName\fR .BE .SH DESCRIPTION The \fBbitmap\fR command lets you create new bitmaps directly from your Tcl script. The bitmap can be specified as a list of data or a text string which is converted into a bitmap. You can arbitrarily scale or rotate the bitmap too. .SH INTRODUCTION Bitmaps are commonly used within Tk. In label and button widgets, you display bitmaps them instead of text strings and in the canvas and text widgets, they're used for stippling. But Tk let's you can create new bitmaps only by reading the bitmap data from a file. This makes bitmaps cumbersome to manage, especially in packaging the program as a \fBwish\fR script, since each bitmap must be its own file. It would be nicer if you could create new bitmaps directly from your Tcl script. .PP The \fBbitmap\fR command lets you do just that. You can specify the bitmap as in various formats (such as the X11 bitmap format). You can also compose a bitmap from a text string. The \fBbitmap\fR command also lets you and arbitrarily rotate or scale the bitmap. For example, you could use this to create button widgets with the text label rotated 90 degrees. .SH EXAMPLE <<<<<<< bitmap.mann You can define a new bitmap with the \fBdefine\fR operation. For example, let's say you are using the X11 bitmap "gray1". Normally to use it, you would specify the location of the file. .CS label .l -bitmap @/usr/X11R6/include/X11/bitmaps/gray1 .CE But you can simply cut and paste the contents of "gray1" into the \fBbitmap\fR command. .CS bitmap define gray1 { #define gray1_width 2 #define gray1_height 2 static char gray1_bits[] = { 0x01, 0x02}; } label .l -bitmap gray1 .CE Tk will recognize "gray1" as a bitmap which can now be used with any widget that accepts bitmaps. .CS .barchart element configure elem1 -stipple gray1 .CE The bitmap data can be specified in a mulitude of forms. The following commands are all equivalent. .CS bitmap define gray1 { #define gray1_width 2 #define gray1_height 2 static char gray1_bits[] = { 0x01, 0x02}; } bitmap define gray1 { { 2 2 } { 0x01, 0x02 } } bitmap define gray1 { { 2 2 } { 0x01 0x02 } } bitmap define gray1 { { 2 2 } { 1 2 } } .CE Either the data is in the standard X11 bitmap form, or it's a list of two lists. The first list contains the height and width of the bitmap. The second list is the bitmap source data. Each element of that list is an hexadecimal number specifying which pixels are foreground (1) and which are background (0) of the bitmap. Note that the format of the source data is exactly that of the XBM format. .P You can scale or rotate the bitmap as you create it, by using the \fB-scale\fR or\fB-rotate\fR options. .CS bitmap define gray1 { #define gray1_width 2 #define gray1_height 2 static char gray1_bits[] = { 0x01, 0x02}; } -scale 2.0 -rotate 90.0 .CE In addition, you can compose bitmaps from text strings. This makes it easy to create rotated buttons or labels. The text string can have multi-line. .CS bitmap compose rot_text "This is rotated\\ntext" \\ -rotate 90.0 -font fixed .CE There are also a number of ways to query bitmaps. This isn't limited to bitmaps that you create, but any bitmap. .CS bitmap exists rot_text bitmap width rot_text bitmap height rot_text bitmap data rot_text bitmap source rot_text .CE The \fBexists\fR operation indicates if a bitmap by that name is defined. You can query the dimensions of the bitmap using the \fBwidth\fR and \fBheight\fR operations. The \fBdata\fR operation returns the list of the data used to create the bitmap. For example, you could query the data of a bitmap and \fBsend\fR it across the network to another Tk application. .CS set data [bitmap data @/usr/X11R6/include/X11/bitmaps/ghost.xbm] send {wish #2} bitmap define ghost $data .CE .SH OPERATIONS The following operations are available for \fBbitmap\fR: .TP \fBbitmap compose \fIbitmapName text \fR?\fIoption value\fR?... Creates a bitmap \fIbitmapName\fR from the text string \fItext\fR. A bitmap \fIbitmapName\fR can not already exist. The following options are available. .RS .TP \fB\-font \fIfontName\fR Specifies a font to use when drawing text into the bitmap. If this option isn't specified then \fIfontName\fR defaults to \f(CW*-Helvetica-Bold-R-Normal-*-140-*\fR. .TP \fB\-rotate \fItheta\fR Specifies the angle of rotation of the text in the bitmap. \fITheta\fR is a real number representing the angle in degrees. It defaults to \f(CW0.0\fR degrees. .TP \fB\-scale \fIvalue\fR Specifies the scale of the bitmap. \fIValue\fR is a real number representing the scale. A scale of 1.0 indicates no scaling is necessary, while 2.0 would double the size of the bitmap. There is no way to specify differents scales for the width and height of the bitmap. The default scale is \f(CW1.0\fR. .RE .TP \fBbitmap data \fIbitmapName\fR Returns a list of both the dimensions of the bitmap \fIbitmapName\fR and its source data. .TP \fBbitmap define \fIbitmapName data\fR \fR?\fIoption value\fR?... Associates \fIbitmapName\fR with in-memory bitmap data so that \fIbitmapName\fR can be used in later calls to \fBTk_GetBitmap\fR. The \fIbitmapName\fR argument is the name of the bitmap; it must not previously have been defined in either a call to Tk_DefineBitmap or \fBbitmap\fR. The argument \fIdata\fP describes the bitmap to be created. It is either the X11 bitmap format (a C structure) or a list of two lists: the dimensions and source data. The dimensions are a list of two numbers which are the width and height of the bitmap. The source data is a list of hexadecimal values in a format similar to the X11 or X10 bitmap format. The values may be optionally separated by commas and do not need to be prefixed with "0x". The following options are available. .RS .TP \fB\-rotate \fItheta\fR Specifies how many degrees to rotate the bitmap. \fITheta\fR is a real number representing the angle. The default is \f(CW0.0\fR degrees. .TP \fB\-scale \fIvalue\fR Specifies how to scale the bitmap. \fIValue\fR is a real number representing the scale. A scale of 1.0 indicates no scaling is necessary, while 2.0 would double the size of the bitmap. There is no way to specify differents scales for the width and height of the bitmap. The default scale is \f(CW1.0\fR. .RE .TP \fBbitmap exists \fIbitmapName\fR Returns \f(CW1\fR if a bitmap \fIbitmapName\fR exists, otherwise \f(CW0\fR. .TP \fBbitmap height \fIbitmapName\fR Returns the height in pixels of the bitmap \fIbitmapName\fR. .TP \fBbitmap source \fIbitmapName\fR Returns the source data of the bitmap \fIbitmapName\fR. The source data is a list of the hexadecimal values. .TP \fBbitmap width \fIbitmapName\fR Returns the width in pixels of the bitmap \fIbitmapName\fR. .SH LIMITATIONS Tk currently offers no way of destroying bitmaps. Once a bitmap is created, it exists until the application terminates. .SH KEYWORDS bitmap blt-2.4z.orig/man/bltdebug.mann0100644000175000017500000000342407240160103015156 0ustar dokodoko'\" '\" 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. '\" .so man.macros .TH bltdebug n BLT_VERSION BLT "BLT Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME bltdebug \- print Tcl commands before execution .SH SYNOPSIS \fBbltdebug\fR ?\fIlevel\fR? .BE .SH DESCRIPTION The \fBbltdebug\fR command is a simple tracing facility for Tcl commands. Each command line is printed before it is executed on standard error. The output consists of the command line both before and after substitutions have occurred. \fILevel\fR indicates at what level to stop tracing commands. If \fIlevel\fR is \f(CW0\fR, no tracing is performed. This is the default. If no \fIlevel\fR argument is given, the current level is printed. .SH KEYWORDS debug blt-2.4z.orig/man/busy.mann0100644000175000017500000002335407240160103014354 0ustar dokodoko'\" '\" 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. '\" '\" Busy command created by George Howlett. '\" .so man.macros .TH busy n BLT_VERSION BLT "BLT Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME busy \- Make Tk widgets busy, temporarily blocking user interactions. .SH SYNOPSIS \fBbusy hold \fIwindow\fR ?\fIoption value\fR?... .sp \fBbusy release \fIwindow\fR ?\fIwindow\fR?... .sp \fBbusy configure \fIwindow\fR ?\fIoption value\fR?... .sp \fBbusy forget \fIwindow\fR ?\fIwindow\fR?... .sp \fBbusy isbusy \fR?\fIpattern\fR? .sp \fBbusy names \fR?\fIpattern\fR? .sp \fBbusy status \fIwindow\fR .BE .SH DESCRIPTION .PP The \fBbusy\fR command provides a simple means to block keyboard, button, and pointer events from Tk widgets, while overriding the widget's cursor with a configurable busy cursor. .SH INTRODUCTION .PP There are many times in applications where you want to temporarily restrict what actions the user can take. For example, an application could have a "run" button that when pressed causes some processing to occur. But while the application is busy processing, you probably don't want the the user to be able to click the "run" button again. You may also want restrict the user from other tasks such as clicking a "print" button. .PP The \fBbusy\fR command lets you make Tk widgets busy. This means that user interactions such as button clicks, moving the mouse, typing at the keyboard, etc. are ignored by the widget. You can set a special cursor (like a watch) that overrides the widget's normal cursor, providing feedback that the application (widget) is temporarily busy. .PP When a widget is made busy, the widget and all of its descendents will ignore events. It's easy to make an entire panel of widgets busy. You can simply make the toplevel widget (such as ".") busy. This is easier and far much more efficient than recursively traversing the widget hierarchy, disabling each widget and re-configuring its cursor. .PP Often, the busy command can be used instead of Tk's \fBgrab\fR command. Unlike \fBgrab\fR which restricts all user interactions to one widget, with the busy command you can have more than one widget active (for example, a "cancel" dialog and a "help" button). .SH EXAMPLE You can make several widgets busy by simply making its ancestor widget busy using the \fBhold\fR operation. .CS frame .top button .top.button; canvas .top.canvas pack .top.button .top.canvas pack .top . . . busy hold .top update .CE All the widgets within \f(CW.top\fR (including \f(CW.top\fR) are now busy. Using \fBupdate\fR insures that \fBbusy\fR command will take effect before any other user events can occur. .PP When the application is no longer busy processing, you can allow user interactions again by the \fBrelease\fR operation. .nf \f(CW busy release .top \fR .fi The busy window has a configurable cursor. You can change the busy cursor using the \fBconfigure\fR operation. .nf \f(CW busy configure .top -cursor "watch"\fR .fi Finally, when you no longer need to the busy window, invoke the \fBforget\fR operation to free any resources it allocated. .nf \f(CW busy forget .top \fR .fi Destroying the widget will also clean up any resources allocated by the busy command. .PP .SH OPERATIONS The following operations are available for the \fBbusy\fR command: .TP \fBbusy hold \fIwindow\fR ?\fIoption value\fR?... Makes the widget \fIwindow\fR (and its descendants in the Tk window hierarchy) busy. \fIWindow\fR must be a valid path name of a Tk widget. The busy window is mapped the next time idle tasks are processed, and the widget and its descendants will be blocked from user interactions. All events in the widget window and its descendants are ignored. Normally \fBupdate\fR should be called immediately afterward to insure that the \fBhold\fR operation is in effect \fIbefore\fR the application starts its processing. The following configuration options are valid: .RS .TP \fB\-cursor \fIcursorName\fR Specifies the cursor to be displayed when the widget is made busy. \fICursorName\fR can be in any form accepted by \fBTk_GetCursor\fR. The default cursor is \f(CWwatch\fR. .RE .TP \fBbusy configure \fIwindow\fR ?\fIoption value\fR?... Queries or modifies the \fBbusy\fR command configuration options for \fIwindow\fR. \fIWindow\fR must be the path name of a widget previously made busy by the \fBhold\fR operation. If no options are specified, a list describing all of the available options for \fIwindow\fR (see \fBTk_ConfigureInfo\fR for information on the format of this list) is returned. If \fIoption\fR is specified with no \fIvalue\fR, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no \fIoption\fR is specified). If one or more \fIoption\-value\fR pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns the empty string. \fIOption\fR may have any of the values accepted by the \fBhold\fR operation. .sp Please note that the option database is referenced through \fIwindow\fR. For example, if the widget \f(CW.frame\fR is to be made busy, the busy cursor can be specified for it by either \fBoption\fR command: .nf \f(CWoption add *frame.busyCursor gumby\fR \f(CWoption add *Frame.BusyCursor gumby\fR .fi .TP \fBbusy forget \fIwindow\fR ?\fIwindow\fR?... Releases resources allocated by the busy command for \fIwindow\fR, including the busy window. User events will again be received again by \fIwindow\fR. Resources are also released when \fIwindow\fR is destroyed. \fIWindow\fR must be the name of a widget specified in the \fBhold\fR operation, otherwise an error is reported. .TP \fBbusy isbusy \fR?\fIpattern\fR? Returns the pathnames of all widgets that are currently busy. If a \fIpattern\fR is given, the path names of busy widgets matching \fIpattern\fR are returned. .TP \fBbusy names \fR?\fIpattern\fR? Returns the pathnames of all widgets that have previously been made busy (i.e. a busy window is allocated and associated with the widget). It makes no difference if the window is currently busy or not. If a \fIpattern\fR is given, the path names of busy widgets matching \fIpattern\fR are returned. .TP \fBbusy release \fIwindow\fR ?\fIwindow\fR?... Restores user interactions to the widget \fIwindow\fR again. This differs from the \fBforget\fR operation in that the busy window is not destroyed, but simply unmapped. \fIWindow\fR must be the name of a widget specified in a \fBhold\fR operation, otherwise an error is reported. .TP \fBbusy status \fIwindow\fR Returns the status of a widget \fIwindow\fR previously made busy. An error is reported if \fIwindow\fR was never made busy, or the \fBforget\fR operation was invoked (i.e. does not currently have a busy window associated with it). If \fIwindow\fR is presently can not receive user interactions, \f(CW1\fR is returned, otherwise \f(CW0\fR. .sp 1 .SH BINDINGS The event blocking feature is implemented by creating and mapping a transparent window that completely covers the widget. When the busy window is mapped, it invisibly shields the widget and its hierarchy from all events that may be sent. Like Tk widgets, busy windows have widget names in the Tk window hierarchy. This means that you can use the \fBbind\fR command, to handle events in the busy window. .CS busy hold .frame.canvas bind .frame.canvas_Busy { ... } .CE .PP Normally the busy window is a sibling of the widget. The name of the busy window is "\fIwidget\f(CW_Busy\fR" where \fIwidget\fR is the name of the widget to be made busy. In the previous example, the pathname of the busy window is "\f(CW.frame.canvas_Busy\fR" The exception is when the widget is a toplevel widget (such as ".") where the busy window can't be made a sibling. The busy window is then a child of the widget named "\fIwidget\f(CW._Busy\fR" where \fIwidget\fR is the name of the toplevel widget. In the following example, the pathname of the busy window is "\f(CW._Busy\fR" .CS busy hold . bind ._Busy { ... } .CE .SH ENTER/LEAVE EVENTS Mapping and unmapping busy windows generates Enter/Leave events for all widgets they cover. Please note this if you are tracking Enter/Leave events in widgets. .SH KEYBOARD EVENTS When a widget is made busy, the widget is prevented from gaining the keyboard focus by the busy window. But if the widget already had focus, it still may received keyboard events. To prevent this, you must move focus to another window. .CS busy hold .frame label .dummy focus .dummy update .CE The above example moves the focus from .frame immediately after invoking the \fBhold\fR so that no keyboard events will be sent to \f(CW.frame\fR or any of its descendants. .SH KEYWORDS busy, keyboard events, pointer events, window, cursor blt-2.4z.orig/man/container.mann0100644000175000017500000003202107240160103015343 0ustar dokodoko'\" '\" Copyright 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. '\" '\" Container widget created by George Howlett. '\" .so man.macros.in .TH container n BLT_VERSION BLT "BLT Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME container \- Widget to contain a foreign window. .BE .SH SYNOPSIS \fBcontainer\fR \fIpathName \fR?\fIoptions\fR? .SH DESCRIPTION The \fBcontainer\fR widget lets you embed an X11 window from a foreign application into your Tk application. The foreign window is reparented inside of the widget. You can then place and arrange the container just as you would any Tk widget. .SH INTRODUCTION Notebooks are a popular graphical paradigm. They allow you to organize many windows in a single widget. For example, you might have an application the displays several X-Y graphs at the same time. Typically, you can't pack the graphs into the same \fBframe\fR because they are too large. The other alternative is to pack the graphs into several \fBtoplevel\fR widgets, allowing them to overlap on the screen. The problem is that all the different toplevel windows clutter the screen and are difficult to manage. .PP The \fBcontainer\fR widget lets organize your application by displaying each graph as a page in a folder of a notebook. Only one page is visible at a time. When you click on a tab, the folder (graph) corresponding to the tab is displayed in the \fBcontainer\fR widget. The container also lets you temporarily tear pages out of the notebook into a separate toplevel widget, and put them back in the container later. For example, you could compare two graphs side-by-side by tearing them out, and then replace them when you are finished. .PP A container may contain an unlimited number of folders. If there are too many tabs to view, you can arrange them as multiple tiers or scroll the tabs. The container uses the conventional Tk scrollbar syntax, so you can attach a scrollbar too. .SH EXAMPLE You create a container widget with the \fBcontainer\fR command. .CS # Create a new container container .c .CE A new Tcl command \f(CW.c\fR is also created. This command can be used to query and modify the container. For example, to change the default borderwidth, you use the new command and the container's \fBconfigure\fR operation. .CS # Change the default font. \&.c configure \-borderwidth 2 .CE You can then add folders using the \fBinsert\fR operation. .CS # Create a new folder "f1" \&.c coinsert 0 "f1" .CE This inserts the new tab named "f1" into the container. The index \f(CW0\fR indicates location to insert the new tab. You can also use the index \f(CWend\fR to append a tab to the end of the container. By default, the text of the tab is the name of the tab. You can change this by configuring the \fB\-text\fR option. .CS # Change the label of "f1" \&.ts tab configure "f1" -label "Tab #1" .CE The \fBinsert\fR operation lets you add one or more folders at a time. .CS \&.ts insert end "f2" -label "Tab #2" "f3" "f4" .CE The tab on each folder contains a label. A label may display both an image and a text string. You can reconfigure the tab's attributes (foreground/background colors, font, rotation, etc) using the \fBtab configure\fR operation. .CS # Add an image to the label of "f1" set image [image create photo -file stopsign.gif] \&.ts tab configure "f1" -image $image \&.ts tab configure "f2" -rotate 90 .CE Each folder may contain an embedded widget to represent its contents. The widget to be embedded must be a child of the container widget. Using the \fB\-window\fR option, you specify the name of widget to be embedded. But don't pack the widget, the container takes care of placing and arranging the widget for you. .CS graph .ts.graph \&.ts tab configure "f1" -window ".ts.graph" \\ -fill both -padx 0.25i -pady 0.25i .CE The size of the folder is determined the sizes of the Tk widgets embedded inside each folder. The folder will be as wide as the widest widget in any folder. The tallest determines the height. You can use the tab's \fB\-pagewidth\fR and \fB\-pageheight\fR options override this. .PP Other options control how the widget appears in the folder. The \fB\-fill\fR option says that you wish to have the widget stretch to fill the available space in the folder. .CS \&.ts tab configure "f1" -fill both -padx 0.25i -pady 0.25i .CE .PP Now when you click the left mouse button on "f1", the graph will be displayed in the folder. It will be automatically hidden when another folder is selected. If you click on the right mouse button, the embedded widget will be moved into a toplevel widget of its own. Clicking again on the right mouse button puts it back into the folder. .PP If you want to share a page between two different folders, the \fB\-command\fR option lets you specify a Tcl command to be invoked whenever the folder is selected. You can reset the \fB\-window\fR option for the tab whenever it's clicked. .CS \&.ts tab configure "f2" -command { \&.ts tab configure "f2" -window ".ts.graph" } \&.ts tab configure "f1" -command { \&.ts tab configure "f1" -window ".ts.graph" } .CE If you have many folders, you may wish to stack tabs in multiple tiers. The container's \fB\-tiers\fR option requests a maximum number of tiers. The default is one tier. .CS \&.ts configure -tiers 2 .CE If the tabs can fit in less tiers, the widget will use that many. Whenever there are more tabs than can be displayed in the maximum number of tiers, the container will automatically let you scroll the tabs. You can even attach a scrollbar to the container. .CS \&.ts configure -scrollcommand { .sbar set } -scrollincrement 20 \&.sbar configure -orient horizontal -command { .ts view } .CE By default tabs are along the top of the container from left to right. But tabs can be placed on any side of the container using the \fB\-side\fR option. .CS # Arrange tabs along the right side of the container. \&.ts configure -side right -rotate 270 .CE .SH SYNTAX The \fBcontainer\fR command creates a new window using the \fIpathName\fR argument and makes it into a container widget. .CS \fBcontainer \fIpathName \fR?\fIoption value\fR?... .CE Additional options may be specified on the command line or in the option database to configure aspects of the container such as its colors, font, text, and relief. The \fBcontainer\fR command returns its \fIpathName\fR argument. At the time this command is invoked, there must not exist a window named \fIpathName\fR, but \fIpathName\fR's parent must exist. .PP When first created, a new container contains no tabs. Tabs are added or deleted using widget operations described below. It is not necessary for all the tabs to be displayed in the container window at once; commands described below may be used to change the view in the window. Containers allow scrolling of tabs using the \fB\-scrollcommand\fR option. They also support scanning (see the \fBscan\fR operation). Tabs may be arranged along any side of the container window using the \fB\-side\fR option. .PP The size of the container window is determined the number of tiers of tabs and the sizes of the Tk widgets embedded inside each folder. The widest widget determines the width of the folder. The tallest determines the height. If no folders contain an embedded widget, the size is detemined solely by the size of the tabs. .PP You can override either dimension with the container's \fB\-width\fR and \fB\-height\fR options. .SH "CONTAINER OPERATIONS" All \fBcontainer\fR operations are invoked by specifying the widget's pathname, the operation, and any arguments that pertain to that operation. The general form is: .sp .CS \fIpathName operation \fR?\fIarg arg ...\fR? .CE .sp \fIOperation\fR and the \fIarg\fRs determine the exact behavior of the command. The following operations are available for container widgets: .TP \fIpathName \fBcget\fR \fIoption\fR Returns the current value of the configuration option given by \fIoption\fR. \fIOption\fR may have any of the values accepted by the \fBconfigure\fR operation described below. .TP \fIpathName \fBconfigure\fR ?\fIoption\fR? ?\fIvalue option value ...\fR? Query or modify the configuration options of the widget. If no \fIoption\fR is specified, returns a list describing all the available options for \fIpathName\fR (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no \fIoption\fR is specified). If one or more \fIoption\-value\fR pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. \fIOption\fR and \fIvalue\fR are described below: .RS .TP \fB\-background \fIcolor\fR Sets the border color of the container. .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 how the border is to be drawn. The default is \f(CW2\fR. .TP \fB\-command \fIpattern\fR Specifies to search for a window whose \f(CWWM_COMMAND\fR property matches the given pattern. If no windows, or more than one window, matches the pattern, an error is generated. If \fIpattern\fR is the empty string, then no command search is performed. The default is \f(CW""\fR. .TP \fB\-cursor \fIcursor\fR Specifies the widget's cursor. The default cursor is \f(CW""\fR. .TP \fB\-height \fIpixels\fR Specifies the requested height of widget. If \fIpixels\fR is 0, then the height is height the embedded window plus the specified borderwidth. The default is \f(CW0\fR. .TP \fB\-highlightbackground \fIcolor\fR Sets the color to display in the traversal highlight region when the container does not have the input focus. .TP \fB\-highlightcolor \fIcolor\fR Sets the color to use for the traversal highlight rectangle that is drawn around the widget when it has the input focus. The default is \f(CWblack\fR. .TP \fB\-highlightthickness \fIpixels\fR Sets the width of the highlight rectangle to draw around the outside of the widget when it has the input focus. \fIPixels\fR is a non-negative value and may have any of the forms acceptable to \fBTk_GetPixels\fR. If the value is zero, no focus highlight is drawn around the widget. The default is \f(CW2\fR. .TP \fB\-name \fIpattern\fR Specifies to search for a window whose \f(CWWM_NAME\fR property matches the given pattern. If no windows, or more than one window, matches the pattern, an error is generated. If \fIpattern\fR is the empty string, then no name search is performed. The default is \f(CW""\fR. .TP \fB\-relief \fIrelief\fR Specifies the 3-D effect for the container widget. \fIRelief\fR specifies how the container should appear relative to widget that it is packed into; for example, \f(CWraised\fR means the container should appear to protrude. The default is \f(CWsunken\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 decide whether to focus on the window. The default is \f(CW1\fR. .TP \fB\-width \fIpixels\fR Specifies the requested width of the widget. If \fIpixels\fR is 0, then the width is the width the embedded window and the specified borderwidth. The default is \f(CW0\fR. .TP \fB\-window \fIid\fR Specifies the foreign embedded using its X window id. .RE .TP \fIpathName \fBfind \fB\-command\fR|\fB\-name\fR \fIpattern\fR Searches for all windows that match the given pattern. If the \fB\-command\fR switch is given, all windows whose \fCWWM_COMMAND\fR property match \fIpattern\fR are returned in a list. If the \fB\-name\fR switch is given, all windows whose \fCWWM_NAME\fR property match \fIpattern\fR are returned in a list. The list returned will contains pairs of the window id and the matching property. .SH KEYWORDS container, widget blt-2.4z.orig/man/cutbuffer.mann0100644000175000017500000000442207240160103015352 0ustar dokodoko'\" '\" 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. '\" .so man.macros .TH cutbuffer n BLT_VERSION BLT "BLT Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME cutbuffer \- Manipulate X cut buffer properties .SH SYNOPSIS \fBcutbuffer\fI get ?number?\fR .br \fBcutbuffer\fI rotate ?count?\fR .br \fBcutbuffer\fI set value ?number?\fR .BE .SH DESCRIPTION .PP The \fBcutbuffer\fR command allows you to read or modify the eight X cut buffer properties. You can also rotate the buffers properties. .SH OPERATIONS The following operations are available for the \fBcutbuffer\fR command: .TP \fBcutbuffer get \fI?number?\fR Returns the value of a cutbuffer \fInumber\fR. \fINumber\fR must be a number between 0 and 7. The default is 0. The cutbuffer is returned exactly, except that NUL bytes are converted to '@' characters. If a cut buffer \fInumber\fR does not exist, then \f(CW""\fR is returned. .TP \fBcutbuffer rotate \fI?count?\fR Rotates the cut buffers by \fIcount\fR. \fICount\fR must be a number between -7 and 7. The default is 1. .TP \fBcutbuffer set \fIvalue\fR ?\fInumber\fR? Sets the cutbuffer \fInumber\fR to \fIvalue\fR. \fINumber\fR must be a number between 0 and 7. The default is 0. .SH KEYWORDS cut buffer, property blt-2.4z.orig/man/dragdrop.mann0100644000175000017500000004273407240160103015177 0ustar dokodoko'\" '\" 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. '\" '\" .so man.macros .TH drag&drop n BLT_VERSION BLT "BLT Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME drag&drop \- facilities for handling drag&drop data transfers .SH SYNOPSIS \fBdrag&drop source .br \fBdrag&drop source \fIwindow \fR?\fIoptions\fR? .br \fBdrag&drop source \fIwindow \fBhandler \fR?\fIdataType\fR? ?\fIcommand arg arg...\fR? .sp \fBdrag&drop target .br \fBdrag&drop target \fIwindow \fBhandler \fR?\fIdataType command arg arg...\fR? .sp \fBdrag&drop target \fIwindow \fBhandle \fIdataType\fR ?\fIvalue\fR? .sp \fBdrag&drop token \fIwindow .sp \fBdrag&drop drag \fIwindow x y .br \fBdrag&drop drop \fIwindow x y .br \fBdrag&drop active .br \fBdrag&drop errors \fR?\fIproc\fR? .br \fBdrag&drop location \fR?\fIx y\fR? .BE .SH DESCRIPTION .PP The \fBdrag&drop\fR command provides access to a set of facilities for managing drag-and-drop data transfers. Any of the usual Tk widgets can be registered to participate in the drag-and-drop process. Widgets registered as a drag&drop \fIsource\fP can export data to other widgets registered as a drag&drop \fItarget\fP. Note that a particular widget can be registered as a source, as a target, or as both. .PP The drag-and-drop process begins when the user clicks and holds a mouse button in a source window; a token window appears with an icon or message to represent the data being transferred. As the user moves the mouse pointer, the token window follows along, acting as a movable packet of data. Whenever the mouse pointer falls on a valid target window, the border of the token window is changed to a raised (active) state. When the mouse button is released over the target window, a Tcl routine is invoked to send the data to the desired application, and the target window is asked to "handle" the data. If this communication process fails, a rejection symbol (a circle with a line through it) is displayed on the token window to indicate failure. .PP The details of the communication process are fully configurable by the application developer. In the simplest case, the value that is sent to the target window is a simple string. The target window is simply asked to "handle" that string value. In general, the source window can have a special "handler" procedure to transfer a particular data type by issuing a series of "send" commands. After this, the target window is again asked to "handle" the result. .PP Both sources and targets can have a list of "handlers" for different data types. As a token window is dragged from its source to various targets, each target is checked to see if it recognizes a handler offered by the source. If it does, it is treated as a valid target. Otherwise, it is ignored. This scheme allows the same source to interact with many different kinds of targets. For example, a source for RGB color samples might have "color" and "string" handlers. This would allow it to communicate with "color" targets (sending RGB data) as well as entry widgets (sending strings of the form "#rrggbb"). .PP This introduction was presented as a brief overview of the communication process; further details are presented below: .TP \fBdrag&drop source\fR Returns a list of path names for widgets registered as drag&drop sources. Returns an empty string if no widgets have been registered. .TP \fBdrag&drop source \fIwindow \fR?\fIoptions\fR? Registers a new drag&drop source window with the given options, or modifies the options for an existing window: .RS .LP .nf Name: \fBbuttonBinding\fR Class: \fBButtonBinding\fR Switch: \fB\-button\fR \fIn\fR .fi .IP Specifies the mouse button (integer 1-5) that will invoke the drag&drop operation on the source window. This causes the following bindings to be added to the widget: .sp .nf .RS \f(CWbind \fIwin\fP {drag&drop drag %W %X %Y} \f(CWbind \fIwin\fP {drag&drop drag %W %X %Y} \f(CWbind \fIwin\fP {drag&drop drop %W %X %Y}\fR .RE .fi .sp The default value is button 3. If the value "0" is specified, then no bindings are added; this enables the user to establish bindings manually. .LP .nf Name: \fBpackageCommand\fR Class: \fBCommand\fR Switch: \fB\-packagecmd \fIcommand\fR .fi .IP Specifies a Tcl command used to establish the appearance of the token window at the start of each drag&drop operation. This command is automatically invoked by the \fBdrag&drop drag\fP command whenever the token window is about to be mapped for a drag operation. It should update the appearance of the token window to represent the data that is being moved. .PP The following substitutions are made in the \fIcommand\fR string before it is executed: .RS .TP \fB%t\fR Replaced with the window path name for the token which represents the data being dragged. .TP \fB%W\fR Replaced with the window path name for the drag&drop source. .RE .LP The return value from the package command represents the data being transferred. If the package command returns an empty string, the drag operation is quietly aborted. This can be used to disallow drag&drop operations from certain parts of a widget, if the drag position is inappropriate. .LP For example, the following package routine will select an item from a listbox and configure the token window to display the selected string. It uses the \fBdrag&drop location\fR command to determine the entry in the listbox that the user has selected and it returns this as the data value: .sp .nf .RS \f(CWproc package_list_item {lbox token} { set xy [drag&drop location] set y [expr [lindex $xy 1]-[winfo rooty $lbox]] set str [$lbox get [$lbox nearest $y]] $token.value configure -text $str return $str }\fR .RE .fi .sp The return value is available later when the source and target communicate. If the source has a command associated with its data handler, then this value is substituted in place of "%v" in the source handler. Otherwise, it is substituted in place of "%v" in the target handler. .LP .nf Name: \fBrejectBackground\fR Class: \fBBackground\fR Switch: \fB\-rejectbg \fIcolor\fR .fi .IP Specifies the color used to draw the background of the rejection symbol on the token window. The rejection symbol (a circle with a line through it--the international "no") appears whenever communication fails. .LP .nf Name: \fBrejectForeground\fR Class: \fBForeground\fR Switch: \fB\-rejectfg \fIcolor\fR .fi .IP Specifies the color used to draw the foreground of the rejection symbol on the token window. .LP .nf Name: \fBrejectStipple\fR Class: \fBStipple\fR Switch: \fB\-rejectstipple \fIpattern\fR .fi .IP Specifies a stipple pattern used to draw the foreground of the rejection symbol on the token window. Any of the forms acceptable to Tk_GetBitmap can be used. .LP .nf Name: \fBselfTarget\fR Class: \fBSelfTarget\fR Switch: \fB\-selftarget \fIboolean\fR .fi .IP If the \fIboolean\fR value is true, and if a source widget is also registered as a compatible target, then the source will be able to transmit to itself during drag&drop operations. This is primarily useful for complex sources such as a canvas widget, where items may be moved from place to place within the same widget. By default, this option is disabled. .LP .nf Name: \fBsend\fR Class: \fBSend\fR Switch: \fB\-send \fIlist\fR .fi .IP Specifies a \fIlist\fR of \fIdataTypes\fR enabled for communication. Only \fIdataTypes\fR defined by commands of the form "\fBdrag&drop source \fIwindow \fBhandler \fR?\fIdataType\fR ?\fIcommand arg arg...\fR?" are allowed. This list also determines the priority of the various \fIdataTypes\fR. When a token window is over a potential drag&drop target, this list is searched from start to finish for a \fIdataType\fR that is also recognized by the target. The first matching \fIdataType\fR found determines the value that will be sent if the token is dropped. If no matching \fIdataType\fR is found, then the target is incompatible, and is ignored. By default, this option has the value "all", indicating that all \fIdataTypes\fR should be considered in the order that they were defined for the source. .LP Note that this option makes it easy to control a drag&drop source. Setting the value to an empty string disables the source; setting the value back to "all" restores communication. .LP .nf Name: \fBsiteCommand\fR Class: \fBCommand\fR Switch: \fB\-sitecmd \fIcommand\fR .fi .IP Specifies a Tcl command used to update the appearance of the token window. If specified, this command is automatically invoked by the \fBdrag&drop drag\fP command whenever the token window is over a compatible drag&drop target. .PP The following substitutions are made in the \fIcommand\fR string before it is executed: .RS .TP \fB%s\fR Replaced with "1" if the token window is over a compatible target, and "0" otherwise. .TP \fB%t\fR Replaced with the window path name for the token which represents the data being dragged. .RE .LP Regardless of this command, border of the token window will become raised whenever the token is over a valid target. This command can be used to display other visual cues. .LP .nf Name: \fBtokenAnchor\fR Class: \fBAnchor\fR Switch: \fB\-tokenanchor \fIanchor\fR .fi .IP Specifies how the token window is positioned relative to the mouse pointer coordinates passed to the \fBdrag&drop drag\fP command. Must be one of the values n, s, e, w, center, nw, ne, sw or se. For example, "nw" means to position the token such that its upper-left corner is at the mouse pointer. The default value is "center". .LP .nf Name: \fBtokenBackground\fR Class: \fBBackground\fR Switch: \fB\-tokenbg \fIcolor\fR .fi .IP Specifies the color used to draw the background of the token window. .LP .nf Name: \fBtokenBorderWidth\fR Class: \fBBorderWidth\fR Switch: \fB\-tokenborderwidth \fIsize\fR .fi .IP Specifies the width in pixels of the border around the token window. This border becomes raised to indicate when the token is over a compatible drag&drop target site. The value may have any of the forms acceptable to Tk_GetPixels. The default value is "3". .LP .nf Name: \fBtokenCursor\fR Class: \fBCursor\fR Switch: \fB\-tokencursor \fIcursor\fR .fi .IP Specifies the cursor used when a token window is active. The value may have any of the forms acceptable to Tk_GetCursor. The default value is "center_ptr". .RE .TP \fBdrag&drop source \fIwindow \fBhandler \fR?\fIdataType\fR? ?\fIcommand arg arg...\fR? With no extra arguments, this command returns a list of all \fIdataType\fR names that have been registered for the source \fIwindow\fR. If only the \fIdataType\fR is specified, then the \fIdataType\fR is created if necessary, and the command associated with the \fIdataType\fR is returned. Otherwise, it concatenates the \fIcommand\fR and any extra \fIarg\fR strings, and registers a new \fIdataType\fR with this command. .PP The following substitutions are made in the \fIcommand\fR string before it is executed: .RS .TP \fB%i\fR Replaced with the name of the interpreter for the target application. .TP \fB%v\fR Replaced with the value returned from the "-packagecmd" command. .TP \fB%w\fR Replaced with the window path name for the target window. .RE .LP A typical source handler contains one or more "send" commands which transfer data to the remote application. The target window is then asked to handle the new data. Whatever value is returned by the source \fIcommand\fR handler is automatically substituted into the "%v" fields of the target handler. .LP This separation between the transfer and the handling of the data is important. It allows the same source handler to transfer data for many different targets, and it allows each of the targets to handle the incoming data differently. If an error is encountered during the communication process, the rejection symbol is posted on the token window to indicate failure. .RE .sp .TP \fBdrag&drop target\fR Returns a list of path names for widgets registered as drag&drop targets. Returns an empty string if no widgets have been registered. .TP \fBdrag&drop target \fIwindow \fBhandler \fR?\fIdataType command arg arg...\fR? Registers a new drag&drop target window with a given handler, or modifies the handlers for an existing window. If no \fIdataType\fR is specified, this command returns the current list of recognized \fIdataType\fR strings. Each \fIdataType\fR is a symbolic name representing a form of data, and the corresponding \fIcommand\fR is a Tcl command that specifies how the target will make use of the data. This command is invoked indirectly after a source has transferred data to a target application. .PP The following substitutions are made in the \fIcommand\fR string before it is executed: .RS .TP \fB%v\fR In the simplest case, the source window does not have a handler command for the selected \fIdataType\fR, and this field is replaced with the result from the "-packagecmd" command. When the source does have a handler command, the result from the "-packagecmd" command is substituted into its "%v" field, and the result from this command is substituted into this field in the target command. .TP \fB%W\fR Replaced with the window path name for the target window. .RE .TP \fBdrag&drop target \fIwindow \fRhandle \fIdataType\fR ?\fIvalue\fR? Searches for the given \fIdataType\fR name among the handlers registered for the target \fIwindow\fR, and invokes the appropriate \fIcommand\fR. If a \fIvalue\fR is specified, it is substituted into any "%v" fields in the handler command associated with the \fIdataType\fR. If the \fIdataType\fR name is not recognized, this command returns an error. This command is invoked automatically by the drag&drop facility when data is being transferred from a source to a target. .TP \fBdrag&drop token \fIwindow\fR Returns the token window associated with a drag&drop source \fIwindow\fR. The token window is used to represent data as it is being dragged from the source to a target. When a source is first established, its token window must be filled with widgets to display the source data. For example, .sp .nf .RS \f(CWdrag&drop source .foo set win [drag&drop token .foo] label $win.label -text "Data" pack $win.label\fR .RE .fi .sp .TP \fBdrag&drop drag \fIwindow x y\fR Marks the start of (or movement during) a drag&drop operation. If the token window is unmapped when this command is invoked, then the \fB\-packagecmd\fR for the source \fIwindow\fR is executed. If this command is successful and returns a non-null string, the token window is mapped. On subsequent calls, the token window is moved to the new \fIx y\fR location. Unless the "\fB\-button 0\fR" option is specified for the source, this command is automatically bound to and events for "\fB\-button \fIn\fR" of the source widget. .TP \fBdrag&drop drop \fIwindow x y\fR Marks the end of a drag&drop operation. If the mouse pointer is over a compatible target window, then the appropriate send handler for the first compatible \fIdataType\fR is invoked to handle the data transfer. If the data transfer is successful, then the token window is unmapped; otherwise, a rejection symbol is drawn on the token window, and the window is unmapped after a small delay. Unless the "\fB\-button 0\fR" option is specified for the source, this command is automatically bound to the event for "\fB\-button \fIn\fR" of the source widget. .TP \fBdrag&drop active\fR Returns "1" if a drag&drop operation is in progress, and "0" otherwise. A drag&drop operation officially starts after the package command has been executed successfully, and ends after the send handler has been executed (successfully or otherwise). .TP \fBdrag&drop errors \fR?\fIproc\fR? Specifies a Tcl \fIproc\fR used to handle errors encountered during drag&drop operations. If a \fIproc\fR is not specified, this command returns the current error handler. By default, all errors are sent to the usual \fBtkerror\fR command, and therefore appear in a dialog box to the user. This behavior is quite useful when debugging communication protocols, but may not be desirable in a finished application. Errors can be suppressed entirely (leaving the rejection symbol as the only error indicator) by specifying a null string in place of the \fIproc\fR name. .TP \fBdrag&drop location \fR?\fIx y\fR? Used to set or query the pointer location during a drag&drop operation. The \fIx y\fR arguments specify the current location; if these arguments are missing, then the last reported (x,y) location is returned as a list with two elements. This command is issued automatically within the \fBdrag&drop drag\fR and \fBdrag&drop drop\fR commands, to keep track of pointer movement. .SH KEYWORDS drag&drop, send, bind, widget blt-2.4z.orig/man/eps.mann0100644000175000017500000001477607435034423014204 0ustar dokodoko'\" '\" 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. '\" '\" Graph widget created by Sani Nassif and George Howlett. '\" .so man.macros .TH eps n BLT_VERSION BLT "BLT Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME eps \- Encapsulated PostScript canvas item. .SH SYNOPSIS \fIcanvas\fB create eps \fIx y \fR?\fIoption value\fR?... .BE .SH DESCRIPTION The \fBeps\fR canvas item lets you place encapulated PostScript (EPS) on a canvas, controlling its size and placement. The EPS item is displayed either as a solid rectangle or a preview image. The preview image is designated in one of two ways: 1) the EPS file contains an ASCII hexidecimal preview, or 2) a Tk photo image. When the canvas generates PostScript output, the EPS will be inserted with the proper translation and scaling to match that of the EPS item. So can use the canvas widget as a page layout tool. .SH EXAMPLE Let's say you have for PostScript files of four graphs which you want to tile two-by-two on a single page. Maybe you'd like to annotate the graphs by putting a caption at the bottom of each graph. .PP Normally, you would have to resort to an external tool or write your own PostScript program. The \fBeps\fR canvas item lets you do this through Tk's canvas widget. An \fBeps\fR item displays an image (or rectangle) representing the encapsulated PostScript file. It also scales and translates the EPS file when the canvas is printed. .SH SYNTAX .DS \fIcanvas \fBcreate eps \fIx y \fR?\fIoption value\fR?... .DE The \fBeps\fR item creates a new canvas item. \fICanvas\fR is the name of a \fBcanvas\fR widget. You must supply the X-Y coordinate of the new eps item. How the coordinate is exactly interpretered is controlled by the \fB\-anchor\fR option (see below). .PP Additional options may be specified on the command line to configure aspects of the eps item such as its color, stipple, and font. The following \fIoption\fR and \fIvalue\fR pairs are valid. .TP \fB\-anchor \fIanchor\fR Tells how to position the EPS item relative to its X-Y coordinate. The default is \f(CWcenter\fR. .TP \fB\-background \fIcolor\fR Sets the background color of the EPS rectangle. .TP \fB\-borderwidth \fIpixels\fR Sets the width of the 3\-D border around the outside edge of the item. The \fB\-relief\fR option determines if the border is to be drawn. The default is \f(CW0\fR. .TP \fB\-file \fIfileName\fR Specifies the name of the EPS file. The first line of an EPS file must start with "%!PS" and contain a "EPS" version specification. The other requirement is that there be a "%%BoundingBox:" entry which contains four integers representing the lower-left and upper-right coordinates of the area bounding the EPS. The default is \f(CW""\fR. .TP \fB\-font \fIfontName\fR Specifies the font of the title. The default is \f(CW*-Helvetica-Bold-R-Normal-*-18-180-*\fR. .TP \fB\-foreground \fIcolor\fR Specifies the foreground color of the EPS rectangle. The option matters only when the \fB\-stipple\fR option is set. The default is \f(CWwhite\fR. .TP \fB\-height \fIpixels\fR Specifies the height EPS item. If \fIpixels\fR is \f(CW0\fR, then the height is determined from the PostScript "BoundingBox:" entry in the EPS file. The default is \f(CW0\fR. .TP \fB\-image \fIphoto\fR Specifies the name of a Tk photo image to be displayed as in the item as a preview image. This option overrides any preview specification found in the EPS file. The default is \f(CW""\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\-relief \fIrelief\fR Specifies the 3-D effect for the EPS item. \fIRelief\fR specifies how the item should appear relative to canvas; for example, \f(CWraised\fR means the item should appear to protrude. The default is \f(CWflat\fR. .TP \fB\-shadowcolor \fIcolor\fR Specifies the color of the drop shadow used for the title. The option with the \fB\-shadowoffset\fR option control how the title's drop shadow appears. The default is \f(CWgrey\fR. .TP \fB\-shadowoffset \fIpixels\fR Specifies the offset of the drop shadow from the title's text. If \fIpixels\fR is \f(CW0\fR, no shadow will be seen. The default is \f(CW0\fR. .TP \fB\-showimage \fIboolean\fR Indicates whether to display the image preview (if one exists), or a simple rectangle. The default is \f(CWyes\fR. .TP \fB\-stipple \fIbitmap\fR Specifies a bitmap to used to stipple the rectangle representing the EPS item. The default is \f(CW""\fR. .TP \fB\-title \fIstring\fR Sets the title of the EPS item. If \fIstring\fR is \f(CW""\fR, then the title specified by the PostScript "Title:" entry is used. You can set the string a single space to display no title. The default is \f(CW""\fR. .TP \fB\-titleanchor \fIanchor\fR Tells how to position the title within EPS item. The default is \f(CWn\fR. .TP \fB\-titlecolor \fIcolor\fR Specifies the color of the title. The default is \f(CWwhite\fR. .TP \fB\-titlerotate \fIdegrees\fR Sets the rotation of the title. \fIDegrees\fR is a real number representing the angle of rotation. The title is first rotated in space and then placed according to the \fB\-titleanchor\fR position. The default rotation is \f(CW0.0\fR. .TP \fB\-width \fIpixels\fR Specifies the width EPS item. If \fIpixels\fR is \f(CW0\fR, then the width is determined from the PostScript "BoundingBox:" entry in the EPS file. The default is \f(CW0\fR. \f(CW5i\fR. blt-2.4z.orig/man/graph.mann0100644000175000017500000030703307507476637014526 0ustar dokodoko'\" '\" 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. '\" .so man.macros .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\-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 graph is redrawn. You may query configuration options. But do not them, 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 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\-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 \fIvarName\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 is not be hidden. \fIVarName\fR is the name of a Tcl array variable and will contain the search results: the name of the closest element, the index of the closest data point, and the graph coordinates of the point. Returns \f(CW0\fR, if no data point within the threshold distance can be found, otherwise \f(CW1\fR is returned. 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\-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 blt-2.4z.orig/man/hierbox.mann0100644000175000017500000025372107434255426015057 0ustar dokodoko'\" '\" Copyright 2001-2 by Silicon Metrics Corporation. '\" '\" 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 Silicon Metrics or any of their entities not be used '\" in advertising or publicity pertaining to distribution of the software '\" without specific, written prior permission. '\" '\" Silicon Metrics disclaims all warranties with regard to this software, '\" including all implied warranties of merchantability and fitness. In no event '\" shall Silicon Metrics 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. '\" '\" The hierarchical table widget created by George Howlett. '\" .so man.macros .TH treeview n BLT_VERSION BLT "BLT Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME treeview \- Create and manipulate hierarchical table widgets .BE .SH SYNOPSIS \fBtreeview\fR \fIpathName \fR?\fIoptions\fR? .SH DESCRIPTION The \fBtreeview\fR widget displays a tree of data. It replaces both the \fBhiertable\fR and \fBhierbox\fR widgets. The \fBtreeview\fR is 100% syntax compatible with the \fBhiertable\fR widget. The \fBhiertable\fR command is retained for sake of script-level compatibility. This widget obsoletes the \fBhierbox\fR widget. It does everything the old \fBhierbox\fR widget did, but also provides data sharing (via \fItree data objects\fR) and the ability to tag nodes. .SH INTRODUCTION The \fBtreeview\fR widget displays hierarchical data. Data is represented as nodes in a general-ordered tree. Each node may have sub-nodes and these nodes can in turn has their own children. .PP A node is displayed as a row entry in the widget. Each entry has a text label and icon. When a node has children, its entry is drawn with a small button to the left of the label. Clicking the mouse over this button opens or closes the node. When a node is \fIopen\fR, its children are exposed. When it is \fIclosed\fR, the children and their descedants are hidden. The button is normally a \f(CW+\fR or \f(CW\-\fR symbol (ala Windows Explorer), but can be replaced with a pair of Tk images (open and closed images). .PP If the node has data associated with it, they can be displayed in columns running vertically on either side the tree. You can control the color, font, etc of each entry. Any entry label or data field can be edited in-place. .SH "TREE DATA OBJECT" The tree is not stored inside the widget but in a tree data object (see the \fBtree\fR command for a further explanation). Tree data objects can be shared among different clients, such as a \fBtreeview\fR widget or the \fBtree\fR command. You can walk the tree and manage its data with the \fBtree\fR command tree, while displaying it with the \fBtreeview\fR widget. Whenever the tree is updated, the \fBtreeview\fR widget is automatically redrawn. .PP By default, the \fBtreeview\fR widget creates its own tree object. The tree initially contains just a root node. But you can also display trees created by the \fBtree\fR command using the \fB\-tree\fR configuration option. \fBTreeview\fR widgets can share the same tree object, possibly displaying different views of the same data. .PP A tree object has both a Tcl and C API. You can insert or delete nodes using \fBtreeview\fR widget or \fBtree\fR command operations, but also from C code. For example, you can load the tree from your C code while still managing and displaying the tree from Tcl. The widget is automatically notified whenever the tree is modified via C or Tcl. .SH SYNTAX .DS \fBtreeview \fIpathName \fR?\fIoption value\fR?... .DE The \fBtreeview\fR command creates a new window \fIpathName\fR and makes it into a \fBtreeview\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 widget 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, \fBtreeview\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 widget. 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 are described in the .SB "TREEVIEW OPERATIONS" section. .SH "IDS AND TAGS" Nodes can be inserted into a tree using the \fBtreeview\fR widget .CS blt::treeview .t set node [.t insert end root "one"] .CE or \fBtree\fR command. .CS set tree [blt::tree create] set node [$tree insert root "one"] .CE In both cases, a number identifying the node is returned (the value of \f(CW$node\fR). This serial number or \fIid\fR uniquely identifies the node. Please note that you can't infer a location or position of a node from its id. The only exception is that the root node is always id \f(CW0\fR. Since nodes may have the same labels or be moved within the tree, ids provide an convenient way to identify nodes. If a tree is shared, the ids will be the same regardless if you are using by the \fBtreeview\fR widget or the \fBtree\fR command. Ids are recycled when the node deleted. .PP A node may also have any number of \fItags\fR associated with it. A tag is just a string of characters, and it may take any form except that of an integer. For example, "\f(CWx123\fR" is valid, but "\f(CW123\fR" isn't. The same tag may be associated with many different nodes. This is typically done to associate a group of nodes. Many operations in the \fBtreeview\fR widget take either node ids or tag names as arguments. Using a tag says to apply the operation to all nodes with that tag. .PP The tag \fBall\fR is implicitly associated with every node in the tree. It may be used to invoke operations on all the nodes in the tree. .PP Tags may be shared, just like trees, between clients. For example, you can use the tags created by the \fBtree\fR command with \fBtreeview\fR widgets. .SH SPECIAL NODE IDS There are also several special non-numeric ids. Special ids differ from tags in that they are always translated to their numeric equivalent. They also take precedence over tags. For example, you can't use a tag name that is a special id. These ids are specific to the \fBtreeview\fR widget. .TP 15 \fBactive\fR The node where the mouse pointer is currently located. When a node is active, it is drawn using its active icon (see the \fB\-activeicon\fR option). The \fBactive\fR id is changed automatically by moving the mouse pointer over another node or by using the \fBentry activate\fR operation. Note that there can be only one active node at a time. .TP 15 \fBanchor\fR The node representing the fixed end of the current selection. The anchor is set by the \fBselection anchor\fR operation. .TP 15 \fBcurrent\fR The node where the mouse pointer is currently located. But unlike \fBactive\fR, this id changes while the selection is dragged. It is used to determine the current node during button drags. .TP 15 \fBdown\fR The next open node from the current focus. The \fBdown\fR of the last open node is the same. .TP 15 \fBend\fR The last open node (in depth-first order) on the tree. .TP 15 \fBfocus\fR The node that currently has focus. When a node has focus, it receives key events. To indicate focus, the node is drawn with a dotted line around its label. You can change the focus using the \fBfocus\fR operation. .TP 15 \fBlast\fR The last open node from the current focus. But unlike \fBup\fR, when the focus is at root, \fBlast\fR wraps around to the last open node in the tree. .TP 15 \fBmark\fR The node representing the non-fixed end of the current selection. The mark is set by the \fBselection mark\fR operation. .TP 15 \fBnext\fR The next open node from the current focus. But unlike \fBdown\fR, when the focus is on last open node, \fBnext\fR wraps around to the root node. .TP 15 \fBnextsibling\fR The next sibling from the node with the current focus. If the node is already the last sibling then it is the \fBnextsibling\fB. .TP 15 \fBparent\fR The parent of the node with the current focus. The \fBparent\fR of the root is also the root. .TP 15 \fBprevsibling\fR The previous sibling from the node with the current focus. If the node is already the first sibling then it is the \fBprevsibling\fB. .TP 15 \fBroot\fR The root node. You can also use id \f(CW0\fR to indicate the root. .TP 15 \fBup\fR The last open node (in depth-first order) from the current focus. The \fBup\fR of the root node (i.e. the root has focus) is also the root. .TP 15 \fBview.top\fR First node that's current visible in the widget. .TP 15 \fBview.bottom\fR Last node that's current visible in the widget. .TP 15 \fIpath\fR Absolute path of a node. Path names refer to the node name, not their entry labels. Paths don't have to start with a separator (see the \fB\-separator\fR configuration option), but component names must be separated by the designated separator. .TP 15 \fB@\fIx\fB,\fIy\fR Indicates the node that covers the point in the treeview window specified by \fIx\fR and \fIy\fR (in pixel coordinates). If no part of the entryd covers that point, then the closest node to that point is used. .PP A node may be specified as an id or tag. If the specifier is an integer then it is assumed to refer to the single node with that id. If the specifier is not an integer, it's checked to see if it's a special id (such as focus). Otherwise, it's assumed to be tag. Some operations only operate on a single node at a time; if a tag refers to more than one node, then an error is generated. .SH DATA FIELDS A node in the tree can have \fIdata fields\fR. A data field is a name-value pair, used to represent arbitrary data in the node. Nodes can contain different fields (they aren't required to contain the same fields). You can optionally display these fields in the \fBtreeview\fR widget in columns running on either side of the displayed tree. A node's value for the field is drawn in the column along side its node in the hierarchy. Any node that doesn't have a specific field is left blank. Columns can be interactively resized, hidden, or, moved. .SH ENTRY BINDINGS You can bind Tcl commands to be invoked when events occur on nodes (much like Tk canvas items). You can bind a node using its id or its \fIbindtags\fR. Bindtags are simply names that associate a binding with one or more nodes. There is a built-in tag \f(CWall\fR that all node entries automatically have. .SH "TREEVIEW OPERATIONS" The \fBtreeview\fR operations are the invoked by specifying the widget's pathname, the operation, and any arguments that pertain to that operation. The general form is: .sp .CS \fIpathName operation \fR?\fIarg arg ...\fR? .CE .sp \fIOperation\fR and the \fIarg\fRs determine the exact behavior of the command. The following operation are available for \fBtreeview\fR widgets: .TP \fIpathName \fBbbox\fR ?\fB-screen\fR? \fItagOrId...\fR Returns a list of 4 numbers, representing a bounding box of around the specified entries. The entries is given by one or more \fItagOrId\fR arguments. If the \fB\-screen\fR flag is given, then the x-y coordinates of the bounding box are returned as screen coordinates, not virtual coordinates. Virtual coordinates start from \f(CW0\fR from the root node. The returned list contains the following values. .RS .TP 1.25i \fIx\fR X-coordinate of the upper-left corner of the bounding box. .TP \fIy\fR Y-coordinate of the upper-left corner of the bounding box. .TP \fIwidth\fR Width of the bounding box. .TP \fIheight\fR Height of the bounding box. .RE .TP \fIpathName \fBbind\fR \fItagName\fR ?\fIsequence command\fR? Associates \fIcommand\fR with \fItagName\fR such that whenever the event sequence given by \fIsequence\fR occurs for a node with this tag, \fIcommand\fR will be invoked. The syntax is similar to the \fBbind\fR command except that it operates on \fBtreeview\fR 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 \fBbutton \fIoperation\fR ?\fIargs\fR? This command is used to control the button selectors within a \fBtreeview\fR widget. It has several forms, depending on \fIoperation\fR: .RS .TP \fIpathName \fBbutton activate\fR \fItagOrId\fR Designates the node given by \fItagOrId\fR as active. When a node is active it's entry is drawn using its active icon (see the \fB\-activeicon\fR option). Note that there can be only one active entry at a time. The special id \fBactive\fR indicates the currently active node. .TP \fIpathName \fBbutton bind\fR \fItagName\fR ?\fIsequence command\fR? Associates \fIcommand\fR with \fItagName\fR such that whenever the event sequence given by \fIsequence\fR occurs for an button of a node entry with this tag, \fIcommand\fR will be invoked. The syntax is similar to the \fBbind\fR command except that it operates on \fBtreeview\fR buttons, 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 \fBbutton cget\fR \fIoption\fR Returns the current value of the configuration option given by \fIoption\fR. \fIOption\fR may have any of the values accepted by the \fBconfigure\fR operation described below. .TP \fIpathName \fBbutton configure\fR ?\fIoption\fR? ?\fIvalue option value ...\fR? Query or modify the configuration options of the widget. If no \fIoption\fR is specified, returns a list describing all of the available options for \fIpathName\fR (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no \fIoption\fR is specified). If one or more \fIoption\-value\fR pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. \fIOption\fR and \fIvalue\fR are described in the section .SB "BUTTON OPTIONS" below. .RE .TP \fIpathName \fBcget\fR \fIoption\fR Returns the current value of the configuration option given by \fIoption\fR. \fIOption\fR may have any of the values accepted by the \fBconfigure\fR operation described below. .TP \fIpathName \fBclose \fR?\fB\-recurse\fR? \fItagOrId...\fR Closes the node specified by \fItagOrId\fR. In addition, if a Tcl script was specified by the \fB\-closecommand\fR option, it is invoked. If the node is already closed, this command has no effect. If the \fB\-recurse\fR flag is present, each child node is recursively closed. .TP \fIpathName \fBcolumn \fIoperation\fR ?\fIargs\fR? The following operations are available for treeview columns. .RS .TP \fIpathName \fBcolumn activate\fR \fIcolumn\fR Sets the active column to \fIcolumn\fR. \fIColumn\fR is the name of a column in the widget. When a column is active, it's drawn using its \fB\-activetitlebackground\fR and \fB\-activetitleforeground\fR options. If \fIcolumn\fR is the \f(CW""\fR, then no column will be active. If no column argument is provided, then the name of the currently active column is returned. .TP \fIpathName \fBcolumn cget\fR \fIname\fR \fIoption\fR Returns the current value of the column configuration option given by \fIoption\fR for \fIname\fR. \fIName\fR is the name of column that corresponds to a data field. \fIOption\fR may have any of the values accepted by the \fBconfigure\fR operation described below. .TP \fIpathName \fBcolumn configure\fR \fIname\fR ?\fIoption\fR? ?\fIvalue option value ...\fR? Query or modify the configuration options of the column designated by \fIname\fR. \fIName\fR is the name of the column corresponding to a data field. If no \fIoption\fR is specified, returns a list describing all of the available options for \fIpathName\fR (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no \fIoption\fR is specified). If one or more \fIoption\-value\fR pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. \fIOption\fR and \fIvalue\fR are described in the section .SB "COLUMN OPTIONS" below. .TP \fIpathName \fBcolumn delete\fR \fIfield\fR ?\fIfield\fR...? Deletes one of more columns designated by \fIfield\fR. Note that this does not delete the data fields themselves. .TP \fIpathName \fBcolumn insert\fR \fIposition\fR \fIfield\fR ?\fIoptions\fR...? Inserts one of more columns designated by \fIfield\fR. A column displays each node's data field by the same name. If the node doesn't have the given field, the cell is left blank. \fIPosition\fR indicates where in the list of columns to add the new column. It may be either a number or \f(CWend\fR. .TP \fIpathName \fBcolumn invoke\fR \fIfield\fR Invokes the Tcl command associated with the column \fIfield\fR, if there is one (using the column's \fB\-command\fR option). The command is ignored if the column's \fB\-state\fR option set to \f(CWdisabled\fR. .TP \fIpathName \fBcolumn move \fIname\fR \fIdest\fR Moves the column \fIname\fR to the destination position. \fIDest\fR is the name of another column or a screen position in the form \f(CW@\fIx\f(CW,\fIy\fR. .TP \fIpathName \fBcolumn names\fR Returns a list of the names of all columns in the widget. The list is ordered as the columns are drawn from left-to-right. .TP \fIpathName \fBcolumn nearest\fR \fIx\fR ?\fIy\fR? Returns the name of the column closest to the given X-Y screen coordinate. If you provide a \fIy\fR argument (it's optional), a name is returned only when if the point is over a column's title. .RE .TP \fIpathName \fBconfigure\fR ?\fIoption\fR? ?\fIvalue option value ...\fR? Query or modify the configuration options of the widget. If no \fIoption\fR is specified, returns a list describing all of the available options for \fIpathName\fR (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no \fIoption\fR is specified). If one or more \fIoption\-value\fR pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. \fIOption\fR and \fIvalue\fR are described in the section .SB "TREEVIEW OPTIONS" below. .TP \fIpathName \fBcurselection\fR Returns a list containing the ids of all of the entries that are currently selected. If there are no entries selected, then the empty string is returned. .TP \fIpathName \fBdelete \fItagOrId\fR... Deletes one or more entries given by \fItagOrId\fR and its children. .TP \fIpathName \fBentry \fIoperation\fR ?\fIargs\fR? The following operations are available for treeview entries. .RS .TP \fIpathName \fBentry activate\fR \fItagOrId\fR Sets the active entry to the one specified by \fItagOrId\fR. When an entry is active it is drawn using its active icon (see the \fB\-activeicon\fR option). Note that there can be only one active node at a time. The special id of the currently active node is \fBactive\fR. .TP \fIpathName \fBentry cget\fR \fIoption\fR Returns the current value of the configuration option given by \fIoption\fR. \fIOption\fR may have any of the values accepted by the \fBconfigure\fR operation described below. .TP \fIpathName \fBentry children\fR \fItagOrId\fR ?\fIfirst\fR? ?\fIlast\fR? Returns a list of ids for the given range of children of \fItagOrId\fR. \fITagOrId\fR is the id or tag of the node to be examined. If only a \fIfirst\fR argument is present, then the id of the that child at that numeric position is returned. If both \fIfirst\fR and \fIlast\fR arguments are given, then the ids of all the children in that range are returned. Otherwise the ids of all children are returned. .TP \fIpathName \fBentry configure\fR ?\fIoption\fR? ?\fIvalue option value ...\fR? Query or modify the configuration options of the widget. If no \fIoption\fR is specified, returns a list describing all of the available options for \fIpathName\fR (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no \fIoption\fR is specified). If one or more \fIoption\-value\fR pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. \fIOption\fR and \fIvalue\fR are described below: .TP \fIpathName \fBentry delete\fR \fItagOrId\fR ?\fIfirst\fR ?\fIlast\fR? Deletes the one or more children nodes of the parent \fItagOrId\fR. If \fIfirst\fR and \fIlast\fR arguments are present, they are positions designating a range of children nodes to be deleted. .TP \fIpathName \fBentry isbefore \fItagOrId1\fR \fItagOrId2\fR Returns 1 if \fItagOrId1\fR is before \fItagOrId2\fR and 0 otherwise. .TP \fIpathName \fBentry ishidden \fItagOrId\fR Returns 1 if the node is currently hidden and 0 otherwise. A node is also hidden if any of its ancestor nodes are closed or hidden. .TP \fIpathName \fBentry isopen \fItagOrId\fR Returns 1 if the node is currently open and 0 otherwise. .TP \fIpathName \fBentry size\fR \fB\-recurse\fR \fItagOrId\fR Returns the number of children for parent node \fItagOrId\fR. If the \fB\-recurse\fR flag is set, the number of all its descendants is returned. The node itself is not counted. .RE .TP \fIpathName \fBfind \fR?\fIflags\fR? \fIfirst\fR \fIlast\fR Finds for all entries matching the criteria given by \fIflags\fR. A list of ids for all matching nodes is returned. \fIFirst\fR and \fIlast\fR are ids designating the range of the search in depth-first order. If \fIlast\fR is before \fIfirst\fR, then nodes are searched in reverse order. The valid flags are: .RS .TP 1.25i \fB\-name\fI pattern\fR Specifies pattern to match against node names. .TP 1.25i \fB\-full\fI pattern\fR Specifies pattern to match against node pathnames. .TP 1.25i \fB\-\fIoption\fI pattern\fR Specifies pattern to match against the node entry's configuration option. .TP 1.25i \fB\-exact\fR Patterns must match exactly. The is the default. .TP 1.25i \fB\-glob\fR Use global pattern matching. Matching is done in a fashion similar to that used by the C-shell. For the two strings to match, their contents must be identical except that the following special sequences may appear in pattern: .RS .TP 5 \f(CW*\fR Matches any sequence of characters in string, including a null string. .TP 5 \f(CW?\fR Matches any single character in string. .TP 5 \f(CW[\fIchars\f(CW]\fR Matches any character in the set given by \fIchars\fR. If a sequence of the form \fIx\fR-\fIy\fR appears in \fIchars\fR, then any character between \fIx\fR and \fIy\fR, inclusive, will match. .TP 5 \f(CW\\\fIx\fR Matches the single character \fIx\fR. This provides a way of avoiding the special interpretation of the characters \f(CW*?[]\\\fR in the pattern. .RE .TP 1.25i \fB\-regexp\fR Use regular expression pattern matching (i.e. the same as implemented by the \fBregexp\fR command). .TP 1.25i \fB\-nonmatching\fR Pick entries that don't match. .TP 1.25i \fB\-exec\fI string\fR Specifies a Tcl script to be invoked for each matching node. Percent substitutions are performed on \fIstring\fR before it is executed. The following substitutions are valid: .RS .TP 5 \f(CW%W\fR The pathname of the widget. .TP 5 \f(CW%p\fR The name of the node. .TP 5 \f(CW%P\fR The full pathname of the node. .TP 5 \f(CW%#\fR The id of the node. .TP 5 \f(CW%%\fR Translates to a single percent. .RE .TP 1.25i \fB\-count\fI number\fR Stop searching after \fInumber\fR matches. .TP 1.25i \fB\-\-\fR Indicates the end of flags. .RE .TP \fIpathName \fBfocus \fR \fItagOrId\fR Sets the focus to the node given by \fItagOrId\fR. When a node has focus, it can receive keyboard events. The special id \fBfocus\fR designates the node that currently has focus. .TP \fIpathName \fBget \fR?\fB\-full\fR? \fItagOrId\fR \fItagOrId\fR... Translates one or more ids to their node entry names. It returns a list of names for all the ids specified. If the \fB\-full\fR flag is set, then the full pathnames are returned. .TP \fIpathName \fBhide \fR?\fBflags\fR? \fItagOrId\fR... Hides all nodes matching the criteria given by \fIflags\fR. The search is performed recursively for each node given by \fItagOrId\fR. The valid flags are described below: .RS .TP 1.25i \fB\-name\fI pattern\fR Specifies pattern to match against node names. .TP 1.25i \fB\-full\fI pattern\fR Specifies pattern to match against node pathnames. .TP 1.25i \fB\-\fIoption\fI pattern\fR Specifies pattern to match against the node entry's configuration option. .TP 1.25i \fB\-exact\fR Match patterns exactly. The is the default. .TP 1.25i \fB\-glob\fR Use global pattern matching. Matching is done in a fashion similar to that used by the C-shell. For the two strings to match, their contents must be identical except that the following special sequences may appear in pattern: .RS .TP 5 \f(CW*\fR Matches any sequence of characters in string, including a null string. .TP 5 \f(CW?\fR Matches any single character in string. .TP 5 \f(CW[\fIchars\f(CW]\fR Matches any character in the set given by \fIchars\fR. If a sequence of the form \fIx\fR-\fIy\fR appears in \fIchars\fR, then any character between \fIx\fR and \fIy\fR, inclusive, will match. .TP 5 \f(CW\\\fIx\fR Matches the single character \fIx\fR. This provides a way of avoiding the special interpretation of the characters \f(CW*?[]\\\fR in the pattern. .RE .TP 1.25i \fB\-regexp\fR Use regular expression pattern matching (i.e. the same as implemented by the \fBregexp\fR command). .TP 1.25i \fB\-nonmatching\fR Hide nodes that don't match. .TP 1.25i \fB\-\-\fR Indicates the end of flags. .RE .TP \fIpathName \fBindex \fR?\fB\-at\fR \fItagOrId\fR? \fIstring\fR Returns the id of the node specified by \fIstring\fR. \fIString\fR may be a tag or node id. Some special ids are normally relative to the node that has focus. The \fB\-at\fR flag lets you select another node. .TP \fIpathName \fBinsert \fR?\fB\-at \fItagOrId\fR? \fIposition\fR \fIpath\fR ?\fIoptions...\fR? ?\fIpath\fR? ?\fIoptions...\fR? Inserts one or more nodes at \fIposition\fR. \fIPosition\fR is the location (number or \f(CWend\fR) where the new nodes are added to the parent node. \fIPath\fR is the pathname of the new node. Pathnames can be formated either as a Tcl list (each element is a path component) or as a string separated by a special character sequence (using the \fB\-separator\fR option). Pathnames are normally absolute, but the \fB\-at\fR switch lets you select a relative starting point. Its value is the id of the starting node. .sp All ancestors of the new node must already exist, unless the \fB\-autocreate\fR option is set. It is also an error if a node already exists, unless the \fB\-allowduplicates\fR option is set. .sp \fIOption\fR and \fIvalue\fR may have any of the values accepted by the \fBentry configure\fR operation described in the .SB "ENTRY OPERATIONS" section below. This command returns a list of the ids of the new entries. .TP \fIpathName \fBmove \fItagOrId\fR \fIhow\fR \fIdestId\fR Moves the node given by \fItagOrId\fR to the destination node. The node can not be an ancestor of the destination. \fIDestId\fR is the id of the destination node and can not be the root of the tree. In conjunction with \fIhow\fR, it describes how the move is performed. .RS .TP 8 \f(CWbefore\fR Moves the node before the destination node. .TP 8 \f(CWafter\fR Moves the node after the destination node. .TP 8 \f(CWinto\fR Moves the node to the end of the destination's list of children. .RE .TP \fIpathName \fBnearest \fIx y\fR ?\fIvarName\fR? Returns the id of the node entry closest to the given X-Y screen coordinate. The optional argument \fIvarName\fR is the name of variable which is set to either \f(CWbutton\fR or \f(CWselect\fR to indicate over what part of the node the coordinate lies. If the coordinate is not directly over any node, then \fIvarName\fR will contain the empty string. .TP \fIpathName \fBopen \fR?\fB\-recurse\fR? \fItagOrId...\fR Opens the one or more nodes specified by \fItagOrId\fR. If a node is not already open, the Tcl script specified by the \fB\-opencommand\fR option is invoked. If the \fB\-recurse\fR flag is present, then each descendant is recursively opened. .TP \fIpathName \fBrange\fR ?\fB-open\fR? \fIfirst last\fR Returns the ids in depth-first order of the nodes between the \fIfirst\fR and \fIlast\fR ids. If the \fB\-open\fR flag is present, it indicates to consider only open nodes. If \fIlast\fR is before \fIfirst\fR, then the ids are returned in reverse order. .TP \fIpathName \fBscan\fR \fIoption args\fR This command implements scanning. It has two forms, depending on \fIoption\fR: .RS .TP \fIpathName \fBscan mark \fIx y\fR Records \fIx\fR and \fIy\fR and the current view in the treeview window; used in conjunction with later \fBscan dragto\fR commands. Typically this command is associated with a mouse button press in the widget. It returns an empty string. .TP \fIpathName \fBscan dragto \fIx y\fR. Computes the difference between its \fIx\fR and \fIy\fR arguments and the \fIx\fR and \fIy\fR arguments to the last \fBscan mark\fR command for the widget. It then adjusts the view by 10 times the difference in coordinates. This command is typically associated with mouse motion events in the widget, to produce the effect of dragging the list at high speed through the window. The return value is an empty string. .RE .TP \fIpathName \fBsee\fR ?\fB\-anchor \fIanchor\fR? \fItagOrId\fR Adjusts the view of entries so that the node given by \fItagOrId\fR is visible in the widget window. It is an error if \fBtagOrId\fR is a tag that refers to more than one node. By default the node's entry is displayed in the middle of the window. This can changed using the \fB\-anchor\fR flag. Its value is a Tk anchor position. .TP \fIpathName \fBselection \fIoption arg\fR This command is used to adjust the selection within a \fBtreeview\fR widget. It has several forms, depending on \fIoption\fR: .RS .TP \fIpathName \fBselection anchor \fItagOrId\fR Sets the selection anchor to the node given by \fItagOrId\fR. If \fItagOrId\fR refers to a non-existent node, then the closest node is used. The selection anchor is the end of the selection that is fixed while dragging out a selection with the mouse. The special id \fBanchor\fR may be used to refer to the anchor node. .TP \fIpathName \fBselection cancel\fR Clears the temporary selection of entries back to the current anchor. Temporary selections are created by the \fBselection mark\fR operation. .TP \fIpathName \fBselection clear \fIfirst \fR?\fIlast\fR? Removes the entries between \fIfirst\fR and \fIlast\fR (inclusive) from the selection. Both \fIfirst\fR and \fIlast\fR are ids representing a range of entries. If \fIlast\fR isn't given, then only \fIfirst\fR is deselected. Entries outside the selection are not affected. .TP \fIpathName \fBselection clearall\fR Clears the entire selection. .TP \fIpathName \fBselection mark \fItagOrId\fR Sets the selection mark to the node given by \fItagOrId\fR. This causes the range of entries between the anchor and the mark to be temporarily added to the selection. The selection mark is the end of the selection that is fixed while dragging out a selection with the mouse. The special id \fBmark\fR may be used to refer to the current mark node. If \fItagOrId\fR refers to a non-existent node, then the mark is ignored. Resetting the mark will unselect the previous range. Setting the anchor finalizes the range. .TP \fIpathName \fBselection includes \fItagOrId\fR Returns 1 if the node given by \fItagOrId\fR is currently selected, 0 if it isn't. .TP \fIpathName \fBselection present\fR Returns 1 if any nodes are currently selected and 0 otherwise. .TP \fIpathName \fBselection set \fIfirst \fR?\fIlast\fR? Selects all of the nodes in the range between \fIfirst\fR and \fIlast\fR, inclusive, without affecting the selection state of nodes outside that range. .TP \fIpathName \fBselection toggle \fIfirst \fR?\fIlast\fR? Selects/deselects nodes in the range between \fIfirst\fR and \fIlast\fR, inclusive, from the selection. If a node is currently selected, it becomes deselected, and visa versa. .RE .TP \fIpathName \fBshow \fR?\fBflags\fR? \fItagOrId\fR... Exposes all nodes matching the criteria given by \fIflags\fR. This is the inverse of the \fBhide\fR operation. The search is performed recursively for each node given by \fItagOrId\fR. The valid flags are described below: .RS .TP 1.25i \fB\-name\fI pattern\fR Specifies pattern to match against node names. .TP 1.25i \fB\-full\fI pattern\fR Specifies pattern to match against node pathnames. .TP 1.25i \fB\-\fIoption\fI pattern\fR Specifies pattern to match against the entry's configuration option. .TP 1.25i \fB\-exact\fR Match patterns exactly. The is the default. .TP 1.25i \fB\-glob\fR \fB\-glob\fR Use global pattern matching. Matching is done in a fashion similar to that used by the C-shell. For the two strings to match, their contents must be identical except that the following special sequences may appear in pattern: .RS .TP 5 \f(CW*\fR Matches any sequence of characters in string, including a null string. .TP 5 \f(CW?\fR Matches any single character in string. .TP 5 \f(CW[\fIchars\f(CW]\fR Matches any character in the set given by \fIchars\fR. If a sequence of the form \fIx\fR-\fIy\fR appears in \fIchars\fR, then any character between \fIx\fR and \fIy\fR, inclusive, will match. .TP 5 \f(CW\\\fIx\fR Matches the single character \fIx\fR. This provides a way of avoiding the special interpretation of the characters \f(CW*?[]\\\fR in the pattern. .RE .TP 1.25i \fB\-regexp\fR Use regular expression pattern matching (i.e. the same as implemented by the \fBregexp\fR command). .TP 1.25i \fB\-nonmatching\fR Expose nodes that don't match. .TP 1.25i \fB\-\-\fR Indicates the end of flags. .RE .TP \fIpathName \fBsort\fR ?\fIoperation\fR? \fIargs...\fR .RS .TP \fIpathName \fBsort auto\fR ?\fIboolean\fR Turns on/off automatic sorting of node entries. If \fIboolean\fR is true, entries will be automatically sorted as they are opened, closed, inserted, or deleted. If no \fIboolean\fR argument is provided, the current state is returned. .TP \fIpathName \fBsort cget\fR \fIoption\fR Returns the current value of the configuration option given by \fIoption\fR. \fIOption\fR may have any of the values accepted by the \fBconfigure\fR operation described below. .TP \fIpathName \fBsort configure\fR ?\fIoption\fR? ?\fIvalue option value ...\fR? Query or modify the sorting configuration options of the widget. If no \fIoption\fR is specified, returns a list describing all of the available options for \fIpathName\fR (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no \fIoption\fR is specified). If one or more \fIoption\-value\fR pairs are specified, then the command modifies the given sorting option(s) to have the given value(s); in this case the command returns an empty string. \fIOption\fR and \fIvalue\fR are described below: .RS .TP \fB\-column\fI string\fR Specifies the column to sort. Entries in the widget are rearranged according to this column. If \fIcolumn\fR is \f(CW""\fR then no sort is performed. .TP \fB\-command\fI string\fR Specifies a Tcl procedure to be called when sorting nodes. The procedure is called with three arguments: the pathname of the widget and the fields of two entries. The procedure returns 1 if the first node is greater than the second, -1 is the second is greater, and 0 if equal. .TP \fB\-decreasing\fI boolean\fR Indicates to sort in ascending/descending order. If \fIboolean\fR is true, then the entries as in descending order. The default is \f(CWno\fR. .TP \fB\-mode\fI string\fR Specifies how to compare entries when sorting. \fIString\fR may be one of the following: .RS .TP 1.5i \f(CWascii\fR Use string comparison based upon the ASCII collation order. .TP 1.5i \f(CWdictionary\fR Use dictionary-style comparison. This is the same as \f(CWascii\fR except (a) case is ignored except as a tie-breaker and (b) if two strings contain embedded numbers, the numbers compare as integers, not characters. For example, "bigBoy" sorts between "bigbang" and "bigboy", and "x10y" sorts between "x9y" and "x11y". .TP 1.5i \f(CWinteger\fR Compares fields as integers. .TP 1.5i \f(CWreal\fR Compares fields as floating point numbers. .TP 1.5i \f(CWcommand\fR Use the Tcl proc specified by the \fB\-command\fR option to compare entries when sorting. If no command is specified, the sort reverts to \f(CWascii\fR sorting. .RE .RE .TP \fIpathName \fBsort once\fR ?\fIflags\fR? \fItagOrId...\fR Sorts the children for each entries specified by \fItagOrId\fR. By default, entries are sorted by name, but you can specify a Tcl proc to do your own comparisons. .RS .TP 1.5i \fB\-recurse\fR Recursively sort the entire branch, not just the children. .RE .RE .TP \fIpathName \fBtag \fIoperation args\fR Tags are a general means of selecting and marking nodes in the tree. A tag is just a string of characters, and it may take any form except that of an integer. The same tag may be associated with many different nodes. .sp Both \fIoperation\fR and its arguments determine the exact behavior of the command. The operations available for tags are listed below. .RS .TP \fIpathName\fR \fBtag add\fR \fIstring\fR \fIid\fR... Adds the tag \fIstring\fR to one of more entries. .TP \fIpathName\fR \fBtag delete\fR \fIstring\fR \fIid\fR... Deletes the tag \fIstring\fR from one or more entries. .TP \fIpathName\fR \fBtag forget\fR \fIstring\fR Removes the tag \fIstring\fR from all entries. It's not an error if no entries are tagged as \fIstring\fR. .TP \fIpathName\fR \fBtag names\fR ?\fIid\fR? Returns a list of tags used. If an \fIid\fR argument is present, only those tags used by the node designated by \fIid\fR are returned. .TP \fIpathName\fR \fBtag nodes\fR \fIstring\fR Returns a list of ids that have the tag \fIstring\fR. If no node is tagged as \fIstring\fR, then an empty string is returned. .RE .TP \fIpathName \fBtext \fIoperation\fR ?\fIargs\fR? This operation is used to provide text editing for cells (data fields in a column) or entry labels. It has several forms, depending on \fIoperation\fR: .RS .TP \fIpathName \fBtext apply\fR Applies the edited buffer, replacing the entry label or data field. The edit window is hidden. .TP \fIpathName \fBtext cancel\fR Cancels the editing operation, reverting the entry label or data value back to the previous value. The edit window is hidden. .TP \fIpathName \fBtext cget\fI value\fR Returns the current value of the configuration option given by \fIoption\fR. \fIOption\fR may have any of the values accepted by the \fBconfigure\fR operation described below. .TP \fIpathName \fBtext configure\fR ?\fIoption value\fR? Query or modify the configuration options of the edit window. If no \fIoption\fR is specified, returns a list describing all of the available options (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no \fIoption\fR is specified). If one or more \fIoption\-value\fR pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. \fIOption\fR and \fIvalue\fR are described in the section .SB "TEXT EDITING OPTIONS" below. .RE .TP \fIpathName \fBtext delete\fI first last\fR Deletes the characters in the edit buffer between the two given character positions. .TP \fIpathName \fBtext get\fR ?\fI\-root\fR? \fIx y\fR .TP \fIpathName \fBtext icursor\fI index\fR .TP \fIpathName \fBtext index\fI index\fR Returns the text index of given \fIindex\fR. .TP \fIpathName \fBtext insert\fI index string\fR Insert the text string \fIstring\fR into the edit buffer at the index \fIindex\fR. For example, the index 0 will prepend the buffer. .TP \fIpathName \fBtext selection\fI args\fR This operation controls the selection of the editing window. Note that this differs from the selection of entries. It has the following forms: .RS .TP \fIpathName \fBtext selection adjust\fI index\fR Adjusts either the first or last index of the selection. .TP \fIpathName \fBtext selection clear\fR Clears the selection. .TP \fIpathName \fBtext selection from\fI index\fR Sets the anchor of the selection. .TP \fIpathName \fBtext selection present\fR Indicates if a selection is present. .TP \fIpathName \fBtext selection range\fI start end\fR Sets both the anchor and mark of the selection. .TP \fIpathName \fBtext selection to\fI index\fR Sets the unanchored end (mark) of the selection. .RE .TP \fIpathName \fBtoggle \fItagOrId\fR Opens or closes the node given by \fItagOrId\fR. If the corresponding \fB\-opencommand\fR or \fB\-closecommand\fR option is set, then that command is also invoked. .TP \fIpathName \fBxview \fIargs\fR This command is used to query and change the horizontal position of the information in the widget's window. It can take any of the following forms: .RS .TP \fIpathName \fBxview\fR Returns a list containing two elements. Each element is a real fraction between 0 and 1; together they describe the horizontal span that is visible in the window. For example, if the first element is .2 and the second element is .6, 20% of the \fBtreeview\fR widget's text is off-screen to the left, the middle 40% is visible in the window, and 40% of the text is off-screen to the right. These are the same values passed to scrollbars via the \fB\-xscrollcommand\fR option. .TP \fIpathName \fBxview\fR \fItagOrId\fR Adjusts the view in the window so that the character position given by \fItagOrId\fR is displayed at the left edge of the window. Character positions are defined by the width of the character \fB0\fR. .TP \fIpathName \fBxview moveto\fI fraction\fR Adjusts the view in the window so that \fIfraction\fR of the total width of the \fBtreeview\fR widget's text is off-screen to the left. \fIfraction\fR must be a fraction between 0 and 1. .TP \fIpathName \fBxview scroll \fInumber what\fR This command shifts the view in the window left or right according to \fInumber\fR and \fIwhat\fR. \fINumber\fR must be an integer. \fIWhat\fR must be either \fBunits\fR or \fBpages\fR or an abbreviation of one of these. If \fIwhat\fR is \fBunits\fR, the view adjusts left or right by \fInumber\fR character units (the width of the \fB0\fR character) on the display; if it is \fBpages\fR then the view adjusts by \fInumber\fR screenfuls. If \fInumber\fR is negative then characters farther to the left become visible; if it is positive then characters farther to the right become visible. .RE .TP \fIpathName \fByview \fI?args\fR? This command is used to query and change the vertical position of the text in the widget's window. It can take any of the following forms: .RS .TP \fIpathName \fByview\fR Returns a list containing two elements, both of which are real fractions between 0 and 1. The first element gives the position of the node at the top of the window, relative to the widget as a whole (0.5 means it is halfway through the treeview window, for example). The second element gives the position of the node just after the last one in the window, relative to the widget as a whole. These are the same values passed to scrollbars via the \fB\-yscrollcommand\fR option. .TP \fIpathName \fByview\fR \fItagOrId\fR Adjusts the view in the window so that the node given by \fItagOrId\fR is displayed at the top of the window. .TP \fIpathName \fByview moveto\fI fraction\fR Adjusts the view in the window so that the node given by \fIfraction\fR appears at the top of the window. \fIFraction\fR is a fraction between 0 and 1; 0 indicates the first node, 0.33 indicates the node one-third the way through the \fBtreeview\fR widget, and so on. .TP \fIpathName \fByview scroll \fInumber what\fR This command adjusts the view in the window up or down according to \fInumber\fR and \fIwhat\fR. \fINumber\fR must be an integer. \fIWhat\fR must be either \fBunits\fR or \fBpages\fR. If \fIwhat\fR is \fBunits\fR, the view adjusts up or down by \fInumber\fR lines; if it is \fBpages\fR then the view adjusts by \fInumber\fR screenfuls. If \fInumber\fR is negative then earlier nodes become visible; if it is positive then later nodes become visible. .RE .SH "TREEVIEW OPTIONS" In addition to the \fBconfigure\fR operation, widget configuration options may also be set by the Tk \fBoption\fR command. The class resource name is \f(CWTreeView\fR. .CS option add *TreeView.Foreground white option add *TreeView.Background blue .CE The following widget options are available: .TP \fB\-activebackground \fIcolor\fR Sets the background color for active entries. A node is active when the mouse passes over it's entry or using the \fBactivate\fR operation. .TP \fB\-activeforeground \fIcolor\fR Sets the foreground color of the active node. A node is active when the mouse passes over it's entry or using the \fBactivate\fR operation. .TP \fB\-activeicons \fIimages\fR Specifies images to be displayed for an entry's icon when it is active. \fIImages\fR is a list of two Tk images: the first image is displayed when the node is open, the second when it is closed. .TP \fB\-autocreate \fIboolean\fR If \fIboolean\fR is true, automatically create missing ancestor nodes when inserting new nodes. Otherwise flag an error. The default is \f(CWno\fR. .TP \fB\-allowduplicates \fIboolean\fR If \fIboolean\fR is true, allow nodes with duplicate pathnames when inserting new nodes. Otherwise flag an error. The default is \f(CWno\fR. .TP \fB\-background \fIcolor\fR Sets the background color of the widget. The default is \f(CWwhite\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\-closecommand \fIstring\fR Specifies a Tcl script to be invoked when a node is closed. You can overrider this for individual entries using the entry's \fB\-closecommand\fR option. The default is \f(CW""\fR. Percent substitutions are performed on \fIstring\fR before it is executed. The following substitutions are valid: .RS .TP 5 \f(CW%W\fR The pathname of the widget. .TP 5 \f(CW%p\fR The name of the node. .TP 5 \f(CW%P\fR The full pathname of the node. .TP 5 \f(CW%#\fR The id of the node. .TP 5 \f(CW%%\fR Translates to a single percent. .RE .TP \fB\-cursor \fIcursor\fR Specifies the widget's cursor. The default cursor is \f(CW""\fR. .TP \fB\-dashes \fInumber\fR Sets the dash style of the horizontal and vertical lines drawn connecting entries. \fINumber\fR is the length in pixels of the dashes and gaps in the line. If \fInumber\fR is \f(CW0\fR, solid lines will be drawn. The default is \f(CW1\fR (dotted). .TP \fB\-exportselection \fIboolean\fR Indicates if the selection is exported. If the widget is exporting its selection then it will observe the standard X11 protocols for handling the selection. Selections are available as type \fBSTRING\fR; the value of the selection will be the label of the selected nodes, separated by newlines. The default is \f(CWno\fR. .TP \fB\-flat \fIboolean\fR Indicates whether to display the tree as a flattened list. If \fIboolean\fR is true, then the hierarchy will be a list of full paths for the nodes. This option also has affect on sorting. See the .SB "SORT OPERATIONS" section for more information. The default is \f(CWno\fR. .TP \fB\-focusdashes \fIdashList\fR Sets the dash style of the outline rectangle drawn around the entry label of the node that current has focus. \fINumber\fR is the length in pixels of the dashes and gaps in the line. If \fInumber\fR is \f(CW0\fR, a solid line will be drawn. The default is \f(CW1\fR. .TP \fB\-focusforeground \fIcolor\fR Sets the color of the focus rectangle. The default is \f(CWblack\fR. .TP \fB\-font \fIfontName\fR Specifies the font for entry labels. You can override this for individual entries with the entry's \fB\-font\fR configuration option. The default is \f(CW*-Helvetica-Bold-R-Normal-*-12-120-*\fR. .TP \fB\-foreground \fIcolor\fR Sets the text color of entry labels. You can override this for individual entries with the entry's \fB\-foreground\fR configuration option. The default is \f(CWblack\fR. .TP \fB\-height \fIpixels\fR Specifies the requested height of widget. The default is \f(CW400\fR. .TP \fB\-hideroot \fIboolean\fR If \fIboolean\fR is true, it indicates that no entry for the root node should be displayed. The default is \f(CWno\fR. .TP \fB\-highlightbackground \fIcolor\fR Specifies the normal color of the traversal highlight region when the widget does not have the input focus. .TP \fB\-highlightcolor \fIcolor\fR Specifies the color of the traversal highlight rectangle when the widget has the input focus. The default is \f(CWblack\fR. .TP \fB\-highlightthickness \fIpixels\fR Specifies the width of the highlight rectangle indicating when the widget has input focus. The value may have any of the forms acceptable to \fBTk_GetPixels\fR. If the value is zero, no focus highlight will be displayed. The default is \f(CW2\fR. .TP \fB\-icons \fIimages\fR Specifies images for the entry's icon. \fIImages\fR is a list of two Tk images: the first image is displayed when the node is open, the second when it is closed. .TP \fB\-linecolor \fIcolor\fR Sets the color of the connecting lines drawn between entries. The default is \f(CWblack\fR. .TP \fB\-linespacing \fIpixels\fR Sets the number of pixels spacing between entries. The default is \f(CW0\fR. .TP \fB\-linewidth \fIpixels\fR Set the width of the lines drawn connecting entries. If \fIpixels\fR is \f(CW0\fR, no vertical or horizontal lines are drawn. The default is \f(CW1\fR. .TP \fB\-opencommand \fIstring\fR Specifies a Tcl script to be invoked when a node is open. You can override this for individual entries with the entry's \fB\-opencommand\fR configuration option. The default is \f(CW""\fR. Percent substitutions are performed on \fIstring\fR before it is executed. The following substitutions are valid: .RS .TP 5 \f(CW%W\fR The pathname of the widget. .TP 5 \f(CW%p\fR The name of the node. .TP 5 \f(CW%P\fR The full pathname of the node. .TP 5 \f(CW%#\fR The id of the node. .TP 5 \f(CW%%\fR Translates to a single percent. .RE .TP \fB\-relief \fIrelief\fR Specifies the 3-D effect for the widget. \fIRelief\fR specifies how the \fBtreeview\fR widget should appear relative to widget it is packed into; for example, \f(CWraised\fR means the \fBtreeview\fR widget should appear to protrude. The default is \f(CWsunken\fR. .TP \fB\-scrollmode \fImode\fR Specifies the style of scrolling to be used. The following styles are valid. This is the default is \f(CWhierbox\fR. .RS .TP 1.25i \f(CWlistbox\fR Like the \fBlistbox\fR widget, the last entry can always be scrolled to the top of the widget window. This allows the scrollbar thumb to shrink as the last entry is scrolled upward. .TP 1.25i \f(CWhierbox\fR Like the \fBhierbox\fR widget, the last entry can only be viewed at the bottom of the widget window. The scrollbar stays a constant size. .TP 1.25i \f(CWcanvas\fR Like the \fBcanvas\fR widget, the entries are bound within the scrolling area. .RE .TP \fB\-selectbackground \fIcolor\fR Sets the background color selected node entries. The default is \f(CW#ffffea\fR. .TP \fB\-selectborderwidth \fIpixels\fR Sets the width of the raised 3-D border drawn around the labels of selected entries. The default is \f(CW0\fR. \fB\-selectcommand \fIstring\fR Specifies a Tcl script to invoked when the set of selected nodes changes. The default is \f(CW""\fR. .TP \fB\-selectforeground \fIcolor\fB Sets the color of the labels of selected node entries. The default is \f(CWblack\fR. .TP \fB\-selectmode \fImode\fR Specifies the selection mode. If \fImode\fR is \f(CWsingle\fR, only one node can be selected at a time. If \f(CWmultiple\fR more than one node can be selected. The default is \f(CWsingle\fR. .TP \fB\-separator \fIstring\fR Specifies the character sequence to use when spliting the path components. The separator may be several characters wide (such as "::") Consecutive separators in a pathname are treated as one. If \fIstring\fR is the empty string, the pathnames are Tcl lists. Each element is a path component. The default is \f(CW""\fR. .TP \fB\-showtitles \fIboolean\fR If \fIboolean\fR is false, column titles are not be displayed. The default is \f(CWyes\fR. .TP \fB\-sortselection \fIboolean\fR If \fIboolean\fR is true, nodes in the selection are ordered as they are currently displayed (depth-first or sorted), not in the order they were selected. The default is \f(CWno\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"1"\fR. .TP \fB\-trim \fIstring\fR Specifies a string leading characters to trim from entry pathnames before parsing. This only makes sense if the \fB\-separator\fR is also set. The default is \f(CW""\fR. .TP \fB\-width \fIpixels\fR Sets the requested width of the widget. If \fIpixels\fR is 0, then the with is computed from the contents of the \fBtreeview\fR widget. The default is \f(CW200\fR. .TP \fB\-xscrollcommand \fIstring\fR Specifies the prefix for a command used to communicate with horizontal scrollbars. Whenever the horizontal view in the widget's window changes, the widget will generate a Tcl command by concatenating the scroll command and two numbers. If this option is not specified, then no command will be executed. .TP \fB\-xscrollincrement\fR \fIpixels\fR Sets the horizontal scrolling distance. The default is 20 pixels. .TP \fB\-yscrollcommand \fIstring\fR Specifies the prefix for a command used to communicate with vertical scrollbars. Whenever the vertical view in the widget's window changes, the widget will generate a Tcl command by concatenating the scroll command and two numbers. If this option is not specified, then no command will be executed. .TP \fB\-yscrollincrement\fR \fIpixels\fR Sets the vertical scrolling distance. The default is 20 pixels. .SH "ENTRY OPTIONS" Many widget configuration options have counterparts in entries. For example, there is a \fB\-closecommand\fR configuration option for both widget itself and for individual entries. Options set at the widget level are global for all entries. If the entry configuration option is set, then it overrides the widget option. This is done to avoid wasting memory by replicated options. Most entries will have redundant options. .PP There is no resource class or name for entries. .TP \fB\-activeicons \fIimages\fR Specifies images to be displayed as the entry's icon when it is active. This overrides the global \fB\-activeicons\fR configuration option for the specific entry. \fIImages\fR is a list of two Tk images: the first image is displayed when the node is open, the second when it is closed. .TP \fB\-bindtags \fItagList\fR Specifies the binding tags for nodes. \fITagList\fR is a list of binding tag names. The tags and their order will determine how events are handled for nodes. 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\-button \fIstring\fR Indicates whether a button should be displayed on the left side of the node entry. \fIString\fR can be \f(CWyes\fR, \f(CWno\fR, or \f(CWauto\fR. If \f(CWauto\fR, then a button is automatically displayed if the node has children. This is the default. .TP \fB\-closecommand \fIstring\fR Specifies a Tcl script to be invoked when the node is closed. This overrides the global \fB\-closecommand\fR option for this entry. The default is \f(CW""\fR. Percent substitutions are performed on \fIstring\fR before it is executed. The following substitutions are valid: .RS .TP 5 \f(CW%W\fR The pathname of the widget. .TP 5 \f(CW%p\fR The name of the node. .TP 5 \f(CW%P\fR The full pathname of the node. .TP 5 \f(CW%#\fR The id of the node. .TP 5 \f(CW%%\fR Translates to a single percent. .RE .TP \fB\-data \fIstring\fR Sets data fields for the node. \fIString\fR is a list of name-value pairs to be set. The default is \f(CW""\fR. .TP \fB\-font \fIfontName\fR Sets the font for entry labels. This overrides the widget's \fB\-font\fR option for this node. The default is \f(CW*-Helvetica-Bold-R-Normal-*-12-120-*\fR. .TP \fB\-foreground \fIcolor\fR Sets the text color of the entry label. This overrides the widget's \fB\-foreground\fR configuration option. The default is \f(CW""\fR. .TP \fB\-icons \fIimages\fR Specifies images to be displayed for the entry's icon. This overrides the global \fB\-icons\fR configuration option. \fIImages\fR is a list of two Tk images: the first image is displayed when the node is open, the second when it is closed. .TP \fB\-label \fIstring\fR Sets the text for the entry's label. If not set, this defaults to the name of the node. The default is \f(CW""\fR. .TP \fB\-opencommand \fIstring\fR Specifies a Tcl script to be invoked when the entry is opened. This overrides the widget's \fB\-opencommand\fR option for this node. The default is \f(CW""\fR. Percent substitutions are performed on \fIstring\fR before it is executed. The following substitutions are valid: .RS .TP 5 \f(CW%W\fR The pathname of the widget. .TP 5 \f(CW%p\fR The name of the node. .TP 5 \f(CW%P\fR The full pathname of the node. .TP 5 \f(CW%#\fR The id of the node. .TP 5 \f(CW%%\fR Translates to a single percent. .RE .SH "BUTTON OPTIONS" Button configuration options may also be set by the \fBoption\fR command. The resource subclass is \f(CWButton\fR. The resource name is always \f(CWbutton\fR. .CS option add *TreeView.Button.Foreground white option add *TreeView.button.Background blue .CE The following are the configuration options available for buttons. .TP \fB\-activebackground \fIcolor\fR Sets the background color of active buttons. A button is made active when the mouse passes over it or by the \fBbutton activate\fR operation. .TP \fB\-activeforeground \fIcolor\fR Sets the foreground color of active buttons. A button is made active when the mouse passes over it or by the \fBbutton activate\fR operation. .TP \fB\-background \fIcolor\fR Sets the background of the button. The default is \f(CWwhite\fR. .TP \fB\-borderwidth \fIpixels\fR Sets the width of the 3\-D border around the button. The \fB\-relief\fR option determines if a border is to be drawn. The default is \f(CW1\fR. .TP \fB\-closerelief \fIrelief\fR Specifies the 3-D effect for the closed button. \fIRelief\fR indicates how the button should appear relative to the widget; for example, \f(CWraised\fR means the button should appear to protrude. The default is \f(CWsolid\fR. .TP \fB\-cursor \fIcursor\fR Sets the widget's cursor. The default cursor is \f(CW""\fR. .TP \fB\-foreground \fIcolor\fR Sets the foreground color of buttons. The default is \f(CWblack\fR. .TP \fB\-images \fIimages\fR Specifies images to be displayed for the button. \fIImages\fR is a list of two Tk images: the first image is displayed when the button is open, the second when it is closed. If the \fIimages\fR is the empty string, then a plus/minus gadget is drawn. The default is \f(CW""\fR. .TP \fB\-openrelief \fIrelief\fR Specifies the 3-D effect of the open button. \fIRelief\fR indicates how the button should appear relative to the widget; for example, \f(CWraised\fR means the button should appear to protrude. The default is \f(CWflat\fR. .TP \fB\-size \fIpixels\fR Sets the requested size of the button. The default is \f(CW0\fR. .RE .SH "COLUMN OPTIONS" Column configuration options may also be set by the \fBoption\fR command. The resource subclass is \f(CWColumn\fR. The resource name is the name of the column. .CS option add *TreeView.Column.Foreground white option add *TreeView.treeView.Background blue .CE The following configuration options are available for columns. .TP \fB\-background \fIcolor\fR Sets the background color of the column. This overrides the widget's \fB\-background\fR option. The default is \f(CWwhite\fR. .TP \fB\-borderwidth \fIpixels\fR Sets the width of the 3\-D border of the column. The \fB\-relief\fR option determines if a border is to be drawn. The default is \f(CW0\fR. .TP \fB\-edit \fIboolean\fR Indicates if the column's data fields can be edited. If \fIboolean\fR is false, the data fields in the column may not be edited. The default is \f(CWyes\fR. .TP \fB\-foreground \fIcolor\fR Specifies the foreground color of the column. You can override this for individual entries with the entry's \fB\-foreground\fR option. The default is \f(CWblack\fR. .TP \fB\-font \fIfontName\fR Sets the font for a column. You can override this for individual entries with the entry's \fB\-font\fR option. The default is \f(CW*-Helvetica-Bold-R-Normal-*-12-120-*\fR. .TP \fB\-hide \fIboolean\fR If \fIboolean\fR is true, the column is not displayed. The default is \f(CWyes\fR. .TP \fB\-justify \fIjustify\fR Specifies how the column data fields title should be justified within the column. This matters only when the column is wider than the data field to be display. \fIJustify\fR must be \f(CWleft\fR, \f(CWright\fR, or \f(CWcenter\fR. The default is \f(CWleft\fR. .TP \fB\-pad \fIpad\fR Specifies how much padding for the left and right sides of the column. \fIPad\fR is a list of one or two screen distances. If \fIpad\fR has two elements, the left side of the column 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(CW2\fR. .TP \fB\-relief \fIrelief\fR Specifies the 3-D effect of the column. \fIRelief\fR specifies how the column should appear relative to the widget; for example, \f(CWraised\fR means the column should appear to protrude. The default is \f(CWflat\fR. .TP \fB\-state \fIstate\fR Sets the state of the column. If \fIstate\fR is \f(CWdisable\fR then the column title can not be activated nor invoked. The default is \f(CWnormal\fR. .TP \fB\-text \fIstring\fR Sets the title for the column. The default is \f(CW""\fR. .TP \fB\-titleforeground \fIcolor\fR Sets the foreground color of the column title. The default is \f(CWblack\fR. .TP \fB\-titleshadow \fIcolor\fR Sets the color of the drop shadow of the column title. The default is \f(CW""\fR. .TP \fB\-width \fIpixels\fR Sets the requested width of the column. This overrides the computed with of the column. If \fIpixels\fR is 0, the width is computed as from the contents of the column. The default is \f(CW0\fR. .RE .SH "TEXT EDITING OPTIONS" Text edit window configuration options may also be set by the \fBoption\fR command. The resource class is \f(CWTreeViewEditor\fR. The resource name is always \f(CWedit\fR. .CS option add *TreeViewEditor.Foreground white option add *edit.Background blue .CE The following are the configuration options available for the text editing window. .TP \fB\-background \fIcolor\fR Sets the background of the text edit window. The default is \f(CWwhite\fR. .TP \fB\-borderwidth \fIpixels\fR Sets the width of the 3\-D border around the edit window. The \fB\-relief\fR option determines if a border is to be drawn. The default is \f(CW1\fR. .TP \fB\-exportselection \fIboolean\fR Indicates if the text selection is exported. If the edit window is exporting its selection then it will observe the standard X11 protocols for handling the selection. Selections are available as type \fBSTRING\fR. The default is \f(CWno\fR. .TP \fB\-relief \fIrelief\fR Specifies the 3-D effect of the edit window. \fIRelief\fR indicates how the background should appear relative to the edit window; for example, \f(CWraised\fR means the background should appear to protrude. The default is \f(CWsolid\fR. .TP \fB\-selectbackground \fIcolor\fR Sets the background of the selected text in the edit window. The default is \f(CWwhite\fR. .TP \fB\-selectborderwidth \fIpixels\fR Sets the width of the 3\-D border around the selected text in the edit window. The \fB\-selectrelief\fR option determines if a border is to be drawn. The default is \f(CW1\fR. .TP \fB\-selectforeground \fIcolor\fR Sets the foreground of the selected text in the edit window. The default is \f(CWwhite\fR. .TP \fB\-selectrelief \fIrelief\fR Specifies the 3-D effect of the selected text in the edit window. \fIRelief\fR indicates how the text should appear relative to the edit window; for example, \f(CWraised\fR means the text should appear to protrude. The default is \f(CWflat\fR. .RE .SH "DEFAULT BINDINGS" Tk automatically creates class bindings for treeviews that give them Motif-like behavior. Much of the behavior of a \fBtreeview\fR widget is determined by its \fB\-selectmode\fR option, which selects one of two ways of dealing with the selection. .PP If the selection mode is \fBsingle\fR, only one node can be selected at a time. Clicking button 1 on an node selects it and deselects any other selected item. .PP If the selection mode is \fBmultiple\fR, any number of entries may be selected at once, including discontiguous ranges. Clicking Control-Button-1 on a node entry toggles its selection state without affecting any other entries. Pressing Shift-Button-1 on a node entry selects it, extends the selection. .IP [1] In \fBextended\fR mode, the selected range can be adjusted by pressing button 1 with the Shift key down: this modifies the selection to consist of the entries between the anchor and the entry under the mouse, inclusive. The un-anchored end of this new selection can also be dragged with the button down. .IP [2] In \fBextended\fR mode, pressing button 1 with the Control key down starts a toggle operation: the anchor is set to the entry under the mouse, and its selection state is reversed. The selection state of other entries isn't changed. If the mouse is dragged with button 1 down, then the selection state of all entries between the anchor and the entry under the mouse is set to match that of the anchor entry; the selection state of all other entries remains what it was before the toggle operation began. .IP [3] If the mouse leaves the treeview window with button 1 down, the window scrolls away from the mouse, making information visible that used to be off-screen on the side of the mouse. The scrolling continues until the mouse re-enters the window, the button is released, or the end of the hierarchy is reached. .IP [4] Mouse button 2 may be used for scanning. If it is pressed and dragged over the \fBtreeview\fR widget, the contents of the hierarchy drag at high speed in the direction the mouse moves. .IP [5] If the Up or Down key is pressed, the location cursor (active entry) moves up or down one entry. If the selection mode is \fBbrowse\fR or \fBextended\fR then the new active entry is also selected and all other entries are deselected. In \fBextended\fR mode the new active entry becomes the selection anchor. .IP [6] In \fBextended\fR mode, Shift-Up and Shift-Down move the location cursor (active entry) up or down one entry and also extend the selection to that entry in a fashion similar to dragging with mouse button 1. .IP [7] The Left and Right keys scroll the \fBtreeview\fR widget view left and right by the width of the character \fB0\fR. Control-Left and Control-Right scroll the \fBtreeview\fR widget view left and right by the width of the window. Control-Prior and Control-Next also scroll left and right by the width of the window. .IP [8] The Prior and Next keys scroll the \fBtreeview\fR widget view up and down by one page (the height of the window). .IP [9] The Home and End keys scroll the \fBtreeview\fR widget horizontally to the left and right edges, respectively. .IP [10] Control-Home sets the location cursor to the the first entry, selects that entry, and deselects everything else in the widget. .IP [11] Control-End sets the location cursor to the the last entry, selects that entry, and deselects everything else in the widget. .IP [12] In \fBextended\fR mode, Control-Shift-Home extends the selection to the first entry and Control-Shift-End extends the selection to the last entry. .IP [13] In \fBmultiple\fR mode, Control-Shift-Home moves the location cursor to the first entry and Control-Shift-End moves the location cursor to the last entry. .IP [14] The space and Select keys make a selection at the location cursor (active entry) just as if mouse button 1 had been pressed over this entry. .IP [15] In \fBextended\fR mode, Control-Shift-space and Shift-Select extend the selection to the active entry just as if button 1 had been pressed with the Shift key down. .IP [16] In \fBextended\fR mode, the Escape key cancels the most recent selection and restores all the entries in the selected range to their previous selection state. .IP [17] Control-slash selects everything in the widget, except in \fBsingle\fR and \fBbrowse\fR modes, in which case it selects the active entry and deselects everything else. .IP [18] Control-backslash deselects everything in the widget, except in \fBbrowse\fR mode where it has no effect. .IP [19] The F16 key (labelled Copy on many Sun workstations) or Meta-w copies the selection in the widget to the clipboard, if there is a selection. .PP The behavior of \fBtreeview\fR widgets can be changed by defining new bindings for individual widgets or by redefining the class bindings. .SS WIDGET BINDINGS In addition to the above behavior, the following additional behavior is defined by the default widget class (TreeView) bindings. .IP \f(CW\fR Starts scanning. .IP \f(CW\fR Adjusts the scan. .IP \f(CW\fR Stops scanning. .IP \f(CW\fR Starts auto-scrolling. .IP \f(CW\fR Starts auto-scrolling .IP \f(CW\fR Moves the focus to the previous entry. .IP \f(CW\fR Moves the focus to the next entry. .IP \f(CW\fR Moves the focus to the previous sibling. .IP \f(CW\fR Moves the focus to the next sibling. .IP \f(CW\fR Moves the focus to first entry. Closed or hidden entries are ignored. .IP \f(CW\fR Move the focus to the last entry. Closed or hidden entries are ignored. .IP \f(CW\fR Closes the entry. It is not an error if the entry has no children. .IP \f(CW\fR Opens the entry, displaying its children. It is not an error if the entry has no children. .IP \f(CW\fR In "single" select mode this selects the entry. In "multiple" mode, it toggles the entry (if it was previous selected, it is not deselected). .IP \f(CW\fR Turns off select mode. .IP \f(CW\fR Sets the focus to the current entry. .IP \f(CW\fR Turns off select mode. .IP \f(CW\fR Moves to the next entry whose label starts with the letter typed. .IP \f(CW\fR Moves the focus to first entry. Closed or hidden entries are ignored. .IP \f(CW\fR Move the focus to the last entry. Closed or hidden entries are ignored. .IP \f(CW\fR Opens all entries. .IP \f(CW\fR Closes all entries (except root). .SS BUTTON BINDINGS Buttons have bindings. There are associated with the "all" bindtag (see the entry's -bindtag option). You can use the \fBbind\fR operation to change them. .IP \f(CW\fR Highlights the button of the current entry. .IP \f(CW\fR Returns the button back to its normal state. .IP \f(CW\fR Adjust the view so that the current entry is visible. .SS ENTRY BINDINGS Entries have default bindings. There are associated with the "all" bindtag (see the entry's -bindtag option). You can use the \fBbind\fR operation to modify them. .IP \f(CW\fR Highlights the current entry. .IP \f(CW\fR Returns the entry back to its normal state. .IP \f(CW\fR Sets the selection anchor the current entry. .IP \f(CW\fR Toggles the selection of the current entry. .IP \f(CW\fR For "multiple" mode only. Saves the current location of the pointer for auto-scrolling. Resets the selection mark. .IP \f(CW\fR For "multiple" mode only. Sets the selection anchor to the current entry. .IP \f(CW\fR For "multiple" mode only. Extends the selection. .IP \f(CW\fR Place holder. Does nothing. .IP \f(CW\fR Place holder. Does nothing. .IP \f(CW\fR Stop auto-scrolling. .IP \f(CW\fR For "multiple" mode only. Toggles and extends the selection. .IP \f(CW\fR Place holder. Does nothing. .IP \f(CW\fR Place holder. Does nothing. .IP \f(CW\fR Stops auto-scrolling. .IP \f(CW\fR ??? .IP \f(CW\fR Place holder. Does nothing. .IP \f(CW\fR Place holder. Does nothing. .SS COLUMN BINDINGS Columns have bindings too. They are associated with the column's "all" bindtag (see the column -bindtag option). You can use the \fBcolumn bind\fR operation to change them. .IP \f(CW\fR Highlights the current column title. .IP \f(CW\fR Returns the column back to its normal state. .IP \f(CW\fR Invokes the command (see the column's -command option) if one if specified. .SS COLUMN RULE BINDINGS .IP \f(CW\fR Highlights the current and activates the ruler. .IP \f(CW\fR Returns the column back to its normal state. Deactivates the ruler. .IP \f(CW\fR Sets the resize anchor for the column. .IP \f(CW\fR Sets the resize mark for the column. .IP \f(CW\fR Adjust the size of the column, based upon the resize anchor and mark positions. .SH EXAMPLE The \fBtreeview\fR command creates a new widget. .CS treeview .h \-bg white .CE A new Tcl command \f(CW.h\fR is also created. This command can be used to query and modify the \fBtreeview\fR widget. For example, to change the background color of the table to "green", you use the new command and the widget's \fBconfigure\fR operation. .CS # Change the background color. \&.h configure \-background "green" .CE By default, the \fBtreeview\fR widget will automatically create a new tree object to contain the data. The name of the new tree is the pathname of the widget. Above, the new tree object name is ".h". But you can use the \fB\-tree\fR option to specify the name of another tree. .CS # View the tree "myTree". \&.h configure \-tree "myTree" .CE When a new tree is created, it contains only a root node. The node is automatically opened. The id of the root node is always \f(CW0\fR (you can use also use the special id \f(CWroot\fR). The \fBinsert\fR operation lets you insert one or more new entries into the tree. The last argument is the node's \fIpathname\fR. .CS # Create a new entry named "myEntry" set id [\&.h insert end "myEntry"] .CE This appends a new node named "myEntry". It will positioned as the last child of the root of the tree (using the position "end"). You can supply another position to order the node within its siblings. .CS # Prepend "fred". set id [\&.h insert 0 "fred"] .CE Entry names do not need to be unique. By default, the node's label is its name. To supply a different text label, add the \fB\-label\fR option. .CS # Create a new node named "fred" set id [\&.h insert end "fred" -label "Fred Flintstone"] .CE The \fBinsert\fR operation returns the id of the new node. You can also use the \fBindex\fR operation to get this information. .CS # Get the id of "fred" \&.h index "fred" .CE To insert a node somewhere other than root, use the \fB\-at\fR switch. It takes the id of the node where the new child will be added. .CS # Create a new node "barney" in "fred". \&.h insert -at $id end "barney" .CE A pathname describes the path to an entry in the hierarchy. It's a list of entry names that compose the path in the tree. Therefore, you can also add "barney" to "fred" as follows. .CS # Create a new sub-entry of "fred" \&.h insert end "fred barney" .CE Every name in the list is ancestor of the next. All ancestors must already exist. That means that an entry "fred" is an ancestor of "barney" and must already exist. But you can use the \fB\-autocreate\fR configuration option to force the creation of ancestor nodes. .CS # Force the creation of ancestors. \&.h configure -autocreate yes \&.h insert end "fred barney wilma betty" .CE Sometimes the pathname is already separated by a character sequence rather than formed as a list. A file name is a good example of this. You can use the \fB\-separator\fR option to specify a separator string to split the path into its components. Each pathname inserted is automatically split using the separator string as a separator. Multiple separators are treated as one. .CS \&.h configure -separator / \&.h insert end "/usr/local/tcl/bin" .CE If the path is prefixed by extraneous characters, you can automatically trim it off using the \fB\-trim\fR option. It removed the string from the path before it is parsed. .CS \&.h configure -trim C:/windows -separator / \&.h insert end "C:/window/system" .CE You can insert more than one entry at a time with the \fBinsert\fR operation. This can be much faster than looping over a list of names. .CS # The slow way foreach f [glob $dir/*] { \&.h insert end $f } # The fast way eval .h insert end [glob $dir/*] .CE In this case, the \fBinsert\fR operation will return a list of ids of the new entries. .PP You can delete entries with the \fBdelete\fR operation. It takes one or more tags of ids as its argument. It deletes the entry and all its children. .CS \&.h delete $id .CE Entries have several configuration options. They control the appearance of the entry's icon and label. We have already seen the \fB\-label\fR option that sets the entry's text label. The \fBentry configure\fR operation lets you set or modify an entry's configuration options. .CS \&.h entry configure $id -color red -font fixed .CE You can hide an entry and its children using the \fB\-hide\fR option. .CS \&.h entry configure $id -hide yes .CE More that one entry can be configured at once. All entries specified are configured with the same options. .CS \&.h entry configure $i1 $i2 $i3 $i4 -color brown .CE An icon is displayed for each entry. It's a Tk image drawn to the left of the label. You can set the icon with the entry's \fB\-icons\fR option. It takes a list of two image names: one to represent the open entry, another when it is closed. .CS set im1 [image create photo -file openfolder.gif] set im2 [image create photo -file closefolder.gif] \&.h entry configure $id -icons "$im1 $im2" .CE If \fB\-icons\fR is set to the empty string, no icons are display. .PP If an entry has children, a button is displayed to the left of the icon. Clicking the mouse on this button opens or closes the sub-hierarchy. The button is normally a \f(CW+\fR or \f(CW\-\fR symbol, but can be configured in a variety of ways using the \fBbutton configure\fR operation. For example, the \f(CW+\fR and \f(CW\-\fR symbols can be replaced with Tk images. .CS set im1 [image create photo -file closefolder.gif] set im2 [image create photo -file downarrow.gif] \&.h button configure $id -images "$im1 $im2" \\ -openrelief raised -closerelief raised .CE Entries can contain an arbitrary number of \fIdata fields\fR. Data fields are name-value pairs. Both the value and name are strings. The entry's \fB\-data\fR option lets you set data fields. .CS \&.h entry configure $id -data {mode 0666 group users} .CE The \fB\-data\fR takes a list of name-value pairs. .PP You can display these data fields as \fIcolumns\fR in the \fBtreeview\fR widget. You can create and configure columns with the \fBcolumn\fR operation. For example, to add a new column to the widget, use the \fBcolumn insert\fR operation. The last argument is the name of the data field that you want to display. .CS \&.h column insert end "mode" .CE The column title is displayed at the top of the column. By default, it's is the field name. You can override this using the column's \fB\-text\fR option. .CS \&.h column insert end "mode" -text "File Permissions" .CE Columns have several configuration options. The \fBcolumn configure\fR operation lets you query or modify column options. .CS \&.h column configure "mode" -justify left .CE The \fB\-justify\fR option says how the data is justified within in the column. The \fB\-hide\fR option indicates whether the column is displayed. .CS \&.h column configure "mode" -hide yes .CE Entries can be selected by clicking on the mouse. Selected entries are drawn using the colors specified by the \fB\-selectforeground\fR and \fB\-selectbackground\fR configuration options. The selection itself is managed by the \fBselection\fR operation. .CS # Clear all selections \&.h selection clear 0 end # Select the root node \&.h selection set 0 .CE The \fBcurselection\fR operation returns a list of ids of all the selected entries. .CS set ids [\&.h curselection] .CE You can use the \fBget\fR operation to convert the ids to their pathnames. .CS set names [eval .h get -full $ids] .CE If a treeview is exporting its selection (using the \fB\-exportselection\fR option), then it will observe the standard X11 protocols for handling the selection. Treeview selections are available as type \fBSTRING\fR; the value of the selection will be the pathnames of the selected entries, separated by newlines. .PP The \fBtreeview\fR supports two modes of selection: \f(CWsingle\fR and \f(CWmultiple\fR. In single select mode, only one entry can be selected at a time, while multiple select mode allows several entries to be selected. The mode is set by the widget's \fB\-selectmode\fR option. .CS \&.h configure -selectmode "multiple" .CE You can be notified when the list of selected entries changes. The widget's \fB\-selectcommand\fR specifies a Tcl procedure that is called whenever the selection changes. .CS proc SelectNotify { widget } { set ids [\&$widget curselection] } \&.h configure -selectcommand "SelectNotify .h" .CE The widget supports the standard Tk scrolling and scanning operations. The \fBtreeview\fR can be both horizontally and vertically. You can attach scrollbars to the \fBtreeview\fR the same way as the listbox or canvas widgets. .CS scrollbar .xbar -orient horizontal -command ".h xview" scrollbar .ybar -orient vertical -command ".h yview" \&.h configure -xscrollcommand ".xbar set" \\ -yscrollcommand ".ybar set" .CE There are three different modes of scrolling: \f(CWlistbox\fR, \f(CWcanvas\fR, and \f(CWhierbox\fR. In \f(CWlistbox\fR mode, the last entry can always be scrolled to the top of the widget. In \f(CWhierbox\fR mode, the last entry is always drawn at the bottom of the widget. The scroll mode is set by the widget's \fB\-selectmode\fR option. .CS \&.h configure -scrollmode "listbox" .CE Entries can be programmatically opened or closed using the \fBopen\fR and \fBclose\fR operations respectively. .CS \&.h open $id \&.h close $id .CE When an entry is opened, a Tcl procedure can be automatically invoked. The \fB\-opencommand\fR option specifies this procedure. This procedure can lazily insert entries as needed. .CS proc AddEntries { dir } { eval .h insert end [glob -nocomplain $dir/*] } \&.h configure -opencommand "AddEntries %P" .CE Now when an entry is opened, the procedure \f(CWAddEntries\fR is called and adds children to the entry. Before the command is invoked, special "%" substitutions (like \fBbind\fR) are performed. Above, \f(CW%P\fR is translated to the pathname of the entry. .PP The same feature exists when an entry is closed. The \fB\-closecommand\fR option specifies the procedure. .CS proc DeleteEntries { id } { .h entry delete $id 0 end } \&.h configure -closecommand "DeleteEntries %#" .CE When an entry is closed, the procedure \f(CWDeleteEntries\fR is called and deletes the entry's children using the \fBentry delete\fR operation (\f(CW%#\fR is the id of entry). .SH KEYWORDS treeview, widget blt-2.4z.orig/man/hiertable.mann0100644000175000017500000025372107434255426015356 0ustar dokodoko'\" '\" Copyright 2001-2 by Silicon Metrics Corporation. '\" '\" 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 Silicon Metrics or any of their entities not be used '\" in advertising or publicity pertaining to distribution of the software '\" without specific, written prior permission. '\" '\" Silicon Metrics disclaims all warranties with regard to this software, '\" including all implied warranties of merchantability and fitness. In no event '\" shall Silicon Metrics 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. '\" '\" The hierarchical table widget created by George Howlett. '\" .so man.macros .TH treeview n BLT_VERSION BLT "BLT Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME treeview \- Create and manipulate hierarchical table widgets .BE .SH SYNOPSIS \fBtreeview\fR \fIpathName \fR?\fIoptions\fR? .SH DESCRIPTION The \fBtreeview\fR widget displays a tree of data. It replaces both the \fBhiertable\fR and \fBhierbox\fR widgets. The \fBtreeview\fR is 100% syntax compatible with the \fBhiertable\fR widget. The \fBhiertable\fR command is retained for sake of script-level compatibility. This widget obsoletes the \fBhierbox\fR widget. It does everything the old \fBhierbox\fR widget did, but also provides data sharing (via \fItree data objects\fR) and the ability to tag nodes. .SH INTRODUCTION The \fBtreeview\fR widget displays hierarchical data. Data is represented as nodes in a general-ordered tree. Each node may have sub-nodes and these nodes can in turn has their own children. .PP A node is displayed as a row entry in the widget. Each entry has a text label and icon. When a node has children, its entry is drawn with a small button to the left of the label. Clicking the mouse over this button opens or closes the node. When a node is \fIopen\fR, its children are exposed. When it is \fIclosed\fR, the children and their descedants are hidden. The button is normally a \f(CW+\fR or \f(CW\-\fR symbol (ala Windows Explorer), but can be replaced with a pair of Tk images (open and closed images). .PP If the node has data associated with it, they can be displayed in columns running vertically on either side the tree. You can control the color, font, etc of each entry. Any entry label or data field can be edited in-place. .SH "TREE DATA OBJECT" The tree is not stored inside the widget but in a tree data object (see the \fBtree\fR command for a further explanation). Tree data objects can be shared among different clients, such as a \fBtreeview\fR widget or the \fBtree\fR command. You can walk the tree and manage its data with the \fBtree\fR command tree, while displaying it with the \fBtreeview\fR widget. Whenever the tree is updated, the \fBtreeview\fR widget is automatically redrawn. .PP By default, the \fBtreeview\fR widget creates its own tree object. The tree initially contains just a root node. But you can also display trees created by the \fBtree\fR command using the \fB\-tree\fR configuration option. \fBTreeview\fR widgets can share the same tree object, possibly displaying different views of the same data. .PP A tree object has both a Tcl and C API. You can insert or delete nodes using \fBtreeview\fR widget or \fBtree\fR command operations, but also from C code. For example, you can load the tree from your C code while still managing and displaying the tree from Tcl. The widget is automatically notified whenever the tree is modified via C or Tcl. .SH SYNTAX .DS \fBtreeview \fIpathName \fR?\fIoption value\fR?... .DE The \fBtreeview\fR command creates a new window \fIpathName\fR and makes it into a \fBtreeview\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 widget 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, \fBtreeview\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 widget. 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 are described in the .SB "TREEVIEW OPERATIONS" section. .SH "IDS AND TAGS" Nodes can be inserted into a tree using the \fBtreeview\fR widget .CS blt::treeview .t set node [.t insert end root "one"] .CE or \fBtree\fR command. .CS set tree [blt::tree create] set node [$tree insert root "one"] .CE In both cases, a number identifying the node is returned (the value of \f(CW$node\fR). This serial number or \fIid\fR uniquely identifies the node. Please note that you can't infer a location or position of a node from its id. The only exception is that the root node is always id \f(CW0\fR. Since nodes may have the same labels or be moved within the tree, ids provide an convenient way to identify nodes. If a tree is shared, the ids will be the same regardless if you are using by the \fBtreeview\fR widget or the \fBtree\fR command. Ids are recycled when the node deleted. .PP A node may also have any number of \fItags\fR associated with it. A tag is just a string of characters, and it may take any form except that of an integer. For example, "\f(CWx123\fR" is valid, but "\f(CW123\fR" isn't. The same tag may be associated with many different nodes. This is typically done to associate a group of nodes. Many operations in the \fBtreeview\fR widget take either node ids or tag names as arguments. Using a tag says to apply the operation to all nodes with that tag. .PP The tag \fBall\fR is implicitly associated with every node in the tree. It may be used to invoke operations on all the nodes in the tree. .PP Tags may be shared, just like trees, between clients. For example, you can use the tags created by the \fBtree\fR command with \fBtreeview\fR widgets. .SH SPECIAL NODE IDS There are also several special non-numeric ids. Special ids differ from tags in that they are always translated to their numeric equivalent. They also take precedence over tags. For example, you can't use a tag name that is a special id. These ids are specific to the \fBtreeview\fR widget. .TP 15 \fBactive\fR The node where the mouse pointer is currently located. When a node is active, it is drawn using its active icon (see the \fB\-activeicon\fR option). The \fBactive\fR id is changed automatically by moving the mouse pointer over another node or by using the \fBentry activate\fR operation. Note that there can be only one active node at a time. .TP 15 \fBanchor\fR The node representing the fixed end of the current selection. The anchor is set by the \fBselection anchor\fR operation. .TP 15 \fBcurrent\fR The node where the mouse pointer is currently located. But unlike \fBactive\fR, this id changes while the selection is dragged. It is used to determine the current node during button drags. .TP 15 \fBdown\fR The next open node from the current focus. The \fBdown\fR of the last open node is the same. .TP 15 \fBend\fR The last open node (in depth-first order) on the tree. .TP 15 \fBfocus\fR The node that currently has focus. When a node has focus, it receives key events. To indicate focus, the node is drawn with a dotted line around its label. You can change the focus using the \fBfocus\fR operation. .TP 15 \fBlast\fR The last open node from the current focus. But unlike \fBup\fR, when the focus is at root, \fBlast\fR wraps around to the last open node in the tree. .TP 15 \fBmark\fR The node representing the non-fixed end of the current selection. The mark is set by the \fBselection mark\fR operation. .TP 15 \fBnext\fR The next open node from the current focus. But unlike \fBdown\fR, when the focus is on last open node, \fBnext\fR wraps around to the root node. .TP 15 \fBnextsibling\fR The next sibling from the node with the current focus. If the node is already the last sibling then it is the \fBnextsibling\fB. .TP 15 \fBparent\fR The parent of the node with the current focus. The \fBparent\fR of the root is also the root. .TP 15 \fBprevsibling\fR The previous sibling from the node with the current focus. If the node is already the first sibling then it is the \fBprevsibling\fB. .TP 15 \fBroot\fR The root node. You can also use id \f(CW0\fR to indicate the root. .TP 15 \fBup\fR The last open node (in depth-first order) from the current focus. The \fBup\fR of the root node (i.e. the root has focus) is also the root. .TP 15 \fBview.top\fR First node that's current visible in the widget. .TP 15 \fBview.bottom\fR Last node that's current visible in the widget. .TP 15 \fIpath\fR Absolute path of a node. Path names refer to the node name, not their entry labels. Paths don't have to start with a separator (see the \fB\-separator\fR configuration option), but component names must be separated by the designated separator. .TP 15 \fB@\fIx\fB,\fIy\fR Indicates the node that covers the point in the treeview window specified by \fIx\fR and \fIy\fR (in pixel coordinates). If no part of the entryd covers that point, then the closest node to that point is used. .PP A node may be specified as an id or tag. If the specifier is an integer then it is assumed to refer to the single node with that id. If the specifier is not an integer, it's checked to see if it's a special id (such as focus). Otherwise, it's assumed to be tag. Some operations only operate on a single node at a time; if a tag refers to more than one node, then an error is generated. .SH DATA FIELDS A node in the tree can have \fIdata fields\fR. A data field is a name-value pair, used to represent arbitrary data in the node. Nodes can contain different fields (they aren't required to contain the same fields). You can optionally display these fields in the \fBtreeview\fR widget in columns running on either side of the displayed tree. A node's value for the field is drawn in the column along side its node in the hierarchy. Any node that doesn't have a specific field is left blank. Columns can be interactively resized, hidden, or, moved. .SH ENTRY BINDINGS You can bind Tcl commands to be invoked when events occur on nodes (much like Tk canvas items). You can bind a node using its id or its \fIbindtags\fR. Bindtags are simply names that associate a binding with one or more nodes. There is a built-in tag \f(CWall\fR that all node entries automatically have. .SH "TREEVIEW OPERATIONS" The \fBtreeview\fR operations are the invoked by specifying the widget's pathname, the operation, and any arguments that pertain to that operation. The general form is: .sp .CS \fIpathName operation \fR?\fIarg arg ...\fR? .CE .sp \fIOperation\fR and the \fIarg\fRs determine the exact behavior of the command. The following operation are available for \fBtreeview\fR widgets: .TP \fIpathName \fBbbox\fR ?\fB-screen\fR? \fItagOrId...\fR Returns a list of 4 numbers, representing a bounding box of around the specified entries. The entries is given by one or more \fItagOrId\fR arguments. If the \fB\-screen\fR flag is given, then the x-y coordinates of the bounding box are returned as screen coordinates, not virtual coordinates. Virtual coordinates start from \f(CW0\fR from the root node. The returned list contains the following values. .RS .TP 1.25i \fIx\fR X-coordinate of the upper-left corner of the bounding box. .TP \fIy\fR Y-coordinate of the upper-left corner of the bounding box. .TP \fIwidth\fR Width of the bounding box. .TP \fIheight\fR Height of the bounding box. .RE .TP \fIpathName \fBbind\fR \fItagName\fR ?\fIsequence command\fR? Associates \fIcommand\fR with \fItagName\fR such that whenever the event sequence given by \fIsequence\fR occurs for a node with this tag, \fIcommand\fR will be invoked. The syntax is similar to the \fBbind\fR command except that it operates on \fBtreeview\fR 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 \fBbutton \fIoperation\fR ?\fIargs\fR? This command is used to control the button selectors within a \fBtreeview\fR widget. It has several forms, depending on \fIoperation\fR: .RS .TP \fIpathName \fBbutton activate\fR \fItagOrId\fR Designates the node given by \fItagOrId\fR as active. When a node is active it's entry is drawn using its active icon (see the \fB\-activeicon\fR option). Note that there can be only one active entry at a time. The special id \fBactive\fR indicates the currently active node. .TP \fIpathName \fBbutton bind\fR \fItagName\fR ?\fIsequence command\fR? Associates \fIcommand\fR with \fItagName\fR such that whenever the event sequence given by \fIsequence\fR occurs for an button of a node entry with this tag, \fIcommand\fR will be invoked. The syntax is similar to the \fBbind\fR command except that it operates on \fBtreeview\fR buttons, 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 \fBbutton cget\fR \fIoption\fR Returns the current value of the configuration option given by \fIoption\fR. \fIOption\fR may have any of the values accepted by the \fBconfigure\fR operation described below. .TP \fIpathName \fBbutton configure\fR ?\fIoption\fR? ?\fIvalue option value ...\fR? Query or modify the configuration options of the widget. If no \fIoption\fR is specified, returns a list describing all of the available options for \fIpathName\fR (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no \fIoption\fR is specified). If one or more \fIoption\-value\fR pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. \fIOption\fR and \fIvalue\fR are described in the section .SB "BUTTON OPTIONS" below. .RE .TP \fIpathName \fBcget\fR \fIoption\fR Returns the current value of the configuration option given by \fIoption\fR. \fIOption\fR may have any of the values accepted by the \fBconfigure\fR operation described below. .TP \fIpathName \fBclose \fR?\fB\-recurse\fR? \fItagOrId...\fR Closes the node specified by \fItagOrId\fR. In addition, if a Tcl script was specified by the \fB\-closecommand\fR option, it is invoked. If the node is already closed, this command has no effect. If the \fB\-recurse\fR flag is present, each child node is recursively closed. .TP \fIpathName \fBcolumn \fIoperation\fR ?\fIargs\fR? The following operations are available for treeview columns. .RS .TP \fIpathName \fBcolumn activate\fR \fIcolumn\fR Sets the active column to \fIcolumn\fR. \fIColumn\fR is the name of a column in the widget. When a column is active, it's drawn using its \fB\-activetitlebackground\fR and \fB\-activetitleforeground\fR options. If \fIcolumn\fR is the \f(CW""\fR, then no column will be active. If no column argument is provided, then the name of the currently active column is returned. .TP \fIpathName \fBcolumn cget\fR \fIname\fR \fIoption\fR Returns the current value of the column configuration option given by \fIoption\fR for \fIname\fR. \fIName\fR is the name of column that corresponds to a data field. \fIOption\fR may have any of the values accepted by the \fBconfigure\fR operation described below. .TP \fIpathName \fBcolumn configure\fR \fIname\fR ?\fIoption\fR? ?\fIvalue option value ...\fR? Query or modify the configuration options of the column designated by \fIname\fR. \fIName\fR is the name of the column corresponding to a data field. If no \fIoption\fR is specified, returns a list describing all of the available options for \fIpathName\fR (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no \fIoption\fR is specified). If one or more \fIoption\-value\fR pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. \fIOption\fR and \fIvalue\fR are described in the section .SB "COLUMN OPTIONS" below. .TP \fIpathName \fBcolumn delete\fR \fIfield\fR ?\fIfield\fR...? Deletes one of more columns designated by \fIfield\fR. Note that this does not delete the data fields themselves. .TP \fIpathName \fBcolumn insert\fR \fIposition\fR \fIfield\fR ?\fIoptions\fR...? Inserts one of more columns designated by \fIfield\fR. A column displays each node's data field by the same name. If the node doesn't have the given field, the cell is left blank. \fIPosition\fR indicates where in the list of columns to add the new column. It may be either a number or \f(CWend\fR. .TP \fIpathName \fBcolumn invoke\fR \fIfield\fR Invokes the Tcl command associated with the column \fIfield\fR, if there is one (using the column's \fB\-command\fR option). The command is ignored if the column's \fB\-state\fR option set to \f(CWdisabled\fR. .TP \fIpathName \fBcolumn move \fIname\fR \fIdest\fR Moves the column \fIname\fR to the destination position. \fIDest\fR is the name of another column or a screen position in the form \f(CW@\fIx\f(CW,\fIy\fR. .TP \fIpathName \fBcolumn names\fR Returns a list of the names of all columns in the widget. The list is ordered as the columns are drawn from left-to-right. .TP \fIpathName \fBcolumn nearest\fR \fIx\fR ?\fIy\fR? Returns the name of the column closest to the given X-Y screen coordinate. If you provide a \fIy\fR argument (it's optional), a name is returned only when if the point is over a column's title. .RE .TP \fIpathName \fBconfigure\fR ?\fIoption\fR? ?\fIvalue option value ...\fR? Query or modify the configuration options of the widget. If no \fIoption\fR is specified, returns a list describing all of the available options for \fIpathName\fR (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no \fIoption\fR is specified). If one or more \fIoption\-value\fR pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. \fIOption\fR and \fIvalue\fR are described in the section .SB "TREEVIEW OPTIONS" below. .TP \fIpathName \fBcurselection\fR Returns a list containing the ids of all of the entries that are currently selected. If there are no entries selected, then the empty string is returned. .TP \fIpathName \fBdelete \fItagOrId\fR... Deletes one or more entries given by \fItagOrId\fR and its children. .TP \fIpathName \fBentry \fIoperation\fR ?\fIargs\fR? The following operations are available for treeview entries. .RS .TP \fIpathName \fBentry activate\fR \fItagOrId\fR Sets the active entry to the one specified by \fItagOrId\fR. When an entry is active it is drawn using its active icon (see the \fB\-activeicon\fR option). Note that there can be only one active node at a time. The special id of the currently active node is \fBactive\fR. .TP \fIpathName \fBentry cget\fR \fIoption\fR Returns the current value of the configuration option given by \fIoption\fR. \fIOption\fR may have any of the values accepted by the \fBconfigure\fR operation described below. .TP \fIpathName \fBentry children\fR \fItagOrId\fR ?\fIfirst\fR? ?\fIlast\fR? Returns a list of ids for the given range of children of \fItagOrId\fR. \fITagOrId\fR is the id or tag of the node to be examined. If only a \fIfirst\fR argument is present, then the id of the that child at that numeric position is returned. If both \fIfirst\fR and \fIlast\fR arguments are given, then the ids of all the children in that range are returned. Otherwise the ids of all children are returned. .TP \fIpathName \fBentry configure\fR ?\fIoption\fR? ?\fIvalue option value ...\fR? Query or modify the configuration options of the widget. If no \fIoption\fR is specified, returns a list describing all of the available options for \fIpathName\fR (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no \fIoption\fR is specified). If one or more \fIoption\-value\fR pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. \fIOption\fR and \fIvalue\fR are described below: .TP \fIpathName \fBentry delete\fR \fItagOrId\fR ?\fIfirst\fR ?\fIlast\fR? Deletes the one or more children nodes of the parent \fItagOrId\fR. If \fIfirst\fR and \fIlast\fR arguments are present, they are positions designating a range of children nodes to be deleted. .TP \fIpathName \fBentry isbefore \fItagOrId1\fR \fItagOrId2\fR Returns 1 if \fItagOrId1\fR is before \fItagOrId2\fR and 0 otherwise. .TP \fIpathName \fBentry ishidden \fItagOrId\fR Returns 1 if the node is currently hidden and 0 otherwise. A node is also hidden if any of its ancestor nodes are closed or hidden. .TP \fIpathName \fBentry isopen \fItagOrId\fR Returns 1 if the node is currently open and 0 otherwise. .TP \fIpathName \fBentry size\fR \fB\-recurse\fR \fItagOrId\fR Returns the number of children for parent node \fItagOrId\fR. If the \fB\-recurse\fR flag is set, the number of all its descendants is returned. The node itself is not counted. .RE .TP \fIpathName \fBfind \fR?\fIflags\fR? \fIfirst\fR \fIlast\fR Finds for all entries matching the criteria given by \fIflags\fR. A list of ids for all matching nodes is returned. \fIFirst\fR and \fIlast\fR are ids designating the range of the search in depth-first order. If \fIlast\fR is before \fIfirst\fR, then nodes are searched in reverse order. The valid flags are: .RS .TP 1.25i \fB\-name\fI pattern\fR Specifies pattern to match against node names. .TP 1.25i \fB\-full\fI pattern\fR Specifies pattern to match against node pathnames. .TP 1.25i \fB\-\fIoption\fI pattern\fR Specifies pattern to match against the node entry's configuration option. .TP 1.25i \fB\-exact\fR Patterns must match exactly. The is the default. .TP 1.25i \fB\-glob\fR Use global pattern matching. Matching is done in a fashion similar to that used by the C-shell. For the two strings to match, their contents must be identical except that the following special sequences may appear in pattern: .RS .TP 5 \f(CW*\fR Matches any sequence of characters in string, including a null string. .TP 5 \f(CW?\fR Matches any single character in string. .TP 5 \f(CW[\fIchars\f(CW]\fR Matches any character in the set given by \fIchars\fR. If a sequence of the form \fIx\fR-\fIy\fR appears in \fIchars\fR, then any character between \fIx\fR and \fIy\fR, inclusive, will match. .TP 5 \f(CW\\\fIx\fR Matches the single character \fIx\fR. This provides a way of avoiding the special interpretation of the characters \f(CW*?[]\\\fR in the pattern. .RE .TP 1.25i \fB\-regexp\fR Use regular expression pattern matching (i.e. the same as implemented by the \fBregexp\fR command). .TP 1.25i \fB\-nonmatching\fR Pick entries that don't match. .TP 1.25i \fB\-exec\fI string\fR Specifies a Tcl script to be invoked for each matching node. Percent substitutions are performed on \fIstring\fR before it is executed. The following substitutions are valid: .RS .TP 5 \f(CW%W\fR The pathname of the widget. .TP 5 \f(CW%p\fR The name of the node. .TP 5 \f(CW%P\fR The full pathname of the node. .TP 5 \f(CW%#\fR The id of the node. .TP 5 \f(CW%%\fR Translates to a single percent. .RE .TP 1.25i \fB\-count\fI number\fR Stop searching after \fInumber\fR matches. .TP 1.25i \fB\-\-\fR Indicates the end of flags. .RE .TP \fIpathName \fBfocus \fR \fItagOrId\fR Sets the focus to the node given by \fItagOrId\fR. When a node has focus, it can receive keyboard events. The special id \fBfocus\fR designates the node that currently has focus. .TP \fIpathName \fBget \fR?\fB\-full\fR? \fItagOrId\fR \fItagOrId\fR... Translates one or more ids to their node entry names. It returns a list of names for all the ids specified. If the \fB\-full\fR flag is set, then the full pathnames are returned. .TP \fIpathName \fBhide \fR?\fBflags\fR? \fItagOrId\fR... Hides all nodes matching the criteria given by \fIflags\fR. The search is performed recursively for each node given by \fItagOrId\fR. The valid flags are described below: .RS .TP 1.25i \fB\-name\fI pattern\fR Specifies pattern to match against node names. .TP 1.25i \fB\-full\fI pattern\fR Specifies pattern to match against node pathnames. .TP 1.25i \fB\-\fIoption\fI pattern\fR Specifies pattern to match against the node entry's configuration option. .TP 1.25i \fB\-exact\fR Match patterns exactly. The is the default. .TP 1.25i \fB\-glob\fR Use global pattern matching. Matching is done in a fashion similar to that used by the C-shell. For the two strings to match, their contents must be identical except that the following special sequences may appear in pattern: .RS .TP 5 \f(CW*\fR Matches any sequence of characters in string, including a null string. .TP 5 \f(CW?\fR Matches any single character in string. .TP 5 \f(CW[\fIchars\f(CW]\fR Matches any character in the set given by \fIchars\fR. If a sequence of the form \fIx\fR-\fIy\fR appears in \fIchars\fR, then any character between \fIx\fR and \fIy\fR, inclusive, will match. .TP 5 \f(CW\\\fIx\fR Matches the single character \fIx\fR. This provides a way of avoiding the special interpretation of the characters \f(CW*?[]\\\fR in the pattern. .RE .TP 1.25i \fB\-regexp\fR Use regular expression pattern matching (i.e. the same as implemented by the \fBregexp\fR command). .TP 1.25i \fB\-nonmatching\fR Hide nodes that don't match. .TP 1.25i \fB\-\-\fR Indicates the end of flags. .RE .TP \fIpathName \fBindex \fR?\fB\-at\fR \fItagOrId\fR? \fIstring\fR Returns the id of the node specified by \fIstring\fR. \fIString\fR may be a tag or node id. Some special ids are normally relative to the node that has focus. The \fB\-at\fR flag lets you select another node. .TP \fIpathName \fBinsert \fR?\fB\-at \fItagOrId\fR? \fIposition\fR \fIpath\fR ?\fIoptions...\fR? ?\fIpath\fR? ?\fIoptions...\fR? Inserts one or more nodes at \fIposition\fR. \fIPosition\fR is the location (number or \f(CWend\fR) where the new nodes are added to the parent node. \fIPath\fR is the pathname of the new node. Pathnames can be formated either as a Tcl list (each element is a path component) or as a string separated by a special character sequence (using the \fB\-separator\fR option). Pathnames are normally absolute, but the \fB\-at\fR switch lets you select a relative starting point. Its value is the id of the starting node. .sp All ancestors of the new node must already exist, unless the \fB\-autocreate\fR option is set. It is also an error if a node already exists, unless the \fB\-allowduplicates\fR option is set. .sp \fIOption\fR and \fIvalue\fR may have any of the values accepted by the \fBentry configure\fR operation described in the .SB "ENTRY OPERATIONS" section below. This command returns a list of the ids of the new entries. .TP \fIpathName \fBmove \fItagOrId\fR \fIhow\fR \fIdestId\fR Moves the node given by \fItagOrId\fR to the destination node. The node can not be an ancestor of the destination. \fIDestId\fR is the id of the destination node and can not be the root of the tree. In conjunction with \fIhow\fR, it describes how the move is performed. .RS .TP 8 \f(CWbefore\fR Moves the node before the destination node. .TP 8 \f(CWafter\fR Moves the node after the destination node. .TP 8 \f(CWinto\fR Moves the node to the end of the destination's list of children. .RE .TP \fIpathName \fBnearest \fIx y\fR ?\fIvarName\fR? Returns the id of the node entry closest to the given X-Y screen coordinate. The optional argument \fIvarName\fR is the name of variable which is set to either \f(CWbutton\fR or \f(CWselect\fR to indicate over what part of the node the coordinate lies. If the coordinate is not directly over any node, then \fIvarName\fR will contain the empty string. .TP \fIpathName \fBopen \fR?\fB\-recurse\fR? \fItagOrId...\fR Opens the one or more nodes specified by \fItagOrId\fR. If a node is not already open, the Tcl script specified by the \fB\-opencommand\fR option is invoked. If the \fB\-recurse\fR flag is present, then each descendant is recursively opened. .TP \fIpathName \fBrange\fR ?\fB-open\fR? \fIfirst last\fR Returns the ids in depth-first order of the nodes between the \fIfirst\fR and \fIlast\fR ids. If the \fB\-open\fR flag is present, it indicates to consider only open nodes. If \fIlast\fR is before \fIfirst\fR, then the ids are returned in reverse order. .TP \fIpathName \fBscan\fR \fIoption args\fR This command implements scanning. It has two forms, depending on \fIoption\fR: .RS .TP \fIpathName \fBscan mark \fIx y\fR Records \fIx\fR and \fIy\fR and the current view in the treeview window; used in conjunction with later \fBscan dragto\fR commands. Typically this command is associated with a mouse button press in the widget. It returns an empty string. .TP \fIpathName \fBscan dragto \fIx y\fR. Computes the difference between its \fIx\fR and \fIy\fR arguments and the \fIx\fR and \fIy\fR arguments to the last \fBscan mark\fR command for the widget. It then adjusts the view by 10 times the difference in coordinates. This command is typically associated with mouse motion events in the widget, to produce the effect of dragging the list at high speed through the window. The return value is an empty string. .RE .TP \fIpathName \fBsee\fR ?\fB\-anchor \fIanchor\fR? \fItagOrId\fR Adjusts the view of entries so that the node given by \fItagOrId\fR is visible in the widget window. It is an error if \fBtagOrId\fR is a tag that refers to more than one node. By default the node's entry is displayed in the middle of the window. This can changed using the \fB\-anchor\fR flag. Its value is a Tk anchor position. .TP \fIpathName \fBselection \fIoption arg\fR This command is used to adjust the selection within a \fBtreeview\fR widget. It has several forms, depending on \fIoption\fR: .RS .TP \fIpathName \fBselection anchor \fItagOrId\fR Sets the selection anchor to the node given by \fItagOrId\fR. If \fItagOrId\fR refers to a non-existent node, then the closest node is used. The selection anchor is the end of the selection that is fixed while dragging out a selection with the mouse. The special id \fBanchor\fR may be used to refer to the anchor node. .TP \fIpathName \fBselection cancel\fR Clears the temporary selection of entries back to the current anchor. Temporary selections are created by the \fBselection mark\fR operation. .TP \fIpathName \fBselection clear \fIfirst \fR?\fIlast\fR? Removes the entries between \fIfirst\fR and \fIlast\fR (inclusive) from the selection. Both \fIfirst\fR and \fIlast\fR are ids representing a range of entries. If \fIlast\fR isn't given, then only \fIfirst\fR is deselected. Entries outside the selection are not affected. .TP \fIpathName \fBselection clearall\fR Clears the entire selection. .TP \fIpathName \fBselection mark \fItagOrId\fR Sets the selection mark to the node given by \fItagOrId\fR. This causes the range of entries between the anchor and the mark to be temporarily added to the selection. The selection mark is the end of the selection that is fixed while dragging out a selection with the mouse. The special id \fBmark\fR may be used to refer to the current mark node. If \fItagOrId\fR refers to a non-existent node, then the mark is ignored. Resetting the mark will unselect the previous range. Setting the anchor finalizes the range. .TP \fIpathName \fBselection includes \fItagOrId\fR Returns 1 if the node given by \fItagOrId\fR is currently selected, 0 if it isn't. .TP \fIpathName \fBselection present\fR Returns 1 if any nodes are currently selected and 0 otherwise. .TP \fIpathName \fBselection set \fIfirst \fR?\fIlast\fR? Selects all of the nodes in the range between \fIfirst\fR and \fIlast\fR, inclusive, without affecting the selection state of nodes outside that range. .TP \fIpathName \fBselection toggle \fIfirst \fR?\fIlast\fR? Selects/deselects nodes in the range between \fIfirst\fR and \fIlast\fR, inclusive, from the selection. If a node is currently selected, it becomes deselected, and visa versa. .RE .TP \fIpathName \fBshow \fR?\fBflags\fR? \fItagOrId\fR... Exposes all nodes matching the criteria given by \fIflags\fR. This is the inverse of the \fBhide\fR operation. The search is performed recursively for each node given by \fItagOrId\fR. The valid flags are described below: .RS .TP 1.25i \fB\-name\fI pattern\fR Specifies pattern to match against node names. .TP 1.25i \fB\-full\fI pattern\fR Specifies pattern to match against node pathnames. .TP 1.25i \fB\-\fIoption\fI pattern\fR Specifies pattern to match against the entry's configuration option. .TP 1.25i \fB\-exact\fR Match patterns exactly. The is the default. .TP 1.25i \fB\-glob\fR \fB\-glob\fR Use global pattern matching. Matching is done in a fashion similar to that used by the C-shell. For the two strings to match, their contents must be identical except that the following special sequences may appear in pattern: .RS .TP 5 \f(CW*\fR Matches any sequence of characters in string, including a null string. .TP 5 \f(CW?\fR Matches any single character in string. .TP 5 \f(CW[\fIchars\f(CW]\fR Matches any character in the set given by \fIchars\fR. If a sequence of the form \fIx\fR-\fIy\fR appears in \fIchars\fR, then any character between \fIx\fR and \fIy\fR, inclusive, will match. .TP 5 \f(CW\\\fIx\fR Matches the single character \fIx\fR. This provides a way of avoiding the special interpretation of the characters \f(CW*?[]\\\fR in the pattern. .RE .TP 1.25i \fB\-regexp\fR Use regular expression pattern matching (i.e. the same as implemented by the \fBregexp\fR command). .TP 1.25i \fB\-nonmatching\fR Expose nodes that don't match. .TP 1.25i \fB\-\-\fR Indicates the end of flags. .RE .TP \fIpathName \fBsort\fR ?\fIoperation\fR? \fIargs...\fR .RS .TP \fIpathName \fBsort auto\fR ?\fIboolean\fR Turns on/off automatic sorting of node entries. If \fIboolean\fR is true, entries will be automatically sorted as they are opened, closed, inserted, or deleted. If no \fIboolean\fR argument is provided, the current state is returned. .TP \fIpathName \fBsort cget\fR \fIoption\fR Returns the current value of the configuration option given by \fIoption\fR. \fIOption\fR may have any of the values accepted by the \fBconfigure\fR operation described below. .TP \fIpathName \fBsort configure\fR ?\fIoption\fR? ?\fIvalue option value ...\fR? Query or modify the sorting configuration options of the widget. If no \fIoption\fR is specified, returns a list describing all of the available options for \fIpathName\fR (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no \fIoption\fR is specified). If one or more \fIoption\-value\fR pairs are specified, then the command modifies the given sorting option(s) to have the given value(s); in this case the command returns an empty string. \fIOption\fR and \fIvalue\fR are described below: .RS .TP \fB\-column\fI string\fR Specifies the column to sort. Entries in the widget are rearranged according to this column. If \fIcolumn\fR is \f(CW""\fR then no sort is performed. .TP \fB\-command\fI string\fR Specifies a Tcl procedure to be called when sorting nodes. The procedure is called with three arguments: the pathname of the widget and the fields of two entries. The procedure returns 1 if the first node is greater than the second, -1 is the second is greater, and 0 if equal. .TP \fB\-decreasing\fI boolean\fR Indicates to sort in ascending/descending order. If \fIboolean\fR is true, then the entries as in descending order. The default is \f(CWno\fR. .TP \fB\-mode\fI string\fR Specifies how to compare entries when sorting. \fIString\fR may be one of the following: .RS .TP 1.5i \f(CWascii\fR Use string comparison based upon the ASCII collation order. .TP 1.5i \f(CWdictionary\fR Use dictionary-style comparison. This is the same as \f(CWascii\fR except (a) case is ignored except as a tie-breaker and (b) if two strings contain embedded numbers, the numbers compare as integers, not characters. For example, "bigBoy" sorts between "bigbang" and "bigboy", and "x10y" sorts between "x9y" and "x11y". .TP 1.5i \f(CWinteger\fR Compares fields as integers. .TP 1.5i \f(CWreal\fR Compares fields as floating point numbers. .TP 1.5i \f(CWcommand\fR Use the Tcl proc specified by the \fB\-command\fR option to compare entries when sorting. If no command is specified, the sort reverts to \f(CWascii\fR sorting. .RE .RE .TP \fIpathName \fBsort once\fR ?\fIflags\fR? \fItagOrId...\fR Sorts the children for each entries specified by \fItagOrId\fR. By default, entries are sorted by name, but you can specify a Tcl proc to do your own comparisons. .RS .TP 1.5i \fB\-recurse\fR Recursively sort the entire branch, not just the children. .RE .RE .TP \fIpathName \fBtag \fIoperation args\fR Tags are a general means of selecting and marking nodes in the tree. A tag is just a string of characters, and it may take any form except that of an integer. The same tag may be associated with many different nodes. .sp Both \fIoperation\fR and its arguments determine the exact behavior of the command. The operations available for tags are listed below. .RS .TP \fIpathName\fR \fBtag add\fR \fIstring\fR \fIid\fR... Adds the tag \fIstring\fR to one of more entries. .TP \fIpathName\fR \fBtag delete\fR \fIstring\fR \fIid\fR... Deletes the tag \fIstring\fR from one or more entries. .TP \fIpathName\fR \fBtag forget\fR \fIstring\fR Removes the tag \fIstring\fR from all entries. It's not an error if no entries are tagged as \fIstring\fR. .TP \fIpathName\fR \fBtag names\fR ?\fIid\fR? Returns a list of tags used. If an \fIid\fR argument is present, only those tags used by the node designated by \fIid\fR are returned. .TP \fIpathName\fR \fBtag nodes\fR \fIstring\fR Returns a list of ids that have the tag \fIstring\fR. If no node is tagged as \fIstring\fR, then an empty string is returned. .RE .TP \fIpathName \fBtext \fIoperation\fR ?\fIargs\fR? This operation is used to provide text editing for cells (data fields in a column) or entry labels. It has several forms, depending on \fIoperation\fR: .RS .TP \fIpathName \fBtext apply\fR Applies the edited buffer, replacing the entry label or data field. The edit window is hidden. .TP \fIpathName \fBtext cancel\fR Cancels the editing operation, reverting the entry label or data value back to the previous value. The edit window is hidden. .TP \fIpathName \fBtext cget\fI value\fR Returns the current value of the configuration option given by \fIoption\fR. \fIOption\fR may have any of the values accepted by the \fBconfigure\fR operation described below. .TP \fIpathName \fBtext configure\fR ?\fIoption value\fR? Query or modify the configuration options of the edit window. If no \fIoption\fR is specified, returns a list describing all of the available options (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no \fIoption\fR is specified). If one or more \fIoption\-value\fR pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. \fIOption\fR and \fIvalue\fR are described in the section .SB "TEXT EDITING OPTIONS" below. .RE .TP \fIpathName \fBtext delete\fI first last\fR Deletes the characters in the edit buffer between the two given character positions. .TP \fIpathName \fBtext get\fR ?\fI\-root\fR? \fIx y\fR .TP \fIpathName \fBtext icursor\fI index\fR .TP \fIpathName \fBtext index\fI index\fR Returns the text index of given \fIindex\fR. .TP \fIpathName \fBtext insert\fI index string\fR Insert the text string \fIstring\fR into the edit buffer at the index \fIindex\fR. For example, the index 0 will prepend the buffer. .TP \fIpathName \fBtext selection\fI args\fR This operation controls the selection of the editing window. Note that this differs from the selection of entries. It has the following forms: .RS .TP \fIpathName \fBtext selection adjust\fI index\fR Adjusts either the first or last index of the selection. .TP \fIpathName \fBtext selection clear\fR Clears the selection. .TP \fIpathName \fBtext selection from\fI index\fR Sets the anchor of the selection. .TP \fIpathName \fBtext selection present\fR Indicates if a selection is present. .TP \fIpathName \fBtext selection range\fI start end\fR Sets both the anchor and mark of the selection. .TP \fIpathName \fBtext selection to\fI index\fR Sets the unanchored end (mark) of the selection. .RE .TP \fIpathName \fBtoggle \fItagOrId\fR Opens or closes the node given by \fItagOrId\fR. If the corresponding \fB\-opencommand\fR or \fB\-closecommand\fR option is set, then that command is also invoked. .TP \fIpathName \fBxview \fIargs\fR This command is used to query and change the horizontal position of the information in the widget's window. It can take any of the following forms: .RS .TP \fIpathName \fBxview\fR Returns a list containing two elements. Each element is a real fraction between 0 and 1; together they describe the horizontal span that is visible in the window. For example, if the first element is .2 and the second element is .6, 20% of the \fBtreeview\fR widget's text is off-screen to the left, the middle 40% is visible in the window, and 40% of the text is off-screen to the right. These are the same values passed to scrollbars via the \fB\-xscrollcommand\fR option. .TP \fIpathName \fBxview\fR \fItagOrId\fR Adjusts the view in the window so that the character position given by \fItagOrId\fR is displayed at the left edge of the window. Character positions are defined by the width of the character \fB0\fR. .TP \fIpathName \fBxview moveto\fI fraction\fR Adjusts the view in the window so that \fIfraction\fR of the total width of the \fBtreeview\fR widget's text is off-screen to the left. \fIfraction\fR must be a fraction between 0 and 1. .TP \fIpathName \fBxview scroll \fInumber what\fR This command shifts the view in the window left or right according to \fInumber\fR and \fIwhat\fR. \fINumber\fR must be an integer. \fIWhat\fR must be either \fBunits\fR or \fBpages\fR or an abbreviation of one of these. If \fIwhat\fR is \fBunits\fR, the view adjusts left or right by \fInumber\fR character units (the width of the \fB0\fR character) on the display; if it is \fBpages\fR then the view adjusts by \fInumber\fR screenfuls. If \fInumber\fR is negative then characters farther to the left become visible; if it is positive then characters farther to the right become visible. .RE .TP \fIpathName \fByview \fI?args\fR? This command is used to query and change the vertical position of the text in the widget's window. It can take any of the following forms: .RS .TP \fIpathName \fByview\fR Returns a list containing two elements, both of which are real fractions between 0 and 1. The first element gives the position of the node at the top of the window, relative to the widget as a whole (0.5 means it is halfway through the treeview window, for example). The second element gives the position of the node just after the last one in the window, relative to the widget as a whole. These are the same values passed to scrollbars via the \fB\-yscrollcommand\fR option. .TP \fIpathName \fByview\fR \fItagOrId\fR Adjusts the view in the window so that the node given by \fItagOrId\fR is displayed at the top of the window. .TP \fIpathName \fByview moveto\fI fraction\fR Adjusts the view in the window so that the node given by \fIfraction\fR appears at the top of the window. \fIFraction\fR is a fraction between 0 and 1; 0 indicates the first node, 0.33 indicates the node one-third the way through the \fBtreeview\fR widget, and so on. .TP \fIpathName \fByview scroll \fInumber what\fR This command adjusts the view in the window up or down according to \fInumber\fR and \fIwhat\fR. \fINumber\fR must be an integer. \fIWhat\fR must be either \fBunits\fR or \fBpages\fR. If \fIwhat\fR is \fBunits\fR, the view adjusts up or down by \fInumber\fR lines; if it is \fBpages\fR then the view adjusts by \fInumber\fR screenfuls. If \fInumber\fR is negative then earlier nodes become visible; if it is positive then later nodes become visible. .RE .SH "TREEVIEW OPTIONS" In addition to the \fBconfigure\fR operation, widget configuration options may also be set by the Tk \fBoption\fR command. The class resource name is \f(CWTreeView\fR. .CS option add *TreeView.Foreground white option add *TreeView.Background blue .CE The following widget options are available: .TP \fB\-activebackground \fIcolor\fR Sets the background color for active entries. A node is active when the mouse passes over it's entry or using the \fBactivate\fR operation. .TP \fB\-activeforeground \fIcolor\fR Sets the foreground color of the active node. A node is active when the mouse passes over it's entry or using the \fBactivate\fR operation. .TP \fB\-activeicons \fIimages\fR Specifies images to be displayed for an entry's icon when it is active. \fIImages\fR is a list of two Tk images: the first image is displayed when the node is open, the second when it is closed. .TP \fB\-autocreate \fIboolean\fR If \fIboolean\fR is true, automatically create missing ancestor nodes when inserting new nodes. Otherwise flag an error. The default is \f(CWno\fR. .TP \fB\-allowduplicates \fIboolean\fR If \fIboolean\fR is true, allow nodes with duplicate pathnames when inserting new nodes. Otherwise flag an error. The default is \f(CWno\fR. .TP \fB\-background \fIcolor\fR Sets the background color of the widget. The default is \f(CWwhite\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\-closecommand \fIstring\fR Specifies a Tcl script to be invoked when a node is closed. You can overrider this for individual entries using the entry's \fB\-closecommand\fR option. The default is \f(CW""\fR. Percent substitutions are performed on \fIstring\fR before it is executed. The following substitutions are valid: .RS .TP 5 \f(CW%W\fR The pathname of the widget. .TP 5 \f(CW%p\fR The name of the node. .TP 5 \f(CW%P\fR The full pathname of the node. .TP 5 \f(CW%#\fR The id of the node. .TP 5 \f(CW%%\fR Translates to a single percent. .RE .TP \fB\-cursor \fIcursor\fR Specifies the widget's cursor. The default cursor is \f(CW""\fR. .TP \fB\-dashes \fInumber\fR Sets the dash style of the horizontal and vertical lines drawn connecting entries. \fINumber\fR is the length in pixels of the dashes and gaps in the line. If \fInumber\fR is \f(CW0\fR, solid lines will be drawn. The default is \f(CW1\fR (dotted). .TP \fB\-exportselection \fIboolean\fR Indicates if the selection is exported. If the widget is exporting its selection then it will observe the standard X11 protocols for handling the selection. Selections are available as type \fBSTRING\fR; the value of the selection will be the label of the selected nodes, separated by newlines. The default is \f(CWno\fR. .TP \fB\-flat \fIboolean\fR Indicates whether to display the tree as a flattened list. If \fIboolean\fR is true, then the hierarchy will be a list of full paths for the nodes. This option also has affect on sorting. See the .SB "SORT OPERATIONS" section for more information. The default is \f(CWno\fR. .TP \fB\-focusdashes \fIdashList\fR Sets the dash style of the outline rectangle drawn around the entry label of the node that current has focus. \fINumber\fR is the length in pixels of the dashes and gaps in the line. If \fInumber\fR is \f(CW0\fR, a solid line will be drawn. The default is \f(CW1\fR. .TP \fB\-focusforeground \fIcolor\fR Sets the color of the focus rectangle. The default is \f(CWblack\fR. .TP \fB\-font \fIfontName\fR Specifies the font for entry labels. You can override this for individual entries with the entry's \fB\-font\fR configuration option. The default is \f(CW*-Helvetica-Bold-R-Normal-*-12-120-*\fR. .TP \fB\-foreground \fIcolor\fR Sets the text color of entry labels. You can override this for individual entries with the entry's \fB\-foreground\fR configuration option. The default is \f(CWblack\fR. .TP \fB\-height \fIpixels\fR Specifies the requested height of widget. The default is \f(CW400\fR. .TP \fB\-hideroot \fIboolean\fR If \fIboolean\fR is true, it indicates that no entry for the root node should be displayed. The default is \f(CWno\fR. .TP \fB\-highlightbackground \fIcolor\fR Specifies the normal color of the traversal highlight region when the widget does not have the input focus. .TP \fB\-highlightcolor \fIcolor\fR Specifies the color of the traversal highlight rectangle when the widget has the input focus. The default is \f(CWblack\fR. .TP \fB\-highlightthickness \fIpixels\fR Specifies the width of the highlight rectangle indicating when the widget has input focus. The value may have any of the forms acceptable to \fBTk_GetPixels\fR. If the value is zero, no focus highlight will be displayed. The default is \f(CW2\fR. .TP \fB\-icons \fIimages\fR Specifies images for the entry's icon. \fIImages\fR is a list of two Tk images: the first image is displayed when the node is open, the second when it is closed. .TP \fB\-linecolor \fIcolor\fR Sets the color of the connecting lines drawn between entries. The default is \f(CWblack\fR. .TP \fB\-linespacing \fIpixels\fR Sets the number of pixels spacing between entries. The default is \f(CW0\fR. .TP \fB\-linewidth \fIpixels\fR Set the width of the lines drawn connecting entries. If \fIpixels\fR is \f(CW0\fR, no vertical or horizontal lines are drawn. The default is \f(CW1\fR. .TP \fB\-opencommand \fIstring\fR Specifies a Tcl script to be invoked when a node is open. You can override this for individual entries with the entry's \fB\-opencommand\fR configuration option. The default is \f(CW""\fR. Percent substitutions are performed on \fIstring\fR before it is executed. The following substitutions are valid: .RS .TP 5 \f(CW%W\fR The pathname of the widget. .TP 5 \f(CW%p\fR The name of the node. .TP 5 \f(CW%P\fR The full pathname of the node. .TP 5 \f(CW%#\fR The id of the node. .TP 5 \f(CW%%\fR Translates to a single percent. .RE .TP \fB\-relief \fIrelief\fR Specifies the 3-D effect for the widget. \fIRelief\fR specifies how the \fBtreeview\fR widget should appear relative to widget it is packed into; for example, \f(CWraised\fR means the \fBtreeview\fR widget should appear to protrude. The default is \f(CWsunken\fR. .TP \fB\-scrollmode \fImode\fR Specifies the style of scrolling to be used. The following styles are valid. This is the default is \f(CWhierbox\fR. .RS .TP 1.25i \f(CWlistbox\fR Like the \fBlistbox\fR widget, the last entry can always be scrolled to the top of the widget window. This allows the scrollbar thumb to shrink as the last entry is scrolled upward. .TP 1.25i \f(CWhierbox\fR Like the \fBhierbox\fR widget, the last entry can only be viewed at the bottom of the widget window. The scrollbar stays a constant size. .TP 1.25i \f(CWcanvas\fR Like the \fBcanvas\fR widget, the entries are bound within the scrolling area. .RE .TP \fB\-selectbackground \fIcolor\fR Sets the background color selected node entries. The default is \f(CW#ffffea\fR. .TP \fB\-selectborderwidth \fIpixels\fR Sets the width of the raised 3-D border drawn around the labels of selected entries. The default is \f(CW0\fR. \fB\-selectcommand \fIstring\fR Specifies a Tcl script to invoked when the set of selected nodes changes. The default is \f(CW""\fR. .TP \fB\-selectforeground \fIcolor\fB Sets the color of the labels of selected node entries. The default is \f(CWblack\fR. .TP \fB\-selectmode \fImode\fR Specifies the selection mode. If \fImode\fR is \f(CWsingle\fR, only one node can be selected at a time. If \f(CWmultiple\fR more than one node can be selected. The default is \f(CWsingle\fR. .TP \fB\-separator \fIstring\fR Specifies the character sequence to use when spliting the path components. The separator may be several characters wide (such as "::") Consecutive separators in a pathname are treated as one. If \fIstring\fR is the empty string, the pathnames are Tcl lists. Each element is a path component. The default is \f(CW""\fR. .TP \fB\-showtitles \fIboolean\fR If \fIboolean\fR is false, column titles are not be displayed. The default is \f(CWyes\fR. .TP \fB\-sortselection \fIboolean\fR If \fIboolean\fR is true, nodes in the selection are ordered as they are currently displayed (depth-first or sorted), not in the order they were selected. The default is \f(CWno\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"1"\fR. .TP \fB\-trim \fIstring\fR Specifies a string leading characters to trim from entry pathnames before parsing. This only makes sense if the \fB\-separator\fR is also set. The default is \f(CW""\fR. .TP \fB\-width \fIpixels\fR Sets the requested width of the widget. If \fIpixels\fR is 0, then the with is computed from the contents of the \fBtreeview\fR widget. The default is \f(CW200\fR. .TP \fB\-xscrollcommand \fIstring\fR Specifies the prefix for a command used to communicate with horizontal scrollbars. Whenever the horizontal view in the widget's window changes, the widget will generate a Tcl command by concatenating the scroll command and two numbers. If this option is not specified, then no command will be executed. .TP \fB\-xscrollincrement\fR \fIpixels\fR Sets the horizontal scrolling distance. The default is 20 pixels. .TP \fB\-yscrollcommand \fIstring\fR Specifies the prefix for a command used to communicate with vertical scrollbars. Whenever the vertical view in the widget's window changes, the widget will generate a Tcl command by concatenating the scroll command and two numbers. If this option is not specified, then no command will be executed. .TP \fB\-yscrollincrement\fR \fIpixels\fR Sets the vertical scrolling distance. The default is 20 pixels. .SH "ENTRY OPTIONS" Many widget configuration options have counterparts in entries. For example, there is a \fB\-closecommand\fR configuration option for both widget itself and for individual entries. Options set at the widget level are global for all entries. If the entry configuration option is set, then it overrides the widget option. This is done to avoid wasting memory by replicated options. Most entries will have redundant options. .PP There is no resource class or name for entries. .TP \fB\-activeicons \fIimages\fR Specifies images to be displayed as the entry's icon when it is active. This overrides the global \fB\-activeicons\fR configuration option for the specific entry. \fIImages\fR is a list of two Tk images: the first image is displayed when the node is open, the second when it is closed. .TP \fB\-bindtags \fItagList\fR Specifies the binding tags for nodes. \fITagList\fR is a list of binding tag names. The tags and their order will determine how events are handled for nodes. 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\-button \fIstring\fR Indicates whether a button should be displayed on the left side of the node entry. \fIString\fR can be \f(CWyes\fR, \f(CWno\fR, or \f(CWauto\fR. If \f(CWauto\fR, then a button is automatically displayed if the node has children. This is the default. .TP \fB\-closecommand \fIstring\fR Specifies a Tcl script to be invoked when the node is closed. This overrides the global \fB\-closecommand\fR option for this entry. The default is \f(CW""\fR. Percent substitutions are performed on \fIstring\fR before it is executed. The following substitutions are valid: .RS .TP 5 \f(CW%W\fR The pathname of the widget. .TP 5 \f(CW%p\fR The name of the node. .TP 5 \f(CW%P\fR The full pathname of the node. .TP 5 \f(CW%#\fR The id of the node. .TP 5 \f(CW%%\fR Translates to a single percent. .RE .TP \fB\-data \fIstring\fR Sets data fields for the node. \fIString\fR is a list of name-value pairs to be set. The default is \f(CW""\fR. .TP \fB\-font \fIfontName\fR Sets the font for entry labels. This overrides the widget's \fB\-font\fR option for this node. The default is \f(CW*-Helvetica-Bold-R-Normal-*-12-120-*\fR. .TP \fB\-foreground \fIcolor\fR Sets the text color of the entry label. This overrides the widget's \fB\-foreground\fR configuration option. The default is \f(CW""\fR. .TP \fB\-icons \fIimages\fR Specifies images to be displayed for the entry's icon. This overrides the global \fB\-icons\fR configuration option. \fIImages\fR is a list of two Tk images: the first image is displayed when the node is open, the second when it is closed. .TP \fB\-label \fIstring\fR Sets the text for the entry's label. If not set, this defaults to the name of the node. The default is \f(CW""\fR. .TP \fB\-opencommand \fIstring\fR Specifies a Tcl script to be invoked when the entry is opened. This overrides the widget's \fB\-opencommand\fR option for this node. The default is \f(CW""\fR. Percent substitutions are performed on \fIstring\fR before it is executed. The following substitutions are valid: .RS .TP 5 \f(CW%W\fR The pathname of the widget. .TP 5 \f(CW%p\fR The name of the node. .TP 5 \f(CW%P\fR The full pathname of the node. .TP 5 \f(CW%#\fR The id of the node. .TP 5 \f(CW%%\fR Translates to a single percent. .RE .SH "BUTTON OPTIONS" Button configuration options may also be set by the \fBoption\fR command. The resource subclass is \f(CWButton\fR. The resource name is always \f(CWbutton\fR. .CS option add *TreeView.Button.Foreground white option add *TreeView.button.Background blue .CE The following are the configuration options available for buttons. .TP \fB\-activebackground \fIcolor\fR Sets the background color of active buttons. A button is made active when the mouse passes over it or by the \fBbutton activate\fR operation. .TP \fB\-activeforeground \fIcolor\fR Sets the foreground color of active buttons. A button is made active when the mouse passes over it or by the \fBbutton activate\fR operation. .TP \fB\-background \fIcolor\fR Sets the background of the button. The default is \f(CWwhite\fR. .TP \fB\-borderwidth \fIpixels\fR Sets the width of the 3\-D border around the button. The \fB\-relief\fR option determines if a border is to be drawn. The default is \f(CW1\fR. .TP \fB\-closerelief \fIrelief\fR Specifies the 3-D effect for the closed button. \fIRelief\fR indicates how the button should appear relative to the widget; for example, \f(CWraised\fR means the button should appear to protrude. The default is \f(CWsolid\fR. .TP \fB\-cursor \fIcursor\fR Sets the widget's cursor. The default cursor is \f(CW""\fR. .TP \fB\-foreground \fIcolor\fR Sets the foreground color of buttons. The default is \f(CWblack\fR. .TP \fB\-images \fIimages\fR Specifies images to be displayed for the button. \fIImages\fR is a list of two Tk images: the first image is displayed when the button is open, the second when it is closed. If the \fIimages\fR is the empty string, then a plus/minus gadget is drawn. The default is \f(CW""\fR. .TP \fB\-openrelief \fIrelief\fR Specifies the 3-D effect of the open button. \fIRelief\fR indicates how the button should appear relative to the widget; for example, \f(CWraised\fR means the button should appear to protrude. The default is \f(CWflat\fR. .TP \fB\-size \fIpixels\fR Sets the requested size of the button. The default is \f(CW0\fR. .RE .SH "COLUMN OPTIONS" Column configuration options may also be set by the \fBoption\fR command. The resource subclass is \f(CWColumn\fR. The resource name is the name of the column. .CS option add *TreeView.Column.Foreground white option add *TreeView.treeView.Background blue .CE The following configuration options are available for columns. .TP \fB\-background \fIcolor\fR Sets the background color of the column. This overrides the widget's \fB\-background\fR option. The default is \f(CWwhite\fR. .TP \fB\-borderwidth \fIpixels\fR Sets the width of the 3\-D border of the column. The \fB\-relief\fR option determines if a border is to be drawn. The default is \f(CW0\fR. .TP \fB\-edit \fIboolean\fR Indicates if the column's data fields can be edited. If \fIboolean\fR is false, the data fields in the column may not be edited. The default is \f(CWyes\fR. .TP \fB\-foreground \fIcolor\fR Specifies the foreground color of the column. You can override this for individual entries with the entry's \fB\-foreground\fR option. The default is \f(CWblack\fR. .TP \fB\-font \fIfontName\fR Sets the font for a column. You can override this for individual entries with the entry's \fB\-font\fR option. The default is \f(CW*-Helvetica-Bold-R-Normal-*-12-120-*\fR. .TP \fB\-hide \fIboolean\fR If \fIboolean\fR is true, the column is not displayed. The default is \f(CWyes\fR. .TP \fB\-justify \fIjustify\fR Specifies how the column data fields title should be justified within the column. This matters only when the column is wider than the data field to be display. \fIJustify\fR must be \f(CWleft\fR, \f(CWright\fR, or \f(CWcenter\fR. The default is \f(CWleft\fR. .TP \fB\-pad \fIpad\fR Specifies how much padding for the left and right sides of the column. \fIPad\fR is a list of one or two screen distances. If \fIpad\fR has two elements, the left side of the column 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(CW2\fR. .TP \fB\-relief \fIrelief\fR Specifies the 3-D effect of the column. \fIRelief\fR specifies how the column should appear relative to the widget; for example, \f(CWraised\fR means the column should appear to protrude. The default is \f(CWflat\fR. .TP \fB\-state \fIstate\fR Sets the state of the column. If \fIstate\fR is \f(CWdisable\fR then the column title can not be activated nor invoked. The default is \f(CWnormal\fR. .TP \fB\-text \fIstring\fR Sets the title for the column. The default is \f(CW""\fR. .TP \fB\-titleforeground \fIcolor\fR Sets the foreground color of the column title. The default is \f(CWblack\fR. .TP \fB\-titleshadow \fIcolor\fR Sets the color of the drop shadow of the column title. The default is \f(CW""\fR. .TP \fB\-width \fIpixels\fR Sets the requested width of the column. This overrides the computed with of the column. If \fIpixels\fR is 0, the width is computed as from the contents of the column. The default is \f(CW0\fR. .RE .SH "TEXT EDITING OPTIONS" Text edit window configuration options may also be set by the \fBoption\fR command. The resource class is \f(CWTreeViewEditor\fR. The resource name is always \f(CWedit\fR. .CS option add *TreeViewEditor.Foreground white option add *edit.Background blue .CE The following are the configuration options available for the text editing window. .TP \fB\-background \fIcolor\fR Sets the background of the text edit window. The default is \f(CWwhite\fR. .TP \fB\-borderwidth \fIpixels\fR Sets the width of the 3\-D border around the edit window. The \fB\-relief\fR option determines if a border is to be drawn. The default is \f(CW1\fR. .TP \fB\-exportselection \fIboolean\fR Indicates if the text selection is exported. If the edit window is exporting its selection then it will observe the standard X11 protocols for handling the selection. Selections are available as type \fBSTRING\fR. The default is \f(CWno\fR. .TP \fB\-relief \fIrelief\fR Specifies the 3-D effect of the edit window. \fIRelief\fR indicates how the background should appear relative to the edit window; for example, \f(CWraised\fR means the background should appear to protrude. The default is \f(CWsolid\fR. .TP \fB\-selectbackground \fIcolor\fR Sets the background of the selected text in the edit window. The default is \f(CWwhite\fR. .TP \fB\-selectborderwidth \fIpixels\fR Sets the width of the 3\-D border around the selected text in the edit window. The \fB\-selectrelief\fR option determines if a border is to be drawn. The default is \f(CW1\fR. .TP \fB\-selectforeground \fIcolor\fR Sets the foreground of the selected text in the edit window. The default is \f(CWwhite\fR. .TP \fB\-selectrelief \fIrelief\fR Specifies the 3-D effect of the selected text in the edit window. \fIRelief\fR indicates how the text should appear relative to the edit window; for example, \f(CWraised\fR means the text should appear to protrude. The default is \f(CWflat\fR. .RE .SH "DEFAULT BINDINGS" Tk automatically creates class bindings for treeviews that give them Motif-like behavior. Much of the behavior of a \fBtreeview\fR widget is determined by its \fB\-selectmode\fR option, which selects one of two ways of dealing with the selection. .PP If the selection mode is \fBsingle\fR, only one node can be selected at a time. Clicking button 1 on an node selects it and deselects any other selected item. .PP If the selection mode is \fBmultiple\fR, any number of entries may be selected at once, including discontiguous ranges. Clicking Control-Button-1 on a node entry toggles its selection state without affecting any other entries. Pressing Shift-Button-1 on a node entry selects it, extends the selection. .IP [1] In \fBextended\fR mode, the selected range can be adjusted by pressing button 1 with the Shift key down: this modifies the selection to consist of the entries between the anchor and the entry under the mouse, inclusive. The un-anchored end of this new selection can also be dragged with the button down. .IP [2] In \fBextended\fR mode, pressing button 1 with the Control key down starts a toggle operation: the anchor is set to the entry under the mouse, and its selection state is reversed. The selection state of other entries isn't changed. If the mouse is dragged with button 1 down, then the selection state of all entries between the anchor and the entry under the mouse is set to match that of the anchor entry; the selection state of all other entries remains what it was before the toggle operation began. .IP [3] If the mouse leaves the treeview window with button 1 down, the window scrolls away from the mouse, making information visible that used to be off-screen on the side of the mouse. The scrolling continues until the mouse re-enters the window, the button is released, or the end of the hierarchy is reached. .IP [4] Mouse button 2 may be used for scanning. If it is pressed and dragged over the \fBtreeview\fR widget, the contents of the hierarchy drag at high speed in the direction the mouse moves. .IP [5] If the Up or Down key is pressed, the location cursor (active entry) moves up or down one entry. If the selection mode is \fBbrowse\fR or \fBextended\fR then the new active entry is also selected and all other entries are deselected. In \fBextended\fR mode the new active entry becomes the selection anchor. .IP [6] In \fBextended\fR mode, Shift-Up and Shift-Down move the location cursor (active entry) up or down one entry and also extend the selection to that entry in a fashion similar to dragging with mouse button 1. .IP [7] The Left and Right keys scroll the \fBtreeview\fR widget view left and right by the width of the character \fB0\fR. Control-Left and Control-Right scroll the \fBtreeview\fR widget view left and right by the width of the window. Control-Prior and Control-Next also scroll left and right by the width of the window. .IP [8] The Prior and Next keys scroll the \fBtreeview\fR widget view up and down by one page (the height of the window). .IP [9] The Home and End keys scroll the \fBtreeview\fR widget horizontally to the left and right edges, respectively. .IP [10] Control-Home sets the location cursor to the the first entry, selects that entry, and deselects everything else in the widget. .IP [11] Control-End sets the location cursor to the the last entry, selects that entry, and deselects everything else in the widget. .IP [12] In \fBextended\fR mode, Control-Shift-Home extends the selection to the first entry and Control-Shift-End extends the selection to the last entry. .IP [13] In \fBmultiple\fR mode, Control-Shift-Home moves the location cursor to the first entry and Control-Shift-End moves the location cursor to the last entry. .IP [14] The space and Select keys make a selection at the location cursor (active entry) just as if mouse button 1 had been pressed over this entry. .IP [15] In \fBextended\fR mode, Control-Shift-space and Shift-Select extend the selection to the active entry just as if button 1 had been pressed with the Shift key down. .IP [16] In \fBextended\fR mode, the Escape key cancels the most recent selection and restores all the entries in the selected range to their previous selection state. .IP [17] Control-slash selects everything in the widget, except in \fBsingle\fR and \fBbrowse\fR modes, in which case it selects the active entry and deselects everything else. .IP [18] Control-backslash deselects everything in the widget, except in \fBbrowse\fR mode where it has no effect. .IP [19] The F16 key (labelled Copy on many Sun workstations) or Meta-w copies the selection in the widget to the clipboard, if there is a selection. .PP The behavior of \fBtreeview\fR widgets can be changed by defining new bindings for individual widgets or by redefining the class bindings. .SS WIDGET BINDINGS In addition to the above behavior, the following additional behavior is defined by the default widget class (TreeView) bindings. .IP \f(CW\fR Starts scanning. .IP \f(CW\fR Adjusts the scan. .IP \f(CW\fR Stops scanning. .IP \f(CW\fR Starts auto-scrolling. .IP \f(CW\fR Starts auto-scrolling .IP \f(CW\fR Moves the focus to the previous entry. .IP \f(CW\fR Moves the focus to the next entry. .IP \f(CW\fR Moves the focus to the previous sibling. .IP \f(CW\fR Moves the focus to the next sibling. .IP \f(CW\fR Moves the focus to first entry. Closed or hidden entries are ignored. .IP \f(CW\fR Move the focus to the last entry. Closed or hidden entries are ignored. .IP \f(CW\fR Closes the entry. It is not an error if the entry has no children. .IP \f(CW\fR Opens the entry, displaying its children. It is not an error if the entry has no children. .IP \f(CW\fR In "single" select mode this selects the entry. In "multiple" mode, it toggles the entry (if it was previous selected, it is not deselected). .IP \f(CW\fR Turns off select mode. .IP \f(CW\fR Sets the focus to the current entry. .IP \f(CW\fR Turns off select mode. .IP \f(CW\fR Moves to the next entry whose label starts with the letter typed. .IP \f(CW\fR Moves the focus to first entry. Closed or hidden entries are ignored. .IP \f(CW\fR Move the focus to the last entry. Closed or hidden entries are ignored. .IP \f(CW\fR Opens all entries. .IP \f(CW\fR Closes all entries (except root). .SS BUTTON BINDINGS Buttons have bindings. There are associated with the "all" bindtag (see the entry's -bindtag option). You can use the \fBbind\fR operation to change them. .IP \f(CW\fR Highlights the button of the current entry. .IP \f(CW\fR Returns the button back to its normal state. .IP \f(CW\fR Adjust the view so that the current entry is visible. .SS ENTRY BINDINGS Entries have default bindings. There are associated with the "all" bindtag (see the entry's -bindtag option). You can use the \fBbind\fR operation to modify them. .IP \f(CW\fR Highlights the current entry. .IP \f(CW\fR Returns the entry back to its normal state. .IP \f(CW\fR Sets the selection anchor the current entry. .IP \f(CW\fR Toggles the selection of the current entry. .IP \f(CW\fR For "multiple" mode only. Saves the current location of the pointer for auto-scrolling. Resets the selection mark. .IP \f(CW\fR For "multiple" mode only. Sets the selection anchor to the current entry. .IP \f(CW\fR For "multiple" mode only. Extends the selection. .IP \f(CW\fR Place holder. Does nothing. .IP \f(CW\fR Place holder. Does nothing. .IP \f(CW\fR Stop auto-scrolling. .IP \f(CW\fR For "multiple" mode only. Toggles and extends the selection. .IP \f(CW\fR Place holder. Does nothing. .IP \f(CW\fR Place holder. Does nothing. .IP \f(CW\fR Stops auto-scrolling. .IP \f(CW\fR ??? .IP \f(CW\fR Place holder. Does nothing. .IP \f(CW\fR Place holder. Does nothing. .SS COLUMN BINDINGS Columns have bindings too. They are associated with the column's "all" bindtag (see the column -bindtag option). You can use the \fBcolumn bind\fR operation to change them. .IP \f(CW\fR Highlights the current column title. .IP \f(CW\fR Returns the column back to its normal state. .IP \f(CW\fR Invokes the command (see the column's -command option) if one if specified. .SS COLUMN RULE BINDINGS .IP \f(CW\fR Highlights the current and activates the ruler. .IP \f(CW\fR Returns the column back to its normal state. Deactivates the ruler. .IP \f(CW\fR Sets the resize anchor for the column. .IP \f(CW\fR Sets the resize mark for the column. .IP \f(CW\fR Adjust the size of the column, based upon the resize anchor and mark positions. .SH EXAMPLE The \fBtreeview\fR command creates a new widget. .CS treeview .h \-bg white .CE A new Tcl command \f(CW.h\fR is also created. This command can be used to query and modify the \fBtreeview\fR widget. For example, to change the background color of the table to "green", you use the new command and the widget's \fBconfigure\fR operation. .CS # Change the background color. \&.h configure \-background "green" .CE By default, the \fBtreeview\fR widget will automatically create a new tree object to contain the data. The name of the new tree is the pathname of the widget. Above, the new tree object name is ".h". But you can use the \fB\-tree\fR option to specify the name of another tree. .CS # View the tree "myTree". \&.h configure \-tree "myTree" .CE When a new tree is created, it contains only a root node. The node is automatically opened. The id of the root node is always \f(CW0\fR (you can use also use the special id \f(CWroot\fR). The \fBinsert\fR operation lets you insert one or more new entries into the tree. The last argument is the node's \fIpathname\fR. .CS # Create a new entry named "myEntry" set id [\&.h insert end "myEntry"] .CE This appends a new node named "myEntry". It will positioned as the last child of the root of the tree (using the position "end"). You can supply another position to order the node within its siblings. .CS # Prepend "fred". set id [\&.h insert 0 "fred"] .CE Entry names do not need to be unique. By default, the node's label is its name. To supply a different text label, add the \fB\-label\fR option. .CS # Create a new node named "fred" set id [\&.h insert end "fred" -label "Fred Flintstone"] .CE The \fBinsert\fR operation returns the id of the new node. You can also use the \fBindex\fR operation to get this information. .CS # Get the id of "fred" \&.h index "fred" .CE To insert a node somewhere other than root, use the \fB\-at\fR switch. It takes the id of the node where the new child will be added. .CS # Create a new node "barney" in "fred". \&.h insert -at $id end "barney" .CE A pathname describes the path to an entry in the hierarchy. It's a list of entry names that compose the path in the tree. Therefore, you can also add "barney" to "fred" as follows. .CS # Create a new sub-entry of "fred" \&.h insert end "fred barney" .CE Every name in the list is ancestor of the next. All ancestors must already exist. That means that an entry "fred" is an ancestor of "barney" and must already exist. But you can use the \fB\-autocreate\fR configuration option to force the creation of ancestor nodes. .CS # Force the creation of ancestors. \&.h configure -autocreate yes \&.h insert end "fred barney wilma betty" .CE Sometimes the pathname is already separated by a character sequence rather than formed as a list. A file name is a good example of this. You can use the \fB\-separator\fR option to specify a separator string to split the path into its components. Each pathname inserted is automatically split using the separator string as a separator. Multiple separators are treated as one. .CS \&.h configure -separator / \&.h insert end "/usr/local/tcl/bin" .CE If the path is prefixed by extraneous characters, you can automatically trim it off using the \fB\-trim\fR option. It removed the string from the path before it is parsed. .CS \&.h configure -trim C:/windows -separator / \&.h insert end "C:/window/system" .CE You can insert more than one entry at a time with the \fBinsert\fR operation. This can be much faster than looping over a list of names. .CS # The slow way foreach f [glob $dir/*] { \&.h insert end $f } # The fast way eval .h insert end [glob $dir/*] .CE In this case, the \fBinsert\fR operation will return a list of ids of the new entries. .PP You can delete entries with the \fBdelete\fR operation. It takes one or more tags of ids as its argument. It deletes the entry and all its children. .CS \&.h delete $id .CE Entries have several configuration options. They control the appearance of the entry's icon and label. We have already seen the \fB\-label\fR option that sets the entry's text label. The \fBentry configure\fR operation lets you set or modify an entry's configuration options. .CS \&.h entry configure $id -color red -font fixed .CE You can hide an entry and its children using the \fB\-hide\fR option. .CS \&.h entry configure $id -hide yes .CE More that one entry can be configured at once. All entries specified are configured with the same options. .CS \&.h entry configure $i1 $i2 $i3 $i4 -color brown .CE An icon is displayed for each entry. It's a Tk image drawn to the left of the label. You can set the icon with the entry's \fB\-icons\fR option. It takes a list of two image names: one to represent the open entry, another when it is closed. .CS set im1 [image create photo -file openfolder.gif] set im2 [image create photo -file closefolder.gif] \&.h entry configure $id -icons "$im1 $im2" .CE If \fB\-icons\fR is set to the empty string, no icons are display. .PP If an entry has children, a button is displayed to the left of the icon. Clicking the mouse on this button opens or closes the sub-hierarchy. The button is normally a \f(CW+\fR or \f(CW\-\fR symbol, but can be configured in a variety of ways using the \fBbutton configure\fR operation. For example, the \f(CW+\fR and \f(CW\-\fR symbols can be replaced with Tk images. .CS set im1 [image create photo -file closefolder.gif] set im2 [image create photo -file downarrow.gif] \&.h button configure $id -images "$im1 $im2" \\ -openrelief raised -closerelief raised .CE Entries can contain an arbitrary number of \fIdata fields\fR. Data fields are name-value pairs. Both the value and name are strings. The entry's \fB\-data\fR option lets you set data fields. .CS \&.h entry configure $id -data {mode 0666 group users} .CE The \fB\-data\fR takes a list of name-value pairs. .PP You can display these data fields as \fIcolumns\fR in the \fBtreeview\fR widget. You can create and configure columns with the \fBcolumn\fR operation. For example, to add a new column to the widget, use the \fBcolumn insert\fR operation. The last argument is the name of the data field that you want to display. .CS \&.h column insert end "mode" .CE The column title is displayed at the top of the column. By default, it's is the field name. You can override this using the column's \fB\-text\fR option. .CS \&.h column insert end "mode" -text "File Permissions" .CE Columns have several configuration options. The \fBcolumn configure\fR operation lets you query or modify column options. .CS \&.h column configure "mode" -justify left .CE The \fB\-justify\fR option says how the data is justified within in the column. The \fB\-hide\fR option indicates whether the column is displayed. .CS \&.h column configure "mode" -hide yes .CE Entries can be selected by clicking on the mouse. Selected entries are drawn using the colors specified by the \fB\-selectforeground\fR and \fB\-selectbackground\fR configuration options. The selection itself is managed by the \fBselection\fR operation. .CS # Clear all selections \&.h selection clear 0 end # Select the root node \&.h selection set 0 .CE The \fBcurselection\fR operation returns a list of ids of all the selected entries. .CS set ids [\&.h curselection] .CE You can use the \fBget\fR operation to convert the ids to their pathnames. .CS set names [eval .h get -full $ids] .CE If a treeview is exporting its selection (using the \fB\-exportselection\fR option), then it will observe the standard X11 protocols for handling the selection. Treeview selections are available as type \fBSTRING\fR; the value of the selection will be the pathnames of the selected entries, separated by newlines. .PP The \fBtreeview\fR supports two modes of selection: \f(CWsingle\fR and \f(CWmultiple\fR. In single select mode, only one entry can be selected at a time, while multiple select mode allows several entries to be selected. The mode is set by the widget's \fB\-selectmode\fR option. .CS \&.h configure -selectmode "multiple" .CE You can be notified when the list of selected entries changes. The widget's \fB\-selectcommand\fR specifies a Tcl procedure that is called whenever the selection changes. .CS proc SelectNotify { widget } { set ids [\&$widget curselection] } \&.h configure -selectcommand "SelectNotify .h" .CE The widget supports the standard Tk scrolling and scanning operations. The \fBtreeview\fR can be both horizontally and vertically. You can attach scrollbars to the \fBtreeview\fR the same way as the listbox or canvas widgets. .CS scrollbar .xbar -orient horizontal -command ".h xview" scrollbar .ybar -orient vertical -command ".h yview" \&.h configure -xscrollcommand ".xbar set" \\ -yscrollcommand ".ybar set" .CE There are three different modes of scrolling: \f(CWlistbox\fR, \f(CWcanvas\fR, and \f(CWhierbox\fR. In \f(CWlistbox\fR mode, the last entry can always be scrolled to the top of the widget. In \f(CWhierbox\fR mode, the last entry is always drawn at the bottom of the widget. The scroll mode is set by the widget's \fB\-selectmode\fR option. .CS \&.h configure -scrollmode "listbox" .CE Entries can be programmatically opened or closed using the \fBopen\fR and \fBclose\fR operations respectively. .CS \&.h open $id \&.h close $id .CE When an entry is opened, a Tcl procedure can be automatically invoked. The \fB\-opencommand\fR option specifies this procedure. This procedure can lazily insert entries as needed. .CS proc AddEntries { dir } { eval .h insert end [glob -nocomplain $dir/*] } \&.h configure -opencommand "AddEntries %P" .CE Now when an entry is opened, the procedure \f(CWAddEntries\fR is called and adds children to the entry. Before the command is invoked, special "%" substitutions (like \fBbind\fR) are performed. Above, \f(CW%P\fR is translated to the pathname of the entry. .PP The same feature exists when an entry is closed. The \fB\-closecommand\fR option specifies the procedure. .CS proc DeleteEntries { id } { .h entry delete $id 0 end } \&.h configure -closecommand "DeleteEntries %#" .CE When an entry is closed, the procedure \f(CWDeleteEntries\fR is called and deletes the entry's children using the \fBentry delete\fR operation (\f(CW%#\fR is the id of entry). .SH KEYWORDS treeview, widget blt-2.4z.orig/man/htext.mann0100644000175000017500000004144707240160104014532 0ustar dokodoko'\" '\" 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. '\" '\" Hypertext widget created by George Howlett. '\" .so man.macros .TH htext n BLT_VERSION BLT "BLT Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME htext \- Create and manipulate hypertext widgets .SH SYNOPSIS \fBhtext\fP \fIpathName \fR?\fIoption value\fR?... .BE .SH DESCRIPTION .PP The \fBhtext\fR command creates a new window (given by the \fIpathName\fR argument) and makes it into a \fBhtext\fP widget. Additional options, described above, may be specified on the command line or in the option database to configure aspects of the widget such as its color and font. At the time this command is invoked, there must not exist a window named \fIpathName\fR, but \fIpathName\fR's parent must exist. The \fBhtext\fR command returns its \fIpathName\fR. .PP The \fBhtext\fP widget is hybrid of a non-editable text widget and a geometry manager (e.g. the packer). It displays text (optionally read from file) in a window. Text can be scrolled either horizontally or vertically using the \fBhtext\fR window as a viewport. In addition, Tcl commands can be embedded into the text which are evaluated as the text is parsed. Text between special double characters (percent signs "%%") is immediately passed to the Tcl interpreter for evaluation. .PP Furthermore, any widget or widget hierarchy can be packed in-line and made to appear on the current line of the text. Widgets are packed using the \fBhtext append\fP command. All widgets must be children of the \fBhtext\fP window and must already exist before packing. Once a widget has been packed it cannot be moved to a different position within the text. Widgets can be resized but they will remain at the same position within the text. .PP Before a file or text string is parsed by the \fBhtext\fR widget, all the widget's current children are destroyed. You can reload files or text without worrying about unmapping or destroying each child window beforehand. .PP Setting the either the \fB\-filename\fR or \fB\-text\fR configuration option will adjust the value of the other. If both options are set, the file takes precedence. When a new file is read using the \fB\-filename\fR option, the value of the \fB\-text\fR option is reset to the empty string. Likewise, when the \fB\-text\fR option is set, the string representing the \fB\-filename\fR option is cleared. .SH FILE FORMAT The format of \fBhtext\fP text file is typically ASCII text. Text enclosed by special double characters (by default, percent signs '%%') is interpreted and executed as Tcl commands. The special character may be specified by the \fB\-specialchar\fP option. In the following example of a \fBhtext\fP file, a button widget is appended to the text between the words "\f(CWa\fP" and "\f(CWwhich\fP". The \fIpathName\fR of the \fBhtext\fP widget is "\f(CW.ht\fP". .CS \f(CWThis will be displayed as normal text. But this will become a %% button .ht.button -text "button" -fg red .ht append .ht.button %% which can invoke a Tcl command.\fR .CE .LP .SH INDICES .PP Some of the widget operations (\fBselection\fR, \fRgotoline\fR, \fBsearch\fR, etc.) take one or more indices as arguments. An index is a string used to indicate a particular place within the text, such as the first and last characters in a range to be selected. .LP An index must have one of the following forms: .TP 12 \fIline\fB.\fIchar\fR Indicates \fIchar\fR'th character on line \fIline\fR. Both lines and characters are number from 0, so "0.0" is the first beginning of the text. \fIChar\fR may be undesignated. In this case a character position of 0 is assumed. .TP 12 \fB@\fIx\fB,\fIy\fR Indicates the character that covers the pixel whose x and y coordinates within the text's window are \fIx\fR and \fIy\fR. .TP 12 \fBend\fR Indicates the end of the text. .TP 12 \fBanchor\fR Indicates the anchor point for the selection, which is set with the \fBselection\fR operation. .TP 12 \fBsel.first\fR Indicates the first character in the selection. It is an error to use this form if the selection isn't in the entry window. .TP 12 \fBsel.last\fR .VS Indicates the character just after the last one in the selection. .VE It is an error to use this form if the selection isn't in the entry window. .SH "VARIABLES" .PP The following global Tcl variables are maintained when an \fBhtext\fR file is parsed. .TP \fBhtext(widget)\fR is the pathname of the \fBhtext\fP widget. .TP \fBhtext(file)\fR is the name of the file the \fBhtext\fP widget is currently parsing. It is the empty string when the \fB\-text\fP option is used. .TP \fBhtext(line)\fR is the current line number in the text. .PP This information might be used to construct hyper links between different files and/or lines. .LP .SH "SYNTAX" The \fBhtext\fP command creates a new Tcl command whose name is \fIpathName\fR. This command may be used to invoke various operations on the widget. It has the following general form: .DS \fIpathName oper \fR?\fIargs\fR? .DE \fIOper\fR and \fIargs\fR determine the exact behavior of the command. .PP .SH "OPERATIONS" The following operations are available for \fBhtext\fP widgets: .TP \fIpathName \fBappend \fIwindow \fR?\fIoption value\fR?... Embeds the widget \fIwindow\fP into the htext widget. \fIWindow\fP is the pathname of the widget to be embedded which must be a child of \fIpathName\fR. \fIWindow\fR will be positioned in the htext widget at the current location of the text. If \fIoption\fR and \fIvalue\fR pairs are present, they configure various aspects how \fIwindow\fR appears in \fIpathName\fR. The following options are available. .RS .TP \fB\-anchor \fIanchorPos\fR Specifies how \fIwindow\fR will be arranged if there is any extra space in the cavity surrounding the window. For example, if \fIanchorPos\fR is \fBcenter\fR then the window is centered in the cavity; if \fIanchorPos\fR is \fBw\fR then the window will be drawn such it touches the leftmost edge of the cavity. The default is \f(CWcenter\fR. .TP \fB\-fill \fIstyle\fR Specifies how the \fIwindow\fR should be stretched to occupy the extra space in the cavity surrounding it (if any exists). \fIStyle\fR is \f(CWnone\fR, \f(CWx\fR, \f(CWy\fR, \f(CWboth\fR. If \fIstyle\fR is \f(CWx\fR, the width of \fIwindow\fR is expanded to fill the cavity. If \fIstyle\fR is \fBy\fR, the height is expanded. The default is \f(CWnone\fR. .TP \fB\-height \fIpixels\fR Sets the height of the cavity surrounding \fIwindow\fR. If \fIpixels\fP is zero, the height of the cavity will be the same as the requested height of \fIwindow\fR. If \fIpixels\fR is less than the requested height of \fIwindow\fR, \fIwindow\fR will be reduced to fit the cavity. The default is \f(CW0\fR. .TP \fB\-ipadx \fIpad\fR Sets the amount of internal padding to be added to the width \fIwindow\fR. \fIPad\fR can be a list of one or two numbers. If \fIpad\fR has two elements, the left side of \fIwindow\fR is extended by the first value and the right side by the second value. If \fIpad\fR is just one value, both the left and right sides are padded by evenly by the value. The default is \f(CW0\fR. .TP \fB\-ipady \fIpad\fR Sets an amount of internal padding to be added to the height of \fIwindow\fR. \fIPad\fR can be a list of one or two numbers. If \fIpad\fR has two elements, the top of \fIwindow\fR is padded by the first value and the bottom by the second value. If \fIpad\fR is just one number, both the top and bottom are padded evenly by the value. The default is \f(CW0\fR. .TP \fB\-justify \fIjustify\fR Justifies \fIwindow\fR vertically within the cavity containing it in relation to the line of text. \fIJustify\fR is \fBtop\fP, \fBbottom\fR, or \fBcenter\fR. If \fIjustify\fR is \f(CWcenter\fR the widget is centered along the baseline of the line of text. The default is \f(CWcenter\fR. .TP \fB\-padx \fIpad\fR Sets the padding on the left and right sides of \fIwindow\fR. \fIPad\fR can be a list of one or two numbers. If \fIpad\fR has two elements, the left side of \fIwindow\fR is padded by the first value and the right side by the second value. If \fIpad\fR has just one value, both the left and right sides are padded evenly by the value. The default is \f(CW0\fR. .TP \fB\-pady \fIpad\fR Sets the padding above and below \fIwindow\fR. \fIPad\fR can be a list of one or two numbers. If \fIpad\fR has two elements, the area above \fIwindow\fR is padded by the first value and the area below by the second value. If \fIpad\fR is just one number, both the top and bottom are padded by the value. The default is \f(CW0\fR. .TP \fB\-relheight \fIvalue\fR Specifies the height of the cavity containing \fIwindow\fR relative to the height of \fIpathName\fR. \fIValue\fP is real number indicating the ratio of the height of the cavity to the height of \fIpathName\fR. As the height of \fIpathName\fR changes, so will the height of \fIwindow\fR. If \fIvalue\fR is 0.0 or less, the height of the cavity is the requested height \fIwindow\fR. The default is \f(CW0.0\fR. .TP \fB\-relwidth \fIvalue\fR Specifies the width of the cavity containing \fIwindow\fR relative to the width of \fIpathName\fR. \fIValue\fP is real number indicating the ratio of the width of the cavity to the width of \IpathName\fR. As the height of \fIpathName\fR changes, so will the height of \fIwindow\fR. If \fIvalue\fR is 0.0 or less, the width of the cavity is the requested width of \fIwindow\fR. The default is \f(CW0.0\fR. .TP \fB\-width \fIvalue\fR Species the width of the cavity containing the child window. \fIValue\fP must be in a form accepted by \fBTk_GetPixels\fR. If \fIvalue\fP is greater than zero, the cavity is resized to that width. If the requested window width is greater than the cavity's width, the window will be reduced to fit the cavity. By default, the cavity is requested width of the child window. .RE .TP \fIpathName \fBconfigure\fR ?\fIwindow\fR? ?\fIoption\fR? ?\fIvalue option value ...\fR? Queries or modifies the configuration options of the text widget or one of its embedded widgets. If no \fIwindow\fR argument is present, the htext widget itself is configured. Otherwise \fIwindow\fR is the pathname of a widget already embedded into the htext widget. Then this command configure the options for the embedded widget. .PP If \fIoption\fR isn't specified, a list describing all of the current options for \fIpathName\fR or \fIwindow\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 htext or embedded window option \fIoption\fR is set to \fIvalue\fR. .PP The following options are valid for the htext widget. .RS .TP \fB\-background\fR \fIcolor\fI Sets the background of the htext widget to \fIcolor\fR. This default is \f(CWwhite\fR. .TP \fB\-cursor\fR \fIcursor\fR Specifies the cursor for the htext widget. The default cursor is \f(CWpencil\fR. .TP \fB\-filename\fR \fIfileName\fR Specifies a \fBhtext\fP file to be displayed in the window. If the value is the empty string, the \fB\-text\fR option is used instead. See the section .SB FILE FORMAT for a description of the \fBhtext\fP file format. .TP \fB\-font\fR \fIfontName\fR Sets the font of the text in the htext widget to \fIfontName\fR. The default is \f(CW*-Helvetica-Bold-R-Normal-*-12-120-*\fR. .TP \fB\-foreground\fR \fIcolor\fR Sets the foreground of the htext widget to \fIcolor\fR. This is the color of the text. This default is \f(CWblack\fR. .TP \fB\-height\fR \fIpixels\fR Specifies the height of the htext widget window. .TP \fB\-linespacing\fR \fIpixels\fR Specifies the spacing between each line of text. The value must be in a form accepted by \fBTk_GetPixels\fR. The default value is 1 pixel. .TP \fB\-specialchar\fR \fInumber\fR Specifies the ASCII value of the special double character delimiters. In \fBhtext\fP files, the text between these special characters is evaluated as a block of Tcl commands. The default special character is the \f(CW0x25\fR (percent sign). .TP \fB\-text\fR \fItext\fR Specifies the text to be displayed in the htext widget. \fIText\fR can be any valid string of characters. See .SB "FILE FORMAT" for a description. .TP \fB\-xscrollcommand\fR \fIstring\fR Specifies the prefix for a command used to communicate with horizontal scrollbars. When the view in the htext widget's window changes (or whenever anything else occurs that could change the display in a scrollbar, such as a change in the total size of the widget's contents), the widget invoke \fIstring\fR concatenated by two numbers. Each of the numbers is a fraction between 0 and 1, which indicates a position in the document. If this option is not specified, then no command will be executed. .TP \fB\-yscrollcommand\fR \fIstring\fR Specifies the prefix for a command used to communicate with vertical scrollbars. When the view in the htext widget's window changes (or whenever anything else occurs that could change the display in a scrollbar, such as a change in the total size of the widget's contents), the widget invoke \fIstring\fR concatenated by two numbers. Each of the numbers is a fraction between 0 and 1, which indicates a position in the document. If this option is not specified, then no command will be executed. .TP \fB\-width\fR \fIpixels\fR Specifies the desired width of the viewport window. If the \fIpixels\fR is less than one, the window will grow to accommodate the widest line of text. .TP \fB\-xscrollunits\fR \fIpixels\fR Specifies the horizontal scrolling distance. The default is 10 pixels. .TP \fB\-yscrollunits\fR \fIpixels\fR Specifies the vertical scrolling distance. The default is 10 pixels. .RE .TP \fIpathName \fBgotoline \fR?\fIindex\fR? Sets the top line of the text to \fIindex\fP. \fIIndex\fP must be a valid text index (the character offset is ignored). If an \fIindex\fP isn't provided, the current line number is returned. .TP \fIpathName \fBscan mark \fIposition\fR Records \fIposition\fR and the current view in the text window; used in conjunction with later \fBscan dragto\fR commands. \fIPosition\fR must be in the form "\fI@x,y\fR, where \fIx\fR and \fIy\fR are window coordinates. Typically this command is associated with a mouse button press in the widget. It returns an empty string. .TP \fIpathName \fBscan dragto \fIposition\fR Computes the difference between \fIposition\fR and the position registered in the last \fBscan mark\fR command for the widget. The view is then adjusted up or down by 10 times the difference in coordinates. This command is can be associated with mouse motion events to produce the effect of dragging the text at high speed through the window. \fIPosition\fR must be in the form "\fI@x,y\fR, where \fIx\fR and \fIy\fR are window coordinates. The command returns an empty string. .TP \fIpathName \fBsearch \fIpattern\fR ?\fIfrom\fR? ?\fIto\fR? Returns the number of the next line matching \fIpattern\fR. \fIPattern\fR is a string which obeys the matching rules of \fBTcl_StringMatch\fR. \fIFrom\fR and \fIto\fR are text line numbers (inclusive) which bound the search. If no match for \fIpattern\fR can be found, \fB-1\fR is returned. .TP \fIpathName \fBxview \fR?\fIposition\fR? Moves the viewport horizontally to the new text x-coordinate position. \fIPosition\fR is the offset from the left side of the text to the current position and must be in a form accepted by \fBTk_GetPixels\fR. If \fIposition\fR is not present, the current text position is returned. .TP \fIpathName \fByview \fR?\fIposition\fR? Moves the viewport vertically to the new text y-coordinate position. \fIPosition\fR is the offset from the top of the text to the current position and must be in a form accepted by \fBTk_GetPixels\fR. If \fIposition\fR is not present, the current text position is returned. .SH BUGS Text with embedded tabs can be obscured by child windows when scrolled horizontally. .SH KEYWORDS hypertext, widget blt-2.4z.orig/man/man.macros0100644000175000017500000001155707243426113014513 0ustar dokodoko'\" The definitions below are for supplemental macros used in Tcl/Tk '\" manual entries. '\" '\" .AP type name in/out ?indent? '\" Start paragraph describing an argument to a library procedure. '\" type is type of argument (int, etc.), in/out is either "in", "out", '\" or "in/out" to describe whether procedure reads or modifies arg, '\" and indent is equivalent to second arg of .IP (shouldn't ever be '\" needed; use .AS below instead) '\" '\" .AS ?type? ?name? '\" Give maximum sizes of arguments for setting tab stops. Type and '\" name are examples of largest possible arguments that will be passed '\" to .AP later. If args are omitted, default tab stops are used. '\" '\" .BS '\" Start box enclosure. From here until next .BE, everything will be '\" enclosed in one large box. '\" '\" .BE '\" End of box enclosure. '\" '\" .CS '\" Begin code excerpt. '\" '\" .CE '\" End code excerpt. '\" '\" .VS ?version? ?br? '\" Begin vertical sidebar, for use in marking newly-changed parts '\" of man pages. The first argument is ignored and used for recording '\" the version when the .VS was added, so that the sidebars can be '\" found and removed when they reach a certain age. If another argument '\" is present, then a line break is forced before starting the sidebar. '\" '\" .VE '\" End of vertical sidebar. '\" '\" .DS '\" Begin an indented unfilled display. '\" '\" .DE '\" End of indented unfilled display. '\" '\" .SO '\" Start of list of standard options for a Tk widget. The '\" options follow on successive lines, in four columns separated '\" by tabs. '\" '\" .SE '\" End of list of standard options for a Tk widget. '\" '\" .OP cmdName dbName dbClass '\" Start of description of a specific option. cmdName gives the '\" option's name as specified in the class command, dbName gives '\" the option's name in the option database, and dbClass gives '\" the option's class in the option database. '\" '\" .UL arg1 arg2 '\" Print arg1 underlined, then print arg2 normally. '\" '\" RCS: @(#) $Id: man.macros,v 1.3 2001/02/17 07:46:19 ghowlett Exp $ '\" '\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages. .if t .wh -1.3i ^B .nr ^l \n(.l .ad b '\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. '\" # define tabbing values for .AP .de AS .nr )A 10n .if !"\\$1"" .nr )A \\w'\\$1'u+3n .nr )B \\n()Au+15n .\" .if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n .nr )C \\n()Bu+\\w'(in/out)'u+2n .. .AS Tcl_Interp Tcl_CreateInterp in/out '\" # BS - start boxed text '\" # ^y = starting y location '\" # ^b = 1 .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. '\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. '\" # VS - start vertical sidebar '\" # ^Y = starting y location '\" # ^v = 1 (for troff; for nroff this doesn't matter) .de VS .if !"\\$2"" .br .mk ^Y .ie n 'mc \s12\(br\s0 .el .nr ^v 1u .. '\" # VE - end of vertical sidebar .de VE .ie n 'mc .el \{\ .ev 2 .nf .ti 0 .mk ^t \h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n' .sp -1 .fi .ev .\} .nr ^v 0 .. '\" # Special macro to handle page bottom: finish off current '\" # box/sidebar if in box/sidebar mode, then invoked standard '\" # page bottom macro. .de ^B .ev 2 'ti 0 'nf .mk ^t .if \\n(^b \{\ .\" Draw three-sided box if this is the box's first page, .\" draw two sides but no top otherwise. .ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .\} .if \\n(^v \{\ .nr ^x \\n(^tu+1v-\\n(^Yu \kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c .\} .bp 'fi .ev .if \\n(^b \{\ .mk ^y .nr ^b 2 .\} .if \\n(^v \{\ .mk ^Y .\} .. '\" # DS - begin display .de DS .RS .nf .sp .. '\" # DE - end display .de DE .fi .RE .sp .. '\" # SO - start of list of standard options .de SO .SH "STANDARD OPTIONS" .LP .nf .ta 4c 8c 12c .ft B .. '\" # SE - end of list of standard options .de SE .fi .ft R .LP See the \\fBoptions\\fR manual entry for details on the standard options. .. '\" # OP - start of full description for a single option .de OP .LP .nf .ta 4c Command-Line Name: \\fB\\$1\\fR Database Name: \\fB\\$2\\fR Database Class: \\fB\\$3\\fR .fi .IP .. '\" # CS - begin code excerpt .de CS .RS .nf .ta .25i .5i .75i 1i .ft CW .sp .. '\" # CE - end code excerpt .de CE .fi .RE .ft R .sp .. .de UL \\$1\l'|0\(ul'\\$2 .. blt-2.4z.orig/man/spline.mann0100644000175000017500000001747307240160104014672 0ustar dokodoko'\" '\" 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. '\" '\" Spline command created by George Howlett. '\" .so man.macros .TH spline n BLT_VERSION BLT "BLT Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME spline \- Fit curves with spline interpolation .SH SYNOPSIS .sp \fBspline natural \fIx y sx sy\fR .sp \fBspline quadratic \fIx y sx sy\fR .BE .SH DESCRIPTION The \fBspline\fR command computes a spline fitting a set of data points (x and y vectors) and produces a vector of the interpolated images (y-coordinates) at a given set of x-coordinates. .SH INTRODUCTION Curve fitting has many applications. In graphs, curve fitting can be useful for displaying curves which are aesthetically pleasing to the eye. Another advantage is that you can quickly generate arbitrary points on the curve from a small set of data points. .PP A spline is a device used in drafting to produce smoothed curves. The points of the curve, known as \fIknots\fR, are fixed and the \fIspline\fR, typically a thin strip of wood or metal, is bent around the knots to create the smoothed curve. Spline interpolation is the mathematical equivalent. The curves between adjacent knots are piecewise functions such that the resulting spline runs exactly through all the knots. The order and coefficients of the polynominal determine the "looseness" or "tightness" of the curve fit from the line segments formed by the knots. .PP The \fBspline\fR command performs spline interpolation using cubic ("natural") or quadratic polynomial functions. It computes the spline based upon the knots, which are given as x and y vectors. The interpolated new points are determined by another vector which represents the abscissas (x-coordinates) or the new points. The ordinates (y-coordinates) are interpolated using the spline and written to another vector. .SH EXAMPLE Before we can use the \fBspline\fR command, we need to create two BLT vectors which will represent the knots (x and y coordinates) of the data that we're going to fit. Obviously, both vectors must be the same length. .CS # Create sample data of ten points. vector x(10) y(10) for {set i 10} {$i > 0} {incr i -1} { set x($i-1) [expr $i*$i] set y($i-1) [expr sin($i*$i*$i)] } .CE We now have two vectors \f(CWx\fR and \f(CWy\fR representing the ten data points we're trying to fit. The order of the values of \f(CWx\fR must be monotonically increasing. We can use the vector's \fBsort\fR operation to sort the vectors. .CS x sort y .CE The components of \f(CWx\fR are sorted in increasing order. The components of \f(CWy\fR are rearranged so that the original x,y coordinate pairings are retained. .PP A third vector is needed to indicate the abscissas (x-coordinates) of the new points to be interpolated by the spline. Like the x vector, the vector of abscissas must be monotonically increasing. All the abscissas must lie between the first and last knots (x vector) forming the spline. .PP How the abscissas are picked is arbitrary. But if we are going to plot the spline, we will want to include the knots too. Since both the quadratic and natural splines preserve the knots (an abscissa from the x vector will always produce the corresponding ordinate from the y vector), we can simply make the new vector a superset of \f(CWx\fR. It will contain the same coordinates as \f(CWx\fR, but also the abscissas of the new points we want interpolated. A simple way is to use the vector's \fBpopulate\fR operation. .CS x populate sx 10 .CE This creates a new vector \f(CWsx\fR. It contains the abscissas of \f(CWx\fR, but in addition \f(CWsx\fR will have ten evenly distributed values between each abscissa. You can interpolate any points you wish, simply by setting the vector values. .PP Finally, we generate the ordinates (the images of the spline) using the \fBspline\fR command. The ordinates are stored in a fourth vector. .CS spline natural x y sx sy .CE This creates a new vector \f(CWsy\fR. It will have the same length as \f(CWsx\fR. The vectors \f(CWsx\fR and \f(CWsy\fR represent the smoothed curve which we can now plot. .CS graph .graph \&.graph element create original -x x -y x -color blue \&.graph element create spline -x sx -y sy -color red table . .graph .CE The \fBnatural\fR operation employs a cubic interpolant when forming the spline. In terms of the draftmen's spline, a \fInatural spline\fR requires the least amount of energy to bend the spline (strip of wood), while still passing through each knot. In mathematical terms, the second derivatives of the first and last points are zero. .PP Alternatively, you can generate a spline using the \fBquadratic\fR operation. Quadratic interpolation produces a spline which follows the line segments of the data points much more closely. .CS spline quadratic x y sx sy .CE .SH OPERATIONS .TP \fBspline natural \fIx y sx sy\fR Computes a cubic spline from the data points represented by the vectors \fIx\fR and \fIy\fR and interpolates new points using vector \fIsx\fR as the x-coordinates. The resulting y-coordinates are written to a new vector \fIsy\fR. The vectors \fIx\fR and \fIy\fR must be the same length and contain at least three components. The order of the components of \fIx\fR must be monotonically increasing. \fISx\fR is the vector containing the x-coordinates of the points to be interpolated. No component of \fIsx\fR can be less than first component of \fIx\fR or greater than the last component. The order of the components of \fIsx\fR must be monotonically increasing. \fISy\fR is the name of the vector where the calculated y-coordinates will be stored. If \fIsy\fR does not already exist, a new vector will be created. .TP \fBspline quadratic \fIx y sx sy\fR Computes a quadratic spline from the data points represented by the vectors \fIx\fR and \fIy\fR and interpolates new points using vector \fIsx\fR as the x-coordinates. The resulting y-coordinates are written to a new vector \fIsy\fR. The vectors \fIx\fR and \fIy\fR must be the same length and contain at least three components. The order of the components of \fIx\fR must be monotonically increasing. \fISx\fR is the vector containing the x-coordinates of the points to be interpolated. No component of \fIsx\fR can be less than first component of \fIx\fR or greater than the last component. The order of the components of \fIsx\fR must be monotonically increasing. \fISy\fR is the name of the vector where the calculated y-coordinates are stored. If \fIsy\fR does not already exist, a new vector will be created. .SH REFERENCES .nf .sp Numerical Analysis by R. Burden, J. Faires and A. Reynolds. Prindle, Weber & Schmidt, 1981, pp. 112 .sp Shape Preserving Quadratic Splines by D.F.Mcallister & J.A.Roulier Coded by S.L.Dodd & M.Roulier N.C.State University. .sp .fi The original code for the quadratric spline can be found in TOMS #574. .SH KEYWORDS spline, vector, graph blt-2.4z.orig/man/stripchart.mann0100644000175000017500000026563707364206454015612 0ustar dokodoko'\" 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. '\" '\" Stripchart widget created by Sani Nassif and George Howlett. '\" .so man.macros .TH stripchart n BLT_VERSION BLT "BLT Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME stripchart \- 2D strip chart for plotting x and y coordinate data. .SH SYNOPSIS \fBstripchart\fI \fIpathName \fR?\fIoption value\fR?... .BE .SH DESCRIPTION The \fBstripchart\fR command creates a strip chart 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 strip chart. .PP The \fBstripchart\fR is essentially the same as the \fBgraph\fR widget. It works almost exactly the very same way. .PP The use of a strip chart differs in that the X-axis typically refers to time points. Data values are added at intervals. The strip chart lets you automatically maintain a view of the most recent time points. The axis options \fB\-shiftby\fR and \fB\-autorange\fR control this. You can specify different line styles for data points (see the \fB\-styles\fR option). .SH INTRODUCTION The \fBstripchart\fR command creates a new window for plotting two-dimensional data (x,y coordinates). Data points are plotted in a box displayed in the center of the new window. This is the \fIplotting area\fR. The coordinate axes are displayed 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 A strip chart is composed of several components: coordinate axes, data elements, legend, grid, cross hairs, pens, postscript, and annotation markers. .TP 1i \f(CWaxis\fR The stripchart widget can display up to four coordinate axes (two X-coordinate and two Y-coordinate axes), 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 of each major tick. .TP 1i \f(CWcrosshairs\fR Cross hairs are used to finely position the mouse pointer in relation to the coordinate axes. Two perpendicular lines are drawn across the plotting area, intersecting at the current location of the mouse pointer. .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 \fBstripchart \fIpathName \fR?\fIoption value\fR?... .DE The \fBstripchart\fR command creates a new window \fIpathName\fR and makes it into a \fBstripchart\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 may be specified on the command line or in the option database to configure aspects of the strip 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, \fBstripchart\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 perform 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 strip chart are described in the .SB "STRIPCHART OPERATIONS" section. .PP The command can also be used to access components of the strip chart. .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 \fBstripchart\fR command creates a new strip chart. .CS # Create a new strip chart. Plotting area is black. stripchart .s -plotbackground black .CE A new Tcl command \f(CW.s\fR is also created. This command can be used to query and modify the strip chart. For example, to change the title of the strip chart to "My Plot", you use the new command and the widget's \fBconfigure\fR operation. .CS # Change the title. \&.s configure \-title "My Plot" .CE A strip chart 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" \&.s 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 and 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 strip chart. 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 } \&.s 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 display the new values. .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.s\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. \&.s 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 \&.s 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". \&.s 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 operation. .CS # Y-axis is log scale. \&.s axis configure y -logscale yes .CE Axis limits are reset by simply specifying new axis limits using the \fB\-min\fR and \fB\-max\fR configuration options. .CS \&.s axis configure x -min 1.0 -max 1.5 \&.s axis configure y -min 12.0 -max 55.15 .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. \&.s axis configure x -min {} -max {} \&.s axis configure y -min {} -max {} .CE It's common with strip charts to automatically maintain a view of the most recent time points. You can do this my setting the \fB\-autorange\fR option. .CS \&.s axis configure x -autorange 20.0 .CE If the time points are added in X-coordinates 1.0 unit, only the last twenty time points will be displayed. As more data is added, the view will march along. .PP Sometimes the rate of data is so high that changing the axis limits with each additional time point is prohibitive. You can use the \fB\-shiftby\fR option to define an increment to shift the view when needed. .CS \&.s axis configure x -shiftby 15.0 .CE When the view is shifted, it will allow a range of 15 new time points to be added until the axis limits are recomputed. .PP By default, the legend is displayed in the right margin. You can change this or any other legend configuration options using the \fBlegend\fR component. .CS # Configure the legend font, color, and relief \&.s 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. \&.s legend configure -hide yes\fR .CE The \fBstripchart\fR widget has simple drawing procedures called markers. They can be used to highlight or annotate data in the strip chart. The types of markers available are bitmaps, images, polygons, lines, or windows. Markers can be used, for example, to mark or brush points. Here is a text marker which labels the data first point. Markers are created using the \fBmarker\fR operation. .CS # Create a label for the first data point of "line1". \&.s 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 actual 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. \&.s marker configure first_marker -under yes .CE You can add cross hairs or grid lines using the \fBcrosshairs\fR and \fBgrid\fR operations. .CS # Display both cross hairs and grid lines. \&.s crosshairs configure \-hide no \-color red \&.s grid configure \-hide no \-dashes { 2 2 } .CE Finally, to get hardcopy of the strip chart, use the \fBpostscript\fR operation. .CS # Print the strip chart into file "file.ps" \&.s postscript output file.ps \-maxpect yes \-decorations no .CE This generates a file \f(CWfile.ps\fR containing the encapsulated PostScript of the strip chart. The option \fB\-maxpect\fR says to scale the plot to the size of the page. Turning off the \fB\-decorations\fR option indicates that no borders or color backgrounds should be displayed (i.e. the background of the margins, legend, and plotting area will be white). .SH "STRIPCHART 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 stripchart 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 strip chart. If \fIoption\fR isn't specified, a list describing all of 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 stripchart option \fIoption\fR is set to \fIvalue\fR. The following options are valid for the stripchart. .RS .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 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 to draw elements into a pixmap before displaying them on the screen. The advantage of buffering elements is when markers are used heavily. Markers can be moved and redrawn without requiring every element to be redrawn again. The disadvantage is that it takes slightly longer to draw the graph. If \fIboolean\fR is true, data elements are drawn to an internal pixmap. The option should be turned off if the plot is updated frequently. See the .SB "SPEED TIPS" section. The default is \f(CW1\fR. .TP \fB\-buffergraph \fIboolean\fR Indicates whether to draw the graph into a pixmap first. If \fIboolean\fR is true, the entire graph is drawn into a pixmap and then copied onto the screen. This reduces flashing. If false, the graph is drawn directly into the window. Especially under Windows, turning off the option can be helpful when the stripchart is updated frequently. Turning off this option also turns \fB\-bufferelements\fR off. 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 title font. 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 indicates how the interior of the plotting area should appear relative to rest of the strip chart; for example, \f(CWraised\fR means the plot should appear to protrude from the strip chart, relative to the surface of the strip chart. The default is \f(CWsunken\fR. .TP \fB\-relief \fIrelief\fR Specifies the 3-D effect for the widget. \fIRelief\fR indicates how the strip chart should appear relative to widget it is packed into; for example, \f(CWraised\fR means the strip chart 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 displayed 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. 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 strip chart. \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 graph coordinates. .TP \fIpathName \fBlegend \fIoperation \fR?\fIarg\fR?... See the .SB "LEGEND COMPONENT" section. .TP \fIpathName \fBline \fIelemName\fR ?\fIoption value\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 stripchart. 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 strip chart 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 "STRIPCHART COMPONENTS" A strip chart 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 strip chart is partitioned, where each component has its own configuration options and operations that specifically control that aspect or part of the strip chart. .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" \&.s 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. \&.s 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 x and y are drawn in the bottom 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. .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. \&.s 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 as 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?\fIoption value\fR?... Queries or modifies the configuration options of \fIaxisName\fR. 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 strip chart is redrawn. You may query the configuration options. But do not reset them, 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 done. 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 *Stripchart.Axis.Color blue option add *Stripchart.x.LogScale true option add *Stripchart.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 strip chart. .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 *Stripchart.Crosshairs.LineWidth 2 option add *Stripchart.Crosshairs.Color red .CE .RE .TP \fIpathName \fBcrosshairs off\fR Turns of 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 cget \fIelemName \fIoption\fR Returns the current value of the element configuration option given by \fIoption\fR. \fIOption\fR may be any option described below for the element \fBconfigure\fR operation. .TP \fIpathName \fBelement closest \fIx y\fR \fIvarName\fR ?\fIoption value\fR?... ?\fIelemName\fR?... Finds the data point closest to the window coordinates \fIx\fR and \fIy\fR in the element \fIelemName\fR. \fIElemName\fR is the name of an element, that must not be hidden. If no elements are specified, then all visible elements are searched. It returns via the array variable \fIvarName\fR the name of the closest element, the index of its closest point, and the graph coordinates of the point. Returns \f(CW0\fR, if no data point within the threshold distance can be found, otherwise \f(CW1\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 stripchart's \fB\-halo\fR option. .TP \fB\-interpolate \fIboolean\fR Indicates that both the data points and interpolated points along the line segment formed should be considered. If \fIboolean\fR is true, the closest line segment will be selected instead of the closest point. If this option isn't specified, \fIboolean\fR defaults to \f(CW0\fR. .RE .TP \fIpathName \fBelement configure \fIelemName \fR?\fIoption value\fR?... Queries or modifies the configuration options for elements. 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\-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\-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 which 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 upon 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 number of the pen in the list. .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\-weights \fIwVec\fR Specifies the weights of the individual data points. This, in conjunction 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 *Stripchart.Element.symbol line option add *Stripchart.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 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. The default is \f(CWx\fR. .TP \fB\-mapy \fIyAxis\fR Specifies the Y\-axis to display grid lines. \fIYAxis\fR must be the name of an axis. 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 *Stripchart.grid.LineWidth 2 option add *Stripchart.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 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\-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 strip chart; for example, \f(CWraised\fR means the legend should appear to protrude from the strip chart, relative to the surface of the strip 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 *Stripchart.legend.Foreground blue option add *Stripchart.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 \&.s pen configure "activeLine" -color green .CE You can create and use any number of pens. To create a pen, invoke the pen component and its create operation. .CS \&.s 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 \&.s 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 \&.s 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?\fIoption value\fR?... Queries or modifies the configuration options of \fIpenName\fR. 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 *Stripchart.Pen.Color blue option add *Stripchart.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 strip chart can generate encapsulated PostScript output. There are several configuration options you can specify to control how the plot is 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 outputting color information in PostScript, the array variable \fIvarName\fR is checked to see if an element of the name of the color exists. If so, it uses the value of the element 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, which are 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 an element of 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 if PostScript commands to generate color backgrounds and 3-D borders should 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 plot the stripchart with a height different from the one displayed on the screen. If \fIpixels\fR is 0, the height is the same as the displayed 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 the plot so that it fills the PostScript page. The aspect ratio of the strip chart 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 plot the strip chart with a width different from the one drawn on the screen. 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 *Stripchart.postscript.Decorations false option add *Stripchart.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 strip chart. 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 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\-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 *Stripchart.TextMarker.Foreground white option add *Stripchart.BitmapMarker.Foreground white option add *Stripchart.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 Sets the background color of the bitmap. If \fIcolor\fR is \f(CW""\fR, the background color will be transparent. The default background color is \f(CWwhite\fR. .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\-foreground \fIcolor\fR Sets the foreground color of the bitmap. The default foreground color is \f(CWblack\fR. .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\-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\-background \fIcolor\fR Sets the background color of the line. The option is affects the line color only when the \fB\-stipple\fR option is set. If this option isn't specified then it defaults to \f(CWwhite\fR. .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\-foreground \fIcolor\fR Sets the foreground color. The default foreground color is \f(CWblack\fR. .TP \fB\-linewidth \fIpixels\fR Sets the width of the lines. The default width is \f(CW0\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 strip chart. 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 Sets the background color of the text string. If \fIcolor\fR is \f(CW""\fR, the background will be transparent. The default is \f(CWwhite\fR. .TP \fB\-font \fIfontName\fR Specifies the font of the text. The default is \f(CW*-Helvetica-Bold-R-Normal-*-120-*\fR. .TP \fB\-foreground \fIcolor\fR Sets the foreground color of the text. The default is \f(CWblack\fR. .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\-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. \fIPathName\fR must be a child of the \fBstripchart\fR widget. .SH "GRAPH COMPONENT BINDINGS" Specific stripchart 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). .sp 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. .sp 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. .sp The \fB\-bindtags\R 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 and y data coordinates of an element as vectors and manipulate the vector from C. The strip chart 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 \&.s 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 strip chart 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 strip 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 the looked at, the more work the strip 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 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 strip chart is first displayed, it draws data elements into an internal pixmap. The pixmap acts as a cache, so that when the strip 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 strip chart. But if the strip 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 "FUTURE INCOMPATIBILITY" The \fB\-mapped\fR options are obsoleted and will be removed. You can achieve the same results using the \fB\-hide\fR option instead. .CS # Works for now. \&.s legend configure -mapped no # Instead use this. \&.s legend configure -hide yes .CE .SH KEYWORDS stripchart, graph, widget blt-2.4z.orig/man/table.mann0100644000175000017500000007161707240160105014470 0ustar dokodoko'\" '\" 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. '\" '\" The table geometry manager created by George Howlett. '\" .so man.macros .TH table n BLT_VERSION BLT "BLT Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME table \- Arranges widgets in a table .SH SYNOPSIS \fBtable \fIcontainer\fR ?\fIwidget index option value\fR?... .sp \fBtable arrange\fR \fIcontainer\fR .sp \fBtable cget \fIcontainer\fR ?\fIitem\fR? \fIoption\fR .sp \fBtable configure \fIcontainer\fR ?\fIitem\fR?... ?\fIoption value\fR?... .sp \fBtable extents \fIcontainer\fR \fIitem\fR .sp \fBtable forget \fIwidget\fR ?\fIwidget\fR?... .sp \fBtable info \fIcontainer\fR \fIitem\fR .sp \fBtable locate \fIcontainer\fR \fIx y\fR .sp \fBtable containers \fR?\fIswitch\fR? ?\fIarg\fR? .sp \fBtable save \fIcontainer\fR .sp \fBtable search \fIcontainer\fR ?\fIswitch arg\fR?... .BE .SH DESCRIPTION The \fBtable\fR command arranges widgets in a table. The alignment of widgets is detemined by their row and column positions and the number of rows or columns that they span. .SH INTRODUCTION Probably the most painstaking aspect of building a graphical application is getting the placement and size of the widgets just right. It usually takes many iterations to align widgets and adjust their spacing. That's because managing the geometry of widgets is simply not a packing problem, but also graphical design problem. Attributes such as alignment, symmetry, and balance are more important than minimizing the amount of space used for packing. .PP The \fBtable\fR geometry manager arranges widgets in a table. It's easy to align widgets (horizontally and vertically) or to create empty space to balance the arrangement of the widgets. Widgets (called \fIslaves\fR in the Tk parlance) are arranged inside a containing widget (called the \fImaster\fR). Widgets are positioned at row,column locations and may span any number of rows or columns. More than one widget can occupy a single location. .PP The placement of widget windows determines both the size and arrangement of the table. The table queries the requested size of each widget. The \fIrequested size\fR of a widget is the natural size of the widget (before the widget is shrunk or expanded). The height of each row and the width of each column is the largest widget spanning that row or column. The size of the table is in turn the sum of the row and column sizes. This is the table's \fInormal size\fR. .PP The total number of rows and columns in a table is determined from the indices specified. The table grows dynamically as windows are added at larger indices. .SH EXAMPLE The table geometry manager is created by invoking the \fBtable\fR command. .CS # Create a table in the root window table . .CE The window \f(CW.\fR is now the \fIcontainer\fR of the table. Widgets are packed into the table and displayed within the confines of the container. .PP You add widgets to the table by row and column location. Row and column indices start from zero. .CS label .title -text "This is a title" # Add a label to the table table . .title 0,0 .CE The label \f(CW.title\fR is added to the table. We can add more widgets in the same way. .CS button .ok -text "Ok" button .cancel -text "Cancel" # Add two buttons table . .ok 1,0 table . .cancel 1,1 .CE Two buttons \f(CW.ok\fR and \f(CW.cancel\fR are now packed into the second row of the table. They each occupy one cell of the table. By default, widgets span only a single row and column. .PP The first column contains two widgets, \f(CW.title\fR and \f(CW.ok\fR. By default, the widest of the two widgets will define the width of the column. However, we want \f(CW.title\fR to be centered horizontally along the top of the table. We can make \f(CW.title\fR span two columns using the \fBconfigure\fR operation. .CS # Make the label span both columns table configure . .title -cspan 2 .CE The label \f(CW.title\fR will now be centered along the top row of the table. .PP In the above example, we've create and arranged the layout for the table invoking the \fBtable\fR command several times. Alternately, we could have used a single \fBtable\fR command. .CS label .title -text "This is a title" button .ok -text "Ok" button .cancel -text "Cancel" # Create and pack the table table . \\ .title 0,0 -cspan 2 \\ .ok 1,0 \\ .cancel 1,1 .CE The table will override the requested width and height of the container so that the window fits the table exactly. This also means that any change to the size of table will be propagated up through the Tk window hierarchy. This feature can be turned off using the \fBconfigure\fR operation again. .CS table configure . -propagate no .CE You can also set the width of height of the table to a specific value. This supersedes the calculated table size. .CS # Make the container 4 inches wide, 3 inches high table configure . -reqwidth 4i -reqheight 3i .CE If a widget is smaller than the cell(s) it occupies, the widget will float within the extra space. By default, the widget will be centered within the space, but you can anchor the widget to any side of cell using the \fB\-anchor\fR configuration option. .CS table configure . .ok -anchor w .CE The \fB\-fill\fR option expands the widget to fill the extra space either vertically or horizontally (or both). .CS # Make the title label fill the entire top row table configure . .title -cspan 2 -fill x # Each button will be as height of the 2nd row. table configure . .ok .cancel -fill y .CE The width of \f(CW.title\fR will be the combined widths of both columns. Both \f(CW.ok\fR and \f(CW.cancel\fR will become as tall as the second row. .PP The \fB\-padx\fR and \fB\-pady\fR options control the amount of padding around the widget. Both options take a list of one or two values. .CS # Pad the title by two pixels above and below. table configure . .title -pady 2 # Pad each button 2 pixels on the left, and 4 on the right. table configure . .ok .cancel -padx { 2 4 } .CE If the list has only one value, then both exterior sides (top and bottom or left and right) of the widget are padded by that amount. If the list has two elements, the first specifies padding for the top or left side and the second for the bottom or right side. .PP Like the container, you can also override the requested widths and heights of widgets using the \fB\-reqwidth\fR and \fB\-reqheight\fR options. This is especially useful with character-based widgets (such as buttons, labels, text, listbox, etc) that let you specify their size only in units of characters and lines, instead of pixels. .CS # Make all buttons one inch wide table configure . .ok .cancel -reqwidth 1i .CE .PP Each row and column of the table can be configured, again using the \fBconfigure\fR operation. Rows are and columns are designated by \f(CWR\fIi\fR and \f(CWC\fIi\fR respectively, where \fIi\fR is the index of the row or column. .PP For example, you can set the size of a row or column. .CS # Make the 1st column 2 inches wide table configure . c0 -width 2.0i # Make the 2nd row 1/2 inch high. table configure . r1 -height 0.5i .CE The new size for the row or column overrides its calculated size. If no widgets span the row or column, its height or width is zero. So you can use the \fB\-width\fR and \fB\-height\fR options to create empty spaces in the table. .CS # Create an empty row and column table configure . r2 c2 -width 1i .CE The \fB\-pady\fR option lets you add padding to the top and bottom sides of rows. The \fB\-padx\fR option adds padding to the left and right sides of columns. Both options take a list of one or two values. .CS # Pad above the title by two pixels table configure . r0 -pady { 2 0 } # Pad each column 4 pixels on the left, and 2 on the right. table configure . c* -padx { 2 4 } .CE .PP Notice that you can configure all the rows and columns using either \f(CWR*\fR or \f(CWC*\fR. .PP When the container is resized, the rows and columns of the table are also resized. Only the rows or columns that contain widgets (a widget spans the row or column) grow or shrink. The \fB\-resize\fR option indicates whether the row or column can be shrunk or stretched. If the value is \f(CWshrink\fR, the row or column can only be resized smaller. If \f(CWexpand\fR, it can only be resized larger. If \f(CWnone\fR, the row or column is frozen at its requested size. .CS # Let the 1st column get smaller, but not bigger table configure . c0 -resize shrink # Let the 2nd column get bigger, not smaller table configure . c1 -resize expand # Don't resize the first row table configure . r0 -resize none .CE The following example packs a canvas, two scrollbars, and a title. The rows and columns containing the scrollbars are frozen at their requested size, so that even if the frame is resized, the scrollbars will remain the same width. .CS table . \\ .title 0,0 -cspan 3 \\ .canvas 1,1 -fill both \\ .vscroll 1,2 -fill y \\ .hscroll 2,1 -fill x # Don't let the scrollbars resize table configure . c2 r2 -resize none # Create an empty space to balance the scrollbar table configure . c0 -width .vscroll .CE Note that the value of the \fB\-width\fR option is the name of a widget window. This indicates that the width of the column should be the same as the requested width of \f(CW.vscroll\fR. .PP Finally, the \fBforget\fR operation removes widgets from the table. .CS # Remove the windows from the table table forget .quit .frame .CE It's not necessary to specify the container. The \fBtable\fR command determines the container from the widget name. .SH OPERATIONS The following operations are available for the \fBtable\fR: .TP \fBtable \fIcontainer\fR ?\fIwidget index option value\fR?... Adds the widget \fIwidget\fR to the table at \fIindex\fR. \fIIndex\fR is a row,column position in the table. It must be in the form \fIrow\fR,\fIcolumn\fR where \fIrow\fR and \fIcolumn\fR are the respective row and column numbers, starting from zero (0,0 is the upper leftmost position). \fIRow\fR and \fIcolumn\fR may also be numeric expressions that are recursively evaluated. If a table doesn't exist for \fIcontainer\fR, one is created. \fIWidget\fR is the path name of the window, that must already exist, to be arranged inside of \fIcontainer\fR. \fIOption\fR and \fIvalue\fR are described in the .SB WIDGET OPTIONS section. .TP \fBtable arrange\fR \fIcontainer\fR Forces the table to compute its layout immediately. Normally, the table geometry manager will wait until the next idle point, before calculating the size of its rows and columns. This is useful for collecting the \fInormal\fR sizes of rows and columns, that are based upon the requested widget sizes. .TP \fBtable cget\fR \fIcontainer \fR?\fIitem\fR?\fI option\fR Returns the current value of the configuration option specific to \fIitem\fR given by \fIoption\fR. \fIItem\fR is either a row or column index, or the path name of a widget. \fIItem\fR can be in any form describe in the \fBconfigure\fR operation below. If no \fIitem\fR argument is provided, then the configuration option is for the table itself. \fIOption\fR may be any one of the options described in the appropiate section for \fIitem\fR. .TP \fBtable configure\fR \fIcontainer item\fR... ?\fIoption value\fR?... Queries or modifies the configuration options specific to \fIitem\fR. If no \fIoption\fR is specified, this command returns a list describing all of the available options for \fIitem\fR If the argument \fIitem\fR is omitted, then the specified configuration options are for the table itself. Otherwise \fIitem\fR must be either a row or column specification, or the path name of a widget. The following \fIitem\fR types are available. .RS .TP \f(CWC\fIi\fR Specifies the column of \fIcontainer\fR to be configured. \fIItem\fR must be in the form \f(CWC\fIn\fR, where \fIi\fR is the index of the column. See the .SB COLUMN OPTIONS section. .TP \f(CWR\fIi\fR Specifies the row of \fIcontainer\fR to be configured. \fIItem\fR must be in the form \f(CWR\fIi\fR, where \fIi\fR is the index of the row. See the .SB ROW OPTIONS section. .TP \fIwidget\fR Specifies a widget of \fIcontainer\fR to be queried. \fIWidget\fR is the path name of a widget packed in \fIcontainer\fR. See the .SB WIDGET OPTIONS section. .TP No argument Specifies that the table itself is to be queried. See the .SB TABLE OPTIONS section for a description of the option-value pairs for the table. .RE .RS .sp The \fIoption\fI and \fIvalue\fR pairs are specific to \fIitem\fR. If \fIoption\fR is specified with no \fIvalue\fR, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no \fIoption\fR is specified). If one or more \fIoption\-value\fR pairs are specified, then the command modifies the given option(s) to have the given value(s); in this case the command returns the empty string. .RE .TP \fBtable extents \fIcontainer\fR \fIindex\fR Queries the location and dimensions of row and columns in the table. \fIIndex\fR can be either a row or column index or a table index. Returns a list of the x,y coordinates (upperleft corner) and dimensions (width and height) of the cell, row, or column. .TP \fBtable forget \fIwidget\fR ?\fIwidget\fR?... Requests that \fIwidget\fR no longer have its geometry managed. \fIWidget\fR is the pathname of the window currently managed by some table. The window will be unmapped so that it no longer appears on the screen. If \fIwidget\fR is not currently managed by any table, an error message is returned, otherwise the empty string. .TP \fBtable info \fIcontainer\fR \fIitem\fR Returns a list of the current configuration options for \fIitem\fR. The list returned is exactly in the form that might be specified to the \fBtable\fR command. It can be used to save and reset table configurations. \fIItem\fR must be one of the following. .RS .TP .75i \f(CWC\fIi\fR Specifies the column of \fIcontainer\fR to be queried. \fIItem\fR must be in the form \f(CWC\fIn\fR, where \fIn\fR is the index of the column. .TP \f(CWR\fIi\fR Specifies the row of \fIcontainer\fR to be queried. \fIItem\fR must be in the form \f(CWR\fIi\fR, where \fIi\fR is the index of the row. .TP \fIwidget\fR Specifies a widget of \fIcontainer\fR to be queried. \fIWidget\fR is the path name of a widget packed in \fIcontainer\fR. .TP No argument Specifies that the table itself is to be queried. .RE .TP \fBtable locate \fIcontainer\fR \fIx y\fR Returns the table index (row,column) of the cell containing the given screen coordinates. The \fIx\fR and \fIy\fR arguments represent the x and y coordinates of the sample point to be tested. .TP \fBtable containers \fR?\fIswitch arg\fR? Returns a list of all container windows matching a given criteria (using \fIswitch\fR and \fIarg\fR). If no \fIswitch\fR and \fIarg\fR arguments are given, the names of all container windows (only those using the \fBtable\fR command) are returned. The following are valid switches: .RS .TP \fB\-pattern\fR \fIpattern\fR Returns a list of pathnames of all container windows matching \fIpattern\fR. .TP \fB\-slave\fR \fIwindow\fR Returns the name of the container window of table managing \fIwindow\fR. \fIWindow\fR must be the path name of widget. If \fIwindow\fR is not managed by any table, the empty string is returned. .RE .TP \fBtable search \fIcontainer\fR ?\fIswitch arg\fR?... Returns the names of all the widgets in \fIcontainer\fR matching the criteria given by \fIswitch\fR and \fIarg\fR. \fIContainer\fR is name of the container window associated with the table to be searched. The name of the widget is returned if any one \fIswitch\fR-\fIarg\fR criteria matches. If no \fIswitch\fR-\fIarg\fR arguments are given, the names of all widgets managed by \fIcontainer\fR are returned. The following are switches are available: .RS .TP \fB\-pattern\fR \fIpattern\fR Returns the names of any names of the widgets matching \fIpattern\fR. .TP \fB\-span\fR \fIindex\fR Returns the names of widgets that span \fIindex\fR. A widget does not need to start at \fIindex\fR to be included. \fIIndex\fR must be in the form \fIrow\fR,\fIcolumn\fR, where \fIrow\fR and \fIcolumn\fR are valid row and column numbers. .TP \fB\-start\fR \fIindex\fR Returns the names of widgets that start at \fIindex\fR. \fIIndex\fR must be in the form \fIrow\fR,\fIcolumn\fR, where \fIrow\fR and \fIcolumn\fR are valid row and column numbers. .RE .SH TABLE OPTIONS To configure the table itself, you omit the \fIitem\fR argument when invoking the \fBconfigure\fR operation. .CS \fBtable configure\fR \fIcontainer\fR ?\fIoption value\fR?... .CE The following options are available for the table: .RS .TP \fB\-padx \fIpad\fR Sets how much padding to add to the left and right exteriors of the table. \fIPad\fR can be a list of one or two numbers. If \fIpad\fR has two elements, the left side of the table is padded by the first value and the right side by the second value. If \fIpad\fR has just one value, both the left and right sides are padded evenly by the value. The default is \f(CW0\fR. .TP \fB\-pady \fIpad\fR Sets how much padding to add to the top and bottom exteriors of the table. \fIPad\fR can be a list of one or two numbers. If \fIpad\fR has two elements, the area above the table is padded by the first value and the area below by the second value. If \fIpad\fR is just one number, both the top and bottom areas are padded by the value. The default is \f(CW0\fR. .TP \fB\-propagate \fIboolean\fR Indicates if the table should override the requested width and height of the \fIcontainer\fR window. If \fIboolean\fR is false, \fIcontainer\fR will not be resized. \fIContainer\fR will be its requested size. The default is \f(CW1\fR. .RE .SH WIDGET OPTIONS widgets are configured by specifying the name of the widget when invoking the \fBconfigure\fR operation. .DS \fBtable configure\fR \fIcontainer \fIwidget\fR ?\fIoption value\fR?... .DE \fIWidget\fR must be the path name of a window already packed in the table associated with \fIcontainer\fR. The following options are available for widgets: .RS .TP \fB\-anchor \fIanchor\fR Anchors \fIwidget\fR to a particular edge of the cell(s) it resides. This option has effect only if the space of the spans surrounding \fIwidget\fR is larger than \fIwidget\fR. \fIAnchor\fR specifies how \fIwidget\fR will be positioned in the space. For example, if \fIanchor\fR is \f(CWcenter\fR then the window is centered in the rows and columns it spans; if \fIanchor\fR is \f(CWw\fR then the window will be aligned with the leftmost edge of the span. The default is \f(CWcenter\fR. .TP \fB\-columnspan \fInumber\fR Sets the number of columns \fIwidget\fR will span. The default is \f(CW1\fR. .TP \fB\-columncontrol \fIcontrol\fR Specifies how the width of \fIwidget\fR should control the width of the columns it spans. \fIControl\fR is either \f(CWnormal\fR, \f(CWnone\fR, or \f(CWfull\fR. The default is \f(CWnormal\fR. .RS .TP 1i \f(CWnone\fR The width of \fIwidget\fR is not considered. .TP 1i \f(CWfull\fR Only the width of \fIwidget\fR will be considered when computing the widths of the columns. .TP 1i \f(CWnormal\fR Indicates that the widest widget spanning the column will determine the width of the span. .RE .TP \fB\-fill \fIfill\fR Specifies if \fIwidget\fR should be stretched to fill any free space in the span surrounding \fIwidget\fR. \fIFill\fR is either \f(CWnone\fR, \f(CWx\fR, \f(CWy\fR, \f(CWboth\fR. The default is \f(CWnone\fR. .RS .TP 1i \f(CWx\fR The widget can grow horizontally. .TP 1i \f(CWy\fR The widget can grow vertically. .TP 1i \f(CWboth\fR The widget can grow both vertically and horizontally. .TP 1i \f(CWnone\fR The widget does not grow along with the span. .RE .TP \fB\-ipadx \fIpixels\fR Sets how much horizontal padding to add internally on the left and right sides of \fIwidget\fR. \fIPixels\fR must be a valid screen distance like \f(CW2\fR or \f(CW0.3i\fR. The default is \f(CW0\fR. .TP \fB\-ipady \fIpixels\fR Sets how much vertical padding to add internally on the top and bottom of \fIwidget\fR. \fIPixels\fR must be a valid screen distance like \f(CW2\fR or \f(CW0.3i\fR. The default is \f(CW0\fR. .TP \fB\-padx \fIpad\fR Sets how much padding to add to the left and right exteriors of \fIwidget\fR. \fIPad\fR can be a list of one or two numbers. If \fIpad\fR has two elements, the left side of \fIwidget\fR is padded by the first value and the right side by the second value. If \fIpad\fR has just one value, both the left and right sides are padded evenly by the value. The default is \f(CW0\fR. .TP \fB\-pady \fIpad\fR Sets how much padding to add to the top and bottom exteriors of \fIwidget\fR. \fIPad\fR can be a list of one or two numbers. If \fIpad\fR has two elements, the area above \fIwidget\fR is padded by the first value and the area below by the second value. If \fIpad\fR is just one number, both the top and bottom areas are padded by the value. The default is \f(CW0\fR. .TP \fB\-reqheight \fIheight\fR Specifies the limits of the requested height for \fIwidget\fR. \fIHeight\fR is a list of bounding values. See the .SB BOUNDING SIZES section for a description of this list. By default, the height of \fIwidget\fR is its requested height with its internal padding (see the \fB\-ipady\fR option). The bounds specified by \fIheight\fR either override the height completely, or bound the height between two sizes. The default is \f(CW""\fR. .TP \fB\-reqwidth \fIwidth\fR Specifies the limits of the requested width for \fIwidget\fR. \fIWidth\fR is a list of bounding values. See the .SB BOUNDING SIZES section for a description of this list. By default, the width of \fIwidget\fR is its requested width with its internal padding (set the \fB\-ipadx\fR option). The bounds specified by \fIwidth\fR either override the width completely, or bound the height between two sizes. The default is \f(CW""\fR. .TP \fB\-rowspan \fInumber\fR Sets the number of rows \fIwidget\fR will span. The default is \f(CW1\fR. .TP \fB\-rowcontrol \fIcontrol\fR Specifies how the height of \fIwidget\fR should control the height of the rows it spans. \fIControl\fR is either \f(CWnormal\fR, \f(CWnone\fR, or \f(CWfull\fR. The default is \f(CWnormal\fR. .RS .TP 1i \f(CWnone\fR The height of \fIwidget\fR is not considered. .TP 1i \f(CWfull\fR Only the height of \fIwidget\fR will be considered when computing the heights of the rows. .TP 1i \f(CWnormal\fR Indicates that the tallest widget spanning the row will determine the height of the span. .RE .RE .SH COLUMN OPTIONS To configure a column in the table, specify the column index as \f(CWC\fIi\fR, where \fIi\fR is the index of the column to be configured. .DS \fBtable configure\fR \fIcontainer \f(CWC\fIi\fR ?\fIoption value\fR?... .DE If the index is specified as \f(CWC*\fR, then all columns of the table will be configured. The following options are available for table columns. .RS .TP \fB\-padx \fIpad\fR Sets the padding to the left and right of the column. \fIPad\fR can be a list of one or two numbers. If \fIpad\fR has two elements, the left side of the column is padded by the first value and the right side by the second value. If \fIpad\fR has just one value, both the left and right sides are padded evenly by the value. The default is \f(CW0\fR. .TP \fB\-resize \fImode\fR Indicates that the column can expand or shrink from its requested width when the table is resized. \fIMode\fR must be one of the following: \f(CWnone\fR, \f(CWexpand\fR, \f(CWshrink\fR, or \f(CWboth\fR. If \fImode\fR is \f(CWexpand\fR the width of the column is expanded if there is extra space in the container window. If \fImode\fR is \f(CWshrink\fR its width may be reduced beyond its requested width if there is not enough space in the container. The default is \f(CWnone\fR. .TP \fB\-width \fIwidth\fR Specifies the limits within that the width of the column may expand or shrink. \fIWidth\fR is a list of bounding values. See the section .SB BOUNDING SIZES for a description of this list. By default there are no constraints. .RE .SH ROW OPTIONS To configure a row in the table, specify the row index as \f(CWR\fIi\fR, where \fIi\fR is the index of the row to be configured. .DS \fBtable configure\fR \fIcontainer \f(CWR\fIi\fR ?\fIoption value\fR?... .DE If the index is specified as \f(CWR*\fR, then all rows of the table will be configured. The following options are available for table rows. .RS .TP \fB\-height \fIheight\fR Specifies the limits of the height that the row may expand or shrink to. \fIHeight\fR is a list of bounding values. See the section .SB BOUNDING SIZES for a description of this list. By default there are no constraints. .TP \fB\-pady \fIpad\fR Sets the padding above and below the row. \fIPad\fR can be a list of one or two numbers. If \fIpad\fR has two elements, the area above the row is padded by the first value and the area below by the second value. If \fIpad\fR is just one number, both the top and bottom areas are padded by the value. The default is \f(CW0\fR. .TP \fB\-resize \fImode\fR Indicates that the row can expand or shrink from its requested height when the table is resized. \fIMode\fR must be one of the following: \f(CWnone\fR, \f(CWexpand\fR, \f(CWshrink\fR, or \f(CWboth\fR. If \fImode\fR is \f(CWexpand\fR the height of the row is expanded if there is extra space in the container. If \fImode\fR is \f(CWshrink\fR its height may be reduced beyond its requested height if there is not enough space in the container. The default is \f(CWnone\fR. .RE .SH BOUNDING SIZES Sometimes it's more useful to limit resizes to an acceptable range, than to fix the size to a particular value or disallow resizing altogether. Similar to the way the \fBwm\fR command lets you specify a \fBminsize\fR and \fBmaxsize\fR for a toplevel window, you can bound the sizes the container, a widget, row, or column may take. The \fB\-width\fR, \fB\-height\fR, \fB\-reqwidth\fR, and \fB\-reqheight\fR options, take a list of one, two, or three values. We can take a previous example and instead preventing resizing, bound the size of the scrollbars between two values. .CS table . \\ .title 0,0 -cspan 3 \\ .canvas 1,1 -fill both \\ .vscroll 1,2 -fill y \\ .hscroll 2,1 -fill x # Bound the scrollbars between 1/8 and 1/2 inch table configure . c2 -width { 0.125 0.5 } table configure . r2 -height { 0.125 0.5 } table configure . vscroll .hscroll -fill both .CE The scrollbars will get no smaller than 1/8 of an inch, or bigger than 1/2 inch. The initial size will be their requested size, so long as it is within the specified bounds. .PP How the elements of the list are interpreted is dependent upon the number of elements in the list. .RS .TP 1i {\fI\fR} Empty list. No bounds are set. The default sizing is performed. .TP {\fI x \fR} Fixes the size to \fIx\fR. The window or partition cannot grow or shrink. .TP {\fI min max \fR} Sets up minimum and maximum limits for the size of the window or partition. The window or partition can be reduced less than \fImin\fR, nor can it be stretched beyond \fImax\fR. .TP {\fI min max nom \fR} Specifies minimum and maximum size limits, but also specifies a nominal size \fInom\fR. This overrides the calculated size of the window or partition. .RE .SH MISCELLANEOUS Another feature is that you can put two widgets in the same cell of the table. This is useful when you want to add decorations around a widget. .CS frame .frame -bd 1 -relief sunken button .quit -text "Quit" # Put both the frame and the button in the same cell. table . \\ .quit 1,0 -padx 2 -pady 2 \\ .frame 1,0 -fill both .CE .SH LIMITATIONS A long standing bug in Tk (circa 1993), there is no way to detect if a window is already a container of a different geometry manager. This is usually done by accident, such as the following where all three widgets are arranged in the same container ".", but using different geometry managers. .CS table .f1 ... pack .f2 ... grid .f3 .CE This leads to bizarre window resizing, as each geometry manager applies its own brand of layout policies. When the container is a top level window (such as "."), your window manager may become locked as it responds to the never-ending stream of resize requests. .SH KEYWORDS frame, geometry manager, location, table, size blt-2.4z.orig/man/tabset.mann0100644000175000017500000012011607464047705014672 0ustar dokodoko'\" '\" Copyright 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. '\" '\" Tabset widget created by George Howlett. '\" .so man.macros .TH tabset n BLT_VERSION BLT "BLT Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME tabset \- Create and manipulate tabset widgets .BE .SH SYNOPSIS \fBtabset\fR \fIpathName \fR?\fIoptions\fR? .SH DESCRIPTION The \fBtabset\fR widget displays a series of overlapping folders. Only the contents of one folder at a time is displayed. By clicking on the tab's of a folder, you can view other folders. Each folder may contain any Tk widget that can be automatically positioned and resized in the folder. .PP There's no limit to the number of folders. Tabs can be tiered or scrolled. Pages (i.e. embedded widgets) can be torn off and displayed in another toplevel widget, and also restored. A tabset can also be used as just a set of tabs, without a displaying any pages. You can bind events to individual tabs, so it's easy to add features like "balloon help". .SH INTRODUCTION Notebooks are a popular graphical paradigm. They allow you to organize several windows that are too big to display at the same time as pages of a notebook. For example, your application may display several X-Y graphs at the same time. The graphs are too big to pack into the same frame. Managing them in several \fBtoplevel\fR widgets is also cumbersome and clutters the screen. Instead, the \fBtabset\fR widget organizes the graphs as folders in a notebook. .PP Only one page is visible at a time. When you click on a tab, the folder corresponding to the tab is displayed in the \fBtabset\fR widget. The tabset also lets you temporarily tear pages out of the notebook into a separate toplevel widget, and put them back in the tabset later. For example, you could compare two graphs side-by-side by tearing them out, and then replace them when you are finished. .PP A tabset can contain any number of folders. If there are too many tabs to view, you can arrange them as multiple tiers or scroll the tabs. You can also attach Tk scrollbars to the tabset to scroll the tabs. .SH SYNTAX The \fBtabset\fR command creates a new window using the \fIpathName\fR argument and makes it into a tabset widget. .DS \fBtabset \fIpathName \fR?\fIoption value\fR?... .DE Additional options may be specified on the command line or in the option database to configure aspects of the tabset such as its colors, font, text, and relief. The \fBtabset\fR command returns its \fIpathName\fR argument. At the time this command is invoked, there must not exist a window named \fIpathName\fR, but \fIpathName\fR's parent must exist. .PP When first created, a new tabset contains no tabs. Tabs are added or deleted using widget operations described below. It is not necessary for all the tabs to be displayed in the tabset window at once; commands described below may be used to change the view in the window. Tabsets allow scrolling of tabs using the \fB\-scrollcommand\fR option. They also support scanning (see the \fBscan\fR operation). Tabs may be arranged along any side of the tabset window using the \fB\-side\fR option. .PP The size of the tabset window is determined the number of tiers of tabs and the sizes of the Tk widgets embedded inside each folder. The widest widget determines the width of the folder. The tallest determines the height. If no folders contain an embedded widget, the size is detemined solely by the size of the tabs. .PP You can override either dimension with the tabset's \fB\-width\fR and \fB\-height\fR options. .SH "INDICES" Indices refer to individual tabs/folders in the tabset. Many of the operations for tabset widgets take one or more indices as arguments. An index may take several forms: .TP 12 \fInumber\fR Unique node id of the tab. .TP 12 \fB@\fIx\fB,\fIy\fR Tab that covers the point in the tabset window specified by \fIx\fR and \fIy\fR (in screen coordinates). If no tab covers that point, then the index is ignored. .TP 12 \fBselect\fR The currently selected tab. The \fBselect\fR index is typically changed by either clicking on the tab with the left mouse button or using the widget's \fBinvoke\fR operation. .TP 12 \fBactive\fR The tab where the mouse pointer is currently located. The label is drawn using its active colors (see the \fB\-activebackground\fR and \fB\-activeforeground\fR options). The \fBactive\fR index is typically changed by moving the mouse pointer over a tab or using the widget's \fBactivate\fR operation. There can be only one active tab at a time. If there is no tab located under the mouse pointer, the index is ignored. .TP 12 \fBfocus\fR Tab that currently has the widget's focus. This tab is displayed with a dashed line around its label. You can change this using the \fBfocus\fR operation. If no tab has focus, then the index is ignored. .TP 12 \fBdown\fR Tab immediately below the tab that currently has focus, if there is one. If there is no tab below, the current tab is returned. .TP 12 \fBleft\fR Tab immediately to the left the tab that currently has focus, if there is one. If there is no tab to the left, the current tab is returned. .TP 12 \fBright\fR Tab immediately to the right the tab that currently has focus, if there is one. If there is no tab to the right, the current tab is returned. .TP 12 \fBup\fR Tab immediately above, if there is one, to the tab that currently has focus. If there is no tab above, the current tab is returned. .TP 12 \fBend\fR Last tab in the tabset. If there are no tabs in the tabset then the index is ignored. .LP Some indices may not always be available. For example, if the mouse is not over any tab, "active" does not have an index. For most tabset operations this is harmless and ignored. .SH "OPERATIONS" All \fBtabset\fR operations are invoked by specifying the widget's pathname, the operation, and any arguments that pertain to that operation. The general form is: .sp .DS \fIpathName operation \fR?\fIarg arg ...\fR? .DE .sp \fIOperation\fR and the \fIarg\fRs determine the exact behavior of the command. The following operations are available for tabset widgets: .TP \fIpathName \fBactivate\fR \fIindex\fR Sets the active tab to the one indicated by \fIindex\fR. The active tab is drawn with its \fIactive\fR colors (see the \fB\-activebackground\fR and \fB\-activeforeground\fR options) and may be retrieved with the index \fBactive\fR. Only one tab may be active at a time. If \fIindex\fR is the empty string, then all tabs will be drawn with their normal foreground and background colors. .TP \fIpathName \fBbind\fR \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 tab with this tag, \fIcommand\fR will be invoked. The syntax is similar to the \fBbind\fR command except that it operates on tabs, rather than widgets. See the \fBbind\fR manual entry for complete details on \fIsequence\fR and the substitutions performed on \fIcommand\fR. .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 \fBcget\fR \fIoption\fR Returns the current value of the configuration option given by \fIoption\fR. \fIOption\fR may have any of the values accepted by the \fBconfigure\fR operation described in the section .SB "WIDGET OPTIONS" below. .TP \fIpathName \fBconfigure\fR ?\fIoption\fR? ?\fIvalue option value ...\fR? Query or modify the configuration options of the widget. If no \fIoption\fR is specified, returns a list describing all the available options for \fIpathName\fR (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no \fIoption\fR is specified). If one or more \fIoption\-value\fR pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. \fIOption\fR and \fIvalue\fR are described in the section .SB "WIDGET OPTIONS" below. .TP \fIpathName \fBdelete \fIfirst \fR?\fIlast\fR? Deletes one or more tabs from the tabset. \fIFirst\fR and \fIlast\fR are the first and last indices, defining a range of tabs to be deleted. If \fIlast\fR isn't specified, then only the tab at \fIfirst\fR is deleted. .TP \fIpathName \fBfocus \fIindex\fR Designates a tab to get the widget's focus. This tab is displayed with a dashed line around its label. .TP \fIpathName \fBget\fR \fIindex\fR Returns the name of the tab. The value of \fIindex\fR may be in any form described in the section .SB "INDICES". .TP \fIpathName \fBindex\fR ?\fIflag\fR? \fIstring\fR Returns the node id of the tab specified by \fIstring\fR. If \fIflag\fR is \fB\-name\fR, then \fIstring\fR is the name of a tab. If \fIflag\fR is \fB\-index\fR, \fIstring\fR is an index such as "active" or "focus". If \fIflag\fR isn't specified, it defaults to \fB\-index\fR. .TP \fIpathName \fBinsert\fR \fIposition \fIname\fR ?\fIoption value\fR?... Inserts new tabs into the tabset. Tabs are inserted just before the tab given by \fIposition\fR. \fIPosition\fR may be either a number, indicating where in the list the new tab should be added, or \fBend\fR, indicating that the new tab is to be added the end of the list. \fIName\fR is the symbolic name of the tab. \fIBe careful not to use a number. Otherwise the tabset will confuse it with tab indices\fR. Returns a list of indices for all the new tabs. .TP \fIpathName \fBinvoke \fIindex\fR Selects the tab given by \fIindex\fR, maps the tab's embedded widget, and invokes the Tcl command associated with the tab, if there is one. The return value is the return value from the Tcl command, or an empty string if there is no command associated with the tab. This command is ignored if the tab's state (see the \fB\-state\fR option) is disabled. .TP \fIpathName \fBmove\fR \fIindex\fR \fBbefore\fR|\fBafter\fR \fIindex\fR Moves the tab \fIindex\fR to a new position in the tabset. .TP \fIpathName \fBnearest\fR \fIx\fR \fIy\fR Returns the name of the tab nearest to given X-Y screen coordinate. .TP \fIpathName \fBperforation \fIoperation\fR ?\fIargs\fR? This operation controls the perforation on the tab label. .RS .TP \fIpathName \fBperforation highlight\fR \fIindex\fR \fIboolean\fR .TP \fIpathName \fBperforation invoke\fR \fIindex\fR Invokes the command specified for perforations (see the \fB\-perforationcommand\fR widget option). Typically this command places the page into a top level widget. The name of the toplevel is the concatonation of the \fIpathName\fR, "-", and the \fItabName\fR. The return value is the return value from the Tcl command, or an empty string if there is no command associated with the tab. This command is ignored if the tab's state (see the \fB\-state\fR option) is disabled. .RE .TP \fIpathName \fBscan\fR \fIoption args\fR This command implements scanning on tabsets. It has two forms, depending on \fIoption\fR: .RS .TP \fIpathName \fBscan mark \fIx y\fR Records \fIx\fR and \fIy\fR and the current view in the tabset window; used with later \fBscan dragto\fR commands. Typically this command is associated with a mouse button press in the widget. It returns an empty string. .TP \fIpathName \fBscan dragto \fIx y\fR. This command computes the difference between its \fIx\fR and \fIy\fR arguments and the \fIx\fR and \fIy\fR arguments to the last \fBscan mark\fR command for the widget. It then adjusts the view by 10 times the difference in coordinates. This command is typically associated with mouse motion events in the widget, to produce the effect of dragging the list at high speed through the window. The return value is an empty string. .RE .TP \fIpathName \fBsee \fIindex\fR Scrolls the tabset so that the tab \fIindex\fR is visible in the widget's window. .TP \fIpathName \fBsize\fR Returns the number of tabs in the tabset. .TP \fIpathName \fBtab \fIoperation\fR ?\fIargs\fR? .RS .TP \fIpathName \fBtab cget\fR \fInameOrIndex\fR \fIoption\fR Returns the current value of the configuration option given by \fIoption\fR. \fIOption\fR may have any of the values accepted by the \fBtab configure\fR operation described in the section .SB "TAB OPTIONS" below. .TP \fIpathName \fBtab configure\fR \fInameOrIndex\fR ?\fInameOrIndex\fR...? \fIoption\fR? ?\fIvalue option value ...\fR? Query or modify the configuration options of one or more tabs. If no \fIoption\fR is specified, this operation returns a list describing all the available options for \fInameOrIndex\fR. \fINameOrIndex\fR can be either the name of a tab or its index. Names of tabs take precedence over their indices. That means a tab named \fIfocus\fR is picked over the "focus" tab. .sp If \fIoption\fR is specified, but not \fIvalue\fR, then a list describing the one named option is returned. If one or more \fIoption\-value\fR pairs are specified, then each named tab (specified by \fInameOrIndex\fR) will have its configurations option(s) set the given value(s). In this last case, the empty string is returned. \fIOption\fR and \fIvalue\fR are described in the section .SB "TAB OPTIONS" below. .TP \fIpathName \fBtab names\fR ?\fIpattern\fR? Returns the names of all the tabs matching the given pattern. If no \fIpattern\fR argument is provided, then all tab names are returned. .TP \fIpathName \fBtab tearoff \fIindex\fR ?\fInewName\fR? Reparents the widget embedded into \fIindex\fR, placing it inside of \fInewName\fR. \fINewName\fR is either the name of an new widget that will contain the embedded widget or the name of the \fBtabset\fR widget. It the last case, the embedded widget is put back into the folder. .sp If no \fInewName\fR argument is provided, then the name of the current parent of the embedded widget is returned. .RE .TP \fIpathName \fBview \fIargs\fR This command queries or changes the position of the tabset in the widget's window. It can take any of the following forms: .RS .TP \fIpathName \fBview\fR Returns a list of two numbers between 0.0 and 1.0 that describe the amount and position of the tabset that is visible in the window. For example, if \fIview\fR is "0.2 0.6", 20% of the tabset's text is off-screen to the left, 40% is visible in the window, and 40% of the tabset is off-screen to the right. These are the same values passed to scrollbars via the \fB\-scrollcommand\fR option. .TP \fIpathName \fBview moveto\fI fraction\fR Adjusts the view in the window so that \fIfraction\fR of the total width of the tabset text is off-screen to the left. \fIfraction\fR must be a number between 0.0 and 1.0. .TP \fIpathName \fBview scroll \fInumber what\fR This command shifts the view in the window (left/top or right/bottom) according to \fInumber\fR and \fIwhat\fR. \fINumber\fR must be an integer. \fIWhat\fR must be either \fBunits\fR or \fBpages\fR or an abbreviation of these. If \fIwhat\fR is \fBunits\fR, the view adjusts left or right by \fInumber\fR scroll units (see the \fB\-scrollincrement\fR option). ; if it is \fBpages\fR then the view adjusts by \fInumber\fR widget windows. If \fInumber\fR is negative then tabs farther to the left become visible; if it is positive then tabs farther to the right become visible. .RE .SH "WIDGET OPTIONS" Widget configuration options may be set either by the \fBconfigure\fR operation or the Tk \fBoption\fR command. The resource class is \f(CWTabset\fR. The resource name is the name of the widget. .CS option add *Tabset.Foreground white option add *Tabset.Background blue .CE The following widget options are available: .TP \fB\-activebackground \fIcolor\fR Sets the default active background color for tabs. A tab is active when the mouse is positioned over it or set by the \fBactivate\fR operation. Individual tabs may override this option by setting the tab's \fB\-activebackground\fR option. .TP \fB\-activeforeground \fIcolor\fR Sets the default active foreground color for tabs. A tab is active when the mouse is positioned over it or set by the \fBactivate\fR operation. Individual tabs may override this option by setting the tab's \fB\-activeforeground\fR option. .TP \fB\-background \fIcolor\fR Sets the background color of the tabset. .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 how the border is to be drawn. The default is \f(CW2\fR. .TP \fB\-cursor \fIcursor\fR Specifies the widget's cursor. The default cursor is \f(CW""\fR. .TP \fB\-dashes \fIdashList\fR Sets the dash style of the focus outline. When a tab has the widget's focus, it is drawn with a dashed outline around its label. \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 outline will be a solid line. The default value is \f(CW5 2\fR. .TP \fB\-font \fIfontName\fR Sets the default font for the text in tab labels. Individual tabs may override this by setting the tab's \fB\-font\fR option. The default value is \f(CW*-Helvetica-Bold-R-Normal-*-12-120-*\fR. .TP \fB\-foreground \fIcolor\fR Sets the default color of tab labels. Individual tabs may override this option by setting the tab's \fB\-foreground\fR option. The default value is \f(CWblack\fR. .TP \fB\-gap \fIsize\fR Sets the gap (in pixels) between tabs. The default value is \f(CW2\fR. .TP \fB\-height \fIpixels\fR Specifies the requested height of widget. If \fIpixels\fR is 0, then the height of the widget will be calculated based on the size the tabs and their pages. The default is \f(CW0\fR. .TP \fB\-highlightbackground \fIcolor\fR Sets the color to display in the traversal highlight region when the tabset does not have the input focus. .TP \fB\-highlightcolor \fIcolor\fR Sets the color to use for the traversal highlight rectangle that is drawn around the widget when it has the input focus. The default is \f(CWblack\fR. .TP \fB\-highlightthickness \fIpixels\fR Sets the width of the highlight rectangle to draw around the outside of the widget when it has the input focus. \fIPixels\fR is a non-negative value and may have any of the forms acceptable to \fBTk_GetPixels\fR. If the value is zero, no focus highlight is drawn around the widget. The default is \f(CW2\fR. .TP \fB\-outerpad \fIpixels\fR Padding around the exterior of the tabset and folder. .TP \fB\-pageheight \fIpixels\fR Sets the requested height of the page. The page is the area under the tab used to display the page contents. If \fIpixels\fR is \f(CW0\fR, the maximum height of all embedded tab windows is used. The default is \f(CW0\fR. .TP \fB\-pagewidth \fIpixels\fR Sets the requested width of the page. The page is the area under the tab used to display the page contents. If \fIpixels\fR is \f(CW0\fR, the maximum width of all embedded tab windows is used. The default is \f(CW0\fR. .TP \fB\-perforationcommand\fR \fIstring\fR Specifies a Tcl script to be invoked to tear off the current page in the tabset. This command is typically invoked when left mouse button is released over the tab perforation. The default action is to tear-off the page and place it into a new toplevel window. .TP \fB\-relief \fIrelief\fR Specifies the 3-D effect for the tabset widget. \fIRelief\fR specifies how the tabset should appear relative to widget that it is packed into; for example, \f(CWraised\fR means the tabset should appear to protrude. The default is \f(CWsunken\fR. .TP \fB\-rotate \fItheta\fR Specifies the degrees to rotate text in tab 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\-samewidth \fIboolean\fR Indicates if each tab should be the same width. If true, each tab will be as wide as the widest tab. The default is \f(CWno\fR. .TP \fB\-scrollcommand \fIstring\fR Specifies the prefix for a command for communicating with scrollbars. Whenever the view in the widget's window changes, the widget will generate a Tcl command by concatenating the scroll command and two numbers. If this option is not specified, then no command will be executed. .TP \fB\-scrollincrement \fIpixels\fR Sets the smallest number of pixels to scroll the tabs. If \fIpixels\fR is greater than 0, this sets the units for scrolling (e.g., when you the change the view by clicking on the left and right arrows of a scrollbar). .TP \fB\-selectbackground \fIcolor\fR Sets the color to use when displaying background of the selected tab. Individual tabs can override this option by setting the tab's \fB\-selectbackground\fR option. '\".TP '\" \fB\-selectborderwidth \fIpixels\fR '\" Sets the width of the raised 3-D border to draw around the label of '\" the selected tab. \fIPixels\fR must be a non-negative value. '\" The default value is \f(CW1\fR. .TP \fB\-selectcommand \fIstring\fR Specifies a default Tcl script to be associated with tabs. This command is typically invoked when left mouse button is released over the tab. Individual tabs may override this with the tab's \fB\-command\fR option. The default value is \f(CW""\fR. .TP \fB\-selectforeground \fIcolor\fB Sets the default color of the selected tab's text label. Individual tabs can override this option by setting the tab's \fB\-selectforeground\fR option. The default value is \f(CWblack\fR. .TP \fB\-selectpad \fIpixels\fB Specifies extra padding to be displayed around the selected tab. The default value is \f(CW3\fR. .TP \fB\-side \fIside\fB Specifies the side of the widget to place tabs. The following values are valid for \fIside\fR. The default value is \f(CWtop\fR. .RS .TP 1i \f(CWtop\fR Tabs are drawn along the top. .TP 1i \f(CWleft\fR Tabs are drawn along the left side. .TP 1i \f(CWright\fR Tabs are drawn along the right side. .TP 1i \f(CWboth\fR Tabs are drawn along the bottom side. .RE .TP \fB\-slant \fIslant\fR Specifies if the tabs should be slanted 45 degrees on the left and/or right sides. The following values are valid for \fIslant\fR. The default is \f(CWnone\fR. .RS .TP 1i \f(CWnone\fR Tabs are drawn as a rectangle. .TP 1i \f(CWleft\fR The left side of the tab is slanted. .TP 1i \f(CWright\fR The right side of the tab is slanted. .TP 1i \f(CWboth\fR Boths sides of the tab are slanted. .RE .TP \fB\-tabbackground \fIcolor\fR Sets the default background color of tabs. Individual tabs can override this option by setting the tab's \fB\-background\fR option. .TP \fB\-tabborderwidth \fIpixels\fR Sets the width of the 3\-D border around the outside edge of the tab. The \fB\-tabrelief\fR option determines how the border is to be drawn. The default is \f(CW2\fR. .TP \fB\-tabforeground \fIcolor\fR Specifies the color to use when displaying a tab's label. Individual tabs can override this option by setting the tab's \fB\-foreground\fR option. .TP \fB\-tabrelief \fIrelief\fR Specifies the 3-D effect for both tabs and folders. \fIRelief\fR specifies how the tabs should appear relative to background of the widget; for example, \f(CWraised\fR means the tab should appear to protrude. The default is \f(CWraised\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 decide whether to focus on the window. The default is \f(CW1\fR. .TP \fB\-tearoff \fIboolean\fR .TP \fB\-textside \fIside\fB If both images and text are specified for a tab, this option determines on which side of the tab the text is to be displayed. The valid sides are \f(CWleft\fR, \f(CWright\fR, \f(CWtop\fR, and \f(CWbottom\fR. The default value is \f(CWleft\fR. .TP \fB\-tiers \fInumber\fB Specifies the maximum number of tiers to use to display the tabs. The default value is \f(CW1\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\-width \fIpixels\fR Specifies the requested width of the widget. If \fIpixels\fR is 0, then the width of the widget will be calculated based on the size the tabs and their pages. The default is \f(CW0\fR. .SH "TAB OPTIONS" In addition to the \fBconfigure\fR operation, widget configuration options may also be set by the Tk \fBoption\fR command. The class resource name is \f(CWTab\fR. .CS option add *Tabset.Tab.Foreground white option add *Tabset.name.Background blue .CE The following widget options are available: .TP \fB\-activebackground \fIcolor\fR Sets the active background color for \fInameOrIndex\fR. A tab is active when the mouse is positioned over it or set by the \fBactivate\fR operation. This overrides the widget's \fB-activebackground\fR option. .TP \fB\-activeforeground \fIcolor\fR Sets the default active foreground color \fInameOrIndex\fR. A tab is "active" when the mouse is positioned over it or set by the \fBactivate\fR operation. Individual tabs may override this option by setting the tab's \fB-activeforeground\fR option. .TP \fB\-anchor \fIanchor\fR Anchors the tab's embedded widget to a particular edge of the folder. This option has effect only if the space in the folder surrounding the embedded widget is larger than the widget itself. \fIAnchor\fR specifies how the widget will be positioned in the extra space. For example, if \fIanchor\fR is \f(CWcenter\fR then the window is centered in the folder ; if \fIanchor\fR is \f(CWw\fR then the window will be aligned with the leftmost edge of the folder. The default value is \f(CWcenter\fR. .TP \fB\-background \fIcolor\fR Sets the background color for \fInameOrIndex\fR. Setting this option overides the widget's \fB\-tabbackground\fR option. .TP \fB\-bindtags \fItagList\fR Specifies the binding tags for this tab. \fITagList\fR is a list of binding tag names. The tags and their order will determine how commands for events in tabs are invoked. Each tag in the list matching the event sequence will have its Tcl command executed. Implicitly the name of the tab is always the first tag in the list. The default value is \f(CWall\fR. .TP \fB\-command \fIstring\fR Specifies a Tcl script to be associated with \fInameOrIndex\fR. This command is typically invoked when left mouse button is released over the tab. Setting this option overrides the widget's \fB\-selectcommand\fR option. .TP \fB\-data \fIstring\fR Specifies a string to be associated with \fInameOrIndex\fR. This value isn't used in the widget code. It may be used in Tcl bindings to associate extra data (other than the image or text) with the tab. The default value is \f(CW""\fR. .TP \fB\-fill \fIfill\fR If the space in the folder surrounding the tab's embedded widget is larger than the widget, then \fIfill\fR indicates if the embedded widget should be stretched to occupy the extra space. \fIFill\fR is either \f(CWnone\fR, \f(CWx\fR, \f(CWy\fR, \f(CWboth\fR. For example, if \fIfill\fR is \f(CWx\fR, then the widget is stretched horizontally. If \fIfill\fR is \f(CWy\fR, the widget is stretched vertically. The default is \f(CWnone\fR. .TP \fB\-font \fIfontName\fR Sets the font for the text in tab labels. If \fIfontName\fR is not the empty string, this overrides the tabset's \fB\-font\fR option. The default value is \f(CW""\fR. .TP \fB\-foreground \fIcolor\fR Sets the color of the label for \fInameOrIndex\fR. If \fIcolor\fR is not the empty string, this overrides the widget's \fB\-tabforeground\fR option. The default value is \f(CW""\fR. .TP \fB\-image \fIimageName\fR Specifies the image to be drawn in label for \fInameOrIndex\fR. If \fIimage\fR is \f(CW""\fR, no image will be drawn. Both text and images may be displayed at the same time in tab labels. The default value is \f(CW""\fR. .TP \fB\-ipadx \fIpad\fR Sets the padding to the left and right of the label. \fIPad\fR can be a list of one or two screen distances. If \fIpad\fR has two elements, the left side of the label 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 value is \f(CW0\fR. .TP \fB\-ipady \fIpad\fR Sets the padding to the top and bottom of the label. \fIPad\fR can be a list of one or two screen distances. If \fIpad\fR has two elements, the top of the label is padded by the first distance and the bottom by the second. If \fIpad\fR has just one distance, both the top and bottom sides are padded evenly. The default value is \f(CW0\fR. .TP \fB\-padx \fIpad\fR Sets the padding around the left and right of the embedded widget, if one exists. \fIPad\fR can be a list of one or two screen distances. If \fIpad\fR has two elements, the left side of the widget 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 value is \f(CW0\fR. .TP \fB\-pady \fIpad\fR Sets the padding around the top and bottom of the embedded widget, if one exists. \fIPad\fR can be a list of one or two screen distances. If \fIpad\fR has two elements, the top of the widget is padded by the first distance and the bottom by the second. If \fIpad\fR has just one distance, both the top and bottom sides are padded evenly. The default value is \f(CW0\fR. .TP \fB\-selectbackground \fIcolor\fR Sets the color to use when displaying background of the selected tab. If \fIcolor\fR is not the empty string, this overrides the widget's \fB\-selectbackground\fR option. The default value is \f(CW""\fR. .TP \fB\-shadow \fIcolor\fR Sets the shadow color for the text in the tab's label. Drop shadows are useful when both the foreground and background of the tab have similar color intensities. If \fIcolor\fR is the empty string, no shadow is drawn. The default value is \f(CW""\fR. .TP \fB\-state \fIstate\fR Sets the state of the tab. If \fIstate\fR is \f(CWdisable\fR the text of the tab is drawn as engraved and operations on the tab (such as \fBinvoke\fR and \fBtab tearoff\fR) are ignored. The default is \f(CWnormal\fR. .TP \fB\-stipple \fIbitmap\fR Specifies a stipple pattern to use for the background of the folder when the window is torn off. \fIBitmap\fR specifies a bitmap to use as the stipple pattern. The default is \f(CWBLT\fR. .TP \fB\-text \fItext\fR Specifies the text of the tab's label. The exact way the text is drawn may be affected by other options such as \fB\-state\fR or \fB\-rotate\fR. .TP \fB\-window \fIpathName\fR Specifies the widget to be embedded into the tab. \fIPathName\fR must be a child of the \fBtabset\fR widget. The tabset will "pack" and manage the size and placement of \fIpathName\fR. The default value is \f(CW""\fR. .TP \fB\-windowheight \fIpixels\fR Sets the requested height of the page. The page is the area under the tab used to display the page contents. If \fIpixels\fR is \f(CW0\fR, the maximum height of all embedded tab windows is used. The default is \f(CW0\fR. .TP \fB\-windowwidth \fIpixels\fR Sets the requested width of the page. The page is the area under the tab used to display the page contents. If \fIpixels\fR is \f(CW0\fR, the maximum width of all embedded tab windows is used. The default is \f(CW0\fR. .SH "DEFAULT BINDINGS" .PP BLT automatically generates class bindings that supply tabsets their default behaviors. The following event sequences are set by default for tabsets (via the class bind tag \f(CWTabset\fR): .IP \fB\fR .IP \fB\fR .IP \fB\fR Mouse button 2 may be used for scanning. If it is pressed and dragged over the tabset, the contents of the tabset drag at high speed in the direction the mouse moves. .IP \fB\fR .IP \fB\fR The up and down arrow keys move the focus to the tab immediately above or below the current focus tab. The tab with focus is drawn with the a dashed outline around the tab label. .IP \fB\fR .IP \fB\fR The left and right arrow keys move the focus to the tab immediately to the left or right of the current focus tab. The tab with focus is drawn with the a dashed outline around the tab label. .IP \fB\fR .IP \fB\fR The space and return keys select the current tab given focus. When a folder is selected, it's command is invoked and the embedded widget is mapped. .PP Each tab, by default, also has a set of bindings (via the tag \f(CWall\fR). These bindings may be reset using the tabset's \fBbind\fR operation. .IP \fB\fR .IP \fB\fR When the mouse pointer enters a tab, it is activated (i.e. drawn in its active colors) and when the pointer leaves, it is redrawn in its normal colors. .IP \fB\fR Clicking with the left mouse button on a tab causes the tab to be selected and its Tcl script (see the \fB\-command\fR or \fB\-selectcommand\fR options) to be invoked. The folder and any embedded widget (if one is specified) is automatically mapped. .IP \fB\fR .IP \fB\fR Clicking on the right mouse button (or the left mouse button with the Control key held down) tears off the current page into its own toplevel widget. The embedded widget is re-packed into a new toplevel and an outline of the widget is drawn in the folder. Clicking again (toggling) will reverse this operation and replace the page back in the folder. .SH "BIND TAGS" You can bind commands to tabs that are triggered when a particular event sequence 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 It is possible for multiple bindings to match a particular event. This could occur, for example, if one binding is associated with the tab name and another is associated with the tab's tags (see the \fB\-bindtags\fR option). When this occurs, all the matching bindings are invoked. A binding associated with the tab name is invoked first, followed by one binding for each of the tab'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 tabs controls addition tag names that can be matched. Implicitly the first tag for each tab is its name. Setting the value of the \fB\-bindtags\fR option doesn't change this. .SH EXAMPLE You create a tabset widget with the \fBtabset\fR command. .CS # Create a new tabset tabset .ts -relief sunken -borderwidth 2 .CE A new Tcl command \f(CW.ts\fR is also created. This command can be used to query and modify the tabset. For example, to change the default font used by all the tab labels, you use the new command and the tabset's \fBconfigure\fR operation. .CS # Change the default font. \&.ts configure \-font "fixed" .CE You can then add folders using the \fBinsert\fR operation. .CS # Create a new folder "f1" \&.ts insert 0 "f1" .CE This inserts the new tab named "f1" into the tabset. The index \f(CW0\fR indicates location to insert the new tab. You can also use the index \f(CWend\fR to append a tab to the end of the tabset. By default, the text of the tab is the name of the tab. You can change this by configuring the \fB\-text\fR option. .CS # Change the label of "f1" \&.ts tab configure "f1" -text "Tab #1" .CE The \fBinsert\fR operation lets you add one or more folders at a time. .CS \&.ts insert end "f2" -text "Tab #2" "f3" "f4" .CE The tab on each folder contains a label. A label may display both an image and a text string. You can reconfigure the tab's attributes (foreground/background colors, font, rotation, etc) using the \fBtab configure\fR operation. .CS # Add an image to the label of "f1" set image [image create photo -file stopsign.gif] \&.ts tab configure "f1" -image $image \&.ts tab configure "f2" -rotate 90 .CE Each folder may contain an embedded widget to represent its contents. The widget to be embedded must be a child of the tabset widget. Using the \fB\-window\fR option, you specify the name of widget to be embedded. But don't pack the widget, the tabset takes care of placing and arranging the widget for you. .CS graph .ts.graph \&.ts tab configure "f1" -window ".ts.graph" \\ -fill both -padx 0.25i -pady 0.25i .CE The size of the folder is determined the sizes of the Tk widgets embedded inside each folder. The folder will be as wide as the widest widget in any folder. The tallest determines the height. You can use the tab's \fB\-pagewidth\fR and \fB\-pageheight\fR options override this. .PP Other options control how the widget appears in the folder. The \fB\-fill\fR option says that you wish to have the widget stretch to fill the available space in the folder. .CS \&.ts tab configure "f1" -fill both -padx 0.25i -pady 0.25i .CE .PP Now when you click the left mouse button on "f1", the graph will be displayed in the folder. It will be automatically hidden when another folder is selected. If you click on the right mouse button, the embedded widget will be moved into a toplevel widget of its own. Clicking again on the right mouse button puts it back into the folder. .PP If you want to share a page between two different folders, the \fB\-command\fR option lets you specify a Tcl command to be invoked whenever the folder is selected. You can reset the \fB\-window\fR option for the tab whenever it's clicked. .CS \&.ts tab configure "f2" -command { \&.ts tab configure "f2" -window ".ts.graph" } \&.ts tab configure "f1" -command { \&.ts tab configure "f1" -window ".ts.graph" } .CE If you have many folders, you may wish to stack tabs in multiple tiers. The tabset's \fB\-tiers\fR option requests a maximum number of tiers. The default is one tier. .CS \&.ts configure -tiers 2 .CE If the tabs can fit in less tiers, the widget will use that many. Whenever there are more tabs than can be displayed in the maximum number of tiers, the tabset will automatically let you scroll the tabs. You can even attach a scrollbar to the tabset. .CS \&.ts configure -scrollcommand { .sbar set } -scrollincrement 20 \&.sbar configure -orient horizontal -command { .ts view } .CE By default tabs are along the top of the tabset from left to right. But tabs can be placed on any side of the tabset using the \fB\-side\fR option. .CS # Arrange tabs along the right side of the tabset. \&.ts configure -side right -rotate 270 .CE .SH KEYWORDS tabset, widget blt-2.4z.orig/man/tile.mann0100644000175000017500000001073707260556222014345 0ustar dokodoko'\" '\" 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. '\" '\" Tile command created by George Howlett. '\" .so man.macros .TH tile n BLT_VERSION BLT "BLT Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME tile \- Tiling versions of Tk widgets .SH SYNOPSIS .sp \fBtile::button \fIpathName\fR \fIoption value\fR... .sp \fBtile::checkbutton \fIpathName\fR \fIoption value\fR... .sp \fBtile::frame \fIpathName\fR \fIoption value\fR... .sp \fBtile::label \fIpathName\fR \fIoption value\fR... .sp \fBtile::radiobutton \fIpathName\fR \fIoption value\fR... .sp \fBtile::scrollbar \fIpathName\fR \fIoption value\fR... .sp \fBtile::toplevel \fIpathName\fR \fIoption value\fR... .sp .BE .SH DESCRIPTION The tile widgets let you create textured backgrounds. The texture is a Tk image which is tiled over the entire background of the widget. .SH INTRODUCTION With the advent of Tk 4.0, images are now easy to create and use in applications. Images add interest to applications and they convey more information. But one area where Tk hasn't taken advantage of images is using images as textures for widgets. Since tiling is a standard feature of windowing systems, it's very easy to use images as textures. .PP The tile widgets take the standard Tk 4.0 widgets and add tiling configuration options to them. Textures are specified by the name of the image you wish to be tiled across the background of the widget. .SH EXAMPLE To add tiling to a widget, you simply create an image using Tk's \fBimage\fR command and use the image name as the value for the \fB\-tile\fR configuration option of the widget. .CS image create photo my_texture -file tan_paper.gif blt::tile::frame .f -tile my_texture .CE The image \f(CWmy_texture\fR is added to the frame. If \f(CWmy_texture\fR is updated, so will the widget background. .CS image create photo my_texture -file rain.gif .CE The tile widget commands reside in the "blt::tile" namespace, so as not to collide with the normal Tk widgets. An easy way to add tiling to existing programs is to import the tile widget commands into the global namespace. .CS image create photo my_texture -file tan_paper.gif namespace import -force blt::tile::* frame .f -tile my_texture .CE To use one image for all texturing, you can use the "Tile" option class name to specify the same image for all tile widgets. .CS image create photo my_texture -file tan_paper.gif option add *Tile my_texture .CE .SH OPTIONS The following configurations options are added to the widgets. If a \fB\-tile\fB or \fB\-activetile\fR option is specified, it overrides the background color of the widget. .TP \fB\-activetile \fIimage\fR Specifies a textured background to display when the widget is active. This option is available for the \fBtilebutton\fR, \fBtilecheckbutton\fR, \fBtileradiobutton\fR, and \fBtilescrollbar\fR widgets. \fIImage\fR is the name an image created using Tk's \fBimage\fR command. The background of the widget is tiled with \fIimage\fR. If \fIimage\fR is \f(CW""\fR, then the active background color is displayed. The default is \f(CW""\fR. .TP \fB\-tile \fIimage\fR Specifies a textured background to display for the widget. \fIImage\fR is the name an image created using Tk's \fBimage\fR command. The background of the widget is tiled with \fIimage\fR. If \fIimage\fR is \f(CW""\fR, then the normal background color is displayed. The default is \f(CW""\fR. .SH KEYWORDS tile, texture, button, label, radiobutton, checkbutton, scrollbar, frame, toplevel blt-2.4z.orig/man/tree.mann0100644000175000017500000010621307505147041014337 0ustar dokodoko'\" '\" 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. '\" '\" Tree command created by George Howlett. '\" .so man.macros .TH tree n BLT_VERSION BLT "BLT Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME tree \- Create and manage tree data objects. .SH SYNOPSIS \fBblt::tree create \fR?\fItreeName\fR? .sp \fBblt::tree destroy\fR \fItreeName\fR... .sp \fBblt::tree names\fR \fR?\fIpattern\fR? .BE .SH DESCRIPTION The \fBtree\fR command creates tree data objects. A \fItree object\fR is general ordered tree of nodes. Each node has both a label and a key-value list of data. Data can be heterogeneous, since nodes do not have to contain the same data keys. It is associated with a Tcl command that you can use to access and modify the its structure and data. Tree objects can also be managed via a C API. .SH INTRODUCTION .SH EXAMPLE .SH SYNTAX .TP \fBtree create\fR ?\fItreeName\fR? Creates a new tree object. The name of the new tree is returned. If no \fItreeName\fR argument is present, then the name of the tree is automatically generated in the form "\f(CWtree0\fR", "\f(CWtree1\fR", etc. If the substring "\f(CW#auto\fR" is found in \fItreeName\fR, it is automatically substituted by a generated name. For example, the name \f(CW.foo.#auto.bar\fR will be translated to \f(CW.foo.tree0.bar\fR. .sp A new Tcl command (by the same name as the tree) is also created. Another Tcl command or tree object can not already exist as \fItreeName\fR. If the Tcl command is deleted, the tree will also be freed. The new tree will contain just the root node. Trees are by default, created in the current namespace, not the global namespace, unless \fItreeName\fR contains a namespace qualifier, such as "\f(CWfred::myTree\fR". .TP \fBtree destroy\fR \fItreeName\fR... Releases one of more trees. The Tcl command associated with \fItreeName\fR is also removed. Trees are reference counted. The internal tree data object isn't destroyed until no one else is using the tree. .TP \fBtree names \fR?\fIpattern\fR? Returns the names of all tree objects. if a \fIpattern\fR argument is given, then the only those trees whose name matches pattern will be listed. .SH NODE IDS AND TAGS Nodes in a tree object may be referred in either of two ways: by id or by tag. Each node has a unique serial number or id that is assigned to that node when it's created. The id of an node never changes and id numbers are not re-used. .PP A node may also have any number of tags associated with it. A tag is just a string of characters, and it may take any form except that of an integer. For example, "\f(CWx123\fR" is valid, but "\f(CW123\fR" isn't. The same tag may be associated with many different nodes. This is commonly done to group nodes in various interesting ways. .sp There are two built-in tags: The tag \fBall\fR is implicitly associated with every node in the tree. It may be used to invoke operations on all the nodes in the tree. The tag \fBroot\fR is managed automatically by the tree object. It applies to the node currently set as root. .sp When specifying nodes in tree object commands, if the specifier is an integer then it is assumed to refer to the single node with that id. If the specifier is not an integer, then it is assumed to refer to all of the nodes in the tree that have a tag matching the specifier. The symbol \fInode\fR is used below to indicate that an argument specifies either an id that selects a single node or a tag that selects zero or more nodes. Many tree commands only operate on a single node at a time; if \fInode\fR is specified in a way that names multiple items, then an error "refers to more than one node" is generated. .SH NODE MODIFIERS You can also specify node in relation to another node by appending one or more modifiers to the node id or tag. A modifier refers to a node in relation to the specified node. For example, "\f(CWroot->firstchild\fR" selects the first subtree of the root node. .PP The following modifiers are available: .RS .TP 1i \fBfirstchild\fR Selects the first child of the node. .TP 1i \fBlastchild\fR Selects the last child of the node. .TP 1i \fBnext\fR Selects the next node in preorder to the node. .TP 1i \fBnextsibling\fR Selects the next sibling of the node. .TP 1i \fBparent\fR Selects the parent of the node. .TP 1i \fBprevious\fR Selects the previous node in preorder to the node. .TP 1i \fBprevsibling\fR Selects the previous sibling of the node. .TP 1i "\fIlabel\fR" Selects the node whose label is \fIlabel\fR. Enclosing \fIlabel\fR in quotes indicates to always search for a node by its label (for example, even if the node is labeled "parent"). .RE .sp It's an error the node can't be found. For example, \fBlastchild\fR and \fBfirstchild\fR will generate errors if the node has no children. The exception to this is the \fBindex\fR operation. You can use \fBindex\fR to test if a modifier is valid. .SH TREE OPERATIONS Once you create a tree object, you can use its Tcl command to query or modify it. The general form is .DS \fItreeName\fR \fIoperation\fR \fR?\fIarg\fR?... .DE Both \fIoperation\fR and its arguments determine the exact behavior of the command. The operations available for trees are listed below. .TP \fItreeName\fR \fBancestor\fR \fInode1\fR \fInode2\fR Returns the mutual ancestor of the two nodes \fInode1\fR and \fInode2\fR. The ancestor can be one of the two nodes. For example, if \fInode1\fR and \fInode2\fR are the same nodes, their ancestor is \fInode1\fR. .TP \fItreeName\fR \fBapply\fR \fInode\fR ?\fIswitches\fR? Runs commands for all nodes matching the criteria given by \fIswitches\fR for the subtree designated by \fInode\fR. By default all nodes match, but you can set switches to narrow the match. This operation differs from \fBfind\fR in two ways: 1) Tcl commands can be invoked both pre- and post-traversal of a node and 2) the tree is always traversed in depth first order. .sp The \fB\-exact\fR, \fB\-glob\fR, and \fB\-regexp\fR switches indicate both what kind of pattern matching to perform and the pattern. By default each pattern will be compared with the node label. You can set more than one of these switches. If any of the patterns match (logical or), the node matches. If the \fB\-key\fR switch is used, it designates the data field to be matched. .sp The valid switches are listed below: .RS .TP 1i \fB\-depth\fR \fInumber\fR Descend at most \fInumber\fR (a non-negative integer) levels If \fInumber\fR is \f(CW1\fR this means only apply the tests to the children of \fInode\fR. .TP 1i \fB\-exact\fR \fIstring\fR Matches each node using \fIstring\fR. The node must match \fIstring\fR exactly. .TP 1i \fB\-glob\fR \fIstring\fR Test each node to \fIstring\fR using global pattern matching. Matching is done in a fashion similar to that used by the C-shell. .TP 1i \fB\-invert\fR Select non-matching nodes. Any node that \fIdoesn't\fR match the given criteria will be selected. .TP 1i \fB\-key\fR \fIkey\fR If pattern matching is selected (using the \fB\-exact\fR, \fB\-glob\fR, or \fB\-regexp\fR switches), compare the values of the data field keyed by \fIkey\fR instead of the node's label. If no pattern matching switches are set, then any node with this data key will match. .TP 1i \fB\-leafonly\fR Only test nodes with no children. .TP 1i \fB\-nocase\fR Ignore case when matching patterns. .TP 1i \fB\-path\fR Use the node's full path when comparing nodes. The node's full path is a list of labels, starting from the root of each ancestor and the node itself. .TP 1i \fB\-precommand\fR \fIcommand\fR Invoke \fIcommand\fR for each matching node. Before \fIcommand\fR is invoked, the id of the node is appended. You can control processing by the return value of \fIcommand\fR. If \fIcommand\fR generates an error, processing stops and the \fBfind\fR operation returns an error. But if \fIcommand\fR returns \fBbreak\fR, then processing stops, no error is generated. If \fIcommand\fR returns \fBcontinue\fR, then processing stops on that subtree and continues on the next. .TP 1i \fB\-postcommand\fR \fIcommand\fR Invoke \fIcommand\fR for each matching node. Before \fIcommand\fR is invoked, the id of the node is appended. You can control processing by the return value of \fIcommand\fR. If \fIcommand\fR generates an error, processing stops and the \fBfind\fR operation returns an error. But if \fIcommand\fR returns \fBbreak\fR, then processing stops, no error is generated. If \fIcommand\fR returns \fBcontinue\fR, then processing stops on that subtree and continues on the next. .TP 1i \fB\-regexp\fR \fIstring\fR Test each node using \fIstring\fR as a regular expression pattern. .TP 1i \fB\-tag\fR \fIstring\fR Only test nodes that have the tag \fIstring\fR. .RE .TP \fItreeName\fR \fBattach\fR \fItreeObject\fR Attaches to an existing tree object \fItreeObject\fR. This is for cases where the tree object was previously created via the C API. The current tree associated with \fItreeName\fR is discarded. In addition, the current set of tags, notifier events, and traces are removed. .TP \fItreeName\fR \fBchildren\fR \fInode\fR Returns a list of children for \fInode\fR. If \fInode\fR is a leaf, then an empty string is returned. .TP \fItreeName\fR \fBcopy\fR \fIsrcNode\fR ?\fIdestTree\fR? \fIparentNode\fR ?\fIswitches\fR? Copies \fIsrcNode\fR into \fIparentNode\fR. Both nodes \fIsrcNode\fR and \fIparentNode\fR must already exist. The id of the new node is returned. You can copy from one tree to another. If a \fIdestTree\fR argument is present, it indicates the name of the destination tree. By default both the source and destination trees are the same. The valid \fIswitches\fR are listed below: .RS .TP \fB\-label\fR \fIstring\fR Label \fIdestNode\fR as \fIstring\fR. By default, \fIdestNode\fR has the same label as \fIsrcNode\fR. .TP \fB\-overwrite\fR Overwrite nodes that already exist. Normally nodes are always created, even if there already exists a node by the same name. This switch indicates to add or overwrite the node's data fields. .TP \fB\-recurse\fR Recursively copy all the subtrees of \fIsrcNode\fR as well. In this case, \fIsrcNode\fR can't be an ancestor of \fIdestNode\fR as it would result in a cyclic copy. .TP \fB\-tags\fR Copy tag inforation. Normally the following node is copied: its label and data fields. This indicates to copy tags as well. .RE .TP \fItreeName\fR \fBdegree\fR \fInode\fR Returns the number of children of \fInode\fR. .TP \fItreeName\fR \fBdelete\fR \fInode\fR... Recursively deletes one or more nodes from the tree. The node and all its descendants are removed. The one exception is the root node. In this case, only its descendants are removed. The root node will remain. Any tags or traces on the nodes are released. .TP \fItreeName\fR \fBdepth\fR \fInode\fR Returns the depth of the node. The depth is the number of steps from the node to the root of the tree. The depth of the root node is \f(CW0\fR. .TP \fItreeName\fR \fBdump\fR \fInode\fR Returns a list of the paths and respective data for \fInode\fR and its descendants. The subtree designated by \fInode\fR is traversed returning the following information for each node: 1) the node's path relative to \fInode\fR, 2) a sublist key value pairs representing the node's data fields, and 3) a sublist of tags. This list returned can be used later to copy or restore the tree with the \fBrestore\fR operation. .TP \fItreeName\fR \fBdumpfile\fR \fInode\fR \fIfileName\fR Writes a list of the paths and respective data for \fInode\fR and its descendants to the given file \fIfileName\fR. The subtree designated by \fInode\fR is traversed returning the following information for each node: 1) the node's path relative to \fInode\fR, 2) a sublist key value pairs representing the node's data fields, and 3) a sublist of tags. This list returned can be used later to copy or restore the tree with the \fBrestore\fR operation. .TP \fItreeName\fR \fBexists\fR \fInode\fR ?\fIkey\fR? Indicates if \fInode\fR exists in the tree. If a \fIkey\fR argument is present then the command also indicates if the named data field exists. .TP \fItreeName\fR \fBfind\fR \fInode\fR ?\fIswitches\fR? Finds for all nodes matching the criteria given by \fIswitches\fR for the subtree designated by \fInode\fR. A list of the selected nodes is returned. By default all nodes match, but you can set switches to narrow the match. .sp The \fB\-exact\fR, \fB\-glob\fR, and \fB\-regexp\fR switches indicate both what kind of pattern matching to perform and the pattern. By default each pattern will be compared with the node label. You can set more than one of these switches. If any of the patterns match (logical or), the node matches. If the \fB\-key\fR switch is used, it designates the data field to be matched. .sp The order in which the nodes are traversed is controlled by the \fB\-order\fR switch. The possible orderings are \fBpreorder\fR, \fBpostorder\fR, \fBinorder\fR, and \fBbreadthfirst\fR. The default is \fBpostorder\fR. .sp The valid switches are listed below: .RS .TP 1i \fB\-addtag\fR \fIstring\fR Add the tag \fIstring\fR to each selected node. .TP 1i \fB\-count\fR \fInumber\fR Stop processing after \fInumber\fR (a positive integer) matches. .TP 1i \fB\-depth\fR \fInumber\fR Descend at most \fInumber\fR (a non-negative integer) levels If \fInumber\fR is \f(CW1\fR this means only apply the tests to the children of \fInode\fR. .TP 1i \fB\-exact\fR \fIstring\fR Matches each node using \fIstring\fR. The node must match \fIstring\fR exactly. .TP 1i \fB\-exec\fR \fIcommand\fR Invoke \fIcommand\fR for each matching node. Before \fIcommand\fR is invoked, the id of the node is appended. You can control processing by the return value of \fIcommand\fR. If \fIcommand\fR generates an error, processing stops and the \fBfind\fR operation returns an error. But if \fIcommand\fR returns \fBbreak\fR, then processing stops, no error is generated. If \fIcommand\fR returns \fBcontinue\fR, then processing stops on that subtree and continues on the next. .TP 1i \fB\-glob\fR \fIstring\fR Test each node to \fIstring\fR using global pattern matching. Matching is done in a fashion similar to that used by the C-shell. .TP 1i \fB\-invert\fR Select non-matching nodes. Any node that \fIdoesn't\fR match the given criteria will be selected. .TP 1i \fB\-key\fR \fIkey\fR Compare the values of the data field keyed by \fIkey\fR instead of the node's label. If no pattern is given (\fB\-exact\fR, \fB\-glob\fR, or \fB\-regexp\fR switches), then any node with this data key will match. .TP 1i \fB\-leafonly\fR Only test nodes with no children. .TP 1i \fB\-nocase\fR Ignore case when matching patterns. .TP \fB\-order\fR \fIstring\fR Traverse the tree and process nodes according to \fIstring\fR. \fIString\fR can be one of the following: .RS .TP 1i \fBbreadthfirst\fR Process the node and the subtrees at each sucessive level. Each node on a level is processed before going to the next level. .TP 1i \fBinorder\fR Recursively process the nodes of the first subtree, the node itself, and any the remaining subtrees. .TP 1i \fBpostorder\fR Recursively process all subtrees before the node. .TP 1i \fBpreorder\fR Recursively process the node first, then any subtrees. .RE .TP \fB\-path\fR Use the node's full path when comparing nodes. .TP \fB\-regexp\fR \fIstring\fR Test each node using \fIstring\fR as a regular expression pattern. .TP \fB\-tag\fR \fIstring\fR Only test nodes that have the tag \fIstring\fR. .RE .TP \fItreeName\fR \fBfindchild\fR \fInode\fR \fIlabel\fR Searches for a child node \Ilabel\fR in \fInode\fR. The id of the child node is returned if found. Otherwise \f(CW-1\fR is returned. .TP \fItreeName\fR \fBfirstchild\fR \fInode\fR Returns the id of the first child in the \fInode\fR's list of subtrees. If \fInode\fR is a leaf (has no children), then \f(CW-1\fR is returned. .TP \fItreeName\fR \fBget\fR \fInode\fR ?\fIkey\fR? ?\fIdefaultValue\fR? Returns a list of key-value pairs of data for the node. If \fIkey\fR is present, then onlyx the value for that particular data field is returned. It's normally an error if \fInode\fR does not contain the data field \fIkey\fR. But if you provide a \fIdefaultValue\fR argument, this value is returned instead (\fInode\fR will still not contain \fIkey\fR). This feature can be used to access a data field of \fInode\fR without first testing if it exists. This operation may trigger \fBread\fR data traces. .TP \fItreeName\fR \fBindex\fR \fInode\fR Returns the id of \fInode\fR. If \fInode\fR is a tag, it can only specify one node. If \fInode\fR does not represent a valid node id or tag, or has modifiers that are invalid, then \f(CW-1\fR is returned. .TP \fItreeName\fR \fBinsert\fR \fIparent\fR ?\fIswitches\fR? Inserts a new node into parent node \fIparent\fR. The id of the new node is returned. The following switches are available: .RS .TP 1i \fB\-after\fR \fIchild\fR Position \fInode\fR after \fIchild\fR. The node \fIchild\fR must be a child of \fIparent\fR. .TP 1i \fB\-at\fR \fInumber\fR Inserts the node into \fIparent\fR's list of children at position \fInumber\fR. The default is to append \fInode\fR. .TP 1i \fB\-before\fR \fIchild\fR Position \fInode\fR before \fIchild\fR. The node \fIchild\fR must be a child of \fIparent\fR. .TP 1i \fB\-data\fR \fIdataList\fR Sets the value for each data field in \fIdataList\fR for the new node. \fIDataList\fR is a list of key-value pairs. .TP 1i \fB\-label\fR \fIstring\fR Designates the labels of the node as \fIstring\fR. By default, nodes are labeled as \f(CWnode0\fR, \f(CWnode1\fR, etc. .TP 1i \fB\-node\fR \fIid\fR Designates the id for the node. Normally new ids are automatically generated. This allows you to create a node with a specific id. It is an error if the id is already used by another node in the tree. .TP 1i \fB\-tags\fR \fItagList\fR Adds each tag in \fItagList\fR to the new node. \fITagList\fR is a list of tags, so be careful if a tag has embedded space. .RE .TP \fItreeName\fR \fBis\fR \fIproperty\fR \fIargs\fR Indicates the property of a node. Both \fIproperty\fR and \fIargs\fR determine the property being tested. Returns \f(CW1\fR if true and \f(CW0\fR otherwise. The following \fIproperty\fR and \fIargs\fR are valid: .RS .TP 1i \fBancestor\fR \fInode1\fR \fInode2\fR Indicates if \fInode1\fR is an ancestor of \fInode2\fR. .TP 1i \fBbefore\fR \fInode1\fR \fInode2\fR Indicates if \fInode1\fR is before \fInode2\fR in depth first traversal. .TP 1i \fBleaf\fR \fInode\fR Indicates if \fInode\fR is a leaf (it has no subtrees). .TP 1i \fBroot\fR \fInode\fR Indicates if \fInode\fR is the designated root. This can be changed by the \fBroot\fR operation. .RE .TP \fItreeName\fR \fBlabel\fR \fInode\fR ?\fInewLabel\fR? Returns the label of the node designated by \fInode\fR. If \fInewLabel\fR is present, the node is relabeled using it as the new label. .TP \fItreeName\fR \fBlastchild\fR \fInode\fR Returns the id of the last child in the \fInode\fR's list of subtrees. If \fInode\fR is a leaf (has no children), then \f(CW-1\fR is returned. .TP \fItreeName\fR \fBmove\fR \fInode\fR \fInewParent\fR ?\fIswitches\fR? Moves \fInode\fR into \fInewParent\fR. \fINode\fR is appended to the list children of \fInewParent\fR. \fINode\fR can not be an ancestor of \fInewParent\fR. The valid flags for \fIswitches\fR are described below. .RS .TP 1i \fB\-after\fR \fIchild\fR Position \fInode\fR after \fIchild\fR. The node \fIchild\fR must be a child of \fInewParent\fR. .TP 1i \fB\-at\fR \fInumber\fR Inserts \fInode\fR into \fIparent\fR's list of children at position \fInumber\fR. The default is to append the node. .TP 1i \fB\-before\fR \fIchild\fR Position \fInode\fR before \fIchild\fR. The node \fIchild\fR must be a child of \fInewParent\fR. .RE .TP \fItreeName\fR \fBnext\fR \fInode\fR Returns the next node from \fInode\fR in a preorder traversal. If \fInode\fR is the last node in the tree, then \f(CW-1\fR is returned. .TP \fItreeName\fR \fBnextsibling\fR \fInode\fR Returns the node representing the next subtree from \fInode\fR in its parent's list of children. If \fInode\fR is the last child, then \f(CW-1\fR is returned. .TP \fItreeName\fR \fBnotify\fR \fIargs\fR Manages notification events that indicate that the tree structure has been changed. See the .SB "NOTIFY OPERATIONS" section below. .TP \fItreeName\fR \fBparent\fR \fInode\fR Returns the parent node of \fInode\fR. If \fInode\fR is the root of the tree, then \f(CW-1\fR is returned. .TP \fItreeName\fR \fBpath\fR \fInode\fR Returns the full path (from root) of \fInode\fR. .TP \fItreeName\fR \fBposition\fR \fInode\fR Returns the position of the node in its parent's list of children. Positions are numbered from 0. The position of the root node is always 0. .TP \fItreeName\fR \fBprevious\fR \fInode\fR Returns the previous node from \fInode\fR in a preorder traversal. If \fInode\fR is the root of the tree, then \f(CW-1\fR is returned. .TP \fItreeName\fR \fBprevsibling\fR \fInode\fR Returns the node representing the previous subtree from \fInode\fR in its parent's list of children. If \fInode\fR is the first child, then \f(CW-1\fR is returned. .TP \fItreeName\fR \fBrestore\fR \fInode\fR \fIdataString\fR \fIswitches\fR Performs the inverse function of the \fBdump\fR operation, restoring nodes to the tree. The format of \fIdataString\fR is exactly what is returned by the \fBdump\fR operation. It's a list containing information for each node to be restored. The information consists of 1) the relative path of the node, 2) a sublist of key value pairs representing the node's data, and 3) a list of tags for the node. Nodes are created starting from \fInode\fR. Nodes can be listed in any order. If a node's path describes ancestor nodes that do not already exist, they are automatically created. The valid \fIswitches\fR are listed below: .RS .TP \fB\-overwrite\fR Overwrite nodes that already exist. Normally nodes are always created, even if there already exists a node by the same name. This switch indicates to add or overwrite the node's data fields. .RE .TP \fItreeName\fR \fBrestorefile\fR \fInode\fR \fIfileName\fR \fIswitches\fR Performs the inverse function of the \fBdumpfile\fR operation, restoring nodes to the tree from the file \fIfileName\fR. The format of \fIfileName\fR is exactly what is returned by the \fBdumpfile\fR operation. It's a list containing information for each node to be restored. The information consists of 1) the relative path of the node, 2) a sublist of key value pairs representing the node's data, and 3) a list of tags for the node. Nodes are created starting from \fInode\fR. Nodes can be listed in any order. If a node's path describes ancestor nodes that do not already exist, they are automatically created. The valid \fIswitches\fR are listed below: .RS .TP \fB\-overwrite\fR Overwrite nodes that already exist. Normally nodes are always created, even if there already exists a node by the same name. This switch indicates to add or overwrite the node's data fields. .RE .TP \fItreeName\fR \fBroot\fR ?\fInode\fR? Returns the id of the root node. Normally this is node \f(CW0\fR. If a \fInode\fR argument is provided, it will become the new root of the tree. This lets you temporarily work within a subset of the tree. Changing root affects operations such as \fBnext\fR, \fBpath\fR, \fBprevious\fR, etc. .TP \fItreeName\fR \fBset\fR \fInode\fR \fIkey value\fR ?\fIkey value\fR...? Sets one or more data fields in \fInode\fR. \fINode\fR may be a tag that represents several nodes. \fIKey\fR is the name of the data field to be set and \fIvalue\fR is its respective value. This operation may trigger \fBwrite\fR and \fBcreate\fR data traces. .TP \fItreeName\fR \fBsize\fR \fInode\fR Returns the number of nodes in the subtree. This includes the node and all its descendants. The size of a leaf node is 1. .TP \fItreeName\fR \fBsort\fR \fInode\fR ?\fIswitches\fR? .RS .TP 1i \fB\-ascii\fR Compare strings using the ASCII collation order. .TP 1i \fB\-command\fR \fIstring\fR Use command \fIstring\fR as a comparison command. To compare two elements, evaluate a Tcl script consisting of command with the two elements appended as additional arguments. The script should return an integer less than, equal to, or greater than zero if the first element is to be considered less than, equal to, or greater than the second, respectively. .TP 1i \fB\-decreasing\fR Sort in decreasing order (largest items come first). .TP 1i \fB\-dictionary\fR Compare strings using a dictionary-style comparison. This is the same as \fB\-ascii\fR except (a) case is ignored except as a tie-breaker and (b) if two strings contain embedded numbers, the numbers compare as integers, not characters. For example, in \fB\-dictionary\fR mode, bigBoy sorts between bigbang and bigboy, and x10y sorts between x9y and x11y. .TP 1i \fB\-integer\fR Compare the nodes as integers. .TP 1i \fB\-key\fR \fIstring\fR Sort based upon the node's data field keyed by \fIstring\fR. Normally nodes are sorted according to their label. .TP 1i \fB\-path\fR Compare the full path of each node. The default is to compare only its label. .TP 1i \fB\-real\fR Compare the nodes as real numbers. .TP 1i \fB\-recurse\fR Recursively sort the entire subtree rooted at \fInode\fR. .TP 1i \fB\-reorder\fR Recursively sort subtrees for each node. \fBWarning\fR. Unlike the normal flat sort, where a list of nodes is returned, this will reorder the tree. .RE .TP \fItreeName\fR \fBtag\fR \fIargs\fR Manages tags for the tree object. See the .SB "TAG OPERATIONS" section below. .TP \fItreeName\fR \fBtrace\fR \fIargs\fR Manages traces for data fields in the tree object. Traces cause Tcl commands to be executed whenever a data field of a node is created, read, written, or unset. Traces can be set for a specific node or a tag, representing possibly many nodes. See the .SB "TRACE OPERATIONS" section below. .TP \fItreeName\fR \fBunset\fR \fInode\fR \fIkey\fR... Removes one or more data fields from \fInode\fR. \fINode\fR may be a tag that represents several nodes. \fIKey\fR is the name of the data field to be removed. It's not an error is \fInode\fR does not contain \fIkey\fR. This operation may trigger \fBunset\fR data traces. .RE .SH TAG OPERATIONS Tags are a general means of selecting and marking nodes in the tree. A tag is just a string of characters, and it may take any form except that of an integer. The same tag may be associated with many different nodes. .sp There are two built-in tags: The tag \fBall\fR is implicitly associated with every node in the tree. It may be used to invoke operations on all the nodes in the tree. The tag \fBroot\fR is managed automatically by the tree object. It specifies the node that is currently set as the root of the tree. .sp Most tree operations use tags. And several operations let you operate on multiple nodes at once. For example, you can use the \fBset\fR operation with the tag \fBall\fR to set a data field in for all nodes in the tree. .PP Tags are invoked by the \fBtag\fR operation. The general form is .DS \fItreeName\fR \fBtag\fR \fIoperation\fR \fR?\fIarg\fR?... .DE Both \fIoperation\fR and its arguments determine the exact behavior of the command. The operations available for tags are listed below. .TP \fItreeName\fR \fBtag add\fR \fIstring\fR \fInode\fR... Adds the tag \fIstring\fR to one of more nodes. .TP \fItreeName\fR \fBtag delete\fR \fIstring\fR \fInode\fR... Deletes the tag \fIstring\fR from one or more nodes. .TP \fItreeName\fR \fBtag forget\fR \fIstring\fR Removes the tag \fIstring\fR from all nodes. It's not an error if no nodes are tagged as \fIstring\fR. .TP \fItreeName\fR \fBtag names\fR ?\fInode\fR? Returns a list of tags used by the tree. If a \fInode\fR argument is present, only those tags used by \fInode\fR are returned. .TP \fItreeName\fR \fBtag nodes\fR \fIstring\fR Returns a list of nodes that have the tag \fIstring\fR. If no node is tagged as \fIstring\fR, then an empty string is returned. .SH TRACE OPERATIONS Data fields can be traced much in the same way that you can trace Tcl variables. Data traces cause Tcl commands to be executed whenever a particular data field of a node is created, read, written, or unset. A trace can apply to one or more nodes. You can trace a specific node by using its id, or a group of nodes by a their tag. .PP The tree's \fBget\fR, \fBset\fR, and \fBunset\fR operations can trigger various traces. The \fBget\fR operation can cause a \fIread\fR trace to fire. The \fBset\fR operation causes a \fIwrite\fR trace to fire. And if the data field is written for the first time, you will also get a \fIcreate\fR trace. The \fBunset\fR operation triggers \fIunset\fR traces. .PP Data traces are invoked by the \fBtrace\fR operation. The general form is .DS \fItreeName\fR \fBtrace\fR \fIoperation\fR \fR?\fIarg\fR?... .DE Both \fIoperation\fR and its arguments determine the exact behavior of the command. The operations available for traces are listed below. .TP \fItreeName\fR \fBtrace create\fR \fInode\fR \fIkey\fR \fIops\fR \fIcommand\fR Creates a trace for \fInode\fR on data field \fIkey\fR. \fINode\fR can refer to more than one node (for example, the tag \fBall\fR). If \fInode\fR is a tag, any node with that tag can possibly trigger a trace, invoking \fIcommand\fR. \fICommand\fR is command prefix, typically a procedure name. Whenever a trace is triggered, four arguments are appended to \fIcommand\fR before it is invoked: \fItreeName\fR, id of the node, \fIkey\fR and, \fIops\fR. Note that no nodes need have the field \fIkey\fR. A trace identifier in the form "\f(CWtrace0\fR", "\f(CWtrace1\fR", etc. is returned. .sp \fIOps\fR indicates which operations are of interest, and consists of one or more of the following letters: .RS .TP \fBr\fR Invoke \fIcommand\fR whenever \fIkey\fR is read. Both read and write traces are temporarily disabled when \fIcommand\fR is executed. .TP \fBw\fR Invoke \fIcommand\fR whenever \fIkey\fR is written. Both read and write traces are temporarily disabled when \fIcommand\fR is executed. .TP \fBc\fR Invoke \fIcommand\fR whenever \fIkey\fR is created. .TP \fBu\fR Invoke \fIcommand\fR whenever \fIkey\fR is unset. Data fields are typically unset with the \fBunset\fR command. Data fields are also unset when the tree is released, but all traces are disabled prior to that. .sp .RE .TP \fItreeName\fR \fBtrace delete\fR \fItraceId\fR... Deletes one of more traces. \fITraceId\fR is the trace identifier returned by the \fBtrace create\fR operation. .TP \fItreeName\fR \fBtrace info\fR \fItraceId\fR Returns information about the trace \fItraceId\fR. \fITraceId\fR is a trace identifier previously returned by the \fBtrace create\fR operation. It's the same information specified for the \fBtrace create\fR operation. It consists of the node id or tag, data field key, a string of letters indicating the operations that are traced (it's in the same form as \fIops\fR) and, the command prefix. .TP \fItreeName\fR \fBtrace names\fR Returns a list of identifers for all the current traces. .SH NOTIFY OPERATIONS Tree objects can be shared among many clients, such as a \fBhiertable\fR widget. Any client can create or delete nodes, sorting the tree, etc. You can request to be notified whenever these events occur. Notify events cause Tcl commands to be executed whenever the tree structure is changed. .PP Notifications are handled by the \fBnotify\fR operation. The general form is .DS \fItreeName\fR \fBnotify\fR \fIoperation\fR \fR?\fIarg\fR?... .DE Both \fIoperation\fR and its arguments determine the exact behavior of the command. The operations available for events are listed below. .TP \fItreeName\fR \fBnotify create\fR ?\fIswitches\fR? \fIcommand\fR \fR?\fIargs\fR?... Creates a notifier for the tree. A notify identifier in the form "\f(CWnotify0\fR", "\f(CWnotify1\fR", etc. is returned. .sp \fICommand\fR and \fIargs\fR are saved and invoked whenever the tree structure is changed (according to \fIswitches\fR). Two arguments are appended to \fIcommand\fR and \fIargs\fR before it's invoked: the id of the node and a string representing the type of event that occured. One of more switches can be set to indicate the events that are of interest. The valid switches are as follows: .RS .TP 1i \fB\-create\fR Invoke \fIcommand\fR whenever a new node has been added. .TP 1i \fB\-delete\fR Invoke \fIcommand\fR whenever a node has been deleted. .TP 1i \fB\-move\fR Invoke \fIcommand\fR whenever a node has been moved. .TP 1i \fB\-sort\fR Invoke \fIcommand\fR whenever the tree has been sorted and reordered. .TP 1i \fB\-relabel\fR Invoke \fIcommand\fR whenever a node has been relabeled. .TP 1i \fB\-allevents\fR Invoke \fIcommand\fR whenever any of the above events occur. .TP 1i \fB\-whenidle\fR When an event occurs don't invoke \fIcommand\fR immediately, but queue it to be run the next time the event loop is entered and there are no events to process. If subsequent events occur before the event loop is entered, \fIcommand\fR will still be invoked only once. .RE .TP \fItreeName\fR \fBnotify delete\fR \fInotifyId\fR Deletes one or more notifiers from the tree. \fINotifyId\fR is the notifier identifier returned by the \fBnotify create\fR operation. .TP \fItreeName\fR \fBnotify info\fR \fInotifyId\fR Returns information about the notify event \fInotifyId\fR. \fINotifyId\fR is a notify identifier previously returned by the \fBnotify create\fR operation. It's the same information specified for the \fBnotify create\fR operation. It consists of the notify id, a sublist of event flags (it's in the same form as \fIflags\fR) and, the command prefix. .TP \fItreeName\fR \fBnotify names\fR Returns a list of identifers for all the current notifiers. .SH C LANGUAGE API Blt_TreeApply, Blt_TreeApplyBFS, Blt_TreeApplyDFS, Blt_TreeChangeRoot, Blt_TreeCreate, Blt_TreeCreateEventHandler, Blt_TreeCreateNode, Blt_TreeCreateTrace, Blt_TreeDeleteEventHandler, Blt_TreeDeleteNode, Blt_TreeDeleteTrace, Blt_TreeExists, Blt_TreeFindChild, Blt_TreeFirstChild, Blt_TreeFirstKey, Blt_TreeGetNode, Blt_TreeGetToken, Blt_TreeGetValue, Blt_TreeIsAncestor, Blt_TreeIsBefore, Blt_TreeIsLeaf, Blt_TreeLastChild, Blt_TreeMoveNode, Blt_TreeName, Blt_TreeNextKey, Blt_TreeNextNode, Blt_TreeNextSibling, Blt_TreeNodeDegree, Blt_TreeNodeDepth, Blt_TreeNodeId, Blt_TreeNodeLabel, Blt_TreeNodeParent, Blt_TreePrevNode, Blt_TreePrevSibling, Blt_TreeRelabelNode, Blt_TreeReleaseToken, Blt_TreeRootNode, Blt_TreeSetValue, Blt_TreeSize, Blt_TreeSortNode, and Blt_TreeUnsetValue. .SH KEYWORDS tree, hiertable, widget blt-2.4z.orig/man/treeview.mann0100644000175000017500000025405607506667063015257 0ustar dokodoko'\" '\" Copyright 2001-2 by Silicon Metrics Corporation. '\" '\" 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 Silicon Metrics or any of their entities not be used '\" in advertising or publicity pertaining to distribution of the software '\" without specific, written prior permission. '\" '\" Silicon Metrics disclaims all warranties with regard to this software, '\" including all implied warranties of merchantability and fitness. In no event '\" shall Silicon Metrics 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. '\" '\" The hierarchical table widget created by George Howlett. '\" .so man.macros .TH treeview n BLT_VERSION BLT "BLT Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME treeview \- Create and manipulate hierarchical table widgets .BE .SH SYNOPSIS \fBtreeview\fR \fIpathName \fR?\fIoptions\fR? .SH DESCRIPTION The \fBtreeview\fR widget displays a tree of data. It replaces both the \fBhiertable\fR and \fBhierbox\fR widgets. The \fBtreeview\fR is 100% syntax compatible with the \fBhiertable\fR widget. The \fBhiertable\fR command is retained for sake of script-level compatibility. This widget obsoletes the \fBhierbox\fR widget. It does everything the old \fBhierbox\fR widget did, but also provides data sharing (via \fItree data objects\fR) and the ability to tag nodes. .SH INTRODUCTION The \fBtreeview\fR widget displays hierarchical data. Data is represented as nodes in a general-ordered tree. Each node may have sub-nodes and these nodes can in turn has their own children. .PP A node is displayed as a row entry in the widget. Each entry has a text label and icon. When a node has children, its entry is drawn with a small button to the left of the label. Clicking the mouse over this button opens or closes the node. When a node is \fIopen\fR, its children are exposed. When it is \fIclosed\fR, the children and their descedants are hidden. The button is normally a \f(CW+\fR or \f(CW\-\fR symbol (ala Windows Explorer), but can be replaced with a pair of Tk images (open and closed images). .PP If the node has data associated with it, they can be displayed in columns running vertically on either side the tree. You can control the color, font, etc of each entry. Any entry label or data field can be edited in-place. .SH "TREE DATA OBJECT" The tree is not stored inside the widget but in a tree data object (see the \fBtree\fR command for a further explanation). Tree data objects can be shared among different clients, such as a \fBtreeview\fR widget or the \fBtree\fR command. You can walk the tree and manage its data with the \fBtree\fR command tree, while displaying it with the \fBtreeview\fR widget. Whenever the tree is updated, the \fBtreeview\fR widget is automatically redrawn. .PP By default, the \fBtreeview\fR widget creates its own tree object. The tree initially contains just a root node. But you can also display trees created by the \fBtree\fR command using the \fB\-tree\fR configuration option. \fBTreeview\fR widgets can share the same tree object, possibly displaying different views of the same data. .PP A tree object has both a Tcl and C API. You can insert or delete nodes using \fBtreeview\fR widget or \fBtree\fR command operations, but also from C code. For example, you can load the tree from your C code while still managing and displaying the tree from Tcl. The widget is automatically notified whenever the tree is modified via C or Tcl. .SH SYNTAX .DS \fBtreeview \fIpathName \fR?\fIoption value\fR?... .DE The \fBtreeview\fR command creates a new window \fIpathName\fR and makes it into a \fBtreeview\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 widget 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, \fBtreeview\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 widget. 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 are described in the .SB "TREEVIEW OPERATIONS" section. .SH "IDS AND TAGS" Nodes can be inserted into a tree using the \fBtreeview\fR widget .CS blt::treeview .t set node [.t insert end root "one"] .CE or \fBtree\fR command. .CS set tree [blt::tree create] set node [$tree insert root "one"] .CE In both cases, a number identifying the node is returned (the value of \f(CW$node\fR). This serial number or \fIid\fR uniquely identifies the node. Please note that you can't infer a location or position of a node from its id. The only exception is that the root node is always id \f(CW0\fR. Since nodes may have the same labels or be moved within the tree, ids provide an convenient way to identify nodes. If a tree is shared, the ids will be the same regardless if you are using by the \fBtreeview\fR widget or the \fBtree\fR command. Ids are recycled when the node deleted. .PP A node may also have any number of \fItags\fR associated with it. A tag is just a string of characters, and it may take any form except that of an integer. For example, "\f(CWx123\fR" is valid, but "\f(CW123\fR" isn't. The same tag may be associated with many different nodes. This is typically done to associate a group of nodes. Many operations in the \fBtreeview\fR widget take either node ids or tag names as arguments. Using a tag says to apply the operation to all nodes with that tag. .PP The tag \fBall\fR is implicitly associated with every node in the tree. It may be used to invoke operations on all the nodes in the tree. .PP Tags may be shared, just like trees, between clients. For example, you can use the tags created by the \fBtree\fR command with \fBtreeview\fR widgets. .SH SPECIAL NODE IDS There are also several special non-numeric ids. Special ids differ from tags in that they are always translated to their numeric equivalent. They also take precedence over tags. For example, you can't use a tag name that is a special id. These ids are specific to the \fBtreeview\fR widget. .TP 15 \fBactive\fR The node where the mouse pointer is currently located. When a node is active, it is drawn using its active icon (see the \fB\-activeicon\fR option). The \fBactive\fR id is changed automatically by moving the mouse pointer over another node or by using the \fBentry activate\fR operation. Note that there can be only one active node at a time. .TP 15 \fBanchor\fR The node representing the fixed end of the current selection. The anchor is set by the \fBselection anchor\fR operation. .TP 15 \fBcurrent\fR The node where the mouse pointer is currently located. But unlike \fBactive\fR, this id changes while the selection is dragged. It is used to determine the current node during button drags. .TP 15 \fBdown\fR The next open node from the current focus. The \fBdown\fR of the last open node is the same. .TP 15 \fBend\fR The last open node (in depth-first order) on the tree. .TP 15 \fBfocus\fR The node that currently has focus. When a node has focus, it receives key events. To indicate focus, the node is drawn with a dotted line around its label. You can change the focus using the \fBfocus\fR operation. .TP 15 \fBlast\fR The last open node from the current focus. But unlike \fBup\fR, when the focus is at root, \fBlast\fR wraps around to the last open node in the tree. .TP 15 \fBmark\fR The node representing the non-fixed end of the current selection. The mark is set by the \fBselection mark\fR operation. .TP 15 \fBnext\fR The next open node from the current focus. But unlike \fBdown\fR, when the focus is on last open node, \fBnext\fR wraps around to the root node. .TP 15 \fBnextsibling\fR The next sibling from the node with the current focus. If the node is already the last sibling then it is the \fBnextsibling\fB. .TP 15 \fBparent\fR The parent of the node with the current focus. The \fBparent\fR of the root is also the root. .TP 15 \fBprevsibling\fR The previous sibling from the node with the current focus. If the node is already the first sibling then it is the \fBprevsibling\fB. .TP 15 \fBroot\fR The root node. You can also use id \f(CW0\fR to indicate the root. .TP 15 \fBup\fR The last open node (in depth-first order) from the current focus. The \fBup\fR of the root node (i.e. the root has focus) is also the root. .TP 15 \fBview.top\fR First node that's current visible in the widget. .TP 15 \fBview.bottom\fR Last node that's current visible in the widget. .TP 15 \fB@\fIx\fB,\fIy\fR Indicates the node that covers the point in the treeview window specified by \fIx\fR and \fIy\fR (in pixel coordinates). If no part of the entryd covers that point, then the closest node to that point is used. .PP A node may be specified as an id or tag. If the specifier is an integer then it is assumed to refer to the single node with that id. If the specifier is not an integer, it's checked to see if it's a special id (such as focus). Otherwise, it's assumed to be tag. Some operations only operate on a single node at a time; if a tag refers to more than one node, then an error is generated. .SH DATA FIELDS A node in the tree can have \fIdata fields\fR. A data field is a name-value pair, used to represent arbitrary data in the node. Nodes can contain different fields (they aren't required to contain the same fields). You can optionally display these fields in the \fBtreeview\fR widget in columns running on either side of the displayed tree. A node's value for the field is drawn in the column along side its node in the hierarchy. Any node that doesn't have a specific field is left blank. Columns can be interactively resized, hidden, or, moved. .SH ENTRY BINDINGS You can bind Tcl commands to be invoked when events occur on nodes (much like Tk canvas items). You can bind a node using its id or its \fIbindtags\fR. Bindtags are simply names that associate a binding with one or more nodes. There is a built-in tag \f(CWall\fR that all node entries automatically have. .SH "TREEVIEW OPERATIONS" The \fBtreeview\fR operations are the invoked by specifying the widget's pathname, the operation, and any arguments that pertain to that operation. The general form is: .sp .CS \fIpathName operation \fR?\fIarg arg ...\fR? .CE .sp \fIOperation\fR and the \fIarg\fRs determine the exact behavior of the command. The following operation are available for \fBtreeview\fR widgets: .TP \fIpathName \fBbbox\fR ?\fB-screen\fR? \fItagOrId...\fR Returns a list of 4 numbers, representing a bounding box of around the specified entries. The entries is given by one or more \fItagOrId\fR arguments. If the \fB\-screen\fR flag is given, then the x-y coordinates of the bounding box are returned as screen coordinates, not virtual coordinates. Virtual coordinates start from \f(CW0\fR from the root node. The returned list contains the following values. .RS .TP 1.25i \fIx\fR X-coordinate of the upper-left corner of the bounding box. .TP \fIy\fR Y-coordinate of the upper-left corner of the bounding box. .TP \fIwidth\fR Width of the bounding box. .TP \fIheight\fR Height of the bounding box. .RE .TP \fIpathName \fBbind\fR \fItagName\fR ?\fIsequence command\fR? Associates \fIcommand\fR with \fItagName\fR such that whenever the event sequence given by \fIsequence\fR occurs for a node with this tag, \fIcommand\fR will be invoked. The syntax is similar to the \fBbind\fR command except that it operates on \fBtreeview\fR 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 \fBbutton \fIoperation\fR ?\fIargs\fR? This command is used to control the button selectors within a \fBtreeview\fR widget. It has several forms, depending on \fIoperation\fR: .RS .TP \fIpathName \fBbutton activate\fR \fItagOrId\fR Designates the node given by \fItagOrId\fR as active. When a node is active it's entry is drawn using its active icon (see the \fB\-activeicon\fR option). Note that there can be only one active entry at a time. The special id \fBactive\fR indicates the currently active node. .TP \fIpathName \fBbutton bind\fR \fItagName\fR ?\fIsequence command\fR? Associates \fIcommand\fR with \fItagName\fR such that whenever the event sequence given by \fIsequence\fR occurs for an button of a node entry with this tag, \fIcommand\fR will be invoked. The syntax is similar to the \fBbind\fR command except that it operates on \fBtreeview\fR buttons, 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 \fBbutton cget\fR \fIoption\fR Returns the current value of the configuration option given by \fIoption\fR. \fIOption\fR may have any of the values accepted by the \fBconfigure\fR operation described below. .TP \fIpathName \fBbutton configure\fR ?\fIoption\fR? ?\fIvalue option value ...\fR? Query or modify the configuration options of the widget. If no \fIoption\fR is specified, returns a list describing all of the available options for \fIpathName\fR (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no \fIoption\fR is specified). If one or more \fIoption\-value\fR pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. \fIOption\fR and \fIvalue\fR are described in the section .SB "BUTTON OPTIONS" below. .RE .TP \fIpathName \fBcget\fR \fIoption\fR Returns the current value of the configuration option given by \fIoption\fR. \fIOption\fR may have any of the values accepted by the \fBconfigure\fR operation described below. .TP \fIpathName \fBclose \fR?\fB\-recurse\fR? \fItagOrId...\fR Closes the node specified by \fItagOrId\fR. In addition, if a Tcl script was specified by the \fB\-closecommand\fR option, it is invoked. If the node is already closed, this command has no effect. If the \fB\-recurse\fR flag is present, each child node is recursively closed. .TP \fIpathName \fBcolumn \fIoperation\fR ?\fIargs\fR? The following operations are available for treeview columns. .RS .TP \fIpathName \fBcolumn activate\fR \fIcolumn\fR Sets the active column to \fIcolumn\fR. \fIColumn\fR is the name of a column in the widget. When a column is active, it's drawn using its \fB\-activetitlebackground\fR and \fB\-activetitleforeground\fR options. If \fIcolumn\fR is the \f(CW""\fR, then no column will be active. If no column argument is provided, then the name of the currently active column is returned. .TP \fIpathName \fBcolumn cget\fR \fIname\fR \fIoption\fR Returns the current value of the column configuration option given by \fIoption\fR for \fIname\fR. \fIName\fR is the name of column that corresponds to a data field. \fIOption\fR may have any of the values accepted by the \fBconfigure\fR operation described below. .TP \fIpathName \fBcolumn configure\fR \fIname\fR ?\fIoption\fR? ?\fIvalue option value ...\fR? Query or modify the configuration options of the column designated by \fIname\fR. \fIName\fR is the name of the column corresponding to a data field. If no \fIoption\fR is specified, returns a list describing all of the available options for \fIpathName\fR (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no \fIoption\fR is specified). If one or more \fIoption\-value\fR pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. \fIOption\fR and \fIvalue\fR are described in the section .SB "COLUMN OPTIONS" below. .TP \fIpathName \fBcolumn delete\fR \fIfield\fR ?\fIfield\fR...? Deletes one of more columns designated by \fIfield\fR. Note that this does not delete the data fields themselves. .TP \fIpathName \fBcolumn insert\fR \fIposition\fR \fIfield\fR ?\fIoptions\fR...? Inserts one of more columns designated by \fIfield\fR. A column displays each node's data field by the same name. If the node doesn't have the given field, the cell is left blank. \fIPosition\fR indicates where in the list of columns to add the new column. It may be either a number or \f(CWend\fR. .TP \fIpathName \fBcolumn invoke\fR \fIfield\fR Invokes the Tcl command associated with the column \fIfield\fR, if there is one (using the column's \fB\-command\fR option). The command is ignored if the column's \fB\-state\fR option set to \f(CWdisabled\fR. .TP \fIpathName \fBcolumn move \fIname\fR \fIdest\fR Moves the column \fIname\fR to the destination position. \fIDest\fR is the name of another column or a screen position in the form \f(CW@\fIx\f(CW,\fIy\fR. .TP \fIpathName \fBcolumn names\fR Returns a list of the names of all columns in the widget. The list is ordered as the columns are drawn from left-to-right. .TP \fIpathName \fBcolumn nearest\fR \fIx\fR ?\fIy\fR? Returns the name of the column closest to the given X-Y screen coordinate. If you provide a \fIy\fR argument (it's optional), a name is returned only when if the point is over a column's title. .RE .TP \fIpathName \fBconfigure\fR ?\fIoption\fR? ?\fIvalue option value ...\fR? Query or modify the configuration options of the widget. If no \fIoption\fR is specified, returns a list describing all of the available options for \fIpathName\fR (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no \fIoption\fR is specified). If one or more \fIoption\-value\fR pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. \fIOption\fR and \fIvalue\fR are described in the section .SB "TREEVIEW OPTIONS" below. .TP \fIpathName \fBcurselection\fR Returns a list containing the ids of all of the entries that are currently selected. If there are no entries selected, then the empty string is returned. .TP \fIpathName \fBdelete \fItagOrId\fR... Deletes one or more entries given by \fItagOrId\fR and its children. .TP \fIpathName \fBentry \fIoperation\fR ?\fIargs\fR? The following operations are available for treeview entries. .RS .TP \fIpathName \fBentry activate\fR \fItagOrId\fR Sets the active entry to the one specified by \fItagOrId\fR. When an entry is active it is drawn using its active icon (see the \fB\-activeicon\fR option). Note that there can be only one active node at a time. The special id of the currently active node is \fBactive\fR. .TP \fIpathName \fBentry cget\fR \fIoption\fR Returns the current value of the configuration option given by \fIoption\fR. \fIOption\fR may have any of the values accepted by the \fBconfigure\fR operation described below. .TP \fIpathName \fBentry children\fR \fItagOrId\fR ?\fIfirst\fR? ?\fIlast\fR? Returns a list of ids for the given range of children of \fItagOrId\fR. \fITagOrId\fR is the id or tag of the node to be examined. If only a \fIfirst\fR argument is present, then the id of the that child at that numeric position is returned. If both \fIfirst\fR and \fIlast\fR arguments are given, then the ids of all the children in that range are returned. Otherwise the ids of all children are returned. .TP \fIpathName \fBentry configure\fR ?\fIoption\fR? ?\fIvalue option value ...\fR? Query or modify the configuration options of the widget. If no \fIoption\fR is specified, returns a list describing all of the available options for \fIpathName\fR (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no \fIoption\fR is specified). If one or more \fIoption\-value\fR pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. \fIOption\fR and \fIvalue\fR are described below: .TP \fIpathName \fBentry delete\fR \fItagOrId\fR ?\fIfirst\fR ?\fIlast\fR? Deletes the one or more children nodes of the parent \fItagOrId\fR. If \fIfirst\fR and \fIlast\fR arguments are present, they are positions designating a range of children nodes to be deleted. .TP \fIpathName \fBentry isbefore \fItagOrId1\fR \fItagOrId2\fR Returns 1 if \fItagOrId1\fR is before \fItagOrId2\fR and 0 otherwise. .TP \fIpathName \fBentry ishidden \fItagOrId\fR Returns 1 if the node is currently hidden and 0 otherwise. A node is also hidden if any of its ancestor nodes are closed or hidden. .TP \fIpathName \fBentry isopen \fItagOrId\fR Returns 1 if the node is currently open and 0 otherwise. .TP \fIpathName \fBentry size\fR \fB\-recurse\fR \fItagOrId\fR Returns the number of children for parent node \fItagOrId\fR. If the \fB\-recurse\fR flag is set, the number of all its descendants is returned. The node itself is not counted. .RE .TP \fIpathName \fBfind \fR?\fIflags\fR? \fIfirst\fR \fIlast\fR Finds for all entries matching the criteria given by \fIflags\fR. A list of ids for all matching nodes is returned. \fIFirst\fR and \fIlast\fR are ids designating the range of the search in depth-first order. If \fIlast\fR is before \fIfirst\fR, then nodes are searched in reverse order. The valid flags are: .RS .TP 1.25i \fB\-name\fI pattern\fR Specifies pattern to match against node names. .TP 1.25i \fB\-full\fI pattern\fR Specifies pattern to match against node pathnames. .TP 1.25i \fB\-\fIoption\fI pattern\fR Specifies pattern to match against the node entry's configuration option. .TP 1.25i \fB\-exact\fR Patterns must match exactly. The is the default. .TP 1.25i \fB\-glob\fR Use global pattern matching. Matching is done in a fashion similar to that used by the C-shell. For the two strings to match, their contents must be identical except that the following special sequences may appear in pattern: .RS .TP 5 \f(CW*\fR Matches any sequence of characters in string, including a null string. .TP 5 \f(CW?\fR Matches any single character in string. .TP 5 \f(CW[\fIchars\f(CW]\fR Matches any character in the set given by \fIchars\fR. If a sequence of the form \fIx\fR-\fIy\fR appears in \fIchars\fR, then any character between \fIx\fR and \fIy\fR, inclusive, will match. .TP 5 \f(CW\\\fIx\fR Matches the single character \fIx\fR. This provides a way of avoiding the special interpretation of the characters \f(CW*?[]\\\fR in the pattern. .RE .TP 1.25i \fB\-regexp\fR Use regular expression pattern matching (i.e. the same as implemented by the \fBregexp\fR command). .TP 1.25i \fB\-nonmatching\fR Pick entries that don't match. .TP 1.25i \fB\-exec\fI string\fR Specifies a Tcl script to be invoked for each matching node. Percent substitutions are performed on \fIstring\fR before it is executed. The following substitutions are valid: .RS .TP 5 \f(CW%W\fR The pathname of the widget. .TP 5 \f(CW%p\fR The name of the node. .TP 5 \f(CW%P\fR The full pathname of the node. .TP 5 \f(CW%#\fR The id of the node. .TP 5 \f(CW%%\fR Translates to a single percent. .RE .TP 1.25i \fB\-count\fI number\fR Stop searching after \fInumber\fR matches. .TP 1.25i \fB\-\-\fR Indicates the end of flags. .RE .TP \fIpathName \fBfocus \fR \fItagOrId\fR Sets the focus to the node given by \fItagOrId\fR. When a node has focus, it can receive keyboard events. The special id \fBfocus\fR designates the node that currently has focus. .TP \fIpathName \fBget \fR?\fB\-full\fR? \fItagOrId\fR \fItagOrId\fR... Translates one or more ids to their node entry names. It returns a list of names for all the ids specified. If the \fB\-full\fR flag is set, then the full pathnames are returned. .sp Note: If the \fB\-separator\fR option is the empty string (the default), the result is always a list of lists, even if there is only one node specified. .TP \fIpathName \fBhide \fR?\fBflags\fR? \fItagOrId\fR... Hides all nodes matching the criteria given by \fIflags\fR. The search is performed recursively for each node given by \fItagOrId\fR. The valid flags are described below: .RS .TP 1.25i \fB\-name\fI pattern\fR Specifies pattern to match against node names. .TP 1.25i \fB\-full\fI pattern\fR Specifies pattern to match against node pathnames. .TP 1.25i \fB\-\fIoption\fI pattern\fR Specifies pattern to match against the node entry's configuration option. .TP 1.25i \fB\-exact\fR Match patterns exactly. The is the default. .TP 1.25i \fB\-glob\fR Use global pattern matching. Matching is done in a fashion similar to that used by the C-shell. For the two strings to match, their contents must be identical except that the following special sequences may appear in pattern: .RS .TP 5 \f(CW*\fR Matches any sequence of characters in string, including a null string. .TP 5 \f(CW?\fR Matches any single character in string. .TP 5 \f(CW[\fIchars\f(CW]\fR Matches any character in the set given by \fIchars\fR. If a sequence of the form \fIx\fR-\fIy\fR appears in \fIchars\fR, then any character between \fIx\fR and \fIy\fR, inclusive, will match. .TP 5 \f(CW\\\fIx\fR Matches the single character \fIx\fR. This provides a way of avoiding the special interpretation of the characters \f(CW*?[]\\\fR in the pattern. .RE .TP 1.25i \fB\-regexp\fR Use regular expression pattern matching (i.e. the same as implemented by the \fBregexp\fR command). .TP 1.25i \fB\-nonmatching\fR Hide nodes that don't match. .TP 1.25i \fB\-\-\fR Indicates the end of flags. .RE .TP \fIpathName \fBindex \fR?\fB\-at\fR ?\fB\-path\fR? \fItagOrId\fR? \fIstring\fR Returns the id of the node specified by \fIstring\fR. \fIString\fR may be a tag or node id. Some special ids are normally relative to the node that has focus. The \fB\-at\fR flag lets you select another node. .TP \fIpathName \fBinsert \fR?\fB\-at \fItagOrId\fR? \fIposition\fR \fIpath\fR ?\fIoptions...\fR? ?\fIpath\fR? ?\fIoptions...\fR? Inserts one or more nodes at \fIposition\fR. \fIPosition\fR is the location (number or \f(CWend\fR) where the new nodes are added to the parent node. \fIPath\fR is the pathname of the new node. Pathnames can be formated either as a Tcl list (each element is a path component) or as a string separated by a special character sequence (using the \fB\-separator\fR option). Pathnames are normally absolute, but the \fB\-at\fR switch lets you select a relative starting point. Its value is the id of the starting node. .sp All ancestors of the new node must already exist, unless the \fB\-autocreate\fR option is set. It is also an error if a node already exists, unless the \fB\-allowduplicates\fR option is set. .sp \fIOption\fR and \fIvalue\fR may have any of the values accepted by the \fBentry configure\fR operation described in the .SB "ENTRY OPERATIONS" section below. This command returns a list of the ids of the new entries. .TP \fIpathName \fBmove \fItagOrId\fR \fIhow\fR \fIdestId\fR Moves the node given by \fItagOrId\fR to the destination node. The node can not be an ancestor of the destination. \fIDestId\fR is the id of the destination node and can not be the root of the tree. In conjunction with \fIhow\fR, it describes how the move is performed. .RS .TP 8 \f(CWbefore\fR Moves the node before the destination node. .TP 8 \f(CWafter\fR Moves the node after the destination node. .TP 8 \f(CWinto\fR Moves the node to the end of the destination's list of children. .RE .TP \fIpathName \fBnearest \fIx y\fR ?\fIvarName\fR? Returns the id of the node entry closest to the given X-Y screen coordinate. If the coordinate is not directly over any node, then the empty string is returned. If the argument \fIvarName\fR is present, this is a Tcl variable that is set to either \f(CWbutton\fR, \f(CWlabel\fR, \f(CWlabel\fR, or \f(CW""\fR depending what part of the entry the coordinate lies. .TP \fIpathName \fBopen \fR?\fB\-recurse\fR? \fItagOrId...\fR Opens the one or more nodes specified by \fItagOrId\fR. If a node is not already open, the Tcl script specified by the \fB\-opencommand\fR option is invoked. If the \fB\-recurse\fR flag is present, then each descendant is recursively opened. .TP \fIpathName \fBrange\fR ?\fB-open\fR? \fIfirst last\fR Returns the ids in depth-first order of the nodes between the \fIfirst\fR and \fIlast\fR ids. If the \fB\-open\fR flag is present, it indicates to consider only open nodes. If \fIlast\fR is before \fIfirst\fR, then the ids are returned in reverse order. .TP \fIpathName \fBscan\fR \fIoption args\fR This command implements scanning. It has two forms, depending on \fIoption\fR: .RS .TP \fIpathName \fBscan mark \fIx y\fR Records \fIx\fR and \fIy\fR and the current view in the treeview window; used in conjunction with later \fBscan dragto\fR commands. Typically this command is associated with a mouse button press in the widget. It returns an empty string. .TP \fIpathName \fBscan dragto \fIx y\fR. Computes the difference between its \fIx\fR and \fIy\fR arguments and the \fIx\fR and \fIy\fR arguments to the last \fBscan mark\fR command for the widget. It then adjusts the view by 10 times the difference in coordinates. This command is typically associated with mouse motion events in the widget, to produce the effect of dragging the list at high speed through the window. The return value is an empty string. .RE .TP \fIpathName \fBsee\fR ?\fB\-anchor \fIanchor\fR? \fItagOrId\fR Adjusts the view of entries so that the node given by \fItagOrId\fR is visible in the widget window. It is an error if \fBtagOrId\fR is a tag that refers to more than one node. By default the node's entry is displayed in the middle of the window. This can changed using the \fB\-anchor\fR flag. Its value is a Tk anchor position. .TP \fIpathName \fBselection \fIoption arg\fR This command is used to adjust the selection within a \fBtreeview\fR widget. It has several forms, depending on \fIoption\fR: .RS .TP \fIpathName \fBselection anchor \fItagOrId\fR Sets the selection anchor to the node given by \fItagOrId\fR. If \fItagOrId\fR refers to a non-existent node, then the closest node is used. The selection anchor is the end of the selection that is fixed while dragging out a selection with the mouse. The special id \fBanchor\fR may be used to refer to the anchor node. .TP \fIpathName \fBselection cancel\fR Clears the temporary selection of entries back to the current anchor. Temporary selections are created by the \fBselection mark\fR operation. .TP \fIpathName \fBselection clear \fIfirst \fR?\fIlast\fR? Removes the entries between \fIfirst\fR and \fIlast\fR (inclusive) from the selection. Both \fIfirst\fR and \fIlast\fR are ids representing a range of entries. If \fIlast\fR isn't given, then only \fIfirst\fR is deselected. Entries outside the selection are not affected. .TP \fIpathName \fBselection clearall\fR Clears the entire selection. .TP \fIpathName \fBselection mark \fItagOrId\fR Sets the selection mark to the node given by \fItagOrId\fR. This causes the range of entries between the anchor and the mark to be temporarily added to the selection. The selection mark is the end of the selection that is fixed while dragging out a selection with the mouse. The special id \fBmark\fR may be used to refer to the current mark node. If \fItagOrId\fR refers to a non-existent node, then the mark is ignored. Resetting the mark will unselect the previous range. Setting the anchor finalizes the range. .TP \fIpathName \fBselection includes \fItagOrId\fR Returns 1 if the node given by \fItagOrId\fR is currently selected, 0 if it isn't. .TP \fIpathName \fBselection present\fR Returns 1 if any nodes are currently selected and 0 otherwise. .TP \fIpathName \fBselection set \fIfirst \fR?\fIlast\fR? Selects all of the nodes in the range between \fIfirst\fR and \fIlast\fR, inclusive, without affecting the selection state of nodes outside that range. .TP \fIpathName \fBselection toggle \fIfirst \fR?\fIlast\fR? Selects/deselects nodes in the range between \fIfirst\fR and \fIlast\fR, inclusive, from the selection. If a node is currently selected, it becomes deselected, and visa versa. .RE .TP \fIpathName \fBshow \fR?\fBflags\fR? \fItagOrId\fR... Exposes all nodes matching the criteria given by \fIflags\fR. This is the inverse of the \fBhide\fR operation. The search is performed recursively for each node given by \fItagOrId\fR. The valid flags are described below: .RS .TP 1.25i \fB\-name\fI pattern\fR Specifies pattern to match against node names. .TP 1.25i \fB\-full\fI pattern\fR Specifies pattern to match against node pathnames. .TP 1.25i \fB\-\fIoption\fI pattern\fR Specifies pattern to match against the entry's configuration option. .TP 1.25i \fB\-exact\fR Match patterns exactly. The is the default. .TP 1.25i \fB\-glob\fR \fB\-glob\fR Use global pattern matching. Matching is done in a fashion similar to that used by the C-shell. For the two strings to match, their contents must be identical except that the following special sequences may appear in pattern: .RS .TP 5 \f(CW*\fR Matches any sequence of characters in string, including a null string. .TP 5 \f(CW?\fR Matches any single character in string. .TP 5 \f(CW[\fIchars\f(CW]\fR Matches any character in the set given by \fIchars\fR. If a sequence of the form \fIx\fR-\fIy\fR appears in \fIchars\fR, then any character between \fIx\fR and \fIy\fR, inclusive, will match. .TP 5 \f(CW\\\fIx\fR Matches the single character \fIx\fR. This provides a way of avoiding the special interpretation of the characters \f(CW*?[]\\\fR in the pattern. .RE .TP 1.25i \fB\-regexp\fR Use regular expression pattern matching (i.e. the same as implemented by the \fBregexp\fR command). .TP 1.25i \fB\-nonmatching\fR Expose nodes that don't match. .TP 1.25i \fB\-\-\fR Indicates the end of flags. .RE .TP \fIpathName \fBsort\fR ?\fIoperation\fR? \fIargs...\fR .RS .TP \fIpathName \fBsort auto\fR ?\fIboolean\fR Turns on/off automatic sorting of node entries. If \fIboolean\fR is true, entries will be automatically sorted as they are opened, closed, inserted, or deleted. If no \fIboolean\fR argument is provided, the current state is returned. .TP \fIpathName \fBsort cget\fR \fIoption\fR Returns the current value of the configuration option given by \fIoption\fR. \fIOption\fR may have any of the values accepted by the \fBconfigure\fR operation described below. .TP \fIpathName \fBsort configure\fR ?\fIoption\fR? ?\fIvalue option value ...\fR? Query or modify the sorting configuration options of the widget. If no \fIoption\fR is specified, returns a list describing all of the available options for \fIpathName\fR (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no \fIoption\fR is specified). If one or more \fIoption\-value\fR pairs are specified, then the command modifies the given sorting option(s) to have the given value(s); in this case the command returns an empty string. \fIOption\fR and \fIvalue\fR are described below: .RS .TP \fB\-column\fI string\fR Specifies the column to sort. Entries in the widget are rearranged according to this column. If \fIcolumn\fR is \f(CW""\fR then no sort is performed. .TP \fB\-command\fI string\fR Specifies a Tcl procedure to be called when sorting nodes. The procedure is called with three arguments: the pathname of the widget and the fields of two entries. The procedure returns 1 if the first node is greater than the second, -1 is the second is greater, and 0 if equal. .TP \fB\-decreasing\fI boolean\fR Indicates to sort in ascending/descending order. If \fIboolean\fR is true, then the entries as in descending order. The default is \f(CWno\fR. .TP \fB\-mode\fI string\fR Specifies how to compare entries when sorting. \fIString\fR may be one of the following: .RS .TP 1.5i \f(CWascii\fR Use string comparison based upon the ASCII collation order. .TP 1.5i \f(CWdictionary\fR Use dictionary-style comparison. This is the same as \f(CWascii\fR except (a) case is ignored except as a tie-breaker and (b) if two strings contain embedded numbers, the numbers compare as integers, not characters. For example, "bigBoy" sorts between "bigbang" and "bigboy", and "x10y" sorts between "x9y" and "x11y". .TP 1.5i \f(CWinteger\fR Compares fields as integers. .TP 1.5i \f(CWreal\fR Compares fields as floating point numbers. .TP 1.5i \f(CWcommand\fR Use the Tcl proc specified by the \fB\-command\fR option to compare entries when sorting. If no command is specified, the sort reverts to \f(CWascii\fR sorting. .RE .RE .TP \fIpathName \fBsort once\fR ?\fIflags\fR? \fItagOrId...\fR Sorts the children for each entries specified by \fItagOrId\fR. By default, entries are sorted by name, but you can specify a Tcl proc to do your own comparisons. .RS .TP 1.5i \fB\-recurse\fR Recursively sort the entire branch, not just the children. .RE .RE .TP \fIpathName \fBtag \fIoperation args\fR Tags are a general means of selecting and marking nodes in the tree. A tag is just a string of characters, and it may take any form except that of an integer. The same tag may be associated with many different nodes. .sp Both \fIoperation\fR and its arguments determine the exact behavior of the command. The operations available for tags are listed below. .RS .TP \fIpathName\fR \fBtag add\fR \fIstring\fR \fIid\fR... Adds the tag \fIstring\fR to one of more entries. .TP \fIpathName\fR \fBtag delete\fR \fIstring\fR \fIid\fR... Deletes the tag \fIstring\fR from one or more entries. .TP \fIpathName\fR \fBtag forget\fR \fIstring\fR Removes the tag \fIstring\fR from all entries. It's not an error if no entries are tagged as \fIstring\fR. .TP \fIpathName\fR \fBtag names\fR ?\fIid\fR? Returns a list of tags used. If an \fIid\fR argument is present, only those tags used by the node designated by \fIid\fR are returned. .TP \fIpathName\fR \fBtag nodes\fR \fIstring\fR Returns a list of ids that have the tag \fIstring\fR. If no node is tagged as \fIstring\fR, then an empty string is returned. .RE .TP \fIpathName \fBtext \fIoperation\fR ?\fIargs\fR? This operation is used to provide text editing for cells (data fields in a column) or entry labels. It has several forms, depending on \fIoperation\fR: .RS .TP \fIpathName \fBtext apply\fR Applies the edited buffer, replacing the entry label or data field. The edit window is hidden. .TP \fIpathName \fBtext cancel\fR Cancels the editing operation, reverting the entry label or data value back to the previous value. The edit window is hidden. .TP \fIpathName \fBtext cget\fI value\fR Returns the current value of the configuration option given by \fIoption\fR. \fIOption\fR may have any of the values accepted by the \fBconfigure\fR operation described below. .TP \fIpathName \fBtext configure\fR ?\fIoption value\fR? Query or modify the configuration options of the edit window. If no \fIoption\fR is specified, returns a list describing all of the available options (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no \fIoption\fR is specified). If one or more \fIoption\-value\fR pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. \fIOption\fR and \fIvalue\fR are described in the section .SB "TEXT EDITING OPTIONS" below. .RE .TP \fIpathName \fBtext delete\fI first last\fR Deletes the characters in the edit buffer between the two given character positions. .TP \fIpathName \fBtext get\fR ?\fI\-root\fR? \fIx y\fR .TP \fIpathName \fBtext icursor\fI index\fR .TP \fIpathName \fBtext index\fI index\fR Returns the text index of given \fIindex\fR. .TP \fIpathName \fBtext insert\fI index string\fR Insert the text string \fIstring\fR into the edit buffer at the index \fIindex\fR. For example, the index 0 will prepend the buffer. .TP \fIpathName \fBtext selection\fI args\fR This operation controls the selection of the editing window. Note that this differs from the selection of entries. It has the following forms: .RS .TP \fIpathName \fBtext selection adjust\fI index\fR Adjusts either the first or last index of the selection. .TP \fIpathName \fBtext selection clear\fR Clears the selection. .TP \fIpathName \fBtext selection from\fI index\fR Sets the anchor of the selection. .TP \fIpathName \fBtext selection present\fR Indicates if a selection is present. .TP \fIpathName \fBtext selection range\fI start end\fR Sets both the anchor and mark of the selection. .TP \fIpathName \fBtext selection to\fI index\fR Sets the unanchored end (mark) of the selection. .RE .TP \fIpathName \fBtoggle \fItagOrId\fR Opens or closes the node given by \fItagOrId\fR. If the corresponding \fB\-opencommand\fR or \fB\-closecommand\fR option is set, then that command is also invoked. .TP \fIpathName \fBxview \fIargs\fR This command is used to query and change the horizontal position of the information in the widget's window. It can take any of the following forms: .RS .TP \fIpathName \fBxview\fR Returns a list containing two elements. Each element is a real fraction between 0 and 1; together they describe the horizontal span that is visible in the window. For example, if the first element is .2 and the second element is .6, 20% of the \fBtreeview\fR widget's text is off-screen to the left, the middle 40% is visible in the window, and 40% of the text is off-screen to the right. These are the same values passed to scrollbars via the \fB\-xscrollcommand\fR option. .TP \fIpathName \fBxview\fR \fItagOrId\fR Adjusts the view in the window so that the character position given by \fItagOrId\fR is displayed at the left edge of the window. Character positions are defined by the width of the character \fB0\fR. .TP \fIpathName \fBxview moveto\fI fraction\fR Adjusts the view in the window so that \fIfraction\fR of the total width of the \fBtreeview\fR widget's text is off-screen to the left. \fIfraction\fR must be a fraction between 0 and 1. .TP \fIpathName \fBxview scroll \fInumber what\fR This command shifts the view in the window left or right according to \fInumber\fR and \fIwhat\fR. \fINumber\fR must be an integer. \fIWhat\fR must be either \fBunits\fR or \fBpages\fR or an abbreviation of one of these. If \fIwhat\fR is \fBunits\fR, the view adjusts left or right by \fInumber\fR character units (the width of the \fB0\fR character) on the display; if it is \fBpages\fR then the view adjusts by \fInumber\fR screenfuls. If \fInumber\fR is negative then characters farther to the left become visible; if it is positive then characters farther to the right become visible. .RE .TP \fIpathName \fByview \fI?args\fR? This command is used to query and change the vertical position of the text in the widget's window. It can take any of the following forms: .RS .TP \fIpathName \fByview\fR Returns a list containing two elements, both of which are real fractions between 0 and 1. The first element gives the position of the node at the top of the window, relative to the widget as a whole (0.5 means it is halfway through the treeview window, for example). The second element gives the position of the node just after the last one in the window, relative to the widget as a whole. These are the same values passed to scrollbars via the \fB\-yscrollcommand\fR option. .TP \fIpathName \fByview\fR \fItagOrId\fR Adjusts the view in the window so that the node given by \fItagOrId\fR is displayed at the top of the window. .TP \fIpathName \fByview moveto\fI fraction\fR Adjusts the view in the window so that the node given by \fIfraction\fR appears at the top of the window. \fIFraction\fR is a fraction between 0 and 1; 0 indicates the first node, 0.33 indicates the node one-third the way through the \fBtreeview\fR widget, and so on. .TP \fIpathName \fByview scroll \fInumber what\fR This command adjusts the view in the window up or down according to \fInumber\fR and \fIwhat\fR. \fINumber\fR must be an integer. \fIWhat\fR must be either \fBunits\fR or \fBpages\fR. If \fIwhat\fR is \fBunits\fR, the view adjusts up or down by \fInumber\fR lines; if it is \fBpages\fR then the view adjusts by \fInumber\fR screenfuls. If \fInumber\fR is negative then earlier nodes become visible; if it is positive then later nodes become visible. .RE .SH "TREEVIEW OPTIONS" In addition to the \fBconfigure\fR operation, widget configuration options may also be set by the Tk \fBoption\fR command. The class resource name is \f(CWTreeView\fR. .CS option add *TreeView.Foreground white option add *TreeView.Background blue .CE The following widget options are available: .TP \fB\-activebackground \fIcolor\fR Sets the background color for active entries. A node is active when the mouse passes over it's entry or using the \fBactivate\fR operation. .TP \fB\-activeforeground \fIcolor\fR Sets the foreground color of the active node. A node is active when the mouse passes over it's entry or using the \fBactivate\fR operation. .TP \fB\-activeicons \fIimages\fR Specifies images to be displayed for an entry's icon when it is active. \fIImages\fR is a list of two Tk images: the first image is displayed when the node is open, the second when it is closed. .TP \fB\-autocreate \fIboolean\fR If \fIboolean\fR is true, automatically create missing ancestor nodes when inserting new nodes. Otherwise flag an error. The default is \f(CWno\fR. .TP \fB\-allowduplicates \fIboolean\fR If \fIboolean\fR is true, allow nodes with duplicate pathnames when inserting new nodes. Otherwise flag an error. The default is \f(CWno\fR. .TP \fB\-background \fIcolor\fR Sets the background color of the widget. The default is \f(CWwhite\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\-closecommand \fIstring\fR Specifies a Tcl script to be invoked when a node is closed. You can overrider this for individual entries using the entry's \fB\-closecommand\fR option. The default is \f(CW""\fR. Percent substitutions are performed on \fIstring\fR before it is executed. The following substitutions are valid: .RS .TP 5 \f(CW%W\fR The pathname of the widget. .TP 5 \f(CW%p\fR The name of the node. .TP 5 \f(CW%P\fR The full pathname of the node. .TP 5 \f(CW%#\fR The id of the node. .TP 5 \f(CW%%\fR Translates to a single percent. .RE .TP \fB\-cursor \fIcursor\fR Specifies the widget's cursor. The default cursor is \f(CW""\fR. .TP \fB\-dashes \fInumber\fR Sets the dash style of the horizontal and vertical lines drawn connecting entries. \fINumber\fR is the length in pixels of the dashes and gaps in the line. If \fInumber\fR is \f(CW0\fR, solid lines will be drawn. The default is \f(CW1\fR (dotted). .TP \fB\-exportselection \fIboolean\fR Indicates if the selection is exported. If the widget is exporting its selection then it will observe the standard X11 protocols for handling the selection. Selections are available as type \fBSTRING\fR; the value of the selection will be the label of the selected nodes, separated by newlines. The default is \f(CWno\fR. .TP \fB\-flat \fIboolean\fR Indicates whether to display the tree as a flattened list. If \fIboolean\fR is true, then the hierarchy will be a list of full paths for the nodes. This option also has affect on sorting. See the .SB "SORT OPERATIONS" section for more information. The default is \f(CWno\fR. .TP \fB\-focusdashes \fIdashList\fR Sets the dash style of the outline rectangle drawn around the entry label of the node that current has focus. \fINumber\fR is the length in pixels of the dashes and gaps in the line. If \fInumber\fR is \f(CW0\fR, a solid line will be drawn. The default is \f(CW1\fR. .TP \fB\-focusforeground \fIcolor\fR Sets the color of the focus rectangle. The default is \f(CWblack\fR. .TP \fB\-font \fIfontName\fR Specifies the font for entry labels. You can override this for individual entries with the entry's \fB\-font\fR configuration option. The default is \f(CW*-Helvetica-Bold-R-Normal-*-12-120-*\fR. .TP \fB\-foreground \fIcolor\fR Sets the text color of entry labels. You can override this for individual entries with the entry's \fB\-foreground\fR configuration option. The default is \f(CWblack\fR. .TP \fB\-height \fIpixels\fR Specifies the requested height of widget. The default is \f(CW400\fR. .TP \fB\-hideroot \fIboolean\fR If \fIboolean\fR is true, it indicates that no entry for the root node should be displayed. The default is \f(CWno\fR. .TP \fB\-highlightbackground \fIcolor\fR Specifies the normal color of the traversal highlight region when the widget does not have the input focus. .TP \fB\-highlightcolor \fIcolor\fR Specifies the color of the traversal highlight rectangle when the widget has the input focus. The default is \f(CWblack\fR. .TP \fB\-highlightthickness \fIpixels\fR Specifies the width of the highlight rectangle indicating when the widget has input focus. The value may have any of the forms acceptable to \fBTk_GetPixels\fR. If the value is zero, no focus highlight will be displayed. The default is \f(CW2\fR. .TP \fB\-icons \fIimages\fR Specifies images for the entry's icon. \fIImages\fR is a list of two Tk images: the first image is displayed when the node is open, the second when it is closed. .TP \fB\-linecolor \fIcolor\fR Sets the color of the connecting lines drawn between entries. The default is \f(CWblack\fR. .TP \fB\-linespacing \fIpixels\fR Sets the number of pixels spacing between entries. The default is \f(CW0\fR. .TP \fB\-linewidth \fIpixels\fR Set the width of the lines drawn connecting entries. If \fIpixels\fR is \f(CW0\fR, no vertical or horizontal lines are drawn. The default is \f(CW1\fR. .TP \fB\-newtags \fIboolean\fR If \fIboolean\fR is true, when sharing a tree object (see the \fB\-tree\fR option), don't share its tags too. The default is \f(CW0\fR. .TP \fB\-opencommand \fIstring\fR Specifies a Tcl script to be invoked when a node is open. You can override this for individual entries with the entry's \fB\-opencommand\fR configuration option. The default is \f(CW""\fR. Percent substitutions are performed on \fIstring\fR before it is executed. The following substitutions are valid: .RS .TP 5 \f(CW%W\fR The pathname of the widget. .TP 5 \f(CW%p\fR The name of the node. .TP 5 \f(CW%P\fR The full pathname of the node. .TP 5 \f(CW%#\fR The id of the node. .TP 5 \f(CW%%\fR Translates to a single percent. .RE .TP \fB\-relief \fIrelief\fR Specifies the 3-D effect for the widget. \fIRelief\fR specifies how the \fBtreeview\fR widget should appear relative to widget it is packed into; for example, \f(CWraised\fR means the \fBtreeview\fR widget should appear to protrude. The default is \f(CWsunken\fR. .TP \fB\-scrollmode \fImode\fR Specifies the style of scrolling to be used. The following styles are valid. This is the default is \f(CWhierbox\fR. .RS .TP 1.25i \f(CWlistbox\fR Like the \fBlistbox\fR widget, the last entry can always be scrolled to the top of the widget window. This allows the scrollbar thumb to shrink as the last entry is scrolled upward. .TP 1.25i \f(CWhierbox\fR Like the \fBhierbox\fR widget, the last entry can only be viewed at the bottom of the widget window. The scrollbar stays a constant size. .TP 1.25i \f(CWcanvas\fR Like the \fBcanvas\fR widget, the entries are bound within the scrolling area. .RE .TP \fB\-selectbackground \fIcolor\fR Sets the background color selected node entries. The default is \f(CW#ffffea\fR. .TP \fB\-selectborderwidth \fIpixels\fR Sets the width of the raised 3-D border drawn around the labels of selected entries. The default is \f(CW0\fR. \fB\-selectcommand \fIstring\fR Specifies a Tcl script to invoked when the set of selected nodes changes. The default is \f(CW""\fR. .TP \fB\-selectforeground \fIcolor\fB Sets the color of the labels of selected node entries. The default is \f(CWblack\fR. .TP \fB\-selectmode \fImode\fR Specifies the selection mode. If \fImode\fR is \f(CWsingle\fR, only one node can be selected at a time. If \f(CWmultiple\fR more than one node can be selected. The default is \f(CWsingle\fR. .TP \fB\-separator \fIstring\fR Specifies the character sequence to use when spliting the path components. The separator may be several characters wide (such as "::") Consecutive separators in a pathname are treated as one. If \fIstring\fR is the empty string, the pathnames are Tcl lists. Each element is a path component. The default is \f(CW""\fR. .TP \fB\-showtitles \fIboolean\fR If \fIboolean\fR is false, column titles are not be displayed. The default is \f(CWyes\fR. .TP \fB\-sortselection \fIboolean\fR If \fIboolean\fR is true, nodes in the selection are ordered as they are currently displayed (depth-first or sorted), not in the order they were selected. The default is \f(CWno\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"1"\fR. .TP \fB\-trim \fIstring\fR Specifies a string leading characters to trim from entry pathnames before parsing. This only makes sense if the \fB\-separator\fR is also set. The default is \f(CW""\fR. .TP \fB\-width \fIpixels\fR Sets the requested width of the widget. If \fIpixels\fR is 0, then the with is computed from the contents of the \fBtreeview\fR widget. The default is \f(CW200\fR. .TP \fB\-xscrollcommand \fIstring\fR Specifies the prefix for a command used to communicate with horizontal scrollbars. Whenever the horizontal view in the widget's window changes, the widget will generate a Tcl command by concatenating the scroll command and two numbers. If this option is not specified, then no command will be executed. .TP \fB\-xscrollincrement\fR \fIpixels\fR Sets the horizontal scrolling distance. The default is 20 pixels. .TP \fB\-yscrollcommand \fIstring\fR Specifies the prefix for a command used to communicate with vertical scrollbars. Whenever the vertical view in the widget's window changes, the widget will generate a Tcl command by concatenating the scroll command and two numbers. If this option is not specified, then no command will be executed. .TP \fB\-yscrollincrement\fR \fIpixels\fR Sets the vertical scrolling distance. The default is 20 pixels. .SH "ENTRY OPTIONS" Many widget configuration options have counterparts in entries. For example, there is a \fB\-closecommand\fR configuration option for both widget itself and for individual entries. Options set at the widget level are global for all entries. If the entry configuration option is set, then it overrides the widget option. This is done to avoid wasting memory by replicated options. Most entries will have redundant options. .PP There is no resource class or name for entries. .TP \fB\-activeicons \fIimages\fR Specifies images to be displayed as the entry's icon when it is active. This overrides the global \fB\-activeicons\fR configuration option for the specific entry. \fIImages\fR is a list of two Tk images: the first image is displayed when the node is open, the second when it is closed. .TP \fB\-bindtags \fItagList\fR Specifies the binding tags for nodes. \fITagList\fR is a list of binding tag names. The tags and their order will determine how events are handled for nodes. 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\-button \fIstring\fR Indicates whether a button should be displayed on the left side of the node entry. \fIString\fR can be \f(CWyes\fR, \f(CWno\fR, or \f(CWauto\fR. If \f(CWauto\fR, then a button is automatically displayed if the node has children. This is the default. .TP \fB\-closecommand \fIstring\fR Specifies a Tcl script to be invoked when the node is closed. This overrides the global \fB\-closecommand\fR option for this entry. The default is \f(CW""\fR. Percent substitutions are performed on \fIstring\fR before it is executed. The following substitutions are valid: .RS .TP 5 \f(CW%W\fR The pathname of the widget. .TP 5 \f(CW%p\fR The name of the node. .TP 5 \f(CW%P\fR The full pathname of the node. .TP 5 \f(CW%#\fR The id of the node. .TP 5 \f(CW%%\fR Translates to a single percent. .RE .TP \fB\-data \fIstring\fR Sets data fields for the node. \fIString\fR is a list of name-value pairs to be set. The default is \f(CW""\fR. .TP \fB\-font \fIfontName\fR Sets the font for entry labels. This overrides the widget's \fB\-font\fR option for this node. The default is \f(CW*-Helvetica-Bold-R-Normal-*-12-120-*\fR. .TP \fB\-foreground \fIcolor\fR Sets the text color of the entry label. This overrides the widget's \fB\-foreground\fR configuration option. The default is \f(CW""\fR. .TP \fB\-icons \fIimages\fR Specifies images to be displayed for the entry's icon. This overrides the global \fB\-icons\fR configuration option. \fIImages\fR is a list of two Tk images: the first image is displayed when the node is open, the second when it is closed. .TP \fB\-label \fIstring\fR Sets the text for the entry's label. If not set, this defaults to the name of the node. The default is \f(CW""\fR. .TP \fB\-opencommand \fIstring\fR Specifies a Tcl script to be invoked when the entry is opened. This overrides the widget's \fB\-opencommand\fR option for this node. The default is \f(CW""\fR. Percent substitutions are performed on \fIstring\fR before it is executed. The following substitutions are valid: .RS .TP 5 \f(CW%W\fR The pathname of the widget. .TP 5 \f(CW%p\fR The name of the node. .TP 5 \f(CW%P\fR The full pathname of the node. .TP 5 \f(CW%#\fR The id of the node. .TP 5 \f(CW%%\fR Translates to a single percent. .RE .SH "BUTTON OPTIONS" Button configuration options may also be set by the \fBoption\fR command. The resource subclass is \f(CWButton\fR. The resource name is always \f(CWbutton\fR. .CS option add *TreeView.Button.Foreground white option add *TreeView.button.Background blue .CE The following are the configuration options available for buttons. .TP \fB\-activebackground \fIcolor\fR Sets the background color of active buttons. A button is made active when the mouse passes over it or by the \fBbutton activate\fR operation. .TP \fB\-activeforeground \fIcolor\fR Sets the foreground color of active buttons. A button is made active when the mouse passes over it or by the \fBbutton activate\fR operation. .TP \fB\-background \fIcolor\fR Sets the background of the button. The default is \f(CWwhite\fR. .TP \fB\-borderwidth \fIpixels\fR Sets the width of the 3\-D border around the button. The \fB\-relief\fR option determines if a border is to be drawn. The default is \f(CW1\fR. .TP \fB\-closerelief \fIrelief\fR Specifies the 3-D effect for the closed button. \fIRelief\fR indicates how the button should appear relative to the widget; for example, \f(CWraised\fR means the button should appear to protrude. The default is \f(CWsolid\fR. .TP \fB\-cursor \fIcursor\fR Sets the widget's cursor. The default cursor is \f(CW""\fR. .TP \fB\-foreground \fIcolor\fR Sets the foreground color of buttons. The default is \f(CWblack\fR. .TP \fB\-images \fIimages\fR Specifies images to be displayed for the button. \fIImages\fR is a list of two Tk images: the first image is displayed when the button is open, the second when it is closed. If the \fIimages\fR is the empty string, then a plus/minus gadget is drawn. The default is \f(CW""\fR. .TP \fB\-openrelief \fIrelief\fR Specifies the 3-D effect of the open button. \fIRelief\fR indicates how the button should appear relative to the widget; for example, \f(CWraised\fR means the button should appear to protrude. The default is \f(CWflat\fR. .TP \fB\-size \fIpixels\fR Sets the requested size of the button. The default is \f(CW0\fR. .RE .SH "COLUMN OPTIONS" Column configuration options may also be set by the \fBoption\fR command. The resource subclass is \f(CWColumn\fR. The resource name is the name of the column. .CS option add *TreeView.Column.Foreground white option add *TreeView.treeView.Background blue .CE The following configuration options are available for columns. .TP \fB\-background \fIcolor\fR Sets the background color of the column. This overrides the widget's \fB\-background\fR option. The default is \f(CWwhite\fR. .TP \fB\-borderwidth \fIpixels\fR Sets the width of the 3\-D border of the column. The \fB\-relief\fR option determines if a border is to be drawn. The default is \f(CW0\fR. .TP \fB\-edit \fIboolean\fR Indicates if the column's data fields can be edited. If \fIboolean\fR is false, the data fields in the column may not be edited. The default is \f(CWyes\fR. .TP \fB\-foreground \fIcolor\fR Specifies the foreground color of the column. You can override this for individual entries with the entry's \fB\-foreground\fR option. The default is \f(CWblack\fR. .TP \fB\-font \fIfontName\fR Sets the font for a column. You can override this for individual entries with the entry's \fB\-font\fR option. The default is \f(CW*-Helvetica-Bold-R-Normal-*-12-120-*\fR. .TP \fB\-hide \fIboolean\fR If \fIboolean\fR is true, the column is not displayed. The default is \f(CWyes\fR. .TP \fB\-justify \fIjustify\fR Specifies how the column data fields title should be justified within the column. This matters only when the column is wider than the data field to be display. \fIJustify\fR must be \f(CWleft\fR, \f(CWright\fR, or \f(CWcenter\fR. The default is \f(CWleft\fR. .TP \fB\-pad \fIpad\fR Specifies how much padding for the left and right sides of the column. \fIPad\fR is a list of one or two screen distances. If \fIpad\fR has two elements, the left side of the column 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(CW2\fR. .TP \fB\-relief \fIrelief\fR Specifies the 3-D effect of the column. \fIRelief\fR specifies how the column should appear relative to the widget; for example, \f(CWraised\fR means the column should appear to protrude. The default is \f(CWflat\fR. .TP \fB\-state \fIstate\fR Sets the state of the column. If \fIstate\fR is \f(CWdisable\fR then the column title can not be activated nor invoked. The default is \f(CWnormal\fR. .TP \fB\-title \fIstring\fR Sets the title for the column. The default is \f(CW""\fR. .TP \fB\-titleforeground \fIcolor\fR Sets the foreground color of the column title. The default is \f(CWblack\fR. .TP \fB\-titleshadow \fIcolor\fR Sets the color of the drop shadow of the column title. The default is \f(CW""\fR. .TP \fB\-width \fIpixels\fR Sets the requested width of the column. This overrides the computed with of the column. If \fIpixels\fR is 0, the width is computed as from the contents of the column. The default is \f(CW0\fR. .RE .SH "TEXT EDITING OPTIONS" Text edit window configuration options may also be set by the \fBoption\fR command. The resource class is \f(CWTreeViewEditor\fR. The resource name is always \f(CWedit\fR. .CS option add *TreeViewEditor.Foreground white option add *edit.Background blue .CE The following are the configuration options available for the text editing window. .TP \fB\-background \fIcolor\fR Sets the background of the text edit window. The default is \f(CWwhite\fR. .TP \fB\-borderwidth \fIpixels\fR Sets the width of the 3\-D border around the edit window. The \fB\-relief\fR option determines if a border is to be drawn. The default is \f(CW1\fR. .TP \fB\-exportselection \fIboolean\fR Indicates if the text selection is exported. If the edit window is exporting its selection then it will observe the standard X11 protocols for handling the selection. Selections are available as type \fBSTRING\fR. The default is \f(CWno\fR. .TP \fB\-relief \fIrelief\fR Specifies the 3-D effect of the edit window. \fIRelief\fR indicates how the background should appear relative to the edit window; for example, \f(CWraised\fR means the background should appear to protrude. The default is \f(CWsolid\fR. .TP \fB\-selectbackground \fIcolor\fR Sets the background of the selected text in the edit window. The default is \f(CWwhite\fR. .TP \fB\-selectborderwidth \fIpixels\fR Sets the width of the 3\-D border around the selected text in the edit window. The \fB\-selectrelief\fR option determines if a border is to be drawn. The default is \f(CW1\fR. .TP \fB\-selectforeground \fIcolor\fR Sets the foreground of the selected text in the edit window. The default is \f(CWwhite\fR. .TP \fB\-selectrelief \fIrelief\fR Specifies the 3-D effect of the selected text in the edit window. \fIRelief\fR indicates how the text should appear relative to the edit window; for example, \f(CWraised\fR means the text should appear to protrude. The default is \f(CWflat\fR. .RE .SH "DEFAULT BINDINGS" Tk automatically creates class bindings for treeviews that give them Motif-like behavior. Much of the behavior of a \fBtreeview\fR widget is determined by its \fB\-selectmode\fR option, which selects one of two ways of dealing with the selection. .PP If the selection mode is \fBsingle\fR, only one node can be selected at a time. Clicking button 1 on an node selects it and deselects any other selected item. .PP If the selection mode is \fBmultiple\fR, any number of entries may be selected at once, including discontiguous ranges. Clicking Control-Button-1 on a node entry toggles its selection state without affecting any other entries. Pressing Shift-Button-1 on a node entry selects it, extends the selection. .IP [1] In \fBextended\fR mode, the selected range can be adjusted by pressing button 1 with the Shift key down: this modifies the selection to consist of the entries between the anchor and the entry under the mouse, inclusive. The un-anchored end of this new selection can also be dragged with the button down. .IP [2] In \fBextended\fR mode, pressing button 1 with the Control key down starts a toggle operation: the anchor is set to the entry under the mouse, and its selection state is reversed. The selection state of other entries isn't changed. If the mouse is dragged with button 1 down, then the selection state of all entries between the anchor and the entry under the mouse is set to match that of the anchor entry; the selection state of all other entries remains what it was before the toggle operation began. .IP [3] If the mouse leaves the treeview window with button 1 down, the window scrolls away from the mouse, making information visible that used to be off-screen on the side of the mouse. The scrolling continues until the mouse re-enters the window, the button is released, or the end of the hierarchy is reached. .IP [4] Mouse button 2 may be used for scanning. If it is pressed and dragged over the \fBtreeview\fR widget, the contents of the hierarchy drag at high speed in the direction the mouse moves. .IP [5] If the Up or Down key is pressed, the location cursor (active entry) moves up or down one entry. If the selection mode is \fBbrowse\fR or \fBextended\fR then the new active entry is also selected and all other entries are deselected. In \fBextended\fR mode the new active entry becomes the selection anchor. .IP [6] In \fBextended\fR mode, Shift-Up and Shift-Down move the location cursor (active entry) up or down one entry and also extend the selection to that entry in a fashion similar to dragging with mouse button 1. .IP [7] The Left and Right keys scroll the \fBtreeview\fR widget view left and right by the width of the character \fB0\fR. Control-Left and Control-Right scroll the \fBtreeview\fR widget view left and right by the width of the window. Control-Prior and Control-Next also scroll left and right by the width of the window. .IP [8] The Prior and Next keys scroll the \fBtreeview\fR widget view up and down by one page (the height of the window). .IP [9] The Home and End keys scroll the \fBtreeview\fR widget horizontally to the left and right edges, respectively. .IP [10] Control-Home sets the location cursor to the the first entry, selects that entry, and deselects everything else in the widget. .IP [11] Control-End sets the location cursor to the the last entry, selects that entry, and deselects everything else in the widget. .IP [12] In \fBextended\fR mode, Control-Shift-Home extends the selection to the first entry and Control-Shift-End extends the selection to the last entry. .IP [13] In \fBmultiple\fR mode, Control-Shift-Home moves the location cursor to the first entry and Control-Shift-End moves the location cursor to the last entry. .IP [14] The space and Select keys make a selection at the location cursor (active entry) just as if mouse button 1 had been pressed over this entry. .IP [15] In \fBextended\fR mode, Control-Shift-space and Shift-Select extend the selection to the active entry just as if button 1 had been pressed with the Shift key down. .IP [16] In \fBextended\fR mode, the Escape key cancels the most recent selection and restores all the entries in the selected range to their previous selection state. .IP [17] Control-slash selects everything in the widget, except in \fBsingle\fR and \fBbrowse\fR modes, in which case it selects the active entry and deselects everything else. .IP [18] Control-backslash deselects everything in the widget, except in \fBbrowse\fR mode where it has no effect. .IP [19] The F16 key (labelled Copy on many Sun workstations) or Meta-w copies the selection in the widget to the clipboard, if there is a selection. .PP The behavior of \fBtreeview\fR widgets can be changed by defining new bindings for individual widgets or by redefining the class bindings. .SS WIDGET BINDINGS In addition to the above behavior, the following additional behavior is defined by the default widget class (TreeView) bindings. .IP \f(CW\fR Starts scanning. .IP \f(CW\fR Adjusts the scan. .IP \f(CW\fR Stops scanning. .IP \f(CW\fR Starts auto-scrolling. .IP \f(CW\fR Starts auto-scrolling .IP \f(CW\fR Moves the focus to the previous entry. .IP \f(CW\fR Moves the focus to the next entry. .IP \f(CW\fR Moves the focus to the previous sibling. .IP \f(CW\fR Moves the focus to the next sibling. .IP \f(CW\fR Moves the focus to first entry. Closed or hidden entries are ignored. .IP \f(CW\fR Move the focus to the last entry. Closed or hidden entries are ignored. .IP \f(CW\fR Closes the entry. It is not an error if the entry has no children. .IP \f(CW\fR Opens the entry, displaying its children. It is not an error if the entry has no children. .IP \f(CW\fR In "single" select mode this selects the entry. In "multiple" mode, it toggles the entry (if it was previous selected, it is not deselected). .IP \f(CW\fR Turns off select mode. .IP \f(CW\fR Sets the focus to the current entry. .IP \f(CW\fR Turns off select mode. .IP \f(CW\fR Moves to the next entry whose label starts with the letter typed. .IP \f(CW\fR Moves the focus to first entry. Closed or hidden entries are ignored. .IP \f(CW\fR Move the focus to the last entry. Closed or hidden entries are ignored. .IP \f(CW\fR Opens all entries. .IP \f(CW\fR Closes all entries (except root). .SS BUTTON BINDINGS Buttons have bindings. There are associated with the "all" bindtag (see the entry's -bindtag option). You can use the \fBbind\fR operation to change them. .IP \f(CW\fR Highlights the button of the current entry. .IP \f(CW\fR Returns the button back to its normal state. .IP \f(CW\fR Adjust the view so that the current entry is visible. .SS ENTRY BINDINGS Entries have default bindings. There are associated with the "all" bindtag (see the entry's -bindtag option). You can use the \fBbind\fR operation to modify them. .IP \f(CW\fR Highlights the current entry. .IP \f(CW\fR Returns the entry back to its normal state. .IP \f(CW\fR Sets the selection anchor the current entry. .IP \f(CW\fR Toggles the selection of the current entry. .IP \f(CW\fR For "multiple" mode only. Saves the current location of the pointer for auto-scrolling. Resets the selection mark. .IP \f(CW\fR For "multiple" mode only. Sets the selection anchor to the current entry. .IP \f(CW\fR For "multiple" mode only. Extends the selection. .IP \f(CW\fR Place holder. Does nothing. .IP \f(CW\fR Place holder. Does nothing. .IP \f(CW\fR Stop auto-scrolling. .IP \f(CW\fR For "multiple" mode only. Toggles and extends the selection. .IP \f(CW\fR Place holder. Does nothing. .IP \f(CW\fR Place holder. Does nothing. .IP \f(CW\fR Stops auto-scrolling. .IP \f(CW\fR ??? .IP \f(CW\fR Place holder. Does nothing. .IP \f(CW\fR Place holder. Does nothing. .SS COLUMN BINDINGS Columns have bindings too. They are associated with the column's "all" bindtag (see the column -bindtag option). You can use the \fBcolumn bind\fR operation to change them. .IP \f(CW\fR Highlights the current column title. .IP \f(CW\fR Returns the column back to its normal state. .IP \f(CW\fR Invokes the command (see the column's -command option) if one if specified. .SS COLUMN RULE BINDINGS .IP \f(CW\fR Highlights the current and activates the ruler. .IP \f(CW\fR Returns the column back to its normal state. Deactivates the ruler. .IP \f(CW\fR Sets the resize anchor for the column. .IP \f(CW\fR Sets the resize mark for the column. .IP \f(CW\fR Adjust the size of the column, based upon the resize anchor and mark positions. .SH EXAMPLE The \fBtreeview\fR command creates a new widget. .CS treeview .h \-bg white .CE A new Tcl command \f(CW.h\fR is also created. This command can be used to query and modify the \fBtreeview\fR widget. For example, to change the background color of the table to "green", you use the new command and the widget's \fBconfigure\fR operation. .CS # Change the background color. \&.h configure \-background "green" .CE By default, the \fBtreeview\fR widget will automatically create a new tree object to contain the data. The name of the new tree is the pathname of the widget. Above, the new tree object name is ".h". But you can use the \fB\-tree\fR option to specify the name of another tree. .CS # View the tree "myTree". \&.h configure \-tree "myTree" .CE When a new tree is created, it contains only a root node. The node is automatically opened. The id of the root node is always \f(CW0\fR (you can use also use the special id \f(CWroot\fR). The \fBinsert\fR operation lets you insert one or more new entries into the tree. The last argument is the node's \fIpathname\fR. .CS # Create a new entry named "myEntry" set id [\&.h insert end "myEntry"] .CE This appends a new node named "myEntry". It will positioned as the last child of the root of the tree (using the position "end"). You can supply another position to order the node within its siblings. .CS # Prepend "fred". set id [\&.h insert 0 "fred"] .CE Entry names do not need to be unique. By default, the node's label is its name. To supply a different text label, add the \fB\-label\fR option. .CS # Create a new node named "fred" set id [\&.h insert end "fred" -label "Fred Flintstone"] .CE The \fBinsert\fR operation returns the id of the new node. You can also use the \fBindex\fR operation to get this information. .CS # Get the id of "fred" \&.h index "fred" .CE To insert a node somewhere other than root, use the \fB\-at\fR switch. It takes the id of the node where the new child will be added. .CS # Create a new node "barney" in "fred". \&.h insert -at $id end "barney" .CE A pathname describes the path to an entry in the hierarchy. It's a list of entry names that compose the path in the tree. Therefore, you can also add "barney" to "fred" as follows. .CS # Create a new sub-entry of "fred" \&.h insert end "fred barney" .CE Every name in the list is ancestor of the next. All ancestors must already exist. That means that an entry "fred" is an ancestor of "barney" and must already exist. But you can use the \fB\-autocreate\fR configuration option to force the creation of ancestor nodes. .CS # Force the creation of ancestors. \&.h configure -autocreate yes \&.h insert end "fred barney wilma betty" .CE Sometimes the pathname is already separated by a character sequence rather than formed as a list. A file name is a good example of this. You can use the \fB\-separator\fR option to specify a separator string to split the path into its components. Each pathname inserted is automatically split using the separator string as a separator. Multiple separators are treated as one. .CS \&.h configure -separator / \&.h insert end "/usr/local/tcl/bin" .CE If the path is prefixed by extraneous characters, you can automatically trim it off using the \fB\-trim\fR option. It removed the string from the path before it is parsed. .CS \&.h configure -trim C:/windows -separator / \&.h insert end "C:/window/system" .CE You can insert more than one entry at a time with the \fBinsert\fR operation. This can be much faster than looping over a list of names. .CS # The slow way foreach f [glob $dir/*] { \&.h insert end $f } # The fast way eval .h insert end [glob $dir/*] .CE In this case, the \fBinsert\fR operation will return a list of ids of the new entries. .PP You can delete entries with the \fBdelete\fR operation. It takes one or more tags of ids as its argument. It deletes the entry and all its children. .CS \&.h delete $id .CE Entries have several configuration options. They control the appearance of the entry's icon and label. We have already seen the \fB\-label\fR option that sets the entry's text label. The \fBentry configure\fR operation lets you set or modify an entry's configuration options. .CS \&.h entry configure $id -color red -font fixed .CE You can hide an entry and its children using the \fB\-hide\fR option. .CS \&.h entry configure $id -hide yes .CE More that one entry can be configured at once. All entries specified are configured with the same options. .CS \&.h entry configure $i1 $i2 $i3 $i4 -color brown .CE An icon is displayed for each entry. It's a Tk image drawn to the left of the label. You can set the icon with the entry's \fB\-icons\fR option. It takes a list of two image names: one to represent the open entry, another when it is closed. .CS set im1 [image create photo -file openfolder.gif] set im2 [image create photo -file closefolder.gif] \&.h entry configure $id -icons "$im1 $im2" .CE If \fB\-icons\fR is set to the empty string, no icons are display. .PP If an entry has children, a button is displayed to the left of the icon. Clicking the mouse on this button opens or closes the sub-hierarchy. The button is normally a \f(CW+\fR or \f(CW\-\fR symbol, but can be configured in a variety of ways using the \fBbutton configure\fR operation. For example, the \f(CW+\fR and \f(CW\-\fR symbols can be replaced with Tk images. .CS set im1 [image create photo -file closefolder.gif] set im2 [image create photo -file downarrow.gif] \&.h button configure $id -images "$im1 $im2" \\ -openrelief raised -closerelief raised .CE Entries can contain an arbitrary number of \fIdata fields\fR. Data fields are name-value pairs. Both the value and name are strings. The entry's \fB\-data\fR option lets you set data fields. .CS \&.h entry configure $id -data {mode 0666 group users} .CE The \fB\-data\fR takes a list of name-value pairs. .PP You can display these data fields as \fIcolumns\fR in the \fBtreeview\fR widget. You can create and configure columns with the \fBcolumn\fR operation. For example, to add a new column to the widget, use the \fBcolumn insert\fR operation. The last argument is the name of the data field that you want to display. .CS \&.h column insert end "mode" .CE The column title is displayed at the top of the column. By default, it's is the field name. You can override this using the column's \fB\-title\fR option. .CS \&.h column insert end "mode" -title "File Permissions" .CE Columns have several configuration options. The \fBcolumn configure\fR operation lets you query or modify column options. .CS \&.h column configure "mode" -justify left .CE The \fB\-justify\fR option says how the data is justified within in the column. The \fB\-hide\fR option indicates whether the column is displayed. .CS \&.h column configure "mode" -hide yes .CE Entries can be selected by clicking on the mouse. Selected entries are drawn using the colors specified by the \fB\-selectforeground\fR and \fB\-selectbackground\fR configuration options. The selection itself is managed by the \fBselection\fR operation. .CS # Clear all selections \&.h selection clear 0 end # Select the root node \&.h selection set 0 .CE The \fBcurselection\fR operation returns a list of ids of all the selected entries. .CS set ids [\&.h curselection] .CE You can use the \fBget\fR operation to convert the ids to their pathnames. .CS set names [eval .h get -full $ids] .CE If a treeview is exporting its selection (using the \fB\-exportselection\fR option), then it will observe the standard X11 protocols for handling the selection. Treeview selections are available as type \fBSTRING\fR; the value of the selection will be the pathnames of the selected entries, separated by newlines. .PP The \fBtreeview\fR supports two modes of selection: \f(CWsingle\fR and \f(CWmultiple\fR. In single select mode, only one entry can be selected at a time, while multiple select mode allows several entries to be selected. The mode is set by the widget's \fB\-selectmode\fR option. .CS \&.h configure -selectmode "multiple" .CE You can be notified when the list of selected entries changes. The widget's \fB\-selectcommand\fR specifies a Tcl procedure that is called whenever the selection changes. .CS proc SelectNotify { widget } { set ids [\&$widget curselection] } \&.h configure -selectcommand "SelectNotify .h" .CE The widget supports the standard Tk scrolling and scanning operations. The \fBtreeview\fR can be both horizontally and vertically. You can attach scrollbars to the \fBtreeview\fR the same way as the listbox or canvas widgets. .CS scrollbar .xbar -orient horizontal -command ".h xview" scrollbar .ybar -orient vertical -command ".h yview" \&.h configure -xscrollcommand ".xbar set" \\ -yscrollcommand ".ybar set" .CE There are three different modes of scrolling: \f(CWlistbox\fR, \f(CWcanvas\fR, and \f(CWhierbox\fR. In \f(CWlistbox\fR mode, the last entry can always be scrolled to the top of the widget. In \f(CWhierbox\fR mode, the last entry is always drawn at the bottom of the widget. The scroll mode is set by the widget's \fB\-selectmode\fR option. .CS \&.h configure -scrollmode "listbox" .CE Entries can be programmatically opened or closed using the \fBopen\fR and \fBclose\fR operations respectively. .CS \&.h open $id \&.h close $id .CE When an entry is opened, a Tcl procedure can be automatically invoked. The \fB\-opencommand\fR option specifies this procedure. This procedure can lazily insert entries as needed. .CS proc AddEntries { dir } { eval .h insert end [glob -nocomplain $dir/*] } \&.h configure -opencommand "AddEntries %P" .CE Now when an entry is opened, the procedure \f(CWAddEntries\fR is called and adds children to the entry. Before the command is invoked, special "%" substitutions (like \fBbind\fR) are performed. Above, \f(CW%P\fR is translated to the pathname of the entry. .PP The same feature exists when an entry is closed. The \fB\-closecommand\fR option specifies the procedure. .CS proc DeleteEntries { id } { .h entry delete $id 0 end } \&.h configure -closecommand "DeleteEntries %#" .CE When an entry is closed, the procedure \f(CWDeleteEntries\fR is called and deletes the entry's children using the \fBentry delete\fR operation (\f(CW%#\fR is the id of entry). .SH KEYWORDS treeview, widget blt-2.4z.orig/man/vector.mann0100644000175000017500000011372207470566627014725 0ustar dokodoko'\" '\" 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. '\" .so man.macros .TH vector n BLT_VERSION BLT "BLT Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME vector \- Vector data type for Tcl .SH SYNOPSIS \fBvector create \fIvecName \fR?\fIvecName\fR...? ?\fIswitches\fR? .sp \fBvector destroy \fIvecName \fR?\fIvecName\fR...? .sp \fBvector expr \fIexpression\fR .sp \fBvector names \fR?\fIpattern\fR...? .BE .SH DESCRIPTION The \fBvector\fR command 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 INTRODUCTION A vector is simply an ordered set of numbers. The components of a vector are real numbers, indexed by counting numbers. .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. 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 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 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 \fBvector create \fIvecName\fR This creates a new vector \fIvecName\fR which initially has no components. .TP \fBvector 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 \fBvector 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 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 [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 \fBvector 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 \fBvector destroy \fIvecName\fR \fR?\fIvecName...\fR? .TP \fBvector 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 3c 6c 9c \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 .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 blt-2.4z.orig/man/watch.mann0100644000175000017500000001245607240160105014503 0ustar dokodoko'\" '\" 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. '\" '\" .so man.macros .TH watch n BLT_VERSION BLT "BLT Built-In Commands" .BS .SH NAME watch \- call Tcl procedures before and after each command .SH SYNOPSIS \fBwatch create\fR \fIwatchName\fR ?\fIoptions\fR? .sp \fBwatch activate\fR \fIwatchName\fR .sp \fBwatch deactivate\fR \fIwatchName\fR .sp \fBwatch delete\fR \fIwatchName\fR .sp \fBwatch configure\fR \fIwatchName\fR ?\fIoptions\fR .sp \fBwatch info\fR \fIwatchName\fR .sp \fBwatch names\fR .BE .SH DESCRIPTION The \fBwatch\fR command arranges for Tcl procedures to be invoked before and after the execution of each Tcl command. .SH INTRODUCTION When an error occurs in Tcl, the global variable \fIerrorInfo\fR will contain a stack-trace of the active procedures when the error occured. Sometimes, however, the stack trace is insufficient. You may need to know exactly where in the program's execution the error occured. In cases like this, a more general tracing facility would be useful. .PP The \fBwatch\fR command lets you designate Tcl procedures to be invoked before and after the execution of each Tcl command. This means you can display the command line and its results for each command as it executes. Another use is to profile your Tcl commands. You can profile any Tcl command (like \fBif\fR and \fBset\fR), not just Tcl procedures. .SH EXAMPLE The following example use \fBwatch\fR to trace Tcl commands (printing to standard error) both before and after they are executed. .CS proc preCmd { level command argv } { set name [lindex $argv 0] puts stderr "$level $name => $command" } proc postCmd { level command argv retcode results } { set name [lindex $argv 0] puts stderr "$level $name => $argv\n<= ($retcode) $results" } watch create trace \\ -postcmd postCmd -precmd preCmd .CE .SH "OPERATIONS" The following operations are available for the \fBwatch\fR command: .TP \fBwatch activate \fIwatchName\fR Activates the watch, causing Tcl commands the be traced to the maximum depth selected. .TP \fBwatch create \fIwatchName\fR ?\fIoptions\fR?... Creates a new watch \fIwatchName\fR. It's an error if another watch \fIwatchName\fR already exists and an error message will be returned. \fIOptions\fR may have any of the values accepted by the \fBwatch configure\fR command. This command returns the empty string. .TP \fBwatch configure \fIwatchName\fR ?\fIoptions...\fR? Queries or modifies the configuration options of the watch \fIwatchName\fR. \fIWatchName\fR is the name of a watch. \fIOptions\fR may have any of the following values: .RS .TP \fB\-active \fIboolean\fR Specifies if the watch is active. By default, watches are active when created. .TP \fB\-postcmd \fIstring\fR Specifies a Tcl procedure to be called immediately after each Tcl command. \fIString\fR is name of a Tcl procedure and any extra arguments to be passed to it. Before \fIstring\fR is invoked, five more arguments are appended: 1) the current level 2) the current command line 3) a list containing the command after substitutions and split into words 4) the return code of the command, and 5) the results of the command. The return status of the postcmd procedure is always ignored. .TP \fB\-precmd \fIstring\fR Specifies a Tcl procedure to be called immediately before each Tcl command. \fIString\fR is name of a Tcl procedure and any extra arguments to be passed to it. Before \fIstring\fR is invoked, three arguments are appended: 1) the current level 2) the current command line, and 3) a list containing the command after substitutions and split into words. The return status of the \fB\-precmd\fR procedure is always ignored. .TP \fB\-maxlevel \fInumber\fR Specifies the maximum evaluation depth to watch Tcl commands. The default maximum level is 10000. .RE .TP \fBwatch deactivate \fIwatchName\fR Deactivates the watch. The \fB\-precmd\fR and \fB\-postcmd\fR procedures will no longer be invoked. .TP \fBwatch info \fIwatchName\fR Returns the configuration information associated with the watch \fIwatchName\fR. \fIWatchName\fR is the name of a watch. .TP \fBwatch names\fR ?\fIstate\fR? Lists the names of the watches for a given state. \fIState\fR may be one of the following: \f(CWactive\fR, \f(CWidle\fR, or \f(CWignore\fR. If a \fIstate\fR argument isn't specified, all watches are listed. .RE .SH KEYWORDS debug, profile blt-2.4z.orig/man/winop.mann0100644000175000017500000001203107240160105014516 0ustar dokodoko'\" '\" 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. '\" '\" Window command created by George Howlett. '\" .so man.macros .TH winop n BLT_VERSION BLT "BLT Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME winop \- Perform assorted window operations .SH SYNOPSIS \fBwinop lower\fR ?\fIwindow\fR?... .sp \fBwinop map\fR ?\fIwindow\fR?... .sp \fBwinop move \fIwindow x y\fR .sp \fBwinop raise\fR ?\fIwindow\fR?... .sp \fBwinop snap \fIwindow photoName\fR .sp \fBwinop unmap\fR ?\fIwindow\fR?... .sp \fBwinop warpto\fR ?\fIwindow\fR? .BE .SH DESCRIPTION The \fBwinop\fR command performs various window operations on Tk windows using low-level Xlib function calls to work around window manager pecularities. .SH INTRODUCTION Tk has several commands for manipulating its windows: \fBraise\fR, \fBlower\fR, \fBwm\fR, etc. These commands ask the window manager to perform operations on Tk windows. In some cases, a particular window manager won't perform the operation as expected. .PP For example, if you positioned a toplevel window using \fBwm geometry\fR, the window may not actually be at those particular coordinates. The position of the window may be offset by dimensions of the title bar added by the window manager. .PP In situations like these, the \fBwinop\fR command can be used to workaround these difficulties. Instead, it makes low-level Xlib (such \fBXRaiseWindow\fR and \fBXMapWindow\fR) calls to perform these operations. .CS toplevel .top wm withdraw .top # Set the geometry to make the window manager # place the window. wm geometry .top +100+100 # Move the window to the desired location # and "update" to force the window manager # to recognize it. winop move .top 100 100 update wm deiconify .top winop move .top 100 100 .CE .SH OPERATIONS The following operations are available for the \fBwinop\fR command: .TP \fBwinop lower\fR ?\fIwindow\fR?... Lowers \fIwindow\fR to the bottom of the X window stack. \fIWindow\fR is the path name of a Tk window. .TP \fBwinop map\fR ?\fIwindow\fR?... Maps \fIwindow\fR on the screen. \fIWindow\fR is the path name of a Tk window. If \fIwindow\fR is already mapped, this command has no effect. .TP \fBwinop move \fIwindow x y\fR Move \fIwindow\fR to the screen location specified by \fIx\fR and \fIy\fR. \fIWindow\fR is the path name of a Tk window, while \fIx\fR and \fIy\fR are screen coordinates. This command returns the empty string. .TP \fBwinop raise\fR ?\fIwindow\fR?... Raises \fIwindow\fR to the top of the X window stack. \fIWindow\fR must be a valid path name of a Tk window. This command returns the empty string. .TP \fBwinop snap \fIwindow photoName\fR Takes a snapshot of the \fIwindow\fR and stores the contents in the photo image \fIphotoName\fR. \fIWindow\fR is the valid path name of a Tk window which must be totally visible (unobscured). \fIPhotoName\fR is the name of a Tk photo image which must already exist. This command can fail if the window is obscured in any fashion, such as covered by another window or partially offscreen. In that case, an error message is returned. .TP \fBwinop unmap\fR ?\fIwindow\fR?... Unmaps \fIwindow\fR from the screen. \fIWindow\fR is the path name of a Tk window. .TP \fBwinop warpto\fR ?\fIwindow\fR? Warps the pointer to \fIwindow\fR. \fIWindow\fR is the path name of a Tk window which must be mapped. If \fIwindow\fR is in the form \fI@x,y\fR, where \fIx\fR and \fIy\fR are root screen coordinates, the pointer is warped to that location on the screen. .sp [\fII've never heard a good case for warping the pointer in an application. It can be useful for testing, but in applications, it's always a bad idea. Simply stated, the user owns the pointer, not the application. If you have an application that needs it, I'd like to hear about it.\fR] .sp If no \fIwindow\fR argument is present the current location of the pointer is returned. The location is returned as a list in the form "\fIx y\fR", where \fIx\fR and \fIy\fR are the current coordinates of the pointer. .SH KEYWORDS window, map, raise, lower, pointer, warp blt-2.4z.orig/src/0042755000175000017500000000000007553201250012537 5ustar dokodokoblt-2.4z.orig/src/shared/0042755000175000017500000000000007553201250014005 5ustar dokodokoblt-2.4z.orig/src/shared/Makefile.in0100644000175000017500000002153107470301617016055 0ustar dokodoko# ------------------------------------------------------------------------ # Makefile for shared version of BLT library # ------------------------------------------------------------------------ SHLIB_SUFFIX = @SHLIB_SUFFIX@ version = @BLT_MAJOR_VERSION@@BLT_MINOR_VERSION@ # ------------------------------------------------------------------------ # C Compiler options # ------------------------------------------------------------------------ CC = @CC@ CFLAGS = @CFLAGS@ EXTRA_CFLAGS = @GCCFLAGS@ @SHLIB_CFLAGS@ DEFINES = @DEFINES@ DEF_BLTINIT = -DBLT_LIBRARY=\"$(scriptdir)\" SHLIB_LD_FLAGS = @SHLIB_LD_FLAGS@ @LD_RUN_PATH@ SHLIB_TCL_ONLY_LIB_SPECS = @SHLIB_TCL_ONLY_LIB_SPECS@ SHLIB_LIB_SPECS = @SHLIB_LIB_SPECS@ SHLIB_LD = @SHLIB_LD@ LDFLAGS = @LDFLAGS@ @LD_RUN_PATH@ prefix = @prefix@ exec_prefix = @exec_prefix@ libdir = @libdir@ bindir = $(exec_prefix)/bin srcdir = @srcdir@/.. instdirs = $(exec_prefix) $(libdir) scriptdir = @BLT_LIBRARY@ LIBS = @LIB_SPECS@ @EXTRA_LIB_SPECS@ TCL_ONLY_LIB_SPECS = @TCL_ONLY_LIB_SPECS@ @EXTRA_LIB_SPECS@ # ------------------------------------------------------------------------ # Don't edit anything beyond this point # ------------------------------------------------------------------------ N_OBJS = bltTed.o V3_OBJS = bltTri.o bltGrMt.o TK_OBJS = tkButton.o tkFrame.o bltScrollbar.o GRAPH_OBJS = bltGrAxis.o \ bltGrBar.o \ bltGrElem.o \ bltGrGrid.o \ bltGrHairs.o \ bltGrLegd.o \ bltGrLine.o \ bltGrMarker.o \ bltGrMisc.o \ bltGrPen.o \ bltGrPs.o \ bltGraph.o TCL_ONLY_OBJS = bltAlloc.o \ bltArrayObj.o \ bltBgexec.o \ bltChain.o \ bltDebug.o \ bltHash.o \ bltList.o \ bltNsUtil.o \ bltParse.o \ bltPool.o \ bltSpline.o \ bltSwitch.o \ bltTree.o \ bltTreeCmd.o \ bltUnixPipe.o \ bltUtil.o \ bltVector.o \ bltVecMath.o \ bltVecCmd.o \ bltVecObjCmd.o \ bltWatch.o OBJS = $(GRAPH_OBJS) \ $(TCL_ONLY_OBJS) \ bltBeep.o \ bltBind.o \ bltBitmap.o \ bltBusy.o \ bltCanvEps.o \ bltColor.o \ bltConfig.o \ bltContainer.o \ bltCutbuffer.o \ bltDragdrop.o \ bltHierbox.o \ bltHtext.o \ bltImage.o \ bltUnixImage.o \ bltPs.o \ bltTable.o \ bltTabnotebook.o \ bltTabset.o \ bltText.o \ bltTile.o \ bltTreeView.o \ bltTreeViewCmd.o \ bltTreeViewColumn.o \ bltTreeViewEdit.o \ bltTreeViewStyle.o \ bltUnixDnd.o \ bltWindow.o \ bltObjConfig.o \ bltWinop.o \ $(TK_OBJS) $(N_OBJS) INCLUDES = -I.. -I$(srcdir) -I$(srcdir)/.. @INCLUDES@ CC_SWITCHES = $(EXTRA_CFLAGS) $(CFLAGS) $(DEFINES) $(INCLUDES) INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_ROOT = SHELL = /bin/sh RM = rm -f LN_S = @LN_S@ bltwish = bltwish$(version) bltsh = bltsh$(version) lib_so = libBLT$(version)$(SHLIB_SUFFIX) tcl_only_lib_so = libBLTlite$(version)$(SHLIB_SUFFIX) all: build_lib build_demo build_demo: $(bltwish) $(bltsh) $(bltwish): $(lib_so) $(RM) $(bltwish) $(CC) $(CC_SWITCHES) $(LDFLAGS) -o $(bltwish) \ $(srcdir)/bltUnixMain.c $(lib_so) $(LIBS) $(bltsh): $(tcl_only_lib_so) $(RM) $(bltsh) $(CC) $(CC_SWITCHES) $(LDFLAGS) -DTCL_ONLY -o $(bltsh) \ $(srcdir)/bltUnixMain.c $(tcl_only_lib_so) \ $(TCL_ONLY_LIB_SPECS) build_lib: $(lib_so) $(tcl_only_lib_so) $(lib_so): $(OBJS) $(CC) -c $(CC_SWITCHES) -DBLT_LIBRARY=\"$(scriptdir)\" \ $(srcdir)/bltInit.c $(RM) $@ $(SHLIB_LD) $(SHLIB_LD_FLAGS) -o $@ bltInit.o $(OBJS) \ $(SHLIB_LIB_SPECS) $(tcl_only_lib_so): $(TCL_ONLY_OBJS) $(CC) -c $(CC_SWITCHES) -DTCL_ONLY -DBLT_LIBRARY=\"$(scriptdir)\" \ $(srcdir)/bltInit.c $(RM) $@ $(SHLIB_LD) $(SHLIB_LD_FLAGS) -o $@ bltInit.o $(TCL_ONLY_OBJS) \ $(SHLIB_TCL_ONLY_LIB_SPECS) install: mkdirs install-lib install-demo install-demo: $(bltwish) $(INSTALL) -m 0755 bltwish$(version) $(INSTALL_ROOT)$(bindir) $(INSTALL) -m 0755 bltsh$(version) $(INSTALL_ROOT)$(bindir) install-lib: $(lib_so) $(tcl_only_lib_so) $(INSTALL) -m 0755 $(lib_so) $(INSTALL_ROOT)$(libdir) $(INSTALL) -m 0755 $(tcl_only_lib_so) $(INSTALL_ROOT)$(libdir) mkdirs: @for i in $(instdirs) ; do \ if test -d $(INSTALL_ROOT)$$i ; then \ : ;\ else \ echo " mkdir $(INSTALL_ROOT)$$i" ; \ mkdir $(INSTALL_ROOT)$$i ; \ fi ; \ done clean: $(RM) $(OBJS) $(lib_so) $(tcl_only_lib_so) $(bltwish) $(bltsh) \ *pure* .pure* distclean: clean $(RM) $(srcdir)/*.bak $(srcdir)/*\~ $(srcdir)/"#"* # ------------------------------------------------------------------------ # in lieu of viewpath-ing... # bltAlloc.o: $(srcdir)/bltAlloc.c $(CC) -c $(CC_SWITCHES) $? bltArrayObj.o: $(srcdir)/bltArrayObj.c $(CC) -c $(CC_SWITCHES) $? bltBeep.o: $(srcdir)/bltBeep.c $(CC) -c $(CC_SWITCHES) $? bltBgexec.o: $(srcdir)/bltBgexec.c $(CC) -c $(CC_SWITCHES) $? bltBind.o: $(srcdir)/bltBind.c $(CC) -c $(CC_SWITCHES) $? bltBitmap.o: $(srcdir)/bltBitmap.c $(CC) -c $(CC_SWITCHES) $? bltBusy.o: $(srcdir)/bltBusy.c $(CC) -c $(CC_SWITCHES) $? bltCanvEps.o: $(srcdir)/bltCanvEps.c $(CC) -c $(CC_SWITCHES) $? bltColor.o: $(srcdir)/bltColor.c $(CC) -c $(CC_SWITCHES) $? bltConfig.o: $(srcdir)/bltConfig.c $(CC) -c $(CC_SWITCHES) $? bltObjConfig.o: $(srcdir)/bltObjConfig.c $(CC) -c $(CC_SWITCHES) $? bltContainer.o: $(srcdir)/bltContainer.c $(CC) -c $(CC_SWITCHES) $? bltCutbuffer.o: $(srcdir)/bltCutbuffer.c $(CC) -c $(CC_SWITCHES) $? bltDebug.o: $(srcdir)/bltDebug.c $(CC) -c $(CC_SWITCHES) $? bltDragdrop.o: $(srcdir)/bltDragdrop.c $(CC) -c $(CC_SWITCHES) $? bltUnixDnd.o: $(srcdir)/bltUnixDnd.c $(CC) -c $(CC_SWITCHES) $? bltGrAxis.o: $(srcdir)/bltGrAxis.c $(CC) -c $(CC_SWITCHES) $? bltGrBar.o: $(srcdir)/bltGrBar.c $(CC) -c $(CC_SWITCHES) $? bltGrElem.o: $(srcdir)/bltGrElem.c $(CC) -c $(CC_SWITCHES) $? bltGrGrid.o: $(srcdir)/bltGrGrid.c $(CC) -c $(CC_SWITCHES) $? bltGrHairs.o: $(srcdir)/bltGrHairs.c $(CC) -c $(CC_SWITCHES) $? bltGrLegd.o: $(srcdir)/bltGrLegd.c $(CC) -c $(CC_SWITCHES) $? bltGrLine.o: $(srcdir)/bltGrLine.c $(CC) -c $(CC_SWITCHES) $? bltGrMisc.o: $(srcdir)/bltGrMisc.c $(CC) -c $(CC_SWITCHES) $? bltGrPen.o: $(srcdir)/bltGrPen.c $(CC) -c $(CC_SWITCHES) $? bltGrPs.o: $(srcdir)/bltGrPs.c $(CC) -c $(CC_SWITCHES) $? bltGrMarker.o: $(srcdir)/bltGrMarker.c $(CC) -c $(CC_SWITCHES) $? bltGrMt.o: $(srcdir)/bltGrMt.c $(CC) -c $(CC_SWITCHES) $? bltGrCont.o: $(srcdir)/bltGrCont.c $(CC) -c $(CC_SWITCHES) $? bltGraph.o: $(srcdir)/bltGraph.c $(CC) -c $(CC_SWITCHES) $? bltHash.o: $(srcdir)/bltHash.c $(CC) -c $(CC_SWITCHES) $? bltHierbox.o: $(srcdir)/bltHierbox.c $(CC) -c $(CC_SWITCHES) $? bltHtext.o: $(srcdir)/bltHtext.c $(CC) -c $(CC_SWITCHES) $? bltImage.o: $(srcdir)/bltImage.c $(CC) -c $(CC_SWITCHES) $? bltUnixImage.o: $(srcdir)/bltUnixImage.c $(CC) -c $(CC_SWITCHES) $? bltList.o: $(srcdir)/bltList.c $(CC) -c $(CC_SWITCHES) $? bltChain.o: $(srcdir)/bltChain.c $(CC) -c $(CC_SWITCHES) $? bltNsUtil.o: $(srcdir)/bltNsUtil.c $(CC) -c $(CC_SWITCHES) $? bltParse.o: $(srcdir)/bltParse.c $(CC) -c $(CC_SWITCHES) $? bltPool.o: $(srcdir)/bltPool.c $(CC) -c $(CC_SWITCHES) $? bltPs.o: $(srcdir)/bltPs.c $(CC) -c $(CC_SWITCHES) $? bltSpline.o: $(srcdir)/bltSpline.c $(CC) -c $(CC_SWITCHES) $? bltSwitch.o: $(srcdir)/bltSwitch.c $(CC) -c $(CC_SWITCHES) $? bltTable.o: $(srcdir)/bltTable.c $(CC) -c $(CC_SWITCHES) $? bltTabset.o: $(srcdir)/bltTabset.c $(CC) -c $(CC_SWITCHES) $? bltTabnotebook.o: $(srcdir)/bltTabnotebook.c $(CC) -c $(CC_SWITCHES) $? bltTed.o: $(srcdir)/bltTed.c $(CC) -c $(CC_SWITCHES) $? bltText.o: $(srcdir)/bltText.c $(CC) -c $(CC_SWITCHES) $? bltTile.o: $(srcdir)/bltTile.c $(CC) -c $(CC_SWITCHES) $? bltTree.o: $(srcdir)/bltTree.c $(CC) -c $(CC_SWITCHES) $? bltTreeCmd.o: $(srcdir)/bltTreeCmd.c $(CC) -c $(CC_SWITCHES) $? bltTreeView.o: $(srcdir)/bltTreeView.c $(CC) -c $(CC_SWITCHES) $? bltTreeViewCmd.o: $(srcdir)/bltTreeViewCmd.c $(CC) -c $(CC_SWITCHES) $? bltTreeViewColumn.o: $(srcdir)/bltTreeViewColumn.c $(CC) -c $(CC_SWITCHES) $? bltTreeViewEdit.o: $(srcdir)/bltTreeViewEdit.c $(CC) -c $(CC_SWITCHES) $? bltTreeViewStyle.o: $(srcdir)/bltTreeViewStyle.c $(CC) -c $(CC_SWITCHES) $? bltTri.o: $(srcdir)/bltTri.c $(CC) -c $(CC_SWITCHES) $? bltVector.o: $(srcdir)/bltVector.c $(CC) -c $(CC_SWITCHES) $? bltVecObjCmd.o: $(srcdir)/bltVecObjCmd.c $(CC) -c $(CC_SWITCHES) $? bltVecCmd.o: $(srcdir)/bltVecCmd.c $(CC) -c $(CC_SWITCHES) $? bltVecMath.o: $(srcdir)/bltVecMath.c $(CC) -c $(CC_SWITCHES) $? bltWatch.o: $(srcdir)/bltWatch.c $(CC) -c $(CC_SWITCHES) $? bltWindow.o: $(srcdir)/bltWindow.c $(CC) -c $(CC_SWITCHES) $? bltWinop.o: $(srcdir)/bltWinop.c $(CC) -c $(CC_SWITCHES) $? bltUnixPipe.o: $(srcdir)/bltUnixPipe.c $(CC) -c $(CC_SWITCHES) $? bltUtil.o: $(srcdir)/bltUtil.c $(CC) -c $(CC_SWITCHES) $? tkButton.o: $(srcdir)/tkButton.c $(CC) -c $(CC_SWITCHES) $? tkFrame.o: $(srcdir)/tkFrame.c $(CC) -c $(CC_SWITCHES) $? tkMenubutton.o: $(srcdir)/tkMenubutton.c $(CC) -c $(CC_SWITCHES) $? bltScrollbar.o: $(srcdir)/bltScrollbar.c $(CC) -c $(CC_SWITCHES) $? blt-2.4z.orig/src/Makefile-cyg.in0100644000175000017500000001525507514405104015370 0ustar dokodoko # ------------------------------------------------------------------------ # Makefile for static version of BLT library # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ # C Compiler options # ------------------------------------------------------------------------ BLT_LIBRARY = @BLT_LIBRARY@ TCLLIBPATH = @TCL_LIB_DIR@/tcl@TCL_VERSION@ CC = @CC@ CFLAGS = @CFLAGS@ DEFINES = @DEFINES@ -DWIN32 EXTRA_CFLAGS = @GCCFLAGS@ LDFLAGS = @LDFLAGS@ @LD_RUN_PATH@ SHLIB_LD = @SHLIB_LD@ SHLIB_LD_FLAGS = @SHLIB_LD_FLAGS@ version = @BLT_MAJOR_VERSION@@BLT_MINOR_VERSION@ cyg_prefix = @BLT_LIB_PREFIX@ # ------------------------------------------------------------------------ # Source and targer installation directories # ------------------------------------------------------------------------ bindir = $(exec_prefix)/bin exec_prefix = @exec_prefix@ incdir = $(prefix)/include libdir = @libdir@ scriptdir = @BLT_LIBRARY@ prefix = @prefix@ srcdir = @srcdir@ instdirs = $(prefix) $(exec_prefix) $(bindir) $(scriptdir) $(libdir) $(incdir) # ------------------------------------------------------------------------ # Directories containing Tcl and Tk include files and libraries # ------------------------------------------------------------------------ INCLUDES = -I. -I$(srcdir) -I$(srcdir)/../win @INCLUDES@ # ------------------------------------------------------------------------ # Libraries directives for Tcl, Tk, X11, and BLT # ------------------------------------------------------------------------ LIBS = @LIB_SPECS@ @EXTRA_LIB_SPECS@ TCL_ONLY_LIBS = @TCL_ONLY_LIB_SPECS@ @EXTRA_LIB_SPECS@ # ------------------------------------------------------------------------ # You don't need to edit anything beyond this point # ------------------------------------------------------------------------ N_OBJS = bltTed.o V3_OBJS = bltTri.o bltGrMt.o TK_OBJS = tkButton.o tkFrame.o tkScrollbar.o GRAPH_OBJS = bltGrAxis.o \ bltGrBar.o \ bltGrElem.o \ bltGrGrid.o \ bltGrHairs.o \ bltGrLegd.o \ bltGrLine.o \ bltGrMarker.o \ bltGrMisc.o \ bltGrPen.o \ bltGrPs.o \ bltGraph.o TCL_ONLY_OBJS = bltAlloc.o \ bltArrayObj.o \ bltBgexec.o \ bltChain.o \ bltDebug.o \ bltHash.o \ bltList.o \ bltNsUtil.o \ bltParse.o \ bltPool.o \ bltSpline.o \ bltSwitch.o \ bltTree.o \ bltTreeCmd.o \ bltUtil.o \ bltVecCmd.o \ bltVecMath.o \ bltVecObjCmd.o \ bltVector.o \ bltWatch.o \ bltWinPipe.o \ bltWinUtil.o \ bltWinDde.o \ pure_api.o DEMO_OBJS = tkConsole.o bltWinMain.o OBJS = $(GRAPH_OBJS) \ $(TCL_ONLY_OBJS) \ bltBeep.o \ bltBind.o \ bltBitmap.o \ bltBusy.o \ bltCanvEps.o \ bltConfig.o \ bltContainer.o \ bltDragdrop.o \ bltHierbox.o \ bltHtext.o \ bltImage.o \ bltWinImage.o \ bltPs.o \ bltTable.o \ bltTabnotebook.o \ bltTabset.o \ bltText.o \ bltTile.o \ bltTreeView.o \ bltTreeViewCmd.o \ bltTreeViewEdit.o \ bltTreeViewColumn.o \ bltTreeViewStyle.o \ bltWinDraw.o \ bltWinPrnt.o \ bltWindow.o \ bltObjConfig.o \ bltWinop.o \ $(TK_OBJS) $(N_OBJS) NOT_YET = bltContainer.o bltCutBuffer.o bltColor.o # GNU Make-specific macro SRCS = $(patsubst %.o,$(srcdir)/%.c,$(OBJS)) bltwish = ${cyg_prefix}bltwish$(version).exe bltsh = ${cyg_prefix}bltsh$(version).exe headers = $(srcdir)/blt.h \ $(srcdir)/bltBind.h \ $(srcdir)/bltChain.h \ bltHash.h \ $(srcdir)/bltList.h \ $(srcdir)/bltPool.h \ $(srcdir)/bltTree.h \ $(srcdir)/bltVector.h lib_a = libBLT$(version).a tcl_only_lib_a = libBLTlite$(version).a lib_so = $(cyg_prefix)BLT$(version).dll tcl_only_lib_so = $(cyg_prefix)BLTlite$(version).dll CC_SWITCHES = $(EXTRA_CFLAGS) $(CFLAGS) $(DEFINES) $(INCLUDES) INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_ROOT = RANLIB = @RANLIB@ SHELL = /bin/sh AR = ar rc RM = rm -f LINT = lint LINTFLAGS = -axhbns XREF = cxref XREFFLAGS = -dltR LN_S = @LN_S@ VPATH = $(srcdir) all: $(tcl_only_lib_so) $(lib_so) $(bltsh) $(bltwish) $(bltwish): $(lib_a) $(srcdir)/tkConsole.c $(srcdir)/bltWinMain.c $(RM) $(bltwish) $(CC) $(CC_SWITCHES) $(LDFLAGS) -o $(bltwish) \ -DTCLLIBPATH=\"$(TCLLIBPATH)\" \ $(srcdir)/bltWinMain.c $(srcdir)/tkConsole.c \ $(lib_a) $(LIBS) $(bltsh): $(tcl_only_lib_a) $(srcdir)/bltWinMain.c $(RM) $(bltsh) $(CC) $(CC_SWITCHES) $(LDFLAGS) -DTCL_ONLY -o $(bltsh) \ -DTCLLIBPATH=\"$(TCLLIBPATH)\" \ $(srcdir)/bltWinMain.c $(tcl_only_lib_a) $(TCL_ONLY_LIBS) $(lib_a): $(OBJS) $(srcdir)/bltInit.c $(CC) -c $(CC_SWITCHES) -DBLT_LIBRARY=\"$(BLT_LIBRARY)\" \ $(srcdir)/bltInit.c $(RM) $@ $(AR) $@ $(OBJS) bltInit.o $(RANLIB) $@ $(lib_so): $(OBJS) $(CC) -c $(CC_SWITCHES) -DBLT_LIBRARY=\"$(BLT_LIBRARY)\" \ $(srcdir)/bltInit.c $(RM) $@ $(SHLIB_LD) $(SHLIB_LD_FLAGS) -o $@ bltInit.o $(OBJS) $(LIBS) \ $(EXTRA_SHLIB_FLAGS) $(tcl_only_lib_a): $(TCL_ONLY_OBJS) $(srcdir)/bltInit.c $(CC) -c $(CC_SWITCHES) -DTCL_ONLY -DBLT_LIBRARY=\"$(BLT_LIBRARY)\" \ $(srcdir)/bltInit.c $(RM) $@ $(AR) $@ $(TCL_ONLY_OBJS) bltInit.o $(RANLIB) $@ $(tcl_only_lib_so): $(TCL_ONLY_OBJS) $(srcdir)/bltInit.c $(CC) -c $(CC_SWITCHES) -DTCL_ONLY -DBLT_LIBRARY=\"$(BLT_LIBRARY)\" \ $(srcdir)/bltInit.c $(RM) $@ $(SHLIB_LD) $(SHLIB_LD_FLAGS) -o $@ bltInit.o $(TCL_ONLY_OBJS) \ $(TCL_ONLY_LIBS) install: mkdirs install-lib install-demo install-headers install-demo: $(bltwish) $(bltsh) $(INSTALL) -m 0755 $(bltwish) $(INSTALL_ROOT)$(bindir) $(INSTALL) -m 0755 $(bltsh) $(INSTALL_ROOT)$(bindir) install-lib: $(lib_a) $(tcl_only_lib_a) $(lib_so) $(tcl_only_lib_so) $(INSTALL_DATA) $(lib_a) $(INSTALL_ROOT)$(libdir) $(RANLIB) $(INSTALL_ROOT)$(libdir)/$(lib_a) $(INSTALL_DATA) $(tcl_only_lib_a) $(INSTALL_ROOT)$(libdir) $(RANLIB) $(INSTALL_ROOT)$(libdir)/$(tcl_only_lib_a) $(INSTALL) -m 0755 $(lib_so) $(INSTALL_ROOT)$(bindir) $(INSTALL) -m 0755 $(tcl_only_lib_so) $(INSTALL_ROOT)$(bindir) mkdirs: @for i in $(instdirs) ; do \ if test -d $(INSTALL_ROOT)$$i ; then \ : ; \ else \ echo " mkdir $(INSTALL_ROOT)$$i" ; \ mkdir $(INSTALL_ROOT)$$i ; \ fi ; \ done install-headers: @for i in $(headers) ; do \ echo "installing $$i..." ; \ $(INSTALL_DATA) -m 0444 $$i $(INSTALL_ROOT)$(incdir) ; \ done lint: $(LINT) $(LINTFLAGS) $(DEFINES) $(INCLUDES) $(SRCS) xref: $(XREF) $(XREFFLAGS) $(DEFINES) $(INCLUDES) $(SRCS) clean: $(RM) $(OBJS) bltInit.o $(lib_a) $(tcl_only_lib_a) \ $(lib_so) $(tcl_only_lib_so) \ $(bltsh)* $(bltwish)* .pure* *~ distclean: clean $(RM) $(srcdir)/*.bak $(srcdir)/*\~ $(srcdir)/"#"* Makefile $(RM) bltConfig.h bltHash.h Makefile TAGS .c.o: $(CC) -c $(CC_SWITCHES) $< blt-2.4z.orig/src/Makefile.bc0100644000175000017500000002233307526635202014570 0ustar dokodoko # ------------------------------------------------------------------------ # Makefile for BLT library using BCC55. # ------------------------------------------------------------------------ .SUFFIXES: .obj .c !include ..\win\makedefs prefix = C:\Program Files\Tcl exec_prefix = $(prefix) includedir = $(prefix)\include bindir = $(prefix)\bin libdir = $(prefix)\lib scriptdir = $(libdir)\blt$(BLT_VERSION) BLT_LIBRARY = $(libdir)\blt$(BLT_VERSION) TCLLIBPATH = $(libdir)\tcl$(v1) SHLIB_SUFFIX = .dll SHELL = bash.exe RM = -del TOOLS32 = c:\Borland\BCC55 AR = $(TOOLS32)\bin\implib.exe LD = $(TOOLS32)\bin\ilink32.exe CC = $(TOOLS32)\bin\bcc32.exe rc32 = $(TOOLS32)\bin\rc.exe !if ($(WITH_JPEG) == 0) EXTRA_DEFINES = !endif !if ($(WITH_JPEG) == 1) EXTRA_DEFINES = -DHAVE_JPEGLIB_H=1 JPEGDIR = $(srcdir)\..\..\jpeg-6b JPEGLIB = $(JPEGDIR)\libjpeg.lib JPEGINC = $(JPEGDIR) !endif !if ($(WITH_JPEG) == 2) EXTRA_DEFINES = -DHAVE_IJL_H=1 JPEGDIR = c:\Program\ Files\Intel\IJL JPEGLIB = $(JPEGDIR)\lib\ijl15l.lib JPEGINC = $(JPEGDIR)\Include !endif # ------------------------------------------------------------------------ # C Compiler options # ------------------------------------------------------------------------ DEFINES = -D__STDC__ -DWIN32 -DCONSOLE -D_MT -DNO_STRICT -D_NO_VCL \ $(DEBUG_DEFINES) $(SHLIB_DEFINES) $(EXTRA_DEFINES) !if ($(SHARED) == 1) SHLIB_DEFINES = -D_DLL SHLIB_TARGET = build-dll LIBS = $(COMMON_LIBS) $(EXTRA_LIBS) !else SHLIB_CFLAGS = SHLIB_DEFINES = LIBS = $(COMMON_LIBS) $(EXTRA_LIBS) !endif !if ($(DEBUG) == 1) # -Od Disable all optimizations. # -k Turn on standard stack frame. # -r- Disable use of registers. # -v Turn on source debugging. # -vG All code guard options on. # -vi- Turn off expansion of inline functions. # -y Debug line numbers on. DEBUG_CFLAGS = -v -k -Od -vi- -y -r- -lv -tW -tWM # -v Turn on source debugging. DEBUG_LDFLAGS = -v DEBUG_DEFINES = -DUSE_TCLALLOC=0 DEBUG_DEFINES = TK_LIB = $(TKDIR)\win\Debug\tk$(v2)d.lib TCL_LIB = $(TCLDIR)\win\Debug\tcl$(v2)d.lib MSVCRT = !else # -v- Turn off source debugging. # -vi- Turn off expansion of inline functions. # -O2 Generate fastest code possible. DEBUG_CFLAGS = -v- -vi- -O2 -D_DEBUG DEBUG_LDFLAGS = TK_LIB = $(TKDIR)\win\Release\tk$(v2).lib TCL_LIB = $(TCLDIR)\win\Release\tcl$(v2).lib MSVCRT = !endif # Turn off the following bcc warnings: # -w-pro Call to function with no prototype # -w-par Parameter is never used. # -w-sus Suspicious pointer conversion (bltCanvEps.c). # -w-eff Code has no effect (pure_api.c). # WARNINGS = -w-pro -w-par -w-eff -w-sus # -q Suppress compiler identification banner. # -g1 Stop after the first warning. # -tWC Target is a Windows console application. # -X Disable compiler autodependency output. # -ps Use stdcall calling convention. EXTRA_CFLAGS = -q -g1 -tWC -X CFLAGS = $(WARNINGS) $(DEBUG_CFLAGS) $(SHLIB_CFLAGS) $(EXTRA_CFLAGS) # ------------------------------------------------------------------------ # Linker flags and options # ------------------------------------------------------------------------ # -D Save specified description. # -w Turn on warnings. # -c Treate case as significant in symbols. # -x # -Gi Generate .lib file. # -r Verbose linking. # -x Suppresses map creation. COMMON_LDFLAGS = -D"" -w -c -x $(DEBUG_LDFLAGS) -L$(TOOLS32)\lib SHLIB_LDFLAGS = $(COMMON_LDFLAGS) -x -Gi -Tpd $(TOOLS32)\lib\c0d32 LDFLAGS = $(COMMON_LDFLAGS) -x -Tpe -S:2400000 COMMON_LIBS = $(TK_LIB) $(TCL_LIB) import32 cw32 EXTRA_LIBS = $(OLELIB) \ $(JPEGLIB) TCL_ONLY_COMMON_LIBS = $(TCL_LIB) import32 cw32 TCL_ONLY_LIBS = $(TCL_ONLY_COMMON_LIBS) $(EXTRA_LIBS) # ------------------------------------------------------------------------ # Source and target installation directories # ------------------------------------------------------------------------ srcdir = . instdirs = $(prefix) $(exec_prefix) $(bindir) $(libdir) $(includedir) instdirs = $(exec_prefix) $(prefix) $(libdir) # ------------------------------------------------------------------------ # Directories containing Tcl and Tk include files and libraries # ------------------------------------------------------------------------ TCLDIR = $(srcdir)\..\..\tcl$(v3) TKDIR = $(srcdir)\..\..\tk$(v3) INCLUDES = -I. -I$(srcdir) \ -I$(TOOLS32)\include \ -I$(JPEGINC) \ -I$(TCLDIR)\win -I$(TCLDIR)\generic \ -I$(TKDIR)\win -I$(TKDIR)\generic -I$(TKDIR)\xlib \ SHLIB_LD_LIBS = $(COMMON_LIBS) $(EXTRA_LIBS) SHLIB_TCL_ONLY_LIBS = $(COMMON_LIBS) $(EXTRA_LIBS) # ------------------------------------------------------------------------ # You don't need to edit anything beyond this point # ------------------------------------------------------------------------ N_OBJS = bltTed.obj V3_OBJS = bltTri.obj bltGrMt.obj TK_OBJS = tkButton.obj tkFrame.obj tkScrollbar.obj GRAPH_OBJS = bltGrAxis.obj \ bltGrBar.obj \ bltGrElem.obj \ bltGrGrid.obj \ bltGrHairs.obj \ bltGrLegd.obj \ bltGrLine.obj \ bltGrMarker.obj \ bltGrMisc.obj \ bltGrPen.obj \ bltGrPs.obj \ bltGraph.obj TCL_ONLY_OBJS = bltAlloc.obj \ bltArrayObj.obj \ bltBgexec.obj \ bltChain.obj \ bltDebug.obj \ bltHash.obj \ bltList.obj \ bltNsUtil.obj \ bltParse.obj \ bltPool.obj \ bltSpline.obj \ bltSwitch.obj \ bltTree.obj \ bltTreeCmd.obj \ bltUtil.obj \ bltVecCmd.obj \ bltVecMath.obj \ bltVecObjCmd.obj \ bltVector.obj \ bltWatch.obj \ bltWinPipe.obj \ bltWinUtil.obj \ bltWinDde.obj \ pure_api.obj DEMO_OBJS = tkConsole.obj bltWinMain.obj OBJS = $(GRAPH_OBJS) \ $(TCL_ONLY_OBJS) \ bltBeep.obj \ bltBind.obj \ bltBitmap.obj \ bltBusy.obj \ bltCanvEps.obj \ bltConfig.obj \ bltContainer.obj \ bltDragdrop.obj \ bltHierbox.obj \ bltHtext.obj \ bltImage.obj \ bltWinImage.obj \ bltPs.obj \ bltTable.obj \ bltTabnotebook.obj \ bltTabset.obj \ bltText.obj \ bltTile.obj \ bltTreeView.obj \ bltTreeViewCmd.obj \ bltTreeViewEdit.obj \ bltTreeViewColumn.obj \ bltTreeViewStyle.obj \ bltWinDraw.obj \ bltWinPrnt.obj \ bltWindow.obj \ bltObjConfig.obj \ bltWinop.obj \ $(TK_OBJS) $(N_OBJS) NOT_YET = bltContainer.obj bltCutBuffer.obj bltColor.obj HEADERS = blt.h bltChain.h bltVector.h bltTree.h bltPool.h bltHash.h # GNU Make-specific macro SRCS = $(patsubst %.obj,$(srcdir)\%.c,$(OBJS)) shell_name = bltwish version = $(BLT_MAJOR_VERSION)$(BLT_MINOR_VERSION) bltwish = bltwish.exe bltsh = bltsh.exe lib_name = BLT$(version) lib_a = BLT$(version).lib lib_so = BLT$(version).dll tcl_only_lib_a = BLTlite$(version).lib tcl_only_lib_so = BLTlite$(version).dll CC_SWITCHES = $(CFLAGS) $(DEFINES) $(INCLUDES) VPATH = $(srcdir) all: build-library build-demos build-demos: $(bltsh) $(bltwish) build-library: $(lib_a) $(tcl_only_lib_a) build-dll: build-library $(lib_so) $(tcl_only_lib_so) $(bltwish): $(lib_a) tkConsole.obj bltWinMain.c -del $(bltwish) 2>nul $(CC) -c $(CC_SWITCHES) -DTCLLIBPATH="\"$(TCLLIBPATH)\"" \ -obltWinMain.obj $(srcdir)\bltWinMain.c $(LD) $(LDFLAGS) -aa $(TOOLS32)\lib\c0w32 \ tkConsole.obj bltWinMain.obj, \ $(bltwish),, $(lib_a) $(LIBS) $(bltsh): $(tcl_only_lib_a) bltWinMain.c -del $(bltsh) 2>nul $(CC) -c $(CC_SWITCHES) -DTCL_ONLY \ -DTCLLIBPATH="\"$(TCLLIBPATH)\"" \ -obltWinMain.obj $(srcdir)\bltWinMain.c $(LD) $(LDFLAGS) -ap $(TOOLS32)\lib\c0x32 bltWinMain.obj, \ $(bltsh),, $(tcl_only_lib_a) $(TCL_ONLY_LIBS) $(lib_a): $(lib_so) bltHash.h $(OBJS) bltInit.c -del bltInit.obj 2>nul $(CC) -c $(CC_SWITCHES) -DBLT_LIBRARY="\"$(BLT_LIBRARY)\"" \ -obltInit.obj $(srcdir)\bltInit.c -del $@ 2>nul $(AR) $@ $(lib_so) $(lib_so): $(OBJS) bltInit.c -del bltInit.obj 2>nul $(CC) -c $(CC_SWITCHES) -DBLT_LIBRARY="\"$(BLT_LIBRARY)\"" \ -obltInit.obj $(srcdir)\bltInit.c -del $@ 2>nul $(LD) $(SHLIB_LDFLAGS) bltInit.obj $(OBJS), $@,, $(LIBS) $(tcl_only_lib_a): $(tcl_only_lib_so) bltHash.h $(TCL_ONLY_OBJS) bltInit.c -del bltInit.obj 2>nul $(CC) -c $(CC_SWITCHES) -DTCL_ONLY -DBLT_LIBRARY="\"$(BLT_LIBRARY)\"" \ -obltInit.obj $(srcdir)\bltInit.c -del $@ 2>nul $(AR) $@ $(tcl_only_lib_so) $(tcl_only_lib_so): $(TCL_ONLY_OBJS) bltInit.c -del bltInit.obj 2>nul $(CC) -c $(CC_SWITCHES) -DTCL_ONLY -DBLT_LIBRARY="\"$(BLT_LIBRARY)\"" \ -obltInit.obj $(srcdir)\bltInit.c -del $@ 2>nul $(LD) $(SHLIB_LDFLAGS) bltInit.obj $(TCL_ONLY_OBJS), $@, -x, \ $(TCL_ONLY_LIBS),, bltHash.h: bltHash.h.in sed -e 's/@SIZEOF_VOID_P@/4/' \ -e 's/@SIZEOF_INT@/4/' \ -e 's/@SIZEOF_LONG@/4/' \ -e 's/@SIZEOF_LONG_LONG@/8/' \ -e 's/@HAVE_INTTYPES_H@/0/' \ bltHash.h.in > bltHash.h clean: -del *.obj 2>nul -del *.pdb 2>nul -del *.exp 2>nul -del $(lib_a) 2>nul -del $(lib_so) 2>nul -del $(tcl_only_lib_a) 2>nul -del $(tcl_only_lib_so) 2>nul -del $(bltwish) 2>nul -del $(bltsh) 2>nul -del $(srcdir)\*.bak 2>nul -del $(srcdir)\*~ 2>nul -del $(srcdir)\"#"* 2>nul -del *.pdb 2>nul -del *.ilf 2>nul -del *.ils 2>nul -del *.ilc 2>nul -del *.ild 2>nul -del *.tds 2>nul -del *.td2 2>nul -del *.TR2 2>nul .c.obj: $(CC) -c $(CC_SWITCHES) $< blt-2.4z.orig/src/Makefile.in0100644000175000017500000001441607514513161014611 0ustar dokodoko # ------------------------------------------------------------------------ # Makefile for static version of BLT library # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ # C Compiler options # ------------------------------------------------------------------------ BLT_LIBRARY = @BLT_LIBRARY@ TCLLIBPATH = @TCL_LIB_DIR@/tcl@TCL_VERSION@ CC = @CC@ CFLAGS = @CFLAGS@ DEFINES = @DEFINES@ EXTRA_CFLAGS = @GCCFLAGS@ LDFLAGS = @LDFLAGS@ @LD_RUN_PATH@ version = @BLT_MAJOR_VERSION@@BLT_MINOR_VERSION@ # ------------------------------------------------------------------------ # Source and targer installation directories # ------------------------------------------------------------------------ bindir = $(exec_prefix)/bin exec_prefix = @exec_prefix@ incdir = $(prefix)/include libdir = @libdir@ scriptdir = $(exec_prefix)/lib prefix = @prefix@ srcdir = @srcdir@ instdirs = $(prefix) $(exec_prefix) $(bindir) $(libdir) $(incdir) # ------------------------------------------------------------------------ # Directories containing Tcl and Tk include files and libraries # ------------------------------------------------------------------------ INCLUDES = -I. -I$(srcdir) @INCLUDES@ # ------------------------------------------------------------------------ # Libraries directives for Tcl, Tk, X11, and BLT # ------------------------------------------------------------------------ LIBS = @LIB_SPECS@ @EXTRA_LIB_SPECS@ TCL_ONLY_LIBS = @TCL_ONLY_LIB_SPECS@ @EXTRA_LIB_SPECS@ # ------------------------------------------------------------------------ # You don't need to edit anything beyond this point # ------------------------------------------------------------------------ N_OBJS = bltTed.o V3_OBJS = bltTri.o bltGrMt.o TK_OBJS = tkButton.o tkFrame.o bltScrollbar.o GRAPH_OBJS = bltGrAxis.o \ bltGrBar.o \ bltGrElem.o \ bltGrGrid.o \ bltGrHairs.o \ bltGrLegd.o \ bltGrLine.o \ bltGrMarker.o \ bltGrMisc.o \ bltGrPen.o \ bltGrPs.o \ bltGraph.o TCL_ONLY_OBJS = bltAlloc.o \ bltArrayObj.o \ bltBgexec.o \ bltChain.o \ bltDebug.o \ bltHash.o \ bltList.o \ bltNsUtil.o \ bltParse.o \ bltPool.o \ bltSpline.o \ bltSwitch.o \ bltTree.o \ bltTreeCmd.o \ bltUnixPipe.o \ bltUtil.o \ bltVector.o \ bltVecMath.o \ bltVecCmd.o \ bltVecObjCmd.o \ bltWatch.o OBJS = $(GRAPH_OBJS) \ $(TCL_ONLY_OBJS) \ bltBeep.o \ bltBind.o \ bltBitmap.o \ bltBusy.o \ bltCanvEps.o \ bltColor.o \ bltConfig.o \ bltContainer.o \ bltCutbuffer.o \ bltDragdrop.o \ bltHierbox.o \ bltHtext.o \ bltImage.o \ bltUnixImage.o \ bltPs.o \ bltTable.o \ bltTabnotebook.o \ bltTabset.o \ bltText.o \ bltTile.o \ bltTreeView.o \ bltTreeViewCmd.o \ bltTreeViewEdit.o \ bltTreeViewColumn.o \ bltTreeViewStyle.o \ bltUnixDnd.o \ bltWindow.o \ bltObjConfig.o \ bltWinop.o \ $(TK_OBJS) $(N_OBJS) # GNU Make-specific macro SRCS = $(patsubst %.o,$(srcdir)/%.c,$(OBJS)) bltwish = bltwish bltsh = bltsh headers = $(srcdir)/blt.h \ $(srcdir)/bltBind.h \ $(srcdir)/bltChain.h \ bltHash.h \ $(srcdir)/bltList.h \ $(srcdir)/bltPool.h \ $(srcdir)/bltTree.h \ $(srcdir)/bltVector.h lib_a = libBLT.a libvers_a = libBLT$(version).a tcl_only_lib_a = libBLTlite.a tcl_only_libvers_a = libBLTlite$(version).a CC_SWITCHES = $(EXTRA_CFLAGS) $(CFLAGS) $(DEFINES) $(INCLUDES) INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_ROOT = RANLIB = @RANLIB@ SHELL = /bin/sh AR = ar rc RM = rm -f LINT = lint LINTFLAGS = -axhbns XREF = cxref XREFFLAGS = -dltR LN_S = @LN_S@ VPATH = $(srcdir) all: $(bltsh) $(bltwish) @SHLIB_TARGET@ build_shared: (cd shared; $(MAKE) CFLAGS="$(CFLAGS)" all) $(bltwish): $(lib_a) $(srcdir)/bltUnixMain.c $(RM) $(bltwish) $(CC) $(CC_SWITCHES) $(LDFLAGS) -o $(bltwish) \ -DTCLLIBPATH=\"$(TCLLIBPATH)\" \ $(srcdir)/bltUnixMain.c $(lib_a) $(LIBS) $(bltsh): $(tcl_only_lib_a) $(srcdir)/bltUnixMain.c $(RM) $(bltsh) $(CC) $(CC_SWITCHES) $(LDFLAGS) -DTCL_ONLY -o $(bltsh) \ -DTCLLIBPATH=\"$(TCLLIBPATH)\" \ $(srcdir)/bltUnixMain.c $(tcl_only_lib_a) $(TCL_ONLY_LIBS) $(lib_a): $(OBJS) $(srcdir)/bltInit.c $(CC) -c $(CC_SWITCHES) -DBLT_LIBRARY=\"$(BLT_LIBRARY)\" \ $(srcdir)/bltInit.c $(RM) $@ $(AR) $@ $(OBJS) bltInit.o $(RANLIB) $@ $(tcl_only_lib_a): $(TCL_ONLY_OBJS) $(srcdir)/bltInit.c $(CC) -c $(CC_SWITCHES) -DTCL_ONLY -DBLT_LIBRARY=\"$(BLT_LIBRARY)\" \ $(srcdir)/bltInit.c $(RM) $@ $(AR) $@ $(TCL_ONLY_OBJS) bltInit.o $(RANLIB) $@ install: mkdirs install-lib install-demo install-headers install-demo: $(bltwish) $(bltsh) $(INSTALL) -m 0755 $(bltwish) $(INSTALL_ROOT)$(bindir) $(INSTALL) -m 0755 $(bltsh) $(INSTALL_ROOT)$(bindir) install-lib: $(lib_a) $(tcl_only_lib_a) $(INSTALL_DATA) $(lib_a) $(INSTALL_ROOT)$(libdir)/$(libvers_a) (cd $(INSTALL_ROOT)$(libdir); $(RM) $(lib_a) ; $(LN_S) $(libvers_a) $(lib_a)) $(RANLIB) $(INSTALL_ROOT)$(libdir)/$(libvers_a) $(INSTALL_DATA) $(tcl_only_lib_a) $(INSTALL_ROOT)$(libdir)/$(tcl_only_libvers_a) (cd $(INSTALL_ROOT)$(libdir); $(RM) $(tcl_only_lib_a) ; $(LN_S) $(tcl_only_libvers_a) $(tcl_only_lib_a)) $(RANLIB) $(INSTALL_ROOT)$(libdir)/$(tcl_only_libvers_a) (cd shared; $(MAKE) install) mkdirs: @for i in $(instdirs) ; do \ if test -d $(INSTALL_ROOT)$$i ; then \ : ; \ else \ echo " mkdir $(INSTALL_ROOT)$$i" ; \ mkdir $(INSTALL_ROOT)$$i ; \ fi ; \ done install-headers: @for i in $(headers) ; do \ echo "installing $$i..." ; \ $(INSTALL_DATA) -m 0444 $$i $(INSTALL_ROOT)$(incdir) ; \ done lint: $(LINT) $(LINTFLAGS) $(DEFINES) $(INCLUDES) $(SRCS) xref: $(XREF) $(XREFFLAGS) $(DEFINES) $(INCLUDES) $(SRCS) clean: $(RM) $(OBJS) bltInit.o $(lib_a) $(tcl_only_lib_a) \ $(bltsh)* $(bltwish)* *pure* .pure* (cd shared; $(MAKE) clean) distclean: clean $(RM) $(srcdir)/*.bak $(srcdir)/*\~ $(srcdir)/"#"* Makefile $(RM) bltConfig.h Makefile TAGS .c.o: $(CC) -c $(CC_SWITCHES) $< PUREFLAGS= pure: $(lib_a) $(PURIFYHOME)/purify $(PUREFLAGS) $(CC) $(CC_SWITCHES) \ $(srcdir)/bltUnixMain.c -o bltwish $(lib_a) $(LIBS) QUANTIFYFLAGS= quant: $(lib_a) $(QUANTIFYHOME)/quantify $(QUANTIFYFLAGS) $(CC) $(CC_SWITCHES) \ $(srcdir)/bltUnixMain.c -o bltwish $(lib_a) $(LIBS) blt-2.4z.orig/src/Makefile.vc0100644000175000017500000002076707536456632014636 0ustar dokodoko # ------------------------------------------------------------------------ # Makefile for BLT library using VC++. # ------------------------------------------------------------------------ include e:/src/blt/win/makedefs TOOLS32 = c:/Program\ Files/Microsoft\ Visual\ Studio/Vc98 AR = lib.exe -link50compat LD = link.exe CC = cl.exe rc32 = rc.exe ifeq ($(WITH_JPEG),0) EXTRA_DEFINES = endif ifeq ($(WITH_JPEG),1) EXTRA_DEFINES = -DHAVE_JPEGLIB_H=1 JPEGDIR = $(srcdir)/../../jpeg-6b JPEGLIB = $(JPEGDIR)/libjpeg.lib JPEGINC = $(JPEGDIR) endif ifeq ($(WITH_JPEG),2) EXTRA_DEFINES = -DHAVE_IJL_H=1 JPEGDIR = c:/Program\ Files/Intel/IJL JPEGLIB = $(JPEGDIR)/lib/ijl15l.lib JPEGINC = $(JPEGDIR)/Include endif # ------------------------------------------------------------------------ # C Compiler options # ------------------------------------------------------------------------ DEFINES = -D_X86_=1 -D__STDC__ -DWIN32 -DCONSOLE -D_MT \ $(DEBUG_DEFINES) $(SHLIB_DEFINES) $(EXTRA_DEFINES) ifeq ($(SHARED),1) SHLIB_DEFINES = -D_DLL SHLIB_TARGET = build-dll LIBS = $(COMMON_LIBS) else SHLIB_DEFINES = -D_CTYPE_DISABLE_MACROS LIBS = $(COMMON_LIBS) $(EXTRA_LIBS) endif ifeq ($(DEBUG),1) CFLAGS = -Z7 -Od DEBUG_LDFLAGS = -debug:full -debugtype:cv DEBUG_DEFINES = -DUSE_TCLALLOC=0 TK_LIB = $(TKDIR)/win/Debug/tk$(v2)d.lib TCL_LIB = $(TCLDIR)/win/Debug/tcl$(v2)d.lib MSVCRT = msvcrtd.lib else CFLAGS = -Ox -GB -GD DEBUG_LDFLAGS = -debug:full -debugtype:cv TK_LIB = $(TKDIR)/win/Release/tk$(v2).lib TCL_LIB = $(TCLDIR)/win/Release/tcl$(v2).lib MSVCRT = msvcrt.lib endif EXTRA_CFLAGS = -nologo -W3 # ------------------------------------------------------------------------ # Linker flags and options # ------------------------------------------------------------------------ COMMON_LDFLAGS = -nodefaultlib -release -nologo -warn:3 \ -machine:IX86 -align:0x1000 \ $(DEBUG_LDFLAGS) DLLENTRY = @12 SHLIB_LDFLAGS = $(COMMON_LDFLAGS) \ -subsystem:console -entry:mainCRTStartup \ -subsystem:windows -entry:WinMainCRTStartup \ -entry:_DllMainCRTStartup$(DLLENTRY) -dll LDFLAGS = $(COMMON_LDFLAGS) \ -fixed:NO -stack:2300000 COMMON_LIBS = $(TK_LIB) $(TCL_LIB) \ $(MSVCRT) \ kernel32.lib user32.lib EXTRA_LIBS = $(OLELIB) \ $(JPEGLIB) \ gdi32.lib \ oldnames.lib \ advapi32.lib \ winspool.lib \ comdlg32.lib TCL_ONLY_LIBS = $(TCL_LIB) $(MSVCRT) kernel32.lib user32.lib advapi32.lib # ------------------------------------------------------------------------ # Source and target installation directories # ------------------------------------------------------------------------ srcdir = . instdirs = $(prefix) $(exec_prefix) $(bindir) $(libdir) \ $(includedir) instdirs = $(exec_prefix) $(prefix) $(libdir) # ------------------------------------------------------------------------ # Directories containing Tcl and Tk include files and libraries # ------------------------------------------------------------------------ TCLDIR = $(srcdir)/../../tcl$(v3) TKDIR = $(srcdir)/../../tk$(v3) INCLUDES = -I. -I$(srcdir) \ -I$(TOOLS32)/include \ -I$(JPEGINC) \ -I$(TCLDIR)/win -I$(TCLDIR)/generic \ -I$(TKDIR)/win -I$(TKDIR)/generic -I$(TKDIR)/xlib \ #-I$(TCLROOT)/include SHLIB_LD_LIBS = $(COMMON_LIBS) $(EXTRA_LIBS) # ------------------------------------------------------------------------ # You don't need to edit anything beyond this point # ------------------------------------------------------------------------ N_OBJS = bltTed.o V3_OBJS = bltTri.o bltGrMt.o TK_OBJS = tkButton.o tkFrame.o tkScrollbar.o GRAPH_OBJS = bltGrAxis.o \ bltGrBar.o \ bltGrElem.o \ bltGrGrid.o \ bltGrHairs.o \ bltGrLegd.o \ bltGrLine.o \ bltGrMarker.o \ bltGrMisc.o \ bltGrPen.o \ bltGrPs.o \ bltGraph.o TCL_ONLY_OBJS = bltAlloc.o \ bltArrayObj.o \ bltBgexec.o \ bltChain.o \ bltDebug.o \ bltHash.o \ bltList.o \ bltNsUtil.o \ bltParse.o \ bltPool.o \ bltSpline.o \ bltSwitch.o \ bltTree.o \ bltTreeCmd.o \ bltUtil.o \ bltVecCmd.o \ bltVecMath.o \ bltVecObjCmd.o \ bltVector.o \ bltWatch.o \ bltWinPipe.o \ bltWinUtil.o \ bltWinDde.o \ pure_api.o DEMO_OBJS = tkConsole.o bltWinMain.o OBJS = $(GRAPH_OBJS) \ $(TCL_ONLY_OBJS) \ bltBeep.o \ bltBind.o \ bltBitmap.o \ bltBusy.o \ bltCanvEps.o \ bltConfig.o \ bltContainer.o \ bltDragdrop.o \ bltHierbox.o \ bltHtext.o \ bltImage.o \ bltWinImage.o \ bltPs.o \ bltTable.o \ bltTabnotebook.o \ bltTabset.o \ bltText.o \ bltTile.o \ bltTreeView.o \ bltTreeViewCmd.o \ bltTreeViewEdit.o \ bltTreeViewColumn.o \ bltTreeViewStyle.o \ bltWinDraw.o \ bltWinPrnt.o \ bltWindow.o \ bltObjConfig.o \ bltWinop.o \ $(TK_OBJS) $(N_OBJS) NOT_YET = bltContainer.o bltCutBuffer.o bltColor.o HEADERS = blt.h bltChain.h bltVector.h bltTree.h bltPool.h bltHash.h # GNU Make-specific macro SRCS = $(patsubst %.o,$(srcdir)/%.c,$(OBJS)) shell_name = bltwish version = $(BLT_MAJOR_VERSION)$(BLT_MINOR_VERSION) bltwish = bltwish.exe bltsh = bltsh.exe bltwish2 = bltwish$(version).exe bltsh2 = bltsh$(version).exe lib_name = BLT$(version) lib_a = BLT$(version).lib lib_so = BLT$(version).dll tcl_only_lib_a = BLTlite$(version).lib tcl_only_lib_so = BLTlite$(version).dll CC_SWITCHES = $(CFLAGS) $(EXTRA_CFLAGS) $(DEFINES) $(INCLUDES) VPATH = $(srcdir) all: build-library $(SHLIB_TARGET) build-demos install: all install-dirs install-headers install-binaries install-demos build-demos: $(SHLIB_TARGET) $(bltwish) $(bltsh) build-library: $(lib_a) $(tcl_only_lib_a) build-dll: build-library $(lib_so) $(tcl_only_lib_so) $(bltwish): $(lib_a) tkConsole.o bltWinMain.c $(RM) $(bltwish) $(CC) -c $(CC_SWITCHES) -DTCLLIBPATH=\"$(TCLLIBPATH)\" \ -FobltWinMain.o $(srcdir)/bltWinMain.c LIB=$(TOOLS32)/lib \ $(LD) $(LDFLAGS) tkConsole.o bltWinMain.o -out:$(bltwish) \ $(lib_a) $(LIBS) $(bltsh): $(tcl_only_lib_a) bltWinMain.c $(RM) $(bltsh) $(CC) -c $(CC_SWITCHES) -DTCL_ONLY \ -DTCLLIBPATH=\"$(TCLLIBPATH)\" \ -FobltWinMain.o $(srcdir)/bltWinMain.c LIB=$(TOOLS32)/lib \ $(LD) $(LDFLAGS) bltWinMain.o -out:$(bltsh) \ $(tcl_only_lib_a) $(TCL_ONLY_LIBS) $(lib_a): bltHash.h $(OBJS) bltInit.c $(RM) bltInit.o $(CC) -c $(CC_SWITCHES) -DBLT_LIBRARY=\"$(BLT_LIBRARY)\" \ -FobltInit.o $(srcdir)/bltInit.c $(RM) $@ $(AR) -out:$@ bltInit.o $(OBJS) $(lib_so): $(lib_a) $(OBJS) bltInit.c $(RM) bltInit.o $(CC) -c $(CC_SWITCHES) -DBLT_LIBRARY=\"$(BLT_LIBRARY)\" \ -FobltInit.o $(srcdir)/bltInit.c $(RM) $@ LIB=$(TOOLS32)/lib \ $(LD) $(SHLIB_LDFLAGS) -out:$@ bltInit.o $(OBJS) $(SHLIB_LD_LIBS) $(tcl_only_lib_a): bltHash.h $(TCL_ONLY_OBJS) bltInit.c $(RM) bltInit.o $(CC) -c $(CC_SWITCHES) -DTCL_ONLY -DBLT_LIBRARY=\"$(BLT_LIBRARY)\" \ -FobltInit.o $(srcdir)/bltInit.c $(RM) $@ $(AR) -out:$@ bltInit.o $(TCL_ONLY_OBJS) $(tcl_only_lib_so): $(tcl_only_lib_a) $(TCL_ONLY_OBJS) bltInit.c $(RM) bltInit.o $(CC) -c $(CC_SWITCHES) -DTCL_ONLY -DBLT_LIBRARY=\"$(BLT_LIBRARY)\" \ -FobltInit.o $(srcdir)/bltInit.c $(RM) $@ LIB=$(TOOLS32)/lib \ $(LD) $(SHLIB_LDFLAGS) -out:$@ bltInit.o $(TCL_ONLY_OBJS) \ $(TCL_ONLY_LIBS) bltHash.h: bltHash.h.in sed -e 's/@SIZEOF_VOID_P@/4/' \ -e 's/@SIZEOF_INT@/4/' \ -e 's/@SIZEOF_LONG@/4/' \ -e 's/@SIZEOF_LONG_LONG@/8/' \ -e 's/@HAVE_INTTYPES_H@/0/' \ bltHash.h.in > bltHash.h install-dirs: @for i in $(instdirs) ; do \ if test ! -d "$$i" ; then \ echo " mkdir $$i" ; \ mkdir "$$i" ; \ fi ; \ done install-binaries: install-lib install-demos install-demos: build-demos $(INSTALL) $(bltwish) $(bindir)/$(bltwish) $(INSTALL) $(bltwish) $(bindir)/$(bltwish2) $(INSTALL) $(bltsh) $(bindir)/$(bltsh) $(INSTALL) $(bltsh) $(bindir)/$(bltsh2) install-lib: $(lib_so) $(lib_a) $(INSTALL_DATA) $(lib_so) $(bindir) $(INSTALL_DATA) $(lib_a) $(libdir) $(INSTALL_DATA) $(tcl_only_lib_so) $(bindir) $(INSTALL_DATA) $(tcl_only_lib_a) $(libdir) install-headers: for i in $(HEADERS) ; do \ $(INSTALL_DATA) "$(srcdir)/$$i" $(includedir) ; \ done lint: $(LINT) $(LINTFLAGS) $(DEFINES) $(INCLUDES) $(SRCS) clean: $(RM) *.o *.pdb *.exp \ $(lib_a) $(lib_so) $(tcl_only_lib_a) $(tcl_only_lib_so) \ $(bltwish) $(bltsh) $(bltwish2) $(bltsh2) $(RM) $(srcdir)/*.bak $(srcdir)/*\~ $(srcdir)/"#"* distclean: clean $(RM) Makefile .c.o: $(CC) -c $(CC_SWITCHES) -Fo$*.o $< blt-2.4z.orig/src/TODO0100644000175000017500000000732607367371461013251 0ustar dokodoko To do: bgexec (Windows) 1. (BUG) Convert collected data to UTF before passing to the interpreter. container (Unix) 1. (done) Add timeout option to control how long to search for application window. debug 1. (done) Recent versions of Tcl swamp Tcl_CommandTrace. Add line cutoff option (default is 6). dnd (Unix) 1. (DOC) Create manual page for "dnd" command. 2. (Feature) Add Motif drag-and-drop capabilities. eps 1. (DOC) Update manual page for eps canvas item. 2. (FEATURE) Read Windows EPS files with embedded TIFF images. graph 1. (done) Fix zooming graph procedure to handle multiple axes. 2. (BUG) Windows printing commands "print1" and "print2" need to use postscript options like -maxpect, -pad, etc. to control graph size. 3. (BUG) No PostScript generated for polygon tiling. 4. (BUG) Clip background polygon for text/bitmap markers. 5. (FEATURE) Add -mask option for bitmap marker. 6. (FEATURE) Allow rotated image markers. 7. (FEATURE) Add oval and rectangle markers. 8. (FEATURE) Add arrowheads to line markers. 9. (BUG) Finish adding error bars. 10. (DOC) Review and update documentation for new typos, new features. 11. (BUG) Store converted screen coordinates in floating point. Can't use integer coordinates for higher resolution PostScript devices. How do Windows' print devices handle this? hierbox 1. (CHANGE) Hierbox to use tree object for data. The -data option will be a field in the tree. 2. (FEATURE) Add edit bindings for entries. 3. (DOCUMENTATION) Create real hierbox manual page. hiertable 1. (done) -tree option dumps core. 2. (done) Sorting tree view affects all other hiertables using the tree. Is separate data structure needed for non-flattened sorts? What about moves? 3. (done) Call tree update procedure when tree object is sorted. This is only when a tree is shared between more than one hiertable. It goes out-of-sync with actual tree positions. 4. (CHANGE) "column resize set" should change the width of the active column automatically. 5a.(FEATURE) XOR outline for entry move operation. 5b.(FEATURE) XOR outline for entry resize operation. 6a.(done) XOR outline for column resize operation. 6b.(FEATURE) XOR outline for column move operation. 7. (???) Update procedure isn't called for moved nodes. Call global update routine (like sort) or selected node update procedures? 8. (DOC) Explain selection modes ("single" and "multiple") in manual page. 9. (BUG) Multi-line entry editting is broken. 10. (BUG) Add default bindings for entry editting. Need to set grab on edit window. 11. (BUG) Add standard keyboard bindings. 12. (FEATURE) Images in column title. 13. (PERFORMANCE) Don't redraw entire widget for scrolling. Copy portions of pixmap and redraw only changed areas. This will affect lots of code. 14. (PERFORMANCE) Don't redraw entire widget for selections. Draw only changed entries. 15. (???) Add checkbox column entries. 16. (BUG) "column resize" reports incorrect width of column. printer (Windows) 1. (DOC) Create manual page for "printer" command. 2. (FEATURE) Add operation to print text and canvas widgets. 3. (FEATURE) Create sample print dialog. 4. (BUG) Needs print job abort handler. tabset 1. (done) Add perforation gizmo for tearoffs. 2. (FEATURE) Allow alternatative tearout styles. tree 1. (done) Create Tcl interface. 2. (DOC) Create manuals for both Tcl and C APIs. vector 1. (FEATURE) Add Tcl-based notification callbacks. gradient 1. (FEATURE) Create gradient command that interfaces with tiling. all (Mac) blt-2.4z.orig/src/blt.h0100644000175000017500000000413607514405104013471 0ustar dokodoko/* * blt.h -- * * 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. */ #ifndef _BLT_H #define _BLT_H #define BLT_MAJOR_VERSION 2 #define BLT_MINOR_VERSION 4 #define BLT_VERSION "2.4" #define BLT_PATCH_LEVEL "2.4z" #define BLT_RELEASE_SERIAL 0 #include #ifndef EXPORT #define EXPORT #endif #undef EXTERN #ifdef __cplusplus # define EXTERN extern "C" EXPORT #else # define EXTERN extern EXPORT #endif #ifndef _ANSI_ARGS_ # define _ANSI_ARGS_(x) () #endif #include #include typedef char *Blt_Uid; EXTERN Blt_Uid Blt_GetUid _ANSI_ARGS_((char *string)); EXTERN void Blt_FreeUid _ANSI_ARGS_((Blt_Uid uid)); EXTERN Blt_Uid Blt_FindUid _ANSI_ARGS_((char *string)); #if (TCL_MAJOR_VERSION >= 8) EXTERN int Blt_GetArrayFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, Blt_HashTable **tablePtrPtr)); EXTERN Tcl_Obj *Blt_NewArrayObj _ANSI_ARGS_((int objc, Tcl_Obj *objv[])); EXTERN void Blt_RegisterArrayObj _ANSI_ARGS_((Tcl_Interp *interp)); EXTERN int Blt_IsArrayObj _ANSI_ARGS_((Tcl_Obj *obj)); #endif /* TCL_MAJOR_VERSION >= 8 */ #endif /*_BLT_H*/ blt-2.4z.orig/src/blt.mak0100644000175000017500000001674207460676373014042 0ustar dokodoko # ------------------------------------------------------------------------ # # Nmakefile for BLT library using VC++. # # Please note this file may or may not be up-to-date. # # You can compare it with "Makefile.vc" in this directory. That's # what I use to build BLT (so it should be current). It builds BLT # with VC++ 6.0 and the cygwin32 tool suite from # # http://sourceware.cygnus.com # # ------------------------------------------------------------------------ !INCLUDE ../win/makedefs TOOLS32 = C:/Program Files/Microsoft Visual Studio/Vc98 prefix = C:/Program Files/Tcl AR = lib.exe LD = link.exe CC = cl.exe rc32 = rc.exe RM = -del # ------------------------------------------------------------------------ # C Compiler options # ------------------------------------------------------------------------ DEFINES = -D_X86_=1 -D__STDC__ -DWIN32 -DCONSOLE -D_MT \ $(DEBUG_DEFINES) $(SHLIB_DEFINES) EXTRA_CFLAGS = -nologo -W3 !IF "$(SHARED)" == "1" SHLIB_DEFINES = -D_DLL SHLIB_TARGET = build-dll LIBS = $(COMMON_LIBS) !ELSE SHLIB_DEFINES = -D_CTYPE_DISABLE_MACROS LIBS = $(COMMON_LIBS) $(EXTRA_LIBS) !ENDIF !IF "$(DEBUG)" == "1" CFLAGS = -Z7 -Od DEBUG_LDFLAGS = -debug:full -debugtype:cv D = d builddir = .\Debug !ELSE CFLAGS = -Ox -GB -GD DEBUG_LDFLAGS = -debug:full -debugtype:cv D = builddir = .\Release !ENDIF MSVCRT = msvcrt$(DBG).lib TK_LIB = $(TKDIR)/win/$(builddir)/tk$(v2)$(D).lib TCL_LIB = $(TCLDIR)/win/$(builddir)/tcl$(v2)$(D).lib # ------------------------------------------------------------------------ # Linker flags and options # ------------------------------------------------------------------------ JPEGLIB = $(JPEGDIR)/libjpeg.lib COMMON_LDFLAGS = -nodefaultlib -release -nologo -warn:3 \ -machine:IX86 -align:0x1000 \ $(DEBUG_LDFLAGS) DLLENTRY = @12 SHLIB_LDFLAGS = $(COMMON_LDFLAGS) \ -subsystem:console -entry:mainCRTStartup \ -subsystem:windows -entry:WinMainCRTStartup \ -entry:_DllMainCRTStartup$(DLLENTRY) -dll LDFLAGS = $(COMMON_LDFLAGS) \ -fixed:NO -stack:2300000 COMMON_LIBS = $(TK_LIB) $(TCL_LIB) \ $(MSVCRT) \ kernel32.lib user32.lib EXTRA_LIBS = $(OLELIB) \ $(JPEGLIB) \ gdi32.lib \ oldnames.lib \ advapi32.lib \ winspool.lib TCL_ONLY_LIBS = $(TCL_LIB) $(MSVCRT) kernel32.lib user32.lib advapi32.lib # ------------------------------------------------------------------------ # Source and target directories # ------------------------------------------------------------------------ srcdir = . instdirs = $(prefix) $(exec_prefix) $(bindir) $(libdir) \ $(includedir) instdirs = $(exec_prefix) $(prefix) $(libdir) # ------------------------------------------------------------------------ # Directories containing Tcl and Tk include files and libraries # ------------------------------------------------------------------------ JPEGDIR = $(srcdir)/../../jpeg-6b TCLDIR = $(srcdir)/../../tcl$(v3) TKDIR = $(srcdir)/../../tk$(v3) INCLUDES = -I. -I$(srcdir) \ -I"$(TOOLS32)/include" \ -I$(TCLDIR)/win \ -I$(TCLDIR)/generic \ -I$(TKDIR)/win \ -I$(TKDIR)/generic \ -I$(TKDIR)/xlib \ -I$(JPEGDIR) SHLIB_LD_LIBS = $(COMMON_LIBS) $(EXTRA_LIBS) # ------------------------------------------------------------------------ # You don't need to edit anything beyond this point # ------------------------------------------------------------------------ N_OBJS = bltTed.o V3_OBJS = bltTri.o bltGrMt.o TK_OBJS = tkButton.o tkFrame.o tkScrollbar.o GRAPH_OBJS = bltGrAxis.o \ bltGrBar.o \ bltGrElem.o \ bltGrGrid.o \ bltGrHairs.o \ bltGrLegd.o \ bltGrLine.o \ bltGrMarker.o \ bltGrMisc.o \ bltGrPen.o \ bltGrPs.o \ bltGraph.o TCL_ONLY_OBJS = bltAlloc.o \ bltArrayObj.o \ bltBgexec.o \ bltChain.o \ bltDebug.o \ bltHash.o \ bltList.o \ bltNsUtil.o \ bltParse.o \ bltPool.o \ bltSpline.o \ bltSwitch.o \ bltTree.o \ bltTreeCmd.o \ bltUnixPipe.o \ bltUtil.o \ bltVector.o \ bltVecMath.o \ bltVecCmd.o \ bltVecObjCmd.o \ bltWatch.o OBJS = $(GRAPH_OBJS) \ $(TCL_ONLY_OBJS) \ bltBeep.o \ bltBind.o \ bltBitmap.o \ bltBusy.o \ bltCanvEps.o \ bltColor.o \ bltConfig.o \ bltContainer.o \ bltCutbuffer.o \ bltDragdrop.o \ bltHierbox.o \ bltHtext.o \ bltImage.o \ bltUnixImage.o \ bltPs.o \ bltTable.o \ bltTabnotebook.o \ bltTabset.o \ bltText.o \ bltTile.o \ bltTreeView.o \ bltTreeViewCmd.o \ bltTreeViewEdit.o \ bltTreeViewColumn.o \ bltTreeViewStyle.o \ bltUnixDnd.o \ bltWindow.o \ bltObjConfig.o \ bltWinop.o \ $(TK_OBJS) $(N_OBJS) bltwish = bltwish.exe bltsh = bltsh.exe headers = $(srcdir)/blt.h \ $(srcdir)/bltBind.h \ $(srcdir)/bltChain.h \ bltHash.h \ $(srcdir)/bltList.h \ $(srcdir)/bltPool.h \ $(srcdir)/bltTree.h \ $(srcdir)/bltVector.h version = $(BLT_MAJOR_VERSION)$(BLT_MINOR_VERSION) bltwish2 = bltwish$(version).exe bltsh2 = bltsh$(version).exe lib_name = BLT$(version) lib_a = BLT$(version).lib lib_so = BLT$(version).dll tcl_only_lib_a = BLTlite$(version).lib tcl_only_lib_so = BLTlite$(version).dll CC_SWITCHES = $(CFLAGS) $(EXTRA_CFLAGS) $(DEFINES) $(INCLUDES) VPATH = $(srcdir) all: build-library $(SHLIB_TARGET) build-demos build-demos: $(SHLIB_TARGET) $(bltwish) $(bltsh) build-library: $(BLT_LIB) build-library: $(lib_a) $(tcl_only_lib_a) build-dll: build-library $(lib_so) $(tcl_only_lib_so) $(bltwish): $(lib_a) tkConsole.o bltWinMain.c $(RM) $(bltwish) $(CC) -c $(CC_SWITCHES) -DTCLLIBPATH=\"$(TCLLIBPATH)\" \ -FobltWinMain.o $(srcdir)/bltWinMain.c LIB=$(TOOLS32)/lib \ $(LD) $(LDFLAGS) tkConsole.o bltWinMain.o -out:$(bltwish) \ $(lib_a) $(LIBS) $(bltsh): $(tcl_only_lib_a) bltWinMain.c $(RM) $(bltsh) $(CC) -c $(CC_SWITCHES) -DTCL_ONLY \ -DTCLLIBPATH=\"$(TCLLIBPATH)\" \ -FobltWinMain.o $(srcdir)/bltWinMain.c LIB=$(TOOLS32)/lib \ $(LD) $(LDFLAGS) bltWinMain.o -out:$(bltsh) \ $(tcl_only_lib_a) $(TCL_ONLY_LIBS) $(lib_a): bltHash.h $(OBJS) bltInit.c $(RM) bltInit.o $(CC) -c $(CC_SWITCHES) -DBLT_LIBRARY=\"$(BLT_LIBRARY)\" \ -FobltInit.o $(srcdir)/bltInit.c $(RM) $@ $(AR) -out:$@ bltInit.o $(OBJS) $(lib_so): $(lib_a) $(OBJS) bltInit.c $(RM) bltInit.o $(CC) -c $(CC_SWITCHES) -DBLT_LIBRARY=\"$(BLT_LIBRARY)\" \ -FobltInit.o $(srcdir)/bltInit.c $(RM) $@ LIB=$(TOOLS32)/lib \ $(LD) $(SHLIB_LDFLAGS) -out:$@ bltInit.o $(OBJS) $(SHLIB_LD_LIBS) $(tcl_only_lib_a): bltHash.h $(TCL_ONLY_OBJS) bltInit.c $(RM) bltInit.o $(CC) -c $(CC_SWITCHES) -DTCL_ONLY -DBLT_LIBRARY=\"$(BLT_LIBRARY)\" \ -FobltInit.o $(srcdir)/bltInit.c $(RM) $@ $(AR) -out:$@ bltInit.o $(TCL_ONLY_OBJS) $(tcl_only_lib_so): $(tcl_only_lib_a) $(TCL_ONLY_OBJS) bltInit.c $(RM) bltInit.o $(CC) -c $(CC_SWITCHES) -DTCL_ONLY -DBLT_LIBRARY=\"$(BLT_LIBRARY)\" \ -FobltInit.o $(srcdir)/bltInit.c $(RM) $@ LIB=$(TOOLS32)/lib \ $(LD) $(SHLIB_LDFLAGS) -out:$@ bltInit.o $(TCL_ONLY_OBJS) \ $(TCL_ONLY_LIBS) bltHash.h: bltHash.h.in sed -e 's/@SIZEOF_VOID_P@/4/' \ -e 's/@SIZEOF_INT@/4/' \ -e 's/@SIZEOF_LONG@/4/' \ -e 's/@SIZEOF_LONG_LONG@/8/' \ -e 's/@HAVE_INTTYPES_H@/0/' \ bltHash.h.in > bltHash.h clean: -del *.o 2>nul -del *.pdb 2>nul -del *.exp 2>nul -del $(lib_name).* 2>nul -del $(bltwish) 2>nul -del $(bltsh) 2>nul -del $(srcdir)\*.bak 2>nul -del $(srcdir)\*~ 2>nul -del $(srcdir)\"#"* 2>nul {$(srcdir)}.c.o: $(CC) -c $(CC_SWITCHES) -Fo$*.o $< blt-2.4z.orig/src/bltAlloc.c0100644000175000017500000000473607517105324014451 0ustar dokodoko#include "bltInt.h" #ifndef linux #ifdef HAVE_MALLOC_H #include #endif /* HAVE_MALLOC_H */ #endif /* * Blt_MallocProcPtr, Blt_FreeProcPtr -- * * These global variables allow you to override the default * memory allocation/deallocation routines, simply by setting the * pointers to your own C functions. By default, we try to use * the same memory allocation scheme that Tcl is using: generally * that's Tcl_Alloc and Tcl_Free. */ #ifdef WIN32 #ifdef __GNUC__ extern char *Tcl_Alloc _ANSI_ARGS_((unsigned int size)); extern void Tcl_Free _ANSI_ARGS_((char * ptr)); extern char *Tcl_Realloc _ANSI_ARGS_((char *ptr, unsigned int size)); #endif /*__GNUC__*/ Blt_MallocProc *Blt_MallocProcPtr = (Blt_MallocProc *)Tcl_Alloc; Blt_FreeProc *Blt_FreeProcPtr = (Blt_FreeProc *)Tcl_Free; Blt_ReallocProc *Blt_ReallocProcPtr = (Blt_ReallocProc *)Tcl_Realloc; #else /* * Try to use the same memory allocator/deallocator that Tcl is * using. Before 8.1 it used malloc/free. */ #if (TCL_VERSION_NUMBER >= _VERSION(8,1,0)) /* * We're pointing to the private TclpAlloc/TclpFree instead of public * Tcl_Alloc/Tcl_Free routines because they don't automatically cause * a panic when not enough memory is available. There are cases (such * as allocating a very large vector) where it's recoverable. */ EXTERN Blt_MallocProc TclpAlloc; EXTERN Blt_FreeProc TclpFree; EXTERN Blt_ReallocProc TclpRealloc; Blt_MallocProc *Blt_MallocProcPtr = TclpAlloc; Blt_FreeProc *Blt_FreeProcPtr = TclpFree; Blt_ReallocProc *Blt_ReallocProcPtr = TclpRealloc; #else Blt_MallocProc *Blt_MallocProcPtr = malloc; Blt_FreeProc *Blt_FreeProcPtr = free; Blt_ReallocProc *Blt_ReallocProcPtr = realloc; #endif /* >= 8.1.0 */ #endif /* WIN32 */ void * Blt_Calloc(nElems, sizeOfElem) unsigned int nElems; size_t sizeOfElem; { char *ptr; size_t size; size = nElems * sizeOfElem; ptr = Blt_Malloc(size); if (ptr != NULL) { memset(ptr, 0, size); } return ptr; } /* *---------------------------------------------------------------------- * * Blt_Strdup -- * * Create a copy of the string from heap storage. * * Results: * Returns a pointer to the need string copy. * *---------------------------------------------------------------------- */ char * Blt_Strdup(string) CONST char *string; { size_t size; char *ptr; size = strlen(string) + 1; ptr = Blt_Malloc(size * sizeof(char)); if (ptr != NULL) { strcpy(ptr, string); } return ptr; } blt-2.4z.orig/src/bltArrayObj.c0100644000175000017500000001635107513621067015127 0ustar dokodoko /* * bltArrayObj.c -- * * Copyright 2000 Silicon Metrics, 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 or 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. * * The array Tcl object was created by George A. Howlett. */ #include "bltInt.h" #ifndef NO_ARRAY #include "bltHash.h" static Tcl_DupInternalRepProc DupArrayInternalRep; static Tcl_FreeInternalRepProc FreeArrayInternalRep; static Tcl_UpdateStringProc UpdateStringOfArray; static Tcl_SetFromAnyProc SetArrayFromAny; static Tcl_ObjType arrayObjType = { "array", FreeArrayInternalRep, /* Called when an object is freed. */ DupArrayInternalRep, /* Copies an internal representation * from one object to another. */ UpdateStringOfArray, /* Creates string representation from * an object's internal representation. */ SetArrayFromAny, /* Creates valid internal representation * from an object's string representation. */ }; static int SetArrayFromAny(interp, objPtr) Tcl_Interp *interp; Tcl_Obj *objPtr; { Blt_HashEntry *hPtr; Blt_HashTable *tablePtr; Tcl_Obj *elemObjPtr; Tcl_ObjType *oldTypePtr = objPtr->typePtr; char **elemArr; char *string; int isNew; int nElem; register int i; if (objPtr->typePtr == &arrayObjType) { return TCL_OK; } /* * Get the string representation. Make it up-to-date if necessary. */ string = Tcl_GetString(objPtr); if (Tcl_SplitList(interp, string, &nElem, &elemArr) != TCL_OK) { return TCL_ERROR; } tablePtr = Blt_Malloc(sizeof(Blt_HashTable)); assert(tablePtr); Blt_InitHashTable(tablePtr, BLT_STRING_KEYS); for (i = 0; i < nElem; i += 2) { hPtr = Blt_CreateHashEntry(tablePtr, elemArr[i], &isNew); elemObjPtr = Tcl_NewStringObj(elemArr[i + 1], -1); Blt_SetHashValue(hPtr, elemObjPtr); /* Make sure we increment the reference count */ Tcl_IncrRefCount(elemObjPtr); } if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) { oldTypePtr->freeIntRepProc(objPtr); } objPtr->internalRep.otherValuePtr = (VOID *)tablePtr; objPtr->typePtr = &arrayObjType; Blt_Free(elemArr); return TCL_OK; } static void DupArrayInternalRep(srcPtr, destPtr) Tcl_Obj *srcPtr; /* Object with internal rep to copy. */ Tcl_Obj *destPtr; /* Object with internal rep to set. */ { Blt_HashEntry *hPtr; Blt_HashSearch cursor; Blt_HashTable *srcTablePtr, *destTablePtr; Tcl_Obj *valueObjPtr; char *key; int isNew; srcTablePtr = (Blt_HashTable *)srcPtr->internalRep.otherValuePtr; destTablePtr = Blt_Malloc(sizeof(Blt_HashTable)); assert(destTablePtr); Blt_InitHashTable(destTablePtr, BLT_STRING_KEYS); for (hPtr = Blt_FirstHashEntry(srcTablePtr, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { key = Blt_GetHashKey(srcTablePtr, hPtr); Blt_CreateHashEntry(destTablePtr, key, &isNew); valueObjPtr = (Tcl_Obj *)Blt_GetHashValue(hPtr); Blt_SetHashValue(hPtr, valueObjPtr); /* Make sure we increment the reference count now that both * array objects are using the same elements. */ Tcl_IncrRefCount(valueObjPtr); } Tcl_InvalidateStringRep(destPtr); destPtr->internalRep.otherValuePtr = (VOID *)destTablePtr; destPtr->typePtr = &arrayObjType; } static void UpdateStringOfArray(objPtr) Tcl_Obj *objPtr; /* Array object whose string rep to update. */ { Tcl_DString dString; Blt_HashTable *tablePtr; Blt_HashEntry *hPtr; Blt_HashSearch cursor; Tcl_Obj *elemObjPtr; tablePtr = (Blt_HashTable *)objPtr->internalRep.otherValuePtr; Tcl_DStringInit(&dString); for (hPtr = Blt_FirstHashEntry(tablePtr, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { elemObjPtr = (Tcl_Obj *)Blt_GetHashValue(hPtr); Tcl_DStringAppendElement(&dString, Blt_GetHashKey(tablePtr, hPtr)); Tcl_DStringAppendElement(&dString, Tcl_GetString(elemObjPtr)); } objPtr->bytes = Blt_Strdup(Tcl_DStringValue(&dString)); objPtr->length = strlen(Tcl_DStringValue(&dString)); Tcl_DStringFree(&dString); } static void FreeArrayInternalRep(objPtr) Tcl_Obj *objPtr; /* Array object to release. */ { Blt_HashEntry *hPtr; Blt_HashSearch cursor; Blt_HashTable *tablePtr; Tcl_Obj *elemObjPtr; Tcl_InvalidateStringRep(objPtr); tablePtr = (Blt_HashTable *)objPtr->internalRep.otherValuePtr; for (hPtr = Blt_FirstHashEntry(tablePtr, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { elemObjPtr = (Tcl_Obj *)Blt_GetHashValue(hPtr); Tcl_DecrRefCount(elemObjPtr); } Blt_DeleteHashTable(tablePtr); Blt_Free(tablePtr); } int Blt_GetArrayFromObj(interp, objPtr, tablePtrPtr) Tcl_Interp *interp; Tcl_Obj *objPtr; Blt_HashTable **tablePtrPtr; { if (objPtr->typePtr == &arrayObjType) { *tablePtrPtr = (Blt_HashTable *)objPtr->internalRep.otherValuePtr; return TCL_OK; } if (SetArrayFromAny(interp, objPtr) == TCL_OK) { *tablePtrPtr = (Blt_HashTable *)objPtr->internalRep.otherValuePtr; return TCL_OK; } return TCL_ERROR; } Tcl_Obj * Blt_NewArrayObj(objc, objv) int objc; Tcl_Obj *objv[]; { Blt_HashEntry *hPtr; Blt_HashTable *tablePtr; Tcl_Obj *arrayObjPtr, *objPtr; int isNew; register int i; tablePtr = Blt_Malloc(sizeof(Blt_HashTable)); assert(tablePtr); Blt_InitHashTable(tablePtr, BLT_STRING_KEYS); for (i = 0; i < objc; i += 2) { hPtr = Blt_CreateHashEntry(tablePtr, Tcl_GetString(objv[i]), &isNew); if ((i + 1) == objc) { objPtr = bltEmptyStringObjPtr; } else { objPtr = objv[i+1]; } Tcl_IncrRefCount(objPtr); if (!isNew) { Tcl_Obj *oldObjPtr; oldObjPtr = Blt_GetHashValue(hPtr); Tcl_DecrRefCount(oldObjPtr); } Blt_SetHashValue(hPtr, objPtr); } arrayObjPtr = Tcl_NewObj(); /* * Reference counts for entry objects are initialized to 0. They * are incremented as they are inserted into the tree via the * Blt_TreeSetValue call. */ arrayObjPtr->refCount = 0; arrayObjPtr->internalRep.otherValuePtr = (VOID *)tablePtr; arrayObjPtr->bytes = NULL; arrayObjPtr->length = 0; arrayObjPtr->typePtr = &arrayObjType; return arrayObjPtr; } int Blt_IsArrayObj(objPtr) Tcl_Obj *objPtr; { return (objPtr->typePtr == &arrayObjType); } /*ARGSUSED*/ void Blt_RegisterArrayObj(interp) Tcl_Interp *interp; /* Not used. */ { Tcl_RegisterObjType(&arrayObjType); } #endif /* NO_ARRAY */ blt-2.4z.orig/src/bltBeep.c0100644000175000017500000000507107462636257014300 0ustar dokodoko/* * bltBeep.c -- * * Copyright 1993-1998 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. */ #include "bltInt.h" #ifndef NO_BEEP /* *---------------------------------------------------------------------- * * Blt_BeepCmd -- * * This procedure is invoked to process the "bell" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_CmdProc BeepCmd; /* ARGSUSED */ static int BeepCmd(clientData, interp, argc, argv) ClientData clientData; /* Main window associated with interpreter.*/ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { int percent; if (argc > 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ?volumePercent?\"", (char *)NULL); return TCL_ERROR; } if (argc == 1) { percent = 50; /* Default setting */ } else if (argc == 2) { if (Tcl_GetInt(interp, argv[1], &percent) != TCL_OK) { return TCL_ERROR; } if ((percent < -100) || (percent > 100)) { Tcl_AppendResult(interp, "bad volume percentage value \"", argv[1], "\"", (char *)NULL); return TCL_ERROR; } } XBell(Tk_Display(Tk_MainWindow(interp)), percent); return TCL_OK; } int Blt_BeepInit(interp) Tcl_Interp *interp; { static Blt_CmdSpec cmdSpec = {"beep", BeepCmd,}; if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) { return TCL_ERROR; } return TCL_OK; } #endif /* NO_BEEP */ blt-2.4z.orig/src/bltBgexec.c0100644000175000017500000014707707542177232014627 0ustar dokodoko/* * bltBgexec.c -- * * This module implements a background "exec" command for the * BLT toolkit. * * Copyright 1993-1998 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. * * The "bgexec" command was created by George Howlett. */ #include "bltInt.h" #ifndef NO_BGEXEC #include #include #ifdef HAVE_SYS_PARAM_H #include #endif #include #include "bltWait.h" #include "bltSwitch.h" #if (TCL_MAJOR_VERSION == 7) #define FILEHANDLER_USES_TCLFILES 1 #else typedef int Tcl_File; #endif static Tcl_CmdProc BgexecCmd; #ifdef WIN32 typedef struct { DWORD pid; HANDLE hProcess; } Process; #else typedef int Process; #endif #if (TCL_VERSION_NUMBER < _VERSION(8,1,0)) typedef void *Tcl_Encoding; /* Make up dummy type for encoding. */ #endif #define ENCODING_ASCII ((Tcl_Encoding)NULL) #define ENCODING_BINARY ((Tcl_Encoding)1) /* * As of Tcl 7.6, we're using our own version of the old * Tcl_CreatePipeline routine. I would have tried to use * Tcl_OpenCommandChannel but you can't get at the array of * process ids, unless of course you pry open the undocumented * structure PipeStatus as clientData. Nor could I figure out * how to set one side of the pipe to be non-blocking. The whole * channel API seems overly complex for what its supposed to * do. [And maybe that's why it keeps changing every release.] */ extern int Blt_CreatePipeline _ANSI_ARGS_((Tcl_Interp *interp, int argc, char **argv, Process **pidPtrPtr, int *inPipePtr, int *outPipePtr, int *errFilePtr)); #ifdef WIN32 #define read(fd, buf, size) Blt_AsyncRead((fd),(buf),(size)) #define close(fd) CloseHandle((HANDLE)fd) #define Tcl_CreateFileHandler Blt_CreateFileHandler #define Tcl_DeleteFileHandler Blt_DeleteFileHandler #define kill KillProcess #define waitpid WaitProcess #endif #define READ_AGAIN (0) #define READ_EOF (-1) #define READ_ERROR (-2) /* The wait-related definitions are taken from tclUnix.h */ #define TRACE_FLAGS (TCL_TRACE_WRITES | TCL_TRACE_UNSETS | TCL_GLOBAL_ONLY) #define BLOCK_SIZE 1024 /* Size of allocation blocks for buffer */ #define DEF_BUFFER_SIZE (BLOCK_SIZE * 8) #define MAX_READS 100 /* Maximum number of successful reads * before stopping to let Tcl catch up * on events */ #ifndef NSIG #define NSIG 32 /* Number of signals available */ #endif /*NSIG*/ #ifndef SIGINT #define SIGINT 2 #endif /* SIGINT */ #ifndef SIGQUIT #define SIGQUIT 3 #endif /* SIGQUIT */ #ifndef SIGKILL #define SIGKILL 9 #endif /* SIGKILL */ #ifndef SIGTERM #define SIGTERM 14 #endif /* SIGTERM */ typedef struct { int number; char *name; } SignalId; static SignalId signalIds[] = { #ifdef SIGABRT {SIGABRT, "SIGABRT"}, #endif #ifdef SIGALRM {SIGALRM, "SIGALRM"}, #endif #ifdef SIGBUS {SIGBUS, "SIGBUS"}, #endif #ifdef SIGCHLD {SIGCHLD, "SIGCHLD"}, #endif #if defined(SIGCLD) && (!defined(SIGCHLD) || (SIGCLD != SIGCHLD)) {SIGCLD, "SIGCLD"}, #endif #ifdef SIGCONT {SIGCONT, "SIGCONT"}, #endif #if defined(SIGEMT) && (!defined(SIGXCPU) || (SIGEMT != SIGXCPU)) {SIGEMT, "SIGEMT"}, #endif #ifdef SIGFPE {SIGFPE, "SIGFPE"}, #endif #ifdef SIGHUP {SIGHUP, "SIGHUP"}, #endif #ifdef SIGILL {SIGILL, "SIGILL"}, #endif #ifdef SIGINT {SIGINT, "SIGINT"}, #endif #ifdef SIGIO {SIGIO, "SIGIO"}, #endif #if defined(SIGIOT) && (!defined(SIGABRT) || (SIGIOT != SIGABRT)) {SIGIOT, "SIGIOT"}, #endif #ifdef SIGKILL {SIGKILL, "SIGKILL"}, #endif #if defined(SIGLOST) && (!defined(SIGIOT) || (SIGLOST != SIGIOT)) && (!defined(SIGURG) || (SIGLOST != SIGURG)) {SIGLOST, "SIGLOST"}, #endif #ifdef SIGPIPE {SIGPIPE, "SIGPIPE"}, #endif #if defined(SIGPOLL) && (!defined(SIGIO) || (SIGPOLL != SIGIO)) {SIGPOLL, "SIGPOLL"}, #endif #ifdef SIGPROF {SIGPROF, "SIGPROF"}, #endif #if defined(SIGPWR) && (!defined(SIGXFSZ) || (SIGPWR != SIGXFSZ)) {SIGPWR, "SIGPWR"}, #endif #ifdef SIGQUIT {SIGQUIT, "SIGQUIT"}, #endif #ifdef SIGSEGV {SIGSEGV, "SIGSEGV"}, #endif #ifdef SIGSTOP {SIGSTOP, "SIGSTOP"}, #endif #ifdef SIGSYS {SIGSYS, "SIGSYS"}, #endif #ifdef SIGTERM {SIGTERM, "SIGTERM"}, #endif #ifdef SIGTRAP {SIGTRAP, "SIGTRAP"}, #endif #ifdef SIGTSTP {SIGTSTP, "SIGTSTP"}, #endif #ifdef SIGTTIN {SIGTTIN, "SIGTTIN"}, #endif #ifdef SIGTTOU {SIGTTOU, "SIGTTOU"}, #endif #if defined(SIGURG) && (!defined(SIGIO) || (SIGURG != SIGIO)) {SIGURG, "SIGURG"}, #endif #if defined(SIGUSR1) && (!defined(SIGIO) || (SIGUSR1 != SIGIO)) {SIGUSR1, "SIGUSR1"}, #endif #if defined(SIGUSR2) && (!defined(SIGURG) || (SIGUSR2 != SIGURG)) {SIGUSR2, "SIGUSR2"}, #endif #ifdef SIGVTALRM {SIGVTALRM, "SIGVTALRM"}, #endif #ifdef SIGWINCH {SIGWINCH, "SIGWINCH"}, #endif #ifdef SIGXCPU {SIGXCPU, "SIGXCPU"}, #endif #ifdef SIGXFSZ {SIGXFSZ, "SIGXFSZ"}, #endif {-1, "unknown signal"}, }; /* * Sink buffer: * ____________________ * | | "size" current allocated length of buffer. * | | * |--------------------| "fill" fill point (# characters in buffer). * | Raw | * |--------------------| "mark" Marks end of cooked characters. * | | * | Cooked | * | | * | | * |--------------------| "lastMark" Mark end of processed characters. * | | * | | * | Processed | * | | * |____________________| 0 */ typedef struct { char *name; /* Name of the sink */ char *doneVar; /* Name of a Tcl variable (malloc'ed) * set to the collected data of the * last UNIX subprocess. */ char *updateVar; /* Name of a Tcl variable (malloc'ed) * updated as data is read from the * pipe. */ char **updateCmd; /* Start of a Tcl command executed * whenever data is read from the * pipe. */ #if (TCL_MAJOR_VERSION >= 8) Tcl_Obj **objv; /* */ int objc; /* */ #endif int flags; Tcl_File file; /* Used for backward compatability * with Tcl 7.5 */ Tcl_Encoding encoding; int fd; /* File descriptor of the pipe. */ int status; int echo; /* Indicates if the pipeline's stderr stream * should be echoed */ unsigned char *byteArr; /* Stores pipeline output (malloc-ed): * Initially points to static storage */ size_t size; /* Size of dynamically allocated buffer. */ size_t fill; /* # of bytes read into the buffer. Marks * the current fill point of the buffer. */ size_t mark; /* # of bytes translated (cooked). */ size_t lastMark; /* # of bytes as of the last read. * This indicates the start of the new * data in the buffer since the last * time the "update" variable was * set. */ unsigned char staticSpace[DEF_BUFFER_SIZE]; /* Static space */ } Sink; #define SINK_BUFFERED (1<<0) #define SINK_KEEP_NL (1<<1) #define SINK_NOTIFY (1<<2) typedef struct { char *statVar; /* Name of a Tcl variable set to the * exit status of the last * process. Setting this variable * triggers the termination of all * subprocesses (regardless whether * they have already completed) */ int signalNum; /* If non-zero, indicates the signal * to send subprocesses when cleaning * up.*/ int keepNewline; /* If non-zero, indicates to set Tcl * output variables with trailing * newlines intact */ int lineBuffered; /* If non-zero, indicates provide data * to update variable and update proc on * a line-by-line basis. */ int interval; /* Interval to poll for the exiting * processes */ char *outputEncodingName; /* Name of decoding scheme to use when * translating output data. */ char *errorEncodingName; /* Name of decoding scheme to use when * translating output data. */ /* Private */ Tcl_Interp *interp; /* Interpreter containing variables */ int nProcs; /* Number of processes in pipeline */ Process *procArr; /* Array of process tokens from pipeline. * The token for Unix are pid_t, while * for Win32 they're handles. */ int traced; /* Indicates that the status variable * is currently being traced. */ int detached; /* Indicates that the pipeline is * detached from standard I/O, running * in the background. */ Tcl_TimerToken timerToken; /* Token for timer handler which polls * for the exit status of each * sub-process. If zero, there's no * timer handler queued. */ int *exitCodePtr; /* Pointer to a memory location to * contain the last process' exit * code. */ int *donePtr; Sink sink1, sink2; } BackgroundInfo; static Blt_SwitchParseProc StringToSignal; static Blt_SwitchCustom killSignalSwitch = { StringToSignal, (Blt_SwitchFreeProc *)NULL, (ClientData)0, }; static Blt_SwitchSpec switchSpecs[] = { {BLT_SWITCH_STRING, "-decodeoutput", Blt_Offset(BackgroundInfo, outputEncodingName), 0}, {BLT_SWITCH_STRING, "-decodeerror", Blt_Offset(BackgroundInfo, errorEncodingName), 0}, {BLT_SWITCH_BOOLEAN, "-echo", Blt_Offset(BackgroundInfo, sink2.echo), 0}, {BLT_SWITCH_STRING, "-error", Blt_Offset(BackgroundInfo, sink2.doneVar), 0}, {BLT_SWITCH_STRING, "-update", Blt_Offset(BackgroundInfo, sink1.updateVar), 0}, {BLT_SWITCH_STRING, "-output", Blt_Offset(BackgroundInfo, sink1.doneVar), 0}, {BLT_SWITCH_STRING, "-lasterror", Blt_Offset(BackgroundInfo, sink2.updateVar), 0}, {BLT_SWITCH_STRING, "-lastoutput", Blt_Offset(BackgroundInfo, sink1.updateVar), 0}, {BLT_SWITCH_LIST, "-onerror", Blt_Offset(BackgroundInfo, sink2.updateCmd), 0}, {BLT_SWITCH_LIST, "-onoutput", Blt_Offset(BackgroundInfo, sink1.updateCmd), 0}, {BLT_SWITCH_BOOLEAN, "-keepnewline", Blt_Offset(BackgroundInfo, keepNewline), 0}, {BLT_SWITCH_BOOLEAN, "-check", Blt_Offset(BackgroundInfo, interval), 0}, {BLT_SWITCH_CUSTOM, "-killsignal", Blt_Offset(BackgroundInfo, signalNum), 0, &killSignalSwitch}, {BLT_SWITCH_BOOLEAN, "-linebuffered", Blt_Offset(BackgroundInfo, lineBuffered), 0}, {BLT_SWITCH_END, NULL, 0, 0} }; static char *VariableProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, char *part1, char *part2, int flags)); static void TimerProc _ANSI_ARGS_((ClientData clientData)); static void StdoutProc _ANSI_ARGS_((ClientData clientData, int mask)); static void StderrProc _ANSI_ARGS_((ClientData clientData, int mask)); /* *---------------------------------------------------------------------- * * GetSignal -- * * Convert a string represent a signal number into its integer * value. * * Results: * The return value is a standard Tcl result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToSignal(clientData, interp, switchName, string, record, offset) ClientData clientData; /* Contains a pointer to the tabset containing * this image. */ Tcl_Interp *interp; /* Interpreter to send results back to */ char *switchName; /* Not used. */ char *string; /* String representation */ char *record; /* Structure record */ int offset; /* Offset to field in structure */ { int *signalPtr = (int *)(record + offset); int signalNum; if ((string == NULL) || (*string == '\0')) { *signalPtr = 0; return TCL_OK; } if (isdigit(UCHAR(string[0]))) { if (Tcl_GetInt(interp, string, &signalNum) != TCL_OK) { return TCL_ERROR; } } else { char *name; register SignalId *sigPtr; name = string; /* Clip off any "SIG" prefix from the signal name */ if ((name[0] == 'S') && (name[1] == 'I') && (name[2] == 'G')) { name += 3; } signalNum = -1; for (sigPtr = signalIds; sigPtr->number > 0; sigPtr++) { if (strcmp(sigPtr->name + 3, name) == 0) { signalNum = sigPtr->number; break; } } if (signalNum < 0) { Tcl_AppendResult(interp, "unknown signal \"", string, "\"", (char *)NULL); return TCL_ERROR; } } if ((signalNum < 0) || (signalNum > NSIG)) { /* Outside range of signals */ Tcl_AppendResult(interp, "signal number \"", string, "\" is out of range", (char *)NULL); return TCL_ERROR; } *signalPtr = signalNum; return TCL_OK; } /* *---------------------------------------------------------------------- * * GetSinkData -- * * Returns the data currently saved in the buffer * *---------------------------------------------------------------------- */ static void GetSinkData(sinkPtr, dataPtr, lengthPtr) Sink *sinkPtr; unsigned char **dataPtr; size_t *lengthPtr; { size_t length; sinkPtr->byteArr[sinkPtr->mark] = '\0'; length = sinkPtr->mark; if ((sinkPtr->mark > 0) && (sinkPtr->encoding != ENCODING_BINARY)) { unsigned char *last; last = sinkPtr->byteArr + (sinkPtr->mark - 1); if ((!(sinkPtr->flags & SINK_KEEP_NL)) && (*last == '\n')) { length--; } } *dataPtr = sinkPtr->byteArr; *lengthPtr = length; } /* *---------------------------------------------------------------------- * * NextBlock -- * * Returns the next block of data since the last time this * routine was called. * *---------------------------------------------------------------------- */ static unsigned char * NextBlock(sinkPtr, lengthPtr) Sink *sinkPtr; int *lengthPtr; { unsigned char *string; int length; string = sinkPtr->byteArr + sinkPtr->lastMark; length = sinkPtr->mark - sinkPtr->lastMark; sinkPtr->lastMark = sinkPtr->mark; if (length > 0) { if ((!(sinkPtr->flags & SINK_KEEP_NL)) && (string[length - 1] == '\n')) { length--; } *lengthPtr = length; return string; } return NULL; } /* *---------------------------------------------------------------------- * * NextLine -- * * Returns the next line of data. * *---------------------------------------------------------------------- */ static unsigned char * NextLine(sinkPtr, lengthPtr) Sink *sinkPtr; int *lengthPtr; { if (sinkPtr->mark > sinkPtr->lastMark) { unsigned char *string; int newBytes; register int i; string = sinkPtr->byteArr + sinkPtr->lastMark; newBytes = sinkPtr->mark - sinkPtr->lastMark; for (i = 0; i < newBytes; i++) { if (string[i] == '\n') { int length; length = i + 1; sinkPtr->lastMark += length; if (!(sinkPtr->flags & SINK_KEEP_NL)) { length--; /* Backup over the newline. */ } *lengthPtr = length; return string; } } /* Newline not found. On errors or EOF, also return a partial line. */ if (sinkPtr->status < 0) { *lengthPtr = newBytes; sinkPtr->lastMark = sinkPtr->mark; return string; } } return NULL; } /* *---------------------------------------------------------------------- * * ResetSink -- * * Removes the bytes already processed from the buffer, possibly * resetting it to empty. This used when we don't care about * keeping all the data collected from the channel (no -output * flag and the process is detached). * *---------------------------------------------------------------------- */ static void ResetSink(sinkPtr) Sink *sinkPtr; { if ((sinkPtr->flags & SINK_BUFFERED) && (sinkPtr->fill > sinkPtr->lastMark)) { register size_t i, j; /* There may be bytes remaining in the buffer, awaiting * another read before we see the next newline. So move the * bytes to the front of the array. */ for (i = 0, j = sinkPtr->lastMark; j < sinkPtr->fill; i++, j++) { sinkPtr->byteArr[i] = sinkPtr->byteArr[j]; } /* Move back the fill point and processed point. */ sinkPtr->fill -= sinkPtr->lastMark; sinkPtr->mark -= sinkPtr->lastMark; } else { sinkPtr->mark = sinkPtr->fill = 0; } sinkPtr->lastMark = 0; } /* *---------------------------------------------------------------------- * * InitSink -- * * Initializes the buffer's storage. * * Results: * None. * * Side effects: * Storage is cleared. * *---------------------------------------------------------------------- */ static void InitSink(bgPtr, sinkPtr, name, encoding) BackgroundInfo *bgPtr; Sink *sinkPtr; char *name; Tcl_Encoding encoding; { sinkPtr->name = name; sinkPtr->echo = FALSE; sinkPtr->fd = -1; sinkPtr->file = (Tcl_File)NULL; sinkPtr->byteArr = sinkPtr->staticSpace; sinkPtr->size = DEF_BUFFER_SIZE; sinkPtr->encoding = encoding; if (bgPtr->keepNewline) { sinkPtr->flags |= SINK_KEEP_NL; } if (bgPtr->lineBuffered) { sinkPtr->flags |= SINK_BUFFERED; } if ((sinkPtr->updateCmd != NULL) || (sinkPtr->updateVar != NULL) || (sinkPtr->echo)) { sinkPtr->flags |= SINK_NOTIFY; } #if (TCL_MAJOR_VERSION >= 8) if (sinkPtr->updateCmd != NULL) { Tcl_Obj **objArr; char **p; int count; register int i; count = 0; for (p = sinkPtr->updateCmd; *p != NULL; p++) { count++; } objArr = Blt_Malloc((count + 1) * sizeof(Tcl_Obj *)); for (i = 0; i < count; i++) { objArr[i] = Tcl_NewStringObj(sinkPtr->updateCmd[i], -1); Tcl_IncrRefCount(objArr[i]); } sinkPtr->objv = objArr; sinkPtr->objc = count + 1; } #endif ResetSink(sinkPtr); } /* *---------------------------------------------------------------------- * * FreeSinkBuffer -- * * Frees the buffer's storage, freeing any malloc'ed space. * * Results: * None. * *---------------------------------------------------------------------- */ static void FreeSinkBuffer(sinkPtr) Sink *sinkPtr; { if (sinkPtr->byteArr != sinkPtr->staticSpace) { Blt_Free(sinkPtr->byteArr); } sinkPtr->fd = -1; sinkPtr->file = (Tcl_File)NULL; #if (TCL_MAJOR_VERSION >= 8) if (sinkPtr->objv != NULL) { register int i; for (i = 0; i < sinkPtr->objc - 1; i++) { Tcl_DecrRefCount(sinkPtr->objv[i]); } Blt_Free(sinkPtr->objv); } #endif } /* *---------------------------------------------------------------------- * * ExtendSinkBuffer -- * * Doubles the size of the current buffer. * * Results: * None. * *---------------------------------------------------------------------- */ static int ExtendSinkBuffer(sinkPtr) Sink *sinkPtr; { unsigned char *arrayPtr; register unsigned char *srcPtr, *destPtr, *endPtr; /* * Allocate a new array, double the old size */ sinkPtr->size += sinkPtr->size; arrayPtr = Blt_Malloc(sizeof(unsigned char) * sinkPtr->size); if (arrayPtr == NULL) { return -1; } srcPtr = sinkPtr->byteArr; endPtr = sinkPtr->byteArr + sinkPtr->fill; destPtr = arrayPtr; while (srcPtr < endPtr) { *destPtr++ = *srcPtr++; } if (sinkPtr->byteArr != sinkPtr->staticSpace) { Blt_Free(sinkPtr->byteArr); } sinkPtr->byteArr = arrayPtr; return (sinkPtr->size - sinkPtr->fill); /* Return bytes left. */ } /* *---------------------------------------------------------------------- * * ReadBytes -- * * Reads and appends any available data from a given file descriptor * to the buffer. * * Results: * Returns TCL_OK when EOF is found, TCL_RETURN if reading * data would block, and TCL_ERROR if an error occurred. * *---------------------------------------------------------------------- */ static void ReadBytes(sinkPtr) Sink *sinkPtr; { int nBytes, bytesLeft; register int i; unsigned char *array; /* * ------------------------------------------------------------------ * * Worry about indefinite postponement. * * Typically we want to stay in the read loop as long as it takes * to collect all the data that's currently available. But if * it's coming in at a constant high rate, we need to arbitrarily * break out at some point. This allows for both setting the * update variable and the Tk program to handle idle events. * * ------------------------------------------------------------------ */ for (i = 0; i < MAX_READS; i++) { /* Allocate a larger buffer when the number of remaining bytes * is below the threshold BLOCK_SIZE. */ bytesLeft = sinkPtr->size - sinkPtr->fill; if (bytesLeft < BLOCK_SIZE) { bytesLeft = ExtendSinkBuffer(sinkPtr); if (bytesLeft < 0) { sinkPtr->status = READ_ERROR; return; } } array = sinkPtr->byteArr + sinkPtr->fill; /* * Read into a buffer but make sure we leave room for a * trailing NUL byte. */ nBytes = read(sinkPtr->fd, array, bytesLeft - 1); if (nBytes == 0) { /* EOF: break out of loop. */ sinkPtr->status = READ_EOF; return; } if (nBytes < 0) { #ifdef O_NONBLOCK #define BLOCKED EAGAIN #else #define BLOCKED EWOULDBLOCK #endif /*O_NONBLOCK*/ /* Either an error has occurred or no more data is * currently available to read. */ if (errno == BLOCKED) { sinkPtr->status = READ_AGAIN; return; } sinkPtr->byteArr[0] = '\0'; sinkPtr->status = READ_ERROR; return; } sinkPtr->fill += nBytes; sinkPtr->byteArr[sinkPtr->fill] = '\0'; } sinkPtr->status = nBytes; } #define IsOpenSink(sinkPtr) ((sinkPtr)->fd != -1) static void CloseSink(interp, sinkPtr) Tcl_Interp *interp; Sink *sinkPtr; { if (IsOpenSink(sinkPtr)) { close(sinkPtr->fd); #ifdef FILEHANDLER_USES_TCLFILES Tcl_DeleteFileHandler(sinkPtr->file); Tcl_FreeFile(sinkPtr->file); #else Tcl_DeleteFileHandler(sinkPtr->fd); #endif sinkPtr->file = (Tcl_File)NULL; sinkPtr->fd = -1; #if WINDEBUG PurifyPrintf("CloseSink: set done var %s\n", sinkPtr->name); #endif if (sinkPtr->doneVar != NULL) { unsigned char *data; size_t length; /* * If data is to be collected, set the "done" variable * with the contents of the buffer. */ GetSinkData(sinkPtr, &data, &length); #if (TCL_VERSION_NUMBER < _VERSION(8,1,0)) data[length] = '\0'; if (Tcl_SetVar(interp, sinkPtr->doneVar, data, TCL_GLOBAL_ONLY) == NULL) { Tcl_BackgroundError(interp); } #else if (Tcl_SetVar2Ex(interp, sinkPtr->doneVar, NULL, Tcl_NewByteArrayObj(data, length), (TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG)) == NULL) { Tcl_BackgroundError(interp); } #endif } #if WINDEBUG PurifyPrintf("CloseSink %s: done\n", sinkPtr->name); #endif } } /* *---------------------------------------------------------------------- * * CookSink -- * * For Windows, translate CR/NL combinations to NL alone. * * Results: * None. * * Side Effects: * The size of the byte array may shrink and array contents * shifted as carriage returns are found and removed. * *---------------------------------------------------------------------- */ static void CookSink(interp, sinkPtr) Tcl_Interp *interp; Sink *sinkPtr; { unsigned char *srcPtr, *endPtr; #ifdef WIN32 size_t oldMark; oldMark = sinkPtr->mark; #endif if (sinkPtr->encoding == ENCODING_BINARY) { /* binary */ /* No translation needed. */ sinkPtr->mark = sinkPtr->fill; } else if (sinkPtr->encoding == ENCODING_ASCII) { /* ascii */ #if (TCL_VERSION_NUMBER < _VERSION(8,1,0)) /* Convert NUL bytes to question marks. */ srcPtr = sinkPtr->byteArr + sinkPtr->mark; endPtr = sinkPtr->byteArr + sinkPtr->fill; while (srcPtr < endPtr) { if (*srcPtr == '\0') { *srcPtr = '?'; } srcPtr++; } #endif /* < 8.1.0 */ /* One-to-one translation. mark == fill. */ sinkPtr->mark = sinkPtr->fill; #if (TCL_VERSION_NUMBER >= _VERSION(8,1,0)) } else { /* unicode. */ int nSrcCooked, nCooked; int result; size_t cookedSize, spaceLeft, needed; size_t nRaw, nLeftOver; unsigned char *destPtr; unsigned char *raw, *cooked; unsigned char leftover[100]; raw = sinkPtr->byteArr + sinkPtr->mark; nRaw = sinkPtr->fill - sinkPtr->mark; /* Ideally, the cooked buffer size should be smaller */ cookedSize = nRaw * TCL_UTF_MAX + 1; cooked = Blt_Malloc(cookedSize); result = Tcl_ExternalToUtf(interp, sinkPtr->encoding, (char *)raw, nRaw, 0, NULL, (char *)cooked, cookedSize, &nSrcCooked, &nCooked, NULL); nLeftOver = 0; if (result == TCL_CONVERT_MULTIBYTE) { /* * Last multibyte sequence wasn't completed. Save the * extra characters in a temporary buffer. */ nLeftOver = (nRaw - nSrcCooked); srcPtr = sinkPtr->byteArr + (sinkPtr->mark + nSrcCooked); endPtr = srcPtr + nLeftOver; destPtr = leftover; while (srcPtr < endPtr) { *destPtr++ = *srcPtr++; } } /* * Create a bigger */ needed = nLeftOver + nCooked; spaceLeft = sinkPtr->size - sinkPtr->mark; if (spaceLeft >= needed) { spaceLeft = ExtendSinkBuffer(sinkPtr); } assert(spaceLeft > needed); /* * Replace the characters from the mark with the translated * characters. */ srcPtr = cooked; endPtr = cooked + nCooked; destPtr = sinkPtr->byteArr + sinkPtr->mark; while (srcPtr < endPtr) { *destPtr++ = *srcPtr++; } /* Add the number of newly translated characters to the mark */ sinkPtr->mark += nCooked; srcPtr = leftover; endPtr = leftover + nLeftOver; while (srcPtr < endPtr) { *destPtr++ = *srcPtr++; } sinkPtr->fill = sinkPtr->mark + nLeftOver; #endif /* >= 8.1.0 */ } #ifdef WIN32 /* * Translate CRLF character sequences to LF characters. We have to * do this after converting the string to UTF from UNICODE. */ if (sinkPtr->encoding != ENCODING_BINARY) { int count; unsigned char *destPtr; destPtr = srcPtr = sinkPtr->byteArr + oldMark; endPtr = sinkPtr->byteArr + sinkPtr->fill; *endPtr = '\0'; count = 0; for (endPtr--; srcPtr < endPtr; srcPtr++) { if ((*srcPtr == '\r') && (*(srcPtr + 1) == '\n')) { count++; continue; /* Skip the CR in CR/LF sequences. */ } if (srcPtr != destPtr) { *destPtr = *srcPtr; /* Collapse the string, overwriting * the \r's encountered. */ } destPtr++; } sinkPtr->mark -= count; sinkPtr->fill -= count; *destPtr = *srcPtr; /* Copy the last byte */ if (*destPtr == '\r') { sinkPtr->mark--; } } #endif /* WIN32 */ } #ifdef WIN32 /* *---------------------------------------------------------------------- * * WaitProcess -- * * Emulates the waitpid system call under the Win32 API. * * Results: * Returns 0 if the process is still alive, -1 on an error, or * the pid on a clean close. * * Side effects: * Unless WNOHANG is set and the wait times out, the process * information record will be deleted and the process handle * will be closed. * *---------------------------------------------------------------------- */ #define WINDEBUG 0 static int WaitProcess( Process child, int *statusPtr, int flags) { int result; DWORD status, exitCode; int timeout; #if WINDEBUG PurifyPrintf("WAITPID(%x)\n", child.hProcess); #endif *statusPtr = 0; if (child.hProcess == INVALID_HANDLE_VALUE) { errno = EINVAL; return -1; } #if WINDEBUG PurifyPrintf("WAITPID: waiting for 0x%x\n", child.hProcess); #endif timeout = (flags & WNOHANG) ? 0 : INFINITE; status = WaitForSingleObject(child.hProcess, timeout); #if WINDEBUG PurifyPrintf("WAITPID: wait status is %d\n", status); #endif switch (status) { case WAIT_FAILED: errno = ECHILD; *statusPtr = ECHILD; result = -1; break; case WAIT_TIMEOUT: if (timeout == 0) { return 0; /* Try again */ } result = 0; break; default: case WAIT_ABANDONED: case WAIT_OBJECT_0: GetExitCodeProcess(child.hProcess, &exitCode); *statusPtr = ((exitCode << 8) & 0xff00); #if WINDEBUG PurifyPrintf("WAITPID: exit code of %d is %d (%x)\n", child.hProcess, *statusPtr, exitCode); #endif result = child.pid; assert(result != -1); break; } CloseHandle(child.hProcess); return result; } static BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam) { DWORD pid = 0; Process *procPtr = (Process *)lParam; GetWindowThreadProcessId(hWnd, &pid); if (pid == procPtr->pid) { PostMessage(hWnd, WM_CLOSE, 0, 0); } return TRUE; } /* *---------------------------------------------------------------------- * * KillProcess -- * * Emulates the UNIX kill system call under Win32 API. * * Results: * Returns 0 if the process is killed, -1 on an error. * * Side effects: * Process is terminated. * *---------------------------------------------------------------------- */ static int KillProcess(Process proc, int signal) { DWORD status; if ((proc.hProcess == NULL) || (proc.hProcess == INVALID_HANDLE_VALUE)) { errno = EINVAL; return -1; } EnumWindows(EnumWindowsProc, (LPARAM)&proc); /* * Wait on the handle. If it signals, great. If it times out, * then call TerminateProcess on it. * * On Windows 95/98 this also has the added benefit of stopping * KERNEL32.dll from dumping. The 2 second number is arbitrary. * (1 second seems to fail intermittently). */ status = WaitForSingleObject(proc.hProcess, 2000); if (status == WAIT_OBJECT_0) { return 0; } if (!TerminateProcess(proc.hProcess, 1)) { #if WINDEBUG PurifyPrintf("can't terminate process (handle=%d): %s\n", proc.hProcess, Blt_LastError()); #endif /* WINDEBUG */ return -1; } return 0; } #endif /* WIN32 */ #if (TCL_VERSION_NUMBER < _VERSION(8,1,0)) static void NotifyOnUpdate(interp, sinkPtr, data, nBytes) Tcl_Interp *interp; Sink *sinkPtr; unsigned char *data; int nBytes; { char save; #if WINDEBUG_0 PurifyPrintf("read %s\n", data); #endif if (data[0] == '\0') { return; } save = data[nBytes]; data[nBytes] = '\0'; if (sinkPtr->echo) { Tcl_Channel channel; channel = Tcl_GetStdChannel(TCL_STDERR); if (channel == NULL) { Tcl_AppendResult(interp, "can't get stderr channel", (char *)NULL); Tcl_BackgroundError(interp); sinkPtr->echo = FALSE; } else { Tcl_Write(channel, data, nBytes); if (save == '\n') { Tcl_Write(channel, "\n", 1); } Tcl_Flush(channel); } } if (sinkPtr->updateCmd != NULL) { Tcl_DString dString; int result; register char **p; Tcl_DStringInit(&dString); for (p = sinkPtr->updateCmd; *p != NULL; p++) { Tcl_DStringAppendElement(&dString, *p); } Tcl_DStringAppendElement(&dString, data); result = Tcl_GlobalEval(interp, Tcl_DStringValue(&dString)); Tcl_DStringFree(&dString); if (result != TCL_OK) { Tcl_BackgroundError(interp); } } if (sinkPtr->updateVar != NULL) { int flags; char *result; flags = (TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG); result = Tcl_SetVar(interp, sinkPtr->updateVar, data, flags); if (result == NULL) { Tcl_BackgroundError(interp); } } data[nBytes] = save; } #else static void NotifyOnUpdate(interp, sinkPtr, data, nBytes) Tcl_Interp *interp; Sink *sinkPtr; unsigned char *data; int nBytes; { Tcl_Obj *objPtr; #if WINDEBUG_0 PurifyPrintf("read %s\n", data); #endif if ((nBytes == 0) || (data[0] == '\0')) { return; } if (sinkPtr->echo) { Tcl_Channel channel; channel = Tcl_GetStdChannel(TCL_STDERR); if (channel == NULL) { Tcl_AppendResult(interp, "can't get stderr channel", (char *)NULL); Tcl_BackgroundError(interp); sinkPtr->echo = FALSE; } else { if (data[nBytes] == '\n') { objPtr = Tcl_NewByteArrayObj(data, nBytes + 1); } else { objPtr = Tcl_NewByteArrayObj(data, nBytes); } Tcl_WriteObj(channel, objPtr); Tcl_Flush(channel); } } objPtr = Tcl_NewByteArrayObj(data, nBytes); Tcl_IncrRefCount(objPtr); if (sinkPtr->objv != NULL) { int result; sinkPtr->objv[sinkPtr->objc - 1] = objPtr; result = Tcl_EvalObjv(interp, sinkPtr->objc, sinkPtr->objv, 0); if (result != TCL_OK) { Tcl_BackgroundError(interp); } } if (sinkPtr->updateVar != NULL) { Tcl_Obj *result; result = Tcl_SetVar2Ex(interp, sinkPtr->updateVar, NULL, objPtr, (TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG)); if (result == NULL) { Tcl_BackgroundError(interp); } } Tcl_DecrRefCount(objPtr); } #endif /* < 8.1.0 */ static int CollectData(bgPtr, sinkPtr) BackgroundInfo *bgPtr; Sink *sinkPtr; { if ((bgPtr->detached) && (sinkPtr->doneVar == NULL)) { ResetSink(sinkPtr); } ReadBytes(sinkPtr); CookSink(bgPtr->interp, sinkPtr); if ((sinkPtr->mark > sinkPtr->lastMark) && (sinkPtr->flags & SINK_NOTIFY)) { unsigned char *data; int length; if (sinkPtr->flags & SINK_BUFFERED) { /* For line-by-line updates, call NotifyOnUpdate for each * new complete line. */ while ((data = NextLine(sinkPtr, &length)) != NULL) { NotifyOnUpdate(bgPtr->interp, sinkPtr, data, length); } } else { data = NextBlock(sinkPtr, &length); NotifyOnUpdate(bgPtr->interp, sinkPtr, data, length); } } if (sinkPtr->status >= 0) { return TCL_OK; } if (sinkPtr->status == READ_ERROR) { Tcl_AppendResult(bgPtr->interp, "can't read data from ", sinkPtr->name, ": ", Tcl_PosixError(bgPtr->interp), (char *)NULL); Tcl_BackgroundError(bgPtr->interp); return TCL_ERROR; } #if WINDEBUG PurifyPrintf("CollectData %s: done\n", sinkPtr->name); #endif return TCL_RETURN; } /* *---------------------------------------------------------------------- * * CreateSinkHandler -- * * Creates a file handler for the given sink. The file * descriptor is also set for non-blocking I/O. * * Results: * None. * * Side effects: * The memory allocated to the BackgroundInfo structure released. * *---------------------------------------------------------------------- */ static int CreateSinkHandler(bgPtr, sinkPtr, proc) BackgroundInfo *bgPtr; Sink *sinkPtr; Tcl_FileProc *proc; { #ifndef WIN32 int flags; flags = fcntl(sinkPtr->fd, F_GETFL); #ifdef O_NONBLOCK flags |= O_NONBLOCK; #else flags |= O_NDELAY; #endif if (fcntl(sinkPtr->fd, F_SETFL, flags) < 0) { Tcl_AppendResult(bgPtr->interp, "can't set file descriptor ", Blt_Itoa(sinkPtr->fd), " to non-blocking:", Tcl_PosixError(bgPtr->interp), (char *)NULL); return TCL_ERROR; } #endif /* WIN32 */ #ifdef FILEHANDLER_USES_TCLFILES sinkPtr->file = Tcl_GetFile((ClientData)sinkPtr->fd, TCL_UNIX_FD); Tcl_CreateFileHandler(sinkPtr->file, TCL_READABLE, proc, bgPtr); #else Tcl_CreateFileHandler(sinkPtr->fd, TCL_READABLE, proc, bgPtr); #endif /* FILEHANDLER_USES_TCLFILES */ return TCL_OK; } static void DisableTriggers(bgPtr) BackgroundInfo *bgPtr; /* Background info record. */ { if (bgPtr->traced) { Tcl_UntraceVar(bgPtr->interp, bgPtr->statVar, TRACE_FLAGS, VariableProc, bgPtr); bgPtr->traced = FALSE; } if (IsOpenSink(&bgPtr->sink1)) { CloseSink(bgPtr->interp, &bgPtr->sink1); } if (IsOpenSink(&bgPtr->sink2)) { CloseSink(bgPtr->interp, &bgPtr->sink2); } if (bgPtr->timerToken != (Tcl_TimerToken) 0) { Tcl_DeleteTimerHandler(bgPtr->timerToken); bgPtr->timerToken = 0; } if (bgPtr->donePtr != NULL) { *bgPtr->donePtr = TRUE; } } /* *---------------------------------------------------------------------- * * FreeBackgroundInfo -- * * Releases the memory allocated for the backgrounded process. * *---------------------------------------------------------------------- */ static void FreeBackgroundInfo(bgPtr) BackgroundInfo *bgPtr; { Blt_FreeSwitches(switchSpecs, (char *)bgPtr, 0); if (bgPtr->statVar != NULL) { Blt_Free(bgPtr->statVar); } if (bgPtr->procArr != NULL) { Blt_Free(bgPtr->procArr); } Blt_Free(bgPtr); } /* *---------------------------------------------------------------------- * * DestroyBackgroundInfo -- * * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release * to clean up the internal structure (BackgroundInfo) at a safe * time (when no one is using it anymore). * * Results: * None.b * * Side effects: * The memory allocated to the BackgroundInfo structure released. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static void DestroyBackgroundInfo(bgPtr) BackgroundInfo *bgPtr; /* Background info record. */ { DisableTriggers(bgPtr); FreeSinkBuffer(&bgPtr->sink2); FreeSinkBuffer(&bgPtr->sink1); if (bgPtr->procArr != NULL) { register int i; for (i = 0; i < bgPtr->nProcs; i++) { if (bgPtr->signalNum > 0) { kill(bgPtr->procArr[i], bgPtr->signalNum); } #ifdef WIN32 Tcl_DetachPids(1, (Tcl_Pid *)&bgPtr->procArr[i].pid); #else #if (TCL_MAJOR_VERSION == 7) Tcl_DetachPids(1, &bgPtr->procArr[i]); #else Tcl_DetachPids(1, (Tcl_Pid *)bgPtr->procArr[i]); #endif /* TCL_MAJOR_VERSION == 7 */ #endif /* WIN32 */ } } FreeBackgroundInfo(bgPtr); Tcl_ReapDetachedProcs(); } /* * ---------------------------------------------------------------------- * * VariableProc -- * * Kills all currently running subprocesses (given the specified * signal). This procedure is called when the user sets the status * variable associated with this group of child subprocesses. * * Results: * Always returns NULL. Only called from a variable trace. * * Side effects: * The subprocesses are signaled for termination using the * specified kill signal. Additionally, any resources allocated * to track the subprocesses is released. * * ---------------------------------------------------------------------- */ /* ARGSUSED */ static char * VariableProc( ClientData clientData, /* File output information. */ Tcl_Interp *interp, char *part1, char *part2, /* Not Used. */ int flags) { if (flags & TRACE_FLAGS) { BackgroundInfo *bgPtr = clientData; /* Kill all child processes that remain alive. */ if ((bgPtr->procArr != NULL) && (bgPtr->signalNum > 0)) { register int i; for (i = 0; i < bgPtr->nProcs; i++) { kill(bgPtr->procArr[i], bgPtr->signalNum); } } } return NULL; } /* *---------------------------------------------------------------------- * * TimerProc -- * * This is a timer handler procedure which gets called * periodically to reap any of the sub-processes if they have * terminated. After the last process has terminated, the * contents of standard output are stored * in the output variable, which triggers the cleanup proc (using * a variable trace). The status the last process to exit is * written to the status variable. * * Results: * None. Called from the Tcl event loop. * * Side effects: * Many. The contents of procArr is shifted, leaving only those * sub-processes which have not yet terminated. If there are * still subprocesses left, this procedure is placed in the timer * queue again. Otherwise the output and possibly the status * variables are updated. The former triggers the cleanup * routine which will destroy the information and resources * associated with these background processes. * *---------------------------------------------------------------------- */ static void TimerProc(clientData) ClientData clientData; { BackgroundInfo *bgPtr = clientData; register int i; unsigned int lastPid; int pid; enum PROCESS_STATUS { PROCESS_EXITED, PROCESS_STOPPED, PROCESS_KILLED, PROCESS_UNKNOWN } pcode; WAIT_STATUS_TYPE waitStatus, lastStatus; int nLeft; /* Number of processes still not reaped */ char string[200]; Tcl_DString dString; int code; CONST char *result; lastPid = (unsigned int)-1; *((int *)&waitStatus) = 0; *((int *)&lastStatus) = 0; nLeft = 0; for (i = 0; i < bgPtr->nProcs; i++) { #ifdef WIN32 pid = WaitProcess(bgPtr->procArr[i], (int *)&waitStatus, WNOHANG); #else pid = waitpid(bgPtr->procArr[i], (int *)&waitStatus, WNOHANG); #endif if (pid == 0) { /* Process has not terminated yet */ if (nLeft < i) { bgPtr->procArr[nLeft] = bgPtr->procArr[i]; } nLeft++; /* Count the number of processes left */ } else if (pid != -1) { /* * Save the status information associated with the subprocess. * We'll use it only if this is the last subprocess to be reaped. */ lastStatus = waitStatus; lastPid = (unsigned int)pid; } } bgPtr->nProcs = nLeft; if ((nLeft > 0) || (IsOpenSink(&bgPtr->sink1)) || (IsOpenSink(&bgPtr->sink2))) { /* Keep polling for the status of the children that are left */ bgPtr->timerToken = Tcl_CreateTimerHandler(bgPtr->interval, TimerProc, bgPtr); #if WINDEBUG PurifyPrintf("schedule TimerProc(nProcs=%d)\n", nLeft); #endif return; } /* * All child processes have completed. Set the status variable * with the status of the last process reaped. The status is a * list of an error token, the exit status, and a message. */ code = WEXITSTATUS(lastStatus); Tcl_DStringInit(&dString); if (WIFEXITED(lastStatus)) { Tcl_DStringAppendElement(&dString, "EXITED"); pcode = PROCESS_EXITED; } else if (WIFSIGNALED(lastStatus)) { Tcl_DStringAppendElement(&dString, "KILLED"); pcode = PROCESS_KILLED; code = -1; } else if (WIFSTOPPED(lastStatus)) { Tcl_DStringAppendElement(&dString, "STOPPED"); pcode = PROCESS_STOPPED; code = -1; } else { Tcl_DStringAppendElement(&dString, "UNKNOWN"); pcode = PROCESS_UNKNOWN; } #ifdef WIN32 sprintf(string, "%u", lastPid); Tcl_DStringAppendElement(&dString, string); #else Tcl_DStringAppendElement(&dString, Blt_Itoa(lastPid)); #endif Tcl_DStringAppendElement(&dString, Blt_Itoa(code)); switch(pcode) { case PROCESS_EXITED: Tcl_DStringAppendElement(&dString, "child completed normally"); break; case PROCESS_KILLED: Tcl_DStringAppendElement(&dString, Tcl_SignalMsg((int)(WTERMSIG(lastStatus)))); break; case PROCESS_STOPPED: Tcl_DStringAppendElement(&dString, Tcl_SignalMsg((int)(WSTOPSIG(lastStatus)))); break; case PROCESS_UNKNOWN: sprintf(string, "child completed with unknown status 0x%x", *((int *)&lastStatus)); Tcl_DStringAppendElement(&dString, string); break; } if (bgPtr->exitCodePtr != NULL) { *bgPtr->exitCodePtr = code; } DisableTriggers(bgPtr); result = Tcl_SetVar(bgPtr->interp, bgPtr->statVar, Tcl_DStringValue(&dString), TCL_GLOBAL_ONLY); Tcl_DStringFree(&dString); if (result == NULL) { Tcl_BackgroundError(bgPtr->interp); } if (bgPtr->detached) { DestroyBackgroundInfo(bgPtr); } } /* *---------------------------------------------------------------------- * * Stdoutproc -- * * This procedure is called when output from the detached pipeline * is available. The output is read and saved in a buffer in the * BackgroundInfo structure. * * Results: * None. * * Side effects: * Data is stored in the buffer. This character array may * be increased as more space is required to contain the output * of the pipeline. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static void StdoutProc(clientData, mask) ClientData clientData; /* File output information. */ int mask; /* Not used. */ { BackgroundInfo *bgPtr = clientData; if (CollectData(bgPtr, &bgPtr->sink1) == TCL_OK) { return; } /* * Either EOF or an error has occurred. In either case, close the * sink. Note that closing the sink will also remove the file * handler, so this routine will not be called again. */ CloseSink(bgPtr->interp, &bgPtr->sink1); /* * If both sinks (stdout and stderr) are closed, this doesn't * necessarily mean that the process has terminated. Set up a * timer handler to periodically poll for the exit status of each * process. Initially check at the next idle interval. */ if (!IsOpenSink(&bgPtr->sink2)) { bgPtr->timerToken = Tcl_CreateTimerHandler(0, TimerProc, clientData); } } /* *---------------------------------------------------------------------- * * StderrProc -- * * This procedure is called when error from the detached pipeline * is available. The error is read and saved in a buffer in the * BackgroundInfo structure. * * Results: * None. * * Side effects: * Data is stored in the buffer. This character array may * be increased as more space is required to contain the stderr * of the pipeline. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static void StderrProc(clientData, mask) ClientData clientData; /* File output information. */ int mask; /* Not used. */ { BackgroundInfo *bgPtr = clientData; if (CollectData(bgPtr, &bgPtr->sink2) == TCL_OK) { return; } /* * Either EOF or an error has occurred. In either case, close the * sink. Note that closing the sink will also remove the file * handler, so this routine will not be called again. */ CloseSink(bgPtr->interp, &bgPtr->sink2); /* * If both sinks (stdout and stderr) are closed, this doesn't * necessarily mean that the process has terminated. Set up a * timer handler to periodically poll for the exit status of each * process. Initially check at the next idle interval. */ if (!IsOpenSink(&bgPtr->sink1)) { bgPtr->timerToken = Tcl_CreateTimerHandler(0, TimerProc, clientData); } } /* *---------------------------------------------------------------------- * * BgexecCmd -- * * This procedure is invoked to process the "bgexec" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int BgexecCmd(clientData, interp, argc, argv) ClientData clientData; /* Thread-specific data. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { int *outFdPtr, *errFdPtr; int nProcs; Process *pidPtr; char *lastArg; BackgroundInfo *bgPtr; int i; int detached; Tcl_Encoding encoding; if (argc < 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " varName ?options? command ?arg...?\"", (char *)NULL); return TCL_ERROR; } /* Check if the command line is to be run detached (the last * argument is "&") */ lastArg = argv[argc - 1]; detached = ((lastArg[0] == '&') && (lastArg[1] == '\0')); if (detached) { argc--; argv[argc] = NULL; /* Remove the '&' argument */ } bgPtr = Blt_Calloc(1, sizeof(BackgroundInfo)); assert(bgPtr); /* Initialize the background information record */ bgPtr->interp = interp; bgPtr->signalNum = SIGKILL; bgPtr->nProcs = -1; bgPtr->interval = 1000; bgPtr->detached = detached; bgPtr->keepNewline = FALSE; bgPtr->statVar = Blt_Strdup(argv[1]); /* Try to clean up any detached processes */ Tcl_ReapDetachedProcs(); i = Blt_ProcessSwitches(interp, switchSpecs, argc - 2, argv + 2, (char *)bgPtr, BLT_SWITCH_ARGV_PARTIAL); if (i < 0) { FreeBackgroundInfo(bgPtr); return TCL_ERROR; } i += 2; /* Must be at least one argument left as the command to execute. */ if (argc <= i) { Tcl_AppendResult(interp, "missing command to execute: should be \"", argv[0], " varName ?options? command ?arg...?\"", (char *)NULL); FreeBackgroundInfo(bgPtr); return TCL_ERROR; } /* Put a trace on the exit status variable. The will also allow * the user to prematurely terminate the pipeline by simply * setting it. */ Tcl_TraceVar(interp, bgPtr->statVar, TRACE_FLAGS, VariableProc, bgPtr); bgPtr->traced = TRUE; encoding = ENCODING_ASCII; if (bgPtr->outputEncodingName != NULL) { if (strcmp(bgPtr->outputEncodingName, "binary") == 0) { encoding = ENCODING_BINARY; } else { #if (TCL_VERSION_NUMBER >= _VERSION(8,1,0)) encoding = Tcl_GetEncoding(interp, bgPtr->outputEncodingName); if (encoding == NULL) { goto error; } #endif } } InitSink(bgPtr, &bgPtr->sink1, "stdout", encoding); if (bgPtr->errorEncodingName != NULL) { if (strcmp(bgPtr->errorEncodingName, "binary") == 0) { encoding = ENCODING_BINARY; } else { #if (TCL_VERSION_NUMBER >= _VERSION(8,1,0)) encoding = Tcl_GetEncoding(interp, bgPtr->errorEncodingName); if (encoding == NULL) { goto error; } #endif } } InitSink(bgPtr, &bgPtr->sink2, "stderr", encoding); outFdPtr = errFdPtr = (int *)NULL; #ifdef WIN32 if ((!bgPtr->detached) || (bgPtr->sink1.doneVar != NULL) || (bgPtr->sink1.updateVar != NULL) || (bgPtr->sink1.updateCmd != NULL)) { outFdPtr = &bgPtr->sink1.fd; } #else outFdPtr = &bgPtr->sink1.fd; #endif if ((bgPtr->sink2.doneVar != NULL) || (bgPtr->sink2.updateVar != NULL) || (bgPtr->sink2.updateCmd != NULL) || (bgPtr->sink2.echo)) { errFdPtr = &bgPtr->sink2.fd; } nProcs = Blt_CreatePipeline(interp, argc - i, argv + i, &pidPtr, (int *)NULL, outFdPtr, errFdPtr); if (nProcs < 0) { goto error; } bgPtr->procArr = pidPtr; bgPtr->nProcs = nProcs; if (bgPtr->sink1.fd == -1) { /* If output has been redirected, start polling immediately * for the exit status of each process. Normally, this is * done only after stdout has been closed by the last process, * but here stdout has been redirected. The default polling * interval is every 1 second. */ bgPtr->timerToken = Tcl_CreateTimerHandler(bgPtr->interval, TimerProc, bgPtr); } else if (CreateSinkHandler(bgPtr, &bgPtr->sink1, StdoutProc) != TCL_OK) { goto error; } if ((bgPtr->sink2.fd != -1) && (CreateSinkHandler(bgPtr, &bgPtr->sink2, StderrProc) != TCL_OK)) { goto error; } if (bgPtr->detached) { char string[200]; /* If detached, return a list of the child process ids instead * of the output of the pipeline. */ for (i = 0; i < nProcs; i++) { #ifdef WIN32 sprintf(string, "%u", (unsigned int)bgPtr->procArr[i].pid); #else sprintf(string, "%d", bgPtr->procArr[i]); #endif Tcl_AppendElement(interp, string); } } else { int exitCode; int done; bgPtr->exitCodePtr = &exitCode; bgPtr->donePtr = &done; exitCode = done = 0; while (!done) { Tcl_DoOneEvent(0); } DisableTriggers(bgPtr); if ((exitCode == 0) && (bgPtr->sink1.doneVar == NULL)) { unsigned char *data; size_t length; /* Return the output of the pipeline. */ GetSinkData(&bgPtr->sink1, &data, &length); #if (TCL_VERSION_NUMBER < _VERSION(8,1,0)) data[length] = '\0'; Tcl_SetResult(interp, data, TCL_VOLATILE); #else Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(data, length)); #endif } /* Clean up resources used. */ DestroyBackgroundInfo(bgPtr); if (exitCode != 0) { Tcl_AppendResult(interp, "child process exited abnormally", (char *)NULL); return TCL_ERROR; } } return TCL_OK; error: DisableTriggers(bgPtr); DestroyBackgroundInfo(bgPtr); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * Blt_BgexecInit -- * * This procedure is invoked to initialize the "bgexec" Tcl * command. See the user documentation for details on what it * does. * * Results: * None. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int Blt_BgexecInit(interp) Tcl_Interp *interp; { static Blt_CmdSpec cmdSpec = {"bgexec", BgexecCmd, }; if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) { return TCL_ERROR; } return TCL_OK; } #endif /* NO_BGEXEC */ blt-2.4z.orig/src/bltBind.c0100644000175000017500000004661307542177233014301 0ustar dokodoko/* * bltBind.c -- * * This module implements object binding procedures for the BLT * toolkit. * * Copyright 1998 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. */ #include "bltInt.h" #include "bltBind.h" static Tk_EventProc BindProc; /* * Binding table procedures. */ #define REPICK_IN_PROGRESS (1<<0) #define LEFT_GRABBED_ITEM (1<<1) #define ALL_BUTTONS_MASK \ (Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask) #ifndef VirtualEventMask #define VirtualEventMask (1L << 30) #endif #define ALL_VALID_EVENTS_MASK \ (ButtonMotionMask | Button1MotionMask | Button2MotionMask | \ Button3MotionMask | Button4MotionMask | Button5MotionMask | \ ButtonPressMask | ButtonReleaseMask | EnterWindowMask | \ LeaveWindowMask | KeyPressMask | KeyReleaseMask | \ PointerMotionMask | VirtualEventMask) static int buttonMasks[] = { 0, /* No buttons pressed */ Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask, }; /* * How to make drag&drop work? * * Right now we generate pseudo events within * button grab on an object. They're marked NotifyVirtual instead * of NotifyAncestor. A better solution: generate new-style * virtual <> <> <> events. * These virtual events don't have to exist as "real" event * sequences, like virtual events do now. */ /* *-------------------------------------------------------------- * * DoEvent -- * * This procedure is called to invoke binding processing * for a new event that is associated with the current item * for a legend. * * Results: * None. * * Side effects: * Depends on the bindings for the legend. A binding script * could delete an entry, so callers should protect themselves * with Tcl_Preserve and Tcl_Release. * *-------------------------------------------------------------- */ static void DoEvent(bindPtr, eventPtr, item, context) struct Blt_BindTableStruct *bindPtr; /* Binding information for widget in * which event occurred. */ XEvent *eventPtr; /* Real or simulated X event that * is to be processed. */ ClientData item; /* Item picked. */ ClientData context; /* Context of item. */ { Blt_List bindIds; int nIds; if ((bindPtr->tkwin == NULL) || (bindPtr->bindingTable == NULL)) { return; } if ((eventPtr->type == KeyPress) || (eventPtr->type == KeyRelease)) { item = bindPtr->focusItem; context = bindPtr->focusContext; } if (item == NULL) { return; } /* * Invoke the binding system. */ bindIds = Blt_ListCreate(BLT_ONE_WORD_KEYS); if (bindPtr->tagProc == NULL) { Blt_ListAppend(bindIds, (char *)Tk_GetUid("all"), 0); Blt_ListAppend(bindIds, (char *)item, 0); } else { (*bindPtr->tagProc) (bindPtr, item, context, bindIds); } nIds = Blt_ListGetLength(bindIds); if (nIds > 0) { ClientData *idArray; ClientData tags[32]; register Blt_ListNode node; idArray = tags; if (nIds >= 32) { idArray = Blt_Malloc(sizeof(ClientData) * nIds); } nIds = 0; for (node = Blt_ListFirstNode(bindIds); node != NULL; node = Blt_ListNextNode(node)) { idArray[nIds++] = (ClientData)Blt_ListGetKey(node); } Tk_BindEvent(bindPtr->bindingTable, eventPtr, bindPtr->tkwin, nIds, idArray); if (nIds >= 32) { Blt_Free(idArray); } } Blt_ListDestroy(bindIds); } /* *-------------------------------------------------------------- * * PickCurrentItem -- * * Find the topmost item in a legend that contains a given * location and mark the the current item. If the current * item has changed, generate a fake exit event on the old * current item and a fake enter event on the new current * item. * * Results: * None. * * Side effects: * The current item may change. If it does, then the commands * associated with item entry and exit could do just about * anything. A binding script could delete the legend, so * callers should protect themselves with Tcl_Preserve and * Tcl_Release. * *-------------------------------------------------------------- */ static void PickCurrentItem(bindPtr, eventPtr) struct Blt_BindTableStruct *bindPtr; /* Binding table information. */ XEvent *eventPtr; /* Event describing location of * mouse cursor. Must be EnterWindow, * LeaveWindow, ButtonRelease, or * MotionNotify. */ { int buttonDown; ClientData newItem; ClientData newContext; /* * Check whether or not a button is down. If so, we'll log entry * and exit into and out of the current item, but not entry into * any other item. This implements a form of grabbing equivalent * to what the X server does for windows. */ buttonDown = (bindPtr->state & ALL_BUTTONS_MASK); if (!buttonDown) { bindPtr->flags &= ~LEFT_GRABBED_ITEM; } /* * Save information about this event in the widget. The event in * the widget is used for two purposes: * * 1. Event bindings: if the current item changes, fake events are * generated to allow item-enter and item-leave bindings to trigger. * 2. Reselection: if the current item gets deleted, can use the * saved event to find a new current item. * Translate MotionNotify events into EnterNotify events, since that's * what gets reported to item handlers. */ if (eventPtr != &bindPtr->pickEvent) { if ((eventPtr->type == MotionNotify) || (eventPtr->type == ButtonRelease)) { bindPtr->pickEvent.xcrossing.type = EnterNotify; bindPtr->pickEvent.xcrossing.serial = eventPtr->xmotion.serial; bindPtr->pickEvent.xcrossing.send_event = eventPtr->xmotion.send_event; bindPtr->pickEvent.xcrossing.display = eventPtr->xmotion.display; bindPtr->pickEvent.xcrossing.window = eventPtr->xmotion.window; bindPtr->pickEvent.xcrossing.root = eventPtr->xmotion.root; bindPtr->pickEvent.xcrossing.subwindow = None; bindPtr->pickEvent.xcrossing.time = eventPtr->xmotion.time; bindPtr->pickEvent.xcrossing.x = eventPtr->xmotion.x; bindPtr->pickEvent.xcrossing.y = eventPtr->xmotion.y; bindPtr->pickEvent.xcrossing.x_root = eventPtr->xmotion.x_root; bindPtr->pickEvent.xcrossing.y_root = eventPtr->xmotion.y_root; bindPtr->pickEvent.xcrossing.mode = NotifyNormal; bindPtr->pickEvent.xcrossing.detail = NotifyNonlinear; bindPtr->pickEvent.xcrossing.same_screen = eventPtr->xmotion.same_screen; bindPtr->pickEvent.xcrossing.focus = False; bindPtr->pickEvent.xcrossing.state = eventPtr->xmotion.state; } else { bindPtr->pickEvent = *eventPtr; } } bindPtr->activePick = TRUE; /* * If this is a recursive call (there's already a partially completed * call pending on the stack; it's in the middle of processing a * Leave event handler for the old current item) then just return; * the pending call will do everything that's needed. */ if (bindPtr->flags & REPICK_IN_PROGRESS) { return; } /* * A LeaveNotify event automatically means that there's no current * item, so the check for closest item can be skipped. */ newContext = NULL; if (bindPtr->pickEvent.type != LeaveNotify) { int x, y; x = bindPtr->pickEvent.xcrossing.x; y = bindPtr->pickEvent.xcrossing.y; newItem = (*bindPtr->pickProc) (bindPtr->clientData, x, y, &newContext); } else { newItem = NULL; } if (((newItem == bindPtr->currentItem) && (newContext == bindPtr->currentContext)) && (!(bindPtr->flags & LEFT_GRABBED_ITEM))) { /* * Nothing to do: the current item hasn't changed. */ return; } #ifndef FULLY_SIMULATE_GRAB if (((newItem != bindPtr->currentItem) || (newContext != bindPtr->currentContext)) && (buttonDown)) { bindPtr->flags |= LEFT_GRABBED_ITEM; return; } #endif /* * Simulate a LeaveNotify event on the previous current item and * an EnterNotify event on the new current item. Remove the "current" * tag from the previous current item and place it on the new current * item. */ if ((bindPtr->currentItem != NULL) && ((newItem != bindPtr->currentItem) || (newContext != bindPtr->currentContext)) && !(bindPtr->flags & LEFT_GRABBED_ITEM)) { XEvent event; event = bindPtr->pickEvent; event.type = LeaveNotify; /* * If the event's detail happens to be NotifyInferior the * binding mechanism will discard the event. To be consistent, * always use NotifyAncestor. */ event.xcrossing.detail = NotifyAncestor; bindPtr->flags |= REPICK_IN_PROGRESS; DoEvent(bindPtr, &event, bindPtr->currentItem, bindPtr->currentContext); bindPtr->flags &= ~REPICK_IN_PROGRESS; /* * Note: during DoEvent above, it's possible that * bindPtr->newItem got reset to NULL because the * item was deleted. */ } if (((newItem != bindPtr->currentItem) || (newContext != bindPtr->currentContext)) && (buttonDown)) { XEvent event; bindPtr->flags |= LEFT_GRABBED_ITEM; event = bindPtr->pickEvent; if ((newItem != bindPtr->newItem) || (newContext != bindPtr->newContext)) { ClientData savedItem; ClientData savedContext; /* * Generate and events for objects during * button grabs. This isn't standard. But for example, it * allows one to provide balloon help on the individual * entries of the Hierbox widget. */ savedItem = bindPtr->currentItem; savedContext = bindPtr->currentContext; if (bindPtr->newItem != NULL) { event.type = LeaveNotify; event.xcrossing.detail = NotifyVirtual /* Ancestor */ ; bindPtr->currentItem = bindPtr->newItem; DoEvent(bindPtr, &event, bindPtr->newItem, bindPtr->newContext); } bindPtr->newItem = newItem; bindPtr->newContext = newContext; if (newItem != NULL) { event.type = EnterNotify; event.xcrossing.detail = NotifyVirtual /* Ancestor */ ; bindPtr->currentItem = newItem; DoEvent(bindPtr, &event, newItem, newContext); } bindPtr->currentItem = savedItem; bindPtr->currentContext = savedContext; } return; } /* * Special note: it's possible that * bindPtr->newItem == bindPtr->currentItem * here. This can happen, for example, if LEFT_GRABBED_ITEM was set. */ bindPtr->flags &= ~LEFT_GRABBED_ITEM; bindPtr->currentItem = bindPtr->newItem = newItem; bindPtr->currentContext = bindPtr->newContext = newContext; if (bindPtr->currentItem != NULL) { XEvent event; event = bindPtr->pickEvent; event.type = EnterNotify; event.xcrossing.detail = NotifyAncestor; DoEvent(bindPtr, &event, newItem, newContext); } } /* *-------------------------------------------------------------- * * BindProc -- * * This procedure is invoked by the Tk dispatcher to handle * events associated with bindings on items. * * Results: * None. * * Side effects: * Depends on the command invoked as part of the binding * (if there was any). * *-------------------------------------------------------------- */ static void BindProc(clientData, eventPtr) ClientData clientData; /* Pointer to widget structure. */ XEvent *eventPtr; /* Pointer to X event that just * happened. */ { struct Blt_BindTableStruct *bindPtr = clientData; int mask; Tcl_Preserve(bindPtr->clientData); /* * This code below keeps track of the current modifier state in * bindPtr->state. This information is used to defer repicks of * the current item while buttons are down. */ switch (eventPtr->type) { case ButtonPress: case ButtonRelease: mask = 0; if ((eventPtr->xbutton.button >= Button1) && (eventPtr->xbutton.button <= Button5)) { mask = buttonMasks[eventPtr->xbutton.button]; } /* * For button press events, repick the current item using the * button state before the event, then process the event. For * button release events, first process the event, then repick * the current item using the button state *after* the event * (the button has logically gone up before we change the * current item). */ if (eventPtr->type == ButtonPress) { /* * On a button press, first repick the current item using * the button state before the event, the process the event. */ bindPtr->state = eventPtr->xbutton.state; PickCurrentItem(bindPtr, eventPtr); bindPtr->state ^= mask; DoEvent(bindPtr, eventPtr, bindPtr->currentItem, bindPtr->currentContext); } else { /* * Button release: first process the event, with the button * still considered to be down. Then repick the current * item under the assumption that the button is no longer down. */ bindPtr->state = eventPtr->xbutton.state; DoEvent(bindPtr, eventPtr, bindPtr->currentItem, bindPtr->currentContext); eventPtr->xbutton.state ^= mask; bindPtr->state = eventPtr->xbutton.state; PickCurrentItem(bindPtr, eventPtr); eventPtr->xbutton.state ^= mask; } break; case EnterNotify: case LeaveNotify: bindPtr->state = eventPtr->xcrossing.state; PickCurrentItem(bindPtr, eventPtr); break; case MotionNotify: bindPtr->state = eventPtr->xmotion.state; PickCurrentItem(bindPtr, eventPtr); DoEvent(bindPtr, eventPtr, bindPtr->currentItem, bindPtr->currentContext); break; case KeyPress: case KeyRelease: bindPtr->state = eventPtr->xkey.state; PickCurrentItem(bindPtr, eventPtr); DoEvent(bindPtr, eventPtr, bindPtr->currentItem, bindPtr->currentContext); break; } Tcl_Release(bindPtr->clientData); } int Blt_ConfigureBindings(interp, bindPtr, item, argc, argv) Tcl_Interp *interp; struct Blt_BindTableStruct *bindPtr; ClientData item; int argc; char **argv; { char *command; unsigned long mask; char *seq; if (argc == 0) { Tk_GetAllBindings(interp, bindPtr->bindingTable, item); return TCL_OK; } if (argc == 1) { command = Tk_GetBinding(interp, bindPtr->bindingTable, item, argv[0]); if (command == NULL) { return TCL_ERROR; } Tcl_SetResult(interp, command, TCL_VOLATILE); return TCL_OK; } seq = argv[0]; command = argv[1]; if (command[0] == '\0') { return Tk_DeleteBinding(interp, bindPtr->bindingTable, item, seq); } if (command[0] == '+') { mask = Tk_CreateBinding(interp, bindPtr->bindingTable, item, seq, command + 1, TRUE); } else { mask = Tk_CreateBinding(interp, bindPtr->bindingTable, item, seq, command, FALSE); } if (mask == 0) { return TCL_ERROR; } if (mask & (unsigned)~ALL_VALID_EVENTS_MASK) { Tk_DeleteBinding(interp, bindPtr->bindingTable, item, seq); Tcl_ResetResult(interp); Tcl_AppendResult(interp, "requested illegal events; ", "only key, button, motion, enter, leave, and virtual ", "events may be used", (char *)NULL); return TCL_ERROR; } return TCL_OK; } #if (TCL_MAJOR_VERSION >= 8) int Blt_ConfigureBindingsFromObj(interp, bindPtr, item, objc, objv) Tcl_Interp *interp; struct Blt_BindTableStruct *bindPtr; ClientData item; int objc; Tcl_Obj *CONST *objv; { char *command; unsigned long mask; char *seq; char *string; if (objc == 0) { Tk_GetAllBindings(interp, bindPtr->bindingTable, item); return TCL_OK; } string = Tcl_GetString(objv[0]); if (objc == 1) { command = Tk_GetBinding(interp, bindPtr->bindingTable, item, string); if (command == NULL) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, "invalid binding event \"", string, "\"", (char *)NULL); return TCL_ERROR; } Tcl_SetResult(interp, command, TCL_VOLATILE); return TCL_OK; } seq = string; command = Tcl_GetString(objv[1]); if (command[0] == '\0') { return Tk_DeleteBinding(interp, bindPtr->bindingTable, item, seq); } if (command[0] == '+') { mask = Tk_CreateBinding(interp, bindPtr->bindingTable, item, seq, command + 1, TRUE); } else { mask = Tk_CreateBinding(interp, bindPtr->bindingTable, item, seq, command, FALSE); } if (mask == 0) { return TCL_ERROR; } if (mask & (unsigned)~ALL_VALID_EVENTS_MASK) { Tk_DeleteBinding(interp, bindPtr->bindingTable, item, seq); Tcl_ResetResult(interp); Tcl_AppendResult(interp, "requested illegal events; ", "only key, button, motion, enter, leave, and virtual ", "events may be used", (char *)NULL); return TCL_ERROR; } return TCL_OK; } #endif Blt_BindTable Blt_CreateBindingTable(interp, tkwin, clientData, pickProc, tagProc) Tcl_Interp *interp; Tk_Window tkwin; ClientData clientData; Blt_BindPickProc *pickProc; Blt_BindTagProc *tagProc; { unsigned int mask; struct Blt_BindTableStruct *bindPtr; bindPtr = Blt_Calloc(1, sizeof(struct Blt_BindTableStruct)); assert(bindPtr); bindPtr->clientData = clientData; bindPtr->pickProc = pickProc; bindPtr->tagProc = tagProc; bindPtr->tkwin = tkwin; bindPtr->bindingTable = Tk_CreateBindingTable(interp); mask = (KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask); Tk_CreateEventHandler(tkwin, mask, BindProc, bindPtr); return bindPtr; } void Blt_DestroyBindingTable(bindPtr) struct Blt_BindTableStruct *bindPtr; { unsigned int mask; Tk_DeleteBindingTable(bindPtr->bindingTable); mask = (KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask); Tk_DeleteEventHandler(bindPtr->tkwin, mask, BindProc, bindPtr); Blt_Free(bindPtr); } void Blt_PickCurrentItem(bindPtr) struct Blt_BindTableStruct *bindPtr; { if (bindPtr->activePick) { PickCurrentItem(bindPtr, &(bindPtr->pickEvent)); } } void Blt_DeleteBindings(bindPtr, object) struct Blt_BindTableStruct *bindPtr; ClientData object; { Tk_DeleteAllBindings(bindPtr->bindingTable, object); /* * If this is the object currently picked, we need to repick one. */ if (bindPtr->currentItem == object) { bindPtr->currentItem = NULL; bindPtr->currentContext = NULL; } if (bindPtr->newItem == object) { bindPtr->newItem = NULL; bindPtr->newContext = NULL; } if (bindPtr->focusItem == object) { bindPtr->focusItem = NULL; bindPtr->focusContext = NULL; } } void Blt_MoveBindingTable(bindPtr, tkwin) struct Blt_BindTableStruct *bindPtr; Tk_Window tkwin; { unsigned int mask; mask = (KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask); if (bindPtr->tkwin != NULL) { Tk_DeleteEventHandler(bindPtr->tkwin, mask, BindProc, bindPtr); } Tk_CreateEventHandler(tkwin, mask, BindProc, bindPtr); bindPtr->tkwin = tkwin; } blt-2.4z.orig/src/bltBind.h0100644000175000017500000001061407511407605014271 0ustar dokodoko/* * bltBind.h -- * * Copyright 1993-1998 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. */ #ifndef _BLT_BIND_H #define _BLT_BIND_H #include typedef struct Blt_BindTableStruct *Blt_BindTable; typedef ClientData (Blt_BindPickProc) _ANSI_ARGS_((ClientData clientData, int x, int y, ClientData *contextPtr)); typedef void (Blt_BindTagProc) _ANSI_ARGS_((Blt_BindTable bindTable, ClientData object, ClientData context, Blt_List list)); /* * Binding structure information: */ struct Blt_BindTableStruct { unsigned int flags; Tk_BindingTable bindingTable; /* Table of all bindings currently defined. * NULL means that no bindings exist, so the * table hasn't been created. Each "object" * used for this table is either a Tk_Uid for * a tag or the address of an item named by * id. */ ClientData currentItem; /* The item currently containing the mouse * pointer, or NULL if none. */ ClientData currentContext; /* One word indicating what kind of object * was picked. */ ClientData newItem; /* The item that is about to become the * current one, or NULL. This field is * used to detect deletions of the new * current item pointer that occur during * Leave processing of the previous current * tab. */ ClientData newContext; /* One-word indicating what kind of object * was just picked. */ ClientData focusItem; ClientData focusContext; XEvent pickEvent; /* The event upon which the current choice * of the current tab is based. Must be saved * so that if the current item is deleted, * we can pick another. */ int activePick; /* The pick event has been initialized so * that we can repick it */ int state; /* Last known modifier state. Used to * defer picking a new current object * while buttons are down. */ ClientData clientData; Tk_Window tkwin; Blt_BindPickProc *pickProc; /* Routine to report the item the mouse is * currently over. */ Blt_BindTagProc *tagProc; /* Routine to report tags picked items. */ }; EXTERN void Blt_DestroyBindingTable _ANSI_ARGS_((Blt_BindTable table)); EXTERN Blt_BindTable Blt_CreateBindingTable _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, ClientData clientData, Blt_BindPickProc *pickProc, Blt_BindTagProc *tagProc)); EXTERN int Blt_ConfigureBindings _ANSI_ARGS_((Tcl_Interp *interp, Blt_BindTable table, ClientData item, int argc, char **argv)); #if (TCL_MAJOR_VERSION >= 8) EXTERN int Blt_ConfigureBindingsFromObj _ANSI_ARGS_((Tcl_Interp *interp, Blt_BindTable table, ClientData item, int objc, Tcl_Obj *CONST *objv)); #endif EXTERN void Blt_PickCurrentItem _ANSI_ARGS_((Blt_BindTable table)); EXTERN void Blt_DeleteBindings _ANSI_ARGS_((Blt_BindTable table, ClientData object)); EXTERN void Blt_MoveBindingTable _ANSI_ARGS_((Blt_BindTable table, Tk_Window tkwin)); #define Blt_SetFocusItem(bindPtr, object, context) \ ((bindPtr)->focusItem = (ClientData)(object),\ (bindPtr)->focusContext = (ClientData)(context)) #define Blt_SetCurrentItem(bindPtr, object, context) \ ((bindPtr)->currentItem = (ClientData)(object),\ (bindPtr)->currentContext = (ClientData)(context)) #define Blt_GetCurrentItem(bindPtr) ((bindPtr)->currentItem) #define Blt_GetCurrentContext(bindPtr) ((bindPtr)->currentContext) #define Blt_GetLatestItem(bindPtr) ((bindPtr)->newItem) #define Blt_GetBindingData(bindPtr) ((bindPtr)->clientData) #endif /*_BLT_BIND_H*/ blt-2.4z.orig/src/bltBitmap.c0100644000175000017500000012433007526260716014633 0ustar dokodoko /* * bltBitmap.c -- * * This module implements Tcl bitmaps for the Tk toolkit. * * Much of the code is taken from XRdBitF.c and XWrBitF.c * from the MIT X11R5 distribution. * * Copyright, 1987, Massachusetts Institute of Technology Permission * to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation, and that the name of M.I.T. not be * used in advertising or publicity pertaining to distribution of the * software without specific, written prior permission. M.I.T. makes * no representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied * warranty. * * Copyright 1993-1998 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. * * The "bitmap" command created by George Howlett. */ /* Predefined table holds bitmap info (source width, height) Name table holds bitmap names Id table hold bitmap ids Both id and name tables get you the actual bitmap. */ #include "bltInt.h" #ifndef NO_BITMAP #include "bltHash.h" #include #define BITMAP_THREAD_KEY "BLT Bitmap Data" /* * BitmapInterpData -- * * Tk's routine to create a bitmap, Tk_DefineBitmap, assumes that * the source (bit array) is always statically allocated. This * isn't true here (we dynamically allocate the arrays), so we have * to save them in a hashtable and cleanup after the interpreter * is deleted. */ typedef struct { Blt_HashTable bitmapTable; /* Hash table of bitmap data keyed by * the name of the bitmap. */ Tcl_Interp *interp; Display *display; /* Display of interpreter. */ Tk_Window tkwin; /* Main window of interpreter. */ } BitmapInterpData; #define MAX_SIZE 255 /* * BitmapInfo -- */ typedef struct { double rotate; /* Rotation of text string */ double scale; /* Scaling factor */ Tk_Font font; /* Font pointer */ Tk_Justify justify; /* Justify text */ Blt_Pad padX, padY; /* Padding around the text */ } BitmapInfo; /* * BitmapData -- */ typedef struct { int width, height; /* Dimension of image */ unsigned char *bits; /* Data array for bitmap image */ int arraySize; /* Number of bytes in data array */ } BitmapData; #define DEF_BITMAP_FONT STD_FONT #define DEF_BITMAP_PAD "4" #define DEF_BITMAP_ROTATE "0.0" #define DEF_BITMAP_SCALE "1.0" #define DEF_BITMAP_JUSTIFY "center" #define ROTATE_0 0 #define ROTATE_90 1 #define ROTATE_180 2 #define ROTATE_270 3 extern Tk_CustomOption bltPadOption; static Tk_ConfigSpec composeConfigSpecs[] = { {TK_CONFIG_FONT, "-font", (char *)NULL, (char *)NULL, DEF_BITMAP_FONT, Tk_Offset(BitmapInfo, font), 0}, {TK_CONFIG_JUSTIFY, "-justify", (char *)NULL, (char *)NULL, DEF_BITMAP_JUSTIFY, Tk_Offset(BitmapInfo, justify), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-padx", (char *)NULL, (char *)NULL, DEF_BITMAP_PAD, Tk_Offset(BitmapInfo, padX), TK_CONFIG_DONT_SET_DEFAULT, &bltPadOption}, {TK_CONFIG_CUSTOM, "-pady", (char *)NULL, (char *)NULL, DEF_BITMAP_PAD, Tk_Offset(BitmapInfo, padY), TK_CONFIG_DONT_SET_DEFAULT, &bltPadOption}, {TK_CONFIG_DOUBLE, "-rotate", (char *)NULL, (char *)NULL, DEF_BITMAP_ROTATE, Tk_Offset(BitmapInfo, rotate), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_DOUBLE, "-scale", (char *)NULL, (char *)NULL, DEF_BITMAP_SCALE, Tk_Offset(BitmapInfo, scale), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; static Tk_ConfigSpec defineConfigSpecs[] = { {TK_CONFIG_DOUBLE, "-rotate", (char *)NULL, (char *)NULL, DEF_BITMAP_ROTATE, Tk_Offset(BitmapInfo, rotate), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_DOUBLE, "-scale", (char *)NULL, (char *)NULL, DEF_BITMAP_SCALE, Tk_Offset(BitmapInfo, scale), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; /* Shared data for the image read/parse logic */ static char hexTable[256]; /* conversion value */ static int initialized = 0; /* easier to fill in at run time */ #define blt_width 40 #define blt_height 40 static unsigned char blt_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x03, 0x00, 0x04, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x02, 0x00, 0xe4, 0x33, 0x3f, 0x01, 0x00, 0x64, 0x36, 0x0c, 0x01, 0x00, 0x64, 0x36, 0x8c, 0x00, 0x00, 0xe4, 0x33, 0x8c, 0x00, 0x00, 0x64, 0x36, 0x8c, 0x00, 0x00, 0x64, 0x36, 0x0c, 0x01, 0x00, 0xe4, 0xf3, 0x0d, 0x01, 0x00, 0x04, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x02, 0x00, 0xfc, 0xff, 0xff, 0x03, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xf8, 0xff, 0x03, 0x80, 0xed, 0x07, 0x00, 0x04, 0xe0, 0x0c, 0x00, 0x20, 0x09, 0x10, 0x0c, 0x00, 0x00, 0x12, 0x10, 0x0c, 0x00, 0x00, 0x10, 0x30, 0x00, 0x00, 0x00, 0x19, 0xd0, 0x03, 0x00, 0x00, 0x14, 0xb0, 0xfe, 0xff, 0xff, 0x1b, 0x50, 0x55, 0x55, 0x55, 0x0d, 0xe8, 0xaa, 0xaa, 0xaa, 0x16, 0xe4, 0xff, 0xff, 0xff, 0x2f, 0xf4, 0xff, 0xff, 0xff, 0x27, 0xd8, 0xae, 0xaa, 0xbd, 0x2d, 0x6c, 0x5f, 0xd5, 0x67, 0x1b, 0xbc, 0xf3, 0x7f, 0xd0, 0x36, 0xf8, 0x01, 0x10, 0xcc, 0x1f, 0xe0, 0x45, 0x8e, 0x92, 0x0f, 0xb0, 0x32, 0x41, 0x43, 0x0b, 0xd0, 0xcf, 0x3c, 0x7c, 0x0d, 0xb0, 0xaa, 0xc2, 0xab, 0x0a, 0x60, 0x55, 0x55, 0x55, 0x05, 0xc0, 0xff, 0xab, 0xaa, 0x03, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #define bigblt_width 64 #define bigblt_height 64 static unsigned char bigblt_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xe2, 0x0f, 0xc7, 0xff, 0x10, 0x00, 0x00, 0x00, 0xe2, 0x1f, 0xc7, 0xff, 0x10, 0x00, 0x00, 0x00, 0xe2, 0x38, 0x07, 0x1c, 0x08, 0x00, 0x00, 0x00, 0xe2, 0x38, 0x07, 0x1c, 0x08, 0x00, 0x00, 0x00, 0xe2, 0x38, 0x07, 0x1c, 0x08, 0x00, 0x00, 0x00, 0xe2, 0x1f, 0x07, 0x1c, 0x04, 0x00, 0x00, 0x00, 0xe2, 0x1f, 0x07, 0x1c, 0x04, 0x00, 0x00, 0x00, 0xe2, 0x38, 0x07, 0x1c, 0x08, 0x00, 0x00, 0x00, 0xe2, 0x38, 0x07, 0x1c, 0x08, 0x00, 0x00, 0x00, 0xe2, 0x38, 0x07, 0x1c, 0x08, 0x00, 0x00, 0x00, 0xe2, 0x1f, 0xff, 0x1c, 0x10, 0x00, 0x00, 0x00, 0xe2, 0x0f, 0xff, 0x1c, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0xc0, 0xff, 0xff, 0x07, 0x00, 0x00, 0xe0, 0xf6, 0x3f, 0x00, 0x00, 0x38, 0x00, 0x00, 0x1c, 0x06, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x80, 0x03, 0x06, 0x00, 0x00, 0xc0, 0x08, 0x03, 0x40, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x04, 0x40, 0x00, 0x06, 0x00, 0x00, 0x00, 0x40, 0x04, 0x40, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x04, 0x40, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x40, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x06, 0x40, 0x55, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x05, 0x80, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x06, 0x80, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x03, 0x40, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x01, 0x70, 0x57, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x04, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0b, 0xd8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x14, 0xd0, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0xf0, 0xda, 0xbf, 0xaa, 0xba, 0xfd, 0xd6, 0x0b, 0x70, 0xed, 0x77, 0x55, 0x57, 0xe5, 0xad, 0x07, 0xb8, 0xf7, 0xab, 0xaa, 0xaa, 0xd2, 0x5b, 0x0f, 0xf8, 0xfb, 0x54, 0x55, 0x75, 0x94, 0xf7, 0x1e, 0xf0, 0x7b, 0xfa, 0xff, 0x9f, 0xa9, 0xef, 0x1f, 0xc0, 0xbf, 0x00, 0x20, 0x40, 0x54, 0xfe, 0x0f, 0x00, 0x1f, 0x92, 0x00, 0x04, 0xa9, 0xfc, 0x01, 0xc0, 0x5f, 0x41, 0xf9, 0x04, 0x21, 0xfd, 0x00, 0xc0, 0x9b, 0x28, 0x04, 0xd8, 0x0a, 0x9a, 0x03, 0x40, 0x5d, 0x08, 0x40, 0x44, 0x44, 0x62, 0x03, 0xc0, 0xaa, 0x67, 0xe2, 0x03, 0x64, 0xba, 0x02, 0x40, 0x55, 0xd5, 0x55, 0xfd, 0xdb, 0x55, 0x03, 0x80, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x01, 0x00, 0x57, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x00, 0x00, 0xac, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x00, 0x00, 0xf0, 0xff, 0x57, 0x55, 0x55, 0x1d, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static Tcl_CmdProc BitmapCmd; static Tcl_InterpDeleteProc BitmapInterpDeleteProc; /* * ----------------------------------------------------------------------- * * GetHexValue -- * * Converts the hexadecimal string into an unsigned integer * value. The hexadecimal string need not have a leading "0x". * * Results: * Returns a standard TCL result. If the conversion was * successful, TCL_OK is returned, otherwise TCL_ERROR. * * Side Effects: * If the conversion fails, interp->result is filled with an * error message. * * ----------------------------------------------------------------------- */ static int GetHexValue(interp, string, valuePtr) Tcl_Interp *interp; char *string; int *valuePtr; { register int c; register char *s; register int value; s = string; if ((s[0] == '0') && ((s[1] == 'x') || (s[1] == 'X'))) { s += 2; } if (s[0] == '\0') { Tcl_AppendResult(interp, "expecting hex value: got \"", string, "\"", (char *)NULL); return TCL_ERROR; /* Only found "0x" */ } value = 0; for ( /*empty*/ ; *s != '\0'; s++) { /* Trim high bits, check type and accumulate */ c = *s & 0xff; if (!isxdigit(c)) { Tcl_AppendResult(interp, "expecting hex value: got \"", string, "\"", (char *)NULL); return TCL_ERROR; /* Not a hexadecimal number */ } value = (value << 4) + hexTable[c]; } *valuePtr = value; return TCL_OK; } #ifdef WIN32 /* * ----------------------------------------------------------------------- * * BitmapToData -- * * Converts a bitmap into an data array. * * Results: * Returns the number of bytes in an data array representing the bitmap. * * Side Effects: * Memory is allocated for the data array. Caller must free * array later. * * ----------------------------------------------------------------------- */ static int BitmapToData( Tk_Window tkwin, /* Main window of interpreter */ Pixmap bitmap, /* Bitmap to be queried */ int width, int height, /* Dimensions of the bitmap */ unsigned char **bitsPtr) /* Pointer to converted array of data */ { int value, bitMask; unsigned long pixel; register int x, y; int count; int arraySize, bytes_per_line; unsigned char *bits; unsigned char *srcPtr, *srcBits; int bytesPerRow; *bitsPtr = NULL; srcBits = Blt_GetBitmapData(Tk_Display(tkwin), bitmap, width, height, &bytesPerRow); if (srcBits == NULL) { OutputDebugString("BitmapToData: Can't get bitmap data"); return 0; } bytes_per_line = (width + 7) / 8; arraySize = height * bytes_per_line; bits = Blt_Malloc(sizeof(unsigned char) * arraySize); assert(bits); count = 0; for (y = height - 1; y >= 0; y--) { srcPtr = srcBits + (bytesPerRow * y); value = 0, bitMask = 1; for (x = 0; x < width; /* empty */ ) { pixel = (*srcPtr & (0x80 >> (x % 8))); if (pixel) { value |= bitMask; } bitMask <<= 1; x++; if (!(x & 7)) { bits[count++] = (unsigned char)value; value = 0, bitMask = 1; srcPtr++; } } if (x & 7) { bits[count++] = (unsigned char)value; } } *bitsPtr = bits; return count; } #else /* * ----------------------------------------------------------------------- * * BitmapToData -- * * Converts a bitmap into an data array. * * Results: * Returns the number of bytes in an data array representing the bitmap. * * Side Effects: * Memory is allocated for the data array. Caller must free * array later. * * ----------------------------------------------------------------------- */ static int BitmapToData(tkwin, bitmap, width, height, bitsPtr) Tk_Window tkwin; /* Main window of interpreter */ Pixmap bitmap; /* Bitmap to be queried */ int width, height; /* Dimensions of the bitmap */ unsigned char **bitsPtr; /* Pointer to converted array of data */ { int value, bitMask; unsigned long pixel; register int x, y; int count; int arraySize, bytes_per_line; Display *display; XImage *imagePtr; unsigned char *bits; display = Tk_Display(tkwin); /* Convert the bitmap to an image */ imagePtr = XGetImage(display, bitmap, 0, 0, width, height, 1L, XYPixmap); /* * The slow but robust brute force method of converting an image: */ bytes_per_line = (width + 7) / 8; arraySize = height * bytes_per_line; bits = Blt_Malloc(sizeof(unsigned char) * arraySize); assert(bits); count = 0; for (y = 0; y < height; y++) { value = 0, bitMask = 1; for (x = 0; x < width; /*empty*/ ) { pixel = XGetPixel(imagePtr, x, y); if (pixel) { value |= bitMask; } bitMask <<= 1; x++; if (!(x & 7)) { bits[count++] = (unsigned char)value; value = 0, bitMask = 1; } } if (x & 7) { bits[count++] = (unsigned char)value; } } XDestroyImage(imagePtr); *bitsPtr = bits; return count; } #endif /* * ----------------------------------------------------------------------- * * AsciiToData -- * * Converts a Tcl list of ASCII values into a data array. * * Results: * A standard TCL result. * * Side Effects: * If an error occurs while processing the data, interp->result * is filled with a corresponding error message. * * ----------------------------------------------------------------------- */ static int AsciiToData(interp, elemList, width, height, bitsPtr) Tcl_Interp *interp; /* Interpreter to report results to */ char *elemList; /* List of of hex numbers representing * bitmap data */ int width, height; /* Height and width */ unsigned char **bitsPtr; /* data array (output) */ { int arraySize; /* Number of bytes of data */ int value; /* from an input line */ int padding; /* to handle alignment */ int bytesPerLine; /* per scanline of data */ unsigned char *bits; register int count; enum Formats { V10, V11 } format; register int i; /* */ char **valueArr; int nValues; /* First time through initialize the ascii->hex translation table */ if (!initialized) { Blt_InitHexTable(hexTable); initialized = 1; } if (Tcl_SplitList(interp, elemList, &nValues, &valueArr) != TCL_OK) { return -1; } bytesPerLine = (width + 7) / 8; arraySize = bytesPerLine * height; if (nValues == arraySize) { format = V11; } else if (nValues == (arraySize / 2)) { format = V10; } else { Tcl_AppendResult(interp, "bitmap has wrong # of data values", (char *)NULL); goto error; } padding = 0; if (format == V10) { padding = ((width % 16) && ((width % 16) < 9)); if (padding) { bytesPerLine = (width + 7) / 8 + padding; arraySize = bytesPerLine * height; } } bits = Blt_Calloc(sizeof(unsigned char), arraySize); if (bits == NULL) { Tcl_AppendResult(interp, "can't allocate memory for bitmap", (char *)NULL); goto error; } count = 0; for (i = 0; i < nValues; i++) { if (GetHexValue(interp, valueArr[i], &value) != TCL_OK) { Blt_Free(bits); goto error; } bits[count++] = (unsigned char)value; if (format == V10) { if ((!padding) || (((i * 2) + 2) % bytesPerLine)) { bits[count++] = value >> 8; } } } Blt_Free(valueArr); *bitsPtr = bits; return count; error: Blt_Free(valueArr); return -1; } static int ParseListData(interp, string, widthPtr, heightPtr, bitsPtr) Tcl_Interp *interp; char *string; int *widthPtr; int *heightPtr; unsigned char **bitsPtr; { register char *p; char **elemArr; int nElem; int width, height; int result; int arraySize; arraySize = -1; if (Tcl_SplitList(interp, string, &nElem, &elemArr) != TCL_OK) { return -1; } if (nElem == 2) { char **dimArr; int nDim; if (Tcl_SplitList(interp, elemArr[0], &nDim, &dimArr) != TCL_OK) { goto error; } if (nDim != 2) { Tcl_AppendResult(interp, "wrong # of bitmap dimensions: ", "should be \"width height\"", (char *)NULL); result = TCL_ERROR; } else { result = ((Tcl_GetInt(interp, dimArr[0], &width) == TCL_OK) && (Tcl_GetInt(interp, dimArr[1], &height) == TCL_OK)); } Blt_Free(dimArr); if (!result) { goto error; } string = elemArr[1]; } else if (nElem == 3) { if ((Tcl_GetInt(interp, elemArr[0], &width) != TCL_OK) || (Tcl_GetInt(interp, elemArr[1], &height) != TCL_OK)) { goto error; } string = elemArr[2]; } else { Tcl_AppendResult(interp, "wrong # of bitmap data components: ", "should be \"dimensions sourceData\"", (char *)NULL); goto error; } if ((width < 1) || (height < 1)) { Tcl_AppendResult(interp, "bad bitmap dimensions", (char *)NULL); goto error; } /* Convert commas to blank spaces */ for (p = string; *p != '\0'; p++) { if (*p == ',') { *p = ' '; } } arraySize = AsciiToData(interp, string, width, height, bitsPtr); *widthPtr = width; *heightPtr = height; error: Blt_Free(elemArr); return arraySize; } /* * Parse the lines that define the dimensions of the bitmap, * plus the first line that defines the bitmap data (it declares * the name of a data variable but doesn't include any actual * data). These lines look something like the following: * * #define foo_width 16 * #define foo_height 16 * #define foo_x_hot 3 * #define foo_y_hot 3 * static char foo_bits[] = { * * The x_hot and y_hot lines may or may not be present. It's * important to check for "char" in the last line, in order to * reject old X10-style bitmaps that used shorts. */ static int ParseStructData(interp, string, widthPtr, heightPtr, bitsPtr) Tcl_Interp *interp; char *string; int *widthPtr; int *heightPtr; unsigned char **bitsPtr; { int width, height; int hotX, hotY; char *line, *nextline; register char *p; Tcl_RegExp re; char *name, *value, *data; int len; int arraySize; width = height = 0; hotX = hotY = -1; data = NULL; nextline = string; for (line = string; nextline != NULL; line = nextline + 1) { nextline = strchr(line, '\n'); if ((nextline == NULL) || (line == nextline)) { continue; /* Empty line */ } *nextline = '\0'; re = Tcl_RegExpCompile(interp, " *# *define +"); if (Tcl_RegExpExec(interp, re, line, line)) { char *start, *end; Tcl_RegExpRange(re, 0, &start, &end); name = strtok(end, " \t"); value = strtok(NULL, " \t"); if ((name == NULL) || (value == NULL)) { return TCL_ERROR; } len = strlen(name); if ((len >= 6) && (name[len-6] == '_') && (strcmp(name+len-6, "_width") == 0)) { if (Tcl_GetInt(interp, value, &width) != TCL_OK) { return -1; } } else if ((len >= 7) && (name[len-7] == '_') && (strcmp(name+len-7, "_height") == 0)) { if (Tcl_GetInt(interp, value, &height) != TCL_OK) { return -1; } } else if ((len >= 6) && (name[len-6] == '_') && (strcmp(name+len-6, "_x_hot") == 0)) { if (Tcl_GetInt(interp, value, &hotX) != TCL_OK) { return -1; } } else if ((len >= 6) && (name[len-6] == '_') && (strcmp(name+len-6, "_y_hot") == 0)) { if (Tcl_GetInt(interp, value, &hotY) != TCL_OK) { return -1; } } } else { re = Tcl_RegExpCompile(interp, " *static +.*char +"); if (Tcl_RegExpExec(interp, re, line, line)) { /* Find the { */ /* Repair the string so we can search the entire string. */ *nextline = ' '; p = strchr(line, '{'); if (p == NULL) { return -1; } data = p + 1; break; } else { Tcl_AppendResult(interp, "unknown bitmap format: ", "obsolete X10 bitmap file?", (char *) NULL); return -1; } } } /* * Now we've read everything but the data. Allocate an array * and read in the data. */ if ((width <= 0) || (height <= 0)) { Tcl_AppendResult(interp, "invalid bitmap dimensions \"", (char *)NULL); Tcl_AppendResult(interp, Blt_Itoa(width), " x ", (char *)NULL); Tcl_AppendResult(interp, Blt_Itoa(height), "\"", (char *)NULL); return -1; } *widthPtr = width; *heightPtr = height; for (p = data; *p != '\0'; p++) { if ((*p == ',') || (*p == ';') || (*p == '}')) { *p = ' '; } } arraySize = AsciiToData(interp, data, width, height, bitsPtr); return arraySize; } /* * ----------------------------------------------------------------------- * * ScaleRotateData -- * * Creates a new data array of the rotated and scaled bitmap. * * Results: * A standard Tcl result. If the bitmap data is rotated * successfully, TCL_OK is returned. But if memory could not be * allocated for the new data array, TCL_ERROR is returned and an * error message is left in interp->result. * * Side Effects: * Memory is allocated for rotated, scaled data array. Caller * must free array later. * * ----------------------------------------------------------------------- */ static int ScaleRotateData( Tcl_Interp *interp, /* Interpreter to report results to */ BitmapData *srcPtr, /* Source bitmap to transform. */ double theta, /* Number of degrees to rotate the bitmap. */ double scale, /* Factor to scale the bitmap. */ BitmapData *destPtr) /* Destination bitmap. */ { register int x, y, sx, sy; double srcX, srcY, destX, destY; /* Origins of source and destination * bitmaps */ double dx, dy; double sinTheta, cosTheta; double rotWidth, rotHeight; double radians; unsigned char *bits; int arraySize; int pixel, ipixel; int srcBytesPerLine, destBytesPerLine; srcBytesPerLine = (srcPtr->width + 7) / 8; Blt_GetBoundingBox(srcPtr->width, srcPtr->height, theta, &rotWidth, &rotHeight, (Point2D *)NULL); destPtr->width = (int)(rotWidth * scale + 0.5) ; destPtr->height = (int)(rotHeight * scale + 0.5); destBytesPerLine = (destPtr->width + 7) / 8; arraySize = destPtr->height * destBytesPerLine; bits = Blt_Calloc(arraySize, sizeof(unsigned char)); if (bits == NULL) { Tcl_AppendResult(interp, "can't allocate bitmap data array", (char *)NULL); return TCL_ERROR; } scale = 1.0 / scale; destPtr->bits = bits; destPtr->arraySize = arraySize; radians = (theta / 180.0) * M_PI; sinTheta = sin(radians); cosTheta = cos(radians); /* * Coordinates of the centers of the source and destination rectangles */ srcX = srcPtr->width * 0.5; srcY = srcPtr->height * 0.5; destX = rotWidth * 0.5; destY = rotHeight * 0.5; /* * Rotate each pixel of dest image, placing results in source image */ for (y = 0; y < destPtr->height; y++) { for (x = 0; x < destPtr->width; x++) { dx = scale * (double)x; dy = scale * (double)y; if (theta == 270.0) { sx = (int)dy, sy = (int)(rotWidth - dx) - 1; } else if (theta == 180.0) { sx = (int)(rotWidth - dx) - 1, sy = (int)(rotHeight - dy) - 1; } else if (theta == 90.0) { sx = (int)(rotHeight - dy) - 1, sy = (int)dx; } else if (theta == 0.0) { sx = (int)dx, sy = (int)dy; } else { double transX, transY, rotX, rotY; /* Translate origin to center of destination image */ transX = dx - destX; transY = dy - destY; /* Rotate the coordinates about the origin */ rotX = (transX * cosTheta) - (transY * sinTheta); rotY = (transX * sinTheta) + (transY * cosTheta); /* Translate back to the center of the source image */ rotX += srcX; rotY += srcY; sx = ROUND(rotX); sy = ROUND(rotY); /* * Verify the coordinates, since the destination image * can be bigger than the source. */ if ((sx >= srcPtr->width) || (sx < 0) || (sy >= srcPtr->height) || (sy < 0)) { continue; } } ipixel = (srcBytesPerLine * sy) + (sx / 8); pixel = srcPtr->bits[ipixel] & (1 << (sx % 8)); if (pixel) { ipixel = (destBytesPerLine * y) + (x / 8); bits[ipixel] |= (1 << (x % 8)); } } } return TCL_OK; } /* * ----------------------------------------------------------------------- * * BitmapDataToString -- * * Returns a list of hex values corresponding to the data * bits of the bitmap given. * * Converts the unsigned character value into a two character * hexadecimal string. A separator is also added, which may * either a newline or space according the the number of bytes * already output. * * Results: * Returns TCL_ERROR if a data array can't be generated * from the bitmap (memory allocation failure), otherwise TCL_OK. * * ----------------------------------------------------------------------- */ static void BitmapDataToString(tkwin, bitmap, resultPtr) Tk_Window tkwin; /* Main window of interpreter */ Pixmap bitmap; /* Bitmap to be queried */ Tcl_DString *resultPtr; /* Dynamic string to output results to */ { unsigned char *bits; char *separator; int arraySize; register int i; char string[200]; int width, height; /* Get the dimensions of the bitmap */ Tk_SizeOfBitmap(Tk_Display(tkwin), bitmap, &width, &height); arraySize = BitmapToData(tkwin, bitmap, width, height, &bits); #define BYTES_PER_OUTPUT_LINE 24 for (i = 0; i < arraySize; i++) { separator = (i % BYTES_PER_OUTPUT_LINE) ? " " : "\n "; sprintf(string, "%s%02x", separator, bits[i]); Tcl_DStringAppend(resultPtr, string, -1); } if (bits != NULL) { Blt_Free(bits); } } /* *-------------------------------------------------------------- * * ComposeOp -- * * Converts the text string into an internal bitmap. * * There's a lot of extra (read unnecessary) work going on here, * but I don't (right now) think that it matters much. The * rotated bitmap (formerly an image) is converted back to an * image just so we can convert it to a data array for * Tk_DefineBitmap. * * Results: * A standard TCL result. * * Side Effects: * If an error occurs while processing the data, interp->result * is filled with a corresponding error message. * *-------------------------------------------------------------- */ static int ComposeOp(clientData, interp, argc, argv) ClientData clientData; /* Thread-specific data for bitmaps. */ Tcl_Interp *interp; /* Interpreter to report results to */ int argc; /* Number of arguments */ char **argv; /* Argument list */ { BitmapInterpData *dataPtr = clientData; int width, height; /* Dimensions of bitmap */ Pixmap bitmap; /* Text bitmap */ unsigned char *bits; /* Data array derived from text bitmap */ int arraySize; BitmapInfo info; /* Text rotation and font information */ int result; double theta; TextStyle ts; TextLayout *textPtr; Tk_Window tkwin; /* Main window of interpreter */ Blt_HashEntry *hPtr; int isNew; tkwin = dataPtr->tkwin; bitmap = Tk_GetBitmap(interp, tkwin, Tk_GetUid(argv[2])); Tcl_ResetResult(interp); if (bitmap != None) { Tk_FreeBitmap(dataPtr->display, bitmap); return TCL_OK; } /* Initialize info and process flags */ info.justify = TK_JUSTIFY_CENTER; info.rotate = 0.0; /* No rotation or scaling by default */ info.scale = 1.0; info.padLeft = info.padRight = 0; info.padTop = info.padBottom = 0; info.font = (Tk_Font)NULL; /* Initialized by Tk_ConfigureWidget */ if (Tk_ConfigureWidget(interp, tkwin, composeConfigSpecs, argc - 4, argv + 4, (char *)&info, 0) != TCL_OK) { return TCL_ERROR; } theta = FMOD(info.rotate, (double)360.0); if (theta < 0.0) { theta += 360.0; } Blt_InitTextStyle(&ts); ts.font = info.font; ts.theta = 0.0; ts.justify = info.justify; ts.padX = info.padX; ts.padY = info.padY; ts.leader = 0; ts.anchor = TK_ANCHOR_CENTER; textPtr = Blt_GetTextLayout(argv[3], &ts); bitmap = Blt_CreateTextBitmap(tkwin, textPtr, &ts, &width, &height); Blt_Free(textPtr); if (bitmap == None) { Tcl_AppendResult(interp, "can't create bitmap", (char *)NULL); return TCL_ERROR; } /* Free the font structure, since we don't need it anymore */ Tk_FreeOptions(composeConfigSpecs, (char *)&info, dataPtr->display, 0); /* Convert bitmap back to a data array */ arraySize = BitmapToData(tkwin, bitmap, width, height, &bits); Tk_FreePixmap(dataPtr->display, bitmap); if (arraySize == 0) { Tcl_AppendResult(interp, "can't get bitmap data", (char *)NULL); return TCL_ERROR; } /* If bitmap is to be rotated or scale, do it here */ if ((theta != 0.0) || (info.scale != 1.0)) { BitmapData srcData, destData; srcData.bits = bits; srcData.width = width; srcData.height = height; srcData.arraySize = arraySize; result = ScaleRotateData(interp, &srcData, theta, info.scale, &destData); Blt_Free(bits); /* Free the un-transformed data array. */ if (result != TCL_OK) { return TCL_ERROR; } bits = destData.bits; width = destData.width; height = destData.height; } /* Create the bitmap again, this time using Tk's bitmap facilities */ result = Tk_DefineBitmap(interp, Tk_GetUid(argv[2]), (char *)bits, width, height); if (result != TCL_OK) { Blt_Free(bits); } hPtr = Blt_CreateHashEntry(&(dataPtr->bitmapTable), argv[2], &isNew); Blt_SetHashValue(hPtr, bits); return result; } /* *-------------------------------------------------------------- * * DefineOp -- * * Converts the dataList into an internal bitmap. * * Results: * A standard TCL result. * * Side Effects: * If an error occurs while processing the data, interp->result * is filled with a corresponding error message. * *-------------------------------------------------------------- */ /* ARGSUSED */ static int DefineOp(clientData, interp, argc, argv) ClientData clientData; /* Thread-specific data for bitmaps. */ Tcl_Interp *interp; /* Interpreter to report results to */ int argc; /* Number of arguments */ char **argv; /* Argument list */ { BitmapInterpData *dataPtr = clientData; int width, height; /* Dimensions of bitmap */ unsigned char *bits; /* working variable */ register char *p; char *defn; /* Definition of bitmap. */ BitmapInfo info; /* Not used. */ int arraySize; int result; double theta; Pixmap bitmap; Blt_HashEntry *hPtr; int isNew; bitmap = Tk_GetBitmap(interp, dataPtr->tkwin, Tk_GetUid(argv[2])); Tcl_ResetResult(interp); if (bitmap != None) { Tk_FreeBitmap(dataPtr->display, bitmap); return TCL_OK; } /* Initialize info and then process flags */ info.rotate = 0.0; /* No rotation by default */ info.scale = 1.0; /* No scaling by default */ if (Tk_ConfigureWidget(interp, dataPtr->tkwin, defineConfigSpecs, argc - 4, argv + 4, (char *)&info, 0) != TCL_OK) { return TCL_ERROR; } /* Skip leading spaces. */ for (p = argv[3]; isspace(UCHAR(*p)); p++) { /*empty*/ } defn = Blt_Strdup(p); bits = NULL; if (*p == '#') { arraySize = ParseStructData(interp, defn, &width, &height, &bits); } else { arraySize = ParseListData(interp, defn, &width, &height, &bits); } Blt_Free(defn); if (arraySize <= 0) { return TCL_ERROR; } theta = FMOD(info.rotate, 360.0); if (theta < 0.0) { theta += 360.0; } /* If bitmap is to be rotated or scale, do it here */ if ((theta != 0.0) || (info.scale != 1.0)) { BitmapData srcData, destData; srcData.bits = bits; srcData.width = width; srcData.height = height; srcData.arraySize = arraySize; result = ScaleRotateData(interp, &srcData, theta, info.scale, &destData); Blt_Free(bits); /* Free the array of un-transformed data. */ if (result != TCL_OK) { return TCL_ERROR; } bits = destData.bits; width = destData.width; height = destData.height; } result = Tk_DefineBitmap(interp, Tk_GetUid(argv[2]), (char *)bits, width, height); if (result != TCL_OK) { Blt_Free(bits); } hPtr = Blt_CreateHashEntry(&(dataPtr->bitmapTable), argv[2], &isNew); Blt_SetHashValue(hPtr, bits); return result; } /* *-------------------------------------------------------------- * * ExistOp -- * * Indicates if the named bitmap exists. * *-------------------------------------------------------------- */ /*ARGSUSED*/ static int ExistsOp(clientData, interp, argc, argv) ClientData clientData; /* Thread-specific data for bitmaps. */ Tcl_Interp *interp; /* Interpreter to report results to */ int argc; /* Not used. */ char **argv; /* Argument list */ { BitmapInterpData *dataPtr = clientData; Pixmap bitmap; bitmap = Tk_GetBitmap(interp, dataPtr->tkwin, Tk_GetUid(argv[2])); Tcl_ResetResult(interp); if (bitmap != None) { Tk_FreeBitmap(dataPtr->display, bitmap); } Blt_SetBooleanResult(interp, (bitmap != None)); return TCL_OK; } /* *-------------------------------------------------------------- * * HeightOp -- * * Returns the height of the named bitmap. * *-------------------------------------------------------------- */ /*ARGSUSED*/ static int HeightOp(clientData, interp, argc, argv) ClientData clientData; /* Thread-specific data for bitmaps. */ Tcl_Interp *interp; /* Interpreter to report results to */ int argc; /* Not used. */ char **argv; /* Argument list */ { BitmapInterpData *dataPtr = clientData; int width, height; Pixmap bitmap; bitmap = Tk_GetBitmap(interp, dataPtr->tkwin, Tk_GetUid(argv[2])); if (bitmap == None) { return TCL_ERROR; } Tk_SizeOfBitmap(dataPtr->display, bitmap, &width, &height); Tcl_SetResult(interp, Blt_Itoa(height), TCL_VOLATILE); Tk_FreeBitmap(dataPtr->display, bitmap); return TCL_OK; } /* *-------------------------------------------------------------- * * WidthOp -- * * Returns the width of the named bitmap. * *-------------------------------------------------------------- */ /*ARGSUSED*/ static int WidthOp(clientData, interp, argc, argv) ClientData clientData; /* Thread-specific data for bitmaps. */ Tcl_Interp *interp; /* Interpreter to report results to */ int argc; /* Not used. */ char **argv; /* Argument list */ { BitmapInterpData *dataPtr = clientData; int width, height; Pixmap bitmap; bitmap = Tk_GetBitmap(interp, dataPtr->tkwin, Tk_GetUid(argv[2])); if (bitmap == None) { return TCL_ERROR; } Tk_SizeOfBitmap(dataPtr->display, bitmap, &width, &height); Tcl_SetResult(interp, Blt_Itoa(width), TCL_VOLATILE); Tk_FreeBitmap(dataPtr->display, bitmap); return TCL_OK; } /* *-------------------------------------------------------------- * * SourceOp -- * * Returns the data array (excluding width and height) * of the named bitmap. * *-------------------------------------------------------------- */ /*ARGSUSED*/ static int SourceOp(clientData, interp, argc, argv) ClientData clientData; /* Thread-specific data for bitmaps. */ Tcl_Interp *interp; /* Interpreter to report results to */ int argc; /* Not used. */ char **argv; /* Argument list */ { BitmapInterpData *dataPtr = clientData; Pixmap bitmap; Tcl_DString dString; bitmap = Tk_GetBitmap(interp, dataPtr->tkwin, Tk_GetUid(argv[2])); if (bitmap == None) { return TCL_ERROR; } Tcl_DStringInit(&dString); BitmapDataToString(dataPtr->tkwin, bitmap, &dString); Tk_FreeBitmap(dataPtr->display, bitmap); Tcl_DStringResult(interp, &dString); return TCL_OK; } /* *-------------------------------------------------------------- * * DataOp -- * * Returns the data array, including width and height, * of the named bitmap. * *-------------------------------------------------------------- */ /*ARGSUSED*/ static int DataOp(clientData, interp, argc, argv) ClientData clientData; /* Thread-specific data for bitmaps. */ Tcl_Interp *interp; /* Interpreter to report results to */ int argc; /* Not used. */ char **argv; /* Argument list */ { BitmapInterpData *dataPtr = clientData; Pixmap bitmap; int width, height; Tcl_DString dString; bitmap = Tk_GetBitmap(interp, dataPtr->tkwin, Tk_GetUid(argv[2])); if (bitmap == None) { return TCL_ERROR; } Tk_SizeOfBitmap(dataPtr->display, bitmap, &width, &height); Tcl_DStringInit(&dString); Tcl_DStringAppendElement(&dString, Blt_Itoa(width)); Tcl_DStringAppendElement(&dString, Blt_Itoa(height)); Tcl_DStringStartSublist(&dString); BitmapDataToString(dataPtr->tkwin, bitmap, &dString); Tcl_DStringEndSublist(&dString); Tk_FreeBitmap(dataPtr->display, bitmap); Tcl_DStringResult(interp, &dString); return TCL_OK; } /* *-------------------------------------------------------------- * * BLT Sub-command specification: * * - Name of the sub-command. * - Minimum number of characters needed to unambiguously * recognize the sub-command. * - Pointer to the function to be called for the sub-command. * - Minimum number of arguments accepted. * - Maximum number of arguments accepted. * - String to be displayed for usage. * *-------------------------------------------------------------- */ static Blt_OpSpec bitmapOps[] = { {"compose", 1, (Blt_Op)ComposeOp, 4, 0, "bitmapName text ?flags?",}, {"data", 2, (Blt_Op)DataOp, 3, 3, "bitmapName",}, {"define", 2, (Blt_Op)DefineOp, 4, 0, "bitmapName data ?flags?",}, {"exists", 1, (Blt_Op)ExistsOp, 3, 3, "bitmapName",}, {"height", 1, (Blt_Op)HeightOp, 3, 3, "bitmapName",}, {"source", 1, (Blt_Op)SourceOp, 3, 3, "bitmapName",}, {"width", 1, (Blt_Op)WidthOp, 3, 3, "bitmapName",}, }; static int nBitmapOps = sizeof(bitmapOps) / sizeof(Blt_OpSpec); /* *-------------------------------------------------------------- * * BitmapCmd -- * * This procedure is invoked to process the Tcl command * that corresponds to bitmaps managed by this module. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ /*ARGSUSED*/ static int BitmapCmd(clientData, interp, argc, argv) ClientData clientData; /* Thread-specific data for bitmaps. */ Tcl_Interp *interp; /* Interpreter to report results to */ int argc; char **argv; { Blt_Op proc; int result; proc = Blt_GetOp(interp, nBitmapOps, bitmapOps, BLT_OP_ARG1, argc, argv,0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (clientData, interp, argc, argv); return result; } /* * ----------------------------------------------------------------------- * * BitmapInterpDeleteProc -- * * This is called when the interpreter is deleted. All the tiles * are specific to that interpreter are destroyed. * * Results: * None. * * Side effects: * Destroys the tile table. * * ------------------------------------------------------------------------ */ /* ARGSUSED */ static void BitmapInterpDeleteProc(clientData, interp) ClientData clientData; /* Thread-specific data. */ Tcl_Interp *interp; { BitmapInterpData *dataPtr = clientData; Blt_HashEntry *hPtr; unsigned char *bits; Blt_HashSearch cursor; for (hPtr = Blt_FirstHashEntry(&(dataPtr->bitmapTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { bits = (unsigned char *)Blt_GetHashValue(hPtr); Blt_Free(bits); } Blt_DeleteHashTable(&(dataPtr->bitmapTable)); Tcl_DeleteAssocData(interp, BITMAP_THREAD_KEY); Blt_Free(dataPtr); } static BitmapInterpData * GetBitmapInterpData(interp) Tcl_Interp *interp; { BitmapInterpData *dataPtr; Tcl_InterpDeleteProc *proc; dataPtr = (BitmapInterpData *) Tcl_GetAssocData(interp, BITMAP_THREAD_KEY, &proc); if (dataPtr == NULL) { dataPtr = Blt_Malloc(sizeof(BitmapInterpData)); assert(dataPtr); dataPtr->interp = interp; dataPtr->tkwin = Tk_MainWindow(interp); dataPtr->display = Tk_Display(dataPtr->tkwin); Tcl_SetAssocData(interp, BITMAP_THREAD_KEY, BitmapInterpDeleteProc, dataPtr); Blt_InitHashTable(&(dataPtr->bitmapTable), BLT_STRING_KEYS); } return dataPtr; } /* *-------------------------------------------------------------- * * Blt_BitmapInit -- * * This procedure is invoked to initialize the bitmap command. * * Results: * None. * * Side effects: * Adds the command to the interpreter and sets an array variable * which its version number. * *-------------------------------------------------------------- */ int Blt_BitmapInit(interp) Tcl_Interp *interp; { BitmapInterpData *dataPtr; static Blt_CmdSpec cmdSpec = {"bitmap", BitmapCmd}; /* Define the BLT logo bitmaps */ dataPtr = GetBitmapInterpData(interp); cmdSpec.clientData = dataPtr; if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) { return TCL_ERROR; } Tk_DefineBitmap(interp, Tk_GetUid("bigBLT"), (char *)bigblt_bits, bigblt_width, bigblt_height); Tk_DefineBitmap(interp, Tk_GetUid("BLT"), (char *)blt_bits, blt_width, blt_height); Tcl_ResetResult(interp); return TCL_OK; } #endif /* NO_BITMAP */ blt-2.4z.orig/src/bltBusy.c0100644000175000017500000010370307513654110014331 0ustar dokodoko/* * bltBusy.c -- * * This module implements busy windows for the BLT toolkit. * * Copyright 1993-1998 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. * * The "busy" command was created by George Howlett. */ #include "bltInt.h" #ifndef NO_BUSY #include "bltHash.h" #define BUSYDEBUG 0 #ifndef TK_REPARENTED #define TK_REPARENTED 0 #endif #define BUSY_THREAD_KEY "BLT Busy Data" typedef struct { Display *display; /* Display of busy window */ Tcl_Interp *interp; /* Interpreter where "busy" command was * created. It's used to key the * searches in the window hierarchy. See the * "windows" command. */ Tk_Window tkBusy; /* Busy window: Transparent window used * to block delivery of events to windows * underneath it. */ Tk_Window tkParent; /* Parent window of the busy * window. It may be the reference * window (if the reference is a * toplevel) or a mutual ancestor of * the reference window */ Tk_Window tkRef; /* Reference window of the busy window. * It's is used to manage the size and * position of the busy window. */ int x, y; /* Position of the reference window */ int width, height; /* Size of the reference window. Retained to * know if the reference window has been * reconfigured to a new size. */ int isBusy; /* Indicates whether the transparent * window should be displayed. This * can be different from what * Tk_IsMapped says because the a * sibling reference window may be * unmapped, forcing the busy window * to be also hidden. */ int menuBar; /* Menu bar flag. */ Tk_Cursor cursor; /* Cursor for the busy window. */ Blt_HashEntry *hashPtr; /* Used the delete the busy window entry * out of the global hash table. */ Blt_HashTable *tablePtr; } Busy; #ifdef WIN32 #define DEF_BUSY_CURSOR "wait" #else #define DEF_BUSY_CURSOR "watch" #endif static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_CURSOR, "-cursor", "busyCursor", "BusyCursor", DEF_BUSY_CURSOR, Tk_Offset(Busy, cursor), TK_CONFIG_NULL_OK}, {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} }; typedef struct { Blt_HashTable busyTable; /* Hash table of busy window * structures keyed by the address of * the reference Tk window */ } BusyInterpData; static void BusyGeometryProc _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin)); static void BusyCustodyProc _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin)); static Tk_GeomMgr busyMgrInfo = { "busy", /* Name of geometry manager used by winfo */ BusyGeometryProc, /* Procedure to for new geometry requests */ BusyCustodyProc, /* Procedure when window is taken away */ }; /* Forward declarations */ static void DestroyBusy _ANSI_ARGS_((DestroyData dataPtr)); static void BusyEventProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); static Tk_EventProc RefWinEventProc; static Tcl_CmdProc BusyCmd; static Tcl_InterpDeleteProc BusyInterpDeleteProc; static void ShowBusyWindow(busyPtr) Busy *busyPtr; { if (busyPtr->tkBusy != NULL) { Tk_MapWindow(busyPtr->tkBusy); /* * Always raise the busy window just in case new sibling * windows have been created in the meantime. Can't use * Tk_RestackWindow because it doesn't work under Win32. */ XRaiseWindow(Tk_Display(busyPtr->tkBusy), Tk_WindowId(busyPtr->tkBusy)); } #ifdef WIN32 { POINT point; /* * Under Win32, cursors aren't associated with windows. Tk * fakes this by watching Motion events on its windows. So Tk * will automatically change the cursor when the pointer * enters the Busy window. But Windows doesn't immediately * change the cursor; it waits for the cursor position to * change or a system call. We need to change the cursor * before the application starts processing, so set the cursor * position redundantly back to the current position. */ GetCursorPos(&point); SetCursorPos(point.x, point.y); } #endif /* WIN32 */ } static void HideBusyWindow(busyPtr) Busy *busyPtr; { if (busyPtr->tkBusy != NULL) { Tk_UnmapWindow(busyPtr->tkBusy); } #ifdef WIN32 { POINT point; /* * Under Win32, cursors aren't associated with windows. Tk * fakes this by watching Motion events on its windows. So Tk * will automatically change the cursor when the pointer * enters the Busy window. But Windows doesn't immediately * change the cursor: it waits for the cursor position to * change or a system call. We need to change the cursor * before the application starts processing, so set the cursor * position redundantly back to the current position. */ GetCursorPos(&point); SetCursorPos(point.x, point.y); } #endif /* WIN32 */ } /* *---------------------------------------------------------------------- * * BusyEventProc -- * * This procedure is invoked by the Tk dispatcher for events on * the busy window itself. We're only concerned with destroy * events. * * It might be necessary (someday) to watch resize events. Right * now, I don't think there's any point in it. * * Results: * None. * * Side effects: * When a busy window is destroyed, all internal structures * associated with it released at the next idle point. * *---------------------------------------------------------------------- */ static void BusyEventProc(clientData, eventPtr) ClientData clientData; /* Busy window record */ XEvent *eventPtr; /* Event which triggered call to routine */ { Busy *busyPtr = clientData; if (eventPtr->type == DestroyNotify) { busyPtr->tkBusy = NULL; Tcl_EventuallyFree(busyPtr, DestroyBusy); } } /* * ---------------------------------------------------------------------------- * * BusyCustodyProc -- * * This procedure is invoked when the busy window has been stolen * by another geometry manager. The information and memory * associated with the busy window is released. I don't know why * anyone would try to pack a busy window, but this should keep * everything sane, if it is. * * Results: * None. * * Side effects: * The Busy structure is freed at the next idle point. * * ---------------------------------------------------------------------------- */ /* ARGSUSED */ static void BusyCustodyProc(clientData, tkwin) ClientData clientData; /* Information about the busy window. */ Tk_Window tkwin; /* Not used. */ { Busy *busyPtr = clientData; Tk_DeleteEventHandler(busyPtr->tkBusy, StructureNotifyMask, BusyEventProc, busyPtr); HideBusyWindow(busyPtr); busyPtr->tkBusy = NULL; Tcl_EventuallyFree(busyPtr, DestroyBusy); } /* * ---------------------------------------------------------------------------- * * BusyGeometryProc -- * * This procedure is invoked by Tk_GeometryRequest for busy * windows. Busy windows never request geometry, so it's * unlikely that this routine will ever be called. The routine * exists simply as a place holder for the GeomProc in the * Geometry Manager structure. * * Results: * None. * * ---------------------------------------------------------------------------- */ /* ARGSUSED */ static void BusyGeometryProc(clientData, tkwin) ClientData clientData; /* Information about window that got new * preferred geometry. */ Tk_Window tkwin; /* Other Tk-related information about the * window. */ { /* Should never get here */ } /* * ------------------------------------------------------------------ * * RefWinEventProc -- * * This procedure is invoked by the Tk dispatcher for the * following events on the reference window. If the reference and * parent windows are the same, only the first event is * important. * * 1) ConfigureNotify - The reference window has been resized or * moved. Move and resize the busy window * to be the same size and position of the * reference window. * * 2) DestroyNotify - The reference window was destroyed. Destroy * the busy window and the free resources * used. * * 3) MapNotify - The reference window was (re)shown. Map the * busy window again. * * 4) UnmapNotify - The reference window was hidden. Unmap the * busy window. * * Results: * None. * * Side effects: * When the reference window gets deleted, internal structures get * cleaned up. When it gets resized, the busy window is resized * accordingly. If it's displayed, the busy window is displayed. And * when it's hidden, the busy window is unmapped. * * ------------------------------------------------------------------- */ static void RefWinEventProc(clientData, eventPtr) ClientData clientData; /* Busy window record */ register XEvent *eventPtr; /* Event which triggered call to routine */ { register Busy *busyPtr = clientData; switch (eventPtr->type) { case ReparentNotify: case DestroyNotify: /* * Arrange for the busy structure to be removed at a proper time. */ Tcl_EventuallyFree(busyPtr, DestroyBusy); break; case ConfigureNotify: if ((busyPtr->width != Tk_Width(busyPtr->tkRef)) || (busyPtr->height != Tk_Height(busyPtr->tkRef)) || (busyPtr->x != Tk_X(busyPtr->tkRef)) || (busyPtr->y != Tk_Y(busyPtr->tkRef))) { int x, y; busyPtr->width = Tk_Width(busyPtr->tkRef); busyPtr->height = Tk_Height(busyPtr->tkRef); busyPtr->x = Tk_X(busyPtr->tkRef); busyPtr->y = Tk_Y(busyPtr->tkRef); x = y = 0; if (busyPtr->tkParent != busyPtr->tkRef) { Tk_Window tkwin; for (tkwin = busyPtr->tkRef; (tkwin != NULL) && (!Tk_IsTopLevel(tkwin)); tkwin = Tk_Parent(tkwin)) { if (tkwin == busyPtr->tkParent) { break; } x += Tk_X(tkwin) + Tk_Changes(tkwin)->border_width; y += Tk_Y(tkwin) + Tk_Changes(tkwin)->border_width; } } #if BUSYDEBUG PurifyPrintf("menubar2: width=%d, height=%d\n", busyPtr->width, busyPtr->height); #endif if (busyPtr->tkBusy != NULL) { #if BUSYDEBUG fprintf(stderr, "busy window %s is at %d,%d %dx%d\n", Tk_PathName(busyPtr->tkBusy), x, y, busyPtr->width, busyPtr->height); #endif Tk_MoveResizeWindow(busyPtr->tkBusy, x, y, busyPtr->width, busyPtr->height); if (busyPtr->isBusy) { ShowBusyWindow(busyPtr); } } } break; case MapNotify: if ((busyPtr->tkParent != busyPtr->tkRef) && (busyPtr->isBusy)) { ShowBusyWindow(busyPtr); } break; case UnmapNotify: if (busyPtr->tkParent != busyPtr->tkRef) { HideBusyWindow(busyPtr); } break; } } /* * ------------------------------------------------------------------ * * ConfigureBusy -- * * This procedure is called from the Tk event dispatcher. It * releases X resources and memory used by the busy window and * updates the internal hash table. * * Results: * None. * * Side effects: * Memory and resources are released and the Tk event handler * is removed. * * ------------------------------------------------------------------- */ static int ConfigureBusy(interp, busyPtr, argc, argv) Tcl_Interp *interp; Busy *busyPtr; int argc; char **argv; { Tk_Cursor oldCursor; oldCursor = busyPtr->cursor; if (Tk_ConfigureWidget(interp, busyPtr->tkRef, configSpecs, argc, argv, (char *)busyPtr, 0) != TCL_OK) { return TCL_ERROR; } if (busyPtr->cursor != oldCursor) { if (busyPtr->cursor == None) { Tk_UndefineCursor(busyPtr->tkBusy); } else { Tk_DefineCursor(busyPtr->tkBusy, busyPtr->cursor); } } return TCL_OK; } /* * ------------------------------------------------------------------ * * CreateBusy -- * * Creates a child transparent window that obscures its parent * window thereby effectively blocking device events. The size * and position of the busy window is exactly that of the reference * window. * * We want to create sibling to the window to be blocked. If the * busy window is a child of the window to be blocked, Enter/Leave * events can sneak through. Futhermore under WIN32, messages of * transparent windows are sent directly to the parent. The only * exception to this are toplevels, since we can't make a sibling. * Fortunately, toplevel windows rarely receive events that need * blocking. * * Results: * Returns a pointer to the new busy window structure. * * Side effects: * When the busy window is eventually displayed, it will screen * device events (in the area of the reference window) from reaching * its parent window and its children. User feed back can be * achieved by changing the cursor. * * ------------------------------------------------------------------- */ static Busy * CreateBusy(interp, tkRef) Tcl_Interp *interp; /* Interpreter to report error to */ Tk_Window tkRef; /* Window hosting the busy window */ { Busy *busyPtr; int length; char *fmt, *name; Tk_Window tkBusy; Window parent; Tk_Window tkChild, tkParent; Tk_FakeWin *winPtr; int x, y; busyPtr = Blt_Calloc(1, sizeof(Busy)); assert(busyPtr); x = y = 0; length = strlen(Tk_Name(tkRef)); name = Blt_Malloc(length + 6); if (Tk_IsTopLevel(tkRef)) { fmt = "_Busy"; /* Child */ tkParent = tkRef; } else { Tk_Window tkwin; fmt = "%s_Busy"; /* Sibling */ tkParent = Tk_Parent(tkRef); for (tkwin = tkRef; (tkwin != NULL) && (!Tk_IsTopLevel(tkwin)); tkwin = Tk_Parent(tkwin)) { if (tkwin == tkParent) { break; } x += Tk_X(tkwin) + Tk_Changes(tkwin)->border_width; y += Tk_Y(tkwin) + Tk_Changes(tkwin)->border_width; } } for (tkChild = Blt_FirstChild(tkParent); tkChild != NULL; tkChild = Blt_NextChild(tkChild)) { Tk_MakeWindowExist(tkChild); } sprintf(name, fmt, Tk_Name(tkRef)); tkBusy = Tk_CreateWindow(interp, tkParent, name, (char *)NULL); Blt_Free(name); if (tkBusy == NULL) { return NULL; } Tk_MakeWindowExist(tkRef); busyPtr->display = Tk_Display(tkRef); busyPtr->interp = interp; busyPtr->tkRef = tkRef; busyPtr->tkParent = tkParent; busyPtr->tkBusy = tkBusy; busyPtr->width = Tk_Width(tkRef); busyPtr->height = Tk_Height(tkRef); busyPtr->x = Tk_X(tkRef); busyPtr->y = Tk_Y(tkRef); busyPtr->cursor = None; busyPtr->isBusy = FALSE; Tk_SetClass(tkBusy, "Busy"); #if (TK_MAJOR_VERSION > 4) Blt_SetWindowInstanceData(tkBusy, busyPtr); #endif winPtr = (Tk_FakeWin *) tkRef; if (winPtr->flags & TK_REPARENTED) { /* * This works around a bug in the implementation of menubars * for non-MacIntosh window systems (Win32 and X11). Tk * doesn't reset the pointers to the parent window when the * menu is reparented (winPtr->parentPtr points to the * wrong window). We get around this by determining the parent * via the native API calls. */ #ifdef WIN32 { HWND hWnd; RECT rect; hWnd = GetParent(Tk_GetHWND(Tk_WindowId(tkRef))); parent = (Window) hWnd; if (GetWindowRect(hWnd, &rect)) { busyPtr->width = rect.right - rect.left; busyPtr->height = rect.bottom - rect.top; #if BUSYDEBUG PurifyPrintf("menubar: width=%d, height=%d\n", busyPtr->width, busyPtr->height); #endif } } #else parent = Blt_GetParent(Tk_Display(tkRef), Tk_WindowId(tkRef)); #endif } else { parent = Tk_WindowId(tkParent); #ifdef WIN32 parent = (Window) Tk_GetHWND(parent); #endif } Blt_MakeTransparentWindowExist(tkBusy, parent, TRUE); #if BUSYDEBUG PurifyPrintf("menubar1: width=%d, height=%d\n", busyPtr->width, busyPtr->height); fprintf(stderr, "busy window %s is at %d,%d %dx%d\n", Tk_PathName(tkBusy), x, y, busyPtr->width, busyPtr->height); #endif Tk_MoveResizeWindow(tkBusy, x, y, busyPtr->width, busyPtr->height); /* Only worry if the busy window is destroyed. */ Tk_CreateEventHandler(tkBusy, StructureNotifyMask, BusyEventProc, busyPtr); /* * Indicate that the busy window's geometry is being managed. * This will also notify us if the busy window is ever packed. */ Tk_ManageGeometry(tkBusy, &busyMgrInfo, busyPtr); if (busyPtr->cursor != None) { Tk_DefineCursor(tkBusy, busyPtr->cursor); } /* Track the reference window to see if it is resized or destroyed. */ Tk_CreateEventHandler(tkRef, StructureNotifyMask, RefWinEventProc, busyPtr); return busyPtr; } /* * ------------------------------------------------------------------ * * DestroyBusy -- * * This procedure is called from the Tk event dispatcher. It * releases X resources and memory used by the busy window and * updates the internal hash table. * * Results: * None. * * Side effects: * Memory and resources are released and the Tk event handler * is removed. * * ------------------------------------------------------------------- */ static void DestroyBusy(data) DestroyData data; /* Busy window structure record */ { Busy *busyPtr = (Busy *)data; Tk_FreeOptions(configSpecs, (char *)busyPtr, busyPtr->display, 0); if (busyPtr->hashPtr != NULL) { Blt_DeleteHashEntry(busyPtr->tablePtr, busyPtr->hashPtr); } Tk_DeleteEventHandler(busyPtr->tkRef, StructureNotifyMask, RefWinEventProc, busyPtr); if (busyPtr->tkBusy != NULL) { Tk_DeleteEventHandler(busyPtr->tkBusy, StructureNotifyMask, BusyEventProc, busyPtr); Tk_ManageGeometry(busyPtr->tkBusy, NULL, busyPtr); Tk_DestroyWindow(busyPtr->tkBusy); } Blt_Free(busyPtr); } /* * ------------------------------------------------------------------ * * GetBusy -- * * Returns the busy window structure associated with the reference * window, keyed by its path name. The clientData argument is * the main window of the interpreter, used to search for the * reference window in its own window hierarchy. * * Results: * If path name represents a reference window with a busy window, a * pointer to the busy window structure is returned. Otherwise, * NULL is returned and an error message is left in * interp->result. * * ------------------------------------------------------------------- */ static int GetBusy(dataPtr, interp, pathName, busyPtrPtr) BusyInterpData *dataPtr; /* Interpreter-specific data. */ Tcl_Interp *interp; /* Interpreter to report errors to */ char *pathName; /* Path name of parent window */ Busy **busyPtrPtr; /* Will contain address of busy window if * found. */ { Blt_HashEntry *hPtr; Tk_Window tkwin; tkwin = Tk_NameToWindow(interp, pathName, Tk_MainWindow(interp)); if (tkwin == NULL) { return TCL_ERROR; } hPtr = Blt_FindHashEntry(&dataPtr->busyTable, (char *)tkwin); if (hPtr == NULL) { Tcl_AppendResult(interp, "can't find busy window \"", pathName, "\"", (char *)NULL); return TCL_ERROR; } *busyPtrPtr = ((Busy *)Blt_GetHashValue(hPtr)); return TCL_OK; } /* * ------------------------------------------------------------------ * * HoldBusy -- * * Creates (if necessary) and maps a busy window, thereby * preventing device events from being be received by the parent * window and its children. * * Results: * Returns a standard TCL result. If path name represents a busy * window, it is unmapped and TCL_OK is returned. Otherwise, * TCL_ERROR is returned and an error message is left in * interp->result. * * Side effects: * The busy window is created and displayed, blocking events from * the parent window and its children. * * ------------------------------------------------------------------- */ static int HoldBusy(dataPtr, interp, argc, argv) BusyInterpData *dataPtr; /* Interpreter-specific data. */ Tcl_Interp *interp; /* Interpreter to report errors to */ int argc; char **argv; /* Window name and option pairs */ { Tk_Window tkwin; Blt_HashEntry *hPtr; Busy *busyPtr; int isNew; int result; tkwin = Tk_NameToWindow(interp, argv[0], Tk_MainWindow(interp)); if (tkwin == NULL) { return TCL_ERROR; } hPtr = Blt_CreateHashEntry(&dataPtr->busyTable, (char *)tkwin, &isNew); if (isNew) { busyPtr = (Busy *)CreateBusy(interp, tkwin); if (busyPtr == NULL) { return TCL_ERROR; } Blt_SetHashValue(hPtr, (char *)busyPtr); busyPtr->hashPtr = hPtr; } else { busyPtr = (Busy *)Blt_GetHashValue(hPtr); } busyPtr->tablePtr = &dataPtr->busyTable; result = ConfigureBusy(interp, busyPtr, argc - 1, argv + 1); /* * Don't map the busy window unless the reference window is also * currently displayed. */ if (Tk_IsMapped(busyPtr->tkRef)) { ShowBusyWindow(busyPtr); } else { HideBusyWindow(busyPtr); } busyPtr->isBusy = TRUE; return result; } /* * ------------------------------------------------------------------ * * StatusOp -- * * Returns the status of the busy window; whether it's blocking * events or not. * * Results: * Returns a standard TCL result. If path name represents a busy * window, the status is returned via interp->result and TCL_OK * is returned. Otherwise, TCL_ERROR is returned and an error * message is left in interp->result. * * ------------------------------------------------------------------- */ /*ARGSUSED*/ static int StatusOp(clientData, interp, argc, argv) ClientData clientData; /* Interpreter-specific data. */ Tcl_Interp *interp; /* Interpreter to report error to */ int argc; /* Not used. */ char **argv; { BusyInterpData *dataPtr = clientData; Busy *busyPtr; if (GetBusy(dataPtr, interp, argv[2], &busyPtr) != TCL_OK) { return TCL_ERROR; } Tcl_Preserve(busyPtr); Blt_SetBooleanResult(interp, busyPtr->isBusy); Tcl_Release(busyPtr); return TCL_OK; } /* * ------------------------------------------------------------------ * * ForgetOp -- * * Destroys the busy window associated with the reference window and * arranges for internal resources to the released when they're * not being used anymore. * * Results: * Returns a standard TCL result. If path name represents a busy * window, it is destroyed and TCL_OK is returned. Otherwise, * TCL_ERROR is returned and an error message is left in * interp->result. * * Side effects: * The busy window is removed. Other related memory and resources * are eventually released by the Tk dispatcher. * * ------------------------------------------------------------------- */ static int ForgetOp(clientData, interp, argc, argv) ClientData clientData; /* Interpreter-specific data. */ Tcl_Interp *interp; /* Interpreter to report errors to */ int argc; char **argv; { BusyInterpData *dataPtr = clientData; Busy *busyPtr; register int i; for (i = 2; i < argc; i++) { if (GetBusy(dataPtr, interp, argv[i], &busyPtr) != TCL_OK) { return TCL_ERROR; } /* Unmap the window even though it will be soon destroyed */ HideBusyWindow(busyPtr); Tcl_EventuallyFree(busyPtr, DestroyBusy); } return TCL_OK; } /* * ------------------------------------------------------------------ * * ReleaseOp -- * * Unmaps the busy window, thereby permitting device events * to be received by the parent window and its children. * * Results: * Returns a standard TCL result. If path name represents a busy * window, it is unmapped and TCL_OK is returned. Otherwise, * TCL_ERROR is returned and an error message is left in * interp->result. * * Side effects: * The busy window is hidden, allowing the parent window and * its children to receive events again. * * ------------------------------------------------------------------- */ static int ReleaseOp(clientData, interp, argc, argv) ClientData clientData; /* Interpreter-specific data. */ Tcl_Interp *interp; /* Interpreter to report errors to */ int argc; char **argv; { BusyInterpData *dataPtr = clientData; Busy *busyPtr; int i; for (i = 2; i < argc; i++) { if (GetBusy(dataPtr, interp, argv[i], &busyPtr) != TCL_OK) { return TCL_ERROR; } HideBusyWindow(busyPtr); busyPtr->isBusy = FALSE; } return TCL_OK; } /* * ------------------------------------------------------------------ * * NamesOp -- * * Reports the names of all widgets with busy windows attached to * them, matching a given pattern. If no pattern is given, all * busy widgets are listed. * * Results: * Returns a TCL list of the names of the widget with busy windows * attached to them, regardless if the widget is currently busy * or not. * * ------------------------------------------------------------------- */ static int NamesOp(clientData, interp, argc, argv) ClientData clientData; /* Interpreter-specific data. */ Tcl_Interp *interp; /* Interpreter to report errors to */ int argc; char **argv; { BusyInterpData *dataPtr = clientData; Blt_HashEntry *hPtr; Blt_HashSearch cursor; Busy *busyPtr; for (hPtr = Blt_FirstHashEntry(&dataPtr->busyTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { busyPtr = (Busy *)Blt_GetHashValue(hPtr); if ((argc == 2) || (Tcl_StringMatch(Tk_PathName(busyPtr->tkRef), argv[2]))) { Tcl_AppendElement(interp, Tk_PathName(busyPtr->tkRef)); } } return TCL_OK; } /* * ------------------------------------------------------------------ * * BusyOp -- * * Reports the names of all widgets with busy windows attached to * them, matching a given pattern. If no pattern is given, all * busy widgets are listed. * * Results: * Returns a TCL list of the names of the widget with busy windows * attached to them, regardless if the widget is currently busy * or not. * * ------------------------------------------------------------------- */ static int BusyOp(clientData, interp, argc, argv) ClientData clientData; /* Interpreter-specific data. */ Tcl_Interp *interp; /* Interpreter to report errors to */ int argc; char **argv; { BusyInterpData *dataPtr = clientData; Blt_HashEntry *hPtr; Blt_HashSearch cursor; Busy *busyPtr; for (hPtr = Blt_FirstHashEntry(&dataPtr->busyTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { busyPtr = (Busy *)Blt_GetHashValue(hPtr); if (!busyPtr->isBusy) { continue; } if ((argc == 2) || (Tcl_StringMatch(Tk_PathName(busyPtr->tkRef), argv[2]))) { Tcl_AppendElement(interp, Tk_PathName(busyPtr->tkRef)); } } return TCL_OK; } /* * ------------------------------------------------------------------ * * HoldOp -- * * Creates (if necessary) and maps a busy window, thereby * preventing device events from being be received by the parent * window and its children. The argument vector may contain * option-value pairs of configuration options to be set. * * Results: * Returns a standard TCL result. * * Side effects: * The busy window is created and displayed, blocking events from the * parent window and its children. * * ------------------------------------------------------------------- */ static int HoldOp(clientData, interp, argc, argv) ClientData clientData; /* Interpreter-specific data. */ Tcl_Interp *interp; /* Interpreter to report errors to */ int argc; char **argv; /* Window name and option pairs */ { BusyInterpData *dataPtr = clientData; register int i, count; if ((argv[1][0] == 'h') && (strcmp(argv[1], "hold") == 0)) { argc--, argv++; /* Command used "hold" keyword */ } for (i = 1; i < argc; i++) { /* * Find the end of the option-value pairs for this window. */ for (count = i + 1; count < argc; count += 2) { if (argv[count][0] != '-') { break; } } if (count > argc) { count = argc; } if (HoldBusy(dataPtr, interp, count - i, argv + i) != TCL_OK) { return TCL_ERROR; } i = count; } return TCL_OK; } /* ARGSUSED*/ static int CgetOp(clientData, interp, argc, argv) ClientData clientData; /* Interpreter-specific data. */ Tcl_Interp *interp; /* Interpreter to report errors to */ int argc; char **argv; /* Widget pathname and option switch */ { BusyInterpData *dataPtr = clientData; Busy *busyPtr; int result; if (GetBusy(dataPtr, interp, argv[2], &busyPtr) != TCL_OK) { return TCL_ERROR; } Tcl_Preserve(busyPtr); result = Tk_ConfigureValue(interp, busyPtr->tkRef, configSpecs, (char *)busyPtr, argv[3], 0); Tcl_Release(busyPtr); return result; } /* *---------------------------------------------------------------------- * * ConfigureOp -- * * This procedure is called to process an argv/argc list in order * to configure (or reconfigure) a busy window. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then interp->result contains an error message. * * Side effects: * Configuration information get set for busyPtr; old resources * get freed, if there were any. The busy window destroyed and * recreated in a new parent window. * *---------------------------------------------------------------------- */ static int ConfigureOp(clientData, interp, argc, argv) ClientData clientData; /* Interpreter-specific data. */ Tcl_Interp *interp; /* Interpreter to report errors to */ int argc; char **argv; /* Reference window path name and options */ { BusyInterpData *dataPtr = clientData; Busy *busyPtr; int result; if (GetBusy(dataPtr, interp, argv[2], &busyPtr) != TCL_OK) { return TCL_ERROR; } if (argc == 3) { result = Tk_ConfigureInfo(interp, busyPtr->tkRef, configSpecs, (char *)busyPtr, (char *)NULL, 0); } else if (argc == 4) { result = Tk_ConfigureInfo(interp, busyPtr->tkRef, configSpecs, (char *)busyPtr, argv[3], 0); } else { Tcl_Preserve(busyPtr); result = ConfigureBusy(interp, busyPtr, argc - 3, argv + 3); Tcl_Release(busyPtr); } return result; } /* * ----------------------------------------------------------------------- * * BusyInterpDeleteProc -- * * This is called when the interpreter hosting the "busy" command * is destroyed. * * Results: * None. * * Side effects: * Destroys all the hash table managing the busy windows. * * ------------------------------------------------------------------------ */ /* ARGSUSED */ static void BusyInterpDeleteProc(clientData, interp) ClientData clientData; /* Interpreter-specific data. */ Tcl_Interp *interp; { BusyInterpData *dataPtr = clientData; Blt_HashEntry *hPtr; Blt_HashSearch cursor; Busy *busyPtr; for (hPtr = Blt_FirstHashEntry(&dataPtr->busyTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { busyPtr = (Busy *)Blt_GetHashValue(hPtr); busyPtr->hashPtr = NULL; DestroyBusy((DestroyData)busyPtr); } Blt_DeleteHashTable(&dataPtr->busyTable); Tcl_DeleteAssocData(interp, BUSY_THREAD_KEY); Blt_Free(dataPtr); } /* *-------------------------------------------------------------- * * Busy Sub-command specification: * * - Name of the sub-command. * - Minimum number of characters needed to unambiguously * recognize the sub-command. * - Pointer to the function to be called for the sub-command. * - Minimum number of arguments accepted. * - Maximum number of arguments accepted. * - String to be displayed for usage (arguments only). * *-------------------------------------------------------------- */ static Blt_OpSpec busyOps[] = { {"cget", 2, (Blt_Op)CgetOp, 4, 4, "window option",}, {"configure", 2, (Blt_Op)ConfigureOp, 3, 0, "window ?options?...",}, {"forget", 1, (Blt_Op)ForgetOp, 2, 0, "?window?...",}, {"hold", 3, (Blt_Op)HoldOp, 3, 0, "window ?options?... ?window options?...",}, {"isbusy", 1, (Blt_Op)BusyOp, 2, 3, "?pattern?",}, {"names", 1, (Blt_Op)NamesOp, 2, 3, "?pattern?",}, {"release", 1, (Blt_Op)ReleaseOp, 2, 0, "?window?...",}, {"status", 1, (Blt_Op)StatusOp, 3, 3, "window",}, {"windows", 1, (Blt_Op)NamesOp, 2, 3, "?pattern?",}, }; static int nBusyOps = sizeof(busyOps) / sizeof(Blt_OpSpec); /* *---------------------------------------------------------------------- * * BusyCmd -- * * This procedure is invoked to process the "busy" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ static int BusyCmd(clientData, interp, argc, argv) ClientData clientData; /* Interpreter-specific data. */ Tcl_Interp *interp; /* Interpreter associated with command */ int argc; char **argv; { Blt_Op proc; int result; if ((argc > 1) && (argv[1][0] == '.')) { return HoldOp(clientData, interp, argc, argv); } proc = Blt_GetOp(interp, nBusyOps, busyOps, BLT_OP_ARG1, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (clientData, interp, argc, argv); return result; } static BusyInterpData * GetBusyInterpData(interp) Tcl_Interp *interp; { BusyInterpData *dataPtr; Tcl_InterpDeleteProc *proc; dataPtr = (BusyInterpData *) Tcl_GetAssocData(interp, BUSY_THREAD_KEY, &proc); if (dataPtr == NULL) { dataPtr = Blt_Malloc(sizeof(BusyInterpData)); assert(dataPtr); Tcl_SetAssocData(interp, BUSY_THREAD_KEY, BusyInterpDeleteProc, dataPtr); Blt_InitHashTable(&dataPtr->busyTable, BLT_ONE_WORD_KEYS); } return dataPtr; } int Blt_BusyInit(interp) Tcl_Interp *interp; { static Blt_CmdSpec cmdSpec = {"busy", BusyCmd, }; BusyInterpData *dataPtr; dataPtr = GetBusyInterpData(interp); cmdSpec.clientData = dataPtr; if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) { return TCL_ERROR; } return TCL_OK; } #endif /* NO_BUSY */ blt-2.4z.orig/src/bltCanvEps.c0100644000175000017500000014573507526635202014766 0ustar dokodoko/* * bltCanvEps.c -- * * This file implements Encapsulated PostScript items for canvas widgets. * * Copyright 1991-1998 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. * * EPS canvas item created by George Howlett. */ /* * To do: * * 1. Add -rotate option. Allow arbitrary rotation of image and EPS. * 2. Draw color images instead of photos. This will eliminate the need * to create hidden photo images. * 3. Create a spiffy demo that lets you edit your page description. */ #include "bltInt.h" #include "bltPs.h" #include "bltImage.h" #ifdef HAVE_TIFF_H #include "tiff.h" #endif #include #if defined(_MSC_VER) || defined(__BORLANDC__) #include #define open _open #define close _close #define write _write #define unlink _unlink #define lseek _lseek #define fdopen _fdopen #define fcntl _fcntl #ifdef _MSC_VER #define O_RDWR _O_RDWR #define O_CREAT _O_CREAT #define O_TRUNC _O_TRUNC #define O_EXCL _O_EXCL #endif /* _MSC_VER */ #endif /* _MSC_VER || __BORLANDC__ */ #define DEBUG_READER 0 #ifndef WIN32 #define PurifyPrintf printf #endif #define PS_PREVIEW_EPSI 0 #define PS_PREVIEW_WMF 1 #define PS_PREVIEW_TIFF 2 #define xLeft header.x1 #define xRight header.x2 #define yTop header.y1 #define yBottom header.y2 #define MAX_EPS_LINE_LENGTH 255 /* Maximum line length for a EPS file */ /* * ParseInfo -- * * This structure is used to pass PostScript file information * around to various routines while parsing the EPS file. */ typedef struct { int maxBytes; /* Maximum length of PostScript code. */ int lineNumber; /* Current line number of EPS file */ char line[MAX_EPS_LINE_LENGTH + 1]; /* Buffer to contain a single line from * the PostScript file. */ char hexTable[256]; /* Table for converting ASCII hex digits to * values */ char *nextPtr; /* Pointer to the next character to process on * the current line. If NULL (or if nextPtr * points a NULL byte), this indicates the * the next line needs to be read. */ FILE *f; /* */ } ParseInfo; #define DEF_EPS_ANCHOR "nw" #define DEF_EPS_OUTLINE_COLOR RGB_BLACK #define DEF_EPS_OUTLINE_MONO RGB_BLACK #define DEF_EPS_BORDERWIDTH STD_BORDERWIDTH #define DEF_EPS_FILE_NAME (char *)NULL #define DEF_EPS_FONT STD_FONT #define DEF_EPS_FILL_COLOR STD_NORMAL_FOREGROUND #define DEF_EPS_FILL_MONO STD_NORMAL_FG_MONO #define DEF_EPS_HEIGHT "0" #define DEF_EPS_IMAGE_NAME (char *)NULL #define DEF_EPS_JUSTIFY "center" #define DEF_EPS_QUICK_RESIZE "no" #define DEF_EPS_RELIEF "sunken" #define DEF_EPS_SHADOW_COLOR (char *)NULL #define DEF_EPS_SHADOW_MONO (char *)NULL #define DEF_EPS_SHOW_IMAGE "yes" #define DEF_EPS_STIPPLE (char *)NULL #define DEF_EPS_TAGS (char *)NULL #define DEF_EPS_TITLE (char *)NULL #define DEF_EPS_TITLE_ANCHOR "center" #define DEF_EPS_TITLE_COLOR RGB_BLACK #define DEF_EPS_TITLE_ROTATE "0" #define DEF_EPS_WIDTH "0" /* * Information used for parsing configuration specs: */ static Tk_CustomOption tagsOption; extern Tk_CustomOption bltDistanceOption; extern Tk_CustomOption bltShadowOption; /* * The structure below defines the record for each EPS item. */ typedef struct { Tk_Item header; /* Generic stuff that's the same for all * types. MUST BE FIRST IN STRUCTURE. */ Tk_Canvas canvas; /* Canvas containing the EPS item. */ int canvasX, canvasY; /* Translated (by the anchor) canvas * coordinates of the EPS item. */ int lastWidth, lastHeight; /* Last known dimensions of the EPS item. * This is used to know if the color image * preview needs to be resized. */ Tcl_Interp *interp; FILE *psFile; /* File pointer to Encapsulated * PostScript file. We'll hold this as * long as the EPS item is using this * file. */ size_t psStart; /* File offset of PostScript code. */ size_t psLength; /* Length of PostScript code. If zero, * indicates to read to EOF. */ size_t wmfStart; /* File offset of Windows Metafile preview. */ size_t wmfLength; /* Length of WMF portion in bytes. If zero, * indicates there is no WMF preview. */ size_t tiffStart; /* File offset of TIFF preview. */ size_t tiffLength; /* Length of TIFF portion in bytes. If zero, * indicates there is no TIFF preview. */ char *previewName; int previewFormat; Tk_Image preview; /* A Tk photo image provided as a * preview of the EPS contents. This * image supersedes any EPS preview * embedded PostScript preview (EPSI). */ Tk_Image tmpImage; /* Used to display the resized preview image. * Created and deleted internally. */ Pixmap pixmap; /* Pixmap representing scaled preview. This * isn't currently used. For now we're * overwriting the Tk image everytime the * EPS item is resized. In the future * we'll use our own image routines. */ ColorTable colorTable; /* Pointer to color table */ Blt_ColorImage colorImage; /* The original photo or PostScript * preview image converted to a color * image. This is kept around for * resampling or resizing the image. */ int firstLine, lastLine; /* First and last line numbers of the * PostScript preview. They are used * to skip over the preview when * encapsulating PostScript for the * canvas item. */ GC fillGC; /* Graphics context to fill background * of image outline if no preview image * was present. */ int llx, lly, urx, ury; /* Lower left and upper right coordinates * of PostScript bounding box, retrieved * from file's "BoundingBox:" field. */ char *title; /* Title, retrieved from the file's "Title:" * field, to be displayed over the top of * the EPS preview (malloc-ed). */ Tcl_DString dString; /* Contains the encapsulate PostScript. */ /* User configurable fields */ double x, y; /* Canvas coordinates of the item */ Tk_Anchor anchor; char *fileName; /* Name of the encapsulated PostScript file. * If NULL, indicates that no EPS file * has be successfully loaded yet. */ char *reqTitle; /* Title to be displayed in the EPS item. * Supersedes the title found in the EPS * file. If NULL, indicates that the title * found in the EPS file should be used. */ int width, height; /* Dimensions of EPS item. If set to zero, * the dimension found in the "%%BoundingBox:" * specification from the EPS file are * used. */ int showImage; /* Indicates if the image or the outline * rectangle should be displayed */ int quick; XColor *fillColor; /* Fill color of the image outline. */ Tk_3DBorder border; /* Outline color */ int borderWidth; int relief; TextStyle titleStyle; /* Font, color, etc. for title */ Pixmap stipple; /* Stipple for image fill */ ClientData tiffPtr; #ifdef WIN32 HENHMETAFILE *hMetaFile; /* Windows metafile. */ #endif } EpsItem; static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_ANCHOR, "-anchor", (char *)NULL, (char *)NULL, DEF_EPS_ANCHOR, Tk_Offset(EpsItem, anchor), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_CUSTOM, "-borderwidth", "borderWidth", (char *)NULL, DEF_EPS_BORDERWIDTH, Tk_Offset(EpsItem, borderWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_STRING, "-file", (char *)NULL, (char *)NULL, DEF_EPS_FILE_NAME, Tk_Offset(EpsItem, fileName), TK_CONFIG_NULL_OK}, {TK_CONFIG_FONT, "-font", "font", "Font", DEF_EPS_FONT, Tk_Offset(EpsItem, titleStyle.font), 0}, {TK_CONFIG_COLOR, "-fill", "fill", (char *)NULL, DEF_EPS_FILL_COLOR, Tk_Offset(EpsItem, fillColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-fill", "fill", (char *)NULL, DEF_EPS_FILL_MONO, Tk_Offset(EpsItem, fillColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_CUSTOM, "-height", (char *)NULL, (char *)NULL, DEF_EPS_HEIGHT, Tk_Offset(EpsItem, height), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_STRING, "-image", (char *)NULL, (char *)NULL, DEF_EPS_IMAGE_NAME, Tk_Offset(EpsItem, previewName), TK_CONFIG_NULL_OK}, {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify", DEF_EPS_JUSTIFY, Tk_Offset(EpsItem, titleStyle.justify), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_BORDER, "-outline", "outline", (char *)NULL, DEF_EPS_OUTLINE_COLOR, Tk_Offset(EpsItem, border), TK_CONFIG_COLOR_ONLY | TK_CONFIG_NULL_OK}, {TK_CONFIG_BORDER, "-outline", "outline", (char *)NULL, DEF_EPS_OUTLINE_MONO, Tk_Offset(EpsItem, border), TK_CONFIG_MONO_ONLY | TK_CONFIG_NULL_OK}, {TK_CONFIG_BOOLEAN, "-quick", "quick", "Quick", DEF_EPS_QUICK_RESIZE, Tk_Offset(EpsItem, quick), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_RELIEF, "-relief", (char *)NULL, (char *)NULL, DEF_EPS_RELIEF, Tk_Offset(EpsItem, relief), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-shadow", "shadow", "Shadow", DEF_EPS_SHADOW_COLOR, Tk_Offset(EpsItem, titleStyle.shadow), TK_CONFIG_COLOR_ONLY, &bltShadowOption}, {TK_CONFIG_CUSTOM, "-shadow", "shadow", "Shadow", DEF_EPS_SHADOW_MONO, Tk_Offset(EpsItem, titleStyle.shadow), TK_CONFIG_MONO_ONLY, &bltShadowOption}, {TK_CONFIG_BOOLEAN, "-showimage", "showImage", "ShowImage", DEF_EPS_SHOW_IMAGE, Tk_Offset(EpsItem, showImage), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_BITMAP, "-stipple", (char *)NULL, (char *)NULL, DEF_EPS_STIPPLE, Tk_Offset(EpsItem, stipple), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-tags", (char *)NULL, (char *)NULL, DEF_EPS_TAGS, 0, TK_CONFIG_NULL_OK, &tagsOption}, {TK_CONFIG_STRING, "-title", (char *)NULL, (char *)NULL, DEF_EPS_TITLE, Tk_Offset(EpsItem, reqTitle), TK_CONFIG_NULL_OK}, {TK_CONFIG_ANCHOR, "-titleanchor", (char *)NULL, (char *)NULL, DEF_EPS_TITLE_ANCHOR, Tk_Offset(EpsItem, titleStyle.anchor), 0}, {TK_CONFIG_COLOR, "-titlecolor", (char *)NULL, (char *)NULL, DEF_EPS_TITLE_COLOR, Tk_Offset(EpsItem, titleStyle.color), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_DOUBLE, "-titlerotate", "titleRotate", "TitleRotate", DEF_EPS_TITLE_ROTATE, Tk_Offset(EpsItem, titleStyle.theta), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-width", (char *)NULL, (char *)NULL, DEF_EPS_WIDTH, Tk_Offset(EpsItem, width), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; /* * Prototypes for procedures defined in this file: */ static void ImageChangedProc _ANSI_ARGS_((ClientData clientData, int x, int y, int width, int height, int imgWidth, int imgHeight)); static int EpsCoords _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item * itemPtr, int argc, char **argv)); static int EpsToArea _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item * itemPtr, double *rectPtr)); static double EpsToPoint _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item * itemPtr, double *coordPtr)); static void ComputeEpsBbox _ANSI_ARGS_((Tk_Canvas canvas, EpsItem *imgPtr)); static int ConfigureEps _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item * itemPtr, int argc, char **argv, int flags)); static int CreateEps _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, struct Tk_Item * itemPtr, int argc, char **argv)); static void DeleteEps _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item * itemPtr, Display *display)); static void DisplayEps _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item * itemPtr, Display *display, Drawable dst, int x, int y, int width, int height)); static void ScaleEps _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item * itemPtr, double originX, double originY, double scaleX, double scaleY)); static void TranslateEps _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item * itemPtr, double deltaX, double deltaY)); static int EpsToPostScript _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item * itemPtr, int prepass)); static int ReadPostScript _ANSI_ARGS_((Tcl_Interp *interp, EpsItem *epsPtr)); static char * SkipBlanks(piPtr) ParseInfo *piPtr; { char *s; for (s = piPtr->line; isspace(UCHAR(*s)); s++) { /*empty*/ } return s; } static int ReadPsLine(piPtr) ParseInfo *piPtr; { if (ftell(piPtr->f) < piPtr->maxBytes) { if (fgets(piPtr->line, MAX_EPS_LINE_LENGTH, piPtr->f) != NULL) { piPtr->lineNumber++; #if DEBUG_READER PurifyPrintf("%d: %s\n", piPtr->lineNumber, piPtr->line); #endif return TRUE; } } return FALSE; } /* *---------------------------------------------------------------------- * * ReverseBits -- * * Convert a byte from a X image into PostScript image order. * This requires not only the nybbles to be reversed but also * their bit values. * * Results: * The converted byte is returned. * *---------------------------------------------------------------------- */ INLINE static unsigned char ReverseBits(byte) register 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; } /* *---------------------------------------------------------------------- * * GetHexValue -- * * Reads the next ASCII hex value from EPS preview image and * converts it. * * Results: * One of three Tcl return values is possible. * * TCL_OK the next byte was successfully parsed. * TCL_ERROR an error occurred processing the next hex value. * TCL_RETURN "%%EndPreview" line was detected. * * The converted hex value is returned via "bytePtr". * *---------------------------------------------------------------------- */ static int GetHexValue(piPtr, bytePtr) ParseInfo *piPtr; unsigned char *bytePtr; { register char *p; unsigned int byte; p = piPtr->nextPtr; if (p == NULL) { nextLine: if (!ReadPsLine(piPtr)) { #if DEBUG_READER PurifyPrintf("short file\n"); #endif return TCL_ERROR; /* Short file */ } if (piPtr->line[0] != '%') { #if DEBUG_READER PurifyPrintf("line doesn't start with %% (%s)\n", piPtr->line); #endif return TCL_ERROR; } if ((piPtr->line[1] == '%') && (strncmp(piPtr->line + 2, "EndPreview", 10) == 0)) { #if DEBUG_READER PurifyPrintf("end of preview (%s)\n", piPtr->line); #endif return TCL_RETURN; } p = piPtr->line + 1; } while (isspace((int)*p)) { p++; /* Skip spaces */ } if (*p == '\0') { goto nextLine; } if ((!isxdigit((int)p[0])) || (!isxdigit((int)p[1]))) { #if DEBUG_READER PurifyPrintf("not a hex digit (%s)\n", piPtr->line); #endif return TCL_ERROR; } byte = (piPtr->hexTable[(int)p[0]] << 4) | piPtr->hexTable[(int)p[1]]; p += 2; piPtr->nextPtr = p; *bytePtr = byte; return TCL_OK; } /* *---------------------------------------------------------------------- * * ReadEPSI -- * * Reads the EPS preview image from the PostScript file, converting * the image into a Blt_ColorImage. If an error occurs when parsing * the preview, the preview is silently ignored. * * Results: * None. * *---------------------------------------------------------------------- */ static void ReadEPSI(epsPtr, piPtr) EpsItem *epsPtr; ParseInfo *piPtr; { Blt_ColorImage image; int width, height, bitsPerPixel, nLines; char *dscBeginPreview; dscBeginPreview = piPtr->line + 16; if (sscanf(dscBeginPreview, "%d %d %d %d", &width, &height, &bitsPerPixel, &nLines) != 4) { #if DEBUG_READER PurifyPrintf("bad %%BeginPreview (%s) format\n", dscBeginPreview); #endif return; } if (((bitsPerPixel != 1) && (bitsPerPixel != 8)) || (width < 1) || (width > SHRT_MAX) || (height < 1) || (height > SHRT_MAX)) { #if DEBUG_READER PurifyPrintf("Bad %%BeginPreview (%s) values\n", dscBeginPreview); #endif return; /* Bad "%%BeginPreview:" information */ } epsPtr->firstLine = piPtr->lineNumber; Blt_InitHexTable(piPtr->hexTable); piPtr->nextPtr = NULL; image = Blt_CreateColorImage(width, height); if (bitsPerPixel == 8) { int result; register Pix32 *destPtr; register int x, y; unsigned char byte; for (y = height - 1; y >= 0; y--) { destPtr = Blt_ColorImageBits(image) + (y * width); for (x = 0; x < width; x++, destPtr++) { result = GetHexValue(piPtr, &byte); if (result == TCL_ERROR) { goto error; } if (result == TCL_RETURN) { goto done; } destPtr->Red = destPtr->Green = destPtr->Blue = ~byte; destPtr->Alpha = 0xFF; } } } else if (bitsPerPixel == 1) { int result; register Pix32 *destPtr; register int x, y; unsigned char byte; register int bit; destPtr = Blt_ColorImageBits(image); for (y = 0; y < height; y++) { bit = 8; for (x = 0; x < width; x++, destPtr++) { if (bit == 8) { result = GetHexValue(piPtr, &byte); if (result == TCL_ERROR) { goto error; } if (result == TCL_RETURN) { goto done; } byte = ReverseBits(byte); bit = 0; } if (((byte >> bit) & 0x01) == 0) { destPtr->value = 0xFFFFFFFF; } bit++; } } } else { fprintf(stderr, "unknown EPSI bitsPerPixel (%d)\n", bitsPerPixel); } done: epsPtr->colorImage = image; epsPtr->lastLine = piPtr->lineNumber + 1; return; error: epsPtr->firstLine = epsPtr->lastLine = -1; if (image != NULL) { Blt_FreeColorImage(image); } } /* *---------------------------------------------------------------------- * * ReadPostScript -- * * This routine reads and parses the few fields we need out * of an EPS file. * * The EPS standards are outlined from Appendix H of the * "PostScript Language Reference Manual" pp. 709-736. * * Mandatory fields: * * - Starts with "%!PS*" * - Contains "%%BoundingBox: llx lly urx ury" * * Optional fields for EPS item: * - "%%BeginPreview: w h bpp #lines" * Preview is in hexadecimal. Each line must start with "%" * - "%%EndPreview" * - "%%Title: (string)" * *---------------------------------------------------------------------- */ static int ReadPostScript(interp, epsPtr) Tcl_Interp *interp; EpsItem *epsPtr; { char *field; char *dscTitle, *dscBoundingBox; char *dscEndComments; ParseInfo pi; pi.line[0] = '\0'; pi.maxBytes = epsPtr->psLength; pi.lineNumber = 0; pi.f = epsPtr->psFile; Tcl_DStringInit(&epsPtr->dString); if (pi.maxBytes == 0) { pi.maxBytes = INT_MAX; } if (epsPtr->psStart > 0) { if (fseek(epsPtr->psFile, epsPtr->psStart, 0) != 0) { Tcl_AppendResult(interp, "can't seek to start of PostScript code in \"", epsPtr->fileName, "\"", (char *)NULL); return TCL_ERROR; } } if (!ReadPsLine(&pi)) { Tcl_AppendResult(interp, "file \"", epsPtr->fileName, "\" is empty?", (char *)NULL); return TCL_ERROR; } if (strncmp(pi.line, "%!PS", 4) != 0) { Tcl_AppendResult(interp, "file \"", epsPtr->fileName, "\" doesn't start with \"%!PS\"", (char *)NULL); return TCL_ERROR; } /* * Initialize field flags to NULL. We want to look only at the * first appearance of these comment fields. The file itself may * have another EPS file embedded into it. */ dscBoundingBox = dscTitle = dscEndComments = NULL; pi.lineNumber = 1; while (ReadPsLine(&pi)) { pi.lineNumber++; if ((pi.line[0] == '%') && (pi.line[1] == '%')) { /* Header comment */ field = pi.line + 2; if (field[0] == 'B') { if (strncmp(field, "BeginSetup", 8) == 0) { break; /* Done */ } if (strncmp(field, "BeginProlog", 8) == 0) { break; /* Done */ } if ((strncmp(field, "BoundingBox:", 12) == 0) && (dscBoundingBox == NULL)) { int nFields; dscBoundingBox = field + 12; nFields = sscanf(dscBoundingBox, "%d %d %d %d", &(epsPtr->llx), &(epsPtr->lly), &(epsPtr->urx), &(epsPtr->ury)); if (nFields != 4) { Tcl_AppendResult(interp, "bad \"%%BoundingBox\" values: \"", dscBoundingBox, "\"", (char *)NULL); goto error; } } } else if ((field[0] == 'T') && (strncmp(field, "Title:", 6) == 0)) { if (dscTitle == NULL) { dscTitle = Blt_Strdup(field + 6); } } else if (field[0] == 'E') { if (strncmp(field, "EndComments", 11) == 0) { dscEndComments = field; break; /* Done */ } } } /* %% */ } if (dscBoundingBox == NULL) { Tcl_AppendResult(interp, "no \"%%BoundingBox:\" found in \"", epsPtr->fileName, "\"", (char *)NULL); goto error; } if (dscEndComments != NULL) { /* Check if a "%%BeginPreview" immediately follows */ while (ReadPsLine(&pi)) { field = SkipBlanks(&pi); if (field[0] != '\0') { break; } } if (strncmp(pi.line, "%%BeginPreview:", 15) == 0) { ReadEPSI(epsPtr, &pi); } } if (dscTitle != NULL) { epsPtr->title = dscTitle; } /* Finally save the PostScript into a dynamic string. */ while (ReadPsLine(&pi)) { Tcl_DStringAppend(&epsPtr->dString, pi.line, -1); Tcl_DStringAppend(&epsPtr->dString, "\n", 1); } return TCL_OK; error: if (dscTitle != NULL) { Blt_Free(dscTitle); } return TCL_ERROR; /* BoundingBox: is required. */ } static int OpenEpsFile(interp, epsPtr) Tcl_Interp *interp; EpsItem *epsPtr; { FILE *f; #ifdef WIN32 DOSEPSHEADER dosHeader; int nBytes; #endif f = fopen(epsPtr->fileName, "rb"); if (f == NULL) { Tcl_AppendResult(epsPtr->interp, "can't open \"", epsPtr->fileName, "\": ", Tcl_PosixError(epsPtr->interp), (char *)NULL); return TCL_ERROR; } epsPtr->psFile = f; epsPtr->psStart = epsPtr->psLength = 0L; epsPtr->wmfStart = epsPtr->wmfLength = 0L; epsPtr->tiffStart = epsPtr->tiffLength = 0L; #ifdef WIN32 nBytes = fread(&dosHeader, sizeof(DOSEPSHEADER), 1, f); if ((nBytes == sizeof(DOSEPSHEADER)) && (dosHeader.magic[0] == 0xC5) && (dosHeader.magic[1] == 0xD0) && (dosHeader.magic[2] == 0xD3) && (dosHeader.magic[3] == 0xC6)) { /* DOS EPS file */ epsPtr->psStart = dosHeader.psStart; epsPtr->wmfStart = dosHeader.wmfStart; epsPtr->wmfLength = dosHeader.wmfLength; epsPtr->tiffStart = dosHeader.tiffStart; epsPtr->tiffLength = dosHeader.tiffLength; epsPtr->previewFormat = PS_PREVIEW_EPSI; #ifdef HAVE_TIFF_H if (epsPtr->tiffLength > 0) { epsPtr->previewFormat = PS_PREVIEW_TIFF; } #endif /* HAVE_TIFF_H */ if (epsPtr->wmfLength > 0) { epsPtr->previewFormat = PS_PREVIEW_WMF; } } fseek(f, 0, 0); #endif /* WIN32 */ return ReadPostScript(interp, epsPtr); } static void CloseEpsFile(epsPtr) EpsItem *epsPtr; { if (epsPtr->psFile != NULL) { fclose(epsPtr->psFile); epsPtr->psFile = NULL; } } #ifdef HAVE_TIFF_H static void ReadTiffPreview(epsPtr) EpsItem *epsPtr; { unsigned int width, height; Blt_ColorImage image; Pix32 *dataPtr; FILE *f; int n; TIFFGetField(epsPtr->tiffPtr, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(epsPtr->tiffPtr, TIFFTAG_IMAGELENGTH, &height); image = Blt_CreateColorImage(width, height); dataPtr = Blt_ColorImageBits(image); if (!TIFFReadRGBAImage(epsPtr->tiffPtr, width, height, dataPtr, 0)) { Blt_FreeColorImage(image); return; } /* Reverse the order of the components for each pixel. */ /* ... */ epsPtr->colorImage = image; } #endif #ifdef notdef ReadWMF(f, epsPtr, headerPtr) FILE *f; { HANDLE hMem; Tk_Window tkwin; if (fseek(f, headerPtr->wmfStart, 0) != 0) { Tcl_AppendResult(interp, "can't seek in \"", epsPtr->fileName, "\"", (char *)NULL); return TCL_ERROR; } hMem = GlobalAlloc(GHND, size); if (hMem == NULL) { Tcl_AppendResult(graphPtr->interp, "can't allocate global memory:", Blt_LastError(), (char *)NULL); return TCL_ERROR; } buffer = (LPVOID)GlobalLock(hMem); /* Read the header and see what kind of meta file it is. */ fread(buffer, sizeof(unsigned char), headerPtr->wmfLength, f); mfp.mm = 0; mfp.xExt = epsPtr->width; mfp.yExt = epsPtr->height; mfp.hMF = hMetaFile; tkwin = Tk_CanvasTkwin(epsPtr->canvas); hRefDC = TkWinGetDrawableDC(Tk_Display(tkwin), Tk_WindowId(tkwin), &state); hDC = CreateEnhMetaFile(hRefDC, NULL, NULL, NULL); mfp.hMF = CloseEnhMetaFile(hDC); hMetaFile = SetWinMetaFileBits(size, buffer, MM_ANISOTROPIC, &pict); Tcl_AppendResult(graphPtr->interp, "can't get metafile data:", Blt_LastError(), (char *)NULL); goto error; } #endif /* *---------------------------------------------------------------------- * * DeleteEps -- * * This procedure is called to clean up the data structure * associated with a EPS item. * * Results: * None. * * Side effects: * Resources associated with itemPtr are released. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static void DeleteEps(canvas, itemPtr, display) Tk_Canvas canvas; /* Info about overall canvas widget. */ Tk_Item *itemPtr; /* Item that is being deleted. */ Display *display; /* Display containing window for * canvas. */ { EpsItem *epsPtr = (EpsItem *)itemPtr; Tk_FreeOptions(configSpecs, (char *)epsPtr, display, 0); CloseEpsFile(epsPtr); if (epsPtr->colorImage != NULL) { Blt_FreeColorImage(epsPtr->colorImage); } if (epsPtr->preview != NULL) { Tk_FreeImage(epsPtr->preview); } if (epsPtr->previewName != NULL) { Blt_Free(epsPtr->previewName); } if (epsPtr->tmpImage != NULL) { Blt_DestroyTemporaryImage(epsPtr->interp, epsPtr->tmpImage); } if (epsPtr->pixmap != None) { #ifdef notyet Blt_FreeColorTable(epsPtr->colorTable); #endif Tk_FreePixmap(display, epsPtr->pixmap); } if (epsPtr->stipple != None) { Tk_FreePixmap(display, epsPtr->stipple); } if (epsPtr->fillGC != NULL) { Tk_FreeGC(display, epsPtr->fillGC); } Blt_FreeTextStyle(display, &(epsPtr->titleStyle)); if (epsPtr->title != NULL) { Blt_Free(epsPtr->title); } } /* *---------------------------------------------------------------------- * * CreateEps -- * * This procedure is invoked to create a new EPS item * in a canvas. * * Results: * A standard Tcl return value. If an error occurred in * creating the item, then an error message is left in * interp->result; in this case itemPtr is left uninitialized, * so it can be safely freed by the caller. * * Side effects: * A new EPS item is created. * *---------------------------------------------------------------------- */ static int CreateEps(interp, canvas, itemPtr, argc, argv) Tcl_Interp *interp; /* Interpreter for error reporting. */ Tk_Canvas canvas; /* Canvas to hold new item. */ Tk_Item *itemPtr; /* Record to hold new item; header * has been initialized by caller. */ int argc; /* Number of arguments in argv. */ char **argv; /* Arguments describing rectangle. */ { EpsItem *epsPtr = (EpsItem *)itemPtr; Tk_Window tkwin; tkwin = Tk_CanvasTkwin(canvas); if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tk_PathName(tkwin), " create ", itemPtr->typePtr->name, " x1 y1 ?options?\"", (char *)NULL); return TCL_ERROR; } /* * Initialize the item's record by hand (bleah). */ epsPtr->anchor = TK_ANCHOR_NW; epsPtr->border = NULL; epsPtr->borderWidth = 2; epsPtr->canvas = canvas; epsPtr->fileName = NULL; epsPtr->psFile = NULL; epsPtr->fillGC = NULL; epsPtr->fillColor = NULL; epsPtr->colorImage = NULL; epsPtr->previewName = NULL; epsPtr->preview = NULL; epsPtr->interp = interp; epsPtr->tmpImage = NULL; epsPtr->pixmap = None; epsPtr->firstLine = epsPtr->lastLine = -1; epsPtr->relief = TK_RELIEF_SUNKEN; epsPtr->reqTitle = NULL; epsPtr->stipple = None; epsPtr->showImage = TRUE; epsPtr->quick = FALSE; epsPtr->title = NULL; epsPtr->lastWidth = epsPtr->lastHeight = 0; epsPtr->width = epsPtr->height = 0; epsPtr->x = epsPtr->y = 0.0; epsPtr->llx = epsPtr->lly = epsPtr->urx = epsPtr->ury = 0; epsPtr->canvasX = epsPtr->canvasY = 0; Tcl_DStringInit(&epsPtr->dString); memset(&(epsPtr->titleStyle), 0, sizeof(TextStyle)); #define PAD 8 epsPtr->titleStyle.padLeft = epsPtr->titleStyle.padRight = PAD; epsPtr->titleStyle.padTop = epsPtr->titleStyle.padBottom = PAD; /* * Process the arguments to fill in the item record. */ if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &(epsPtr->x)) != TCL_OK) || (Tk_CanvasGetCoord(interp, canvas, argv[1], &(epsPtr->y)) != TCL_OK)) { return TCL_ERROR; } if (ConfigureEps(interp, canvas, itemPtr, argc - 2, argv + 2, 0) != TCL_OK) { DeleteEps(canvas, itemPtr, Tk_Display(tkwin)); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * ImageChangedProc * * The image is over-written each time the EPS item is resized. * So we only worry if the image is deleted. * * We always resample from the color image we saved when the * photo image was specified (-image option). * * Results: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static void ImageChangedProc(clientData, x, y, width, height, imageWidth, imageHeight) ClientData clientData; int x, y, width, height; /* Not used. */ int imageWidth, imageHeight;/* Not used. */ { EpsItem *epsPtr = clientData; if ((epsPtr->preview == NULL) || (Tk_ImageIsDeleted(epsPtr->preview))) { epsPtr->preview = NULL; if (epsPtr->previewName != NULL) { Blt_Free(epsPtr->previewName); epsPtr->previewName = NULL; } Tk_CanvasEventuallyRedraw(epsPtr->canvas, epsPtr->xLeft, epsPtr->yTop, epsPtr->xRight, epsPtr->yBottom); } } /* *---------------------------------------------------------------------- * * ConfigureEps -- * * This procedure is invoked to configure various aspects * of an EPS item, such as its background color. * * Results: * A standard Tcl result code. If an error occurs, then * an error message is left in interp->result. * * Side effects: * Configuration information may be set for itemPtr. * *---------------------------------------------------------------------- */ static int ConfigureEps(interp, canvas, itemPtr, argc, argv, flags) Tcl_Interp *interp; /* Used for error reporting. */ Tk_Canvas canvas; /* Canvas containing itemPtr. */ Tk_Item *itemPtr; /* EPS item to reconfigure. */ int argc; /* Number of elements in argv. */ char **argv; /* Arguments describing things to configure. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { EpsItem *epsPtr = (EpsItem *)itemPtr; Tk_Window tkwin; XGCValues gcValues; unsigned long gcMask; GC newGC; int width, height; tkwin = Tk_CanvasTkwin(canvas); if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv, (char *)epsPtr, flags) != TCL_OK) { return TCL_ERROR; } /* Determine the size of the EPS item */ width = height = 0; /* * Check for a "-image" option specifying an image to be displayed * representing the EPS canvas item. */ if (Blt_ConfigModified(configSpecs, "-image", (char *)NULL)) { if (epsPtr->preview != NULL) { Tk_FreeImage(epsPtr->preview); /* Release old Tk image */ Blt_FreeColorImage(epsPtr->colorImage); epsPtr->preview = NULL; epsPtr->colorImage = NULL; } if (epsPtr->previewName != NULL) { Tk_PhotoHandle photo; /* Photo handle to Tk image. */ /* * Allocate a new image, if one was named. */ photo = Blt_FindPhoto(interp, epsPtr->previewName); if (photo == NULL) { Tcl_AppendResult(interp, "image \"", epsPtr->previewName, "\" doesn't exist or is not a photo image", (char *)NULL); return TCL_ERROR; } epsPtr->preview = Tk_GetImage(interp, tkwin, epsPtr->previewName, ImageChangedProc, epsPtr); if (epsPtr->preview == NULL) { Tcl_AppendResult(interp, "can't find an image \"", epsPtr->previewName, "\"", (char *)NULL); Blt_Free(epsPtr->previewName); epsPtr->previewName = NULL; return TCL_ERROR; } epsPtr->colorImage = Blt_PhotoToColorImage(photo); width = Blt_ColorImageWidth(epsPtr->colorImage); height = Blt_ColorImageHeight(epsPtr->colorImage); } } if (Blt_ConfigModified(configSpecs, "-file", (char *)NULL)) { CloseEpsFile(epsPtr); if (epsPtr->pixmap != None) { #ifdef notyet Blt_FreeColorTable(epsPtr->colorTable); #endif Tk_FreePixmap(Tk_Display(tkwin), epsPtr->pixmap); epsPtr->pixmap = None; } if (epsPtr->colorImage != NULL) { Blt_FreeColorImage(epsPtr->colorImage); epsPtr->colorImage = NULL; } epsPtr->firstLine = epsPtr->lastLine = -1; if (epsPtr->fileName != NULL) { if (OpenEpsFile(interp, epsPtr) != TCL_OK) { return TCL_ERROR; } } } if ((epsPtr->colorImage != NULL) && (epsPtr->tmpImage == NULL)) { epsPtr->tmpImage = Blt_CreateTemporaryImage(interp, tkwin, epsPtr); if (epsPtr->tmpImage == NULL) { return TCL_ERROR; } } else if ((epsPtr->colorImage == NULL) && (epsPtr->tmpImage != NULL)) { Blt_DestroyTemporaryImage(epsPtr->interp, epsPtr->tmpImage); } if (epsPtr->preview != NULL) { Tk_SizeOfImage(epsPtr->preview, &width, &height); } if (epsPtr->width == 0) { if (epsPtr->fileName != NULL) { width = (epsPtr->urx - epsPtr->llx); } epsPtr->width = width; } if (epsPtr->height == 0) { if (epsPtr->fileName != NULL) { height = (epsPtr->ury - epsPtr->lly); } epsPtr->height = height; } Blt_ResetTextStyle(tkwin, &(epsPtr->titleStyle)); if (Blt_ConfigModified(configSpecs, "-quick", (char *)NULL)) { epsPtr->lastWidth = epsPtr->lastHeight = 0; } /* Fill color GC */ newGC = NULL; if (epsPtr->fillColor != NULL) { gcMask = GCForeground; gcValues.foreground = epsPtr->fillColor->pixel; if (epsPtr->stipple != None) { gcMask |= (GCStipple | GCFillStyle); gcValues.stipple = epsPtr->stipple; if (epsPtr->border != NULL) { gcValues.foreground = Tk_3DBorderColor(epsPtr->border)->pixel; gcValues.background = epsPtr->fillColor->pixel; gcMask |= GCBackground; gcValues.fill_style = FillOpaqueStippled; } else { gcValues.fill_style = FillStippled; } } newGC = Tk_GetGC(tkwin, gcMask, &gcValues); } if (epsPtr->fillGC != NULL) { Tk_FreeGC(Tk_Display(tkwin), epsPtr->fillGC); } epsPtr->fillGC = newGC; CloseEpsFile(epsPtr); ComputeEpsBbox(canvas, epsPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * EpsCoords -- * * This procedure is invoked to process the "coords" widget * command on EPS items. See the user documentation for * details on what it does. * * Results: * Returns TCL_OK or TCL_ERROR, and sets interp->result. * * Side effects: * The coordinates for the given item may be changed. * *---------------------------------------------------------------------- */ static int EpsCoords(interp, canvas, itemPtr, argc, argv) Tcl_Interp *interp; /* Used for error reporting. */ Tk_Canvas canvas; /* Canvas containing item. */ Tk_Item *itemPtr; /* Item whose coordinates are to be * read or modified. */ int argc; /* Number of coordinates supplied in * argv. */ char **argv; /* Array of coordinates: x1, y1, * x2, y2, ... */ { EpsItem *epsPtr = (EpsItem *)itemPtr; if ((argc != 0) && (argc != 2)) { Tcl_AppendResult(interp, "wrong # coordinates: expected 0 or 2, got ", Blt_Itoa(argc), (char *)NULL); return TCL_ERROR; } if (argc == 2) { double x, y; /* Don't overwrite old coordinates on errors */ if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &x) != TCL_OK) || (Tk_CanvasGetCoord(interp, canvas, argv[1], &y) != TCL_OK)) { return TCL_ERROR; } epsPtr->x = x; epsPtr->y = y; ComputeEpsBbox(canvas, epsPtr); return TCL_OK; } Tcl_AppendElement(interp, Blt_Dtoa(interp, epsPtr->x)); Tcl_AppendElement(interp, Blt_Dtoa(interp, epsPtr->y)); return TCL_OK; } /* *---------------------------------------------------------------------- * * ComputeEpsBbox -- * * This procedure is invoked to compute the bounding box of * all the pixels that may be drawn as part of a EPS item. * This procedure is where the preview image's placement is * computed. * * Results: * None. * * Side effects: * The fields x1, y1, x2, and y2 are updated in the header * for itemPtr. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static void ComputeEpsBbox(canvas, epsPtr) Tk_Canvas canvas; /* Canvas that contains item. */ EpsItem *epsPtr; /* Item whose bbox is to be recomputed. */ { int x, y; x = ROUND(epsPtr->x), y = ROUND(epsPtr->y); Blt_TranslateAnchor(x, y, epsPtr->width, epsPtr->height, epsPtr->anchor, &x, &y); epsPtr->xLeft = epsPtr->canvasX = x; epsPtr->yTop = epsPtr->canvasY = y; /* * The right and bottom are (weirdly) exterior to the item. Can't * complain much since it's documented in the Tk_CreateItemType * manual page. * * "These fields give a bounding box for the items using integer * canvas coordinates: the item should not cover any pixels with * x-coordinate lower than x1 or y-coordinate lower than y1, nor * should it cover any pixels with x-coordinate greater than or * equal to x2 or y-coordinate greater than or equal to y2." */ epsPtr->xRight = x + epsPtr->width; epsPtr->yBottom = y + epsPtr->height; } /* *---------------------------------------------------------------------- * * DisplayEps -- * * This procedure is invoked to draw the EPS item in a * given drawable. The EPS item may be drawn as either * a solid rectangle or a pixmap of the preview image. * * Results: * None. * * Side effects: * ItemPtr is drawn in drawable using the transformation * information in canvas. * *---------------------------------------------------------------------- */ static void DisplayEps(canvas, itemPtr, display, drawable, x, y, width, height) Tk_Canvas canvas; /* Canvas that contains item. */ Tk_Item *itemPtr; /* Item to be displayed. */ Display *display; /* Display on which to draw item. */ Drawable drawable; /* Pixmap or window in which to draw * item. */ int x, y, width, height; /* Describes region of canvas that * must be redisplayed (not used). */ { Tk_Window tkwin; EpsItem *epsPtr = (EpsItem *)itemPtr; short int drawableX, drawableY; char *title; int twiceBW; int noImage; if ((epsPtr->width < 1) || (epsPtr->height < 1)) { return; } tkwin = Tk_CanvasTkwin(canvas); epsPtr->showImage = TRUE; if ((epsPtr->showImage) && (epsPtr->colorImage != NULL) && ((epsPtr->lastWidth != epsPtr->width) || (epsPtr->lastHeight != epsPtr->height))) { Blt_ColorImage image; if (epsPtr->quick) { image = Blt_ResizeColorImage(epsPtr->colorImage, 0, 0, Blt_ColorImageWidth(epsPtr->colorImage), Blt_ColorImageHeight(epsPtr->colorImage), epsPtr->width, epsPtr->height); } else { image = Blt_ResampleColorImage(epsPtr->colorImage, epsPtr->width, epsPtr->height, bltBoxFilterPtr, bltBoxFilterPtr); } if (epsPtr->tmpImage != NULL) { Tk_PhotoHandle photo; /* * Resize the Tk photo image used to represent the EPS item. * We will over-write the temporary image with a resampled one. */ photo = Blt_FindPhoto(epsPtr->interp, Blt_NameOfImage(epsPtr->tmpImage)); Blt_ColorImageToPhoto(image, photo); } else { #ifdef notyet epsPtr->pixmap = Blt_ColorImageToPixmap(epsPtr->interp, tkwin, image, &(epsPtr->colorTable)); #endif } epsPtr->lastHeight = epsPtr->height; epsPtr->lastWidth = epsPtr->width; Blt_FreeColorImage(image); } /* * Translate the coordinates to those of the EPS item, then redisplay it. */ Tk_CanvasDrawableCoords(canvas, (double)epsPtr->canvasX, (double)epsPtr->canvasY, &drawableX, &drawableY); x = (int)drawableX; y = (int)drawableY; twiceBW = epsPtr->borderWidth * 2; title = epsPtr->title; if (epsPtr->reqTitle != NULL) { title = epsPtr->reqTitle; } width = epsPtr->width; height = epsPtr->height; noImage = ((!epsPtr->showImage) || ((epsPtr->tmpImage == NULL) && (epsPtr->pixmap == None))); if (noImage) { if ((twiceBW >= width) || (twiceBW >= height)) { return; } width -= twiceBW; height -= twiceBW; if (epsPtr->fillGC != NULL) { XSetTSOrigin(display, epsPtr->fillGC, x, y); XFillRectangle(display, drawable, epsPtr->fillGC, x, y, epsPtr->width, epsPtr->height); XSetTSOrigin(display, epsPtr->fillGC, 0, 0); } } else { if (epsPtr->pixmap != None) { XCopyArea(Tk_Display(tkwin), epsPtr->pixmap, drawable, epsPtr->fillGC, 0, 0, width, height, x, y); } else { Tk_RedrawImage(epsPtr->tmpImage, 0, 0, width, height, drawable, x, y); } } if (title != NULL) { TextLayout *textPtr; double rotWidth, rotHeight; int destWidth, destHeight; /* Translate the title to an anchor position within the EPS item */ textPtr = Blt_GetTextLayout(title, &(epsPtr->titleStyle)); Blt_GetBoundingBox(textPtr->width, textPtr->height, epsPtr->titleStyle.theta, &rotWidth, &rotHeight, (Point2D *)NULL); destWidth = (int)ceil(rotWidth); destHeight = (int)ceil(rotHeight); if ((destWidth <= width) && (destHeight <= height)) { int titleX, titleY; Blt_TranslateAnchor(x, y, width, height, epsPtr->titleStyle.anchor, &titleX, &titleY); if (noImage) { titleX += epsPtr->borderWidth; titleY += epsPtr->borderWidth; } Blt_DrawTextLayout(tkwin, drawable, textPtr, &(epsPtr->titleStyle), titleX, titleY); } Blt_Free(textPtr); } if ((noImage) && (epsPtr->border != NULL)) { Blt_Draw3DRectangle(tkwin, drawable, epsPtr->border, x, y, epsPtr->width, epsPtr->height, epsPtr->borderWidth, epsPtr->relief); } } /* *---------------------------------------------------------------------- * * EpsToPoint -- * * Computes the distance from a given point to a given * rectangle, in canvas units. * * Results: * The return value is 0 if the point whose x and y coordinates * are coordPtr[0] and coordPtr[1] is inside the EPS item. If the * point isn't inside the item then the return value is the * distance from the point to the EPS item. * * Side effects: * None. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static double EpsToPoint(canvas, itemPtr, coordArr) Tk_Canvas canvas; /* Canvas containing item. */ Tk_Item *itemPtr; /* Item to check against point. */ double *coordArr; /* Pointer to x and y coordinates. */ { EpsItem *epsPtr = (EpsItem *)itemPtr; double dx, dy; /* * Point is outside rectangle. */ if (coordArr[0] < epsPtr->xLeft) { dx = epsPtr->xLeft - coordArr[0]; } else if (coordArr[0] > epsPtr->xRight) { dx = coordArr[0] - epsPtr->xRight; } else { dx = 0; } if (coordArr[1] < epsPtr->yTop) { dy = epsPtr->yTop - coordArr[1]; } else if (coordArr[1] > epsPtr->yBottom) { dy = coordArr[1] - epsPtr->yBottom; } else { dy = 0; } return hypot(dx, dy); } /* *---------------------------------------------------------------------- * * EpsToArea -- * * This procedure is called to determine whether an item * lies entirely inside, entirely outside, or overlapping * a given rectangle. * * Results: * -1 is returned if the item is entirely outside the area * given by rectPtr, 0 if it overlaps, and 1 if it is entirely * inside the given area. * * Side effects: * None. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int EpsToArea(canvas, itemPtr, area) Tk_Canvas canvas; /* Canvas containing item. */ Tk_Item *itemPtr; /* Item to check against rectangle. */ double area[]; /* Pointer to array of four coordinates * (x1, y1, x2, y2) describing rectangular * area. */ { EpsItem *epsPtr = (EpsItem *)itemPtr; if ((area[2] <= epsPtr->xLeft) || (area[0] >= epsPtr->xRight) || (area[3] <= epsPtr->yTop) || (area[1] >= epsPtr->yBottom)) { return -1; } if ((area[0] <= epsPtr->xLeft) && (area[1] <= epsPtr->yTop) && (area[2] >= epsPtr->xRight) && (area[3] >= epsPtr->yBottom)) { return 1; } return 0; } /* *---------------------------------------------------------------------- * * ScaleEps -- * * This procedure is invoked to rescale an item. * * Results: * None. * * Side effects: * The item referred to by itemPtr is rescaled so that the * following transformation is applied to all point coordinates: * x' = originX + scaleX*(x-originX) * y' = originY + scaleY*(y-originY) * *---------------------------------------------------------------------- */ static void ScaleEps(canvas, itemPtr, originX, originY, scaleX, scaleY) Tk_Canvas canvas; /* Canvas containing rectangle. */ Tk_Item *itemPtr; /* Rectangle to be scaled. */ double originX, originY; /* Origin about which to scale rect. */ double scaleX; /* Amount to scale in X direction. */ double scaleY; /* Amount to scale in Y direction. */ { EpsItem *epsPtr = (EpsItem *)itemPtr; epsPtr->x = originX + scaleX * (epsPtr->x - originX); epsPtr->y = originY + scaleY * (epsPtr->y - originY); ComputeEpsBbox(canvas, epsPtr); } /* *---------------------------------------------------------------------- * * TranslateEps -- * * This procedure is called to move an item by a given amount. * * Results: * None. * * Side effects: * The position of the item is offset by (xDelta, yDelta), and * the bounding box is updated in the generic part of the item * structure. * *---------------------------------------------------------------------- */ static void TranslateEps(canvas, itemPtr, deltaX, deltaY) Tk_Canvas canvas; /* Canvas containing item. */ Tk_Item *itemPtr; /* Item that is being moved. */ double deltaX, deltaY; /* Amount by which item is to be * moved. */ { EpsItem *epsPtr = (EpsItem *)itemPtr; epsPtr->x += deltaX; epsPtr->y += deltaY; ComputeEpsBbox(canvas, epsPtr); } /* *---------------------------------------------------------------------- * * EpsToPostscript -- * * This procedure is called to generate Postscript for EPS * canvas items. * * Results: * The return value is a standard Tcl result. If an error * occurs in generating Postscript then an error message is * left in interp->result, replacing whatever used * to be there. If no error occurs, then Postscript for the * item is appended to the result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int EpsToPostScript(interp, canvas, itemPtr, prepass) Tcl_Interp *interp; /* Leave Postscript or error message * here. */ Tk_Canvas canvas; /* Information about overall canvas. */ Tk_Item *itemPtr; /* Item for which Postscript is * wanted. */ int prepass; /* 1 means this is a prepass to * collect font information; 0 means * final Postscript is being created. */ { EpsItem *epsPtr = (EpsItem *)itemPtr; PsToken psToken; Tk_Window tkwin; double xScale, yScale; int x, y, width, height; if (prepass) { return TCL_OK; } tkwin = Tk_CanvasTkwin(epsPtr->canvas); psToken = Blt_GetPsToken(interp, tkwin); x = epsPtr->canvasX; y = (int)Tk_CanvasPsY(canvas, (double)epsPtr->canvasY + epsPtr->height); if (epsPtr->fileName == NULL) { /* No PostScript file, generate PostScript of resized image instead. */ if (epsPtr->tmpImage != NULL) { Tk_PhotoHandle photo; Blt_FormatToPostScript(psToken, "gsave\n"); /* * First flip the PostScript y-coordinate axis so that the * origin is the upper-left corner like our color image. */ Blt_FormatToPostScript(psToken, " %d %d translate\n", x, y + epsPtr->height); Blt_FormatToPostScript(psToken, " 1 -1 scale\n"); photo = Blt_FindPhoto(epsPtr->interp, Blt_NameOfImage(epsPtr->tmpImage)); Blt_PhotoToPostScript(psToken, photo, 0.0, 0.0); Blt_FormatToPostScript(psToken, "grestore\n"); Tcl_AppendResult(interp, Blt_PostScriptFromToken(psToken), (char *)NULL); Blt_ReleasePsToken(psToken); } return TCL_OK; } /* Copy in the PostScript prolog for EPS encapsulation. */ if (Blt_FileToPostScript(psToken, "bltCanvEps.pro") != TCL_OK) { goto error; } Blt_AppendToPostScript(psToken, "BeginEPSF\n", (char *)NULL); width = epsPtr->width; height = epsPtr->height; xScale = (double)width / (double)(epsPtr->urx - epsPtr->llx); yScale = (double)height / (double)(epsPtr->ury - epsPtr->lly); /* Set up scaling and translation transformations for the EPS item */ Blt_FormatToPostScript(psToken, "%d %d translate\n", x, y); Blt_FormatToPostScript(psToken, "%g %g scale\n", xScale, yScale); Blt_FormatToPostScript(psToken, "%d %d translate\n", -(epsPtr->llx), -(epsPtr->lly)); Blt_FormatToPostScript(psToken, "%d %d %d %d SetClipRegion\n", epsPtr->llx, epsPtr->lly, epsPtr->urx, epsPtr->ury); Blt_AppendToPostScript(psToken, "%% including \"", epsPtr->fileName, "\"\n\n", (char *)NULL); Blt_AppendToPostScript(psToken, Tcl_DStringValue(&epsPtr->dString), (char *)NULL); Blt_AppendToPostScript(psToken, "EndEPSF\n", (char *)NULL); Tcl_AppendResult(interp, Blt_PostScriptFromToken(psToken), (char *)NULL); Blt_ReleasePsToken(psToken); return TCL_OK; error: Blt_ReleasePsToken(psToken); return TCL_ERROR; } /* * The structures below defines the EPS item type in terms of * procedures that can be invoked by generic item code. */ static Tk_ItemType epsItemType = { "eps", /* name */ sizeof(EpsItem), /* itemSize */ CreateEps, /* createProc */ configSpecs, /* configSpecs */ ConfigureEps, /* configureProc */ EpsCoords, /* coordProc */ DeleteEps, /* deleteProc */ DisplayEps, /* displayProc */ 0, /* alwaysRedraw */ EpsToPoint, /* pointProc */ EpsToArea, /* areaProc */ EpsToPostScript, /* postscriptProc */ ScaleEps, /* scaleProc */ TranslateEps, /* translateProc */ (Tk_ItemIndexProc *) NULL, /* indexProc */ (Tk_ItemCursorProc *) NULL, /* icursorProc */ (Tk_ItemSelectionProc *) NULL, /* selectionProc */ (Tk_ItemInsertProc *) NULL, /* insertProc */ (Tk_ItemDCharsProc *) NULL, /* dTextProc */ (Tk_ItemType *) NULL /* nextPtr */ }; /*ARGSUSED*/ void Blt_InitEpsCanvasItem(interp) Tcl_Interp *interp; /* Not used. */ { Tk_CreateItemType(&epsItemType); /* Initialize custom canvas option routines. */ tagsOption.parseProc = Tk_CanvasTagsParseProc; tagsOption.printProc = Tk_CanvasTagsPrintProc; } blt-2.4z.orig/src/bltChain.c0100644000175000017500000002544207467756243014456 0ustar dokodoko/* * bltChain.c -- * * The module implements a generic linked list package. * * Copyright 1991-1998 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. */ #include "bltInt.h" #include "bltChain.h" #ifndef ALIGN #define ALIGN(a) \ (((size_t)a + (sizeof(double) - 1)) & (~(sizeof(double) - 1))) #endif /* ALIGN */ /* *---------------------------------------------------------------------- * * Blt_ChainCreate -- * * Creates a new linked list (chain) structure and initializes * its pointers; * * Results: * Returns a pointer to the newly created chain structure. * *---------------------------------------------------------------------- */ Blt_Chain * Blt_ChainCreate() { Blt_Chain *chainPtr; chainPtr = Blt_Malloc(sizeof(Blt_Chain)); if (chainPtr != NULL) { Blt_ChainInit(chainPtr); } return chainPtr; } /* *---------------------------------------------------------------------- * * Blt_ChainAllocLink -- * * Creates a new chain link. Unlink Blt_ChainNewLink, this * routine also allocates extra memory in the node for data. * * Results: * The return value is the pointer to the newly created entry. * *---------------------------------------------------------------------- */ Blt_ChainLink * Blt_ChainAllocLink(extraSize) unsigned int extraSize; { Blt_ChainLink *linkPtr; unsigned int linkSize; linkSize = ALIGN(sizeof(Blt_ChainLink)); linkPtr = Blt_Calloc(1, linkSize + extraSize); assert(linkPtr); if (extraSize > 0) { /* Point clientData at the memory beyond the normal structure. */ linkPtr->clientData = (ClientData)((char *)linkPtr + linkSize); } return linkPtr; } /* *---------------------------------------------------------------------- * * Blt_ChainNewLink -- * * Creates a new link. * * Results: * The return value is the pointer to the newly created link. * *---------------------------------------------------------------------- */ Blt_ChainLink * Blt_ChainNewLink() { Blt_ChainLink *linkPtr; linkPtr = Blt_Malloc(sizeof(Blt_ChainLink)); assert(linkPtr); linkPtr->clientData = NULL; linkPtr->nextPtr = linkPtr->prevPtr = NULL; return linkPtr; } /* *---------------------------------------------------------------------- * * Blt_ChainReset -- * * Removes all the links from the chain, freeing the memory for * each link. Memory pointed to by the link (clientData) is not * freed. It's the caller's responsibility to deallocate it. * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_ChainReset(chainPtr) Blt_Chain *chainPtr; /* Chain to clear */ { if (chainPtr != NULL) { Blt_ChainLink *oldPtr; Blt_ChainLink *linkPtr = chainPtr->headPtr; while (linkPtr != NULL) { oldPtr = linkPtr; linkPtr = linkPtr->nextPtr; Blt_Free(oldPtr); } Blt_ChainInit(chainPtr); } } /* *---------------------------------------------------------------------- * * Blt_ChainDestroy * * Frees all the nodes from the chain and deallocates the memory * allocated for the chain structure itself. It's assumed that * the chain was previous allocated by Blt_ChainCreate. * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_ChainDestroy(chainPtr) Blt_Chain *chainPtr; { if (chainPtr != NULL) { Blt_ChainReset(chainPtr); Blt_Free(chainPtr); } } /* *---------------------------------------------------------------------- * * Blt_ChainInit -- * * Initializes a linked list. * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_ChainInit(chainPtr) Blt_Chain *chainPtr; { chainPtr->nLinks = 0; chainPtr->headPtr = chainPtr->tailPtr = NULL; } /* *---------------------------------------------------------------------- * * Blt_ChainLinkAfter -- * * Inserts an entry following a given entry. * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_ChainLinkAfter(chainPtr, linkPtr, afterPtr) Blt_Chain *chainPtr; Blt_ChainLink *linkPtr, *afterPtr; { if (chainPtr->headPtr == NULL) { chainPtr->tailPtr = chainPtr->headPtr = linkPtr; } else { if (afterPtr == NULL) { /* Prepend to the front of the chain */ linkPtr->nextPtr = chainPtr->headPtr; linkPtr->prevPtr = NULL; chainPtr->headPtr->prevPtr = linkPtr; chainPtr->headPtr = linkPtr; } else { linkPtr->nextPtr = afterPtr->nextPtr; linkPtr->prevPtr = afterPtr; if (afterPtr == chainPtr->tailPtr) { chainPtr->tailPtr = linkPtr; } else { afterPtr->nextPtr->prevPtr = linkPtr; } afterPtr->nextPtr = linkPtr; } } chainPtr->nLinks++; } /* *---------------------------------------------------------------------- * * Blt_ChainLinkBefore -- * * Inserts a link preceding a given link. * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_ChainLinkBefore(chainPtr, linkPtr, beforePtr) Blt_Chain *chainPtr; /* Chain to contain new entry */ Blt_ChainLink *linkPtr; /* New entry to be inserted */ Blt_ChainLink *beforePtr; /* Entry to link before */ { if (chainPtr->headPtr == NULL) { chainPtr->tailPtr = chainPtr->headPtr = linkPtr; } else { if (beforePtr == NULL) { /* Append to the end of the chain. */ linkPtr->nextPtr = NULL; linkPtr->prevPtr = chainPtr->tailPtr; chainPtr->tailPtr->nextPtr = linkPtr; chainPtr->tailPtr = linkPtr; } else { linkPtr->prevPtr = beforePtr->prevPtr; linkPtr->nextPtr = beforePtr; if (beforePtr == chainPtr->headPtr) { chainPtr->headPtr = linkPtr; } else { beforePtr->prevPtr->nextPtr = linkPtr; } beforePtr->prevPtr = linkPtr; } } chainPtr->nLinks++; } /* *---------------------------------------------------------------------- * * Blt_ChainUnlinkLink -- * * Unlinks a link from the chain. The link is not deallocated, * but only removed from the chain. * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_ChainUnlinkLink(chainPtr, linkPtr) Blt_Chain *chainPtr; Blt_ChainLink *linkPtr; { int unlinked; /* Indicates if the link is actually * removed from the chain. */ unlinked = FALSE; if (chainPtr->headPtr == linkPtr) { chainPtr->headPtr = linkPtr->nextPtr; unlinked = TRUE; } if (chainPtr->tailPtr == linkPtr) { chainPtr->tailPtr = linkPtr->prevPtr; unlinked = TRUE; } if (linkPtr->nextPtr != NULL) { linkPtr->nextPtr->prevPtr = linkPtr->prevPtr; unlinked = TRUE; } if (linkPtr->prevPtr != NULL) { linkPtr->prevPtr->nextPtr = linkPtr->nextPtr; unlinked = TRUE; } if (unlinked) { chainPtr->nLinks--; } linkPtr->prevPtr = linkPtr->nextPtr = NULL; } /* *---------------------------------------------------------------------- * * Blt_ChainDeleteLink -- * * Unlinks and also frees the given link. * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_ChainDeleteLink(chainPtr, linkPtr) Blt_Chain *chainPtr; Blt_ChainLink *linkPtr; { Blt_ChainUnlinkLink(chainPtr, linkPtr); Blt_Free(linkPtr); } Blt_ChainLink * Blt_ChainAppend(chainPtr, clientData) Blt_Chain *chainPtr; ClientData clientData; { Blt_ChainLink *linkPtr; linkPtr = Blt_ChainNewLink(); Blt_ChainLinkBefore(chainPtr, linkPtr, (Blt_ChainLink *)NULL); Blt_ChainSetValue(linkPtr, clientData); return linkPtr; } Blt_ChainLink * Blt_ChainPrepend(chainPtr, clientData) Blt_Chain *chainPtr; ClientData clientData; { Blt_ChainLink *linkPtr; linkPtr = Blt_ChainNewLink(); Blt_ChainLinkAfter(chainPtr, linkPtr, (Blt_ChainLink *)NULL); Blt_ChainSetValue(linkPtr, clientData); return linkPtr; } /* *---------------------------------------------------------------------- * * Blt_ChainGetNthLink -- * * Find the link at the given position in the chain. * * Results: * Returns the pointer to the link, if that numbered link * exists. Otherwise NULL. * *---------------------------------------------------------------------- */ Blt_ChainLink * Blt_ChainGetNthLink(chainPtr, position) Blt_Chain *chainPtr; /* Chain to traverse */ int position; /* Index of link to select from front * or back of the chain. */ { Blt_ChainLink *linkPtr; if (chainPtr != NULL) { for (linkPtr = chainPtr->headPtr; linkPtr != NULL; linkPtr = linkPtr->nextPtr) { if (position == 0) { return linkPtr; } position--; } } return NULL; } /* *---------------------------------------------------------------------- * * Blt_ChainSort -- * * Sorts the chain according to the given comparison routine. * * Results: * None. * * Side Effects: * The chain is reordered. * *---------------------------------------------------------------------- */ void Blt_ChainSort(chainPtr, proc) Blt_Chain *chainPtr; /* Chain to traverse */ Blt_ChainCompareProc *proc; { Blt_ChainLink **linkArr; register Blt_ChainLink *linkPtr; register int i; if (chainPtr->nLinks < 2) { return; } linkArr = Blt_Malloc(sizeof(Blt_ChainLink *) * (chainPtr->nLinks + 1)); if (linkArr == NULL) { return; /* Out of memory. */ } i = 0; for (linkPtr = chainPtr->headPtr; linkPtr != NULL; linkPtr = linkPtr->nextPtr) { linkArr[i++] = linkPtr; } qsort((char *)linkArr, chainPtr->nLinks, sizeof(Blt_ChainLink *), (QSortCompareProc *)proc); /* Rethread the chain. */ linkPtr = linkArr[0]; chainPtr->headPtr = linkPtr; linkPtr->prevPtr = NULL; for (i = 1; i < chainPtr->nLinks; i++) { linkPtr->nextPtr = linkArr[i]; linkPtr->nextPtr->prevPtr = linkPtr; linkPtr = linkPtr->nextPtr; } chainPtr->tailPtr = linkPtr; linkPtr->nextPtr = NULL; Blt_Free(linkArr); } blt-2.4z.orig/src/bltChain.h0100644000175000017500000000711107403601146014431 0ustar dokodoko/* * bltChain.h -- * * Copyright 1993-2000 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. */ #ifndef _BLT_CHAIN_H #define _BLT_CHAIN_H typedef struct Blt_ChainLinkStruct Blt_ChainLink; /* * A Blt_ChainLink is the container structure for the Blt_Chain. */ struct Blt_ChainLinkStruct { Blt_ChainLink *prevPtr; /* Link to the previous link */ Blt_ChainLink *nextPtr; /* Link to the next link */ ClientData clientData; /* Pointer to the data object */ }; typedef int (Blt_ChainCompareProc) _ANSI_ARGS_((Blt_ChainLink **l1PtrPtr, Blt_ChainLink **l2PtrPtr)); /* * A Blt_Chain is a doubly chained list structure. */ typedef struct { Blt_ChainLink *headPtr; /* Pointer to first element in chain */ Blt_ChainLink *tailPtr; /* Pointer to last element in chain */ int nLinks; /* Number of elements in chain */ } Blt_Chain; extern void Blt_ChainInit _ANSI_ARGS_((Blt_Chain * chainPtr)); extern Blt_Chain *Blt_ChainCreate _ANSI_ARGS_(()); extern void Blt_ChainDestroy _ANSI_ARGS_((Blt_Chain * chainPtr)); extern Blt_ChainLink *Blt_ChainNewLink _ANSI_ARGS_((void)); extern Blt_ChainLink *Blt_ChainAllocLink _ANSI_ARGS_((unsigned int size)); extern Blt_ChainLink *Blt_ChainAppend _ANSI_ARGS_((Blt_Chain * chainPtr, ClientData clientData)); extern Blt_ChainLink *Blt_ChainPrepend _ANSI_ARGS_((Blt_Chain * chainPtr, ClientData clientData)); extern void Blt_ChainReset _ANSI_ARGS_((Blt_Chain * chainPtr)); extern void Blt_ChainLinkAfter _ANSI_ARGS_((Blt_Chain * chainPtr, Blt_ChainLink * linkPtr, Blt_ChainLink * afterLinkPtr)); extern void Blt_ChainLinkBefore _ANSI_ARGS_((Blt_Chain * chainPtr, Blt_ChainLink * linkPtr, Blt_ChainLink * beforeLinkPtr)); extern void Blt_ChainUnlinkLink _ANSI_ARGS_((Blt_Chain * chainPtr, Blt_ChainLink * linkPtr)); extern void Blt_ChainDeleteLink _ANSI_ARGS_((Blt_Chain * chainPtr, Blt_ChainLink * linkPtr)); extern Blt_ChainLink *Blt_ChainGetNthLink _ANSI_ARGS_((Blt_Chain * chainPtr, int n)); extern void Blt_ChainSort _ANSI_ARGS_((Blt_Chain * chainPtr, Blt_ChainCompareProc * proc)); #define Blt_ChainGetLength(c) (((c) == NULL) ? 0 : (c)->nLinks) #define Blt_ChainFirstLink(c) (((c) == NULL) ? NULL : (c)->headPtr) #define Blt_ChainLastLink(c) (((c) == NULL) ? NULL : (c)->tailPtr) #define Blt_ChainPrevLink(l) ((l)->prevPtr) #define Blt_ChainNextLink(l) ((l)->nextPtr) #define Blt_ChainGetValue(l) ((l)->clientData) #define Blt_ChainSetValue(l, value) ((l)->clientData = (ClientData)(value)) #define Blt_ChainAppendLink(c, l) \ (Blt_ChainLinkBefore((c), (l), (Blt_ChainLink *)NULL)) #define Blt_ChainPrependLink(c, l) \ (Blt_ChainLinkAfter((c), (l), (Blt_ChainLink *)NULL)) #endif /* _BLT_CHAIN_H */ blt-2.4z.orig/src/bltColor.c0100644000175000017500000006515107525066175014504 0ustar dokodoko /* * bltColor.c -- * * This module contains routines for color allocation strategies * used with color images in the BLT toolkit. * * Copyright 1997-1998 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. */ /* * Color strategies of 8-bit visuals: * * Try to "best" represent an N-color image into 8-bit (256 color) * colormap. The simplest method is use the high bits of each RGB * value (3 bits for red and green, 2 bits for blue). But this * produces lots of contouring since the distribution of colors tends * to be clustered. Other problems: probably can't allocate even 256 * colors. Other applications will have already taken some color * slots. Furthermore, we might be displaying several images, and we * can't assume that all images are representative of the colors used. * * If we use a private colormap, we may want to allocate some number * of colors from the default colormap to prevent flashing when * colormaps are switched. * * Switches: * * -exact boolean Try to match the colors of the image rather * then generating a "best" color ramp. * * -threshold value Maximum average error. Indicates how far * to reduce the quantized color palette. * * -tolerance value Allow colors within this distance to match. * This will weight allocation towards harder * to match colors, rather than the most * frequent. * * -mincolors number Minimum number of reduced quantized colors. * or color ramp. * * -dither boolean Turn on/off Floyd-Steinberg dithering. * * -keep number Hint to keep the first N colors in the * in the default colormap. This only applies to * private colormaps. * * -ramp number Number of colors to use in a linear ramp. * */ #include "bltInt.h" #ifndef WIN32 #include "bltHash.h" #include "bltImage.h" #define NCOLORS 256 static void GetPaletteSizes(nColors, nRedsPtr, nGreensPtr, nBluesPtr) int nColors; /* Number of colors requested. */ unsigned int *nRedsPtr; /* (out) Number of red components. */ unsigned int *nGreensPtr; /* (out) Number of green components. */ unsigned int *nBluesPtr; /* (out) Number of blue components. */ { unsigned int nBlues, nReds, nGreens; assert(nColors > 1); nBlues = nReds = nGreens = 0; while ((nBlues * nBlues * nBlues) <= nColors) { nBlues++; } nBlues--; while ((nReds * nReds * nBlues) <= nColors) { nReds++; } nReds--; nGreens = nColors / (nBlues * nReds); *nRedsPtr = nReds; *nGreensPtr = nGreens; *nBluesPtr = nBlues; } static void BuildColorRamp(palettePtr, nColors) Pix32 *palettePtr; int nColors; { register unsigned int r, g, b; unsigned int short red, green, blue; unsigned int nReds, nGreens, nBlues; GetPaletteSizes(nColors, &nReds, &nGreens, &nBlues); for (r = 0; r < nReds; r++) { red = (r * USHRT_MAX) / (nReds - 1); for (g = 0; g < nGreens; g++) { green = (g * USHRT_MAX) / (nGreens - 1); for (b = 0; b < nBlues; b++) { blue = (b * USHRT_MAX) / (nBlues - 1); palettePtr->Red = red; palettePtr->Green = green; palettePtr->Blue = blue; palettePtr++; } } } } /* *---------------------------------------------------------------------- * * QueryColormap -- * * This is for psuedo-color displays only. Fills an array or * XColors with the color values (RGB and pixel) currently * allocated in the colormap. * * Results: * The number of colors allocated is returned. The array "colorArr" * will contain the XColor values of each color in the colormap. * *---------------------------------------------------------------------- */ static int QueryColormap(display, colorMap, mapColors, numMapColorsPtr) Display *display; Colormap colorMap; XColor mapColors[]; int *numMapColorsPtr; { unsigned long int pixelValues[NCOLORS]; int numAvail, numMapColors; register int i; register XColor *colorPtr; register unsigned long *indexPtr; int inUse[NCOLORS]; /* Initially, we assume all color cells are allocated. */ memset((char *)inUse, 0, sizeof(int) * NCOLORS); /* * Start allocating color cells. This will tell us which color cells * haven't already been allocated in the colormap. We'll release the * cells as soon as we find out how many there are. */ numAvail = 0; for (indexPtr = pixelValues, i = 0; i < NCOLORS; i++, indexPtr++) { if (!XAllocColorCells(display, colorMap, False, NULL, 0, indexPtr, 1)) { break; } inUse[*indexPtr] = TRUE;/* Indicate the cell is unallocated */ numAvail++; } XFreeColors(display, colorMap, pixelValues, numAvail, 0); /* * Put the indices of the cells already allocated into a color array. * We'll use the array to query the RGB values of the allocated colors. */ numMapColors = 0; colorPtr = mapColors; for (i = 0; i < NCOLORS; i++) { if (!inUse[i]) { colorPtr->pixel = i; colorPtr->flags = (DoRed | DoGreen | DoBlue); colorPtr++, numMapColors++; } } XQueryColors(display, colorMap, mapColors, numMapColors); *numMapColorsPtr = numMapColors; #ifdef notdef fprintf(stderr, "Number of colors (allocated/free) %d/%d\n", numMapColors, numAvail); #endif return numAvail; } static void FindClosestColor(colorPtr, mapColors, numMapColors) ColorInfo *colorPtr; XColor mapColors[]; int numMapColors; { double r, g, b; register int i; double dist, min; XColor *lastMatch; register XColor *mapColorPtr; min = DBL_MAX; /* Any color is closer. */ lastMatch = NULL; /* Linear search of color */ mapColorPtr = mapColors; for (i = 0; i < numMapColors; i++, mapColorPtr++) { r = (double)mapColorPtr->red - (double)colorPtr->exact.red; g = (double)mapColorPtr->green - (double)colorPtr->exact.green; b = (double)mapColorPtr->blue - (double)colorPtr->exact.blue; dist = (r * r) + (b * b) + (g * g); if (dist < min) { min = dist; lastMatch = mapColorPtr; } } colorPtr->best = *lastMatch; colorPtr->best.flags = (DoRed | DoGreen | DoBlue); colorPtr->error = (float)sqrt(min); } static int CompareColors(a, b) void *a, *b; { ColorInfo *i1Ptr, *i2Ptr; i1Ptr = *(ColorInfo **) a; i2Ptr = *(ColorInfo **) b; if (i2Ptr->error > i1Ptr->error) { return 1; } else if (i2Ptr->error < i1Ptr->error) { return -1; } return 0; } static float MatchColors(colorTabPtr, rgbPtr, numColors, numAvailColors, numMapColors, mapColors) struct ColorTableStruct *colorTabPtr; Pix32 *rgbPtr; int numColors; int numAvailColors; int numMapColors; XColor mapColors[NCOLORS]; { int numMatched; float sum; register int i; register ColorInfo *colorPtr; /* * For each quantized color, compute and store the error (i.e * the distance from a color that's already been allocated). * We'll use this information to sort the colors based upon how * badly they match and their frequency to the color image. */ colorPtr = colorTabPtr->colorInfo; for (i = 0; i < numColors; i++, colorPtr++, rgbPtr++) { colorPtr->index = i; colorTabPtr->sortedColors[i] = colorPtr; colorPtr->exact.red = rgbPtr->Red; colorPtr->exact.green = rgbPtr->Green; colorPtr->exact.blue = rgbPtr->Blue; colorPtr->exact.flags = (DoRed | DoGreen | DoBlue); FindClosestColor(colorPtr, mapColors, numMapColors); } /* Sort the colors, first by frequency (most to least), then by * matching error (worst to best). */ qsort(colorTabPtr->sortedColors, numColors, sizeof(ColorInfo *), (QSortCompareProc *)CompareColors); for (i = 0; i < numColors; i++) { colorPtr = colorTabPtr->sortedColors[i]; fprintf(stderr, "%d. %04x%04x%04x / %04x%04x%04x = %f (%d)\n", i, colorPtr->exact.red, colorPtr->exact.green, colorPtr->exact.blue, colorPtr->best.red, colorPtr->best.green, colorPtr->best.blue, colorPtr->error, colorPtr->freq); } sum = 0.0; numMatched = 0; for (i = numAvailColors; i < numColors; i++) { colorPtr = colorTabPtr->sortedColors[i]; sum += colorPtr->error; numMatched++; } if (numMatched > 0) { sum /= numMatched; } return sum; } static int AllocateColors(nImageColors, colorTabPtr, matchOnly) int nImageColors; struct ColorTableStruct *colorTabPtr; int matchOnly; { register int i; register ColorInfo *colorPtr; unsigned long int pixelValue; for (i = 0; i < nImageColors; i++) { colorPtr = colorTabPtr->sortedColors[i]; if (matchOnly) { XAllocColor(colorTabPtr->display, colorTabPtr->colorMap, &colorPtr->best); pixelValue = colorPtr->best.pixel; } else { colorPtr->allocated = XAllocColor(colorTabPtr->display, colorTabPtr->colorMap, &colorPtr->exact); if (colorPtr->allocated) { pixelValue = colorPtr->exact.pixel; } else { XAllocColor(colorTabPtr->display, colorTabPtr->colorMap, &colorPtr->best); pixelValue = colorPtr->best.pixel; } } colorTabPtr->pixelValues[colorPtr->index] = pixelValue; } colorTabPtr->nPixels = nImageColors; return 1; } ColorTable Blt_CreateColorTable(tkwin) Tk_Window tkwin; { XVisualInfo visualInfo, *visualInfoPtr; int nVisuals; Visual *visualPtr; Display *display; struct ColorTableStruct *colorTabPtr; display = Tk_Display(tkwin); visualPtr = Tk_Visual(tkwin); colorTabPtr = Blt_Calloc(1, sizeof(struct ColorTableStruct)); assert(colorTabPtr); colorTabPtr->display = Tk_Display(tkwin); colorTabPtr->colorMap = Tk_Colormap(tkwin); visualInfo.screen = Tk_ScreenNumber(tkwin); visualInfo.visualid = XVisualIDFromVisual(visualPtr); visualInfoPtr = XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &visualInfo, &nVisuals); colorTabPtr->visualInfo = *visualInfoPtr; XFree(visualInfoPtr); return colorTabPtr; } void Blt_FreeColorTable(colorTabPtr) struct ColorTableStruct *colorTabPtr; { if (colorTabPtr == NULL) { return; } if (colorTabPtr->nPixels > 0) { XFreeColors(colorTabPtr->display, colorTabPtr->colorMap, colorTabPtr->pixelValues, colorTabPtr->nPixels, 0); } Blt_Free(colorTabPtr); } extern int redAdjust, greenAdjust, blueAdjust; extern int redMaskShift, greenMaskShift, blueMaskShift; /* *---------------------------------------------------------------------- * * Blt_DirectColorTable -- * * Creates a color table using the DirectColor visual. We try * to allocate colors across the color spectrum. * * Results: * * *---------------------------------------------------------------------- */ /*ARGSUSED*/ ColorTable Blt_DirectColorTable(interp, tkwin, image) Tcl_Interp *interp; Tk_Window tkwin; Blt_ColorImage image; { struct ColorTableStruct *colorTabPtr; Visual *visualPtr; Display *display; XColor color; int nr, ng, nb; int rBand, gBand, bBand; int rLast, gLast, bLast; unsigned int r, g, b; unsigned int value; register int i; display = Tk_Display(tkwin); visualPtr = Tk_Visual(tkwin); colorTabPtr = Blt_CreateColorTable(tkwin); /* * Compute the number of distinct colors in each band */ nr = ((unsigned int)visualPtr->red_mask >> redMaskShift) + 1; ng = ((unsigned int)visualPtr->green_mask >> greenMaskShift) + 1; nb = ((unsigned int)visualPtr->blue_mask >> blueMaskShift) + 1; #ifdef notdef assert((nr <= visualPtr->map_entries) && (ng <= visualPtr->map_entries) && (nb <= visualPtr->map_entries)); #endif rBand = NCOLORS / nr; gBand = NCOLORS / ng; bBand = NCOLORS / nb; retry: color.flags = (DoRed | DoGreen | DoBlue); rLast = gLast = bLast = 0; r = g = b = 0; for (i = 0; i < visualPtr->map_entries; i++) { if (rLast < NCOLORS) { r = rLast + rBand; if (r > NCOLORS) { r = NCOLORS; } } if (gLast < NCOLORS) { g = gLast + gBand; if (g > NCOLORS) { g = NCOLORS; } } if (bLast < NCOLORS) { b = bLast + bBand; if (b > NCOLORS) { b = NCOLORS; } } color.red = (r - 1) * (NCOLORS + 1); color.green = (g - 1) * (NCOLORS + 1); color.blue = (b - 1) * (NCOLORS + 1); if (!XAllocColor(display, colorTabPtr->colorMap, &color)) { XFreeColors(display, colorTabPtr->colorMap, colorTabPtr->pixelValues, i, 0); if ((colorTabPtr->flags & PRIVATE_COLORMAP) == 0) { /* * If we can't allocate a color in the default * colormap, try again, this time with a private * colormap. */ fprintf(stderr, "Need to allocate private colormap\n"); colorTabPtr->colorMap = Tk_GetColormap(interp, tkwin, "."); XSetWindowColormap(display, Tk_WindowId(tkwin), colorTabPtr->colorMap); colorTabPtr->flags |= PRIVATE_COLORMAP; goto retry; } #ifdef notdef fprintf(stderr, "Failed to allocate after %d colors\n", i); #endif Blt_Free(colorTabPtr); return NULL; /* Ran out of colors in private map? */ } colorTabPtr->pixelValues[i] = color.pixel; /* * Fill in pixel values for each band at this intensity */ value = color.pixel & visualPtr->red_mask; while (rLast < r) { colorTabPtr->red[rLast++] = value; } value = color.pixel & visualPtr->green_mask; while (gLast < g) { colorTabPtr->green[gLast++] = value; } value = color.pixel & visualPtr->blue_mask; while (bLast < b) { colorTabPtr->blue[bLast++] = value; } } colorTabPtr->nPixels = i; return colorTabPtr; } /* * First attempt: * Allocate colors all the colors in the image (up to NCOLORS). Bail out * on the first failure or if we need more than NCOLORS. */ static int GetUniqueColors(image) Blt_ColorImage image; { register int i, nColors; register Pix32 *pixelPtr; Pix32 color; Blt_HashEntry *hPtr; int isNew, nPixels; int refCount; Blt_HashTable colorTable; Blt_InitHashTable(&colorTable, BLT_ONE_WORD_KEYS); nPixels = Blt_ColorImageWidth(image) * Blt_ColorImageHeight(image); nColors = 0; pixelPtr = Blt_ColorImageBits(image); for (i = 0; i < nPixels; i++, pixelPtr++) { color.value = pixelPtr->value; color.Alpha = 0xFF; /* Ignore alpha-channel values */ hPtr = Blt_CreateHashEntry(&colorTable, (char *)color.value, &isNew); if (isNew) { refCount = 1; nColors++; } else { refCount = (int)Blt_GetHashValue(hPtr); refCount++; } Blt_SetHashValue(hPtr, (ClientData)refCount); } Blt_DeleteHashTable(&colorTable); return nColors; } #define Blt_DefaultColormap(tkwin) \ DefaultColormap(Tk_Display(tkwin), Tk_ScreenNumber(tkwin)) static void PrivateColormap(interp, colorTabPtr, image, tkwin) Tcl_Interp *interp; struct ColorTableStruct *colorTabPtr; Blt_ColorImage image; Tk_Window tkwin; { int keepColors = 0; register int i; XColor usedColors[NCOLORS]; int nFreeColors, nUsedColors; Colormap colorMap; int inUse[NCOLORS]; XColor *colorPtr; XColor *imageColors; /* * Create a private colormap if one doesn't already exist for the * window. */ colorTabPtr->colorMap = colorMap = Tk_Colormap(tkwin); nUsedColors = 0; /* Number of colors allocated */ if (colorTabPtr->nPixels > 0) { XFreeColors(colorTabPtr->display, colorTabPtr->colorMap, colorTabPtr->pixelValues, colorTabPtr->nPixels, 0); } nFreeColors = QueryColormap(colorTabPtr->display, colorMap, usedColors, &nUsedColors); memset((char *)inUse, 0, sizeof(int) * NCOLORS); if ((nUsedColors == 0) && (keepColors > 0)) { /* * We're starting with a clean colormap so find out what colors * have been used in the default colormap. */ nFreeColors = QueryColormap(colorTabPtr->display, Blt_DefaultColormap(tkwin), usedColors, &nUsedColors); /* * Copy a number of colors from the default colormap into the private * colormap. We can assume that this is the working set from most * (non-image related) applications. While this doesn't stop our * image from flashing and looking dumb when colormaps are swapped * in and out, at least everything else should remain unaffected. */ if (nUsedColors > keepColors) { nUsedColors = keepColors; } /* * We want to allocate colors in the same ordering as the old colormap, * and we can't assume that the colors in the old map were contiguous. * So mark the colormap locations (i.e. pixels) that we find in use. */ } for (colorPtr = usedColors, i = 0; i < nUsedColors; i++, colorPtr++) { inUse[colorPtr->pixel] = TRUE; } /* * In an "exact" colormap, we try to allocate as many of colors from the * image as we can fit. If necessary, we'll cheat and reduce the number * of colors by quantizing. */ imageColors = usedColors + nUsedColors; Tk_SetWindowColormap(tkwin, colorMap); } ColorTable Blt_PseudoColorTable(interp, tkwin, image) Tcl_Interp *interp; Tk_Window tkwin; Blt_ColorImage image; { struct ColorTableStruct *colorTabPtr; Colormap defColorMap; int usePrivate; colorTabPtr = Blt_CreateColorTable(tkwin); defColorMap = DefaultColormap(colorTabPtr->display, Tk_ScreenNumber(tkwin)); if (colorTabPtr->colorMap == defColorMap) { fprintf(stderr, "Using default colormap\n"); } /* All other visuals use an 8-bit colormap */ colorTabPtr->lut = Blt_Malloc(sizeof(unsigned int) * 33 * 33 * 33); assert(colorTabPtr->lut); usePrivate = TRUE; if (usePrivate) { PrivateColormap(interp, colorTabPtr, image, tkwin); } else { #ifdef notdef ReadOnlyColormap(colorTabPtr, image, tkwin); #endif } return colorTabPtr; } #ifdef notdef static void ConvoleColorImage(srcImage, destImage, kernelPtr) Blt_ColorImage srcImage, destImage; ConvoleKernel *kernelPtr; { Pix32 *srcPtr, *destPtr; Pix32 *src[MAXROWS]; register int x, y, i, j; int red, green, blue; /* i = 0 case, ignore left column of pixels */ srcPtr = Blt_ColorImageBits(srcImage); destPtr = Blt_ColorImageBits(destImage); width = Blt_ColorImageWidth(srcImage); height = Blt_ColorImageHeight(srcImage); yOffset = kernelPtr->height / 2; xOffset = kernelPtr->width / 2; for (y = yOffset; y < (height - yOffset); y++) { /* Set up pointers to individual rows */ for (i = 0; i < kernelPtr->height; i++) { src[i] = srcPtr + (i * width); } for (x = xOffset; x < (width - xOffset); x++) { red = green = blue = 0; kernPtr = kernelPtr->values; for (i = 0; i < kernelPtr->height; i++) { for (j = 0; j < kernelPtr->width; j++) { red += *valuePtr * src[i][j].Red; green += *valuePtr * src[i][j].Green; blue += *valuePtr * src[i][j].Blue; valuePtr++; } } destPtr->Red = red / kernelPtr->sum; destPtr->Green = green / kernelPtr->sum; destPtr->Blue = blue / kernelPtr->sum; destPtr++; } srcPtr += width; } sum = bot[0].Red + red = bot[0].Red + bot[1].Red + mid[1].Red + top[0].Red + top[1].Red; green = bot[0].Green + bot[1].Green + mid[1].Green + top[0].Green + top[1].Green; blue = bot[0].Blue + bot[1].Blue + mid[1].Blue + top[0].Blue + top[1].Blue; error = (red / 5) - mid[0].Red; redVal = mid[0].Red - (error * blend / blend_divisor); error = (green / 5) - mid[0].Green; greenVal = mid[0].Green - (error * blend / blend_divisor); error = (blue / 5) - mid[0].Blue; blueVal = mid[0].Blue - (error * blend / blend_divisor); out[0].Red = CLAMP(redVal); out[0].Green = CLAMP(greenVal); out[0].Blue = CLAMP(blueVal); for (i = 1; i < (width - 1); i++) { for (chan = 0; chan < 3; chan++) { total = bot[chan][i - 1] + bot[chan][i] + bot[chan][i + 1] + mid[chan][i - 1] + mid[chan][i + 1] + top[chan][i - 1] + top[chan][i] + top[chan][i + 1]; avg = total >> 3; /* divide by 8 */ diff = avg - mid[chan][i]; result = mid[chan][i] - (diff * blend / blend_divisor); out[chan][i] = CLAMP(result); } } /* i = in_hdr.xmax case, ignore right column of pixels */ for (chan = 0; chan < 3; chan++) { total = bot[chan][i - 1] + bot[chan][i] + mid[chan][i - 1] + top[chan][i - 1] + top[chan][i]; avg = total / 5; diff = avg - mid[chan][i]; result = mid[chan][i] - (diff * blend / blend_divisor); out[chan][i] = CLAMP(result); } } static void DitherRow(srcImage, destImage, lastRow, curRow) Blt_ColorImage srcImage, destImage; int width, height; int bottom, top; { int width, height; width = Blt_ColorImageWidth(srcImage); topPtr = Blt_ColorImageBits(destPtr) + (width * row); rowPtr = topPtr + width; botPtr = rowPtr + width; for (x = 0; x < width; x++) { /* Clamp current error entry */ midPtr->red = CLAMP(midPtr->red); midPtr->blue = CLAMP(midPtr->blue); midPtr->green = CLAMP(midPtr->green); r = (midPtr->red >> 3) + 1; g = (midPtr->green >> 3) + 1; b = (midPtr->blue >> 3) + 1; index = colorTabPtr->lut[r][g][b]; redVal = midPtr->red * (NCOLORS + 1); greenVal = midPtr->green * (NCOLORS + 1); blueVal = midPtr->blue * (NCOLORS + 1); error = colorVal - colorMap[index].red; if (x < 511) { currRow[x + 1].Red = currRow[x + 1].Red + 7 * error / 16; nextRow[x + 1].Red = nextRow[x + 1].Red + error / 16; } nextRow[x].Red = nextRow[x].Red + 5 * error / 16; if (x > 0) { nextRow[x - 1].Red = nextRow[x - 1].Red + 3 * error / 16; } error = row[x][c] - colormap[index][c]; value = srcPtr->channel[i] * error[i]; value = CLAMP(value); destPtr->channel[i] = value; /* Closest pixel */ pixel = PsuedoColorPixel(); error[RED] = colorPtr->Red - srcPtr->Red * (NCOLORS + 1); /* translate pixel to colorInfoPtr to get error */ colorTabPtr->lut[r][g][b]; colorPtr = PixelToColorInfo(pixel); error = colorPtr->error; register rle_pixel *optr; register int j; register short *thisptr, *nextptr = NULL; int chan; static int nchan = 0; int lastline = 0, lastpixel; static int *cval = 0; static rle_pixel *pixel = 0; if (nchan != in_hdr->ncolors) if (cval) { Blt_Free(cval); Blt_Free(pixel); } nchan = in_hdr->ncolors; if (!cval) { if ((cval = Blt_Malloc(nchan * sizeof(int))) == 0) malloc_ERR; if ((pixel = Blt_Malloc(nchan * sizeof(rle_pixel))) == 0) malloc_ERR; } optr = outrow[RLE_RED]; thisptr = row_top; if (row_bottom) nextptr = row_bottom; else lastline = 1; for (x = 0; x < width; x++) { int cmap_index = 0; lastpixel = (x == (width - 1)); val = srcPtr->Red; for (chan = 0; chan < 3; chan++) { cval[chan] = *thisptr++; /* * Current channel value has been accumulating error, * it could be out of range. */ if (cval[chan] < 0) cval[chan] = 0; else if (cval[chan] > 255) cval[chan] = 255; pixel[chan] = cval[chan]; } /* find closest color */ find_closest(map, nchan, maplen, pixel, &cmap_index); *optr++ = cmap_index; /* thisptr is now looking at pixel to the right of current pixel * nextptr is looking at pixel below current pixel * So, increment thisptr as stuff gets stored. nextptr gets moved * by one, and indexing is done +/- nchan. */ for (chan = 0; chan < nchan; chan++) { cval[chan] -= map[chan][cmap_index]; if (!lastpixel) { thisptr[chan] += cval[chan] * 7 / 16; } if (!lastline) { if (j != 0) { nextptr[-nchan] += cval[chan] * 3 / 16; } nextptr[0] += cval[chan] * 5 / 16; if (!lastpixel) { nextptr[nchan] += cval[chan] / 16; } nextptr++; } } } } } /********************************************/ static Blt_ColorImage DoColorDither(pic24, pic8, w, h, rmap, gmap, bmap, rdisp, gdisp, bdisp, maplen) byte *pic24, *pic8, *rmap, *gmap, *bmap, *rdisp, *gdisp, *bdisp; int w, h, maplen; { /* takes a 24 bit picture, of size w*h, dithers with the colors in rdisp, gdisp, bdisp (which have already been allocated), and generates an 8-bit w*h image, which it returns. ignores input value 'pic8' returns NULL on error note: the rdisp,gdisp,bdisp arrays should be the 'displayed' colors, not the 'desired' colors if pic24 is NULL, uses the passed-in pic8 (an 8-bit image) as the source, and the rmap,gmap,bmap arrays as the desired colors */ byte *np, *ep, *newpic; short *cache; int r2, g2, b2; int *thisline, *nextline, *thisptr, *nextptr, *tmpptr; int i, j, rerr, gerr, berr, pwide3; int imax, jmax; int key; long cnt1, cnt2; int error[512]; /* -255 .. 0 .. +255 */ /* compute somewhat non-linear floyd-steinberg error mapping table */ for (i = j = 0; i <= 0x40; i++, j++) { error[256 + i] = j; error[256 - i] = -j; } for ( /*empty*/ ; i < 0x80; i++, j += !(i & 1) ? 1 : 0) { error[256 + i] = j; error[256 - i] = -j; } for ( /*empty*/ ; i <= 0xff; i++) { error[256 + i] = j; error[256 - i] = -j; } cnt1 = cnt2 = 0; pwide3 = w * 3; imax = h - 1; jmax = w - 1; ep = (pic24) ? pic24 : pic8; /* attempt to malloc things */ newpic = Blt_Malloc((size_t) (w * h)); cache = Blt_Calloc((size_t) (2 << 14), sizeof(short)); thisline = Blt_Malloc(pwide3 * sizeof(int)); nextline = Blt_Malloc(pwide3 * sizeof(int)); if (!cache || !newpic || !thisline || !nextline) { if (newpic) Blt_Free(newpic); if (cache) Blt_Free(cache); if (thisline) Blt_Free(thisline); if (nextline) Blt_Free(nextline); return (byte *) NULL; } np = newpic; /* Get first line of picture in reverse order. */ srcPtr = Blt_ColorImageBits(image), tempPtr = tempArr; for (x = 0; x < width; x++, tempPtr++, srcPtr--) { *tempPtr = *srcPtr; } for (y = 0; y < height; y++) { tempPtr = curRowPtr, curRowPtr = nextRowPtr, nextRowPtr = tempPtr; if (y != (height - 1)) {/* get next line */ for (x = 0; x < width; x++, tempPtr++, srcPtr--) *tempPtr = *srcPtr; } } Blt_Free(thisline); Blt_Free(nextline); Blt_Free(cache); return newpic; } static void DitherImage(image) Blt_ColorImage image; { int width, height; } #endif #endif /* WIN32 */ blt-2.4z.orig/src/bltConfig.c0100644000175000017500000011270407542177233014625 0ustar dokodoko/* * bltConfig.c -- * * This module implements custom configuration options for the BLT * toolkit. * * Copyright 1991-1998 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. */ #include "bltInt.h" #if defined(__STDC__) #include #else #include #endif #include "bltTile.h" static int StringToFill _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *string, char *widgRec, int flags)); static char *FillToString _ANSI_ARGS_((ClientData, Tk_Window, char *, int, Tcl_FreeProc **)); Tk_CustomOption bltFillOption = { StringToFill, FillToString, (ClientData)0 }; static int StringToPad _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *string, char *widgRec, int offset)); static char *PadToString _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, char *widgRec, int offset, Tcl_FreeProc **freeProcPtr)); Tk_CustomOption bltPadOption = { StringToPad, PadToString, (ClientData)0 }; static int StringToDistance _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *string, char *widgRec, int flags)); static char *DistanceToString _ANSI_ARGS_((ClientData, Tk_Window, char *, int, Tcl_FreeProc **)); Tk_CustomOption bltDistanceOption = { StringToDistance, DistanceToString, (ClientData)PIXELS_NONNEGATIVE }; Tk_CustomOption bltPositiveDistanceOption = { StringToDistance, DistanceToString, (ClientData)PIXELS_POSITIVE }; Tk_CustomOption bltAnyDistanceOption = { StringToDistance, DistanceToString, (ClientData)PIXELS_ANY }; static int StringToCount _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *string, char *widgRec, int flags)); static char *CountToString _ANSI_ARGS_((ClientData, Tk_Window, char *, int, Tcl_FreeProc **)); Tk_CustomOption bltCountOption = { StringToCount, CountToString, (ClientData)COUNT_NONNEGATIVE }; Tk_CustomOption bltPositiveCountOption = { StringToCount, CountToString, (ClientData)COUNT_POSITIVE }; static int StringToDashes _ANSI_ARGS_((ClientData, Tcl_Interp *, Tk_Window, char *, char *, int)); static char *DashesToString _ANSI_ARGS_((ClientData, Tk_Window, char *, int, Tcl_FreeProc **)); Tk_CustomOption bltDashesOption = { StringToDashes, DashesToString, (ClientData)0 }; static int StringToShadow _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *string, char *widgRec, int offset)); static char *ShadowToString _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, char *widgRec, int offset, Tcl_FreeProc **freeProcPtr)); Tk_CustomOption bltShadowOption = { StringToShadow, ShadowToString, (ClientData)0 }; static int StringToUid _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *string, char *widgRec, int flags)); static char *UidToString _ANSI_ARGS_((ClientData, Tk_Window, char *, int, Tcl_FreeProc **)); Tk_CustomOption bltUidOption = { StringToUid, UidToString, (ClientData)0 }; static int StringToState _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *string, char *widgRec, int flags)); static char *StateToString _ANSI_ARGS_((ClientData, Tk_Window, char *, int, Tcl_FreeProc **)); Tk_CustomOption bltStateOption = { StringToState, StateToString, (ClientData)0 }; static int StringToList _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *string, char *widgRec, int flags)); static char *ListToString _ANSI_ARGS_((ClientData, Tk_Window, char *, int, Tcl_FreeProc **)); Tk_CustomOption bltListOption = { StringToList, ListToString, (ClientData)0 }; static int StringToTile _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *value, char *widgRec, int flags)); static char *TileToString _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, char *widgRec, int offset, Tcl_FreeProc **freeProcPtr)); Tk_CustomOption bltTileOption = { StringToTile, TileToString, (ClientData)0 }; /* *---------------------------------------------------------------------- * * Blt_NameOfFill -- * * Converts the integer representing the fill direction into a string. * *---------------------------------------------------------------------- */ char * Blt_NameOfFill(fill) int fill; { switch (fill) { case FILL_X: return "x"; case FILL_Y: return "y"; case FILL_NONE: return "none"; case FILL_BOTH: return "both"; default: return "unknown value"; } } /* *---------------------------------------------------------------------- * * StringToFill -- * * Converts the fill style string into its numeric representation. * * Valid style strings are: * * "none" Use neither plane. * "x" X-coordinate plane. * "y" Y-coordinate plane. * "both" Use both coordinate planes. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToFill(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* Fill style string */ char *widgRec; /* Cubicle structure record */ int offset; /* Offset of style in record */ { int *fillPtr = (int *)(widgRec + offset); unsigned int length; char c; c = string[0]; length = strlen(string); if ((c == 'n') && (strncmp(string, "none", length) == 0)) { *fillPtr = FILL_NONE; } else if ((c == 'x') && (strncmp(string, "x", length) == 0)) { *fillPtr = FILL_X; } else if ((c == 'y') && (strncmp(string, "y", length) == 0)) { *fillPtr = FILL_Y; } else if ((c == 'b') && (strncmp(string, "both", length) == 0)) { *fillPtr = FILL_BOTH; } else { Tcl_AppendResult(interp, "bad argument \"", string, "\": should be \"none\", \"x\", \"y\", or \"both\"", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * FillToString -- * * Returns the fill style string based upon the fill flags. * * Results: * The fill style string is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * FillToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget structure record */ int offset; /* Offset of fill in widget record */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { int fill = *(int *)(widgRec + offset); return Blt_NameOfFill(fill); } /* *---------------------------------------------------------------------- * * Blt_StringToFlag -- * * Converts the fill style string into its numeric representation. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ int Blt_StringToFlag(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Bit mask to be tested in status word */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* Fill style string */ char *widgRec; /* Cubicle structure record */ int offset; /* Offset of style in record */ { unsigned int mask = (unsigned int)clientData; /* Bit to be tested */ int *flagPtr = (int *)(widgRec + offset); int bool; if (Tcl_GetBoolean(interp, string, &bool) != TCL_OK) { return TCL_ERROR; } if (bool) { *flagPtr |= mask; } else { *flagPtr &= ~mask; } return TCL_OK; } /* *---------------------------------------------------------------------- * * Blt_FlagToString -- * * Returns the fill style string based upon the fill flags. * * Results: * The fill style string is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ char * Blt_FlagToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Bit mask to be test in status word */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget structure record */ int offset; /* Offset of fill in widget record */ Tcl_FreeProc **freeProcPtr; /* Not Used. */ { unsigned int mask = (unsigned int)clientData; /* Bit to be tested */ unsigned int bool = *(unsigned int *)(widgRec + offset); return (bool & mask) ? "1" : "0"; } /* *---------------------------------------------------------------------- * * Blt_GetPixels -- * * Like Tk_GetPixels, but checks for negative, zero. * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ int Blt_GetPixels(interp, tkwin, string, check, valuePtr) Tcl_Interp *interp; Tk_Window tkwin; char *string; int check; /* Can be PIXELS_POSITIVE, PIXELS_NONNEGATIVE, * or PIXELS_ANY, */ int *valuePtr; { int length; if (Tk_GetPixels(interp, tkwin, string, &length) != TCL_OK) { return TCL_ERROR; } if (length >= SHRT_MAX) { Tcl_AppendResult(interp, "bad distance \"", string, "\": ", "too big to represent", (char *)NULL); return TCL_ERROR; } switch (check) { case PIXELS_NONNEGATIVE: if (length < 0) { Tcl_AppendResult(interp, "bad distance \"", string, "\": ", "can't be negative", (char *)NULL); return TCL_ERROR; } break; case PIXELS_POSITIVE: if (length <= 0) { Tcl_AppendResult(interp, "bad distance \"", string, "\": ", "must be positive", (char *)NULL); return TCL_ERROR; } break; case PIXELS_ANY: break; } *valuePtr = length; return TCL_OK; } /* *---------------------------------------------------------------------- * * StringToDistance -- * * Like TK_CONFIG_PIXELS, but adds an extra check for negative * values. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToDistance(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Indicated how to check distance */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Window */ char *string; /* Pixel value string */ char *widgRec; /* Widget record */ int offset; /* Offset of pixel size in record */ { int *valuePtr = (int *)(widgRec + offset); return Blt_GetPixels(interp, tkwin, string, (int)clientData, valuePtr); } /* *---------------------------------------------------------------------- * * DistanceToString -- * * Returns the string representing the positive pixel size. * * Results: * The pixel size string is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * DistanceToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget structure record */ int offset; /* Offset in widget record */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { int value = *(int *)(widgRec + offset); char *result; result = Blt_Strdup(Blt_Itoa(value)); assert(result); *freeProcPtr = (Tcl_FreeProc *)Blt_Free; return result; } int Blt_GetInt(interp, string, check, valuePtr) Tcl_Interp *interp; char *string; int check; /* Can be COUNT_POSITIVE, COUNT_NONNEGATIVE, * or COUNT_ANY, */ int *valuePtr; { int count; if (Tcl_GetInt(interp, string, &count) != TCL_OK) { return TCL_ERROR; } switch (check) { case COUNT_NONNEGATIVE: if (count < 0) { Tcl_AppendResult(interp, "bad value \"", string, "\": ", "can't be negative", (char *)NULL); return TCL_ERROR; } break; case COUNT_POSITIVE: if (count <= 0) { Tcl_AppendResult(interp, "bad value \"", string, "\": ", "must be positive", (char *)NULL); return TCL_ERROR; } break; case COUNT_ANY: break; } *valuePtr = count; return TCL_OK; } /* *---------------------------------------------------------------------- * * StringToCount -- * * Like TK_CONFIG_PIXELS, but adds an extra check for negative * values. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToCount(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Indicated how to check distance */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* Pixel value string */ char *widgRec; /* Widget record */ int offset; /* Offset of pixel size in record */ { int *valuePtr = (int *)(widgRec + offset); return Blt_GetInt(interp, string, (int)clientData, valuePtr); } /* *---------------------------------------------------------------------- * * CountToString -- * * Returns the string representing the positive pixel size. * * Results: * The pixel size string is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * CountToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget structure record */ int offset; /* Offset in widget record */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { int value = *(int *)(widgRec + offset); char *result; result = Blt_Strdup(Blt_Itoa(value)); assert(result); *freeProcPtr = (Tcl_FreeProc *)Blt_Free; return result; } /* *---------------------------------------------------------------------- * * StringToPad -- * * Convert a string into two pad values. The string may be in one of * the following forms: * * n - n is a non-negative integer. This sets both * pad values to n. * {n m} - both n and m are non-negative integers. side1 * is set to n, side2 is set to m. * * Results: * If the string is successfully converted, TCL_OK is returned. * Otherwise, TCL_ERROR is returned and an error message is left in * interp->result. * * Side Effects: * The padding structure passed is updated with the new values. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToPad(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Window */ char *string; /* Pixel value string */ char *widgRec; /* Widget record */ int offset; /* Offset of pad in widget */ { Blt_Pad *padPtr = (Blt_Pad *)(widgRec + offset); int nElem; int pad, result; char **padArr; if (Tcl_SplitList(interp, string, &nElem, &padArr) != TCL_OK) { return TCL_ERROR; } result = TCL_ERROR; if ((nElem < 1) || (nElem > 2)) { Tcl_AppendResult(interp, "wrong # elements in padding list", (char *)NULL); goto error; } if (Blt_GetPixels(interp, tkwin, padArr[0], PIXELS_NONNEGATIVE, &pad) != TCL_OK) { goto error; } padPtr->side1 = pad; if ((nElem > 1) && (Blt_GetPixels(interp, tkwin, padArr[1], PIXELS_NONNEGATIVE, &pad) != TCL_OK)) { goto error; } padPtr->side2 = pad; result = TCL_OK; error: Blt_Free(padArr); return result; } /* *---------------------------------------------------------------------- * * PadToString -- * * Converts the two pad values into a Tcl list. Each pad has two * pixel values. For vertical pads, they represent the top and bottom * margins. For horizontal pads, they're the left and right margins. * All pad values are non-negative integers. * * Results: * The padding list is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * PadToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Structure record */ int offset; /* Offset of pad in record */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { Blt_Pad *padPtr = (Blt_Pad *)(widgRec + offset); char *result; char string[200]; sprintf(string, "%d %d", padPtr->side1, padPtr->side2); result = Blt_Strdup(string); if (result == NULL) { return "out of memory"; } *freeProcPtr = (Tcl_FreeProc *)Blt_Free; return result; } /* *---------------------------------------------------------------------- * * StringToShadow -- * * Convert a string into two pad values. The string may be in one of * the following forms: * * n - n is a non-negative integer. This sets both * pad values to n. * {n m} - both n and m are non-negative integers. side1 * is set to n, side2 is set to m. * * Results: * If the string is successfully converted, TCL_OK is returned. * Otherwise, TCL_ERROR is returned and an error message is left in * interp->result. * * Side Effects: * The padding structure passed is updated with the new values. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToShadow(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Window */ char *string; /* Pixel value string */ char *widgRec; /* Widget record */ int offset; /* Offset of pad in widget */ { Shadow *shadowPtr = (Shadow *) (widgRec + offset); XColor *colorPtr; int dropOffset; colorPtr = NULL; dropOffset = 0; if ((string != NULL) && (string[0] != '\0')) { int nElem; char **elemArr; if (Tcl_SplitList(interp, string, &nElem, &elemArr) != TCL_OK) { return TCL_ERROR; } if ((nElem < 1) || (nElem > 2)) { Tcl_AppendResult(interp, "wrong # elements in drop shadow value", (char *)NULL); Blt_Free(elemArr); return TCL_ERROR; } colorPtr = Tk_GetColor(interp, tkwin, Tk_GetUid(elemArr[0])); if (colorPtr == NULL) { Blt_Free(elemArr); return TCL_ERROR; } dropOffset = 1; if (nElem == 2) { if (Blt_GetPixels(interp, tkwin, elemArr[1], PIXELS_NONNEGATIVE, &dropOffset) != TCL_OK) { Tk_FreeColor(colorPtr); Blt_Free(elemArr); return TCL_ERROR; } } Blt_Free(elemArr); } if (shadowPtr->color != NULL) { Tk_FreeColor(shadowPtr->color); } shadowPtr->color = colorPtr; shadowPtr->offset = dropOffset; return TCL_OK; } /* *---------------------------------------------------------------------- * * ShadowToString -- * * Converts the two pad values into a Tcl list. Each pad has two * pixel values. For vertical pads, they represent the top and bottom * margins. For horizontal pads, they're the left and right margins. * All pad values are non-negative integers. * * Results: * The padding list is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * ShadowToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Structure record */ int offset; /* Offset of pad in record */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { Shadow *shadowPtr = (Shadow *) (widgRec + offset); char *result; result = ""; if (shadowPtr->color != NULL) { char string[200]; sprintf(string, "%s %d", Tk_NameOfColor(shadowPtr->color), shadowPtr->offset); result = Blt_Strdup(string); *freeProcPtr = (Tcl_FreeProc *)Blt_Free; } return result; } /* *---------------------------------------------------------------------- * * GetDashes -- * * Converts a Tcl list of dash values into a dash list ready for * use with XSetDashes. * * A valid list dash values can have zero through 11 elements * (PostScript limit). Values must be between 1 and 255. Although * a list of 0 (like the empty string) means no dashes. * * Results: * A standard Tcl result. If the list represented a valid dash * list TCL_OK is returned and *dashesPtr* will contain the * valid dash list. Otherwise, TCL_ERROR is returned and * interp->result will contain an error message. * * *---------------------------------------------------------------------- */ static int GetDashes(interp, string, dashesPtr) Tcl_Interp *interp; char *string; Blt_Dashes *dashesPtr; { if ((string == NULL) || (*string == '\0')) { dashesPtr->values[0] = 0; } else if (strcmp(string, "dash") == 0) { /* 5 2 */ dashesPtr->values[0] = 5; dashesPtr->values[1] = 2; dashesPtr->values[2] = 0; } else if (strcmp(string, "dot") == 0) { /* 1 */ dashesPtr->values[0] = 1; dashesPtr->values[1] = 0; } else if (strcmp(string, "dashdot") == 0) { /* 2 4 2 */ dashesPtr->values[0] = 2; dashesPtr->values[1] = 4; dashesPtr->values[2] = 2; dashesPtr->values[3] = 0; } else if (strcmp(string, "dashdotdot") == 0) { /* 2 4 2 2 */ dashesPtr->values[0] = 2; dashesPtr->values[1] = 4; dashesPtr->values[2] = 2; dashesPtr->values[3] = 2; dashesPtr->values[4] = 0; } else { int nValues; char **strArr; long int value; register int i; if (Tcl_SplitList(interp, string, &nValues, &strArr) != TCL_OK) { return TCL_ERROR; } if (nValues > 11) { /* This is the postscript limit */ Tcl_AppendResult(interp, "too many values in dash list \"", string, "\"", (char *)NULL); Blt_Free(strArr); return TCL_ERROR; } for (i = 0; i < nValues; i++) { if (Tcl_ExprLong(interp, strArr[i], &value) != TCL_OK) { Blt_Free(strArr); return TCL_ERROR; } /* * Backward compatibility: * Allow list of 0 to turn off dashes */ if ((value == 0) && (nValues == 1)) { break; } if ((value < 1) || (value > 255)) { Tcl_AppendResult(interp, "dash value \"", strArr[i], "\" is out of range", (char *)NULL); Blt_Free(strArr); return TCL_ERROR; } dashesPtr->values[i] = (unsigned char)value; } /* Make sure the array ends with a NUL byte */ dashesPtr->values[i] = 0; Blt_Free(strArr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * StringToDashes -- * * Convert the list of dash values into a dashes array. * * Results: * The return value is a standard Tcl result. * * Side Effects: * The Dashes structure is updated with the new dash list. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToDashes(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* New dash value list */ char *widgRec; /* Widget record */ int offset; /* offset to Dashes structure */ { Blt_Dashes *dashesPtr = (Blt_Dashes *)(widgRec + offset); return GetDashes(interp, string, dashesPtr); } /* *---------------------------------------------------------------------- * * DashesToString -- * * Convert the dashes array into a list of values. * * Results: * The string representing the dashes returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * DashesToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget record */ int offset; /* offset of Dashes in record */ Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */ { Blt_Dashes *dashesPtr = (Blt_Dashes *)(widgRec + offset); Tcl_DString dString; unsigned char *p; char *result; if (dashesPtr->values[0] == 0) { return ""; } Tcl_DStringInit(&dString); for (p = dashesPtr->values; *p != 0; p++) { Tcl_DStringAppendElement(&dString, Blt_Itoa(*p)); } result = Tcl_DStringValue(&dString); if (result == dString.staticSpace) { result = Blt_Strdup(result); } *freeProcPtr = (Tcl_FreeProc *)Blt_Free; return result; } /* *---------------------------------------------------------------------- * * StringToUid -- * * Converts the string to a BLT Uid. Blt Uid's are hashed, reference * counted strings. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToUid(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* Fill style string */ char *widgRec; /* Cubicle structure record */ int offset; /* Offset of style in record */ { Blt_Uid *uidPtr = (Blt_Uid *)(widgRec + offset); Blt_Uid newId; newId = NULL; if ((string != NULL) && (*string != '\0')) { newId = Blt_GetUid(string); } if (*uidPtr != NULL) { Blt_FreeUid(*uidPtr); } *uidPtr = newId; return TCL_OK; } /* *---------------------------------------------------------------------- * * UidToString -- * * Returns the fill style string based upon the fill flags. * * Results: * The fill style string is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * UidToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget structure record */ int offset; /* Offset of fill in widget record */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { Blt_Uid uid = *(Blt_Uid *)(widgRec + offset); return (uid == NULL) ? "" : uid; } /* *---------------------------------------------------------------------- * * StringToState -- * * Converts the string to a state value. Valid states are * disabled, normal. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToState(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* String representation of option value */ char *widgRec; /* Widget structure record */ int offset; /* Offset of field in record */ { int *statePtr = (int *)(widgRec + offset); if (strcmp(string, "normal") == 0) { *statePtr = STATE_NORMAL; } else if (strcmp(string, "disabled") == 0) { *statePtr = STATE_DISABLED; } else if (strcmp(string, "active") == 0) { *statePtr = STATE_ACTIVE; } else { Tcl_AppendResult(interp, "bad state \"", string, "\": should be normal, active, or disabled", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * StateToString -- * * Returns the string representation of the state configuration field * * Results: * The string is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * StateToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget structure record */ int offset; /* Offset of fill in widget record */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { int state = *(int *)(widgRec + offset); switch (state) { case STATE_ACTIVE: return "active"; case STATE_DISABLED: return "disabled"; case STATE_NORMAL: return "normal"; default: return "???"; } } /* *---------------------------------------------------------------------- * * StringToList -- * * Converts the string to a list. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToList(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* String representation of option value */ char *widgRec; /* Widget structure record */ int offset; /* Offset of field in record */ { char ***listPtr = (char ***)(widgRec + offset); char **elemArr; int nElem; if (*listPtr != NULL) { Blt_Free(*listPtr); *listPtr = NULL; } if ((string == NULL) || (*string == '\0')) { return TCL_OK; } if (Tcl_SplitList(interp, string, &nElem, &elemArr) != TCL_OK) { return TCL_ERROR; } if (nElem > 0) { *listPtr = elemArr; } return TCL_OK; } /* *---------------------------------------------------------------------- * * ListToString -- * * Returns the string representation of the state configuration field * * Results: * The string is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * ListToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget structure record. */ int offset; /* Offset of fill in widget record. */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { char **list = *(char ***)(widgRec + offset); register char **p; char *result; Tcl_DString dString; if (list == NULL) { return ""; } Tcl_DStringInit(&dString); for (p = list; *p != NULL; p++) { Tcl_DStringAppendElement(&dString, *p); } result = Tcl_DStringValue(&dString); if (result == dString.staticSpace) { result = Blt_Strdup(result); } Tcl_DStringFree(&dString); *freeProcPtr = (Tcl_FreeProc *)Blt_Free; return result; } /* *---------------------------------------------------------------------- * * StringToTile -- * * Converts the name of an image into a tile. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToTile(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Window on same display as tile */ char *string; /* Name of image */ char *widgRec; /* Widget structure record */ int offset; /* Offset of tile in record */ { Blt_Tile *tilePtr = (Blt_Tile *)(widgRec + offset); Blt_Tile tile, oldTile; oldTile = *tilePtr; tile = NULL; if ((string != NULL) && (*string != '\0')) { if (Blt_GetTile(interp, tkwin, string, &tile) != TCL_OK) { return TCL_ERROR; } } /* Don't delete the information for the old tile, until we know * that we successfully allocated a new one. */ if (oldTile != NULL) { Blt_FreeTile(oldTile); } *tilePtr = tile; return TCL_OK; } /* *---------------------------------------------------------------------- * * TileToString -- * * Returns the name of the tile. * * Results: * The name of the tile is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * TileToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget structure record */ int offset; /* Offset of tile in record */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { Blt_Tile tile = *(Blt_Tile *)(widgRec + offset); return Blt_NameOfTile(tile); } /* *---------------------------------------------------------------------- * * Blt_ConfigModified -- * * Given the configuration specifications and one or more option * patterns (terminated by a NULL), indicate if any of the matching * configuration options has been reset. * * Results: * Returns 1 if one of the options has changed, 0 otherwise. * *---------------------------------------------------------------------- */ int Blt_ConfigModified TCL_VARARGS_DEF(Tk_ConfigSpec *, arg1) { va_list argList; Tk_ConfigSpec *specs; register Tk_ConfigSpec *specPtr; register char *option; specs = TCL_VARARGS_START(Tk_ConfigSpec *, arg1, argList); while ((option = va_arg(argList, char *)) != NULL) { for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) { if ((Tcl_StringMatch(specPtr->argvName, option)) && (specPtr->specFlags & TK_CONFIG_OPTION_SPECIFIED)) { va_end(argList); return 1; } } } va_end(argList); return 0; } /* *---------------------------------------------------------------------- * * Blt_ConfigureWidgetComponent -- * * Configures a component of a widget. This is useful for * widgets that have multiple components which aren't uniquely * identified by a Tk_Window. It allows us, for example, set * resources for axes of the graph widget. The graph really has * only one window, but its convenient to specify components in a * hierarchy of options. * * *graph.x.logScale yes * *graph.Axis.logScale yes * *graph.temperature.scaleSymbols yes * *graph.Element.scaleSymbols yes * * This is really a hack to work around the limitations of the Tk * resource database. It creates a temporary window, needed to * call Tk_ConfigureWidget, using the name of the component. * * Results: * A standard Tcl result. * * Side Effects: * A temporary window is created merely to pass to Tk_ConfigureWidget. * *---------------------------------------------------------------------- */ int Blt_ConfigureWidgetComponent(interp, parent, resName, className, specsPtr, argc, argv, widgRec, flags) Tcl_Interp *interp; Tk_Window parent; /* Window to associate with component */ char resName[]; /* Name of component */ char className[]; Tk_ConfigSpec *specsPtr; int argc; char *argv[]; char *widgRec; int flags; { Tk_Window tkwin; int result; char *tempName; int isTemporary = FALSE; tempName = Blt_Strdup(resName); /* Window name can't start with an upper case letter */ tempName[0] = tolower(resName[0]); /* * Create component if a child window by the component's name * doesn't already exist. */ tkwin = Blt_FindChild(parent, tempName); if (tkwin == NULL) { tkwin = Tk_CreateWindow(interp, parent, tempName, (char *)NULL); isTemporary = TRUE; } if (tkwin == NULL) { Tcl_AppendResult(interp, "can't find window in \"", Tk_PathName(parent), "\"", (char *)NULL); return TCL_ERROR; } assert(Tk_Depth(tkwin) == Tk_Depth(parent)); Blt_Free(tempName); Tk_SetClass(tkwin, className); result = Tk_ConfigureWidget(interp, tkwin, specsPtr, argc, argv, widgRec, flags); if (isTemporary) { Tk_DestroyWindow(tkwin); } return result; } /* *---------------------------------------------------------------------- * * Blt_StringToEnum -- * * Converts the string into its enumerated type. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ int Blt_StringToEnum(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Vectors of valid strings. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* String to match. */ char *widgRec; /* Widget record. */ int offset; /* Offset of field in record */ { int *enumPtr = (int *)(widgRec + offset); char c; register char **p; register int i; int count; c = string[0]; count = 0; for (p = (char **)clientData; *p != NULL; p++) { if ((c == p[0][0]) && (strcmp(string, *p) == 0)) { *enumPtr = count; return TCL_OK; } count++; } *enumPtr = -1; Tcl_AppendResult(interp, "bad value \"", string, "\": should be ", (char *)NULL); p = (char **)clientData; if (count > 0) { Tcl_AppendResult(interp, p[0], (char *)NULL); } for (i = 1; i < (count - 1); i++) { Tcl_AppendResult(interp, " ", p[i], ", ", (char *)NULL); } if (count > 1) { Tcl_AppendResult(interp, " or ", p[count - 1], ".", (char *)NULL); } return TCL_ERROR; } /* *---------------------------------------------------------------------- * * Blt_EnumToString -- * * Returns the string associated with the enumerated type. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ char * Blt_EnumToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* List of strings. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget record */ int offset; /* Offset of field in widget record */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { int value = *(int *)(widgRec + offset); char **p; int count; count = 0; for (p = (char **)clientData; *p != NULL; p++) { count++; } if ((value >= count) || (value < 0)) { return "unknown value"; } p = (char **)clientData; return p[value]; } blt-2.4z.orig/src/bltConfig.h.in0100644000175000017500000000706207511466705015240 0ustar dokodoko/* src/bltConfig.h.in. Generated automatically from configure.in by autoheader. */ /* Define if you have that is POSIX.1 compatible. */ #undef HAVE_SYS_WAIT_H /* Define to `int' if doesn't define. */ #undef pid_t /* Define to `unsigned' if doesn't define. */ #undef size_t /* Define if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define if you can safely include both and . */ #undef TIME_WITH_SYS_TIME /* Define if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel and VAX). */ #undef WORDS_BIGENDIAN /* Define if DBL_EPSILON is not defined in float.h */ #undef BLT_DBL_EPSILON /* Define if drand48 isn't declared in math.h. */ #undef NEED_DECL_DRAND48 /* Define if srand48 isn't declared in math.h. */ #undef NEED_DECL_SRAND48 /* Define if strdup isn't declared in a standard header file. */ #undef NEED_DECL_STRDUP /* Define if j1 isn't declared in a standard header file. */ #undef NEED_DECL_J1 /* Define if union wait type is defined incorrectly. */ #undef HAVE_UNION_WAIT /* Define if isfinite is found in libm. */ #undef HAVE_ISFINITE /* The number of bytes in a int. */ #undef SIZEOF_INT /* The number of bytes in a long. */ #undef SIZEOF_LONG /* The number of bytes in a long long. */ #undef SIZEOF_LONG_LONG /* The number of bytes in a void *. */ #undef SIZEOF_VOID_P /* Define if you have the XExtendedMaxRequestSize function. */ #undef HAVE_XEXTENDEDMAXREQUESTSIZE /* Define if you have the drand48 function. */ #undef HAVE_DRAND48 /* Define if you have the finite function. */ #undef HAVE_FINITE /* Define if you have the isnan function. */ #undef HAVE_ISNAN /* Define if you have the srand48 function. */ #undef HAVE_SRAND48 /* Define if you have the strcasecmp function. */ #undef HAVE_STRCASECMP /* Define if you have the strdup function. */ #undef HAVE_STRDUP /* Define if you have the strncasecmp function. */ #undef HAVE_STRNCASECMP /* Define if you have the header file. */ #undef HAVE_CTYPE_H /* Define if you have the header file. */ #undef HAVE_ERRNO_H /* Define if you have the header file. */ #undef HAVE_FLOAT_H /* Define if you have the header file. */ #undef HAVE_IEEEFP_H /* Define if you have the header file. */ #undef HAVE_INTTYPES_H /* Define if you have the header file. */ #undef HAVE_JPEGLIB_H /* Define if you have the header file. */ #undef HAVE_LIMITS_H /* Define if you have the header file. */ #undef HAVE_MALLOC_H /* Define if you have the header file. */ #undef HAVE_MATH_H /* Define if you have the header file. */ #undef HAVE_MEMORY_H /* Define if you have the header file. */ #undef HAVE_SETJMP_H /* Define if you have the header file. */ #undef HAVE_STDLIB_H /* Define if you have the header file. */ #undef HAVE_STRING_H /* Define if you have the header file. */ #undef HAVE_SYS_PARAM_H /* Define if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define if you have the header file. */ #undef HAVE_SYS_WAIT_H /* Define if you have the header file. */ #undef HAVE_UNISTD_H /* Define if you have the header file. */ #undef HAVE_WAITFLAGS_H /* Define if you have the m library (-lm). */ #undef HAVE_LIBM /* Define if you have the nsl library (-lnsl). */ #undef HAVE_LIBNSL /* Define if you have the socket library (-lsocket). */ #undef HAVE_LIBSOCKET blt-2.4z.orig/src/bltContainer.c0100644000175000017500000014045507514405104015334 0ustar dokodoko /* * bltContainer.c -- * * This module implements a container widget for the BLT toolkit. * * Copyright 1998 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 or 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. * * Container widget created by George A. Howlett */ #include "bltInt.h" #ifndef NO_CONTAINER #include "bltChain.h" #ifndef WIN32 #include #include #endif #define XDEBUG #define SEARCH_TRIES 100 /* Maximum number of attempts to check for * a given window before failing. */ #define SEARCH_INTERVAL 20 /* Number milliseconds to wait after each * attempt to find a window. */ #define SEARCH_TKWIN (1<<0) /* Search via Tk window pathname. */ #define SEARCH_XID (1<<1) /* Search via an XID 0x0000000. */ #define SEARCH_CMD (1<<2) /* Search via a command-line arguments. */ #define SEARCH_NAME (1<<3) /* Search via the application name. */ #define SEARCH_ALL (SEARCH_TKWIN | SEARCH_XID | SEARCH_CMD | SEARCH_NAME) #define CONTAINER_REDRAW (1<<1) #define CONTAINER_MAPPED (1<<2) #define CONTAINER_FOCUS (1<<4) #define CONTAINER_INIT (1<<5) #define CONTAINER_MOVE (1<<7) #define DEF_CONTAINER_BG_MONO STD_NORMAL_BG_MONO #define DEF_CONTAINER_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_CONTAINER_BORDERWIDTH STD_BORDERWIDTH #define DEF_CONTAINER_COMMAND (char *)NULL #define DEF_CONTAINER_CURSOR (char *)NULL #define DEF_CONTAINER_HEIGHT "0" #define DEF_CONTAINER_HIGHLIGHT_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_CONTAINER_HIGHLIGHT_BG_MONO STD_NORMAL_BG_MONO #define DEF_CONTAINER_HIGHLIGHT_COLOR RGB_BLACK #define DEF_CONTAINER_HIGHLIGHT_WIDTH "2" #define DEF_CONTAINER_RELIEF "sunken" #define DEF_CONTAINER_TAKE_FOCUS "0" #define DEF_CONTAINER_TIMEOUT "20" #define DEF_CONTAINER_WIDTH "0" #define DEF_CONTAINER_WINDOW (char *)NULL #if (TK_MAJOR_VERSION == 4) #define TK_REPARENTED 0x2000 #endif typedef struct SearchInfoStruct SearchInfo; typedef void (SearchProc) _ANSI_ARGS_((Display *display, Window window, SearchInfo *searchPtr)); struct SearchInfoStruct { SearchProc *proc; char *pattern; /* Search pattern. */ Window window; /* XID of last window that matches criteria. */ int nMatches; /* Number of windows that match the pattern. */ int saveNames; /* Indicates to save the names of the * window XIDs that match the search * criteria. */ Tcl_DString dString; /* Will contain the strings of the * window XIDs matching the search * criteria. */ }; typedef struct { Tk_Window tkwin; /* Window that embodies the widget. * NULL means that the window has been * destroyed but the data structures * haven't yet been cleaned up.*/ Display *display; /* Display containing widget; needed, * among other things, to release * resources after tkwin has already * gone away. */ Tcl_Interp *interp; /* Interpreter associated with widget. */ Tcl_Command cmdToken; /* Token for widget's command. */ unsigned int flags; /* For bit-field definitions, see above. */ int inset; /* Total width of borders; focus * highlight and 3-D border. Indicates * the offset from outside edges to * leave room for borders. */ Tk_Cursor cursor; /* X Cursor */ Tk_3DBorder border; /* 3D border surrounding the adopted * window. */ int borderWidth; /* Width of 3D border. */ int relief; /* 3D border relief. */ Tk_Window tkToplevel; /* Toplevel (wrapper) window of * container. It's used to track the * location of the container. If it * moves we need to notify the * embedded application. */ /* * Focus highlight ring */ int highlightWidth; /* Width in pixels of highlight to * draw around widget when it has the * focus. <= 0 means don't draw a * highlight. */ XColor *highlightBgColor; /* Color for drawing traversal * highlight area when highlight is * off. */ XColor *highlightColor; /* Color for drawing traversal highlight. */ GC highlightGC; /* GC for focus highlight. */ char *takeFocus; /* Says whether to select this widget during * tab traveral operations. This value isn't * used in C code, but for the widget's Tcl * bindings. */ int reqWidth, reqHeight; /* Requested dimensions of the container * window. */ Window adopted; /* X window Id or Win32 handle of adopted * window contained by the widget. If None, * no window has been reparented. */ Tk_Window tkAdopted; /* Non-NULL if this is a Tk window that's * been adopted. */ int adoptedX, adoptedY; /* Current position of the adopted window. */ int adoptedWidth; /* Current width of the adopted window. */ int adoptedHeight; /* Current height of the adopted window. */ int origX, origY; int origWidth, origHeight; /* Dimensions of the window when it * was adopted. When the window is * released it's returned to it's * original dimensions. */ int timeout; } Container; static Tk_OptionParseProc StringToXID; static Tk_OptionPrintProc XIDToString; static Tk_CustomOption XIDOption = { StringToXID, XIDToString, (ClientData)(SEARCH_TKWIN | SEARCH_XID), }; #ifndef WIN32 static Tk_CustomOption XIDNameOption = { StringToXID, XIDToString, (ClientData)SEARCH_NAME, }; static Tk_CustomOption XIDCmdOption = { StringToXID, XIDToString, (ClientData)SEARCH_CMD, }; #endif extern Tk_CustomOption bltDistanceOption; extern Tk_CustomOption bltPositiveCountOption; static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_CONTAINER_BG_MONO, Tk_Offset(Container, border), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_CONTAINER_BACKGROUND, Tk_Offset(Container, border), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_CUSTOM, "-borderwidth", "borderWidth", "BorderWidth", DEF_CONTAINER_BORDERWIDTH, Tk_Offset(Container, borderWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, #ifndef WIN32 {TK_CONFIG_CUSTOM, "-command", "command", "Command", DEF_CONTAINER_WINDOW, Tk_Offset(Container, adopted), TK_CONFIG_DONT_SET_DEFAULT, &XIDCmdOption}, #endif {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", DEF_CONTAINER_CURSOR, Tk_Offset(Container, cursor), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-height", "height", "Height", DEF_CONTAINER_HEIGHT, Tk_Offset(Container, reqHeight), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", "HighlightBackground", DEF_CONTAINER_HIGHLIGHT_BACKGROUND, Tk_Offset(Container, highlightBgColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", "HighlightBackground", DEF_CONTAINER_HIGHLIGHT_BG_MONO, Tk_Offset(Container, highlightBgColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", DEF_CONTAINER_HIGHLIGHT_COLOR, Tk_Offset(Container, highlightColor), 0}, {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", "HighlightThickness", DEF_CONTAINER_HIGHLIGHT_WIDTH, Tk_Offset(Container, highlightWidth), TK_CONFIG_DONT_SET_DEFAULT}, #ifndef WIN32 {TK_CONFIG_CUSTOM, "-name", "name", "Name", DEF_CONTAINER_WINDOW, Tk_Offset(Container, adopted), TK_CONFIG_DONT_SET_DEFAULT, &XIDNameOption}, #endif {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_CONTAINER_RELIEF, Tk_Offset(Container, relief), 0}, {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", DEF_CONTAINER_TAKE_FOCUS, Tk_Offset(Container, takeFocus), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-timeout", "timeout", "Timeout", DEF_CONTAINER_TIMEOUT, Tk_Offset(Container, timeout), TK_CONFIG_DONT_SET_DEFAULT, &bltPositiveCountOption}, {TK_CONFIG_CUSTOM, "-width", "width", "Width", DEF_CONTAINER_WIDTH, Tk_Offset(Container, reqWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-window", "window", "Window", DEF_CONTAINER_WINDOW, Tk_Offset(Container, adopted), TK_CONFIG_DONT_SET_DEFAULT, &XIDOption}, {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; /* Forward Declarations */ static Tcl_IdleProc DisplayContainer; static Tcl_CmdProc ContainerInstCmd; static Tcl_CmdDeleteProc ContainerInstCmdDeleteProc; static Tk_EventProc ToplevelEventProc; static Tk_GenericProc AdoptedWindowEventProc; static Tk_EventProc ContainerEventProc; static Tcl_FreeProc DestroyContainer; static Tcl_CmdProc ContainerCmd; static void EventuallyRedraw _ANSI_ARGS_((Container *cntrPtr)); #ifdef notdef /* *---------------------------------------------------------------------- * * GetWindowId -- * * Returns the XID for the Tk_Window given. Starting in Tk 8.0, * the toplevel widgets are wrapped by another window. * Currently there's no way to get at that window, other than * what is done here: query the X window hierarchy and grab the * parent. * * Results: * Returns the X Window ID of the widget. If it's a toplevel, then * the XID of the wrapper is returned. * *---------------------------------------------------------------------- */ Window GetXID(tkwin) Tk_Window tkwin; { HWND hWnd; TkWinWindow *twdPtr; hWnd = Tk_GetHWND(Tk_WindowId(tkwin)); #if (TK_MAJOR_VERSION > 4) if (Tk_IsTopLevel(tkwin)) { hWnd = GetParent(hWnd); } #endif /* TK_MAJOR_VERSION > 4 */ twdPtr = Blt_Malloc(sizeof(TkWinWindow)); twdPtr->handle = hWnd; twdPtr->type = TWD_WINDOW; twdPtr->winPtr = tkwin; return (Window)twdPtr; } #endif /* *---------------------------------------------------------------------- * * NameOfId -- * * Returns a string representing the given XID. * * Results: * A static string containing either the hexidecimal number or * the pathname of a Tk window. * *---------------------------------------------------------------------- */ static char * NameOfId(display, window) Display *display; /* Display containing both the container widget * and the adopted window. */ Window window; /* XID of the adopted window. */ { if (window != None) { Tk_Window tkwin; static char string[200]; /* See first if it's a window that Tk knows about. */ /* * Note: If the wrapper window is reparented, Tk pretends it's * no longer connected to the toplevel, so if you look for * the child of the wrapper tkwin, it's NULL. */ tkwin = Tk_IdToWindow(display, window); if ((tkwin != NULL) && (Tk_PathName(tkwin) != NULL)) { return Tk_PathName(tkwin); } sprintf(string, "0x%x", (unsigned int)window); return string; } return ""; /* Return empty string if XID is None. */ } #ifndef WIN32 /* *---------------------------------------------------------------------- * * XGeometryErrorProc -- * * Flags errors generated from XGetGeometry calls to the X server. * * Results: * Always returns 0. * * Side Effects: * Sets a flag, indicating an error occurred. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int XGeometryErrorProc(clientData, eventPtr) ClientData clientData; XErrorEvent *eventPtr; /* Not used. */ { int *errorPtr = clientData; *errorPtr = TCL_ERROR; return 0; } /* *---------------------------------------------------------------------- * * GetAdoptedWindowGeometry -- * * Computes the requested geometry of the container using the * size of adopted window as a reference. * * Results: * A standard Tcl result. * * Side Effects: * Sets a flag, indicating an error occurred. * *---------------------------------------------------------------------- */ static int GetAdoptedWindowGeometry(interp, cntrPtr) Tcl_Interp *interp; Container *cntrPtr; { int x, y, width, height, borderWidth, depth; int xOffset, yOffset; Window root, dummy; Tk_ErrorHandler handler; int result; int any = -1; width = height = 1; xOffset = yOffset = 0; if (cntrPtr->adopted != None) { handler = Tk_CreateErrorHandler(cntrPtr->display, any, X_GetGeometry, any, XGeometryErrorProc, &result); root = RootWindow(cntrPtr->display, Tk_ScreenNumber(cntrPtr->tkwin)); XTranslateCoordinates(cntrPtr->display, cntrPtr->adopted, root, 0, 0, &xOffset, &yOffset, &dummy); result = XGetGeometry(cntrPtr->display, cntrPtr->adopted, &root, &x, &y, (unsigned int *)&width, (unsigned int *)&height, (unsigned int *)&borderWidth, (unsigned int *)&depth); Tk_DeleteErrorHandler(handler); XSync(cntrPtr->display, False); if (result == 0) { Tcl_AppendResult(interp, "can't get geometry for \"", NameOfId(cntrPtr->display, cntrPtr->adopted), "\"", (char *)NULL); return TCL_ERROR; } cntrPtr->origX = xOffset; cntrPtr->origY = yOffset; cntrPtr->origWidth = width; cntrPtr->origHeight = height; } else { cntrPtr->origX = cntrPtr->origY = 0; cntrPtr->origWidth = cntrPtr->origHeight = 0; } cntrPtr->adoptedX = x; cntrPtr->adoptedY = y; cntrPtr->adoptedWidth = width; cntrPtr->adoptedHeight = height; return TCL_OK; } /* * ------------------------------------------------------------------------ * * GetChildren -- * * Returns a chain of the child windows according to their stacking * order. The window ids are ordered from top to bottom. * * ------------------------------------------------------------------------ */ static Blt_Chain * GetChildren(display, window) Display *display; Window window; { Window *children; unsigned int nChildren; Window dummy; if (!XQueryTree(display, window, &dummy /*parent*/, &dummy /*root*/, &children, &nChildren)) { return NULL; } if (nChildren > 0) { Blt_Chain *chainPtr; register int i; chainPtr = Blt_ChainCreate(); for (i = 0; i < nChildren; i++) { /* * XQuery returns windows in bottom to top order. * We'll reverse the order. */ Blt_ChainPrepend(chainPtr, (ClientData)children[i]); } if (children != NULL) { XFree((char *)children); } return chainPtr; } return NULL; } /* *---------------------------------------------------------------------- * * NameSearch -- * * Traverses the entire window hierarchy, searching for windows * matching the name field in the SearchInfo structure. This * routine is recursively called for each successive level in * the window hierarchy. * * Results: * None. * * Side Effects: * The SearchInfo structure will track the number of windows that * match the given criteria. * *---------------------------------------------------------------------- */ static void NameSearch(display, window, searchPtr) Display *display; Window window; SearchInfo *searchPtr; { Blt_Chain *chainPtr; char *wmName; if (XFetchName(display, window, &wmName)) { /* Compare the name of the window to the search pattern. */ if (Tcl_StringMatch(wmName, searchPtr->pattern)) { if (searchPtr->saveNames) { /* Record names of matching windows. */ Tcl_DStringAppendElement(&(searchPtr->dString), NameOfId(display, window)); Tcl_DStringAppendElement(&(searchPtr->dString), wmName); } searchPtr->window = window; searchPtr->nMatches++; } XFree(wmName); } /* Process the window's descendants. */ chainPtr = GetChildren(display, window); if (chainPtr != NULL) { Blt_ChainLink *linkPtr; Window child; for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { child = (Window)Blt_ChainGetValue(linkPtr); NameSearch(display, child, searchPtr); } Blt_ChainDestroy(chainPtr); } } /* *---------------------------------------------------------------------- * * CmdSearch -- * * Traverses the entire window hierarchy, searching for windows * matching the command-line specified in the SearchInfo structure. * This routine is recursively called for each successive level * in the window hierarchy. * * Results: * None. * * Side Effects: * The SearchInfo structure will track the number of windows that * match the given command-line. * *---------------------------------------------------------------------- */ static void CmdSearch(display, window, searchPtr) Display *display; Window window; SearchInfo *searchPtr; { Blt_Chain *chainPtr; int cmdArgc; char **cmdArgv; if (XGetCommand(display, window, &cmdArgv, &cmdArgc)) { char *string; string = Tcl_Merge(cmdArgc, cmdArgv); XFreeStringList(cmdArgv); if (Tcl_StringMatch(string, searchPtr->pattern)) { if (searchPtr->saveNames) { /* Record names of matching windows. */ Tcl_DStringAppendElement(&(searchPtr->dString), NameOfId(display, window)); Tcl_DStringAppendElement(&(searchPtr->dString), string); } searchPtr->window = window; searchPtr->nMatches++; } Blt_Free(string); } /* Process the window's descendants. */ chainPtr = GetChildren(display, window); if (chainPtr != NULL) { Blt_ChainLink *linkPtr; Window child; for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { child = (Window)Blt_ChainGetValue(linkPtr); CmdSearch(display, child, searchPtr); } Blt_ChainDestroy(chainPtr); } } /* *---------------------------------------------------------------------- * * TimeoutProc -- * * Procedure called when the timer event elapses. Used to wait * between attempts checking for the designated window. * * Results: * None. * * Side Effects: * Sets a flag, indicating the timeout occurred. * *---------------------------------------------------------------------- */ static void TimeoutProc(clientData) ClientData clientData; { int *expirePtr = clientData; *expirePtr = TRUE; } /* *---------------------------------------------------------------------- * * TestAndWaitForWindow -- * * Searches, possibly multiple times, for windows matching the * criteria given, using the search proc also given. * * Results: * None. * * Side Effects: * Sets a flag, indicating the timeout occurred. * *---------------------------------------------------------------------- */ static void TestAndWaitForWindow(cntrPtr, searchPtr) Container *cntrPtr; /* Container widget record. */ SearchInfo *searchPtr; /* Search criteria. */ { Window root; Tcl_TimerToken timerToken; int expire; int i; /* Get the root window to start the search. */ root = RootWindow(cntrPtr->display, Tk_ScreenNumber(cntrPtr->tkwin)); timerToken = NULL; for (i = 0; i < SEARCH_TRIES; i++) { searchPtr->nMatches = 0; (*searchPtr->proc)(cntrPtr->display, root, searchPtr); if (searchPtr->nMatches > 0) { if (timerToken != NULL) { Tcl_DeleteTimerHandler(timerToken); } return; } expire = FALSE; /* * If the X11 application associated with the adopted window * was just started (via "exec" or "bgexec"), the window may * not exist yet. We have to wait a little bit for the program * to start up. Create a timer event break us out of an wait * loop. We'll wait for a given interval for the adopted window * to appear. */ timerToken = Tcl_CreateTimerHandler(cntrPtr->timeout, TimeoutProc, &expire); while (!expire) { /* Should file events be allowed? */ Tcl_DoOneEvent(TCL_TIMER_EVENTS | TCL_WINDOW_EVENTS | TCL_FILE_EVENTS); } } } #else /* * ------------------------------------------------------------------------ * * GetChildren -- * * Returns a chain of the child windows according to their stacking * order. The window ids are ordered from top to bottom. * * ------------------------------------------------------------------------ */ static Blt_Chain * GetChildren(Display *display, Window window) { Blt_Chain *chainPtr; HWND hWnd; HWND parent; parent = Tk_GetHWND(window); chainPtr = Blt_ChainCreate(); for (hWnd = GetTopWindow(parent); hWnd != NULL; hWnd = GetNextWindow(hWnd, GW_HWNDNEXT)) { Blt_ChainAppend(chainPtr, (ClientData)hWnd); } return chainPtr; } /* *---------------------------------------------------------------------- * * GetAdoptedWindowGeometry -- * * Computes the requested geometry of the container using the * size of adopted window as a reference. * * Results: * A standard Tcl result. * * Side Effects: * Sets a flag, indicating an error occurred. * *---------------------------------------------------------------------- */ static int GetAdoptedWindowGeometry(Tcl_Interp *interp, Container *cntrPtr) { int x, y, width, height; int xOffset, yOffset; Window root, dummy; width = height = 1; xOffset = yOffset = 0; x = y = 0; if (cntrPtr->adopted != None) { HWND hWnd; RECT rect; hWnd = Tk_GetHWND(cntrPtr->adopted); if (GetWindowRect(hWnd, &rect)) { x = rect.left; y = rect.top; width = rect.right - rect.left + 1; height = rect.bottom - rect.top + 1; } else { Tcl_AppendResult(interp, "can't get geometry for \"", NameOfId(cntrPtr->display, cntrPtr->adopted), "\"", (char *)NULL); return TCL_ERROR; } root = RootWindow(cntrPtr->display, Tk_ScreenNumber(cntrPtr->tkwin)); XTranslateCoordinates(cntrPtr->display, cntrPtr->adopted, root, 0, 0, &xOffset, &yOffset, &dummy); cntrPtr->origX = xOffset; cntrPtr->origY = yOffset; cntrPtr->origWidth = width; cntrPtr->origHeight = height; } else { cntrPtr->origX = cntrPtr->origY = 0; cntrPtr->origWidth = cntrPtr->origHeight = 0; } cntrPtr->adoptedX = x; cntrPtr->adoptedY = y; cntrPtr->adoptedWidth = width; cntrPtr->adoptedHeight = height; return TCL_OK; } #endif /*WIN32*/ /* * ------------------------------------------------------------------------ * * MapTree -- * * Maps each window in the hierarchy. This is needed because * * Results: * None. * * Side Effects: * Each window in the hierarchy is mapped. * * ------------------------------------------------------------------------ */ static void MapTree(display, window) Display *display; Window window; { Blt_Chain *chainPtr; XMapWindow(display, window); chainPtr = GetChildren(display, window); if (chainPtr != NULL) { Blt_ChainLink *linkPtr; Window child; for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { child = (Window)Blt_ChainGetValue(linkPtr); MapTree(display, child); } Blt_ChainDestroy(chainPtr); } } /* *---------------------------------------------------------------------- * * StringToXID -- * * Converts a string into an X window Id. * * Results: * If the string is successfully converted, TCL_OK is returned. * Otherwise, TCL_ERROR is returned and an error message is left * in interpreter's result field. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToXID(clientData, interp, parent, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window parent; /* Parent window */ char *string; /* String representation. */ char *widgRec; /* Widget record */ int offset; /* Offset to field in structure */ { unsigned int flags = (int)clientData; Container *cntrPtr = (Container *)widgRec; Window *winPtr = (Window *) (widgRec + offset); Tk_Window tkAdopted; Window window; tkAdopted = NULL; window = None; if ((flags & SEARCH_TKWIN) && (string[0] == '.')) { Tk_Window tkwin; tkwin = Tk_NameToWindow(interp, string, Tk_MainWindow(interp)); if (tkwin == NULL) { return TCL_ERROR; } if (!Tk_IsTopLevel(tkwin)) { Tcl_AppendResult(interp, "can't reparent non-toplevel Tk windows", (char *)NULL); return TCL_ERROR; } tkAdopted = tkwin; Tk_MakeWindowExist(tkwin); window = Blt_GetRealWindowId(tkwin); #ifndef WIN32 } else if ((flags & SEARCH_XID) && (string[0] == '0') && (string[1] == 'x')) { int token; /* Hexidecimal string specifying the Window token. */ if (Tcl_GetInt(interp, string, &token) != TCL_OK) { return TCL_ERROR; } window = token; } else if ((string == NULL) || (string[0] == '\0')) { window = None; } else { SearchInfo search; memset(&search, 0, sizeof(search)); if (flags & (SEARCH_NAME | SEARCH_CMD)) { search.pattern = string; if (flags & SEARCH_NAME) { search.proc = NameSearch; } else if (flags & SEARCH_CMD) { search.proc = CmdSearch; } TestAndWaitForWindow(cntrPtr, &search); if (search.nMatches > 1) { Tcl_AppendResult(interp, "more than one window matches \"", string, "\"", (char *)NULL); return TCL_ERROR; } } if (search.nMatches == 0) { Tcl_AppendResult(interp, "can't find window from pattern \"", string, "\"", (char *)NULL); return TCL_ERROR; } window = search.window; #endif /*WIN32*/ } if (*winPtr != None) { Window root; root = RootWindow(cntrPtr->display, Tk_ScreenNumber(cntrPtr->tkwin)); if (Blt_ReparentWindow(cntrPtr->display, *winPtr, root, cntrPtr->origX, cntrPtr->origY) != TCL_OK) { Tcl_AppendResult(interp, "can't restore \"", NameOfId(cntrPtr->display, *winPtr), "\" window to root", (char *)NULL); return TCL_ERROR; } cntrPtr->flags &= ~CONTAINER_MAPPED; if (cntrPtr->tkAdopted == NULL) { /* This wasn't a Tk window. So deselect the event mask. */ XSelectInput(cntrPtr->display, *winPtr, 0); } else { MapTree(cntrPtr->display, *winPtr); } XMoveResizeWindow(cntrPtr->display, *winPtr, cntrPtr->origX, cntrPtr->origY, cntrPtr->origWidth, cntrPtr->origHeight); } cntrPtr->tkAdopted = tkAdopted; *winPtr = window; return TCL_OK; } /* *---------------------------------------------------------------------- * * XIDToString -- * * Converts the Tk window back to its string representation (i.e. * its name). * * Results: * The name of the window is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * XIDToString(clientData, parent, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window parent; /* Not used. */ char *widgRec; /* Widget record */ int offset; /* Offset of field in record */ Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */ { Container *cntrPtr = (Container *) widgRec; Window window = *(Window *)(widgRec + offset); if (cntrPtr->tkAdopted != NULL) { return Tk_PathName(cntrPtr->tkAdopted); } return NameOfId(cntrPtr->display, window); } /* *---------------------------------------------------------------------- * * EventuallyRedraw -- * * Queues a request to redraw the widget at the next idle point. * * Results: * None. * * Side effects: * Information gets redisplayed. Right now we don't do selective * redisplays: the whole window will be redrawn. * *---------------------------------------------------------------------- */ static void EventuallyRedraw(cntrPtr) Container *cntrPtr; { if ((cntrPtr->tkwin != NULL) && !(cntrPtr->flags & CONTAINER_REDRAW)) { cntrPtr->flags |= CONTAINER_REDRAW; Tcl_DoWhenIdle(DisplayContainer, cntrPtr); } } /* * -------------------------------------------------------------- * * AdoptedWindowEventProc -- * * This procedure is invoked by the Tk dispatcher for various * events on the encapsulated window. * * Results: * None. * * Side effects: * When the window gets deleted, internal structures get * cleaned up. When it gets resized or exposed, it's redisplayed. * * -------------------------------------------------------------- */ static int AdoptedWindowEventProc(clientData, eventPtr) ClientData clientData; /* Information about the tab window. */ XEvent *eventPtr; /* Information about event. */ { Container *cntrPtr = (Container *) clientData; if (eventPtr->xany.window != cntrPtr->adopted) { return 0; } if (eventPtr->type == DestroyNotify) { cntrPtr->adopted = None; EventuallyRedraw(cntrPtr); } return 1; } /* * -------------------------------------------------------------- * * ContainerEventProc -- * * This procedure is invoked by the Tk dispatcher for various * events on container widgets. * * Results: * None. * * Side Effects: * When the window gets deleted, internal structures get * cleaned up. When it gets exposed, it is redisplayed. * * -------------------------------------------------------------- */ static void ContainerEventProc(clientData, eventPtr) ClientData clientData; /* Information about window. */ XEvent *eventPtr; /* Information about event. */ { Container *cntrPtr = clientData; switch (eventPtr->type) { case Expose: if (eventPtr->xexpose.count == 0) { EventuallyRedraw(cntrPtr); } break; case FocusIn: case FocusOut: if (eventPtr->xfocus.detail != NotifyInferior) { if (eventPtr->type == FocusIn) { cntrPtr->flags |= CONTAINER_FOCUS; } else { cntrPtr->flags &= ~CONTAINER_FOCUS; } EventuallyRedraw(cntrPtr); } break; case ConfigureNotify: EventuallyRedraw(cntrPtr); break; case DestroyNotify: if (cntrPtr->tkwin != NULL) { cntrPtr->tkwin = NULL; Tcl_DeleteCommandFromToken(cntrPtr->interp, cntrPtr->cmdToken); } if (cntrPtr->flags & CONTAINER_REDRAW) { Tcl_CancelIdleCall(DisplayContainer, cntrPtr); } Tcl_EventuallyFree(cntrPtr, DestroyContainer); break; } } /* * -------------------------------------------------------------- * * ToplevelEventProc -- * * Some applications assume that they are always a toplevel * window and play tricks accordingly. For example, Netscape * positions menus in relation to the toplevel. But if the * container's toplevel is moved, this positioning is wrong. * So watch if the toplevel is moved. * * [This would be easier and cleaner if Tk toplevels weren't so * botched by the addition of menubars. It's not enough to * track the ) * * Results: * None. * * -------------------------------------------------------------- */ static void ToplevelEventProc(clientData, eventPtr) ClientData clientData; /* Information about the tab window. */ XEvent *eventPtr; /* Information about event. */ { Container *cntrPtr = clientData; if ((cntrPtr->adopted != None) && (cntrPtr->tkwin != NULL) && (eventPtr->type == ConfigureNotify)) { cntrPtr->flags |= CONTAINER_MOVE; EventuallyRedraw(cntrPtr); } } /* * ---------------------------------------------------------------------- * * DestroyContainer -- * * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release * to clean up the internal structure of the widget at a safe * time (when no-one is using it anymore). * * Results: * None. * * Side Effects: * Everything associated with the widget is freed up. * * ---------------------------------------------------------------------- */ static void DestroyContainer(dataPtr) DestroyData dataPtr; /* Pointer to the widget record. */ { Container *cntrPtr = (Container *) dataPtr; if (cntrPtr->highlightGC != NULL) { Tk_FreeGC(cntrPtr->display, cntrPtr->highlightGC); } if (cntrPtr->flags & CONTAINER_INIT) { Tk_DeleteGenericHandler(AdoptedWindowEventProc, cntrPtr); } if (cntrPtr->tkToplevel != NULL) { Tk_DeleteEventHandler(cntrPtr->tkToplevel, StructureNotifyMask, ToplevelEventProc, cntrPtr); } Tk_FreeOptions(configSpecs, (char *)cntrPtr, cntrPtr->display, 0); Blt_Free(cntrPtr); } /* * ---------------------------------------------------------------------- * * ConfigureContainer -- * * This procedure is called to process an argv/argc list, plus * the Tk option database, in order to configure (or reconfigure) * the widget. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then interp->result contains an error message. * * Side Effects: * Configuration information, such as text string, colors, font, * etc. get set for cntrPtr; old resources get freed, if there * were any. The widget is redisplayed. * * ---------------------------------------------------------------------- */ static int ConfigureContainer(interp, cntrPtr, argc, argv, flags) Tcl_Interp *interp; /* Interpreter to report errors. */ Container *cntrPtr; /* Information about widget; may or * may not already have values for * some fields. */ int argc; char **argv; int flags; { XGCValues gcValues; unsigned long gcMask; GC newGC; int width, height; if (Tk_ConfigureWidget(interp, cntrPtr->tkwin, configSpecs, argc, argv, (char *)cntrPtr, flags) != TCL_OK) { return TCL_ERROR; } cntrPtr->inset = cntrPtr->borderWidth + cntrPtr->highlightWidth; if (Tk_WindowId(cntrPtr->tkwin) == None) { Tk_MakeWindowExist(cntrPtr->tkwin); } if (GetAdoptedWindowGeometry(interp, cntrPtr) != TCL_OK) { return TCL_ERROR; } if (Blt_ConfigModified(configSpecs, "-window", "-name", "-command", (char *)NULL)) { cntrPtr->flags &= ~CONTAINER_MAPPED; if (cntrPtr->adopted != None) { if (Blt_ReparentWindow(cntrPtr->display, cntrPtr->adopted, Tk_WindowId(cntrPtr->tkwin), cntrPtr->inset, cntrPtr->inset) != TCL_OK) { Tcl_AppendResult(interp, "can't adopt window \"", NameOfId(cntrPtr->display, cntrPtr->adopted), "\"", (char *)NULL); return TCL_ERROR; } XSelectInput(cntrPtr->display, cntrPtr->adopted, StructureNotifyMask); if ((cntrPtr->flags & CONTAINER_INIT) == 0) { Tk_CreateGenericHandler(AdoptedWindowEventProc, cntrPtr); cntrPtr->flags |= CONTAINER_INIT; } } } /* Add the designated inset to the requested dimensions. */ width = cntrPtr->origWidth + 2 * cntrPtr->inset; height = cntrPtr->origHeight + 2 * cntrPtr->inset; if (cntrPtr->reqWidth > 0) { width = cntrPtr->reqWidth; } if (cntrPtr->reqHeight > 0) { height = cntrPtr->reqHeight; } /* Set the requested width and height for the container. */ if ((Tk_ReqWidth(cntrPtr->tkwin) != width) || (Tk_ReqHeight(cntrPtr->tkwin) != height)) { Tk_GeometryRequest(cntrPtr->tkwin, width, height); } /* * GC for focus highlight. */ gcMask = GCForeground; gcValues.foreground = cntrPtr->highlightColor->pixel; newGC = Tk_GetGC(cntrPtr->tkwin, gcMask, &gcValues); if (cntrPtr->highlightGC != NULL) { Tk_FreeGC(cntrPtr->display, cntrPtr->highlightGC); } cntrPtr->highlightGC = newGC; EventuallyRedraw(cntrPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * ContainerInstCmdDeleteProc -- * * This procedure can be called if the window was destroyed * (tkwin will be NULL) and the command was deleted * automatically. In this case, we need to do nothing. * * Otherwise this routine was called because the command was * deleted. Then we need to clean-up and destroy the widget. * * Results: * None. * * Side Effects: * The widget is destroyed. * *---------------------------------------------------------------------- */ static void ContainerInstCmdDeleteProc(clientData) ClientData clientData; /* Pointer to widget record for widget. */ { Container *cntrPtr = clientData; if (cntrPtr->tkwin != NULL) { Tk_Window tkwin; tkwin = cntrPtr->tkwin; cntrPtr->tkwin = NULL; Tk_DestroyWindow(tkwin); #ifdef ITCL_NAMESPACES Itk_SetWidgetCommand(tkwin, (Tcl_Command) NULL); #endif /* ITCL_NAMESPACES */ } } /* * ------------------------------------------------------------------------ * * ContainerCmd -- * * This procedure is invoked to process the Tcl command that * corresponds to a widget managed by this module. See the user * documentation for details on what it does. * * Results: * A standard Tcl result. * * Side Effects: * See the user documentation. * * ----------------------------------------------------------------------- */ /* ARGSUSED */ static int ContainerCmd(clientData, interp, argc, argv) ClientData clientData; /* Main window associated with interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { Container *cntrPtr; Tk_Window tkwin; unsigned int mask; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " pathName ?option value?...\"", (char *)NULL); return TCL_ERROR; } tkwin = Tk_MainWindow(interp); tkwin = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *)NULL); if (tkwin == NULL) { return TCL_ERROR; } cntrPtr = Blt_Calloc(1, sizeof(Container)); assert(cntrPtr); cntrPtr->tkwin = tkwin; cntrPtr->display = Tk_Display(tkwin); cntrPtr->interp = interp; cntrPtr->flags = 0; cntrPtr->timeout = SEARCH_INTERVAL; cntrPtr->borderWidth = cntrPtr->highlightWidth = 2; cntrPtr->relief = TK_RELIEF_SUNKEN; Tk_SetClass(tkwin, "Container"); #if (TK_MAJOR_VERSION > 4) Blt_SetWindowInstanceData(tkwin, cntrPtr); #endif if (ConfigureContainer(interp, cntrPtr, argc - 2, argv + 2, 0) != TCL_OK) { Tk_DestroyWindow(cntrPtr->tkwin); return TCL_ERROR; } mask = (StructureNotifyMask | ExposureMask | FocusChangeMask); Tk_CreateEventHandler(tkwin, mask, ContainerEventProc, cntrPtr); cntrPtr->cmdToken = Tcl_CreateCommand(interp, argv[1], ContainerInstCmd, cntrPtr, ContainerInstCmdDeleteProc); #ifdef ITCL_NAMESPACES Itk_SetWidgetCommand(cntrPtr->tkwin, cntrPtr->cmdToken); #endif Tk_MakeWindowExist(tkwin); Tcl_SetResult(interp, Tk_PathName(cntrPtr->tkwin), TCL_VOLATILE); return TCL_OK; } /* * ---------------------------------------------------------------------- * * DisplayContainer -- * * This procedure is invoked to display the widget. * * Results: * None. * * Side effects: * The widget is redisplayed. * * ---------------------------------------------------------------------- */ static void DisplayContainer(clientData) ClientData clientData; /* Information about widget. */ { Container *cntrPtr = clientData; Drawable drawable; int width, height; cntrPtr->flags &= ~CONTAINER_REDRAW; if (cntrPtr->tkwin == NULL) { return; /* Window has been destroyed. */ } if (!Tk_IsMapped(cntrPtr->tkwin)) { return; } drawable = Tk_WindowId(cntrPtr->tkwin); #ifndef WIN32 if (cntrPtr->tkToplevel == NULL) { Window window; Tk_Window tkToplevel; /* Create an event handler for the toplevel of the container. */ tkToplevel = Blt_Toplevel(cntrPtr->tkwin); window = Blt_GetRealWindowId(tkToplevel); cntrPtr->tkToplevel = Tk_IdToWindow(cntrPtr->display, window); if (cntrPtr->tkToplevel != NULL) { Tk_CreateEventHandler(cntrPtr->tkToplevel, StructureNotifyMask, ToplevelEventProc, cntrPtr); } } #endif /* WIN32 */ if (cntrPtr->adopted != None) { #ifndef WIN32 if (cntrPtr->flags & CONTAINER_MOVE) { /* * Some applications like Netscape cache its location to * position its popup menus. But when it's reparented, it * thinks it's always at the same position. It doesn't * know when the container's moved. The hack here is to * force the application to update its coordinates by * moving the adopted window (over by 1 pixel and * then back in case the application is comparing the last * location). */ XMoveWindow(cntrPtr->display, cntrPtr->adopted, cntrPtr->inset + 1, cntrPtr->inset + 1); XMoveWindow(cntrPtr->display, cntrPtr->adopted, cntrPtr->inset, cntrPtr->inset); cntrPtr->flags &= ~CONTAINER_MOVE; } #endif /* WIN32 */ /* Compute the available space inside the container. */ width = Tk_Width(cntrPtr->tkwin) - (2 * cntrPtr->inset); height = Tk_Height(cntrPtr->tkwin) - (2 * cntrPtr->inset); if ((cntrPtr->adoptedX != cntrPtr->inset) || (cntrPtr->adoptedY != cntrPtr->inset) || (cntrPtr->adoptedWidth != width) || (cntrPtr->adoptedHeight != height)) { /* Resize the window to the new size */ if (width < 1) { width = 1; } if (height < 1) { height = 1; } XMoveResizeWindow(cntrPtr->display, cntrPtr->adopted, cntrPtr->inset, cntrPtr->inset, width, height); cntrPtr->adoptedWidth = width; cntrPtr->adoptedHeight = height; cntrPtr->adoptedX = cntrPtr->adoptedY = cntrPtr->inset; if (cntrPtr->tkAdopted != NULL) { Tk_ResizeWindow(cntrPtr->tkAdopted, width, height); } } #ifndef WIN32 if (!(cntrPtr->flags & CONTAINER_MAPPED)) { XMapWindow(cntrPtr->display, cntrPtr->adopted); cntrPtr->flags |= CONTAINER_MAPPED; } #endif if (cntrPtr->borderWidth > 0) { Blt_Draw3DRectangle(cntrPtr->tkwin, drawable, cntrPtr->border, cntrPtr->highlightWidth, cntrPtr->highlightWidth, Tk_Width(cntrPtr->tkwin) - 2 * cntrPtr->highlightWidth, Tk_Height(cntrPtr->tkwin) - 2 * cntrPtr->highlightWidth, cntrPtr->borderWidth, cntrPtr->relief); } } else { Blt_Fill3DRectangle(cntrPtr->tkwin, drawable, cntrPtr->border, cntrPtr->highlightWidth, cntrPtr->highlightWidth, Tk_Width(cntrPtr->tkwin) - 2 * cntrPtr->highlightWidth, Tk_Height(cntrPtr->tkwin) - 2 * cntrPtr->highlightWidth, cntrPtr->borderWidth, cntrPtr->relief); } /* Draw focus highlight ring. */ if (cntrPtr->highlightWidth > 0) { XColor *color; GC gc; color = (cntrPtr->flags & CONTAINER_FOCUS) ? cntrPtr->highlightColor : cntrPtr->highlightBgColor; gc = Tk_GCForColor(color, drawable); Tk_DrawFocusHighlight(cntrPtr->tkwin, gc, cntrPtr->highlightWidth, drawable); } } #ifdef notdef /* *---------------------------------------------------------------------- * * SendOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int SendOp(cntrPtr, interp, argc, argv) Container *cntrPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { if (cntrPtr->adopted != None) { XEvent event; char *p; KeySym symbol; int xid; Window window; if (Tcl_GetInt(interp, argv[2], &xid) != TCL_OK) { return TCL_ERROR; } window = (Window)xid; event.xkey.type = KeyPress; event.xkey.serial = 0; event.xkey.display = cntrPtr->display; event.xkey.window = event.xkey.subwindow = window; event.xkey.time = CurrentTime; event.xkey.x = event.xkey.x = 100; event.xkey.root = RootWindow(cntrPtr->display, Tk_ScreenNumber(cntrPtr->tkwin)); event.xkey.x_root = Tk_X(cntrPtr->tkwin) + cntrPtr->inset; event.xkey.x_root = Tk_Y(cntrPtr->tkwin) + cntrPtr->inset; event.xkey.state = 0; event.xkey.same_screen = TRUE; for (p = argv[3]; *p != '\0'; p++) { if (*p == '\r') { symbol = XStringToKeysym("Return"); } else if (*p == ' ') { symbol = XStringToKeysym("space"); } else { char save; save = *(p+1); *(p+1) = '\0'; symbol = XStringToKeysym(p); *(p+1) = save; } event.xkey.keycode = XKeysymToKeycode(cntrPtr->display, symbol); event.xkey.type = KeyPress; if (!XSendEvent(cntrPtr->display, window, False, KeyPress, &event)) { fprintf(stderr, "send press event failed\n"); } event.xkey.type = KeyRelease; if (!XSendEvent(cntrPtr->display, window, False, KeyRelease, &event)) { fprintf(stderr, "send release event failed\n"); } } } return TCL_OK; } #endif #ifndef WIN32 /* *---------------------------------------------------------------------- * * FindOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int FindOp(cntrPtr, interp, argc, argv) Container *cntrPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Window root; SearchInfo search; memset(&search, 0, sizeof(search)); search.pattern = argv[3]; Tcl_DStringInit(&(search.dString)); search.saveNames = TRUE; /* Indicates to record all matching XIDs. */ if (strcmp(argv[2], "-name") == 0) { search.proc = NameSearch; } else if (strcmp(argv[2], "-command") == 0) { search.proc = CmdSearch; } else { Tcl_AppendResult(interp, "missing \"-name\" or \"-command\" switch", (char *)NULL); return TCL_ERROR; } root = RootWindow(cntrPtr->display, Tk_ScreenNumber(cntrPtr->tkwin)); (*search.proc)(cntrPtr->display, root, &search); Tcl_DStringResult(interp, &search.dString); return TCL_OK; } #endif /*WIN32*/ /* *---------------------------------------------------------------------- * * CgetOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int CgetOp(cntrPtr, interp, argc, argv) Container *cntrPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { return Tk_ConfigureValue(interp, cntrPtr->tkwin, configSpecs, (char *)cntrPtr, argv[2], 0); } /* *---------------------------------------------------------------------- * * ConfigureOp -- * * This procedure is called to process an argv/argc list, plus * the Tk option database, in order to configure (or reconfigure) * the widget. * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side Effects: * Configuration information, such as text string, colors, font, * etc. get set for cntrPtr; old resources get freed, if there * were any. The widget is redisplayed. * *---------------------------------------------------------------------- */ static int ConfigureOp(cntrPtr, interp, argc, argv) Container *cntrPtr; Tcl_Interp *interp; int argc; char **argv; { if (argc == 2) { return Tk_ConfigureInfo(interp, cntrPtr->tkwin, configSpecs, (char *)cntrPtr, (char *)NULL, 0); } else if (argc == 3) { return Tk_ConfigureInfo(interp, cntrPtr->tkwin, configSpecs, (char *)cntrPtr, argv[2], 0); } if (ConfigureContainer(interp, cntrPtr, argc - 2, argv + 2, TK_CONFIG_ARGV_ONLY) != TCL_OK) { return TCL_ERROR; } EventuallyRedraw(cntrPtr); return TCL_OK; } /* * -------------------------------------------------------------- * * ContainerCmd -- * * This procedure is invoked to process the "container" command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * * -------------------------------------------------------------- */ static Blt_OpSpec opSpecs[] = { {"cget", 2, (Blt_Op)CgetOp, 3, 3, "option",}, {"configure", 2, (Blt_Op)ConfigureOp, 2, 0, "?option value?...",}, #ifndef WIN32 {"find", 1, (Blt_Op)FindOp, 3, 4, "?-command|-name? pattern",}, #endif /*WIN32*/ #ifdef notdef {"send", 1, (Blt_Op)SendOp, 4, 4, "window string",}, #endif }; static int nSpecs = sizeof(opSpecs) / sizeof(Blt_OpSpec); static int ContainerInstCmd(clientData, interp, argc, argv) ClientData clientData; /* Information about the widget. */ Tcl_Interp *interp; /* Interpreter to report errors back to. */ int argc; /* Number of arguments. */ char **argv; /* Vector of argument strings. */ { Blt_Op proc; Container *cntrPtr = clientData; int result; proc = Blt_GetOp(interp, nSpecs, opSpecs, BLT_OP_ARG1, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } Tcl_Preserve(cntrPtr); result = (*proc)(cntrPtr, interp, argc, argv); Tcl_Release(cntrPtr); return result; } int Blt_ContainerInit(interp) Tcl_Interp *interp; { static Blt_CmdSpec cmdSpec = { "container", ContainerCmd, }; if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) { return TCL_ERROR; } return TCL_OK; } #endif /* NO_CONTAINER */ blt-2.4z.orig/src/bltCutbuffer.c0100644000175000017500000001453007414715766015352 0ustar dokodoko/* * bltCutbuffer.c -- * * Copyright 1993-1998 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. */ #include "bltInt.h" #ifndef NO_CUTBUFFER #ifndef WIN32 #include #endif static int GetCutNumber(interp, string, bufferPtr) Tcl_Interp *interp; char *string; int *bufferPtr; { int number; if (Tcl_GetInt(interp, string, &number) != TCL_OK) { return TCL_ERROR; } if ((number < 0) || (number > 7)) { Tcl_AppendResult(interp, "bad buffer # \"", string, "\"", (char *)NULL); return TCL_ERROR; } *bufferPtr = number; return TCL_OK; } /* ARGSUSED */ static int RotateErrorProc(clientData, errEventPtr) ClientData clientData; XErrorEvent *errEventPtr; { int *errorPtr = clientData; *errorPtr = TCL_ERROR; return 0; } static int GetOp(interp, tkwin, argc, argv) Tcl_Interp *interp; Tk_Window tkwin; int argc; char **argv; { char *string; int buffer; int nBytes; buffer = 0; if (argc == 3) { if (GetCutNumber(interp, argv[2], &buffer) != TCL_OK) { return TCL_ERROR; } } string = XFetchBuffer(Tk_Display(tkwin), &nBytes, buffer); if (string != NULL) { int limit; register char *p; register int i; int c; if (string[nBytes - 1] == '\0') { limit = nBytes - 1; } else { limit = nBytes; } for (p = string, i = 0; i < limit; i++, p++) { c = (unsigned char)*p; if (c == 0) { *p = ' '; /* Convert embedded NUL bytes */ } } if (limit == nBytes) { char *newPtr; /* * Need to copy the string into a bigger buffer so we can * add a NUL byte on the end. */ newPtr = Blt_Malloc(nBytes + 1); assert(newPtr); memcpy(newPtr, string, nBytes); newPtr[nBytes] = '\0'; Blt_Free(string); string = newPtr; } Tcl_SetResult(interp, string, TCL_DYNAMIC); } return TCL_OK; } static int RotateOp(interp, tkwin, argc, argv) Tcl_Interp *interp; Tk_Window tkwin; int argc; char **argv; { int count; int result; Tk_ErrorHandler handler; count = 1; /* Default: rotate one position */ if (argc == 3) { if (Tcl_GetInt(interp, argv[2], &count) != TCL_OK) { return TCL_ERROR; } if ((count < 0) || (count > 8)) { Tcl_AppendResult(interp, "bad rotate count \"", argv[2], "\"", (char *)NULL); return TCL_ERROR; } } result = TCL_OK; handler = Tk_CreateErrorHandler(Tk_Display(tkwin), BadMatch, X_RotateProperties, -1, RotateErrorProc, &result); XRotateBuffers(Tk_Display(tkwin), count); Tk_DeleteErrorHandler(handler); XSync(Tk_Display(tkwin), False); if (result != TCL_OK) { Tcl_AppendResult(interp, "can't rotate cutbuffers unless all are set", (char *)NULL); return TCL_ERROR; } return TCL_OK; } static int SetOp(interp, tkwin, argc, argv) Tcl_Interp *interp; Tk_Window tkwin; int argc; char **argv; { int buffer; buffer = 0; if (argc == 4) { if (GetCutNumber(interp, argv[3], &buffer) != TCL_OK) { return TCL_ERROR; } } XStoreBuffer(Tk_Display(tkwin), argv[2], strlen(argv[2]) + 1, buffer); return TCL_OK; } /* *-------------------------------------------------------------- * * BLT Sub-command specification: * * - Name of the sub-command. * - Minimum number of characters needed to unambiguously * recognize the sub-command. * - Pointer to the function to be called for the sub-command. * - Minimum number of arguments accepted. * - Maximum number of arguments accepted. * - String to be displayed for usage. * *-------------------------------------------------------------- */ static Blt_OpSpec cbOps[] = { {"get", 1, (Blt_Op)GetOp, 2, 3, "?buffer?",}, {"rotate", 1, (Blt_Op)RotateOp, 2, 3, "?count?",}, {"set", 1, (Blt_Op)SetOp, 3, 4, "value ?buffer?",}, }; static int numCbOps = sizeof(cbOps) / sizeof(Blt_OpSpec); /* *---------------------------------------------------------------------- * * CutBufferCmd -- * * This procedure is invoked to process the "cutbuffer" Tcl * command. See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int CutbufferCmd(clientData, interp, argc, argv) ClientData clientData; /* Main window associated with * interpreter.*/ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { Tk_Window tkwin; Blt_Op proc; int result; proc = Blt_GetOp(interp, numCbOps, cbOps, BLT_OP_ARG1, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } tkwin = Tk_MainWindow(interp); result = (*proc) (interp, tkwin, argc, argv); return result; } /* *---------------------------------------------------------------------- * * Blt_CutbufferInit -- * * This procedure is invoked to initialize the "cutbuffer" Tcl * command. See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Blt_CutbufferInit(interp) Tcl_Interp *interp; { static Blt_CmdSpec cmdSpec = {"cutbuffer", CutbufferCmd,}; if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) { return TCL_ERROR; } return TCL_OK; } #endif /* NO_CUTBUFFER */ blt-2.4z.orig/src/bltDebug.c0100644000175000017500000002032107462636257014446 0ustar dokodoko /* * bltDebug.c -- * * Copyright 1993-1998 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. */ #include "bltInt.h" #ifndef NO_BLTDEBUG #ifdef TIME_WITH_SYS_TIME #include #include #else #ifdef HAVE_SYS_TIME_H #include #else #include #endif /* HAVE_SYS_TIME_H */ #endif /* TIME_WITH_SYS_TIME */ #include "bltChain.h" static Blt_Chain watchChain; static Tcl_CmdTraceProc DebugProc; static Tcl_CmdProc DebugCmd; typedef struct { char *pattern; char *name; } WatchInfo; static WatchInfo * GetWatch(name) char *name; { Blt_ChainLink *linkPtr; char c; WatchInfo *infoPtr; c = name[0]; for (linkPtr = Blt_ChainFirstLink(&watchChain); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { infoPtr = Blt_ChainGetValue(linkPtr); if ((infoPtr->name[0] == c) && (strcmp(name, infoPtr->name) == 0)) { return infoPtr; } } linkPtr = Blt_ChainAllocLink(sizeof(WatchInfo)); infoPtr = Blt_ChainGetValue(linkPtr); infoPtr->name = Blt_Strdup(name); Blt_ChainLinkAfter(&watchChain, linkPtr, (Blt_ChainLink *)NULL); return infoPtr; } static void DeleteWatch(watchName) char *watchName; { Blt_ChainLink *linkPtr; char c; WatchInfo *infoPtr; c = watchName[0]; for (linkPtr = Blt_ChainFirstLink(&watchChain); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { infoPtr = Blt_ChainGetValue(linkPtr); if ((infoPtr->name[0] == c) && (strcmp(infoPtr->name, watchName) == 0)) { Blt_Free(infoPtr->name); Blt_ChainDeleteLink(&watchChain, linkPtr); return; } } } /*ARGSUSED*/ static void DebugProc(clientData, interp, level, command, proc, cmdClientData, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Not used. */ int level; /* Current level */ char *command; /* Command before substitution */ Tcl_CmdProc *proc; /* Not used. */ ClientData cmdClientData; /* Not used. */ int argc; char **argv; /* Command after parsing, but before * evaluation */ { static unsigned char traceStack[200]; register int i; char *string; Tcl_Channel errChannel; Tcl_DString dString; char prompt[200]; register char *p; char *lineStart; int count; /* This is pretty crappy, but there's no way to trigger stack pops */ for (i = level + 1; i < 200; i++) { traceStack[i] = 0; } if (Blt_ChainGetLength(&watchChain) > 0) { WatchInfo *infoPtr; int found; Blt_ChainLink *linkPtr; found = FALSE; for (linkPtr = Blt_ChainFirstLink(&watchChain); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { infoPtr = Blt_ChainGetValue(linkPtr); if (Tcl_StringMatch(argv[0], infoPtr->name)) { found = TRUE; break; } } if ((found) && (level < 200)) { traceStack[level] = 1; traceStack[level + 1] = 1; } if ((level >= 200) || (!traceStack[level])) { return; } } /* * Use stderr channel, for compatibility with systems that don't have a * tty (like WIN32). In reality, it doesn't make a difference since * Tk's Win32 console can't handle large streams of data anyways. */ errChannel = Tcl_GetStdChannel(TCL_STDERR); if (errChannel == NULL) { Tcl_AppendResult(interp, "can't get stderr channel", (char *)NULL); Tcl_BackgroundError(interp); return; } Tcl_DStringInit(&dString); sprintf(prompt, "%-2d-> ", level); p = command; /* Skip leading spaces in command line. */ while(isspace(UCHAR(*p))) { p++; } lineStart = p; count = 0; for (/* empty */; *p != '\0'; /* empty */) { if (*p == '\n') { if (count > 0) { Tcl_DStringAppend(&dString, " ", -1); } else { Tcl_DStringAppend(&dString, prompt, -1); } Tcl_DStringAppend(&dString, lineStart, p - lineStart); Tcl_DStringAppend(&dString, "\n", -1); p++; lineStart = p; count++; if (count > 6) { break; } } else { p++; } } while (isspace(UCHAR(*lineStart))) { lineStart++; } if (lineStart < p) { if (count > 0) { Tcl_DStringAppend(&dString, " ", -1); } else { Tcl_DStringAppend(&dString, prompt, -1); } Tcl_DStringAppend(&dString, lineStart, p - lineStart); if (count <= 6) { Tcl_DStringAppend(&dString, "\n", -1); } } if (count > 6) { Tcl_DStringAppend(&dString, " ...\n", -1); } string = Tcl_Merge(argc, argv); lineStart = string; sprintf(prompt, " <- "); count = 0; for (p = string; *p != '\0'; /* empty */) { if (*p == '\n') { if (count > 0) { Tcl_DStringAppend(&dString, " ", -1); } else { Tcl_DStringAppend(&dString, prompt, -1); } count++; Tcl_DStringAppend(&dString, lineStart, p - lineStart); Tcl_DStringAppend(&dString, "\n", -1); p++; lineStart = p; if (count > 6) { break; } } else { p++; } } if (lineStart < p) { if (count > 0) { Tcl_DStringAppend(&dString, " ", -1); } else { Tcl_DStringAppend(&dString, prompt, -1); } Tcl_DStringAppend(&dString, lineStart, p - lineStart); if (count <= 6) { Tcl_DStringAppend(&dString, "\n", -1); } } if (count > 6) { Tcl_DStringAppend(&dString, " ...\n", -1); } Tcl_DStringAppend(&dString, "\n", -1); Blt_Free(string); Tcl_Write(errChannel, (char *)Tcl_DStringValue(&dString), -1); Tcl_Flush(errChannel); Tcl_DStringFree(&dString); } /*ARGSUSED*/ static int DebugCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; int argc; char **argv; { static Tcl_Trace token; static int level; int newLevel; char c; int length; WatchInfo *infoPtr; Blt_ChainLink *linkPtr; register int i; if (argc == 1) { Tcl_SetResult(interp, Blt_Itoa(level), TCL_VOLATILE); return TCL_OK; } c = argv[1][0]; length = strlen(argv[1]); if ((c == 'w') && (strncmp(argv[1], "watch", length) == 0)) { /* Add patterns of command names to watch to the chain */ for (i = 2; i < argc; i++) { GetWatch(argv[i]); } } else if ((c == 'i') && (strncmp(argv[1], "ignore", length) == 0)) { for (i = 2; i < argc; i++) { DeleteWatch(argv[i]); } } else { goto levelTest; } /* Return the current watch patterns */ for (linkPtr = Blt_ChainFirstLink(&watchChain); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { infoPtr = Blt_ChainGetValue(linkPtr); Tcl_AppendElement(interp, infoPtr->name); } return TCL_OK; levelTest: if (Tcl_GetBoolean(interp, argv[1], &newLevel) == TCL_OK) { if (newLevel > 0) { newLevel = 10000; /* Max out the level */ } } else if (Tcl_GetInt(interp, argv[1], &newLevel) == TCL_OK) { if (newLevel < 0) { newLevel = 0; } } else { return TCL_ERROR; } if (token != 0) { Tcl_DeleteTrace(interp, token); } if (newLevel > 0) { token = Tcl_CreateTrace(interp, newLevel, DebugProc, (ClientData)0); } level = newLevel; Tcl_SetResult(interp, Blt_Itoa(level), TCL_VOLATILE); return TCL_OK; } int Blt_DebugInit(interp) Tcl_Interp *interp; { static Blt_CmdSpec cmdSpec = {"bltdebug", DebugCmd,}; Blt_ChainInit(&watchChain); if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) { return TCL_ERROR; } return TCL_OK; } #endif /* NO_BLTDEBUG */ blt-2.4z.orig/src/bltDragdrop.c0100644000175000017500000023600707515460664015170 0ustar dokodoko/* * bltDnd.c -- * * This module implements a drag-and-drop mechanism for the Tk * Toolkit. Allows widgets to be registered as drag&drop sources * and targets for handling "drag-and-drop" operations between * Tcl/Tk applications. * * Copyright 1993-1998 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. * * The "drag&drop" command was created by Michael J. McLennan. */ #include "bltInt.h" #ifndef NO_DRAGDROP #include "bltHash.h" #include "bltChain.h" #include #ifdef WIN32 #define MAX_PROP_SIZE 255 /* Maximum size of property. */ typedef HWND WINDOW; #else #define MAX_PROP_SIZE 1000 /* Maximum size of property. */ typedef Window WINDOW; static Atom dndAtom; #endif /* * Each "drag&drop" target widget is tagged with a "BltDrag&DropTarget" * property in XA_STRING format. This property identifies the window * as a "drag&drop" target. It's formated as a Tcl list and contains * the following information: * * "INTERP_NAME TARGET_NAME DATA_TYPE DATA_TYPE ..." * * INTERP_NAME Name of the target application's interpreter. * TARGET_NAME Path name of widget registered as the drop target. * DATA_TYPE One or more "types" handled by the target. * * When the user invokes the "drag" operation, the window hierarchy * is progressively examined. Window information is cached during * the operation, to minimize X server traffic. Windows carrying a * "BltDrag&DropTarget" property are identified. When the token is * dropped over a valid site, the drop information is sent to the * application * via the usual "send" command. If communication fails, the drag&drop * facility automatically posts a rejection symbol on the token window. */ #define INTERP_NAME 0 #define TARGET_NAME 1 #define DATA_TYPE 2 /* Error Proc used to report drag&drop background errors */ #define DEF_ERROR_PROC "bgerror" /* * CONFIG PARAMETERS */ #define DEF_DND_BUTTON_BACKGROUND RGB_YELLOW #define DEF_DND_BUTTON_BG_MONO STD_NORMAL_BG_MONO #define DEF_DND_BUTTON_NUMBER "3" #define DEF_DND_PACKAGE_COMMAND (char *)NULL #define DEF_DND_SELF_TARGET "no" #define DEF_DND_SEND "all" #define DEF_DND_SITE_COMMAND (char *)NULL #define DEF_TOKEN_ACTIVE_BACKGROUND STD_ACTIVE_BACKGROUND #define DEF_TOKEN_ACTIVE_BG_MONO STD_ACTIVE_BG_MONO #define DEF_TOKEN_ACTIVE_BORDERWIDTH "3" #define DEF_TOKEN_ACTIVE_RELIEF "sunken" #define DEF_TOKEN_ANCHOR "se" #define DEF_TOKEN_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_TOKEN_BG_MONO STD_NORMAL_BG_MONO #define DEF_TOKEN_BORDERWIDTH "3" #define DEF_TOKEN_CURSOR "arrow" #define DEF_TOKEN_OUTLINE_COLOR RGB_BLACK #define DEF_TOKEN_OUTLINE_MONO RGB_BLACK #define DEF_TOKEN_REJECT_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_TOKEN_REJECT_BG_MONO RGB_WHITE #define DEF_TOKEN_REJECT_FOREGROUND RGB_RED #define DEF_TOKEN_REJECT_FG_MONO RGB_BLACK #define DEF_TOKEN_REJECT_STIPPLE_COLOR (char *)NULL #define DEF_TOKEN_REJECT_STIPPLE_MONO RGB_GREY50 #define DEF_TOKEN_RELIEF "raised" #if HAVE_NAMESPACES static char dragDropCmd[] = "blt::drag&drop"; #else static char dragDropCmd[] = "drag&drop"; #endif static char className[] = "DragDropToken"; /* CLASS NAME of token window */ static char propName[] = "BltDrag&DropTarget"; /* Property name */ static Blt_HashTable sourceTable; static Blt_HashTable targetTable; static char *errorCmd; static int nActive; static int locX, locY; static int initialized = FALSE; /* * Percent substitutions */ typedef struct { char letter; /* character like 'x' in "%x" */ char *value; /* value to be substituted in place of "%x" */ } SubstDescriptors; /* * AnyWindow -- * * This structure represents a window hierarchy examined during * a single "drag" operation. It's used to cache information * to reduce the round-trip calls to the server needed to query * window geometry information and grab the target property. */ typedef struct AnyWindowStruct AnyWindow; struct AnyWindowStruct { WINDOW nativeWindow; /* Native window: HWINDOW (Win32) or * Window (X11). */ int initialized; /* If non-zero, the rest of this structure's * information had been previously built. */ int x1, y1, x2, y2; /* Extents of the window (upper-left and * lower-right corners). */ AnyWindow *parentPtr; /* Parent node. NULL if root. Used to * compute offset for X11 windows. */ Blt_Chain *chainPtr; /* List of this window's children. If NULL, * there are no children. */ char **targetInfo; /* An array of target window drag&drop * information: target interpreter, * pathname, and optionally possible * type matches. NULL if the window is * not a drag&drop target or is not a * valid match for the drop source. */ }; /* * Drag&Drop Registration Data */ typedef struct { /* * This is a goof in the Tk API. It assumes that only an official * Tk "toplevel" widget will ever become a toplevel window (i.e. a * window whose parent is the root window). Because under Win32, * Tk tries to use the widget record associated with the TopLevel * as a Tk frame widget, to read its menu name. What this means * is that any widget that's going to be a toplevel, must also look * like a frame. Therefore we've copied the frame widget structure * fields into the token. */ Tk_Window tkwin; /* Window that embodies the frame. NULL * means that the window has been destroyed * but the data structures haven't yet been * cleaned up. */ Display *display; /* Display containing widget. Used, among * other things, so that resources can be * freed even after tkwin has gone away. */ Tcl_Interp *interp; /* Interpreter associated with widget. Used * to delete widget command. */ Tcl_Command widgetCmd; /* Token for frame's widget command. */ char *className; /* Class name for widget (from configuration * option). Malloc-ed. */ int mask; /* Either FRAME or TOPLEVEL; used to select * which configuration options are valid for * widget. */ char *screenName; /* Screen on which widget is created. Non-null * only for top-levels. Malloc-ed, may be * NULL. */ char *visualName; /* Textual description of visual for window, * from -visual option. Malloc-ed, may be * NULL. */ char *colormapName; /* Textual description of colormap for window, * from -colormap option. Malloc-ed, may be * NULL. */ char *menuName; /* Textual description of menu to use for * menubar. Malloc-ed, may be NULL. */ Colormap colormap; /* If not None, identifies a colormap * allocated for this window, which must be * freed when the window is deleted. */ Tk_3DBorder border; /* Structure used to draw 3-D border and * background. NULL means no background * or border. */ int borderWidth; /* Width of 3-D border (if any). */ int relief; /* 3-d effect: TK_RELIEF_RAISED etc. */ int highlightWidth; /* Width in pixels of highlight to draw * around widget when it has the focus. * 0 means don't draw a highlight. */ XColor *highlightBgColorPtr; /* Color for drawing traversal highlight * area when highlight is off. */ XColor *highlightColorPtr; /* Color for drawing traversal highlight. */ int width; /* Width to request for window. <= 0 means * don't request any size. */ int height; /* Height to request for window. <= 0 means * don't request any size. */ Tk_Cursor cursor; /* Current cursor for window, or None. */ char *takeFocus; /* Value of -takefocus option; not used in * the C code, but used by keyboard traversal * scripts. Malloc'ed, but may be NULL. */ int isContainer; /* 1 means this window is a container, 0 means * that it isn't. */ char *useThis; /* If the window is embedded, this points to * the name of the window in which it is * embedded (malloc'ed). For non-embedded * windows this is NULL. */ int flags; /* Various flags; see below for * definitions. */ /* Token specific fields */ int lastX, lastY; /* last position of token window */ int active; /* non-zero => over target window */ Tcl_TimerToken timer; /* token for routine to hide tokenwin */ GC rejectFgGC; /* GC used to draw rejection fg: (\) */ GC rejectBgGC; /* GC used to draw rejection bg: (\) */ /* User-configurable fields */ Tk_Anchor anchor; /* Position of token win relative to mouse */ Tk_3DBorder outline; /* Outline border around token window */ Tk_3DBorder normalBorder; /* Border/background for token window */ Tk_3DBorder activeBorder; /* Border/background for token window */ int activeRelief; int activeBorderWidth; /* Border width in pixels */ XColor *rejectFg; /* Color used to draw rejection fg: (\) */ XColor *rejectBg; /* Color used to draw rejection bg: (\) */ Pixmap rejectStipple; /* Stipple used to draw rejection: (\) */ } Token; typedef struct { Tcl_Interp *interp; /* Interpreter associated with the Tk source * widget. */ Tk_Window tkwin; /* Tk window registered as the drag&drop * source. */ Display *display; /* Drag&drop source window display */ Blt_HashTable handlerTable; /* Table of data handlers (converters) * registered for this source. */ int button; /* Button used to invoke drag operation. */ Token token; /* Token used to provide special cursor. */ int pkgCmdInProgress; /* Indicates if a pkgCmd is currently active. */ char *pkgCmd; /* Tcl command executed at start of "drag" * operation to gather information about * the source data. */ char *pkgCmdResult; /* Result returned by the most recent * pkgCmd. */ char *siteCmd; /* Tcl command executed to update token * window. */ AnyWindow *rootPtr; /* Cached window information: Gathered * and used during the "drag" operation * to see if the mouse pointer is over a * valid target. */ int selfTarget; /* Indicated if the source should drop onto * itself. */ Tk_Cursor cursor; /* cursor restored after dragging */ char **sendTypes; /* list of data handler names or "all" */ Blt_HashEntry *hashPtr; AnyWindow *windowPtr; /* Last target examined. If NULL, mouse * pointer is not currently over a valid * target. */ } Source; typedef struct { Tcl_Interp *interp; Tk_Window tkwin; /* drag&drop target window */ Display *display; /* drag&drop target window display */ Blt_HashTable handlerTable; /* Table of data handlers (converters) * registered for this target. */ Blt_HashEntry *hashPtr; } Target; extern Tk_CustomOption bltListOption; static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_INT, "-button", "buttonBinding", "ButtonBinding", DEF_DND_BUTTON_NUMBER, Tk_Offset(Source, button), 0}, {TK_CONFIG_STRING, "-packagecmd", "packageCommand", "Command", DEF_DND_PACKAGE_COMMAND, Tk_Offset(Source, pkgCmd), TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-rejectbg", "rejectBackground", "Background", DEF_TOKEN_REJECT_BACKGROUND, Tk_Offset(Source, token.rejectBg), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-rejectbg", "rejectBackground", "Background", DEF_TOKEN_REJECT_BG_MONO, Tk_Offset(Source, token.rejectBg), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-rejectfg", "rejectForeground", "Foreground", DEF_TOKEN_REJECT_FOREGROUND, Tk_Offset(Source, token.rejectFg), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-rejectfg", "rejectForeground", "Foreground", DEF_TOKEN_REJECT_BACKGROUND, Tk_Offset(Source, token.rejectFg), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_BITMAP, "-rejectstipple", "rejectStipple", "Stipple", DEF_TOKEN_REJECT_STIPPLE_COLOR, Tk_Offset(Source, token.rejectStipple), TK_CONFIG_COLOR_ONLY | TK_CONFIG_NULL_OK}, {TK_CONFIG_BITMAP, "-rejectstipple", "rejectStipple", "Stipple", DEF_TOKEN_REJECT_STIPPLE_MONO, Tk_Offset(Source, token.rejectStipple), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_BOOLEAN, "-selftarget", "selfTarget", "SelfTarget", DEF_DND_SELF_TARGET, Tk_Offset(Source, selfTarget), 0}, {TK_CONFIG_CUSTOM, "-send", "send", "Send", DEF_DND_SEND, Tk_Offset(Source, sendTypes), TK_CONFIG_NULL_OK, &bltListOption}, {TK_CONFIG_STRING, "-sitecmd", "siteCommand", "Command", DEF_DND_SITE_COMMAND, Tk_Offset(Source, siteCmd), TK_CONFIG_NULL_OK}, {TK_CONFIG_ANCHOR, "-tokenanchor", "tokenAnchor", "Anchor", DEF_TOKEN_ANCHOR, Tk_Offset(Source, token.anchor), 0}, {TK_CONFIG_BORDER, "-tokenactivebackground", "tokenActiveBackground", "ActiveBackground", DEF_TOKEN_ACTIVE_BACKGROUND, Tk_Offset(Source, token.activeBorder), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-tokenactivebackground", "tokenActiveBackground", "ActiveBackground", DEF_TOKEN_ACTIVE_BG_MONO, Tk_Offset(Source, token.activeBorder), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_BORDER, "-tokenbg", "tokenBackground", "Background", DEF_TOKEN_BACKGROUND, Tk_Offset(Source, token.normalBorder), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-tokenbg", "tokenBackground", "Background", DEF_TOKEN_BG_MONO, Tk_Offset(Source, token.normalBorder), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_BORDER, "-tokenoutline", "tokenOutline", "Outline", DEF_TOKEN_OUTLINE_COLOR, Tk_Offset(Source, token.outline), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-tokenoutline", "tokenOutline", "Outline", DEF_TOKEN_OUTLINE_MONO, Tk_Offset(Source, token.outline), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_PIXELS, "-tokenborderwidth", "tokenBorderWidth", "BorderWidth", DEF_TOKEN_BORDERWIDTH, Tk_Offset(Source, token.borderWidth), 0}, {TK_CONFIG_CURSOR, "-tokencursor", "tokenCursor", "Cursor", DEF_TOKEN_CURSOR, Tk_Offset(Source, token.cursor), TK_CONFIG_NULL_OK}, {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0}, }; static Tk_ConfigSpec tokenConfigSpecs[] = { {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "ActiveBackground", DEF_TOKEN_ACTIVE_BACKGROUND, Tk_Offset(Token, activeBorder), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "ActiveBackground", DEF_TOKEN_ACTIVE_BG_MONO, Tk_Offset(Token, activeBorder), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_RELIEF, "-activerelief", "activeRelief", "activeRelief", DEF_TOKEN_ACTIVE_RELIEF, Tk_Offset(Token, activeRelief), 0}, {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", DEF_TOKEN_ANCHOR, Tk_Offset(Token, anchor), 0}, {TK_CONFIG_PIXELS, "-activeborderwidth", "activeBorderWidth", "ActiveBorderWidth", DEF_TOKEN_ACTIVE_BORDERWIDTH, Tk_Offset(Token, activeBorderWidth), 0}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_TOKEN_BACKGROUND, Tk_Offset(Token, normalBorder), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_TOKEN_BG_MONO, Tk_Offset(Token, normalBorder), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", DEF_TOKEN_BORDERWIDTH, Tk_Offset(Token, borderWidth), 0}, {TK_CONFIG_CURSOR, "-cursor", "cursor", "Cursor", DEF_TOKEN_CURSOR, Tk_Offset(Token, cursor), TK_CONFIG_NULL_OK}, {TK_CONFIG_BORDER, "-outline", "outline", "Outline", DEF_TOKEN_OUTLINE_COLOR, Tk_Offset(Token, outline), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-outline", "outline", "Outline", DEF_TOKEN_OUTLINE_MONO, Tk_Offset(Token, outline), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-rejectbg", "rejectBackground", "Background", DEF_TOKEN_REJECT_BACKGROUND, Tk_Offset(Token, rejectBg), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-rejectbg", "rejectBackground", "Background", DEF_TOKEN_REJECT_BG_MONO, Tk_Offset(Token, rejectBg), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-rejectfg", "rejectForeground", "Foreground", DEF_TOKEN_REJECT_FOREGROUND, Tk_Offset(Token, rejectFg), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-rejectfg", "rejectForeground", "Foreground", DEF_TOKEN_REJECT_BACKGROUND, Tk_Offset(Token, rejectFg), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_BITMAP, "-rejectstipple", "rejectStipple", "Stipple", DEF_TOKEN_REJECT_STIPPLE_COLOR, Tk_Offset(Token, rejectStipple), TK_CONFIG_COLOR_ONLY | TK_CONFIG_NULL_OK}, {TK_CONFIG_BITMAP, "-rejectstipple", "rejectStipple", "Stipple", DEF_TOKEN_REJECT_STIPPLE_MONO, Tk_Offset(Token, rejectStipple), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_TOKEN_RELIEF, Tk_Offset(Token, relief), 0}, {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0}, }; /* * Forward Declarations */ static int DragDropCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, char **argv)); static void TokenEventProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); static void TargetEventProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); static void MoveToken _ANSI_ARGS_((Source * srcPtr, Token *tokenPtr)); static void UpdateToken _ANSI_ARGS_((ClientData clientData)); static void HideToken _ANSI_ARGS_((Token *tokenPtr)); static void RejectToken _ANSI_ARGS_((Token *tokenPtr)); static int GetSource _ANSI_ARGS_((Tcl_Interp *interp, char *name, Source **srcPtrPtr)); static Source *CreateSource _ANSI_ARGS_((Tcl_Interp *interp, char *pathname, int *newEntry)); static void DestroySource _ANSI_ARGS_((Source * srcPtr)); static void SourceEventProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); static int ConfigureSource _ANSI_ARGS_((Tcl_Interp *interp, Source * srcPtr, int argc, char **argv, int flags)); static int ConfigureToken _ANSI_ARGS_((Tcl_Interp *interp, Source * srcPtr, int argc, char **argv)); static Target *CreateTarget _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin)); static Target *FindTarget _ANSI_ARGS_((Tk_Window tkwin)); static void DestroyTarget _ANSI_ARGS_((DestroyData dataPtr)); static int OverTarget _ANSI_ARGS_((Source * srcPtr, int x, int y)); static void AddTargetProperty _ANSI_ARGS_((Tcl_Interp *interp, Target * targetPtr)); static void DndSend _ANSI_ARGS_((Source * srcPtr)); static void InitRoot _ANSI_ARGS_((Source * srcPtr)); static void RemoveWindow _ANSI_ARGS_((AnyWindow *wr)); static void QueryWindow _ANSI_ARGS_((Display *display, AnyWindow * windowPtr)); static char *ExpandPercents _ANSI_ARGS_((char *str, SubstDescriptors * subs, int nsubs, Tcl_DString *resultPtr)); #ifdef WIN32 #if defined( _MSC_VER) || defined(__BORLANDC__) #include #endif /* _MSC_VER || __BORLANDC__ */ typedef struct { char *prefix; int prefixSize; char *propReturn; } PropertyInfo; static BOOL CALLBACK GetEnumWindowsProc(HWND hWnd, LPARAM clientData) { Blt_Chain *chainPtr = (Blt_Chain *) clientData; Blt_ChainAppend(chainPtr, (ClientData)hWnd); return TRUE; } static WINDOW GetNativeWindow(Tk_Window tkwin) { return (WINDOW) Tk_GetHWND(Tk_WindowId(tkwin)); } /* * ------------------------------------------------------------------------ * * GetWindowZOrder -- * * Returns a list of the child windows according to their stacking * order. The window handles are ordered from top to bottom. * * ------------------------------------------------------------------------ */ static Blt_Chain * GetWindowZOrder( Display *display, HWND parent) { Blt_Chain *chainPtr; HWND hWnd; chainPtr = Blt_ChainCreate(); for (hWnd = GetTopWindow(parent); hWnd != NULL; hWnd = GetNextWindow(hWnd, GW_HWNDNEXT)) { Blt_ChainAppend(chainPtr, (ClientData)hWnd); } return chainPtr; } /* * ------------------------------------------------------------------------ * * GetEnumPropsExProc -- * * ------------------------------------------------------------------------ */ static BOOL CALLBACK GetEnumPropsExProc( HWND hwnd, LPCTSTR atom, HANDLE hData, DWORD clientData) { PropertyInfo *infoPtr = (PropertyInfo *) clientData; if (strncmp(infoPtr->prefix, atom, infoPtr->prefixSize) == 0) { assert(infoPtr->propReturn == NULL); infoPtr->propReturn = (char *)atom; return FALSE; } return TRUE; } /* * ------------------------------------------------------------------------ * * GetPropData -- * * This is a bad Windows hack to pass property information between * applications. (Ab)Normally the property data (one-word value) is * stored in the data handle. But the data content is available only * within the application. The pointer value is meaningless outside * of the current application address space. Not really useful at all. * * So the trick here is to encode the property name with all the * necessary information and to loop through all the properties * of a window, looking for one that starts with our property name * prefix. The downside is that the property name is limited to * 255 bytes. But that should be enough. It's also slower since * we examine each property until we find ours. * * We'll plug in the OLE stuff later. * * ------------------------------------------------------------------------ */ static char * GetPropData(HWND hWnd, char *atom) { PropertyInfo propInfo; if (hWnd == NULL) { return NULL; } propInfo.prefix = atom; propInfo.prefixSize = strlen(atom); propInfo.propReturn = NULL; EnumPropsEx(hWnd, (PROPENUMPROCEX)GetEnumPropsExProc, (DWORD)&propInfo); return propInfo.propReturn; } static char * GetProperty(Display *display, HWND hWnd) { ATOM atom; atom = (ATOM)GetProp(hWnd, propName); if (atom != (ATOM)0) { char buffer[MAX_PROP_SIZE + 1]; UINT nBytes; nBytes = GlobalGetAtomName(atom, buffer, MAX_PROP_SIZE); if (nBytes > 0) { buffer[nBytes] = '\0'; return Blt_Strdup(buffer); } } return NULL; } static void SetProperty(Tk_Window tkwin, char *data) { HWND hWnd; ATOM atom; hWnd = Tk_GetHWND(Tk_WindowId(tkwin)); if (hWnd == NULL) { return; } atom = (ATOM)GetProp(hWnd, propName); if (atom != 0) { GlobalDeleteAtom(atom); } atom = GlobalAddAtom(data); if (atom != (ATOM)0) { SetProp(hWnd, propName, (HANDLE)atom); } } static void RemoveProperty(Tk_Window tkwin) { HWND hWnd; ATOM atom; hWnd = Tk_GetHWND(Tk_WindowId(tkwin)); if (hWnd == NULL) { return; } atom = (ATOM)GetProp(hWnd, propName); if (atom != 0) { GlobalDeleteAtom(atom); } RemoveProp(hWnd, propName); } /* *---------------------------------------------------------------------- * * GetWindowRegion -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int GetWindowRegion( Display *display, /* Not used. */ HWND hWnd, int *x1Ptr, int *y1Ptr, int *x2Ptr, int *y2Ptr) { RECT rect; if (GetWindowRect(hWnd, &rect)) { *x1Ptr = rect.left; *y1Ptr = rect.top; *x2Ptr = rect.right; *y2Ptr = rect.bottom; return IsWindowVisible(hWnd); } return FALSE; } #else static WINDOW GetNativeWindow(tkwin) Tk_Window tkwin; { return Tk_WindowId(tkwin); } /* * ------------------------------------------------------------------------ * * GetWindowZOrder -- * * Returns a chain of the child windows according to their stacking * order. The window ids are ordered from top to bottom. * * ------------------------------------------------------------------------ */ static Blt_Chain * GetWindowZOrder(display, window) Display *display; Window window; { Blt_Chain *chainPtr; Window *childArr; unsigned int nChildren; Window dummy; chainPtr = NULL; if ((XQueryTree(display, window, &dummy, &dummy, &childArr, &nChildren)) && (nChildren > 0)) { register int i; chainPtr = Blt_ChainCreate(); for (i = 0; i < nChildren; i++) { /* * XQuery returns windows in bottom to top order. * We only care about the top window. */ Blt_ChainPrepend(chainPtr, (ClientData)childArr[i]); } if (childArr != NULL) { XFree((char *)childArr); /* done with list of kids */ } } return chainPtr; } static char * GetProperty(display, window) Display *display; Window window; { char *data; int result, actualFormat; Atom actualType; unsigned long nItems, bytesAfter; if (window == None) { return NULL; } data = NULL; result = XGetWindowProperty(display, window, dndAtom, 0, MAX_PROP_SIZE, False, XA_STRING, &actualType, &actualFormat, &nItems, &bytesAfter, (unsigned char **)&data); if ((result != Success) || (actualFormat != 8) || (actualType != XA_STRING)) { if (data != NULL) { XFree((char *)data); data = NULL; } } return data; } static void SetProperty(tkwin, data) Tk_Window tkwin; char *data; { XChangeProperty(Tk_Display(tkwin), Tk_WindowId(tkwin), dndAtom, XA_STRING, 8, PropModeReplace, (unsigned char *)data, strlen(data) + 1); } static int GetWindowRegion(display, window, x1Ptr, y1Ptr, x2Ptr, y2Ptr) Display *display; Window window; int *x1Ptr, *y1Ptr, *x2Ptr, *y2Ptr; { XWindowAttributes winAttrs; if (XGetWindowAttributes(display, window, &winAttrs)) { *x1Ptr = winAttrs.x; *y1Ptr = winAttrs.y; *x2Ptr = winAttrs.x + winAttrs.width - 1; *y2Ptr = winAttrs.y + winAttrs.height - 1; } return (winAttrs.map_state == IsViewable); } #endif /* WIN32 */ /* * ------------------------------------------------------------------------ * * ChangeToken -- * * ------------------------------------------------------------------------ */ static void ChangeToken(tokenPtr, active) Token *tokenPtr; int active; { int relief; Tk_3DBorder border; int borderWidth; Blt_Fill3DRectangle(tokenPtr->tkwin, Tk_WindowId(tokenPtr->tkwin), tokenPtr->outline, 0, 0, Tk_Width(tokenPtr->tkwin), Tk_Height(tokenPtr->tkwin), 0, TK_RELIEF_FLAT); if (active) { relief = tokenPtr->activeRelief; border = tokenPtr->activeBorder; borderWidth = tokenPtr->activeBorderWidth; } else { relief = tokenPtr->relief; border = tokenPtr->normalBorder; borderWidth = tokenPtr->borderWidth; } Blt_Fill3DRectangle(tokenPtr->tkwin, Tk_WindowId(tokenPtr->tkwin), border, 2, 2, Tk_Width(tokenPtr->tkwin) - 4, Tk_Height(tokenPtr->tkwin) - 4, borderWidth, relief); } /* * ------------------------------------------------------------------------ * * TokenEventProc -- * * Invoked by the Tk dispatcher to handle widget events. * Manages redraws for the drag&drop token window. * * ------------------------------------------------------------------------ */ static void TokenEventProc(clientData, eventPtr) ClientData clientData; /* data associated with widget */ XEvent *eventPtr; /* information about event */ { Token *tokenPtr = clientData; if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) { if (tokenPtr->tkwin != NULL) { ChangeToken(tokenPtr, tokenPtr->active); } } else if (eventPtr->type == DestroyNotify) { tokenPtr->tkwin = NULL; } } /* * ------------------------------------------------------------------------ * * HideToken -- * * Unmaps the drag&drop token. Invoked directly at the end of a * successful communication, or after a delay if the communication * fails (allowing the user to see a graphical picture of failure). * * ------------------------------------------------------------------------ */ static void HideToken(tokenPtr) Token *tokenPtr; { if (tokenPtr->tkwin != NULL) { Tk_UnmapWindow(tokenPtr->tkwin); } tokenPtr->timer = NULL; } /* * ------------------------------------------------------------------------ * * RaiseToken -- * * ------------------------------------------------------------------------ */ static void RaiseToken(tokenPtr) Token *tokenPtr; { Blt_MapToplevel(tokenPtr->tkwin); Blt_RaiseToplevel(tokenPtr->tkwin); } /* * ------------------------------------------------------------------------ * * MoveToken -- * * Invoked during "drag" operations to move a token window to its * current "drag" coordinate. * * ------------------------------------------------------------------------ */ static void MoveToken(srcPtr, tokenPtr) Source *srcPtr; /* drag&drop source window data */ Token *tokenPtr; { int x, y; int maxX, maxY; int vx, vy, vw, vh; Screen *screenPtr; /* Adjust current location for virtual root windows. */ Tk_GetVRootGeometry(srcPtr->tkwin, &vx, &vy, &vw, &vh); x = tokenPtr->lastX + vx - 3; y = tokenPtr->lastY + vy - 3; screenPtr = Tk_Screen(srcPtr->tkwin); maxX = WidthOfScreen(screenPtr) - Tk_Width(tokenPtr->tkwin); maxY = HeightOfScreen(screenPtr) - Tk_Height(tokenPtr->tkwin); Blt_TranslateAnchor(x, y, Tk_Width(tokenPtr->tkwin), Tk_Height(tokenPtr->tkwin), tokenPtr->anchor, &x, &y); if (x > maxX) { x = maxX; } else if (x < 0) { x = 0; } if (y > maxY) { y = maxY; } else if (y < 0) { y = 0; } if ((x != Tk_X(tokenPtr->tkwin)) || (y != Tk_Y(tokenPtr->tkwin))) { Tk_MoveToplevelWindow(tokenPtr->tkwin, x, y); } RaiseToken(tokenPtr); } static Tk_Cursor GetWidgetCursor(interp, tkwin) Tk_Window tkwin; Tcl_Interp *interp; { CONST char *cursorName; Tk_Cursor cursor; cursor = None; if (Tcl_VarEval(interp, Tk_PathName(tkwin), " cget -cursor", (char *)NULL) != TCL_OK) { return None; } cursorName = Tcl_GetStringResult(interp); if ((cursorName != NULL) && (cursorName[0] != '\0')) { cursor = Tk_GetCursor(interp, tkwin, Tk_GetUid((char *)cursorName)); } Tcl_ResetResult(interp); return cursor; } /* * ------------------------------------------------------------------------ * * UpdateToken -- * * Invoked when the event loop is idle to determine whether or not * the current drag&drop token position is over another drag&drop * target. * * ------------------------------------------------------------------------ */ static void UpdateToken(clientData) ClientData clientData; /* widget data */ { Source *srcPtr = clientData; Token *tokenPtr = &(srcPtr->token); ChangeToken(tokenPtr, tokenPtr->active); /* * If the source has a site command, then invoke it to * modify the appearance of the token window. Pass any * errors onto the drag&drop error handler. */ if (srcPtr->siteCmd) { char buffer[200]; Tcl_DString dString; int result; SubstDescriptors subs[2]; sprintf(buffer, "%d", tokenPtr->active); subs[0].letter = 's'; subs[0].value = buffer; subs[1].letter = 't'; subs[1].value = Tk_PathName(tokenPtr->tkwin); Tcl_DStringInit(&dString); result = Tcl_Eval(srcPtr->interp, ExpandPercents(srcPtr->siteCmd, subs, 2, &dString)); Tcl_DStringFree(&dString); if ((result != TCL_OK) && (errorCmd != NULL) && (*errorCmd)) { (void)Tcl_VarEval(srcPtr->interp, errorCmd, " {", Tcl_GetStringResult(srcPtr->interp), "}", (char *)NULL); } } } /* * ------------------------------------------------------------------------ * * RejectToken -- * * Draws a rejection mark on the current drag&drop token, and arranges * for the token to be unmapped after a small delay. * * ------------------------------------------------------------------------ */ static void RejectToken(tokenPtr) Token *tokenPtr; { int divisor = 6; /* controls size of rejection symbol */ int w, h, lineWidth, x, y, margin; margin = 2 * tokenPtr->borderWidth; w = Tk_Width(tokenPtr->tkwin) - 2 * margin; h = Tk_Height(tokenPtr->tkwin) - 2 * margin; lineWidth = (w < h) ? w / divisor : h / divisor; lineWidth = (lineWidth < 1) ? 1 : lineWidth; w = h = lineWidth * (divisor - 1); x = (Tk_Width(tokenPtr->tkwin) - w) / 2; y = (Tk_Height(tokenPtr->tkwin) - h) / 2; /* * Draw the rejection symbol background (\) on the token window... */ XSetLineAttributes(Tk_Display(tokenPtr->tkwin), tokenPtr->rejectBgGC, lineWidth + 4, LineSolid, CapButt, JoinBevel); XDrawArc(Tk_Display(tokenPtr->tkwin), Tk_WindowId(tokenPtr->tkwin), tokenPtr->rejectBgGC, x, y, w, h, 0, 23040); XDrawLine(Tk_Display(tokenPtr->tkwin), Tk_WindowId(tokenPtr->tkwin), tokenPtr->rejectBgGC, x + lineWidth, y + lineWidth, x + w - lineWidth, y + h - lineWidth); /* * Draw the rejection symbol foreground (\) on the token window... */ XSetLineAttributes(Tk_Display(tokenPtr->tkwin), tokenPtr->rejectFgGC, lineWidth, LineSolid, CapButt, JoinBevel); XDrawArc(Tk_Display(tokenPtr->tkwin), Tk_WindowId(tokenPtr->tkwin), tokenPtr->rejectFgGC, x, y, w, h, 0, 23040); XDrawLine(Tk_Display(tokenPtr->tkwin), Tk_WindowId(tokenPtr->tkwin), tokenPtr->rejectFgGC, x + lineWidth, y + lineWidth, x + w - lineWidth, y + h - lineWidth); /* * Arrange for token window to disappear eventually. */ tokenPtr->timer = Tcl_CreateTimerHandler(1000, (Tcl_TimerProc *) HideToken, tokenPtr); } /* * ------------------------------------------------------------------------ * * ConfigureToken -- * * ------------------------------------------------------------------------ */ static int ConfigureToken(interp, srcPtr, argc, argv) Tcl_Interp *interp; Source *srcPtr; int argc; char **argv; { Token *tokenPtr; tokenPtr = &(srcPtr->token); if (Tk_ConfigureWidget(interp, srcPtr->tkwin, tokenConfigSpecs, argc, argv, (char *)tokenPtr, TK_CONFIG_ARGV_ONLY) != TCL_OK) { return TCL_ERROR; } return ConfigureSource(interp, srcPtr, 0, (char **)NULL, TK_CONFIG_ARGV_ONLY); } /* * ------------------------------------------------------------------------ * * CreateToken -- * * ------------------------------------------------------------------------ */ static int CreateToken(interp, srcPtr) Tcl_Interp *interp; Source *srcPtr; { XSetWindowAttributes attrs; Tk_Window tkwin; char string[200]; static int nextTokenId = 0; unsigned int mask; Token *tokenPtr = &(srcPtr->token); sprintf(string, "dd-token%d", ++nextTokenId); /* Create toplevel on parent's screen. */ tkwin = Tk_CreateWindow(interp, srcPtr->tkwin, string, ""); if (tkwin == NULL) { return TCL_ERROR; } Tk_SetClass(tkwin, className); Tk_CreateEventHandler(tkwin, ExposureMask | StructureNotifyMask, TokenEventProc, tokenPtr); attrs.override_redirect = True; attrs.backing_store = WhenMapped; attrs.save_under = True; mask = CWOverrideRedirect | CWSaveUnder | CWBackingStore; Tk_ChangeWindowAttributes(tkwin, mask, &attrs); Tk_SetInternalBorder(tkwin, tokenPtr->borderWidth + 2); tokenPtr->tkwin = tkwin; #ifdef WIN32 { Tk_FakeWin *winPtr = (Tk_FakeWin *) tkwin; winPtr->dummy18 = tokenPtr; } #endif /* WIN32 */ Tk_MakeWindowExist(tkwin); return TCL_OK; } /* * ------------------------------------------------------------------------ * * CreateSource -- * * Looks for a Source record in the hash table for drag&drop source * widgets. Creates a new record if the widget name is not already * registered. Returns a pointer to the desired record. * * ------------------------------------------------------------------------ */ static Source * CreateSource(interp, pathName, newPtr) Tcl_Interp *interp; char *pathName; /* widget pathname for desired record */ int *newPtr; /* returns non-zero => new record created */ { Blt_HashEntry *hPtr; Tk_Window tkwin; Source *srcPtr; tkwin = Tk_NameToWindow(interp, pathName, Tk_MainWindow(interp)); if (tkwin == NULL) { return NULL; } hPtr = Blt_CreateHashEntry(&sourceTable, (char *)tkwin, newPtr); if (!(*newPtr)) { return (Source *) Blt_GetHashValue(hPtr); } srcPtr = Blt_Calloc(1, sizeof(Source)); assert(srcPtr); srcPtr->tkwin = tkwin; srcPtr->display = Tk_Display(tkwin); srcPtr->interp = interp; srcPtr->token.anchor = TK_ANCHOR_SE; srcPtr->token.relief = TK_RELIEF_RAISED; srcPtr->token.activeRelief = TK_RELIEF_SUNKEN; srcPtr->token.borderWidth = srcPtr->token.activeBorderWidth = 3; srcPtr->hashPtr = hPtr; Blt_InitHashTable(&(srcPtr->handlerTable), BLT_STRING_KEYS); if (ConfigureSource(interp, srcPtr, 0, (char **)NULL, 0) != TCL_OK) { DestroySource(srcPtr); return NULL; } Blt_SetHashValue(hPtr, srcPtr); /* * Arrange for the window to unregister itself when it * is destroyed. */ Tk_CreateEventHandler(tkwin, StructureNotifyMask, SourceEventProc, srcPtr); return srcPtr; } /* * ------------------------------------------------------------------------ * * DestroySource -- * * Looks for a Source record in the hash table for drag&drop source * widgets. Destroys the record if found. * * ------------------------------------------------------------------------ */ static void DestroySource(srcPtr) Source *srcPtr; { Blt_HashEntry *hPtr; Blt_HashSearch cursor; char *cmd; Tcl_CancelIdleCall(UpdateToken, srcPtr); if (srcPtr->token.timer) { Tcl_DeleteTimerHandler(srcPtr->token.timer); } Tk_FreeOptions(configSpecs, (char *)srcPtr, srcPtr->display, 0); if (srcPtr->token.rejectFgGC != NULL) { Tk_FreeGC(srcPtr->display, srcPtr->token.rejectFgGC); } if (srcPtr->token.rejectBgGC != NULL) { Tk_FreeGC(srcPtr->display, srcPtr->token.rejectBgGC); } if (srcPtr->pkgCmdResult) { Blt_Free(srcPtr->pkgCmdResult); } if (srcPtr->rootPtr != NULL) { RemoveWindow(srcPtr->rootPtr); } if (srcPtr->cursor != None) { Tk_FreeCursor(srcPtr->display, srcPtr->cursor); } if (srcPtr->token.cursor != None) { Tk_FreeCursor(srcPtr->display, srcPtr->token.cursor); } Blt_Free(srcPtr->sendTypes); for (hPtr = Blt_FirstHashEntry(&(srcPtr->handlerTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { cmd = (char *)Blt_GetHashValue(hPtr); if (cmd != NULL) { Blt_Free(cmd); } } Blt_DeleteHashTable(&(srcPtr->handlerTable)); if (srcPtr->hashPtr != NULL) { Blt_DeleteHashEntry(&sourceTable, srcPtr->hashPtr); } Blt_Free(srcPtr); } /* * ------------------------------------------------------------------------ * * GetSource -- * * Looks for a Source record in the hash table for drag&drop source * widgets. Returns a pointer to the desired record. * * ------------------------------------------------------------------------ */ static int GetSource(interp, pathName, srcPtrPtr) Tcl_Interp *interp; char *pathName; /* widget pathname for desired record */ Source **srcPtrPtr; { Blt_HashEntry *hPtr; Tk_Window tkwin; tkwin = Tk_NameToWindow(interp, pathName, Tk_MainWindow(interp)); if (tkwin == NULL) { return TCL_ERROR; } hPtr = Blt_FindHashEntry(&sourceTable, (char *)tkwin); if (hPtr == NULL) { Tcl_AppendResult(interp, "window \"", pathName, "\" has not been initialized as a drag&drop source", (char *)NULL); return TCL_ERROR; } *srcPtrPtr = (Source *)Blt_GetHashValue(hPtr); return TCL_OK; } /* * ------------------------------------------------------------------------ * * ConfigureSource -- * * Called to process an (argc,argv) list to configure (or * reconfigure) a drag&drop source widget. * * ------------------------------------------------------------------------ */ static int ConfigureSource(interp, srcPtr, argc, argv, flags) Tcl_Interp *interp; /* current interpreter */ register Source *srcPtr; /* drag&drop source widget record */ int argc; /* number of arguments */ char **argv; /* argument strings */ int flags; /* flags controlling interpretation */ { unsigned long gcMask; XGCValues gcValues; GC newGC; Tcl_DString dString; Tcl_CmdInfo cmdInfo; int result; /* * Handle the bulk of the options... */ if (Tk_ConfigureWidget(interp, srcPtr->tkwin, configSpecs, argc, argv, (char *)srcPtr, flags) != TCL_OK) { return TCL_ERROR; } /* * Check the button binding for valid range (0 or 1-5) */ if ((srcPtr->button < 0) || (srcPtr->button > 5)) { Tcl_AppendResult(interp, "button number must be 1-5, or 0 for no bindings", (char *)NULL); return TCL_ERROR; } /* * Set up the rejection foreground GC for the token window... */ gcValues.foreground = srcPtr->token.rejectFg->pixel; gcValues.subwindow_mode = IncludeInferiors; gcValues.graphics_exposures = False; gcMask = GCForeground | GCSubwindowMode | GCGraphicsExposures; if (srcPtr->token.rejectStipple != None) { gcValues.stipple = srcPtr->token.rejectStipple; gcValues.fill_style = FillStippled; gcMask |= GCForeground | GCStipple | GCFillStyle; } newGC = Tk_GetGC(srcPtr->tkwin, gcMask, &gcValues); if (srcPtr->token.rejectFgGC != NULL) { Tk_FreeGC(srcPtr->display, srcPtr->token.rejectFgGC); } srcPtr->token.rejectFgGC = newGC; /* * Set up the rejection background GC for the token window... */ gcValues.foreground = srcPtr->token.rejectBg->pixel; gcValues.subwindow_mode = IncludeInferiors; gcValues.graphics_exposures = False; gcMask = GCForeground | GCSubwindowMode | GCGraphicsExposures; newGC = Tk_GetGC(srcPtr->tkwin, gcMask, &gcValues); if (srcPtr->token.rejectBgGC != NULL) { Tk_FreeGC(srcPtr->display, srcPtr->token.rejectBgGC); } srcPtr->token.rejectBgGC = newGC; /* * Reset the border width in case it has changed... */ if (srcPtr->token.tkwin) { Tk_SetInternalBorder(srcPtr->token.tkwin, srcPtr->token.borderWidth + 2); } if (!Tcl_GetCommandInfo(interp, "blt::Drag&DropInit", &cmdInfo)) { static char cmd[] = "source [file join $blt_library dragdrop.tcl]"; if (Tcl_GlobalEval(interp, cmd) != TCL_OK) { Tcl_AddErrorInfo(interp, "\n (while loading bindings for blt::drag&drop)"); return TCL_ERROR; } } Tcl_DStringInit(&dString); Blt_DStringAppendElements(&dString, "blt::Drag&DropInit", Tk_PathName(srcPtr->tkwin), Blt_Itoa(srcPtr->button), (char *)NULL); result = Tcl_Eval(interp, Tcl_DStringValue(&dString)); Tcl_DStringFree(&dString); return result; } /* * ------------------------------------------------------------------------ * * SourceEventProc -- * * Invoked by Tk_HandleEvent whenever a DestroyNotify event is received * on a registered drag&drop source widget. * * ------------------------------------------------------------------------ */ static void SourceEventProc(clientData, eventPtr) ClientData clientData; /* drag&drop registration list */ XEvent *eventPtr; /* event description */ { Source *srcPtr = (Source *) clientData; if (eventPtr->type == DestroyNotify) { DestroySource(srcPtr); } } /* * ------------------------------------------------------------------------ * * FindTarget -- * * Looks for a Target record in the hash table for drag&drop * target widgets. Creates a new record if the widget name is * not already registered. Returns a pointer to the desired * record. * * ------------------------------------------------------------------------ */ static Target * FindTarget(tkwin) Tk_Window tkwin; /* Widget pathname for desired record */ { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&targetTable, (char *)tkwin); if (hPtr == NULL) { return NULL; } return (Target *) Blt_GetHashValue(hPtr); } /* * ------------------------------------------------------------------------ * * CreateTarget -- * * Looks for a Target record in the hash table for drag&drop * target widgets. Creates a new record if the widget name is * not already registered. Returns a pointer to the desired * record. * * ------------------------------------------------------------------------ */ static Target * CreateTarget(interp, tkwin) Tcl_Interp *interp; Tk_Window tkwin; /* Widget pathname for desired record */ { Target *targetPtr; int isNew; targetPtr = Blt_Calloc(1, sizeof(Target)); assert(targetPtr); targetPtr->display = Tk_Display(tkwin); targetPtr->tkwin = tkwin; Blt_InitHashTable(&(targetPtr->handlerTable), BLT_STRING_KEYS); targetPtr->hashPtr = Blt_CreateHashEntry(&targetTable, (char *)tkwin, &isNew); Blt_SetHashValue(targetPtr->hashPtr, targetPtr); /* * Arrange for the target to removed if the host window is destroyed. */ Tk_CreateEventHandler(tkwin, StructureNotifyMask, TargetEventProc, targetPtr); /* * If this is a new target, attach a property to identify * window as "drag&drop" target, and arrange for the window * to un-register itself when it is destroyed. */ Tk_MakeWindowExist(targetPtr->tkwin); AddTargetProperty(interp, targetPtr); return targetPtr; } /* * ------------------------------------------------------------------------ * * DestroyTarget -- * * ------------------------------------------------------------------------ */ static void DestroyTarget(data) DestroyData data; { Target *targetPtr = (Target *)data; Blt_HashEntry *hPtr; Blt_HashSearch cursor; char *cmd; for (hPtr = Blt_FirstHashEntry(&(targetPtr->handlerTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { cmd = (char *)Blt_GetHashValue(hPtr); if (cmd != NULL) { Blt_Free(cmd); } } Blt_DeleteHashTable(&(targetPtr->handlerTable)); if (targetPtr->hashPtr != NULL) { Blt_DeleteHashEntry(&targetTable, targetPtr->hashPtr); } Tk_DeleteEventHandler(targetPtr->tkwin, StructureNotifyMask, TargetEventProc, targetPtr); Blt_Free(targetPtr); } /* * ------------------------------------------------------------------------ * * TargetEventProc -- * * Invoked by Tk_HandleEvent whenever a DestroyNotify event is received * on a registered drag&drop target widget. * * ------------------------------------------------------------------------ */ static void TargetEventProc(clientData, eventPtr) ClientData clientData; /* drag&drop registration list */ XEvent *eventPtr; /* event description */ { Target *targetPtr = (Target *) clientData; if (eventPtr->type == DestroyNotify) { #ifdef WIN32 /* * Under Win32 the properties must be removed before the window * can be destroyed. */ RemoveProperty(targetPtr->tkwin); #endif DestroyTarget((DestroyData)targetPtr); } } /* * ------------------------------------------------------------------------ * * DndSend -- * * Invoked after a drop operation to send data to the drop * application. * * ------------------------------------------------------------------------ */ static void DndSend(srcPtr) register Source *srcPtr; /* drag&drop source record */ { int status; SubstDescriptors subs[3]; Tcl_DString dString; Blt_HashEntry *hPtr; char *dataType; char **targetInfo; char *cmd; /* See if current position is over drop point. */ if (!OverTarget(srcPtr, srcPtr->token.lastX, srcPtr->token.lastY)) { return; } targetInfo = srcPtr->windowPtr->targetInfo; Tcl_DStringInit(&dString); Blt_DStringAppendElements(&dString, "send", targetInfo[INTERP_NAME], dragDropCmd, "location", (char *)NULL); Tcl_DStringAppendElement(&dString, Blt_Itoa(srcPtr->token.lastX)); Tcl_DStringAppendElement(&dString, Blt_Itoa(srcPtr->token.lastY)); status = Tcl_Eval(srcPtr->interp, Tcl_DStringValue(&dString)); Tcl_DStringFree(&dString); if (status != TCL_OK) { goto reject; } if (targetInfo[DATA_TYPE] == NULL) { Blt_HashSearch cursor; hPtr = Blt_FirstHashEntry(&(srcPtr->handlerTable), &cursor); dataType = Blt_GetHashKey(&(srcPtr->handlerTable), hPtr); } else { hPtr = Blt_FindHashEntry(&(srcPtr->handlerTable), targetInfo[DATA_TYPE]); dataType = targetInfo[DATA_TYPE]; } /* Start building the command line here, before we invoke any Tcl * commands. The is because the Tcl command may let in another * drag event and change the target property data. */ Tcl_DStringInit(&dString); Blt_DStringAppendElements(&dString, "send", targetInfo[INTERP_NAME], dragDropCmd, "target", targetInfo[TARGET_NAME], "handle", dataType, (char *)NULL); cmd = NULL; if (hPtr != NULL) { cmd = (char *)Blt_GetHashValue(hPtr); } if (cmd != NULL) { Tcl_DString cmdString; subs[0].letter = 'i'; subs[0].value = targetInfo[INTERP_NAME]; subs[1].letter = 'w'; subs[1].value = targetInfo[TARGET_NAME]; subs[2].letter = 'v'; subs[2].value = srcPtr->pkgCmdResult; Tcl_DStringInit(&cmdString); status = Tcl_Eval(srcPtr->interp, ExpandPercents(cmd, subs, 3, &cmdString)); Tcl_DStringFree(&cmdString); if (status != TCL_OK) { goto reject; } Tcl_DStringAppendElement(&dString, Tcl_GetStringResult(srcPtr->interp)); } else { Tcl_DStringAppendElement(&dString, srcPtr->pkgCmdResult); } /* * Part 2: Now tell target application to handle the data. */ status = Tcl_Eval(srcPtr->interp, Tcl_DStringValue(&dString)); Tcl_DStringFree(&dString); if (status != TCL_OK) { goto reject; } HideToken(&(srcPtr->token)); return; reject: /* * Give failure information to user. If an error occurred and an * error proc is defined, then use it to handle the error. */ RejectToken(&(srcPtr->token)); if (errorCmd != NULL) { Tcl_VarEval(srcPtr->interp, errorCmd, " {", Tcl_GetStringResult(srcPtr->interp), "}", (char *)NULL); } } /* * ------------------------------------------------------------------------ * * InitRoot -- * * Invoked at the start of a "drag" operation to capture the * positions of all windows on the current root. Queries the * entire window hierarchy and determines the placement of each * window. Queries the "BltDrag&DropTarget" property info where * appropriate. This information is used during the drag * operation to determine when the drag&drop token is over a * valid drag&drop target. * * Results: * Returns the record for the root window, which contains records * for all other windows as children. * * ------------------------------------------------------------------------ */ static void InitRoot(srcPtr) Source *srcPtr; { srcPtr->rootPtr = Blt_Calloc(1, sizeof(AnyWindow)); assert(srcPtr->rootPtr); #ifdef WIN32 srcPtr->rootPtr->nativeWindow = GetDesktopWindow(); #else srcPtr->rootPtr->nativeWindow = DefaultRootWindow(srcPtr->display); #endif srcPtr->windowPtr = NULL; QueryWindow(srcPtr->display, srcPtr->rootPtr); } /* * ------------------------------------------------------------------------ * * FindTopWindow -- * * Searches for the topmost window at a given pair of X-Y coordinates. * * Results: * Returns a pointer to the node representing the window containing * the point. If one can't be found, NULL is returned. * * ------------------------------------------------------------------------ */ static AnyWindow * FindTopWindow(srcPtr, x, y) Source *srcPtr; int x, y; { AnyWindow *rootPtr; register Blt_ChainLink *linkPtr; register AnyWindow *windowPtr; WINDOW nativeTokenWindow; rootPtr = srcPtr->rootPtr; if (!rootPtr->initialized) { QueryWindow(srcPtr->display, rootPtr); } if ((x < rootPtr->x1) || (x > rootPtr->x2) || (y < rootPtr->y1) || (y > rootPtr->y2)) { return NULL; /* Point is not over window */ } windowPtr = rootPtr; nativeTokenWindow = (WINDOW)Blt_GetRealWindowId(srcPtr->token.tkwin); /* * The window list is ordered top to bottom, so stop when we find * the first child that contains the X-Y coordinate. It will be * the topmost window in that hierarchy. If none exists, then we * already have the topmost window. */ descend: for (linkPtr = Blt_ChainFirstLink(rootPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rootPtr = Blt_ChainGetValue(linkPtr); if (!rootPtr->initialized) { QueryWindow(srcPtr->display, rootPtr); } if (rootPtr->nativeWindow == nativeTokenWindow) { continue; /* Don't examine the token window. */ } if ((x >= rootPtr->x1) && (x <= rootPtr->x2) && (y >= rootPtr->y1) && (y <= rootPtr->y2)) { /* * Remember the last window containing the pointer and * descend into its window hierarchy. We'll look for a * child that also contains the pointer. */ windowPtr = rootPtr; goto descend; } } return windowPtr; } /* * ------------------------------------------------------------------------ * * OverTarget -- * * Checks to see if a compatible drag&drop target exists at the * given position. A target is "compatible" if it is a drag&drop * window, and if it has a handler that is compatible with the * current source window. * * Results: * Returns a pointer to a structure describing the target, or NULL * if no compatible target is found. * * ------------------------------------------------------------------------ */ static int OverTarget(srcPtr, x, y) Source *srcPtr; /* drag&drop source window */ int x, y; /* current drag&drop location * (in virtual coords) */ { int virtX, virtY; int dummy; AnyWindow *newPtr, *oldPtr; char **elemArr; int nElems; char *data; int result; /* * If no window info has been been gathered yet for this target, * then abort this call. This probably means that the token is * moved before it has been properly built. */ if (srcPtr->rootPtr == NULL) { return FALSE; } if (srcPtr->sendTypes == NULL) { return FALSE; /* Send is turned off. */ } /* Adjust current location for virtual root windows. */ Tk_GetVRootGeometry(srcPtr->tkwin, &virtX, &virtY, &dummy, &dummy); x += virtX; y += virtY; oldPtr = srcPtr->windowPtr; srcPtr->windowPtr = NULL; newPtr = FindTopWindow(srcPtr, x, y); if (newPtr == NULL) { return FALSE; /* Not over a window. */ } if ((!srcPtr->selfTarget) && (GetNativeWindow(srcPtr->tkwin) == newPtr->nativeWindow)) { return FALSE; /* If the self-target flag isn't set, * don't allow the source window to * drop onto itself. */ } if (newPtr == oldPtr) { srcPtr->windowPtr = oldPtr; /* No need to collect the target information if we're still * over the same window. */ return (newPtr->targetInfo != NULL); } /* See if this window has a "BltDrag&DropTarget" property. */ data = GetProperty(srcPtr->display, newPtr->nativeWindow); if (data == NULL) { return FALSE; /* No such property on window. */ } result = Tcl_SplitList(srcPtr->interp, data, &nElems, &elemArr); XFree((char *)data); if (result != TCL_OK) { return FALSE; /* Malformed property list. */ } srcPtr->windowPtr = newPtr; /* Interpreter name, target name, type1, type2, ... */ if (nElems > 2) { register char **s; int count; register int i; /* * The candidate target has a list of possible types. * Compare this with what types the source is willing to * transmit and compress the list down to just the matching * types. It's up to the target to request the specific type * it wants. */ count = 2; for (i = 2; i < nElems; i++) { for (s = srcPtr->sendTypes; *s != NULL; s++) { if (((**s == 'a') && (strcmp(*s, "all") == 0)) || ((**s == elemArr[i][0]) && (strcmp(*s, elemArr[i]) == 0))) { elemArr[count++] = elemArr[i]; } } } if (count == 2) { Blt_Free(elemArr); fprintf(stderr, "source/target mismatch: No matching types\n"); return FALSE; /* No matching data type. */ } elemArr[count] = NULL; } newPtr->targetInfo = elemArr; return TRUE; } /* * ------------------------------------------------------------------------ * * RemoveWindow -- * * ------------------------------------------------------------------------ */ static void RemoveWindow(windowPtr) AnyWindow *windowPtr; /* window rep to be freed */ { AnyWindow *childPtr; Blt_ChainLink *linkPtr; /* Throw away leftover slots. */ for (linkPtr = Blt_ChainFirstLink(windowPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { childPtr = Blt_ChainGetValue(linkPtr); RemoveWindow(childPtr); } Blt_ChainDestroy(windowPtr->chainPtr); if (windowPtr->targetInfo != NULL) { Blt_Free(windowPtr->targetInfo); } Blt_Free(windowPtr); } /* * ------------------------------------------------------------------------ * * QueryWindow -- * * Invoked during "drag" operations. Digs into the root window * hierarchy and caches the resulting information. * If a point coordinate lies within an uninitialized AnyWindow, * this routine is called to query window coordinates and * drag&drop info. If this particular window has any children, * more uninitialized AnyWindow structures are allocated. * Further queries will cause these structures to be initialized * in turn. * * ------------------------------------------------------------------------ */ static void QueryWindow(display, windowPtr) Display *display; AnyWindow *windowPtr; /* window rep to be initialized */ { int visible; if (windowPtr->initialized) { return; } /* * Query for the window coordinates. */ visible = GetWindowRegion(display, windowPtr->nativeWindow, &(windowPtr->x1), &(windowPtr->y1), &(windowPtr->x2), &(windowPtr->y2)); if (visible) { Blt_ChainLink *linkPtr; Blt_Chain *chainPtr; AnyWindow *childPtr; #ifndef WIN32 /* Add offset from parent's origin to coordinates */ if (windowPtr->parentPtr != NULL) { windowPtr->x1 += windowPtr->parentPtr->x1; windowPtr->y1 += windowPtr->parentPtr->y1; windowPtr->x2 += windowPtr->parentPtr->x1; windowPtr->y2 += windowPtr->parentPtr->y1; } #endif /* * Collect a list of child windows, sorted in z-order. The * topmost window will be first in the list. */ chainPtr = GetWindowZOrder(display, windowPtr->nativeWindow); /* Add and initialize extra slots if needed. */ for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { childPtr = Blt_Calloc(1, sizeof(AnyWindow)); assert(childPtr); childPtr->initialized = FALSE; childPtr->nativeWindow = (WINDOW)Blt_ChainGetValue(linkPtr); childPtr->parentPtr = windowPtr; Blt_ChainSetValue(linkPtr, childPtr); } windowPtr->chainPtr = chainPtr; } else { /* If it's not viewable don't bother doing anything else. */ windowPtr->x1 = windowPtr->y1 = windowPtr->x2 = windowPtr->y2 = -1; windowPtr->chainPtr = NULL; } windowPtr->initialized = TRUE; } /* * ------------------------------------------------------------------------ * * AddTargetProperty -- * * Attaches a drag&drop property to the given target window. * This property allows us to recognize the window later as a * valid target. It also stores important information including * the interpreter managing the target and the pathname of the * target window. Usually this routine is called when the target * is first registered or first exposed (so that the X-window * really exists). * * ------------------------------------------------------------------------ */ static void AddTargetProperty(interp, targetPtr) Tcl_Interp *interp; Target *targetPtr; /* drag&drop target window data */ { Tcl_DString dString; Blt_HashEntry *hPtr; Blt_HashSearch cursor; if (targetPtr->tkwin == NULL) { return; } Tcl_DStringInit(&dString); /* * Each target window's dnd property contains * * 1. name of the application (ie. the interpreter's name). * 2. Tk path name of the target window. * 3. List of all the data types that can be handled. If none * are listed, then all can be handled. */ Tcl_DStringAppendElement(&dString, Tk_Name(Tk_MainWindow(interp))); Tcl_DStringAppendElement(&dString, Tk_PathName(targetPtr->tkwin)); for (hPtr = Blt_FirstHashEntry(&(targetPtr->handlerTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { Tcl_DStringAppendElement(&dString, Blt_GetHashKey(&(targetPtr->handlerTable), hPtr)); } SetProperty(targetPtr->tkwin, Tcl_DStringValue(&dString)); Tcl_DStringFree(&dString); } /* * ------------------------------------------------------------------------ * * ExpandPercents -- * * Expands all percent substitutions found in the input "str" * that match specifications in the "subs" list. Any percent * field that is not found in the "subs" list is left alone. * Returns a string that remains valid until the next call to * this routine. * * ------------------------------------------------------------------------ */ static char * ExpandPercents(string, subsArr, nSubs, resultPtr) char *string; /* Incoming command string */ SubstDescriptors *subsArr; /* Array of known substitutions */ int nSubs; /* Number of elements in subs array */ Tcl_DString *resultPtr; { register char *chunk, *p; char letter; char percentSign; int i; /* * Scan through the copy of the input string, look for * the next '%' character, and try to make the substitution. * Continue doing this to the end of the string. */ chunk = p = string; while ((p = strchr(p, '%')) != NULL) { /* Copy up to the percent sign. Repair the string afterwards */ percentSign = *p; *p = '\0'; Tcl_DStringAppend(resultPtr, chunk, -1); *p = percentSign; /* Search for a matching substition rule */ letter = *(p + 1); for (i = 0; i < nSubs; i++) { if (subsArr[i].letter == letter) { break; } } if (i < nSubs) { /* Make the substitution */ Tcl_DStringAppend(resultPtr, subsArr[i].value, -1); } else { /* Copy in the %letter verbatim */ char verbatim[3]; verbatim[0] = '%'; verbatim[1] = letter; verbatim[2] = '\0'; Tcl_DStringAppend(resultPtr, verbatim, -1); } p += 2; /* Skip % + letter */ if (letter == '\0') { p += 1; /* Premature % substitution (end of string) */ } chunk = p; } /* Pick up last chunk if a substition wasn't the last thing in the string */ if (*chunk != '\0') { Tcl_DStringAppend(resultPtr, chunk, -1); } return Tcl_DStringValue(resultPtr); } static int DragOp(interp, argc, argv) Tcl_Interp *interp; int argc; char **argv; { int x, y; Token *tokenPtr; int status; Source *srcPtr; SubstDescriptors subst[2]; int active; CONST char *result; /* * HANDLE: drag&drop drag */ if (argc != 5) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " drag pathname x y\"", (char *)NULL); return TCL_ERROR; } if ((GetSource(interp, argv[2], &srcPtr) != TCL_OK) || (Tcl_GetInt(interp, argv[3], &x) != TCL_OK) || (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)) { return TCL_ERROR; } tokenPtr = &(srcPtr->token); tokenPtr->lastX = locX = x; /* Save drag&drop location */ tokenPtr->lastY = locY = y; /* If HideToken() is pending, then do it now! */ if (tokenPtr->timer != 0) { Tcl_DeleteTimerHandler(tokenPtr->timer); HideToken(tokenPtr); } /* * If pkgCmd is in progress, then ignore subsequent calls * until it completes. Only perform drag if pkgCmd * completed successfully and token window is mapped. */ if ((!Tk_IsMapped(tokenPtr->tkwin)) && (!srcPtr->pkgCmdInProgress)) { Tcl_DString dString; /* * No list of send handlers? Then source is disabled. * Abort drag quietly. */ if (srcPtr->sendTypes == NULL) { return TCL_OK; } /* * No token command? Then cannot build token. * Signal error. */ if (srcPtr->pkgCmd == NULL) { Tcl_AppendResult(interp, "missing -packagecmd: ", argv[2], (char *)NULL); return TCL_ERROR; } /* * Execute token command to initialize token window. */ srcPtr->pkgCmdInProgress = TRUE; subst[0].letter = 'W'; subst[0].value = Tk_PathName(srcPtr->tkwin); subst[1].letter = 't'; subst[1].value = Tk_PathName(tokenPtr->tkwin); Tcl_DStringInit(&dString); status = Tcl_Eval(srcPtr->interp, ExpandPercents(srcPtr->pkgCmd, subst, 2, &dString)); Tcl_DStringFree(&dString); srcPtr->pkgCmdInProgress = FALSE; result = Tcl_GetStringResult(interp); /* * Null string from the package command? * Then quietly abort the drag&drop operation. */ if (result[0] == '\0') { return TCL_OK; } /* Save result of token command for send command. */ if (srcPtr->pkgCmdResult != NULL) { Blt_Free(srcPtr->pkgCmdResult); } srcPtr->pkgCmdResult = Blt_Strdup(result); if (status != TCL_OK) { /* * Token building failed. If an error handler is defined, * then signal the error. Otherwise, abort quietly. */ if ((errorCmd != NULL) && (errorCmd[0] != '\0')) { return Tcl_VarEval(interp, errorCmd, " {", result, "}", (char *)NULL); } return TCL_OK; } /* Install token cursor. */ if (tokenPtr->cursor != None) { Tk_Cursor cursor; /* Save the old cursor */ cursor = GetWidgetCursor(srcPtr->interp, srcPtr->tkwin); if (srcPtr->cursor != None) { Tk_FreeCursor(srcPtr->display, srcPtr->cursor); } srcPtr->cursor = cursor; /* Temporarily install the token cursor */ Tk_DefineCursor(srcPtr->tkwin, tokenPtr->cursor); } /* * Get ready to drag token window... * 1) Cache info for all windows on root * 2) Map token window to begin drag operation */ if (srcPtr->rootPtr != NULL) { RemoveWindow(srcPtr->rootPtr); } InitRoot(srcPtr); nActive++; /* One more drag&drop window active */ if (Tk_WindowId(tokenPtr->tkwin) == None) { Tk_MakeWindowExist(tokenPtr->tkwin); } if (!Tk_IsMapped(tokenPtr->tkwin)) { Tk_MapWindow(tokenPtr->tkwin); } RaiseToken(tokenPtr); } /* Arrange to update status of token window. */ Tcl_CancelIdleCall(UpdateToken, srcPtr); active = OverTarget(srcPtr, x, y); if (tokenPtr->active != active) { tokenPtr->active = active; Tcl_DoWhenIdle(UpdateToken, srcPtr); } MoveToken(srcPtr, tokenPtr); /* Move token window to current drag point. */ return TCL_OK; } /* * HANDLE: drag&drop drop */ static int DropOp(interp, argc, argv) Tcl_Interp *interp; int argc; char **argv; { Source *srcPtr; Token *tokenPtr; int x, y; if (argc < 5) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " drop pathname x y\"", (char *)NULL); return TCL_ERROR; } if ((GetSource(interp, argv[2], &srcPtr) != TCL_OK) || (Tcl_GetInt(interp, argv[3], &x) != TCL_OK) || (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)) { return TCL_ERROR; } tokenPtr = &(srcPtr->token); tokenPtr->lastX = locX = x; /* Save drag&drop location */ tokenPtr->lastY = locY = y; /* Put the cursor back to its usual state. */ if (srcPtr->cursor == None) { Tk_UndefineCursor(srcPtr->tkwin); } else { Tk_DefineCursor(srcPtr->tkwin, srcPtr->cursor); } Tcl_CancelIdleCall(UpdateToken, srcPtr); /* * Make sure that token window was not dropped before it * was either mapped or packed with info. */ if ((Tk_IsMapped(tokenPtr->tkwin)) && (!srcPtr->pkgCmdInProgress)) { int active; active = OverTarget(srcPtr, tokenPtr->lastX, tokenPtr->lastY); if (tokenPtr->active != active) { tokenPtr->active = active; UpdateToken(srcPtr); } if (srcPtr->sendTypes != NULL) { if (tokenPtr->active) { DndSend(srcPtr); } else { HideToken(tokenPtr); } } nActive--; /* One less active token window. */ } return TCL_OK; } /* * HANDLE: drag&drop errors ?? */ static int ErrorsOp(interp, argc, argv) Tcl_Interp *interp; int argc; char **argv; { if (argc == 3) { if (errorCmd) { Blt_Free(errorCmd); } errorCmd = Blt_Strdup(argv[2]); } else if (argc != 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " errors ?proc?\"", (char *)NULL); return TCL_ERROR; } Tcl_SetResult(interp, errorCmd, TCL_VOLATILE); return TCL_OK; } /* * HANDLE: drag&drop active */ static int ActiveOp(interp, argc, argv) Tcl_Interp *interp; int argc; char **argv; { if (argc != 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " active\"", (char *)NULL); return TCL_ERROR; } Blt_SetBooleanResult(interp, (nActive > 0)); return TCL_OK; } /* * HANDLE: drag&drop location ? ? */ static int LocationOp(interp, argc, argv) Tcl_Interp *interp; int argc; char **argv; { if ((argc != 2) && (argc != 4)) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " location ?x y?\"", (char *)NULL); return TCL_ERROR; } if (argc == 4) { int x, y; if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { return TCL_ERROR; } locX = x; locY = y; } Tcl_AppendElement(interp, Blt_Itoa(locX)); Tcl_AppendElement(interp, Blt_Itoa(locY)); return TCL_OK; } /* * HANDLE: drag&drop token */ static int TokenOp(interp, argc, argv) Tcl_Interp *interp; int argc; char **argv; { Source *srcPtr; if (GetSource(interp, argv[2], &srcPtr) != TCL_OK) { return TCL_ERROR; } if ((argc > 3) && (ConfigureToken(interp, srcPtr, argc - 3, argv + 3) != TCL_OK)) { return TCL_ERROR; } Tcl_SetResult(interp, Tk_PathName(srcPtr->token.tkwin), TCL_VOLATILE); return TCL_OK; } static int HandlerOpOp(srcPtr, interp, argc, argv) Source *srcPtr; Tcl_Interp *interp; int argc; char **argv; { Blt_HashEntry *hPtr; Blt_HashSearch cursor; int isNew; char *cmd; /* * HANDLE: drag&drop source handler \ * ?? ?...? */ if (argc == 4) { /* Show source handler data types */ for (hPtr = Blt_FirstHashEntry(&(srcPtr->handlerTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { Tcl_AppendElement(interp, Blt_GetHashKey(&(srcPtr->handlerTable), hPtr)); } return TCL_OK; } hPtr = Blt_CreateHashEntry(&(srcPtr->handlerTable), argv[4], &isNew); /* * HANDLE: drag&drop source handler * * Create the new type if it doesn't already * exist, and return the code associated with it. */ if (argc == 5) { cmd = (char *)Blt_GetHashValue(hPtr); if (cmd == NULL) { cmd = ""; } Tcl_SetResult(interp, cmd, TCL_VOLATILE); return TCL_OK; } /* * HANDLE: drag&drop source handler \ * ?...? * * Create the new type and set its command */ cmd = Tcl_Concat(argc - 5, argv + 5); Blt_SetHashValue(hPtr, cmd); return TCL_OK; } /* * HANDLE: drag&drop source * drag&drop source ?options...? * drag&drop source handler ?? ? ...? */ static int SourceOp(interp, argc, argv) Tcl_Interp *interp; int argc; char **argv; { Source *srcPtr; int isNew; Token *tokenPtr; if (argc == 2) { Blt_HashSearch cursor; Blt_HashEntry *hPtr; Tk_Window tkwin; for (hPtr = Blt_FirstHashEntry(&sourceTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tkwin = (Tk_Window)Blt_GetHashKey(&sourceTable, hPtr); Tcl_AppendElement(interp, Tk_PathName(tkwin)); } return TCL_OK; } /* * Find or create source info... */ srcPtr = CreateSource(interp, argv[2], &isNew); if (srcPtr == NULL) { return TCL_ERROR; } tokenPtr = &(srcPtr->token); if (argc > 3) { char c; int length; int status; /* * HANDLE: drag&drop source ?options...? */ c = argv[3][0]; length = strlen(argv[3]); if (c == '-') { if (argc == 3) { status = Tk_ConfigureInfo(interp, tokenPtr->tkwin, configSpecs, (char *)srcPtr, (char *)NULL, 0); } else if (argc == 4) { status = Tk_ConfigureInfo(interp, tokenPtr->tkwin, configSpecs, (char *)srcPtr, argv[3], 0); } else { status = ConfigureSource(interp, srcPtr, argc - 3, argv + 3, TK_CONFIG_ARGV_ONLY); } if (status != TCL_OK) { return TCL_ERROR; } } else if ((c == 'h') && strncmp(argv[3], "handler", length) == 0) { return HandlerOpOp(srcPtr, interp, argc, argv); } else { Tcl_AppendResult(interp, "bad operation \"", argv[3], "\": must be \"handler\" or a configuration option", (char *)NULL); return TCL_ERROR; } } if (isNew) { /* * Create the window for the drag&drop token... */ if (CreateToken(interp, srcPtr) != TCL_OK) { DestroySource(srcPtr); return TCL_ERROR; } } return TCL_OK; } /* * HANDLE: drag&drop target ?? ?handling info...? */ static int TargetOp(interp, argc, argv) Tcl_Interp *interp; int argc; char **argv; { SubstDescriptors subst[2]; Tk_Window tkwin; Blt_HashEntry *hPtr; Target *targetPtr; int isNew; if (argc == 2) { Blt_HashSearch cursor; for (hPtr = Blt_FirstHashEntry(&targetTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tkwin = (Tk_Window)Blt_GetHashKey(&targetTable, hPtr); Tcl_AppendElement(interp, Tk_PathName(tkwin)); } return TCL_OK; } tkwin = Tk_NameToWindow(interp, argv[2], Tk_MainWindow(interp)); if (tkwin == NULL) { return TCL_ERROR; } targetPtr = FindTarget(tkwin); if (targetPtr == NULL) { targetPtr = CreateTarget(interp, tkwin); } if (targetPtr == NULL) { return TCL_ERROR; } if ((argc >= 4) && (strcmp(argv[3], "handler") == 0)) { /* * HANDLE: drag&drop target handler * drag&drop target handler ? ...? */ if (argc == 4) { Blt_HashSearch cursor; for (hPtr = Blt_FirstHashEntry(&(targetPtr->handlerTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { Tcl_AppendElement(interp, Blt_GetHashKey(&(targetPtr->handlerTable), hPtr)); } return TCL_OK; } else if (argc >= 6) { char *cmd; /* * Process handler definition */ hPtr = Blt_CreateHashEntry(&(targetPtr->handlerTable), argv[4], &isNew); cmd = Tcl_Concat(argc - 5, argv + 5); if (hPtr != NULL) { char *oldCmd; oldCmd = (char *)Blt_GetHashValue(hPtr); if (oldCmd != NULL) { Blt_Free(oldCmd); } } Blt_SetHashValue(hPtr, cmd); /* * Update the target property on the window. */ AddTargetProperty(interp, targetPtr); return TCL_OK; } Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ", argv[1], " ", argv[2], " ", argv[3], " data command ?arg arg...?", (char *)NULL); return TCL_ERROR; } else if ((argc >= 4) && (strcmp(argv[3], "handle") == 0)) { /* * HANDLE: drag&drop target handle ?? */ Tcl_DString dString; int result; char *cmd; if (argc < 5 || argc > 6) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ", argv[1], " ", argv[2], " handle data ?value?", (char *)NULL); return TCL_ERROR; } hPtr = Blt_FindHashEntry(&(targetPtr->handlerTable), argv[4]); if (hPtr == NULL) { Tcl_AppendResult(interp, "target can't handle datatype: ", argv[4], (char *)NULL); return TCL_ERROR; /* no handler found */ } cmd = (char *)Blt_GetHashValue(hPtr); if (cmd != NULL) { subst[0].letter = 'W'; subst[0].value = Tk_PathName(targetPtr->tkwin); subst[1].letter = 'v'; if (argc > 5) { subst[1].value = argv[5]; } else { subst[1].value = ""; } Tcl_DStringInit(&dString); result = Tcl_Eval(interp, ExpandPercents(cmd, subst, 2, &dString)); Tcl_DStringFree(&dString); return result; } return TCL_OK; } Tcl_AppendResult(interp, "usage: ", argv[0], " target ", argv[2], " handler ?data command arg arg...?\n or: ", argv[0], " target ", argv[2], " handle ", (char *)NULL); return TCL_ERROR; } /* * ------------------------------------------------------------------------ * * DragDropCmd -- * * Invoked by TCL whenever the user issues a drag&drop command. * Handles the following syntax: * * drag&drop source * drag&drop source ?options...? * drag&drop source handler ?? ? ...? * * drag&drop target * drag&drop target handler ? ...? * drag&drop target handle ?? * * drag&drop token * drag&drop drag * drag&drop drop * * drag&drop errors ?? * drag&drop active * drag&drop location ? ? * * ------------------------------------------------------------------------ */ /*ARGSUSED*/ static int DragDropCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter */ int argc; /* # of arguments */ char **argv; /* Argument strings */ { int length; char c; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " oper ?args?\"", (char *)NULL); return TCL_ERROR; } c = argv[1][0]; length = strlen(argv[1]); if ((c == 's') && strncmp(argv[1], "source", length) == 0) { return SourceOp(interp, argc, argv); } else if ((c == 't') && (length >= 2) && (strncmp(argv[1], "target", length) == 0)) { return TargetOp(interp, argc, argv); } else if ((c == 't') && (length >= 2) && (strncmp(argv[1], "token", length) == 0)) { return TokenOp(interp, argc, argv); } else if ((c == 'd') && strncmp(argv[1], "drag", length) == 0) { return DragOp(interp, argc, argv); } else if ((c == 'd') && strncmp(argv[1], "drop", length) == 0) { return DropOp(interp, argc, argv); } else if ((c == 'e') && strncmp(argv[1], "errors", length) == 0) { return ErrorsOp(interp, argc, argv); } else if ((c == 'a') && strncmp(argv[1], "active", length) == 0) { return ActiveOp(interp, argc, argv); } else if ((c == 'l') && strncmp(argv[1], "location", length) == 0) { return LocationOp(interp, argc, argv); } /* * Report improper command arguments */ Tcl_AppendResult(interp, "bad operation \"", argv[1], "\": must be active, drag, drop, errors, location, ", "source, target or token", (char *)NULL); return TCL_ERROR; } /* * ------------------------------------------------------------------------ * * Blt_DragDropInit -- * * Adds the drag&drop command to the given interpreter. Should * be invoked to properly install the command whenever a new * interpreter is created. * * ------------------------------------------------------------------------ */ int Blt_DragDropInit(interp) Tcl_Interp *interp; /* interpreter to be updated */ { static Blt_CmdSpec cmdSpec = { "drag&drop", DragDropCmd, }; if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) { return TCL_ERROR; } if (!initialized) { Blt_InitHashTable(&sourceTable, BLT_ONE_WORD_KEYS); Blt_InitHashTable(&targetTable, BLT_ONE_WORD_KEYS); errorCmd = Blt_Strdup(DEF_ERROR_PROC); nActive = 0; locX = locY = 0; initialized = TRUE; #ifndef WIN32 dndAtom = XInternAtom(Tk_Display(Tk_MainWindow(interp)), propName, False); #endif } return TCL_OK; } #endif /* NO_DRAGDROP */ blt-2.4z.orig/src/bltGrAxis.c0100644000175000017500000040331007542177233014611 0ustar dokodoko /* * bltGrAxis.c -- * * This module implements coordinate axes for the BLT graph widget. * * Copyright 1993-1998 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. */ #include "bltGraph.h" #include "bltGrElem.h" #include #define DEF_NUM_TICKS 4 /* Each minor tick is 20% */ #define STATIC_TICK_SPACE 10 #define TICK_LABEL_SIZE 200 #define MAXTICKS 10001 #define CLAMP(val,low,high) \ (((val) < (low)) ? (low) : ((val) > (high)) ? (high) : (val)) /* * Round x in terms of units */ #define UROUND(x,u) (Round((x)/(u))*(u)) #define UCEIL(x,u) (ceil((x)/(u))*(u)) #define UFLOOR(x,u) (floor((x)/(u))*(u)) #define LENGTH_MAJOR_TICK 0.030 /* Length of a major tick */ #define LENGTH_MINOR_TICK 0.015 /* Length of a minor (sub)tick */ #define LENGTH_LABEL_TICK 0.040 /* Distance from graph to start of the * label */ #define NUMDIGITS 15 /* Specifies the number of * digits of accuracy used when * outputting axis tick labels. */ #define AVG_TICK_NUM_CHARS 16 /* Assumed average tick label size */ #define TICK_RANGE_TIGHT 0 #define TICK_RANGE_LOOSE 1 #define TICK_RANGE_ALWAYS_LOOSE 2 #define AXIS_TITLE_PAD 2 /* Padding for axis title. */ #define AXIS_LINE_PAD 1 /* Padding for axis line. */ #define HORIZMARGIN(m) (!((m)->site & 0x1)) /* Even sites are horizontal */ typedef enum AxisComponents { MAJOR_TICK, MINOR_TICK, TICK_LABEL, AXIS_LINE } AxisComponent; typedef struct { int axis; /* Length of the axis. */ int t1; /* Length of a major tick (in pixels). */ int t2; /* Length of a minor tick (in pixels). */ int label; /* Distance from axis to tick label. */ } AxisInfo; extern Tk_CustomOption bltDistanceOption; extern Tk_CustomOption bltPositiveDistanceOption; extern Tk_CustomOption bltShadowOption; extern Tk_CustomOption bltListOption; static Tk_OptionParseProc StringToLimit; static Tk_OptionPrintProc LimitToString; static Tk_OptionParseProc StringToTicks; static Tk_OptionPrintProc TicksToString; static Tk_OptionParseProc StringToAxis; static Tk_OptionPrintProc AxisToString; static Tk_OptionParseProc StringToAnyAxis; static Tk_OptionParseProc StringToFormat; static Tk_OptionPrintProc FormatToString; static Tk_OptionParseProc StringToLoose; static Tk_OptionPrintProc LooseToString; static Tk_CustomOption limitOption = { StringToLimit, LimitToString, (ClientData)0 }; static Tk_CustomOption majorTicksOption = { StringToTicks, TicksToString, (ClientData)AXIS_CONFIG_MAJOR, }; static Tk_CustomOption minorTicksOption = { StringToTicks, TicksToString, (ClientData)AXIS_CONFIG_MINOR, }; Tk_CustomOption bltXAxisOption = { StringToAxis, AxisToString, (ClientData)&bltXAxisUid }; Tk_CustomOption bltYAxisOption = { StringToAxis, AxisToString, (ClientData)&bltYAxisUid }; Tk_CustomOption bltAnyXAxisOption = { StringToAnyAxis, AxisToString, (ClientData)&bltXAxisUid }; Tk_CustomOption bltAnyYAxisOption = { StringToAnyAxis, AxisToString, (ClientData)&bltYAxisUid }; static Tk_CustomOption formatOption = { StringToFormat, FormatToString, (ClientData)0, }; static Tk_CustomOption looseOption = { StringToLoose, LooseToString, (ClientData)0, }; /* Axis flags: */ #define DEF_AXIS_COMMAND (char *)NULL #define DEF_AXIS_DESCENDING "no" #define DEF_AXIS_FOREGROUND RGB_BLACK #define DEF_AXIS_FG_MONO RGB_BLACK #define DEF_AXIS_HIDE "no" #define DEF_AXIS_JUSTIFY "center" #define DEF_AXIS_LIMITS_FORMAT (char *)NULL #define DEF_AXIS_LINE_WIDTH "1" #define DEF_AXIS_LOGSCALE "no" #define DEF_AXIS_LOOSE "no" #define DEF_AXIS_RANGE "0.0" #define DEF_AXIS_ROTATE "0.0" #define DEF_AXIS_SCROLL_INCREMENT "10" #define DEF_AXIS_SHIFTBY "0.0" #define DEF_AXIS_SHOWTICKS "yes" #define DEF_AXIS_STEP "0.0" #define DEF_AXIS_STEP "0.0" #define DEF_AXIS_SUBDIVISIONS "2" #define DEF_AXIS_TAGS "all" #define DEF_AXIS_TICKS "0" #ifdef WIN32 #define DEF_AXIS_TICK_FONT "{Arial Narrow} 8" #else #define DEF_AXIS_TICK_FONT "*-Helvetica-Medium-R-Normal-*-10-*" #endif #define DEF_AXIS_TICK_LENGTH "8" #define DEF_AXIS_TITLE_ALTERNATE "0" #define DEF_AXIS_TITLE_FG RGB_BLACK #define DEF_AXIS_TITLE_FONT STD_FONT #define DEF_AXIS_X_STEP_BARCHART "1.0" #define DEF_AXIS_X_SUBDIVISIONS_BARCHART "0" #define DEF_AXIS_BACKGROUND (char *)NULL #define DEF_AXIS_BORDERWIDTH "0" #define DEF_AXIS_RELIEF "flat" static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_DOUBLE, "-autorange", "autoRange", "AutoRange", DEF_AXIS_RANGE, Tk_Offset(Axis, windowSize), ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_AXIS_BACKGROUND, Tk_Offset(Axis, border), ALL_GRAPHS | TK_CONFIG_NULL_OK}, {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags", DEF_AXIS_TAGS, Tk_Offset(Axis, tags), ALL_GRAPHS | TK_CONFIG_NULL_OK, &bltListOption}, {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, ALL_GRAPHS}, {TK_CONFIG_CUSTOM, "-borderwidth", "borderWidth", "BorderWidth", DEF_AXIS_BORDERWIDTH, Tk_Offset(Axis, borderWidth), ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_COLOR, "-color", "color", "Color", DEF_AXIS_FOREGROUND, Tk_Offset(Axis, tickTextStyle.color), TK_CONFIG_COLOR_ONLY | ALL_GRAPHS}, {TK_CONFIG_COLOR, "-color", "color", "Color", DEF_AXIS_FG_MONO, Tk_Offset(Axis, tickTextStyle.color), TK_CONFIG_MONO_ONLY | ALL_GRAPHS}, {TK_CONFIG_STRING, "-command", "command", "Command", DEF_AXIS_COMMAND, Tk_Offset(Axis, formatCmd), TK_CONFIG_NULL_OK | ALL_GRAPHS}, {TK_CONFIG_BOOLEAN, "-descending", "descending", "Descending", DEF_AXIS_DESCENDING, Tk_Offset(Axis, descending), ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide", DEF_AXIS_HIDE, Tk_Offset(Axis, hidden), ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify", DEF_AXIS_JUSTIFY, Tk_Offset(Axis, titleTextStyle.justify), ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_BOOLEAN, "-labeloffset", "labelOffset", "LabelOffset", (char *)NULL, Tk_Offset(Axis, labelOffset), ALL_GRAPHS}, {TK_CONFIG_COLOR, "-limitscolor", "limitsColor", "Color", DEF_AXIS_FOREGROUND, Tk_Offset(Axis, limitsTextStyle.color), TK_CONFIG_COLOR_ONLY | ALL_GRAPHS}, {TK_CONFIG_COLOR, "-limitscolor", "limitsColor", "Color", DEF_AXIS_FG_MONO, Tk_Offset(Axis, limitsTextStyle.color), TK_CONFIG_MONO_ONLY | ALL_GRAPHS}, {TK_CONFIG_FONT, "-limitsfont", "limitsFont", "Font", DEF_AXIS_TICK_FONT, Tk_Offset(Axis, limitsTextStyle.font), ALL_GRAPHS}, {TK_CONFIG_CUSTOM, "-limitsformat", "limitsFormat", "LimitsFormat", (char *)NULL, Tk_Offset(Axis, limitsFormats), TK_CONFIG_NULL_OK | ALL_GRAPHS, &formatOption}, {TK_CONFIG_CUSTOM, "-limitsshadow", "limitsShadow", "Shadow", (char *)NULL, Tk_Offset(Axis, limitsTextStyle.shadow), TK_CONFIG_COLOR_ONLY | ALL_GRAPHS, &bltShadowOption}, {TK_CONFIG_CUSTOM, "-limitsshadow", "limitsShadow", "Shadow", (char *)NULL, Tk_Offset(Axis, limitsTextStyle.shadow), TK_CONFIG_MONO_ONLY | ALL_GRAPHS, &bltShadowOption}, {TK_CONFIG_CUSTOM, "-linewidth", "lineWidth", "LineWidth", DEF_AXIS_LINE_WIDTH, Tk_Offset(Axis, lineWidth), ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_BOOLEAN, "-logscale", "logScale", "LogScale", DEF_AXIS_LOGSCALE, Tk_Offset(Axis, logScale), ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-loose", "loose", "Loose", DEF_AXIS_LOOSE, 0, ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT, &looseOption}, {TK_CONFIG_CUSTOM, "-majorticks", "majorTicks", "MajorTicks", (char *)NULL, Tk_Offset(Axis, t1Ptr), TK_CONFIG_NULL_OK | ALL_GRAPHS, &majorTicksOption}, {TK_CONFIG_CUSTOM, "-max", "max", "Max", (char *)NULL, Tk_Offset(Axis, reqMax), TK_CONFIG_NULL_OK | ALL_GRAPHS, &limitOption}, {TK_CONFIG_CUSTOM, "-min", "min", "Min", (char *)NULL, Tk_Offset(Axis, reqMin), TK_CONFIG_NULL_OK | ALL_GRAPHS, &limitOption}, {TK_CONFIG_CUSTOM, "-minorticks", "minorTicks", "MinorTicks", (char *)NULL, Tk_Offset(Axis, t2Ptr), TK_CONFIG_NULL_OK | ALL_GRAPHS, &minorTicksOption}, {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_AXIS_RELIEF, Tk_Offset(Axis, relief), ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_DOUBLE, "-rotate", "rotate", "Rotate", DEF_AXIS_ROTATE, Tk_Offset(Axis, tickTextStyle.theta), ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_STRING, "-scrollcommand", "scrollCommand", "ScrollCommand", (char *)NULL, Tk_Offset(Axis, scrollCmdPrefix), ALL_GRAPHS | TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-scrollincrement", "scrollIncrement", "ScrollIncrement", DEF_AXIS_SCROLL_INCREMENT, Tk_Offset(Axis, scrollUnits), ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT, &bltPositiveDistanceOption}, {TK_CONFIG_CUSTOM, "-scrollmax", "scrollMax", "ScrollMax", (char *)NULL, Tk_Offset(Axis, scrollMax), TK_CONFIG_NULL_OK | ALL_GRAPHS, &limitOption}, {TK_CONFIG_CUSTOM, "-scrollmin", "scrollMin", "ScrollMin", (char *)NULL, Tk_Offset(Axis, scrollMin), TK_CONFIG_NULL_OK | ALL_GRAPHS, &limitOption}, {TK_CONFIG_DOUBLE, "-shiftby", "shiftBy", "ShiftBy", DEF_AXIS_SHIFTBY, Tk_Offset(Axis, shiftBy), ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_BOOLEAN, "-showticks", "showTicks", "ShowTicks", DEF_AXIS_SHOWTICKS, Tk_Offset(Axis, showTicks), ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_DOUBLE, "-stepsize", "stepSize", "StepSize", DEF_AXIS_STEP, Tk_Offset(Axis, reqStep), ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_DOUBLE, "-tickdivider", "tickDivider", "TickDivider", DEF_AXIS_STEP, Tk_Offset(Axis, tickZoom), ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_INT, "-subdivisions", "subdivisions", "Subdivisions", DEF_AXIS_SUBDIVISIONS, Tk_Offset(Axis, reqNumMinorTicks), ALL_GRAPHS}, {TK_CONFIG_FONT, "-tickfont", "tickFont", "Font", DEF_AXIS_TICK_FONT, Tk_Offset(Axis, tickTextStyle.font), ALL_GRAPHS}, {TK_CONFIG_PIXELS, "-ticklength", "tickLength", "TickLength", DEF_AXIS_TICK_LENGTH, Tk_Offset(Axis, tickLength), ALL_GRAPHS}, {TK_CONFIG_CUSTOM, "-tickshadow", "tickShadow", "Shadow", (char *)NULL, Tk_Offset(Axis, tickTextStyle.shadow), TK_CONFIG_COLOR_ONLY | ALL_GRAPHS, &bltShadowOption}, {TK_CONFIG_CUSTOM, "-tickshadow", "tickShadow", "Shadow", (char *)NULL, Tk_Offset(Axis, tickTextStyle.shadow), TK_CONFIG_MONO_ONLY | ALL_GRAPHS, &bltShadowOption}, {TK_CONFIG_STRING, "-title", "title", "Title", (char *)NULL, Tk_Offset(Axis, title), TK_CONFIG_DONT_SET_DEFAULT | TK_CONFIG_NULL_OK | ALL_GRAPHS}, {TK_CONFIG_BOOLEAN, "-titlealternate", "titleAlternate", "TitleAlternate", DEF_AXIS_TITLE_ALTERNATE, Tk_Offset(Axis, titleAlternate), TK_CONFIG_DONT_SET_DEFAULT | ALL_GRAPHS}, {TK_CONFIG_COLOR, "-titlecolor", "titleColor", "Color", DEF_AXIS_FOREGROUND, Tk_Offset(Axis, titleTextStyle.color), TK_CONFIG_COLOR_ONLY | ALL_GRAPHS}, {TK_CONFIG_COLOR, "-titlecolor", "titleColor", "TitleColor", DEF_AXIS_FG_MONO, Tk_Offset(Axis, titleTextStyle.color), TK_CONFIG_MONO_ONLY | ALL_GRAPHS}, {TK_CONFIG_FONT, "-titlefont", "titleFont", "Font", DEF_AXIS_TITLE_FONT, Tk_Offset(Axis, titleTextStyle.font), ALL_GRAPHS}, {TK_CONFIG_CUSTOM, "-titleshadow", "titleShadow", "Shadow", (char *)NULL, Tk_Offset(Axis, titleTextStyle.shadow), TK_CONFIG_COLOR_ONLY | ALL_GRAPHS, &bltShadowOption}, {TK_CONFIG_CUSTOM, "-titleshadow", "titleShadow", "Shadow", (char *)NULL, Tk_Offset(Axis, titleTextStyle.shadow), TK_CONFIG_MONO_ONLY | ALL_GRAPHS, &bltShadowOption}, {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} }; /* Forward declarations */ static void DestroyAxis _ANSI_ARGS_((Graph *graphPtr, Axis *axisPtr)); static int GetAxis _ANSI_ARGS_((Graph *graphPtr, char *name, Blt_Uid classUid, Axis **axisPtrPtr)); static void FreeAxis _ANSI_ARGS_((Graph *graphPtr, Axis *axisPtr)); INLINE static int Round(register double x) { return (int) (x + ((x < 0.0) ? -0.5 : 0.5)); } static void SetAxisRange(AxisRange *rangePtr, double min, double max) { rangePtr->min = min; rangePtr->max = max; rangePtr->range = max - min; if (FABS(rangePtr->range) < DBL_EPSILON) { rangePtr->range = 1.0; } rangePtr->scale = 1.0 / rangePtr->range; } /* * ---------------------------------------------------------------------- * * InRange -- * * Determines if a value lies within a given range. * * The value is normalized and compared against the interval * [0..1], where 0.0 is the minimum and 1.0 is the maximum. * DBL_EPSILON is the smallest number that can be represented * on the host machine, such that (1.0 + epsilon) != 1.0. * * Please note, *max* can't equal *min*. * * Results: * If the value is within the interval [min..max], 1 is * returned; 0 otherwise. * * ---------------------------------------------------------------------- */ INLINE static int InRange(x, rangePtr) register double x; AxisRange *rangePtr; { if (rangePtr->range < DBL_EPSILON) { #ifdef notdef return (((rangePtr->max - x) >= (FABS(x) * DBL_EPSILON)) && ((x - rangePtr->min) >= (FABS(x) * DBL_EPSILON))); #endif 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)); } } INLINE static int AxisIsHorizontal(graphPtr, axisPtr) Graph *graphPtr; Axis *axisPtr; { return ((axisPtr->classUid == bltYAxisUid) == graphPtr->inverted); } /* ---------------------------------------------------------------------- * Custom option parse and print procedures * ---------------------------------------------------------------------- */ /* *---------------------------------------------------------------------- * * StringToAnyAxis -- * * Converts the name of an axis to a pointer to its axis structure. * * Results: * The return value is a standard Tcl result. The axis flags are * written into the widget record. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToAnyAxis(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Class identifier of the type of * axis we are looking for. */ Tcl_Interp *interp; /* Interpreter to send results back to. */ Tk_Window tkwin; /* Used to look up pointer to graph. */ char *string; /* String representing new value. */ char *widgRec; /* Pointer to structure record. */ int offset; /* Offset of field in structure. */ { Axis **axisPtrPtr = (Axis **)(widgRec + offset); Blt_Uid classUid = *(Blt_Uid *)clientData; Graph *graphPtr; Axis *axisPtr; graphPtr = Blt_GetGraphFromWindowData(tkwin); if (*axisPtrPtr != NULL) { FreeAxis(graphPtr, *axisPtrPtr); } if (string[0] == '\0') { axisPtr = NULL; } else if (GetAxis(graphPtr, string, classUid, &axisPtr) != TCL_OK) { return TCL_ERROR; } *axisPtrPtr = axisPtr; return TCL_OK; } /* *---------------------------------------------------------------------- * * StringToAxis -- * * Converts the name of an axis to a pointer to its axis structure. * * Results: * The return value is a standard Tcl result. The axis flags are * written into the widget record. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToAxis(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Class identifier of the type of * axis we are looking for. */ Tcl_Interp *interp; /* Interpreter to send results back to. */ Tk_Window tkwin; /* Used to look up pointer to graph. */ char *string; /* String representing new value. */ char *widgRec; /* Pointer to structure record. */ int offset; /* Offset of field in structure. */ { Axis **axisPtrPtr = (Axis **)(widgRec + offset); Blt_Uid classUid = *(Blt_Uid *)clientData; Graph *graphPtr; graphPtr = Blt_GetGraphFromWindowData(tkwin); if (*axisPtrPtr != NULL) { FreeAxis(graphPtr, *axisPtrPtr); } if (GetAxis(graphPtr, string, classUid, axisPtrPtr) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * AxisToString -- * * Convert the window coordinates into a string. * * Results: * The string representing the coordinate position is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * AxisToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Pointer to structure record .*/ int offset; /* Offset of field in structure. */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { Axis *axisPtr = *(Axis **)(widgRec + offset); if (axisPtr == NULL) { return ""; } return axisPtr->name; } /* *---------------------------------------------------------------------- * * StringToFormat -- * * Convert the name of virtual axis to an pointer. * * Results: * The return value is a standard Tcl result. The axis flags are * written into the widget record. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToFormat(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to. */ Tk_Window tkwin; /* Used to look up pointer to graph */ char *string; /* String representing new value. */ char *widgRec; /* Pointer to structure record. */ int offset; /* Offset of field in structure. */ { Axis *axisPtr = (Axis *)(widgRec); char **argv; int argc; if (axisPtr->limitsFormats != NULL) { Blt_Free(axisPtr->limitsFormats); } axisPtr->limitsFormats = NULL; axisPtr->nFormats = 0; if ((string == NULL) || (*string == '\0')) { return TCL_OK; } if (Tcl_SplitList(interp, string, &argc, &argv) != TCL_OK) { return TCL_ERROR; } if (argc > 2) { Tcl_AppendResult(interp, "too many elements in limits format list \"", string, "\"", (char *)NULL); Blt_Free(argv); return TCL_ERROR; } axisPtr->limitsFormats = argv; axisPtr->nFormats = argc; return TCL_OK; } /* *---------------------------------------------------------------------- * * FormatToString -- * * Convert the window coordinates into a string. * * Results: * The string representing the coordinate position is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * FormatToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget record */ int offset; /* offset of limits field */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { Axis *axisPtr = (Axis *)(widgRec); if (axisPtr->nFormats == 0) { return ""; } *freeProcPtr = (Tcl_FreeProc *)Blt_Free; return Tcl_Merge(axisPtr->nFormats, axisPtr->limitsFormats); } /* * ---------------------------------------------------------------------- * * StringToLimit -- * * Convert the string representation of an axis limit into its numeric * form. * * Results: * The return value is a standard Tcl result. The symbol type is * written into the widget record. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToLimit(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Either AXIS_CONFIG_MIN or AXIS_CONFIG_MAX. * Indicates which axis limit to set. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* String representing new value. */ char *widgRec; /* Pointer to structure record. */ int offset; /* Offset of field in structure. */ { double *limitPtr = (double *)(widgRec + offset); if ((string == NULL) || (*string == '\0')) { *limitPtr = VALUE_UNDEFINED; } else if (Tcl_ExprDouble(interp, string, limitPtr) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } /* * ---------------------------------------------------------------------- * * LimitToString -- * * Convert the floating point axis limits into a string. * * Results: * The string representation of the limits is returned. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * LimitToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Either LMIN or LMAX */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* */ int offset; Tcl_FreeProc **freeProcPtr; { double limit = *(double *)(widgRec + offset); char *result; result = ""; if (DEFINED(limit)) { char string[TCL_DOUBLE_SPACE + 1]; Graph *graphPtr; graphPtr = Blt_GetGraphFromWindowData(tkwin); Tcl_PrintDouble(graphPtr->interp, limit, string); result = Blt_Strdup(string); if (result == NULL) { return ""; } *freeProcPtr = (Tcl_FreeProc *)Blt_Free; } return result; } /* * ---------------------------------------------------------------------- * * StringToTicks -- * * * Results: * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToTicks(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* String representing new value. */ char *widgRec; /* Pointer to structure record. */ int offset; /* Offset of field in structure. */ { unsigned int mask = (unsigned int)clientData; Axis *axisPtr = (Axis *)widgRec; Ticks **ticksPtrPtr = (Ticks **) (widgRec + offset); int nTicks; Ticks *ticksPtr; nTicks = 0; ticksPtr = NULL; if ((string != NULL) && (*string != '\0')) { int nExprs; char **exprArr; if (Tcl_SplitList(interp, string, &nExprs, &exprArr) != TCL_OK) { return TCL_ERROR; } if (nExprs > 0) { register int i; int result = TCL_ERROR; double value; ticksPtr = Blt_Malloc(sizeof(Ticks) + (nExprs * sizeof(double))); assert(ticksPtr); for (i = 0; i < nExprs; i++) { result = Tcl_ExprDouble(interp, exprArr[i], &value); if (result != TCL_OK) { break; } ticksPtr->values[i] = value; } Blt_Free(exprArr); if (result != TCL_OK) { Blt_Free(ticksPtr); return TCL_ERROR; } nTicks = nExprs; } } axisPtr->flags &= ~mask; if (ticksPtr != NULL) { axisPtr->flags |= mask; ticksPtr->nTicks = nTicks; } if (*ticksPtrPtr != NULL) { Blt_Free(*ticksPtrPtr); } *ticksPtrPtr = ticksPtr; return TCL_OK; } /* * ---------------------------------------------------------------------- * * TicksToString -- * * Convert array of tick coordinates to a list. * * Results: * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * TicksToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* */ int offset; Tcl_FreeProc **freeProcPtr; { Ticks *ticksPtr = *(Ticks **) (widgRec + offset); char string[TCL_DOUBLE_SPACE + 1]; register int i; char *result; Tcl_DString dString; Graph *graphPtr; if (ticksPtr == NULL) { return ""; } Tcl_DStringInit(&dString); graphPtr = Blt_GetGraphFromWindowData(tkwin); for (i = 0; i < ticksPtr->nTicks; i++) { Tcl_PrintDouble(graphPtr->interp, ticksPtr->values[i], string); Tcl_DStringAppendElement(&dString, string); } *freeProcPtr = (Tcl_FreeProc *)Blt_Free; result = Blt_Strdup(Tcl_DStringValue(&dString)); Tcl_DStringFree(&dString); return result; } /* *---------------------------------------------------------------------- * * StringToLoose -- * * Convert a string to one of three values. * 0 - false, no, off * 1 - true, yes, on * 2 - always * Results: * If the string is successfully converted, TCL_OK is returned. * Otherwise, TCL_ERROR is returned and an error message is left in * interpreter's result field. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToLoose(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* String representing new value. */ char *widgRec; /* Pointer to structure record. */ int offset; /* Offset of field in structure. */ { Axis *axisPtr = (Axis *)(widgRec); register int i; int argc; char **argv; int values[2]; if (Tcl_SplitList(interp, string, &argc, &argv) != TCL_OK) { return TCL_ERROR; } if ((argc < 1) || (argc > 2)) { Tcl_AppendResult(interp, "wrong # elements in loose value \"", string, "\"", (char *)NULL); return TCL_ERROR; } for (i = 0; i < argc; i++) { if ((argv[i][0] == 'a') && (strcmp(argv[i], "always") == 0)) { values[i] = TICK_RANGE_ALWAYS_LOOSE; } else { int bool; if (Tcl_GetBoolean(interp, argv[i], &bool) != TCL_OK) { Blt_Free(argv); return TCL_ERROR; } values[i] = bool; } } axisPtr->looseMin = axisPtr->looseMax = values[0]; if (argc > 1) { axisPtr->looseMax = values[1]; } Blt_Free(argv); return TCL_OK; } /* *---------------------------------------------------------------------- * * LooseToString -- * * Results: * The string representation of the auto boolean is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * LooseToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget record */ int offset; /* offset of flags field in record */ Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */ { Axis *axisPtr = (Axis *)widgRec; Tcl_DString dString; char *result; Tcl_DStringInit(&dString); if (axisPtr->looseMin == TICK_RANGE_TIGHT) { Tcl_DStringAppendElement(&dString, "0"); } else if (axisPtr->looseMin == TICK_RANGE_LOOSE) { Tcl_DStringAppendElement(&dString, "1"); } else if (axisPtr->looseMin == TICK_RANGE_ALWAYS_LOOSE) { Tcl_DStringAppendElement(&dString, "always"); } if (axisPtr->looseMin != axisPtr->looseMax) { if (axisPtr->looseMax == TICK_RANGE_TIGHT) { Tcl_DStringAppendElement(&dString, "0"); } else if (axisPtr->looseMax == TICK_RANGE_LOOSE) { Tcl_DStringAppendElement(&dString, "1"); } else if (axisPtr->looseMax == TICK_RANGE_ALWAYS_LOOSE) { Tcl_DStringAppendElement(&dString, "always"); } } result = Blt_Strdup(Tcl_DStringValue(&dString)); Tcl_DStringFree(&dString); *freeProcPtr = (Tcl_FreeProc *)Blt_Free; return result; } static void FreeLabels(chainPtr) Blt_Chain *chainPtr; { Blt_ChainLink *linkPtr; TickLabel *labelPtr; for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { labelPtr = Blt_ChainGetValue(linkPtr); Blt_Free(labelPtr); } Blt_ChainReset(chainPtr); } /* * ---------------------------------------------------------------------- * * MakeLabel -- * * Converts a floating point tick value to a string to be used as its * label. * * Results: * None. * * Side Effects: * Returns a new label in the string character buffer. The formatted * tick label will be displayed on the graph. * * ---------------------------------------------------------------------- */ static TickLabel * MakeLabel(graphPtr, axisPtr, value) Graph *graphPtr; Axis *axisPtr; /* Axis structure */ double value; /* Value to be convert to a decimal string */ { char string[TICK_LABEL_SIZE + 1]; TickLabel *labelPtr; /* Generate a default tick label based upon the tick value. */ if (axisPtr->logScale) { sprintf(string, "1E%d", ROUND(value)); } else { sprintf(string, "%.*g", NUMDIGITS, value); } if (axisPtr->formatCmd != NULL) { 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, axisPtr->formatCmd, " ", Tk_PathName(tkwin), " ", string, (char *)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. */ } } labelPtr = Blt_Malloc(sizeof(TickLabel) + strlen(string)); assert(labelPtr); strcpy(labelPtr->string, string); labelPtr->anchorPos.x = labelPtr->anchorPos.y = DBL_MAX; return labelPtr; } /* * ---------------------------------------------------------------------- * * Blt_InvHMap -- * * Maps the given screen coordinate back to a graph coordinate. * Called by the graph locater routine. * * Results: * Returns the graph coordinate value at the given window * y-coordinate. * * ---------------------------------------------------------------------- */ double Blt_InvHMap(graphPtr, axisPtr, x) Graph *graphPtr; Axis *axisPtr; double x; { double value; x = (double)(x - graphPtr->hOffset) * graphPtr->hScale; if (axisPtr->descending) { x = 1.0 - x; } value = (x * axisPtr->axisRange.range) + axisPtr->axisRange.min; if (axisPtr->logScale) { value = EXP10(value); } return value; } /* * ---------------------------------------------------------------------- * * Blt_InvVMap -- * * Maps the given window y-coordinate back to a graph coordinate * value. Called by the graph locater routine. * * Results: * Returns the graph coordinate value at the given window * y-coordinate. * * ---------------------------------------------------------------------- */ double Blt_InvVMap(graphPtr, axisPtr, y) Graph *graphPtr; Axis *axisPtr; double y; { double value; y = (double)(y - graphPtr->vOffset) * graphPtr->vScale; if (axisPtr->descending) { y = 1.0 - y; } value = ((1.0 - y) * axisPtr->axisRange.range) + axisPtr->axisRange.min; if (axisPtr->logScale) { value = EXP10(value); } return value; } /* * ---------------------------------------------------------------------- * * Blt_HMap -- * * Map the given graph coordinate value to its axis, returning a window * position. * * Results: * Returns a double precision number representing the window coordinate * position on the given axis. * * ---------------------------------------------------------------------- */ double Blt_HMap(graphPtr, axisPtr, x) Graph *graphPtr; Axis *axisPtr; double x; { if ((axisPtr->logScale) && (x != 0.0)) { x = log10(FABS(x)); } /* Map graph coordinate to normalized coordinates [0..1] */ x = (x - axisPtr->axisRange.min) * axisPtr->axisRange.scale; if (axisPtr->descending) { x = 1.0 - x; } return (x * graphPtr->hRange + graphPtr->hOffset); } /* * ---------------------------------------------------------------------- * * Blt_VMap -- * * Map the given graph coordinate value to its axis, returning a window * position. * * Results: * Returns a double precision number representing the window coordinate * position on the given axis. * * ---------------------------------------------------------------------- */ double Blt_VMap(graphPtr, axisPtr, y) Graph *graphPtr; Axis *axisPtr; double y; { if ((axisPtr->logScale) && (y != 0.0)) { y = log10(FABS(y)); } /* Map graph coordinate to normalized coordinates [0..1] */ y = (y - axisPtr->axisRange.min) * axisPtr->axisRange.scale; if (axisPtr->descending) { y = 1.0 - y; } return (((1.0 - y) * graphPtr->vRange) + graphPtr->vOffset); } /* * ---------------------------------------------------------------------- * * Blt_Map2D -- * * Maps the given graph x,y coordinate values to a window position. * * Results: * Returns a XPoint structure containing the window coordinates of * the given graph x,y coordinate. * * ---------------------------------------------------------------------- */ Point2D Blt_Map2D(graphPtr, x, y, axesPtr) Graph *graphPtr; double x, y; /* Graph x and y coordinates */ Axis2D *axesPtr; /* Specifies which axes to use */ { Point2D point; if (graphPtr->inverted) { point.x = Blt_HMap(graphPtr, axesPtr->y, y); point.y = Blt_VMap(graphPtr, axesPtr->x, x); } else { point.x = Blt_HMap(graphPtr, axesPtr->x, x); point.y = Blt_VMap(graphPtr, axesPtr->y, y); } return point; } /* * ---------------------------------------------------------------------- * * Blt_InvMap2D -- * * Maps the given window x,y coordinates to graph values. * * Results: * Returns a structure containing the graph coordinates of * the given window x,y coordinate. * * ---------------------------------------------------------------------- */ Point2D Blt_InvMap2D(graphPtr, x, y, axesPtr) Graph *graphPtr; double x, y; /* Window x and y coordinates */ Axis2D *axesPtr; /* Specifies which axes to use */ { Point2D point; if (graphPtr->inverted) { point.x = Blt_InvVMap(graphPtr, axesPtr->x, y); point.y = Blt_InvHMap(graphPtr, axesPtr->y, x); } else { point.x = Blt_InvHMap(graphPtr, axesPtr->x, x); point.y = Blt_InvVMap(graphPtr, axesPtr->y, y); } return point; } static void GetDataLimits(axisPtr, min, max) Axis *axisPtr; double min, max; { if (axisPtr->valueRange.min > min) { axisPtr->valueRange.min = min; } if (axisPtr->valueRange.max < max) { axisPtr->valueRange.max = max; } } static void FixAxisRange(axisPtr) Axis *axisPtr; { double min, max; /* * 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). */ min = axisPtr->valueRange.min; max = axisPtr->valueRange.max; if (min == DBL_MAX) { if (DEFINED(axisPtr->reqMin)) { min = axisPtr->reqMin; } else { min = (axisPtr->logScale) ? 0.001 : 0.0; } } if (max == -DBL_MAX) { if (DEFINED(axisPtr->reqMax)) { max = axisPtr->reqMax; } else { max = 1.0; } } if (min >= max) { double value; /* * There is no range of data (i.e. min is not less than max), * so manufacture one. */ value = min; if (value == 0.0) { min = -0.1, max = 0.1; } else { double x; x = FABS(value) * 0.1; min = value - x, max = value + x; } } SetAxisRange(&axisPtr->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. */ axisPtr->min = min; axisPtr->max = max; if (DEFINED(axisPtr->reqMin)) { axisPtr->min = axisPtr->reqMin; } if (DEFINED(axisPtr->reqMax)) { axisPtr->max = axisPtr->reqMax; } if (axisPtr->max < axisPtr->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 (!DEFINED(axisPtr->reqMin)) { axisPtr->min = axisPtr->max - (FABS(axisPtr->max) * 0.1); } if (!DEFINED(axisPtr->reqMax)) { axisPtr->max = axisPtr->min + (FABS(axisPtr->max) * 0.1); } } /* * If a window size is defined, handle auto ranging by shifting * the axis limits. */ if ((axisPtr->windowSize > 0.0) && (!DEFINED(axisPtr->reqMin)) && (!DEFINED(axisPtr->reqMax))) { if (axisPtr->shiftBy < 0.0) { axisPtr->shiftBy = 0.0; } max = axisPtr->min + axisPtr->windowSize; if (axisPtr->max >= max) { if (axisPtr->shiftBy > 0.0) { max = UCEIL(axisPtr->max, axisPtr->shiftBy); } axisPtr->min = max - axisPtr->windowSize; } axisPtr->max = max; } if ((axisPtr->max != axisPtr->prevMax) || (axisPtr->min != axisPtr->prevMin)) { /* Indicate if the axis limits have changed */ axisPtr->flags |= AXIS_DIRTY; /* and save the previous minimum and maximum values */ axisPtr->prevMin = axisPtr->min; axisPtr->prevMax = axisPtr->max; } } /* * ---------------------------------------------------------------------- * * NiceNum -- * * Reference: Paul Heckbert, "Nice Numbers for Graph Labels", * Graphics Gems, pp 61-63. * * Finds a "nice" number approximately equal to x. * * ---------------------------------------------------------------------- */ static double NiceNum(x, round) double x; int round; /* If non-zero, round. Otherwise take ceiling * of value. */ { 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); } static Ticks * GenerateTicks(sweepPtr) TickSweep *sweepPtr; { Ticks *ticksPtr; register int i; ticksPtr = Blt_Malloc(sizeof(Ticks) + (sweepPtr->nSteps * sizeof(double))); assert(ticksPtr); if (sweepPtr->step == 0.0) { static double logTable[] = /* Precomputed log10 values [1..10] */ { 0.0, 0.301029995663981, 0.477121254719662, 0.602059991327962, 0.698970004336019, 0.778151250383644, 0.845098040014257, 0.903089986991944, 0.954242509439325, 1.0 }; /* Hack: A zero step indicates to use log values. */ for (i = 0; i < sweepPtr->nSteps; i++) { ticksPtr->values[i] = logTable[i]; } } else { double value; value = sweepPtr->initial; /* Start from smallest axis tick */ for (i = 0; i < sweepPtr->nSteps; i++) { value = UROUND(value, sweepPtr->step); ticksPtr->values[i] = value; value += sweepPtr->step; } } ticksPtr->nTicks = sweepPtr->nSteps; return ticksPtr; } /* * ---------------------------------------------------------------------- * * LogScaleAxis -- * * Determine the range and units of a log scaled axis. * * Unless the axis limits are specified, the axis is scaled * automatically, where the smallest and largest major ticks encompass * the range of actual data values. When an axis limit is specified, * that value represents the smallest(min)/largest(max) value in the * displayed range of values. * * Both manual and automatic scaling are affected by the step used. By * default, the step is the largest power of ten to divide the range in * more than one piece. * * Automatic scaling: * Find the smallest number of units which contain the range of values. * The minimum and maximum major tick values will be represent the * range of values for the axis. This greatest number of major ticks * possible is 10. * * Manual scaling: * Make the minimum and maximum data values the represent the range of * the values for the axis. The minimum and maximum major ticks will be * inclusive of this range. This provides the largest area for plotting * and the expected results when the axis min and max values have be set * by the user (.e.g zooming). The maximum number of major ticks is 20. * * For log scale, there's the possibility that the minimum and * maximum data values are the same magnitude. To represent the * points properly, at least one full decade should be shown. * However, if you zoom a log scale plot, the results should be * predictable. Therefore, in that case, show only minor ticks. * Lastly, there should be an appropriate way to handle numbers * <=0. * * maxY * | units = magnitude (of least significant digit) * | high = largest unit tick < max axis value * high _| low = smallest unit tick > min axis value * | * | range = high - low * | # ticks = greatest factor of range/units * _| * U | * n | * i | * t _| * | * | * | * low _| * | * |_minX________________maxX__ * | | | | | * minY low high * minY * * * numTicks = Number of ticks * min = Minimum value of axis * max = Maximum value of axis * range = Range of values (max - min) * * If the number of decades is greater than ten, it is assumed * that the full set of log-style ticks can't be drawn properly. * * Results: * None * * ---------------------------------------------------------------------- */ static void LogScaleAxis(axisPtr, min, max) Axis *axisPtr; double min, max; { double range; double tickMin, tickMax; double majorStep, minorStep; int nMajor, nMinor; 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 / DEF_NUM_TICKS, 1); tickMin = UFLOOR(tickMin, majorStep); tickMax = UCEIL(tickMax, majorStep); nMajor = (int)((tickMax - tickMin) / majorStep) + 1; minorStep = EXP10(floor(log10(majorStep))); if (minorStep == majorStep) { nMinor = 4, minorStep = 0.2; } else { nMinor = Round(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 ((axisPtr->looseMin == TICK_RANGE_TIGHT) || ((axisPtr->looseMin == TICK_RANGE_LOOSE) && (DEFINED(axisPtr->reqMin)))) { tickMin = min; nMajor++; } if ((axisPtr->looseMax == TICK_RANGE_TIGHT) || ((axisPtr->looseMax == TICK_RANGE_LOOSE) && (DEFINED(axisPtr->reqMax)))) { tickMax = max; } axisPtr->majorSweep.step = majorStep; axisPtr->majorSweep.initial = floor(tickMin); axisPtr->majorSweep.nSteps = nMajor; axisPtr->minorSweep.initial = axisPtr->minorSweep.step = minorStep; axisPtr->minorSweep.nSteps = nMinor; SetAxisRange(&axisPtr->axisRange, tickMin, tickMax); } /* * ---------------------------------------------------------------------- * * LinearScaleAxis -- * * Determine the units of a linear scaled axis. * * The axis limits are either the range of the data values mapped * to the axis (autoscaled), or the values specified by the -min * and -max options (manual). * * If autoscaled, the smallest and largest major ticks will * encompass the range of data values. If the -loose option is * selected, the next outer ticks are choosen. If tight, the * ticks are at or inside of the data limits are used. * * If manually set, the ticks are at or inside the data limits * are used. This makes sense for zooming. You want the * selected range to represent the next limit, not something a * bit bigger. * * Note: I added an "always" value to the -loose option to force * the manually selected axes to be loose. It's probably * not a good idea. * * maxY * | units = magnitude (of least significant digit) * | high = largest unit tick < max axis value * high _| low = smallest unit tick > min axis value * | * | range = high - low * | # ticks = greatest factor of range/units * _| * U | * n | * i | * t _| * | * | * | * low _| * | * |_minX________________maxX__ * | | | | | * minY low high * minY * * numTicks = Number of ticks * min = Minimum value of axis * max = Maximum value of axis * range = Range of values (max - min) * * Results: * None. * * Side Effects: * The axis tick information is set. The actual tick values will * be generated later. * * ---------------------------------------------------------------------- */ static void LinearScaleAxis(axisPtr, min, max) Axis *axisPtr; double min, max; { double range, step; double tickMin, tickMax; double axisMin, axisMax; int nTicks; range = max - min; /* Calculate the major tick stepping. */ if (axisPtr->reqStep > 0.0) { /* An interval was designated by the user. Keep scaling it * until it fits comfortably within the current range of the * axis. */ step = axisPtr->reqStep; while ((2 * step) >= range) { step *= 0.5; } } else { range = NiceNum(range, 0); step = NiceNum(range / DEF_NUM_TICKS, 1); } /* Find the outer tick values. Add 0.0 to prevent getting -0.0. */ axisMin = tickMin = floor(min / step) * step + 0.0; axisMax = tickMax = ceil(max / step) * step + 0.0; nTicks = Round((tickMax - tickMin) / step) + 1; axisPtr->majorSweep.step = step; axisPtr->majorSweep.initial = tickMin; axisPtr->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 ((axisPtr->looseMin == TICK_RANGE_TIGHT) || ((axisPtr->looseMin == TICK_RANGE_LOOSE) && (DEFINED(axisPtr->reqMin)))) { axisMin = min; } if ((axisPtr->looseMax == TICK_RANGE_TIGHT) || ((axisPtr->looseMax == TICK_RANGE_LOOSE) && (DEFINED(axisPtr->reqMax)))) { axisMax = max; } SetAxisRange(&axisPtr->axisRange, axisMin, axisMax); /* Now calculate the minor tick step and number. */ if ((axisPtr->reqNumMinorTicks > 0) && ((axisPtr->flags & AXIS_CONFIG_MAJOR) == 0)) { nTicks = axisPtr->reqNumMinorTicks - 1; step = 1.0 / (nTicks + 1); } else { nTicks = 0; /* No minor ticks. */ step = 0.5; /* Don't set the minor tick interval * to 0.0. It makes the GenerateTicks * routine create minor log-scale tick * marks. */ } axisPtr->minorSweep.initial = axisPtr->minorSweep.step = step; axisPtr->minorSweep.nSteps = nTicks; } static void SweepTicks(axisPtr) Axis *axisPtr; { if ((axisPtr->flags & AXIS_CONFIG_MAJOR) == 0) { if (axisPtr->t1Ptr != NULL) { Blt_Free(axisPtr->t1Ptr); } axisPtr->t1Ptr = GenerateTicks(&axisPtr->majorSweep); } if ((axisPtr->flags & AXIS_CONFIG_MINOR) == 0) { if (axisPtr->t2Ptr != NULL) { Blt_Free(axisPtr->t2Ptr); } axisPtr->t2Ptr = GenerateTicks(&axisPtr->minorSweep); } } /* * ---------------------------------------------------------------------- * * Blt_ResetAxes -- * * Results: * None. * * ---------------------------------------------------------------------- */ void Blt_ResetAxes(graphPtr) Graph *graphPtr; { Blt_ChainLink *linkPtr; Element *elemPtr; Axis *axisPtr; Blt_HashEntry *hPtr; Blt_HashSearch cursor; Extents2D exts; double min, max; /* 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. */ Blt_InitFreqTable(graphPtr); if ((graphPtr->mode == MODE_STACKED) && (graphPtr->nStacks > 0)) { Blt_ComputeStacks(graphPtr); } /* * Step 1: Reset all axes. Initialize the data limits of the axis to * impossible values. */ for (hPtr = Blt_FirstHashEntry(&graphPtr->axes.table, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { axisPtr = (Axis *)Blt_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 (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { elemPtr = Blt_ChainGetValue(linkPtr); (*elemPtr->procsPtr->extentsProc) (elemPtr, &exts); GetDataLimits(elemPtr->axes.x, exts.left, exts.right); GetDataLimits(elemPtr->axes.y, 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 (hPtr = Blt_FirstHashEntry(&graphPtr->axes.table, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { axisPtr = (Axis *)Blt_GetHashValue(hPtr); FixAxisRange(axisPtr); /* Calculate min/max tick (major/minor) layouts */ min = axisPtr->min; max = axisPtr->max; if ((DEFINED(axisPtr->scrollMin)) && (min < axisPtr->scrollMin)) { min = axisPtr->scrollMin; } if ((DEFINED(axisPtr->scrollMax)) && (max > axisPtr->scrollMax)) { max = axisPtr->scrollMax; } if (axisPtr->logScale) { LogScaleAxis(axisPtr, min, max); } else { LinearScaleAxis(axisPtr, min, max); } if ((axisPtr->flags & (AXIS_DIRTY | AXIS_ONSCREEN)) == (AXIS_DIRTY | AXIS_ONSCREEN)) { graphPtr->flags |= REDRAW_BACKING_STORE; } } graphPtr->flags &= ~RESET_AXES; /* * When any axis changes, we need to layout the entire graph. */ graphPtr->flags |= (GET_AXIS_GEOMETRY | LAYOUT_NEEDED | MAP_ALL | REDRAW_WORLD); } /* * ---------------------------------------------------------------------- * * ResetTextStyles -- * * Configures axis attributes (font, line width, label, etc) and * allocates a new (possibly shared) graphics context. Line cap * style is projecting. This is for the problem of when a tick * sits directly at the end point of the axis. * * Results: * The return value is a standard Tcl result. * * Side Effects: * Axis resources are allocated (GC, font). Axis layout is * deferred until the height and width of the window are known. * * ---------------------------------------------------------------------- */ static void ResetTextStyles(graphPtr, axisPtr) Graph *graphPtr; Axis *axisPtr; { GC newGC; XGCValues gcValues; unsigned long gcMask; Blt_ResetTextStyle(graphPtr->tkwin, &axisPtr->titleTextStyle); Blt_ResetTextStyle(graphPtr->tkwin, &axisPtr->tickTextStyle); Blt_ResetTextStyle(graphPtr->tkwin, &axisPtr->limitsTextStyle); gcMask = (GCForeground | GCLineWidth | GCCapStyle); gcValues.foreground = axisPtr->tickTextStyle.color->pixel; gcValues.line_width = LineWidth(axisPtr->lineWidth); gcValues.cap_style = CapProjecting; newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues); if (axisPtr->tickGC != NULL) { Tk_FreeGC(graphPtr->display, axisPtr->tickGC); } axisPtr->tickGC = newGC; } /* * ---------------------------------------------------------------------- * * DestroyAxis -- * * Results: * None. * * Side effects: * Resources (font, color, gc, labels, etc.) associated with the * axis are deallocated. * * ---------------------------------------------------------------------- */ static void DestroyAxis(graphPtr, axisPtr) Graph *graphPtr; Axis *axisPtr; { int flags; flags = Blt_GraphType(graphPtr); Tk_FreeOptions(configSpecs, (char *)axisPtr, graphPtr->display, flags); if (graphPtr->bindTable != NULL) { Blt_DeleteBindings(graphPtr->bindTable, axisPtr); } if (axisPtr->linkPtr != NULL) { Blt_ChainDeleteLink(axisPtr->chainPtr, axisPtr->linkPtr); } if (axisPtr->name != NULL) { Blt_Free(axisPtr->name); } if (axisPtr->hashPtr != NULL) { Blt_DeleteHashEntry(&graphPtr->axes.table, axisPtr->hashPtr); } Blt_FreeTextStyle(graphPtr->display, &axisPtr->titleTextStyle); Blt_FreeTextStyle(graphPtr->display, &axisPtr->limitsTextStyle); Blt_FreeTextStyle(graphPtr->display, &axisPtr->tickTextStyle); if (axisPtr->tickGC != NULL) { Tk_FreeGC(graphPtr->display, axisPtr->tickGC); } if (axisPtr->t1Ptr != NULL) { Blt_Free(axisPtr->t1Ptr); } if (axisPtr->t2Ptr != NULL) { Blt_Free(axisPtr->t2Ptr); } if (axisPtr->limitsFormats != NULL) { Blt_Free(axisPtr->limitsFormats); } FreeLabels(axisPtr->tickLabels); Blt_ChainDestroy(axisPtr->tickLabels); if (axisPtr->segments != NULL) { Blt_Free(axisPtr->segments); } if (axisPtr->tags != NULL) { Blt_Free(axisPtr->tags); } Blt_Free(axisPtr); } static double titleRotate[4] = /* Rotation for each axis title */ { 0.0, 90.0, 0.0, 270.0 }; /* * ---------------------------------------------------------------------- * * AxisOffsets -- * * Determines the sites of the axis, major and minor ticks, * and title of the axis. * * Results: * None. * * ---------------------------------------------------------------------- */ static void AxisOffsets(graphPtr, axisPtr, margin, axisOffset, infoPtr) Graph *graphPtr; Axis *axisPtr; int margin; int axisOffset; AxisInfo *infoPtr; { int pad; /* Offset of axis from interior region. This * includes a possible border and the axis * line width. */ int p; int majorOffset, minorOffset, labelOffset; int offset; int x, y; axisPtr->titleTextStyle.theta = titleRotate[margin]; majorOffset = minorOffset = 0; labelOffset = AXIS_TITLE_PAD; if (axisPtr->lineWidth > 0) { majorOffset = ABS(axisPtr->tickLength); minorOffset = 10 * majorOffset / 15; labelOffset = majorOffset + AXIS_TITLE_PAD + axisPtr->lineWidth / 2; } /* Adjust offset for the interior border width and the line width */ pad = axisPtr->lineWidth + 1; if (graphPtr->plotBorderWidth > 0) { pad += graphPtr->plotBorderWidth + 1; } offset = axisOffset + 1 + pad; if ((margin == MARGIN_LEFT) || (margin == MARGIN_TOP)) { majorOffset = -majorOffset; minorOffset = -minorOffset; labelOffset = -labelOffset; } /* * Pre-calculate the x-coordinate positions of the axis, tick labels, and * the individual major and minor ticks. */ p = 0; /* Suppress compiler warning */ switch (margin) { case MARGIN_TOP: p = graphPtr->top - axisOffset - pad; if (axisPtr->titleAlternate) { x = graphPtr->right + AXIS_TITLE_PAD; y = graphPtr->top - axisOffset - (axisPtr->height / 2); axisPtr->titleTextStyle.anchor = TK_ANCHOR_W; } else { x = (graphPtr->right + graphPtr->left) / 2; y = graphPtr->top - axisOffset - axisPtr->height - AXIS_TITLE_PAD; axisPtr->titleTextStyle.anchor = TK_ANCHOR_N; } axisPtr->tickTextStyle.anchor = TK_ANCHOR_S; offset = axisPtr->borderWidth + axisPtr->lineWidth / 2; axisPtr->region.left = graphPtr->hOffset - offset - 2; axisPtr->region.right = graphPtr->hOffset + graphPtr->hRange + offset - 1; axisPtr->region.top = p + labelOffset - 1; axisPtr->region.bottom = p; axisPtr->titlePos.x = x; axisPtr->titlePos.y = y; break; case MARGIN_BOTTOM: p = graphPtr->bottom + axisOffset + pad; if (axisPtr->titleAlternate) { x = graphPtr->right + AXIS_TITLE_PAD; y = graphPtr->bottom + axisOffset + (axisPtr->height / 2); axisPtr->titleTextStyle.anchor = TK_ANCHOR_W; } else { x = (graphPtr->right + graphPtr->left) / 2; y = graphPtr->bottom + axisOffset + axisPtr->height + AXIS_TITLE_PAD; axisPtr->titleTextStyle.anchor = TK_ANCHOR_S; } axisPtr->tickTextStyle.anchor = TK_ANCHOR_N; offset = axisPtr->borderWidth + axisPtr->lineWidth / 2; axisPtr->region.left = graphPtr->hOffset - offset - 2; axisPtr->region.right = graphPtr->hOffset + graphPtr->hRange + offset - 1; axisPtr->region.top = graphPtr->bottom + axisOffset + axisPtr->lineWidth - axisPtr->lineWidth / 2; axisPtr->region.bottom = graphPtr->bottom + axisOffset + axisPtr->lineWidth + labelOffset + 1; axisPtr->titlePos.x = x; axisPtr->titlePos.y = y; break; case MARGIN_LEFT: p = graphPtr->left - axisOffset - pad; if (axisPtr->titleAlternate) { x = graphPtr->left - axisOffset - (axisPtr->width / 2); y = graphPtr->top - AXIS_TITLE_PAD; axisPtr->titleTextStyle.anchor = TK_ANCHOR_SW; } else { x = graphPtr->left - axisOffset - axisPtr->width - graphPtr->plotBorderWidth; y = (graphPtr->bottom + graphPtr->top) / 2; axisPtr->titleTextStyle.anchor = TK_ANCHOR_W; } axisPtr->tickTextStyle.anchor = TK_ANCHOR_E; axisPtr->region.left = graphPtr->left - offset + labelOffset - 1; axisPtr->region.right = graphPtr->left - offset + 2; offset = axisPtr->borderWidth + axisPtr->lineWidth / 2; axisPtr->region.top = graphPtr->vOffset - offset - 2; axisPtr->region.bottom = graphPtr->vOffset + graphPtr->vRange + offset - 1; axisPtr->titlePos.x = x; axisPtr->titlePos.y = y; break; case MARGIN_RIGHT: p = graphPtr->right + axisOffset + pad; if (axisPtr->titleAlternate) { x = graphPtr->right + axisOffset + (axisPtr->width / 2); y = graphPtr->top - AXIS_TITLE_PAD; axisPtr->titleTextStyle.anchor = TK_ANCHOR_SE; } else { x = graphPtr->right + axisOffset + axisPtr->width + AXIS_TITLE_PAD; y = (graphPtr->bottom + graphPtr->top) / 2; axisPtr->titleTextStyle.anchor = TK_ANCHOR_E; } axisPtr->tickTextStyle.anchor = TK_ANCHOR_W; axisPtr->region.left = graphPtr->right + axisOffset + axisPtr->lineWidth - axisPtr->lineWidth / 2; axisPtr->region.right = graphPtr->right + axisOffset + labelOffset + axisPtr->lineWidth + 1; offset = axisPtr->borderWidth + axisPtr->lineWidth / 2; axisPtr->region.top = graphPtr->vOffset - offset - 2; axisPtr->region.bottom = graphPtr->vOffset + graphPtr->vRange + offset - 1; axisPtr->titlePos.x = x; axisPtr->titlePos.y = y; break; case MARGIN_NONE: break; } infoPtr->axis = p - (axisPtr->lineWidth / 2); infoPtr->t1 = p + majorOffset; infoPtr->t2 = p + minorOffset; infoPtr->label = p + labelOffset; if (axisPtr->tickLength < 0) { int hold; hold = infoPtr->t1; infoPtr->t1 = infoPtr->axis; infoPtr->axis = hold; } } static void MakeAxisLine(graphPtr, axisPtr, line, segPtr) Graph *graphPtr; Axis *axisPtr; /* Axis information */ int line; Segment2D *segPtr; { double min, max; min = axisPtr->axisRange.min; max = axisPtr->axisRange.max; if (axisPtr->logScale) { min = EXP10(min); max = EXP10(max); } if (AxisIsHorizontal(graphPtr, axisPtr)) { segPtr->p.x = Blt_HMap(graphPtr, axisPtr, min); segPtr->q.x = Blt_HMap(graphPtr, axisPtr, max); segPtr->p.y = segPtr->q.y = line; } else { segPtr->q.x = segPtr->p.x = line; segPtr->p.y = Blt_VMap(graphPtr, axisPtr, min); segPtr->q.y = Blt_VMap(graphPtr, axisPtr, max); } } static void MakeTick(graphPtr, axisPtr, value, tick, line, segPtr) Graph *graphPtr; Axis *axisPtr; double value; int tick, line; /* Lengths of tick and axis line. */ Segment2D *segPtr; { if (axisPtr->logScale) { value = EXP10(value); } if (AxisIsHorizontal(graphPtr, axisPtr)) { segPtr->p.x = segPtr->q.x = Blt_HMap(graphPtr, axisPtr, value); segPtr->p.y = line; segPtr->q.y = tick; } else { segPtr->p.x = line; segPtr->p.y = segPtr->q.y = Blt_VMap(graphPtr, axisPtr, value); segPtr->q.x = tick; } } /* * ----------------------------------------------------------------- * * MapAxis -- * * Pre-calculates positions of the axis, ticks, and labels (to be * used later when displaying the axis). Calculates the values * for each major and minor tick and checks to see if they are in * range (the outer ticks may be outside of the range of plotted * values). * * Line segments for the minor and major ticks are saved into one * XSegment array so that they can be drawn by a single * XDrawSegments call. The positions of the tick labels are also * computed and saved. * * Results: * None. * * Side Effects: * Line segments and tick labels are saved and used later to draw * the axis. * * ----------------------------------------------------------------- */ static void MapAxis(graphPtr, axisPtr, offset, margin) Graph *graphPtr; Axis *axisPtr; int offset; int margin; { int arraySize; int nMajorTicks, nMinorTicks; AxisInfo info; Segment2D *segments; Segment2D *segPtr; AxisOffsets(graphPtr, axisPtr, margin, offset, &info); /* Save all line coordinates in an array of line segments. */ if (axisPtr->segments != NULL) { Blt_Free(axisPtr->segments); } nMajorTicks = nMinorTicks = 0; if (axisPtr->t1Ptr != NULL) { nMajorTicks = axisPtr->t1Ptr->nTicks; } if (axisPtr->t2Ptr != NULL) { nMinorTicks = axisPtr->t2Ptr->nTicks; } arraySize = 1 + (nMajorTicks * (nMinorTicks + 1)); segments = Blt_Malloc(arraySize * sizeof(Segment2D)); assert(segments); segPtr = segments; if (axisPtr->lineWidth > 0) { /* Axis baseline */ MakeAxisLine(graphPtr, axisPtr, info.axis, segPtr); segPtr++; } if (axisPtr->showTicks) { double t1, t2; double labelPos; register int i, j; int isHoriz; TickLabel *labelPtr; Blt_ChainLink *linkPtr; Segment2D seg; isHoriz = AxisIsHorizontal(graphPtr, axisPtr); for (i = 0; i < axisPtr->t1Ptr->nTicks; i++) { t1 = axisPtr->t1Ptr->values[i]; /* Minor ticks */ for (j = 0; j < axisPtr->t2Ptr->nTicks; j++) { t2 = t1 + (axisPtr->majorSweep.step * axisPtr->t2Ptr->values[j]); if (InRange(t2, &axisPtr->axisRange)) { MakeTick(graphPtr, axisPtr, t2, info.t2, info.axis, segPtr); segPtr++; } } if (!InRange(t1, &axisPtr->axisRange)) { continue; } /* Major tick */ MakeTick(graphPtr, axisPtr, t1, info.t1, info.axis, segPtr); segPtr++; } linkPtr = Blt_ChainFirstLink(axisPtr->tickLabels); labelPos = (double)info.label; for (i = 0; i < axisPtr->t1Ptr->nTicks; i++) { t1 = axisPtr->t1Ptr->values[i]; if (axisPtr->labelOffset) { t1 += axisPtr->majorSweep.step * 0.5; } if (!InRange(t1, &axisPtr->axisRange)) { continue; } labelPtr = Blt_ChainGetValue(linkPtr); linkPtr = Blt_ChainNextLink(linkPtr); MakeTick(graphPtr, axisPtr, t1, info.t1, info.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; } } } if (AxisIsHorizontal(graphPtr, axisPtr)) { axisPtr->width = graphPtr->right - graphPtr->left; } else { axisPtr->height = graphPtr->bottom - graphPtr->top; } axisPtr->segments = segments; axisPtr->nSegments = segPtr - segments; assert(axisPtr->nSegments <= arraySize); } /* *---------------------------------------------------------------------- * * AdjustViewport -- * * Adjusts the offsets of the viewport according to the scroll mode. * This is to accommodate both "listbox" and "canvas" style scrolling. * * "canvas" The viewport scrolls within the range of world * coordinates. This way the viewport always displays * a full page of the world. If the world is smaller * than the viewport, then (bizarrely) the world and * viewport are inverted so that the world moves up * and down within the viewport. * * "listbox" The viewport can scroll beyond the range of world * coordinates. Every entry can be displayed at the * top of the viewport. This also means that the * scrollbar thumb weirdly shrinks as the last entry * is scrolled upward. * * Results: * The corrected offset is returned. * *---------------------------------------------------------------------- */ static double AdjustViewport(offset, windowSize) double offset, 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(interp, argc, argv, offsetPtr, windowSize, scrollUnits) Tcl_Interp *interp; int argc; char **argv; double *offsetPtr; double windowSize; double scrollUnits; { char c; unsigned int length; double offset; int count; double fract; offset = *offsetPtr; c = argv[0][0]; length = strlen(argv[0]); if ((c == 's') && (strncmp(argv[0], "scroll", length) == 0)) { assert(argc == 3); /* scroll number unit/page */ if (Tcl_GetInt(interp, argv[1], &count) != TCL_OK) { return TCL_ERROR; } c = argv[2][0]; length = strlen(argv[2]); if ((c == 'u') && (strncmp(argv[2], "units", length) == 0)) { fract = (double)count * scrollUnits; } else if ((c == 'p') && (strncmp(argv[2], "pages", length) == 0)) { /* A page is 90% of the view-able window. */ fract = (double)count * windowSize * 0.9; } else { Tcl_AppendResult(interp, "unknown \"scroll\" units \"", argv[2], "\"", (char *)NULL); return TCL_ERROR; } offset += fract; } else if ((c == 'm') && (strncmp(argv[0], "moveto", length) == 0)) { assert(argc == 2); /* moveto fraction */ if (Tcl_GetDouble(interp, argv[1], &fract) != TCL_OK) { return TCL_ERROR; } offset = fract; } else { /* Treat like "scroll units" */ if (Tcl_GetInt(interp, argv[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; } /* * ----------------------------------------------------------------- * * DrawAxis -- * * Draws the axis, ticks, and labels onto the canvas. * * Initializes and passes text attribute information through * TextStyle structure. * * Results: * None. * * Side Effects: * Axis gets drawn on window. * * ----------------------------------------------------------------- */ static void DrawAxis(graphPtr, drawable, axisPtr) Graph *graphPtr; Drawable drawable; Axis *axisPtr; { if (axisPtr->border != NULL) { Blt_Fill3DRectangle(graphPtr->tkwin, drawable, axisPtr->border, axisPtr->region.left + graphPtr->plotBorderWidth, axisPtr->region.top + graphPtr->plotBorderWidth, axisPtr->region.right - axisPtr->region.left, axisPtr->region.bottom - axisPtr->region.top, axisPtr->borderWidth, axisPtr->relief); } if (axisPtr->title != NULL) { Blt_DrawText(graphPtr->tkwin, drawable, axisPtr->title, &axisPtr->titleTextStyle, (int)axisPtr->titlePos.x, (int)axisPtr->titlePos.y); } if (axisPtr->scrollCmdPrefix != NULL) { double viewWidth, viewMin, viewMax; double worldWidth, worldMin, worldMax; double fract; int isHoriz; worldMin = axisPtr->valueRange.min; worldMax = axisPtr->valueRange.max; if (DEFINED(axisPtr->scrollMin)) { worldMin = axisPtr->scrollMin; } if (DEFINED(axisPtr->scrollMax)) { worldMax = axisPtr->scrollMax; } viewMin = axisPtr->min; viewMax = axisPtr->max; if (viewMin < worldMin) { viewMin = worldMin; } if (viewMax > worldMax) { viewMax = worldMax; } if (axisPtr->logScale) { worldMin = log10(worldMin); worldMax = log10(worldMax); viewMin = log10(viewMin); viewMax = log10(viewMax); } worldWidth = worldMax - worldMin; viewWidth = viewMax - viewMin; isHoriz = AxisIsHorizontal(graphPtr, axisPtr); if (isHoriz != axisPtr->descending) { fract = (viewMin - worldMin) / worldWidth; } else { fract = (worldMax - viewMax) / worldWidth; } fract = AdjustViewport(fract, viewWidth / worldWidth); if (isHoriz != axisPtr->descending) { viewMin = (fract * worldWidth); axisPtr->min = viewMin + worldMin; axisPtr->max = axisPtr->min + viewWidth; viewMax = viewMin + viewWidth; if (axisPtr->logScale) { axisPtr->min = EXP10(axisPtr->min); axisPtr->max = EXP10(axisPtr->max); } Blt_UpdateScrollbar(graphPtr->interp, axisPtr->scrollCmdPrefix, (viewMin / worldWidth), (viewMax / worldWidth)); } else { viewMax = (fract * worldWidth); axisPtr->max = worldMax - viewMax; axisPtr->min = axisPtr->max - viewWidth; viewMin = viewMax + viewWidth; if (axisPtr->logScale) { axisPtr->min = EXP10(axisPtr->min); axisPtr->max = EXP10(axisPtr->max); } Blt_UpdateScrollbar(graphPtr->interp, axisPtr->scrollCmdPrefix, (viewMax / worldWidth), (viewMin / worldWidth)); } } if (axisPtr->showTicks) { register Blt_ChainLink *linkPtr; TickLabel *labelPtr; for (linkPtr = Blt_ChainFirstLink(axisPtr->tickLabels); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { /* Draw major tick labels */ labelPtr = Blt_ChainGetValue(linkPtr); Blt_DrawText(graphPtr->tkwin, drawable, labelPtr->string, &axisPtr->tickTextStyle, (int)labelPtr->anchorPos.x, (int)labelPtr->anchorPos.y); } } if ((axisPtr->nSegments > 0) && (axisPtr->lineWidth > 0)) { /* Draw the tick marks and axis line. */ Blt_Draw2DSegments(graphPtr->display, drawable, axisPtr->tickGC, axisPtr->segments, axisPtr->nSegments); } } /* * ----------------------------------------------------------------- * * AxisToPostScript -- * * Generates PostScript output to draw the axis, ticks, and * labels. * * Initializes and passes text attribute information through * TextStyle structure. * * Results: * None. * * Side Effects: * PostScript output is left in graphPtr->interp->result; * * ----------------------------------------------------------------- */ /* ARGSUSED */ static void AxisToPostScript(psToken, axisPtr) PsToken psToken; Axis *axisPtr; { if (axisPtr->title != NULL) { Blt_TextToPostScript(psToken, axisPtr->title, &axisPtr->titleTextStyle, axisPtr->titlePos.x, axisPtr->titlePos.y); } if (axisPtr->showTicks) { register Blt_ChainLink *linkPtr; TickLabel *labelPtr; for (linkPtr = Blt_ChainFirstLink(axisPtr->tickLabels); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { labelPtr = Blt_ChainGetValue(linkPtr); Blt_TextToPostScript(psToken, labelPtr->string, &axisPtr->tickTextStyle, labelPtr->anchorPos.x, labelPtr->anchorPos.y); } } if ((axisPtr->nSegments > 0) && (axisPtr->lineWidth > 0)) { Blt_LineAttributesToPostScript(psToken, axisPtr->tickTextStyle.color, axisPtr->lineWidth, (Blt_Dashes *)NULL, CapButt, JoinMiter); Blt_2DSegmentsToPostScript(psToken, axisPtr->segments, axisPtr->nSegments); } } static void MakeGridLine(graphPtr, axisPtr, value, segPtr) Graph *graphPtr; Axis *axisPtr; double value; Segment2D *segPtr; { if (axisPtr->logScale) { value = EXP10(value); } /* Grid lines run orthogonally to the axis */ if (AxisIsHorizontal(graphPtr, axisPtr)) { segPtr->p.y = graphPtr->top; segPtr->q.y = graphPtr->bottom; segPtr->p.x = segPtr->q.x = Blt_HMap(graphPtr, axisPtr, value); } else { segPtr->p.x = graphPtr->left; segPtr->q.x = graphPtr->right; segPtr->p.y = segPtr->q.y = Blt_VMap(graphPtr, axisPtr, value); } } /* *---------------------------------------------------------------------- * * Blt_GetAxisSegments -- * * Assembles the grid lines associated with an axis. Generates * tick positions if necessary (this happens when the axis is * not a logical axis too). * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_GetAxisSegments(graphPtr, axisPtr, segPtrPtr, nSegmentsPtr) Graph *graphPtr; Axis *axisPtr; Segment2D **segPtrPtr; int *nSegmentsPtr; { int needed; Ticks *t1Ptr, *t2Ptr; register int i; double value; Segment2D *segments, *segPtr; *nSegmentsPtr = 0; *segPtrPtr = NULL; if (axisPtr == NULL) { return; } t1Ptr = axisPtr->t1Ptr; if (t1Ptr == NULL) { t1Ptr = GenerateTicks(&axisPtr->majorSweep); } t2Ptr = axisPtr->t2Ptr; if (t2Ptr == NULL) { t2Ptr = GenerateTicks(&axisPtr->minorSweep); } needed = t1Ptr->nTicks; if (graphPtr->gridPtr->minorGrid) { needed += (t1Ptr->nTicks * t2Ptr->nTicks); } if (needed == 0) { return; } segments = Blt_Malloc(sizeof(Segment2D) * needed); if (segments == NULL) { return; /* Can't allocate memory for grid. */ } segPtr = segments; for (i = 0; i < t1Ptr->nTicks; i++) { value = t1Ptr->values[i]; if (graphPtr->gridPtr->minorGrid) { register int j; double subValue; for (j = 0; j < t2Ptr->nTicks; j++) { subValue = value + (axisPtr->majorSweep.step * t2Ptr->values[j]); if (InRange(subValue, &axisPtr->axisRange)) { MakeGridLine(graphPtr, axisPtr, subValue, segPtr); segPtr++; } } } if (InRange(value, &axisPtr->axisRange)) { MakeGridLine(graphPtr, axisPtr, value, segPtr); segPtr++; } } if (t1Ptr != axisPtr->t1Ptr) { Blt_Free(t1Ptr); /* Free generated ticks. */ } if (t2Ptr != axisPtr->t2Ptr) { Blt_Free(t2Ptr); /* Free generated ticks. */ } *nSegmentsPtr = segPtr - segments; assert(*nSegmentsPtr <= needed); *segPtrPtr = segments; } /* *---------------------------------------------------------------------- * * GetAxisGeometry -- * * Results: * None. * *---------------------------------------------------------------------- */ static void GetAxisGeometry(graphPtr, axisPtr) Graph *graphPtr; Axis *axisPtr; { int height; FreeLabels(axisPtr->tickLabels); height = 0; if (axisPtr->lineWidth > 0) { /* Leave room for axis baseline (and pad) */ height += axisPtr->lineWidth + 2; } if (axisPtr->showTicks) { int pad; register int i, nLabels; int lw, lh; double x, x2; int maxWidth, maxHeight; TickLabel *labelPtr; SweepTicks(axisPtr); if (axisPtr->t1Ptr->nTicks < 0) { fprintf(stderr, "%s major ticks can't be %d\n", axisPtr->name, axisPtr->t1Ptr->nTicks); abort(); } if (axisPtr->t1Ptr->nTicks > MAXTICKS) { fprintf(stderr, "too big, %s major ticks can't be %d\n", axisPtr->name, axisPtr->t1Ptr->nTicks); abort(); } maxHeight = maxWidth = 0; nLabels = 0; for (i = 0; i < axisPtr->t1Ptr->nTicks; i++) { x2 = x = axisPtr->t1Ptr->values[i]; if (axisPtr->labelOffset) { x2 += axisPtr->majorSweep.step * 0.5; } if (!InRange(x2, &axisPtr->axisRange)) { continue; } labelPtr = MakeLabel(graphPtr, axisPtr, x); Blt_ChainAppend(axisPtr->tickLabels, labelPtr); nLabels++; /* * Get the dimensions of each tick label. * Remember tick labels can be multi-lined and/or rotated. */ Blt_GetTextExtents(&axisPtr->tickTextStyle, labelPtr->string, &lw, &lh); labelPtr->width = lw; labelPtr->height = lh; if (axisPtr->tickTextStyle.theta > 0.0) { double rotWidth, rotHeight; Blt_GetBoundingBox(lw, lh, axisPtr->tickTextStyle.theta, &rotWidth, &rotHeight, (Point2D *)NULL); lw = ROUND(rotWidth); lh = ROUND(rotHeight); } if (maxWidth < lw) { maxWidth = lw; } if (maxHeight < lh) { maxHeight = lh; } } assert(nLabels <= axisPtr->t1Ptr->nTicks); /* Because the axis cap style is "CapProjecting", we need to * account for an extra 1.5 linewidth at the end of each * line. */ pad = ((axisPtr->lineWidth * 15) / 10); if (AxisIsHorizontal(graphPtr, axisPtr)) { height += maxHeight + pad; } else { height += maxWidth + pad; } if (axisPtr->lineWidth > 0) { /* Distance from axis line to tick label. */ height += AXIS_TITLE_PAD; height += ABS(axisPtr->tickLength); } } if (axisPtr->title != NULL) { if (axisPtr->titleAlternate) { if (height < axisPtr->titleHeight) { height = axisPtr->titleHeight; } } else { height += axisPtr->titleHeight + AXIS_TITLE_PAD; } } /* Correct for orientation of the axis. */ if (AxisIsHorizontal(graphPtr, axisPtr)) { axisPtr->height = height; } else { axisPtr->width = height; } } /* *---------------------------------------------------------------------- * * GetMarginGeometry -- * * Examines all the axes in the given margin and determines the * area required to display them. * * Note: For multiple axes, the titles are displayed in another * margin. So we must keep track of the widest title. * * Results: * Returns the width or height of the margin, depending if it * runs horizontally along the graph or vertically. * * Side Effects: * The area width and height set in the margin. Note again that * this may be corrected later (mulitple axes) to adjust for * the longest title in another margin. * *---------------------------------------------------------------------- */ static int GetMarginGeometry(graphPtr, marginPtr) Graph *graphPtr; Margin *marginPtr; { Blt_ChainLink *linkPtr; Axis *axisPtr; int width, height; int isHoriz; int length, count; isHoriz = HORIZMARGIN(marginPtr); /* Count the number of visible axes. */ count = 0; length = width = height = 0; for (linkPtr = Blt_ChainFirstLink(marginPtr->axes); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { axisPtr = Blt_ChainGetValue(linkPtr); if ((!axisPtr->hidden) && (axisPtr->flags & AXIS_ONSCREEN)) { count++; if (graphPtr->flags & GET_AXIS_GEOMETRY) { GetAxisGeometry(graphPtr, axisPtr); } if ((axisPtr->titleAlternate) && (length < axisPtr->titleWidth)) { length = axisPtr->titleWidth; } if (isHoriz) { height += axisPtr->height; } else { width += axisPtr->width; } } } /* Enforce a minimum size for margins. */ if (width < 3) { width = 3; } if (height < 3) { height = 3; } marginPtr->nAxes = count; marginPtr->axesTitleLength = length; marginPtr->width = width; marginPtr->height = height; marginPtr->axesOffset = (HORIZMARGIN(marginPtr)) ? height : width; return marginPtr->axesOffset; } /* *---------------------------------------------------------------------- * * ComputeMargins -- * * Computes the size of the margins and the plotting area. We * first compute the space needed for the axes in each margin. * Then how much space the legend will occupy. Finally, if the * user has requested a margin size, we override the computed * value. * * Results: * *---------------------------------------------------------------------- */ static void ComputeMargins(graphPtr) Graph *graphPtr; { int left, right, top, bottom; int width, height; int insets; /* * Step 1: Compute the amount of space needed to display the * axes (there many be 0 or more) associated with the * margin. */ top = GetMarginGeometry(graphPtr, &graphPtr->topMargin); bottom = GetMarginGeometry(graphPtr, &graphPtr->bottomMargin); left = GetMarginGeometry(graphPtr, &graphPtr->leftMargin); right = GetMarginGeometry(graphPtr, &graphPtr->rightMargin); /* * Step 2: Add the graph title height to the top margin. */ if (graphPtr->title != NULL) { top += graphPtr->titleTextStyle.height; } insets = 2 * (graphPtr->inset + graphPtr->plotBorderWidth); /* * Step 3: Use the current estimate of the plot area to compute * the legend size. Add it to the proper margin. */ width = graphPtr->width - (insets + left + right); height = graphPtr->height - (insets + top + bottom); Blt_MapLegend(graphPtr->legend, width, height); if (!Blt_LegendIsHidden(graphPtr->legend)) { switch (Blt_LegendSite(graphPtr->legend)) { case LEGEND_RIGHT: right += Blt_LegendWidth(graphPtr->legend) + 2; break; case LEGEND_LEFT: left += Blt_LegendWidth(graphPtr->legend) + 2; break; case LEGEND_TOP: top += Blt_LegendHeight(graphPtr->legend) + 2; break; case LEGEND_BOTTOM: bottom += Blt_LegendHeight(graphPtr->legend) + 2; break; case LEGEND_XY: case LEGEND_PLOT: case LEGEND_WINDOW: /* Do nothing. */ break; } } /* * Recompute the plotarea, now accounting for the legend. */ width = graphPtr->width - (insets + left + right); height = graphPtr->height - (insets + top + bottom); /* * Step 5: If necessary, correct for the requested plot area * aspect ratio. */ if (graphPtr->aspect > 0.0) { double ratio; /* * Shrink one dimension of the plotarea to fit the requested * width/height aspect ratio. */ ratio = (double)width / (double)height; if (ratio > graphPtr->aspect) { int scaledWidth; /* Shrink the width. */ scaledWidth = (int)(height * graphPtr->aspect); if (scaledWidth < 1) { scaledWidth = 1; } right += (width - scaledWidth); /* Add the difference to * the right margin. */ /* CHECK THIS: width = scaledWidth; */ } else { int scaledHeight; /* Shrink the height. */ scaledHeight = (int)(width / graphPtr->aspect); if (scaledHeight < 1) { scaledHeight = 1; } top += (height - scaledHeight); /* Add the difference to * the top margin. */ /* CHECK THIS: height = scaledHeight; */ } } /* * Step 6: If there's multiple axes in a margin, the axis * titles will be displayed in the adjoining marging. * Make sure there's room for the longest axis titles. */ if (top < graphPtr->leftMargin.axesTitleLength) { top = graphPtr->leftMargin.axesTitleLength; } if (right < graphPtr->bottomMargin.axesTitleLength) { right = graphPtr->bottomMargin.axesTitleLength; } if (top < graphPtr->rightMargin.axesTitleLength) { top = graphPtr->rightMargin.axesTitleLength; } if (right < graphPtr->topMargin.axesTitleLength) { right = graphPtr->topMargin.axesTitleLength; } /* * Step 7: Override calculated values with requested margin * sizes. */ graphPtr->leftMargin.width = left; graphPtr->rightMargin.width = right; graphPtr->topMargin.height = top; graphPtr->bottomMargin.height = bottom; if (graphPtr->leftMargin.reqSize > 0) { graphPtr->leftMargin.width = graphPtr->leftMargin.reqSize; } if (graphPtr->rightMargin.reqSize > 0) { graphPtr->rightMargin.width = graphPtr->rightMargin.reqSize; } if (graphPtr->topMargin.reqSize > 0) { graphPtr->topMargin.height = graphPtr->topMargin.reqSize; } if (graphPtr->bottomMargin.reqSize > 0) { graphPtr->bottomMargin.height = graphPtr->bottomMargin.reqSize; } } /* * ----------------------------------------------------------------- * * Blt_LayoutMargins -- * * 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. * * * ----------------------------------------------------------------- */ void Blt_LayoutMargins(graphPtr) Graph *graphPtr; { int width, height; int titleY; int left, right, top, bottom; ComputeMargins(graphPtr); left = graphPtr->leftMargin.width + graphPtr->inset + graphPtr->plotBorderWidth; right = graphPtr->rightMargin.width + graphPtr->inset + graphPtr->plotBorderWidth; top = graphPtr->topMargin.height + graphPtr->inset + graphPtr->plotBorderWidth; bottom = graphPtr->bottomMargin.height + graphPtr->inset + graphPtr->plotBorderWidth; /* Based upon the margins, calculate the space left for the graph. */ width = graphPtr->width - (left + right); height = graphPtr->height - (top + bottom); if (width < 1) { width = 1; } if (height < 1) { height = 1; } graphPtr->left = left; graphPtr->right = left + width; graphPtr->bottom = top + height; graphPtr->top = top; graphPtr->vOffset = top + graphPtr->padTop; graphPtr->vRange = height - PADDING(graphPtr->padY); graphPtr->hOffset = left + graphPtr->padLeft; graphPtr->hRange = width - PADDING(graphPtr->padX); if (graphPtr->vRange < 1) { graphPtr->vRange = 1; } if (graphPtr->hRange < 1) { graphPtr->hRange = 1; } graphPtr->hScale = 1.0 / (double)graphPtr->hRange; graphPtr->vScale = 1.0 / (double)graphPtr->vRange; /* * Calculate the placement of the graph title so it is centered within the * space provided for it in the top margin */ titleY = graphPtr->titleTextStyle.height; graphPtr->titleY = (titleY / 2) + graphPtr->inset; graphPtr->titleX = (graphPtr->right + graphPtr->left) / 2; } /* * ---------------------------------------------------------------------- * * ConfigureAxis -- * * Configures axis attributes (font, line width, label, etc). * * Results: * The return value is a standard Tcl result. * * Side Effects: * Axis layout is deferred until the height and width of the * window are known. * * ---------------------------------------------------------------------- */ static int ConfigureAxis(graphPtr, axisPtr) Graph *graphPtr; Axis *axisPtr; { char errMsg[200]; /* Check the requested axis limits. Can't allow -min to be greater * than -max, or have undefined log scale limits. */ if (((DEFINED(axisPtr->reqMin)) && (DEFINED(axisPtr->reqMax))) && (axisPtr->reqMin >= axisPtr->reqMax)) { sprintf(errMsg, "impossible limits (min %g >= max %g) for axis \"%s\"", axisPtr->reqMin, axisPtr->reqMax, axisPtr->name); Tcl_AppendResult(graphPtr->interp, errMsg, (char *)NULL); /* Bad values, turn on axis auto-scaling */ axisPtr->reqMin = axisPtr->reqMax = VALUE_UNDEFINED; return TCL_ERROR; } if ((axisPtr->logScale) && (DEFINED(axisPtr->reqMin)) && (axisPtr->reqMin <= 0.0)) { sprintf(errMsg, "bad logscale limits (min=%g,max=%g) for axis \"%s\"", axisPtr->reqMin, axisPtr->reqMax, axisPtr->name); Tcl_AppendResult(graphPtr->interp, errMsg, (char *)NULL); /* Bad minimum value, turn on auto-scaling */ axisPtr->reqMin = VALUE_UNDEFINED; return TCL_ERROR; } axisPtr->tickTextStyle.theta = FMOD(axisPtr->tickTextStyle.theta, 360.0); if (axisPtr->tickTextStyle.theta < 0.0) { axisPtr->tickTextStyle.theta += 360.0; } ResetTextStyles(graphPtr, axisPtr); axisPtr->titleWidth = axisPtr->titleHeight = 0; if (axisPtr->title != NULL) { int w, h; Blt_GetTextExtents(&axisPtr->titleTextStyle, axisPtr->title, &w, &h); axisPtr->titleWidth = (short int)w; axisPtr->titleHeight = (short int)h; } /* * Don't bother to check what configuration options have changed. * Almost every option changes the size of the plotting area * (except for -color and -titlecolor), requiring the graph and * its contents to be completely redrawn. * * Recompute the scale and offset of the axis in case -min, -max * options have changed. */ graphPtr->flags |= REDRAW_WORLD; if (!Blt_ConfigModified(configSpecs, "-*color", "-background", "-bg", (char *)NULL)) { graphPtr->flags |= (MAP_WORLD | RESET_AXES); axisPtr->flags |= AXIS_DIRTY; } Blt_EventuallyRedrawGraph(graphPtr); return TCL_OK; } /* * ---------------------------------------------------------------------- * * CreateAxis -- * * Create and initialize a structure containing information to * display a graph axis. * * Results: * The return value is a standard Tcl result. * * ---------------------------------------------------------------------- */ static Axis * CreateAxis(graphPtr, name, margin) Graph *graphPtr; char *name; /* Identifier for axis. */ int margin; { Axis *axisPtr; Blt_HashEntry *hPtr; int isNew; if (name[0] == '-') { Tcl_AppendResult(graphPtr->interp, "name of axis \"", name, "\" can't start with a '-'", (char *)NULL); return NULL; } hPtr = Blt_CreateHashEntry(&graphPtr->axes.table, name, &isNew); if (!isNew) { axisPtr = (Axis *)Blt_GetHashValue(hPtr); if (!axisPtr->deletePending) { Tcl_AppendResult(graphPtr->interp, "axis \"", name, "\" already exists in \"", Tk_PathName(graphPtr->tkwin), "\"", (char *)NULL); return NULL; } axisPtr->deletePending = FALSE; } else { axisPtr = Blt_Calloc(1, sizeof(Axis)); assert(axisPtr); axisPtr->name = Blt_Strdup(name); axisPtr->hashPtr = hPtr; axisPtr->classUid = NULL; axisPtr->looseMin = axisPtr->looseMax = TICK_RANGE_TIGHT; axisPtr->reqNumMinorTicks = 2; axisPtr->scrollUnits = 10; axisPtr->showTicks = TRUE; axisPtr->reqMin = axisPtr->reqMax = VALUE_UNDEFINED; axisPtr->scrollMin = axisPtr->scrollMax = VALUE_UNDEFINED; if ((graphPtr->classUid == bltBarElementUid) && ((margin == MARGIN_TOP) || (margin == MARGIN_BOTTOM))) { axisPtr->reqStep = 1.0; axisPtr->reqNumMinorTicks = 0; } if ((margin == MARGIN_RIGHT) || (margin == MARGIN_TOP)) { axisPtr->hidden = TRUE; } Blt_InitTextStyle(&axisPtr->titleTextStyle); Blt_InitTextStyle(&axisPtr->limitsTextStyle); Blt_InitTextStyle(&axisPtr->tickTextStyle); axisPtr->tickLabels = Blt_ChainCreate(); axisPtr->lineWidth = 1; axisPtr->tickTextStyle.padX.side1 = 2; axisPtr->tickTextStyle.padX.side2 = 2; Blt_SetHashValue(hPtr, axisPtr); } return axisPtr; } static int NameToAxis(graphPtr, name, axisPtrPtr) Graph *graphPtr; /* Graph widget record. */ char *name; /* Name of the axis to be searched for. */ Axis **axisPtrPtr; /* (out) Pointer to found axis structure. */ { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&graphPtr->axes.table, name); if (hPtr != NULL) { Axis *axisPtr; axisPtr = (Axis *)Blt_GetHashValue(hPtr); if (!axisPtr->deletePending) { *axisPtrPtr = axisPtr; return TCL_OK; } } Tcl_AppendResult(graphPtr->interp, "can't find axis \"", name, "\" in \"", Tk_PathName(graphPtr->tkwin), "\"", (char *)NULL); *axisPtrPtr = NULL; return TCL_ERROR; } static int GetAxis(graphPtr, axisName, classUid, axisPtrPtr) Graph *graphPtr; char *axisName; Blt_Uid classUid; Axis **axisPtrPtr; { Axis *axisPtr; if (NameToAxis(graphPtr, axisName, &axisPtr) != TCL_OK) { return TCL_ERROR; } if (classUid != NULL) { if ((axisPtr->refCount == 0) || (axisPtr->classUid == NULL)) { /* Set the axis type on the first use of it. */ axisPtr->classUid = classUid; } else if (axisPtr->classUid != classUid) { Tcl_AppendResult(graphPtr->interp, "axis \"", axisName, "\" is already in use on an opposite ", axisPtr->classUid, "-axis", (char *)NULL); return TCL_ERROR; } axisPtr->refCount++; } *axisPtrPtr = axisPtr; return TCL_OK; } static void FreeAxis(graphPtr, axisPtr) Graph *graphPtr; Axis *axisPtr; { axisPtr->refCount--; if ((axisPtr->deletePending) && (axisPtr->refCount == 0)) { DestroyAxis(graphPtr, axisPtr); } } void Blt_DestroyAxes(graphPtr) Graph *graphPtr; { Blt_HashEntry *hPtr; Blt_HashSearch cursor; Axis *axisPtr; int i; for (hPtr = Blt_FirstHashEntry(&graphPtr->axes.table, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { axisPtr = (Axis *)Blt_GetHashValue(hPtr); axisPtr->hashPtr = NULL; DestroyAxis(graphPtr, axisPtr); } Blt_DeleteHashTable(&graphPtr->axes.table); for (i = 0; i < 4; i++) { Blt_ChainDestroy(graphPtr->axisChain[i]); } Blt_DeleteHashTable(&graphPtr->axes.tagTable); Blt_ChainDestroy(graphPtr->axes.displayList); } int Blt_DefaultAxes(graphPtr) Graph *graphPtr; { register int i; Axis *axisPtr; Blt_Chain *chainPtr; static char *axisNames[4] = { "x", "y", "x2", "y2" } ; int flags; flags = Blt_GraphType(graphPtr); for (i = 0; i < 4; i++) { chainPtr = Blt_ChainCreate(); graphPtr->axisChain[i] = chainPtr; /* Create a default axis for each chain. */ axisPtr = CreateAxis(graphPtr, axisNames[i], i); if (axisPtr == NULL) { return TCL_ERROR; } axisPtr->refCount = 1; /* Default axes are assumed in use. */ axisPtr->classUid = (i & 1) ? bltYAxisUid : bltXAxisUid; axisPtr->flags |= AXIS_ONSCREEN; /* * Blt_ConfigureWidgetComponent creates a temporary child window * by the name of the axis. It's used so that the Tk routines * that access the X resource database can describe a single * component and not the entire graph. */ if (Blt_ConfigureWidgetComponent(graphPtr->interp, graphPtr->tkwin, axisPtr->name, "Axis", configSpecs, 0, (char **)NULL, (char *)axisPtr, flags) != TCL_OK) { return TCL_ERROR; } if (ConfigureAxis(graphPtr, axisPtr) != TCL_OK) { return TCL_ERROR; } axisPtr->linkPtr = Blt_ChainAppend(chainPtr, axisPtr); axisPtr->chainPtr = chainPtr; } return TCL_OK; } /*---------------------------------------------------------------------- * * BindOp -- * * .g axis bind axisName sequence command * *---------------------------------------------------------------------- */ static int BindOp(graphPtr, axisPtr, argc, argv) Graph *graphPtr; Axis *axisPtr; int argc; char **argv; { Tcl_Interp *interp = graphPtr->interp; return Blt_ConfigureBindings(interp, graphPtr->bindTable, Blt_MakeAxisTag(graphPtr, axisPtr->name), argc, argv); } /* * ---------------------------------------------------------------------- * * CgetOp -- * * Queries axis attributes (font, line width, label, etc). * * Results: * Return value is a standard Tcl result. If querying configuration * values, interp->result will contain the results. * * ---------------------------------------------------------------------- */ /* ARGSUSED */ static int CgetOp(graphPtr, axisPtr, argc, argv) Graph *graphPtr; Axis *axisPtr; int argc; /* Not used. */ char *argv[]; { return Tk_ConfigureValue(graphPtr->interp, graphPtr->tkwin, configSpecs, (char *)axisPtr, argv[0], Blt_GraphType(graphPtr)); } /* * ---------------------------------------------------------------------- * * ConfigureOp -- * * Queries or resets axis attributes (font, line width, label, etc). * * Results: * Return value is a standard Tcl result. If querying configuration * values, interp->result will contain the results. * * Side Effects: * Axis resources are possibly allocated (GC, font). Axis layout is * deferred until the height and width of the window are known. * * ---------------------------------------------------------------------- */ static int ConfigureOp(graphPtr, axisPtr, argc, argv) Graph *graphPtr; Axis *axisPtr; int argc; char *argv[]; { int flags; flags = TK_CONFIG_ARGV_ONLY | Blt_GraphType(graphPtr); if (argc == 0) { return Tk_ConfigureInfo(graphPtr->interp, graphPtr->tkwin, configSpecs, (char *)axisPtr, (char *)NULL, flags); } else if (argc == 1) { return Tk_ConfigureInfo(graphPtr->interp, graphPtr->tkwin, configSpecs, (char *)axisPtr, argv[0], flags); } if (Tk_ConfigureWidget(graphPtr->interp, graphPtr->tkwin, configSpecs, argc, argv, (char *)axisPtr, flags) != TCL_OK) { return TCL_ERROR; } if (ConfigureAxis(graphPtr, axisPtr) != TCL_OK) { return TCL_ERROR; } if (axisPtr->flags & AXIS_ONSCREEN) { if (!Blt_ConfigModified(configSpecs, "-*color", "-background", "-bg", (char *)NULL)) { graphPtr->flags |= REDRAW_BACKING_STORE; } graphPtr->flags |= DRAW_MARGINS; Blt_EventuallyRedrawGraph(graphPtr); } return TCL_OK; } /* * ---------------------------------------------------------------------- * * GetOp -- * * Returns the name of the picked axis (using the axis * bind operation). Right now, the only name accepted is * "current". * * Results: * A standard Tcl result. The interpreter result will contain * the name of the axis. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static int GetOp(graphPtr, argc, argv) Graph *graphPtr; int argc; /* Not used. */ char *argv[]; { Tcl_Interp *interp = graphPtr->interp; register Axis *axisPtr; axisPtr = (Axis *)Blt_GetCurrentItem(graphPtr->bindTable); /* Report only on axes. */ if ((axisPtr != NULL) && ((axisPtr->classUid == bltXAxisUid) || (axisPtr->classUid == bltYAxisUid) || (axisPtr->classUid == NULL))) { char c; c = argv[3][0]; if ((c == 'c') && (strcmp(argv[3], "current") == 0)) { Tcl_SetResult(interp, axisPtr->name, TCL_VOLATILE); } else if ((c == 'd') && (strcmp(argv[3], "detail") == 0)) { Tcl_SetResult(interp, axisPtr->detail, TCL_VOLATILE); } } return TCL_OK; } /* *-------------------------------------------------------------- * * LimitsOp -- * * This procedure returns a string representing the axis limits * of the graph. The format of the string is { left top right bottom}. * * Results: * Always returns TCL_OK. The interp->result field is * a list of the graph axis limits. * *-------------------------------------------------------------- */ /*ARGSUSED*/ static int LimitsOp(graphPtr, axisPtr, argc, argv) Graph *graphPtr; Axis *axisPtr; int argc; /* Not used. */ char **argv; /* Not used. */ { Tcl_Interp *interp = graphPtr->interp; double min, max; if (graphPtr->flags & RESET_AXES) { Blt_ResetAxes(graphPtr); } if (axisPtr->logScale) { min = EXP10(axisPtr->axisRange.min); max = EXP10(axisPtr->axisRange.max); } else { min = axisPtr->axisRange.min; max = axisPtr->axisRange.max; } Tcl_AppendElement(interp, Blt_Dtoa(interp, min)); Tcl_AppendElement(interp, Blt_Dtoa(interp, max)); return TCL_OK; } /* * ---------------------------------------------------------------------- * * InvTransformOp -- * * Maps the given window coordinate into an axis-value. * * Results: * Returns a standard Tcl result. interp->result contains * the axis value. If an error occurred, TCL_ERROR is returned * and interp->result will contain an error message. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static int InvTransformOp(graphPtr, axisPtr, argc, argv) Graph *graphPtr; Axis *axisPtr; int argc; /* Not used. */ char **argv; { int x; /* Integer window coordinate*/ double y; /* Real graph coordinate */ if (graphPtr->flags & RESET_AXES) { Blt_ResetAxes(graphPtr); } if (Tcl_GetInt(graphPtr->interp, argv[0], &x) != 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). */ if (AxisIsHorizontal(graphPtr, axisPtr)) { y = Blt_InvHMap(graphPtr, axisPtr, (double)x); } else { y = Blt_InvVMap(graphPtr, axisPtr, (double)x); } Tcl_AppendElement(graphPtr->interp, Blt_Dtoa(graphPtr->interp, y)); return TCL_OK; } /* * ---------------------------------------------------------------------- * * TransformOp -- * * Maps the given axis-value to a window coordinate. * * Results: * Returns a standard Tcl result. interp->result contains * the window coordinate. If an error occurred, TCL_ERROR * is returned and interp->result will contain an error * message. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TransformOp(graphPtr, axisPtr, argc, argv) Graph *graphPtr; Axis *axisPtr; /* Axis */ int argc; /* Not used. */ char **argv; { double x; if (graphPtr->flags & RESET_AXES) { Blt_ResetAxes(graphPtr); } if (Tcl_ExprDouble(graphPtr->interp, argv[0], &x) != TCL_OK) { return TCL_ERROR; } if (AxisIsHorizontal(graphPtr, axisPtr)) { x = Blt_HMap(graphPtr, axisPtr, x); } else { x = Blt_VMap(graphPtr, axisPtr, x); } Tcl_SetResult(graphPtr->interp, Blt_Itoa((int)x), TCL_VOLATILE); return TCL_OK; } /* *-------------------------------------------------------------- * * UseOp -- * * Changes the virtual axis used by the logical axis. * * Results: * A standard Tcl result. If the named axis doesn't exist * an error message is put in interp->result. * * .g xaxis use "abc def gah" * .g xaxis use [lappend abc [.g axis use]] * *-------------------------------------------------------------- */ /*ARGSUSED*/ static int UseOp(graphPtr, axisPtr, argc, argv) Graph *graphPtr; Axis *axisPtr; /* Not used. */ int argc; char **argv; { Blt_Chain *chainPtr; int nNames; char **names; Blt_ChainLink *linkPtr; int i; Blt_Uid classUid; int margin; margin = (int)argv[-1]; chainPtr = graphPtr->margins[margin].axes; if (argc == 0) { for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr!= NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { axisPtr = Blt_ChainGetValue(linkPtr); Tcl_AppendElement(graphPtr->interp, axisPtr->name); } return TCL_OK; } if ((margin == MARGIN_BOTTOM) || (margin == MARGIN_TOP)) { classUid = (graphPtr->inverted) ? bltYAxisUid : bltXAxisUid; } else { classUid = (graphPtr->inverted) ? bltXAxisUid : bltYAxisUid; } if (Tcl_SplitList(graphPtr->interp, argv[0], &nNames, &names) != TCL_OK) { return TCL_ERROR; } for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr!= NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { axisPtr = Blt_ChainGetValue(linkPtr); axisPtr->linkPtr = NULL; axisPtr->flags &= ~AXIS_ONSCREEN; /* Clear the axis type if it's not currently used.*/ if (axisPtr->refCount == 0) { axisPtr->classUid = NULL; } } Blt_ChainReset(chainPtr); for (i = 0; i < nNames; i++) { if (NameToAxis(graphPtr, names[i], &axisPtr) != TCL_OK) { Blt_Free(names); return TCL_ERROR; } if (axisPtr->classUid == NULL) { axisPtr->classUid = classUid; } else if (axisPtr->classUid != classUid) { Tcl_AppendResult(graphPtr->interp, "wrong type axis \"", axisPtr->name, "\": can't use ", classUid, " type axis.", (char *)NULL); Blt_Free(names); return TCL_ERROR; } if (axisPtr->linkPtr != NULL) { /* Move the axis from the old margin's "use" list to the new. */ Blt_ChainUnlinkLink(axisPtr->chainPtr, axisPtr->linkPtr); Blt_ChainAppendLink(chainPtr, axisPtr->linkPtr); } else { axisPtr->linkPtr = Blt_ChainAppend(chainPtr, axisPtr); } axisPtr->chainPtr = chainPtr; axisPtr->flags |= AXIS_ONSCREEN; } graphPtr->flags |= (GET_AXIS_GEOMETRY | LAYOUT_NEEDED | RESET_AXES); /* When any axis changes, we need to layout the entire graph. */ graphPtr->flags |= (MAP_WORLD | REDRAW_WORLD); Blt_EventuallyRedrawGraph(graphPtr); Blt_Free(names); return TCL_OK; } /* * ---------------------------------------------------------------------- * * CreateVirtualOp -- * * Creates a new axis. * * Results: * Returns a standard Tcl result. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static int CreateVirtualOp(graphPtr, argc, argv) Graph *graphPtr; int argc; char **argv; { Axis *axisPtr; int flags; axisPtr = CreateAxis(graphPtr, argv[3], MARGIN_NONE); if (axisPtr == NULL) { return TCL_ERROR; } flags = Blt_GraphType(graphPtr); if (Blt_ConfigureWidgetComponent(graphPtr->interp, graphPtr->tkwin, axisPtr->name, "Axis", configSpecs, argc - 4, argv + 4, (char *)axisPtr, flags) != TCL_OK) { goto error; } if (ConfigureAxis(graphPtr, axisPtr) != TCL_OK) { goto error; } Tcl_SetResult(graphPtr->interp, axisPtr->name, TCL_VOLATILE); return TCL_OK; error: DestroyAxis(graphPtr, axisPtr); return TCL_ERROR; } /*---------------------------------------------------------------------- * * BindVirtualOp -- * * .g axis bind axisName sequence command * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int BindVirtualOp(graphPtr, argc, argv) Graph *graphPtr; int argc; char **argv; { Tcl_Interp *interp = graphPtr->interp; if (argc == 3) { Blt_HashEntry *hPtr; Blt_HashSearch cursor; char *tagName; for (hPtr = Blt_FirstHashEntry(&graphPtr->axes.tagTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tagName = Blt_GetHashKey(&graphPtr->axes.tagTable, hPtr); Tcl_AppendElement(interp, tagName); } return TCL_OK; } return Blt_ConfigureBindings(interp, graphPtr->bindTable, Blt_MakeAxisTag(graphPtr, argv[3]), argc - 4, argv + 4); } /* * ---------------------------------------------------------------------- * * CgetVirtualOp -- * * Queries axis attributes (font, line width, label, etc). * * Results: * Return value is a standard Tcl result. If querying configuration * values, interp->result will contain the results. * * ---------------------------------------------------------------------- */ /* ARGSUSED */ static int CgetVirtualOp(graphPtr, argc, argv) Graph *graphPtr; int argc; char *argv[]; { Axis *axisPtr; if (NameToAxis(graphPtr, argv[3], &axisPtr) != TCL_OK) { return TCL_ERROR; } return CgetOp(graphPtr, axisPtr, argc - 4, argv + 4); } /* * ---------------------------------------------------------------------- * * ConfigureVirtualOp -- * * Queries or resets axis attributes (font, line width, label, etc). * * Results: * Return value is a standard Tcl result. If querying configuration * values, interp->result will contain the results. * * Side Effects: * Axis resources are possibly allocated (GC, font). Axis layout is * deferred until the height and width of the window are known. * * ---------------------------------------------------------------------- */ static int ConfigureVirtualOp(graphPtr, argc, argv) Graph *graphPtr; int argc; char *argv[]; { Axis *axisPtr; int nNames, nOpts; char **options; register int i; /* Figure out where the option value pairs begin */ argc -= 3; argv += 3; for (i = 0; i < argc; i++) { if (argv[i][0] == '-') { break; } if (NameToAxis(graphPtr, argv[i], &axisPtr) != TCL_OK) { return TCL_ERROR; } } nNames = i; /* Number of pen names specified */ nOpts = argc - i; /* Number of options specified */ options = argv + i; /* Start of options in argv */ for (i = 0; i < nNames; i++) { if (NameToAxis(graphPtr, argv[i], &axisPtr) != TCL_OK) { return TCL_ERROR; } if (ConfigureOp(graphPtr, axisPtr, nOpts, options) != TCL_OK) { break; } } if (i < nNames) { return TCL_ERROR; } return TCL_OK; } /* * ---------------------------------------------------------------------- * * DeleteVirtualOp -- * * Deletes one or more axes. The actual removal may be deferred * until the axis is no longer used by any element. The axis * can't be referenced by its name any longer and it may be * recreated. * * Results: * Returns a standard Tcl result. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static int DeleteVirtualOp(graphPtr, argc, argv) Graph *graphPtr; int argc; char **argv; { register int i; Axis *axisPtr; for (i = 3; i < argc; i++) { if (NameToAxis(graphPtr, argv[i], &axisPtr) != TCL_OK) { return TCL_ERROR; } axisPtr->deletePending = TRUE; if (axisPtr->refCount == 0) { DestroyAxis(graphPtr, axisPtr); } } return TCL_OK; } /* * ---------------------------------------------------------------------- * * InvTransformVirtualOp -- * * Maps the given window coordinate into an axis-value. * * Results: * Returns a standard Tcl result. interp->result contains * the axis value. If an error occurred, TCL_ERROR is returned * and interp->result will contain an error message. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static int InvTransformVirtualOp(graphPtr, argc, argv) Graph *graphPtr; int argc; /* Not used. */ char **argv; { Axis *axisPtr; if (NameToAxis(graphPtr, argv[3], &axisPtr) != TCL_OK) { return TCL_ERROR; } return InvTransformOp(graphPtr, axisPtr, argc - 4, argv + 4); } /* *-------------------------------------------------------------- * * LimitsVirtualOp -- * * This procedure returns a string representing the axis limits * of the graph. The format of the string is { left top right bottom}. * * Results: * Always returns TCL_OK. The interp->result field is * a list of the graph axis limits. * *-------------------------------------------------------------- */ /*ARGSUSED*/ static int LimitsVirtualOp(graphPtr, argc, argv) Graph *graphPtr; int argc; /* Not used. */ char **argv; /* Not used. */ { Axis *axisPtr; if (NameToAxis(graphPtr, argv[3], &axisPtr) != TCL_OK) { return TCL_ERROR; } return LimitsOp(graphPtr, axisPtr, argc - 4, argv + 4); } /* * ---------------------------------------------------------------------- * * NamesVirtualOp -- * * Return a list of the names of all the axes. * * Results: * Returns a standard Tcl result. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static int NamesVirtualOp(graphPtr, argc, argv) Graph *graphPtr; int argc; /* Not used. */ char **argv; /* Not used. */ { Blt_HashEntry *hPtr; Blt_HashSearch cursor; Axis *axisPtr; register int i; for (hPtr = Blt_FirstHashEntry(&graphPtr->axes.table, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { axisPtr = (Axis *)Blt_GetHashValue(hPtr); if (axisPtr->deletePending) { continue; } if (argc == 3) { Tcl_AppendElement(graphPtr->interp, axisPtr->name); continue; } for (i = 3; i < argc; i++) { if (Tcl_StringMatch(axisPtr->name, argv[i])) { Tcl_AppendElement(graphPtr->interp, axisPtr->name); break; } } } return TCL_OK; } /* * ---------------------------------------------------------------------- * * TransformVirtualOp -- * * Maps the given axis-value to a window coordinate. * * Results: * Returns a standard Tcl result. interp->result contains * the window coordinate. If an error occurred, TCL_ERROR * is returned and interp->result will contain an error * message. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TransformVirtualOp(graphPtr, argc, argv) Graph *graphPtr; int argc; /* Not used. */ char **argv; { Axis *axisPtr; if (NameToAxis(graphPtr, argv[3], &axisPtr) != TCL_OK) { return TCL_ERROR; } return TransformOp(graphPtr, axisPtr, argc - 4, argv + 4); } static int ViewOp(graphPtr, argc, argv) Graph *graphPtr; int argc; char **argv; { Axis *axisPtr; Tcl_Interp *interp = graphPtr->interp; double axisOffset, scrollUnits; double fract; double viewMin, viewMax, worldMin, worldMax; double viewWidth, worldWidth; if (NameToAxis(graphPtr, argv[3], &axisPtr) != TCL_OK) { return TCL_ERROR; } worldMin = axisPtr->valueRange.min; worldMax = axisPtr->valueRange.max; /* Override data dimensions with user-selected limits. */ if (DEFINED(axisPtr->scrollMin)) { worldMin = axisPtr->scrollMin; } if (DEFINED(axisPtr->scrollMax)) { worldMax = axisPtr->scrollMax; } viewMin = axisPtr->min; viewMax = axisPtr->max; /* Bound the view within scroll region. */ if (viewMin < worldMin) { viewMin = worldMin; } if (viewMax > worldMax) { viewMax = worldMax; } if (axisPtr->logScale) { worldMin = log10(worldMin); worldMax = log10(worldMax); viewMin = log10(viewMin); viewMax = log10(viewMax); } worldWidth = worldMax - worldMin; 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. */ if (AxisIsHorizontal(graphPtr, axisPtr) != axisPtr->descending) { axisOffset = viewMin - worldMin; scrollUnits = (double)axisPtr->scrollUnits * graphPtr->hScale; } else { axisOffset = worldMax - viewMax; scrollUnits = (double)axisPtr->scrollUnits * graphPtr->vScale; } if (argc == 4) { /* Note: Bound the fractions between 0.0 and 1.0 to support * "canvas"-style scrolling. */ fract = axisOffset / worldWidth; Tcl_AppendElement(interp, Blt_Dtoa(interp, CLAMP(fract, 0.0, 1.0))); fract = (axisOffset + viewWidth) / worldWidth; Tcl_AppendElement(interp, Blt_Dtoa(interp, CLAMP(fract, 0.0, 1.0))); return TCL_OK; } fract = axisOffset / worldWidth; if (GetAxisScrollInfo(interp, argc - 4, argv + 4, &fract, viewWidth / worldWidth, scrollUnits) != TCL_OK) { return TCL_ERROR; } if (AxisIsHorizontal(graphPtr, axisPtr) != axisPtr->descending) { axisPtr->reqMin = (fract * worldWidth) + worldMin; axisPtr->reqMax = axisPtr->reqMin + viewWidth; } else { axisPtr->reqMax = worldMax - (fract * worldWidth); axisPtr->reqMin = axisPtr->reqMax - viewWidth; } if (axisPtr->logScale) { axisPtr->reqMin = EXP10(axisPtr->reqMin); axisPtr->reqMax = EXP10(axisPtr->reqMax); } graphPtr->flags |= (GET_AXIS_GEOMETRY | LAYOUT_NEEDED | RESET_AXES); Blt_EventuallyRedrawGraph(graphPtr); return TCL_OK; } int Blt_VirtualAxisOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { Blt_Op proc; int result; static Blt_OpSpec axisOps[] = { {"bind", 1, (Blt_Op)BindVirtualOp, 3, 6, "axisName sequence command",}, {"cget", 2, (Blt_Op)CgetVirtualOp, 5, 5, "axisName option",}, {"configure", 2, (Blt_Op)ConfigureVirtualOp, 4, 0, "axisName ?axisName?... ?option value?...",}, {"create", 2, (Blt_Op)CreateVirtualOp, 4, 0, "axisName ?option value?...",}, {"delete", 1, (Blt_Op)DeleteVirtualOp, 3, 0, "?axisName?...",}, {"get", 1, (Blt_Op)GetOp, 4, 4, "name",}, {"invtransform", 1, (Blt_Op)InvTransformVirtualOp, 5, 5, "axisName value",}, {"limits", 1, (Blt_Op)LimitsVirtualOp, 4, 4, "axisName",}, {"names", 1, (Blt_Op)NamesVirtualOp, 3, 0, "?pattern?...",}, {"transform", 1, (Blt_Op)TransformVirtualOp, 5, 5, "axisName value",}, {"view", 1, (Blt_Op)ViewOp, 4, 7, "axisName ?moveto fract? ?scroll number what?",}, }; static int nAxisOps = sizeof(axisOps) / sizeof(Blt_OpSpec); proc = Blt_GetOp(interp, nAxisOps, axisOps, BLT_OP_ARG2, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (graphPtr, argc, argv); return result; } int Blt_AxisOp(graphPtr, margin, argc, argv) Graph *graphPtr; int margin; int argc; char **argv; { int result; Blt_Op proc; Axis *axisPtr; static Blt_OpSpec axisOps[] = { {"bind", 1, (Blt_Op)BindOp, 2, 5, "sequence command",}, {"cget", 2, (Blt_Op)CgetOp, 4, 4, "option",}, {"configure", 2, (Blt_Op)ConfigureOp, 3, 0, "?option value?...",}, {"invtransform", 1, (Blt_Op)InvTransformOp, 4, 4, "value",}, {"limits", 1, (Blt_Op)LimitsOp, 3, 3, "",}, {"transform", 1, (Blt_Op)TransformOp, 4, 4, "value",}, {"use", 1, (Blt_Op)UseOp, 3, 4, "?axisName?",}, }; static int nAxisOps = sizeof(axisOps) / sizeof(Blt_OpSpec); proc = Blt_GetOp(graphPtr->interp, nAxisOps, axisOps, BLT_OP_ARG2, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } argv[2] = (char *)margin; /* Hack. Slide a reference to the margin in * the argument list. Needed only for UseOp. */ axisPtr = Blt_GetFirstAxis(graphPtr->margins[margin].axes); result = (*proc)(graphPtr, axisPtr, argc - 3, argv + 3); return result; } void Blt_MapAxes(graphPtr) Graph *graphPtr; { Axis *axisPtr; Blt_Chain *chainPtr; Blt_ChainLink *linkPtr; register int margin; int offset; for (margin = 0; margin < 4; margin++) { chainPtr = graphPtr->margins[margin].axes; offset = 0; for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { axisPtr = Blt_ChainGetValue(linkPtr); if ((!axisPtr->hidden) && (axisPtr->flags & AXIS_ONSCREEN)) { MapAxis(graphPtr, axisPtr, offset, margin); if (AxisIsHorizontal(graphPtr, axisPtr)) { offset += axisPtr->height; } else { offset += axisPtr->width; } } } } } void Blt_DrawAxes(graphPtr, drawable) Graph *graphPtr; Drawable drawable; { Axis *axisPtr; Blt_ChainLink *linkPtr; register int i; for (i = 0; i < 4; i++) { for (linkPtr = Blt_ChainFirstLink(graphPtr->margins[i].axes); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { axisPtr = Blt_ChainGetValue(linkPtr); if ((!axisPtr->hidden) && (axisPtr->flags & AXIS_ONSCREEN)) { DrawAxis(graphPtr, drawable, axisPtr); } } } } void Blt_AxesToPostScript(graphPtr, psToken) Graph *graphPtr; PsToken psToken; { Axis *axisPtr; Blt_ChainLink *linkPtr; register int i; for (i = 0; i < 4; i++) { for (linkPtr = Blt_ChainFirstLink(graphPtr->margins[i].axes); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { axisPtr = Blt_ChainGetValue(linkPtr); if ((!axisPtr->hidden) && (axisPtr->flags & AXIS_ONSCREEN)) { AxisToPostScript(psToken, axisPtr); } } } } /* * ---------------------------------------------------------------------- * * Blt_DrawAxisLimits -- * * Draws the min/max values of the axis in the plotting area. * The text strings are formatted according to the "sprintf" * format descriptors in the limitsFormats array. * * Results: * None. * * Side Effects: * Draws the numeric values of the axis limits into the outer * regions of the plotting area. * * ---------------------------------------------------------------------- */ void Blt_DrawAxisLimits(graphPtr, drawable) Graph *graphPtr; Drawable drawable; { Axis *axisPtr; Blt_HashEntry *hPtr; Blt_HashSearch cursor; Dim2D textDim; int isHoriz; char *minPtr, *maxPtr; char *minFormat, *maxFormat; char minString[200], maxString[200]; int vMin, hMin, vMax, hMax; #define SPACING 8 vMin = vMax = graphPtr->left + graphPtr->padLeft + 2; hMin = hMax = graphPtr->bottom - graphPtr->padBottom - 2; /* Offsets */ for (hPtr = Blt_FirstHashEntry(&graphPtr->axes.table, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { axisPtr = (Axis *)Blt_GetHashValue(hPtr); if (axisPtr->nFormats == 0) { continue; } isHoriz = AxisIsHorizontal(graphPtr, axisPtr); minPtr = maxPtr = NULL; minFormat = maxFormat = axisPtr->limitsFormats[0]; if (axisPtr->nFormats > 1) { maxFormat = axisPtr->limitsFormats[1]; } if (minFormat[0] != '\0') { minPtr = minString; sprintf(minString, minFormat, axisPtr->axisRange.min); } if (maxFormat[0] != '\0') { maxPtr = maxString; sprintf(maxString, maxFormat, axisPtr->axisRange.max); } if (axisPtr->descending) { char *tmp; tmp = minPtr, minPtr = maxPtr, maxPtr = tmp; } if (maxPtr != NULL) { if (isHoriz) { axisPtr->limitsTextStyle.theta = 90.0; axisPtr->limitsTextStyle.anchor = TK_ANCHOR_SE; Blt_DrawText2(graphPtr->tkwin, drawable, maxPtr, &axisPtr->limitsTextStyle, graphPtr->right, hMax, &textDim); hMax -= (textDim.height + SPACING); } else { axisPtr->limitsTextStyle.theta = 0.0; axisPtr->limitsTextStyle.anchor = TK_ANCHOR_NW; Blt_DrawText2(graphPtr->tkwin, drawable, maxPtr, &axisPtr->limitsTextStyle, vMax, graphPtr->top, &textDim); vMax += (textDim.width + SPACING); } } if (minPtr != NULL) { axisPtr->limitsTextStyle.anchor = TK_ANCHOR_SW; if (isHoriz) { axisPtr->limitsTextStyle.theta = 90.0; Blt_DrawText2(graphPtr->tkwin, drawable, minPtr, &axisPtr->limitsTextStyle, graphPtr->left, hMin, &textDim); hMin -= (textDim.height + SPACING); } else { axisPtr->limitsTextStyle.theta = 0.0; Blt_DrawText2(graphPtr->tkwin, drawable, minPtr, &axisPtr->limitsTextStyle, vMin, graphPtr->bottom, &textDim); vMin += (textDim.width + SPACING); } } } /* Loop on axes */ } void Blt_AxisLimitsToPostScript(graphPtr, psToken) Graph *graphPtr; PsToken psToken; { Axis *axisPtr; Blt_HashEntry *hPtr; Blt_HashSearch cursor; double vMin, hMin, vMax, hMax; char string[200]; int textWidth, textHeight; char *minFmt, *maxFmt; #define SPACING 8 vMin = vMax = graphPtr->left + graphPtr->padLeft + 2; hMin = hMax = graphPtr->bottom - graphPtr->padBottom - 2; /* Offsets */ for (hPtr = Blt_FirstHashEntry(&graphPtr->axes.table, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { axisPtr = (Axis *)Blt_GetHashValue(hPtr); if (axisPtr->nFormats == 0) { continue; } minFmt = maxFmt = axisPtr->limitsFormats[0]; if (axisPtr->nFormats > 1) { maxFmt = axisPtr->limitsFormats[1]; } if (*maxFmt != '\0') { sprintf(string, maxFmt, axisPtr->axisRange.max); Blt_GetTextExtents(&axisPtr->tickTextStyle, string, &textWidth, &textHeight); if ((textWidth > 0) && (textHeight > 0)) { if (axisPtr->classUid == bltXAxisUid) { axisPtr->limitsTextStyle.theta = 90.0; axisPtr->limitsTextStyle.anchor = TK_ANCHOR_SE; Blt_TextToPostScript(psToken, string, &axisPtr->limitsTextStyle, (double)graphPtr->right, hMax); hMax -= (textWidth + SPACING); } else { axisPtr->limitsTextStyle.theta = 0.0; axisPtr->limitsTextStyle.anchor = TK_ANCHOR_NW; Blt_TextToPostScript(psToken, string, &axisPtr->limitsTextStyle, vMax, (double)graphPtr->top); vMax += (textWidth + SPACING); } } } if (*minFmt != '\0') { sprintf(string, minFmt, axisPtr->axisRange.min); Blt_GetTextExtents(&axisPtr->tickTextStyle, string, &textWidth, &textHeight); if ((textWidth > 0) && (textHeight > 0)) { axisPtr->limitsTextStyle.anchor = TK_ANCHOR_SW; if (axisPtr->classUid == bltXAxisUid) { axisPtr->limitsTextStyle.theta = 90.0; Blt_TextToPostScript(psToken, string, &axisPtr->limitsTextStyle, (double)graphPtr->left, hMin); hMin -= (textWidth + SPACING); } else { axisPtr->limitsTextStyle.theta = 0.0; Blt_TextToPostScript(psToken, string, &axisPtr->limitsTextStyle, vMin, (double)graphPtr->bottom); vMin += (textWidth + SPACING); } } } } } Axis * Blt_GetFirstAxis(chainPtr) Blt_Chain *chainPtr; { Blt_ChainLink *linkPtr; linkPtr = Blt_ChainFirstLink(chainPtr); if (linkPtr == NULL) { return NULL; } return Blt_ChainGetValue(linkPtr); } Axis * Blt_NearestAxis(graphPtr, x, y) Graph *graphPtr; int x, y; /* Point to be tested */ { register Blt_HashEntry *hPtr; Blt_HashSearch cursor; Axis *axisPtr; int width, height; double rotWidth, rotHeight; Point2D bbox[5]; for (hPtr = Blt_FirstHashEntry(&graphPtr->axes.table, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { axisPtr = (Axis *)Blt_GetHashValue(hPtr); if ((axisPtr->hidden) || (!(axisPtr->flags & AXIS_ONSCREEN))) { continue; /* Don't check hidden axes or axes * that are virtual. */ } if (axisPtr->showTicks) { register Blt_ChainLink *linkPtr; TickLabel *labelPtr; Point2D t; for (linkPtr = Blt_ChainFirstLink(axisPtr->tickLabels); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { labelPtr = Blt_ChainGetValue(linkPtr); Blt_GetBoundingBox(labelPtr->width, labelPtr->height, axisPtr->tickTextStyle.theta, &rotWidth, &rotHeight, bbox); width = ROUND(rotWidth); height = ROUND(rotHeight); t = Blt_TranslatePoint(&labelPtr->anchorPos, width, height, axisPtr->tickTextStyle.anchor); t.x = x - t.x - (width * 0.5); t.y = y - t.y - (height * 0.5); bbox[4] = bbox[0]; if (Blt_PointInPolygon(&t, bbox, 5)) { axisPtr->detail = "label"; return axisPtr; } } } if (axisPtr->title != NULL) { /* and then the title string. */ Point2D t; Blt_GetTextExtents(&axisPtr->titleTextStyle, axisPtr->title,&width, &height); Blt_GetBoundingBox(width, height, axisPtr->titleTextStyle.theta, &rotWidth, &rotHeight, bbox); width = ROUND(rotWidth); height = ROUND(rotHeight); t = Blt_TranslatePoint(&axisPtr->titlePos, width, height, axisPtr->titleTextStyle.anchor); /* Translate the point so that the 0,0 is the upper left * corner of the bounding box. */ t.x = x - t.x - (width / 2); t.y = y - t.y - (height / 2); bbox[4] = bbox[0]; if (Blt_PointInPolygon(&t, bbox, 5)) { axisPtr->detail = "title"; return axisPtr; } } if (axisPtr->lineWidth > 0) { /* Check for the axis region */ if (PointInRegion(&axisPtr->region, x, y)) { axisPtr->detail = "line"; return axisPtr; } } } return NULL; } ClientData Blt_MakeAxisTag(graphPtr, tagName) Graph *graphPtr; char *tagName; { Blt_HashEntry *hPtr; int isNew; hPtr = Blt_CreateHashEntry(&graphPtr->axes.tagTable, tagName, &isNew); assert(hPtr); return Blt_GetHashKey(&graphPtr->axes.tagTable, hPtr); } blt-2.4z.orig/src/bltGrAxis.h0100644000175000017500000002221107542177233014613 0ustar dokodoko/* * bltGrAxis.h -- * * Copyright 1991-1998 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. */ #ifndef _BLT_GR_AXIS_H #define _BLT_GR_AXIS_H #include "bltList.h" /* * ------------------------------------------------------------------- * * AxisRange -- * * Designates a range of values by a minimum and maximum limit. * * ------------------------------------------------------------------- */ typedef struct { double min, max, range, scale; } AxisRange; /* * ---------------------------------------------------------------------- * * TickLabel -- * * Structure containing the X-Y screen coordinates of the tick * label (anchored at its center). * * ---------------------------------------------------------------------- */ typedef struct { Point2D anchorPos; int width, height; char string[1]; } TickLabel; /* * ---------------------------------------------------------------------- * * Ticks -- * * Structure containing information where the ticks (major or * minor) will be displayed on the graph. * * ---------------------------------------------------------------------- */ typedef struct { int nTicks; /* # of ticks on axis */ double values[1]; /* Array of tick values (malloc-ed). */ } Ticks; /* * ---------------------------------------------------------------------- * * TickSweep -- * * Structure containing information where the ticks (major or * minor) will be displayed on the graph. * * ---------------------------------------------------------------------- */ typedef struct { double initial; /* Initial value */ double step; /* Size of interval */ int nSteps; /* Number of intervals. */ } TickSweep; /* * ---------------------------------------------------------------------- * * Axis -- * * Structure contains options controlling how the axis will be * displayed. * * ---------------------------------------------------------------------- */ typedef struct { char *name; /* Identifier to refer the element. * Used in the "insert", "delete", or * "show", commands. */ Blt_Uid classUid; /* Type of axis. */ Graph *graphPtr; /* Graph widget of element*/ unsigned int flags; /* Set bit field definitions below */ /* * AXIS_DRAWN Axis is designated as a logical axis * AXIS_DIRTY * * AXIS_CONFIG_MAJOR User specified major ticks. * AXIS_CONFIG_MINOR User specified minor ticks. */ char **tags; char *detail; int deletePending; /* Indicates that the axis was * scheduled for deletion. The actual * deletion may be deferred until the * axis is no longer in use. */ int refCount; /* Number of elements referencing this * axis. */ Blt_HashEntry *hashPtr; /* Points to axis entry in hash * table. Used to quickly remove axis * entries. */ int logScale; /* If non-zero, scale the axis values * logarithmically. */ int hidden; /* If non-zero, don't display the * axis title, ticks, or line. */ int showTicks; /* If non-zero, display tick marks and * labels. */ int descending; /* If non-zero, display the range of * values on the axis in descending * order, from high to low. */ int looseMin, looseMax; /* If non-zero, axis range extends to * the outer major ticks, otherwise at * the limits of the data values. This * is overriddened by setting the -min * and -max options. */ char *title; /* Title of the axis. */ TextStyle titleTextStyle; /* Text attributes (color, font, * rotation, etc.) of the axis * title. */ int titleAlternate; /* Indicates whether to position the * title above/left of the axis. */ Point2D titlePos; /* Position of the title */ unsigned short int titleWidth, titleHeight; int lineWidth; /* Width of lines representing axis * (including ticks). If zero, then * no axis lines or ticks are * drawn. */ char **limitsFormats; /* One or two strings of sprintf-like * formats describing how to display * virtual axis limits. If NULL, * display no limits. */ int nFormats; TextStyle limitsTextStyle; /* Text attributes (color, font, * rotation, etc.) of the limits. */ double windowSize; /* Size of a sliding window of values * used to scale the axis automatically * as new data values are added. The axis * will always display the latest values * in this range. */ double shiftBy; /* Shift maximum by this interval. */ int tickLength; /* Length of major ticks in pixels */ TextStyle tickTextStyle; /* Text attributes (color, font, rotation, * etc.) for labels at each major tick. */ char *formatCmd; /* Specifies a Tcl command, to be invoked * by the axis whenever it has to generate * tick labels. */ char *scrollCmdPrefix; int scrollUnits; double min, max; /* The actual axis range. */ double reqMin, reqMax; /* Requested axis bounds. Consult the * axisPtr->flags field for * AXIS_CONFIG_MIN and AXIS_CONFIG_MAX * to see if the requested bound have * been set. They override the * computed range of the axis * (determined by auto-scaling). */ double scrollMin, scrollMax;/* Defines the scrolling reqion of the axis. * Normally the region is determined from * the data limits. If specified, these * values override the data-range. */ AxisRange valueRange; /* Range of data values of elements mapped * to this axis. This is used to auto-scale * the axis in "tight" mode. */ AxisRange axisRange; /* Smallest and largest major tick values * for the axis. The tick values lie outside * the range of data values. This is used to * auto-scale the axis in "loose" mode. */ double prevMin, prevMax; double reqStep; /* If > 0.0, overrides the computed major * tick interval. Otherwise a stepsize * is automatically calculated, based * upon the range of elements mapped to the * axis. The default value is 0.0. */ double tickZoom; /* If > 0.0, overrides the computed major * tick interval. Otherwise a stepsize * is automatically calculated, based * upon the range of elements mapped to the * axis. The default value is 0.0. */ GC tickGC; /* Graphics context for axis and tick labels */ Ticks *t1Ptr; /* Array of major tick positions. May be * set by the user or generated from the * major sweep below. */ Ticks *t2Ptr; /* Array of minor tick positions. May be * set by the user or generated from the * minor sweep below. */ TickSweep minorSweep, majorSweep; int reqNumMinorTicks; /* If non-zero, represents the * requested the number of minor ticks * to be uniformally displayed along * each major tick. */ int labelOffset; /* If non-zero, indicates that the tick * label should be offset to sit in the * middle of the next interval. */ /* The following fields are specific to logical axes */ Blt_ChainLink *linkPtr; /* Axis link in margin list. */ Blt_Chain *chainPtr; short int width, height; /* Extents of axis */ Segment2D *segments; /* Array of line segments representing * the major and minor ticks, but also * the axis line itself. The segment * coordinates are relative to the * axis. */ int nSegments; /* Number of segments in the above array. */ Blt_Chain *tickLabels; /* Contains major tick label strings * and their offsets along the axis. */ Region2D region; Tk_3DBorder border; int borderWidth; int relief; } Axis; #define AXIS_CONFIG_MAJOR (1<<4) /* User specified major tick intervals. */ #define AXIS_CONFIG_MINOR (1<<5) /* User specified minor tick intervals. */ #define AXIS_ONSCREEN (1<<6) /* Axis is displayed on the screen via * the "use" operation */ #define AXIS_DIRTY (1<<7) #define AXIS_ALLOW_NULL (1<<12) /* * ------------------------------------------------------------------- * * Axis2D -- * * The pair of axes mapping a point onto the graph. * * ------------------------------------------------------------------- */ typedef struct { Axis *x, *y; } Axis2D; #endif /* _BLT_GR_AXIS_H */ blt-2.4z.orig/src/bltGrBar.c0100644000175000017500000021251107542177233014412 0ustar dokodoko /* * bltGrBar.c -- * * This module implements barchart elements for the BLT graph widget. * * Copyright 1993-1998 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. */ #include "bltGraph.h" #include #include "bltGrElem.h" typedef struct { char *name; /* Pen style identifier. If NULL pen * was statically allocated. */ Blt_Uid classUid; /* Type of pen */ char *typeId; /* String token identifying the type of pen */ unsigned int flags; /* Indicates if the pen element is active or * normal */ int refCount; /* Reference count for elements using * this pen. */ Blt_HashEntry *hashPtr; Tk_ConfigSpec *specsPtr; /* Configuration specifications */ PenConfigureProc *configProc; PenDestroyProc *destroyProc; XColor *fgColor; /* Foreground color of bar */ Tk_3DBorder border; /* 3D border and background color */ int borderWidth; /* 3D border width of bar */ int relief; /* Relief of the bar */ Pixmap stipple; /* Stipple */ GC gc; /* Graphics context */ /* Error bar attributes. */ int errorBarShow; /* Describes which error bars to * display: none, x, y, or * both. */ int errorBarLineWidth; /* Width of the error bar segments. */ int errorBarCapWidth; XColor *errorBarColor; /* Color of the error bar. */ GC errorBarGC; /* Error bar graphics context. */ /* Show value attributes. */ int valueShow; /* Indicates whether to display data value. * Values are x, y, or none. */ char *valueFormat; /* A printf format string. */ TextStyle valueStyle; /* Text attributes (color, font, * rotation, etc.) of the value. */ } BarPen; typedef struct { Weight weight; /* Weight range where this pen is valid. */ BarPen *penPtr; /* Pen to draw */ Segment2D *xErrorBars; /* Point to start of this pen's X-error bar * segments in the element's array. */ Segment2D *yErrorBars; /* Point to start of this pen's Y-error bar * segments in the element's array. */ int xErrorBarCnt; /* # of error bars for this pen. */ int yErrorBarCnt; /* # of error bars for this pen. */ int errorBarCapWidth; /* Length of the cap ends on each * error bar. */ int symbolSize; /* Size of the pen's symbol scaled to the * current graph size. */ /* Bar chart specific data. */ XRectangle *rectangles; /* Indicates starting location in bar * array for this pen. */ int nRects; /* Number of bar segments for this pen. */ } BarPenStyle; typedef struct { char *name; /* Identifier to refer the * element. Used in the "insert", * "delete", or "show", commands. */ Blt_Uid classUid; /* Type of element; either * bltBarElementUid, bltLineElementUid, or * bltStripElementUid. */ Graph *graphPtr; /* Graph widget of element*/ unsigned int flags; /* Indicates if the entire element is * active, or if coordinates need to * be calculated */ char **tags; int hidden; /* If non-zero, don't display the element. */ Blt_HashEntry *hashPtr; char *label; /* Label displayed in legend */ int labelRelief; /* Relief of label in legend. */ Axis2D axes; ElemVector x, y, w; /* Contains array of numeric values */ ElemVector xError; /* Relative/symmetric X error values. */ ElemVector yError; /* Relative/symmetric Y error values. */ ElemVector xHigh, xLow; /* Absolute/asymmetric X-coordinate high/low error values. */ ElemVector yHigh, yLow; /* Absolute/asymmetric Y-coordinate high/low error values. */ int *activeIndices; /* Array of indices (malloc-ed) that * indicate the data points have been * selected as active (drawn with * "active" colors). */ int nActiveIndices; /* Number of active data points. Special * case: if nActiveIndices < 0 and the * active bit is set in "flags", then all * data points are drawn active. */ ElementProcs *procsPtr; /* Class information for bar elements */ Tk_ConfigSpec *specsPtr; /* Configuration specifications */ Segment2D *xErrorBars; /* Point to start of this pen's X-error bar * segments in the element's array. */ Segment2D *yErrorBars; /* Point to start of this pen's Y-error bar * segments in the element's array. */ int xErrorBarCnt; /* # of error bars for this pen. */ int yErrorBarCnt; /* # of error bars for this pen. */ int *xErrorToData; /* Maps individual error bar segments back * to the data point associated with it. */ int *yErrorToData; /* Maps individual error bar segments back * to the data point associated with it. */ int errorBarCapWidth; /* Length of cap on error bars */ BarPen *activePenPtr; /* Standard Pens */ BarPen *normalPenPtr; Blt_Chain *palette; /* Chain of pen style information. */ /* Symbol scaling */ int scaleSymbols; /* If non-zero, the symbols will scale * in size as the graph is zoomed * in/out. */ double xRange, yRange; /* Initial X-axis and Y-axis ranges: * used to scale the size of element's * symbol. */ int state; /* * Bar specific attributes */ BarPen builtinPen; int *rectToData; XRectangle *rectangles; /* Array of rectangles comprising the bar * segments of the element. */ int nRects; /* # of visible bar segments for element */ int padX; /* Spacing on either side of bar */ double barWidth; int nActive; XRectangle *activeRects; int *activeToData; } Bar; extern Tk_CustomOption bltBarPenOption; extern Tk_CustomOption bltDataOption; extern Tk_CustomOption bltDataPairsOption; extern Tk_CustomOption bltDistanceOption; extern Tk_CustomOption bltListOption; extern Tk_CustomOption bltXAxisOption; extern Tk_CustomOption bltYAxisOption; extern Tk_CustomOption bltShadowOption; extern Tk_CustomOption bltFillOption; extern Tk_CustomOption bltColorOption; extern Tk_CustomOption bltStateOption; extern Tk_OptionParseProc Blt_StringToStyles; extern Tk_OptionPrintProc Blt_StylesToString; static Tk_OptionParseProc StringToBarMode; static Tk_OptionPrintProc BarModeToString; static Tk_CustomOption stylesOption = { Blt_StringToStyles, Blt_StylesToString, (ClientData)sizeof(BarPenStyle) }; Tk_CustomOption bltBarModeOption = { StringToBarMode, BarModeToString, (ClientData)0 }; #define DEF_BAR_ACTIVE_PEN "activeBar" #define DEF_BAR_AXIS_X "x" #define DEF_BAR_AXIS_Y "y" #define DEF_BAR_BACKGROUND "navyblue" #define DEF_BAR_BG_MONO BLACK #define DEF_BAR_BORDERWIDTH "2" #define DEF_BAR_DATA (char *)NULL #define DEF_BAR_ERRORBAR_COLOR "defcolor" #define DEF_BAR_ERRORBAR_LINE_WIDTH "1" #define DEF_BAR_ERRORBAR_CAP_WIDTH "1" #define DEF_BAR_FOREGROUND "blue" #define DEF_BAR_FG_MONO WHITE #define DEF_BAR_HIDE "no" #define DEF_BAR_LABEL (char *)NULL #define DEF_BAR_LABEL_RELIEF "flat" #define DEF_BAR_NORMAL_STIPPLE "" #define DEF_BAR_RELIEF "raised" #define DEF_BAR_SHOW_ERRORBARS "both" #define DEF_BAR_STATE "normal" #define DEF_BAR_STYLES "" #define DEF_BAR_TAGS "all" #define DEF_BAR_WIDTH "0.0" #define DEF_BAR_DATA (char *)NULL #define DEF_PEN_ACTIVE_BACKGROUND "red" #define DEF_PEN_ACTIVE_BG_MONO WHITE #define DEF_PEN_ACTIVE_FOREGROUND "pink" #define DEF_PEN_ACTIVE_FG_MONO BLACK #define DEF_PEN_BORDERWIDTH "2" #define DEF_PEN_NORMAL_BACKGROUND "navyblue" #define DEF_PEN_NORMAL_BG_MONO BLACK #define DEF_PEN_NORMAL_FOREGROUND "blue" #define DEF_PEN_NORMAL_FG_MONO WHITE #define DEF_PEN_RELIEF "raised" #define DEF_PEN_STIPPLE "" #define DEF_PEN_TYPE "bar" #define DEF_PEN_VALUE_ANCHOR "s" #define DEF_PEN_VALUE_COLOR RGB_BLACK #define DEF_PEN_VALUE_FONT STD_FONT_SMALL #define DEF_PEN_VALUE_FORMAT "%g" #define DEF_PEN_VALUE_ROTATE (char *)NULL #define DEF_PEN_VALUE_SHADOW (char *)NULL #define DEF_PEN_SHOW_VALUES "no" static Tk_ConfigSpec barPenConfigSpecs[] = { {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_PEN_ACTIVE_BACKGROUND, Tk_Offset(BarPen, border), TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY | ACTIVE_PEN}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_PEN_ACTIVE_BACKGROUND, Tk_Offset(BarPen, border), TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY | ACTIVE_PEN}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_PEN_NORMAL_BACKGROUND, Tk_Offset(BarPen, border), TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY | NORMAL_PEN}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_PEN_NORMAL_BACKGROUND, Tk_Offset(BarPen, border), TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY | NORMAL_PEN}, {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, ALL_PENS}, {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, ALL_PENS}, {TK_CONFIG_CUSTOM, "-borderwidth", "borderWidth", "BorderWidth", DEF_PEN_BORDERWIDTH, Tk_Offset(BarPen, borderWidth), ALL_PENS, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-errorbarcolor", "errorBarColor", "ErrorBarColor", DEF_BAR_ERRORBAR_COLOR, Tk_Offset(BarPen, errorBarColor), ALL_PENS, &bltColorOption}, {TK_CONFIG_CUSTOM, "-errorbarwidth", "errorBarWidth", "ErrorBarWidth", DEF_BAR_ERRORBAR_LINE_WIDTH, Tk_Offset(BarPen, errorBarLineWidth), ALL_PENS | TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-errorbarcap", "errorBarCap", "ErrorBarCap", DEF_BAR_ERRORBAR_CAP_WIDTH, Tk_Offset(BarPen, errorBarCapWidth), ALL_PENS | TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *)NULL, (char *)NULL, 0, ALL_PENS}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_PEN_ACTIVE_FOREGROUND, Tk_Offset(BarPen, fgColor), ACTIVE_PEN | TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_PEN_ACTIVE_FOREGROUND, Tk_Offset(BarPen, fgColor), ACTIVE_PEN | TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_PEN_NORMAL_FOREGROUND, Tk_Offset(BarPen, fgColor), NORMAL_PEN | TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_PEN_NORMAL_FOREGROUND, Tk_Offset(BarPen, fgColor), NORMAL_PEN | TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY}, {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_PEN_RELIEF, Tk_Offset(BarPen, relief), ALL_PENS}, {TK_CONFIG_CUSTOM, "-showerrorbars", "showErrorBars", "ShowErrorBars", DEF_BAR_SHOW_ERRORBARS, Tk_Offset(BarPen, errorBarShow), TK_CONFIG_DONT_SET_DEFAULT, &bltFillOption}, {TK_CONFIG_CUSTOM, "-showvalues", "showValues", "ShowValues", DEF_PEN_SHOW_VALUES, Tk_Offset(BarPen, valueShow), ALL_PENS | TK_CONFIG_DONT_SET_DEFAULT, &bltFillOption}, {TK_CONFIG_BITMAP, "-stipple", "stipple", "Stipple", DEF_PEN_STIPPLE, Tk_Offset(BarPen, stipple), ALL_PENS | TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-type", (char *)NULL, (char *)NULL, DEF_PEN_TYPE, Tk_Offset(BarPen, typeId), ALL_PENS | TK_CONFIG_NULL_OK}, {TK_CONFIG_ANCHOR, "-valueanchor", "valueAnchor", "ValueAnchor", DEF_PEN_VALUE_ANCHOR, Tk_Offset(BarPen, valueStyle.anchor), ALL_PENS}, {TK_CONFIG_COLOR, "-valuecolor", "valueColor", "ValueColor", DEF_PEN_VALUE_COLOR, Tk_Offset(BarPen, valueStyle.color), ALL_PENS}, {TK_CONFIG_FONT, "-valuefont", "valueFont", "ValueFont", DEF_PEN_VALUE_FONT, Tk_Offset(BarPen, valueStyle.font), ALL_PENS}, {TK_CONFIG_STRING, "-valueformat", "valueFormat", "ValueFormat", DEF_PEN_VALUE_FORMAT, Tk_Offset(BarPen, valueFormat), ALL_PENS | TK_CONFIG_NULL_OK}, {TK_CONFIG_DOUBLE, "-valuerotate", "valueRotate", "ValueRotate", DEF_PEN_VALUE_ROTATE, Tk_Offset(BarPen, valueStyle.theta), ALL_PENS}, {TK_CONFIG_CUSTOM, "-valueshadow", "valueShadow", "ValueShadow", DEF_PEN_VALUE_SHADOW, Tk_Offset(BarPen, valueStyle.shadow), ALL_PENS, &bltShadowOption}, {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} }; static Tk_ConfigSpec barElemConfigSpecs[] = { {TK_CONFIG_CUSTOM, "-activepen", "activePen", "ActivePen", DEF_BAR_ACTIVE_PEN, Tk_Offset(Bar, activePenPtr), TK_CONFIG_NULL_OK, &bltBarPenOption}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_BAR_BACKGROUND, Tk_Offset(Bar, builtinPen.border), TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_BAR_BACKGROUND, Tk_Offset(Bar, builtinPen.border), TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY}, {TK_CONFIG_DOUBLE, "-barwidth", "barWidth", "BarWidth", DEF_BAR_WIDTH, Tk_Offset(Bar, barWidth), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags", DEF_BAR_TAGS, Tk_Offset(Bar, tags), TK_CONFIG_NULL_OK, &bltListOption}, {TK_CONFIG_CUSTOM, "-borderwidth", "borderWidth", "BorderWidth", DEF_BAR_BORDERWIDTH, Tk_Offset(Bar, builtinPen.borderWidth), 0, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-errorbarcolor", "errorBarColor", "ErrorBarColor", DEF_BAR_ERRORBAR_COLOR, Tk_Offset(Bar, builtinPen.errorBarColor), 0, &bltColorOption}, {TK_CONFIG_CUSTOM, "-errorbarwidth", "errorBarWidth", "ErrorBarWidth", DEF_BAR_ERRORBAR_LINE_WIDTH, Tk_Offset(Bar, builtinPen.errorBarLineWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-errorbarcap", "errorBarCap", "ErrorBarCap", DEF_BAR_ERRORBAR_CAP_WIDTH, Tk_Offset(Bar, builtinPen.errorBarCapWidth), ALL_PENS | TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_CUSTOM, "-data", "data", "Data", (char *)NULL, 0, 0, &bltDataPairsOption}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_BAR_FOREGROUND, Tk_Offset(Bar, builtinPen.fgColor), TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_BAR_FOREGROUND, Tk_Offset(Bar, builtinPen.fgColor), TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY}, {TK_CONFIG_STRING, "-label", "label", "Label", DEF_BAR_LABEL, Tk_Offset(Bar, label), TK_CONFIG_NULL_OK}, {TK_CONFIG_RELIEF, "-labelrelief", "labelRelief", "LabelRelief", DEF_BAR_LABEL_RELIEF, Tk_Offset(Bar, labelRelief), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide", DEF_BAR_HIDE, Tk_Offset(Bar, hidden), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-mapx", "mapX", "MapX", DEF_BAR_AXIS_X, Tk_Offset(Bar, axes.x), 0, &bltXAxisOption}, {TK_CONFIG_CUSTOM, "-mapy", "mapY", "MapY", DEF_BAR_AXIS_Y, Tk_Offset(Bar, axes.y), 0, &bltYAxisOption}, {TK_CONFIG_CUSTOM, "-pen", "pen", "Pen", (char *)NULL, Tk_Offset(Bar, normalPenPtr), TK_CONFIG_NULL_OK, &bltBarPenOption}, {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_BAR_RELIEF, Tk_Offset(Bar, builtinPen.relief), 0}, {TK_CONFIG_CUSTOM, "-showerrorbars", "showErrorBars", "ShowErrorBars", DEF_BAR_SHOW_ERRORBARS, Tk_Offset(Bar, builtinPen.errorBarShow), TK_CONFIG_DONT_SET_DEFAULT, &bltFillOption}, {TK_CONFIG_CUSTOM, "-showvalues", "showValues", "ShowValues", DEF_PEN_SHOW_VALUES, Tk_Offset(Bar, builtinPen.valueShow), TK_CONFIG_DONT_SET_DEFAULT, &bltFillOption}, {TK_CONFIG_CUSTOM, "-state", "state", "State", DEF_BAR_STATE, Tk_Offset(Bar, state), TK_CONFIG_DONT_SET_DEFAULT, &bltStateOption}, {TK_CONFIG_BITMAP, "-stipple", "stipple", "Stipple", DEF_BAR_NORMAL_STIPPLE, Tk_Offset(Bar, builtinPen.stipple), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-styles", "styles", "Styles", DEF_BAR_STYLES, Tk_Offset(Bar, palette), TK_CONFIG_NULL_OK, &stylesOption}, {TK_CONFIG_ANCHOR, "-valueanchor", "valueAnchor", "ValueAnchor", DEF_PEN_VALUE_ANCHOR, Tk_Offset(Bar, builtinPen.valueStyle.anchor), 0}, {TK_CONFIG_COLOR, "-valuecolor", "valueColor", "ValueColor", DEF_PEN_VALUE_COLOR, Tk_Offset(Bar, builtinPen.valueStyle.color), 0}, {TK_CONFIG_FONT, "-valuefont", "valueFont", "ValueFont", DEF_PEN_VALUE_FONT, Tk_Offset(Bar, builtinPen.valueStyle.font), 0}, {TK_CONFIG_STRING, "-valueformat", "valueFormat", "ValueFormat", DEF_PEN_VALUE_FORMAT, Tk_Offset(Bar, builtinPen.valueFormat), TK_CONFIG_NULL_OK}, {TK_CONFIG_DOUBLE, "-valuerotate", "valueRotate", "ValueRotate", DEF_PEN_VALUE_ROTATE, Tk_Offset(Bar, builtinPen.valueStyle.theta), 0}, {TK_CONFIG_CUSTOM, "-valueshadow", "valueShadow", "ValueShadow", DEF_PEN_VALUE_SHADOW, Tk_Offset(Bar, builtinPen.valueStyle.shadow), 0, &bltShadowOption}, {TK_CONFIG_CUSTOM, "-weights", "weights", "Weights", (char *)NULL, Tk_Offset(Bar, w), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-x", "xdata", "Xdata", DEF_BAR_DATA, Tk_Offset(Bar, x), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-y", "ydata", "Ydata", DEF_BAR_DATA, Tk_Offset(Bar, y), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-xdata", "xdata", "Xdata", DEF_BAR_DATA, Tk_Offset(Bar, x), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-ydata", "ydata", "Ydata", DEF_BAR_DATA, Tk_Offset(Bar, y), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-xerror", "xError", "XError", DEF_BAR_DATA, Tk_Offset(Bar, xError), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-xhigh", "xHigh", "XHigh", DEF_BAR_DATA, Tk_Offset(Bar, xHigh), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-xlow", "xLow", "XLow", DEF_BAR_DATA, Tk_Offset(Bar, xLow), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-yerror", "yError", "YError", DEF_BAR_DATA, Tk_Offset(Bar, yError), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-yhigh", "yHigh", "YHigh", DEF_BAR_DATA, Tk_Offset(Bar, yHigh), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-ylow", "yLow", "YLow", DEF_BAR_DATA, Tk_Offset(Bar, yLow), 0, &bltDataOption}, {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} }; /* Forward declarations */ static PenConfigureProc ConfigurePen; static PenDestroyProc DestroyPen; static ElementClosestProc ClosestBar; static ElementConfigProc ConfigureBar; static ElementDestroyProc DestroyBar; static ElementDrawProc DrawActiveBar; static ElementDrawProc DrawNormalBar; static ElementDrawSymbolProc DrawSymbol; static ElementExtentsProc GetBarExtents; static ElementToPostScriptProc ActiveBarToPostScript; static ElementToPostScriptProc NormalBarToPostScript; static ElementSymbolToPostScriptProc SymbolToPostScript; static ElementMapProc MapBar; INLINE static int Round(x) register double x; { return (int) (x + ((x < 0.0) ? -0.5 : 0.5)); } /* * ---------------------------------------------------------------------- * Custom option parse and print procedures * ---------------------------------------------------------------------- */ /* * ---------------------------------------------------------------------- * * NameOfBarMode -- * * Converts the integer representing the mode style into a string. * * ---------------------------------------------------------------------- */ static char * NameOfBarMode(mode) BarMode mode; { switch (mode) { case MODE_INFRONT: return "infront"; case MODE_OVERLAP: return "overlap"; case MODE_STACKED: return "stacked"; case MODE_ALIGNED: return "aligned"; default: return "unknown mode value"; } } /* * ---------------------------------------------------------------------- * * StringToMode -- * * Converts the mode string into its numeric representation. * * Valid mode strings are: * * "infront" Draw a full bar at each point in the element. * * "stacked" Stack bar segments vertically. Each stack is defined * by each ordinate at a particular abscissa. The height * of each segment is represented by the sum the previous * ordinates. * * "aligned" Align bar segments as smaller slices one next to * the other. Like "stacks", aligned segments are * defined by each ordinate at a particular abscissa. * * Results: * A standard Tcl result. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToBarMode(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* Mode style string */ char *widgRec; /* Cubicle structure record */ int offset; /* Offset of style in record */ { BarMode *modePtr = (BarMode *)(widgRec + offset); unsigned int length; char c; c = string[0]; length = strlen(string); if ((c == 'n') && (strncmp(string, "normal", length) == 0)) { *modePtr = MODE_INFRONT; } else if ((c == 'i') && (strncmp(string, "infront", length) == 0)) { *modePtr = MODE_INFRONT; } else if ((c == 's') && (strncmp(string, "stacked", length) == 0)) { *modePtr = MODE_STACKED; } else if ((c == 'a') && (strncmp(string, "aligned", length) == 0)) { *modePtr = MODE_ALIGNED; } else if ((c == 'o') && (strncmp(string, "overlap", length) == 0)) { *modePtr = MODE_OVERLAP; } else { Tcl_AppendResult(interp, "bad mode argument \"", string, "\": should be \"infront\", \"stacked\", \"overlap\", or \"aligned\"", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* * ---------------------------------------------------------------------- * * BarModeToString -- * * Returns the mode style string based upon the mode flags. * * Results: * The mode style string is returned. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * BarModeToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Row/column structure record */ int offset; /* Offset of mode in Partition record */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { BarMode mode = *(BarMode *)(widgRec + offset); return NameOfBarMode(mode); } /* * Zero out the style's number of rectangles and errorbars. */ static void ClearPalette(palette) Blt_Chain *palette; { register BarPenStyle *stylePtr; Blt_ChainLink *linkPtr; for (linkPtr = Blt_ChainFirstLink(palette); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { stylePtr = Blt_ChainGetValue(linkPtr); stylePtr->xErrorBarCnt = stylePtr->yErrorBarCnt = stylePtr->nRects = 0; } } static int ConfigurePen(graphPtr, penPtr) Graph *graphPtr; Pen *penPtr; { BarPen *bpPtr = (BarPen *)penPtr; XGCValues gcValues; unsigned long gcMask; int fillStyle; GC newGC; long defColor; Blt_ResetTextStyle(graphPtr->tkwin, &(bpPtr->valueStyle)); gcMask = GCForeground; if (bpPtr->fgColor != NULL) { defColor = bpPtr->fgColor->pixel; gcValues.foreground = bpPtr->fgColor->pixel; } else if (bpPtr->border != NULL) { defColor = Tk_3DBorderColor(bpPtr->border)->pixel; gcValues.foreground = Tk_3DBorderColor(bpPtr->border)->pixel; } else { defColor = BlackPixel(graphPtr->display, Tk_ScreenNumber(graphPtr->tkwin)); } if ((bpPtr->fgColor != NULL) && (bpPtr->border != NULL)) { gcMask |= GCBackground; gcValues.background = Tk_3DBorderColor(bpPtr->border)->pixel; fillStyle = FillOpaqueStippled; } else { fillStyle = FillStippled; } if (bpPtr->stipple != None) { gcValues.stipple = bpPtr->stipple; gcValues.fill_style = fillStyle; gcMask |= (GCStipple | GCFillStyle); } newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues); if (bpPtr->gc != NULL) { Tk_FreeGC(graphPtr->display, bpPtr->gc); } bpPtr->gc = newGC; gcMask = GCForeground | GCLineWidth; if (bpPtr->errorBarColor == COLOR_DEFAULT) { gcValues.foreground = defColor; } else { gcValues.foreground = bpPtr->errorBarColor->pixel; } gcValues.line_width = LineWidth(bpPtr->errorBarLineWidth); newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues); if (bpPtr->errorBarGC != NULL) { Tk_FreeGC(graphPtr->display, bpPtr->errorBarGC); } bpPtr->errorBarGC = newGC; return TCL_OK; } static void DestroyPen(graphPtr, penPtr) Graph *graphPtr; Pen *penPtr; { BarPen *bpPtr = (BarPen *)penPtr; Blt_FreeTextStyle(graphPtr->display, &(bpPtr->valueStyle)); if (bpPtr->gc != NULL) { Tk_FreeGC(graphPtr->display, bpPtr->gc); } if (bpPtr->errorBarGC != NULL) { Tk_FreeGC(graphPtr->display, bpPtr->errorBarGC); } } static void InitPen(penPtr) BarPen *penPtr; { Blt_InitTextStyle(&(penPtr->valueStyle)); penPtr->specsPtr = barPenConfigSpecs; penPtr->configProc = ConfigurePen; penPtr->destroyProc = DestroyPen; penPtr->relief = TK_RELIEF_RAISED; penPtr->flags = NORMAL_PEN; penPtr->errorBarShow = SHOW_BOTH; penPtr->valueShow = SHOW_NONE; penPtr->borderWidth = 2; } Pen * Blt_BarPen(penName) char *penName; { BarPen *penPtr; penPtr = Blt_Calloc(1, sizeof(BarPen)); assert(penPtr); InitPen(penPtr); penPtr->name = Blt_Strdup(penName); if (strcmp(penName, "activeBar") == 0) { penPtr->flags = ACTIVE_PEN; } return (Pen *) penPtr; } /* * ---------------------------------------------------------------------- * * CheckStacks -- * * Check that the data limits are not superseded by the heights * of stacked bar segments. The heights are calculated by * Blt_ComputeStacks. * * Results: * If the y-axis limits need to be adjusted for stacked segments, * *minPtr* or *maxPtr* are updated. * * Side effects: * Autoscaling of the y-axis is affected. * * ---------------------------------------------------------------------- */ static void CheckStacks(graphPtr, pairPtr, minPtr, maxPtr) Graph *graphPtr; Axis2D *pairPtr; double *minPtr, *maxPtr; /* Current minimum maximum for y-axis */ { FreqInfo *infoPtr; register int i; if ((graphPtr->mode != MODE_STACKED) || (graphPtr->nStacks == 0)) { return; } infoPtr = graphPtr->freqArr; for (i = 0; i < graphPtr->nStacks; i++) { if ((infoPtr->axes.x == pairPtr->x) && (infoPtr->axes.y == pairPtr->y)) { /* * Check if any of the y-values (because of stacking) are * greater than the current limits of the graph. */ if (infoPtr->sum < 0.0) { if (*minPtr > infoPtr->sum) { *minPtr = infoPtr->sum; } } else { if (*maxPtr < infoPtr->sum) { *maxPtr = infoPtr->sum; } } } infoPtr++; } } /* * ---------------------------------------------------------------------- * * ConfigureBar -- * * Sets up the appropriate configuration parameters in the GC. * It is assumed the parameters have been previously set by * a call to Tk_ConfigureWidget. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then interp->result contains an error message. * * Side effects: * Configuration information such as bar foreground/background * color and stipple etc. get set in a new GC. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ConfigureBar(graphPtr, elemPtr) Graph *graphPtr; register Element *elemPtr; { Bar *barPtr = (Bar *)elemPtr; Blt_ChainLink *linkPtr; if (ConfigurePen(graphPtr, (Pen *)&(barPtr->builtinPen)) != TCL_OK) { return TCL_ERROR; } /* * Point to the static normal pen if no external pens have * been selected. */ if (barPtr->normalPenPtr == NULL) { barPtr->normalPenPtr = &(barPtr->builtinPen); } linkPtr = Blt_ChainFirstLink(barPtr->palette); if (linkPtr != NULL) { BarPenStyle *stylePtr; stylePtr = Blt_ChainGetValue(linkPtr); stylePtr->penPtr = barPtr->normalPenPtr; } if (Blt_ConfigModified(barPtr->specsPtr, "-barwidth", "-*data", "-map*", "-label", "-hide", "-x", "-y", (char *)NULL)) { barPtr->flags |= MAP_ITEM; } return TCL_OK; } static void GetBarExtents(elemPtr, extsPtr) Element *elemPtr; Extents2D *extsPtr; { Graph *graphPtr = elemPtr->graphPtr; Bar *barPtr = (Bar *)elemPtr; double middle, barWidth; int nPoints; extsPtr->top = extsPtr->left = DBL_MAX; extsPtr->bottom = extsPtr->right = -DBL_MAX; nPoints = NumberOfPoints(barPtr); if (nPoints < 1) { return; /* No data points */ } barWidth = graphPtr->barWidth; if (barPtr->barWidth > 0.0) { barWidth = barPtr->barWidth; } middle = barWidth * 0.5; extsPtr->left = barPtr->x.min - middle; extsPtr->right = barPtr->x.max + middle; extsPtr->top = barPtr->y.min; extsPtr->bottom = barPtr->y.max; if (extsPtr->bottom < graphPtr->baseline) { extsPtr->bottom = graphPtr->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 ((graphPtr->mode == MODE_STACKED) && (graphPtr->nStacks > 0)) { CheckStacks(graphPtr, &(elemPtr->axes), &(extsPtr->top), &(extsPtr->bottom)); } /* Warning: You get what you deserve if the x-axis is logScale */ if (elemPtr->axes.x->logScale) { extsPtr->left = Blt_FindElemVectorMinimum(&(barPtr->x), DBL_MIN) + middle; } /* Fix y-min limits for barchart */ if (elemPtr->axes.y->logScale) { if ((extsPtr->top <= 0.0) || (extsPtr->top > 1.0)) { extsPtr->top = 1.0; } } else { if (extsPtr->top > 0.0) { extsPtr->top = 0.0; } } /* Correct the extents for error bars if they exist. */ if (elemPtr->xError.nValues > 0) { register int i; double x; /* Correct the data limits for error bars */ nPoints = MIN(elemPtr->xError.nValues, nPoints); for (i = 0; i < nPoints; i++) { x = elemPtr->x.valueArr[i] + elemPtr->xError.valueArr[i]; if (x > extsPtr->right) { extsPtr->right = x; } x = elemPtr->x.valueArr[i] - elemPtr->xError.valueArr[i]; if (elemPtr->axes.x->logScale) { if (x < 0.0) { x = -x; /* Mirror negative values, instead * of ignoring them. */ } if ((x > DBL_MIN) && (x < extsPtr->left)) { extsPtr->left = x; } } else if (x < extsPtr->left) { extsPtr->left = x; } } } else { if ((elemPtr->xHigh.nValues > 0) && (elemPtr->xHigh.max > extsPtr->right)) { extsPtr->right = elemPtr->xHigh.max; } if (elemPtr->xLow.nValues > 0) { double left; if ((elemPtr->xLow.min <= 0.0) && (elemPtr->axes.x->logScale)) { left = Blt_FindElemVectorMinimum(&elemPtr->xLow, DBL_MIN); } else { left = elemPtr->xLow.min; } if (left < extsPtr->left) { extsPtr->left = left; } } } if (elemPtr->yError.nValues > 0) { register int i; double y; nPoints = MIN(elemPtr->yError.nValues, nPoints); for (i = 0; i < nPoints; i++) { y = elemPtr->y.valueArr[i] + elemPtr->yError.valueArr[i]; if (y > extsPtr->bottom) { extsPtr->bottom = y; } y = elemPtr->y.valueArr[i] - elemPtr->yError.valueArr[i]; if (elemPtr->axes.y->logScale) { if (y < 0.0) { y = -y; /* Mirror negative values, instead * of ignoring them. */ } if ((y > DBL_MIN) && (y < extsPtr->left)) { extsPtr->top = y; } } else if (y < extsPtr->top) { extsPtr->top = y; } } } else { if ((elemPtr->yHigh.nValues > 0) && (elemPtr->yHigh.max > extsPtr->bottom)) { extsPtr->bottom = elemPtr->yHigh.max; } if (elemPtr->yLow.nValues > 0) { double top; if ((elemPtr->yLow.min <= 0.0) && (elemPtr->axes.y->logScale)) { top = Blt_FindElemVectorMinimum(&elemPtr->yLow, DBL_MIN); } else { top = elemPtr->yLow.min; } if (top < extsPtr->top) { extsPtr->top = top; } } } } /* * ---------------------------------------------------------------------- * * ClosestBar -- * * Find the bar segment closest to the window coordinates point * specified. * * Note: This does not return the height of the stacked segment * (in graph coordinates) properly. * * Results: * Returns 1 if the point is width any bar segment, otherwise 0. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static void ClosestBar(graphPtr, elemPtr, searchPtr) Graph *graphPtr; /* Graph widget record */ Element *elemPtr; /* Bar element */ ClosestSearch *searchPtr; /* Info of closest point in element */ { Bar *barPtr = (Bar *)elemPtr; Point2D *pointPtr, *endPtr; Point2D t, outline[5]; XRectangle *rectPtr; double left, right, top, bottom; double minDist, dist; int imin; register int i; minDist = searchPtr->dist; imin = 0; rectPtr = barPtr->rectangles; for (i = 0; i < barPtr->nRects; i++) { if (PointInRectangle(rectPtr, searchPtr->x, searchPtr->y)) { imin = barPtr->rectToData[i]; minDist = 0.0; break; } left = rectPtr->x, top = rectPtr->y; right = (double)(rectPtr->x + rectPtr->width); bottom = (double)(rectPtr->y + rectPtr->height); 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; for (pointPtr = outline, endPtr = outline + 4; pointPtr < endPtr; pointPtr++) { t = Blt_GetProjection(searchPtr->x, searchPtr->y, pointPtr, pointPtr + 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; } dist = hypot((t.x - searchPtr->x), (t.y - searchPtr->y)); if (dist < minDist) { minDist = dist; imin = barPtr->rectToData[i]; } } rectPtr++; } if (minDist < searchPtr->dist) { searchPtr->elemPtr = (Element *)elemPtr; searchPtr->dist = minDist; searchPtr->index = imin; searchPtr->point.x = (double)barPtr->x.valueArr[imin]; searchPtr->point.y = (double)barPtr->y.valueArr[imin]; } } /* *---------------------------------------------------------------------- * * MergePens -- * * Reorders the both arrays of points and errorbars to merge pens. * * Results: * None. * * Side effects: * The old arrays are freed and new ones allocated containing * the reordered points and errorbars. * *---------------------------------------------------------------------- */ static void MergePens(barPtr, dataToStyle) Bar *barPtr; PenStyle **dataToStyle; { BarPenStyle *stylePtr; Blt_ChainLink *linkPtr; if (Blt_ChainGetLength(barPtr->palette) < 2) { linkPtr = Blt_ChainFirstLink(barPtr->palette); stylePtr = Blt_ChainGetValue(linkPtr); stylePtr->nRects = barPtr->nRects; stylePtr->rectangles = barPtr->rectangles; stylePtr->symbolSize = barPtr->rectangles->width / 2; stylePtr->xErrorBarCnt = barPtr->xErrorBarCnt; stylePtr->xErrorBars = barPtr->xErrorBars; stylePtr->yErrorBarCnt = barPtr->yErrorBarCnt; stylePtr->yErrorBars = barPtr->yErrorBars; return; } /* We have more than one style. Group bar segments of like pen * styles together. */ if (barPtr->nRects > 0) { XRectangle *rectangles; int *rectToData; int dataIndex; register XRectangle *rectPtr; register int *indexPtr; register int i; rectangles = Blt_Malloc(barPtr->nRects * sizeof(XRectangle)); rectToData = Blt_Malloc(barPtr->nRects * sizeof(int)); assert(rectangles && rectToData); rectPtr = rectangles, indexPtr = rectToData; for (linkPtr = Blt_ChainFirstLink(barPtr->palette); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { stylePtr = Blt_ChainGetValue(linkPtr); stylePtr->symbolSize = rectPtr->width / 2; stylePtr->rectangles = rectPtr; for (i = 0; i < barPtr->nRects; i++) { dataIndex = barPtr->rectToData[i]; if (dataToStyle[dataIndex] == (PenStyle *)stylePtr) { *rectPtr++ = barPtr->rectangles[i]; *indexPtr++ = dataIndex; } } stylePtr->nRects = rectPtr - stylePtr->rectangles; } Blt_Free(barPtr->rectangles); barPtr->rectangles = rectangles; Blt_Free(barPtr->rectToData); barPtr->rectToData = rectToData; } if (barPtr->xErrorBarCnt > 0) { Segment2D *errorBars, *segPtr; int *errorToData, *indexPtr; int dataIndex; register int i; errorBars = Blt_Malloc(barPtr->xErrorBarCnt * sizeof(Segment2D)); errorToData = Blt_Malloc(barPtr->xErrorBarCnt * sizeof(int)); assert(errorBars); segPtr = errorBars, indexPtr = errorToData; for (linkPtr = Blt_ChainFirstLink(barPtr->palette); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { stylePtr = Blt_ChainGetValue(linkPtr); stylePtr->xErrorBars = segPtr; for (i = 0; i < barPtr->xErrorBarCnt; i++) { dataIndex = barPtr->xErrorToData[i]; if (dataToStyle[dataIndex] == (PenStyle *)stylePtr) { *segPtr++ = barPtr->xErrorBars[i]; *indexPtr++ = dataIndex; } } stylePtr->xErrorBarCnt = segPtr - stylePtr->xErrorBars; } Blt_Free(barPtr->xErrorBars); barPtr->xErrorBars = errorBars; Blt_Free(barPtr->xErrorToData); barPtr->xErrorToData = errorToData; } if (barPtr->yErrorBarCnt > 0) { Segment2D *errorBars, *segPtr; int *errorToData, *indexPtr; int dataIndex; register int i; errorBars = Blt_Malloc(barPtr->yErrorBarCnt * sizeof(Segment2D)); errorToData = Blt_Malloc(barPtr->yErrorBarCnt * sizeof(int)); assert(errorBars); segPtr = errorBars, indexPtr = errorToData; for (linkPtr = Blt_ChainFirstLink(barPtr->palette); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { stylePtr = Blt_ChainGetValue(linkPtr); stylePtr->yErrorBars = segPtr; for (i = 0; i < barPtr->yErrorBarCnt; i++) { dataIndex = barPtr->yErrorToData[i]; if (dataToStyle[dataIndex] == (PenStyle *)stylePtr) { *segPtr++ = barPtr->yErrorBars[i]; *indexPtr++ = dataIndex; } } stylePtr->yErrorBarCnt = segPtr - stylePtr->yErrorBars; } Blt_Free(barPtr->yErrorBars); barPtr->yErrorBars = errorBars; Blt_Free(barPtr->yErrorToData); barPtr->yErrorToData = errorToData; } } /* *---------------------------------------------------------------------- * * MapActiveBars -- * * Creates an array of points of the active graph coordinates. * * Results: * None. * * Side effects: * Memory is freed and allocated for the active point array. * *---------------------------------------------------------------------- */ static void MapActiveBars(barPtr) Bar *barPtr; { if (barPtr->activeRects != NULL) { Blt_Free(barPtr->activeRects); barPtr->activeRects = NULL; } if (barPtr->activeToData != NULL) { Blt_Free(barPtr->activeToData); barPtr->activeToData = NULL; } barPtr->nActive = 0; if (barPtr->nActiveIndices > 0) { XRectangle *activeRects; int *activeToData; register int i, n; register int count; activeRects = Blt_Malloc(sizeof(XRectangle) * barPtr->nActiveIndices); assert(activeRects); activeToData = Blt_Malloc(sizeof(int) * barPtr->nActiveIndices); assert(activeToData); count = 0; for (i = 0; i < barPtr->nRects; i++) { for (n = 0; n < barPtr->nActiveIndices; n++) { if (barPtr->rectToData[i] == barPtr->activeIndices[n]) { activeRects[count] = barPtr->rectangles[i]; activeToData[count] = i; count++; } } } barPtr->nActive = count; barPtr->activeRects = activeRects; barPtr->activeToData = activeToData; } barPtr->flags &= ~ACTIVE_PENDING; } static void ResetBar(barPtr) Bar *barPtr; { /* Release any storage associated with the display of the bar */ ClearPalette(barPtr->palette); if (barPtr->activeRects != NULL) { Blt_Free(barPtr->activeRects); } if (barPtr->activeToData != NULL) { Blt_Free(barPtr->activeToData); } if (barPtr->xErrorBars != NULL) { Blt_Free(barPtr->xErrorBars); } if (barPtr->xErrorToData != NULL) { Blt_Free(barPtr->xErrorToData); } if (barPtr->yErrorBars != NULL) { Blt_Free(barPtr->yErrorBars); } if (barPtr->yErrorToData != NULL) { Blt_Free(barPtr->yErrorToData); } if (barPtr->rectangles != NULL) { Blt_Free(barPtr->rectangles); } if (barPtr->rectToData != NULL) { Blt_Free(barPtr->rectToData); } barPtr->activeToData = barPtr->xErrorToData = barPtr->yErrorToData = barPtr->rectToData = NULL; barPtr->activeRects = barPtr->rectangles = NULL; barPtr->xErrorBars = barPtr->yErrorBars = NULL; barPtr->nActive = barPtr->xErrorBarCnt = barPtr->yErrorBarCnt = barPtr->nRects = 0; } /* * ---------------------------------------------------------------------- * * MapBar -- * * Calculates the actual window coordinates of the bar element. * The window coordinates are saved in the bar element structure. * * Results: * None. * * Notes: * A bar can have multiple segments (more than one x,y pairs). * In this case, the bar can be represented as either a set of * non-contiguous bars or a single multi-segmented (stacked) bar. * * The x-axis layout for a barchart may be presented in one of * two ways. If abscissas are used, the bars are placed at those * coordinates. Otherwise, the range will represent the number * of values. * * ---------------------------------------------------------------------- */ static void MapBar(graphPtr, elemPtr) Graph *graphPtr; Element *elemPtr; { Bar *barPtr = (Bar *)elemPtr; FreqKey key; PenStyle **dataToStyle; Point2D c1, c2; /* Two opposite corners of the rectangle * in graph coordinates. */ double *x, *y; double barWidth, barOffset; double baseline; double dx, dy; int *rectToData; /* Maps rectangles to data point indices */ int height; int invertBar; int nPoints, count; register XRectangle *rectPtr, *rectangles; register int i; int size; Blt_ChainLink *linkPtr; BarPenStyle *stylePtr; ResetBar(barPtr); nPoints = NumberOfPoints(barPtr); if (nPoints < 1) { return; /* No data points */ } barWidth = graphPtr->barWidth; if (barPtr->barWidth > 0.0) { barWidth = barPtr->barWidth; } baseline = (barPtr->axes.y->logScale) ? 1.0 : graphPtr->baseline; barOffset = barWidth * 0.5; /* * Create an array of rectangles representing the screen coordinates * of all the segments in the bar. */ rectPtr = rectangles = Blt_Malloc(nPoints * sizeof(XRectangle)); assert(rectangles); rectToData = Blt_Calloc(nPoints, sizeof(int)); assert(rectToData); x = barPtr->x.valueArr, y = barPtr->y.valueArr; count = 0; for (i = 0; i < nPoints; i++) { if (((x[i] - barWidth) > barPtr->axes.x->axisRange.max) || ((x[i] + barWidth) < barPtr->axes.x->axisRange.min)) { continue; /* Abscissa is out of range of the x-axis */ } c1.x = x[i] - barOffset; c1.y = y[i]; 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 ((graphPtr->nStacks > 0) && (graphPtr->mode != MODE_INFRONT)) { Blt_HashEntry *hPtr; key.value = x[i]; key.axes = barPtr->axes; hPtr = Blt_FindHashEntry(&(graphPtr->freqTable), (char *)&key); if (hPtr != NULL) { FreqInfo *infoPtr; double slice, width; infoPtr = (FreqInfo *)Blt_GetHashValue(hPtr); switch (graphPtr->mode) { case MODE_STACKED: c2.y = infoPtr->lastY; c1.y += c2.y; infoPtr->lastY = c1.y; break; case MODE_ALIGNED: infoPtr->count++; slice = barWidth / (double)infoPtr->freq; c1.x += slice * (infoPtr->freq - infoPtr->count); c2.x = c1.x + slice; break; case MODE_OVERLAP: infoPtr->count++; slice = barWidth / (double)(infoPtr->freq * 2); width = slice * (infoPtr->freq + 1); c1.x += slice * (infoPtr->freq - infoPtr->count); c2.x = c1.x + width; break; case MODE_INFRONT: break; } } } invertBar = FALSE; if (c1.y < c2.y) { double temp; /* Handle negative bar values by swapping ordinates */ temp = c1.y, c1.y = c2.y, c2.y = temp; invertBar = TRUE; } /* * Get the two corners of the bar segment and compute the rectangle */ c1 = Blt_Map2D(graphPtr, c1.x, c1.y, &barPtr->axes); c2 = Blt_Map2D(graphPtr, c2.x, c2.y, &barPtr->axes); /* Bound the bars vertically by the size of the graph window */ if (c1.y < 0.0) { c1.y = 0.0; } else if (c1.y > (double)graphPtr->height) { c1.y = (double)graphPtr->height; } if (c2.y < 0.0) { c2.y = 0.0; } else if (c2.y > (double)graphPtr->height) { c2.y = (double)graphPtr->height; } dx = c1.x - c2.x; dy = c1.y - c2.y; height = (int)Round(FABS(dy)); if (invertBar) { rectPtr->y = (short int)MIN(c1.y, c2.y); } else { rectPtr->y = (short int)(MAX(c1.y, c2.y)) - height; } rectPtr->x = (short int)MIN(c1.x, c2.x); rectPtr->width = (short int)Round(FABS(dx)) + 1; if (rectPtr->width < 1) { rectPtr->width = 1; } rectPtr->height = height + 1; if (rectPtr->height < 1) { rectPtr->height = 1; } rectToData[count] = i; /* Save the data index corresponding to the * rectangle */ rectPtr++; count++; } barPtr->nRects = count; barPtr->rectangles = rectangles; barPtr->rectToData = rectToData; if (barPtr->nActiveIndices > 0) { MapActiveBars(barPtr); } size = 20; if (count > 0) { size = rectangles->width; } /* Set the symbol size of all the pen styles. */ for (linkPtr = Blt_ChainFirstLink(barPtr->palette); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { stylePtr = Blt_ChainGetValue(linkPtr); stylePtr->symbolSize = size; stylePtr->errorBarCapWidth = (stylePtr->penPtr->errorBarCapWidth > 0) ? stylePtr->penPtr->errorBarCapWidth : (int)(size * 0.6666666); stylePtr->errorBarCapWidth /= 2; } dataToStyle = Blt_StyleMap((Element *)barPtr); if (((barPtr->yHigh.nValues > 0) && (barPtr->yLow.nValues > 0)) || ((barPtr->xHigh.nValues > 0) && (barPtr->xLow.nValues > 0)) || (barPtr->xError.nValues > 0) || (barPtr->yError.nValues > 0)) { Blt_MapErrorBars(graphPtr, (Element *)barPtr, dataToStyle); } MergePens(barPtr, dataToStyle); Blt_Free(dataToStyle); } /* * ----------------------------------------------------------------- * * DrawSymbol -- * * Draw a symbol centered at the given x,y window coordinate * based upon the element symbol type and size. * * Results: * None. * * Problems: * Most notable is the round-off errors generated when * calculating the centered position of the symbol. * ----------------------------------------------------------------- */ /*ARGSUSED*/ static void DrawSymbol(graphPtr, drawable, elemPtr, x, y, size) Graph *graphPtr; Drawable drawable; /* Pixmap or window to draw into */ Element *elemPtr; int x, y; int size; { BarPen *penPtr = ((Bar *)elemPtr)->normalPenPtr; int radius; if ((penPtr->border == NULL) && (penPtr->fgColor == NULL)) { return; } radius = (size / 2); size--; x -= radius; y -= radius; XSetTSOrigin(graphPtr->display, penPtr->gc, x, y); XFillRectangle(graphPtr->display, drawable, penPtr->gc, x, y, size, size); XSetTSOrigin(graphPtr->display, penPtr->gc, 0, 0); } /* * ----------------------------------------------------------------- * * DrawBarSegments -- * * Draws each of the rectangular segments for the element. * * Results: * None. * * ----------------------------------------------------------------- */ static void DrawBarSegments( Graph *graphPtr, Drawable drawable, /* Pixmap or window to draw into */ BarPen *penPtr, XRectangle *rectangles, int nRects) { register XRectangle *rectPtr; if ((penPtr->border == NULL) && (penPtr->fgColor == NULL)) { return; } XFillRectangles(graphPtr->display, drawable, penPtr->gc, rectangles, nRects); if ((penPtr->border != NULL) && (penPtr->borderWidth > 0) && (penPtr->relief != TK_RELIEF_FLAT)) { XRectangle *endPtr; for (rectPtr = rectangles, endPtr = rectangles + nRects; rectPtr < endPtr; rectPtr++) { Blt_Draw3DRectangle(graphPtr->tkwin, drawable, penPtr->border, rectPtr->x, rectPtr->y, rectPtr->width, rectPtr->height, penPtr->borderWidth, penPtr->relief); } } } /* * ----------------------------------------------------------------- * * DrawBarValues -- * * Draws the numeric value of the bar. * * Results: * None. * * ----------------------------------------------------------------- */ static void DrawBarValues( Graph *graphPtr, Drawable drawable, Bar *barPtr, BarPen *penPtr, XRectangle *rectangles, int nRects, int *rectToData) { XRectangle *rectPtr, *endPtr; int count; char *fmt; char string[TCL_DOUBLE_SPACE * 2 + 2]; double x, y; Point2D anchorPos; count = 0; fmt = penPtr->valueFormat; if (fmt == NULL) { fmt = "%g"; } for (rectPtr = rectangles, endPtr = rectangles + nRects; rectPtr < endPtr; rectPtr++) { x = barPtr->x.valueArr[rectToData[count]]; y = barPtr->y.valueArr[rectToData[count]]; count++; if (penPtr->valueShow == SHOW_X) { sprintf(string, fmt, x); } else if (penPtr->valueShow == SHOW_Y) { sprintf(string, fmt, y); } else if (penPtr->valueShow == SHOW_BOTH) { sprintf(string, fmt, x); strcat(string, ","); sprintf(string + strlen(string), fmt, y); } if (graphPtr->inverted) { anchorPos.y = rectPtr->y + rectPtr->height * 0.5; anchorPos.x = rectPtr->x + rectPtr->width; if (y < graphPtr->baseline) { anchorPos.x -= rectPtr->width; } } else { anchorPos.x = rectPtr->x + rectPtr->width * 0.5; anchorPos.y = rectPtr->y; if (y < graphPtr->baseline) { anchorPos.y += rectPtr->height; } } Blt_DrawText(graphPtr->tkwin, drawable, string, &(penPtr->valueStyle), (int)anchorPos.x, (int)anchorPos.y); } } /* * ---------------------------------------------------------------------- * * DrawNormalBar -- * * Draws the rectangle representing the bar element. If the * relief option is set to "raised" or "sunken" and the bar * borderwidth is set (borderwidth > 0), a 3D border is drawn * around the bar. * * Don't draw bars that aren't visible (i.e. within the limits * of the axis). * * Results: * None. * * Side effects: * X drawing commands are output. * * ---------------------------------------------------------------------- */ static void DrawNormalBar(graphPtr, drawable, elemPtr) Graph *graphPtr; Drawable drawable; Element *elemPtr; { Bar *barPtr = (Bar *)elemPtr; int count; Blt_ChainLink *linkPtr; register BarPenStyle *stylePtr; BarPen *penPtr; count = 0; for (linkPtr = Blt_ChainFirstLink(barPtr->palette); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { stylePtr = Blt_ChainGetValue(linkPtr); penPtr = stylePtr->penPtr; if (stylePtr->nRects > 0) { DrawBarSegments(graphPtr, drawable, penPtr, stylePtr->rectangles, stylePtr->nRects); } if ((stylePtr->xErrorBarCnt > 0) && (penPtr->errorBarShow & SHOW_X)) { Blt_Draw2DSegments(graphPtr->display, drawable, penPtr->errorBarGC, stylePtr->xErrorBars, stylePtr->xErrorBarCnt); } if ((stylePtr->yErrorBarCnt > 0) && (penPtr->errorBarShow & SHOW_Y)) { Blt_Draw2DSegments(graphPtr->display, drawable, penPtr->errorBarGC, stylePtr->yErrorBars, stylePtr->yErrorBarCnt); } if (penPtr->valueShow != SHOW_NONE) { DrawBarValues(graphPtr, drawable, barPtr, penPtr, stylePtr->rectangles, stylePtr->nRects, barPtr->rectToData + count); } count += stylePtr->nRects; } } /* * ---------------------------------------------------------------------- * * DrawActiveBar -- * * Draws rectangles representing the active segments of the * bar element. If the -relief option is set (other than "flat") * and the borderwidth is greater than 0, a 3D border is drawn * around the each bar segment. * * Results: * None. * * Side effects: * X drawing commands are output. * * ---------------------------------------------------------------------- */ static void DrawActiveBar(graphPtr, drawable, elemPtr) Graph *graphPtr; Drawable drawable; Element *elemPtr; { Bar *barPtr = (Bar *)elemPtr; if (barPtr->activePenPtr != NULL) { BarPen *penPtr = barPtr->activePenPtr; if (barPtr->nActiveIndices > 0) { if (barPtr->flags & ACTIVE_PENDING) { MapActiveBars(barPtr); } DrawBarSegments(graphPtr, drawable, penPtr, barPtr->activeRects, barPtr->nActive); if (penPtr->valueShow != SHOW_NONE) { DrawBarValues(graphPtr, drawable, barPtr, penPtr, barPtr->activeRects, barPtr->nActive, barPtr->activeToData); } } else if (barPtr->nActiveIndices < 0) { DrawBarSegments(graphPtr, drawable, penPtr, barPtr->rectangles, barPtr->nRects); if (penPtr->valueShow != SHOW_NONE) { DrawBarValues(graphPtr, drawable, barPtr, penPtr, barPtr->rectangles, barPtr->nRects, barPtr->rectToData); } } } } /* * ----------------------------------------------------------------- * * SymbolToPostScript -- * * Draw a symbol centered at the given x,y window coordinate * based upon the element symbol type and size. * * Results: * None. * * Problems: * Most notable is the round-off errors generated when * calculating the centered position of the symbol. * * ----------------------------------------------------------------- */ /*ARGSUSED*/ static void SymbolToPostScript(graphPtr, psToken, elemPtr, x, y, size) Graph *graphPtr; PsToken psToken; Element *elemPtr; int size; double x, y; { Bar *barPtr = (Bar *)elemPtr; BarPen *bpPtr = barPtr->normalPenPtr; if ((bpPtr->border == NULL) && (bpPtr->fgColor == NULL)) { return; } /* * Build a PostScript procedure to draw the fill and outline of * the symbol after the path of the symbol shape has been formed */ Blt_AppendToPostScript(psToken, "\n", "/DrawSymbolProc {\n", " gsave\n ", (char *)NULL); if (bpPtr->stipple != None) { if (bpPtr->border != NULL) { Blt_BackgroundToPostScript(psToken,Tk_3DBorderColor(bpPtr->border)); Blt_AppendToPostScript(psToken, " Fill\n ", (char *)NULL); } if (bpPtr->fgColor != NULL) { Blt_ForegroundToPostScript(psToken, bpPtr->fgColor); } else { Blt_ForegroundToPostScript(psToken,Tk_3DBorderColor(bpPtr->border)); } Blt_StippleToPostScript(psToken, graphPtr->display, bpPtr->stipple); } else if (bpPtr->fgColor != NULL) { Blt_ForegroundToPostScript(psToken, bpPtr->fgColor); Blt_AppendToPostScript(psToken, " fill\n", (char *)NULL); } Blt_AppendToPostScript(psToken, " grestore\n", (char *)NULL); Blt_AppendToPostScript(psToken, "} def\n\n", (char *)NULL); Blt_FormatToPostScript(psToken, "%g %g %d Sq\n", x, y, size); } static void SegmentsToPostScript(graphPtr, psToken, penPtr, rectPtr, nRects) Graph *graphPtr; PsToken psToken; BarPen *penPtr; register XRectangle *rectPtr; int nRects; { XRectangle *endPtr; if ((penPtr->border == NULL) && (penPtr->fgColor == NULL)) { return; } for (endPtr = rectPtr + nRects; rectPtr < endPtr; rectPtr++) { if ((rectPtr->width < 1) || (rectPtr->height < 1)) { continue; } if (penPtr->stipple != None) { Blt_RegionToPostScript(psToken, (double)rectPtr->x, (double)rectPtr->y, (int)rectPtr->width - 1, (int)rectPtr->height - 1); if (penPtr->border != NULL) { Blt_BackgroundToPostScript(psToken, Tk_3DBorderColor(penPtr->border)); Blt_AppendToPostScript(psToken, "Fill\n", (char *)NULL); } if (penPtr->fgColor != NULL) { Blt_ForegroundToPostScript(psToken, penPtr->fgColor); } else { Blt_ForegroundToPostScript(psToken, Tk_3DBorderColor(penPtr->border)); } Blt_StippleToPostScript(psToken, graphPtr->display, penPtr->stipple); } else if (penPtr->fgColor != NULL) { Blt_ForegroundToPostScript(psToken, penPtr->fgColor); Blt_RectangleToPostScript(psToken, (double)rectPtr->x, (double)rectPtr->y, (int)rectPtr->width - 1, (int)rectPtr->height - 1); } if ((penPtr->border != NULL) && (penPtr->borderWidth > 0) && (penPtr->relief != TK_RELIEF_FLAT)) { Blt_Draw3DRectangleToPostScript(psToken, penPtr->border, (double)rectPtr->x, (double)rectPtr->y, (int)rectPtr->width, (int)rectPtr->height, penPtr->borderWidth, penPtr->relief); } } } static void BarValuesToPostScript( Graph *graphPtr, PsToken psToken, Bar *barPtr, BarPen *penPtr, XRectangle *rectangles, int nRects, int *rectToData) { XRectangle *rectPtr, *endPtr; int count; char *fmt; char string[TCL_DOUBLE_SPACE * 2 + 2]; double x, y; Point2D anchorPos; count = 0; fmt = penPtr->valueFormat; if (fmt == NULL) { fmt = "%g"; } for (rectPtr = rectangles, endPtr = rectangles + nRects; rectPtr < endPtr; rectPtr++) { x = barPtr->x.valueArr[rectToData[count]]; y = barPtr->y.valueArr[rectToData[count]]; count++; if (penPtr->valueShow == SHOW_X) { sprintf(string, fmt, x); } else if (penPtr->valueShow == SHOW_Y) { sprintf(string, fmt, y); } else if (penPtr->valueShow == SHOW_BOTH) { sprintf(string, fmt, x); strcat(string, ","); sprintf(string + strlen(string), fmt, y); } if (graphPtr->inverted) { anchorPos.y = rectPtr->y + rectPtr->height * 0.5; anchorPos.x = rectPtr->x + rectPtr->width; if (y < graphPtr->baseline) { anchorPos.x -= rectPtr->width; } } else { anchorPos.x = rectPtr->x + rectPtr->width * 0.5; anchorPos.y = rectPtr->y; if (y < graphPtr->baseline) { anchorPos.y += rectPtr->height; } } Blt_TextToPostScript(psToken, string, &(penPtr->valueStyle), anchorPos.x, anchorPos.y); } } /* * ---------------------------------------------------------------------- * * ActiveBarToPostScript -- * * Similar to the NormalBarToPostScript procedure, generates * PostScript commands to display the rectangles representing the * active bar segments of the element. * * Results: * None. * * Side effects: * PostScript pen width, dashes, and color settings are changed. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static void ActiveBarToPostScript(graphPtr, psToken, elemPtr) Graph *graphPtr; PsToken psToken; Element *elemPtr; { Bar *barPtr = (Bar *)elemPtr; if (barPtr->activePenPtr != NULL) { BarPen *penPtr = barPtr->activePenPtr; if (barPtr->nActiveIndices > 0) { if (barPtr->flags & ACTIVE_PENDING) { MapActiveBars(barPtr); } SegmentsToPostScript(graphPtr, psToken, penPtr, barPtr->activeRects, barPtr->nActive); if (penPtr->valueShow != SHOW_NONE) { BarValuesToPostScript(graphPtr, psToken, barPtr, penPtr, barPtr->activeRects, barPtr->nActive, barPtr->activeToData); } } else if (barPtr->nActiveIndices < 0) { SegmentsToPostScript(graphPtr, psToken, penPtr, barPtr->rectangles, barPtr->nRects); if (penPtr->valueShow != SHOW_NONE) { BarValuesToPostScript(graphPtr, psToken, barPtr, penPtr, barPtr->rectangles, barPtr->nRects, barPtr->rectToData); } } } } /* * ---------------------------------------------------------------------- * * NormalBarToPostScript -- * * Generates PostScript commands to form the rectangles * representing the segments of the bar element. * * Results: * None. * * Side effects: * PostScript pen width, dashes, and color settings are changed. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static void NormalBarToPostScript(graphPtr, psToken, elemPtr) Graph *graphPtr; PsToken psToken; Element *elemPtr; { Bar *barPtr = (Bar *)elemPtr; Blt_ChainLink *linkPtr; register BarPenStyle *stylePtr; int count; BarPen *penPtr; XColor *colorPtr; count = 0; for (linkPtr = Blt_ChainFirstLink(barPtr->palette); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { stylePtr = Blt_ChainGetValue(linkPtr); penPtr = stylePtr->penPtr; if (stylePtr->nRects > 0) { SegmentsToPostScript(graphPtr, psToken, penPtr, stylePtr->rectangles, stylePtr->nRects); } colorPtr = penPtr->errorBarColor; if (colorPtr == COLOR_DEFAULT) { colorPtr = penPtr->fgColor; } if ((stylePtr->xErrorBarCnt > 0) && (penPtr->errorBarShow & SHOW_X)) { Blt_LineAttributesToPostScript(psToken, colorPtr, penPtr->errorBarLineWidth, NULL, CapButt, JoinMiter); Blt_2DSegmentsToPostScript(psToken, stylePtr->xErrorBars, stylePtr->xErrorBarCnt); } if ((stylePtr->yErrorBarCnt > 0) && (penPtr->errorBarShow & SHOW_Y)) { Blt_LineAttributesToPostScript(psToken, colorPtr, penPtr->errorBarLineWidth, NULL, CapButt, JoinMiter); Blt_2DSegmentsToPostScript(psToken, stylePtr->yErrorBars, stylePtr->yErrorBarCnt); } if (penPtr->valueShow != SHOW_NONE) { BarValuesToPostScript(graphPtr, psToken, barPtr, penPtr, stylePtr->rectangles, stylePtr->nRects, barPtr->rectToData + count); } count += stylePtr->nRects; } } /* * ---------------------------------------------------------------------- * * DestroyBar -- * * Release memory and resources allocated for the bar element. * * Results: * None. * * Side effects: * Everything associated with the bar element is freed up. * * ---------------------------------------------------------------------- */ #define FreeElemVector(v) \ if ((v).clientId != NULL) { \ Blt_FreeVectorId((v).clientId); \ } else if ((v).valueArr != NULL) { \ Blt_Free((v).valueArr); \ } static void DestroyBar(graphPtr, elemPtr) Graph *graphPtr; Element *elemPtr; { Bar *barPtr = (Bar *)elemPtr; if (barPtr->normalPenPtr != &(barPtr->builtinPen)) { Blt_FreePen(graphPtr, (Pen *)barPtr->normalPenPtr); } DestroyPen(graphPtr, (Pen *)&(barPtr->builtinPen)); if (barPtr->activePenPtr != NULL) { Blt_FreePen(graphPtr, (Pen *)barPtr->activePenPtr); } FreeElemVector(barPtr->x); FreeElemVector(barPtr->y); FreeElemVector(barPtr->w); FreeElemVector(barPtr->xHigh); FreeElemVector(barPtr->xLow); FreeElemVector(barPtr->xError); FreeElemVector(barPtr->yHigh); FreeElemVector(barPtr->yLow); FreeElemVector(barPtr->yError); ResetBar(barPtr); if (barPtr->activeIndices != NULL) { Blt_Free(barPtr->activeIndices); } if (barPtr->palette != NULL) { Blt_FreePalette(graphPtr, barPtr->palette); Blt_ChainDestroy(barPtr->palette); } if (barPtr->tags != NULL) { Blt_Free(barPtr->tags); } } /* * ---------------------------------------------------------------------- * * Blt_BarElement -- * * Allocate memory and initialize methods for the new bar element. * * Results: * The pointer to the newly allocated element structure is returned. * * Side effects: * Memory is allocated for the bar element structure. * * ---------------------------------------------------------------------- */ static ElementProcs barProcs = { ClosestBar, ConfigureBar, DestroyBar, DrawActiveBar, DrawNormalBar, DrawSymbol, GetBarExtents, ActiveBarToPostScript, NormalBarToPostScript, SymbolToPostScript, MapBar, }; Element * Blt_BarElement(graphPtr, name, type) Graph *graphPtr; char *name; Blt_Uid type; { register Bar *barPtr; barPtr = Blt_Calloc(1, sizeof(Bar)); assert(barPtr); barPtr->normalPenPtr = &(barPtr->builtinPen); barPtr->procsPtr = &barProcs; barPtr->specsPtr = barElemConfigSpecs; barPtr->labelRelief = TK_RELIEF_FLAT; barPtr->classUid = type; /* By default, an element's name and label are the same. */ barPtr->label = Blt_Strdup(name); barPtr->name = Blt_Strdup(name); barPtr->graphPtr = graphPtr; barPtr->hidden = FALSE; InitPen(barPtr->normalPenPtr); barPtr->palette = Blt_ChainCreate(); return (Element *)barPtr; } /* * ---------------------------------------------------------------------- * * Blt_InitFreqTable -- * * Generate a table of abscissa frequencies. Duplicate * x-coordinates (depending upon the bar drawing mode) indicate * that something special should be done with each bar segment * mapped to the same abscissa (i.e. it should be stacked, * aligned, or overlay-ed with other segments) * * Results: * None. * * Side effects: * Memory is allocated for the bar element structure. * * ---------------------------------------------------------------------- */ void Blt_InitFreqTable(graphPtr) Graph *graphPtr; { register Element *elemPtr; Blt_ChainLink *linkPtr; Blt_HashEntry *hPtr; Blt_HashSearch cursor; Bar *barPtr; int isNew, count; int nStacks, nSegs; int nPoints; FreqKey key; Blt_HashTable freqTable; register int i; double *xArr; /* * Free resources associated with a previous frequency table. This * includes the array of frequency information and the table itself */ if (graphPtr->freqArr != NULL) { Blt_Free(graphPtr->freqArr); graphPtr->freqArr = NULL; } if (graphPtr->nStacks > 0) { Blt_DeleteHashTable(&(graphPtr->freqTable)); graphPtr->nStacks = 0; } if (graphPtr->mode == MODE_INFRONT) { return; /* No frequency table is needed for * "infront" mode */ } Blt_InitHashTable(&(graphPtr->freqTable), sizeof(FreqKey) / sizeof(int)); /* * 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. */ Blt_InitHashTable(&freqTable, sizeof(FreqKey) / sizeof(int)); nSegs = nStacks = 0; for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { elemPtr = Blt_ChainGetValue(linkPtr); if ((elemPtr->hidden) || (elemPtr->classUid != bltBarElementUid)) { continue; } nSegs++; barPtr = (Bar *)elemPtr; xArr = barPtr->x.valueArr; nPoints = NumberOfPoints(barPtr); for (i = 0; i < nPoints; i++) { key.value = xArr[i]; key.axes = barPtr->axes; hPtr = Blt_CreateHashEntry(&freqTable, (char *)&key, &isNew); assert(hPtr != NULL); if (isNew) { count = 1; } else { count = (int)Blt_GetHashValue(hPtr); if (count == 1) { nStacks++; } count++; } Blt_SetHashValue(hPtr, (ClientData)count); } } if (nSegs == 0) { return; /* No bar elements to be displayed */ } if (nStacks > 0) { FreqInfo *infoPtr; FreqKey *keyPtr; Blt_HashEntry *h2Ptr; graphPtr->freqArr = Blt_Calloc(nStacks, sizeof(FreqInfo)); assert(graphPtr->freqArr); infoPtr = graphPtr->freqArr; for (hPtr = Blt_FirstHashEntry(&freqTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { count = (int)Blt_GetHashValue(hPtr); keyPtr = (FreqKey *)Blt_GetHashKey(&freqTable, hPtr); if (count > 1) { h2Ptr = Blt_CreateHashEntry(&(graphPtr->freqTable), (char *)keyPtr, &isNew); count = (int)Blt_GetHashValue(hPtr); infoPtr->freq = count; infoPtr->axes = keyPtr->axes; Blt_SetHashValue(h2Ptr, infoPtr); infoPtr++; } } } Blt_DeleteHashTable(&freqTable); graphPtr->nStacks = nStacks; } /* * ---------------------------------------------------------------------- * * Blt_ComputeStacks -- * * Determine the height of each stack of bar segments. A stack * is created by designating two or more points with the same * abscissa. Each ordinate defines the height of a segment in * the stack. This procedure simply looks at all the data points * summing the heights of each stacked segment. The sum is saved * in the frequency information table. This value will be used * to calculate the y-axis limits (data limits aren't sufficient). * * Results: * None. * * Side effects: * The heights of each stack is computed. CheckStacks will * use this information to adjust the y-axis limits if necessary. * * ---------------------------------------------------------------------- */ void Blt_ComputeStacks(graphPtr) Graph *graphPtr; { Element *elemPtr; Bar *barPtr; FreqKey key; Blt_ChainLink *linkPtr; Blt_HashEntry *hPtr; int nPoints; register int i; register FreqInfo *infoPtr; double *xArr, *yArr; if ((graphPtr->mode != MODE_STACKED) || (graphPtr->nStacks == 0)) { return; } /* Reset the sums for all duplicate values to zero. */ infoPtr = graphPtr->freqArr; for (i = 0; i < graphPtr->nStacks; i++) { infoPtr->sum = 0.0; infoPtr++; } /* Look at each bar point, adding the ordinates of duplicate abscissas */ for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { elemPtr = Blt_ChainGetValue(linkPtr); if ((elemPtr->hidden) || (elemPtr->classUid != bltBarElementUid)) { continue; } barPtr = (Bar *)elemPtr; xArr = barPtr->x.valueArr; yArr = barPtr->y.valueArr; nPoints = NumberOfPoints(barPtr); for (i = 0; i < nPoints; i++) { key.value = xArr[i]; key.axes = barPtr->axes; hPtr = Blt_FindHashEntry(&(graphPtr->freqTable), (char *)&key); if (hPtr == NULL) { continue; } infoPtr = (FreqInfo *)Blt_GetHashValue(hPtr); infoPtr->sum += yArr[i]; } } } void Blt_ResetStacks(graphPtr) Graph *graphPtr; { register FreqInfo *infoPtr, *endPtr; for (infoPtr = graphPtr->freqArr, endPtr = graphPtr->freqArr + graphPtr->nStacks; infoPtr < endPtr; infoPtr++) { infoPtr->lastY = 0.0; infoPtr->count = 0; } } blt-2.4z.orig/src/bltGrElem.c0100644000175000017500000017062607542177233014602 0ustar dokodoko /* * bltGrElem.c -- * * This module implements generic elements for the BLT graph widget. * * Copyright 1993-1998 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. */ #include "bltGraph.h" #include "bltChain.h" #include static Tk_OptionParseProc StringToData; static Tk_OptionPrintProc DataToString; static Tk_OptionParseProc StringToDataPairs; static Tk_OptionPrintProc DataPairsToString; static Tk_OptionParseProc StringToAlong; static Tk_OptionPrintProc AlongToString; static Tk_CustomOption alongOption = { StringToAlong, AlongToString, (ClientData)0 }; Tk_CustomOption bltDataOption = { StringToData, DataToString, (ClientData)0 }; Tk_CustomOption bltDataPairsOption = { StringToDataPairs, DataPairsToString, (ClientData)0 }; extern Tk_CustomOption bltDistanceOption; static int counter; #include "bltGrElem.h" extern Element *Blt_BarElement(); extern Element *Blt_LineElement(); static Blt_VectorChangedProc VectorChangedProc; EXTERN int Blt_VectorExists2 _ANSI_ARGS_((Tcl_Interp *interp, char *vecName)); /* * ---------------------------------------------------------------------- * Custom option parse and print procedures * ---------------------------------------------------------------------- */ static int GetPenStyle(graphPtr, string, type, stylePtr) Graph *graphPtr; char *string; Blt_Uid type; PenStyle *stylePtr; { Pen *penPtr; Tcl_Interp *interp = graphPtr->interp; char **elemArr; int nElem; elemArr = NULL; if (Tcl_SplitList(interp, string, &nElem, &elemArr) != TCL_OK) { return TCL_ERROR; } if ((nElem != 1) && (nElem != 3)) { Tcl_AppendResult(interp, "bad style \"", string, "\": should be ", "\"penName\" or \"penName min max\"", (char *)NULL); if (elemArr != NULL) { Blt_Free(elemArr); } return TCL_ERROR; } if (Blt_GetPen(graphPtr, elemArr[0], type, &penPtr) != TCL_OK) { Blt_Free(elemArr); return TCL_ERROR; } if (nElem == 3) { double min, max; if ((Tcl_GetDouble(interp, elemArr[1], &min) != TCL_OK) || (Tcl_GetDouble(interp, elemArr[2], &max) != TCL_OK)) { Blt_Free(elemArr); return TCL_ERROR; } SetWeight(stylePtr->weight, min, max); } stylePtr->penPtr = penPtr; Blt_Free(elemArr); return TCL_OK; } static void SyncElemVector(vPtr) ElemVector *vPtr; { vPtr->nValues = Blt_VecLength(vPtr->vecPtr); vPtr->valueArr = Blt_VecData(vPtr->vecPtr); vPtr->min = Blt_VecMin(vPtr->vecPtr); vPtr->max = Blt_VecMax(vPtr->vecPtr); } /* *---------------------------------------------------------------------- * * FindRange -- * * Find the minimum, positive minimum, and maximum values in a * given vector and store the results in the vector structure. * * Results: * None. * * Side Effects: * Minimum, positive minimum, and maximum values are stored in * the vector. * *---------------------------------------------------------------------- */ static void FindRange(vPtr) ElemVector *vPtr; { register int i; register double *x; register double min, max; if ((vPtr->nValues < 1) || (vPtr->valueArr == NULL)) { return; /* This shouldn't ever happen. */ } x = vPtr->valueArr; min = DBL_MAX, max = -DBL_MAX; for(i = 0; i < vPtr->nValues; i++) { if (FINITE(x[i])) { min = max = x[i]; break; } } /* Initialize values to track the vector range */ for (/* empty */; i < vPtr->nValues; i++) { if (FINITE(x[i])) { if (x[i] < min) { min = x[i]; } else if (x[i] > max) { max = x[i]; } } } vPtr->min = min, vPtr->max = max; } /* *---------------------------------------------------------------------- * * Blt_FindElemVectorMinimum -- * * Find the minimum, positive minimum, and maximum values in a * given vector and store the results in the vector structure. * * Results: * None. * * Side Effects: * Minimum, positive minimum, and maximum values are stored in * the vector. * *---------------------------------------------------------------------- */ double Blt_FindElemVectorMinimum(vPtr, minLimit) ElemVector *vPtr; double minLimit; { register int i; register double *arr; register double min, x; min = DBL_MAX; arr = vPtr->valueArr; for (i = 0; i < vPtr->nValues; i++) { x = arr[i]; if (x < 0.0) { /* What do you do about negative values when using log * scale values seems like a grey area. Mirror. */ x = -x; } if ((x > minLimit) && (min > x)) { min = x; } } if (min == DBL_MAX) { min = minLimit; } return min; } static void FreeDataVector(vPtr) ElemVector *vPtr; { if (vPtr->clientId != NULL) { Blt_FreeVectorId(vPtr->clientId); /* Free the old vector */ vPtr->clientId = NULL; } else if (vPtr->valueArr != NULL) { Blt_Free(vPtr->valueArr); } vPtr->valueArr = NULL; vPtr->nValues = 0; } /* *---------------------------------------------------------------------- * * VectorChangedProc -- * * * Results: * None. * * Side Effects: * Graph is redrawn. * *---------------------------------------------------------------------- */ static void VectorChangedProc(interp, clientData, notify) Tcl_Interp *interp; ClientData clientData; Blt_VectorNotify notify; { ElemVector *vPtr = clientData; Element *elemPtr = vPtr->elemPtr; Graph *graphPtr = elemPtr->graphPtr; switch (notify) { case BLT_VECTOR_NOTIFY_DESTROY: vPtr->clientId = NULL; vPtr->valueArr = NULL; vPtr->nValues = 0; break; case BLT_VECTOR_NOTIFY_UPDATE: default: Blt_GetVectorById(interp, vPtr->clientId, &vPtr->vecPtr); SyncElemVector(vPtr); break; } graphPtr->flags |= RESET_AXES; elemPtr->flags |= MAP_ITEM; if (!elemPtr->hidden) { graphPtr->flags |= REDRAW_BACKING_STORE; Blt_EventuallyRedrawGraph(graphPtr); } } static int EvalExprList(interp, list, nElemPtr, arrayPtr) Tcl_Interp *interp; char *list; int *nElemPtr; double **arrayPtr; { int nElem; char **elemArr; double *array; int result; result = TCL_ERROR; elemArr = NULL; if (Tcl_SplitList(interp, list, &nElem, &elemArr) != TCL_OK) { return TCL_ERROR; } array = NULL; if (nElem > 0) { register double *valuePtr; register int i; counter++; array = Blt_Malloc(sizeof(double) * nElem); if (array == NULL) { Tcl_AppendResult(interp, "can't allocate new vector", (char *)NULL); goto badList; } valuePtr = array; for (i = 0; i < nElem; i++) { if (Tcl_ExprDouble(interp, elemArr[i], valuePtr) != TCL_OK) { goto badList; } valuePtr++; } } result = TCL_OK; badList: Blt_Free(elemArr); *arrayPtr = array; *nElemPtr = nElem; if (result != TCL_OK) { Blt_Free(array); } return result; } /* *---------------------------------------------------------------------- * * StringToData -- * * Given a Tcl list of numeric expression representing the element * values, convert into an array of double precision values. In * addition, the minimum and maximum values are saved. Since * elastic values are allow (values which translate to the * min/max of the graph), we must try to get the non-elastic * minimum and maximum. * * Results: * The return value is a standard Tcl result. The vector is passed * back via the vPtr. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToData(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Type of axis vector to fill */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* Tcl list of expressions */ char *widgRec; /* Element record */ int offset; /* Offset of vector in Element record */ { Element *elemPtr = (Element *)(widgRec); ElemVector *vPtr = (ElemVector *)(widgRec + offset); FreeDataVector(vPtr); if (Blt_VectorExists2(interp, string)) { Blt_VectorId clientId; clientId = Blt_AllocVectorId(interp, string); if (Blt_GetVectorById(interp, clientId, &vPtr->vecPtr) != TCL_OK) { return TCL_ERROR; } Blt_SetVectorChangedProc(clientId, VectorChangedProc, vPtr); vPtr->elemPtr = elemPtr; vPtr->clientId = clientId; SyncElemVector(vPtr); elemPtr->flags |= MAP_ITEM; } else { double *newArr; int nValues; if (EvalExprList(interp, string, &nValues, &newArr) != TCL_OK) { return TCL_ERROR; } if (nValues > 0) { vPtr->valueArr = newArr; } vPtr->nValues = nValues; FindRange(vPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * DataToString -- * * Convert the vector of floating point values into a Tcl list. * * Results: * The string representation of the vector is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * DataToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Type of axis vector to print */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Element record */ int offset; /* Offset of vector in Element record */ Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */ { ElemVector *vPtr = (ElemVector *)(widgRec + offset); Element *elemPtr = (Element *)(widgRec); Tcl_DString dString; char *result; char string[TCL_DOUBLE_SPACE + 1]; double *p, *endPtr; if (vPtr->clientId != NULL) { return Blt_NameOfVectorId(vPtr->clientId); } if (vPtr->nValues == 0) { return ""; } Tcl_DStringInit(&dString); endPtr = vPtr->valueArr + vPtr->nValues; for (p = vPtr->valueArr; p < endPtr; p++) { Tcl_PrintDouble(elemPtr->graphPtr->interp, *p, string); Tcl_DStringAppendElement(&dString, string); } result = Tcl_DStringValue(&dString); /* * If memory wasn't allocated for the dynamic string, do it here (it's * currently on the stack), so that Tcl can free it normally. */ if (result == dString.staticSpace) { result = Blt_Strdup(result); } *freeProcPtr = (Tcl_FreeProc *)Blt_Free; return result; } /* *---------------------------------------------------------------------- * * StringToDataPairs -- * * This procedure is like StringToData except that it interprets * the list of numeric expressions as X Y coordinate pairs. The * minimum and maximum for both the X and Y vectors are * determined. * * Results: * The return value is a standard Tcl result. The vectors are * passed back via the widget record (elemPtr). * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToDataPairs(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* Tcl list of numeric expressions */ char *widgRec; /* Element record */ int offset; /* Not used. */ { Element *elemPtr = (Element *)widgRec; int nElem; unsigned int newSize; double *newArr; if (EvalExprList(interp, string, &nElem, &newArr) != TCL_OK) { return TCL_ERROR; } if (nElem & 1) { Tcl_AppendResult(interp, "odd number of data points", (char *)NULL); Blt_Free(newArr); return TCL_ERROR; } nElem /= 2; newSize = nElem * sizeof(double); FreeDataVector(&elemPtr->x); FreeDataVector(&elemPtr->y); elemPtr->x.valueArr = Blt_Malloc(newSize); elemPtr->y.valueArr = Blt_Malloc(newSize); assert(elemPtr->x.valueArr && elemPtr->y.valueArr); elemPtr->x.nValues = elemPtr->y.nValues = nElem; if (newSize > 0) { register double *dataPtr; register int i; for (dataPtr = newArr, i = 0; i < nElem; i++) { elemPtr->x.valueArr[i] = *dataPtr++; elemPtr->y.valueArr[i] = *dataPtr++; } Blt_Free(newArr); FindRange(&elemPtr->x); FindRange(&elemPtr->y); } return TCL_OK; } /* *---------------------------------------------------------------------- * * DataPairsToString -- * * Convert pairs of floating point values in the X and Y arrays * into a Tcl list. * * Results: * The return value is a string (Tcl list). * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * DataPairsToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Element information record */ int offset; /* Not used. */ Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */ { Element *elemPtr = (Element *)widgRec; Tcl_Interp *interp = elemPtr->graphPtr->interp; int i; int length; char *result; char string[TCL_DOUBLE_SPACE + 1]; Tcl_DString dString; length = NumberOfPoints(elemPtr); if (length < 1) { return ""; } Tcl_DStringInit(&dString); for (i = 0; i < length; i++) { Tcl_PrintDouble(interp, elemPtr->x.valueArr[i], string); Tcl_DStringAppendElement(&dString, string); Tcl_PrintDouble(interp, elemPtr->y.valueArr[i], string); Tcl_DStringAppendElement(&dString, string); } result = Tcl_DStringValue(&dString); /* * If memory wasn't allocated for the dynamic string, do it here * (it's currently on the stack), so that Tcl can free it * normally. */ if (result == dString.staticSpace) { result = Blt_Strdup(result); } *freeProcPtr = (Tcl_FreeProc *)Blt_Free; return result; } /* *---------------------------------------------------------------------- * * StringToAlong -- * * Given a Tcl list of numeric expression representing the element * values, convert into an array of double precision values. In * addition, the minimum and maximum values are saved. Since * elastic values are allow (values which translate to the * min/max of the graph), we must try to get the non-elastic * minimum and maximum. * * Results: * The return value is a standard Tcl result. The vector is passed * back via the vPtr. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToAlong(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* String representation of value. */ char *widgRec; /* Widget record. */ int offset; /* Offset of field in widget record. */ { int *intPtr = (int *)(widgRec + offset); if ((string[0] == 'x') && (string[1] == '\0')) { *intPtr = SEARCH_X; } else if ((string[0] == 'y') && (string[1] == '\0')) { *intPtr = SEARCH_Y; } else if ((string[0] == 'b') && (strcmp(string, "both") == 0)) { *intPtr = SEARCH_BOTH; } else { Tcl_AppendResult(interp, "bad along value \"", string, "\"", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * AlongToString -- * * Convert the vector of floating point values into a Tcl list. * * Results: * The string representation of the vector is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * AlongToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget record */ int offset; /* Offset of field in widget record */ Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */ { int along = *(int *)(widgRec + offset); switch (along) { case SEARCH_X: return "x"; case SEARCH_Y: return "y"; case SEARCH_BOTH: return "both"; default: return "unknown along value"; } } void Blt_FreePalette(graphPtr, palette) Graph *graphPtr; Blt_Chain *palette; { Blt_ChainLink *linkPtr; /* Skip the first slot. It contains the built-in "normal" pen of * the element. */ linkPtr = Blt_ChainFirstLink(palette); if (linkPtr != NULL) { register PenStyle *stylePtr; Blt_ChainLink *nextPtr; for (linkPtr = Blt_ChainNextLink(linkPtr); linkPtr != NULL; linkPtr = nextPtr) { nextPtr = Blt_ChainNextLink(linkPtr); stylePtr = Blt_ChainGetValue(linkPtr); Blt_FreePen(graphPtr, stylePtr->penPtr); Blt_ChainDeleteLink(palette, linkPtr); } } } /* *---------------------------------------------------------------------- * * Blt_StringToStyles -- * * Parse the list of style names. * * Results: * The return value is a standard Tcl result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ int Blt_StringToStyles(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* String representing style list */ char *widgRec; /* Element information record */ int offset; /* Offset of symbol type field in record */ { Blt_Chain *palette = *(Blt_Chain **)(widgRec + offset); Blt_ChainLink *linkPtr; Element *elemPtr = (Element *)(widgRec); PenStyle *stylePtr; char **elemArr; int nStyles; register int i; size_t size = (size_t)clientData; elemArr = NULL; Blt_FreePalette(elemPtr->graphPtr, palette); if ((string == NULL) || (*string == '\0')) { nStyles = 0; } else if (Tcl_SplitList(interp, string, &nStyles, &elemArr) != TCL_OK) { return TCL_ERROR; } /* Reserve the first entry for the "normal" pen. We'll set the * style later */ linkPtr = Blt_ChainFirstLink(palette); if (linkPtr == NULL) { linkPtr = Blt_ChainAllocLink(size); Blt_ChainLinkBefore(palette, linkPtr, NULL); } stylePtr = Blt_ChainGetValue(linkPtr); stylePtr->penPtr = elemPtr->normalPenPtr; for (i = 0; i < nStyles; i++) { linkPtr = Blt_ChainAllocLink(size); stylePtr = Blt_ChainGetValue(linkPtr); stylePtr->weight.min = (double)i; stylePtr->weight.max = (double)i + 1.0; stylePtr->weight.range = 1.0; if (GetPenStyle(elemPtr->graphPtr, elemArr[i], elemPtr->classUid, (PenStyle *)stylePtr) != TCL_OK) { Blt_Free(elemArr); Blt_FreePalette(elemPtr->graphPtr, palette); return TCL_ERROR; } Blt_ChainLinkBefore(palette, linkPtr, NULL); } if (elemArr != NULL) { Blt_Free(elemArr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * Blt_StylesToString -- * * Convert the style information into a string. * * Results: * The string representing the style information is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ char * Blt_StylesToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Element information record */ int offset; /* Not used. */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { Blt_Chain *palette = *(Blt_Chain **)(widgRec + offset); Tcl_DString dString; char *result; Blt_ChainLink *linkPtr; Tcl_DStringInit(&dString); linkPtr = Blt_ChainFirstLink(palette); if (linkPtr != NULL) { Element *elemPtr = (Element *)(widgRec); char string[TCL_DOUBLE_SPACE]; Tcl_Interp *interp; PenStyle *stylePtr; interp = elemPtr->graphPtr->interp; for (linkPtr = Blt_ChainNextLink(linkPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { stylePtr = Blt_ChainGetValue(linkPtr); Tcl_DStringStartSublist(&dString); Tcl_DStringAppendElement(&dString, stylePtr->penPtr->name); Tcl_PrintDouble(interp, stylePtr->weight.min, string); Tcl_DStringAppendElement(&dString, string); Tcl_PrintDouble(interp, stylePtr->weight.max, string); Tcl_DStringAppendElement(&dString, string); Tcl_DStringEndSublist(&dString); } } result = Blt_Strdup(Tcl_DStringValue(&dString)); *freeProcPtr = (Tcl_FreeProc *)Blt_Free; return result; } /* *---------------------------------------------------------------------- * * Blt_StyleMap -- * * Creates an array of style indices and fills it based on the weight * of each data point. * * Results: * None. * * Side effects: * Memory is freed and allocated for the index array. * *---------------------------------------------------------------------- */ PenStyle ** Blt_StyleMap(elemPtr) Element *elemPtr; { register int i; int nWeights; /* Number of weights to be examined. * If there are more data points than * weights, they will default to the * normal pen. */ PenStyle **dataToStyle; /* Directory of styles. Each array * element represents the style for * the data point at that index */ Blt_ChainLink *linkPtr; PenStyle *stylePtr; double *w; /* Weight vector */ int nPoints; nPoints = NumberOfPoints(elemPtr); nWeights = MIN(elemPtr->w.nValues, nPoints); w = elemPtr->w.valueArr; linkPtr = Blt_ChainFirstLink(elemPtr->palette); stylePtr = Blt_ChainGetValue(linkPtr); /* * Create a style mapping array (data point index to style), * initialized to the default style. */ dataToStyle = Blt_Malloc(nPoints * sizeof(PenStyle *)); assert(dataToStyle); for (i = 0; i < nPoints; i++) { dataToStyle[i] = stylePtr; } for (i = 0; i < nWeights; i++) { for (linkPtr = Blt_ChainLastLink(elemPtr->palette); linkPtr != NULL; linkPtr = Blt_ChainPrevLink(linkPtr)) { stylePtr = Blt_ChainGetValue(linkPtr); if (stylePtr->weight.range > 0.0) { double norm; norm = (w[i] - stylePtr->weight.min) / stylePtr->weight.range; if (((norm - 1.0) <= DBL_EPSILON) && (((1.0 - norm) - 1.0) <= DBL_EPSILON)) { dataToStyle[i] = stylePtr; break; /* Done: found range that matches. */ } } } } return dataToStyle; } /* *---------------------------------------------------------------------- * * Blt_MapErrorBars -- * * Creates two arrays of points and pen indices, filled with * the screen coordinates of the visible * * Results: * None. * * Side effects: * Memory is freed and allocated for the index array. * *---------------------------------------------------------------------- */ void Blt_MapErrorBars(graphPtr, elemPtr, dataToStyle) Graph *graphPtr; Element *elemPtr; PenStyle **dataToStyle; { int n, nPoints; Extents2D exts; PenStyle *stylePtr; Blt_GraphExtents(graphPtr, &exts); nPoints = NumberOfPoints(elemPtr); if (elemPtr->xError.nValues > 0) { n = MIN(elemPtr->xError.nValues, nPoints); } else { n = MIN3(elemPtr->xHigh.nValues, elemPtr->xLow.nValues, nPoints); } if (n > 0) { Segment2D *errorBars; Segment2D *segPtr; double high, low; double x, y; int *errorToData; int *indexPtr; register int i; segPtr = errorBars = Blt_Malloc(n * 3 * sizeof(Segment2D)); indexPtr = errorToData = Blt_Malloc(n * 3 * sizeof(int)); for (i = 0; i < n; i++) { x = elemPtr->x.valueArr[i]; y = elemPtr->y.valueArr[i]; stylePtr = dataToStyle[i]; if ((FINITE(x)) && (FINITE(y))) { if (elemPtr->xError.nValues > 0) { high = x + elemPtr->xError.valueArr[i]; low = x - elemPtr->xError.valueArr[i]; } else { high = elemPtr->xHigh.valueArr[i]; low = elemPtr->xLow.valueArr[i]; } if ((FINITE(high)) && (FINITE(low))) { Point2D p, q; p = Blt_Map2D(graphPtr, high, y, &elemPtr->axes); q = Blt_Map2D(graphPtr, low, y, &elemPtr->axes); segPtr->p = p; segPtr->q = q; if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) { segPtr++; *indexPtr++ = i; } /* Left cap */ segPtr->p.x = segPtr->q.x = p.x; segPtr->p.y = p.y - stylePtr->errorBarCapWidth; segPtr->q.y = p.y + stylePtr->errorBarCapWidth; if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) { segPtr++; *indexPtr++ = i; } /* Right cap */ segPtr->p.x = segPtr->q.x = q.x; segPtr->p.y = q.y - stylePtr->errorBarCapWidth; segPtr->q.y = q.y + stylePtr->errorBarCapWidth; if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) { segPtr++; *indexPtr++ = i; } } } } elemPtr->xErrorBars = errorBars; elemPtr->xErrorBarCnt = segPtr - errorBars; elemPtr->xErrorToData = errorToData; } if (elemPtr->yError.nValues > 0) { n = MIN(elemPtr->yError.nValues, nPoints); } else { n = MIN3(elemPtr->yHigh.nValues, elemPtr->yLow.nValues, nPoints); } if (n > 0) { Segment2D *errorBars; Segment2D *segPtr; double high, low; double x, y; int *errorToData; int *indexPtr; register int i; segPtr = errorBars = Blt_Malloc(n * 3 * sizeof(Segment2D)); indexPtr = errorToData = Blt_Malloc(n * 3 * sizeof(int)); for (i = 0; i < n; i++) { x = elemPtr->x.valueArr[i]; y = elemPtr->y.valueArr[i]; stylePtr = dataToStyle[i]; if ((FINITE(x)) && (FINITE(y))) { if (elemPtr->yError.nValues > 0) { high = y + elemPtr->yError.valueArr[i]; low = y - elemPtr->yError.valueArr[i]; } else { high = elemPtr->yHigh.valueArr[i]; low = elemPtr->yLow.valueArr[i]; } if ((FINITE(high)) && (FINITE(low))) { Point2D p, q; p = Blt_Map2D(graphPtr, x, high, &elemPtr->axes); q = Blt_Map2D(graphPtr, x, low, &elemPtr->axes); segPtr->p = p; segPtr->q = q; if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) { segPtr++; *indexPtr++ = i; } /* Top cap. */ segPtr->p.y = segPtr->q.y = p.y; segPtr->p.x = p.x - stylePtr->errorBarCapWidth; segPtr->q.x = p.x + stylePtr->errorBarCapWidth; if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) { segPtr++; *indexPtr++ = i; } /* Bottom cap. */ segPtr->p.y = segPtr->q.y = q.y; segPtr->p.x = q.x - stylePtr->errorBarCapWidth; segPtr->q.x = q.x + stylePtr->errorBarCapWidth; if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) { segPtr++; *indexPtr++ = i; } } } } elemPtr->yErrorBars = errorBars; elemPtr->yErrorBarCnt = segPtr - errorBars; elemPtr->yErrorToData = errorToData; } } /* *---------------------------------------------------------------------- * * GetIndex -- * * Given a string representing the index of a pair of x,y * coordinates, return the numeric index. * * Results: * A standard TCL result. * *---------------------------------------------------------------------- */ static int GetIndex(interp, elemPtr, string, indexPtr) Tcl_Interp *interp; Element *elemPtr; char *string; int *indexPtr; { long ielem; int last; last = NumberOfPoints(elemPtr) - 1; if ((*string == 'e') && (strcmp("end", string) == 0)) { ielem = last; } else if (Tcl_ExprLong(interp, string, &ielem) != TCL_OK) { return TCL_ERROR; } *indexPtr = (int)ielem; return TCL_OK; } /* *---------------------------------------------------------------------- * * NameToElement -- * * Find the element represented the given name, returning * a pointer to its data structure via elemPtrPtr. * * Results: * A standard TCL result. * *---------------------------------------------------------------------- */ static int NameToElement(graphPtr, name, elemPtrPtr) Graph *graphPtr; char *name; Element **elemPtrPtr; { Blt_HashEntry *hPtr; if (name == NULL) { return TCL_ERROR; } hPtr = Blt_FindHashEntry(&graphPtr->elements.table, name); if (hPtr == NULL) { Tcl_AppendResult(graphPtr->interp, "can't find element \"", name, "\" in \"", Tk_PathName(graphPtr->tkwin), "\"", (char *)NULL); return TCL_ERROR; } *elemPtrPtr = (Element *)Blt_GetHashValue(hPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * DestroyElement -- * * Add a new element to the graph. * * Results: * The return value is a standard Tcl result. * *---------------------------------------------------------------------- */ static void DestroyElement(graphPtr, elemPtr) Graph *graphPtr; Element *elemPtr; { Blt_ChainLink *linkPtr; Blt_DeleteBindings(graphPtr->bindTable, elemPtr); Blt_LegendRemoveElement(graphPtr->legend, elemPtr); Tk_FreeOptions(elemPtr->specsPtr, (char *)elemPtr, graphPtr->display, 0); /* * Call the element's own destructor to release the memory and * resources allocated for it. */ (*elemPtr->procsPtr->destroyProc) (graphPtr, elemPtr); /* Remove it also from the element display list */ for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { if (elemPtr == Blt_ChainGetValue(linkPtr)) { Blt_ChainDeleteLink(graphPtr->elements.displayList, linkPtr); if (!elemPtr->hidden) { graphPtr->flags |= RESET_WORLD; Blt_EventuallyRedrawGraph(graphPtr); } break; } } /* Remove the element for the graph's hash table of elements */ if (elemPtr->hashPtr != NULL) { Blt_DeleteHashEntry(&graphPtr->elements.table, elemPtr->hashPtr); } if (elemPtr->name != NULL) { Blt_Free(elemPtr->name); } Blt_Free(elemPtr); } /* *---------------------------------------------------------------------- * * CreateElement -- * * Add a new element to the graph. * * Results: * The return value is a standard Tcl result. * *---------------------------------------------------------------------- */ static int CreateElement(graphPtr, interp, argc, argv, classUid) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; Blt_Uid classUid; { Element *elemPtr; Blt_HashEntry *hPtr; int isNew; if (argv[3][0] == '-') { Tcl_AppendResult(graphPtr->interp, "name of element \"", argv[3], "\" can't start with a '-'", (char *)NULL); return TCL_ERROR; } hPtr = Blt_CreateHashEntry(&graphPtr->elements.table, argv[3], &isNew); if (!isNew) { Tcl_AppendResult(interp, "element \"", argv[3], "\" already exists in \"", argv[0], "\"", (char *)NULL); return TCL_ERROR; } if (classUid == bltBarElementUid) { elemPtr = Blt_BarElement(graphPtr, argv[3], classUid); } else { /* Stripcharts are line graphs with some options enabled. */ elemPtr = Blt_LineElement(graphPtr, argv[3], classUid); } elemPtr->hashPtr = hPtr; Blt_SetHashValue(hPtr, elemPtr); if (Blt_ConfigureWidgetComponent(interp, graphPtr->tkwin, elemPtr->name, "Element", elemPtr->specsPtr, argc - 4, argv + 4, (char *)elemPtr, 0) != TCL_OK) { DestroyElement(graphPtr, elemPtr); return TCL_ERROR; } (*elemPtr->procsPtr->configProc) (graphPtr, elemPtr); Blt_ChainPrepend(graphPtr->elements.displayList, elemPtr); if (!elemPtr->hidden) { /* If the new element isn't hidden then redraw the graph. */ graphPtr->flags |= REDRAW_BACKING_STORE; Blt_EventuallyRedrawGraph(graphPtr); } elemPtr->flags |= MAP_ITEM; graphPtr->flags |= RESET_AXES; Tcl_SetResult(interp, elemPtr->name, TCL_VOLATILE); return TCL_OK; } /* *---------------------------------------------------------------------- * * RebuildDisplayList -- * * Given a Tcl list of element names, this procedure rebuilds the * display list, ignoring invalid element names. This list describes * not only only which elements to draw, but in what order. This is * only important for bar and pie charts. * * Results: * The return value is a standard Tcl result. Only if the Tcl list * can not be split, a TCL_ERROR is returned and interp->result contains * an error message. * * Side effects: * The graph is eventually redrawn using the new display list. * *---------------------------------------------------------------------- */ static int RebuildDisplayList(graphPtr, newList) Graph *graphPtr; /* Graph widget record */ char *newList; /* Tcl list of element names */ { int nNames; /* Number of names found in Tcl name list */ char **nameArr; /* Broken out array of element names */ Blt_HashSearch cursor; register int i; register Blt_HashEntry *hPtr; Element *elemPtr; /* Element information record */ if (Tcl_SplitList(graphPtr->interp, newList, &nNames, &nameArr) != TCL_OK) { Tcl_AppendResult(graphPtr->interp, "can't split name list \"", newList, "\"", (char *)NULL); return TCL_ERROR; } /* Clear the display list and mark all elements as hidden. */ Blt_ChainReset(graphPtr->elements.displayList); for (hPtr = Blt_FirstHashEntry(&graphPtr->elements.table, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { elemPtr = (Element *)Blt_GetHashValue(hPtr); elemPtr->hidden = TRUE; } /* Rebuild the display list, checking that each name it exists * (currently ignoring invalid element names). */ for (i = 0; i < nNames; i++) { if (NameToElement(graphPtr, nameArr[i], &elemPtr) == TCL_OK) { elemPtr->hidden = FALSE; Blt_ChainAppend(graphPtr->elements.displayList, elemPtr); } } Blt_Free(nameArr); graphPtr->flags |= RESET_WORLD; Blt_EventuallyRedrawGraph(graphPtr); Tcl_ResetResult(graphPtr->interp); return TCL_OK; } /* *---------------------------------------------------------------------- * * Blt_DestroyElements -- * * Removes all the graph's elements. This routine is called when * the graph is destroyed. * * Results: * None. * * Side effects: * Memory allocated for the graph's elements is freed. * *---------------------------------------------------------------------- */ void Blt_DestroyElements(graphPtr) Graph *graphPtr; { Blt_HashEntry *hPtr; Blt_HashSearch cursor; Element *elemPtr; for (hPtr = Blt_FirstHashEntry(&graphPtr->elements.table, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { elemPtr = (Element *)Blt_GetHashValue(hPtr); elemPtr->hashPtr = NULL; DestroyElement(graphPtr, elemPtr); } Blt_DeleteHashTable(&graphPtr->elements.table); Blt_DeleteHashTable(&graphPtr->elements.tagTable); Blt_ChainDestroy(graphPtr->elements.displayList); } void Blt_MapElements(graphPtr) Graph *graphPtr; { Element *elemPtr; Blt_ChainLink *linkPtr; if (graphPtr->mode != MODE_INFRONT) { Blt_ResetStacks(graphPtr); } for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { elemPtr = Blt_ChainGetValue(linkPtr); if (elemPtr->hidden) { continue; } if ((graphPtr->flags & MAP_ALL) || (elemPtr->flags & MAP_ITEM)) { (*elemPtr->procsPtr->mapProc) (graphPtr, elemPtr); elemPtr->flags &= ~MAP_ITEM; } } } /* * ----------------------------------------------------------------- * * Blt_DrawElements -- * * Calls the individual element drawing routines for each * element. * * Results: * None * * Side Effects: * Elements are drawn into the drawable (pixmap) which will * eventually be displayed in the graph window. * * ----------------------------------------------------------------- */ void Blt_DrawElements(graphPtr, drawable) Graph *graphPtr; Drawable drawable; /* Pixmap or window to draw into */ { Blt_ChainLink *linkPtr; Element *elemPtr; for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { elemPtr = Blt_ChainGetValue(linkPtr); if (!elemPtr->hidden) { (*elemPtr->procsPtr->drawNormalProc) (graphPtr, drawable, elemPtr); } } } /* * ----------------------------------------------------------------- * * Blt_DrawActiveElements -- * * Calls the individual element drawing routines to display * the active colors for each element. * * Results: * None * * Side Effects: * Elements are drawn into the drawable (pixmap) which will * eventually be displayed in the graph window. * * ----------------------------------------------------------------- */ void Blt_DrawActiveElements(graphPtr, drawable) Graph *graphPtr; Drawable drawable; /* Pixmap or window to draw into */ { Blt_ChainLink *linkPtr; Element *elemPtr; for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { elemPtr = Blt_ChainGetValue(linkPtr); if ((!elemPtr->hidden) && (elemPtr->flags & ELEM_ACTIVE)) { (*elemPtr->procsPtr->drawActiveProc) (graphPtr, drawable, elemPtr); } } } /* * ----------------------------------------------------------------- * * Blt_ElementsToPostScript -- * * Generates PostScript output for each graph element in the * element display list. * * ----------------------------------------------------------------- */ void Blt_ElementsToPostScript(graphPtr, psToken) Graph *graphPtr; PsToken psToken; { Blt_ChainLink *linkPtr; Element *elemPtr; for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { elemPtr = Blt_ChainGetValue(linkPtr); if (!elemPtr->hidden) { /* Comment the PostScript to indicate the start of the element */ Blt_FormatToPostScript(psToken, "\n%% Element \"%s\"\n\n", elemPtr->name); (*elemPtr->procsPtr->printNormalProc) (graphPtr, psToken, elemPtr); } } } /* * ----------------------------------------------------------------- * * Blt_ActiveElementsToPostScript -- * * ----------------------------------------------------------------- */ void Blt_ActiveElementsToPostScript(graphPtr, psToken) Graph *graphPtr; PsToken psToken; { Blt_ChainLink *linkPtr; Element *elemPtr; for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { elemPtr = Blt_ChainGetValue(linkPtr); if ((!elemPtr->hidden) && (elemPtr->flags & ELEM_ACTIVE)) { Blt_FormatToPostScript(psToken, "\n%% Active Element \"%s\"\n\n", elemPtr->name); (*elemPtr->procsPtr->printActiveProc) (graphPtr, psToken, elemPtr); } } } int Blt_GraphUpdateNeeded(graphPtr) Graph *graphPtr; { Blt_ChainLink *linkPtr; Element *elemPtr; for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { elemPtr = Blt_ChainGetValue(linkPtr); if (elemPtr->hidden) { continue; } /* Check if the x or y vectors have notifications pending */ if ((Blt_VectorNotifyPending(elemPtr->x.clientId)) || (Blt_VectorNotifyPending(elemPtr->y.clientId))) { return 1; } } return 0; } /* *---------------------------------------------------------------------- * * ActivateOp -- * * Marks data points of elements (given by their index) as active. * * Results: * Returns TCL_OK if no errors occurred. * *---------------------------------------------------------------------- */ static int ActivateOp(graphPtr, interp, argc, argv) Graph *graphPtr; /* Graph widget */ Tcl_Interp *interp; /* Interpreter to report errors to */ int argc; /* Number of element names */ char **argv; /* List of element names */ { Element *elemPtr; register int i; int *activeArr; int nActiveIndices; if (argc == 3) { register Blt_HashEntry *hPtr; Blt_HashSearch cursor; /* List all the currently active elements */ for (hPtr = Blt_FirstHashEntry(&graphPtr->elements.table, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { elemPtr = (Element *)Blt_GetHashValue(hPtr); if (elemPtr->flags & ELEM_ACTIVE) { Tcl_AppendElement(graphPtr->interp, elemPtr->name); } } return TCL_OK; } if (NameToElement(graphPtr, argv[3], &elemPtr) != TCL_OK) { return TCL_ERROR; /* Can't find named element */ } elemPtr->flags |= ELEM_ACTIVE | ACTIVE_PENDING; activeArr = NULL; nActiveIndices = -1; if (argc > 4) { register int *activePtr; nActiveIndices = argc - 4; activePtr = activeArr = Blt_Malloc(sizeof(int) * nActiveIndices); assert(activeArr); for (i = 4; i < argc; i++) { if (GetIndex(interp, elemPtr, argv[i], activePtr) != TCL_OK) { return TCL_ERROR; } activePtr++; } } if (elemPtr->activeIndices != NULL) { Blt_Free(elemPtr->activeIndices); } elemPtr->nActiveIndices = nActiveIndices; elemPtr->activeIndices = activeArr; Blt_EventuallyRedrawGraph(graphPtr); return TCL_OK; } ClientData Blt_MakeElementTag(graphPtr, tagName) Graph *graphPtr; char *tagName; { Blt_HashEntry *hPtr; int isNew; hPtr = Blt_CreateHashEntry(&graphPtr->elements.tagTable, tagName, &isNew); assert(hPtr); return Blt_GetHashKey(&graphPtr->elements.tagTable, hPtr); } /* *---------------------------------------------------------------------- * * BindOp -- * * .g element bind elemName sequence command * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int BindOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { if (argc == 3) { Blt_HashEntry *hPtr; Blt_HashSearch cursor; char *tagName; for (hPtr = Blt_FirstHashEntry(&graphPtr->elements.tagTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tagName = Blt_GetHashKey(&graphPtr->elements.tagTable, hPtr); Tcl_AppendElement(interp, tagName); } return TCL_OK; } return Blt_ConfigureBindings(interp, graphPtr->bindTable, Blt_MakeElementTag(graphPtr, argv[3]), argc - 4, argv + 4); } /* *---------------------------------------------------------------------- * * CreateOp -- * * Add a new element to the graph (using the default type of the * graph). * * Results: * The return value is a standard Tcl result. * *---------------------------------------------------------------------- */ static int CreateOp(graphPtr, interp, argc, argv, type) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; Blt_Uid type; { return CreateElement(graphPtr, interp, argc, argv, type); } /* *---------------------------------------------------------------------- * * CgetOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int CgetOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char *argv[]; { Element *elemPtr; if (NameToElement(graphPtr, argv[3], &elemPtr) != TCL_OK) { return TCL_ERROR; /* Can't find named element */ } if (Tk_ConfigureValue(interp, graphPtr->tkwin, elemPtr->specsPtr, (char *)elemPtr, argv[4], 0) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * ClosestOp -- * * Find the element closest to the specified screen coordinates. * Options: * -halo Consider points only with this maximum distance * from the picked coordinate. * -interpolate Find closest point along element traces, not just * data points. * -along * * Results: * A standard Tcl result. If an element could be found within * the halo distance, the interpreter result is "1", otherwise * "0". If a closest element exists, the designated Tcl array * variable will be set with the following information: * * 1) the element name, * 2) the index of the closest point, * 3) the distance (in screen coordinates) from the picked X-Y * coordinate and the closest point, * 4) the X coordinate (graph coordinate) of the closest point, * 5) and the Y-coordinate. * *---------------------------------------------------------------------- */ static Tk_ConfigSpec closestSpecs[] = { {TK_CONFIG_CUSTOM, "-halo", (char *)NULL, (char *)NULL, (char *)NULL, Tk_Offset(ClosestSearch, halo), 0, &bltDistanceOption}, {TK_CONFIG_BOOLEAN, "-interpolate", (char *)NULL, (char *)NULL, (char *)NULL, Tk_Offset(ClosestSearch, mode), 0 }, {TK_CONFIG_CUSTOM, "-along", (char *)NULL, (char *)NULL, (char *)NULL, Tk_Offset(ClosestSearch, along), 0, &alongOption}, {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; static int ClosestOp(graphPtr, interp, argc, argv) Graph *graphPtr; /* Graph widget */ Tcl_Interp *interp; /* Interpreter to report results to */ int argc; /* Number of element names */ char **argv; /* List of element names */ { Element *elemPtr; ClosestSearch search; int i, x, y; int flags = TCL_LEAVE_ERR_MSG; if (graphPtr->flags & RESET_AXES) { Blt_ResetAxes(graphPtr); } if (Tk_GetPixels(interp, graphPtr->tkwin, argv[3], &x) != TCL_OK) { Tcl_AppendResult(interp, ": bad window x-coordinate", (char *)NULL); return TCL_ERROR; } if (Tk_GetPixels(interp, graphPtr->tkwin, argv[4], &y) != TCL_OK) { Tcl_AppendResult(interp, ": bad window y-coordinate", (char *)NULL); return TCL_ERROR; } if (graphPtr->inverted) { int temp; temp = x, x = y, y = temp; } for (i = 6; i < argc; i += 2) { /* Count switches-value pairs */ if ((argv[i][0] != '-') || ((argv[i][1] == '-') && (argv[i][2] == '\0'))) { break; } } if (i > argc) { i = argc; } search.mode = SEARCH_POINTS; search.halo = graphPtr->halo; search.index = -1; search.along = SEARCH_BOTH; search.x = x; search.y = y; if (Tk_ConfigureWidget(interp, graphPtr->tkwin, closestSpecs, i - 6, argv + 6, (char *)&search, TK_CONFIG_ARGV_ONLY) != TCL_OK) { return TCL_ERROR; /* Error occurred processing an option. */ } if ((i < argc) && (argv[i][0] == '-')) { i++; /* Skip "--" */ } search.dist = (double)(search.halo + 1); if (i < argc) { for ( /* empty */ ; i < argc; i++) { if (NameToElement(graphPtr, argv[i], &elemPtr) != TCL_OK) { return TCL_ERROR; /* Can't find named element */ } if (elemPtr->hidden) { Tcl_AppendResult(interp, "element \"", argv[i], "\" is hidden", (char *)NULL); return TCL_ERROR; /* Element isn't visible */ } /* Check if the X or Y vectors have notifications pending */ if ((elemPtr->flags & MAP_ITEM) || (Blt_VectorNotifyPending(elemPtr->x.clientId)) || (Blt_VectorNotifyPending(elemPtr->y.clientId))) { continue; } (*elemPtr->procsPtr->closestProc) (graphPtr, elemPtr, &search); } } else { Blt_ChainLink *linkPtr; /* * 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 (linkPtr = Blt_ChainLastLink(graphPtr->elements.displayList); linkPtr != NULL; linkPtr = Blt_ChainPrevLink(linkPtr)) { elemPtr = Blt_ChainGetValue(linkPtr); /* Check if the X or Y vectors have notifications pending */ if ((elemPtr->flags & MAP_ITEM) || (Blt_VectorNotifyPending(elemPtr->x.clientId)) || (Blt_VectorNotifyPending(elemPtr->y.clientId))) { continue; } if (!elemPtr->hidden) { (*elemPtr->procsPtr->closestProc) (graphPtr, elemPtr, &search); } } } if (search.dist < (double)search.halo) { char string[200]; /* * Return an array of 5 elements */ if (Tcl_SetVar2(interp, argv[5], "name", search.elemPtr->name, flags) == NULL) { return TCL_ERROR; } sprintf(string, "%d", search.index); if (Tcl_SetVar2(interp, argv[5], "index", string, flags) == NULL) { return TCL_ERROR; } Tcl_PrintDouble(interp, search.point.x, string); if (Tcl_SetVar2(interp, argv[5], "x", string, flags) == NULL) { return TCL_ERROR; } Tcl_PrintDouble(interp, search.point.y, string); if (Tcl_SetVar2(interp, argv[5], "y", string, flags) == NULL) { return TCL_ERROR; } Tcl_PrintDouble(interp, search.dist, string); if (Tcl_SetVar2(interp, argv[5], "dist", string, flags) == NULL) { return TCL_ERROR; } Tcl_SetResult(interp, "1", TCL_STATIC); } else { if (Tcl_SetVar2(interp, argv[5], "name", "", flags) == NULL) { return TCL_ERROR; } Tcl_SetResult(interp, "0", TCL_STATIC); } return TCL_OK; } /* *---------------------------------------------------------------------- * * ConfigureOp -- * * Sets the element specifications by the given the command line * arguments and calls the element specification configuration * routine. If zero or one command line options are given, only * information about the option(s) is returned in interp->result. * If the element configuration has changed and the element is * currently displayed, the axis limits are updated and * recomputed. * * Results: * The return value is a standard Tcl result. * * Side Effects: * Graph will be redrawn to reflect the new display list. * *---------------------------------------------------------------------- */ static int ConfigureOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char *argv[]; { Element *elemPtr; int flags; int numNames, numOpts; char **options; register int i; /* Figure out where the option value pairs begin */ argc -= 3; argv += 3; for (i = 0; i < argc; i++) { if (argv[i][0] == '-') { break; } if (NameToElement(graphPtr, argv[i], &elemPtr) != TCL_OK) { return TCL_ERROR; /* Can't find named element */ } } numNames = i; /* Number of element names specified */ numOpts = argc - i; /* Number of options specified */ options = argv + numNames; /* Start of options in argv */ for (i = 0; i < numNames; i++) { NameToElement(graphPtr, argv[i], &elemPtr); flags = TK_CONFIG_ARGV_ONLY; if (numOpts == 0) { return Tk_ConfigureInfo(interp, graphPtr->tkwin, elemPtr->specsPtr, (char *)elemPtr, (char *)NULL, flags); } else if (numOpts == 1) { return Tk_ConfigureInfo(interp, graphPtr->tkwin, elemPtr->specsPtr, (char *)elemPtr, options[0], flags); } if (Tk_ConfigureWidget(interp, graphPtr->tkwin, elemPtr->specsPtr, numOpts, options, (char *)elemPtr, flags) != TCL_OK) { return TCL_ERROR; } if ((*elemPtr->procsPtr->configProc) (graphPtr, elemPtr) != TCL_OK) { return TCL_ERROR; /* Failed to configure element */ } if (Blt_ConfigModified(elemPtr->specsPtr, "-hide", (char *)NULL)) { Blt_ChainLink *linkPtr; for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { if (elemPtr == Blt_ChainGetValue(linkPtr)) { break; } } if ((elemPtr->hidden) != (linkPtr == NULL)) { /* The element's "hidden" variable is out of sync with * the display list. [That's what you get for having * two ways to do the same thing.] This affects what * elements are considered for axis ranges and * displayed in the legend. Update the display list by * either by adding or removing the element. */ if (linkPtr == NULL) { Blt_ChainPrepend(graphPtr->elements.displayList, elemPtr); } else { Blt_ChainDeleteLink(graphPtr->elements.displayList, linkPtr); } } graphPtr->flags |= RESET_AXES; elemPtr->flags |= MAP_ITEM; } /* If data points or axes have changed, reset the axes (may * affect autoscaling) and recalculate the screen points of * the element. */ if (Blt_ConfigModified(elemPtr->specsPtr, "-*data", "-map*", "-x", "-y", (char *)NULL)) { graphPtr->flags |= RESET_WORLD; elemPtr->flags |= MAP_ITEM; } /* The new label may change the size of the legend */ if (Blt_ConfigModified(elemPtr->specsPtr, "-label", (char *)NULL)) { graphPtr->flags |= (MAP_WORLD | REDRAW_WORLD); } } /* Update the pixmap if any configuration option changed */ graphPtr->flags |= (REDRAW_BACKING_STORE | DRAW_MARGINS); Blt_EventuallyRedrawGraph(graphPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * DeactivateOp -- * * Clears the active bit for the named elements. * * Results: * Returns TCL_OK if no errors occurred. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int DeactivateOp(graphPtr, interp, argc, argv) Graph *graphPtr; /* Graph widget */ Tcl_Interp *interp; /* Not used. */ int argc; /* Number of element names */ char **argv; /* List of element names */ { Element *elemPtr; register int i; for (i = 3; i < argc; i++) { if (NameToElement(graphPtr, argv[i], &elemPtr) != TCL_OK) { return TCL_ERROR; /* Can't find named element */ } elemPtr->flags &= ~ELEM_ACTIVE; if (elemPtr->activeIndices != NULL) { Blt_Free(elemPtr->activeIndices); elemPtr->activeIndices = NULL; } elemPtr->nActiveIndices = 0; } Blt_EventuallyRedrawGraph(graphPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * DeleteOp -- * * Delete the named elements from the graph. * * Results: * TCL_ERROR is returned if any of the named elements can not be * found. Otherwise TCL_OK is returned; * * Side Effects: * If the element is currently displayed, the plotting area of * the graph is redrawn. Memory and resources allocated by the * elements are released. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int DeleteOp(graphPtr, interp, argc, argv) Graph *graphPtr; /* Graph widget */ Tcl_Interp *interp; /* Not used. */ int argc; /* Number of element names */ char **argv; /* List of element names */ { Element *elemPtr; register int i; for (i = 3; i < argc; i++) { if (NameToElement(graphPtr, argv[i], &elemPtr) != TCL_OK) { return TCL_ERROR; /* Can't find named element */ } DestroyElement(graphPtr, elemPtr); } Blt_EventuallyRedrawGraph(graphPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * ExistsOp -- * * Indicates if the named element exists in the graph. * * Results: * The return value is a standard Tcl result. The interpreter * result will contain "1" or "0". * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int ExistsOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&graphPtr->elements.table, argv[3]); Blt_SetBooleanResult(interp, (hPtr != NULL)); return TCL_OK; } /* *---------------------------------------------------------------------- * * GetOp -- * * Returns the name of the picked element (using the element * bind operation). Right now, the only name accepted is * "current". * * Results: * A standard Tcl result. The interpreter result will contain * the name of the element. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int GetOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; /* Not used. */ char *argv[]; { register Element *elemPtr; if ((argv[3][0] == 'c') && (strcmp(argv[3], "current") == 0)) { elemPtr = (Element *)Blt_GetCurrentItem(graphPtr->bindTable); /* Report only on elements. */ if ((elemPtr != NULL) && ((elemPtr->classUid == bltBarElementUid) || (elemPtr->classUid == bltLineElementUid) || (elemPtr->classUid == bltStripElementUid))) { Tcl_SetResult(interp, elemPtr->name, TCL_VOLATILE); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * NamesOp -- * * Returns the names of the elements is the graph matching * one of more patterns provided. If no pattern arguments * are given, then all element names will be returned. * * Results: * The return value is a standard Tcl result. The interpreter * result will contain a Tcl list of the element names. * *---------------------------------------------------------------------- */ static int NamesOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { Element *elemPtr; Blt_HashSearch cursor; register Blt_HashEntry *hPtr; register int i; for (hPtr = Blt_FirstHashEntry(&graphPtr->elements.table, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { elemPtr = (Element *)Blt_GetHashValue(hPtr); if (argc == 3) { Tcl_AppendElement(graphPtr->interp, elemPtr->name); continue; } for (i = 3; i < argc; i++) { if (Tcl_StringMatch(elemPtr->name, argv[i])) { Tcl_AppendElement(interp, elemPtr->name); break; } } } return TCL_OK; } /* *---------------------------------------------------------------------- * * ShowOp -- * * Queries or resets the element display list. * * Results: * The return value is a standard Tcl result. The interpreter * result will contain the new display list of element names. * *---------------------------------------------------------------------- */ static int ShowOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { Element *elemPtr; Blt_ChainLink *linkPtr; if (argc == 4) { if (RebuildDisplayList(graphPtr, argv[3]) != TCL_OK) { return TCL_ERROR; } } for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { elemPtr = Blt_ChainGetValue(linkPtr); Tcl_AppendElement(interp, elemPtr->name); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TypeOp -- * * Returns the name of the type of the element given by some * element name. * * Results: * A standard Tcl result. Returns the type of the element in * interp->result. If the identifier given doesn't represent an * element, then an error message is left in interp->result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TypeOp(graphPtr, interp, argc, argv) Graph *graphPtr; /* Graph widget */ Tcl_Interp *interp; int argc; /* Not used. */ char **argv; /* Element name */ { Element *elemPtr; if (NameToElement(graphPtr, argv[3], &elemPtr) != TCL_OK) { return TCL_ERROR; /* Can't find named element */ } Tcl_SetResult(interp, elemPtr->classUid, TCL_STATIC); return TCL_OK; } /* * Global routines: */ static Blt_OpSpec elemOps[] = { {"activate", 1, (Blt_Op)ActivateOp, 3, 0, "?elemName? ?index...?",}, {"bind", 1, (Blt_Op)BindOp, 3, 6, "elemName sequence command",}, {"cget", 2, (Blt_Op)CgetOp, 5, 5, "elemName option",}, {"closest", 2, (Blt_Op)ClosestOp, 6, 0, "x y varName ?option value?... ?elemName?...",}, {"configure", 2, (Blt_Op)ConfigureOp, 4, 0, "elemName ?elemName?... ?option value?...",}, {"create", 2, (Blt_Op)CreateOp, 4, 0, "elemName ?option value?...",}, {"deactivate", 3, (Blt_Op)DeactivateOp, 3, 0, "?elemName?...",}, {"delete", 3, (Blt_Op)DeleteOp, 3, 0, "?elemName?...",}, {"exists", 1, (Blt_Op)ExistsOp, 4, 4, "elemName",}, {"get", 1, (Blt_Op)GetOp, 4, 4, "name",}, {"names", 1, (Blt_Op)NamesOp, 3, 0, "?pattern?...",}, {"show", 1, (Blt_Op)ShowOp, 3, 4, "?elemList?",}, {"type", 1, (Blt_Op)TypeOp, 4, 4, "elemName",}, }; static int numElemOps = sizeof(elemOps) / sizeof(Blt_OpSpec); /* * ---------------------------------------------------------------- * * Blt_ElementOp -- * * This procedure is invoked to process the Tcl command that * corresponds to a widget managed by this module. See the user * documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * * ---------------------------------------------------------------- */ int Blt_ElementOp(graphPtr, interp, argc, argv, type) Graph *graphPtr; /* Graph widget record */ Tcl_Interp *interp; int argc; /* # arguments */ char **argv; /* Argument list */ Blt_Uid type; { Blt_Op proc; int result; proc = Blt_GetOp(interp, numElemOps, elemOps, BLT_OP_ARG2, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } if (proc == CreateOp) { result = CreateOp(graphPtr, interp, argc, argv, type); } else { result = (*proc) (graphPtr, interp, argc, argv); } return result; } blt-2.4z.orig/src/bltGrElem.h0100644000175000017500000002257407542177233014605 0ustar dokodoko/* * bltGrElem.h -- * * Copyright 1991-1998 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. */ #ifndef _BLT_GR_ELEM_H #define _BLT_GR_ELEM_H #define SEARCH_X 0 #define SEARCH_Y 1 #define SEARCH_BOTH 2 #define SHOW_NONE 0 #define SHOW_X 1 #define SHOW_Y 2 #define SHOW_BOTH 3 #define SEARCH_POINTS 0 /* Search for closest data point. */ #define SEARCH_TRACES 1 /* Search for closest point on trace. * Interpolate the connecting line segments * if necessary. */ #define SEARCH_AUTO 2 /* Automatically determine whether to search * for data points or traces. Look for * traces if the linewidth is > 0 and if * there is more than one data point. */ #define ELEM_ACTIVE (1<<8) /* Non-zero indicates that the element * should be drawn in its active * foreground and background * colors. */ #define ACTIVE_PENDING (1<<7) #define LABEL_ACTIVE (1<<9) /* Non-zero indicates that the * element's entry in the legend * should be drawn in its active * foreground and background * colors. */ #define SCALE_SYMBOL (1<<10) #define NumberOfPoints(e) MIN((e)->x.nValues, (e)->y.nValues) /* * ------------------------------------------------------------------- * * Weight -- * * Designates a range of values by a minimum and maximum limit. * * ------------------------------------------------------------------- */ typedef struct { double min, max, range; } Weight; #define SetRange(l) \ ((l).range = ((l).max > (l).min) ? ((l).max - (l).min) : DBL_EPSILON) #define SetScale(l) \ ((l).scale = 1.0 / (l).range) #define SetWeight(l, lo, hi) \ ((l).min = (lo), (l).max = (hi), SetRange(l)) /* * An element has one or more vectors plus several attributes, such as * line style, thickness, color, and symbol type. It has an * identifier which distinguishes it among the list of all elements. */ typedef struct { Weight weight; /* Weight range where this pen is valid. */ Pen *penPtr; /* Pen to use. */ Segment2D *xErrorBars; /* Point to start of this pen's X-error bar * segments in the element's array. */ Segment2D *yErrorBars; /* Point to start of this pen's Y-error bar * segments in the element's array. */ int xErrorBarCnt; /* # of error bars for this pen. */ int yErrorBarCnt; /* # of error bars for this pen. */ int errorBarCapWidth; /* Length of the cap ends on each * error bar. */ int symbolSize; /* Size of the pen's symbol scaled to * the current graph size. */ } PenStyle; typedef struct { XColor *color; /* Color of error bar */ int lineWidth; /* Width of the error bar segments. */ GC gc; int show; /* Flags for errorbars: none, x, y, or both */ } ErrorBarAttributes; typedef struct { int halo; /* Maximal distance a candidate point * can be from the sample window * coordinate */ int mode; /* Indicates whether to find the closest * data point or the closest point on the * trace by interpolating the line segments. * Can also be SEARCH_AUTO, indicating to * choose how to search.*/ int x, y; /* Screen coordinates of test point */ int along; /* Indicates to let search run along a * particular axis: x, y, or both. */ /* Output */ Element *elemPtr; /* Name of the closest element */ Point2D point; /* Graph coordinates of closest point */ int index; /* Index of closest data point */ double dist; /* Distance in screen coordinates */ } ClosestSearch; typedef void (ElementDrawProc) _ANSI_ARGS_((Graph *graphPtr, Drawable drawable, Element *elemPtr)); typedef void (ElementToPostScriptProc) _ANSI_ARGS_((Graph *graphPtr, PsToken psToken, Element *elemPtr)); typedef void (ElementDestroyProc) _ANSI_ARGS_((Graph *graphPtr, Element *elemPtr)); typedef int (ElementConfigProc) _ANSI_ARGS_((Graph *graphPtr, Element *elemPtr)); typedef void (ElementMapProc) _ANSI_ARGS_((Graph *graphPtr, Element *elemPtr)); typedef void (ElementExtentsProc) _ANSI_ARGS_((Element *elemPtr, Extents2D *extsPtr)); typedef void (ElementClosestProc) _ANSI_ARGS_((Graph *graphPtr, Element *elemPtr, ClosestSearch *searchPtr)); typedef void (ElementDrawSymbolProc) _ANSI_ARGS_((Graph *graphPtr, Drawable drawable, Element *elemPtr, int x, int y, int symbolSize)); typedef void (ElementSymbolToPostScriptProc) _ANSI_ARGS_((Graph *graphPtr, PsToken psToken, Element *elemPtr, double x, double y, int symSize)); typedef struct { ElementClosestProc *closestProc; ElementConfigProc *configProc; ElementDestroyProc *destroyProc; ElementDrawProc *drawActiveProc; ElementDrawProc *drawNormalProc; ElementDrawSymbolProc *drawSymbolProc; ElementExtentsProc *extentsProc; ElementToPostScriptProc *printActiveProc; ElementToPostScriptProc *printNormalProc; ElementSymbolToPostScriptProc *printSymbolProc; ElementMapProc *mapProc; } ElementProcs; /* * The data structure below contains information pertaining to a line * vector. It consists of an array of floating point data values and * for convenience, the number and minimum/maximum values. */ typedef struct { Blt_Vector *vecPtr; double *valueArr; int nValues; int arraySize; double min, max; Blt_VectorId clientId; /* If non-NULL, a client token identifying the * external vector. */ Element *elemPtr; /* Element associated with vector. */ } ElemVector; struct ElementStruct { char *name; /* Identifier to refer the element. * Used in the "insert", "delete", or * "show", commands. */ Blt_Uid classUid; /* Type of element */ Graph *graphPtr; /* Graph widget of element*/ unsigned int flags; /* Indicates if the entire element is * active, or if coordinates need to * be calculated */ char **tags; int hidden; /* If non-zero, don't display the element. */ Blt_HashEntry *hashPtr; char *label; /* Label displayed in legend */ int labelRelief; /* Relief of label in legend. */ Axis2D axes; /* X-axis and Y-axis mapping the element */ ElemVector x, y, w; /* Contains array of floating point * graph coordinate values. Also holds * min/max and the number of * coordinates */ ElemVector xError; /* Relative/symmetric X error values. */ ElemVector yError; /* Relative/symmetric Y error values. */ ElemVector xHigh, xLow; /* Absolute/asymmetric X-coordinate high/low error values. */ ElemVector yHigh, yLow; /* Absolute/asymmetric Y-coordinate high/low error values. */ int *activeIndices; /* Array of indices (malloc-ed) which * indicate which data points are * active (drawn with "active" * colors). */ int nActiveIndices; /* Number of active data points. * Special case: if nActiveIndices < 0 * and the active bit is set in * "flags", then all data points are * drawn active. */ ElementProcs *procsPtr; Tk_ConfigSpec *specsPtr; /* Configuration specifications. */ Segment2D *xErrorBars; /* Point to start of this pen's X-error bar * segments in the element's array. */ Segment2D *yErrorBars; /* Point to start of this pen's Y-error bar * segments in the element's array. */ int xErrorBarCnt; /* # of error bars for this pen. */ int yErrorBarCnt; /* # of error bars for this pen. */ int *xErrorToData; /* Maps error bar segments back to the data * point. */ int *yErrorToData; /* Maps error bar segments back to the data * point. */ int errorBarCapWidth; /* Length of cap on error bars */ Pen *activePenPtr; /* Standard Pens */ Pen *normalPenPtr; Blt_Chain *palette; /* Palette of pens. */ /* Symbol scaling */ int scaleSymbols; /* If non-zero, the symbols will scale * in size as the graph is zoomed * in/out. */ double xRange, yRange; /* Initial X-axis and Y-axis ranges: * used to scale the size of element's * symbol. */ int state; }; extern double Blt_FindElemVectorMinimum _ANSI_ARGS_((ElemVector *vecPtr, double minLimit)); extern void Blt_ResizeStatusArray _ANSI_ARGS_((Element *elemPtr, int nPoints)); extern int Blt_GetPenStyle _ANSI_ARGS_((Graph *graphPtr, char *name, Blt_Uid classUid, PenStyle *stylePtr)); extern void Blt_FreePalette _ANSI_ARGS_((Graph *graphPtr, Blt_Chain *palette)); extern PenStyle **Blt_StyleMap _ANSI_ARGS_((Element *elemPtr)); extern void Blt_MapErrorBars _ANSI_ARGS_((Graph *graphPtr, Element *elemPtr, PenStyle **dataToStyle)); #endif /* _BLT_GR_ELEM_H */ blt-2.4z.orig/src/bltGrGrid.c0100644000175000017500000003302207501321463014560 0ustar dokodoko /* * bltGrGrid.c -- * * This module implements grid lines for the BLT graph widget. * * Copyright 1995-1998 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. * * Graph widget created by Sani Nassif and George Howlett. */ #include "bltGraph.h" extern Tk_CustomOption bltDistanceOption; extern Tk_CustomOption bltDashesOption; extern Tk_CustomOption bltAnyXAxisOption; extern Tk_CustomOption bltAnyYAxisOption; #define DEF_GRID_DASHES "dot" #define DEF_GRID_FOREGROUND RGB_GREY64 #define DEF_GRID_FG_MONO RGB_BLACK #define DEF_GRID_LINE_WIDTH "0" #define DEF_GRID_HIDE_BARCHART "no" #define DEF_GRID_HIDE_GRAPH "yes" #define DEF_GRID_MINOR "yes" #define DEF_GRID_MAP_X_GRAPH "x" #define DEF_GRID_MAP_X_BARCHART (char *)NULL #define DEF_GRID_MAP_Y "y" #define DEF_GRID_POSITION (char *)NULL static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_COLOR, "-color", "color", "Color", DEF_GRID_FOREGROUND, Tk_Offset(Grid, colorPtr), TK_CONFIG_COLOR_ONLY | ALL_GRAPHS}, {TK_CONFIG_COLOR, "-color", "color", "color", DEF_GRID_FG_MONO, Tk_Offset(Grid, colorPtr), TK_CONFIG_MONO_ONLY | ALL_GRAPHS}, {TK_CONFIG_CUSTOM, "-dashes", "dashes", "Dashes", DEF_GRID_DASHES, Tk_Offset(Grid, dashes), TK_CONFIG_NULL_OK | ALL_GRAPHS, &bltDashesOption}, {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide", DEF_GRID_HIDE_BARCHART, Tk_Offset(Grid, hidden), BARCHART}, {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide", DEF_GRID_HIDE_GRAPH, Tk_Offset(Grid, hidden), GRAPH | STRIPCHART}, {TK_CONFIG_CUSTOM, "-linewidth", "lineWidth", "Linewidth", DEF_GRID_LINE_WIDTH, Tk_Offset(Grid, lineWidth), TK_CONFIG_DONT_SET_DEFAULT | ALL_GRAPHS, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-mapx", "mapX", "MapX", DEF_GRID_MAP_X_GRAPH, Tk_Offset(Grid, axes.x), GRAPH | STRIPCHART, &bltAnyXAxisOption}, {TK_CONFIG_CUSTOM, "-mapx", "mapX", "MapX", DEF_GRID_MAP_X_BARCHART, Tk_Offset(Grid, axes.x), BARCHART, &bltAnyXAxisOption}, {TK_CONFIG_CUSTOM, "-mapy", "mapY", "MapY", DEF_GRID_MAP_Y, Tk_Offset(Grid, axes.y), ALL_GRAPHS, &bltAnyYAxisOption}, {TK_CONFIG_BOOLEAN, "-minor", "minor", "Minor", DEF_GRID_MINOR, Tk_Offset(Grid, minorGrid), TK_CONFIG_DONT_SET_DEFAULT | ALL_GRAPHS}, {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} }; /* *---------------------------------------------------------------------- * * ConfigureGrid -- * * Configures attributes of the grid such as line width, * dashes, and position. The grid are first turned off * before any of the attributes changes. * * Results: * None * * Side Effects: * Crosshair GC is allocated. * *---------------------------------------------------------------------- */ static void ConfigureGrid(graphPtr, gridPtr) Graph *graphPtr; Grid *gridPtr; { XGCValues gcValues; unsigned long gcMask; GC newGC; gcValues.background = gcValues.foreground = gridPtr->colorPtr->pixel; gcValues.line_width = LineWidth(gridPtr->lineWidth); gcMask = (GCForeground | GCBackground | GCLineWidth); if (LineIsDashed(gridPtr->dashes)) { gcValues.line_style = LineOnOffDash; gcMask |= GCLineStyle; } newGC = Blt_GetPrivateGC(graphPtr->tkwin, gcMask, &gcValues); if (LineIsDashed(gridPtr->dashes)) { Blt_SetDashes(graphPtr->display, newGC, &(gridPtr->dashes)); } if (gridPtr->gc != NULL) { Blt_FreePrivateGC(graphPtr->display, gridPtr->gc); } gridPtr->gc = newGC; } /* *---------------------------------------------------------------------- * * MapGrid -- * * Determines the coordinates of the line segments corresponding * to the grid lines for each axis. * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_MapGrid(graphPtr) Graph *graphPtr; { Grid *gridPtr = (Grid *)graphPtr->gridPtr; int nSegments; Segment2D *segments; if (gridPtr->x.segments != NULL) { Blt_Free(gridPtr->x.segments); gridPtr->x.segments = NULL; } if (gridPtr->y.segments != NULL) { Blt_Free(gridPtr->y.segments); gridPtr->y.segments = NULL; } gridPtr->x.nSegments = gridPtr->y.nSegments = 0; /* * Generate line segments to represent the grid. Line segments * are calculated from the major tick intervals of each axis mapped. */ Blt_GetAxisSegments(graphPtr, gridPtr->axes.x, &segments, &nSegments); if (nSegments > 0) { gridPtr->x.nSegments = nSegments; gridPtr->x.segments = segments; } Blt_GetAxisSegments(graphPtr, gridPtr->axes.y, &segments, &nSegments); if (nSegments > 0) { gridPtr->y.nSegments = nSegments; gridPtr->y.segments = segments; } } /* *---------------------------------------------------------------------- * * DrawGrid -- * * Draws the grid lines associated with each axis. * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_DrawGrid(graphPtr, drawable) Graph *graphPtr; Drawable drawable; /* Pixmap or window to draw into */ { Grid *gridPtr = (Grid *)graphPtr->gridPtr; if (gridPtr->hidden) { return; } if (gridPtr->x.nSegments > 0) { Blt_Draw2DSegments(graphPtr->display, drawable, gridPtr->gc, gridPtr->x.segments, gridPtr->x.nSegments); } if (gridPtr->y.nSegments > 0) { Blt_Draw2DSegments(graphPtr->display, drawable, gridPtr->gc, gridPtr->y.segments, gridPtr->y.nSegments); } } /* *---------------------------------------------------------------------- * * Blt_GridToPostScript -- * * Prints the grid lines associated with each axis. * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_GridToPostScript(graphPtr, psToken) Graph *graphPtr; PsToken psToken; { Grid *gridPtr = (Grid *)graphPtr->gridPtr; if (gridPtr->hidden) { return; } Blt_LineAttributesToPostScript(psToken, gridPtr->colorPtr, gridPtr->lineWidth, &(gridPtr->dashes), CapButt, JoinMiter); if (gridPtr->x.nSegments > 0) { Blt_2DSegmentsToPostScript(psToken, gridPtr->x.segments, gridPtr->x.nSegments); } if (gridPtr->y.nSegments > 0) { Blt_2DSegmentsToPostScript(psToken, gridPtr->y.segments, gridPtr->y.nSegments); } } /* *---------------------------------------------------------------------- * * Blt_DestroyGrid -- * * Results: * None * * Side Effects: * Grid GC is released. * *---------------------------------------------------------------------- */ void Blt_DestroyGrid(graphPtr) Graph *graphPtr; { Grid *gridPtr = (Grid *)graphPtr->gridPtr; Tk_FreeOptions(configSpecs, (char *)gridPtr, graphPtr->display, Blt_GraphType(graphPtr)); if (gridPtr->gc != NULL) { Blt_FreePrivateGC(graphPtr->display, gridPtr->gc); } if (gridPtr->x.segments != NULL) { Blt_Free(gridPtr->x.segments); } if (gridPtr->y.segments != NULL) { Blt_Free(gridPtr->y.segments); } Blt_Free(gridPtr); } /* *---------------------------------------------------------------------- * * Blt_CreateGrid -- * * Creates and initializes a new grid structure. * * Results: * Returns TCL_ERROR if the configuration failed, otherwise TCL_OK. * * Side Effects: * Memory for grid structure is allocated. * *---------------------------------------------------------------------- */ int Blt_CreateGrid(graphPtr) Graph *graphPtr; { Grid *gridPtr; gridPtr = Blt_Calloc(1, sizeof(Grid)); assert(gridPtr); gridPtr->minorGrid = TRUE; graphPtr->gridPtr = gridPtr; if (Blt_ConfigureWidgetComponent(graphPtr->interp, graphPtr->tkwin, "grid", "Grid", configSpecs, 0, (char **)NULL, (char *)gridPtr, Blt_GraphType(graphPtr)) != TCL_OK) { return TCL_ERROR; } ConfigureGrid(graphPtr, gridPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * CgetOp -- * * Queries configuration attributes of the grid such as line * width, dashes, and position. * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int CgetOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { Grid *gridPtr = (Grid *)graphPtr->gridPtr; return Tk_ConfigureValue(interp, graphPtr->tkwin, configSpecs, (char *)gridPtr, argv[3], Blt_GraphType(graphPtr)); } /* *---------------------------------------------------------------------- * * ConfigureOp -- * * Queries or resets configuration attributes of the grid * such as line width, dashes, and position. * * Results: * A standard Tcl result. * * Side Effects: * Grid attributes are reset. The graph is redrawn at the * next idle point. * *---------------------------------------------------------------------- */ static int ConfigureOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { Grid *gridPtr = (Grid *)graphPtr->gridPtr; int flags; flags = Blt_GraphType(graphPtr) | TK_CONFIG_ARGV_ONLY; if (argc == 3) { return Tk_ConfigureInfo(interp, graphPtr->tkwin, configSpecs, (char *)gridPtr, (char *)NULL, flags); } else if (argc == 4) { return Tk_ConfigureInfo(interp, graphPtr->tkwin, configSpecs, (char *)gridPtr, argv[3], flags); } if (Tk_ConfigureWidget(graphPtr->interp, graphPtr->tkwin, configSpecs, argc - 3, argv + 3, (char *)gridPtr, flags) != TCL_OK) { return TCL_ERROR; } ConfigureGrid(graphPtr, gridPtr); graphPtr->flags |= REDRAW_BACKING_STORE; Blt_EventuallyRedrawGraph(graphPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * MapOp -- * * Maps the grid. * * Results: * A standard Tcl result. * * Side Effects: * Grid attributes are reset and the graph is redrawn if necessary. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int MapOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { Grid *gridPtr = (Grid *)graphPtr->gridPtr; if (gridPtr->hidden) { gridPtr->hidden = FALSE;/* Changes "-hide" configuration option */ graphPtr->flags |= REDRAW_BACKING_STORE; Blt_EventuallyRedrawGraph(graphPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * MapOp -- * * Maps or unmaps the grid (off or on). * * Results: * A standard Tcl result. * * Side Effects: * Grid attributes are reset and the graph is redrawn if necessary. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int UnmapOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { Grid *gridPtr = (Grid *)graphPtr->gridPtr; if (!gridPtr->hidden) { gridPtr->hidden = TRUE; /* Changes "-hide" configuration option */ graphPtr->flags |= REDRAW_BACKING_STORE; Blt_EventuallyRedrawGraph(graphPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * ToggleOp -- * * Toggles the state of the grid shown/hidden. * * Results: * A standard Tcl result. * * Side Effects: * Grid is hidden/displayed. The graph is redrawn at the next * idle time. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ToggleOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { Grid *gridPtr = (Grid *)graphPtr->gridPtr; gridPtr->hidden = (!gridPtr->hidden); graphPtr->flags |= REDRAW_BACKING_STORE; Blt_EventuallyRedrawGraph(graphPtr); return TCL_OK; } static Blt_OpSpec gridOps[] = { {"cget", 2, (Blt_Op)CgetOp, 4, 4, "option",}, {"configure", 2, (Blt_Op)ConfigureOp, 3, 0, "?options...?",}, {"off", 2, (Blt_Op)UnmapOp, 3, 3, "",}, {"on", 2, (Blt_Op)MapOp, 3, 3, "",}, {"toggle", 1, (Blt_Op)ToggleOp, 3, 3, "",}, }; static int nGridOps = sizeof(gridOps) / sizeof(Blt_OpSpec); /* *---------------------------------------------------------------------- * * Blt_GridOp -- * * User routine to configure grid lines. Grids are drawn * at major tick intervals across the graph. * * Results: * The return value is a standard Tcl result. * * Side Effects: * Grid may be drawn in the plotting area. * *---------------------------------------------------------------------- */ int Blt_GridOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { Blt_Op proc; proc = Blt_GetOp(interp, nGridOps, gridOps, BLT_OP_ARG2, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } return (*proc) (graphPtr, interp, argc, argv); } blt-2.4z.orig/src/bltGrHairs.c0100644000175000017500000003406007503465647014763 0ustar dokodoko /* * bltGrHairs.c -- * * This module implements crosshairs for the BLT graph widget. * * Copyright 1993-1998 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. * * Graph widget created by Sani Nassif and George Howlett. */ #include "bltGraph.h" extern Tk_CustomOption bltPointOption; extern Tk_CustomOption bltDistanceOption; extern Tk_CustomOption bltDashesOption; /* * ------------------------------------------------------------------- * * Crosshairs * * Contains the line segments positions and graphics context used * to simulate crosshairs (by XORing) on the graph. * * ------------------------------------------------------------------- */ struct CrosshairsStruct { XPoint hotSpot; /* Hot spot for crosshairs */ int visible; /* Internal state of crosshairs. If non-zero, * crosshairs are displayed. */ int hidden; /* If non-zero, crosshairs are not displayed. * This is not necessarily consistent with the * internal state variable. This is true when * the hot spot is off the graph. */ Blt_Dashes dashes; /* Dashstyle of the crosshairs. This represents * an array of alternatingly drawn pixel * values. If NULL, the hairs are drawn as a * solid line */ int lineWidth; /* Width of the simulated crosshair lines */ XSegment segArr[2]; /* Positions of line segments representing the * simulated crosshairs. */ XColor *colorPtr; /* Foreground color of crosshairs */ GC gc; /* Graphics context for crosshairs. Set to * GXxor to not require redraws of graph */ }; #define DEF_HAIRS_DASHES (char *)NULL #define DEF_HAIRS_FOREGROUND RGB_BLACK #define DEF_HAIRS_FG_MONO RGB_BLACK #define DEF_HAIRS_LINE_WIDTH "0" #define DEF_HAIRS_HIDE "yes" #define DEF_HAIRS_POSITION (char *)NULL static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_COLOR, "-color", "color", "Color", DEF_HAIRS_FOREGROUND, Tk_Offset(Crosshairs, colorPtr), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-color", "color", "Color", DEF_HAIRS_FG_MONO, Tk_Offset(Crosshairs, colorPtr), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_CUSTOM, "-dashes", "dashes", "Dashes", DEF_HAIRS_DASHES, Tk_Offset(Crosshairs, dashes), TK_CONFIG_NULL_OK, &bltDashesOption}, {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide", DEF_HAIRS_HIDE, Tk_Offset(Crosshairs, hidden), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-linewidth", "lineWidth", "Linewidth", DEF_HAIRS_LINE_WIDTH, Tk_Offset(Crosshairs, lineWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-position", "position", "Position", DEF_HAIRS_POSITION, Tk_Offset(Crosshairs, hotSpot), 0, &bltPointOption}, {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} }; /* *---------------------------------------------------------------------- * * TurnOffHairs -- * * XOR's the existing line segments (representing the crosshairs), * thereby erasing them. The internal state of the crosshairs is * tracked. * * Results: * None * * Side Effects: * Crosshairs are erased. * *---------------------------------------------------------------------- */ static void TurnOffHairs(tkwin, chPtr) Tk_Window tkwin; Crosshairs *chPtr; { if (Tk_IsMapped(tkwin) && (chPtr->visible)) { XDrawSegments(Tk_Display(tkwin), Tk_WindowId(tkwin), chPtr->gc, chPtr->segArr, 2); chPtr->visible = FALSE; } } /* *---------------------------------------------------------------------- * * TurnOnHairs -- * * Draws (by XORing) new line segments, creating the effect of * crosshairs. The internal state of the crosshairs is tracked. * * Results: * None * * Side Effects: * Crosshairs are displayed. * *---------------------------------------------------------------------- */ static void TurnOnHairs(graphPtr, chPtr) Graph *graphPtr; Crosshairs *chPtr; { if (Tk_IsMapped(graphPtr->tkwin) && (!chPtr->visible)) { if (!PointInGraph(graphPtr, chPtr->hotSpot.x, chPtr->hotSpot.y)) { return; /* Coordinates are off the graph */ } XDrawSegments(graphPtr->display, Tk_WindowId(graphPtr->tkwin), chPtr->gc, chPtr->segArr, 2); chPtr->visible = TRUE; } } /* *---------------------------------------------------------------------- * * ConfigureCrosshairs -- * * Configures attributes of the crosshairs such as line width, * dashes, and position. The crosshairs are first turned off * before any of the attributes changes. * * Results: * None * * Side Effects: * Crosshair GC is allocated. * *---------------------------------------------------------------------- */ void Blt_ConfigureCrosshairs(graphPtr) Graph *graphPtr; { XGCValues gcValues; unsigned long gcMask; GC newGC; long colorValue; Crosshairs *chPtr = graphPtr->crosshairs; /* * Turn off the crosshairs temporarily. This is in case the new * configuration changes the size, style, or position of the lines. */ TurnOffHairs(graphPtr->tkwin, chPtr); gcValues.function = GXxor; if (graphPtr->plotBg == NULL) { /* The graph's color option may not have been set yet */ colorValue = WhitePixelOfScreen(Tk_Screen(graphPtr->tkwin)); } else { colorValue = graphPtr->plotBg->pixel; } gcValues.background = colorValue; gcValues.foreground = (colorValue ^ chPtr->colorPtr->pixel); gcValues.line_width = LineWidth(chPtr->lineWidth); gcMask = (GCForeground | GCBackground | GCFunction | GCLineWidth); if (LineIsDashed(chPtr->dashes)) { gcValues.line_style = LineOnOffDash; gcMask |= GCLineStyle; } newGC = Blt_GetPrivateGC(graphPtr->tkwin, gcMask, &gcValues); if (LineIsDashed(chPtr->dashes)) { Blt_SetDashes(graphPtr->display, newGC, &(chPtr->dashes)); } if (chPtr->gc != NULL) { Blt_FreePrivateGC(graphPtr->display, chPtr->gc); } chPtr->gc = newGC; /* * Are the new coordinates on the graph? */ chPtr->segArr[0].x2 = chPtr->segArr[0].x1 = chPtr->hotSpot.x; chPtr->segArr[0].y1 = graphPtr->bottom; chPtr->segArr[0].y2 = graphPtr->top; chPtr->segArr[1].y2 = chPtr->segArr[1].y1 = chPtr->hotSpot.y; chPtr->segArr[1].x1 = graphPtr->left; chPtr->segArr[1].x2 = graphPtr->right; if (!chPtr->hidden) { TurnOnHairs(graphPtr, chPtr); } } void Blt_EnableCrosshairs(graphPtr) Graph *graphPtr; { if (!graphPtr->crosshairs->hidden) { TurnOnHairs(graphPtr, graphPtr->crosshairs); } } void Blt_DisableCrosshairs(graphPtr) Graph *graphPtr; { if (!graphPtr->crosshairs->hidden) { TurnOffHairs(graphPtr->tkwin, graphPtr->crosshairs); } } /* *---------------------------------------------------------------------- * * UpdateCrosshairs -- * * Update the length of the hairs (not the hot spot). * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_UpdateCrosshairs(graphPtr) Graph *graphPtr; { Crosshairs *chPtr = graphPtr->crosshairs; chPtr->segArr[0].y1 = graphPtr->bottom; chPtr->segArr[0].y2 = graphPtr->top; chPtr->segArr[1].x1 = graphPtr->left; chPtr->segArr[1].x2 = graphPtr->right; } /* *---------------------------------------------------------------------- * * Blt_DestroyCrosshairs -- * * Results: * None * * Side Effects: * Crosshair GC is allocated. * *---------------------------------------------------------------------- */ void Blt_DestroyCrosshairs(graphPtr) Graph *graphPtr; { Crosshairs *chPtr = graphPtr->crosshairs; Tk_FreeOptions(configSpecs, (char *)chPtr, graphPtr->display, 0); if (chPtr->gc != NULL) { Blt_FreePrivateGC(graphPtr->display, chPtr->gc); } Blt_Free(chPtr); } /* *---------------------------------------------------------------------- * * Blt_CreateCrosshairs -- * * Creates and initializes a new crosshair structure. * * Results: * Returns TCL_ERROR if the crosshair structure can't be created, * otherwise TCL_OK. * * Side Effects: * Crosshair GC is allocated. * *---------------------------------------------------------------------- */ int Blt_CreateCrosshairs(graphPtr) Graph *graphPtr; { Crosshairs *chPtr; chPtr = Blt_Calloc(1, sizeof(Crosshairs)); assert(chPtr); chPtr->hidden = TRUE; chPtr->hotSpot.x = chPtr->hotSpot.y = -1; graphPtr->crosshairs = chPtr; if (Blt_ConfigureWidgetComponent(graphPtr->interp, graphPtr->tkwin, "crosshairs", "Crosshairs", configSpecs, 0, (char **)NULL, (char *)chPtr, 0) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * CgetOp -- * * Queries configuration attributes of the crosshairs such as * line width, dashes, and position. * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int CgetOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Crosshairs *chPtr = graphPtr->crosshairs; return Tk_ConfigureValue(interp, graphPtr->tkwin, configSpecs, (char *)chPtr, argv[3], 0); } /* *---------------------------------------------------------------------- * * ConfigureOp -- * * Queries or resets configuration attributes of the crosshairs * such as line width, dashes, and position. * * Results: * A standard Tcl result. * * Side Effects: * Crosshairs are reset. * *---------------------------------------------------------------------- */ static int ConfigureOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { Crosshairs *chPtr = graphPtr->crosshairs; if (argc == 3) { return Tk_ConfigureInfo(interp, graphPtr->tkwin, configSpecs, (char *)chPtr, (char *)NULL, 0); } else if (argc == 4) { return Tk_ConfigureInfo(interp, graphPtr->tkwin, configSpecs, (char *)chPtr, argv[3], 0); } if (Tk_ConfigureWidget(interp, graphPtr->tkwin, configSpecs, argc - 3, argv + 3, (char *)chPtr, TK_CONFIG_ARGV_ONLY) != TCL_OK) { return TCL_ERROR; } Blt_ConfigureCrosshairs(graphPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * OnOp -- * * Maps the crosshairs. * * Results: * A standard Tcl result. * * Side Effects: * Crosshairs are reset if necessary. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int OnOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { Crosshairs *chPtr = graphPtr->crosshairs; if (chPtr->hidden) { TurnOnHairs(graphPtr, chPtr); chPtr->hidden = FALSE; } return TCL_OK; } /* *---------------------------------------------------------------------- * * OffOp -- * * Unmaps the crosshairs. * * Results: * A standard Tcl result. * * Side Effects: * Crosshairs are reset if necessary. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int OffOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { Crosshairs *chPtr = graphPtr->crosshairs; if (!chPtr->hidden) { TurnOffHairs(graphPtr->tkwin, chPtr); chPtr->hidden = TRUE; } return TCL_OK; } /* *---------------------------------------------------------------------- * * ToggleOp -- * * Toggles the state of the crosshairs. * * Results: * A standard Tcl result. * * Side Effects: * Crosshairs are reset. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ToggleOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { Crosshairs *chPtr = graphPtr->crosshairs; chPtr->hidden = (chPtr->hidden == 0); if (chPtr->hidden) { TurnOffHairs(graphPtr->tkwin, chPtr); } else { TurnOnHairs(graphPtr, chPtr); } return TCL_OK; } static Blt_OpSpec xhairOps[] = { {"cget", 2, (Blt_Op)CgetOp, 4, 4, "option",}, {"configure", 2, (Blt_Op)ConfigureOp, 3, 0, "?options...?",}, {"off", 2, (Blt_Op)OffOp, 3, 3, "",}, {"on", 2, (Blt_Op)OnOp, 3, 3, "",}, {"toggle", 1, (Blt_Op)ToggleOp, 3, 3, "",}, }; static int nXhairOps = sizeof(xhairOps) / sizeof(Blt_OpSpec); /* *---------------------------------------------------------------------- * * Blt_CrosshairsOp -- * * User routine to configure crosshair simulation. Crosshairs * are simulated by drawing line segments parallel to both axes * using the XOR drawing function. The allows the lines to be * erased (by drawing them again) without redrawing the entire * graph. Care must be taken to erase crosshairs before redrawing * the graph and redraw them after the graph is redraw. * * Results: * The return value is a standard Tcl result. * * Side Effects: * Crosshairs may be drawn in the plotting area. * *---------------------------------------------------------------------- */ int Blt_CrosshairsOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { Blt_Op proc; proc = Blt_GetOp(interp, nXhairOps, xhairOps, BLT_OP_ARG2, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } return (*proc) (graphPtr, interp, argc, argv); } blt-2.4z.orig/src/bltGrLegd.c0100644000175000017500000013056707542177233014573 0ustar dokodoko /* * bltGrLegd.c -- * * This module implements the legend for the BLT graph widget. * * Copyright 1993-1998 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. */ #include "bltGraph.h" #include "bltGrElem.h" /* * ------------------------------------------------------------------- * * Legend -- * * Contains information specific to how the legend will be * displayed. * * * ------------------------------------------------------------------- */ struct LegendStruct { unsigned int flags; Blt_Uid classUid; /* Type: Element or Marker. */ int hidden; /* If non-zero, don't display the legend. */ int raised; /* If non-zero, draw the legend last, above * everything else. */ int nEntries; /* Number of element entries in table. */ short int width, height; /* Dimensions of the legend */ short int nColumns, nRows; /* Number of columns and rows in legend */ int site; Point2D anchorPos; /* Says how to position the legend. Indicates * the site and/or x-y screen coordinates of * the legend. Used in conjunction with the * anchor to determine its location. */ Tk_Anchor anchor; /* Anchor of legend. Used to interpret the * positioning point of the legend in the * graph*/ int x, y; /* Computed origin of legend. */ Graph *graphPtr; Tcl_Command cmdToken; /* Token for graph's widget command. */ int reqColumns, reqRows; Blt_Pad ipadX, ipadY; /* # of pixels padding around legend entries */ Blt_Pad padX, padY; /* # of pixels padding to exterior of legend */ Tk_Window tkwin; /* Optional external window to draw legend. */ TextStyle style; int maxSymSize; /* Size of largest symbol to be displayed. * Used to calculate size of legend */ Tk_3DBorder activeBorder; /* Active legend entry background color. */ int activeRelief; /* 3-D effect on active entry. */ int entryBorderWidth; /* Border width around each entry in legend. */ Tk_3DBorder border; /* 3-D effect of legend. */ int borderWidth; /* Width of legend 3-D border */ int relief; /* 3-d effect of border around the legend: * TK_RELIEF_RAISED etc. */ Blt_BindTable bindTable; }; #define padLeft padX.side1 #define padRight padX.side2 #define padTop padY.side1 #define padBottom padY.side2 #define PADDING(x) ((x).side1 + (x).side2) #define DEF_LEGEND_ACTIVE_BACKGROUND STD_ACTIVE_BACKGROUND #define DEF_LEGEND_ACTIVE_BG_MONO STD_ACTIVE_BG_MONO #define DEF_LEGEND_ACTIVE_BORDERWIDTH "2" #define DEF_LEGEND_ACTIVE_FOREGROUND STD_ACTIVE_FOREGROUND #define DEF_LEGEND_ACTIVE_FG_MONO STD_ACTIVE_FG_MONO #define DEF_LEGEND_ACTIVE_RELIEF "flat" #define DEF_LEGEND_ANCHOR "n" #define DEF_LEGEND_BACKGROUND (char *)NULL #define DEF_LEGEND_BG_MONO (char *)NULL #define DEF_LEGEND_BORDERWIDTH STD_BORDERWIDTH #define DEF_LEGEND_FOREGROUND STD_NORMAL_FOREGROUND #define DEF_LEGEND_FG_MONO STD_NORMAL_FG_MONO #define DEF_LEGEND_FONT STD_FONT_SMALL #define DEF_LEGEND_HIDE "no" #define DEF_LEGEND_IPAD_X "1" #define DEF_LEGEND_IPAD_Y "1" #define DEF_LEGEND_PAD_X "1" #define DEF_LEGEND_PAD_Y "1" #define DEF_LEGEND_POSITION "rightmargin" #define DEF_LEGEND_RAISED "no" #define DEF_LEGEND_RELIEF "sunken" #define DEF_LEGEND_SHADOW_COLOR (char *)NULL #define DEF_LEGEND_SHADOW_MONO (char *)NULL #define DEF_LEGEND_ROWS "0" #define DEF_LEGEND_COLUMNS "0" static Tk_OptionParseProc StringToPosition; static Tk_OptionPrintProc PositionToString; static Tk_CustomOption legendPositionOption = { StringToPosition, PositionToString, (ClientData)0 }; extern Tk_CustomOption bltDistanceOption; extern Tk_CustomOption bltPadOption; extern Tk_CustomOption bltShadowOption; extern Tk_CustomOption bltCountOption; static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "ActiveBackground", DEF_LEGEND_ACTIVE_BACKGROUND, Tk_Offset(Legend, activeBorder), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "ActiveBackground", DEF_LEGEND_ACTIVE_BG_MONO, Tk_Offset(Legend, activeBorder), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_CUSTOM, "-activeborderwidth", "activeBorderWidth", "BorderWidth", DEF_LEGEND_BORDERWIDTH, Tk_Offset(Legend, entryBorderWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "ActiveForeground", DEF_LEGEND_ACTIVE_FOREGROUND, Tk_Offset(Legend, style.activeColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "ActiveForeground", DEF_LEGEND_ACTIVE_FG_MONO, Tk_Offset(Legend, style.activeColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_RELIEF, "-activerelief", "activeRelief", "Relief", DEF_LEGEND_ACTIVE_RELIEF, Tk_Offset(Legend, activeRelief), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", DEF_LEGEND_ANCHOR, Tk_Offset(Legend, anchor), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_LEGEND_BG_MONO, Tk_Offset(Legend, border), TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_LEGEND_BACKGROUND, Tk_Offset(Legend, border), TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_CUSTOM, "-borderwidth", "borderWidth", "BorderWidth", DEF_LEGEND_BORDERWIDTH, Tk_Offset(Legend, borderWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_CUSTOM, "-columns", "columns", "columns", DEF_LEGEND_COLUMNS, Tk_Offset(Legend, reqColumns), TK_CONFIG_DONT_SET_DEFAULT, &bltCountOption}, {TK_CONFIG_FONT, "-font", "font", "Font", DEF_LEGEND_FONT, Tk_Offset(Legend, style.font), 0}, {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_LEGEND_FOREGROUND, Tk_Offset(Legend, style.color), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_LEGEND_FG_MONO, Tk_Offset(Legend, style.color), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide", DEF_LEGEND_HIDE, Tk_Offset(Legend, hidden), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-ipadx", "iPadX", "Pad", DEF_LEGEND_IPAD_X, Tk_Offset(Legend, ipadX), TK_CONFIG_DONT_SET_DEFAULT, &bltPadOption}, {TK_CONFIG_CUSTOM, "-ipady", "iPadY", "Pad", DEF_LEGEND_IPAD_Y, Tk_Offset(Legend, ipadY), TK_CONFIG_DONT_SET_DEFAULT, &bltPadOption}, {TK_CONFIG_CUSTOM, "-padx", "padX", "Pad", DEF_LEGEND_PAD_X, Tk_Offset(Legend, padX), TK_CONFIG_DONT_SET_DEFAULT, &bltPadOption}, {TK_CONFIG_CUSTOM, "-pady", "padY", "Pad", DEF_LEGEND_PAD_Y, Tk_Offset(Legend, padY), TK_CONFIG_DONT_SET_DEFAULT, &bltPadOption}, {TK_CONFIG_CUSTOM, "-position", "position", "Position", DEF_LEGEND_POSITION, 0, TK_CONFIG_DONT_SET_DEFAULT, &legendPositionOption}, {TK_CONFIG_BOOLEAN, "-raised", "raised", "Raised", DEF_LEGEND_RAISED, Tk_Offset(Legend, raised), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_LEGEND_RELIEF, Tk_Offset(Legend, relief), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-rows", "rows", "rows", DEF_LEGEND_ROWS, Tk_Offset(Legend, reqRows), TK_CONFIG_DONT_SET_DEFAULT, &bltCountOption}, {TK_CONFIG_CUSTOM, "-shadow", "shadow", "Shadow", DEF_LEGEND_SHADOW_COLOR, Tk_Offset(Legend, style.shadow), TK_CONFIG_COLOR_ONLY, &bltShadowOption}, {TK_CONFIG_CUSTOM, "-shadow", "shadow", "Shadow", DEF_LEGEND_SHADOW_MONO, Tk_Offset(Legend, style.shadow), TK_CONFIG_MONO_ONLY, &bltShadowOption}, {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} }; static Tcl_IdleProc DisplayLegend; static Blt_BindPickProc PickLegendEntry; static Tk_EventProc LegendEventProc; extern Tcl_CmdProc Blt_GraphInstCmdProc; /* *-------------------------------------------------------------- * * EventuallyRedrawLegend -- * * Tells the Tk dispatcher to call the graph display routine at * the next idle point. This request is made only if the window * is displayed and no other redraw request is pending. * * Results: None. * * Side effects: * The window is eventually redisplayed. * *-------------------------------------------------------------- */ static void EventuallyRedrawLegend(legendPtr) Legend *legendPtr; /* Legend record */ { if ((legendPtr->tkwin != NULL) && !(legendPtr->flags & REDRAW_PENDING)) { Tcl_DoWhenIdle(DisplayLegend, legendPtr); legendPtr->flags |= REDRAW_PENDING; } } /* *-------------------------------------------------------------- * * LegendEventProc -- * * This procedure is invoked by the Tk dispatcher for various * events on graphs. * * Results: * None. * * Side effects: * When the window gets deleted, internal structures get * cleaned up. When it gets exposed, the graph is eventually * redisplayed. * *-------------------------------------------------------------- */ static void LegendEventProc(clientData, eventPtr) ClientData clientData; /* Legend record */ register XEvent *eventPtr; /* Event which triggered call to routine */ { Legend *legendPtr = clientData; if (eventPtr->type == Expose) { if (eventPtr->xexpose.count == 0) { EventuallyRedrawLegend(legendPtr); } } else if (eventPtr->type == DestroyNotify) { Graph *graphPtr = legendPtr->graphPtr; if (legendPtr->tkwin != graphPtr->tkwin) { Blt_DeleteWindowInstanceData(legendPtr->tkwin); if (legendPtr->cmdToken != NULL) { Tcl_DeleteCommandFromToken(graphPtr->interp, legendPtr->cmdToken); legendPtr->cmdToken = NULL; } legendPtr->tkwin = graphPtr->tkwin; } if (legendPtr->flags & REDRAW_PENDING) { Tcl_CancelIdleCall(DisplayLegend, legendPtr); legendPtr->flags &= ~REDRAW_PENDING; } legendPtr->site = LEGEND_RIGHT; graphPtr->flags |= (MAP_WORLD | REDRAW_WORLD); Blt_MoveBindingTable(legendPtr->bindTable, graphPtr->tkwin); Blt_EventuallyRedrawGraph(graphPtr); } else if (eventPtr->type == ConfigureNotify) { EventuallyRedrawLegend(legendPtr); } } static int CreateLegendWindow(interp, legendPtr, pathName) Tcl_Interp *interp; Legend *legendPtr; char *pathName; { Tk_Window tkwin; tkwin = Tk_MainWindow(interp); tkwin = Tk_CreateWindowFromPath(interp, tkwin, pathName, NULL); if (tkwin == NULL) { return TCL_ERROR; } Blt_SetWindowInstanceData(tkwin, legendPtr); Tk_CreateEventHandler(tkwin, ExposureMask | StructureNotifyMask, LegendEventProc, legendPtr); /* Move the legend's binding table to the new window. */ Blt_MoveBindingTable(legendPtr->bindTable, tkwin); if (legendPtr->tkwin != legendPtr->graphPtr->tkwin) { Tk_DestroyWindow(legendPtr->tkwin); } legendPtr->cmdToken = Tcl_CreateCommand(interp, pathName, Blt_GraphInstCmdProc, legendPtr->graphPtr, NULL); legendPtr->tkwin = tkwin; legendPtr->site = LEGEND_WINDOW; return TCL_OK; } /* *---------------------------------------------------------------------- * * StringToPosition -- * * Convert the string representation of a legend XY position into * window coordinates. The form of the string must be "@x,y" or * none. * * Results: * The return value is a standard Tcl result. The symbol type is * written into the widget record. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToPosition(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* New legend position string */ char *widgRec; /* Widget record */ int offset; /* offset to XPoint structure */ { Legend *legendPtr = (Legend *)widgRec; char c; unsigned int length; c = string[0]; length = strlen(string); if ((string == NULL) || (*string == '\0')) { legendPtr->site = LEGEND_RIGHT; } else if ((c == 'l') && (strncmp(string, "leftmargin", length) == 0)) { legendPtr->site = LEGEND_LEFT; } else if ((c == 'r') && (strncmp(string, "rightmargin", length) == 0)) { legendPtr->site = LEGEND_RIGHT; } else if ((c == 't') && (strncmp(string, "topmargin", length) == 0)) { legendPtr->site = LEGEND_TOP; } else if ((c == 'b') && (strncmp(string, "bottommargin", length) == 0)) { legendPtr->site = LEGEND_BOTTOM; } else if ((c == 'p') && (strncmp(string, "plotarea", length) == 0)) { legendPtr->site = LEGEND_PLOT; } else if (c == '@') { char *comma; long x, y; int result; comma = strchr(string + 1, ','); if (comma == NULL) { Tcl_AppendResult(interp, "bad screen position \"", string, "\": should be @x,y", (char *)NULL); return TCL_ERROR; } x = y = 0; *comma = '\0'; result = ((Tcl_ExprLong(interp, string + 1, &x) == TCL_OK) && (Tcl_ExprLong(interp, comma + 1, &y) == TCL_OK)); *comma = ','; if (!result) { return TCL_ERROR; } legendPtr->anchorPos.x = (int)x; legendPtr->anchorPos.y = (int)y; legendPtr->site = LEGEND_XY; } else if (c == '.') { if (legendPtr->tkwin != legendPtr->graphPtr->tkwin) { Tk_DestroyWindow(legendPtr->tkwin); legendPtr->tkwin = legendPtr->graphPtr->tkwin; } if (CreateLegendWindow(interp, legendPtr, string) != TCL_OK) { return TCL_ERROR; } legendPtr->site = LEGEND_WINDOW; } else { Tcl_AppendResult(interp, "bad position \"", string, "\": should be \ \"leftmargin\", \"rightmargin\", \"topmargin\", \"bottommargin\", \ \"plotarea\", .window or @x,y", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * PositionToString -- * * Convert the window coordinates into a string. * * Results: * The string representing the coordinate position is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * PositionToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget record */ int offset; /* offset of XPoint in record */ Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */ { Legend *legendPtr = (Legend *)widgRec; switch (legendPtr->site) { case LEGEND_LEFT: return "leftmargin"; case LEGEND_RIGHT: return "rightmargin"; case LEGEND_TOP: return "topmargin"; case LEGEND_BOTTOM: return "bottommargin"; case LEGEND_PLOT: return "plotarea"; case LEGEND_WINDOW: return Tk_PathName(legendPtr->tkwin); case LEGEND_XY: { char string[200]; char *result; sprintf(string, "@%d,%d", (int)legendPtr->anchorPos.x, (int)legendPtr->anchorPos.y); result = Blt_Strdup(string); *freeProcPtr = (Tcl_FreeProc *)Blt_Free; return result; } default: return "unknown legend position"; } } static void SetLegendOrigin(legendPtr) Legend *legendPtr; { Graph *graphPtr; int x, y, width, height; graphPtr = legendPtr->graphPtr; x = y = width = height = 0; /* Suppress compiler warning. */ switch (legendPtr->site) { case LEGEND_RIGHT: width = graphPtr->rightMargin.width - graphPtr->rightMargin.axesOffset; height = graphPtr->bottom - graphPtr->top; x = graphPtr->width - (width + graphPtr->inset); y = graphPtr->top; break; case LEGEND_LEFT: width = graphPtr->leftMargin.width - graphPtr->leftMargin.axesOffset; height = graphPtr->bottom - graphPtr->top; x = graphPtr->inset; y = graphPtr->top; break; case LEGEND_TOP: width = graphPtr->right - graphPtr->left; height = graphPtr->topMargin.height - graphPtr->topMargin.axesOffset; if (graphPtr->title != NULL) { height -= graphPtr->titleTextStyle.height; } x = graphPtr->left; y = graphPtr->inset; if (graphPtr->title != NULL) { y += graphPtr->titleTextStyle.height; } break; case LEGEND_BOTTOM: width = graphPtr->right - graphPtr->left; height = graphPtr->bottomMargin.height - graphPtr->bottomMargin.axesOffset; x = graphPtr->left; y = graphPtr->height - (height + graphPtr->inset); break; case LEGEND_PLOT: width = graphPtr->right - graphPtr->left; height = graphPtr->bottom - graphPtr->top; x = graphPtr->left; y = graphPtr->top; break; case LEGEND_XY: width = legendPtr->width; height = legendPtr->height; x = (int)legendPtr->anchorPos.x; y = (int)legendPtr->anchorPos.y; if (x < 0) { x += graphPtr->width; } if (y < 0) { y += graphPtr->height; } break; case LEGEND_WINDOW: legendPtr->anchor = TK_ANCHOR_NW; legendPtr->x = legendPtr->y = 0; return; } width = legendPtr->width - width; height = legendPtr->height - height; Blt_TranslateAnchor(x, y, width, height, legendPtr->anchor, &x, &y); legendPtr->x = x + legendPtr->padLeft; legendPtr->y = y + legendPtr->padTop; } /*ARGSUSED*/ static ClientData PickLegendEntry(clientData, x, y, contextPtr) ClientData clientData; int x, y; /* Point to be tested */ ClientData *contextPtr; /* Not used. */ { Graph *graphPtr = clientData; Legend *legendPtr; int width, height; legendPtr = graphPtr->legend; width = legendPtr->width; height = legendPtr->height; x -= legendPtr->x + legendPtr->borderWidth; y -= legendPtr->y + legendPtr->borderWidth; width -= 2 * legendPtr->borderWidth + PADDING(legendPtr->padX); height -= 2 * legendPtr->borderWidth + PADDING(legendPtr->padY); if ((x >= 0) && (x < width) && (y >= 0) && (y < height)) { int row, column; int n; /* * It's in the bounding box, so compute the index. */ row = y / legendPtr->style.height; column = x / legendPtr->style.width; n = (column * legendPtr->nRows) + row; if (n < legendPtr->nEntries) { Blt_ChainLink *linkPtr; Element *elemPtr; int count; /* Legend entries are stored in reverse. */ count = 0; for (linkPtr = Blt_ChainLastLink(graphPtr->elements.displayList); linkPtr != NULL; linkPtr = Blt_ChainPrevLink(linkPtr)) { elemPtr = Blt_ChainGetValue(linkPtr); if (elemPtr->label != NULL) { if (count == n) { return elemPtr; } count++; } } if (linkPtr != NULL) { return Blt_ChainGetValue(linkPtr); } } } return NULL; } /* * ----------------------------------------------------------------- * * Blt_MapLegend -- * * Calculates the dimensions (width and height) needed for * the legend. Also determines the number of rows and columns * necessary to list all the valid element labels. * * Results: * None. * * Side effects: * The following fields of the legend are calculated and set. * * nEntries - number of valid labels of elements in the * display list. * nRows - number of rows of entries * nColumns - number of columns of entries * style.height - height of each entry * style.width - width of each entry * height - width of legend (includes borders and padding) * width - height of legend (includes borders and padding) * * ----------------------------------------------------------------- */ void Blt_MapLegend(legendPtr, plotWidth, plotHeight) Legend *legendPtr; int plotWidth; /* Maximum width available in window * to draw the legend. Will calculate number * of columns from this. */ int plotHeight; /* Maximum height available in window * to draw the legend. Will calculate number * of rows from this. */ { Blt_ChainLink *linkPtr; Element *elemPtr; int nRows, nColumns, nEntries; int legendWidth, legendHeight; int entryWidth, entryHeight; int symbolWidth; Tk_FontMetrics fontMetrics; /* Initialize legend values to default (no legend displayed) */ legendPtr->style.width = legendPtr->style.height = 0; legendPtr->nRows = legendPtr->nColumns = 0; legendPtr->nEntries = 0; legendPtr->height = legendPtr->width = 0; if (legendPtr->site == LEGEND_WINDOW) { if (Tk_Width(legendPtr->tkwin) > 1) { plotWidth = Tk_Width(legendPtr->tkwin); } if (Tk_Height(legendPtr->tkwin) > 1) { plotHeight = Tk_Height(legendPtr->tkwin); } } if ((legendPtr->hidden) || (plotWidth < 1) || (plotHeight < 1)) { return; /* Legend is not being displayed */ } /* * 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 1) elements can be hidden and 2) * elements can have no legend entry (-label ""). */ nEntries = 0; entryWidth = entryHeight = 0; for (linkPtr = Blt_ChainLastLink(legendPtr->graphPtr->elements.displayList); linkPtr != NULL; linkPtr = Blt_ChainPrevLink(linkPtr)) { int width, height; elemPtr = Blt_ChainGetValue(linkPtr); if (elemPtr->label == NULL) { continue; /* Element has no legend entry. */ } Blt_GetTextExtents(&legendPtr->style, elemPtr->label, &width, &height); if (entryWidth < width) { entryWidth = width; } if (entryHeight < height) { entryHeight = height; } nEntries++; } if (nEntries == 0) { return; /* No legend entries. */ } Tk_GetFontMetrics(legendPtr->style.font, &fontMetrics); symbolWidth = 2 * fontMetrics.ascent; entryWidth += 2 * legendPtr->entryBorderWidth + PADDING(legendPtr->ipadX) + 5 + symbolWidth; entryHeight += 2 * legendPtr->entryBorderWidth + PADDING(legendPtr->ipadY); legendWidth = plotWidth - 2 * legendPtr->borderWidth - PADDING(legendPtr->padX); legendHeight = plotHeight - 2 * legendPtr->borderWidth - PADDING(legendPtr->padY); /* * 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. */ if (legendPtr->reqRows > 0) { nRows = legendPtr->reqRows; if (nRows > nEntries) { nRows = nEntries; } if (legendPtr->reqColumns > 0) { nColumns = legendPtr->reqColumns; if (nColumns > nEntries) { nColumns = nEntries; /* Both -rows, -columns set. */ } } else { nColumns = ((nEntries - 1) / nRows) + 1; /* Only -rows. */ } } else if (legendPtr->reqColumns > 0) { /* Only -columns. */ nColumns = legendPtr->reqColumns; if (nColumns > nEntries) { nColumns = nEntries; } nRows = ((nEntries - 1) / nColumns) + 1; } else { /* Compute # of rows and columns from the legend size. */ nRows = legendHeight / entryHeight; nColumns = legendWidth / entryWidth; if (nRows > nEntries) { nRows = nEntries; } else if (nRows < 1) { nRows = 1; } if (nColumns > nEntries) { nColumns = nEntries; } else if (nColumns < 1) { nColumns = 1; } if ((legendPtr->site == LEGEND_TOP) || (legendPtr->site == LEGEND_BOTTOM)) { nRows = ((nEntries - 1) / nColumns) + 1; } else { nColumns = ((nEntries - 1) / nRows) + 1; } } if (nRows < 1) { nRows = 1; } if (nColumns < 1) { nColumns = 1; } legendWidth = 2 * legendPtr->borderWidth + PADDING(legendPtr->padX); legendHeight = 2 * legendPtr->borderWidth + PADDING(legendPtr->padY); legendHeight += nRows * entryHeight; legendWidth += nColumns * entryWidth; legendPtr->height = legendHeight; legendPtr->width = legendWidth; legendPtr->nRows = nRows; legendPtr->nColumns = nColumns; legendPtr->nEntries = nEntries; legendPtr->style.height = entryHeight; legendPtr->style.width = entryWidth; if ((legendPtr->tkwin != legendPtr->graphPtr->tkwin) && ((Tk_ReqWidth(legendPtr->tkwin) != legendWidth) || (Tk_ReqHeight(legendPtr->tkwin) != legendHeight))) { Tk_GeometryRequest(legendPtr->tkwin, legendWidth, legendHeight); } } void Blt_DrawLegend(legendPtr, drawable) Legend *legendPtr; Drawable drawable; /* Pixmap or window to draw into */ { Graph *graphPtr; Blt_ChainLink *linkPtr; Pixmap pixmap; Tk_3DBorder border; Tk_FontMetrics fontMetrics; Tk_Window tkwin; int count; int labelX, startY, symbolX, symbolY; int symbolSize, midX, midY; int width, height; int x, y; register Element *elemPtr; graphPtr = legendPtr->graphPtr; graphPtr->flags &= ~DRAW_LEGEND; if ((legendPtr->hidden) || (legendPtr->nEntries == 0)) { return; } SetLegendOrigin(legendPtr); if (legendPtr->tkwin != graphPtr->tkwin) { tkwin = legendPtr->tkwin; width = Tk_Width(tkwin); if (width < 1) { width = legendPtr->width; } height = Tk_Height(tkwin); if (height < 1) { height = legendPtr->height; } } else { width = legendPtr->width; height = legendPtr->height; } Tk_GetFontMetrics(legendPtr->style.font, &fontMetrics); symbolSize = fontMetrics.ascent; midX = symbolSize + 1 + legendPtr->entryBorderWidth; midY = (symbolSize / 2) + 1 + legendPtr->entryBorderWidth; labelX = 2 * symbolSize + legendPtr->entryBorderWidth + legendPtr->ipadX.side1 + 5; symbolY = midY + legendPtr->ipadY.side1; symbolX = midX + legendPtr->ipadX.side1; pixmap = Tk_GetPixmap(graphPtr->display, Tk_WindowId(legendPtr->tkwin), width, height, Tk_Depth(legendPtr->tkwin)); if (legendPtr->border != NULL) { /* Background color and relief. */ Blt_Fill3DRectangle(legendPtr->tkwin, pixmap, legendPtr->border, 0, 0, width, height, 0, TK_RELIEF_FLAT); } else if (legendPtr->site & LEGEND_IN_PLOT) { /* * 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->backPixmap != None) { XCopyArea(graphPtr->display, graphPtr->backPixmap, pixmap, graphPtr->drawGC, legendPtr->x, legendPtr->y, width, height, 0, 0); } else { XFillRectangle(graphPtr->display, pixmap, graphPtr->plotFillGC, 0, 0, width, height); } } else { /* * The legend is positioned in one of the margins or the * external window. Draw either the solid or tiled background * with the the border. */ if (graphPtr->tile != NULL) { Blt_SetTileOrigin(legendPtr->tkwin, graphPtr->tile, legendPtr->x, legendPtr->y); Blt_TileRectangle(legendPtr->tkwin, pixmap, graphPtr->tile, 0, 0, width, height); } else { XFillRectangle(graphPtr->display, pixmap, graphPtr->fillGC, 0, 0, width, height); } } x = legendPtr->padLeft + legendPtr->borderWidth; y = legendPtr->padTop + legendPtr->borderWidth; count = 0; startY = y; for (linkPtr = Blt_ChainLastLink(graphPtr->elements.displayList); linkPtr != NULL; linkPtr = Blt_ChainPrevLink(linkPtr)) { elemPtr = Blt_ChainGetValue(linkPtr); if (elemPtr->label == NULL) { continue; /* Skip this entry */ } if (elemPtr->flags & LABEL_ACTIVE) { legendPtr->style.state |= STATE_ACTIVE; Blt_Fill3DRectangle(legendPtr->tkwin, pixmap, legendPtr->activeBorder, x, y, legendPtr->style.width, legendPtr->style.height, legendPtr->entryBorderWidth, legendPtr->activeRelief); } else { legendPtr->style.state &= ~STATE_ACTIVE; if (elemPtr->labelRelief != TK_RELIEF_FLAT) { Blt_Draw3DRectangle(legendPtr->tkwin, pixmap, graphPtr->border, x, y, legendPtr->style.width, legendPtr->style.height, legendPtr->entryBorderWidth, elemPtr->labelRelief); } } (*elemPtr->procsPtr->drawSymbolProc) (graphPtr, pixmap, elemPtr, x + symbolX, y + symbolY, symbolSize); Blt_DrawText(legendPtr->tkwin, pixmap, elemPtr->label, &legendPtr->style, x + labelX, y + legendPtr->entryBorderWidth + legendPtr->ipadY.side1); count++; /* Check when to move to the next column */ if ((count % legendPtr->nRows) > 0) { y += legendPtr->style.height; } else { x += legendPtr->style.width; y = startY; } } /* * Draw the border and/or background of the legend. */ border = legendPtr->border; if (border == NULL) { border = graphPtr->border; } Blt_Draw3DRectangle(legendPtr->tkwin, pixmap, border, 0, 0, width, height, legendPtr->borderWidth, legendPtr->relief); XCopyArea(graphPtr->display, pixmap, drawable, graphPtr->drawGC, 0, 0, width, height, legendPtr->x, legendPtr->y); Tk_FreePixmap(graphPtr->display, pixmap); } /* * ----------------------------------------------------------------- * * Blt_LegendToPostScript -- * * ----------------------------------------------------------------- */ void Blt_LegendToPostScript(legendPtr, psToken) Legend *legendPtr; PsToken psToken; { Graph *graphPtr; double x, y, startY; Element *elemPtr; int labelX, symbolX, symbolY; int count; Blt_ChainLink *linkPtr; int symbolSize, midX, midY; int width, height; Tk_FontMetrics fontMetrics; if ((legendPtr->hidden) || (legendPtr->nEntries == 0)) { return; } SetLegendOrigin(legendPtr); x = legendPtr->x, y = legendPtr->y; width = legendPtr->width - PADDING(legendPtr->padX); height = legendPtr->height - PADDING(legendPtr->padY); graphPtr = legendPtr->graphPtr; if (graphPtr->postscript->decorations) { if (legendPtr->border != NULL) { Blt_Fill3DRectangleToPostScript(psToken, legendPtr->border, x, y, width, height, legendPtr->borderWidth, legendPtr->relief); } else { Blt_Draw3DRectangleToPostScript(psToken, graphPtr->border, x, y, width, height, legendPtr->borderWidth, legendPtr->relief); } } else { Blt_ClearBackgroundToPostScript(psToken); Blt_RectangleToPostScript(psToken, x, y, width, height); } x += legendPtr->borderWidth; y += legendPtr->borderWidth; Tk_GetFontMetrics(legendPtr->style.font, &fontMetrics); symbolSize = fontMetrics.ascent; midX = symbolSize + 1 + legendPtr->entryBorderWidth; midY = (symbolSize / 2) + 1 + legendPtr->entryBorderWidth; labelX = 2 * symbolSize + legendPtr->entryBorderWidth + legendPtr->ipadX.side1 + 5; symbolY = midY + legendPtr->ipadY.side1; symbolX = midX + legendPtr->ipadX.side1; count = 0; startY = y; for (linkPtr = Blt_ChainLastLink(graphPtr->elements.displayList); linkPtr != NULL; linkPtr = Blt_ChainPrevLink(linkPtr)) { elemPtr = Blt_ChainGetValue(linkPtr); if (elemPtr->label == NULL) { continue; /* Skip this label */ } if (elemPtr->flags & LABEL_ACTIVE) { legendPtr->style.state |= STATE_ACTIVE; Blt_Fill3DRectangleToPostScript(psToken, legendPtr->activeBorder, x, y, legendPtr->style.width, legendPtr->style.height, legendPtr->entryBorderWidth, legendPtr->activeRelief); } else { legendPtr->style.state &= ~STATE_ACTIVE; if (elemPtr->labelRelief != TK_RELIEF_FLAT) { Blt_Draw3DRectangleToPostScript(psToken, graphPtr->border, x, y, legendPtr->style.width, legendPtr->style.height, legendPtr->entryBorderWidth, elemPtr->labelRelief); } } (*elemPtr->procsPtr->printSymbolProc) (graphPtr, psToken, elemPtr, x + symbolX, y + symbolY, symbolSize); Blt_TextToPostScript(psToken, elemPtr->label, &(legendPtr->style), x + labelX, y + legendPtr->entryBorderWidth + legendPtr->ipadY.side1); count++; if ((count % legendPtr->nRows) > 0) { y += legendPtr->style.height; } else { x += legendPtr->style.width; y = startY; } } } /* * ----------------------------------------------------------------- * * DisplayLegend -- * * ----------------------------------------------------------------- */ static void DisplayLegend(clientData) ClientData clientData; { Legend *legendPtr = clientData; int width, height; legendPtr->flags &= ~REDRAW_PENDING; if (legendPtr->tkwin == NULL) { return; /* Window has been destroyed. */ } if (legendPtr->site == LEGEND_WINDOW) { width = Tk_Width(legendPtr->tkwin); height = Tk_Height(legendPtr->tkwin); if ((width <= 1) || (height <= 1)) { return; } if ((width != legendPtr->width) || (height != legendPtr->height)) { Blt_MapLegend(legendPtr, width, height); } } if (!Tk_IsMapped(legendPtr->tkwin)) { return; } Blt_DrawLegend(legendPtr, Tk_WindowId(legendPtr->tkwin)); } /* *---------------------------------------------------------------------- * * ConfigureLegend -- * * Routine to configure the legend. * * Results: * A standard Tcl result. * * Side Effects: * Graph will be redrawn to reflect the new legend attributes. * *---------------------------------------------------------------------- */ static void ConfigureLegend(graphPtr, legendPtr) Graph *graphPtr; Legend *legendPtr; { Blt_ResetTextStyle(graphPtr->tkwin, &(legendPtr->style)); if (legendPtr->site == LEGEND_WINDOW) { EventuallyRedrawLegend(legendPtr); } else { /* * Update the layout of the graph (and redraw the elements) if * any of the following legend options (all of which affect the * size of the legend) have changed. * * -activeborderwidth, -borderwidth * -border * -font * -hide * -ipadx, -ipady, -padx, -pady * -rows * * If the position of the legend changed to/from the default * position, also indicate that a new layout is needed. * */ if (Blt_ConfigModified(configSpecs, "-*border*", "-*pad?", "-position", "-hide", "-font", "-rows", (char *)NULL)) { graphPtr->flags |= MAP_WORLD; } graphPtr->flags |= (REDRAW_WORLD | REDRAW_BACKING_STORE); Blt_EventuallyRedrawGraph(graphPtr); } } /* *---------------------------------------------------------------------- * * Blt_DestroyLegend -- * * Results: * None. * * Side effects: * Resources associated with the legend are freed. * *---------------------------------------------------------------------- */ void Blt_DestroyLegend(graphPtr) Graph *graphPtr; { Legend *legendPtr = graphPtr->legend; Tk_FreeOptions(configSpecs, (char *)legendPtr, graphPtr->display, 0); Blt_FreeTextStyle(graphPtr->display, &(legendPtr->style)); Blt_DestroyBindingTable(legendPtr->bindTable); if (legendPtr->tkwin != graphPtr->tkwin) { Tk_Window tkwin; /* The graph may be in the process of being torn down */ if (legendPtr->cmdToken != NULL) { Tcl_DeleteCommandFromToken(graphPtr->interp, legendPtr->cmdToken); } if (legendPtr->flags & REDRAW_PENDING) { Tcl_CancelIdleCall(DisplayLegend, legendPtr); legendPtr->flags &= ~REDRAW_PENDING; } tkwin = legendPtr->tkwin; legendPtr->tkwin = NULL; if (tkwin != NULL) { Tk_DeleteEventHandler(tkwin, ExposureMask | StructureNotifyMask, LegendEventProc, legendPtr); Blt_DeleteWindowInstanceData(tkwin); Tk_DestroyWindow(tkwin); } } Blt_Free(legendPtr); } /* *---------------------------------------------------------------------- * * Blt_CreateLegend -- * * Creates and initializes a legend structure with default settings * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ int Blt_CreateLegend(graphPtr) Graph *graphPtr; { Legend *legendPtr; legendPtr = Blt_Calloc(1, sizeof(Legend)); assert(legendPtr); graphPtr->legend = legendPtr; legendPtr->graphPtr = graphPtr; legendPtr->tkwin = graphPtr->tkwin; legendPtr->hidden = FALSE; legendPtr->anchorPos.x = legendPtr->anchorPos.y = -SHRT_MAX; legendPtr->relief = TK_RELIEF_SUNKEN; legendPtr->activeRelief = TK_RELIEF_FLAT; legendPtr->entryBorderWidth = legendPtr->borderWidth = 2; legendPtr->ipadX.side1 = legendPtr->ipadX.side2 = 1; legendPtr->ipadY.side1 = legendPtr->ipadY.side2 = 1; legendPtr->padX.side1 = legendPtr->padX.side2 = 1; legendPtr->padY.side1 = legendPtr->padY.side2 = 1; legendPtr->anchor = TK_ANCHOR_N; legendPtr->site = LEGEND_RIGHT; Blt_InitTextStyle(&(legendPtr->style)); legendPtr->style.justify = TK_JUSTIFY_LEFT; legendPtr->style.anchor = TK_ANCHOR_NW; legendPtr->bindTable = Blt_CreateBindingTable(graphPtr->interp, graphPtr->tkwin, graphPtr, PickLegendEntry, Blt_GraphTags); if (Blt_ConfigureWidgetComponent(graphPtr->interp, graphPtr->tkwin, "legend", "Legend", configSpecs, 0, (char **)NULL, (char *)legendPtr, 0) != TCL_OK) { return TCL_ERROR; } ConfigureLegend(graphPtr, legendPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * GetOp -- * * Find the legend entry from the given argument. The argument * can be either a screen position "@x,y" or the name of an * element. * * I don't know how useful it is to test with the name of an * element. * * Results: * A standard Tcl result. * * Side Effects: * Graph will be redrawn to reflect the new legend attributes. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int GetOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; /* Not used. */ char *argv[]; { register Element *elemPtr; Legend *legendPtr = graphPtr->legend; int x, y; char c; if ((legendPtr->hidden) || (legendPtr->nEntries == 0)) { return TCL_OK; } elemPtr = NULL; c = argv[3][0]; if ((c == 'c') && (strcmp(argv[3], "current") == 0)) { elemPtr = (Element *)Blt_GetCurrentItem(legendPtr->bindTable); } else if ((c == '@') && (Blt_GetXY(interp, graphPtr->tkwin, argv[3], &x, &y) == TCL_OK)) { elemPtr = (Element *)PickLegendEntry(graphPtr, x, y, NULL); } if (elemPtr != NULL) { Tcl_SetResult(interp, elemPtr->name, TCL_VOLATILE); } return TCL_OK; } /* *---------------------------------------------------------------------- * * ActivateOp -- * * Activates a particular label in the legend. * * Results: * A standard Tcl result. * * Side Effects: * Graph will be redrawn to reflect the new legend attributes. * *---------------------------------------------------------------------- */ static int ActivateOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char *argv[]; { Legend *legendPtr = graphPtr->legend; Element *elemPtr; unsigned int active, redraw; Blt_HashEntry *hPtr; Blt_HashSearch cursor; register int i; active = (argv[2][0] == 'a') ? LABEL_ACTIVE : 0; redraw = 0; for (hPtr = Blt_FirstHashEntry(&(graphPtr->elements.table), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { elemPtr = Blt_GetHashValue(hPtr); for (i = 3; i < argc; i++) { if (Tcl_StringMatch(elemPtr->name, argv[i])) { break; } } if ((i < argc) && (active != (elemPtr->flags & LABEL_ACTIVE))) { elemPtr->flags ^= LABEL_ACTIVE; if (elemPtr->label != NULL) { redraw++; } } } if ((redraw) && (!legendPtr->hidden)) { /* * See if how much we need to draw. If the graph is already * schedule for a redraw, just make sure the right flags are * set. Otherwise redraw only the legend: it's either in an * external window or it's the only thing that need updating. */ if (graphPtr->flags & REDRAW_PENDING) { if (legendPtr->site & LEGEND_IN_PLOT) { graphPtr->flags |= REDRAW_BACKING_STORE; } graphPtr->flags |= REDRAW_WORLD; /* Redraw entire graph. */ } else { EventuallyRedrawLegend(legendPtr); } } /* Return the names of all the active legend entries */ for (hPtr = Blt_FirstHashEntry(&(graphPtr->elements.table), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { elemPtr = Blt_GetHashValue(hPtr); if (elemPtr->flags & LABEL_ACTIVE) { Tcl_AppendElement(interp, elemPtr->name); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * BindOp -- * * .t bind index sequence command * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int BindOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { if (argc == 3) { Blt_HashEntry *hPtr; Blt_HashSearch cursor; char *tagName; for (hPtr = Blt_FirstHashEntry(&(graphPtr->elements.tagTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tagName = Blt_GetHashKey(&(graphPtr->elements.tagTable), hPtr); Tcl_AppendElement(interp, tagName); } return TCL_OK; } return Blt_ConfigureBindings(interp, graphPtr->legend->bindTable, Blt_MakeElementTag(graphPtr, argv[3]), argc - 4, argv + 4); } /* *---------------------------------------------------------------------- * * CgetOp -- * * Queries or resets options for the legend. * * Results: * A standard Tcl result. * * Side Effects: * Graph will be redrawn to reflect the new legend attributes. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int CgetOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { return Tk_ConfigureValue(interp, graphPtr->tkwin, configSpecs, (char *)graphPtr->legend, argv[3], 0); } /* *---------------------------------------------------------------------- * * ConfigureOp -- * * Queries or resets options for the legend. * * Results: * A standard Tcl result. * * Side Effects: * Graph will be redrawn to reflect the new legend attributes. * *---------------------------------------------------------------------- */ static int ConfigureOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { int flags = TK_CONFIG_ARGV_ONLY; Legend *legendPtr; legendPtr = graphPtr->legend; if (argc == 3) { return Tk_ConfigureInfo(interp, graphPtr->tkwin, configSpecs, (char *)legendPtr, (char *)NULL, flags); } else if (argc == 4) { return Tk_ConfigureInfo(interp, graphPtr->tkwin, configSpecs, (char *)legendPtr, argv[3], flags); } if (Tk_ConfigureWidget(interp, graphPtr->tkwin, configSpecs, argc - 3, argv + 3, (char *)legendPtr, flags) != TCL_OK) { return TCL_ERROR; } ConfigureLegend(graphPtr, legendPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * Blt_LegendOp -- * * Results: * A standard Tcl result. * * Side Effects: * Legend is possibly redrawn. * *---------------------------------------------------------------------- */ static Blt_OpSpec legendOps[] = { {"activate", 1, (Blt_Op)ActivateOp, 3, 0, "?pattern?...",}, {"bind", 1, (Blt_Op)BindOp, 3, 6, "elemName sequence command",}, {"cget", 2, (Blt_Op)CgetOp, 4, 4, "option",}, {"configure", 2, (Blt_Op)ConfigureOp, 3, 0, "?option value?...",}, {"deactivate", 1, (Blt_Op)ActivateOp, 3, 0, "?pattern?...",}, {"get", 1, (Blt_Op)GetOp, 4, 4, "index",}, }; static int nLegendOps = sizeof(legendOps) / sizeof(Blt_OpSpec); int Blt_LegendOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { Blt_Op proc; int result; proc = Blt_GetOp(interp, nLegendOps, legendOps, BLT_OP_ARG2, argc, argv,0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (graphPtr, interp, argc, argv); return result; } int Blt_LegendSite(legendPtr) Legend *legendPtr; { return legendPtr->site; } int Blt_LegendWidth(legendPtr) Legend *legendPtr; { return legendPtr->width; } int Blt_LegendHeight(legendPtr) Legend *legendPtr; { return legendPtr->height; } int Blt_LegendIsHidden(legendPtr) Legend *legendPtr; { return legendPtr->hidden; } int Blt_LegendIsRaised(legendPtr) Legend *legendPtr; { return legendPtr->raised; } int Blt_LegendX(legendPtr) Legend *legendPtr; { return legendPtr->x; } int Blt_LegendY(legendPtr) Legend *legendPtr; { return legendPtr->y; } void Blt_LegendRemoveElement(legendPtr, elemPtr) Legend *legendPtr; Element *elemPtr; { Blt_DeleteBindings(legendPtr->bindTable, elemPtr); } blt-2.4z.orig/src/bltGrLegd.h0100644000175000017500000000502507401551730014556 0ustar dokodoko/* * bltGrLegd.h -- * * Copyright 1991-1998 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. */ #ifndef _BLT_GR_LEGEND_H #define _BLT_GR_LEGEND_H #define LEGEND_RIGHT (1<<0) /* Right margin */ #define LEGEND_LEFT (1<<1) /* Left margin */ #define LEGEND_BOTTOM (1<<2) /* Bottom margin */ #define LEGEND_TOP (1<<3) /* Top margin, below the graph title. */ #define LEGEND_PLOT (1<<4) /* Plot area */ #define LEGEND_XY (1<<5) /* Screen coordinates in the plotting * area. */ #define LEGEND_WINDOW (1<<6) /* External window. */ #define LEGEND_IN_MARGIN \ (LEGEND_RIGHT | LEGEND_LEFT | LEGEND_BOTTOM | LEGEND_TOP) #define LEGEND_IN_PLOT (LEGEND_PLOT | LEGEND_XY) extern int Blt_CreateLegend _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_DestroyLegend _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_DrawLegend _ANSI_ARGS_((Legend *legendPtr, Drawable drawable)); extern void Blt_MapLegend _ANSI_ARGS_((Legend *legendPtr, int width, int height)); extern int Blt_LegendOp _ANSI_ARGS_((Graph *graphPtr, Tcl_Interp *interp, int argc, char **argv)); extern int Blt_LegendSite _ANSI_ARGS_((Legend *legendPtr)); extern int Blt_LegendWidth _ANSI_ARGS_((Legend *legendPtr)); extern int Blt_LegendHeight _ANSI_ARGS_((Legend *legendPtr)); extern int Blt_LegendIsHidden _ANSI_ARGS_((Legend *legendPtr)); extern int Blt_LegendIsRaised _ANSI_ARGS_((Legend *legendPtr)); extern int Blt_LegendX _ANSI_ARGS_((Legend *legendPtr)); extern int Blt_LegendY _ANSI_ARGS_((Legend *legendPtr)); extern void Blt_LegendRemoveElement _ANSI_ARGS_((Legend *legendPtr, Element *elemPtr)); #endif /* BLT_GR_LEGEND_H */ blt-2.4z.orig/src/bltGrLine.c0100644000175000017500000047136007552651714014610 0ustar dokodoko /* * bltGrLine.c -- * * This module implements line graph and stripchart elements for * the BLT graph widget. * * Copyright 1993-1998 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. */ #include "bltGraph.h" #include "bltChain.h" #include #include "bltGrElem.h" #define COLOR_DEFAULT (XColor *)1 #define PATTERN_SOLID ((Pixmap)1) #define PEN_INCREASING 1 /* Draw line segments for only those * data points whose abscissas are * monotonically increasing in * order */ #define PEN_DECREASING 2 /* Lines will be drawn between only * those points whose abscissas are * decreasing in order */ #define PEN_BOTH_DIRECTIONS (PEN_INCREASING | PEN_DECREASING) /* Lines will be drawn between points regardless of the ordering of * the abscissas */ #define BROKEN_TRACE(dir,last,next) \ (((((dir) & PEN_DECREASING) == 0) && ((next) < (last))) || \ ((((dir) & PEN_INCREASING) == 0) && ((next) > (last)))) #define DRAW_SYMBOL(linePtr) \ (((linePtr)->symbolCounter % (linePtr)->symbolInterval) == 0) typedef enum { PEN_SMOOTH_NONE, /* Line segments */ PEN_SMOOTH_STEP, /* Step-and-hold */ PEN_SMOOTH_NATURAL, /* Natural cubic spline */ PEN_SMOOTH_QUADRATIC, /* Quadratic spline */ PEN_SMOOTH_CATROM, /* Catrom parametric spline */ PEN_SMOOTH_LAST /* Sentinel */ } Smoothing; typedef struct { char *name; Smoothing value; } SmoothingInfo; static SmoothingInfo smoothingInfo[] = { { "linear", PEN_SMOOTH_NONE }, { "step", PEN_SMOOTH_STEP }, { "natural", PEN_SMOOTH_NATURAL }, { "cubic", PEN_SMOOTH_NATURAL }, { "quadratic", PEN_SMOOTH_QUADRATIC }, { "catrom", PEN_SMOOTH_CATROM }, { (char *)NULL, PEN_SMOOTH_LAST } }; typedef struct { Point2D *screenPts; /* Array of transformed coordinates */ int nScreenPts; /* Number of coordinates */ int *dataToStyle; /* Index of pen styles */ int *indices; /* Maps segments/traces to data points */ } MapInfo; /* * Symbol types for line elements */ typedef enum { SYMBOL_NONE, SYMBOL_SQUARE, SYMBOL_CIRCLE, SYMBOL_DIAMOND, SYMBOL_PLUS, SYMBOL_CROSS, SYMBOL_SPLUS, SYMBOL_SCROSS, SYMBOL_TRIANGLE, SYMBOL_ARROW, SYMBOL_BITMAP } SymbolType; typedef struct { SymbolType type; /* Type of symbol to be drawn/printed */ int size; /* Requested size of symbol in pixels */ XColor *outlineColor; /* Outline color */ int outlineWidth; /* Width of the outline */ GC outlineGC; /* Outline graphics context */ XColor *fillColor; /* Normal fill color */ GC fillGC; /* Fill graphics context */ /* The last two fields are used only for bitmap symbols. */ Pixmap bitmap; /* Bitmap to determine foreground/background * pixels of the symbol */ Pixmap mask; /* Bitmap representing the transparent * pixels of the symbol */ } Symbol; typedef struct { int start; /* Index into the X-Y coordinate * arrays indicating where trace * starts. */ int nScreenPts; /* Number of points in the continuous * trace */ Point2D *screenPts; /* Array of screen coordinates * (malloc-ed) representing the * trace. */ int *symbolToData; /* Reverse mapping of screen * coordinate indices back to their * data coordinates */ } Trace; typedef struct { char *name; /* Name of pen style. If the pen was * statically allocated the name will * be NULL. */ Blt_Uid classUid; /* Type of pen */ char *typeId; /* String token identifying the type * of pen */ unsigned int flags; /* Indicates if the pen element is * active or normal */ int refCount; /* Reference count for elements using * this pen. */ Blt_HashEntry *hashPtr; Tk_ConfigSpec *configSpecs; /* Configuration specifications */ PenConfigureProc *configProc; PenDestroyProc *destroyProc; /* Symbol attributes. */ Symbol symbol; /* Element symbol type */ /* Trace attributes. */ int traceWidth; /* Width of the line segments. If * lineWidth is 0, no line will be * drawn, only symbols. */ Blt_Dashes traceDashes; /* Dash on-off list value */ XColor *traceColor; /* Line segment color */ XColor *traceOffColor; /* Line segment dash gap color */ GC traceGC; /* Line segment graphics context */ /* Error bar attributes. */ int errorBarShow; /* Describes which error bars to * display: none, x, y, or * both. */ int errorBarLineWidth; /* Width of the error bar segments. */ int errorBarCapWidth; /* Width of the cap on error bars. */ XColor *errorBarColor; /* Color of the error bar. */ GC errorBarGC; /* Error bar graphics context. */ /* Show value attributes. */ int valueShow; /* Indicates whether to display data * value. Values are x, y, both, or * none. */ char *valueFormat; /* A printf format string. */ TextStyle valueStyle; /* Text attributes (color, font, * rotation, etc.) of the value. */ } LinePen; typedef struct { Weight weight; /* Weight range where this pen is valid. */ LinePen *penPtr; /* Pen used to draw symbols, traces, error * bars, segments, etc. */ Segment2D *xErrorBars; /* Point to start of this pen's X-error bar * segments in the element's array. */ Segment2D *yErrorBars; /* Point to start of this pen's Y-error bar * segments in the element's array. */ int xErrorBarCnt; /* # of error bars for this pen. */ int yErrorBarCnt; /* # of error bars for this pen. */ int errorBarCapWidth; /* Length of the cap ends on each * error bar. */ int symbolSize; /* Size of the pen's symbol scaled to the * current graph size. */ /* Graph specific data. */ Point2D *symbolPts; /* Points to start of array for this pen. */ int nSymbolPts; /* # of points for this pen. */ /* The last two fields are used only for stripcharts. */ Segment2D *strips; /* Points to start of the line segments * for this pen. */ int nStrips; /* # of line segments for this pen. */ } LinePenStyle; typedef struct { char *name; /* Identifier used to refer the * element. Used in the "insert", * "delete", or "show", operations. */ Blt_Uid classUid; /* Type of element */ Graph *graphPtr; /* Graph widget of element*/ unsigned int flags; /* Indicates if the entire element is * active, or if coordinates need to * be calculated */ char **tags; int hidden; /* If non-zero, don't display the * element. */ Blt_HashEntry *hashPtr; char *label; /* Label displayed in legend */ int labelRelief; /* Relief of label in legend. */ Axis2D axes; ElemVector x, y, w; /* Contains array of numeric values */ ElemVector xError; /* Relative/symmetric X error values. */ ElemVector yError; /* Relative/symmetric Y error values. */ ElemVector xHigh, xLow; /* Absolute/asymmetric X-coordinate high/low error values. */ ElemVector yHigh, yLow; /* Absolute/asymmetric Y-coordinate high/low error values. */ int *activeIndices; /* Array of indices (malloc-ed) that * indicate the data points are active * (drawn with "active" colors). */ int nActiveIndices; /* Number of active data points. * Special case: if < 0 then all data * points are drawn active. */ ElementProcs *procsPtr; Tk_ConfigSpec *configSpecs; /* Configuration specifications */ Segment2D *xErrorBars; /* Point to start of this pen's X-error bar * segments in the element's array. */ Segment2D *yErrorBars; /* Point to start of this pen's Y-error bar * segments in the element's array. */ int xErrorBarCnt; /* # of error bars for this pen. */ int yErrorBarCnt; /* # of error bars for this pen. */ int *xErrorToData; /* Maps individual error bar segments back * to the data point associated with it. */ int *yErrorToData; /* Maps individual error bar segments back * to the data point associated with it. */ int errorBarCapWidth; /* Length of cap on error bars */ LinePen *activePenPtr; /* Pen to draw "active" elements. */ LinePen *normalPenPtr; /* Pen to draw elements normally. */ Blt_Chain *palette; /* Array of pen styles: pens are associated * with specific ranges of data.*/ /* Symbol scaling */ int scaleSymbols; /* If non-zero, the symbols will scale * in size as the graph is zoomed * in/out. */ double xRange, yRange; /* Initial X-axis and Y-axis ranges: * used to scale the size of element's * symbol. */ int state; /* * Line specific configurable attributes */ LinePen builtinPen; /* Line smoothing */ Smoothing reqSmooth; /* Requested smoothing function to use * for connecting the data points */ Smoothing smooth; /* Smoothing function used. */ double rTolerance; /* Tolerance to reduce the number of * points displayed. */ /* * Drawing related data structures. */ /* Area-under-curve fill attributes. */ XColor *fillFgColor; XColor *fillBgColor; GC fillGC; Blt_Tile fillTile; /* Tile for fill area. */ Pixmap fillStipple; /* Stipple for fill area. */ int nFillPts; Point2D *fillPts; /* Array of points used to draw * polygon to fill area under the * curve */ /* Symbol points */ Point2D *symbolPts; /* Holds the screen coordinates of all * the data points for the element. */ int nSymbolPts; /* Number of points */ int *symbolToData; /* Contains indices of data points. * It's first used to map pens to the * visible points to sort them by pen * style, and later to find data * points from the index of a visible * point. */ /* Active symbol points */ Point2D *activePts; /* Array of indices representing the * "active" points. */ int nActivePts; /* Number of indices in the above array. */ int *activeToData; /* Contains indices of data points. * It's first used to map pens to the * visible points to sort them by pen * style, and later to find data * points from the index of a visible * point. */ int reqMaxSymbols; int symbolInterval; int symbolCounter; /* X-Y graph-specific fields */ int penDir; /* Indicates if a change in the pen * direction should be considered a * retrace (line segment is not * drawn). */ Blt_Chain *traces; /* List of traces (a trace is a series * of contiguous line segments). New * traces are generated when either * the next segment changes the pen * direction, or the end point is * clipped by the plotting area. */ /* Stripchart-specific fields */ Segment2D *strips; /* Holds the the line segments of the * element trace. The segments are * grouped by pen style. */ int nStrips; /* Number of line segments to be drawn. */ int *stripToData; /* Pen to visible line segment mapping. */ } Line; static Tk_OptionParseProc StringToPattern; static Tk_OptionPrintProc PatternToString; static Tk_OptionParseProc StringToSmooth; static Tk_OptionPrintProc SmoothToString; extern Tk_OptionParseProc Blt_StringToStyles; extern Tk_OptionPrintProc Blt_StylesToString; static Tk_OptionParseProc StringToPenDir; static Tk_OptionPrintProc PenDirToString; static Tk_OptionParseProc StringToSymbol; static Tk_OptionPrintProc SymbolToString; static Tk_CustomOption patternOption = { StringToPattern, PatternToString, (ClientData)0 }; static Tk_CustomOption smoothOption = { StringToSmooth, SmoothToString, (ClientData)0 }; static Tk_CustomOption stylesOption = { Blt_StringToStyles, Blt_StylesToString, (ClientData)sizeof(LinePenStyle) }; static Tk_CustomOption penDirOption = { StringToPenDir, PenDirToString, (ClientData)0 }; static Tk_CustomOption symbolOption = { StringToSymbol, SymbolToString, (ClientData)0 }; extern Tk_CustomOption bltColorOption; extern Tk_CustomOption bltDashesOption; extern Tk_CustomOption bltDataOption; extern Tk_CustomOption bltDataPairsOption; extern Tk_CustomOption bltDistanceOption; extern Tk_CustomOption bltListOption; extern Tk_CustomOption bltLinePenOption; extern Tk_CustomOption bltShadowOption; extern Tk_CustomOption bltXAxisOption; extern Tk_CustomOption bltYAxisOption; extern Tk_CustomOption bltTileOption; extern Tk_CustomOption bltFillOption; extern Tk_CustomOption bltStateOption; #define DEF_LINE_ACTIVE_PEN "activeLine" #define DEF_LINE_AXIS_X "x" #define DEF_LINE_AXIS_Y "y" #define DEF_LINE_DASHES (char *)NULL #define DEF_LINE_DATA (char *)NULL #define DEF_LINE_FILL_COLOR "defcolor" #define DEF_LINE_FILL_MONO "defcolor" #define DEF_LINE_HIDE "no" #define DEF_LINE_LABEL (char *)NULL #define DEF_LINE_LABEL_RELIEF "flat" #define DEF_LINE_MAX_SYMBOLS "0" #define DEF_LINE_OFFDASH_COLOR (char *)NULL #define DEF_LINE_OFFDASH_MONO (char *)NULL #define DEF_LINE_OUTLINE_COLOR "defcolor" #define DEF_LINE_OUTLINE_MONO "defcolor" #define DEF_LINE_OUTLINE_WIDTH "1" #define DEF_LINE_PATTERN (char *)NULL #define DEF_LINE_PATTERN_BG "white" #define DEF_LINE_PATTERN_FG "black" #define DEF_LINE_PATTERN_TILE (char *)NULL #define DEF_LINE_PEN_COLOR RGB_NAVYBLUE #define DEF_LINE_PEN_DIRECTION "both" #define DEF_LINE_PEN_MONO RGB_BLACK #define DEF_LINE_PEN_WIDTH "1" #define DEF_LINE_PIXELS "0.125i" #define DEF_LINE_REDUCE "0.0" #define DEF_LINE_SCALE_SYMBOLS "yes" #define DEF_LINE_SMOOTH "linear" #define DEF_LINE_STATE "normal" #define DEF_LINE_STIPPLE (char *)NULL #define DEF_LINE_STYLES "" #define DEF_LINE_SYMBOL "circle" #define DEF_LINE_TAGS "all" #define DEF_LINE_X_DATA (char *)NULL #define DEF_LINE_Y_DATA (char *)NULL #define DEF_LINE_ERRORBAR_COLOR "defcolor" #define DEF_LINE_ERRORBAR_LINE_WIDTH "1" #define DEF_LINE_ERRORBAR_CAP_WIDTH "1" #define DEF_LINE_SHOW_ERRORBARS "both" #define DEF_PEN_ACTIVE_COLOR RGB_BLUE #define DEF_PEN_ACTIVE_MONO RGB_BLACK #define DEF_PEN_DASHES (char *)NULL #define DEF_PEN_FILL_COLOR "defcolor" #define DEF_PEN_FILL_MONO "defcolor" #define DEF_PEN_LINE_WIDTH "1" #define DEF_PEN_NORMAL_COLOR RGB_NAVYBLUE #define DEF_PEN_NORMAL_MONO RGB_BLACK #define DEF_PEN_OFFDASH_COLOR (char *)NULL #define DEF_PEN_OFFDASH_MONO (char *)NULL #define DEF_PEN_OUTLINE_COLOR "defcolor" #define DEF_PEN_OUTLINE_MONO "defcolor" #define DEF_PEN_OUTLINE_WIDTH "1" #define DEF_PEN_PIXELS "0.125i" #define DEF_PEN_SYMBOL "circle" #define DEF_PEN_TYPE "line" #define DEF_PEN_VALUE_ANCHOR "s" #define DEF_PEN_VALUE_COLOR RGB_BLACK #define DEF_PEN_VALUE_FONT STD_FONT_SMALL #define DEF_PEN_VALUE_FORMAT "%g" #define DEF_PEN_VALUE_ROTATE (char *)NULL #define DEF_PEN_VALUE_SHADOW (char *)NULL #define DEF_PEN_SHOW_VALUES "no" static Tk_ConfigSpec lineElemConfigSpecs[] = { {TK_CONFIG_CUSTOM, "-activepen", "activePen", "ActivePen", DEF_LINE_ACTIVE_PEN, Tk_Offset(Line, activePenPtr), TK_CONFIG_NULL_OK, &bltLinePenOption}, {TK_CONFIG_CUSTOM, "-areapattern", "areaPattern", "AreaPattern", DEF_LINE_PATTERN, Tk_Offset(Line, fillStipple), TK_CONFIG_NULL_OK, &patternOption}, {TK_CONFIG_COLOR, "-areaforeground", "areaForeground", "areaForeground", DEF_LINE_PATTERN_FG, Tk_Offset(Line, fillFgColor), TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-areabackground", "areaBackground", "areaBackground", DEF_LINE_PATTERN_BG, Tk_Offset(Line, fillBgColor), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-areatile", "areaTile", "AreaTile", DEF_LINE_PATTERN_TILE, Tk_Offset(Line, fillTile), TK_CONFIG_NULL_OK, &bltTileOption}, {TK_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags", DEF_LINE_TAGS, Tk_Offset(Line, tags), TK_CONFIG_NULL_OK, &bltListOption}, {TK_CONFIG_COLOR, "-color", "color", "Color", DEF_LINE_PEN_COLOR, Tk_Offset(Line, builtinPen.traceColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-color", "color", "Color", DEF_LINE_PEN_MONO, Tk_Offset(Line, builtinPen.traceColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_CUSTOM, "-dashes", "dashes", "Dashes", DEF_LINE_DASHES, Tk_Offset(Line, builtinPen.traceDashes), TK_CONFIG_NULL_OK, &bltDashesOption}, {TK_CONFIG_CUSTOM, "-data", "data", "Data", DEF_LINE_DATA, 0, 0, &bltDataPairsOption}, {TK_CONFIG_CUSTOM, "-errorbarcolor", "errorBarColor", "ErrorBarColor", DEF_LINE_ERRORBAR_COLOR, Tk_Offset(Line, builtinPen.errorBarColor), 0, &bltColorOption}, {TK_CONFIG_CUSTOM, "-errorbarwidth", "errorBarWidth", "ErrorBarWidth", DEF_LINE_ERRORBAR_LINE_WIDTH, Tk_Offset(Line, builtinPen.errorBarLineWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-errorbarcap", "errorBarCap", "ErrorBarCap", DEF_LINE_ERRORBAR_CAP_WIDTH, Tk_Offset(Line, builtinPen.errorBarCapWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-fill", "fill", "Fill", DEF_LINE_FILL_COLOR, Tk_Offset(Line, builtinPen.symbol.fillColor), TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY, &bltColorOption}, {TK_CONFIG_CUSTOM, "-fill", "fill", "Fill", DEF_LINE_FILL_MONO, Tk_Offset(Line, builtinPen.symbol.fillColor), TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY, &bltColorOption}, {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide", DEF_LINE_HIDE, Tk_Offset(Line, hidden), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_STRING, "-label", "label", "Label", (char *)NULL, Tk_Offset(Line, label), TK_CONFIG_NULL_OK}, {TK_CONFIG_RELIEF, "-labelrelief", "labelRelief", "LabelRelief", DEF_LINE_LABEL_RELIEF, Tk_Offset(Line, labelRelief), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-linewidth", "lineWidth", "LineWidth", DEF_LINE_PEN_WIDTH, Tk_Offset(Line, builtinPen.traceWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-mapx", "mapX", "MapX", DEF_LINE_AXIS_X, Tk_Offset(Line, axes.x), 0, &bltXAxisOption}, {TK_CONFIG_CUSTOM, "-mapy", "mapY", "MapY", DEF_LINE_AXIS_Y, Tk_Offset(Line, axes.y), 0, &bltYAxisOption}, {TK_CONFIG_CUSTOM, "-maxsymbols", "maxSymbols", "MaxSymbols", DEF_LINE_MAX_SYMBOLS, Tk_Offset(Line, reqMaxSymbols), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-offdash", "offDash", "OffDash", DEF_LINE_OFFDASH_COLOR, Tk_Offset(Line, builtinPen.traceOffColor), TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY, &bltColorOption}, {TK_CONFIG_CUSTOM, "-offdash", "offDash", "OffDash", DEF_LINE_OFFDASH_MONO, Tk_Offset(Line, builtinPen.traceOffColor), TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY, &bltColorOption}, {TK_CONFIG_CUSTOM, "-outline", "outline", "Outline", DEF_LINE_OUTLINE_COLOR, Tk_Offset(Line, builtinPen.symbol.outlineColor), TK_CONFIG_COLOR_ONLY, &bltColorOption}, {TK_CONFIG_CUSTOM, "-outline", "outline", "Outline", DEF_LINE_OUTLINE_MONO, Tk_Offset(Line, builtinPen.symbol.outlineColor), TK_CONFIG_MONO_ONLY, &bltColorOption}, {TK_CONFIG_CUSTOM, "-outlinewidth", "outlineWidth", "OutlineWidth", DEF_LINE_OUTLINE_WIDTH, Tk_Offset(Line, builtinPen.symbol.outlineWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-pen", "pen", "Pen", (char *)NULL, Tk_Offset(Line, normalPenPtr), TK_CONFIG_NULL_OK, &bltLinePenOption}, {TK_CONFIG_CUSTOM, "-pixels", "pixels", "Pixels", DEF_LINE_PIXELS, Tk_Offset(Line, builtinPen.symbol.size), GRAPH | STRIPCHART, &bltDistanceOption}, {TK_CONFIG_DOUBLE, "-reduce", "reduce", "Reduce", DEF_LINE_REDUCE, Tk_Offset(Line, rTolerance), GRAPH | STRIPCHART | TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_BOOLEAN, "-scalesymbols", "scaleSymbols", "ScaleSymbols", DEF_LINE_SCALE_SYMBOLS, Tk_Offset(Line, scaleSymbols), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-showerrorbars", "showErrorBars", "ShowErrorBars", DEF_LINE_SHOW_ERRORBARS, Tk_Offset(Line, builtinPen.errorBarShow), TK_CONFIG_DONT_SET_DEFAULT, &bltFillOption}, {TK_CONFIG_CUSTOM, "-showvalues", "showValues", "ShowValues", DEF_PEN_SHOW_VALUES, Tk_Offset(Line, builtinPen.valueShow), TK_CONFIG_DONT_SET_DEFAULT, &bltFillOption}, {TK_CONFIG_CUSTOM, "-smooth", "smooth", "Smooth", DEF_LINE_SMOOTH, Tk_Offset(Line, reqSmooth), TK_CONFIG_DONT_SET_DEFAULT, &smoothOption}, {TK_CONFIG_CUSTOM, "-state", "state", "State", DEF_LINE_STATE, Tk_Offset(Line, state), TK_CONFIG_DONT_SET_DEFAULT, &bltStateOption}, {TK_CONFIG_CUSTOM, "-styles", "styles", "Styles", DEF_LINE_STYLES, Tk_Offset(Line, palette), TK_CONFIG_NULL_OK, &stylesOption}, {TK_CONFIG_CUSTOM, "-symbol", "symbol", "Symbol", DEF_LINE_SYMBOL, Tk_Offset(Line, builtinPen.symbol), TK_CONFIG_DONT_SET_DEFAULT, &symbolOption}, {TK_CONFIG_CUSTOM, "-trace", "trace", "Trace", DEF_LINE_PEN_DIRECTION, Tk_Offset(Line, penDir), TK_CONFIG_DONT_SET_DEFAULT, &penDirOption}, {TK_CONFIG_ANCHOR, "-valueanchor", "valueAnchor", "ValueAnchor", DEF_PEN_VALUE_ANCHOR, Tk_Offset(Line, builtinPen.valueStyle.anchor), 0}, {TK_CONFIG_COLOR, "-valuecolor", "valueColor", "ValueColor", DEF_PEN_VALUE_COLOR, Tk_Offset(Line, builtinPen.valueStyle.color), 0}, {TK_CONFIG_FONT, "-valuefont", "valueFont", "ValueFont", DEF_PEN_VALUE_FONT, Tk_Offset(Line, builtinPen.valueStyle.font), 0}, {TK_CONFIG_STRING, "-valueformat", "valueFormat", "ValueFormat", DEF_PEN_VALUE_FORMAT, Tk_Offset(Line, builtinPen.valueFormat), TK_CONFIG_NULL_OK}, {TK_CONFIG_DOUBLE, "-valuerotate", "valueRotate", "ValueRotate", DEF_PEN_VALUE_ROTATE, Tk_Offset(Line, builtinPen.valueStyle.theta), 0}, {TK_CONFIG_CUSTOM, "-valueshadow", "valueShadow", "ValueShadow", DEF_PEN_VALUE_SHADOW, Tk_Offset(Line, builtinPen.valueStyle.shadow), 0, &bltShadowOption}, {TK_CONFIG_CUSTOM, "-weights", "weights", "Weights", (char *)NULL, Tk_Offset(Line, w), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-x", "xData", "XData", (char *)NULL, Tk_Offset(Line, x), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-xdata", "xData", "XData", (char *)NULL, Tk_Offset(Line, x), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-xerror", "xError", "XError", (char *)NULL, Tk_Offset(Line, xError), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-xhigh", "xHigh", "XHigh", (char *)NULL, Tk_Offset(Line, xHigh), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-xlow", "xLow", "XLow", (char *)NULL, Tk_Offset(Line, xLow), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-y", "yData", "YData", (char *)NULL, Tk_Offset(Line, y), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-ydata", "yData", "YData", (char *)NULL, Tk_Offset(Line, y), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-yerror", "yError", "YError", (char *)NULL, Tk_Offset(Line, yError), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-yhigh", "yHigh", "YHigh", (char *)NULL, Tk_Offset(Line, yHigh), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-ylow", "yLow", "YLow", (char *)NULL, Tk_Offset(Line, yLow), 0, &bltDataOption}, {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} }; static Tk_ConfigSpec stripElemConfigSpecs[] = { {TK_CONFIG_CUSTOM, "-activepen", "activePen", "ActivePen", DEF_LINE_ACTIVE_PEN, Tk_Offset(Line, activePenPtr), TK_CONFIG_NULL_OK, &bltLinePenOption}, {TK_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags", DEF_LINE_TAGS, Tk_Offset(Line, tags), TK_CONFIG_NULL_OK, &bltListOption}, {TK_CONFIG_COLOR, "-color", "color", "Color", DEF_LINE_PEN_COLOR, Tk_Offset(Line, builtinPen.traceColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-color", "color", "Color", DEF_LINE_PEN_MONO, Tk_Offset(Line, builtinPen.traceColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_CUSTOM, "-dashes", "dashes", "Dashes", DEF_LINE_DASHES, Tk_Offset(Line, builtinPen.traceDashes), TK_CONFIG_NULL_OK, &bltDashesOption}, {TK_CONFIG_CUSTOM, "-data", "data", "Data", DEF_LINE_DATA, 0, 0, &bltDataPairsOption}, {TK_CONFIG_CUSTOM, "-errorbarcolor", "errorBarColor", "ErrorBarColor", DEF_LINE_ERRORBAR_COLOR, Tk_Offset(Line, builtinPen.errorBarColor), 0, &bltColorOption}, {TK_CONFIG_CUSTOM, "-errorbarwidth", "errorBarWidth", "ErrorBarWidth", DEF_LINE_ERRORBAR_LINE_WIDTH, Tk_Offset(Line, builtinPen.errorBarLineWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-errorbarcap", "errorBarCap", "ErrorBarCap", DEF_LINE_ERRORBAR_CAP_WIDTH, Tk_Offset(Line, builtinPen.errorBarCapWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-fill", "fill", "Fill", DEF_LINE_FILL_COLOR, Tk_Offset(Line, builtinPen.symbol.fillColor), TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY, &bltColorOption}, {TK_CONFIG_CUSTOM, "-fill", "fill", "Fill", DEF_LINE_FILL_MONO, Tk_Offset(Line, builtinPen.symbol.fillColor), TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY, &bltColorOption}, {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide", DEF_LINE_HIDE, Tk_Offset(Line, hidden), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_STRING, "-label", "label", "Label", (char *)NULL, Tk_Offset(Line, label), TK_CONFIG_NULL_OK}, {TK_CONFIG_RELIEF, "-labelrelief", "labelRelief", "LabelRelief", DEF_LINE_LABEL_RELIEF, Tk_Offset(Line, labelRelief), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-linewidth", "lineWidth", "LineWidth", DEF_LINE_PEN_WIDTH, Tk_Offset(Line, builtinPen.traceWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-mapx", "mapX", "MapX", DEF_LINE_AXIS_X, Tk_Offset(Line, axes.x), 0, &bltXAxisOption}, {TK_CONFIG_CUSTOM, "-mapy", "mapY", "MapY", DEF_LINE_AXIS_Y, Tk_Offset(Line, axes.y), 0, &bltYAxisOption}, {TK_CONFIG_CUSTOM, "-maxsymbols", "maxSymbols", "MaxSymbols", DEF_LINE_MAX_SYMBOLS, Tk_Offset(Line, reqMaxSymbols), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-offdash", "offDash", "OffDash", DEF_LINE_OFFDASH_COLOR, Tk_Offset(Line, builtinPen.traceOffColor), TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY, &bltColorOption}, {TK_CONFIG_CUSTOM, "-offdash", "offDash", "OffDash", DEF_LINE_OFFDASH_MONO, Tk_Offset(Line, builtinPen.traceOffColor), TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY, &bltColorOption}, {TK_CONFIG_CUSTOM, "-outline", "outline", "Outline", DEF_LINE_OUTLINE_COLOR, Tk_Offset(Line, builtinPen.symbol.outlineColor), TK_CONFIG_COLOR_ONLY, &bltColorOption}, {TK_CONFIG_CUSTOM, "-outline", "outline", "Outline", DEF_LINE_OUTLINE_MONO, Tk_Offset(Line, builtinPen.symbol.outlineColor), TK_CONFIG_MONO_ONLY, &bltColorOption}, {TK_CONFIG_CUSTOM, "-outlinewidth", "outlineWidth", "OutlineWidth", DEF_LINE_OUTLINE_WIDTH, Tk_Offset(Line, builtinPen.symbol.outlineWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-pen", "pen", "Pen", (char *)NULL, Tk_Offset(Line, normalPenPtr), TK_CONFIG_NULL_OK, &bltLinePenOption}, {TK_CONFIG_CUSTOM, "-pixels", "pixels", "Pixels", DEF_LINE_PIXELS, Tk_Offset(Line, builtinPen.symbol.size), 0, &bltDistanceOption}, {TK_CONFIG_BOOLEAN, "-scalesymbols", "scaleSymbols", "ScaleSymbols", DEF_LINE_SCALE_SYMBOLS, Tk_Offset(Line, scaleSymbols), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-showerrorbars", "showErrorBars", "ShowErrorBars", DEF_LINE_SHOW_ERRORBARS, Tk_Offset(Line, builtinPen.errorBarShow), TK_CONFIG_DONT_SET_DEFAULT, &bltFillOption}, {TK_CONFIG_CUSTOM, "-showvalues", "showValues", "ShowValues", DEF_PEN_SHOW_VALUES, Tk_Offset(Line, builtinPen.valueShow), TK_CONFIG_DONT_SET_DEFAULT, &bltFillOption}, {TK_CONFIG_CUSTOM, "-smooth", "smooth", "Smooth", DEF_LINE_SMOOTH, Tk_Offset(Line, reqSmooth), TK_CONFIG_DONT_SET_DEFAULT, &smoothOption}, {TK_CONFIG_CUSTOM, "-styles", "styles", "Styles", DEF_LINE_STYLES, Tk_Offset(Line, palette), TK_CONFIG_NULL_OK, &stylesOption}, {TK_CONFIG_CUSTOM, "-symbol", "symbol", "Symbol", DEF_LINE_SYMBOL, Tk_Offset(Line, builtinPen.symbol), TK_CONFIG_DONT_SET_DEFAULT, &symbolOption}, {TK_CONFIG_ANCHOR, "-valueanchor", "valueAnchor", "ValueAnchor", DEF_PEN_VALUE_ANCHOR, Tk_Offset(Line, builtinPen.valueStyle.anchor), 0}, {TK_CONFIG_COLOR, "-valuecolor", "valueColor", "ValueColor", DEF_PEN_VALUE_COLOR, Tk_Offset(Line, builtinPen.valueStyle.color), 0}, {TK_CONFIG_FONT, "-valuefont", "valueFont", "ValueFont", DEF_PEN_VALUE_FONT, Tk_Offset(Line, builtinPen.valueStyle.font), 0}, {TK_CONFIG_STRING, "-valueformat", "valueFormat", "ValueFormat", DEF_PEN_VALUE_FORMAT, Tk_Offset(Line, builtinPen.valueFormat), TK_CONFIG_NULL_OK}, {TK_CONFIG_DOUBLE, "-valuerotate", "valueRotate", "ValueRotate", DEF_PEN_VALUE_ROTATE, Tk_Offset(Line, builtinPen.valueStyle.theta), 0}, {TK_CONFIG_CUSTOM, "-valueshadow", "valueShadow", "ValueShadow", DEF_PEN_VALUE_SHADOW, Tk_Offset(Line, builtinPen.valueStyle.shadow), 0, &bltShadowOption}, {TK_CONFIG_CUSTOM, "-weights", "weights", "Weights", (char *)NULL, Tk_Offset(Line, w), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-x", "xData", "XData", (char *)NULL, Tk_Offset(Line, x), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-xdata", "xData", "XData", (char *)NULL, Tk_Offset(Line, x), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-y", "yData", "YData", (char *)NULL, Tk_Offset(Line, y), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-xerror", "xError", "XError", (char *)NULL, Tk_Offset(Line, xError), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-ydata", "yData", "YData", (char *)NULL, Tk_Offset(Line, y), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-yerror", "yError", "YError", (char *)NULL, Tk_Offset(Line, yError), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-xhigh", "xHigh", "XHigh", (char *)NULL, Tk_Offset(Line, xHigh), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-xlow", "xLow", "XLow", (char *)NULL, Tk_Offset(Line, xLow), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-yhigh", "yHigh", "YHigh", (char *)NULL, Tk_Offset(Line, xHigh), 0, &bltDataOption}, {TK_CONFIG_CUSTOM, "-ylow", "yLow", "YLow", (char *)NULL, Tk_Offset(Line, yLow), 0, &bltDataOption}, {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} }; static Tk_ConfigSpec linePenConfigSpecs[] = { {TK_CONFIG_COLOR, "-color", "color", "Color", DEF_PEN_ACTIVE_COLOR, Tk_Offset(LinePen, traceColor), TK_CONFIG_COLOR_ONLY | ACTIVE_PEN}, {TK_CONFIG_COLOR, "-color", "color", "Color", DEF_PEN_ACTIVE_MONO, Tk_Offset(LinePen, traceColor), TK_CONFIG_MONO_ONLY | ACTIVE_PEN}, {TK_CONFIG_COLOR, "-color", "color", "Color", DEF_PEN_NORMAL_COLOR, Tk_Offset(LinePen, traceColor), TK_CONFIG_COLOR_ONLY | NORMAL_PEN}, {TK_CONFIG_COLOR, "-color", "color", "Color", DEF_PEN_NORMAL_MONO, Tk_Offset(LinePen, traceColor), TK_CONFIG_MONO_ONLY | NORMAL_PEN}, {TK_CONFIG_CUSTOM, "-dashes", "dashes", "Dashes", DEF_PEN_DASHES, Tk_Offset(LinePen, traceDashes), TK_CONFIG_NULL_OK | ALL_PENS, &bltDashesOption}, {TK_CONFIG_CUSTOM, "-errorbarcolor", "errorBarColor", "ErrorBarColor", DEF_LINE_ERRORBAR_COLOR, Tk_Offset(LinePen, errorBarColor), ALL_PENS, &bltColorOption}, {TK_CONFIG_CUSTOM, "-errorbarwidth", "errorBarWidth", "ErrorBarWidth", DEF_LINE_ERRORBAR_LINE_WIDTH, Tk_Offset(LinePen, errorBarLineWidth), ALL_PENS | TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-errorbarcap", "errorBarCap", "ErrorBarCap", DEF_LINE_ERRORBAR_CAP_WIDTH, Tk_Offset(LinePen, errorBarCapWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-fill", "fill", "Fill", DEF_PEN_FILL_COLOR, Tk_Offset(LinePen, symbol.fillColor), TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY | ALL_PENS, &bltColorOption}, {TK_CONFIG_CUSTOM, "-fill", "fill", "Fill", DEF_PEN_FILL_MONO, Tk_Offset(LinePen, symbol.fillColor), TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY | ALL_PENS, &bltColorOption}, {TK_CONFIG_CUSTOM, "-linewidth", "lineWidth", "LineWidth", (char *)NULL, Tk_Offset(LinePen, traceWidth), ALL_PENS | TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-offdash", "offDash", "OffDash", DEF_PEN_OFFDASH_COLOR, Tk_Offset(LinePen, traceOffColor), TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY | ALL_PENS, &bltColorOption}, {TK_CONFIG_CUSTOM, "-offdash", "offDash", "OffDash", DEF_PEN_OFFDASH_MONO, Tk_Offset(LinePen, traceOffColor), TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY | ALL_PENS, &bltColorOption}, {TK_CONFIG_CUSTOM, "-outline", "outline", "Outline", DEF_PEN_OUTLINE_COLOR, Tk_Offset(LinePen, symbol.outlineColor), TK_CONFIG_COLOR_ONLY | ALL_PENS, &bltColorOption}, {TK_CONFIG_CUSTOM, "-outline", "outline", "Outline", DEF_PEN_OUTLINE_MONO, Tk_Offset(LinePen, symbol.outlineColor), TK_CONFIG_MONO_ONLY | ALL_PENS, &bltColorOption}, {TK_CONFIG_CUSTOM, "-outlinewidth", "outlineWidth", "OutlineWidth", DEF_PEN_OUTLINE_WIDTH, Tk_Offset(LinePen, symbol.outlineWidth), TK_CONFIG_DONT_SET_DEFAULT | ALL_PENS, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-pixels", "pixels", "Pixels", DEF_PEN_PIXELS, Tk_Offset(LinePen, symbol.size), ALL_PENS, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-showerrorbars", "showErrorBars", "ShowErrorBars", DEF_LINE_SHOW_ERRORBARS, Tk_Offset(LinePen, errorBarShow), TK_CONFIG_DONT_SET_DEFAULT, &bltFillOption}, {TK_CONFIG_CUSTOM, "-showvalues", "showValues", "ShowValues", DEF_PEN_SHOW_VALUES, Tk_Offset(LinePen, valueShow), ALL_PENS | TK_CONFIG_DONT_SET_DEFAULT, &bltFillOption}, {TK_CONFIG_CUSTOM, "-symbol", "symbol", "Symbol", DEF_PEN_SYMBOL, Tk_Offset(LinePen, symbol), TK_CONFIG_DONT_SET_DEFAULT | ALL_PENS, &symbolOption}, {TK_CONFIG_STRING, "-type", (char *)NULL, (char *)NULL, DEF_PEN_TYPE, Tk_Offset(Pen, typeId), ALL_PENS | TK_CONFIG_NULL_OK}, {TK_CONFIG_ANCHOR, "-valueanchor", "valueAnchor", "ValueAnchor", DEF_PEN_VALUE_ANCHOR, Tk_Offset(LinePen, valueStyle.anchor), ALL_PENS}, {TK_CONFIG_COLOR, "-valuecolor", "valueColor", "ValueColor", DEF_PEN_VALUE_COLOR, Tk_Offset(LinePen, valueStyle.color), ALL_PENS}, {TK_CONFIG_FONT, "-valuefont", "valueFont", "ValueFont", DEF_PEN_VALUE_FONT, Tk_Offset(LinePen, valueStyle.font), ALL_PENS}, {TK_CONFIG_STRING, "-valueformat", "valueFormat", "ValueFormat", DEF_PEN_VALUE_FORMAT, Tk_Offset(LinePen, valueFormat), ALL_PENS | TK_CONFIG_NULL_OK}, {TK_CONFIG_DOUBLE, "-valuerotate", "valueRotate", "ValueRotate", DEF_PEN_VALUE_ROTATE, Tk_Offset(LinePen, valueStyle.theta), ALL_PENS}, {TK_CONFIG_CUSTOM, "-valueshadow", "valueShadow", "ValueShadow", DEF_PEN_VALUE_SHADOW, Tk_Offset(LinePen, valueStyle.shadow), ALL_PENS, &bltShadowOption}, {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} }; typedef double (DistanceProc) _ANSI_ARGS_((int x, int y, Point2D *p, Point2D *q, Point2D *t)); /* Forward declarations */ static PenConfigureProc ConfigurePen; static PenDestroyProc DestroyPen; static ElementClosestProc ClosestLine; static ElementConfigProc ConfigureLine; static ElementDestroyProc DestroyLine; static ElementDrawProc DrawActiveLine; static ElementDrawProc DrawNormalLine; static ElementDrawSymbolProc DrawSymbol; static ElementExtentsProc GetLineExtents; static ElementToPostScriptProc ActiveLineToPostScript; static ElementToPostScriptProc NormalLineToPostScript; static ElementSymbolToPostScriptProc SymbolToPostScript; static ElementMapProc MapLine; static DistanceProc DistanceToY; static DistanceProc DistanceToX; static DistanceProc DistanceToLine; static Blt_TileChangedProc TileChangedProc; #ifdef WIN32 static int tkpWinRopModes[] = { R2_BLACK, /* GXclear */ R2_MASKPEN, /* GXand */ R2_MASKPENNOT, /* GXandReverse */ R2_COPYPEN, /* GXcopy */ R2_MASKNOTPEN, /* GXandInverted */ R2_NOT, /* GXnoop */ R2_XORPEN, /* GXxor */ R2_MERGEPEN, /* GXor */ R2_NOTMERGEPEN, /* GXnor */ R2_NOTXORPEN, /* GXequiv */ R2_NOT, /* GXinvert */ R2_MERGEPENNOT, /* GXorReverse */ R2_NOTCOPYPEN, /* GXcopyInverted */ R2_MERGENOTPEN, /* GXorInverted */ R2_NOTMASKPEN, /* GXnand */ R2_WHITE /* GXset */ }; #endif INLINE static int Round(x) register double x; { return (int) (x + ((x < 0.0) ? -0.5 : 0.5)); } /* * ---------------------------------------------------------------------- * Custom configuration option (parse and print) routines * ---------------------------------------------------------------------- */ static int StringToBitmap(interp, tkwin, symbolPtr, string) Tcl_Interp *interp; Tk_Window tkwin; Symbol *symbolPtr; char *string; { Pixmap bitmap, mask; char **elemArr; int nElems; int result; if (Tcl_SplitList(interp, string, &nElems, &elemArr) != TCL_OK) { return TCL_ERROR; } if (nElems > 2) { Tcl_AppendResult(interp, "too many elements in bitmap list \"", string, "\": should be \"bitmap mask\"", (char *)NULL); result = TCL_ERROR; goto error; } mask = None; bitmap = Tk_GetBitmap(interp, tkwin, Tk_GetUid(elemArr[0])); if (bitmap == None) { result = TCL_BREAK; Tcl_ResetResult(interp); goto error; } if ((nElems > 1) && (elemArr[1][0] != '\0')) { mask = Tk_GetBitmap(interp, tkwin, Tk_GetUid(elemArr[1])); if (mask == None) { Tk_FreeBitmap(Tk_Display(tkwin), bitmap); result = TCL_ERROR; goto error; } } Blt_Free(elemArr); if (symbolPtr->bitmap != None) { Tk_FreeBitmap(Tk_Display(tkwin), symbolPtr->bitmap); } symbolPtr->bitmap = bitmap; if (symbolPtr->mask != None) { Tk_FreeBitmap(Tk_Display(tkwin), symbolPtr->mask); } symbolPtr->mask = mask; return TCL_OK; error: Blt_Free(elemArr); return result; } /*ARGSUSED*/ static char * PatternToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; char *widgRec; /* Element information record */ int offset; /* Offset of field in record */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { Pixmap stipple = *(Pixmap *)(widgRec + offset); if (stipple == None) { return ""; } if (stipple == PATTERN_SOLID) { return "solid"; } return Tk_NameOfBitmap(Tk_Display(tkwin), stipple); } /*ARGSUSED*/ static int StringToPattern(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* String representing field */ char *widgRec; /* Element information record */ int offset; /* Offset of field in record */ { Pixmap *stipplePtr = (Pixmap *)(widgRec + offset); Pixmap stipple; if ((string == NULL) || (string[0] == '\0')) { stipple = None; } else if (strcmp(string, "solid") == 0) { stipple = PATTERN_SOLID; } else { stipple = Tk_GetBitmap(interp, tkwin, Tk_GetUid(string)); if (stipple == None) { return TCL_ERROR; } } if ((*stipplePtr != None) && (*stipplePtr != PATTERN_SOLID)) { Tk_FreeBitmap(Tk_Display(tkwin), *stipplePtr); } *stipplePtr = stipple; return TCL_OK; } /* *---------------------------------------------------------------------- * * NameOfSymbol -- * * Converts the symbol value into its string representation. * * Results: * The static string representing the symbol type is returned. * *---------------------------------------------------------------------- */ static char * NameOfSymbol(symbolPtr) Symbol *symbolPtr; { switch (symbolPtr->type) { case SYMBOL_NONE: return "none"; case SYMBOL_SQUARE: return "square"; case SYMBOL_CIRCLE: return "circle"; case SYMBOL_DIAMOND: return "diamond"; case SYMBOL_PLUS: return "plus"; case SYMBOL_CROSS: return "cross"; case SYMBOL_SPLUS: return "splus"; case SYMBOL_SCROSS: return "scross"; case SYMBOL_TRIANGLE: return "triangle"; case SYMBOL_ARROW: return "arrow"; case SYMBOL_BITMAP: return "bitmap"; } return NULL; } /* *---------------------------------------------------------------------- * * StringToSymbol -- * * Convert the string representation of a line style or symbol name * into its numeric form. * * Results: * The return value is a standard Tcl result. The symbol type is * written into the widget record. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToSymbol(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* String representing symbol type */ char *widgRec; /* Element information record */ int offset; /* Offset of symbol type field in record */ { Symbol *symbolPtr = (Symbol *)(widgRec + offset); unsigned int length; char c; c = string[0]; length = strlen(string); if (c == '\0') { symbolPtr->type = SYMBOL_NONE; } else if ((c == 'n') && (strncmp(string, "none", length) == 0)) { symbolPtr->type = SYMBOL_NONE; } else if ((c == 'c') && (length > 1) && (strncmp(string, "circle", length) == 0)) { symbolPtr->type = SYMBOL_CIRCLE; } else if ((c == 's') && (length > 1) && (strncmp(string, "square", length) == 0)) { symbolPtr->type = SYMBOL_SQUARE; } else if ((c == 'd') && (strncmp(string, "diamond", length) == 0)) { symbolPtr->type = SYMBOL_DIAMOND; } else if ((c == 'p') && (strncmp(string, "plus", length) == 0)) { symbolPtr->type = SYMBOL_PLUS; } else if ((c == 'c') && (length > 1) && (strncmp(string, "cross", length) == 0)) { symbolPtr->type = SYMBOL_CROSS; } else if ((c == 's') && (length > 1) && (strncmp(string, "splus", length) == 0)) { symbolPtr->type = SYMBOL_SPLUS; } else if ((c == 's') && (length > 1) && (strncmp(string, "scross", length) == 0)) { symbolPtr->type = SYMBOL_SCROSS; } else if ((c == 't') && (strncmp(string, "triangle", length) == 0)) { symbolPtr->type = SYMBOL_TRIANGLE; } else if ((c == 'a') && (strncmp(string, "arrow", length) == 0)) { symbolPtr->type = SYMBOL_ARROW; } else { int result; result = StringToBitmap(interp, tkwin, symbolPtr, string); if (result != TCL_OK) { if (result != TCL_ERROR) { Tcl_AppendResult(interp, "bad symbol \"", string, "\": should be \"none\", \"circle\", \"square\", \"diamond\", \"plus\", \ \"cross\", \"splus\", \"scross\", \"triangle\", \"arrow\" \ or the name of a bitmap", (char *)NULL); } return TCL_ERROR; } symbolPtr->type = SYMBOL_BITMAP; } return TCL_OK; } /* *---------------------------------------------------------------------- * * SymbolToString -- * * Convert the symbol value into a string. * * Results: * The string representing the symbol type or line style is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * SymbolToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; char *widgRec; /* Element information record */ int offset; /* Offset of symbol type field in record */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { Symbol *symbolPtr = (Symbol *)(widgRec + offset); char *result; if (symbolPtr->type == SYMBOL_BITMAP) { Tcl_DString dString; Tcl_DStringInit(&dString); Tcl_DStringAppendElement(&dString, Tk_NameOfBitmap(Tk_Display(tkwin), symbolPtr->bitmap)); Tcl_DStringAppendElement(&dString, (symbolPtr->mask == None) ? "" : Tk_NameOfBitmap(Tk_Display(tkwin), symbolPtr->mask)); result = Blt_Strdup(Tcl_DStringValue(&dString)); Tcl_DStringFree(&dString); *freeProcPtr = (Tcl_FreeProc *)Blt_Free; } else { result = NameOfSymbol(symbolPtr); } return result; } /* *---------------------------------------------------------------------- * * NameOfSmooth -- * * Converts the smooth value into its string representation. * * Results: * The static string representing the smooth type is returned. * *---------------------------------------------------------------------- */ static char * NameOfSmooth(value) Smoothing value; { if ((value < 0) || (value >= PEN_SMOOTH_LAST)) { return "unknown smooth value"; } return smoothingInfo[value].name; } /* *---------------------------------------------------------------------- * * StringToSmooth -- * * Convert the string representation of a line style or smooth name * into its numeric form. * * Results: * The return value is a standard Tcl result. The smooth type is * written into the widget record. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToSmooth(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* String representing smooth type */ char *widgRec; /* Element information record */ int offset; /* Offset of smooth type field in record */ { Smoothing *valuePtr = (Smoothing *)(widgRec + offset); register SmoothingInfo *siPtr; for (siPtr = smoothingInfo; siPtr->name != NULL; siPtr++) { if (strcmp(string, siPtr->name) == 0) { *valuePtr = siPtr->value; return TCL_OK; } } Tcl_AppendResult(interp, "bad smooth value \"", string, "\": should be \ linear, step, natural, or quadratic", (char *)NULL); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * SmoothToString -- * * Convert the smooth value into a string. * * Results: * The string representing the smooth type or line style is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * SmoothToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Element information record */ int offset; /* Offset of smooth type field in record */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { int smooth = *(int *)(widgRec + offset); return NameOfSmooth(smooth); } /* *---------------------------------------------------------------------- * * StringToPenDir -- * * Convert the string representation of a line style or symbol name * into its numeric form. * * Results: * The return value is a standard Tcl result. The symbol type is * written into the widget record. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToPenDir(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* String representing pen direction */ char *widgRec; /* Element information record */ int offset; /* Offset of pen direction field in record */ { int *penDirPtr = (int *)(widgRec + offset); unsigned int length; char c; c = string[0]; length = strlen(string); if ((c == 'i') && (strncmp(string, "increasing", length) == 0)) { *penDirPtr = PEN_INCREASING; } else if ((c == 'd') && (strncmp(string, "decreasing", length) == 0)) { *penDirPtr = PEN_DECREASING; } else if ((c == 'b') && (strncmp(string, "both", length) == 0)) { *penDirPtr = PEN_BOTH_DIRECTIONS; } else { Tcl_AppendResult(interp, "bad trace value \"", string, "\" : should be \"increasing\", \"decreasing\", or \"both\"", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * NameOfPenDir -- * * Convert the pen direction into a string. * * Results: * The static string representing the pen direction is returned. * *---------------------------------------------------------------------- */ static char * NameOfPenDir(penDir) int penDir; /* Direction for pen drawing between points */ { switch (penDir) { case PEN_INCREASING: return "increasing"; case PEN_DECREASING: return "decreasing"; case PEN_BOTH_DIRECTIONS: return "both"; default: return "unknown trace direction"; } } /* *---------------------------------------------------------------------- * * PenDirToString -- * * Convert the pen direction into a string. * * Results: * The string representing the pen drawing direction is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * PenDirToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Element information record */ int offset; /* Offset of pen direction field in record */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { int penDir = *(int *)(widgRec + offset); return NameOfPenDir(penDir); } /* * Clear the number of points and segments, in case there are no * segments or points */ static void ClearPalette(palette) Blt_Chain *palette; { register LinePenStyle *stylePtr; Blt_ChainLink *linkPtr; for (linkPtr = Blt_ChainFirstLink(palette); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { stylePtr = Blt_ChainGetValue(linkPtr); stylePtr->nStrips = stylePtr->nSymbolPts = 0; stylePtr->xErrorBarCnt = stylePtr->yErrorBarCnt = 0; } } /* *---------------------------------------------------------------------- * * ConfigurePen -- * * Sets up the appropriate configuration parameters in the GC. * It is assumed the parameters have been previously set by * a call to Tk_ConfigureWidget. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then interp->result contains an error message. * * Side effects: * Configuration information such as line width, line style, color * etc. get set in a new GC. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ConfigurePen(graphPtr, penPtr) Graph *graphPtr; Pen *penPtr; { LinePen *lpPtr = (LinePen *)penPtr; unsigned long gcMask; GC newGC; XGCValues gcValues; XColor *colorPtr; Blt_ResetTextStyle(graphPtr->tkwin, &(lpPtr->valueStyle)); /* * Set the outline GC for this pen: GCForeground is outline color. * GCBackground is the fill color (only used for bitmap symbols). */ gcMask = (GCLineWidth | GCForeground); colorPtr = lpPtr->symbol.outlineColor; if (colorPtr == COLOR_DEFAULT) { colorPtr = lpPtr->traceColor; } gcValues.foreground = colorPtr->pixel; if (lpPtr->symbol.type == SYMBOL_BITMAP) { colorPtr = lpPtr->symbol.fillColor; if (colorPtr == COLOR_DEFAULT) { colorPtr = lpPtr->traceColor; } /* * Set a clip mask if either * 1) no background color was designated or * 2) a masking bitmap was specified. * * These aren't necessarily the bitmaps we'll be using for * clipping. But this makes it unlikely that anyone else will * be sharing this GC when we set the clip origin (at the time * the bitmap is drawn). */ if (colorPtr != NULL) { gcValues.background = colorPtr->pixel; gcMask |= GCBackground; if (lpPtr->symbol.mask != None) { gcValues.clip_mask = lpPtr->symbol.mask; gcMask |= GCClipMask; } } else { gcValues.clip_mask = lpPtr->symbol.bitmap; gcMask |= GCClipMask; } } gcValues.line_width = LineWidth(lpPtr->symbol.outlineWidth); newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues); if (lpPtr->symbol.outlineGC != NULL) { Tk_FreeGC(graphPtr->display, lpPtr->symbol.outlineGC); } lpPtr->symbol.outlineGC = newGC; /* Fill GC for symbols: GCForeground is fill color */ gcMask = (GCLineWidth | GCForeground); colorPtr = lpPtr->symbol.fillColor; if (colorPtr == COLOR_DEFAULT) { colorPtr = lpPtr->traceColor; } newGC = NULL; if (colorPtr != NULL) { gcValues.foreground = colorPtr->pixel; newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues); } if (lpPtr->symbol.fillGC != NULL) { Tk_FreeGC(graphPtr->display, lpPtr->symbol.fillGC); } lpPtr->symbol.fillGC = newGC; /* Line segments */ gcMask = (GCLineWidth | GCForeground | GCLineStyle | GCCapStyle | GCJoinStyle); gcValues.cap_style = CapButt; gcValues.join_style = JoinRound; gcValues.line_style = LineSolid; gcValues.line_width = LineWidth(lpPtr->traceWidth); colorPtr = lpPtr->traceOffColor; if (colorPtr == COLOR_DEFAULT) { colorPtr = lpPtr->traceColor; } if (colorPtr != NULL) { gcMask |= GCBackground; gcValues.background = colorPtr->pixel; } gcValues.foreground = lpPtr->traceColor->pixel; if (LineIsDashed(lpPtr->traceDashes)) { gcValues.line_width = lpPtr->traceWidth; gcValues.line_style = (colorPtr == NULL) ? LineOnOffDash : LineDoubleDash; } newGC = Blt_GetPrivateGC(graphPtr->tkwin, gcMask, &gcValues); if (lpPtr->traceGC != NULL) { Blt_FreePrivateGC(graphPtr->display, lpPtr->traceGC); } if (LineIsDashed(lpPtr->traceDashes)) { lpPtr->traceDashes.offset = lpPtr->traceDashes.values[0] / 2; Blt_SetDashes(graphPtr->display, newGC, &(lpPtr->traceDashes)); } lpPtr->traceGC = newGC; gcMask = (GCLineWidth | GCForeground); colorPtr = lpPtr->errorBarColor; if (colorPtr == COLOR_DEFAULT) { colorPtr = lpPtr->traceColor; } gcValues.line_width = LineWidth(lpPtr->errorBarLineWidth); gcValues.foreground = colorPtr->pixel; newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues); if (lpPtr->errorBarGC != NULL) { Tk_FreeGC(graphPtr->display, lpPtr->errorBarGC); } lpPtr->errorBarGC = newGC; return TCL_OK; } /* *---------------------------------------------------------------------- * * DestroyPen -- * * Release memory and resources allocated for the style. * * Results: * None. * * Side effects: * Everything associated with the pen style is freed up. * *---------------------------------------------------------------------- */ static void DestroyPen(graphPtr, penPtr) Graph *graphPtr; Pen *penPtr; { LinePen *lpPtr = (LinePen *)penPtr; Blt_FreeTextStyle(graphPtr->display, &(lpPtr->valueStyle)); if (lpPtr->symbol.outlineGC != NULL) { Tk_FreeGC(graphPtr->display, lpPtr->symbol.outlineGC); } if (lpPtr->symbol.fillGC != NULL) { Tk_FreeGC(graphPtr->display, lpPtr->symbol.fillGC); } if (lpPtr->errorBarGC != NULL) { Tk_FreeGC(graphPtr->display, lpPtr->errorBarGC); } if (lpPtr->traceGC != NULL) { Blt_FreePrivateGC(graphPtr->display, lpPtr->traceGC); } if (lpPtr->symbol.bitmap != None) { Tk_FreeBitmap(graphPtr->display, lpPtr->symbol.bitmap); lpPtr->symbol.bitmap = None; } if (lpPtr->symbol.mask != None) { Tk_FreeBitmap(graphPtr->display, lpPtr->symbol.mask); lpPtr->symbol.mask = None; } } static void InitPen(penPtr) LinePen *penPtr; { Blt_InitTextStyle(&penPtr->valueStyle); penPtr->configProc = ConfigurePen; penPtr->configSpecs = linePenConfigSpecs; penPtr->destroyProc = DestroyPen; penPtr->errorBarLineWidth = 1; penPtr->errorBarShow = SHOW_BOTH; penPtr->flags = NORMAL_PEN; penPtr->name = ""; penPtr->symbol.bitmap = penPtr->symbol.mask = None; penPtr->symbol.outlineColor = penPtr->symbol.fillColor = COLOR_DEFAULT; penPtr->symbol.outlineWidth = penPtr->traceWidth = 1; penPtr->symbol.type = SYMBOL_CIRCLE; penPtr->valueShow = SHOW_NONE; } Pen * Blt_LinePen(penName) char *penName; { LinePen *penPtr; penPtr = Blt_Calloc(1, sizeof(LinePen)); assert(penPtr); InitPen(penPtr); penPtr->name = Blt_Strdup(penName); if (strcmp(penName, "activeLine") == 0) { penPtr->flags = ACTIVE_PEN; } return (Pen *)penPtr; } /* * ---------------------------------------------------------------------- * * In this section, the routines deal with building and filling * the element's data structures with transformed screen * coordinates. They are triggered from TranformLine which is * called whenever the data or coordinates axes have changed and * new screen coordinates need to be calculated. * * ---------------------------------------------------------------------- */ /* *---------------------------------------------------------------------- * * ScaleSymbol -- * * Returns the scaled size for the line element. Scaling depends * upon when the base line ranges for the element were set and * the current range of the graph. * * Results: * The new size of the symbol, after considering how much the * graph has been scaled, is returned. * *---------------------------------------------------------------------- */ static int ScaleSymbol(elemPtr, normalSize) Element *elemPtr; int normalSize; { int maxSize; double scale; int newSize; scale = 1.0; if (elemPtr->scaleSymbols) { double xRange, yRange; xRange = (elemPtr->axes.x->max - elemPtr->axes.x->min); yRange = (elemPtr->axes.y->max - elemPtr->axes.y->min); if (elemPtr->flags & SCALE_SYMBOL) { /* Save the ranges as a baseline for future scaling. */ elemPtr->xRange = xRange; elemPtr->yRange = yRange; elemPtr->flags &= ~SCALE_SYMBOL; } else { double xScale, yScale; /* Scale the symbol by the smallest change in the X or Y axes */ xScale = elemPtr->xRange / xRange; yScale = elemPtr->yRange / yRange; scale = MIN(xScale, yScale); } } newSize = Round(normalSize * scale); /* * Don't let the size of symbols go unbounded. Both X and Win32 * drawing routines assume coordinates to be a signed short int. */ maxSize = (int)MIN(elemPtr->graphPtr->hRange, elemPtr->graphPtr->vRange); if (newSize > maxSize) { newSize = maxSize; } /* Make the symbol size odd so that its center is a single pixel. */ newSize |= 0x01; return newSize; } /* *---------------------------------------------------------------------- * * GetScreenPoints -- * * Generates a coordinate array of transformed screen coordinates * from the data points. * * Results: * The transformed screen coordinates are returned. * * Side effects: * Memory is allocated for the coordinate array. * *---------------------------------------------------------------------- */ static void GetScreenPoints(graphPtr, linePtr, mapPtr) Graph *graphPtr; Line *linePtr; MapInfo *mapPtr; { double *x, *y; register int i, n; register int count; register Point2D *screenPts; register int *indices; n = NumberOfPoints(linePtr); x = linePtr->x.valueArr; y = linePtr->y.valueArr; screenPts = Blt_Malloc(sizeof(Point2D) * n); assert(screenPts); indices = Blt_Malloc(sizeof(int) * n); assert(indices); count = 0; /* Count the valid screen coordinates */ if (graphPtr->inverted) { for (i = 0; i < n; i++) { if ((FINITE(x[i])) && (FINITE(y[i]))) { screenPts[count].x = Blt_HMap(graphPtr, linePtr->axes.y, y[i]); screenPts[count].y = Blt_VMap(graphPtr, linePtr->axes.x, x[i]); indices[count] = i; count++; } } } else { for (i = 0; i < n; i++) { if ((FINITE(x[i])) && (FINITE(y[i]))) { screenPts[count].x = Blt_HMap(graphPtr, linePtr->axes.x, x[i]); screenPts[count].y = Blt_VMap(graphPtr, linePtr->axes.y, y[i]); indices[count] = i; count++; } } } mapPtr->screenPts = screenPts; mapPtr->nScreenPts = count; mapPtr->indices = indices; } /* *---------------------------------------------------------------------- * * ReducePoints -- * * Generates a coordinate array of transformed screen coordinates * from the data points. * * Results: * The transformed screen coordinates are returned. * * Side effects: * Memory is allocated for the coordinate array. * *---------------------------------------------------------------------- */ static void ReducePoints(mapPtr, tolerance) MapInfo *mapPtr; double tolerance; { register int i, k, n; Point2D *screenPts; int *indices, *simple; simple = Blt_Malloc(sizeof(int) * mapPtr->nScreenPts); indices = Blt_Malloc(sizeof(int) * mapPtr->nScreenPts); screenPts = Blt_Malloc(sizeof(Point2D) * mapPtr->nScreenPts); n = Blt_SimplifyLine(mapPtr->screenPts, 0, mapPtr->nScreenPts - 1, tolerance, simple); for (i = 0; i < n; i++) { k = simple[i]; screenPts[i] = mapPtr->screenPts[k]; indices[i] = mapPtr->indices[k]; } #ifdef notdef if (n < mapPtr->nScreenPts) { fprintf(stderr, "reduced from %d to %d\n", mapPtr->nScreenPts, n); } #endif Blt_Free(mapPtr->screenPts); Blt_Free(mapPtr->indices); Blt_Free(simple); mapPtr->screenPts = screenPts; mapPtr->indices = indices; mapPtr->nScreenPts = n; } /* *---------------------------------------------------------------------- * * GenerateSteps -- * * Resets the coordinate and pen index arrays adding new points * for step-and-hold type smoothing. * * Results: * None. * * Side Effects: * The temporary arrays for screen coordinates and pen indices * are updated. * *---------------------------------------------------------------------- */ static void GenerateSteps(mapPtr) MapInfo *mapPtr; { int newSize; register int i, count; Point2D *screenPts; int *indices; newSize = ((mapPtr->nScreenPts - 1) * 2) + 1; screenPts = Blt_Malloc(newSize * sizeof(Point2D)); assert(screenPts); indices = Blt_Malloc(sizeof(int) * newSize); assert(indices); screenPts[0] = mapPtr->screenPts[0]; indices[0] = 0; count = 1; for (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 */ indices[count] = indices[count + 1] = mapPtr->indices[i]; count += 2; } Blt_Free(mapPtr->screenPts); Blt_Free(mapPtr->indices); mapPtr->indices = indices; mapPtr->screenPts = screenPts; mapPtr->nScreenPts = newSize; } /* *---------------------------------------------------------------------- * * GenerateSpline -- * * Computes a spline based upon the data points, returning a new * (larger) coordinate array or points. * * Results: * None. * * Side Effects: * The temporary arrays for screen coordinates and data indices * are updated based upon spline. * * FIXME: Can't interpolate knots along the Y-axis. Need to break * up point array into interchangable X and Y vectors earlier. * Pass extents (left/right or top/bottom) as parameters. * *---------------------------------------------------------------------- */ static void GenerateSpline(graphPtr, linePtr, mapPtr) Graph *graphPtr; Line *linePtr; MapInfo *mapPtr; { int extra; register int i, j, count; Point2D *origPts, *intpPts; int *indices; int nIntpPts, nOrigPts; int result; int x; nOrigPts = mapPtr->nScreenPts; origPts = mapPtr->screenPts; assert(mapPtr->nScreenPts > 0); for (i = 0, j = 1; j < nOrigPts; i++, j++) { if (origPts[j].x <= origPts[i].x) { return; /* Points are not monotonically increasing */ } } if (((origPts[0].x > (double)graphPtr->right)) || ((origPts[mapPtr->nScreenPts - 1].x < (double)graphPtr->left))) { return; /* All points are clipped */ } /* * 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. */ extra = (graphPtr->right - graphPtr->left) + 1; if (extra < 1) { return; } nIntpPts = nOrigPts + extra + 1; intpPts = Blt_Malloc(nIntpPts * sizeof(Point2D)); assert(intpPts); indices = Blt_Malloc(sizeof(int) * nIntpPts); assert(indices); /* Populate the x2 array with both the original X-coordinates and * extra X-coordinates for each horizontal pixel that the line * segment contains. */ count = 0; for (i = 0, j = 1; j < nOrigPts; i++, j++) { /* Add the original x-coordinate */ intpPts[count].x = origPts[i].x; /* Include the starting offset of the point in the offset array */ indices[count] = mapPtr->indices[i]; count++; /* Is any part of the interval (line segment) in the plotting * area? */ if ((origPts[j].x >= (double)graphPtr->left) || (origPts[i].x <= (double)graphPtr->right)) { int last; x = (int)(origPts[i].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, graphPtr->left); last = (int)MIN(origPts[j].x, graphPtr->right); /* Add the extra x-coordinates to the interval. */ while (x < last) { indices[count] = mapPtr->indices[i]; intpPts[count++].x = (double)x; x++; } } } nIntpPts = count; result = FALSE; if (linePtr->smooth == PEN_SMOOTH_NATURAL) { result = Blt_NaturalSpline(origPts, nOrigPts, intpPts, nIntpPts); } else if (linePtr->smooth == PEN_SMOOTH_QUADRATIC) { result = Blt_QuadraticSpline(origPts, nOrigPts, intpPts, nIntpPts); } if (!result) { /* The spline interpolation failed. We'll fallback to the * current coordinates and do no smoothing (standard line * segments). */ linePtr->smooth = PEN_SMOOTH_NONE; Blt_Free(intpPts); Blt_Free(indices); } else { Blt_Free(mapPtr->screenPts); Blt_Free(mapPtr->indices); mapPtr->indices = indices; mapPtr->screenPts = intpPts; mapPtr->nScreenPts = nIntpPts; } } /* *---------------------------------------------------------------------- * * GenerateParametricSpline -- * * Computes a spline based upon the data points, returning a new * (larger) coordinate array or points. * * Results: * None. * * Side Effects: * The temporary arrays for screen coordinates and data indices * are updated based upon spline. * * FIXME: Can't interpolate knots along the Y-axis. Need to break * up point array into interchangable X and Y vectors earlier. * Pass extents (left/right or top/bottom) as parameters. * *---------------------------------------------------------------------- */ static void GenerateParametricSpline(graphPtr, linePtr, mapPtr) Graph *graphPtr; Line *linePtr; MapInfo *mapPtr; { Extents2D exts; Point2D *origPts, *intpPts; Point2D p, q; double dist; int *indices; int nIntpPts, nOrigPts; int result; register int i, j, count; nOrigPts = mapPtr->nScreenPts; origPts = mapPtr->screenPts; assert(mapPtr->nScreenPts > 0); Blt_GraphExtents(graphPtr, &exts); /* * Populate the x2 array with both the original X-coordinates and * extra X-coordinates for each horizontal pixel that the line * segment contains. */ count = 1; for (i = 0, j = 1; j < nOrigPts; i++, j++) { p = origPts[i]; q = origPts[j]; count++; if (Blt_LineRectClip(&exts, &p, &q)) { count += (int)(hypot(q.x - p.x, q.y - p.y) * 0.5); } } nIntpPts = count; intpPts = Blt_Malloc(nIntpPts * sizeof(Point2D)); assert(intpPts); indices = Blt_Malloc(sizeof(int) * nIntpPts); assert(indices); /* * 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; for (i = 0, j = 1; j < nOrigPts; i++, j++) { p = origPts[i]; q = origPts[j]; dist = hypot(q.x - p.x, q.y - p.y); /* Add the original x-coordinate */ intpPts[count].x = (double)i; intpPts[count].y = 0.0; /* Include the starting offset of the point in the offset array */ indices[count] = mapPtr->indices[i]; count++; /* Is any part of the interval (line segment) in the plotting * area? */ if (Blt_LineRectClip(&exts, &p, &q)) { double distP, distQ; distP = hypot(p.x - origPts[i].x, p.y - origPts[i].y); distQ = hypot(q.x - origPts[i].x, q.y - origPts[i].y); distP += 2.0; while(distP <= distQ) { /* Point is indicated by its interval and parameter t. */ intpPts[count].x = (double)i; intpPts[count].y = distP / dist; indices[count] = mapPtr->indices[i]; count++; distP += 2.0; } } } intpPts[count].x = (double)i; intpPts[count].y = 0.0; indices[count] = mapPtr->indices[i]; count++; nIntpPts = count; result = FALSE; if (linePtr->smooth == PEN_SMOOTH_NATURAL) { result = Blt_NaturalParametricSpline(origPts, nOrigPts, &exts, FALSE, intpPts, nIntpPts); } else if (linePtr->smooth == PEN_SMOOTH_CATROM) { result = Blt_CatromParametricSpline(origPts, nOrigPts, intpPts, nIntpPts); } if (!result) { /* The spline interpolation failed. We'll fallback to the * current coordinates and do no smoothing (standard line * segments). */ linePtr->smooth = PEN_SMOOTH_NONE; Blt_Free(intpPts); Blt_Free(indices); } else { Blt_Free(mapPtr->screenPts); Blt_Free(mapPtr->indices); mapPtr->indices = indices; mapPtr->screenPts = intpPts; mapPtr->nScreenPts = nIntpPts; } } /* *---------------------------------------------------------------------- * * MapSymbols -- * * Creates two arrays of points and pen indices, filled with * the screen coordinates of the visible * * Results: * None. * * Side effects: * Memory is freed and allocated for the index array. * *---------------------------------------------------------------------- */ static void MapSymbols(graphPtr, linePtr, mapPtr) Graph *graphPtr; Line *linePtr; MapInfo *mapPtr; { Extents2D exts; Point2D *symbolPts; int *indices; register int i, count; symbolPts = Blt_Malloc(sizeof(Point2D) * mapPtr->nScreenPts); assert(symbolPts); indices = Blt_Malloc(sizeof(int) * mapPtr->nScreenPts); assert(indices); Blt_GraphExtents(graphPtr, &exts); count = 0; /* Count the number of visible points */ for (i = 0; i < mapPtr->nScreenPts; i++) { if (PointInRegion(&exts, mapPtr->screenPts[i].x, mapPtr->screenPts[i].y)) { symbolPts[count].x = mapPtr->screenPts[i].x; symbolPts[count].y = mapPtr->screenPts[i].y; indices[count] = mapPtr->indices[i]; count++; } } linePtr->symbolPts = symbolPts; linePtr->nSymbolPts = count; linePtr->symbolToData = indices; } /* *---------------------------------------------------------------------- * * MapActiveSymbols -- * * Creates an array of points of the active graph coordinates. * * Results: * None. * * Side effects: * Memory is freed and allocated for the active point array. * *---------------------------------------------------------------------- */ static void MapActiveSymbols(graphPtr, linePtr) Graph *graphPtr; Line *linePtr; { Extents2D exts; double x, y; int count; Point2D *activePts; register int i; int pointIndex; int nPoints; int *activeToData; if (linePtr->activePts != NULL) { Blt_Free(linePtr->activePts); linePtr->activePts = NULL; } if (linePtr->activeToData != NULL) { Blt_Free(linePtr->activeToData); linePtr->activeToData = NULL; } Blt_GraphExtents(graphPtr, &exts); activePts = Blt_Malloc(sizeof(Point2D) * linePtr->nActiveIndices); assert(activePts); activeToData = Blt_Malloc(sizeof(int) * linePtr->nActiveIndices); nPoints = NumberOfPoints(linePtr); count = 0; /* Count the visible active points */ for (i = 0; i < linePtr->nActiveIndices; i++) { pointIndex = linePtr->activeIndices[i]; if (pointIndex >= nPoints) { continue; /* Index not available */ } x = linePtr->x.valueArr[pointIndex]; y = linePtr->y.valueArr[pointIndex]; activePts[count] = Blt_Map2D(graphPtr, x, y, &(linePtr->axes)); activeToData[count] = pointIndex; if (PointInRegion(&exts, activePts[count].x, activePts[count].y)) { count++; } } if (count > 0) { linePtr->activePts = activePts; linePtr->activeToData = activeToData; } else { /* No active points were visible. */ Blt_Free(activePts); Blt_Free(activeToData); } linePtr->nActivePts = count; linePtr->flags &= ~ACTIVE_PENDING; } /* *---------------------------------------------------------------------- * * MapStrip -- * * Creates an array of line segments of the graph coordinates. * * Results: * None. * * Side effects: * Memory is allocated for the line segment array. * *---------------------------------------------------------------------- */ static void MapStrip(graphPtr, linePtr, mapPtr) Graph *graphPtr; Line *linePtr; MapInfo *mapPtr; { Extents2D exts; Segment2D *strips; int *indices, *indexPtr; register Point2D *endPtr, *pointPtr; register Segment2D *segPtr; register int count; indices = Blt_Malloc(sizeof(int) * mapPtr->nScreenPts); assert(indices); /* * Create array to hold points for line segments (not polyline * coordinates). So allocate twice the number of points. */ segPtr = strips = Blt_Malloc(mapPtr->nScreenPts * sizeof(Segment2D)); assert(strips); Blt_GraphExtents(graphPtr, &exts); count = 0; /* Count the number of segments. */ indexPtr = mapPtr->indices; for (pointPtr = mapPtr->screenPts, endPtr = mapPtr->screenPts + (mapPtr->nScreenPts - 1); pointPtr < endPtr; pointPtr++, indexPtr++) { segPtr->p = pointPtr[0]; segPtr->q = pointPtr[1]; if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) { segPtr++; indices[count] = *indexPtr; count++; } } linePtr->stripToData = indices; linePtr->nStrips = count; linePtr->strips = strips; } /* *---------------------------------------------------------------------- * * MergePens -- * * Reorders the both arrays of points and segments to merge pens. * * Results: * None. * * Side effects: * The old arrays are freed and new ones allocated containing * the reordered points and segments. * *---------------------------------------------------------------------- */ static void MergePens(linePtr, dataToStyle) Line *linePtr; PenStyle **dataToStyle; { LinePenStyle *stylePtr; register int i; Blt_ChainLink *linkPtr; if (Blt_ChainGetLength(linePtr->palette) < 2) { linkPtr = Blt_ChainFirstLink(linePtr->palette); stylePtr = Blt_ChainGetValue(linkPtr); stylePtr->nStrips = linePtr->nStrips; stylePtr->strips = linePtr->strips; stylePtr->nSymbolPts = linePtr->nSymbolPts; stylePtr->symbolPts = linePtr->symbolPts; stylePtr->xErrorBarCnt = linePtr->xErrorBarCnt; stylePtr->yErrorBarCnt = linePtr->yErrorBarCnt; stylePtr->xErrorBars = linePtr->xErrorBars; stylePtr->yErrorBars = linePtr->yErrorBars; stylePtr->errorBarCapWidth = linePtr->errorBarCapWidth; return; } /* We have more than one style. Group line segments and points of * like pen styles. */ if (linePtr->nStrips > 0) { Segment2D *strips; int *stripToData; register Segment2D *segPtr; register int *indexPtr; int dataIndex; strips = Blt_Malloc(linePtr->nStrips * sizeof(Segment2D)); stripToData = Blt_Malloc(linePtr->nStrips * sizeof(int)); assert(strips && stripToData); segPtr = strips, indexPtr = stripToData; for (linkPtr = Blt_ChainFirstLink(linePtr->palette); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { stylePtr = Blt_ChainGetValue(linkPtr); stylePtr->strips = segPtr; for (i = 0; i < linePtr->nStrips; i++) { dataIndex = linePtr->stripToData[i]; if (dataToStyle[dataIndex] == (PenStyle *)stylePtr) { *segPtr++ = linePtr->strips[i]; *indexPtr++ = dataIndex; } } stylePtr->nStrips = segPtr - stylePtr->strips; } Blt_Free(linePtr->strips); linePtr->strips = strips; Blt_Free(linePtr->stripToData); linePtr->stripToData = stripToData; } if (linePtr->nSymbolPts > 0) { int *indexPtr; register Point2D *symbolPts, *pointPtr; register int *symbolToData; int dataIndex; symbolPts = Blt_Malloc(linePtr->nSymbolPts * sizeof(Point2D)); symbolToData = Blt_Malloc(linePtr->nSymbolPts * sizeof(int)); assert(symbolPts && symbolToData); pointPtr = symbolPts, indexPtr = symbolToData; for (linkPtr = Blt_ChainFirstLink(linePtr->palette); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { stylePtr = Blt_ChainGetValue(linkPtr); stylePtr->symbolPts = pointPtr; for (i = 0; i < linePtr->nSymbolPts; i++) { dataIndex = linePtr->symbolToData[i]; if (dataToStyle[dataIndex] == (PenStyle *)stylePtr) { *pointPtr++ = linePtr->symbolPts[i]; *indexPtr++ = dataIndex; } } stylePtr->nSymbolPts = pointPtr - stylePtr->symbolPts; } Blt_Free(linePtr->symbolPts); linePtr->symbolPts = symbolPts; Blt_Free(linePtr->symbolToData); linePtr->symbolToData = symbolToData; } if (linePtr->xErrorBarCnt > 0) { Segment2D *xErrorBars, *segPtr; int *xErrorToData, *indexPtr; int dataIndex; xErrorBars = Blt_Malloc(linePtr->xErrorBarCnt * sizeof(Segment2D)); xErrorToData = Blt_Malloc(linePtr->xErrorBarCnt * sizeof(int)); assert(xErrorBars); segPtr = xErrorBars, indexPtr = xErrorToData; for (linkPtr = Blt_ChainFirstLink(linePtr->palette); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { stylePtr = Blt_ChainGetValue(linkPtr); stylePtr->xErrorBars = segPtr; for (i = 0; i < linePtr->xErrorBarCnt; i++) { dataIndex = linePtr->xErrorToData[i]; if (dataToStyle[dataIndex] == (PenStyle *)stylePtr) { *segPtr++ = linePtr->xErrorBars[i]; *indexPtr++ = dataIndex; } } stylePtr->xErrorBarCnt = segPtr - stylePtr->xErrorBars; } Blt_Free(linePtr->xErrorBars); linePtr->xErrorBars = xErrorBars; Blt_Free(linePtr->xErrorToData); linePtr->xErrorToData = xErrorToData; } if (linePtr->yErrorBarCnt > 0) { Segment2D *errorBars, *segPtr; int *errorToData, *indexPtr; int dataIndex; errorBars = Blt_Malloc(linePtr->yErrorBarCnt * sizeof(Segment2D)); errorToData = Blt_Malloc(linePtr->yErrorBarCnt * sizeof(int)); assert(errorBars); segPtr = errorBars, indexPtr = errorToData; for (linkPtr = Blt_ChainFirstLink(linePtr->palette); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { stylePtr = Blt_ChainGetValue(linkPtr); stylePtr->yErrorBars = segPtr; for (i = 0; i < linePtr->yErrorBarCnt; i++) { dataIndex = linePtr->yErrorToData[i]; if (dataToStyle[dataIndex] == (PenStyle *)stylePtr) { *segPtr++ = linePtr->yErrorBars[i]; *indexPtr++ = dataIndex; } } stylePtr->yErrorBarCnt = segPtr - stylePtr->yErrorBars; } Blt_Free(linePtr->yErrorBars); linePtr->yErrorBars = errorBars; Blt_Free(linePtr->yErrorToData); linePtr->yErrorToData = errorToData; } } #define CLIP_TOP (1<<0) #define CLIP_BOTTOM (1<<1) #define CLIP_RIGHT (1<<2) #define CLIP_LEFT (1<<3) INLINE static int OutCode(extsPtr, p) Extents2D *extsPtr; Point2D *p; { int code; 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; } static int ClipSegment(extsPtr, code1, code2, p, q) Extents2D *extsPtr; register int code1, code2; register Point2D *p, *q; { int inside, outside; inside = ((code1 | code2) == 0); 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); } /* *---------------------------------------------------------------------- * * SaveTrace -- * * Creates a new trace and inserts it into the line's * list of traces. * * Results: * None. * *---------------------------------------------------------------------- */ static void SaveTrace(linePtr, start, length, mapPtr) Line *linePtr; int start; /* Starting index of the trace in data point * array. Used to figure out closest point */ int length; /* Number of points forming the trace */ MapInfo *mapPtr; { Trace *tracePtr; Point2D *screenPts; int *indices; register int i, j; tracePtr = Blt_Malloc(sizeof(Trace)); assert(tracePtr); screenPts = Blt_Malloc(sizeof(Point2D) * length); assert(screenPts); indices = Blt_Malloc(sizeof(int) * length); assert(indices); /* Copy the screen coordinates of the trace into the point array */ if (mapPtr->indices != NULL) { for (i = 0, j = start; i < length; i++, j++) { screenPts[i].x = mapPtr->screenPts[j].x; screenPts[i].y = mapPtr->screenPts[j].y; indices[i] = mapPtr->indices[j]; } } else { for (i = 0, j = start; i < length; i++, j++) { screenPts[i].x = mapPtr->screenPts[j].x; screenPts[i].y = mapPtr->screenPts[j].y; indices[i] = j; } } tracePtr->nScreenPts = length; tracePtr->screenPts = screenPts; tracePtr->symbolToData = indices; tracePtr->start = start; if (linePtr->traces == NULL) { linePtr->traces = Blt_ChainCreate(); } Blt_ChainAppend(linePtr->traces, tracePtr); } /* *---------------------------------------------------------------------- * * FreeTraces -- * * Deletes all the traces for the line. * * Results: * None. * *---------------------------------------------------------------------- */ static void FreeTraces(linePtr) Line *linePtr; { Blt_ChainLink *linkPtr; Trace *tracePtr; for (linkPtr = Blt_ChainFirstLink(linePtr->traces); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tracePtr = Blt_ChainGetValue(linkPtr); Blt_Free(tracePtr->symbolToData); Blt_Free(tracePtr->screenPts); Blt_Free(tracePtr); } Blt_ChainDestroy(linePtr->traces); linePtr->traces = NULL; } /* *---------------------------------------------------------------------- * * MapTraces -- * * Creates an array of line segments of the graph coordinates. * * Results: * None. * * Side effects: * Memory is allocated for the line segment array. * *---------------------------------------------------------------------- */ static void MapTraces(graphPtr, linePtr, mapPtr) Graph *graphPtr; Line *linePtr; MapInfo *mapPtr; { int start, count; int code1, code2; Point2D *p, *q; Point2D s; Extents2D exts; register int i; int broken, offscreen; Blt_GraphExtents(graphPtr, &exts); count = 1; code1 = OutCode(&exts, mapPtr->screenPts); p = mapPtr->screenPts; q = p + 1; for (i = 1; i < mapPtr->nScreenPts; i++, p++, q++) { code2 = OutCode(&exts, q); if (code2 != 0) { /* Save the coordinates of the last point, before clipping */ s = *q; } broken = BROKEN_TRACE(linePtr->penDir, p->x, q->x); 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 = i - count; SaveTrace(linePtr, start, count, mapPtr); count = 1; } } else { count++; /* Add the point to the trace. */ if (code2 != 0) { /* * 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. */ start = i - (count - 1); SaveTrace(linePtr, start, count, mapPtr); mapPtr->screenPts[i] = s; count = 1; } } code1 = code2; } if (count > 1) { start = i - count; SaveTrace(linePtr, start, count, mapPtr); } } /* *---------------------------------------------------------------------- * * MapFillArea -- * * Creates an array of points that represent a polygon that fills * the area under the element. * * Results: * None. * * Side effects: * Memory is allocated for the polygon point array. * *---------------------------------------------------------------------- */ static void MapFillArea(graphPtr, linePtr, mapPtr) Graph *graphPtr; Line *linePtr; MapInfo *mapPtr; { Point2D *origPts, *clipPts; Extents2D exts; double maxY; register int i, n; if (linePtr->fillPts != NULL) { Blt_Free(linePtr->fillPts); linePtr->fillPts = NULL; linePtr->nFillPts = 0; } if (mapPtr->nScreenPts < 3) { return; } n = mapPtr->nScreenPts + 3; Blt_GraphExtents(graphPtr, &exts); maxY = (double)graphPtr->bottom; origPts = Blt_Malloc(sizeof(Point2D) * n); 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 make (if necessary) the polygon fill 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]; clipPts = Blt_Malloc(sizeof(Point2D) * n * 3); assert(clipPts); n = Blt_PolyRectClip(&exts, origPts, n - 1, clipPts); Blt_Free(origPts); if (n < 3) { Blt_Free(clipPts); } else { linePtr->fillPts = clipPts; linePtr->nFillPts = n; } } static void ResetLine(linePtr) Line *linePtr; { FreeTraces(linePtr); ClearPalette(linePtr->palette); if (linePtr->symbolPts != NULL) { Blt_Free(linePtr->symbolPts); } if (linePtr->symbolToData != NULL) { Blt_Free(linePtr->symbolToData); } if (linePtr->strips != NULL) { Blt_Free(linePtr->strips); } if (linePtr->stripToData != NULL) { Blt_Free(linePtr->stripToData); } if (linePtr->activePts != NULL) { Blt_Free(linePtr->activePts); } if (linePtr->activeToData != NULL) { Blt_Free(linePtr->activeToData); } if (linePtr->xErrorBars != NULL) { Blt_Free(linePtr->xErrorBars); } if (linePtr->xErrorToData != NULL) { Blt_Free(linePtr->xErrorToData); } if (linePtr->yErrorBars != NULL) { Blt_Free(linePtr->yErrorBars); } if (linePtr->yErrorToData != NULL) { Blt_Free(linePtr->yErrorToData); } linePtr->xErrorBars = linePtr->yErrorBars = linePtr->strips = NULL; linePtr->symbolPts = linePtr->activePts = NULL; linePtr->stripToData = linePtr->symbolToData = linePtr->xErrorToData = linePtr->yErrorToData = linePtr->activeToData = NULL; linePtr->nActivePts = linePtr->nSymbolPts = linePtr->nStrips = linePtr->xErrorBarCnt = linePtr->yErrorBarCnt = 0; } /* *---------------------------------------------------------------------- * * MapLine -- * * Calculates the actual window coordinates of the line element. * The window coordinates are saved in an allocated point array. * * Results: * None. * * Side effects: * Memory is (re)allocated for the point array. * *---------------------------------------------------------------------- */ static void MapLine(graphPtr, elemPtr) Graph *graphPtr; /* Graph widget record */ Element *elemPtr; /* Element component record */ { Line *linePtr = (Line *)elemPtr; MapInfo mapInfo; int size, nPoints; PenStyle **dataToStyle; Blt_ChainLink *linkPtr; LinePenStyle *stylePtr; ResetLine(linePtr); nPoints = NumberOfPoints(linePtr); if (nPoints < 1) { return; /* No data points */ } GetScreenPoints(graphPtr, linePtr, &mapInfo); MapSymbols(graphPtr, linePtr, &mapInfo); if ((linePtr->flags & ACTIVE_PENDING) && (linePtr->nActiveIndices > 0)) { MapActiveSymbols(graphPtr, linePtr); } /* * Map connecting line segments if they are to be displayed. */ if ((nPoints > 1) && ((graphPtr->classUid == bltStripElementUid) || (linePtr->builtinPen.traceWidth > 0))) { linePtr->smooth = linePtr->reqSmooth; /* * Do smoothing if necessary. This can extend the coordinate array, * so both mapInfo.points and mapInfo.nPoints may change. */ switch (linePtr->smooth) { case PEN_SMOOTH_STEP: GenerateSteps(&mapInfo); break; case PEN_SMOOTH_NATURAL: case PEN_SMOOTH_QUADRATIC: if (mapInfo.nScreenPts < 3) { /* Can't interpolate with less than three points. */ linePtr->smooth = PEN_SMOOTH_NONE; } else { GenerateSpline(graphPtr, linePtr, &mapInfo); } break; case PEN_SMOOTH_CATROM: if (mapInfo.nScreenPts < 3) { /* Can't interpolate with less than three points. */ linePtr->smooth = PEN_SMOOTH_NONE; } else { GenerateParametricSpline(graphPtr, linePtr, &mapInfo); } break; default: break; } if (linePtr->rTolerance > 0.0) { ReducePoints(&mapInfo, linePtr->rTolerance); } if ((linePtr->fillTile != NULL) || (linePtr->fillStipple != None)) { MapFillArea(graphPtr, linePtr, &mapInfo); } if (graphPtr->classUid == bltStripElementUid) { MapStrip(graphPtr, linePtr, &mapInfo); } else { MapTraces(graphPtr, linePtr, &mapInfo); } } Blt_Free(mapInfo.screenPts); Blt_Free(mapInfo.indices); /* Set the symbol size of all the pen styles. */ for (linkPtr = Blt_ChainFirstLink(linePtr->palette); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { stylePtr = Blt_ChainGetValue(linkPtr); size = ScaleSymbol(elemPtr, stylePtr->penPtr->symbol.size); stylePtr->symbolSize = size; stylePtr->errorBarCapWidth = (stylePtr->penPtr->errorBarCapWidth > 0) ? stylePtr->penPtr->errorBarCapWidth : (int)(size * 0.6666666); stylePtr->errorBarCapWidth /= 2; } dataToStyle = Blt_StyleMap((Element *)linePtr); if (((linePtr->yHigh.nValues > 0) && (linePtr->yLow.nValues > 0)) || ((linePtr->xHigh.nValues > 0) && (linePtr->xLow.nValues > 0)) || (linePtr->xError.nValues > 0) || (linePtr->yError.nValues > 0)) { Blt_MapErrorBars(graphPtr, (Element *)linePtr, dataToStyle); } MergePens(linePtr, dataToStyle); Blt_Free(dataToStyle); } static double DistanceToLine(x, y, p, q, t) int x, y; /* Sample X-Y coordinate. */ Point2D *p, *q; /* End points of the line segment. */ Point2D *t; /* (out) Point on line segment. */ { double right, left, top, bottom; *t = Blt_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)); } static double DistanceToX(x, y, p, q, t) int x, y; /* Search X-Y coordinate. */ Point2D *p, *q; /* End points of the line segment. */ Point2D *t; /* (out) Point on line segment. */ { double dx, dy; double dist; 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, dist = d1; } else { t->y = q->y, dist = d2; } } else if (FABS(dy) < DBL_EPSILON) { /* Horizontal line. */ t->y = p->y, dist = p->y - y; } else { double m, b; m = dy / dx; b = p->y - (m * p->x); t->y = (x * m) + b; dist = y - t->y; } return FABS(dist); } static double DistanceToY(x, y, p, q, t) int x, y; /* Search X-Y coordinate. */ Point2D *p, *q; /* End points of the line segment. */ Point2D *t; /* (out) Point on line segment. */ { double dx, dy; double dist; 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, dist = d1; } else { t->x = q->x, dist = d2; } } else if (FABS(dx) < DBL_EPSILON) { /* Vertical line. */ t->x = p->x, dist = p->x - x; } else { double m, b; m = dy / dx; b = p->y - (m * p->x); t->x = (y - b) / m; dist = x - t->x; } return FABS(dist); } /* *---------------------------------------------------------------------- * * ClosestTrace -- * * Find the line segment closest to the given window coordinate * in the element. * * Results: * If a new minimum distance is found, the information regarding * it is returned via searchPtr. * *---------------------------------------------------------------------- */ static int ClosestTrace(graphPtr, linePtr, searchPtr, distProc) Graph *graphPtr; /* Graph widget record */ Line *linePtr; /* Line element record */ ClosestSearch *searchPtr; /* Info about closest point in element */ DistanceProc *distProc; { Blt_ChainLink *linkPtr; Point2D closest, b; Trace *tracePtr; double dist, minDist; register Point2D *pointPtr, *endPtr; int i; i = -1; /* Suppress compiler warning. */ minDist = searchPtr->dist; for (linkPtr = Blt_ChainFirstLink(linePtr->traces); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tracePtr = Blt_ChainGetValue(linkPtr); for (pointPtr = tracePtr->screenPts, endPtr = tracePtr->screenPts + (tracePtr->nScreenPts - 1); pointPtr < endPtr; pointPtr++) { dist = (*distProc)(searchPtr->x, searchPtr->y, pointPtr, pointPtr + 1, &b); if (dist < minDist) { closest = b; i = tracePtr->symbolToData[pointPtr - tracePtr->screenPts]; minDist = dist; } } } if (minDist < searchPtr->dist) { searchPtr->dist = minDist; searchPtr->elemPtr = (Element *)linePtr; searchPtr->index = i; searchPtr->point = Blt_InvMap2D(graphPtr, closest.x, closest.y, &(linePtr->axes)); return TRUE; } return FALSE; } /* *---------------------------------------------------------------------- * * ClosestStrip -- * * Find the line segment closest to the given window coordinate * in the element. * * Results: * If a new minimum distance is found, the information regarding * it is returned via searchPtr. * *---------------------------------------------------------------------- */ static int ClosestStrip(graphPtr, linePtr, searchPtr, distProc) Graph *graphPtr; /* Graph widget record */ Line *linePtr; /* Line element record */ ClosestSearch *searchPtr; /* Info about closest point in element */ DistanceProc *distProc; { Point2D closest, b; double dist, minDist; int count; int i; register Segment2D *s; i = 0; minDist = searchPtr->dist; s = linePtr->strips; for (count = 0; count < linePtr->nStrips; count++, s++) { dist = (*distProc)(searchPtr->x, searchPtr->y, &(s->p), &(s->q), &b); if (dist < minDist) { closest = b; i = linePtr->stripToData[count]; minDist = dist; } } if (minDist < searchPtr->dist) { searchPtr->dist = minDist; searchPtr->elemPtr = (Element *)linePtr; searchPtr->index = i; searchPtr->point = Blt_InvMap2D(graphPtr, closest.x, closest.y, &(linePtr->axes)); return TRUE; } return FALSE; } /* *---------------------------------------------------------------------- * * ClosestPoint -- * * Find the element whose data point is closest to the given screen * coordinate. * * Results: * If a new minimum distance is found, the information regarding * it is returned via searchPtr. * *---------------------------------------------------------------------- */ static void ClosestPoint(linePtr, searchPtr) Line *linePtr; /* Line element that we are looking at */ ClosestSearch *searchPtr; /* Assorted information related to searching * for the closest point */ { double dist, minDist; double dx, dy; int count, i; register Point2D *pointPtr; minDist = searchPtr->dist; i = 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. */ pointPtr = linePtr->symbolPts; for (count = 0; count < linePtr->nSymbolPts; count++, pointPtr++) { dx = (double)(searchPtr->x - pointPtr->x); dy = (double)(searchPtr->y - pointPtr->y); if (searchPtr->along == SEARCH_BOTH) { dist = hypot(dx, dy); } else if (searchPtr->along == SEARCH_X) { dist = dx; } else if (searchPtr->along == SEARCH_Y) { dist = dy; } else { /* This can't happen */ continue; } if (dist < minDist) { i = linePtr->symbolToData[count]; minDist = dist; } } if (minDist < searchPtr->dist) { searchPtr->elemPtr = (Element *)linePtr; searchPtr->dist = minDist; searchPtr->index = i; searchPtr->point.x = linePtr->x.valueArr[i]; searchPtr->point.y = linePtr->y.valueArr[i]; } } /* *---------------------------------------------------------------------- * * GetLineExtents -- * * Retrieves the range of the line element * * Results: * Returns the number of data points in the element. * *---------------------------------------------------------------------- */ static void GetLineExtents(elemPtr, extsPtr) Element *elemPtr; Extents2D *extsPtr; { int nPoints; extsPtr->top = extsPtr->left = DBL_MAX; extsPtr->bottom = extsPtr->right = -DBL_MAX; nPoints = NumberOfPoints(elemPtr); if (nPoints < 1) { return; } extsPtr->right = elemPtr->x.max; if ((elemPtr->x.min <= 0.0) && (elemPtr->axes.x->logScale)) { extsPtr->left = Blt_FindElemVectorMinimum(&elemPtr->x, DBL_MIN); } else { extsPtr->left = elemPtr->x.min; } extsPtr->bottom = elemPtr->y.max; if ((elemPtr->y.min <= 0.0) && (elemPtr->axes.y->logScale)) { extsPtr->top = Blt_FindElemVectorMinimum(&elemPtr->y, DBL_MIN); } else { extsPtr->top = elemPtr->y.min; } /* Correct the data limits for error bars */ if (elemPtr->xError.nValues > 0) { register int i; double x; nPoints = MIN(elemPtr->xError.nValues, nPoints); for (i = 0; i < nPoints; i++) { x = elemPtr->x.valueArr[i] + elemPtr->xError.valueArr[i]; if (x > extsPtr->right) { extsPtr->right = x; } x = elemPtr->x.valueArr[i] - elemPtr->xError.valueArr[i]; if (elemPtr->axes.x->logScale) { if (x < 0.0) { x = -x; /* Mirror negative values, instead * of ignoring them. */ } if ((x > DBL_MIN) && (x < extsPtr->left)) { extsPtr->left = x; } } else if (x < extsPtr->left) { extsPtr->left = x; } } } else { if ((elemPtr->xHigh.nValues > 0) && (elemPtr->xHigh.max > extsPtr->right)) { extsPtr->right = elemPtr->xHigh.max; } if (elemPtr->xLow.nValues > 0) { double left; if ((elemPtr->xLow.min <= 0.0) && (elemPtr->axes.x->logScale)) { left = Blt_FindElemVectorMinimum(&elemPtr->xLow, DBL_MIN); } else { left = elemPtr->xLow.min; } if (left < extsPtr->left) { extsPtr->left = left; } } } if (elemPtr->yError.nValues > 0) { register int i; double y; nPoints = MIN(elemPtr->yError.nValues, nPoints); for (i = 0; i < nPoints; i++) { y = elemPtr->y.valueArr[i] + elemPtr->yError.valueArr[i]; if (y > extsPtr->bottom) { extsPtr->bottom = y; } y = elemPtr->y.valueArr[i] - elemPtr->yError.valueArr[i]; if (elemPtr->axes.y->logScale) { if (y < 0.0) { y = -y; /* Mirror negative values, instead * of ignoring them. */ } if ((y > DBL_MIN) && (y < extsPtr->left)) { extsPtr->top = y; } } else if (y < extsPtr->top) { extsPtr->top = y; } } } else { if ((elemPtr->yHigh.nValues > 0) && (elemPtr->yHigh.max > extsPtr->bottom)) { extsPtr->bottom = elemPtr->yHigh.max; } if (elemPtr->yLow.nValues > 0) { double top; if ((elemPtr->yLow.min <= 0.0) && (elemPtr->axes.y->logScale)) { top = Blt_FindElemVectorMinimum(&elemPtr->yLow, DBL_MIN); } else { top = elemPtr->yLow.min; } if (top < extsPtr->top) { extsPtr->top = top; } } } } /* *---------------------------------------------------------------------- * * TileChangedProc * * Rebuilds the designated GC with the new tile pixmap. * * Results: * None. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static void TileChangedProc(clientData, tile) ClientData clientData; Blt_Tile tile; /* Not used. */ { Line *linePtr = clientData; Graph *graphPtr; graphPtr = linePtr->graphPtr; if (graphPtr->tkwin != NULL) { graphPtr->flags |= REDRAW_WORLD; Blt_EventuallyRedrawGraph(graphPtr); } } /* *---------------------------------------------------------------------- * * ConfigureLine -- * * Sets up the appropriate configuration parameters in the GC. * It is assumed the parameters have been previously set by * a call to Tk_ConfigureWidget. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then interp->result contains an error message. * * Side effects: * Configuration information such as line width, line style, color * etc. get set in a new GC. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ConfigureLine(graphPtr, elemPtr) Graph *graphPtr; Element *elemPtr; { Line *linePtr = (Line *)elemPtr; unsigned long gcMask; XGCValues gcValues; GC newGC; Blt_ChainLink *linkPtr; if (ConfigurePen(graphPtr, (Pen *)&(linePtr->builtinPen)) != TCL_OK) { return TCL_ERROR; } /* * Point to the static normal/active pens if no external pens have * been selected. */ if (linePtr->normalPenPtr == NULL) { linePtr->normalPenPtr = &(linePtr->builtinPen); } linkPtr = Blt_ChainFirstLink(linePtr->palette); if (linkPtr != NULL) { LinePenStyle *stylePtr; stylePtr = Blt_ChainGetValue(linkPtr); stylePtr->penPtr = linePtr->normalPenPtr; } if (linePtr->fillTile != NULL) { Blt_SetTileChangedProc(linePtr->fillTile, TileChangedProc, linePtr); } /* * Set the outline GC for this pen: GCForeground is outline color. * GCBackground is the fill color (only used for bitmap symbols). */ gcMask = 0; if (linePtr->fillFgColor != NULL) { gcMask |= GCForeground; gcValues.foreground = linePtr->fillFgColor->pixel; } if (linePtr->fillBgColor != NULL) { gcMask |= GCBackground; gcValues.background = linePtr->fillBgColor->pixel; } if ((linePtr->fillStipple != None) && (linePtr->fillStipple != PATTERN_SOLID)) { gcMask |= (GCStipple | GCFillStyle); gcValues.stipple = linePtr->fillStipple; gcValues.fill_style = (linePtr->fillBgColor == NULL) ? FillStippled : FillOpaqueStippled; } newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues); if (linePtr->fillGC != NULL) { Tk_FreeGC(graphPtr->display, linePtr->fillGC); } linePtr->fillGC = newGC; if (Blt_ConfigModified(linePtr->configSpecs, "-scalesymbols", (char *)NULL)) { linePtr->flags |= (MAP_ITEM | SCALE_SYMBOL); } if (Blt_ConfigModified(linePtr->configSpecs, "-pixels", "-trace", "-*data", "-smooth", "-map*", "-label", "-hide", "-x", "-y", "-areapattern", (char *)NULL)) { linePtr->flags |= MAP_ITEM; } return TCL_OK; } /* *---------------------------------------------------------------------- * * ClosestLine -- * * Find the closest point or line segment (if interpolated) to * the given window coordinate in the line element. * * Results: * Returns the distance of the closest point among other * information. * *---------------------------------------------------------------------- */ static void ClosestLine(graphPtr, elemPtr, searchPtr) Graph *graphPtr; /* Graph widget record */ Element *elemPtr; /* Element to examine */ ClosestSearch *searchPtr; /* Info about closest point in element */ { Line *linePtr = (Line *)elemPtr; int mode; mode = searchPtr->mode; if (mode == SEARCH_AUTO) { LinePen *penPtr = linePtr->normalPenPtr; mode = SEARCH_POINTS; if ((NumberOfPoints(linePtr) > 1) && (penPtr->traceWidth > 0)) { mode = SEARCH_TRACES; } } if (mode == SEARCH_POINTS) { ClosestPoint(linePtr, searchPtr); } else { DistanceProc *distProc; int found; if (searchPtr->along == SEARCH_X) { distProc = DistanceToX; } else if (searchPtr->along == SEARCH_Y) { distProc = DistanceToY; } else { distProc = DistanceToLine; } if (elemPtr->classUid == bltStripElementUid) { found = ClosestStrip(graphPtr, linePtr, searchPtr, distProc); } else { found = ClosestTrace(graphPtr, linePtr, searchPtr, distProc); } if ((!found) && (searchPtr->along != SEARCH_BOTH)) { ClosestPoint(linePtr, searchPtr); } } } /* * XDrawLines() points: XMaxRequestSize(dpy) - 3 * XFillPolygon() points: XMaxRequestSize(dpy) - 4 * XDrawSegments() segments: (XMaxRequestSize(dpy) - 3) / 2 * XDrawRectangles() rectangles: (XMaxRequestSize(dpy) - 3) / 2 * XFillRectangles() rectangles: (XMaxRequestSize(dpy) - 3) / 2 * XDrawArcs() or XFillArcs() arcs: (XMaxRequestSize(dpy) - 3) / 3 */ #define MAX_DRAWLINES(d) Blt_MaxRequestSize(d, sizeof(XPoint)) #define MAX_DRAWPOLYGON(d) Blt_MaxRequestSize(d, sizeof(XPoint)) #define MAX_DRAWSEGMENTS(d) Blt_MaxRequestSize(d, sizeof(XSegment)) #define MAX_DRAWRECTANGLES(d) Blt_MaxRequestSize(d, sizeof(XRectangle)) #define MAX_DRAWARCS(d) Blt_MaxRequestSize(d, sizeof(XArc)) #ifdef WIN32 static void DrawCircles( Display *display, Drawable drawable, Line *linePtr, LinePen *penPtr, int nSymbolPts, Point2D *symbolPts, int radius) { HBRUSH brush, oldBrush; HPEN pen, oldPen; HDC dc; TkWinDCState state; register Point2D *pointPtr, *endPtr; if (drawable == None) { return; /* Huh? */ } if ((penPtr->symbol.fillGC == NULL) && (penPtr->symbol.outlineWidth == 0)) { return; } dc = TkWinGetDrawableDC(display, drawable, &state); /* SetROP2(dc, tkpWinRopModes[penPtr->symbol.fillGC->function]); */ if (penPtr->symbol.fillGC != NULL) { brush = CreateSolidBrush(penPtr->symbol.fillGC->foreground); } else { brush = GetStockBrush(NULL_BRUSH); } if (penPtr->symbol.outlineWidth > 0) { pen = Blt_GCToPen(dc, penPtr->symbol.outlineGC); } else { pen = GetStockPen(NULL_PEN); } oldPen = SelectPen(dc, pen); oldBrush = SelectBrush(dc, brush); for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts; pointPtr < endPtr; pointPtr++) { Ellipse(dc, (int)pointPtr->x - radius, (int)pointPtr->y - radius, (int)pointPtr->x + radius + 1, (int)pointPtr->y + radius + 1); } DeleteBrush(SelectBrush(dc, oldBrush)); DeletePen(SelectPen(dc, oldPen)); TkWinReleaseDrawableDC(drawable, dc, &state); } #else static void DrawCircles(display, drawable, linePtr, penPtr, nSymbolPts, symbolPts, radius) Display *display; Drawable drawable; Line *linePtr; LinePen *penPtr; int nSymbolPts; Point2D *symbolPts; int radius; { register int i; XArc *arcArr; /* Array of arcs (circle) */ register XArc *arcPtr; int reqSize, nArcs; int s; int count; register Point2D *pointPtr, *endPtr; s = radius + radius; arcArr = Blt_Malloc(nSymbolPts * sizeof(XArc)); arcPtr = arcArr; if (linePtr->symbolInterval > 0) { count = 0; for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts; pointPtr < endPtr; pointPtr++) { if (DRAW_SYMBOL(linePtr)) { arcPtr->x = (short int)pointPtr->x - radius; arcPtr->y = (short int)pointPtr->y - radius; arcPtr->width = arcPtr->height = (unsigned short)s; arcPtr->angle1 = 0; arcPtr->angle2 = 23040; arcPtr++, count++; } linePtr->symbolCounter++; } } else { count = nSymbolPts; for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts; pointPtr < endPtr; pointPtr++) { arcPtr->x = (short int)pointPtr->x - radius; arcPtr->y = (short int)pointPtr->y - radius; arcPtr->width = arcPtr->height = (unsigned short)s; arcPtr->angle1 = 0; arcPtr->angle2 = 23040; arcPtr++; } } reqSize = MAX_DRAWARCS(display); for (i = 0; i < count; i += reqSize) { nArcs = ((i + reqSize) > count) ? (count - i) : reqSize; if (penPtr->symbol.fillGC != NULL) { XFillArcs(display, drawable, penPtr->symbol.fillGC, arcArr + i, nArcs); } if (penPtr->symbol.outlineWidth > 0) { XDrawArcs(display, drawable, penPtr->symbol.outlineGC, arcArr + i, nArcs); } } Blt_Free(arcArr); } #endif static void DrawSquares(display, drawable, linePtr, penPtr, nSymbolPts, symbolPts, r) Display *display; Drawable drawable; Line *linePtr; LinePen *penPtr; int nSymbolPts; register Point2D *symbolPts; int r; { XRectangle *rectArr; register Point2D *pointPtr, *endPtr; register XRectangle *rectPtr; int reqSize, nRects; int s; register int i; int count; s = r + r; rectArr = Blt_Malloc(nSymbolPts * sizeof(XRectangle)); rectPtr = rectArr; if (linePtr->symbolInterval > 0) { count = 0; for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts; pointPtr < endPtr; pointPtr++) { if (DRAW_SYMBOL(linePtr)) { rectPtr->x = (short int)(pointPtr->x - r); rectPtr->y = (short int)(pointPtr->y - r); rectPtr->width = rectPtr->height = (unsigned short)s; rectPtr++, count++; } linePtr->symbolCounter++; } } else { count = nSymbolPts; for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts; pointPtr < endPtr; pointPtr++) { rectPtr->x = (short int)(pointPtr->x - r); rectPtr->y = (short int)(pointPtr->y - r); rectPtr->width = rectPtr->height = (unsigned short)s; rectPtr++; } } reqSize = MAX_DRAWRECTANGLES(display); for (i = 0; i < count; i += reqSize) { nRects = ((i + reqSize) > count) ? (count - i) : reqSize; if (penPtr->symbol.fillGC != NULL) { XFillRectangles(display, drawable, penPtr->symbol.fillGC, rectArr + i, nRects); } if (penPtr->symbol.outlineWidth > 0) { XDrawRectangles(display, drawable, penPtr->symbol.outlineGC, rectArr + i, nRects); } } Blt_Free(rectArr); } /* * ----------------------------------------------------------------- * * DrawSymbols -- * * Draw the symbols centered at the each given x,y coordinate * in the array of points. * * Results: * None. * * Side Effects: * Draws a symbol at each coordinate given. If active, * only those coordinates which are currently active are * drawn. * * ----------------------------------------------------------------- */ static void DrawSymbols(graphPtr, drawable, linePtr, penPtr, size, nSymbolPts, symbolPts) Graph *graphPtr; /* Graph widget record */ Drawable drawable; /* Pixmap or window to draw into */ Line *linePtr; LinePen *penPtr; int size; /* Size of element */ int nSymbolPts; /* Number of coordinates in array */ Point2D *symbolPts; /* Array of x,y coordinates for line */ { XPoint pattern[13]; /* Template for polygon symbols */ int r1, r2; register int i, n; int count; register Point2D *pointPtr, *endPtr; #define SQRT_PI 1.77245385090552 #define S_RATIO 0.886226925452758 if (size < 3) { if (penPtr->symbol.fillGC != NULL) { XPoint *points; points = Blt_Malloc(nSymbolPts * sizeof(XPoint)); count = 0; for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts; pointPtr < endPtr; pointPtr++) { points[count].x = (short int)pointPtr->x; points[count].y = (short int)pointPtr->y; count++; } XDrawPoints(graphPtr->display, drawable, penPtr->symbol.fillGC, points, nSymbolPts, CoordModeOrigin); Blt_Free(points); } return; } r1 = (int)ceil(size * 0.5); r2 = (int)ceil(size * S_RATIO * 0.5); switch (penPtr->symbol.type) { case SYMBOL_NONE: break; case SYMBOL_SQUARE: DrawSquares(graphPtr->display, drawable, linePtr, penPtr, nSymbolPts, symbolPts, r2); break; case SYMBOL_CIRCLE: DrawCircles(graphPtr->display, drawable, linePtr, penPtr, nSymbolPts, symbolPts, r1); break; case SYMBOL_SPLUS: case SYMBOL_SCROSS: { XSegment *segArr; /* Array of line segments (splus, scross) */ register XSegment *segPtr; int reqSize, nSegs, chunk; if (penPtr->symbol.type == SYMBOL_SCROSS) { r2 = Round(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; } segArr = Blt_Malloc(nSymbolPts * 2 * sizeof(XSegment)); segPtr = segArr; if (linePtr->symbolInterval > 0) { count = 0; for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts; pointPtr < endPtr; pointPtr++) { if (DRAW_SYMBOL(linePtr)) { segPtr->x1 = pattern[0].x + (short int)pointPtr->x; segPtr->y1 = pattern[0].y + (short int)pointPtr->y; segPtr->x2 = pattern[1].x + (short int)pointPtr->x; segPtr->y2 = pattern[1].y + (short int)pointPtr->y; segPtr++; segPtr->x1 = pattern[2].x + (short int)pointPtr->x; segPtr->y1 = pattern[2].y + (short int)pointPtr->y; segPtr->x2 = pattern[3].x + (short int)pointPtr->x; segPtr->y2 = pattern[3].y + (short int)pointPtr->y; segPtr++; count++; } linePtr->symbolCounter++; } } else { count = nSymbolPts; for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts; pointPtr < endPtr; pointPtr++) { segPtr->x1 = pattern[0].x + (short int)pointPtr->x; segPtr->y1 = pattern[0].y + (short int)pointPtr->y; segPtr->x2 = pattern[1].x + (short int)pointPtr->x; segPtr->y2 = pattern[1].y + (short int)pointPtr->y; segPtr++; segPtr->x1 = pattern[2].x + (short int)pointPtr->x; segPtr->y1 = pattern[2].y + (short int)pointPtr->y; segPtr->x2 = pattern[3].x + (short int)pointPtr->x; segPtr->y2 = pattern[3].y + (short int)pointPtr->y; segPtr++; } } nSegs = count * 2; /* Always draw skinny symbols regardless of the outline width */ reqSize = MAX_DRAWSEGMENTS(graphPtr->display); for (i = 0; i < nSegs; i += reqSize) { chunk = ((i + reqSize) > nSegs) ? (nSegs - i) : reqSize; XDrawSegments(graphPtr->display, drawable, penPtr->symbol.outlineGC, segArr + i, chunk); } Blt_Free(segArr); } break; case SYMBOL_PLUS: case SYMBOL_CROSS: { XPoint *polygon; register XPoint *p; int d; /* Small delta for cross/plus thickness */ d = (r2 / 3); /* * * 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 */ 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 (penPtr->symbol.type == SYMBOL_CROSS) { double dx, dy; /* For the cross symbol, rotate the points by 45 degrees. */ for (n = 0; n < 12; n++) { dx = (double)pattern[n].x * M_SQRT1_2; dy = (double)pattern[n].y * M_SQRT1_2; pattern[n].x = Round(dx - dy); pattern[n].y = Round(dx + dy); } pattern[12] = pattern[0]; } polygon = Blt_Malloc(nSymbolPts * 13 * sizeof(XPoint)); p = polygon; if (linePtr->symbolInterval > 0) { count = 0; for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts; pointPtr < endPtr; pointPtr++) { if (DRAW_SYMBOL(linePtr)) { for (n = 0; n < 13; n++) { p->x = pattern[n].x + (short int)pointPtr->x; p->y = pattern[n].y + (short int)pointPtr->y; p++; } count++; } linePtr->symbolCounter++; } } else { count = nSymbolPts; for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts; pointPtr < endPtr; pointPtr++) { for (n = 0; n < 13; n++) { p->x = pattern[n].x + (short int)pointPtr->x; p->y = pattern[n].y + (short int)pointPtr->y; p++; } } } if (penPtr->symbol.fillGC != NULL) { for (p = polygon, i = 0; i < count; i++, p += 13) { XFillPolygon(graphPtr->display, drawable, penPtr->symbol.fillGC, p, 13, Complex, CoordModeOrigin); } } if (penPtr->symbol.outlineWidth > 0) { for (p = polygon, i = 0; i < count; i++, p += 13) { XDrawLines(graphPtr->display, drawable, penPtr->symbol.outlineGC, p, 13, CoordModeOrigin); } } Blt_Free(polygon); } break; case SYMBOL_DIAMOND: { XPoint *polygon; register XPoint *p; /* * * 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. * */ 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]; polygon = Blt_Malloc(nSymbolPts * 5 * sizeof(XPoint)); p = polygon; if (linePtr->symbolInterval > 0) { count = 0; for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts; pointPtr < endPtr; pointPtr++) { if (DRAW_SYMBOL(linePtr)) { for (n = 0; n < 5; n++, p++) { p->x = pattern[n].x + (short int)pointPtr->x; p->y = pattern[n].y + (short int)pointPtr->y; } count++; } linePtr->symbolCounter++; } } else { count = nSymbolPts; for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts; pointPtr < endPtr; pointPtr++) { for (n = 0; n < 5; n++, p++) { p->x = pattern[n].x + (short int)pointPtr->x; p->y = pattern[n].y + (short int)pointPtr->y; } } } if (penPtr->symbol.fillGC != NULL) { for (p = polygon, i = 0; i < count; i++, p += 5) { XFillPolygon(graphPtr->display, drawable, penPtr->symbol.fillGC, p, 5, Convex, CoordModeOrigin); } } if (penPtr->symbol.outlineWidth > 0) { for (p = polygon, i = 0; i < count; i++, p += 5) { XDrawLines(graphPtr->display, drawable, penPtr->symbol.outlineGC, p, 5, CoordModeOrigin); } } Blt_Free(polygon); } break; case SYMBOL_TRIANGLE: case SYMBOL_ARROW: { XPoint *polygon; register XPoint *p; double b; int b2, h1, h2; #define H_RATIO 1.1663402261671607 #define B_RATIO 1.3467736870885982 #define TAN30 0.57735026918962573 #define COS30 0.86602540378443871 b = Round(size * B_RATIO * 0.7); b2 = Round(b * 0.5); h2 = Round(TAN30 * b2); h1 = Round(b2 / 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. * */ if (penPtr->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; } polygon = Blt_Malloc(nSymbolPts * 4 * sizeof(XPoint)); p = polygon; if (linePtr->symbolInterval > 0) { count = 0; for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts; pointPtr < endPtr; pointPtr++) { if (DRAW_SYMBOL(linePtr)) { for (n = 0; n < 4; n++) { p->x = pattern[n].x + (short int)pointPtr->x; p->y = pattern[n].y + (short int)pointPtr->y; p++; } count++; } linePtr->symbolCounter++; } } else { count = nSymbolPts; for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts; pointPtr < endPtr; pointPtr++) { for (n = 0; n < 4; n++) { p->x = pattern[n].x + (short int)pointPtr->x; p->y = pattern[n].y + (short int)pointPtr->y; p++; } } } if (penPtr->symbol.fillGC != NULL) { for (p = polygon, i = 0; i < count; i++, p += 4) { XFillPolygon(graphPtr->display, drawable, penPtr->symbol.fillGC, p, 4, Convex, CoordModeOrigin); } } if (penPtr->symbol.outlineWidth > 0) { for (p = polygon, i = 0; i < count; i++, p += 4) { XDrawLines(graphPtr->display, drawable, penPtr->symbol.outlineGC, p, 4, CoordModeOrigin); } } Blt_Free(polygon); } break; case SYMBOL_BITMAP: { Pixmap bitmap, mask; int width, height, bmWidth, bmHeight; double scale, sx, sy; int dx, dy; register int x, y; Tk_SizeOfBitmap(graphPtr->display, penPtr->symbol.bitmap, &width, &height); mask = None; /* * Compute the size of the scaled bitmap. Stretch the * bitmap to fit a nxn bounding box. */ sx = (double)size / (double)width; sy = (double)size / (double)height; scale = MIN(sx, sy); bmWidth = (int)(width * scale); bmHeight = (int)(height * scale); XSetClipMask(graphPtr->display, penPtr->symbol.outlineGC, None); if (penPtr->symbol.mask != None) { mask = Blt_ScaleBitmap(graphPtr->tkwin, penPtr->symbol.mask, width, height, bmWidth, bmHeight); XSetClipMask(graphPtr->display, penPtr->symbol.outlineGC, mask); } bitmap = Blt_ScaleBitmap(graphPtr->tkwin, penPtr->symbol.bitmap, width, height, bmWidth, bmHeight); if (penPtr->symbol.fillGC == NULL) { XSetClipMask(graphPtr->display, penPtr->symbol.outlineGC, bitmap); } dx = bmWidth / 2; dy = bmHeight / 2; if (linePtr->symbolInterval > 0) { for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts; pointPtr < endPtr; pointPtr++) { if (DRAW_SYMBOL(linePtr)) { x = (int)pointPtr->x - dx; y = (int)pointPtr->y - dy; if ((penPtr->symbol.fillGC == NULL) || (mask != None)) { XSetClipOrigin(graphPtr->display, penPtr->symbol.outlineGC, x, y); } XCopyPlane(graphPtr->display, bitmap, drawable, penPtr->symbol.outlineGC, 0, 0, bmWidth, bmHeight, x, y, 1); } linePtr->symbolCounter++; } } else { for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts; pointPtr < endPtr; pointPtr++) { x = (int)pointPtr->x - dx; y = (int)pointPtr->y - dy; if ((penPtr->symbol.fillGC == NULL) || (mask != None)) { XSetClipOrigin(graphPtr->display, penPtr->symbol.outlineGC, x, y); } XCopyPlane(graphPtr->display, bitmap, drawable, penPtr->symbol.outlineGC, 0, 0, bmWidth, bmHeight, x, y, 1); } } Tk_FreePixmap(graphPtr->display, bitmap); if (mask != None) { Tk_FreePixmap(graphPtr->display, mask); } } break; } } /* * ----------------------------------------------------------------- * * DrawSymbol -- * * Draw the symbol centered at the each given x,y coordinate. * * Results: * None. * * Side Effects: * Draws a symbol at the coordinate given. * * ----------------------------------------------------------------- */ static void DrawSymbol(graphPtr, drawable, elemPtr, x, y, size) Graph *graphPtr; /* Graph widget record */ Drawable drawable; /* Pixmap or window to draw into */ Element *elemPtr; /* Line element information */ int x, y; /* Center position of symbol */ int size; /* Size of symbol. */ { Line *linePtr = (Line *)elemPtr; LinePen *penPtr = linePtr->normalPenPtr; if (penPtr->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 (penPtr->symbol.type != SYMBOL_NONE) { Point2D point; point.x = x, point.y = y; DrawSymbols(graphPtr, drawable, linePtr, linePtr->normalPenPtr, size, 1, &point); } } #ifdef WIN32 static void DrawTraces( Graph *graphPtr, Drawable drawable, /* Pixmap or window to draw into */ Line *linePtr, LinePen *penPtr) { Blt_ChainLink *linkPtr; HBRUSH brush, oldBrush; HDC dc; HPEN pen, oldPen; POINT *points; TkWinDCState state; Trace *tracePtr; int j; int nPoints, remaining; register POINT *p; register int count; /* * Depending if the line is wide (> 1 pixel), arbitrarily break * the line in sections of 100 points. This bit of weirdness has * to do with wide geometric pens. The longer the polyline, the * slower it draws. The trade off is that we lose dash and cap * uniformity for unbearably slow polyline draws. */ if (penPtr->traceGC->line_width > 1) { nPoints = 100; } else { nPoints = Blt_MaxRequestSize(graphPtr->display, sizeof(POINT)) - 1; } points = Blt_Malloc((nPoints + 1) * sizeof(POINT)); dc = TkWinGetDrawableDC(graphPtr->display, drawable, &state); pen = Blt_GCToPen(dc, penPtr->traceGC); oldPen = SelectPen(dc, pen); brush = CreateSolidBrush(penPtr->traceGC->foreground); oldBrush = SelectBrush(dc, brush); SetROP2(dc, tkpWinRopModes[penPtr->traceGC->function]); for (linkPtr = Blt_ChainFirstLink(linePtr->traces); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tracePtr = Blt_ChainGetValue(linkPtr); /* * If the trace has to be split into separate XDrawLines * calls, then the end point of the current trace is also the * starting point of the new split. */ /* Step 1. Convert and draw the first section of the trace. * It may contain the entire trace. */ for (p = points, count = 0; count < MIN(nPoints, tracePtr->nScreenPts); count++, p++) { p->x = (int)tracePtr->screenPts[count].x; p->y = (int)tracePtr->screenPts[count].y; } Polyline(dc, points, count); /* Step 2. Next handle any full-size chunks left. */ while ((count + nPoints) < tracePtr->nScreenPts) { /* Start with the last point of the previous trace. */ points[0].x = points[nPoints - 1].x; points[0].y = points[nPoints - 1].y; for (p = points + 1, j = 0; j < nPoints; j++, count++, p++) { p->x = (int)tracePtr->screenPts[count].x; p->y = (int)tracePtr->screenPts[count].y; } Polyline(dc, points, nPoints + 1); } /* Step 3. Convert and draw the remaining points. */ remaining = tracePtr->nScreenPts - count; if (remaining > 0) { /* Start with the last point of the previous trace. */ points[0].x = points[nPoints - 1].x; points[0].y = points[nPoints - 1].y; for (p = points + 1; count < tracePtr->nScreenPts; count++, p++) { p->x = (int)tracePtr->screenPts[count].x; p->y = (int)tracePtr->screenPts[count].y; } Polyline(dc, points, remaining + 1); } } Blt_Free(points); DeletePen(SelectPen(dc, oldPen)); DeleteBrush(SelectBrush(dc, oldBrush)); TkWinReleaseDrawableDC(drawable, dc, &state); } #else static void DrawTraces(graphPtr, drawable, linePtr, penPtr) Graph *graphPtr; Drawable drawable; /* Pixmap or window to draw into */ Line *linePtr; LinePen *penPtr; { Blt_ChainLink *linkPtr; Trace *tracePtr; XPoint *points; int j; int nPoints, remaining; register XPoint *p; register int count; nPoints = Blt_MaxRequestSize(graphPtr->display, sizeof(XPoint)) - 1; points = Blt_Malloc((nPoints + 1) * sizeof(XPoint)); for (linkPtr = Blt_ChainFirstLink(linePtr->traces); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { int n; tracePtr = Blt_ChainGetValue(linkPtr); /* * If the trace has to be split into separate XDrawLines * calls, then the end point of the current trace is also the * starting point of the new split. */ /* Step 1. Convert and draw the first section of the trace. * It may contain the entire trace. */ n = MIN(nPoints, tracePtr->nScreenPts); for (p = points, count = 0; count < n; count++, p++) { p->x = (short int)tracePtr->screenPts[count].x; p->y = (short int)tracePtr->screenPts[count].y; } XDrawLines(graphPtr->display, drawable, penPtr->traceGC, points, count, CoordModeOrigin); /* Step 2. Next handle any full-size chunks left. */ while ((count + nPoints) < tracePtr->nScreenPts) { /* Start with the last point of the previous trace. */ points[0].x = points[nPoints - 1].x; points[0].y = points[nPoints - 1].y; for (p = points + 1, j = 0; j < nPoints; j++, count++, p++) { p->x = (short int)tracePtr->screenPts[count].x; p->y = (short int)tracePtr->screenPts[count].y; } XDrawLines(graphPtr->display, drawable, penPtr->traceGC, points, nPoints + 1, CoordModeOrigin); } /* Step 3. Convert and draw the remaining points. */ remaining = tracePtr->nScreenPts - count; if (remaining > 0) { /* Start with the last point of the previous trace. */ points[0].x = points[nPoints - 1].x; points[0].y = points[nPoints - 1].y; for (p = points + 1; count < tracePtr->nScreenPts; count++, p++) { p->x = (short int)tracePtr->screenPts[count].x; p->y = (short int)tracePtr->screenPts[count].y; } XDrawLines(graphPtr->display, drawable, penPtr->traceGC, points, remaining + 1, CoordModeOrigin); } } Blt_Free(points); } #endif /* WIN32 */ static void DrawValues(graphPtr, drawable, linePtr, penPtr, nSymbolPts, symbolPts, pointToData) Graph *graphPtr; Drawable drawable; Line *linePtr; LinePen *penPtr; int nSymbolPts; Point2D *symbolPts; int *pointToData; { Point2D *pointPtr, *endPtr; int count; char string[TCL_DOUBLE_SPACE * 2 + 2]; char *fmt; double x, y; fmt = penPtr->valueFormat; if (fmt == NULL) { fmt = "%g"; } count = 0; for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts; pointPtr < endPtr; pointPtr++) { x = linePtr->x.valueArr[pointToData[count]]; y = linePtr->y.valueArr[pointToData[count]]; count++; if (penPtr->valueShow == SHOW_X) { sprintf(string, fmt, x); } else if (penPtr->valueShow == SHOW_Y) { sprintf(string, fmt, y); } else if (penPtr->valueShow == SHOW_BOTH) { sprintf(string, fmt, x); strcat(string, ","); sprintf(string + strlen(string), fmt, y); } Blt_DrawText(graphPtr->tkwin, drawable, string, &(penPtr->valueStyle), (int)pointPtr->x, (int)pointPtr->y); } } /* *---------------------------------------------------------------------- * * DrawActiveLine -- * * Draws the connected line(s) representing the element. If the * line is made up of non-line symbols and the line width * parameter has been set (linewidth > 0), the element will also * be drawn as a line (with the linewidth requested). The line * may consist of separate line segments. * * Results: * None. * * Side effects: * X drawing commands are output. * *---------------------------------------------------------------------- */ static void DrawActiveLine(graphPtr, drawable, elemPtr) Graph *graphPtr; /* Graph widget record */ Drawable drawable; /* Pixmap or window to draw into */ Element *elemPtr; /* Element to be drawn */ { Line *linePtr = (Line *)elemPtr; LinePen *penPtr = linePtr->activePenPtr; int symbolSize; if (penPtr == NULL) { return; } symbolSize = ScaleSymbol(elemPtr, linePtr->activePenPtr->symbol.size); /* * nActiveIndices * > 0 Some points are active. Uses activeArr. * < 0 All points are active. * == 0 No points are active. */ if (linePtr->nActiveIndices > 0) { if (linePtr->flags & ACTIVE_PENDING) { MapActiveSymbols(graphPtr, linePtr); } if (penPtr->symbol.type != SYMBOL_NONE) { DrawSymbols(graphPtr, drawable, linePtr, penPtr, symbolSize, linePtr->nActivePts, linePtr->activePts); } if (penPtr->valueShow != SHOW_NONE) { DrawValues(graphPtr, drawable, linePtr, penPtr, linePtr->nActivePts, linePtr->activePts, linePtr->activeToData); } } else if (linePtr->nActiveIndices < 0) { if (penPtr->traceWidth > 0) { if (linePtr->nStrips > 0) { Blt_Draw2DSegments(graphPtr->display, drawable, penPtr->traceGC, linePtr->strips, linePtr->nStrips); } else if (Blt_ChainGetLength(linePtr->traces) > 0) { DrawTraces(graphPtr, drawable, linePtr, penPtr); } } if (penPtr->symbol.type != SYMBOL_NONE) { DrawSymbols(graphPtr, drawable, linePtr, penPtr, symbolSize, linePtr->nSymbolPts, linePtr->symbolPts); } if (penPtr->valueShow != SHOW_NONE) { DrawValues(graphPtr, drawable, linePtr, penPtr, linePtr->nSymbolPts, linePtr->symbolPts, linePtr->symbolToData); } } } /* *---------------------------------------------------------------------- * * DrawNormalLine -- * * Draws the connected line(s) representing the element. If the * line is made up of non-line symbols and the line width parameter * has been set (linewidth > 0), the element will also be drawn as * a line (with the linewidth requested). The line may consist of * separate line segments. * * Results: * None. * * Side effects: * X drawing commands are output. * *---------------------------------------------------------------------- */ static void DrawNormalLine(graphPtr, drawable, elemPtr) Graph *graphPtr; /* Graph widget record */ Drawable drawable; /* Pixmap or window to draw into */ Element *elemPtr; /* Element to be drawn */ { Line *linePtr = (Line *)elemPtr; LinePen *penPtr; Blt_ChainLink *linkPtr; register LinePenStyle *stylePtr; unsigned int count; /* Fill area under the curve */ if (linePtr->fillPts != NULL) { XPoint *points; Point2D *endPtr, *pointPtr; points = Blt_Malloc(sizeof(XPoint) * linePtr->nFillPts); count = 0; for(pointPtr = linePtr->fillPts, endPtr = linePtr->fillPts + linePtr->nFillPts; pointPtr < endPtr; pointPtr++) { points[count].x = (short int)pointPtr->x; points[count].y = (short int)pointPtr->y; count++; } if (linePtr->fillTile != NULL) { Blt_SetTileOrigin(graphPtr->tkwin, linePtr->fillTile, 0, 0); Blt_TilePolygon(graphPtr->tkwin, drawable, linePtr->fillTile, points, linePtr->nFillPts); } else if (linePtr->fillStipple != None) { XFillPolygon(graphPtr->display, drawable, linePtr->fillGC, points, linePtr->nFillPts, Complex, CoordModeOrigin); } Blt_Free(points); } /* Lines: stripchart segments or graph traces. */ if (linePtr->nStrips > 0) { for (linkPtr = Blt_ChainFirstLink(linePtr->palette); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { stylePtr = Blt_ChainGetValue(linkPtr); penPtr = stylePtr->penPtr; if ((stylePtr->nStrips > 0) && (penPtr->errorBarLineWidth > 0)) { Blt_Draw2DSegments(graphPtr->display, drawable, penPtr->traceGC, stylePtr->strips, stylePtr->nStrips); } } } else if ((Blt_ChainGetLength(linePtr->traces) > 0) && (linePtr->normalPenPtr->traceWidth > 0)) { DrawTraces(graphPtr, drawable, linePtr, linePtr->normalPenPtr); } if (linePtr->reqMaxSymbols > 0) { int total; total = 0; for (linkPtr = Blt_ChainFirstLink(linePtr->palette); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { stylePtr = Blt_ChainGetValue(linkPtr); total += stylePtr->nSymbolPts; } linePtr->symbolInterval = total / linePtr->reqMaxSymbols; linePtr->symbolCounter = 0; } /* Symbols, error bars, values. */ count = 0; for (linkPtr = Blt_ChainFirstLink(linePtr->palette); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { stylePtr = Blt_ChainGetValue(linkPtr); penPtr = stylePtr->penPtr; if ((stylePtr->xErrorBarCnt > 0) && (penPtr->errorBarShow & SHOW_X)) { Blt_Draw2DSegments(graphPtr->display, drawable, penPtr->errorBarGC, stylePtr->xErrorBars, stylePtr->xErrorBarCnt); } if ((stylePtr->yErrorBarCnt > 0) && (penPtr->errorBarShow & SHOW_Y)) { Blt_Draw2DSegments(graphPtr->display, drawable, penPtr->errorBarGC, stylePtr->yErrorBars, stylePtr->yErrorBarCnt); } if ((stylePtr->nSymbolPts > 0) && (penPtr->symbol.type != SYMBOL_NONE)) { DrawSymbols(graphPtr, drawable, linePtr, penPtr, stylePtr->symbolSize, stylePtr->nSymbolPts, stylePtr->symbolPts); } if (penPtr->valueShow != SHOW_NONE) { DrawValues(graphPtr, drawable, linePtr, penPtr, stylePtr->nSymbolPts, stylePtr->symbolPts, linePtr->symbolToData + count); } count += stylePtr->nSymbolPts; } linePtr->symbolInterval = 0; } /* * ----------------------------------------------------------------- * * GetSymbolPostScriptInfo -- * * Set up the PostScript environment with the macros and * attributes needed to draw the symbols of the element. * * Results: * None. * * ----------------------------------------------------------------- */ static void GetSymbolPostScriptInfo(graphPtr, psToken, penPtr, size) Graph *graphPtr; PsToken psToken; LinePen *penPtr; int size; { XColor *outlineColor, *fillColor, *defaultColor; /* Set line and foreground attributes */ outlineColor = penPtr->symbol.outlineColor; fillColor = penPtr->symbol.fillColor; defaultColor = penPtr->traceColor; if (fillColor == COLOR_DEFAULT) { fillColor = defaultColor; } if (outlineColor == COLOR_DEFAULT) { outlineColor = defaultColor; } if (penPtr->symbol.type == SYMBOL_NONE) { Blt_LineAttributesToPostScript(psToken, defaultColor, penPtr->traceWidth + 2, &(penPtr->traceDashes), CapButt, JoinMiter); } else { Blt_LineWidthToPostScript(psToken, penPtr->symbol.outlineWidth); Blt_LineDashesToPostScript(psToken, (Blt_Dashes *)NULL); } /* * Build a PostScript procedure to draw the symbols. For bitmaps, * paint both the bitmap and its mask. Otherwise fill and stroke * the path formed already. */ Blt_AppendToPostScript(psToken, "\n/DrawSymbolProc {\n", (char *)NULL); switch (penPtr->symbol.type) { case SYMBOL_NONE: break; /* Do nothing */ case SYMBOL_BITMAP: { int width, height; double sx, sy, scale; /* * Compute how much to scale the bitmap. Don't let the * scaled bitmap exceed the bounding square for the * symbol. */ Tk_SizeOfBitmap(graphPtr->display, penPtr->symbol.bitmap, &width, &height); sx = (double)size / (double)width; sy = (double)size / (double)height; scale = MIN(sx, sy); if ((penPtr->symbol.mask != None) && (fillColor != NULL)) { Blt_AppendToPostScript(psToken, "\n % Bitmap mask is \"", Tk_NameOfBitmap(graphPtr->display, penPtr->symbol.mask), "\"\n\n ", (char *)NULL); Blt_BackgroundToPostScript(psToken, fillColor); Blt_BitmapToPostScript(psToken, graphPtr->display, penPtr->symbol.mask, scale, scale); } Blt_AppendToPostScript(psToken, "\n % Bitmap symbol is \"", Tk_NameOfBitmap(graphPtr->display, penPtr->symbol.bitmap), "\"\n\n ", (char *)NULL); Blt_ForegroundToPostScript(psToken, outlineColor); Blt_BitmapToPostScript(psToken, graphPtr->display, penPtr->symbol.bitmap, scale, scale); } break; default: if (fillColor != NULL) { Blt_AppendToPostScript(psToken, " ", (char *)NULL); Blt_BackgroundToPostScript(psToken, fillColor); Blt_AppendToPostScript(psToken, " Fill\n", (char *)NULL); } if ((outlineColor != NULL) && (penPtr->symbol.outlineWidth > 0)) { Blt_AppendToPostScript(psToken, " ", (char *)NULL); Blt_ForegroundToPostScript(psToken, outlineColor); Blt_AppendToPostScript(psToken, " stroke\n", (char *)NULL); } break; } Blt_AppendToPostScript(psToken, "} def\n\n", (char *)NULL); } /* * ----------------------------------------------------------------- * * SymbolsToPostScript -- * * Draw a symbol centered at the given x,y window coordinate * based upon the element symbol type and size. * * Results: * None. * * Problems: * Most notable is the round-off errors generated when * calculating the centered position of the symbol. * * ----------------------------------------------------------------- */ static void SymbolsToPostScript(graphPtr, psToken, penPtr, size, nSymbolPts, symbolPts) Graph *graphPtr; PsToken psToken; LinePen *penPtr; int size; int nSymbolPts; Point2D *symbolPts; { double symbolSize; register Point2D *pointPtr, *endPtr; static char *symbolMacros[] = { "Li", "Sq", "Ci", "Di", "Pl", "Cr", "Sp", "Sc", "Tr", "Ar", "Bm", (char *)NULL, }; GetSymbolPostScriptInfo(graphPtr, psToken, penPtr, size); symbolSize = (double)size; switch (penPtr->symbol.type) { case SYMBOL_SQUARE: case SYMBOL_CROSS: case SYMBOL_PLUS: case SYMBOL_SCROSS: case SYMBOL_SPLUS: symbolSize = (double)Round(size * S_RATIO); break; case SYMBOL_TRIANGLE: case SYMBOL_ARROW: symbolSize = (double)Round(size * 0.7); break; case SYMBOL_DIAMOND: symbolSize = (double)Round(size * M_SQRT1_2); break; default: break; } for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts; pointPtr < endPtr; pointPtr++) { Blt_FormatToPostScript(psToken, "%g %g %g %s\n", pointPtr->x, pointPtr->y, symbolSize, symbolMacros[penPtr->symbol.type]); } } /* * ----------------------------------------------------------------- * * SymbolToPostScript -- * * Draw the symbol centered at the each given x,y coordinate. * * Results: * None. * * Side Effects: * Draws a symbol at the coordinate given. * * ----------------------------------------------------------------- */ static void SymbolToPostScript(graphPtr, psToken, elemPtr, x, y, size) Graph *graphPtr; /* Graph widget record */ PsToken psToken; Element *elemPtr; /* Line element information */ double x, y; /* Center position of symbol */ int size; /* Size of element */ { Line *linePtr = (Line *)elemPtr; LinePen *penPtr = linePtr->normalPenPtr; if (penPtr->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. */ Blt_LineAttributesToPostScript(psToken, penPtr->traceColor, penPtr->traceWidth + 2, &(penPtr->traceDashes), CapButt, JoinMiter); Blt_FormatToPostScript(psToken, "%g %g %d Li\n", x, y, size + size); } if (penPtr->symbol.type != SYMBOL_NONE) { Point2D point; point.x = x, point.y = y; SymbolsToPostScript(graphPtr, psToken, penPtr, size, 1, &point); } } static void SetLineAttributes(psToken, penPtr) PsToken psToken; LinePen *penPtr; { /* Set the attributes of the line (color, dashes, linewidth) */ Blt_LineAttributesToPostScript(psToken, penPtr->traceColor, penPtr->traceWidth, &(penPtr->traceDashes), CapButt, JoinMiter); if ((LineIsDashed(penPtr->traceDashes)) && (penPtr->traceOffColor != NULL)) { Blt_AppendToPostScript(psToken, "/DashesProc {\n gsave\n ", (char *)NULL); Blt_BackgroundToPostScript(psToken, penPtr->traceOffColor); Blt_AppendToPostScript(psToken, " ", (char *)NULL); Blt_LineDashesToPostScript(psToken, (Blt_Dashes *)NULL); Blt_AppendToPostScript(psToken, "stroke\n grestore\n} def\n", (char *)NULL); } else { Blt_AppendToPostScript(psToken, "/DashesProc {} def\n", (char *)NULL); } } static void TracesToPostScript(psToken, linePtr, penPtr) PsToken psToken; Line *linePtr; LinePen *penPtr; { Blt_ChainLink *linkPtr; Trace *tracePtr; register Point2D *pointPtr, *endPtr; int count; SetLineAttributes(psToken, penPtr); for (linkPtr = Blt_ChainFirstLink(linePtr->traces); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tracePtr = Blt_ChainGetValue(linkPtr); if (tracePtr->nScreenPts <= 0) { continue; } #define PS_MAXPATH 1500 /* Maximum number of components in a PostScript * (level 1) path. */ pointPtr = tracePtr->screenPts; Blt_FormatToPostScript(psToken, " newpath %g %g moveto\n", pointPtr->x, pointPtr->y); pointPtr++; count = 0; for (endPtr = tracePtr->screenPts + (tracePtr->nScreenPts - 1); pointPtr < endPtr; pointPtr++) { Blt_FormatToPostScript(psToken, " %g %g lineto\n", pointPtr->x, pointPtr->y); if ((count % PS_MAXPATH) == 0) { Blt_FormatToPostScript(psToken, "DashesProc stroke\n newpath %g %g moveto\n", pointPtr->x, pointPtr->y); } count++; } Blt_FormatToPostScript(psToken, " %g %g lineto\n", pointPtr->x, pointPtr->y); Blt_AppendToPostScript(psToken, "DashesProc stroke\n", (char *)NULL); } } static void ValuesToPostScript(psToken, linePtr, penPtr, nSymbolPts, symbolPts, pointToData) PsToken psToken; Line *linePtr; LinePen *penPtr; int nSymbolPts; Point2D *symbolPts; int *pointToData; { Point2D *pointPtr, *endPtr; int count; char string[TCL_DOUBLE_SPACE * 2 + 2]; char *fmt; double x, y; fmt = penPtr->valueFormat; if (fmt == NULL) { fmt = "%g"; } count = 0; for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts; pointPtr < endPtr; pointPtr++) { x = linePtr->x.valueArr[pointToData[count]]; y = linePtr->y.valueArr[pointToData[count]]; count++; if (penPtr->valueShow == SHOW_X) { sprintf(string, fmt, x); } else if (penPtr->valueShow == SHOW_Y) { sprintf(string, fmt, y); } else if (penPtr->valueShow == SHOW_BOTH) { sprintf(string, fmt, x); strcat(string, ","); sprintf(string + strlen(string), fmt, y); } Blt_TextToPostScript(psToken, string, &(penPtr->valueStyle), pointPtr->x, pointPtr->y); } } /* *---------------------------------------------------------------------- * * ActiveLineToPostScript -- * * Generates PostScript commands to draw as "active" the points * (symbols) and or line segments (trace) representing the * element. * * Results: * None. * * Side effects: * PostScript pen width, dashes, and color settings are changed. * *---------------------------------------------------------------------- */ static void ActiveLineToPostScript(graphPtr, psToken, elemPtr) Graph *graphPtr; PsToken psToken; Element *elemPtr; { Line *linePtr = (Line *)elemPtr; LinePen *penPtr = linePtr->activePenPtr; int symbolSize; if (penPtr == NULL) { return; } symbolSize = ScaleSymbol(elemPtr, penPtr->symbol.size); if (linePtr->nActiveIndices > 0) { if (linePtr->flags & ACTIVE_PENDING) { MapActiveSymbols(graphPtr, linePtr); } if (penPtr->symbol.type != SYMBOL_NONE) { SymbolsToPostScript(graphPtr, psToken, penPtr, symbolSize, linePtr->nActivePts, linePtr->activePts); } if (penPtr->valueShow != SHOW_NONE) { ValuesToPostScript(psToken, linePtr, penPtr, linePtr->nActivePts, linePtr->activePts, linePtr->activeToData); } } else if (linePtr->nActiveIndices < 0) { if (penPtr->traceWidth > 0) { if (linePtr->nStrips > 0) { SetLineAttributes(psToken, penPtr); Blt_2DSegmentsToPostScript(psToken, linePtr->strips, linePtr->nStrips); } if (Blt_ChainGetLength(linePtr->traces) > 0) { TracesToPostScript(psToken, linePtr, (LinePen *)penPtr); } } if (penPtr->symbol.type != SYMBOL_NONE) { SymbolsToPostScript(graphPtr, psToken, penPtr, symbolSize, linePtr->nSymbolPts, linePtr->symbolPts); } if (penPtr->valueShow != SHOW_NONE) { ValuesToPostScript(psToken, linePtr, penPtr, linePtr->nSymbolPts, linePtr->symbolPts, linePtr->symbolToData); } } } /* *---------------------------------------------------------------------- * * NormalLineToPostScript -- * * Similar to the DrawLine procedure, prints PostScript related * commands to form the connected line(s) representing the element. * * Results: * None. * * Side effects: * PostScript pen width, dashes, and color settings are changed. * *---------------------------------------------------------------------- */ static void NormalLineToPostScript(graphPtr, psToken, elemPtr) Graph *graphPtr; PsToken psToken; Element *elemPtr; { Line *linePtr = (Line *)elemPtr; register LinePenStyle *stylePtr; Blt_ChainLink *linkPtr; LinePen *penPtr; unsigned int count; XColor *colorPtr; /* Draw fill area */ if (linePtr->fillPts != NULL) { /* Create a path to use for both the polygon and its outline. */ Blt_PathToPostScript(psToken, linePtr->fillPts, linePtr->nFillPts); Blt_AppendToPostScript(psToken, "closepath\n", (char *)NULL); /* If the background fill color was specified, draw the * polygon in a solid fashion with that color. */ if (linePtr->fillBgColor != NULL) { Blt_BackgroundToPostScript(psToken, linePtr->fillBgColor); Blt_AppendToPostScript(psToken, "Fill\n", (char *)NULL); } Blt_ForegroundToPostScript(psToken, linePtr->fillFgColor); if (linePtr->fillTile != NULL) { /* TBA: Transparent tiling is the hard part. */ } else if ((linePtr->fillStipple != None) && (linePtr->fillStipple != PATTERN_SOLID)) { /* Draw the stipple in the foreground color. */ Blt_StippleToPostScript(psToken, graphPtr->display, linePtr->fillStipple); } else { Blt_AppendToPostScript(psToken, "Fill\n", (char *)NULL); } } /* Draw lines */ if (linePtr->nStrips > 0) { for (linkPtr = Blt_ChainFirstLink(linePtr->palette); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { stylePtr = Blt_ChainGetValue(linkPtr); penPtr = stylePtr->penPtr; if ((stylePtr->nStrips > 0) && (penPtr->traceWidth > 0)) { SetLineAttributes(psToken, penPtr); Blt_2DSegmentsToPostScript(psToken, stylePtr->strips, stylePtr->nStrips); } } } else if ((Blt_ChainGetLength(linePtr->traces) > 0) && (linePtr->normalPenPtr->traceWidth > 0)) { TracesToPostScript(psToken, linePtr, linePtr->normalPenPtr); } /* Draw symbols, error bars, values. */ count = 0; for (linkPtr = Blt_ChainFirstLink(linePtr->palette); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { stylePtr = Blt_ChainGetValue(linkPtr); penPtr = stylePtr->penPtr; colorPtr = penPtr->errorBarColor; if (colorPtr == COLOR_DEFAULT) { colorPtr = penPtr->traceColor; } if ((stylePtr->xErrorBarCnt > 0) && (penPtr->errorBarShow & SHOW_X)) { Blt_LineAttributesToPostScript(psToken, colorPtr, penPtr->errorBarLineWidth, NULL, CapButt, JoinMiter); Blt_2DSegmentsToPostScript(psToken, stylePtr->xErrorBars, stylePtr->xErrorBarCnt); } if ((stylePtr->yErrorBarCnt > 0) && (penPtr->errorBarShow & SHOW_Y)) { Blt_LineAttributesToPostScript(psToken, colorPtr, penPtr->errorBarLineWidth, NULL, CapButt, JoinMiter); Blt_2DSegmentsToPostScript(psToken, stylePtr->yErrorBars, stylePtr->yErrorBarCnt); } if ((stylePtr->nSymbolPts > 0) && (stylePtr->penPtr->symbol.type != SYMBOL_NONE)) { SymbolsToPostScript(graphPtr, psToken, penPtr, stylePtr->symbolSize, stylePtr->nSymbolPts, stylePtr->symbolPts); } if (penPtr->valueShow != SHOW_NONE) { ValuesToPostScript(psToken, linePtr, penPtr, stylePtr->nSymbolPts, stylePtr->symbolPts, linePtr->symbolToData + count); } count += stylePtr->nSymbolPts; } } /* *---------------------------------------------------------------------- * * DestroyLine -- * * Release memory and resources allocated for the line element. * * Results: * None. * * Side effects: * Everything associated with the line element is freed up. * *---------------------------------------------------------------------- */ #define FreeVector(v) \ if ((v).clientId != NULL) { \ Blt_FreeVectorId((v).clientId); \ } else if ((v).valueArr != NULL) { \ Blt_Free((v).valueArr); \ } static void DestroyLine(graphPtr, elemPtr) Graph *graphPtr; Element *elemPtr; { Line *linePtr = (Line *)elemPtr; if (linePtr->normalPenPtr != &(linePtr->builtinPen)) { Blt_FreePen(graphPtr, (Pen *)linePtr->normalPenPtr); } DestroyPen(graphPtr, (Pen *)&(linePtr->builtinPen)); if (linePtr->activePenPtr != NULL) { Blt_FreePen(graphPtr, (Pen *)linePtr->activePenPtr); } FreeVector(linePtr->w); FreeVector(linePtr->x); FreeVector(linePtr->xHigh); FreeVector(linePtr->xLow); FreeVector(linePtr->xError); FreeVector(linePtr->y); FreeVector(linePtr->yHigh); FreeVector(linePtr->yLow); FreeVector(linePtr->yError); ResetLine(linePtr); if (linePtr->palette != NULL) { Blt_FreePalette(graphPtr, linePtr->palette); Blt_ChainDestroy(linePtr->palette); } if (linePtr->tags != NULL) { Blt_Free(linePtr->tags); } if (linePtr->activeIndices != NULL) { Blt_Free(linePtr->activeIndices); } if (linePtr->fillPts != NULL) { Blt_Free(linePtr->fillPts); } if (linePtr->fillTile != NULL) { Blt_FreeTile(linePtr->fillTile); } if ((linePtr->fillStipple != None) && (linePtr->fillStipple != PATTERN_SOLID)) { Tk_FreeBitmap(graphPtr->display, linePtr->fillStipple); } if (linePtr->fillGC != NULL) { Tk_FreeGC(graphPtr->display, linePtr->fillGC); } } /* *---------------------------------------------------------------------- * * Blt_LineElement -- * * Allocate memory and initialize methods for the new line element. * * Results: * The pointer to the newly allocated element structure is returned. * * Side effects: * Memory is allocated for the line element structure. * *---------------------------------------------------------------------- */ static ElementProcs lineProcs = { ClosestLine, /* Finds the closest element/data point */ ConfigureLine, /* Configures the element. */ DestroyLine, /* Destroys the element. */ DrawActiveLine, /* Draws active element */ DrawNormalLine, /* Draws normal element */ DrawSymbol, /* Draws the element symbol. */ GetLineExtents, /* Find the extents of the element's data. */ ActiveLineToPostScript, /* Prints active element. */ NormalLineToPostScript, /* Prints normal element. */ SymbolToPostScript, /* Prints the line's symbol. */ MapLine /* Compute element's screen coordinates. */ }; Element * Blt_LineElement(graphPtr, name, classUid) Graph *graphPtr; char *name; Blt_Uid classUid; { register Line *linePtr; linePtr = Blt_Calloc(1, sizeof(Line)); assert(linePtr); linePtr->procsPtr = &lineProcs; if (classUid == bltLineElementUid) { linePtr->configSpecs = lineElemConfigSpecs; } else { linePtr->configSpecs = stripElemConfigSpecs; } /* By default an element's name and label are the same. */ linePtr->label = Blt_Strdup(name); linePtr->name = Blt_Strdup(name); linePtr->classUid = classUid; linePtr->flags = SCALE_SYMBOL; linePtr->graphPtr = graphPtr; linePtr->labelRelief = TK_RELIEF_FLAT; linePtr->normalPenPtr = &linePtr->builtinPen; linePtr->palette = Blt_ChainCreate(); linePtr->penDir = PEN_BOTH_DIRECTIONS; linePtr->reqSmooth = PEN_SMOOTH_NONE; InitPen(linePtr->normalPenPtr); return (Element *)linePtr; } blt-2.4z.orig/src/bltGrMarker.c0100644000175000017500000043512307542177233015135 0ustar dokodoko /* * bltGrMarker.c -- * * This module implements markers for the BLT graph widget. * * Copyright 1993-1998 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. */ #include "bltGraph.h" #include "bltChain.h" #include "bltGrElem.h" #define MAX_OUTLINE_POINTS 12 /* Map graph coordinates to normalized coordinates [0..1] */ #define NORMALIZE(A,x) (((x) - (A)->axisRange.min) / (A)->axisRange.range) #define DEF_MARKER_ANCHOR "center" #define DEF_MARKER_BACKGROUND RGB_WHITE #define DEF_MARKER_BG_MONO RGB_WHITE #define DEF_MARKER_BITMAP (char *)NULL #define DEF_MARKER_CAP_STYLE "butt" #define DEF_MARKER_COORDS (char *)NULL #define DEF_MARKER_DASHES (char *)NULL #define DEF_MARKER_DASH_OFFSET "0" #define DEF_MARKER_ELEMENT (char *)NULL #define DEF_MARKER_FOREGROUND RGB_BLACK #define DEF_MARKER_FG_MONO RGB_BLACK #define DEF_MARKER_FILL_COLOR RGB_RED #define DEF_MARKER_FILL_MONO RGB_WHITE #define DEF_MARKER_FONT STD_FONT #define DEF_MARKER_GAP_COLOR RGB_PINK #define DEF_MARKER_GAP_MONO RGB_BLACK #define DEF_MARKER_HEIGHT "0" #define DEF_MARKER_HIDE "no" #define DEF_MARKER_JOIN_STYLE "miter" #define DEF_MARKER_JUSTIFY "left" #define DEF_MARKER_LINE_WIDTH "1" #define DEF_MARKER_MAP_X "x" #define DEF_MARKER_MAP_Y "y" #define DEF_MARKER_NAME (char *)NULL #define DEF_MARKER_OUTLINE_COLOR RGB_BLACK #define DEF_MARKER_OUTLINE_MONO RGB_BLACK #define DEF_MARKER_PAD "4" #define DEF_MARKER_ROTATE "0.0" #define DEF_MARKER_SCALE "1.0" #define DEF_MARKER_SHADOW_COLOR (char *)NULL #define DEF_MARKER_SHADOW_MONO (char *)NULL #define DEF_MARKER_STATE "normal" #define DEF_MARKER_STIPPLE (char *)NULL #define DEF_MARKER_TEXT (char *)NULL #define DEF_MARKER_UNDER "no" #define DEF_MARKER_WIDTH "0" #define DEF_MARKER_WINDOW (char *)NULL #define DEF_MARKER_XOR "no" #define DEF_MARKER_X_OFFSET "0" #define DEF_MARKER_Y_OFFSET "0" #define DEF_MARKER_TEXT_TAGS "Text all" #define DEF_MARKER_IMAGE_TAGS "Image all" #define DEF_MARKER_BITMAP_TAGS "Bitmap all" #define DEF_MARKER_WINDOW_TAGS "Window all" #define DEF_MARKER_POLYGON_TAGS "Polygon all" #define DEF_MARKER_LINE_TAGS "Line all" static Tk_OptionParseProc StringToCoordinates; static Tk_OptionPrintProc CoordinatesToString; static Tk_CustomOption coordsOption = { StringToCoordinates, CoordinatesToString, (ClientData)0 }; extern Tk_CustomOption bltColorPairOption; extern Tk_CustomOption bltDashesOption; extern Tk_CustomOption bltDistanceOption; extern Tk_CustomOption bltListOption; extern Tk_CustomOption bltPadOption; extern Tk_CustomOption bltPositiveDistanceOption; extern Tk_CustomOption bltShadowOption; extern Tk_CustomOption bltStateOption; extern Tk_CustomOption bltXAxisOption; extern Tk_CustomOption bltYAxisOption; typedef Marker *(MarkerCreateProc) _ANSI_ARGS_((void)); typedef void (MarkerDrawProc) _ANSI_ARGS_((Marker *markerPtr, Drawable drawable)); typedef void (MarkerFreeProc) _ANSI_ARGS_((Graph *graphPtr, Marker *markerPtr)); typedef int (MarkerConfigProc) _ANSI_ARGS_((Marker *markerPtr)); typedef void (MarkerMapProc) _ANSI_ARGS_((Marker *markerPtr)); typedef void (MarkerPostScriptProc) _ANSI_ARGS_((Marker *markerPtr, PsToken psToken)); typedef int (MarkerPointProc) _ANSI_ARGS_((Marker *markerPtr, Point2D *samplePtr)); typedef int (MarkerRegionProc) _ANSI_ARGS_((Marker *markerPtr, Extents2D *extsPtr, int enclosed)); typedef struct { Tk_ConfigSpec *configSpecs; /* Marker configuration specifications */ MarkerConfigProc *configProc; MarkerDrawProc *drawProc; MarkerFreeProc *freeProc; MarkerMapProc *mapProc; MarkerPointProc *pointProc; MarkerRegionProc *regionProc; MarkerPostScriptProc *postscriptProc; } MarkerClass; /* * ------------------------------------------------------------------- * * Marker -- * * Structure defining the generic marker. In C++ parlance this * would be the base type from which all markers are derived. * * This structure corresponds with the specific types of markers. * Don't change this structure without changing the individual * marker structures of each type below. * * ------------------------------------------------------------------- */ struct MarkerStruct { char *name; /* Identifier for marker in list */ Blt_Uid classUid; /* Type of marker. */ Graph *graphPtr; /* Graph widget of marker. */ unsigned int flags; char **tags; int hidden; /* If non-zero, don't display the marker. */ Blt_HashEntry *hashPtr; Blt_ChainLink *linkPtr; Point2D *worldPts; /* Coordinate array to position marker */ int nWorldPts; /* Number of points in above array */ char *elemName; /* Element associated with marker */ Axis2D axes; int drawUnder; /* If non-zero, draw the marker * underneath any elements. This can * be a performance penalty because * the graph must be redraw entirely * each time the marker is redrawn. */ int clipped; /* Indicates if the marker is totally * clipped by the plotting area. */ int xOffset, yOffset; /* Pixel offset from graph position */ MarkerClass *classPtr; int state; }; /* * ------------------------------------------------------------------- * * TextMarker -- * * ------------------------------------------------------------------- */ typedef struct { char *name; /* Identifier for marker */ Blt_Uid classUid; /* Type of marker */ Graph *graphPtr; /* The graph this marker belongs to */ unsigned int flags; char **tags; int hidden; /* If non-zero, don't display the * marker. */ Blt_HashEntry *hashPtr; Blt_ChainLink *linkPtr; Point2D *worldPts; /* Position of marker (1 X-Y coordinate) in * world (graph) coordinates. */ int nWorldPts; /* Number of points */ char *elemName; /* Element associated with marker */ Axis2D axes; int drawUnder; /* If non-zero, draw the marker * underneath any elements. There can * be a performance because the graph * must be redraw entirely each time * this marker is redrawn. */ int clipped; /* Indicates if the marker is totally * clipped by the plotting area. */ int xOffset, yOffset; /* pixel offset from anchor */ MarkerClass *classPtr; int state; /* * Text specific fields and attributes */ #ifdef notdef char *textVarName; /* Name of variable (malloc'ed) or * NULL. If non-NULL, graph displays * the contents of this variable. */ #endif char *string; /* Text string to be display. The string * make contain newlines. */ Tk_Anchor anchor; /* Indicates how to translate the given * marker position. */ Point2D anchorPos; /* Translated anchor point. */ int width, height; /* Dimension of bounding box. */ TextStyle style; /* Text attributes (font, fg, anchor, etc) */ TextLayout *textPtr; /* Contains information about the layout * of the text. */ Point2D outline[5]; XColor *fillColor; GC fillGC; } TextMarker; static Tk_ConfigSpec textConfigSpecs[] = { {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", DEF_MARKER_ANCHOR, Tk_Offset(TextMarker, anchor), 0}, {TK_CONFIG_COLOR, "-background", "background", "MarkerBackground", (char *)NULL, Tk_Offset(TextMarker, fillColor), TK_CONFIG_NULL_OK}, {TK_CONFIG_SYNONYM, "-bg", "background", "Background", (char *)NULL, 0, 0}, {TK_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags", DEF_MARKER_TEXT_TAGS, Tk_Offset(Marker, tags), TK_CONFIG_NULL_OK, &bltListOption}, {TK_CONFIG_CUSTOM, "-coords", "coords", "Coords", DEF_MARKER_COORDS, Tk_Offset(Marker, worldPts), TK_CONFIG_NULL_OK, &coordsOption}, {TK_CONFIG_STRING, "-element", "element", "Element", DEF_MARKER_ELEMENT, Tk_Offset(Marker, elemName), TK_CONFIG_NULL_OK}, {TK_CONFIG_SYNONYM, "-fg", "foreground", "Foreground", (char *)NULL, 0, 0}, {TK_CONFIG_SYNONYM, "-fill", "background", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_FONT, "-font", "font", "Font", DEF_MARKER_FONT, Tk_Offset(TextMarker, style.font), 0}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_MARKER_FOREGROUND, Tk_Offset(TextMarker, style.color), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_MARKER_FG_MONO, Tk_Offset(TextMarker, style.color), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify", DEF_MARKER_JUSTIFY, Tk_Offset(TextMarker, style.justify), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide", DEF_MARKER_HIDE, Tk_Offset(Marker, hidden), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-mapx", "mapX", "MapX", DEF_MARKER_MAP_X, Tk_Offset(Marker, axes.x), 0, &bltXAxisOption}, {TK_CONFIG_CUSTOM, "-mapy", "mapY", "MapY", DEF_MARKER_MAP_Y, Tk_Offset(Marker, axes.y), 0, &bltYAxisOption}, {TK_CONFIG_STRING, "-name", (char *)NULL, (char *)NULL, DEF_MARKER_NAME, Tk_Offset(Marker, name), TK_CONFIG_NULL_OK}, {TK_CONFIG_SYNONYM, "-outline", "foreground", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_CUSTOM, "-padx", "padX", "PadX", DEF_MARKER_PAD, Tk_Offset(TextMarker, style.padX), TK_CONFIG_DONT_SET_DEFAULT, &bltPadOption}, {TK_CONFIG_CUSTOM, "-pady", "padY", "PadY", DEF_MARKER_PAD, Tk_Offset(TextMarker, style.padY), TK_CONFIG_DONT_SET_DEFAULT, &bltPadOption}, {TK_CONFIG_DOUBLE, "-rotate", "rotate", "Rotate", DEF_MARKER_ROTATE, Tk_Offset(TextMarker, style.theta), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-shadow", "shadow", "Shadow", DEF_MARKER_SHADOW_COLOR, Tk_Offset(TextMarker, style.shadow), TK_CONFIG_COLOR_ONLY, &bltShadowOption}, {TK_CONFIG_CUSTOM, "-shadow", "shadow", "Shadow", DEF_MARKER_SHADOW_MONO, Tk_Offset(TextMarker, style.shadow), TK_CONFIG_MONO_ONLY, &bltShadowOption}, {TK_CONFIG_CUSTOM, "-state", "state", "State", DEF_MARKER_STATE, Tk_Offset(Marker, state), TK_CONFIG_DONT_SET_DEFAULT, &bltStateOption}, {TK_CONFIG_STRING, "-text", "text", "Text", DEF_MARKER_TEXT, Tk_Offset(TextMarker, string), TK_CONFIG_NULL_OK}, {TK_CONFIG_BOOLEAN, "-under", "under", "Under", DEF_MARKER_UNDER, Tk_Offset(Marker, drawUnder), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_PIXELS, "-xoffset", "xOffset", "XOffset", DEF_MARKER_X_OFFSET, Tk_Offset(Marker, xOffset), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_PIXELS, "-yoffset", "yOffset", "YOffset", DEF_MARKER_Y_OFFSET, Tk_Offset(Marker, yOffset), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} }; /* * ------------------------------------------------------------------- * * WindowMarker -- * * ------------------------------------------------------------------- */ typedef struct { char *name; /* Identifier for marker */ Blt_Uid classUid; /* Type of marker */ Graph *graphPtr; /* Graph marker belongs to */ unsigned int flags; char **tags; int hidden; /* Indicates if the marker is * currently hidden or not. */ Blt_HashEntry *hashPtr; Blt_ChainLink *linkPtr; Point2D *worldPts; /* Position of marker (1 X-Y coordinate) in * world (graph) coordinates. */ int nWorldPts; /* Number of points */ char *elemName; /* Element associated with marker */ Axis2D axes; int drawUnder; /* If non-zero, draw the marker * underneath any elements. There can * be a performance because the graph * must be redraw entirely each time * this marker is redrawn. */ int clipped; /* Indicates if the marker is totally * clipped by the plotting area. */ int xOffset, yOffset; /* Pixel offset from anchor. */ MarkerClass *classPtr; int state; /* * Window specific attributes */ char *pathName; /* Name of child widget to be displayed. */ Tk_Window tkwin; /* Window to display. */ int reqWidth, reqHeight; /* If non-zero, this overrides the size * requested by the child widget. */ Tk_Anchor anchor; /* Indicates how to translate the given * marker position. */ Point2D anchorPos; /* Translated anchor point. */ int width, height; /* Current size of the child window. */ } WindowMarker; static Tk_ConfigSpec windowConfigSpecs[] = { {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", DEF_MARKER_ANCHOR, Tk_Offset(WindowMarker, anchor), 0}, {TK_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags", DEF_MARKER_WINDOW_TAGS, Tk_Offset(Marker, tags), TK_CONFIG_NULL_OK, &bltListOption}, {TK_CONFIG_CUSTOM, "-coords", "coords", "Coords", DEF_MARKER_COORDS, Tk_Offset(WindowMarker, worldPts), TK_CONFIG_NULL_OK, &coordsOption}, {TK_CONFIG_STRING, "-element", "element", "Element", DEF_MARKER_ELEMENT, Tk_Offset(Marker, elemName), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-height", "height", "Height", DEF_MARKER_HEIGHT, Tk_Offset(WindowMarker, reqHeight), TK_CONFIG_DONT_SET_DEFAULT, &bltPositiveDistanceOption}, {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide", DEF_MARKER_HIDE, Tk_Offset(Marker, hidden), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-mapx", "mapX", "MapX", DEF_MARKER_MAP_X, Tk_Offset(Marker, axes.x), 0, &bltXAxisOption}, {TK_CONFIG_CUSTOM, "-mapy", "mapY", "MapY", DEF_MARKER_MAP_Y, Tk_Offset(Marker, axes.y), 0, &bltYAxisOption}, {TK_CONFIG_STRING, "-name", (char *)NULL, (char *)NULL, DEF_MARKER_NAME, Tk_Offset(Marker, name), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-state", "state", "State", DEF_MARKER_STATE, Tk_Offset(Marker, state), TK_CONFIG_DONT_SET_DEFAULT, &bltStateOption}, {TK_CONFIG_BOOLEAN, "-under", "under", "Under", DEF_MARKER_UNDER, Tk_Offset(Marker, drawUnder), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-width", "width", "Width", DEF_MARKER_WIDTH, Tk_Offset(WindowMarker, reqWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltPositiveDistanceOption}, {TK_CONFIG_STRING, "-window", "window", "Window", DEF_MARKER_WINDOW, Tk_Offset(WindowMarker, pathName), TK_CONFIG_NULL_OK}, {TK_CONFIG_PIXELS, "-xoffset", "xOffset", "XOffset", DEF_MARKER_X_OFFSET, Tk_Offset(Marker, xOffset), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_PIXELS, "-yoffset", "yOffset", "YOffset", DEF_MARKER_Y_OFFSET, Tk_Offset(Marker, yOffset), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} }; /* * ------------------------------------------------------------------- * * BitmapMarker -- * * ------------------------------------------------------------------- */ typedef struct { char *name; /* Identifier for marker */ Blt_Uid classUid; /* Type of marker */ Graph *graphPtr; /* Graph marker belongs to */ unsigned int flags; char **tags; int hidden; /* Indicates if the marker is currently * hidden or not. */ Blt_HashEntry *hashPtr; Blt_ChainLink *linkPtr; Point2D *worldPts; /* Position of marker in world (graph) * coordinates. If 2 pairs of X-Y * coordinates are specified, then the * bitmap is resized to fit this area. * Otherwise if 1 pair, then the bitmap * is positioned at the coordinate at its * normal size. */ int nWorldPts; /* Number of points */ char *elemName; /* Element associated with marker */ Axis2D axes; int drawUnder; /* If non-zero, draw the marker * underneath any elements. There can * be a performance because the graph * must be redraw entirely each time * this marker is redrawn. */ int clipped; /* Indicates if the marker is totally * clipped by the plotting area. */ int xOffset, yOffset; /* Pixel offset from origin of bitmap */ MarkerClass *classPtr; int state; /* Bitmap specific attributes */ Pixmap srcBitmap; /* Original bitmap. May be further * scaled or rotated. */ double rotate; /* Requested rotation of the bitmap */ double theta; /* Normalized rotation (0..360 * degrees) */ Tk_Anchor anchor; /* If only one X-Y coordinate is * given, indicates how to translate * the given marker position. Otherwise, * if there are two X-Y coordinates, then * this value is ignored. */ Point2D anchorPos; /* Translated anchor point. */ XColor *outlineColor; /* Foreground color */ XColor *fillColor; /* Background color */ GC gc; /* Private graphic context */ GC fillGC; /* Shared graphic context */ Pixmap destBitmap; /* Bitmap to be drawn. */ int destWidth, destHeight; /* Dimensions of the final bitmap */ Point2D outline[MAX_OUTLINE_POINTS]; /* Polygon representing the background * of the bitmap. */ int nOutlinePts; } BitmapMarker; static Tk_ConfigSpec bitmapConfigSpecs[] = { {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", DEF_MARKER_ANCHOR, Tk_Offset(BitmapMarker, anchor), 0}, {TK_CONFIG_COLOR, "-background", "background", "Background", DEF_MARKER_BACKGROUND, Tk_Offset(BitmapMarker, fillColor), TK_CONFIG_COLOR_ONLY | TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-background", "background", "Background", DEF_MARKER_BG_MONO, Tk_Offset(BitmapMarker, fillColor), TK_CONFIG_MONO_ONLY | TK_CONFIG_NULL_OK}, {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags", DEF_MARKER_BITMAP_TAGS, Tk_Offset(Marker, tags), TK_CONFIG_NULL_OK, &bltListOption}, {TK_CONFIG_BITMAP, "-bitmap", "bitmap", "Bitmap", DEF_MARKER_BITMAP, Tk_Offset(BitmapMarker, srcBitmap), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-coords", "coords", "Coords", DEF_MARKER_COORDS, Tk_Offset(Marker, worldPts), TK_CONFIG_NULL_OK, &coordsOption}, {TK_CONFIG_STRING, "-element", "element", "Element", DEF_MARKER_ELEMENT, Tk_Offset(Marker, elemName), TK_CONFIG_NULL_OK}, {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_SYNONYM, "-fill", "background", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_MARKER_FOREGROUND, Tk_Offset(BitmapMarker, outlineColor), TK_CONFIG_COLOR_ONLY | TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_MARKER_FG_MONO, Tk_Offset(BitmapMarker, outlineColor), TK_CONFIG_MONO_ONLY | TK_CONFIG_NULL_OK}, {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide", DEF_MARKER_HIDE, Tk_Offset(Marker, hidden), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-mapx", "mapX", "MapX", DEF_MARKER_MAP_X, Tk_Offset(Marker, axes.x), 0, &bltXAxisOption}, {TK_CONFIG_CUSTOM, "-mapy", "mapY", "MapY", DEF_MARKER_MAP_Y, Tk_Offset(Marker, axes.y), 0, &bltYAxisOption}, {TK_CONFIG_STRING, "-name", (char *)NULL, (char *)NULL, DEF_MARKER_NAME, Tk_Offset(Marker, name), TK_CONFIG_NULL_OK}, {TK_CONFIG_SYNONYM, "-outline", "foreground", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_DOUBLE, "-rotate", "rotate", "Rotate", DEF_MARKER_ROTATE, Tk_Offset(BitmapMarker, rotate), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-state", "state", "State", DEF_MARKER_STATE, Tk_Offset(Marker, state), TK_CONFIG_DONT_SET_DEFAULT, &bltStateOption}, {TK_CONFIG_BOOLEAN, "-under", "under", "Under", DEF_MARKER_UNDER, Tk_Offset(Marker, drawUnder), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_PIXELS, "-xoffset", "xOffset", "XOffset", DEF_MARKER_X_OFFSET, Tk_Offset(Marker, xOffset), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_PIXELS, "-yoffset", "yOffset", "YOffset", DEF_MARKER_Y_OFFSET, Tk_Offset(Marker, yOffset), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} }; /* * ------------------------------------------------------------------- * * ImageMarker -- * * ------------------------------------------------------------------- */ typedef struct { char *name; /* Identifier for marker */ Blt_Uid classUid; /* Type of marker */ Graph *graphPtr; /* Graph marker belongs to */ unsigned int flags; char **tags; int hidden; /* Indicates if the marker is * currently hidden or not. */ Blt_HashEntry *hashPtr; Blt_ChainLink *linkPtr; Point2D *worldPts; /* Position of marker in world (graph) * coordinates. If 2 pairs of X-Y * coordinates are specified, then the * image is resized to fit this area. * Otherwise if 1 pair, then the image * is positioned at the coordinate at * its normal size. */ int nWorldPts; /* Number of points */ char *elemName; /* Element associated with marker */ Axis2D axes; int drawUnder; /* If non-zero, draw the marker * underneath any elements. There can * be a performance because the graph * must be redraw entirely each time * this marker is redrawn. */ int clipped; /* Indicates if the marker is totally * clipped by the plotting area. */ int xOffset, yOffset; /* Pixel offset from anchor */ MarkerClass *classPtr; int state; /* Image specific attributes */ char *imageName; /* Name of image to be displayed. */ Tk_Image tkImage; /* Tk image to be displayed. */ Tk_Anchor anchor; /* Indicates how to translate the given * marker position. */ Point2D anchorPos; /* Translated anchor point. */ int width, height; /* Dimensions of the image */ Tk_Image tmpImage; Pixmap pixmap; /* Pixmap containing the scaled image */ ColorTable colorTable; /* Pointer to color table */ Blt_ColorImage srcImage; GC gc; } ImageMarker; static Tk_ConfigSpec imageConfigSpecs[] = { {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", DEF_MARKER_ANCHOR, Tk_Offset(ImageMarker, anchor), 0}, {TK_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags", DEF_MARKER_IMAGE_TAGS, Tk_Offset(Marker, tags), TK_CONFIG_NULL_OK, &bltListOption}, {TK_CONFIG_CUSTOM, "-coords", "coords", "Coords", DEF_MARKER_COORDS, Tk_Offset(Marker, worldPts), TK_CONFIG_NULL_OK, &coordsOption}, {TK_CONFIG_STRING, "-element", "element", "Element", DEF_MARKER_ELEMENT, Tk_Offset(Marker, elemName), TK_CONFIG_NULL_OK}, {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide", DEF_MARKER_HIDE, Tk_Offset(Marker, hidden), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_STRING, "-image", "image", "Image", (char *)NULL, Tk_Offset(ImageMarker, imageName), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-mapx", "mapX", "MapX", DEF_MARKER_MAP_X, Tk_Offset(Marker, axes.x), 0, &bltXAxisOption}, {TK_CONFIG_CUSTOM, "-mapy", "mapY", "MapY", DEF_MARKER_MAP_Y, Tk_Offset(Marker, axes.y), 0, &bltYAxisOption}, {TK_CONFIG_STRING, "-name", (char *)NULL, (char *)NULL, DEF_MARKER_NAME, Tk_Offset(Marker, name), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-state", "state", "State", DEF_MARKER_STATE, Tk_Offset(Marker, state), TK_CONFIG_DONT_SET_DEFAULT, &bltStateOption}, {TK_CONFIG_BOOLEAN, "-under", "under", "Under", DEF_MARKER_UNDER, Tk_Offset(Marker, drawUnder), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_PIXELS, "-xoffset", "xOffset", "XOffset", DEF_MARKER_X_OFFSET, Tk_Offset(Marker, xOffset), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_PIXELS, "-yoffset", "yOffset", "YOffset", DEF_MARKER_Y_OFFSET, Tk_Offset(Marker, yOffset), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} }; /* * ------------------------------------------------------------------- * * LineMarker -- * * ------------------------------------------------------------------- */ typedef struct { char *name; /* Identifier for marker */ Blt_Uid classUid; /* Type is "linemarker" */ Graph *graphPtr; /* Graph marker belongs to */ unsigned int flags; char **tags; int hidden; /* Indicates if the marker is currently * hidden or not. */ Blt_HashEntry *hashPtr; Blt_ChainLink *linkPtr; Point2D *worldPts; /* Position of marker (X-Y coordinates) in * world (graph) coordinates. */ int nWorldPts; /* Number of points */ char *elemName; /* Element associated with marker */ Axis2D axes; int drawUnder; /* If non-zero, draw the marker * underneath any elements. There can * be a performance because the graph * must be redraw entirely each time * this marker is redrawn. */ int clipped; /* Indicates if the marker is totally * clipped by the plotting area. */ int xOffset, yOffset; /* Pixel offset */ MarkerClass *classPtr; int state; /* Line specific attributes */ XColor *fillColor; XColor *outlineColor; /* Foreground and background colors */ int lineWidth; /* Line width. */ int capStyle; /* Cap style. */ int joinStyle; /* Join style.*/ Blt_Dashes dashes; /* Dash list values (max 11) */ GC gc; /* Private graphic context */ Segment2D *segments; /* Malloc'ed array of points. * Represents individual line segments * (2 points per segment) comprising * the mapped line. The segments may * not necessarily be connected after * clipping. */ int nSegments; /* # segments in the above array. */ int xor; int xorState; /* State of the XOR drawing. Indicates * if the marker is currently drawn. */ } LineMarker; static Tk_ConfigSpec lineConfigSpecs[] = { {TK_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags", DEF_MARKER_LINE_TAGS, Tk_Offset(Marker, tags), TK_CONFIG_NULL_OK, &bltListOption}, {TK_CONFIG_CAP_STYLE, "-cap", "cap", "Cap", DEF_MARKER_CAP_STYLE, Tk_Offset(LineMarker, capStyle), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-coords", "coords", "Coords", DEF_MARKER_COORDS, Tk_Offset(Marker, worldPts), TK_CONFIG_NULL_OK, &coordsOption}, {TK_CONFIG_CUSTOM, "-dashes", "dashes", "Dashes", DEF_MARKER_DASHES, Tk_Offset(LineMarker, dashes), TK_CONFIG_NULL_OK, &bltDashesOption}, {TK_CONFIG_CUSTOM, "-dashoffset", "dashOffset", "DashOffset", DEF_MARKER_DASH_OFFSET, Tk_Offset(LineMarker, dashes.offset), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_STRING, "-element", "element", "Element", DEF_MARKER_ELEMENT, Tk_Offset(Marker, elemName), TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-fill", "fill", "Fill", (char *)NULL, Tk_Offset(LineMarker, fillColor), TK_CONFIG_NULL_OK}, {TK_CONFIG_JOIN_STYLE, "-join", "join", "Join", DEF_MARKER_JOIN_STYLE, Tk_Offset(LineMarker, joinStyle), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-linewidth", "lineWidth", "LineWidth", DEF_MARKER_LINE_WIDTH, Tk_Offset(LineMarker, lineWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide", DEF_MARKER_HIDE, Tk_Offset(Marker, hidden), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-mapx", "mapX", "MapX", DEF_MARKER_MAP_X, Tk_Offset(Marker, axes.x), 0, &bltXAxisOption}, {TK_CONFIG_CUSTOM, "-mapy", "mapY", "MapY", DEF_MARKER_MAP_Y, Tk_Offset(Marker, axes.y), 0, &bltYAxisOption}, {TK_CONFIG_STRING, "-name", (char *)NULL, (char *)NULL, DEF_MARKER_NAME, Tk_Offset(Marker, name), TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-outline", "outline", "Outline", DEF_MARKER_OUTLINE_COLOR, Tk_Offset(LineMarker, outlineColor), TK_CONFIG_COLOR_ONLY | TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-outline", "outline", "Outline", DEF_MARKER_OUTLINE_MONO, Tk_Offset(LineMarker, outlineColor), TK_CONFIG_MONO_ONLY | TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-state", "state", "State", DEF_MARKER_STATE, Tk_Offset(Marker, state), TK_CONFIG_DONT_SET_DEFAULT, &bltStateOption}, {TK_CONFIG_BOOLEAN, "-under", "under", "Under", DEF_MARKER_UNDER, Tk_Offset(Marker, drawUnder), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_PIXELS, "-xoffset", "xOffset", "XOffset", DEF_MARKER_X_OFFSET, Tk_Offset(Marker, xOffset), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_BOOLEAN, "-xor", "xor", "Xor", DEF_MARKER_XOR, Tk_Offset(LineMarker, xor), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_PIXELS, "-yoffset", "yOffset", "YOffset", DEF_MARKER_Y_OFFSET, Tk_Offset(Marker, yOffset), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} }; /* * ------------------------------------------------------------------- * * PolygonMarker -- * * ------------------------------------------------------------------- */ typedef struct { char *name; /* Identifier for marker */ Blt_Uid classUid; /* Type of marker */ Graph *graphPtr; /* Graph marker belongs to */ unsigned int flags; char **tags; int hidden; /* Indicates if the marker is currently * hidden or not. */ Blt_HashEntry *hashPtr; Blt_ChainLink *linkPtr; Point2D *worldPts; /* Position of marker (X-Y coordinates) in * world (graph) coordinates. */ int nWorldPts; /* Number of points */ char *elemName; /* Element associated with marker */ Axis2D axes; int drawUnder; /* If non-zero, draw the marker * underneath any elements. There can * be a performance because the graph * must be redraw entirely each time * this marker is redrawn. */ int clipped; /* Indicates if the marker is totally * clipped by the plotting area. */ int xOffset, yOffset; /* Pixel offset */ MarkerClass *classPtr; int state; /* Polygon specific attributes and fields */ Point2D *screenPts; ColorPair outline; ColorPair fill; Pixmap stipple; /* Stipple pattern to fill the polygon. */ int lineWidth; /* Width of polygon outline. */ int capStyle; int joinStyle; Blt_Dashes dashes; /* List of dash values. Indicates how * draw the dashed line. If no dash * values are provided, or the first value * is zero, then the line is drawn solid. */ GC outlineGC; /* Graphics context to draw the outline of * the polygon. */ GC fillGC; /* Graphics context to draw the filled * polygon. */ Point2D *fillPts; /* Malloc'ed array of points used to draw * the filled polygon. These points may * form a degenerate polygon after clipping. */ int nFillPts; /* # points in the above array. */ Segment2D *outlinePts; /* Malloc'ed array of points. * Represents individual line segments * (2 points per segment) comprising * the outline of the polygon. The * segments may not necessarily be * closed or connected after clipping. */ int nOutlinePts; /* # points in the above array. */ int xor; int xorState; /* State of the XOR drawing. Indicates * if the marker is visible. We have * to drawn it again to erase it. */ } PolygonMarker; static Tk_ConfigSpec polygonConfigSpecs[] = { {TK_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags", DEF_MARKER_POLYGON_TAGS, Tk_Offset(Marker, tags), TK_CONFIG_NULL_OK, &bltListOption}, {TK_CONFIG_CAP_STYLE, "-cap", "cap", "Cap", DEF_MARKER_CAP_STYLE, Tk_Offset(PolygonMarker, capStyle), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-coords", "coords", "Coords", DEF_MARKER_COORDS, Tk_Offset(Marker, worldPts), TK_CONFIG_NULL_OK, &coordsOption}, {TK_CONFIG_CUSTOM, "-dashes", "dashes", "Dashes", DEF_MARKER_DASHES, Tk_Offset(PolygonMarker, dashes), TK_CONFIG_NULL_OK, &bltDashesOption}, {TK_CONFIG_STRING, "-element", "element", "Element", DEF_MARKER_ELEMENT, Tk_Offset(Marker, elemName), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-fill", "fill", "Fill", DEF_MARKER_FILL_COLOR, Tk_Offset(PolygonMarker, fill), TK_CONFIG_COLOR_ONLY | TK_CONFIG_NULL_OK, &bltColorPairOption}, {TK_CONFIG_CUSTOM, "-fill", "fill", "Fill", DEF_MARKER_FILL_MONO, Tk_Offset(PolygonMarker, fill), TK_CONFIG_MONO_ONLY | TK_CONFIG_NULL_OK, &bltColorPairOption}, {TK_CONFIG_JOIN_STYLE, "-join", "join", "Join", DEF_MARKER_JOIN_STYLE, Tk_Offset(PolygonMarker, joinStyle), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-linewidth", "lineWidth", "LineWidth", DEF_MARKER_LINE_WIDTH, Tk_Offset(PolygonMarker, lineWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide", DEF_MARKER_HIDE, Tk_Offset(Marker, hidden), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-mapx", "mapX", "MapX", DEF_MARKER_MAP_X, Tk_Offset(Marker, axes.x), 0, &bltXAxisOption}, {TK_CONFIG_CUSTOM, "-mapy", "mapY", "MapY", DEF_MARKER_MAP_Y, Tk_Offset(Marker, axes.y), 0, &bltYAxisOption}, {TK_CONFIG_STRING, "-name", (char *)NULL, (char *)NULL, DEF_MARKER_NAME, Tk_Offset(Marker, name), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-outline", "outline", "Outline", DEF_MARKER_OUTLINE_COLOR, Tk_Offset(PolygonMarker, outline), TK_CONFIG_COLOR_ONLY | TK_CONFIG_NULL_OK, &bltColorPairOption}, {TK_CONFIG_CUSTOM, "-outline", "outline", "Outline", DEF_MARKER_OUTLINE_MONO, Tk_Offset(PolygonMarker, outline), TK_CONFIG_MONO_ONLY | TK_CONFIG_NULL_OK, &bltColorPairOption}, {TK_CONFIG_CUSTOM, "-state", "state", "State", DEF_MARKER_STATE, Tk_Offset(Marker, state), TK_CONFIG_DONT_SET_DEFAULT, &bltStateOption}, {TK_CONFIG_BITMAP, "-stipple", "stipple", "Stipple", DEF_MARKER_STIPPLE, Tk_Offset(PolygonMarker, stipple), TK_CONFIG_NULL_OK}, {TK_CONFIG_BOOLEAN, "-under", "under", "Under", DEF_MARKER_UNDER, Tk_Offset(Marker, drawUnder), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_PIXELS, "-xoffset", "xOffset", "XOffset", DEF_MARKER_X_OFFSET, Tk_Offset(Marker, xOffset), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_BOOLEAN, "-xor", "xor", "Xor", DEF_MARKER_XOR, Tk_Offset(PolygonMarker, xor), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_PIXELS, "-yoffset", "yOffset", "YOffset", DEF_MARKER_Y_OFFSET, Tk_Offset(Marker, yOffset), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} }; static MarkerCreateProc CreateBitmapMarker, CreateLineMarker, CreateImageMarker, CreatePolygonMarker, CreateTextMarker, CreateWindowMarker; static MarkerDrawProc DrawBitmapMarker, DrawLineMarker, DrawImageMarker, DrawPolygonMarker, DrawTextMarker, DrawWindowMarker; static MarkerFreeProc FreeBitmapMarker, FreeLineMarker, FreeImageMarker, FreePolygonMarker, FreeTextMarker, FreeWindowMarker; static MarkerConfigProc ConfigureBitmapMarker, ConfigureLineMarker, ConfigureImageMarker, ConfigurePolygonMarker, ConfigureTextMarker, ConfigureWindowMarker; static MarkerMapProc MapBitmapMarker, MapLineMarker, MapImageMarker, MapPolygonMarker, MapTextMarker, MapWindowMarker; static MarkerPostScriptProc BitmapMarkerToPostScript, LineMarkerToPostScript, ImageMarkerToPostScript, PolygonMarkerToPostScript, TextMarkerToPostScript, WindowMarkerToPostScript; static MarkerPointProc PointInBitmapMarker, PointInLineMarker, PointInImageMarker, PointInPolygonMarker, PointInTextMarker, PointInWindowMarker; static MarkerRegionProc RegionInBitmapMarker, RegionInLineMarker, RegionInImageMarker, RegionInPolygonMarker, RegionInTextMarker, RegionInWindowMarker; static Tk_ImageChangedProc ImageChangedProc; static MarkerClass bitmapMarkerClass = { bitmapConfigSpecs, ConfigureBitmapMarker, DrawBitmapMarker, FreeBitmapMarker, MapBitmapMarker, PointInBitmapMarker, RegionInBitmapMarker, BitmapMarkerToPostScript, }; static MarkerClass imageMarkerClass = { imageConfigSpecs, ConfigureImageMarker, DrawImageMarker, FreeImageMarker, MapImageMarker, PointInImageMarker, RegionInImageMarker, ImageMarkerToPostScript, }; static MarkerClass lineMarkerClass = { lineConfigSpecs, ConfigureLineMarker, DrawLineMarker, FreeLineMarker, MapLineMarker, PointInLineMarker, RegionInLineMarker, LineMarkerToPostScript, }; static MarkerClass polygonMarkerClass = { polygonConfigSpecs, ConfigurePolygonMarker, DrawPolygonMarker, FreePolygonMarker, MapPolygonMarker, PointInPolygonMarker, RegionInPolygonMarker, PolygonMarkerToPostScript, }; static MarkerClass textMarkerClass = { textConfigSpecs, ConfigureTextMarker, DrawTextMarker, FreeTextMarker, MapTextMarker, PointInTextMarker, RegionInTextMarker, TextMarkerToPostScript, }; static MarkerClass windowMarkerClass = { windowConfigSpecs, ConfigureWindowMarker, DrawWindowMarker, FreeWindowMarker, MapWindowMarker, PointInWindowMarker, RegionInWindowMarker, WindowMarkerToPostScript, }; #ifdef notdef static MarkerClass rectangleMarkerClass = { rectangleConfigSpecs, ConfigureRectangleMarker, DrawRectangleMarker, FreeRectangleMarker, MapRectangleMarker, PointInRectangleMarker, RegionInRectangleMarker, RectangleMarkerToPostScript, }; static MarkerClass ovalMarkerClass = { ovalConfigSpecs, ConfigureOvalMarker, DrawOvalMarker, FreeOvalMarker, MapOvalMarker, PointInOvalMarker, RegionInOvalMarker, OvalMarkerToPostScript, }; #endif /* * ---------------------------------------------------------------------- * * BoxesDontOverlap -- * * Tests if the bounding box of a marker overlaps the plotting * area in any way. If so, the marker will be drawn. Just do a * min/max test on the extents of both boxes. * * Note: It's assumed that the extents of the bounding box lie * within the area. So for a 10x10 rectangle, bottom and * left would be 9. * * Results: * Returns 0 is the marker is visible in the plotting area, and * 1 otherwise (marker is clipped). * * ---------------------------------------------------------------------- */ static int BoxesDontOverlap(graphPtr, extsPtr) Graph *graphPtr; Extents2D *extsPtr; { assert(extsPtr->right >= extsPtr->left); assert(extsPtr->bottom >= extsPtr->top); assert(graphPtr->right >= graphPtr->left); assert(graphPtr->bottom >= graphPtr->top); return (((double)graphPtr->right < extsPtr->left) || ((double)graphPtr->bottom < extsPtr->top) || (extsPtr->right < (double)graphPtr->left) || (extsPtr->bottom < (double)graphPtr->top)); } /* * ---------------------------------------------------------------------- * * GetCoordinate -- * * Convert the expression string into a floating point value. The * only reason we use this routine instead of Blt_ExprDouble is to * handle "elastic" bounds. That is, convert the strings "-Inf", * "Inf" into -(DBL_MAX) and DBL_MAX respectively. * * Results: * The return value is a standard Tcl result. The value of the * expression is passed back via valuePtr. * * ---------------------------------------------------------------------- */ static int GetCoordinate(interp, expr, valuePtr) Tcl_Interp *interp; /* Interpreter to send results back to */ char *expr; /* Numeric expression string to parse */ double *valuePtr; /* Real-valued result of expression */ { char c; 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_ExprDouble(interp, expr, valuePtr) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } /* * ---------------------------------------------------------------------- * * PrintCoordinate -- * * Convert the floating point value into its string * representation. The only reason this routine is used in * instead of sprintf, is to handle the "elastic" bounds. That * is, convert the values DBL_MAX and -(DBL_MAX) into "+Inf" and * "-Inf" respectively. * * Results: * The return value is a standard Tcl result. The string of the * expression is passed back via string. * * ---------------------------------------------------------------------- */ static char * PrintCoordinate(interp, x) Tcl_Interp *interp; double x; /* Numeric value */ { if (x == DBL_MAX) { return "+Inf"; } else if (x == -DBL_MAX) { return "-Inf"; } else { static char string[TCL_DOUBLE_SPACE + 1]; Tcl_PrintDouble(interp, (double)x, string); return string; } } /* * ---------------------------------------------------------------------- * * ParseCoordinates -- * * The Tcl coordinate list is converted to their floating point * values. It will then replace the current marker coordinates. * * Since different marker types require different number of * coordinates this must be checked here. * * Results: * The return value is a standard Tcl result. * * Side effects: * If the marker coordinates are reset, the graph is eventually * redrawn with at the new marker coordinates. * * ---------------------------------------------------------------------- */ static int ParseCoordinates(interp, markerPtr, nExprs, exprArr) Tcl_Interp *interp; Marker *markerPtr; int nExprs; char **exprArr; { int nWorldPts; int minArgs, maxArgs; Point2D *worldPts; register int i; register Point2D *pointPtr; double x, y; if (nExprs == 0) { return TCL_OK; } if (nExprs & 1) { Tcl_AppendResult(interp, "odd number of marker coordinates specified", (char *)NULL); return TCL_ERROR; } if (markerPtr->classUid == bltLineMarkerUid) { minArgs = 4, maxArgs = 0; } else if (markerPtr->classUid == bltPolygonMarkerUid) { minArgs = 6, maxArgs = 0; } else if ((markerPtr->classUid == bltWindowMarkerUid) || (markerPtr->classUid == bltTextMarkerUid)) { minArgs = 2, maxArgs = 2; } else if ((markerPtr->classUid == bltImageMarkerUid) || (markerPtr->classUid == bltBitmapMarkerUid)) { minArgs = 2, maxArgs = 4; } else { Tcl_AppendResult(interp, "unknown marker type", (char *)NULL); return TCL_ERROR; } if (nExprs < minArgs) { Tcl_AppendResult(interp, "too few marker coordinates specified", (char *)NULL); return TCL_ERROR; } if ((maxArgs > 0) && (nExprs > maxArgs)) { Tcl_AppendResult(interp, "too many marker coordinates specified", (char *)NULL); return TCL_ERROR; } nWorldPts = nExprs / 2; worldPts = Blt_Malloc(nWorldPts * sizeof(Point2D)); if (worldPts == NULL) { Tcl_AppendResult(interp, "can't allocate new coordinate array", (char *)NULL); return TCL_ERROR; } /* Don't free the old coordinate array until we've parsed the new * coordinates without errors. */ pointPtr = worldPts; for (i = 0; i < nExprs; i += 2) { if ((GetCoordinate(interp, exprArr[i], &x) != TCL_OK) || (GetCoordinate(interp, exprArr[i + 1], &y) != TCL_OK)) { Blt_Free(worldPts); return TCL_ERROR; } pointPtr->x = x, pointPtr->y = y; pointPtr++; } if (markerPtr->worldPts != NULL) { Blt_Free(markerPtr->worldPts); } markerPtr->worldPts = worldPts; markerPtr->nWorldPts = nWorldPts; markerPtr->flags |= MAP_ITEM; return TCL_OK; } /* * ---------------------------------------------------------------------- * * StringToCoordinates -- * * Given a Tcl list of numeric expression representing the * element values, convert into an array of floating point * values. In addition, the minimum and maximum values are saved. * Since elastic values are allow (values which translate to the * min/max of the graph), we must try to get the non-elastic * minimum and maximum. * * Results: * The return value is a standard Tcl result. The vector is * passed back via the vecPtr. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToCoordinates(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* Tcl list of numeric expressions */ char *widgRec; /* Marker record */ int offset; /* Not used. */ { Marker *markerPtr = (Marker *)widgRec; int nExprs; char **exprArr; int result; nExprs = 0; if ((string != NULL) && (Tcl_SplitList(interp, string, &nExprs, &exprArr) != TCL_OK)) { return TCL_ERROR; } if (nExprs == 0) { if (markerPtr->worldPts != NULL) { Blt_Free(markerPtr->worldPts); markerPtr->worldPts = NULL; } markerPtr->nWorldPts = 0; return TCL_OK; } result = ParseCoordinates(interp, markerPtr, nExprs, exprArr); Blt_Free(exprArr); return result; } /* * ---------------------------------------------------------------------- * * CoordinatesToString -- * * Convert the vector of floating point values into a Tcl list. * * Results: * The string representation of the vector is returned. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * CoordinatesToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Marker record */ int offset; /* Not used. */ Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */ { Marker *markerPtr = (Marker *)widgRec; Tcl_Interp *interp; Tcl_DString dString; char *result; register int i; register Point2D *p; if (markerPtr->nWorldPts < 1) { return ""; } interp = markerPtr->graphPtr->interp; Tcl_DStringInit(&dString); p = markerPtr->worldPts; for (i = 0; i < markerPtr->nWorldPts; i++) { Tcl_DStringAppendElement(&dString, PrintCoordinate(interp, p->x)); Tcl_DStringAppendElement(&dString, PrintCoordinate(interp, p->y)); p++; } result = Tcl_DStringValue(&dString); /* * If memory wasn't allocated for the dynamic string, do it here (it's * currently on the stack), so that Tcl can free it normally. */ if (result == dString.staticSpace) { result = Blt_Strdup(result); } *freeProcPtr = (Tcl_FreeProc *)Blt_Free; return result; } /* * ---------------------------------------------------------------------- * * HMap -- * * Map the given graph coordinate value to its axis, returning a * window position. * * Results: * Returns a floating point number representing the window * coordinate position on the given axis. * * ---------------------------------------------------------------------- */ static double HMap(graphPtr, axisPtr, x) Graph *graphPtr; Axis *axisPtr; double x; { register double norm; if (x == DBL_MAX) { norm = 1.0; } else if (x == -DBL_MAX) { norm = 0.0; } else { if (axisPtr->logScale) { if (x > 0.0) { x = log10(x); } else if (x < 0.0) { x = 0.0; } } norm = NORMALIZE(axisPtr, x); } if (axisPtr->descending) { norm = 1.0 - norm; } /* Horizontal transformation */ return ((norm * graphPtr->hRange) + graphPtr->hOffset); } /* * ---------------------------------------------------------------------- * * VMap -- * * Map the given graph coordinate value to its axis, returning a * window position. * * Results: * Returns a double precision number representing the window * coordinate position on the given axis. * * ---------------------------------------------------------------------- */ static double VMap(graphPtr, axisPtr, y) Graph *graphPtr; Axis *axisPtr; double y; { register double norm; if (y == DBL_MAX) { norm = 1.0; } else if (y == -DBL_MAX) { norm = 0.0; } else { if (axisPtr->logScale) { if (y > 0.0) { y = log10(y); } else if (y < 0.0) { y = 0.0; } } norm = NORMALIZE(axisPtr, y); } if (axisPtr->descending) { norm = 1.0 - norm; } /* Vertical transformation */ return (((1.0 - norm) * graphPtr->vRange) + graphPtr->vOffset); } /* * ---------------------------------------------------------------------- * * MapPoint -- * * Maps the given graph x,y coordinate values to a window position. * * Results: * Returns a XPoint structure containing the window coordinates * of the given graph x,y coordinate. * * ---------------------------------------------------------------------- */ static Point2D MapPoint(graphPtr, pointPtr, axesPtr) Graph *graphPtr; Point2D *pointPtr; /* Graph X-Y coordinate. */ Axis2D *axesPtr; /* Specifies which axes to use */ { Point2D result; if (graphPtr->inverted) { result.x = HMap(graphPtr, axesPtr->y, pointPtr->y); result.y = VMap(graphPtr, axesPtr->x, pointPtr->x); } else { result.x = HMap(graphPtr, axesPtr->x, pointPtr->x); result.y = VMap(graphPtr, axesPtr->y, pointPtr->y); } return result; /* Result is screen coordinate. */ } static Marker * CreateMarker(graphPtr, name, classUid) Graph *graphPtr; char *name; Blt_Uid classUid; { Marker *markerPtr; /* Create the new marker based upon the given type */ if (classUid == bltBitmapMarkerUid) { markerPtr = CreateBitmapMarker(); /* bitmap */ } else if (classUid == bltLineMarkerUid) { markerPtr = CreateLineMarker(); /* line */ } else if (classUid == bltImageMarkerUid) { markerPtr = CreateImageMarker(); /* image */ } else if (classUid == bltTextMarkerUid) { markerPtr = CreateTextMarker(); /* text */ } else if (classUid == bltPolygonMarkerUid) { markerPtr = CreatePolygonMarker(); /* polygon */ } else if (classUid == bltWindowMarkerUid) { markerPtr = CreateWindowMarker(); /* window */ } else { return NULL; } assert(markerPtr); markerPtr->graphPtr = graphPtr; markerPtr->hidden = markerPtr->drawUnder = FALSE; markerPtr->flags |= MAP_ITEM; markerPtr->name = Blt_Strdup(name); markerPtr->classUid = classUid; return markerPtr; } static void DestroyMarker(markerPtr) Marker *markerPtr; { Graph *graphPtr = markerPtr->graphPtr; if (markerPtr->drawUnder) { graphPtr->flags |= REDRAW_BACKING_STORE; } /* Free the resources allocated for the particular type of marker */ (*markerPtr->classPtr->freeProc) (graphPtr, markerPtr); if (markerPtr->worldPts != NULL) { Blt_Free(markerPtr->worldPts); } Blt_DeleteBindings(graphPtr->bindTable, markerPtr); Tk_FreeOptions(markerPtr->classPtr->configSpecs, (char *)markerPtr, graphPtr->display, 0); if (markerPtr->hashPtr != NULL) { Blt_DeleteHashEntry(&graphPtr->markers.table, markerPtr->hashPtr); } if (markerPtr->linkPtr != NULL) { Blt_ChainDeleteLink(graphPtr->markers.displayList, markerPtr->linkPtr); } if (markerPtr->name != NULL) { Blt_Free(markerPtr->name); } if (markerPtr->elemName != NULL) { Blt_Free(markerPtr->elemName); } if (markerPtr->tags != NULL) { Blt_Free(markerPtr->tags); } Blt_Free(markerPtr); } /* * ---------------------------------------------------------------------- * * ConfigureBitmapMarker -- * * This procedure is called to process an argv/argc list, plus * the Tk option database, in order to configure (or reconfigure) * a bitmap marker. * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side effects: * Configuration information, such as bitmap pixmap, colors, * rotation, etc. get set for markerPtr; old resources get freed, * if there were any. The marker is eventually redisplayed. * * ---------------------------------------------------------------------- */ /* ARGSUSED */ static int ConfigureBitmapMarker(markerPtr) Marker *markerPtr; { Graph *graphPtr = markerPtr->graphPtr; BitmapMarker *bmPtr = (BitmapMarker *)markerPtr; GC newGC; XGCValues gcValues; unsigned long gcMask; if (bmPtr->srcBitmap == None) { return TCL_OK; } if (bmPtr->destBitmap == None) { bmPtr->destBitmap = bmPtr->srcBitmap; } bmPtr->theta = FMOD(bmPtr->rotate, 360.0); if (bmPtr->theta < 0.0) { bmPtr->theta += 360.0; } gcMask = 0; if (bmPtr->outlineColor != NULL) { gcMask |= GCForeground; gcValues.foreground = bmPtr->outlineColor->pixel; } if (bmPtr->fillColor != NULL) { gcValues.background = bmPtr->fillColor->pixel; gcMask |= GCBackground; } else { gcValues.clip_mask = bmPtr->srcBitmap; gcMask |= GCClipMask; } /* Note that while this is a "shared" GC, we're going to change * the clip origin right before the bitmap is drawn anyways. This * assumes that any drawing code using this GC (with GCClipMask * set) is going to want to set the clip origin anyways. */ newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues); if (bmPtr->gc != NULL) { Tk_FreeGC(graphPtr->display, bmPtr->gc); } bmPtr->gc = newGC; /* Create background GC color */ if (bmPtr->fillColor != NULL) { gcValues.foreground = bmPtr->fillColor->pixel; newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues); if (bmPtr->fillGC != NULL) { Tk_FreeGC(graphPtr->display, bmPtr->fillGC); } bmPtr->fillGC = newGC; } bmPtr->flags |= MAP_ITEM; if (bmPtr->drawUnder) { graphPtr->flags |= REDRAW_BACKING_STORE; } Blt_EventuallyRedrawGraph(graphPtr); return TCL_OK; } /* * ---------------------------------------------------------------------- * * MapBitmapMarker -- * * This procedure gets called each time the layout of the graph * changes. The x, y window coordinates of the bitmap marker are * saved in the marker structure. * * Additionly, if no background color was specified, the * GCTileStipXOrigin and GCTileStipYOrigin attributes are set in * the private GC. * * Results: * None. * * Side effects: * Window coordinates are saved and if no background color was * set, the GC stipple origins are changed to calculated window * coordinates. * * ---------------------------------------------------------------------- */ static void MapBitmapMarker(markerPtr) Marker *markerPtr; { BitmapMarker *bmPtr = (BitmapMarker *)markerPtr; Extents2D exts; Graph *graphPtr = markerPtr->graphPtr; Point2D anchorPos; Point2D corner1, corner2; int destWidth, destHeight; int srcWidth, srcHeight; register int i; if (bmPtr->srcBitmap == None) { return; } if (bmPtr->destBitmap != bmPtr->srcBitmap) { Tk_FreePixmap(graphPtr->display, bmPtr->destBitmap); bmPtr->destBitmap = bmPtr->srcBitmap; } /* * Collect the coordinates. The number of coordinates will determine * the calculations to be made. * * x1 y1 A single pair of X-Y coordinates. They represent * the anchor position of the bitmap. * * x1 y1 x2 y2 Two pairs of X-Y coordinates. They represent * two opposite corners of a bounding rectangle. The * bitmap is possibly rotated and scaled to fit into * this box. * */ Tk_SizeOfBitmap(graphPtr->display, bmPtr->srcBitmap, &srcWidth, &srcHeight); corner1 = MapPoint(graphPtr, bmPtr->worldPts, &bmPtr->axes); if (bmPtr->nWorldPts > 1) { double hold; corner2 = MapPoint(graphPtr, bmPtr->worldPts + 1, &bmPtr->axes); /* Flip the corners if necessary */ if (corner1.x > corner2.x) { hold = corner1.x, corner1.x = corner2.x, corner2.x = hold; } if (corner1.y > corner2.y) { hold = corner1.y, corner1.y = corner2.y, corner2.y = hold; } } else { corner2.x = corner1.x + srcWidth - 1; corner2.y = corner1.y + srcHeight - 1; } destWidth = (int)(corner2.x - corner1.x) + 1; destHeight = (int)(corner2.y - corner1.y) + 1; if (bmPtr->nWorldPts == 1) { anchorPos = Blt_TranslatePoint(&corner1, destWidth, destHeight, bmPtr->anchor); } else { anchorPos = corner1; } anchorPos.x += bmPtr->xOffset; anchorPos.y += bmPtr->yOffset; /* Check if the bitmap sits at least partially in the plot area. */ exts.left = anchorPos.x; exts.top = anchorPos.y; exts.right = anchorPos.x + destWidth - 1; exts.bottom = anchorPos.y + destHeight - 1; bmPtr->clipped = BoxesDontOverlap(graphPtr, &exts); if (bmPtr->clipped) { return; /* Bitmap is offscreen. Don't generate * rotated or scaled bitmaps. */ } /* * Scale the bitmap if necessary. It's a little tricky because we * only want to scale what's visible on the screen, not the entire * bitmap. */ if ((bmPtr->theta != 0.0) || (destWidth != srcWidth) || (destHeight != srcHeight)) { int regionWidth, regionHeight; Region2D region; /* Indicates the portion of the scaled * bitmap that we want to display. */ double left, right, top, bottom; /* * Determine the region of the bitmap visible in the plot area. */ left = MAX(graphPtr->left, exts.left); right = MIN(graphPtr->right, exts.right); top = MAX(graphPtr->top, exts.top); bottom = MIN(graphPtr->bottom, exts.bottom); region.left = region.top = 0; if (graphPtr->left > exts.left) { region.left = (int)(graphPtr->left - exts.left); } if (graphPtr->top > exts.top) { region.top = (int)(graphPtr->top - exts.top); } regionWidth = (int)(right - left) + 1; regionHeight = (int)(bottom - top) + 1; region.right = region.left + (int)(right - left); region.bottom = region.top + (int)(bottom - top); anchorPos.x = left; anchorPos.y = top; bmPtr->destBitmap = Blt_ScaleRotateBitmapRegion(graphPtr->tkwin, bmPtr->srcBitmap, srcWidth, srcHeight, region.left, region.top, regionWidth, regionHeight, destWidth, destHeight, bmPtr->theta); bmPtr->destWidth = regionWidth; bmPtr->destHeight = regionHeight; } else { bmPtr->destWidth = srcWidth; bmPtr->destHeight = srcHeight; bmPtr->destBitmap = bmPtr->srcBitmap; } bmPtr->anchorPos = anchorPos; { double xScale, yScale; double tx, ty; double rotWidth, rotHeight; Point2D polygon[5]; int n; /* * Compute a polygon to represent the background area of the bitmap. * This is needed for backgrounds of arbitrarily rotated bitmaps. * We also use it to print a background in PostScript. */ Blt_GetBoundingBox(srcWidth, srcHeight, bmPtr->theta, &rotWidth, &rotHeight, polygon); xScale = (double)destWidth / rotWidth; yScale = (double)destHeight / rotHeight; /* * Adjust each point of the polygon. Both scale it to the new size * and translate it to the actual screen position of the bitmap. */ tx = exts.left + destWidth * 0.5; ty = exts.top + destHeight * 0.5; for (i = 0; i < 4; i++) { polygon[i].x = (polygon[i].x * xScale) + tx; polygon[i].y = (polygon[i].y * yScale) + ty; } Blt_GraphExtents(graphPtr, &exts); n = Blt_PolyRectClip(&exts, polygon, 4, bmPtr->outline); assert(n <= MAX_OUTLINE_POINTS); if (n < 3) { memcpy(&bmPtr->outline, polygon, sizeof(Point2D) * 4); bmPtr->nOutlinePts = 4; } else { bmPtr->nOutlinePts = n; } } } /* * ---------------------------------------------------------------------- * * PointInBitmapMarker -- * * Indicates if the given point is over the bitmap marker. The * area of the bitmap is the rectangle. * * Results: * Returns 1 is the point is over the bitmap marker, 0 otherwise. * * ---------------------------------------------------------------------- */ static int PointInBitmapMarker(markerPtr, samplePtr) Marker *markerPtr; Point2D *samplePtr; { BitmapMarker *bmPtr = (BitmapMarker *)markerPtr; if (bmPtr->srcBitmap == None) { return 0; } if (bmPtr->theta != 0.0) { Point2D points[MAX_OUTLINE_POINTS]; register int i; /* * Generate the bounding polygon (isolateral) for the bitmap * and see if the point is inside of it. */ for (i = 0; i < bmPtr->nOutlinePts; i++) { points[i].x = bmPtr->outline[i].x + bmPtr->anchorPos.x; points[i].y = bmPtr->outline[i].y + bmPtr->anchorPos.y; } return Blt_PointInPolygon(samplePtr, points, bmPtr->nOutlinePts); } return ((samplePtr->x >= bmPtr->anchorPos.x) && (samplePtr->x < (bmPtr->anchorPos.x + bmPtr->destWidth)) && (samplePtr->y >= bmPtr->anchorPos.y) && (samplePtr->y < (bmPtr->anchorPos.y + bmPtr->destHeight))); } /* * ---------------------------------------------------------------------- * * RegionInBitmapMarker -- * * ---------------------------------------------------------------------- */ static int RegionInBitmapMarker(markerPtr, extsPtr, enclosed) Marker *markerPtr; Extents2D *extsPtr; int enclosed; { BitmapMarker *bmPtr = (BitmapMarker *)markerPtr; if (bmPtr->nWorldPts < 1) { return FALSE; } if (bmPtr->theta != 0.0) { Point2D points[MAX_OUTLINE_POINTS]; register int i; /* * Generate the bounding polygon (isolateral) for the bitmap * and see if the point is inside of it. */ for (i = 0; i < bmPtr->nOutlinePts; i++) { points[i].x = bmPtr->outline[i].x + bmPtr->anchorPos.x; points[i].y = bmPtr->outline[i].y + bmPtr->anchorPos.y; } return Blt_RegionInPolygon(extsPtr, points, bmPtr->nOutlinePts, enclosed); } if (enclosed) { return ((bmPtr->anchorPos.x >= extsPtr->left) && (bmPtr->anchorPos.y >= extsPtr->top) && ((bmPtr->anchorPos.x + bmPtr->destWidth) <= extsPtr->right) && ((bmPtr->anchorPos.y + bmPtr->destHeight) <= extsPtr->bottom)); } return !((bmPtr->anchorPos.x >= extsPtr->right) || (bmPtr->anchorPos.y >= extsPtr->bottom) || ((bmPtr->anchorPos.x + bmPtr->destWidth) <= extsPtr->left) || ((bmPtr->anchorPos.y + bmPtr->destHeight) <= extsPtr->top)); } /* * ---------------------------------------------------------------------- * * DrawBitmapMarker -- * * Draws the bitmap marker that have a transparent of filled * background. * * Results: * None. * * Side effects: * GC stipple origins are changed to current window coordinates. * Commands are output to X to draw the marker in its current * mode. * * ---------------------------------------------------------------------- */ static void DrawBitmapMarker(markerPtr, drawable) Marker *markerPtr; Drawable drawable; /* Pixmap or window to draw into */ { Graph *graphPtr = markerPtr->graphPtr; BitmapMarker *bmPtr = (BitmapMarker *)markerPtr; double theta; if ((bmPtr->destBitmap == None) || (bmPtr->destWidth < 1) || (bmPtr->destHeight < 1)) { return; } theta = FMOD(bmPtr->theta, (double)90.0); if ((bmPtr->fillColor == NULL) || (theta != 0.0)) { /* * If the bitmap is rotated and a filled background is * required, then a filled polygon is drawn before the * bitmap. */ if (bmPtr->fillColor != NULL) { int i; XPoint polygon[MAX_OUTLINE_POINTS]; for (i = 0; i < bmPtr->nOutlinePts; i++) { polygon[i].x = (short int)bmPtr->outline[i].x; polygon[i].y = (short int)bmPtr->outline[i].y; } XFillPolygon(graphPtr->display, drawable, bmPtr->fillGC, polygon, bmPtr->nOutlinePts, Convex, CoordModeOrigin); } XSetClipMask(graphPtr->display, bmPtr->gc, bmPtr->destBitmap); XSetClipOrigin(graphPtr->display, bmPtr->gc, (int)bmPtr->anchorPos.x, (int)bmPtr->anchorPos.y); } else { XSetClipMask(graphPtr->display, bmPtr->gc, None); XSetClipOrigin(graphPtr->display, bmPtr->gc, 0, 0); } XCopyPlane(graphPtr->display, bmPtr->destBitmap, drawable, bmPtr->gc, 0, 0, bmPtr->destWidth, bmPtr->destHeight, (int)bmPtr->anchorPos.x, (int)bmPtr->anchorPos.y, 1); } /* * ---------------------------------------------------------------------- * * BitmapMarkerToPostScript -- * * Generates PostScript to print a bitmap marker. * * Results: * None. * * ---------------------------------------------------------------------- */ static void BitmapMarkerToPostScript(markerPtr, psToken) Marker *markerPtr; /* Marker to be printed */ PsToken psToken; { Graph *graphPtr = markerPtr->graphPtr; BitmapMarker *bmPtr = (BitmapMarker *)markerPtr; if (bmPtr->destBitmap == None) { return; } if (bmPtr->fillColor != NULL) { Blt_BackgroundToPostScript(psToken, bmPtr->fillColor); Blt_PolygonToPostScript(psToken, bmPtr->outline, 4); } Blt_ForegroundToPostScript(psToken, bmPtr->outlineColor); Blt_FormatToPostScript(psToken, " gsave\n %g %g translate\n %d %d scale\n", bmPtr->anchorPos.x, bmPtr->anchorPos.y + bmPtr->destHeight, bmPtr->destWidth, -bmPtr->destHeight); Blt_FormatToPostScript(psToken, " %d %d true [%d 0 0 %d 0 %d] {", bmPtr->destWidth, bmPtr->destHeight, bmPtr->destWidth, -bmPtr->destHeight, bmPtr->destHeight); Blt_BitmapDataToPostScript(psToken, graphPtr->display, bmPtr->destBitmap, bmPtr->destWidth, bmPtr->destHeight); Blt_AppendToPostScript(psToken, " } imagemask\n", "grestore\n", (char *)NULL); } /* * ---------------------------------------------------------------------- * * FreeBitmapMarker -- * * Releases the memory and attributes of the bitmap marker. * * Results: * None. * * Side effects: * Bitmap attributes (GCs, colors, bitmap, etc) get destroyed. * Memory is released, X resources are freed, and the graph is * redrawn. * * ---------------------------------------------------------------------- */ static void FreeBitmapMarker(graphPtr, markerPtr) Graph *graphPtr; Marker *markerPtr; { BitmapMarker *bmPtr = (BitmapMarker *)markerPtr; if (bmPtr->gc != NULL) { Tk_FreeGC(graphPtr->display, bmPtr->gc); } if (bmPtr->fillGC != NULL) { Tk_FreeGC(graphPtr->display, bmPtr->fillGC); } if (bmPtr->destBitmap != bmPtr->srcBitmap) { Tk_FreePixmap(graphPtr->display, bmPtr->destBitmap); } } /* * ---------------------------------------------------------------------- * * CreateBitmapMarker -- * * Allocate memory and initialize methods for the new bitmap marker. * * Results: * The pointer to the newly allocated marker structure is returned. * * Side effects: * Memory is allocated for the bitmap marker structure. * * ---------------------------------------------------------------------- */ static Marker * CreateBitmapMarker() { BitmapMarker *bmPtr; bmPtr = Blt_Calloc(1, sizeof(BitmapMarker)); if (bmPtr != NULL) { bmPtr->classPtr = &bitmapMarkerClass; } return (Marker *)bmPtr; } /* *---------------------------------------------------------------------- * * ImageChangedProc * * * Results: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static void ImageChangedProc(clientData, x, y, width, height, imageWidth, imageHeight) ClientData clientData; int x, y, width, height; /* Not used. */ int imageWidth, imageHeight; /* Not used. */ { ImageMarker *imPtr = clientData; Tk_PhotoHandle photo; photo = Blt_FindPhoto(imPtr->graphPtr->interp, imPtr->imageName); if (photo != NULL) { if (imPtr->srcImage != NULL) { Blt_FreeColorImage(imPtr->srcImage); } /* Convert the latest incarnation of the photo image back to a * color image that we can scale. */ imPtr->srcImage = Blt_PhotoToColorImage(photo); } imPtr->graphPtr->flags |= REDRAW_BACKING_STORE; imPtr->flags |= MAP_ITEM; Blt_EventuallyRedrawGraph(imPtr->graphPtr); } /* * ---------------------------------------------------------------------- * * ConfigureImageMarker -- * * This procedure is called to process an argv/argc list, plus * the Tk option database, in order to configure (or reconfigure) * a image marker. * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side effects: * Configuration information, such as image pixmap, colors, * rotation, etc. get set for markerPtr; old resources get freed, * if there were any. The marker is eventually redisplayed. * * ---------------------------------------------------------------------- */ static int ConfigureImageMarker(markerPtr) Marker *markerPtr; { ImageMarker *imPtr = (ImageMarker *)markerPtr; Graph *graphPtr = markerPtr->graphPtr; if (Blt_ConfigModified(markerPtr->classPtr->configSpecs, "-image", (char *)NULL)) { Tcl_Interp *interp = graphPtr->interp; if (imPtr->tkImage != NULL) { Tk_FreeImage(imPtr->tkImage); imPtr->tkImage = NULL; } if (imPtr->imageName[0] != '\0') { GC newGC; Tk_PhotoHandle photo; imPtr->tkImage = Tk_GetImage(interp, graphPtr->tkwin, imPtr->imageName, ImageChangedProc, imPtr); if (imPtr->tkImage == NULL) { Tcl_AppendResult(interp, "can't find an image \"", imPtr->imageName, "\"", (char *)NULL); Blt_Free(imPtr->imageName); imPtr->imageName = NULL; return TCL_ERROR; } photo = Blt_FindPhoto(interp, imPtr->imageName); if (photo != NULL) { if (imPtr->srcImage != NULL) { Blt_FreeColorImage(imPtr->srcImage); } /* Convert the photo into a color image */ imPtr->srcImage = Blt_PhotoToColorImage(photo); } newGC = Tk_GetGC(graphPtr->tkwin, 0L, (XGCValues *)NULL); if (imPtr->gc != NULL) { Tk_FreeGC(graphPtr->display, imPtr->gc); } imPtr->gc = newGC; } } imPtr->flags |= MAP_ITEM; if (imPtr->drawUnder) { graphPtr->flags |= REDRAW_BACKING_STORE; } Blt_EventuallyRedrawGraph(graphPtr); return TCL_OK; } /* * ---------------------------------------------------------------------- * * MapImageMarker -- * * This procedure gets called each time the layout of the graph * changes. The x, y window coordinates of the image marker are * saved in the marker structure. * * Additionly, if no background color was specified, the * GCTileStipXOrigin and GCTileStipYOrigin attributes are set in * the private GC. * * Results: * None. * * Side effects: * Window coordinates are saved and if no background color was * * set, the GC stipple origins are changed to calculated window * coordinates. * * ---------------------------------------------------------------------- */ static void MapImageMarker(markerPtr) Marker *markerPtr; { Extents2D exts; Graph *graphPtr; ImageMarker *imPtr; Point2D anchorPos; Point2D corner1, corner2; int scaledWidth, scaledHeight; int srcWidth, srcHeight; imPtr = (ImageMarker *)markerPtr; if (imPtr->tkImage == NULL) { return; } graphPtr = imPtr->graphPtr; corner1 = MapPoint(graphPtr, imPtr->worldPts, &imPtr->axes); if (imPtr->srcImage == NULL) { /* * Don't scale or rotate non-photo images. */ Tk_SizeOfImage(imPtr->tkImage, &srcWidth, &srcHeight); imPtr->width = srcWidth; imPtr->height = srcHeight; imPtr->anchorPos.x = corner1.x + imPtr->xOffset; imPtr->anchorPos.y = corner1.y + imPtr->yOffset; exts.left = imPtr->anchorPos.x; exts.top = imPtr->anchorPos.y; exts.right = exts.left + srcWidth - 1; exts.bottom = exts.top + srcHeight - 1; imPtr->clipped = BoxesDontOverlap(graphPtr, &exts); return; } imPtr->width = srcWidth = Blt_ColorImageWidth(imPtr->srcImage); imPtr->height = srcHeight = Blt_ColorImageHeight(imPtr->srcImage); if ((srcWidth == 0) && (srcHeight == 0)) { imPtr->clipped = TRUE; return; /* Empty image. */ } if (imPtr->nWorldPts > 1) { double hold; corner2 = MapPoint(graphPtr, imPtr->worldPts + 1, &imPtr->axes); /* Flip the corners if necessary */ if (corner1.x > corner2.x) { hold = corner1.x, corner1.x = corner2.x, corner2.x = hold; } if (corner1.y > corner2.y) { hold = corner1.y, corner1.y = corner2.y, corner2.y = hold; } } else { corner2.x = corner1.x + srcWidth - 1; corner2.y = corner1.y + srcHeight - 1; } scaledWidth = (int)(corner2.x - corner1.x) + 1; scaledHeight = (int)(corner2.y - corner1.y) + 1; if (imPtr->nWorldPts == 1) { anchorPos = Blt_TranslatePoint(&corner1, scaledWidth, scaledHeight, imPtr->anchor); } else { anchorPos = corner1; } anchorPos.x += imPtr->xOffset; anchorPos.y += imPtr->yOffset; /* Check if the image sits at least partially in the plot area. */ exts.left = anchorPos.x; exts.top = anchorPos.y; exts.right = anchorPos.x + scaledWidth - 1; exts.bottom = anchorPos.y + scaledHeight - 1; imPtr->clipped = BoxesDontOverlap(graphPtr, &exts); if (imPtr->clipped) { return; /* Image is offscreen. Don't generate * rotated or scaled images. */ } if ((scaledWidth != srcWidth) || (scaledHeight != srcHeight)) { Tk_PhotoHandle photo; Blt_ColorImage destImage; int x, y, width, height; int left, right, top, bottom; /* Determine the region of the subimage inside of the * destination image. */ left = MAX((int)exts.left, graphPtr->left); top = MAX((int)exts.top, graphPtr->top); right = MIN((int)exts.right, graphPtr->right); bottom = MIN((int)exts.bottom, graphPtr->bottom); /* Reset image location and coordinates to that of the region */ anchorPos.x = left; anchorPos.y = top; x = y = 0; if (graphPtr->left > (int)exts.left) { x = graphPtr->left - (int)exts.left; } if (graphPtr->top > (int)exts.top) { y = graphPtr->top - (int)exts.top; } width = (int)(right - left + 1); height = (int)(bottom - top + 1); destImage = Blt_ResizeColorSubimage(imPtr->srcImage, x, y, width, height, scaledWidth, scaledHeight); #ifdef notyet /* Now convert the color image into a pixmap */ if (imPtr->pixmap != None) { Blt_FreeColorTable(imPtr->colorTable); Tk_FreePixmap(Tk_Display(graphPtr->tkwin), imPtr->pixmap); imPtr->colorTable = NULL; } imPtr->pixmap = Blt_ColorImageToPixmap(graphPtr->interp, graphPtr->tkwin, destImage, &imPtr->colorTable); #else imPtr->pixmap = None; if (imPtr->tmpImage == NULL) { imPtr->tmpImage = Blt_CreateTemporaryImage(graphPtr->interp, graphPtr->tkwin, imPtr); if (imPtr->tmpImage == NULL) { return; } } /* Put the scaled colorimage into the photo. */ photo = Blt_FindPhoto(graphPtr->interp, Blt_NameOfImage(imPtr->tmpImage)); Blt_ColorImageToPhoto(destImage, photo); #endif Blt_FreeColorImage(destImage); imPtr->width = width; imPtr->height = height; } imPtr->anchorPos = anchorPos; } /* * ---------------------------------------------------------------------- * * PointInWindowMarker -- * * Indicates if the given point is over the window marker. The * area of the window is the rectangle. * * Results: * Returns 1 is the point is over the window marker, 0 otherwise. * * ---------------------------------------------------------------------- */ static int PointInImageMarker(markerPtr, samplePtr) Marker *markerPtr; Point2D *samplePtr; { ImageMarker *imPtr = (ImageMarker *)markerPtr; return ((samplePtr->x >= imPtr->anchorPos.x) && (samplePtr->x < (imPtr->anchorPos.x + imPtr->width)) && (samplePtr->y >= imPtr->anchorPos.y) && (samplePtr->y < (imPtr->anchorPos.y + imPtr->height))); } /* * ---------------------------------------------------------------------- * * RegionInImageMarker -- * * ---------------------------------------------------------------------- */ static int RegionInImageMarker(markerPtr, extsPtr, enclosed) Marker *markerPtr; Extents2D *extsPtr; int enclosed; { ImageMarker *imPtr = (ImageMarker *)markerPtr; if (imPtr->nWorldPts < 1) { return FALSE; } if (enclosed) { return ((imPtr->anchorPos.x >= extsPtr->left) && (imPtr->anchorPos.y >= extsPtr->top) && ((imPtr->anchorPos.x + imPtr->width) <= extsPtr->right) && ((imPtr->anchorPos.y + imPtr->height) <= extsPtr->bottom)); } return !((imPtr->anchorPos.x >= extsPtr->right) || (imPtr->anchorPos.y >= extsPtr->bottom) || ((imPtr->anchorPos.x + imPtr->width) <= extsPtr->left) || ((imPtr->anchorPos.y + imPtr->height) <= extsPtr->top)); } /* * ---------------------------------------------------------------------- * * DrawImageMarker -- * * This procedure is invoked to draw a image marker. * * Results: * None. * * Side effects: * GC stipple origins are changed to current window coordinates. * Commands are output to X to draw the marker in its current mode. * * ---------------------------------------------------------------------- */ static void DrawImageMarker(markerPtr, drawable) Marker *markerPtr; Drawable drawable; /* Pixmap or window to draw into */ { ImageMarker *imPtr = (ImageMarker *)markerPtr; int width, height; if ((imPtr->tkImage == NULL) || (Tk_ImageIsDeleted(imPtr->tkImage))) { return; } if (imPtr->pixmap == None) { Pixmap pixmap; Tk_Image tkImage; tkImage = (imPtr->tmpImage != NULL) ? imPtr->tmpImage : imPtr->tkImage; Tk_SizeOfImage(tkImage, &width, &height); /* pixmap = Tk_ImageGetPhotoPixmap(tkImage); */ pixmap = None; if (pixmap == None) { /* May not be a "photo" image. */ Tk_RedrawImage(tkImage, 0, 0, width, height, drawable, (int)imPtr->anchorPos.x, (int)imPtr->anchorPos.y); } else { XCopyArea(imPtr->graphPtr->display, pixmap, drawable, imPtr->gc, 0, 0, width, height, (int)imPtr->anchorPos.x, (int)imPtr->anchorPos.y); } } else { XCopyArea(imPtr->graphPtr->display, imPtr->pixmap, drawable, imPtr->gc, 0, 0, imPtr->width, imPtr->height, (int)imPtr->anchorPos.x, (int)imPtr->anchorPos.y); } } /* * ---------------------------------------------------------------------- * * ImageMarkerToPostScript -- * * This procedure is invoked to print a image marker. * * Results: * None. * * ---------------------------------------------------------------------- */ static void ImageMarkerToPostScript(markerPtr, psToken) Marker *markerPtr; /* Marker to be printed */ PsToken psToken; { ImageMarker *imPtr = (ImageMarker *)markerPtr; char *imageName; Tk_PhotoHandle photo; if ((imPtr->tkImage == NULL) || (Tk_ImageIsDeleted(imPtr->tkImage))) { return; /* Image doesn't exist anymore */ } imageName = (imPtr->tmpImage == NULL) ? Blt_NameOfImage(imPtr->tkImage) : Blt_NameOfImage(imPtr->tmpImage); photo = Blt_FindPhoto(markerPtr->graphPtr->interp, imageName); if (photo == NULL) { return; /* Image isn't a photo image */ } Blt_PhotoToPostScript(psToken, photo, imPtr->anchorPos.x, imPtr->anchorPos.y); } /* * ---------------------------------------------------------------------- * * FreeImageMarker -- * * Destroys the structure containing the attributes of the image * marker. * * Results: * None. * * Side effects: * Image attributes (GCs, colors, image, etc) get destroyed. * Memory is released, X resources are freed, and the graph is * redrawn. * * ---------------------------------------------------------------------- */ static void FreeImageMarker(graphPtr, markerPtr) Graph *graphPtr; Marker *markerPtr; { ImageMarker *imPtr = (ImageMarker *)markerPtr; if (imPtr->pixmap != None) { Tk_FreePixmap(graphPtr->display, imPtr->pixmap); } if (imPtr->tkImage != NULL) { Tk_FreeImage(imPtr->tkImage); } if (imPtr->tmpImage != NULL) { Blt_DestroyTemporaryImage(graphPtr->interp, imPtr->tmpImage); } if (imPtr->srcImage != NULL) { Blt_FreeColorImage(imPtr->srcImage); } } /* * ---------------------------------------------------------------------- * * CreateImageMarker -- * * Allocate memory and initialize methods for the new image marker. * * Results: * The pointer to the newly allocated marker structure is returned. * * Side effects: * Memory is allocated for the image marker structure. * * ---------------------------------------------------------------------- */ static Marker * CreateImageMarker() { ImageMarker *imPtr; imPtr = Blt_Calloc(1, sizeof(ImageMarker)); if (imPtr != NULL) { imPtr->classPtr = &imageMarkerClass; } return (Marker *)imPtr; } /* * ---------------------------------------------------------------------- * * ConfigureTextMarker -- * * This procedure is called to process an argv/argc list, plus * the Tk option database, in order to configure (or * reconfigure) a text marker. * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for markerPtr; old resources get freed, if there * were any. The marker is eventually redisplayed. * * ---------------------------------------------------------------------- */ static int ConfigureTextMarker(markerPtr) Marker *markerPtr; { Graph *graphPtr = markerPtr->graphPtr; TextMarker *tmPtr = (TextMarker *)markerPtr; GC newGC; XGCValues gcValues; unsigned long gcMask; tmPtr->style.theta = FMOD(tmPtr->style.theta, 360.0); if (tmPtr->style.theta < 0.0) { tmPtr->style.theta += 360.0; } newGC = NULL; if (tmPtr->fillColor != NULL) { gcMask = GCForeground; gcValues.foreground = tmPtr->fillColor->pixel; newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues); } if (tmPtr->fillGC != NULL) { Tk_FreeGC(graphPtr->display, tmPtr->fillGC); } tmPtr->fillGC = newGC; Blt_ResetTextStyle(graphPtr->tkwin, &tmPtr->style); if (Blt_ConfigModified(tmPtr->classPtr->configSpecs, "-text", (char *)NULL)) { if (tmPtr->textPtr != NULL) { Blt_Free(tmPtr->textPtr); tmPtr->textPtr = NULL; } tmPtr->width = tmPtr->height = 0; if (tmPtr->string != NULL) { register int i; double rotWidth, rotHeight; tmPtr->textPtr = Blt_GetTextLayout(tmPtr->string, &tmPtr->style); Blt_GetBoundingBox(tmPtr->textPtr->width, tmPtr->textPtr->height, tmPtr->style.theta, &rotWidth, &rotHeight, tmPtr->outline); tmPtr->width = ROUND(rotWidth); tmPtr->height = ROUND(rotHeight); for (i = 0; i < 4; i++) { tmPtr->outline[i].x += ROUND(rotWidth * 0.5); tmPtr->outline[i].y += ROUND(rotHeight * 0.5); } tmPtr->outline[4].x = tmPtr->outline[0].x; tmPtr->outline[4].y = tmPtr->outline[0].y; } } tmPtr->flags |= MAP_ITEM; if (tmPtr->drawUnder) { graphPtr->flags |= REDRAW_BACKING_STORE; } Blt_EventuallyRedrawGraph(graphPtr); return TCL_OK; } /* * ---------------------------------------------------------------------- * * MapTextMarker -- * * Calculate the layout position for a text marker. Positional * information is saved in the marker. If the text is rotated, * a bitmap containing the text is created. * * Results: * None. * * Side effects: * If no background color has been specified, the GC stipple * origins are changed to current window coordinates. For both * rotated and non-rotated text, if any old bitmap is leftover, * it is freed. * * ---------------------------------------------------------------------- */ static void MapTextMarker(markerPtr) Marker *markerPtr; { Graph *graphPtr = markerPtr->graphPtr; TextMarker *tmPtr = (TextMarker *)markerPtr; Extents2D exts; Point2D anchorPos; if (tmPtr->string == NULL) { return; } anchorPos = MapPoint(graphPtr, tmPtr->worldPts, &tmPtr->axes); anchorPos = Blt_TranslatePoint(&anchorPos, tmPtr->width, tmPtr->height, tmPtr->anchor); anchorPos.x += tmPtr->xOffset; anchorPos.y += tmPtr->yOffset; /* * Determine the bounding box of the text and test to see if it * is at least partially contained within the plotting area. */ exts.left = anchorPos.x; exts.top = anchorPos.y; exts.right = anchorPos.x + tmPtr->width - 1; exts.bottom = anchorPos.y + tmPtr->height - 1; tmPtr->clipped = BoxesDontOverlap(graphPtr, &exts); tmPtr->anchorPos = anchorPos; } static int PointInTextMarker(markerPtr, samplePtr) Marker *markerPtr; Point2D *samplePtr; { TextMarker *tmPtr = (TextMarker *)markerPtr; if (tmPtr->string == NULL) { return 0; } if (tmPtr->style.theta != 0.0) { Point2D points[5]; register int i; /* * Figure out the bounding polygon (isolateral) for the text * and see if the point is inside of it. */ for (i = 0; i < 5; i++) { points[i].x = tmPtr->outline[i].x + tmPtr->anchorPos.x; points[i].y = tmPtr->outline[i].y + tmPtr->anchorPos.y; } return Blt_PointInPolygon(samplePtr, points, 5); } return ((samplePtr->x >= tmPtr->anchorPos.x) && (samplePtr->x < (tmPtr->anchorPos.x + tmPtr->width)) && (samplePtr->y >= tmPtr->anchorPos.y) && (samplePtr->y < (tmPtr->anchorPos.y + tmPtr->height))); } /* * ---------------------------------------------------------------------- * * RegionInTextMarker -- * * ---------------------------------------------------------------------- */ static int RegionInTextMarker(markerPtr, extsPtr, enclosed) Marker *markerPtr; Extents2D *extsPtr; int enclosed; { TextMarker *tmPtr = (TextMarker *)markerPtr; if (tmPtr->nWorldPts < 1) { return FALSE; } if (tmPtr->style.theta != 0.0) { Point2D points[5]; register int i; /* * Generate the bounding polygon (isolateral) for the bitmap * and see if the point is inside of it. */ for (i = 0; i < 4; i++) { points[i].x = tmPtr->outline[i].x + tmPtr->anchorPos.x; points[i].y = tmPtr->outline[i].y + tmPtr->anchorPos.y; } return Blt_RegionInPolygon(extsPtr, points, 4, enclosed); } if (enclosed) { return ((tmPtr->anchorPos.x >= extsPtr->left) && (tmPtr->anchorPos.y >= extsPtr->top) && ((tmPtr->anchorPos.x + tmPtr->width) <= extsPtr->right) && ((tmPtr->anchorPos.y + tmPtr->height) <= extsPtr->bottom)); } return !((tmPtr->anchorPos.x >= extsPtr->right) || (tmPtr->anchorPos.y >= extsPtr->bottom) || ((tmPtr->anchorPos.x + tmPtr->width) <= extsPtr->left) || ((tmPtr->anchorPos.y + tmPtr->height) <= extsPtr->top)); } /* * ---------------------------------------------------------------------- * * DrawTextMarker -- * * Draws the text marker on the graph. * * Results: * None. * * Side effects: * Commands are output to X to draw the marker in its current * mode. * * ---------------------------------------------------------------------- */ static void DrawTextMarker(markerPtr, drawable) Marker *markerPtr; Drawable drawable; /* Pixmap or window to draw into */ { TextMarker *tmPtr = (TextMarker *)markerPtr; Graph *graphPtr = markerPtr->graphPtr; if (tmPtr->string == NULL) { return; } if (tmPtr->fillGC != NULL) { XPoint pointArr[4]; register int i; /* * Simulate the rotated background of the bitmap by * filling a bounding polygon with the background color. */ for (i = 0; i < 4; i++) { pointArr[i].x = (short int) (tmPtr->outline[i].x + tmPtr->anchorPos.x); pointArr[i].y = (short int) (tmPtr->outline[i].y + tmPtr->anchorPos.y); } XFillPolygon(graphPtr->display, drawable, tmPtr->fillGC, pointArr, 4, Convex, CoordModeOrigin); } if (tmPtr->style.color != NULL) { Blt_DrawTextLayout(graphPtr->tkwin, drawable, tmPtr->textPtr, &tmPtr->style, (int)tmPtr->anchorPos.x, (int)tmPtr->anchorPos.y); } } /* * ---------------------------------------------------------------------- * * TextMarkerToPostScript -- * * Outputs PostScript commands to draw a text marker at a given * x,y coordinate, rotation, anchor, and font. * * Results: * None. * * Side effects: * PostScript font and color settings are changed. * * ---------------------------------------------------------------------- */ static void TextMarkerToPostScript(markerPtr, psToken) Marker *markerPtr; PsToken psToken; { TextMarker *tmPtr = (TextMarker *)markerPtr; if (tmPtr->string == NULL) { return; } if (tmPtr->fillGC != NULL) { Point2D polygon[4]; register int i; /* * Simulate the rotated background of the bitmap by * filling a bounding polygon with the background color. */ for (i = 0; i < 4; i++) { polygon[i].x = tmPtr->outline[i].x + tmPtr->anchorPos.x; polygon[i].y = tmPtr->outline[i].y + tmPtr->anchorPos.y; } Blt_BackgroundToPostScript(psToken, tmPtr->fillColor); Blt_PolygonToPostScript(psToken, polygon, 4); } Blt_TextToPostScript(psToken, tmPtr->string, &tmPtr->style, tmPtr->anchorPos.x, tmPtr->anchorPos.y); } /* * ---------------------------------------------------------------------- * * FreeTextMarker -- * * Destroys the structure containing the attributes of the text * marker. * * Results: * None. * * Side effects: * Text attributes (GCs, colors, stipple, font, etc) get destroyed. * Memory is released, X resources are freed, and the graph is * redrawn. * * ---------------------------------------------------------------------- */ static void FreeTextMarker(graphPtr, markerPtr) Graph *graphPtr; Marker *markerPtr; { TextMarker *tmPtr = (TextMarker *)markerPtr; Blt_FreeTextStyle(graphPtr->display, &tmPtr->style); if (tmPtr->textPtr != NULL) { Blt_Free(tmPtr->textPtr); } } /* * ---------------------------------------------------------------------- * * CreateTextMarker -- * * Allocate memory and initialize methods for the new text marker. * * Results: * The pointer to the newly allocated marker structure is returned. * * Side effects: * Memory is allocated for the text marker structure. * * ---------------------------------------------------------------------- */ static Marker * CreateTextMarker() { TextMarker *tmPtr; tmPtr = Blt_Calloc(1, sizeof(TextMarker)); assert(tmPtr); tmPtr->classPtr = &textMarkerClass; Blt_InitTextStyle(&tmPtr->style); tmPtr->style.anchor = TK_ANCHOR_NW; tmPtr->style.padLeft = tmPtr->style.padRight = 4; tmPtr->style.padTop = tmPtr->style.padBottom = 4; return (Marker *)tmPtr; } static void ChildEventProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); static void ChildGeometryProc _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin)); static void ChildCustodyProc _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin)); static Tk_GeomMgr winMarkerMgrInfo = { "graph", /* Name of geometry manager used by winfo */ ChildGeometryProc, /* Procedure to for new geometry requests */ ChildCustodyProc, /* Procedure when window is taken away */ }; /* * ---------------------------------------------------------------------- * * ConfigureWindowMarker -- * * This procedure is called to process an argv/argc list, plus * the Tk option database, in order to configure (or reconfigure) * a window marker. * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side effects: * Configuration information, such as window pathname, placement, * etc. get set for markerPtr; old resources get freed, if there * were any. The marker is eventually redisplayed. * * ---------------------------------------------------------------------- */ static int ConfigureWindowMarker(markerPtr) Marker *markerPtr; { Graph *graphPtr = markerPtr->graphPtr; WindowMarker *wmPtr = (WindowMarker *)markerPtr; Tk_Window tkwin; if (wmPtr->pathName == NULL) { return TCL_OK; } tkwin = Tk_NameToWindow(graphPtr->interp, wmPtr->pathName, graphPtr->tkwin); if (tkwin == NULL) { return TCL_ERROR; } if (Tk_Parent(tkwin) != graphPtr->tkwin) { Tcl_AppendResult(graphPtr->interp, "\"", wmPtr->pathName, "\" is not a child of \"", Tk_PathName(graphPtr->tkwin), "\"", (char *)NULL); return TCL_ERROR; } if (tkwin != wmPtr->tkwin) { if (wmPtr->tkwin != NULL) { Tk_DeleteEventHandler(wmPtr->tkwin, StructureNotifyMask, ChildEventProc, wmPtr); Tk_ManageGeometry(wmPtr->tkwin, (Tk_GeomMgr *) 0, (ClientData)0); Tk_UnmapWindow(wmPtr->tkwin); } Tk_CreateEventHandler(tkwin, StructureNotifyMask, ChildEventProc, wmPtr); Tk_ManageGeometry(tkwin, &winMarkerMgrInfo, wmPtr); } wmPtr->tkwin = tkwin; wmPtr->flags |= MAP_ITEM; if (wmPtr->drawUnder) { graphPtr->flags |= REDRAW_BACKING_STORE; } Blt_EventuallyRedrawGraph(graphPtr); return TCL_OK; } /* * ---------------------------------------------------------------------- * * MapWindowMarker -- * * Calculate the layout position for a window marker. Positional * information is saved in the marker. * * Results: * None. * * ---------------------------------------------------------------------- */ static void MapWindowMarker(markerPtr) Marker *markerPtr; { WindowMarker *wmPtr = (WindowMarker *)markerPtr; Graph *graphPtr = markerPtr->graphPtr; Extents2D exts; int width, height; if (wmPtr->tkwin == (Tk_Window)NULL) { return; } wmPtr->anchorPos = MapPoint(graphPtr, wmPtr->worldPts, &wmPtr->axes); width = Tk_ReqWidth(wmPtr->tkwin); height = Tk_ReqHeight(wmPtr->tkwin); if (wmPtr->reqWidth > 0) { width = wmPtr->reqWidth; } if (wmPtr->reqHeight > 0) { height = wmPtr->reqHeight; } wmPtr->anchorPos = Blt_TranslatePoint(&wmPtr->anchorPos, width, height, wmPtr->anchor); wmPtr->anchorPos.x += wmPtr->xOffset; wmPtr->anchorPos.y += wmPtr->yOffset; wmPtr->width = width; wmPtr->height = height; /* * Determine the bounding box of the window and test to see if it * is at least partially contained within the plotting area. */ exts.left = wmPtr->anchorPos.x; exts.top = wmPtr->anchorPos.y; exts.right = wmPtr->anchorPos.x + wmPtr->width - 1; exts.bottom = wmPtr->anchorPos.y + wmPtr->height - 1; wmPtr->clipped = BoxesDontOverlap(graphPtr, &exts); } /* * ---------------------------------------------------------------------- * * PointInWindowMarker -- * * ---------------------------------------------------------------------- */ static int PointInWindowMarker(markerPtr, samplePtr) Marker *markerPtr; Point2D *samplePtr; { WindowMarker *wmPtr = (WindowMarker *)markerPtr; return ((samplePtr->x >= wmPtr->anchorPos.x) && (samplePtr->x < (wmPtr->anchorPos.x + wmPtr->width)) && (samplePtr->y >= wmPtr->anchorPos.y) && (samplePtr->y < (wmPtr->anchorPos.y + wmPtr->height))); } /* * ---------------------------------------------------------------------- * * RegionInWindowMarker -- * * ---------------------------------------------------------------------- */ static int RegionInWindowMarker(markerPtr, extsPtr, enclosed) Marker *markerPtr; Extents2D *extsPtr; int enclosed; { WindowMarker *wmPtr = (WindowMarker *)markerPtr; if (wmPtr->nWorldPts < 1) { return FALSE; } if (enclosed) { return ((wmPtr->anchorPos.x >= extsPtr->left) && (wmPtr->anchorPos.y >= extsPtr->top) && ((wmPtr->anchorPos.x + wmPtr->width) <= extsPtr->right) && ((wmPtr->anchorPos.y + wmPtr->height) <= extsPtr->bottom)); } return !((wmPtr->anchorPos.x >= extsPtr->right) || (wmPtr->anchorPos.y >= extsPtr->bottom) || ((wmPtr->anchorPos.x + wmPtr->width) <= extsPtr->left) || ((wmPtr->anchorPos.y + wmPtr->height) <= extsPtr->top)); } /* * ---------------------------------------------------------------------- * * DrawWindowMarker -- * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static void DrawWindowMarker(markerPtr, drawable) Marker *markerPtr; Drawable drawable; /* Pixmap or window to draw into */ { WindowMarker *wmPtr = (WindowMarker *)markerPtr; if (wmPtr->tkwin == NULL) { return; } if ((wmPtr->height != Tk_Height(wmPtr->tkwin)) || (wmPtr->width != Tk_Width(wmPtr->tkwin)) || ((int)wmPtr->anchorPos.x != Tk_X(wmPtr->tkwin)) || ((int)wmPtr->anchorPos.y != Tk_Y(wmPtr->tkwin))) { Tk_MoveResizeWindow(wmPtr->tkwin, (int)wmPtr->anchorPos.x, (int)wmPtr->anchorPos.y, wmPtr->width, wmPtr->height); } if (!Tk_IsMapped(wmPtr->tkwin)) { Tk_MapWindow(wmPtr->tkwin); } } /* * ---------------------------------------------------------------------- * * WindowMarkerToPostScript -- * * ---------------------------------------------------------------------- */ static void WindowMarkerToPostScript(markerPtr, psToken) Marker *markerPtr; PsToken psToken; { WindowMarker *wmPtr = (WindowMarker *)markerPtr; if (wmPtr->tkwin == NULL) { return; } if (Tk_IsMapped(wmPtr->tkwin)) { Blt_WindowToPostScript(psToken, wmPtr->tkwin, wmPtr->anchorPos.x, wmPtr->anchorPos.y); } } /* * ---------------------------------------------------------------------- * * FreeWindowMarker -- * * Destroys the structure containing the attributes of the window * marker. * * Results: * None. * * Side effects: * Window is destroyed and removed from the screen. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static void FreeWindowMarker(graphPtr, markerPtr) Graph *graphPtr; Marker *markerPtr; { WindowMarker *wmPtr = (WindowMarker *)markerPtr; if (wmPtr->tkwin != NULL) { Tk_DeleteEventHandler(wmPtr->tkwin, StructureNotifyMask, ChildEventProc, wmPtr); Tk_ManageGeometry(wmPtr->tkwin, (Tk_GeomMgr *) 0, (ClientData)0); Tk_DestroyWindow(wmPtr->tkwin); } } /* * ---------------------------------------------------------------------- * * CreateWindowMarker -- * * Allocate memory and initialize methods for the new window marker. * * Results: * The pointer to the newly allocated marker structure is returned. * * Side effects: * Memory is allocated for the window marker structure. * * ---------------------------------------------------------------------- */ static Marker * CreateWindowMarker() { WindowMarker *wmPtr; wmPtr = Blt_Calloc(1, sizeof(WindowMarker)); if (wmPtr != NULL) { wmPtr->classPtr = &windowMarkerClass; } return (Marker *)wmPtr; } /* * ---------------------------------------------------------------------- * * ChildEventProc -- * * This procedure is invoked whenever StructureNotify events * occur for a window that's managed as part of a graph window * marker. This procedure's only purpose is to clean up when * windows are deleted. * * Results: * None. * * Side effects: * The window is disassociated from the window item when it is * deleted. * * ---------------------------------------------------------------------- */ static void ChildEventProc(clientData, eventPtr) ClientData clientData; /* Pointer to record describing window item. */ XEvent *eventPtr; /* Describes what just happened. */ { WindowMarker *wmPtr = clientData; if (eventPtr->type == DestroyNotify) { wmPtr->tkwin = NULL; } } /* * ---------------------------------------------------------------------- * * ChildGeometryProc -- * * This procedure is invoked whenever a window that's associated * with a window item changes its requested dimensions. * * Results: * None. * * Side effects: * The size and location on the window of the window may change, * depending on the options specified for the window item. * * ---------------------------------------------------------------------- */ /* ARGSUSED */ static void ChildGeometryProc(clientData, tkwin) ClientData clientData; /* Pointer to record for window item. */ Tk_Window tkwin; /* Window that changed its desired size. */ { WindowMarker *wmPtr = clientData; if (wmPtr->reqWidth == 0) { wmPtr->width = Tk_ReqWidth(tkwin); } if (wmPtr->reqHeight == 0) { wmPtr->height = Tk_ReqHeight(tkwin); } } /* * ---------------------------------------------------------------------- * * ChildCustodyProc -- * * This procedure is invoked when an embedded window has been * stolen by another geometry manager. The information and * memory associated with the widget is released. * * Results: * None. * * Side effects: * Arranges for the graph to be redrawn without the embedded * widget at the next idle point. * * ---------------------------------------------------------------------- */ /* ARGSUSED */ static void ChildCustodyProc(clientData, tkwin) ClientData clientData; /* Window marker to be destroyed. */ Tk_Window tkwin; /* Not used. */ { Marker *markerPtr = clientData; Graph *graphPtr; graphPtr = markerPtr->graphPtr; DestroyMarker(markerPtr); /* * Not really needed. We should get an Expose event when the * child window is unmapped. */ Blt_EventuallyRedrawGraph(graphPtr); } /* * ---------------------------------------------------------------------- * * MapLineMarker -- * * Calculate the layout position for a line marker. Positional * information is saved in the marker. The line positions are * stored in an array of points (malloc'ed). * * Results: * None. * * ---------------------------------------------------------------------- */ static void MapLineMarker(markerPtr) Marker *markerPtr; { Graph *graphPtr = markerPtr->graphPtr; LineMarker *lmPtr = (LineMarker *)markerPtr; Point2D *srcPtr, *endPtr; Segment2D *segments, *segPtr; Point2D p, q, next; Extents2D exts; lmPtr->nSegments = 0; if (lmPtr->segments != NULL) { Blt_Free(lmPtr->segments); } if (lmPtr->nWorldPts < 2) { return; /* Too few points */ } Blt_GraphExtents(graphPtr, &exts); /* * 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. */ segments = Blt_Malloc(lmPtr->nWorldPts * sizeof(Segment2D)); srcPtr = lmPtr->worldPts; p = MapPoint(graphPtr, srcPtr, &lmPtr->axes); p.x += lmPtr->xOffset; p.y += lmPtr->yOffset; segPtr = segments; for (srcPtr++, endPtr = lmPtr->worldPts + lmPtr->nWorldPts; srcPtr < endPtr; srcPtr++) { next = MapPoint(graphPtr, srcPtr, &lmPtr->axes); next.x += lmPtr->xOffset; next.y += lmPtr->yOffset; q = next; if (Blt_LineRectClip(&exts, &p, &q)) { segPtr->p = p; segPtr->q = q; segPtr++; } p = next; } lmPtr->nSegments = segPtr - segments; lmPtr->segments = segments; lmPtr->clipped = (lmPtr->nSegments == 0); } static int PointInLineMarker(markerPtr, samplePtr) Marker *markerPtr; Point2D *samplePtr; { LineMarker *lmPtr = (LineMarker *)markerPtr; return Blt_PointInSegments(samplePtr, lmPtr->segments, lmPtr->nSegments, (double)lmPtr->graphPtr->halo); } /* * ---------------------------------------------------------------------- * * RegionInLineMarker -- * * ---------------------------------------------------------------------- */ static int RegionInLineMarker(markerPtr, extsPtr, enclosed) Marker *markerPtr; Extents2D *extsPtr; int enclosed; { LineMarker *lmPtr = (LineMarker *)markerPtr; if (lmPtr->nWorldPts < 2) { return FALSE; } if (enclosed) { Point2D p; Point2D *pointPtr, *endPtr; for (pointPtr = lmPtr->worldPts, endPtr = lmPtr->worldPts + lmPtr->nWorldPts; pointPtr < endPtr; pointPtr++) { p = MapPoint(lmPtr->graphPtr, pointPtr, &lmPtr->axes); if ((p.x < extsPtr->left) && (p.x > extsPtr->right) && (p.y < extsPtr->top) && (p.y > extsPtr->bottom)) { return FALSE; } } return TRUE; /* All points inside bounding box. */ } else { Point2D p, q; int count; Point2D *pointPtr, *endPtr; count = 0; for (pointPtr = lmPtr->worldPts, endPtr = lmPtr->worldPts + (lmPtr->nWorldPts - 1); pointPtr < endPtr; pointPtr++) { p = MapPoint(lmPtr->graphPtr, pointPtr, &lmPtr->axes); q = MapPoint(lmPtr->graphPtr, pointPtr + 1, &lmPtr->axes); if (Blt_LineRectClip(extsPtr, &p, &q)) { count++; } } return (count > 0); /* At least 1 segment passes through region. */ } } /* * ---------------------------------------------------------------------- * * DrawLineMarker -- * * ---------------------------------------------------------------------- */ static void DrawLineMarker(markerPtr, drawable) Marker *markerPtr; Drawable drawable; /* Pixmap or window to draw into */ { LineMarker *lmPtr = (LineMarker *)markerPtr; if (lmPtr->nSegments > 0) { Graph *graphPtr = markerPtr->graphPtr; Blt_Draw2DSegments(graphPtr->display, drawable, lmPtr->gc, lmPtr->segments, lmPtr->nSegments); if (lmPtr->xor) { /* Toggle the drawing state */ lmPtr->xorState = (lmPtr->xorState == 0); } } } /* * ---------------------------------------------------------------------- * * ConfigureLineMarker -- * * This procedure is called to process an argv/argc list, plus * the Tk option database, in order to configure (or reconfigure) * a line marker. * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side effects: * Configuration information, such as line width, colors, dashes, * etc. get set for markerPtr; old resources get freed, if there * were any. The marker is eventually redisplayed. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ConfigureLineMarker(markerPtr) Marker *markerPtr; { Graph *graphPtr = markerPtr->graphPtr; LineMarker *lmPtr = (LineMarker *)markerPtr; GC newGC; XGCValues gcValues; unsigned long gcMask; Drawable drawable; drawable = Tk_WindowId(graphPtr->tkwin); gcMask = (GCLineWidth | GCLineStyle | GCCapStyle | GCJoinStyle); if (lmPtr->outlineColor != NULL) { gcMask |= GCForeground; gcValues.foreground = lmPtr->outlineColor->pixel; } if (lmPtr->fillColor != NULL) { gcMask |= GCBackground; gcValues.background = lmPtr->fillColor->pixel; } gcValues.cap_style = lmPtr->capStyle; gcValues.join_style = lmPtr->joinStyle; gcValues.line_width = LineWidth(lmPtr->lineWidth); gcValues.line_style = LineSolid; if (LineIsDashed(lmPtr->dashes)) { gcValues.line_style = (gcMask & GCBackground) ? LineDoubleDash : LineOnOffDash; } if (lmPtr->xor) { unsigned long pixel; gcValues.function = GXxor; gcMask |= GCFunction; if (graphPtr->plotBg == NULL) { pixel = WhitePixelOfScreen(Tk_Screen(graphPtr->tkwin)); } else { pixel = graphPtr->plotBg->pixel; } if (gcMask & GCBackground) { gcValues.background ^= pixel; } gcValues.foreground ^= pixel; if (drawable != None) { DrawLineMarker(markerPtr, drawable); } } newGC = Blt_GetPrivateGC(graphPtr->tkwin, gcMask, &gcValues); if (lmPtr->gc != NULL) { Blt_FreePrivateGC(graphPtr->display, lmPtr->gc); } if (LineIsDashed(lmPtr->dashes)) { Blt_SetDashes(graphPtr->display, newGC, &lmPtr->dashes); } lmPtr->gc = newGC; if (lmPtr->xor) { if (drawable != None) { MapLineMarker(markerPtr); DrawLineMarker(markerPtr, drawable); } return TCL_OK; } lmPtr->flags |= MAP_ITEM; if (lmPtr->drawUnder) { graphPtr->flags |= REDRAW_BACKING_STORE; } Blt_EventuallyRedrawGraph(graphPtr); return TCL_OK; } /* * ---------------------------------------------------------------------- * * LineMarkerToPostScript -- * * Prints postscript commands to display the connect line. * Dashed lines need to be handled specially, especially if a * background color is designated. * * Results: * None. * * Side effects: * PostScript output commands are saved in the interpreter * (infoPtr->interp) result field. * * ---------------------------------------------------------------------- */ static void LineMarkerToPostScript(markerPtr, psToken) Marker *markerPtr; PsToken psToken; { LineMarker *lmPtr = (LineMarker *)markerPtr; if (lmPtr->nSegments > 0) { Blt_LineAttributesToPostScript(psToken, lmPtr->outlineColor, lmPtr->lineWidth, &lmPtr->dashes, lmPtr->capStyle, lmPtr->joinStyle); if ((LineIsDashed(lmPtr->dashes)) && (lmPtr->fillColor != NULL)) { Blt_AppendToPostScript(psToken, "/DashesProc {\n gsave\n ", (char *)NULL); Blt_BackgroundToPostScript(psToken, lmPtr->fillColor); Blt_AppendToPostScript(psToken, " ", (char *)NULL); Blt_LineDashesToPostScript(psToken, (Blt_Dashes *)NULL); Blt_AppendToPostScript(psToken, "stroke\n", " grestore\n", "} def\n", (char *)NULL); } else { Blt_AppendToPostScript(psToken, "/DashesProc {} def\n", (char *)NULL); } Blt_2DSegmentsToPostScript(psToken, lmPtr->segments, lmPtr->nSegments); } } /* * ---------------------------------------------------------------------- * * FreeLineMarker -- * * Destroys the structure and attributes of a line marker. * * Results: * None. * * Side effects: * Line attributes (GCs, colors, stipple, etc) get released. * Memory is deallocated, X resources are freed. * * ---------------------------------------------------------------------- */ static void FreeLineMarker(graphPtr, markerPtr) Graph *graphPtr; Marker *markerPtr; { LineMarker *lmPtr = (LineMarker *)markerPtr; if (lmPtr->gc != NULL) { Blt_FreePrivateGC(graphPtr->display, lmPtr->gc); } if (lmPtr->segments != NULL) { Blt_Free(lmPtr->segments); } } /* * ---------------------------------------------------------------------- * * CreateLineMarker -- * * Allocate memory and initialize methods for a new line marker. * * Results: * The pointer to the newly allocated marker structure is returned. * * Side effects: * Memory is allocated for the line marker structure. * * ---------------------------------------------------------------------- */ static Marker * CreateLineMarker() { LineMarker *lmPtr; lmPtr = Blt_Calloc(1, sizeof(LineMarker)); if (lmPtr != NULL) { lmPtr->classPtr = &lineMarkerClass; lmPtr->xor = FALSE; lmPtr->capStyle = CapButt; lmPtr->joinStyle = JoinMiter; } return (Marker *)lmPtr; } /* * ---------------------------------------------------------------------- * * MapPolygonMarker -- * * Calculate the layout position for a polygon marker. Positional * information is saved in the polygon in an array of points * (malloc'ed). * * Results: * None. * * ---------------------------------------------------------------------- */ static void MapPolygonMarker(markerPtr) Marker *markerPtr; { Graph *graphPtr = markerPtr->graphPtr; PolygonMarker *pmPtr = (PolygonMarker *)markerPtr; Point2D *srcPtr, *destPtr, *endPtr; Point2D *screenPts; Extents2D exts; int nScreenPts; if (pmPtr->outlinePts != NULL) { Blt_Free(pmPtr->outlinePts); pmPtr->outlinePts = NULL; pmPtr->nOutlinePts = 0; } if (pmPtr->fillPts != NULL) { Blt_Free(pmPtr->fillPts); pmPtr->fillPts = NULL; pmPtr->nFillPts = 0; } if (pmPtr->screenPts != NULL) { Blt_Free(pmPtr->screenPts); pmPtr->screenPts = NULL; } if (pmPtr->nWorldPts < 3) { return; /* Too few points */ } /* * Allocate and fill a temporary array to hold the screen * coordinates of the polygon. */ nScreenPts = pmPtr->nWorldPts + 1; screenPts = Blt_Malloc((nScreenPts + 1) * sizeof(Point2D)); endPtr = pmPtr->worldPts + pmPtr->nWorldPts; destPtr = screenPts; for (srcPtr = pmPtr->worldPts; srcPtr < endPtr; srcPtr++) { *destPtr = MapPoint(graphPtr, srcPtr, &pmPtr->axes); destPtr->x += pmPtr->xOffset; destPtr->y += pmPtr->yOffset; destPtr++; } *destPtr = screenPts[0]; Blt_GraphExtents(graphPtr, &exts); pmPtr->clipped = TRUE; if (pmPtr->fill.fgColor != NULL) { /* Polygon fill required. */ Point2D *fillPts; int n; fillPts = Blt_Malloc(sizeof(Point2D) * nScreenPts * 3); assert(fillPts); n = Blt_PolyRectClip(&exts, screenPts, pmPtr->nWorldPts, fillPts); if (n < 3) { Blt_Free(fillPts); } else { pmPtr->nFillPts = n; pmPtr->fillPts = fillPts; pmPtr->clipped = FALSE; } } if ((pmPtr->outline.fgColor != NULL) && (pmPtr->lineWidth > 0)) { Segment2D *outlinePts; register Segment2D *segPtr; /* * Generate line segments representing the polygon outline. * The resulting outline may or may not be closed from * viewport clipping. */ outlinePts = Blt_Malloc(nScreenPts * sizeof(Segment2D)); if (outlinePts == NULL) { return; /* Can't allocate point array */ } /* * Note that this assumes that the point array contains an * extra point that closes the polygon. */ segPtr = outlinePts; for (srcPtr = screenPts, endPtr = screenPts + (nScreenPts - 1); srcPtr < endPtr; srcPtr++) { segPtr->p = srcPtr[0]; segPtr->q = srcPtr[1]; if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) { segPtr++; } } pmPtr->nOutlinePts = segPtr - outlinePts; pmPtr->outlinePts = outlinePts; if (pmPtr->nOutlinePts > 0) { pmPtr->clipped = FALSE; } } pmPtr->screenPts = screenPts; } static int PointInPolygonMarker(markerPtr, samplePtr) Marker *markerPtr; Point2D *samplePtr; { PolygonMarker *pmPtr = (PolygonMarker *)markerPtr; if (pmPtr->nWorldPts < 2) { return FALSE; } return Blt_PointInPolygon(samplePtr, pmPtr->screenPts, pmPtr->nWorldPts + 1); } /* * ---------------------------------------------------------------------- * * RegionInPolygonMarker -- * * ---------------------------------------------------------------------- */ static int RegionInPolygonMarker(markerPtr, extsPtr, enclosed) Marker *markerPtr; Extents2D *extsPtr; int enclosed; { PolygonMarker *pmPtr = (PolygonMarker *)markerPtr; if (pmPtr->nWorldPts >= 3) { return Blt_RegionInPolygon(extsPtr, pmPtr->screenPts, pmPtr->nWorldPts, enclosed); } return FALSE; } static void DrawPolygonMarker(markerPtr, drawable) Marker *markerPtr; Drawable drawable; /* Pixmap or window to draw into */ { Graph *graphPtr = markerPtr->graphPtr; PolygonMarker *pmPtr = (PolygonMarker *)markerPtr; /* Draw polygon fill region */ if ((pmPtr->nFillPts > 0) && (pmPtr->fill.fgColor != NULL)) { XPoint *destPtr, *pointArr; Point2D *srcPtr, *endPtr; pointArr = Blt_Malloc(pmPtr->nFillPts * sizeof(XPoint)); if (pointArr == NULL) { return; } destPtr = pointArr; for (srcPtr = pmPtr->fillPts, endPtr = pmPtr->fillPts + pmPtr->nFillPts; srcPtr < endPtr; srcPtr++) { destPtr->x = (short int)srcPtr->x; destPtr->y = (short int)srcPtr->y; destPtr++; } XFillPolygon(graphPtr->display, drawable, pmPtr->fillGC, pointArr, pmPtr->nFillPts, Complex, CoordModeOrigin); Blt_Free(pointArr); } /* and then the outline */ if ((pmPtr->nOutlinePts > 0) && (pmPtr->lineWidth > 0) && (pmPtr->outline.fgColor != NULL)) { Blt_Draw2DSegments(graphPtr->display, drawable, pmPtr->outlineGC, pmPtr->outlinePts, pmPtr->nOutlinePts); } } static void PolygonMarkerToPostScript(markerPtr, psToken) Marker *markerPtr; PsToken psToken; { Graph *graphPtr = markerPtr->graphPtr; PolygonMarker *pmPtr = (PolygonMarker *)markerPtr; if (pmPtr->fill.fgColor != NULL) { /* * Options: fg bg * Draw outline only. * x Draw solid or stipple. * x x Draw solid or stipple. */ /* Create a path to use for both the polygon and its outline. */ Blt_PathToPostScript(psToken, pmPtr->fillPts, pmPtr->nFillPts); Blt_AppendToPostScript(psToken, "closepath\n", (char *)NULL); /* If the background fill color was specified, draw the * polygon in a solid fashion with that color. */ if (pmPtr->fill.bgColor != NULL) { Blt_BackgroundToPostScript(psToken, pmPtr->fill.bgColor); Blt_AppendToPostScript(psToken, "Fill\n", (char *)NULL); } Blt_ForegroundToPostScript(psToken, pmPtr->fill.fgColor); if (pmPtr->stipple != None) { /* Draw the stipple in the foreground color. */ Blt_StippleToPostScript(psToken, graphPtr->display, pmPtr->stipple); } else { Blt_AppendToPostScript(psToken, "Fill\n", (char *)NULL); } } /* Draw the outline in the foreground color. */ if ((pmPtr->lineWidth > 0) && (pmPtr->outline.fgColor != NULL)) { /* Set up the line attributes. */ Blt_LineAttributesToPostScript(psToken, pmPtr->outline.fgColor, pmPtr->lineWidth, &pmPtr->dashes, pmPtr->capStyle, pmPtr->joinStyle); /* * Define on-the-fly a PostScript macro "DashesProc" that * will be executed for each call to the Polygon drawing * routine. If the line isn't dashed, simply make this an * empty definition. */ if ((pmPtr->outline.bgColor != NULL) && (LineIsDashed(pmPtr->dashes))) { Blt_AppendToPostScript(psToken, "/DashesProc {\n", "gsave\n ", (char *)NULL); Blt_BackgroundToPostScript(psToken, pmPtr->outline.bgColor); Blt_AppendToPostScript(psToken, " ", (char *)NULL); Blt_LineDashesToPostScript(psToken, (Blt_Dashes *)NULL); Blt_AppendToPostScript(psToken, "stroke\n", " grestore\n", "} def\n", (char *)NULL); } else { Blt_AppendToPostScript(psToken, "/DashesProc {} def\n", (char *)NULL); } Blt_2DSegmentsToPostScript(psToken, pmPtr->outlinePts, pmPtr->nOutlinePts); } } /* * ---------------------------------------------------------------------- * * ConfigurePolygonMarker -- * * This procedure is called to process an argv/argc list, plus * the Tk option database, in order to configure (or reconfigure) * a polygon marker. * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side effects: * Configuration information, such as polygon color, dashes, * fillstyle, etc. get set for markerPtr; old resources get * freed, if there were any. The marker is eventually * redisplayed. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ConfigurePolygonMarker(markerPtr) Marker *markerPtr; { Graph *graphPtr = markerPtr->graphPtr; PolygonMarker *pmPtr = (PolygonMarker *)markerPtr; GC newGC; XGCValues gcValues; unsigned long gcMask; Drawable drawable; drawable = Tk_WindowId(graphPtr->tkwin); gcMask = (GCLineWidth | GCLineStyle); if (pmPtr->outline.fgColor != NULL) { gcMask |= GCForeground; gcValues.foreground = pmPtr->outline.fgColor->pixel; } if (pmPtr->outline.bgColor != NULL) { gcMask |= GCBackground; gcValues.background = pmPtr->outline.bgColor->pixel; } gcMask |= (GCCapStyle | GCJoinStyle); gcValues.cap_style = pmPtr->capStyle; gcValues.join_style = pmPtr->joinStyle; gcValues.line_style = LineSolid; gcValues.dash_offset = 0; gcValues.line_width = LineWidth(pmPtr->lineWidth); if (LineIsDashed(pmPtr->dashes)) { gcValues.line_style = (pmPtr->outline.bgColor == NULL) ? LineOnOffDash : LineDoubleDash; } if (pmPtr->xor) { unsigned long pixel; gcValues.function = GXxor; gcMask |= GCFunction; if (graphPtr->plotBg == NULL) { /* The graph's color option may not have been set yet */ pixel = WhitePixelOfScreen(Tk_Screen(graphPtr->tkwin)); } else { pixel = graphPtr->plotBg->pixel; } if (gcMask & GCBackground) { gcValues.background ^= pixel; } gcValues.foreground ^= pixel; if (drawable != None) { DrawPolygonMarker(markerPtr, drawable); } } newGC = Blt_GetPrivateGC(graphPtr->tkwin, gcMask, &gcValues); if (LineIsDashed(pmPtr->dashes)) { Blt_SetDashes(graphPtr->display, newGC, &pmPtr->dashes); } if (pmPtr->outlineGC != NULL) { Blt_FreePrivateGC(graphPtr->display, pmPtr->outlineGC); } pmPtr->outlineGC = newGC; gcMask = 0; if (pmPtr->fill.fgColor != NULL) { gcMask |= GCForeground; gcValues.foreground = pmPtr->fill.fgColor->pixel; } if (pmPtr->fill.bgColor != NULL) { gcMask |= GCBackground; gcValues.background = pmPtr->fill.bgColor->pixel; } if (pmPtr->stipple != None) { gcValues.stipple = pmPtr->stipple; gcValues.fill_style = (pmPtr->fill.bgColor != NULL) ? FillOpaqueStippled : FillStippled; gcMask |= (GCStipple | GCFillStyle); } newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues); if (pmPtr->fillGC != NULL) { Tk_FreeGC(graphPtr->display, pmPtr->fillGC); } pmPtr->fillGC = newGC; if ((gcMask == 0) && !(graphPtr->flags & RESET_AXES) && (pmPtr->xor)) { if (drawable != None) { MapPolygonMarker(markerPtr); DrawPolygonMarker(markerPtr, drawable); } return TCL_OK; } pmPtr->flags |= MAP_ITEM; if (pmPtr->drawUnder) { graphPtr->flags |= REDRAW_BACKING_STORE; } Blt_EventuallyRedrawGraph(graphPtr); return TCL_OK; } /* * ---------------------------------------------------------------------- * * FreePolygonMarker -- * * Release memory and resources allocated for the polygon element. * * Results: * None. * * Side effects: * Everything associated with the polygon element is freed up. * * ---------------------------------------------------------------------- */ static void FreePolygonMarker(graphPtr, markerPtr) Graph *graphPtr; Marker *markerPtr; { PolygonMarker *pmPtr = (PolygonMarker *)markerPtr; if (pmPtr->fillGC != NULL) { Tk_FreeGC(graphPtr->display, pmPtr->fillGC); } if (pmPtr->outlineGC != NULL) { Blt_FreePrivateGC(graphPtr->display, pmPtr->outlineGC); } if (pmPtr->fillPts != NULL) { Blt_Free(pmPtr->fillPts); } if (pmPtr->outlinePts != NULL) { Blt_Free(pmPtr->outlinePts); } Blt_FreeColorPair(&pmPtr->outline); Blt_FreeColorPair(&pmPtr->fill); } /* * ---------------------------------------------------------------------- * * CreatePolygonMarker -- * * Allocate memory and initialize methods for the new polygon * marker. * * Results: * The pointer to the newly allocated marker structure is * returned. * * Side effects: * Memory is allocated for the polygon marker structure. * * ---------------------------------------------------------------------- */ static Marker * CreatePolygonMarker() { PolygonMarker *pmPtr; pmPtr = Blt_Calloc(1, sizeof(PolygonMarker)); if (pmPtr != NULL) { pmPtr->classPtr = &polygonMarkerClass; pmPtr->capStyle = CapButt; pmPtr->joinStyle = JoinMiter; } return (Marker *)pmPtr; } static int NameToMarker(graphPtr, name, markerPtrPtr) Graph *graphPtr; char *name; Marker **markerPtrPtr; { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&graphPtr->markers.table, name); if (hPtr != NULL) { *markerPtrPtr = (Marker *)Blt_GetHashValue(hPtr); return TCL_OK; } Tcl_AppendResult(graphPtr->interp, "can't find marker \"", name, "\" in \"", Tk_PathName(graphPtr->tkwin), (char *)NULL); return TCL_ERROR; } static int RenameMarker(graphPtr, markerPtr, oldName, newName) Graph *graphPtr; Marker *markerPtr; char *oldName, *newName; { int isNew; Blt_HashEntry *hPtr; /* Rename the marker only if no marker already exists by that name */ hPtr = Blt_CreateHashEntry(&graphPtr->markers.table, newName, &isNew); if (!isNew) { Tcl_AppendResult(graphPtr->interp, "can't rename marker: \"", newName, "\" already exists", (char *)NULL); return TCL_ERROR; } markerPtr->name = Blt_Strdup(newName); markerPtr->hashPtr = hPtr; Blt_SetHashValue(hPtr, (char *)markerPtr); /* Delete the old hash entry */ hPtr = Blt_FindHashEntry(&graphPtr->markers.table, oldName); Blt_DeleteHashEntry(&graphPtr->markers.table, hPtr); if (oldName != NULL) { Blt_Free(oldName); } return TCL_OK; } /* * ---------------------------------------------------------------------- * * NamesOp -- * * Returns a list of marker identifiers in interp->result; * * Results: * The return value is a standard Tcl result. * * ---------------------------------------------------------------------- */ static int NamesOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { Marker *markerPtr; Blt_ChainLink *linkPtr; register int i; Tcl_ResetResult(interp); for (linkPtr = Blt_ChainFirstLink(graphPtr->markers.displayList); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { markerPtr = Blt_ChainGetValue(linkPtr); if (argc == 3) { Tcl_AppendElement(interp, markerPtr->name); continue; } for (i = 3; i < argc; i++) { if (Tcl_StringMatch(markerPtr->name, argv[i])) { Tcl_AppendElement(interp, markerPtr->name); break; } } } return TCL_OK; } ClientData Blt_MakeMarkerTag(graphPtr, tagName) Graph *graphPtr; char *tagName; { Blt_HashEntry *hPtr; int isNew; hPtr = Blt_CreateHashEntry(&graphPtr->markers.tagTable, tagName, &isNew); assert(hPtr); return Blt_GetHashKey(&graphPtr->markers.tagTable, hPtr); } /* *---------------------------------------------------------------------- * * BindOp -- * * .g element bind elemName sequence command * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int BindOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { if (argc == 3) { Blt_HashEntry *hPtr; Blt_HashSearch cursor; char *tag; for (hPtr = Blt_FirstHashEntry(&graphPtr->markers.tagTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tag = Blt_GetHashKey(&graphPtr->markers.tagTable, hPtr); Tcl_AppendElement(interp, tag); } return TCL_OK; } return Blt_ConfigureBindings(interp, graphPtr->bindTable, Blt_MakeMarkerTag(graphPtr, argv[3]), argc - 4, argv + 4); } /* * ---------------------------------------------------------------------- * * CgetOp -- * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static int CgetOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { Marker *markerPtr; if (NameToMarker(graphPtr, argv[3], &markerPtr) != TCL_OK) { return TCL_ERROR; } if (Tk_ConfigureValue(interp, graphPtr->tkwin, markerPtr->classPtr->configSpecs, (char *)markerPtr, argv[4], 0) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } /* * ---------------------------------------------------------------------- * * ConfigureOp -- * * Results: * The return value is a standard Tcl result. * * Side Effects: * * ---------------------------------------------------------------------- */ static int ConfigureOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { Marker *markerPtr; int flags = TK_CONFIG_ARGV_ONLY; char *oldName; int nNames, nOpts; char **options; register int i; /* Figure out where the option value pairs begin */ argc -= 3; argv += 3; for (i = 0; i < argc; i++) { if (argv[i][0] == '-') { break; } if (NameToMarker(graphPtr, argv[i], &markerPtr) != TCL_OK) { return TCL_ERROR; } } nNames = i; /* Number of element names specified */ nOpts = argc - i; /* Number of options specified */ options = argv + nNames; /* Start of options in argv */ for (i = 0; i < nNames; i++) { NameToMarker(graphPtr, argv[i], &markerPtr); if (nOpts == 0) { return Tk_ConfigureInfo(interp, graphPtr->tkwin, markerPtr->classPtr->configSpecs, (char *)markerPtr, (char *)NULL, flags); } else if (nOpts == 1) { return Tk_ConfigureInfo(interp, graphPtr->tkwin, markerPtr->classPtr->configSpecs, (char *)markerPtr, options[0], flags); } /* Save the old marker. */ oldName = markerPtr->name; if (Tk_ConfigureWidget(interp, graphPtr->tkwin, markerPtr->classPtr->configSpecs, nOpts, options, (char *)markerPtr, flags) != TCL_OK) { return TCL_ERROR; } if (oldName != markerPtr->name) { if (RenameMarker(graphPtr, markerPtr, oldName, markerPtr->name) != TCL_OK) { markerPtr->name = oldName; return TCL_ERROR; } } if ((*markerPtr->classPtr->configProc) (markerPtr) != TCL_OK) { return TCL_ERROR; } } return TCL_OK; } /* * ---------------------------------------------------------------------- * * CreateOp -- * * This procedure creates and initializes a new marker. * * Results: * The return value is a pointer to a structure describing * the new element. If an error occurred, then the return * value is NULL and an error message is left in interp->result. * * Side effects: * Memory is allocated, etc. * * ---------------------------------------------------------------------- */ static int CreateOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { Marker *markerPtr; Blt_HashEntry *hPtr; int isNew; Blt_Uid classUid; register int i; char *name; char string[200]; unsigned int length; char c; c = argv[3][0]; /* Create the new marker based upon the given type */ if ((c == 't') && (strcmp(argv[3], "text") == 0)) { classUid = bltTextMarkerUid; } else if ((c == 'l') && (strcmp(argv[3], "line") == 0)) { classUid = bltLineMarkerUid; } else if ((c == 'p') && (strcmp(argv[3], "polygon") == 0)) { classUid = bltPolygonMarkerUid; } else if ((c == 'i') && (strcmp(argv[3], "image") == 0)) { classUid = bltImageMarkerUid; } else if ((c == 'b') && (strcmp(argv[3], "bitmap") == 0)) { classUid = bltBitmapMarkerUid; } else if ((c == 'w') && (strcmp(argv[3], "window") == 0)) { classUid = bltWindowMarkerUid; } else { Tcl_AppendResult(interp, "unknown marker type \"", argv[3], "\": should be \"text\", \"line\", \"polygon\", \"bitmap\", \"image\", or \ \"window\"", (char *)NULL); return TCL_ERROR; } /* Scan for "-name" option. We need it for the component name */ name = NULL; for (i = 4; i < argc; i += 2) { length = strlen(argv[i]); if ((length > 1) && (strncmp(argv[i], "-name", length) == 0)) { name = argv[i + 1]; break; } } /* If no name was given for the marker, make up one. */ if (name == NULL) { sprintf(string, "marker%d", graphPtr->nextMarkerId++); name = string; } else if (name[0] == '-') { Tcl_AppendResult(interp, "name of marker \"", name, "\" can't start with a '-'", (char *)NULL); return TCL_ERROR; } markerPtr = CreateMarker(graphPtr, name, classUid); if (Blt_ConfigureWidgetComponent(interp, graphPtr->tkwin, name, markerPtr->classUid, markerPtr->classPtr->configSpecs, argc - 4, argv + 4, (char *)markerPtr, 0) != TCL_OK) { DestroyMarker(markerPtr); return TCL_ERROR; } if ((*markerPtr->classPtr->configProc) (markerPtr) != TCL_OK) { DestroyMarker(markerPtr); return TCL_ERROR; } hPtr = Blt_CreateHashEntry(&graphPtr->markers.table, name, &isNew); if (!isNew) { Marker *oldMarkerPtr; /* * Marker by the same name already exists. Delete the old * marker and it's list entry. But save the hash entry. */ oldMarkerPtr = (Marker *)Blt_GetHashValue(hPtr); oldMarkerPtr->hashPtr = NULL; DestroyMarker(oldMarkerPtr); } Blt_SetHashValue(hPtr, markerPtr); markerPtr->hashPtr = hPtr; markerPtr->linkPtr = Blt_ChainAppend(graphPtr->markers.displayList, markerPtr); if (markerPtr->drawUnder) { graphPtr->flags |= REDRAW_BACKING_STORE; } Blt_EventuallyRedrawGraph(graphPtr); Tcl_SetResult(interp, name, TCL_VOLATILE); return TCL_OK; } /* * ---------------------------------------------------------------------- * * DeleteOp -- * * Deletes the marker given by markerId. * * Results: * The return value is a standard Tcl result. * * Side Effects: * Graph will be redrawn to reflect the new display list. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static int DeleteOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { Marker *markerPtr; register int i; for (i = 3; i < argc; i++) { if (NameToMarker(graphPtr, argv[i], &markerPtr) == TCL_OK) { DestroyMarker(markerPtr); } } Tcl_ResetResult(interp); Blt_EventuallyRedrawGraph(graphPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * GetOp -- * * Find the legend entry from the given argument. The argument * can be either a screen position "@x,y" or the name of an * element. * * I don't know how useful it is to test with the name of an * element. * * Results: * A standard Tcl result. * * Side Effects: * Graph will be redrawn to reflect the new legend attributes. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int GetOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; /* Not used. */ char *argv[]; { register Marker *markerPtr; if ((argv[3][0] == 'c') && (strcmp(argv[3], "current") == 0)) { markerPtr = (Marker *)Blt_GetCurrentItem(graphPtr->bindTable); /* Report only on markers. */ if (markerPtr == NULL) { return TCL_OK; } if ((markerPtr->classUid == bltBitmapMarkerUid) || (markerPtr->classUid == bltLineMarkerUid) || (markerPtr->classUid == bltWindowMarkerUid) || (markerPtr->classUid == bltPolygonMarkerUid) || (markerPtr->classUid == bltTextMarkerUid) || (markerPtr->classUid == bltImageMarkerUid)) { Tcl_SetResult(interp, markerPtr->name, TCL_VOLATILE); } } return TCL_OK; } /* * ---------------------------------------------------------------------- * * RelinkOp -- * * Reorders the marker (given by the first name) before/after * the another marker (given by the second name) in the * marker display list. If no second name is given, the * marker is placed at the beginning/end of the list. * * Results: * A standard Tcl result. * * Side Effects: * Graph will be redrawn to reflect the new display list. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static int RelinkOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { Blt_ChainLink *linkPtr, *placePtr; Marker *markerPtr; /* Find the marker to be raised or lowered. */ if (NameToMarker(graphPtr, argv[3], &markerPtr) != TCL_OK) { return TCL_ERROR; } /* Right now it's assumed that all markers are always in the display list. */ linkPtr = markerPtr->linkPtr; Blt_ChainUnlinkLink(graphPtr->markers.displayList, markerPtr->linkPtr); placePtr = NULL; if (argc == 5) { if (NameToMarker(graphPtr, argv[4], &markerPtr) != TCL_OK) { return TCL_ERROR; } placePtr = markerPtr->linkPtr; } /* Link the marker at its new position. */ if (argv[2][0] == 'a') { Blt_ChainLinkAfter(graphPtr->markers.displayList, linkPtr, placePtr); } else { Blt_ChainLinkBefore(graphPtr->markers.displayList, linkPtr, placePtr); } if (markerPtr->drawUnder) { graphPtr->flags |= REDRAW_BACKING_STORE; } Blt_EventuallyRedrawGraph(graphPtr); return TCL_OK; } /* * ---------------------------------------------------------------------- * * FindOp -- * * Returns if marker by a given ID currently exists. * * Results: * A standard Tcl result. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static int FindOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { Blt_ChainLink *linkPtr; Extents2D exts; Marker *markerPtr; int mode; int left, right, top, bottom; int enclosed; #define FIND_ENCLOSED (1<<0) #define FIND_OVERLAPPING (1<<1) if (strcmp(argv[3], "enclosed") == 0) { mode = FIND_ENCLOSED; } else if (strcmp(argv[3], "overlapping") == 0) { mode = FIND_OVERLAPPING; } else { Tcl_AppendResult(interp, "bad search type \"", argv[3], ": should be \"enclosed\", or \"overlapping\"", (char *)NULL); return TCL_ERROR; } if ((Tcl_GetInt(interp, argv[4], &left) != TCL_OK) || (Tcl_GetInt(interp, argv[5], &top) != TCL_OK) || (Tcl_GetInt(interp, argv[6], &right) != TCL_OK) || (Tcl_GetInt(interp, argv[7], &bottom) != TCL_OK)) { return TCL_ERROR; } if (left < right) { exts.left = (double)left; exts.right = (double)right; } else { exts.left = (double)right; exts.right = (double)left; } if (top < bottom) { exts.top = (double)top; exts.bottom = (double)bottom; } else { exts.top = (double)bottom; exts.bottom = (double)top; } enclosed = (mode == FIND_ENCLOSED); for (linkPtr = Blt_ChainFirstLink(graphPtr->markers.displayList); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { markerPtr = Blt_ChainGetValue(linkPtr); if (markerPtr->hidden) { continue; } if (markerPtr->elemName != NULL) { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&graphPtr->elements.table, markerPtr->elemName); if (hPtr != NULL) { Element *elemPtr; elemPtr = (Element *)Blt_GetHashValue(hPtr); if (elemPtr->hidden) { continue; } } } if ((*markerPtr->classPtr->regionProc)(markerPtr, &exts, enclosed)) { Tcl_SetResult(interp, markerPtr->name, TCL_VOLATILE); return TCL_OK; } } Tcl_SetResult(interp, "", TCL_VOLATILE); return TCL_OK; } /* * ---------------------------------------------------------------------- * * ExistsOp -- * * Returns if marker by a given ID currently exists. * * Results: * A standard Tcl result. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ExistsOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&graphPtr->markers.table, argv[3]); Blt_SetBooleanResult(interp, (hPtr != NULL)); return TCL_OK; } /* * ---------------------------------------------------------------------- * * TypeOp -- * * Returns a symbolic name for the type of the marker whose ID is * given. * * Results: * A standard Tcl result. interp->result will contain the symbolic * type of the marker. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TypeOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { Marker *markerPtr; if (NameToMarker(graphPtr, argv[3], &markerPtr) != TCL_OK) { return TCL_ERROR; } Tcl_SetResult(interp, markerPtr->classUid, TCL_STATIC); return TCL_OK; } /* Public routines */ /* * ---------------------------------------------------------------------- * * Blt_MarkerOp -- * * This procedure is invoked to process the Tcl command * that corresponds to a widget managed by this module. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * * ---------------------------------------------------------------------- */ static Blt_OpSpec markerOps[] = { {"after", 1, (Blt_Op)RelinkOp, 4, 5, "marker ?afterMarker?",}, {"before", 2, (Blt_Op)RelinkOp, 4, 5, "marker ?beforeMarker?",}, {"bind", 2, (Blt_Op)BindOp, 3, 6, "marker sequence command",}, {"cget", 2, (Blt_Op)CgetOp, 5, 5, "marker option",}, {"configure", 2, (Blt_Op)ConfigureOp, 4, 0, "marker ?marker?... ?option value?...",}, {"create", 2, (Blt_Op)CreateOp, 4, 0, "type ?option value?...",}, {"delete", 1, (Blt_Op)DeleteOp, 3, 0, "?marker?...",}, {"exists", 1, (Blt_Op)ExistsOp, 4, 4, "marker",}, {"find", 1, (Blt_Op)FindOp, 8, 8, "enclosed|overlapping x1 y1 x2 y2",}, {"get", 1, (Blt_Op)GetOp, 4, 4, "name",}, {"names", 1, (Blt_Op)NamesOp, 3, 0, "?pattern?...",}, {"type", 1, (Blt_Op)TypeOp, 4, 4, "marker",}, }; static int nMarkerOps = sizeof(markerOps) / sizeof(Blt_OpSpec); /*ARGSUSED*/ int Blt_MarkerOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { Blt_Op proc; int result; proc = Blt_GetOp(interp, nMarkerOps, markerOps, BLT_OP_ARG2, argc, argv,0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (graphPtr, interp, argc, argv); return result; } /* * ------------------------------------------------------------------------- * * Blt_MarkersToPostScript -- * * ------------------------------------------------------------------------- */ void Blt_MarkersToPostScript(graphPtr, psToken, under) Graph *graphPtr; PsToken psToken; int under; { Blt_ChainLink *linkPtr; register Marker *markerPtr; for (linkPtr = Blt_ChainFirstLink(graphPtr->markers.displayList); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { markerPtr = Blt_ChainGetValue(linkPtr); if ((markerPtr->classPtr->postscriptProc == NULL) || (markerPtr->nWorldPts == 0)) { continue; } if (markerPtr->drawUnder != under) { continue; } if (markerPtr->hidden) { continue; } if (markerPtr->elemName != NULL) { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&graphPtr->elements.table, markerPtr->elemName); if (hPtr != NULL) { Element *elemPtr; elemPtr = (Element *)Blt_GetHashValue(hPtr); if (elemPtr->hidden) { continue; } } } Blt_AppendToPostScript(psToken, "\n% Marker \"", markerPtr->name, "\" is a ", markerPtr->classUid, " marker\n", (char *)NULL); (*markerPtr->classPtr->postscriptProc) (markerPtr, psToken); } } /* * ------------------------------------------------------------------------- * * Blt_DrawMarkers -- * * Calls the individual drawing routines (based on marker type) * for each marker in the display list. * * A marker will not be drawn if * * 1) An element linked to the marker (indicated by elemName) * is currently hidden. * * 2) No coordinates have been specified for the marker. * * 3) The marker is requesting to be drawn at a different level * (above/below the elements) from the current mode. * * 4) The marker is configured as hidden (-hide option). * * 5) The marker isn't visible in the current viewport * (i.e. clipped). * * Results: * None * * Side Effects: * Markers are drawn into the drawable (pixmap) which will eventually * be displayed in the graph window. * * ------------------------------------------------------------------------- */ void Blt_DrawMarkers(graphPtr, drawable, under) Graph *graphPtr; Drawable drawable; /* Pixmap or window to draw into */ int under; { Blt_ChainLink *linkPtr; Marker *markerPtr; for (linkPtr = Blt_ChainFirstLink(graphPtr->markers.displayList); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { markerPtr = Blt_ChainGetValue(linkPtr); if ((markerPtr->nWorldPts == 0) || (markerPtr->drawUnder != under) || (markerPtr->hidden) || (markerPtr->clipped)) { continue; } if (markerPtr->elemName != NULL) { Blt_HashEntry *hPtr; /* Look up the named element and see if it's hidden */ hPtr = Blt_FindHashEntry(&graphPtr->elements.table, markerPtr->elemName); if (hPtr != NULL) { Element *elemPtr; elemPtr = (Element *)Blt_GetHashValue(hPtr); if (elemPtr->hidden) { continue; } } } (*markerPtr->classPtr->drawProc) (markerPtr, drawable); } } void Blt_MapMarkers(graphPtr) Graph *graphPtr; { Blt_ChainLink *linkPtr; Marker *markerPtr; for (linkPtr = Blt_ChainFirstLink(graphPtr->markers.displayList); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { markerPtr = Blt_ChainGetValue(linkPtr); if ((markerPtr->nWorldPts == 0) || (markerPtr->hidden)) { continue; } if ((graphPtr->flags & MAP_ALL) || (markerPtr->flags & MAP_ITEM)) { (*markerPtr->classPtr->mapProc) (markerPtr); markerPtr->flags &= ~MAP_ITEM; } } } void Blt_DestroyMarkers(graphPtr) Graph *graphPtr; { Blt_HashEntry *hPtr; Blt_HashSearch cursor; Marker *markerPtr; for (hPtr = Blt_FirstHashEntry(&graphPtr->markers.table, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { markerPtr = (Marker *)Blt_GetHashValue(hPtr); /* * Dereferencing the pointer to the hash table prevents the * hash table entry from being automatically deleted. */ markerPtr->hashPtr = NULL; DestroyMarker(markerPtr); } Blt_DeleteHashTable(&graphPtr->markers.table); Blt_DeleteHashTable(&graphPtr->markers.tagTable); Blt_ChainDestroy(graphPtr->markers.displayList); } Marker * Blt_NearestMarker(graphPtr, x, y, under) Graph *graphPtr; int x, y; /* Screen coordinates */ int under; { Blt_ChainLink *linkPtr; Marker *markerPtr; Point2D point; point.x = (double)x; point.y = (double)y; for (linkPtr = Blt_ChainLastLink(graphPtr->markers.displayList); linkPtr != NULL; linkPtr = Blt_ChainPrevLink(linkPtr)) { markerPtr = Blt_ChainGetValue(linkPtr); if ((markerPtr->drawUnder == under) && (markerPtr->nWorldPts > 0) && (!markerPtr->hidden) && (markerPtr->state == STATE_NORMAL)) { if ((*markerPtr->classPtr->pointProc) (markerPtr, &point)) { return markerPtr; } } } return NULL; } blt-2.4z.orig/src/bltGrMisc.c0100644000175000017500000014042207515237460014601 0ustar dokodoko /* * bltGrMisc.c -- * * This module implements miscellaneous routines for the BLT * graph widget. * * Copyright 1993-1998 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. */ #include "bltGraph.h" #include #if defined(__STDC__) #include #else #include #endif static Tk_OptionParseProc StringToPoint; static Tk_OptionPrintProc PointToString; static Tk_OptionParseProc StringToColorPair; static Tk_OptionPrintProc ColorPairToString; Tk_CustomOption bltPointOption = { StringToPoint, PointToString, (ClientData)0 }; Tk_CustomOption bltColorPairOption = { StringToColorPair, ColorPairToString, (ClientData)0 }; /* ---------------------------------------------------------------------- * Custom option parse and print procedures * ---------------------------------------------------------------------- */ /* *---------------------------------------------------------------------- * * Blt_GetXY -- * * Converts a string in the form "@x,y" into an XPoint structure * of the x and y coordinates. * * Results: * A standard Tcl result. If the string represents a valid position * *pointPtr* will contain the converted x and y coordinates and * TCL_OK is returned. Otherwise, TCL_ERROR is returned and * interp->result will contain an error message. * *---------------------------------------------------------------------- */ int Blt_GetXY(interp, tkwin, string, xPtr, yPtr) Tcl_Interp *interp; Tk_Window tkwin; char *string; int *xPtr, *yPtr; { char *comma; int result; int x, y; if ((string == NULL) || (*string == '\0')) { *xPtr = *yPtr = -SHRT_MAX; return TCL_OK; } if (*string != '@') { goto badFormat; } comma = strchr(string + 1, ','); if (comma == NULL) { goto badFormat; } *comma = '\0'; 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; badFormat: Tcl_AppendResult(interp, "bad position \"", string, "\": should be \"@x,y\"", (char *)NULL); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * StringToPoint -- * * Convert the string representation of a legend XY position into * window coordinates. The form of the string must be "@x,y" or * none. * * Results: * A standard Tcl result. The symbol type is written into the * widget record. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToPoint(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* New legend position string */ char *widgRec; /* Widget record */ int offset; /* offset to XPoint structure */ { XPoint *pointPtr = (XPoint *)(widgRec + offset); int x, y; if (Blt_GetXY(interp, tkwin, string, &x, &y) != TCL_OK) { return TCL_ERROR; } pointPtr->x = x, pointPtr->y = y; return TCL_OK; } /* *---------------------------------------------------------------------- * * PointToString -- * * Convert the window coordinates into a string. * * Results: * The string representing the coordinate position is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * PointToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget record */ int offset; /* offset of XPoint in record */ Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */ { char *result; XPoint *pointPtr = (XPoint *)(widgRec + offset); result = ""; if ((pointPtr->x != -SHRT_MAX) && (pointPtr->y != -SHRT_MAX)) { char string[200]; sprintf(string, "@%d,%d", pointPtr->x, pointPtr->y); result = Blt_Strdup(string); assert(result); *freeProcPtr = (Tcl_FreeProc *)Blt_Free; } return result; } /*LINTLIBRARY*/ static int GetColorPair(interp, tkwin, fgStr, bgStr, pairPtr, allowDefault) Tcl_Interp *interp; Tk_Window tkwin; char *fgStr, *bgStr; ColorPair *pairPtr; int allowDefault; { unsigned int length; XColor *fgColor, *bgColor; length = strlen(fgStr); if (fgStr[0] == '\0') { fgColor = NULL; } else if ((allowDefault) && (fgStr[0] == 'd') && (strncmp(fgStr, "defcolor", length) == 0)) { fgColor = COLOR_DEFAULT; } else { fgColor = Tk_GetColor(interp, tkwin, Tk_GetUid(fgStr)); if (fgColor == NULL) { return TCL_ERROR; } } length = strlen(bgStr); if (bgStr[0] == '\0') { bgColor = NULL; } else if ((allowDefault) && (bgStr[0] == 'd') && (strncmp(bgStr, "defcolor", length) == 0)) { bgColor = COLOR_DEFAULT; } else { bgColor = Tk_GetColor(interp, tkwin, Tk_GetUid(bgStr)); if (bgColor == NULL) { return TCL_ERROR; } } pairPtr->fgColor = fgColor; pairPtr->bgColor = bgColor; return TCL_OK; } void Blt_FreeColorPair(pairPtr) ColorPair *pairPtr; { if ((pairPtr->bgColor != NULL) && (pairPtr->bgColor != COLOR_DEFAULT)) { Tk_FreeColor(pairPtr->bgColor); } if ((pairPtr->fgColor != NULL) && (pairPtr->fgColor != COLOR_DEFAULT)) { Tk_FreeColor(pairPtr->fgColor); } pairPtr->bgColor = pairPtr->fgColor = NULL; } /* *---------------------------------------------------------------------- * * StringToColorPair -- * * Convert the color names into pair of XColor pointers. * * Results: * A standard Tcl result. The color pointer is written into the * widget record. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToColorPair(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* String representing color */ char *widgRec; /* Widget record */ int offset; /* Offset of color field in record */ { ColorPair *pairPtr = (ColorPair *)(widgRec + offset); ColorPair sample; int allowDefault = (int)clientData; sample.fgColor = sample.bgColor = NULL; if ((string != NULL) && (*string != '\0')) { int nColors; char **colors; int result; if (Tcl_SplitList(interp, string, &nColors, &colors) != TCL_OK) { return TCL_ERROR; } switch (nColors) { case 0: result = TCL_OK; break; case 1: result = GetColorPair(interp, tkwin, colors[0], "", &sample, allowDefault); break; case 2: result = GetColorPair(interp, tkwin, colors[0], colors[1], &sample, allowDefault); break; default: result = TCL_ERROR; Tcl_AppendResult(interp, "too many names in colors list", (char *)NULL); } Blt_Free(colors); if (result != TCL_OK) { return TCL_ERROR; } } Blt_FreeColorPair(pairPtr); *pairPtr = sample; return TCL_OK; } /* *---------------------------------------------------------------------- * * NameOfColor -- * * Convert the color option value into a string. * * Results: * The static string representing the color option is returned. * *---------------------------------------------------------------------- */ static char * NameOfColor(colorPtr) XColor *colorPtr; { if (colorPtr == NULL) { return ""; } else if (colorPtr == COLOR_DEFAULT) { return "defcolor"; } else { return Tk_NameOfColor(colorPtr); } } /* *---------------------------------------------------------------------- * * ColorPairToString -- * * Convert the color pairs into color names. * * Results: * The string representing the symbol color is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * ColorPairToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Element information record */ int offset; /* Offset of symbol type field in record */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { ColorPair *pairPtr = (ColorPair *)(widgRec + offset); Tcl_DString dString; char *result; Tcl_DStringInit(&dString); Tcl_DStringAppendElement(&dString, NameOfColor(pairPtr->fgColor)); Tcl_DStringAppendElement(&dString, NameOfColor(pairPtr->bgColor)); result = Tcl_DStringValue(&dString); if (result == dString.staticSpace) { result = Blt_Strdup(result); } *freeProcPtr = (Tcl_FreeProc *)Blt_Free; return result; } int Blt_PointInSegments(samplePtr, segments, nSegments, halo) Point2D *samplePtr; Segment2D *segments; int nSegments; double halo; { register Segment2D *segPtr, *endPtr; double left, right, top, bottom; Point2D p, t; double dist, minDist; minDist = DBL_MAX; for (segPtr = segments, endPtr = segments + nSegments; segPtr < endPtr; segPtr++) { t = Blt_GetProjection((int)samplePtr->x, (int)samplePtr->y, &segPtr->p, &segPtr->q); if (segPtr->p.x > segPtr->q.x) { right = segPtr->p.x, left = segPtr->q.x; } else { right = segPtr->q.x, left = segPtr->p.x; } if (segPtr->p.y > segPtr->q.y) { bottom = segPtr->p.y, top = segPtr->q.y; } else { bottom = segPtr->q.y, top = segPtr->p.y; } p.x = BOUND(t.x, left, right); p.y = BOUND(t.y, top, bottom); dist = hypot(p.x - samplePtr->x, p.y - samplePtr->y); if (dist < minDist) { minDist = dist; } } return (minDist < halo); } int Blt_PointInPolygon(samplePtr, points, nPoints) Point2D *samplePtr; Point2D *points; int nPoints; { double b; register Point2D *p, *q, *endPtr; register int count; count = 0; for (p = points, q = p + 1, endPtr = p + nPoints; q < endPtr; p++, q++) { if (((p->y <= samplePtr->y) && (samplePtr->y < q->y)) || ((q->y <= samplePtr->y) && (samplePtr->y < p->y))) { b = (q->x - p->x) * (samplePtr->y - p->y) / (q->y - p->y) + p->x; if (samplePtr->x < b) { count++; /* Count the number of intersections. */ } } } return (count & 0x01); } int Blt_RegionInPolygon(extsPtr, points, nPoints, enclosed) Extents2D *extsPtr; Point2D *points; int nPoints; int enclosed; { register Point2D *pointPtr, *endPtr; if (enclosed) { /* * All points of the polygon must be inside the rectangle. */ for (pointPtr = points, endPtr = points + nPoints; pointPtr < endPtr; pointPtr++) { if ((pointPtr->x < extsPtr->left) || (pointPtr->x > extsPtr->right) || (pointPtr->y < extsPtr->top) || (pointPtr->y > extsPtr->bottom)) { return FALSE; /* One point is exterior. */ } } return TRUE; } else { Point2D p, q; /* * If any segment of the polygon clips the bounding region, the * polygon overlaps the rectangle. */ points[nPoints] = points[0]; for (pointPtr = points, endPtr = points + nPoints; pointPtr < endPtr; pointPtr++) { p = *pointPtr; q = *(pointPtr + 1); if (Blt_LineRectClip(extsPtr, &p, &q)) { return TRUE; } } /* * Otherwise the polygon and rectangle are either disjoint * or enclosed. Check if one corner of the rectangle is * inside the polygon. */ p.x = extsPtr->left; p.y = extsPtr->top; return Blt_PointInPolygon(&p, points, nPoints); } } /* *---------------------------------------------------------------------- * * Blt_GraphExtents -- * * Generates a bounding box representing the plotting area of * the graph. This data structure is used to clip the points and * line segments of the line element. * * The clip region is the plotting area plus such arbitrary extra * space. The reason we clip with a bounding box larger than the * plot area is so that symbols will be drawn even if their center * point isn't in the plotting area. * * Results: * None. * * Side Effects: * The bounding box is filled with the dimensions of the plotting * area. * *---------------------------------------------------------------------- */ void Blt_GraphExtents(graphPtr, extsPtr) Graph *graphPtr; Extents2D *extsPtr; { extsPtr->left = (double)(graphPtr->hOffset - graphPtr->padX.side1); extsPtr->top = (double)(graphPtr->vOffset - graphPtr->padY.side1); extsPtr->right = (double)(graphPtr->hOffset + graphPtr->hRange + graphPtr->padX.side2); extsPtr->bottom = (double)(graphPtr->vOffset + graphPtr->vRange + graphPtr->padY.side2); } static int ClipTest (double ds, double dr, double *t1, double *t2) { double t; if (ds < 0.0) { t = dr / ds; if (t > *t2) { return FALSE; } if (t > *t1) { *t1 = t; } } else if (ds > 0.0) { t = dr / ds; if (t < *t1) { return FALSE; } 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 FALSE; } } return TRUE; } /* *---------------------------------------------------------------------- * * Blt_LineRectClip -- * * 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-Barsky Line Clipping Algorithm. * * Results: * Returns if line segment is visible within the region. The * coordinates of the original line segment are overwritten * by the clipped coordinates. * *---------------------------------------------------------------------- */ int Blt_LineRectClip(extsPtr, p, q) Extents2D *extsPtr; /* Rectangular region to clip. */ Point2D *p, *q; /* (in/out) Coordinates of original * and clipped line segment. */ { double t1, t2; double dx, dy; t1 = 0.0; t2 = 1.0; dx = q->x - p->x; if ((ClipTest (-dx, p->x - extsPtr->left, &t1, &t2)) && (ClipTest (dx, extsPtr->right - p->x, &t1, &t2))) { dy = q->y - p->y; if ((ClipTest (-dy, p->y - extsPtr->top, &t1, &t2)) && (ClipTest (dy, extsPtr->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 TRUE; } } return FALSE; } /* *---------------------------------------------------------------------- * * Blt_PolyRectClip -- * * 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-Barsky Polygon Clipping Algorithm * * Results: * Returns the number of points in the clipped polygon. The * points of the clipped polygon are stored in *outputPts*. * *---------------------------------------------------------------------- */ #define EPSILON FLT_EPSILON #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(extsPtr, points, nPoints, clipPts) Extents2D *extsPtr; Point2D *points; int nPoints; Point2D *clipPts; { Point2D *endPtr; double dx, dy; double tin1, tin2; double tinx, tiny; double xin, yin, xout, yout; int count; register Point2D *p; /* First vertex of input polygon edge. */ register Point2D *q; /* Last vertex of input polygon edge. */ register Point2D *r; r = clipPts; count = 0; /* Counts # of vertices in output polygon. */ points[nPoints] = points[0]; for (p = points, q = p + 1, endPtr = p + nPoints; p < endPtr; p++, q++) { dx = q->x - p->x; /* X-direction */ dy = q->y - p->y; /* Y-direction */ if (FABS(dx) < EPSILON) { dx = (p->x > extsPtr->left) ? -EPSILON : EPSILON ; } if (FABS(dy) < EPSILON) { dy = (p->y > extsPtr->top) ? -EPSILON : EPSILON ; } if (dx > 0.0) { /* Left */ xin = extsPtr->left; xout = extsPtr->right + 1.0; } else { /* Right */ xin = extsPtr->right + 1.0; xout = extsPtr->left; } if (dy > 0.0) { /* Top */ yin = extsPtr->top; yout = extsPtr->bottom + 1.0; } else { /* Bottom */ yin = extsPtr->bottom + 1.0; yout = extsPtr->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, touty, tout1; toutx = (xout - p->x) / dx; touty = (yout - p->y) / dy; 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; } /* *---------------------------------------------------------------------- * * Blt_GetProjection -- * * 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. * * Results: * Returns the coordinates of the projection on the line. * *---------------------------------------------------------------------- */ Point2D Blt_GetProjection(x, y, p, q) int x, y; /* Screen coordinates of the sample point. */ Point2D *p, *q; /* Line segment to project point onto */ { double dx, dy; Point2D t; dx = p->x - q->x; dy = p->y - q->y; /* Test for horizontal and vertical lines */ 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 { double m1, m2; /* Slope of both lines */ double b1, b2; /* y-intercepts */ double midX, midY; /* Midpoint of line segment. */ double ax, ay, bx, by; /* Compute the slop and intercept of the line segment. */ m1 = (dy / dx); 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 original segment. */ midX = (p->x + q->x) * 0.5; midY = (p->y + q->y) * 0.5; /* Rotate the line 90 degrees */ ax = midX - (0.5 * dy); ay = midY - (0.5 * -dx); bx = midX + (0.5 * dy); by = midY + (0.5 * -dx); m2 = (ay - by) / (ax - bx); 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; } typedef struct { double hue, sat, val; } HSV; #define SetColor(c,r,g,b) ((c)->red = (int)((r) * 65535.0), \ (c)->green = (int)((g) * 65535.0), \ (c)->blue = (int)((b) * 65535.0)) void Blt_XColorToHSV(colorPtr, hsvPtr) XColor *colorPtr; HSV *hsvPtr; { unsigned short max, min; double range; unsigned short *colorValues; /* Find the minimum and maximum RGB intensities */ colorValues = (unsigned short *)&colorPtr->red; max = MAX3(colorValues[0], colorValues[1], colorValues[2]); min = MIN3(colorValues[0], colorValues[1], colorValues[2]); hsvPtr->val = (double)max / 65535.0; hsvPtr->hue = hsvPtr->sat = 0.0; range = (double)(max - min); if (max != min) { hsvPtr->sat = range / (double)max; } if (hsvPtr->sat > 0.0) { double red, green, blue; /* Normalize the RGB values */ red = (double)(max - colorPtr->red) / range; green = (double)(max - colorPtr->green) / range; blue = (double)(max - colorPtr->blue) / range; if (colorPtr->red == max) { hsvPtr->hue = (blue - green); } else if (colorPtr->green == max) { hsvPtr->hue = 2 + (red - blue); } else if (colorPtr->blue == max) { hsvPtr->hue = 4 + (green - red); } hsvPtr->hue *= 60.0; } else { hsvPtr->sat = 0.5; } if (hsvPtr->hue < 0.0) { hsvPtr->hue += 360.0; } } void Blt_HSVToXColor(hsvPtr, colorPtr) HSV *hsvPtr; XColor *colorPtr; { double hue, p, q, t; double frac; int quadrant; if (hsvPtr->val < 0.0) { hsvPtr->val = 0.0; } else if (hsvPtr->val > 1.0) { hsvPtr->val = 1.0; } if (hsvPtr->sat == 0.0) { SetColor(colorPtr, hsvPtr->val, hsvPtr->val, hsvPtr->val); return; } hue = FMOD(hsvPtr->hue, 360.0) / 60.0; quadrant = (int)floor(hue); frac = hsvPtr->hue - quadrant; p = hsvPtr->val * (1 - (hsvPtr->sat)); q = hsvPtr->val * (1 - (hsvPtr->sat * frac)); t = hsvPtr->val * (1 - (hsvPtr->sat * (1 - frac))); switch (quadrant) { case 0: SetColor(colorPtr, hsvPtr->val, t, p); break; case 1: SetColor(colorPtr, q, hsvPtr->val, p); break; case 2: SetColor(colorPtr, p, hsvPtr->val, t); break; case 3: SetColor(colorPtr, p, q, hsvPtr->val); break; case 4: SetColor(colorPtr, t, p, hsvPtr->val); break; case 5: SetColor(colorPtr, hsvPtr->val, p, q); break; } } /* *---------------------------------------------------------------------- * * Blt_AdjustViewport -- * * Adjusts the offsets of the viewport according to the scroll mode. * This is to accommodate both "listbox" and "canvas" style scrolling. * * "canvas" The viewport scrolls within the range of world * coordinates. This way the viewport always displays * a full page of the world. If the world is smaller * than the viewport, then (bizarrely) the world and * viewport are inverted so that the world moves up * and down within the viewport. * * "listbox" The viewport can scroll beyond the range of world * coordinates. Every entry can be displayed at the * top of the viewport. This also means that the * scrollbar thumb weirdly shrinks as the last entry * is scrolled upward. * * Results: * The corrected offset is returned. * *---------------------------------------------------------------------- */ int Blt_AdjustViewport(offset, worldSize, windowSize, scrollUnits, scrollMode) int offset, worldSize, windowSize; int scrollUnits; int scrollMode; { switch (scrollMode) { case BLT_SCROLL_MODE_CANVAS: /* * Canvas-style scrolling allows the world to be scrolled * within the window. */ if (worldSize < windowSize) { if ((worldSize - offset) > windowSize) { offset = worldSize - windowSize; } if (offset > 0) { offset = 0; } } else { if ((offset + windowSize) > worldSize) { offset = worldSize - windowSize; } if (offset < 0) { offset = 0; } } break; case BLT_SCROLL_MODE_LISTBOX: if (offset < 0) { offset = 0; } if (offset >= worldSize) { offset = worldSize - scrollUnits; } break; case BLT_SCROLL_MODE_HIERBOX: /* * Hierbox-style scrolling allows the world to be scrolled * within the window. */ if ((offset + windowSize) > worldSize) { offset = worldSize - windowSize; } if (offset < 0) { offset = 0; } break; } return offset; } int Blt_GetScrollInfo(interp, argc, argv, offsetPtr, worldSize, windowSize, scrollUnits, scrollMode) Tcl_Interp *interp; int argc; char **argv; int *offsetPtr; int worldSize, windowSize; int scrollUnits; int scrollMode; { char c; unsigned int length; int offset; int count; double fract; offset = *offsetPtr; c = argv[0][0]; length = strlen(argv[0]); if ((c == 's') && (strncmp(argv[0], "scroll", length) == 0)) { if (argc != 3) { return TCL_ERROR; } /* scroll number unit/page */ if (Tcl_GetInt(interp, argv[1], &count) != TCL_OK) { return TCL_ERROR; } c = argv[2][0]; length = strlen(argv[2]); if ((c == 'u') && (strncmp(argv[2], "units", length) == 0)) { fract = (double)count *scrollUnits; } else if ((c == 'p') && (strncmp(argv[2], "pages", length) == 0)) { /* A page is 90% of the view-able window. */ fract = (double)count *windowSize * 0.9; } else { Tcl_AppendResult(interp, "unknown \"scroll\" units \"", argv[2], "\"", (char *)NULL); return TCL_ERROR; } offset += (int)fract; } else if ((c == 'm') && (strncmp(argv[0], "moveto", length) == 0)) { if (argc != 2) { return TCL_ERROR; } /* moveto fraction */ if (Tcl_GetDouble(interp, argv[1], &fract) != TCL_OK) { return TCL_ERROR; } offset = (int)(worldSize * fract); } else { /* Treat like "scroll units" */ if (Tcl_GetInt(interp, argv[0], &count) != TCL_OK) { return TCL_ERROR; } fract = (double)count *scrollUnits; offset += (int)fract; } *offsetPtr = Blt_AdjustViewport(offset, worldSize, windowSize, scrollUnits, scrollMode); return TCL_OK; } #if (TCL_MAJOR_VERSION >= 8) int Blt_GetScrollInfoFromObj(interp, objc, objv, offsetPtr, worldSize, windowSize, scrollUnits, scrollMode) Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; int *offsetPtr; int worldSize, windowSize; int scrollUnits; int scrollMode; { char c; unsigned int length; int offset; int count; double fract; char *string; offset = *offsetPtr; string = Tcl_GetString(objv[0]); c = string[0]; length = strlen(string); if ((c == 's') && (strncmp(string, "scroll", length) == 0)) { if (objc != 3) { return TCL_ERROR; } /* scroll number unit/page */ if (Tcl_GetIntFromObj(interp, objv[1], &count) != TCL_OK) { return TCL_ERROR; } string = Tcl_GetString(objv[2]); c = string[0]; length = strlen(string); if ((c == 'u') && (strncmp(string, "units", length) == 0)) { fract = (double)count *scrollUnits; } else if ((c == 'p') && (strncmp(string, "pages", length) == 0)) { /* A page is 90% of the view-able window. */ fract = (double)count *windowSize * 0.9; } else { Tcl_AppendResult(interp, "unknown \"scroll\" units \"", Tcl_GetString(objv[2]), "\"", (char *)NULL); return TCL_ERROR; } offset += (int)fract; } else if ((c == 'm') && (strncmp(string, "moveto", length) == 0)) { if (objc != 2) { return TCL_ERROR; } /* moveto fraction */ if (Tcl_GetDoubleFromObj(interp, objv[1], &fract) != TCL_OK) { return TCL_ERROR; } offset = (int)(worldSize * fract); } else { /* Treat like "scroll units" */ if (Tcl_GetIntFromObj(interp, objv[0], &count) != TCL_OK) { return TCL_ERROR; } fract = (double)count *scrollUnits; offset += (int)fract; } *offsetPtr = Blt_AdjustViewport(offset, worldSize, windowSize, scrollUnits, scrollMode); return TCL_OK; } #endif /* TCL_MAJOR_VERSION >= 8 */ /* * ---------------------------------------------------------------------- * * Blt_UpdateScrollbar -- * * Invoke a Tcl command to the scrollbar, defining the new * position and length of the scroll. See the Tk documentation * for further information on the scrollbar. It is assumed the * scrollbar command prefix is valid. * * Results: * None. * * Side Effects: * Scrollbar is commanded to change position and/or size. * * ---------------------------------------------------------------------- */ void Blt_UpdateScrollbar(interp, scrollCmd, firstFract, lastFract) Tcl_Interp *interp; char *scrollCmd; /* scrollbar command */ double firstFract, lastFract; { char string[200]; Tcl_DString dString; Tcl_DStringInit(&dString); Tcl_DStringAppend(&dString, scrollCmd, -1); sprintf(string, " %f %f", firstFract, lastFract); Tcl_DStringAppend(&dString, string, -1); if (Tcl_GlobalEval(interp, Tcl_DStringValue(&dString)) != TCL_OK) { Tcl_BackgroundError(interp); } Tcl_DStringFree(&dString); } /* -------------- */ /* *---------------------------------------------------------------------- * * Blt_GetPrivateGCFromDrawable -- * * Like Tk_GetGC, but doesn't share the GC with any other widget. * This is needed because the certain GC parameters (like dashes) * can not be set via XCreateGC, therefore there is no way for * Tk's hashing mechanism to recognize that two such GCs differ. * * Results: * A new GC is returned. * *---------------------------------------------------------------------- */ GC Blt_GetPrivateGCFromDrawable(display, drawable, gcMask, valuePtr) Display *display; Drawable drawable; unsigned long gcMask; XGCValues *valuePtr; { GC newGC; #ifdef WIN32 newGC = Blt_EmulateXCreateGC(display, drawable, gcMask, valuePtr); #else newGC = XCreateGC(display, drawable, gcMask, valuePtr); #endif return newGC; } /* *---------------------------------------------------------------------- * * Blt_GetPrivateGC -- * * Like Tk_GetGC, but doesn't share the GC with any other widget. * This is needed because the certain GC parameters (like dashes) * can not be set via XCreateGC, therefore there is no way for * Tk's hashing mechanism to recognize that two such GCs differ. * * Results: * A new GC is returned. * *---------------------------------------------------------------------- */ GC Blt_GetPrivateGC(tkwin, gcMask, valuePtr) Tk_Window tkwin; unsigned long gcMask; XGCValues *valuePtr; { GC gc; Pixmap pixmap; Drawable drawable; Display *display; pixmap = None; drawable = Tk_WindowId(tkwin); display = Tk_Display(tkwin); if (drawable == None) { Drawable root; int depth; root = RootWindow(display, Tk_ScreenNumber(tkwin)); depth = Tk_Depth(tkwin); if (depth == DefaultDepth(display, Tk_ScreenNumber(tkwin))) { drawable = root; } else { pixmap = Tk_GetPixmap(display, root, 1, 1, depth); drawable = pixmap; } } gc = Blt_GetPrivateGCFromDrawable(display, drawable, gcMask, valuePtr); if (pixmap != None) { Tk_FreePixmap(display, pixmap); } return gc; } void Blt_FreePrivateGC(display, gc) Display *display; GC gc; { Tk_FreeXId(display, (XID) XGContextFromGC(gc)); XFreeGC(display, gc); } #ifndef WIN32 void Blt_SetDashes(display, gc, dashesPtr) Display *display; GC gc; Blt_Dashes *dashesPtr; { XSetDashes(display, gc, dashesPtr->offset, (CONST char *)dashesPtr->values, strlen((char *)dashesPtr->values)); } #endif static double FindSplit(points, i, j, split) Point2D points[]; int i, j; /* Indices specifying the range of points. */ int *split; /* (out) Index of next split. */ { double maxDist; maxDist = -1.0; if ((i + 1) < j) { register int k; double a, b, c; double sqDist; /* * * sqDist 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++) { sqDist = (points[k].x * a) + (points[k].y * b) + c; if (sqDist < 0.0) { sqDist = -sqDist; } if (sqDist > maxDist) { maxDist = sqDist; /* Track the maximum. */ *split = k; } } /* Correction for segment length---should be redone if can == 0 */ maxDist *= maxDist / (a * a + b * b); } return maxDist; } /* Douglas-Peucker line simplification algorithm */ int Blt_SimplifyLine(inputPts, low, high, tolerance, indices) Point2D inputPts[]; int low, 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 sqDist, sqTolerance; int s = -1; /* Points to top stack item. */ int count; stack = Blt_Malloc(sizeof(int) * (high - low + 1)); StackPush(high); count = 0; indices[count++] = 0; sqTolerance = tolerance * tolerance; while (!StackEmpty()) { sqDist = FindSplit(inputPts, low, StackTop(), &split); if (sqDist > sqTolerance) { StackPush(split); } else { indices[count++] = StackTop(); StackPop(low); } } Blt_Free(stack); return count; } void Blt_Draw2DSegments(display, drawable, gc, segPtr, nSegments) Display *display; Drawable drawable; GC gc; register Segment2D *segPtr; int nSegments; { XSegment *xSegPtr, *xSegArr; Segment2D *endPtr; xSegArr = Blt_Malloc(nSegments * sizeof(XSegment)); if (xSegArr == NULL) { return; } xSegPtr = xSegArr; for (endPtr = segPtr + nSegments; segPtr < endPtr; segPtr++) { xSegPtr->x1 = (short int)segPtr->p.x; xSegPtr->y1 = (short int)segPtr->p.y; xSegPtr->x2 = (short int)segPtr->q.x; xSegPtr->y2 = (short int)segPtr->q.y; xSegPtr++; } XDrawSegments(display, drawable, gc, xSegArr, nSegments); Blt_Free(xSegArr); } void Blt_DrawArrow(display, drawable, gc, x, y, arrowHeight, orientation) Display *display; Drawable drawable; GC gc; int x, y; int arrowHeight; int orientation; { XPoint arrow[5]; int a, b; a = arrowHeight / 2 + 1; b = arrowHeight; switch (orientation) { case ARROW_UP: /* * 0 * + * / \ * / \ * / \ a * / \ * x,y / \ * +-----------+ * 1 b 2 */ arrow[0].x = x; arrow[0].y = y - a; arrow[1].x = arrow[0].x - b; arrow[1].y = arrow[0].y + b; arrow[2].x = arrow[0].x + b; arrow[2].y = arrow[0].y + b; arrow[3].x = arrow[0].x; arrow[3].y = arrow[0].y; break; case ARROW_DOWN: /* * 1 b 2 * +-----------+ * \ / * \ x,y / * \ / a * \ / * \ / * + * 0 */ arrow[0].x = x; arrow[0].y = y + a; arrow[1].x = arrow[0].x - b; arrow[1].y = arrow[0].y - b; arrow[2].x = arrow[0].x + b; arrow[2].y = arrow[0].y - b; arrow[3].x = arrow[0].x; arrow[3].y = arrow[0].y; break; case ARROW_RIGHT: /* * 2 * + * |\ * | \ * | \ * | \ * | \ * | x,y + 0 * | / * | / * | / * | / * |/ * + * 1 */ arrow[0].x = x + a; arrow[0].y = y; arrow[1].x = arrow[0].x - b; arrow[1].y = arrow[0].y + b; arrow[2].x = arrow[0].x - b; arrow[2].y = arrow[0].y - b; arrow[3].x = arrow[0].x; arrow[3].y = arrow[0].y; break; case ARROW_LEFT: /* * 2 * + * /| * / | * / | * / | * / | * 0+ x,y | * \ | * \ | * \ | * \ | * \| * + * 1 */ arrow[0].x = x - a; arrow[0].y = y; arrow[1].x = arrow[0].x + b; arrow[1].y = arrow[0].y + b; arrow[2].x = arrow[0].x + b; arrow[2].y = arrow[0].y - b; arrow[3].x = arrow[0].x; arrow[3].y = arrow[0].y; break; } XFillPolygon(display, drawable, gc, arrow, 4, Convex, CoordModeOrigin); XDrawLines(display, drawable, gc, arrow, 4, CoordModeOrigin); } int Blt_MaxRequestSize(Display *display, unsigned int elemSize) { long size; #ifdef HAVE_XEXTENDEDMAXREQUESTSIZE size = XExtendedMaxRequestSize(display); if (size == 0) { size = XMaxRequestSize(display); } #else size = XMaxRequestSize(display); #endif size -= 4; return ((size * 4) / elemSize); } #undef Blt_Fill3DRectangle void Blt_Fill3DRectangle(tkwin, drawable, border, x, y, width, height, borderWidth, relief) Tk_Window tkwin; /* Window for which border was allocated. */ Drawable drawable; /* X window or pixmap in which to draw. */ Tk_3DBorder border; /* Token for border to draw. */ int x, y, width, height; /* Outside area of rectangular region. */ int borderWidth; /* Desired width for border, in * pixels. Border will be *inside* region. */ int relief; /* Indicates 3D effect: TK_RELIEF_FLAT, * TK_RELIEF_RAISED, or TK_RELIEF_SUNKEN. */ { #ifndef notdef if ((borderWidth > 1) && (width > 2) && (height > 2) && ((relief == TK_RELIEF_SUNKEN) || (relief == TK_RELIEF_RAISED))) { GC lightGC, darkGC; int x2, y2; x2 = x + width - 1; y2 = y + height - 1; #define TK_3D_LIGHT2_GC TK_3D_DARK_GC+1 #define TK_3D_DARK2_GC TK_3D_DARK_GC+2 if (relief == TK_RELIEF_RAISED) { lightGC = Tk_3DBorderGC(tkwin, border, TK_3D_FLAT_GC); #ifdef WIN32 darkGC = Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC); #else darkGC = DefaultGC(Tk_Display(tkwin), Tk_ScreenNumber(tkwin)); #endif } else { #ifdef WIN32 lightGC = Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC); #else lightGC = DefaultGC(Tk_Display(tkwin), Tk_ScreenNumber(tkwin)); #endif darkGC = Tk_3DBorderGC(tkwin, border, TK_3D_FLAT_GC); } XDrawLine(Tk_Display(tkwin), drawable, lightGC, x, y, x2, y); XDrawLine(Tk_Display(tkwin), drawable, darkGC, x2, y2, x2, y); XDrawLine(Tk_Display(tkwin), drawable, darkGC, x2, y2, x, y2); XDrawLine(Tk_Display(tkwin), drawable, lightGC, x, y, x, y2); x++, y++, width -= 2, height -= 2, borderWidth--; } #endif Tk_Fill3DRectangle(tkwin, drawable, border, x, y, width, height, borderWidth, relief); } #undef Blt_Draw3DRectangle void Blt_Draw3DRectangle(tkwin, drawable, border, x, y, width, height, borderWidth, relief) Tk_Window tkwin; /* Window for which border was allocated. */ Drawable drawable; /* X window or pixmap in which to draw. */ Tk_3DBorder border; /* Token for border to draw. */ int x, y, width, height; /* Outside area of rectangular region. */ int borderWidth; /* Desired width for border, in * pixels. Border will be *inside* region. */ int relief; /* Indicates 3D effect: TK_RELIEF_FLAT, * TK_RELIEF_RAISED, or TK_RELIEF_SUNKEN. */ { #ifndef notdef if ((borderWidth > 1) && (width > 2) && (height > 2) && ((relief == TK_RELIEF_SUNKEN) || (relief == TK_RELIEF_RAISED))) { GC lightGC, darkGC; int x2, y2; x2 = x + width - 1; y2 = y + height - 1; if (relief == TK_RELIEF_RAISED) { lightGC = Tk_3DBorderGC(tkwin, border, TK_3D_FLAT_GC); #ifdef WIN32 darkGC = Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC); #else darkGC = DefaultGC(Tk_Display(tkwin), Tk_ScreenNumber(tkwin)); #endif } else { #ifdef WIN32 lightGC = Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC); #else lightGC = DefaultGC(Tk_Display(tkwin), Tk_ScreenNumber(tkwin)); #endif darkGC = Tk_3DBorderGC(tkwin, border, TK_3D_FLAT_GC); } XDrawLine(Tk_Display(tkwin), drawable, darkGC, x2, y2, x2, y); XDrawLine(Tk_Display(tkwin), drawable, lightGC, x, y, x2, y); XDrawLine(Tk_Display(tkwin), drawable, darkGC, x2, y2, x, y2); XDrawLine(Tk_Display(tkwin), drawable, lightGC, x, y, x, y2); x++, y++, width -= 2, height -= 2, borderWidth--; } #endif Tk_Draw3DRectangle(tkwin, drawable, border, x, y, width, height, borderWidth, relief); } #ifdef notdef typedef struct { Screen *screen; Visual *visual; Colormap colormap; Tk_Uid nameUid; } BorderKey; typedef struct { 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 refCount; /* Number of active uses of this color * (each active use corresponds to a * call to Blt_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 refCount is * 0. */ XColor *bgColorPtr; /* Color of face. */ XColor *shadows[4]; Pixmap darkStipple; /* Stipple pattern to use for drawing * shadows areas. Used for displays with * <= 64 colors or where colormap has filled * up. */ Pixmap lightStipple; /* 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 lightGC, darkGC; Tcl_HashEntry *hashPtr; /* Entry in borderTable (needed in * order to delete structure). */ struct Blt_3DBorderStruct *nextPtr; } Border, *Blt_3DBorder; void Blt_Draw3DRectangle(tkwin, drawable, border, x, y, width, height, borderWidth, relief) Tk_Window tkwin; /* Window for which border was allocated. */ Drawable drawable; /* X window or pixmap in which to draw. */ Blt_3DBorder *borderPtr; /* Border to draw. */ int x, y, width, height; /* Outside area of rectangular region. */ int borderWidth; /* Desired width for border, in * pixels. Border will be *inside* region. */ int relief; /* Indicates 3D effect: TK_RELIEF_FLAT, * TK_RELIEF_RAISED, or TK_RELIEF_SUNKEN. */ { if ((width > (2 * borderWidth)) && (height > (2 * borderWidth))) { int x2, y2; int i; x2 = x + width - 1; y2 = y + height - 1; XSetForeground(borderPtr->lightGC, borderPtr->shadows[0]); XSetForeground(borderPtr->darkGC, borderPtr->shadows[3]); XDrawLine(Tk_Display(tkwin), drawable, borderPtr->lightGC, x, y, x2, y); XDrawLine(Tk_Display(tkwin), drawable, borderPtr->lightGC, x, y, x, y2); XDrawLine(Tk_Display(tkwin), drawable, borderPtr->darkGC, x2, y, x2, y2); XDrawLine(Tk_Display(tkwin), drawable, borderPtr->darkGC, x2, y2, x, y2); XSetForeground(borderPtr->lightGC, borderPtr->shadows[1]); XSetForeground(borderPtr->darkGC, borderPtr->shadows[2]); for (i = 1; i < (borderWidth - 1); i++) { /* * +--------- * |+------- * ||+----- * ||| * ||| * || * | */ x++, y++, x2--, y2--; XDrawLine(Tk_Display(tkwin), drawable, borderPtr->lightGC, x, y, x2, y); XDrawLine(Tk_Display(tkwin), drawable, borderPtr->lightGC, x, y, x, y2); XDrawLine(Tk_Display(tkwin), drawable, borderPtr->darkGC, x2, y, x2, y2); XDrawLine(Tk_Display(tkwin), drawable, borderPtr->darkGC, x2, y2, x, y2); } } } void Blt_Fill3DRectangle(tkwin, drawable, border, x, y, width, height, borderWidth, relief) Tk_Window tkwin; /* Window for which border was allocated. */ Drawable drawable; /* X window or pixmap in which to draw. */ Tk_3DBorder border; /* Token for border to draw. */ int x, y, width, height; /* Outside area of rectangular region. */ int borderWidth; /* Desired width for border, in * pixels. Border will be *inside* region. */ int relief; /* Indicates 3D effect: TK_RELIEF_FLAT, * TK_RELIEF_RAISED, or TK_RELIEF_SUNKEN. */ { Blt_3DBorder *borderPtr; XFillRectangle(Tk_Display(tkwin), drawable, borderPtr->bgGC, x, y, width, height); if ((borderWidth > 0) && (relief != BLT_RELIEF_FLAT)) { Blt_Draw3DRectangle(tkwin, drawable, borderPtr, x, y, width, height, borderWidth, relief); } } void FreeBorder(display, borderPtr) Display *display; Border *borderPtr; { int i; if (borderPtr->bgColorPtr != NULL) { Tk_FreeColor(display, borderPtr->bgColorPtr); } for (i = 0; i < 4; i++) { Tk_FreeColor(display, borderPtr->shadows[i]); } if (borderPtr->tile != NULL) { Blt_FreeTile(tile); } if (borderPtr->darkGC != NULL) { Blt_FreePrivateGC(display, borderPtr->darkGC); } if (borderPtr->lightGC != NULL) { Blt_FreePrivateGC(tkwin, borderPtr->lightGC); } if (borderPtr->bgGC != NULL) { Blt_FreePrivateGC(tkwin, borderPtr->bgGC); } Blt_Free(borderPtr); } void Blt_Free3DBorder(display, border) Display *display; Blt_3DBorder border; { Border *borderPtr = (Border *)border; borderPtr->refCount--; if (borderPtr->refCount >= 0) { /* Search for the border in the bucket. Start at the head. */ headPtr = Blt_GetHashValue(borderPtr->hashPtr); lastPtr = NULL; while ((headPtr != borderPtr) && (headPtr != NULL)) { lastPtr = headPtr; headPtr = headPtr->next; } if (headPtr == NULL) { return; /* This can't happen. It means that * we could not find the border. */ } if (lastPtr != NULL) { lastPtr->next = borderPtr->next; } else { Tcl_DeleteHashEntry(borderPtr->hashPtr); } FreeBorder(display, borderPtr); } } Blt_3DBorder * Blt_Get3DBorder(interp, tkwin, borderName) Tcl_Interp *interp; Tk_Window tkwin; char *borderName; { Blt_3DBorder *borderPtr, *lastBorderPtr; Blt_HashEntry *hPtr; Blt_Tile tile; XColor *bgColorPtr; char **argv; char *colorName; int argc; int isNew; lastBorderPtr = NULL; hPtr = Tcl_CreateHashEntry(&dataPtr->borderTable, borderName, &isNew); if (!isNew) { borderPtr = lastBorderPtr = Blt_GetHashValue(hPtr); while (borderPtr != NULL) { if ((Tk_Screen(tkwin) == borderPtr->screen) && (Tk_Colormap(tkwin) == borderPtr->colormap)) { borderPtr->refCount++; return borderPtr; } borderPtr = borderPtr->nextPtr; } } /* Create a new border. */ argv = NULL; bgColorPtr = NULL; tile = NULL; if (Tcl_SplitList(interp, borderName, &argc, &argv) != TCL_OK) { goto error; } colorName = borderName; if ((argc == 2) && (Blt_GetTile(interp, tkwin, argv[0], &tile) == TCL_OK)) { colorName = argv[1]; } bgColorPtr = Tk_GetColor(interp, tkwin, colorName); if (bgColorPtr == NULL) { goto error; } /* Create a new border */ borderPtr = Blt_Calloc(1, sizeof(Blt_3DBorder)); assert(borderPtr); borderPtr->screen = Tk_Screen(tkwin); borderPtr->visual = Tk_Visual(tkwin); borderPtr->depth = Tk_Depth(tkwin); borderPtr->colormap = Tk_Colormap(tkwin); borderPtr->refCount = 1; borderPtr->bgColorPtr = bgColorPtr; borderPtr->tile = tile; borderPtr->darkGC = Blt_GetPrivateGC(tkwin, 0, NULL); borderPtr->lightGC = Blt_GetPrivateGC(tkwin, 0, NULL); borderPtr->hashPtr = lastBorderPtr->hashPtr; lastBorderPtr->nextPtr = lastBorderPtr; { HSV hsv; XColor color; double sat, sat0, diff, step, hstep; int count; /* Convert the face (background) color to HSV */ Blt_XColorToHSV(borderPtr->bgColorPtr, &hsv); /* Using the color as the baseline intensity, pick a set of * colors around the intensity. */ #define UFLOOR(x,u) (floor((x)*(u))/(u)) diff = hsv.sat - UFLOOR(hsv.sat, 0.2); sat = 0.1 + (diff - 0.1); sat0 = hsv.sat; count = 0; for (sat = 0.1 + (diff - 0.1); sat <= 1.0; sat += 0.2) { if (FABS(sat0 - sat) >= 0.1) { hsv.sat = sat; Blt_HSVToXColor(&hsv, &color); borderPtr->shadows[count] = Tk_GetColorByValue(tkwin, &color); count++; } } } Blt_SetHashValue(hPtr, borderPtr); if (argv != NULL) { Blt_Free(argv); } return TCL_OK; error: if (argv != NULL) { Blt_Free(argv); } if (tile != NULL) { Blt_FreeTile(tile); } if (bgColorPtr != NULL) { Tk_FreeColor(bgColorPtr); } if (isNew) { Blt_DeleteHashEntry(&borderTable, hPtr); } return NULL; } #endif blt-2.4z.orig/src/bltGrPen.c0100644000175000017500000004314307542177233014433 0ustar dokodoko /* * bltGrPen.c -- * * This module implements pens for the BLT graph widget. * * Copyright 1996-1998 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. */ #include "bltGraph.h" #include static Tk_OptionParseProc StringToColor; static Tk_OptionPrintProc ColorToString; static Tk_OptionParseProc StringToPen; static Tk_OptionPrintProc PenToString; Tk_CustomOption bltColorOption = { StringToColor, ColorToString, (ClientData)0 }; Tk_CustomOption bltPenOption = { StringToPen, PenToString, (ClientData)0 }; Tk_CustomOption bltBarPenOption = { StringToPen, PenToString, (ClientData)&bltBarElementUid }; Tk_CustomOption bltLinePenOption = { StringToPen, PenToString, (ClientData)&bltLineElementUid }; /* *---------------------------------------------------------------------- * StringToColor -- * * Convert the string representation of a color into a XColor pointer. * * Results: * The return value is a standard Tcl result. The color pointer is * written into the widget record. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToColor(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* String representing color */ char *widgRec; /* Widget record */ int offset; /* Offset of color field in record */ { XColor **colorPtrPtr = (XColor **)(widgRec + offset); XColor *colorPtr; unsigned int length; char c; if ((string == NULL) || (*string == '\0')) { *colorPtrPtr = NULL; return TCL_OK; } c = string[0]; length = strlen(string); if ((c == 'd') && (strncmp(string, "defcolor", length) == 0)) { colorPtr = COLOR_DEFAULT; } else { colorPtr = Tk_GetColor(interp, tkwin, Tk_GetUid(string)); if (colorPtr == NULL) { return TCL_ERROR; } } *colorPtrPtr = colorPtr; return TCL_OK; } /* *---------------------------------------------------------------------- * * NameOfColor -- * * Convert the color option value into a string. * * Results: * The static string representing the color option is returned. * *---------------------------------------------------------------------- */ static char * NameOfColor(colorPtr) XColor *colorPtr; { if (colorPtr == NULL) { return ""; } else if (colorPtr == COLOR_DEFAULT) { return "defcolor"; } else { return Tk_NameOfColor(colorPtr); } } /* *---------------------------------------------------------------------- * * ColorToString -- * * Convert the color value into a string. * * Results: * The string representing the symbol color is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * ColorToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget information record */ int offset; /* Offset of symbol type in record */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { XColor *colorPtr = *(XColor **)(widgRec + offset); return NameOfColor(colorPtr); } /* *---------------------------------------------------------------------- * * StringToPen -- * * Convert the color value into a string. * * Results: * The string representing the symbol color is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToPen(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* String representing pen */ char *widgRec; /* Widget record */ int offset; /* Offset of pen field in record */ { Blt_Uid classUid = *(Blt_Uid *)clientData; /* Element type. */ Pen **penPtrPtr = (Pen **)(widgRec + offset); Pen *penPtr; Graph *graphPtr; penPtr = NULL; graphPtr = Blt_GetGraphFromWindowData(tkwin); if (classUid == NULL) { classUid = graphPtr->classUid; } if ((string != NULL) && (string[0] != '\0')) { if (Blt_GetPen(graphPtr, string, classUid, &penPtr) != TCL_OK) { return TCL_ERROR; } } /* Release the old pen */ if (*penPtrPtr != NULL) { Blt_FreePen(graphPtr, *penPtrPtr); } *penPtrPtr = penPtr; return TCL_OK; } /* *---------------------------------------------------------------------- * * PenToString -- * * Parse the name of the name. * * Results: * The return value is a standard Tcl result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * PenToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget information record */ int offset; /* Offset of pen in record */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { Pen *penPtr = *(Pen **)(widgRec + offset); return penPtr->name; } /* *---------------------------------------------------------------------- * * NameToPen -- * * Find and return the pen style from a given name. * * Results: * A standard TCL result. * *---------------------------------------------------------------------- */ static Pen * NameToPen(graphPtr, name) Graph *graphPtr; char *name; { Blt_HashEntry *hPtr; Pen *penPtr; hPtr = Blt_FindHashEntry(&(graphPtr->penTable), name); if (hPtr == NULL) { notFound: Tcl_AppendResult(graphPtr->interp, "can't find pen \"", name, "\" in \"", Tk_PathName(graphPtr->tkwin), "\"", (char *)NULL); return NULL; } penPtr = (Pen *)Blt_GetHashValue(hPtr); if (penPtr->flags & PEN_DELETE_PENDING) { goto notFound; } return penPtr; } static void DestroyPen(graphPtr, penPtr) Graph *graphPtr; Pen *penPtr; { Tk_FreeOptions(penPtr->configSpecs, (char *)penPtr, graphPtr->display, 0); (*penPtr->destroyProc) (graphPtr, penPtr); if ((penPtr->name != NULL) && (penPtr->name[0] != '\0')) { Blt_Free(penPtr->name); } if (penPtr->hashPtr != NULL) { Blt_DeleteHashEntry(&(graphPtr->penTable), penPtr->hashPtr); } Blt_Free(penPtr); } void Blt_FreePen(graphPtr, penPtr) Graph *graphPtr; Pen *penPtr; { penPtr->refCount--; if ((penPtr->refCount == 0) && (penPtr->flags & PEN_DELETE_PENDING)) { DestroyPen(graphPtr, penPtr); } } Pen * Blt_CreatePen(graphPtr, penName, classUid, nOpts, options) Graph *graphPtr; char *penName; Blt_Uid classUid; int nOpts; char **options; { Pen *penPtr; Blt_HashEntry *hPtr; unsigned int length, configFlags; int isNew; register int i; /* * Scan the option list for a "-type" entry. This will indicate * what type of pen we are creating. Otherwise we'll default to the * suggested type. Last -type option wins. */ for (i = 0; i < nOpts; i += 2) { length = strlen(options[i]); if ((length > 2) && (strncmp(options[i], "-type", length) == 0)) { char *arg; arg = options[i + 1]; if (strcmp(arg, "bar") == 0) { classUid = bltBarElementUid; } else if (strcmp(arg, "line") != 0) { classUid = bltLineElementUid; } else if (strcmp(arg, "strip") != 0) { classUid = bltLineElementUid; } else { Tcl_AppendResult(graphPtr->interp, "unknown pen type \"", arg, "\" specified", (char *)NULL); return NULL; } } } if (classUid == bltStripElementUid) { classUid = bltLineElementUid; } hPtr = Blt_CreateHashEntry(&(graphPtr->penTable), penName, &isNew); if (!isNew) { penPtr = (Pen *)Blt_GetHashValue(hPtr); if (!(penPtr->flags & PEN_DELETE_PENDING)) { Tcl_AppendResult(graphPtr->interp, "pen \"", penName, "\" already exists in \"", Tk_PathName(graphPtr->tkwin), "\"", (char *)NULL); return NULL; } if (penPtr->classUid != classUid) { Tcl_AppendResult(graphPtr->interp, "pen \"", penName, "\" in-use: can't change pen type from \"", penPtr->classUid, "\" to \"", classUid, "\"", (char *)NULL); return NULL; } penPtr->flags &= ~PEN_DELETE_PENDING; } else { if (classUid == bltBarElementUid) { penPtr = Blt_BarPen(penName); } else { penPtr = Blt_LinePen(penName); } penPtr->classUid = classUid; penPtr->hashPtr = hPtr; Blt_SetHashValue(hPtr, penPtr); } configFlags = (penPtr->flags & (ACTIVE_PEN | NORMAL_PEN)); if (Blt_ConfigureWidgetComponent(graphPtr->interp, graphPtr->tkwin, penPtr->name, "Pen", penPtr->configSpecs, nOpts, options, (char *)penPtr, configFlags) != TCL_OK) { if (isNew) { DestroyPen(graphPtr, penPtr); } return NULL; } (*penPtr->configProc) (graphPtr, penPtr); return penPtr; } int Blt_GetPen(graphPtr, name, classUid, penPtrPtr) Graph *graphPtr; char *name; Blt_Uid classUid; Pen **penPtrPtr; { Pen *penPtr; penPtr = NameToPen(graphPtr, name); if (penPtr == NULL) { return TCL_ERROR; } if (classUid == bltStripElementUid) { classUid = bltLineElementUid; } if (penPtr->classUid != classUid) { Tcl_AppendResult(graphPtr->interp, "pen \"", name, "\" is the wrong type (is \"", penPtr->classUid, "\"", ", wanted \"", classUid, "\")", (char *)NULL); return TCL_ERROR; } penPtr->refCount++; *penPtrPtr = penPtr; return TCL_OK; } /* *---------------------------------------------------------------------- * * Blt_DestroyPens -- * * Release memory and resources allocated for the style. * * Results: * None. * * Side effects: * Everything associated with the pen style is freed up. * *---------------------------------------------------------------------- */ void Blt_DestroyPens(graphPtr) Graph *graphPtr; { Blt_HashEntry *hPtr; Blt_HashSearch cursor; Pen *penPtr; for (hPtr = Blt_FirstHashEntry(&(graphPtr->penTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { penPtr = (Pen *)Blt_GetHashValue(hPtr); penPtr->hashPtr = NULL; DestroyPen(graphPtr, penPtr); } Blt_DeleteHashTable(&(graphPtr->penTable)); } /* * ---------------------------------------------------------------------- * * CgetOp -- * * Queries axis attributes (font, line width, label, etc). * * Results: * A standard Tcl result. If querying configuration values, * interp->result will contain the results. * * ---------------------------------------------------------------------- */ /* ARGSUSED */ static int CgetOp(interp, graphPtr, argc, argv) Tcl_Interp *interp; Graph *graphPtr; int argc; /* Not used. */ char *argv[]; { Pen *penPtr; unsigned int configFlags; penPtr = NameToPen(graphPtr, argv[3]); if (penPtr == NULL) { return TCL_ERROR; } configFlags = (penPtr->flags & (ACTIVE_PEN | NORMAL_PEN)); return Tk_ConfigureValue(interp, graphPtr->tkwin, penPtr->configSpecs, (char *)penPtr, argv[4], configFlags); } /* * ---------------------------------------------------------------------- * * ConfigureOp -- * * Queries or resets pen attributes (font, line width, color, etc). * * Results: * A standard Tcl result. If querying configuration values, * interp->result will contain the results. * * Side Effects: * Pen resources are possibly allocated (GC, font). * * ---------------------------------------------------------------------- */ static int ConfigureOp(interp, graphPtr, argc, argv) Tcl_Interp *interp; Graph *graphPtr; int argc; char *argv[]; { int flags; Pen *penPtr; int nNames, nOpts; int redraw; char **options; register int i; /* Figure out where the option value pairs begin */ argc -= 3; argv += 3; for (i = 0; i < argc; i++) { if (argv[i][0] == '-') { break; } if (NameToPen(graphPtr, argv[i]) == NULL) { return TCL_ERROR; } } nNames = i; /* Number of pen names specified */ nOpts = argc - i; /* Number of options specified */ options = argv + i; /* Start of options in argv */ redraw = 0; for (i = 0; i < nNames; i++) { penPtr = NameToPen(graphPtr, argv[i]); flags = TK_CONFIG_ARGV_ONLY | (penPtr->flags & (ACTIVE_PEN|NORMAL_PEN)); if (nOpts == 0) { return Tk_ConfigureInfo(interp, graphPtr->tkwin, penPtr->configSpecs, (char *)penPtr, (char *)NULL, flags); } else if (nOpts == 1) { return Tk_ConfigureInfo(interp, graphPtr->tkwin, penPtr->configSpecs, (char *)penPtr, options[0], flags); } if (Tk_ConfigureWidget(interp, graphPtr->tkwin, penPtr->configSpecs, nOpts, options, (char *)penPtr, flags) != TCL_OK) { break; } (*penPtr->configProc) (graphPtr, penPtr); if (penPtr->refCount > 0) { redraw++; } } if (redraw) { graphPtr->flags |= REDRAW_BACKING_STORE | DRAW_MARGINS; Blt_EventuallyRedrawGraph(graphPtr); } if (i < nNames) { return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * CreateOp -- * * Adds a new penstyle to the graph. * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ static int CreateOp(interp, graphPtr, argc, argv) Tcl_Interp *interp; Graph *graphPtr; int argc; char **argv; { Pen *penPtr; penPtr = Blt_CreatePen(graphPtr, argv[3], graphPtr->classUid, argc - 4, argv + 4); if (penPtr == NULL) { return TCL_ERROR; } Tcl_SetResult(interp, penPtr->name, TCL_VOLATILE); return TCL_OK; } /* *-------------------------------------------------------------- * * DeleteOp -- * * Delete the given pen. * * Results: * Always returns TCL_OK. The interp->result field is * a list of the graph axis limits. * *-------------------------------------------------------------- */ /*ARGSUSED*/ static int DeleteOp(interp, graphPtr, argc, argv) Tcl_Interp *interp; Graph *graphPtr; int argc; char **argv; { Pen *penPtr; int i; for (i = 3; i < argc; i++) { penPtr = NameToPen(graphPtr, argv[i]); if (penPtr == NULL) { return TCL_ERROR; } if (penPtr->flags & PEN_DELETE_PENDING) { Tcl_AppendResult(graphPtr->interp, "can't find pen \"", argv[i], "\" in \"", Tk_PathName(graphPtr->tkwin), "\"", (char *)NULL); return TCL_ERROR; } penPtr->flags |= PEN_DELETE_PENDING; if (penPtr->refCount == 0) { DestroyPen(graphPtr, penPtr); } } return TCL_OK; } /* * ---------------------------------------------------------------------- * * NamesOp -- * * Return a list of the names of all the axes. * * Results: * Returns a standard Tcl result. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static int NamesOp(interp, graphPtr, argc, argv) Tcl_Interp *interp; Graph *graphPtr; int argc; char **argv; { Blt_HashSearch cursor; Pen *penPtr; register int i; register Blt_HashEntry *hPtr; for (hPtr = Blt_FirstHashEntry(&(graphPtr->penTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { penPtr = (Pen *)Blt_GetHashValue(hPtr); if (penPtr->flags & PEN_DELETE_PENDING) { continue; } if (argc == 3) { Tcl_AppendElement(interp, penPtr->name); continue; } for (i = 3; i < argc; i++) { if (Tcl_StringMatch(penPtr->name, argv[i])) { Tcl_AppendElement(interp, penPtr->name); break; } } } return TCL_OK; } /* * ---------------------------------------------------------------------- * * TypeOp -- * * Return the type of pen. * * Results: * Returns a standard Tcl result. * * ---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TypeOp(interp, graphPtr, argc, argv) Tcl_Interp *interp; Graph *graphPtr; int argc; char **argv; { Pen *penPtr; penPtr = NameToPen(graphPtr, argv[3]); if (penPtr == NULL) { return TCL_ERROR; } Tcl_SetResult(interp, penPtr->classUid, TCL_STATIC); return TCL_OK; } static Blt_OpSpec penOps[] = { {"cget", 2, (Blt_Op)CgetOp, 5, 5, "penName option",}, {"configure", 2, (Blt_Op)ConfigureOp, 4, 0, "penName ?penName?... ?option value?...",}, {"create", 2, (Blt_Op)CreateOp, 4, 0, "penName ?option value?...",}, {"delete", 2, (Blt_Op)DeleteOp, 3, 0, "?penName?...",}, {"names", 1, (Blt_Op)NamesOp, 3, 0, "?pattern?...",}, {"type", 1, (Blt_Op)TypeOp, 4, 4, "penName",}, }; static int nPenOps = sizeof(penOps) / sizeof(Blt_OpSpec); int Blt_PenOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { Blt_Op proc; proc = Blt_GetOp(interp, nPenOps, penOps, BLT_OP_ARG2, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } return (*proc) (interp, graphPtr, argc, argv); } blt-2.4z.orig/src/bltGrPs.c0100644000175000017500000011532307525066175014276 0ustar dokodoko /* * bltGrPs.c -- * * This module implements the "postscript" operation for BLT * graph widget. * * Copyright 1991-1998 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. */ /* * ----------------------------------------------------------------- * * PostScript routines to print a graph * * ----------------------------------------------------------------- */ #include "bltGraph.h" #include #if defined(__STDC__) #include #else #include #endif #define PS_PREVIEW_EPSI 0 #define PS_PREVIEW_WMF 1 #define PS_PREVIEW_TIFF 2 static Tk_OptionParseProc StringToColorMode; static Tk_OptionPrintProc ColorModeToString; static Tk_CustomOption colorModeOption = { StringToColorMode, ColorModeToString, (ClientData)0, }; static Tk_OptionParseProc StringToFormat; static Tk_OptionPrintProc FormatToString; static Tk_CustomOption formatOption = { StringToFormat, FormatToString, (ClientData)0, }; extern Tk_CustomOption bltDistanceOption; extern Tk_CustomOption bltPositiveDistanceOption; extern Tk_CustomOption bltPadOption; #define DEF_PS_CENTER "yes" #define DEF_PS_COLOR_MAP (char *)NULL #define DEF_PS_COLOR_MODE "color" #define DEF_PS_DECORATIONS "yes" #define DEF_PS_FONT_MAP (char *)NULL #define DEF_PS_FOOTER "no" #define DEF_PS_HEIGHT "0" #define DEF_PS_LANDSCAPE "no" #define DEF_PS_MAXPECT "no" #define DEF_PS_PADX "1.0i" #define DEF_PS_PADY "1.0i" #define DEF_PS_PAPERHEIGHT "11.0i" #define DEF_PS_PAPERWIDTH "8.5i" #define DEF_PS_PREVIEW "no" #define DEF_PS_PREVIEW_FORMAT "epsi" #define DEF_PS_WIDTH "0" static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_BOOLEAN, "-center", "center", "Center", DEF_PS_CENTER, Tk_Offset(PostScript, center), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_STRING, "-colormap", "colorMap", "ColorMap", DEF_PS_COLOR_MAP, Tk_Offset(PostScript, colorVarName), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-colormode", "colorMode", "ColorMode", DEF_PS_COLOR_MODE, Tk_Offset(PostScript, colorMode), TK_CONFIG_DONT_SET_DEFAULT, &colorModeOption}, {TK_CONFIG_BOOLEAN, "-decorations", "decorations", "Decorations", DEF_PS_DECORATIONS, Tk_Offset(PostScript, decorations), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_STRING, "-fontmap", "fontMap", "FontMap", DEF_PS_FONT_MAP, Tk_Offset(PostScript, fontVarName), TK_CONFIG_NULL_OK}, {TK_CONFIG_BOOLEAN, "-footer", "footer", "Footer", DEF_PS_FOOTER, Tk_Offset(PostScript, footer), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-height", "height", "Height", DEF_PS_HEIGHT, Tk_Offset(PostScript, reqHeight), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_BOOLEAN, "-landscape", "landscape", "Landscape", DEF_PS_LANDSCAPE, Tk_Offset(PostScript, landscape), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_BOOLEAN, "-maxpect", "maxpect", "Maxpect", DEF_PS_MAXPECT, Tk_Offset(PostScript, maxpect), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-padx", "padX", "PadX", DEF_PS_PADX, Tk_Offset(PostScript, padX), 0, &bltPadOption}, {TK_CONFIG_CUSTOM, "-pady", "padY", "PadY", DEF_PS_PADY, Tk_Offset(PostScript, padY), 0, &bltPadOption}, {TK_CONFIG_CUSTOM, "-paperheight", "paperHeight", "PaperHeight", DEF_PS_PAPERHEIGHT, Tk_Offset(PostScript, reqPaperHeight), 0, &bltPositiveDistanceOption}, {TK_CONFIG_CUSTOM, "-paperwidth", "paperWidth", "PaperWidth", DEF_PS_PAPERWIDTH, Tk_Offset(PostScript, reqPaperWidth), 0, &bltPositiveDistanceOption}, {TK_CONFIG_BOOLEAN, "-preview", "preview", "Preview", DEF_PS_PREVIEW, Tk_Offset(PostScript, addPreview), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-previewformat", "previewFormat", "PreviewFormat", DEF_PS_PREVIEW_FORMAT, Tk_Offset(PostScript, previewFormat), TK_CONFIG_DONT_SET_DEFAULT, &formatOption}, {TK_CONFIG_CUSTOM, "-width", "width", "Width", DEF_PS_WIDTH, Tk_Offset(PostScript, reqWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} }; extern void Blt_MarkersToPostScript _ANSI_ARGS_((Graph *graphPtr, PsToken psToken, int under)); extern void Blt_ElementsToPostScript _ANSI_ARGS_((Graph *graphPtr, PsToken psToken)); extern void Blt_ActiveElementsToPostScript _ANSI_ARGS_((Graph *graphPtr, PsToken psToken)); extern void Blt_LegendToPostScript _ANSI_ARGS_((Legend *legendPtr, PsToken psToken)); extern void Blt_GridToPostScript _ANSI_ARGS_((Graph *graphPtr, PsToken psToken)); extern void Blt_AxesToPostScript _ANSI_ARGS_((Graph *graphPtr, PsToken psToken)); extern void Blt_AxisLimitsToPostScript _ANSI_ARGS_((Graph *graphPtr, PsToken psToken)); /* *---------------------------------------------------------------------- * * StringToColorMode -- * * Convert the string representation of a PostScript color mode * into the enumerated type representing the color level: * * PS_MODE_COLOR - Full color * PS_MODE_GREYSCALE - Color converted to greyscale * PS_MODE_MONOCHROME - Only black and white * * Results: * A standard Tcl result. The color level is written into the * page layout information structure. * * Side Effects: * Future invocations of the "postscript" option will use this * variable to determine how color information will be displayed * in the PostScript output it produces. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToColorMode(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* New value. */ char *widgRec; /* Widget record */ int offset; /* Offset of field in record */ { PsColorMode *modePtr = (PsColorMode *) (widgRec + offset); unsigned int length; char c; c = string[0]; length = strlen(string); if ((c == 'c') && (strncmp(string, "color", length) == 0)) { *modePtr = PS_MODE_COLOR; } else if ((c == 'g') && (strncmp(string, "grayscale", length) == 0)) { *modePtr = PS_MODE_GREYSCALE; } else if ((c == 'g') && (strncmp(string, "greyscale", length) == 0)) { *modePtr = PS_MODE_GREYSCALE; } else if ((c == 'm') && (strncmp(string, "monochrome", length) == 0)) { *modePtr = PS_MODE_MONOCHROME; } else { Tcl_AppendResult(interp, "bad color mode \"", string, "\": should be \ \"color\", \"greyscale\", or \"monochrome\"", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * NameOfColorMode -- * * Convert the PostScript mode value into the string representing * a valid color mode. * * Results: * The static string representing the color mode is returned. * *---------------------------------------------------------------------- */ static char * NameOfColorMode(colorMode) PsColorMode colorMode; { switch (colorMode) { case PS_MODE_COLOR: return "color"; case PS_MODE_GREYSCALE: return "greyscale"; case PS_MODE_MONOCHROME: return "monochrome"; default: return "unknown color mode"; } } /* *---------------------------------------------------------------------- * * ColorModeToString -- * * Convert the current color mode into the string representing a * valid color mode. * * Results: * The string representing the color mode is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * ColorModeToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget record. */ int offset; /* field of colorMode in record */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { PsColorMode mode = *(PsColorMode *) (widgRec + offset); return NameOfColorMode(mode); } /* *---------------------------------------------------------------------- * * StringToFormat -- * * Convert the string of the PostScript preview format into * an enumerated type representing the desired format. The * available formats are: * * PS_PREVIEW_WMF - Windows Metafile. * PS_PREVIEW_TIFF - TIFF bitmap image. * PS_PREVIEW_EPSI - Device independent ASCII preview * * Results: * A standard Tcl result. The format is written into the * page layout information structure. * * Side Effects: * Future invocations of the "postscript" option will use this * variable to determine how to format a preview image (if one * is selected) when the PostScript output is produced. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToFormat(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* New value. */ char *widgRec; /* Widget record */ int offset; /* Offset of field in record */ { int *formatPtr = (int *) (widgRec + offset); unsigned int length; char c; c = string[0]; length = strlen(string); if ((c == 'c') && (strncmp(string, "epsi", length) == 0)) { *formatPtr = PS_PREVIEW_EPSI; #ifdef WIN32 #ifdef HAVE_TIFF_H } else if ((c == 't') && (strncmp(string, "tiff", length) == 0)) { *formatPtr = PS_PREVIEW_TIFF; #endif /* HAVE_TIFF_H */ } else if ((c == 'w') && (strncmp(string, "wmf", length) == 0)) { *formatPtr = PS_PREVIEW_WMF; #endif /* WIN32 */ } else { Tcl_AppendResult(interp, "bad format \"", string, "\": should be ", #ifdef WIN32 #ifdef HAVE_TIFF_H "\"tiff\" or ", #endif /* HAVE_TIFF_H */ "\"wmf\" or ", #endif /* WIN32 */ "\"epsi\"", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * FormatToString -- * * Convert the preview format into the string representing its * type. * * Results: * The string representing the preview format is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * FormatToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* PostScript structure record */ int offset; /* field of colorMode in record */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { int format = *(int *)(widgRec + offset); switch (format) { case PS_PREVIEW_EPSI: return "epsi"; case PS_PREVIEW_WMF: return "wmf"; case PS_PREVIEW_TIFF: return "tiff"; } return "?unknown preview format?"; } void Blt_DestroyPostScript(graphPtr) Graph *graphPtr; { Tk_FreeOptions(configSpecs, (char *)graphPtr->postscript, graphPtr->display, 0); Blt_Free(graphPtr->postscript); } /* *---------------------------------------------------------------------- * * CgetOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int CgetOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char *argv[]; { PostScript *psPtr = (PostScript *)graphPtr->postscript; if (Tk_ConfigureValue(interp, graphPtr->tkwin, configSpecs, (char *)psPtr, argv[3], 0) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } /* * ---------------------------------------------------------------------- * * ConfigureOp -- * * This procedure is invoked to print the graph in a file. * * Results: * A standard TCL result. * * Side effects: * A new PostScript file is created. * * ---------------------------------------------------------------------- */ static int ConfigureOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; /* Number of options in argv vector */ char **argv; /* Option vector */ { int flags = TK_CONFIG_ARGV_ONLY; PostScript *psPtr = (PostScript *)graphPtr->postscript; if (argc == 3) { return Tk_ConfigureInfo(interp, graphPtr->tkwin, configSpecs, (char *)psPtr, (char *)NULL, flags); } else if (argc == 4) { return Tk_ConfigureInfo(interp, graphPtr->tkwin, configSpecs, (char *)psPtr, argv[3], flags); } if (Tk_ConfigureWidget(interp, graphPtr->tkwin, configSpecs, argc - 3, argv + 3, (char *)psPtr, flags) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } /* * -------------------------------------------------------------------------- * * ComputeBoundingBox -- * * Computes the bounding box for the PostScript plot. First get * the size of the plot (by default, it's the size of graph's X * window). If the plot plus the page border is bigger than the * designated paper size, or if the "-maxpect" option is turned * on, scale the plot to the page. * * Note: All coordinates/sizes are in screen coordinates, not * PostScript coordinates. This includes the computed * bounding box and paper size. They will be scaled to * printer points later. * * Results: * Returns the height of the paper in screen coordinates. * * Side Effects: * The graph dimensions (width and height) are changed to the * requested PostScript plot size. * * -------------------------------------------------------------------------- */ static int ComputeBoundingBox(graphPtr, psPtr) Graph *graphPtr; PostScript *psPtr; { int paperWidth, paperHeight; int x, y, hSize, vSize, hBorder, vBorder; double hScale, vScale, scale; x = psPtr->padLeft; y = psPtr->padTop; hBorder = PADDING(psPtr->padX); vBorder = PADDING(psPtr->padY); if (psPtr->reqWidth > 0) { graphPtr->width = psPtr->reqWidth; } if (psPtr->reqHeight > 0) { graphPtr->height = psPtr->reqHeight; } if (psPtr->landscape) { hSize = graphPtr->height; vSize = graphPtr->width; } else { hSize = graphPtr->width; vSize = graphPtr->height; } /* * If the paper size wasn't specified, set it to the graph size plus * the paper border. */ paperWidth = psPtr->reqPaperWidth; paperHeight = psPtr->reqPaperHeight; if (paperWidth < 1) { paperWidth = hSize + hBorder; } if (paperHeight < 1) { paperHeight = vSize + vBorder; } hScale = vScale = 1.0; /* * Scale the plot size (the graph itself doesn't change size) if * it's bigger than the paper or if -maxpect was set. */ if ((psPtr->maxpect) || ((hSize + hBorder) > paperWidth)) { hScale = (double)(paperWidth - hBorder) / (double)hSize; } if ((psPtr->maxpect) || ((vSize + vBorder) > paperHeight)) { vScale = (double)(paperHeight - vBorder) / (double)vSize; } scale = MIN(hScale, vScale); if (scale != 1.0) { hSize = (int)((hSize * scale) + 0.5); vSize = (int)((vSize * scale) + 0.5); } psPtr->pageScale = scale; if (psPtr->center) { if (paperWidth > hSize) { x = (paperWidth - hSize) / 2; } if (paperHeight > vSize) { y = (paperHeight - vSize) / 2; } } psPtr->left = x; psPtr->bottom = y; psPtr->right = x + hSize - 1; psPtr->top = y + vSize - 1; graphPtr->flags |= LAYOUT_NEEDED | MAP_WORLD; Blt_LayoutGraph(graphPtr); return paperHeight; } /* * -------------------------------------------------------------------------- * * PreviewImage -- * * Generates a EPSI thumbnail of the graph. The thumbnail is * restricted to a certain size. This is to keep the size of the * PostScript file small and the processing time low. * * The graph is drawn into a pixmap. We then take a snapshot * of that pixmap, and rescale it to a smaller image. Finally, * the image is dumped to PostScript. * * Results: * None. * * -------------------------------------------------------------------------- */ static void PreviewImage(graphPtr, psToken) Graph *graphPtr; PsToken psToken; { PostScript *psPtr = (PostScript *)graphPtr->postscript; int noBackingStore = 0; Pixmap drawable; Blt_ColorImage image; int nLines; Tcl_DString dString; /* Create a pixmap and draw the graph into it. */ drawable = Tk_GetPixmap(graphPtr->display, Tk_WindowId(graphPtr->tkwin), graphPtr->width, graphPtr->height, Tk_Depth(graphPtr->tkwin)); Blt_DrawGraph(graphPtr, drawable, noBackingStore); /* Get a color image from the pixmap */ image = Blt_DrawableToColorImage(graphPtr->tkwin, drawable, 0, 0, graphPtr->width, graphPtr->height, 1.0); Tk_FreePixmap(graphPtr->display, drawable); if (image == NULL) { return; /* Can't grab pixmap? */ } #ifdef THUMBNAIL_PREVIEW { double scale, xScale, yScale; int width, height; Blt_ColorImage destImage; /* Scale the source image into a size appropriate for a thumbnail. */ #define PS_MAX_PREVIEW_WIDTH 300.0 #define PS_MAX_PREVIEW_HEIGHT 300.0 xScale = PS_MAX_PREVIEW_WIDTH / (double)graphPtr->width; yScale = PS_MAX_PREVIEW_HEIGHT / (double)graphPtr->height; scale = MIN(xScale, yScale); width = (int)(scale * graphPtr->width + 0.5); height = (int)(scale * graphPtr->height + 0.5); destImage = Blt_ResampleColorImage(image, width, height, bltBoxFilterPtr, bltBoxFilterPtr); Blt_FreeColorImage(image); image = destImage; } #endif /* THUMBNAIL_PREVIEW */ Blt_ColorImageToGreyscale(image); if (psPtr->landscape) { Blt_ColorImage oldImage; oldImage = image; image = Blt_RotateColorImage(image, 90.0); Blt_FreeColorImage(oldImage); } Tcl_DStringInit(&dString); /* Finally, we can generate PostScript for the image */ nLines = Blt_ColorImageToPsData(image, 1, &dString, "%"); Blt_AppendToPostScript(psToken, "%%BeginPreview: ", (char *)NULL); Blt_FormatToPostScript(psToken, "%d %d 8 %d\n", Blt_ColorImageWidth(image), Blt_ColorImageHeight(image), nLines); Blt_AppendToPostScript(psToken, Tcl_DStringValue(&dString), (char *)NULL); Blt_AppendToPostScript(psToken, "%%EndPreview\n\n", (char *)NULL); Tcl_DStringFree(&dString); Blt_FreeColorImage(image); } /* * -------------------------------------------------------------------------- * * PostScriptPreamble * * The PostScript preamble calculates the needed translation and scaling * to make X11 coordinates compatible with PostScript. * * --------------------------------------------------------------------- */ #ifdef TIME_WITH_SYS_TIME #include #include #else #ifdef HAVE_SYS_TIME_H #include #else #include #endif /* HAVE_SYS_TIME_H */ #endif /* TIME_WITH_SYS_TIME */ static int PostScriptPreamble(graphPtr, fileName, psToken) Graph *graphPtr; char *fileName; PsToken psToken; { PostScript *psPtr = (PostScript *)graphPtr->postscript; time_t ticks; char date[200]; /* Hold the date string from ctime() */ CONST char *version; double dpiX, dpiY; double xPixelsToPica, yPixelsToPica; /* Scales to convert pixels to pica */ Screen *screenPtr; char *nl; int paperHeightPixels; paperHeightPixels = ComputeBoundingBox(graphPtr, psPtr); if (fileName == NULL) { fileName = Tk_PathName(graphPtr->tkwin); } Blt_AppendToPostScript(psToken, "%!PS-Adobe-3.0 EPSF-3.0\n", (char *)NULL); /* * Compute the scale factors to convert PostScript to X11 coordinates. * Round the pixels per inch (dpi) to an integral value before computing * the scale. */ #define MM_INCH 25.4 #define PICA_INCH 72.0 screenPtr = Tk_Screen(graphPtr->tkwin); dpiX = (WidthOfScreen(screenPtr) * MM_INCH) / WidthMMOfScreen(screenPtr); xPixelsToPica = PICA_INCH / dpiX; dpiY = (HeightOfScreen(screenPtr) * MM_INCH) / HeightMMOfScreen(screenPtr); yPixelsToPica = PICA_INCH / dpiY; /* * The "BoundingBox" comment is required for EPS files. The box * coordinates are integers, so we need round away from the * center of the box. */ Blt_FormatToPostScript(psToken, "%%%%BoundingBox: %d %d %d %d\n", (int)floor(psPtr->left * xPixelsToPica), (int)floor((paperHeightPixels - psPtr->top) * yPixelsToPica), (int)ceil(psPtr->right * xPixelsToPica), (int)ceil((paperHeightPixels - psPtr->bottom) * yPixelsToPica)); Blt_AppendToPostScript(psToken, "%%Pages: 0\n", (char *)NULL); version = Tcl_GetVar(graphPtr->interp, "blt_version", TCL_GLOBAL_ONLY); if (version == NULL) { version = "???"; } Blt_FormatToPostScript(psToken, "%%%%Creator: (BLT %s %s)\n", version, Tk_Class(graphPtr->tkwin)); ticks = time((time_t *) NULL); strcpy(date, ctime(&ticks)); nl = date + strlen(date) - 1; if (*nl == '\n') { *nl = '\0'; } Blt_FormatToPostScript(psToken, "%%%%CreationDate: (%s)\n", date); Blt_FormatToPostScript(psToken, "%%%%Title: (%s)\n", fileName); Blt_AppendToPostScript(psToken, "%%DocumentData: Clean7Bit\n", (char *)NULL); if (psPtr->landscape) { Blt_AppendToPostScript(psToken, "%%Orientation: Landscape\n", (char *)NULL); } else { Blt_AppendToPostScript(psToken, "%%Orientation: Portrait\n", (char *)NULL); } Blt_AppendToPostScript(psToken, "%%DocumentNeededResources: font Helvetica Courier\n", (char *)NULL); Blt_AppendToPostScript(psToken, "%%EndComments\n\n", (char *)NULL); if ((psPtr->addPreview) && (psPtr->previewFormat == PS_PREVIEW_EPSI)) { PreviewImage(graphPtr, psToken); } if (Blt_FileToPostScript(psToken, "bltGraph.pro") != TCL_OK) { return TCL_ERROR; } if (psPtr->footer) { char *who; who = getenv("LOGNAME"); if (who == NULL) { who = "???"; } Blt_AppendToPostScript(psToken, "8 /Helvetica SetFont\n", "10 30 moveto\n", "(Date: ", date, ") show\n", "10 20 moveto\n", "(File: ", fileName, ") show\n", "10 10 moveto\n", "(Created by: ", who, "@", Tcl_GetHostName(), ") show\n", "0 0 moveto\n", (char *)NULL); } /* * Set the conversion from PostScript to X11 coordinates. Scale * pica to pixels and flip the y-axis (the origin is the upperleft * corner). */ Blt_AppendToPostScript(psToken, "% Transform coordinate system to use X11 coordinates\n\n", "% 1. Flip y-axis over by reversing the scale,\n", "% 2. Translate the origin to the other side of the page,\n", "% making the origin the upper left corner\n", (char *)NULL); Blt_FormatToPostScript(psToken, "%g -%g scale\n", xPixelsToPica, yPixelsToPica); /* Papersize is in pixels. Translate the new origin *after* * changing the scale. */ Blt_FormatToPostScript(psToken, "0 %d translate\n\n", -paperHeightPixels); Blt_AppendToPostScript(psToken, "% User defined page layout\n\n", "% Set color level\n", (char *)NULL); Blt_FormatToPostScript(psToken, "/CL %d def\n\n", psPtr->colorMode); Blt_FormatToPostScript(psToken, "%% Set origin\n%d %d translate\n\n", psPtr->left, psPtr->bottom); if (psPtr->landscape) { Blt_FormatToPostScript(psToken, "%% Landscape orientation\n0 %g translate\n-90 rotate\n", ((double)graphPtr->width * psPtr->pageScale)); } if (psPtr->pageScale != 1.0) { Blt_AppendToPostScript(psToken, "\n% Setting graph scale factor\n", (char *)NULL); Blt_FormatToPostScript(psToken, " %g %g scale\n", psPtr->pageScale, psPtr->pageScale); } Blt_AppendToPostScript(psToken, "\n%%EndSetup\n\n", (char *)NULL); return TCL_OK; } static void MarginsToPostScript(graphPtr, psToken) Graph *graphPtr; PsToken psToken; { PostScript *psPtr = (PostScript *)graphPtr->postscript; XRectangle margin[4]; margin[0].x = margin[0].y = margin[3].x = margin[1].x = 0; margin[0].width = margin[3].width = graphPtr->width; margin[0].height = graphPtr->top; margin[3].y = graphPtr->bottom; margin[3].height = graphPtr->height - graphPtr->bottom; margin[2].y = margin[1].y = graphPtr->top; margin[1].width = graphPtr->left; margin[2].height = margin[1].height = graphPtr->bottom - graphPtr->top; margin[2].x = graphPtr->right; margin[2].width = graphPtr->width - graphPtr->right; /* Clear the surrounding margins and clip the plotting surface */ if (psPtr->decorations) { Blt_BackgroundToPostScript(psToken, Tk_3DBorderColor(graphPtr->border)); } else { Blt_ClearBackgroundToPostScript(psToken); } Blt_RectanglesToPostScript(psToken, margin, 4); /* Interior 3D border */ if ((psPtr->decorations) && (graphPtr->plotBorderWidth > 0)) { int x, y, width, height; x = graphPtr->left - graphPtr->plotBorderWidth; y = graphPtr->top - graphPtr->plotBorderWidth; width = (graphPtr->right - graphPtr->left) + (2 * graphPtr->plotBorderWidth); height = (graphPtr->bottom - graphPtr->top) + (2 * graphPtr->plotBorderWidth); Blt_Draw3DRectangleToPostScript(psToken, graphPtr->border, (double)x, (double)y, width, height, graphPtr->plotBorderWidth, graphPtr->plotRelief); } if (Blt_LegendSite(graphPtr->legend) & LEGEND_IN_MARGIN) { /* * Print the legend if we're using a site which lies in one * of the margins (left, right, top, or bottom) of the graph. */ Blt_LegendToPostScript(graphPtr->legend, psToken); } if (graphPtr->title != NULL) { Blt_TextToPostScript(psToken, graphPtr->title, &graphPtr->titleTextStyle, (double)graphPtr->titleX, (double)graphPtr->titleY); } Blt_AxesToPostScript(graphPtr, psToken); } static int GraphToPostScript(graphPtr, ident, psToken) Graph *graphPtr; char *ident; /* Identifier string (usually the filename) */ PsToken psToken; { int x, y, width, height; int result; /* * 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 (graphPtr->height <= 1) { graphPtr->height = Tk_ReqHeight(graphPtr->tkwin); } if (graphPtr->width <= 1) { graphPtr->width = Tk_ReqWidth(graphPtr->tkwin); } result = PostScriptPreamble(graphPtr, ident, psToken); if (result != TCL_OK) { goto error; } /* * Determine rectangle of the plotting area for the graph window */ x = graphPtr->left - graphPtr->plotBorderWidth; y = graphPtr->top - graphPtr->plotBorderWidth; width = (graphPtr->right - graphPtr->left + 1) + (2 * graphPtr->plotBorderWidth); height = (graphPtr->bottom - graphPtr->top + 1) + (2 * graphPtr->plotBorderWidth); Blt_FontToPostScript(psToken, graphPtr->titleTextStyle.font); Blt_RegionToPostScript(psToken, (double)x, (double)y, width, height); if (graphPtr->postscript->decorations) { Blt_BackgroundToPostScript(psToken, graphPtr->plotBg); } else { Blt_ClearBackgroundToPostScript(psToken); } Blt_AppendToPostScript(psToken, "Fill\n", (char *)NULL); Blt_AppendToPostScript(psToken, "gsave clip\n\n", (char *)NULL); /* Draw the grid, elements, and markers in the plotting area. */ if (!graphPtr->gridPtr->hidden) { Blt_GridToPostScript(graphPtr, psToken); } Blt_MarkersToPostScript(graphPtr, psToken, TRUE); if ((Blt_LegendSite(graphPtr->legend) & LEGEND_IN_PLOT) && (!Blt_LegendIsRaised(graphPtr->legend))) { /* Print legend underneath elements and markers */ Blt_LegendToPostScript(graphPtr->legend, psToken); } Blt_AxisLimitsToPostScript(graphPtr, psToken); Blt_ElementsToPostScript(graphPtr, psToken); if ((Blt_LegendSite(graphPtr->legend) & LEGEND_IN_PLOT) && (Blt_LegendIsRaised(graphPtr->legend))) { /* Print legend above elements (but not markers) */ Blt_LegendToPostScript(graphPtr->legend, psToken); } Blt_MarkersToPostScript(graphPtr, psToken, FALSE); Blt_ActiveElementsToPostScript(graphPtr, psToken); Blt_AppendToPostScript(psToken, "\n", "% Unset clipping\n", "grestore\n\n", (char *)NULL); MarginsToPostScript(graphPtr, psToken); Blt_AppendToPostScript(psToken, "showpage\n", "%Trailer\n", "grestore\n", "end\n", "%EOF\n", (char *)NULL); error: /* Reset height and width of graph window */ graphPtr->width = Tk_Width(graphPtr->tkwin); graphPtr->height = Tk_Height(graphPtr->tkwin); graphPtr->flags = MAP_WORLD; /* * Redraw the graph in order to re-calculate the layout as soon as * possible. This is in the case the crosshairs are active. */ Blt_EventuallyRedrawGraph(graphPtr); return result; } #ifdef WIN32 static void InitAPMHeader( Tk_Window tkwin, int width, int height, APMHEADER *headerPtr) { unsigned int *p; unsigned int sum; Screen *screen; #define MM_INCH 25.4 double dpiX, dpiY; headerPtr->key = 0x9ac6cdd7L; headerPtr->hmf = 0; headerPtr->inch = 1440; screen = Tk_Screen(tkwin); dpiX = (WidthOfScreen(screen) * MM_INCH) / WidthMMOfScreen(screen); dpiY = (HeightOfScreen(screen) * MM_INCH) / HeightMMOfScreen(screen); headerPtr->bbox.Left = headerPtr->bbox.Top = 0; headerPtr->bbox.Bottom = (SHORT)((width * 1440) / dpiX); headerPtr->bbox.Right = (SHORT)((height * 1440) / dpiY); headerPtr->reserved = 0; sum = 0; for (p = (unsigned int *)headerPtr; p < (unsigned int *)&(headerPtr->checksum); p++) { sum ^= *p; } headerPtr->checksum = sum; } /* * -------------------------------------------------------------------------- * * CreateWindowEPS -- * * Generates an EPS file with a Window metafile preview. * * Windows metafiles aren't very robust. Including exactly the * same metafile (one embedded in a DOS EPS, the other as .wmf * file) will play back differently. * * Results: * None. * * -------------------------------------------------------------------------- */ static int CreateWindowsEPS( Graph *graphPtr, PsToken psToken, FILE *f) { DWORD size; DOSEPSHEADER epsHeader; HANDLE hMem; HDC hRefDC, hDC; HENHMETAFILE hMetaFile; Tcl_DString dString; TkWinDC drawableDC; TkWinDCState state; int result; unsigned char *buffer, *psBuffer; Blt_AppendToPostScript(psToken, "\n", (char *)NULL); psBuffer = Blt_PostScriptFromToken(psToken); /* * Fill out as much information as we can into the DOS EPS header. * We won't know the start of the length of the WMF segment until * we create the metafile. */ epsHeader.magic[0] = 0xC5; epsHeader.magic[1] = 0xD0; epsHeader.magic[2] = 0xD3; epsHeader.magic[3] = 0xC6; epsHeader.psStart = sizeof(epsHeader); epsHeader.psLength = strlen(psBuffer) + 1; epsHeader.wmfStart = epsHeader.psStart + epsHeader.psLength; epsHeader.wmfLength = 0L; /* Fill in later. */ epsHeader.tiffStart = 0L; epsHeader.tiffLength = 0L; epsHeader.checksum = 0xFFFF; result = TCL_ERROR; hRefDC = TkWinGetDrawableDC(graphPtr->display, Tk_WindowId(graphPtr->tkwin), &state); /* Build a description string. */ Tcl_DStringInit(&dString); Tcl_DStringAppend(&dString, "BLT Graph ", -1); Tcl_DStringAppend(&dString, BLT_VERSION, -1); Tcl_DStringAppend(&dString, "\0", -1); Tcl_DStringAppend(&dString, Tk_PathName(graphPtr->tkwin), -1); Tcl_DStringAppend(&dString, "\0", -1); hDC = CreateEnhMetaFile(hRefDC, NULL, NULL, Tcl_DStringValue(&dString)); Tcl_DStringFree(&dString); if (hDC == NULL) { Tcl_AppendResult(graphPtr->interp, "can't create metafile: ", Blt_LastError(), (char *)NULL); return TCL_ERROR; } /* Assemble a Tk drawable that points to the metafile and let the * graph's drawing routine draw into it. */ drawableDC.hdc = hDC; drawableDC.type = TWD_WINDC; graphPtr->width = Tk_Width(graphPtr->tkwin); graphPtr->height = Tk_Height(graphPtr->tkwin); graphPtr->flags |= RESET_WORLD; Blt_LayoutGraph(graphPtr); Blt_DrawGraph(graphPtr, (Drawable)&drawableDC, FALSE); GdiFlush(); hMetaFile = CloseEnhMetaFile(hDC); size = GetWinMetaFileBits(hMetaFile, 0, NULL, MM_ANISOTROPIC, hRefDC); hMem = GlobalAlloc(GHND, size); if (hMem == NULL) { Tcl_AppendResult(graphPtr->interp, "can't allocate global memory:", Blt_LastError(), (char *)NULL); goto error; } buffer = (LPVOID)GlobalLock(hMem); if (!GetWinMetaFileBits(hMetaFile, size, buffer, MM_ANISOTROPIC, hRefDC)) { Tcl_AppendResult(graphPtr->interp, "can't get metafile data:", Blt_LastError(), (char *)NULL); goto error; } /* * Fix up the EPS header with the correct metafile length and PS * offset (now that we what they are). */ epsHeader.wmfLength = size; epsHeader.wmfStart = epsHeader.psStart + epsHeader.psLength; /* Write out the eps header, */ if (fwrite(&epsHeader, 1, sizeof(epsHeader), f) != sizeof(epsHeader)) { Tcl_AppendResult(graphPtr->interp, "error writing eps header:", Blt_LastError(), (char *)NULL); goto error; } /* the PostScript, */ if (fwrite(psBuffer, 1, epsHeader.psLength, f) != epsHeader.psLength) { Tcl_AppendResult(graphPtr->interp, "error writing PostScript data:", Blt_LastError(), (char *)NULL); goto error; } /* and finally the metadata itself. */ if (fwrite(buffer, 1, size, f) != size) { Tcl_AppendResult(graphPtr->interp, "error writing metafile data:", Blt_LastError(), (char *)NULL); goto error; } result = TCL_OK; error: DeleteEnhMetaFile(hMetaFile); TkWinReleaseDrawableDC(Tk_WindowId(graphPtr->tkwin), hRefDC, &state); fclose(f); if (hMem != NULL) { GlobalUnlock(hMem); GlobalFree(hMem); } graphPtr->flags = MAP_WORLD; Blt_EventuallyRedrawGraph(graphPtr); return result; } #endif /*WIN32*/ /* *---------------------------------------------------------------------- * * OutputOp -- * * This procedure is invoked to print the graph in a file. * * Results: * Standard TCL result. TCL_OK if plot was successfully printed, * TCL_ERROR otherwise. * * Side effects: * A new PostScript file is created. * *---------------------------------------------------------------------- */ static int OutputOp(graphPtr, interp, argc, argv) Graph *graphPtr; /* Graph widget record */ Tcl_Interp *interp; int argc; /* Number of options in argv vector */ char **argv; /* Option vector */ { PostScript *psPtr = (PostScript *)graphPtr->postscript; FILE *f = NULL; PsToken psToken; char *fileName; /* Name of file to write PostScript output * If NULL, output is returned via * interp->result. */ fileName = NULL; if (argc > 3) { if (argv[3][0] != '-') { fileName = argv[3]; /* First argument is the file name. */ argv++, argc--; } if (Tk_ConfigureWidget(interp, graphPtr->tkwin, configSpecs, argc - 3, argv + 3, (char *)psPtr, TK_CONFIG_ARGV_ONLY) != TCL_OK) { return TCL_ERROR; } if (fileName != NULL) { #ifdef WIN32 f = fopen(fileName, "wb"); #else f = fopen(fileName, "w"); #endif if (f == NULL) { Tcl_AppendResult(interp, "can't create \"", fileName, "\": ", Tcl_PosixError(interp), (char *)NULL); return TCL_ERROR; } } } psToken = Blt_GetPsToken(graphPtr->interp, graphPtr->tkwin); psToken->fontVarName = psPtr->fontVarName; psToken->colorVarName = psPtr->colorVarName; psToken->colorMode = psPtr->colorMode; if (GraphToPostScript(graphPtr, fileName, psToken) != TCL_OK) { goto error; } /* * If a file name was given, write the results to that file */ if (f != NULL) { #ifdef WIN32 if ((psPtr->addPreview) && (psPtr->previewFormat != PS_PREVIEW_EPSI)) { if (CreateWindowsEPS(graphPtr, psToken, f)) { return TCL_ERROR; } } else { fputs(Blt_PostScriptFromToken(psToken), f); if (ferror(f)) { Tcl_AppendResult(interp, "error writing file \"", fileName, "\": ", Tcl_PosixError(interp), (char *)NULL); goto error; } } #else fputs(Blt_PostScriptFromToken(psToken), f); if (ferror(f)) { Tcl_AppendResult(interp, "error writing file \"", fileName, "\": ", Tcl_PosixError(interp), (char *)NULL); goto error; } #endif /* WIN32 */ fclose(f); } else { Tcl_SetResult(interp, Blt_PostScriptFromToken(psToken), TCL_VOLATILE); } Blt_ReleasePsToken(psToken); return TCL_OK; error: if (f != NULL) { fclose(f); } Blt_ReleasePsToken(psToken); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * Blt_CreatePostScript -- * * Creates a postscript structure. * * Results: * Always TCL_OK. * * Side effects: * A new PostScript structure is created. * *---------------------------------------------------------------------- */ int Blt_CreatePostScript(graphPtr) Graph *graphPtr; { PostScript *psPtr; psPtr = Blt_Calloc(1, sizeof(PostScript)); assert(psPtr); psPtr->colorMode = PS_MODE_COLOR; psPtr->center = TRUE; psPtr->decorations = TRUE; graphPtr->postscript = psPtr; if (Blt_ConfigureWidgetComponent(graphPtr->interp, graphPtr->tkwin, "postscript", "Postscript", configSpecs, 0, (char **)NULL, (char *)psPtr, 0) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } /* *-------------------------------------------------------------- * * Blt_PostScriptOp -- * * This procedure is invoked to process the Tcl command * that corresponds to a widget managed by this module. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ static Blt_OpSpec psOps[] = { {"cget", 2, (Blt_Op)CgetOp, 4, 4, "option",}, {"configure", 2, (Blt_Op)ConfigureOp, 3, 0, "?option value?...",}, {"output", 1, (Blt_Op)OutputOp, 3, 0, "?fileName? ?option value?...",}, }; static int nPsOps = sizeof(psOps) / sizeof(Blt_OpSpec); int Blt_PostScriptOp(graphPtr, interp, argc, argv) Graph *graphPtr; /* Graph widget record */ Tcl_Interp *interp; int argc; /* # arguments */ char **argv; /* Argument list */ { Blt_Op proc; int result; proc = Blt_GetOp(interp, nPsOps, psOps, BLT_OP_ARG2, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (graphPtr, interp, argc, argv); return result; } blt-2.4z.orig/src/bltGraph.c0100644000175000017500000022027307542177233014462 0ustar dokodoko /* * bltGraph.c -- * * This module implements a graph widget for the BLT toolkit. * * Copyright 1991-1998 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. * * The graph widget was created by Sani Nassif and George Howlett. */ /* * To do: * * 2) Update manual pages. * * 3) Update comments. * * 5) Surface, contour, and flow graphs * * 7) Arrows for line markers * */ #include "bltGraph.h" #include "bltBind.h" #include "bltGrElem.h" #include "bltSwitch.h" #include Blt_Uid bltXAxisUid; Blt_Uid bltYAxisUid; Blt_Uid bltBarElementUid; Blt_Uid bltLineElementUid; Blt_Uid bltStripElementUid; Blt_Uid bltContourElementUid; Blt_Uid bltLineMarkerUid; Blt_Uid bltBitmapMarkerUid; Blt_Uid bltImageMarkerUid; Blt_Uid bltTextMarkerUid; Blt_Uid bltPolygonMarkerUid; Blt_Uid bltWindowMarkerUid; extern Tk_CustomOption bltLinePenOption; extern Tk_CustomOption bltBarPenOption; extern Tk_CustomOption bltDistanceOption; extern Tk_CustomOption bltBarModeOption; extern Tk_CustomOption bltPadOption; extern Tk_CustomOption bltTileOption; extern Tk_CustomOption bltShadowOption; #define DEF_GRAPH_ASPECT_RATIO "0.0" #define DEF_GRAPH_BAR_BASELINE "0.0" #define DEF_GRAPH_BAR_MODE "normal" #define DEF_GRAPH_BAR_WIDTH "0.8" #define DEF_GRAPH_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_GRAPH_BG_MONO STD_NORMAL_BG_MONO #define DEF_GRAPH_BORDERWIDTH STD_BORDERWIDTH #define DEF_GRAPH_BUFFER_ELEMENTS "1" #define DEF_GRAPH_BUFFER_GRAPH "1" #define DEF_GRAPH_CURSOR "crosshair" #define DEF_GRAPH_FONT STD_FONT_LARGE #define DEF_GRAPH_HALO "2m" #define DEF_GRAPH_HALO_BAR "0.1i" #define DEF_GRAPH_HEIGHT "4i" #define DEF_GRAPH_HIGHLIGHT_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_GRAPH_HIGHLIGHT_BG_MONO STD_NORMAL_BG_MONO #define DEF_GRAPH_HIGHLIGHT_COLOR RGB_BLACK #define DEF_GRAPH_HIGHLIGHT_WIDTH "2" #define DEF_GRAPH_INVERT_XY "0" #define DEF_GRAPH_JUSTIFY "center" #define DEF_GRAPH_MARGIN "0" #define DEF_GRAPH_MARGIN_VAR (char *)NULL #define DEF_GRAPH_PLOT_BACKGROUND RGB_WHITE #define DEF_GRAPH_PLOT_BG_MONO RGB_WHITE #define DEF_GRAPH_PLOT_BW_COLOR STD_BORDERWIDTH #define DEF_GRAPH_PLOT_BW_MONO "0" #define DEF_GRAPH_PLOT_PADX "8" #define DEF_GRAPH_PLOT_PADY "8" #define DEF_GRAPH_PLOT_RELIEF "sunken" #define DEF_GRAPH_RELIEF "flat" #define DEF_GRAPH_SHADOW_COLOR (char *)NULL #define DEF_GRAPH_SHADOW_MONO (char *)NULL #define DEF_GRAPH_SHOW_VALUES "no" #define DEF_GRAPH_TAKE_FOCUS "" #define DEF_GRAPH_TITLE (char *)NULL #define DEF_GRAPH_TITLE_COLOR STD_NORMAL_FOREGROUND #define DEF_GRAPH_TITLE_MONO STD_NORMAL_FG_MONO #define DEF_GRAPH_WIDTH "5i" #define DEF_GRAPH_DATA (char *)NULL #define DEF_GRAPH_DATA_COMMAND (char *)NULL static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_DOUBLE, "-aspect", "aspect", "Aspect", DEF_GRAPH_ASPECT_RATIO, Tk_Offset(Graph, aspect), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_GRAPH_BACKGROUND, Tk_Offset(Graph, border), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_GRAPH_BG_MONO, Tk_Offset(Graph, border), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_CUSTOM, "-barmode", "barMode", "BarMode", DEF_GRAPH_BAR_MODE, Tk_Offset(Graph, mode), TK_CONFIG_DONT_SET_DEFAULT, &bltBarModeOption}, {TK_CONFIG_DOUBLE, "-barwidth", "barWidth", "BarWidth", DEF_GRAPH_BAR_WIDTH, Tk_Offset(Graph, barWidth), 0}, {TK_CONFIG_DOUBLE, "-baseline", "baseline", "Baseline", DEF_GRAPH_BAR_BASELINE, Tk_Offset(Graph, baseline), 0}, {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_SYNONYM, "-bm", "bottomMargin", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_CUSTOM, "-borderwidth", "borderWidth", "BorderWidth", DEF_GRAPH_BORDERWIDTH, Tk_Offset(Graph, borderWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-bottommargin", "bottomMargin", "Margin", DEF_GRAPH_MARGIN, Tk_Offset(Graph, bottomMargin.reqSize), 0, &bltDistanceOption}, {TK_CONFIG_STRING, "-bottomvariable", "bottomVariable", "BottomVariable", DEF_GRAPH_MARGIN_VAR, Tk_Offset(Graph, bottomMargin.varName), TK_CONFIG_NULL_OK}, {TK_CONFIG_BOOLEAN, "-bufferelements", "bufferElements", "BufferElements", DEF_GRAPH_BUFFER_ELEMENTS, Tk_Offset(Graph, backingStore), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_BOOLEAN, "-buffergraph", "bufferGraph", "BufferGraph", DEF_GRAPH_BUFFER_GRAPH, Tk_Offset(Graph, doubleBuffer), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", DEF_GRAPH_CURSOR, Tk_Offset(Graph, cursor), TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-data", "data", "Data", (char *)NULL, Tk_Offset(Graph, data), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_STRING, "-datacommand", "dataCommand", "DataCommand", (char *)NULL, Tk_Offset(Graph, dataCmd), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_FONT, "-font", "font", "Font", DEF_GRAPH_FONT, Tk_Offset(Graph, titleTextStyle.font), 0}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_GRAPH_TITLE_COLOR, Tk_Offset(Graph, titleTextStyle.color), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_GRAPH_TITLE_MONO, Tk_Offset(Graph, titleTextStyle.color), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_CUSTOM, "-halo", "halo", "Halo", DEF_GRAPH_HALO, Tk_Offset(Graph, halo), 0, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-height", "height", "Height", DEF_GRAPH_HEIGHT, Tk_Offset(Graph, reqHeight), 0, &bltDistanceOption}, {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", "HighlightBackground", DEF_GRAPH_HIGHLIGHT_BACKGROUND, Tk_Offset(Graph, highlightBgColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", "HighlightBackground", DEF_GRAPH_HIGHLIGHT_BG_MONO, Tk_Offset(Graph, highlightBgColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", DEF_GRAPH_HIGHLIGHT_COLOR, Tk_Offset(Graph, highlightColor), 0}, {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", "HighlightThickness", DEF_GRAPH_HIGHLIGHT_WIDTH, Tk_Offset(Graph, highlightWidth), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_BOOLEAN, "-invertxy", "invertXY", "InvertXY", DEF_GRAPH_INVERT_XY, Tk_Offset(Graph, inverted), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify", DEF_GRAPH_JUSTIFY, Tk_Offset(Graph, titleTextStyle.justify), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-leftmargin", "leftMargin", "Margin", DEF_GRAPH_MARGIN, Tk_Offset(Graph, leftMargin.reqSize), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_STRING, "-leftvariable", "leftVariable", "LeftVariable", DEF_GRAPH_MARGIN_VAR, Tk_Offset(Graph, leftMargin.varName), TK_CONFIG_NULL_OK}, {TK_CONFIG_SYNONYM, "-lm", "leftMargin", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_COLOR, "-plotbackground", "plotBackground", "Background", DEF_GRAPH_PLOT_BG_MONO, Tk_Offset(Graph, plotBg), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-plotbackground", "plotBackground", "Background", DEF_GRAPH_PLOT_BACKGROUND, Tk_Offset(Graph, plotBg), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_CUSTOM, "-plotborderwidth", "plotBorderWidth", "BorderWidth", DEF_GRAPH_PLOT_BW_COLOR, Tk_Offset(Graph, plotBorderWidth), TK_CONFIG_COLOR_ONLY, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-plotborderwidth", "plotBorderWidth", "BorderWidth", DEF_GRAPH_PLOT_BW_MONO, Tk_Offset(Graph, plotBorderWidth), TK_CONFIG_MONO_ONLY, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-plotpadx", "plotPadX", "PlotPad", DEF_GRAPH_PLOT_PADX, Tk_Offset(Graph, padX), TK_CONFIG_DONT_SET_DEFAULT, &bltPadOption}, {TK_CONFIG_CUSTOM, "-plotpady", "plotPadY", "PlotPad", DEF_GRAPH_PLOT_PADY, Tk_Offset(Graph, padY), TK_CONFIG_DONT_SET_DEFAULT, &bltPadOption}, {TK_CONFIG_RELIEF, "-plotrelief", "plotRelief", "Relief", DEF_GRAPH_PLOT_RELIEF, Tk_Offset(Graph, plotRelief), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_GRAPH_RELIEF, Tk_Offset(Graph, relief), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-rightmargin", "rightMargin", "Margin", DEF_GRAPH_MARGIN, Tk_Offset(Graph, rightMargin.reqSize), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_STRING, "-rightvariable", "rightVariable", "RightVariable", DEF_GRAPH_MARGIN_VAR, Tk_Offset(Graph, rightMargin.varName), TK_CONFIG_NULL_OK}, {TK_CONFIG_SYNONYM, "-rm", "rightMargin", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_CUSTOM, "-shadow", "shadow", "Shadow", DEF_GRAPH_SHADOW_COLOR, Tk_Offset(Graph, titleTextStyle.shadow), TK_CONFIG_COLOR_ONLY, &bltShadowOption}, {TK_CONFIG_CUSTOM, "-shadow", "shadow", "Shadow", DEF_GRAPH_SHADOW_MONO, Tk_Offset(Graph, titleTextStyle.shadow), TK_CONFIG_MONO_ONLY, &bltShadowOption}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_GRAPH_TITLE_MONO, Tk_Offset(Graph, titleTextStyle.color), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", DEF_GRAPH_TAKE_FOCUS, Tk_Offset(Graph, takeFocus), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-tile", "tile", "Tile", (char *)NULL, Tk_Offset(Graph, tile), TK_CONFIG_NULL_OK, &bltTileOption}, {TK_CONFIG_STRING, "-title", "title", "Title", DEF_GRAPH_TITLE, Tk_Offset(Graph, title), TK_CONFIG_NULL_OK}, {TK_CONFIG_SYNONYM, "-tm", "topMargin", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_CUSTOM, "-topmargin", "topMargin", "Margin", DEF_GRAPH_MARGIN, Tk_Offset(Graph, topMargin.reqSize), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_STRING, "-topvariable", "topVariable", "TopVariable", DEF_GRAPH_MARGIN_VAR, Tk_Offset(Graph, topMargin.varName), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-width", "width", "Width", DEF_GRAPH_WIDTH, Tk_Offset(Graph, reqWidth), 0, &bltDistanceOption}, {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} }; static Blt_SwitchParseProc StringToFormat; static Blt_SwitchCustom formatSwitch = { StringToFormat, (Blt_SwitchFreeProc *)NULL, (ClientData)0, }; typedef struct { char *name; int width, height; int format; } SnapData; enum SnapFormats { FORMAT_PHOTO, FORMAT_EMF, FORMAT_WMF }; static Blt_SwitchSpec snapSwitches[] = { {BLT_SWITCH_INT_POSITIVE, "-width", Blt_Offset(SnapData, width), 0}, {BLT_SWITCH_INT_POSITIVE, "-height", Blt_Offset(SnapData, height), 0}, {BLT_SWITCH_CUSTOM, "-format", Blt_Offset(SnapData, format), 0, &formatSwitch}, {BLT_SWITCH_END, NULL, 0, 0} }; static Tcl_IdleProc DisplayGraph; static Tcl_FreeProc DestroyGraph; static Tk_EventProc GraphEventProc; Tcl_CmdProc Blt_GraphInstCmdProc; static Blt_BindPickProc PickEntry; static Tcl_CmdProc StripchartCmd; static Tcl_CmdProc BarchartCmd; static Tcl_CmdProc GraphCmd; static Tcl_CmdDeleteProc GraphInstCmdDeleteProc; static Blt_TileChangedProc TileChangedProc; /* *-------------------------------------------------------------- * * Blt_EventuallyRedrawGraph -- * * Tells the Tk dispatcher to call the graph display routine at * the next idle point. This request is made only if the window * is displayed and no other redraw request is pending. * * Results: None. * * Side effects: * The window is eventually redisplayed. * *-------------------------------------------------------------- */ void Blt_EventuallyRedrawGraph(graphPtr) Graph *graphPtr; /* Graph widget record */ { if ((graphPtr->tkwin != NULL) && !(graphPtr->flags & REDRAW_PENDING)) { Tcl_DoWhenIdle(DisplayGraph, graphPtr); graphPtr->flags |= REDRAW_PENDING; } } /* *-------------------------------------------------------------- * * GraphEventProc -- * * This procedure is invoked by the Tk dispatcher for various * events on graphs. * * Results: * None. * * Side effects: * When the window gets deleted, internal structures get * cleaned up. When it gets exposed, the graph is eventually * redisplayed. * *-------------------------------------------------------------- */ static void GraphEventProc(clientData, eventPtr) ClientData clientData; /* Graph widget record */ register XEvent *eventPtr; /* Event which triggered call to routine */ { Graph *graphPtr = clientData; if (eventPtr->type == Expose) { if (eventPtr->xexpose.count == 0) { graphPtr->flags |= REDRAW_WORLD; Blt_EventuallyRedrawGraph(graphPtr); } } else if ((eventPtr->type == FocusIn) || (eventPtr->type == FocusOut)) { if (eventPtr->xfocus.detail != NotifyInferior) { if (eventPtr->type == FocusIn) { graphPtr->flags |= GRAPH_FOCUS; } else { graphPtr->flags &= ~GRAPH_FOCUS; } graphPtr->flags |= REDRAW_WORLD; Blt_EventuallyRedrawGraph(graphPtr); } } else if (eventPtr->type == DestroyNotify) { if (graphPtr->tkwin != NULL) { Blt_DeleteWindowInstanceData(graphPtr->tkwin); graphPtr->tkwin = NULL; 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 |= (MAP_WORLD | REDRAW_WORLD); Blt_EventuallyRedrawGraph(graphPtr); } } /* *---------------------------------------------------------------------- * * GraphInstCmdDeleteProc -- * * This procedure is invoked when a widget command is deleted. If * the widget isn't already in the process of being destroyed, * this command destroys it. * * Results: * None. * * Side effects: * The widget is destroyed. * *---------------------------------------------------------------------- */ static void GraphInstCmdDeleteProc(clientData) ClientData clientData; /* Pointer to widget record. */ { Graph *graphPtr = clientData; if (graphPtr->tkwin != NULL) { /* NULL indicates window has * already been destroyed. */ Tk_Window tkwin; tkwin = graphPtr->tkwin; graphPtr->tkwin = NULL; #ifdef ITCL_NAMESPACES Itk_SetWidgetCommand(tkwin, (Tcl_Command) NULL); #endif /* ITCL_NAMESPACES */ Blt_DeleteWindowInstanceData(tkwin); Tk_DestroyWindow(tkwin); } } /* *---------------------------------------------------------------------- * * TileChangedProc * * Rebuilds the designated GC with the new tile pixmap. * * Results: * None. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static void TileChangedProc(clientData, tile) ClientData clientData; Blt_Tile tile; /* Not used. */ { Graph *graphPtr = clientData; if (graphPtr->tkwin != NULL) { graphPtr->flags |= REDRAW_WORLD; Blt_EventuallyRedrawGraph(graphPtr); } } /* *-------------------------------------------------------------- * * AdjustAxisPointers -- * * Sets the axis pointers according to whether the axis is * inverted on not. The axis sites are also reset. * * Results: * None. * *-------------------------------------------------------------- */ static void AdjustAxisPointers(graphPtr) Graph *graphPtr; /* Graph widget record */ { if (graphPtr->inverted) { graphPtr->leftMargin.axes = graphPtr->axisChain[0]; graphPtr->bottomMargin.axes = graphPtr->axisChain[1]; graphPtr->rightMargin.axes = graphPtr->axisChain[2]; graphPtr->topMargin.axes = graphPtr->axisChain[3]; } else { graphPtr->leftMargin.axes = graphPtr->axisChain[1]; graphPtr->bottomMargin.axes = graphPtr->axisChain[0]; graphPtr->rightMargin.axes = graphPtr->axisChain[3]; graphPtr->topMargin.axes = graphPtr->axisChain[2]; } } static int InitPens(graphPtr) Graph *graphPtr; { Blt_InitHashTable(&graphPtr->penTable, BLT_STRING_KEYS); if (Blt_CreatePen(graphPtr, "activeLine", bltLineElementUid, 0, (char **)NULL) == NULL) { return TCL_ERROR; } if (Blt_CreatePen(graphPtr, "activeBar", bltBarElementUid, 0, (char **)NULL) == NULL) { return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * Blt_GraphTags -- * * Sets the binding tags for a graph object. This routine is * called by Tk when an event occurs in the graph. It fills * an array of pointers with bind tag addresses. * * The object addresses are strings hashed in one of two tag * tables: one for elements and the another for markers. Note * that there's only one binding table for elements and markers. * [We don't want to trigger both a marker and element bind * command for the same event.] But we don't want a marker and * element with the same tag name to activate the others * bindings. A tag "all" for markers should mean all markers, not * all markers and elements. As a result, element and marker * tags are stored in separate hash tables, which means we can't * generate the same tag address for both an elements and marker, * even if they have the same name. * * Results: * None. * * Side effects: * This information will be used by the binding code in bltUtil.c * to determine what graph objects match the current event. The * tags are placed in tagArr and *nTagsPtr is set with the * number of tags found. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ void Blt_GraphTags(table, object, context, list) Blt_BindTable table; ClientData object; ClientData context; /* Not used. */ Blt_List list; { Element *elemPtr; MakeTagProc *tagProc; Graph *graphPtr; graphPtr = (Graph *)Blt_GetBindingData(table); /* * Trick: Markers, elements, and axes have the same first few * fields in their structures, such as "type", "name", or * "tags". This is so we can look at graph objects * interchangably. It doesn't matter what we cast the * object to. */ elemPtr = (Element *)object; if ((elemPtr->classUid == bltLineElementUid) || (elemPtr->classUid == bltStripElementUid) || (elemPtr->classUid == bltBarElementUid)) { tagProc = Blt_MakeElementTag; } else if ((elemPtr->classUid == bltXAxisUid) || (elemPtr->classUid == bltYAxisUid)) { tagProc = Blt_MakeAxisTag; } else { tagProc = Blt_MakeMarkerTag; } /* * Always add the name of the object to the tag array. */ Blt_ListAppend(list, (*tagProc) (graphPtr, elemPtr->name), 0); Blt_ListAppend(list, (*tagProc) (graphPtr, elemPtr->classUid), 0); if (elemPtr->tags != NULL) { register char **p; for (p = elemPtr->tags; *p != NULL; p++) { Blt_ListAppend(list, (*tagProc) (graphPtr, *p), 0); } } } /* * 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 one that's on top (visible) is picked. */ /*ARGSUSED*/ static ClientData PickEntry(clientData, x, y, contextPtr) ClientData clientData; int x, y; ClientData *contextPtr; /* Not used. */ { Graph *graphPtr = clientData; Blt_ChainLink *linkPtr; Element *elemPtr; Marker *markerPtr; Extents2D exts; if (graphPtr->flags & MAP_ALL) { return NULL; /* Can't pick anything until the next * redraw occurs. */ } Blt_GraphExtents(graphPtr, &exts); if ((x > exts.right) || (x < exts.left) || (y > exts.bottom) || (y < exts.top)) { /* * Sample coordinate is in one of the graph margins. Can only * pick an axis. */ return Blt_NearestAxis(graphPtr, x, y); } /* * 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). */ markerPtr = (Marker *)Blt_NearestMarker(graphPtr, x, y, FALSE); if (markerPtr != NULL) { return markerPtr; /* Found a marker (-under false). */ } { ClosestSearch search; search.along = SEARCH_BOTH; search.halo = graphPtr->halo + 1; search.index = -1; search.x = x; search.y = y; search.dist = (double)(search.halo + 1); search.mode = SEARCH_AUTO; for (linkPtr = Blt_ChainLastLink(graphPtr->elements.displayList); linkPtr != NULL; linkPtr = Blt_ChainPrevLink(linkPtr)) { elemPtr = Blt_ChainGetValue(linkPtr); if ((elemPtr->flags & MAP_ITEM) || (Blt_VectorNotifyPending(elemPtr->x.clientId)) || (Blt_VectorNotifyPending(elemPtr->y.clientId))) { continue; } if ((!elemPtr->hidden) && (elemPtr->state == STATE_NORMAL)) { (*elemPtr->procsPtr->closestProc) (graphPtr, elemPtr, &search); } } if (search.dist <= (double)search.halo) { return search.elemPtr; /* Found an element within the * minimum halo distance. */ } } markerPtr = (Marker *)Blt_NearestMarker(graphPtr, x, y, TRUE); if (markerPtr != NULL) { return markerPtr; /* Found a marker (-under true) */ } return NULL; /* Nothing found. */ } /* *---------------------------------------------------------------------- * * ConfigureGraph -- * * Allocates resources for the graph. * * Results: * None. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for graphPtr; old resources get freed, if there * were any. The graph is redisplayed. * *---------------------------------------------------------------------- */ static void ConfigureGraph(graphPtr) Graph *graphPtr; /* Graph widget record */ { XColor *colorPtr; GC newGC; XGCValues gcValues; unsigned long gcMask; /* Don't allow negative bar widths. Reset to an arbitrary value (0.1) */ if (graphPtr->barWidth <= 0.0) { graphPtr->barWidth = 0.1; } graphPtr->inset = graphPtr->borderWidth + graphPtr->highlightWidth + 1; if ((graphPtr->reqHeight != Tk_ReqHeight(graphPtr->tkwin)) || (graphPtr->reqWidth != Tk_ReqWidth(graphPtr->tkwin))) { Tk_GeometryRequest(graphPtr->tkwin, graphPtr->reqWidth, graphPtr->reqHeight); } Tk_SetInternalBorder(graphPtr->tkwin, graphPtr->borderWidth); colorPtr = Tk_3DBorderColor(graphPtr->border); if (graphPtr->title != NULL) { int w, h; Blt_GetTextExtents(&graphPtr->titleTextStyle, graphPtr->title, &w, &h); graphPtr->titleTextStyle.height = h + 10; } else { graphPtr->titleTextStyle.width = graphPtr->titleTextStyle.height = 0; } /* * Create GCs for interior and exterior regions, and a background * GC for clearing the margins with XFillRectangle */ /* Margin GC */ gcValues.foreground = graphPtr->titleTextStyle.color->pixel; gcValues.background = colorPtr->pixel; gcMask = (GCForeground | GCBackground); newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues); if (graphPtr->drawGC != NULL) { Tk_FreeGC(graphPtr->display, graphPtr->drawGC); } graphPtr->drawGC = newGC; /* Plot fill GC (Background = Foreground) */ gcValues.foreground = graphPtr->plotBg->pixel; newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues); if (graphPtr->plotFillGC != NULL) { Tk_FreeGC(graphPtr->display, graphPtr->plotFillGC); } graphPtr->plotFillGC = newGC; /* Margin fill GC (Background = Foreground) */ gcValues.foreground = colorPtr->pixel; gcValues.background = graphPtr->titleTextStyle.color->pixel; newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues); if (graphPtr->fillGC != NULL) { Tk_FreeGC(graphPtr->display, graphPtr->fillGC); } graphPtr->fillGC = newGC; if (graphPtr->tile != NULL) { Blt_SetTileChangedProc(graphPtr->tile, TileChangedProc, graphPtr); } Blt_ResetTextStyle(graphPtr->tkwin, &graphPtr->titleTextStyle); if (Blt_ConfigModified(configSpecs, "-invertxy", (char *)NULL)) { /* * If the -inverted option changed, we need to readjust the pointers * to the axes and recompute the their scales. */ AdjustAxisPointers(graphPtr); graphPtr->flags |= RESET_AXES; } if ((!graphPtr->backingStore) && (graphPtr->backPixmap != None)) { /* * Free the pixmap if we're not buffering the display of elements * anymore. */ Tk_FreePixmap(graphPtr->display, graphPtr->backPixmap); graphPtr->backPixmap = None; } /* * Reconfigure the crosshairs, just in case the background color of * the plotarea has been changed. */ Blt_ConfigureCrosshairs(graphPtr); /* * Update the layout of the graph (and redraw the elements) if * any of the following graph options which affect the size of * the plotting area has changed. * * -aspect * -borderwidth, -plotborderwidth * -font, -title * -width, -height * -invertxy * -bottommargin, -leftmargin, -rightmargin, -topmargin, * -barmode, -barwidth */ if (Blt_ConfigModified(configSpecs, "-invertxy", "-title", "-font", "-*margin", "-*width", "-height", "-barmode", "-*pad*", "-aspect", (char *)NULL)) { graphPtr->flags |= RESET_WORLD; } if (Blt_ConfigModified(configSpecs, "-plotbackground", (char *)NULL)) { graphPtr->flags |= REDRAW_BACKING_STORE; } graphPtr->flags |= REDRAW_WORLD; Blt_EventuallyRedrawGraph(graphPtr); } /* *---------------------------------------------------------------------- * * DestroyGraph -- * * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release * to clean up the internal structure of a graph at a safe time * (when no-one is using it anymore). * * Results: * None. * * Side effects: * Everything associated with the widget is freed up. * *---------------------------------------------------------------------- */ static void DestroyGraph(dataPtr) DestroyData dataPtr; { Graph *graphPtr = (Graph *)dataPtr; Tk_FreeOptions(configSpecs, (char *)graphPtr, graphPtr->display, 0); /* * Destroy the individual components of the graph: elements, markers, * X and Y axes, legend, display lists etc. */ Blt_DestroyMarkers(graphPtr); Blt_DestroyElements(graphPtr); Blt_DestroyAxes(graphPtr); Blt_DestroyPens(graphPtr); if (graphPtr->legend != NULL) { Blt_DestroyLegend(graphPtr); } if (graphPtr->postscript != NULL) { Blt_DestroyPostScript(graphPtr); } if (graphPtr->crosshairs != NULL) { Blt_DestroyCrosshairs(graphPtr); } if (graphPtr->gridPtr != NULL) { Blt_DestroyGrid(graphPtr); } if (graphPtr->bindTable != NULL) { Blt_DestroyBindingTable(graphPtr->bindTable); } /* Release allocated X resources and memory. */ if (graphPtr->drawGC != NULL) { Tk_FreeGC(graphPtr->display, graphPtr->drawGC); } if (graphPtr->fillGC != NULL) { Tk_FreeGC(graphPtr->display, graphPtr->fillGC); } if (graphPtr->plotFillGC != NULL) { Tk_FreeGC(graphPtr->display, graphPtr->plotFillGC); } Blt_FreeTextStyle(graphPtr->display, &graphPtr->titleTextStyle); if (graphPtr->backPixmap != None) { Tk_FreePixmap(graphPtr->display, graphPtr->backPixmap); } if (graphPtr->freqArr != NULL) { Blt_Free(graphPtr->freqArr); } if (graphPtr->nStacks > 0) { Blt_DeleteHashTable(&graphPtr->freqTable); } if (graphPtr->tile != NULL) { Blt_FreeTile(graphPtr->tile); } Blt_Free(graphPtr); } /* *---------------------------------------------------------------------- * * CreateGraph -- * * This procedure creates and initializes a new widget. * * Results: * The return value is a pointer to a structure describing * the new widget. If an error occurred, then the return * value is NULL and an error message is left in interp->result. * * Side effects: * Memory is allocated, a Tk_Window is created, etc. * *---------------------------------------------------------------------- */ static Graph * CreateGraph(interp, argc, argv, classUid) Tcl_Interp *interp; int argc; char **argv; Blt_Uid classUid; { Graph *graphPtr; Tk_Window tkwin; tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp), argv[1], (char *)NULL); if (tkwin == NULL) { return NULL; } graphPtr = Blt_Calloc(1, sizeof(Graph)); assert(graphPtr); /* Initialize the graph data structure. */ graphPtr->tkwin = tkwin; graphPtr->display = Tk_Display(tkwin); graphPtr->interp = interp; graphPtr->classUid = classUid; graphPtr->backingStore = TRUE; graphPtr->doubleBuffer = TRUE; graphPtr->highlightWidth = 2; graphPtr->plotRelief = TK_RELIEF_SUNKEN; graphPtr->relief = TK_RELIEF_FLAT; graphPtr->flags = (RESET_WORLD); graphPtr->nextMarkerId = 1; graphPtr->padLeft = graphPtr->padRight = 8; graphPtr->padTop = graphPtr->padBottom = 8; graphPtr->bottomMargin.site = MARGIN_BOTTOM; graphPtr->leftMargin.site = MARGIN_LEFT; graphPtr->topMargin.site = MARGIN_TOP; graphPtr->rightMargin.site = MARGIN_RIGHT; Blt_InitTextStyle(&graphPtr->titleTextStyle); Blt_InitHashTable(&graphPtr->axes.table, BLT_STRING_KEYS); Blt_InitHashTable(&graphPtr->axes.tagTable, BLT_STRING_KEYS); Blt_InitHashTable(&graphPtr->elements.table, BLT_STRING_KEYS); Blt_InitHashTable(&graphPtr->elements.tagTable, BLT_STRING_KEYS); Blt_InitHashTable(&graphPtr->markers.table, BLT_STRING_KEYS); Blt_InitHashTable(&graphPtr->markers.tagTable, BLT_STRING_KEYS); graphPtr->elements.displayList = Blt_ChainCreate(); graphPtr->markers.displayList = Blt_ChainCreate(); graphPtr->axes.displayList = Blt_ChainCreate(); if (classUid == bltLineElementUid) { Tk_SetClass(tkwin, "Graph"); } else if (classUid == bltBarElementUid) { Tk_SetClass(tkwin, "Barchart"); } else if (classUid == bltStripElementUid) { Tk_SetClass(tkwin, "Stripchart"); } Blt_SetWindowInstanceData(tkwin, graphPtr); if (InitPens(graphPtr) != TCL_OK) { goto error; } if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc - 2, argv + 2, (char *)graphPtr, 0) != TCL_OK) { goto error; } if (Blt_DefaultAxes(graphPtr) != TCL_OK) { goto error; } AdjustAxisPointers(graphPtr); if (Blt_CreatePostScript(graphPtr) != TCL_OK) { goto error; } if (Blt_CreateCrosshairs(graphPtr) != TCL_OK) { goto error; } if (Blt_CreateLegend(graphPtr) != TCL_OK) { goto error; } if (Blt_CreateGrid(graphPtr) != TCL_OK) { goto error; } Tk_CreateEventHandler(graphPtr->tkwin, ExposureMask | StructureNotifyMask | FocusChangeMask, GraphEventProc, graphPtr); graphPtr->cmdToken = Tcl_CreateCommand(interp, argv[1], Blt_GraphInstCmdProc, graphPtr, GraphInstCmdDeleteProc); #ifdef ITCL_NAMESPACES Itk_SetWidgetCommand(graphPtr->tkwin, graphPtr->cmdToken); #endif ConfigureGraph(graphPtr); graphPtr->bindTable = Blt_CreateBindingTable(interp, tkwin, graphPtr, PickEntry, Blt_GraphTags); return graphPtr; error: DestroyGraph((DestroyData)graphPtr); return NULL; } /* Widget sub-commands */ /*ARGSUSED*/ static int XAxisOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { int margin; margin = (graphPtr->inverted) ? MARGIN_LEFT : MARGIN_BOTTOM; return Blt_AxisOp(graphPtr, margin, argc, argv); } /*ARGSUSED*/ static int X2AxisOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { int margin; margin = (graphPtr->inverted) ? MARGIN_RIGHT : MARGIN_TOP; return Blt_AxisOp(graphPtr, margin, argc, argv); } /*ARGSUSED*/ static int YAxisOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { int margin; margin = (graphPtr->inverted) ? MARGIN_BOTTOM : MARGIN_LEFT; return Blt_AxisOp(graphPtr, margin, argc, argv); } /*ARGSUSED*/ static int Y2AxisOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { int margin; margin = (graphPtr->inverted) ? MARGIN_TOP : MARGIN_RIGHT; return Blt_AxisOp(graphPtr, margin, argc, argv); } /*ARGSUSED*/ static int BarOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { return Blt_ElementOp(graphPtr, interp, argc, argv, bltBarElementUid); } /*ARGSUSED*/ static int LineOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { return Blt_ElementOp(graphPtr, interp, argc, argv, bltLineElementUid); } /*ARGSUSED*/ static int ElementOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { return Blt_ElementOp(graphPtr, interp, argc, argv, graphPtr->classUid); } static int ConfigureOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; char **argv; { int flags; flags = TK_CONFIG_ARGV_ONLY; if (argc == 2) { return Tk_ConfigureInfo(interp, graphPtr->tkwin, configSpecs, (char *)graphPtr, (char *)NULL, flags); } else if (argc == 3) { return Tk_ConfigureInfo(interp, graphPtr->tkwin, configSpecs, (char *)graphPtr, argv[2], flags); } else { if (Tk_ConfigureWidget(interp, graphPtr->tkwin, configSpecs, argc - 2, argv + 2, (char *)graphPtr, flags) != TCL_OK) { return TCL_ERROR; } ConfigureGraph(graphPtr); return TCL_OK; } } /* ARGSUSED*/ static int CgetOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { return Tk_ConfigureValue(interp, graphPtr->tkwin, configSpecs, (char *)graphPtr, argv[2], 0); } /* *-------------------------------------------------------------- * * 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. * *-------------------------------------------------------------- */ /* ARGSUSED*/ static int ExtentsOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { char c; unsigned int length; char string[200]; c = argv[2][0]; length = strlen(argv[2]); if ((c == 'p') && (length > 4) && (strncmp("plotheight", argv[2], length) == 0)) { Tcl_SetResult(interp, Blt_Itoa(graphPtr->bottom - graphPtr->top + 1), TCL_VOLATILE); } else if ((c == 'p') && (length > 4) && (strncmp("plotwidth", argv[2], length) == 0)) { Tcl_SetResult(interp, Blt_Itoa(graphPtr->right - graphPtr->left + 1), TCL_VOLATILE); } else if ((c == 'p') && (length > 4) && (strncmp("plotarea", argv[2], length) == 0)) { sprintf(string, "%d %d %d %d", graphPtr->left, graphPtr->top, graphPtr->right - graphPtr->left + 1, graphPtr->bottom - graphPtr->top + 1); Tcl_SetResult(interp, string, TCL_VOLATILE); } else if ((c == 'l') && (length > 2) && (strncmp("legend", argv[2], length) == 0)) { sprintf(string, "%d %d %d %d", Blt_LegendX(graphPtr->legend), Blt_LegendY(graphPtr->legend), Blt_LegendWidth(graphPtr->legend), Blt_LegendHeight(graphPtr->legend)); Tcl_SetResult(interp, string, TCL_VOLATILE); } else if ((c == 'l') && (length > 2) && (strncmp("leftmargin", argv[2], length) == 0)) { Tcl_SetResult(interp, Blt_Itoa(graphPtr->leftMargin.width), TCL_VOLATILE); } else if ((c == 'r') && (length > 1) && (strncmp("rightmargin", argv[2], length) == 0)) { Tcl_SetResult(interp, Blt_Itoa(graphPtr->rightMargin.width), TCL_VOLATILE); } else if ((c == 't') && (length > 1) && (strncmp("topmargin", argv[2], length) == 0)) { Tcl_SetResult(interp, Blt_Itoa(graphPtr->topMargin.height), TCL_VOLATILE); } else if ((c == 'b') && (length > 1) && (strncmp("bottommargin", argv[2], length) == 0)) { Tcl_SetResult(interp, Blt_Itoa(graphPtr->bottomMargin.height), TCL_VOLATILE); } else { Tcl_AppendResult(interp, "bad extent item \"", argv[2], "\": should be plotheight, plotwidth, leftmargin, rightmargin, \ topmargin, bottommargin, plotarea, or legend", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* *-------------------------------------------------------------- * * InsideOp -- * * Returns true of false whether the given point is inside * the plotting area (defined by left,bottom right, top). * * Results: * Always returns TCL_OK. interp->result will contain * the boolean string representation. * *-------------------------------------------------------------- */ /* ARGSUSED*/ static int InsideOp(graphPtr, interp, argc, argv) Graph *graphPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { int x, y; Extents2D exts; int result; if (Tk_GetPixels(interp, graphPtr->tkwin, argv[2], &x) != TCL_OK) { return TCL_ERROR; } if (Tk_GetPixels(interp, graphPtr->tkwin, argv[3], &y) != TCL_OK) { return TCL_ERROR; } Blt_GraphExtents(graphPtr, &exts); result = PointInRegion(&exts, x, y); Blt_SetBooleanResult(interp, result); return TCL_OK; } /* * ------------------------------------------------------------------------- * * InvtransformOp -- * * This procedure returns a list of the graph coordinate * values corresponding with the given window X and Y * coordinate positions. * * Results: * Returns a standard Tcl result. If an error occurred while * parsing the window positions, TCL_ERROR is returned, and * interp->result will contain the error message. Otherwise * interp->result will contain a Tcl list of the x and y * coordinates. * * ------------------------------------------------------------------------ */ /*ARGSUSED*/ static int InvtransformOp(graphPtr, interp, argc, argv) Graph *graphPtr; /* Graph widget record */ Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { double x, y; Point2D point; Axis2D axes; if (Tcl_ExprDouble(interp, argv[2], &x) != TCL_OK || Tcl_ExprDouble(interp, argv[3], &y) != TCL_OK) { return TCL_ERROR; } if (graphPtr->flags & RESET_AXES) { Blt_ResetAxes(graphPtr); } /* 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). */ /* Pick the first pair of axes */ axes.x = Blt_GetFirstAxis(graphPtr->axisChain[0]); axes.y = Blt_GetFirstAxis(graphPtr->axisChain[1]); point = Blt_InvMap2D(graphPtr, x, y, &axes); Tcl_AppendElement(interp, Blt_Dtoa(interp, point.x)); Tcl_AppendElement(interp, Blt_Dtoa(interp, point.y)); return TCL_OK; } /* * -------------------------------------------------------------------------- * * TransformOp -- * * This procedure returns a list of the window coordinates * corresponding with the given graph x and y coordinates. * * Results: * Returns a standard Tcl result. interp->result contains * the list of the graph coordinates. If an error occurred * while parsing the window positions, TCL_ERROR is returned, * then interp->result will contain an error message. * * ------------------------------------------------------------------------- */ /*ARGSUSED*/ static int TransformOp(graphPtr, interp, argc, argv) Graph *graphPtr; /* Graph widget record */ Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { double x, y; Point2D point; Axis2D axes; if ((Tcl_ExprDouble(interp, argv[2], &x) != TCL_OK) || (Tcl_ExprDouble(interp, argv[3], &y) != TCL_OK)) { return TCL_ERROR; } if (graphPtr->flags & RESET_AXES) { Blt_ResetAxes(graphPtr); } /* * 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). */ axes.x = Blt_GetFirstAxis(graphPtr->axisChain[0]); axes.y = Blt_GetFirstAxis(graphPtr->axisChain[1]); point = Blt_Map2D(graphPtr, x, y, &axes); Tcl_AppendElement(interp, Blt_Itoa(ROUND(point.x))); Tcl_AppendElement(interp, Blt_Itoa(ROUND(point.y))); return TCL_OK; } #ifndef NO_PRINTER /* * -------------------------------------------------------------------------- * * Print1Op -- * * Prints the equivalent of a screen snapshot of the graph * to the designated printer. * * Results: * Returns a standard Tcl result. If an error occurred * TCL_ERROR is returned and interp->result will contain an * error message. * * ------------------------------------------------------------------------- */ /*ARGSUSED*/ static int Print1Op(graphPtr, interp, argc, argv) Graph *graphPtr; /* Graph widget record */ Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { int noBackingStore = 0; BITMAPINFO info; void *data; TkWinDCState state; TkWinBitmap bd; DIBSECTION ds; Drawable drawable; HBITMAP hBitmap; HDC hDC; DOCINFO di; double pageWidth, pageHeight; int result; double scale, sx, sy; int jobId; graphPtr->width = Tk_Width(graphPtr->tkwin); graphPtr->height = Tk_Height(graphPtr->tkwin); if ((graphPtr->width < 2) && (graphPtr->reqWidth > 0)) { graphPtr->width = graphPtr->reqWidth; } if ((graphPtr->height < 2) && (graphPtr->reqHeight > 0)) { graphPtr->height = graphPtr->reqHeight; } if (argc == 2) { result = Blt_PrintDialog(interp, &drawable); if (result == TCL_ERROR) { return TCL_ERROR; } if (result == TCL_RETURN) { return TCL_OK; } } else { if (Blt_GetOpenPrinter(interp, argv[2], &drawable) != TCL_OK) { return TCL_ERROR; } } /* * This is a taken from Blt_SnapPhoto. The difference is that * here we're using the DIBSection directly, without converting * the section into a ColorImage. */ ZeroMemory(&info, sizeof(info)); info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); info.bmiHeader.biWidth = graphPtr->width; info.bmiHeader.biHeight = graphPtr->height; info.bmiHeader.biPlanes = 1; info.bmiHeader.biBitCount = 32; info.bmiHeader.biCompression = BI_RGB; hDC = TkWinGetDrawableDC(graphPtr->display, Tk_WindowId(graphPtr->tkwin), &state); hBitmap = CreateDIBSection(hDC, &info, DIB_RGB_COLORS, &data, NULL, 0); TkWinReleaseDrawableDC(Tk_WindowId(graphPtr->tkwin), hDC, &state); /* * Create our own drawable by hand using the DIB we just created. * We'll then draw into it using the standard drawing functions. */ bd.type = TWD_BITMAP; bd.handle = hBitmap; bd.colormap = DefaultColormap(graphPtr->display, DefaultScreen(graphPtr->display)); bd.depth = Tk_Depth(graphPtr->tkwin); graphPtr->flags |= RESET_WORLD; Blt_DrawGraph(graphPtr, (Drawable)&bd, noBackingStore); /* * Now that the DIB contains the image of the graph, get the the * data bits and write them to the printer device, stretching the * image to the fit the printer's resolution. */ result = TCL_ERROR; if (GetObject(hBitmap, sizeof(DIBSECTION), &ds) == 0) { Tcl_AppendResult(interp, "can't get object: ", Blt_LastError(), (char *)NULL); goto done; } hDC = ((TkWinDC *) drawable)->hdc; /* Get the resolution of the printer device. */ sx = (double)GetDeviceCaps(hDC, HORZRES) / (double)graphPtr->width; sy = (double)GetDeviceCaps(hDC, VERTRES) / (double)graphPtr->height; scale = MIN(sx, sy); pageWidth = scale * graphPtr->width; pageHeight = scale * graphPtr->height; ZeroMemory(&di, sizeof(di)); di.cbSize = sizeof(di); di.lpszDocName = "Graph Contents"; jobId = StartDoc(hDC, &di); if (jobId <= 0) { Tcl_AppendResult(interp, "can't start document: ", Blt_LastError(), (char *)NULL); goto done; } if (StartPage(hDC) <= 0) { Tcl_AppendResult(interp, "error starting page: ", Blt_LastError(), (char *)NULL); goto done; } StretchDIBits(hDC, 0, 0, ROUND(pageWidth), ROUND(pageHeight), 0, 0, graphPtr->width, graphPtr->height, ds.dsBm.bmBits, (LPBITMAPINFO)&ds.dsBmih, DIB_RGB_COLORS, SRCCOPY); EndPage(hDC); EndDoc(hDC); result = TCL_OK; done: DeleteBitmap(hBitmap); return result; } /* * -------------------------------------------------------------------------- * * Print2Op -- * * Prints directly to the designated printer device. * * Results: * Returns a standard Tcl result. If an error occurred, * TCL_ERROR is returned and interp->result will contain an * error message. * * ------------------------------------------------------------------------- */ /*ARGSUSED*/ static int Print2Op(graphPtr, interp, argc, argv) Graph *graphPtr; /* Graph widget record */ Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Drawable drawable; int noBackingStore = 0; int result; graphPtr->width = Tk_Width(graphPtr->tkwin); graphPtr->height = Tk_Height(graphPtr->tkwin); if ((graphPtr->width < 2) && (graphPtr->reqWidth > 0)) { graphPtr->width = graphPtr->reqWidth; } if ((graphPtr->height < 2) && (graphPtr->reqHeight > 0)) { graphPtr->height = graphPtr->reqHeight; } if (argc == 2) { result = Blt_PrintDialog(interp, &drawable); if (result == TCL_ERROR) { return TCL_ERROR; } if (result == TCL_RETURN) { return TCL_OK; } } else { result = Blt_GetOpenPrinter(interp, argv[2], &drawable); } if (result == TCL_OK) { int oldMode; HDC hDC; double xRatio, yRatio; TkWinDC *drawPtr; double vportWidth, vportHeight; drawPtr = (TkWinDC *) drawable; hDC = drawPtr->hdc; Blt_GetPrinterScale(hDC, &xRatio, &yRatio); oldMode = SetMapMode(hDC, MM_ISOTROPIC); if (oldMode == 0) { Tcl_AppendResult(interp, "can't set mode for printer DC: ", Blt_LastError(), (char *)NULL); return TCL_ERROR; } vportWidth = graphPtr->width * xRatio; vportHeight = graphPtr->height * yRatio; SetViewportExtEx(hDC, ROUND(vportWidth), ROUND(vportHeight), NULL); SetWindowExtEx(hDC, graphPtr->width, graphPtr->height, NULL); Blt_StartPrintJob(interp, drawable); graphPtr->flags |= RESET_WORLD; Blt_DrawGraph(graphPtr, drawable, noBackingStore); Blt_EndPrintJob(interp, drawable); } return result; } #endif /* NO_PRINTER */ /* *---------------------------------------------------------------------- * * StringToFormat -- * * Convert a string represent a node number into its integer * value. * * Results: * The return value is a standard Tcl result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToFormat(clientData, interp, switchName, string, record, offset) ClientData clientData; /* Contains a pointer to the tabset containing * this image. */ Tcl_Interp *interp; /* Interpreter to send results back to */ char *switchName; /* Not used. */ char *string; /* String representation */ char *record; /* Structure record */ int offset; /* Offset to field in structure */ { int *formatPtr = (int *)(record + offset); char c; c = string[0]; if ((c == 'p') && (strcmp(string, "photo") == 0)) { *formatPtr = FORMAT_PHOTO; #ifdef WIN32 } else if ((c == 'e') && (strcmp(string, "emf") == 0)) { *formatPtr = FORMAT_EMF; } else if ((c == 'w') && (strcmp(string, "wmf") == 0)) { *formatPtr = FORMAT_WMF; #endif /* WIN32 */ } else { #ifdef WIN32 Tcl_AppendResult(interp, "bad format \"", string, "\": should be photo, emf, or wmf.", (char *)NULL); #else Tcl_AppendResult(interp, "bad format \"", string, "\": should be photo.", (char *)NULL); #endif /* WIN32 */ return TCL_ERROR; } return TCL_OK; } #ifdef WIN32 static int InitMetaFileHeader( Tk_Window tkwin, int width, int height, APMHEADER *mfhPtr) { unsigned int *p; unsigned int sum; Screen *screen; #define MM_INCH 25.4 double dpiX, dpiY; mfhPtr->key = 0x9ac6cdd7L; mfhPtr->hmf = 0; mfhPtr->inch = 1440; screen = Tk_Screen(tkwin); dpiX = (WidthOfScreen(screen) * MM_INCH) / WidthMMOfScreen(screen); dpiY = (HeightOfScreen(screen) * MM_INCH) / HeightMMOfScreen(screen); mfhPtr->bbox.Left = mfhPtr->bbox.Top = 0; mfhPtr->bbox.Bottom = (SHORT)((width * 1440)/ dpiX); mfhPtr->bbox.Right = (SHORT)((height * 1440) / dpiY); mfhPtr->reserved = 0; sum = 0; for (p = (unsigned int *)mfhPtr; p < (unsigned int *)&(mfhPtr->checksum); p++) { sum ^= *p; } mfhPtr->checksum = sum; return TCL_OK; } static int CreateAPMetaFile( Tcl_Interp *interp, HANDLE hMetaFile, HDC hDC, APMHEADER *mfhPtr, char *fileName) { HANDLE hFile; HANDLE hMem; LPVOID buffer; int result; DWORD count, nBytes; result = TCL_ERROR; hMem = NULL; hFile = CreateFile( fileName, /* File path */ GENERIC_WRITE, /* Access mode */ 0, /* No sharing. */ NULL, /* Security attributes */ CREATE_ALWAYS, /* Overwrite any existing file */ FILE_ATTRIBUTE_NORMAL, NULL); /* No template file */ if (hFile == INVALID_HANDLE_VALUE) { Tcl_AppendResult(interp, "can't create metafile \"", fileName, "\":", Blt_LastError(), (char *)NULL); return TCL_ERROR; } if ((!WriteFile(hFile, (LPVOID)mfhPtr, sizeof(APMHEADER), &count, NULL)) || (count != sizeof(APMHEADER))) { Tcl_AppendResult(interp, "can't create metafile header to \"", fileName, "\":", Blt_LastError(), (char *)NULL); goto error; } nBytes = GetWinMetaFileBits(hMetaFile, 0, NULL, MM_ANISOTROPIC, hDC); hMem = GlobalAlloc(GHND, nBytes); if (hMem == NULL) { Tcl_AppendResult(interp, "can't create allocate global memory:", Blt_LastError(), (char *)NULL); goto error; } buffer = (LPVOID)GlobalLock(hMem); if (!GetWinMetaFileBits(hMetaFile, nBytes, buffer, MM_ANISOTROPIC, hDC)) { Tcl_AppendResult(interp, "can't get metafile bits:", Blt_LastError(), (char *)NULL); goto error; } if ((!WriteFile(hFile, buffer, nBytes, &count, NULL)) || (count != nBytes)) { Tcl_AppendResult(interp, "can't write metafile bits:", Blt_LastError(), (char *)NULL); goto error; } result = TCL_OK; error: CloseHandle(hFile); if (hMem != NULL) { GlobalUnlock(hMem); GlobalFree(hMem); } return result; } #endif /*WIN32*/ /* * -------------------------------------------------------------------------- * * SnapOp -- * * Snaps a picture of the graph and stores it in the specified image * * Results: * Returns a standard Tcl result. interp->result contains * the list of the graph coordinates. If an error occurred * while parsing the window positions, TCL_ERROR is returned, * then interp->result will contain an error message. * * ------------------------------------------------------------------------- */ /*ARGSUSED*/ static int SnapOp(graphPtr, interp, argc, argv) Graph *graphPtr; /* Graph widget record */ Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { int result; Pixmap drawable; int noBackingStore = 0; register int i; SnapData data; /* .g snap ?switches? name */ data.height = Tk_Height(graphPtr->tkwin); data.width = Tk_Width(graphPtr->tkwin); data.format = FORMAT_PHOTO; /* Process switches */ i = Blt_ProcessSwitches(interp, snapSwitches, argc - 2, argv + 2, (char *)&data, BLT_SWITCH_OBJV_PARTIAL); if (i < 0) { return TCL_ERROR; } i += 2; if (i >= argc) { Tcl_AppendResult(interp, "missing name argument: should be \"", argv[0], "snap ?switches? name\"", (char *)NULL); return TCL_ERROR; } data.name = argv[i]; if (data.width < 2) { data.width = 400; } if (data.height < 2) { data.height = 400; } /* Always re-compute the layout of the graph before snapping the photo. */ graphPtr->width = data.width; graphPtr->height = data.height; Blt_LayoutGraph(graphPtr); drawable = Tk_WindowId(graphPtr->tkwin); if (data.format == FORMAT_PHOTO) { drawable = Tk_GetPixmap(graphPtr->display, drawable, graphPtr->width, graphPtr->height, Tk_Depth(graphPtr->tkwin)); #ifdef WIN32 assert(drawable != None); #endif graphPtr->flags |= RESET_WORLD; Blt_DrawGraph(graphPtr, drawable, noBackingStore); result = Blt_SnapPhoto(interp, graphPtr->tkwin, drawable, 0, 0, data.width, data.height, data.width, data.height, data.name, 1.0); Tk_FreePixmap(graphPtr->display, drawable); #ifdef WIN32 } else if ((data.format == FORMAT_WMF) || (data.format == FORMAT_EMF)) { TkWinDC drawableDC; TkWinDCState state; HDC hRefDC, hDC; HENHMETAFILE hMetaFile; Tcl_DString dString; char *title; hRefDC = TkWinGetDrawableDC(graphPtr->display, drawable, &state); Tcl_DStringInit(&dString); Tcl_DStringAppend(&dString, "BLT Graph ", -1); Tcl_DStringAppend(&dString, BLT_VERSION, -1); Tcl_DStringAppend(&dString, "\0", -1); Tcl_DStringAppend(&dString, Tk_PathName(graphPtr->tkwin), -1); Tcl_DStringAppend(&dString, "\0", -1); title = Tcl_DStringValue(&dString); hDC = CreateEnhMetaFile(hRefDC, NULL, NULL, title); Tcl_DStringFree(&dString); if (hDC == NULL) { Tcl_AppendResult(interp, "can't create metafile: ", Blt_LastError(), (char *)NULL); return TCL_ERROR; } drawableDC.hdc = hDC; drawableDC.type = TWD_WINDC; Blt_LayoutGraph(graphPtr); graphPtr->flags |= RESET_WORLD; Blt_DrawGraph(graphPtr, (Drawable)&drawableDC, FALSE); hMetaFile = CloseEnhMetaFile(hDC); if (strcmp(data.name, "CLIPBOARD") == 0) { HWND hWnd; hWnd = Tk_GetHWND(drawable); OpenClipboard(hWnd); EmptyClipboard(); SetClipboardData(CF_ENHMETAFILE, hMetaFile); CloseClipboard(); result = TCL_OK; } else { result = TCL_ERROR; if (data.format == FORMAT_WMF) { APMHEADER mfh; assert(sizeof(mfh) == 22); InitMetaFileHeader(graphPtr->tkwin, data.width, data.height, &mfh); result = CreateAPMetaFile(interp, hMetaFile, hRefDC, &mfh, data.name); } else { HENHMETAFILE hMetaFile2; hMetaFile2 = CopyEnhMetaFile(hMetaFile, data.name); if (hMetaFile2 != NULL) { result = TCL_OK; DeleteEnhMetaFile(hMetaFile2); } } DeleteEnhMetaFile(hMetaFile); } TkWinReleaseDrawableDC(drawable, hRefDC, &state); #endif /*WIN32*/ } else { Tcl_AppendResult(interp, "bad snapshot format", (char *)NULL); return TCL_ERROR; } graphPtr->flags = MAP_WORLD; Blt_EventuallyRedrawGraph(graphPtr); return result; } /* * -------------------------------------------------------------------------- * * GraphWidgetCmd -- * * This procedure is invoked to process the Tcl command that * corresponds to a widget managed by this module. See the user * documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * * -------------------------------------------------------------------------- */ static Blt_OpSpec graphOps[] = { {"axis", 1, (Blt_Op)Blt_VirtualAxisOp, 2, 0, "oper ?args?",}, {"bar", 2, (Blt_Op)BarOp, 2, 0, "oper ?args?",}, {"cget", 2, (Blt_Op)CgetOp, 3, 3, "option",}, {"configure", 2, (Blt_Op)ConfigureOp, 2, 0, "?option value?...",}, {"crosshairs", 2, (Blt_Op)Blt_CrosshairsOp, 2, 0, "oper ?args?",}, {"element", 2, (Blt_Op)ElementOp, 2, 0, "oper ?args?",}, {"extents", 2, (Blt_Op)ExtentsOp, 3, 3, "item",}, {"grid", 1, (Blt_Op)Blt_GridOp, 2, 0, "oper ?args?",}, {"inside", 3, (Blt_Op)InsideOp, 4, 4, "winX winY",}, {"invtransform", 3, (Blt_Op)InvtransformOp, 4, 4, "winX winY",}, {"legend", 2, (Blt_Op)Blt_LegendOp, 2, 0, "oper ?args?",}, {"line", 2, (Blt_Op)LineOp, 2, 0, "oper ?args?",}, {"marker", 2, (Blt_Op)Blt_MarkerOp, 2, 0, "oper ?args?",}, {"pen", 2, (Blt_Op)Blt_PenOp, 2, 0, "oper ?args?",}, {"postscript", 2, (Blt_Op)Blt_PostScriptOp, 2, 0, "oper ?args?",}, #ifndef NO_PRINTER {"print1", 2, (Blt_Op)Print1Op, 2, 3, "?printerName?",}, {"print2", 2, (Blt_Op)Print2Op, 2, 3, "?printerName?",}, #endif /*NO_PRINTER*/ {"snap", 1, (Blt_Op)SnapOp, 3, 0, "?switches? name",}, {"transform", 1, (Blt_Op)TransformOp, 4, 4, "x y",}, {"x2axis", 2, (Blt_Op)X2AxisOp, 2, 0, "oper ?args?",}, {"xaxis", 2, (Blt_Op)XAxisOp, 2, 0, "oper ?args?",}, {"y2axis", 2, (Blt_Op)Y2AxisOp, 2, 0, "oper ?args?",}, {"yaxis", 2, (Blt_Op)YAxisOp, 2, 0, "oper ?args?",}, }; static int nGraphOps = sizeof(graphOps) / sizeof(Blt_OpSpec); int Blt_GraphInstCmdProc(clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; int argc; char **argv; { Blt_Op proc; int result; Graph *graphPtr = clientData; proc = Blt_GetOp(interp, nGraphOps, graphOps, BLT_OP_ARG1, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } Tcl_Preserve(graphPtr); result = (*proc) (graphPtr, interp, argc, argv); Tcl_Release(graphPtr); return result; } /* * -------------------------------------------------------------------------- * * NewGraph -- * * Creates a new window and Tcl command representing an * instance of a graph widget. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * * -------------------------------------------------------------------------- */ static int NewGraph(interp, argc, argv, classUid) Tcl_Interp *interp; int argc; char **argv; Blt_Uid classUid; { Graph *graphPtr; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " pathName ?option value?...\"", (char *)NULL); return TCL_ERROR; } graphPtr = CreateGraph(interp, argc, argv, classUid); if (graphPtr == NULL) { return TCL_ERROR; } Tcl_SetResult(interp, Tk_PathName(graphPtr->tkwin), TCL_VOLATILE); return TCL_OK; } /* * -------------------------------------------------------------------------- * * GraphCmd -- * * Creates a new window and Tcl command representing an * instance of a graph widget. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * * -------------------------------------------------------------------------- */ /*ARGSUSED*/ static int GraphCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; int argc; char **argv; { return NewGraph(interp, argc, argv, bltLineElementUid); } /* *-------------------------------------------------------------- * * BarchartCmd -- * * Creates a new window and Tcl command representing an * instance of a barchart widget. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ /*ARGSUSED*/ static int BarchartCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; int argc; char **argv; { return NewGraph(interp, argc, argv, bltBarElementUid); } /* *-------------------------------------------------------------- * * StripchartCmd -- * * Creates a new window and Tcl command representing an * instance of a barchart widget. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ /*ARGSUSED*/ static int StripchartCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; int argc; char **argv; { return NewGraph(interp, argc, argv, bltStripElementUid); } /* * ----------------------------------------------------------------------- * * DrawMargins -- * * Draws the exterior region of the graph (axes, ticks, titles, etc) * onto a pixmap. The interior region is defined by the given * rectangle structure. * * --------------------------------- * | | * | rectArr[0] | * | | * --------------------------------- * | |top right| | * | | | | * | | | | * | [1] | | [2] | * | | | | * | | | | * | | | | * | | | | * | | | | * | |left bottom| | * --------------------------------- * | | * | rectArr[3] | * | | * --------------------------------- * * X coordinate axis * Y coordinate axis * legend * interior border * exterior border * titles (X and Y axis, graph) * * Returns: * None. * * Side Effects: * Exterior of graph is displayed in its window. * * ----------------------------------------------------------------------- */ static void DrawMargins(graphPtr, drawable) Graph *graphPtr; Drawable drawable; /* Pixmap or window to draw into */ { XRectangle 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 = (short int)graphPtr->width; rects[0].height = (short int)graphPtr->top; rects[3].y = graphPtr->bottom; rects[3].height = graphPtr->height - graphPtr->bottom; rects[2].y = rects[1].y = graphPtr->top; rects[1].width = graphPtr->left; rects[2].height = rects[1].height = graphPtr->bottom - graphPtr->top; rects[2].x = graphPtr->right; rects[2].width = graphPtr->width - graphPtr->right; if (graphPtr->tile != NULL) { Blt_SetTileOrigin(graphPtr->tkwin, graphPtr->tile, 0, 0); Blt_TileRectangles(graphPtr->tkwin, drawable, graphPtr->tile, rects, 4); } else { XFillRectangles(graphPtr->display, drawable, graphPtr->fillGC, rects, 4); } /* Draw 3D border around the plotting area */ if (graphPtr->plotBorderWidth > 0) { int x, y, width, height; x = graphPtr->left - graphPtr->plotBorderWidth; y = graphPtr->top - graphPtr->plotBorderWidth; width = (graphPtr->right - graphPtr->left) + (2 * graphPtr->plotBorderWidth); height = (graphPtr->bottom - graphPtr->top) + (2 * graphPtr->plotBorderWidth); Blt_Draw3DRectangle(graphPtr->tkwin, drawable, graphPtr->border, x, y, width, height, graphPtr->plotBorderWidth, graphPtr->plotRelief); } if (Blt_LegendSite(graphPtr->legend) & LEGEND_IN_MARGIN) { /* Legend is drawn on one of the graph margins */ Blt_DrawLegend(graphPtr->legend, drawable); } if (graphPtr->title != NULL) { Blt_DrawText(graphPtr->tkwin, drawable, graphPtr->title, &graphPtr->titleTextStyle, graphPtr->titleX, graphPtr->titleY); } Blt_DrawAxes(graphPtr, drawable); } /* *---------------------------------------------------------------------- * * DrawPlotRegion -- * * Draws the contents of the plotting area. This consists of * the elements, markers (draw under elements), axis limits, * grid lines, and possibly the legend. Typically, the output * will be cached into a backing store pixmap, so that redraws * can occur quickly. * * Results: * None. * *---------------------------------------------------------------------- */ static void DrawPlotRegion(graphPtr, drawable) Graph *graphPtr; Drawable drawable; /* Pixmap or window to draw into */ { /* Clear the background of the plotting area. */ XFillRectangle(graphPtr->display, drawable, graphPtr->plotFillGC, graphPtr->left, graphPtr->top, graphPtr->right - graphPtr->left + 1, graphPtr->bottom - graphPtr->top + 1); /* Draw the elements, markers, legend, and axis limits. */ if (!graphPtr->gridPtr->hidden) { Blt_DrawGrid(graphPtr, drawable); } Blt_DrawMarkers(graphPtr, drawable, MARKER_UNDER); if ((Blt_LegendSite(graphPtr->legend) & LEGEND_IN_PLOT) && (!Blt_LegendIsRaised(graphPtr->legend))) { Blt_DrawLegend(graphPtr->legend, drawable); } Blt_DrawAxisLimits(graphPtr, drawable); Blt_DrawElements(graphPtr, drawable); } void Blt_LayoutGraph(graphPtr) Graph *graphPtr; { if (graphPtr->flags & RESET_AXES) { Blt_ResetAxes(graphPtr); } if (graphPtr->flags & LAYOUT_NEEDED) { Blt_LayoutMargins(graphPtr); graphPtr->flags &= ~LAYOUT_NEEDED; } /* Compute coordinate transformations for graph components */ if ((graphPtr->vRange > 1) && (graphPtr->hRange > 1)) { if (graphPtr->flags & MAP_WORLD) { Blt_MapAxes(graphPtr); } Blt_MapElements(graphPtr); Blt_MapMarkers(graphPtr); Blt_MapGrid(graphPtr); graphPtr->flags &= ~(MAP_ALL); } } void Blt_DrawGraph(graphPtr, drawable, backingStore) Graph *graphPtr; Drawable drawable; /* Pixmap or window to draw into */ int backingStore; /* If non-zero, use backing store for * plotting area. */ { if (backingStore) { /* * Create another pixmap to save elements if one doesn't * already exist or the size of the window has changed. */ if ((graphPtr->backPixmap == None) || (graphPtr->backWidth != graphPtr->width) || (graphPtr->backHeight != graphPtr->height)) { if (graphPtr->backPixmap != None) { Tk_FreePixmap(graphPtr->display, graphPtr->backPixmap); } graphPtr->backPixmap = Tk_GetPixmap(graphPtr->display, Tk_WindowId(graphPtr->tkwin), graphPtr->width, graphPtr->height, Tk_Depth(graphPtr->tkwin)); graphPtr->backWidth = graphPtr->width; graphPtr->backHeight = graphPtr->height; graphPtr->flags |= REDRAW_BACKING_STORE; } if (graphPtr->flags & REDRAW_BACKING_STORE) { /* The backing store is new or out-of-date. */ DrawPlotRegion(graphPtr, graphPtr->backPixmap); graphPtr->flags &= ~REDRAW_BACKING_STORE; } /* Copy the pixmap to the one used for drawing the entire graph. */ XCopyArea(graphPtr->display, graphPtr->backPixmap, drawable, graphPtr->drawGC, graphPtr->left, graphPtr->top, (graphPtr->right - graphPtr->left + 1), (graphPtr->bottom - graphPtr->top + 1), graphPtr->left, graphPtr->top); } else { DrawPlotRegion(graphPtr, drawable); } /* Draw markers above elements */ Blt_DrawMarkers(graphPtr, drawable, MARKER_ABOVE); Blt_DrawActiveElements(graphPtr, drawable); if (graphPtr->flags & DRAW_MARGINS) { DrawMargins(graphPtr, drawable); } if ((Blt_LegendSite(graphPtr->legend) & LEGEND_IN_PLOT) && (Blt_LegendIsRaised(graphPtr->legend))) { Blt_DrawLegend(graphPtr->legend, drawable); } /* Draw 3D border just inside of the focus highlight ring. */ if ((graphPtr->borderWidth > 0) && (graphPtr->relief != TK_RELIEF_FLAT)) { Blt_Draw3DRectangle(graphPtr->tkwin, drawable, graphPtr->border, graphPtr->highlightWidth, graphPtr->highlightWidth, graphPtr->width - 2 * graphPtr->highlightWidth, graphPtr->height - 2 * graphPtr->highlightWidth, graphPtr->borderWidth, graphPtr->relief); } /* Draw focus highlight ring. */ if ((graphPtr->highlightWidth > 0) && (graphPtr->flags & GRAPH_FOCUS)) { GC gc; gc = Tk_GCForColor(graphPtr->highlightColor, drawable); Tk_DrawFocusHighlight(graphPtr->tkwin, gc, graphPtr->highlightWidth, drawable); } } static void UpdateMarginTraces(graphPtr) Graph *graphPtr; { Margin *marginPtr; int size; register int i; for (i = 0; i < 4; i++) { marginPtr = graphPtr->margins + i; if (marginPtr->varName != NULL) { /* Trigger variable traces */ if ((marginPtr->site == MARGIN_LEFT) || (marginPtr->site == MARGIN_RIGHT)) { size = marginPtr->width; } else { size = marginPtr->height; } Tcl_SetVar(graphPtr->interp, marginPtr->varName, Blt_Itoa(size), TCL_GLOBAL_ONLY); } } } /* *---------------------------------------------------------------------- * * DisplayGraph -- * * This procedure is invoked to display a graph widget. * * Results: * None. * * Side effects: * Commands are output to X to display the graph in its * current mode. * *---------------------------------------------------------------------- */ static void DisplayGraph(clientData) ClientData clientData; { Graph *graphPtr = clientData; Pixmap drawable; graphPtr->flags &= ~REDRAW_PENDING; if (graphPtr->tkwin == NULL) { return; /* Window destroyed (should not get here) */ } #ifdef notdef fprintf(stderr, "Calling DisplayGraph(%s)\n", Tk_PathName(graphPtr->tkwin)); #endif if (Blt_GraphUpdateNeeded(graphPtr)) { /* * One of the elements of the graph has a vector notification * pending. This means that the vector will eventually notify * the graph that its data has changed. Since the graph uses * the actual vector (not a copy) we need to keep in-sync. * Therefore don't draw right now but wait until we've been * notified before redrawing. */ return; } graphPtr->width = Tk_Width(graphPtr->tkwin); graphPtr->height = Tk_Height(graphPtr->tkwin); Blt_LayoutGraph(graphPtr); Blt_UpdateCrosshairs(graphPtr); if (!Tk_IsMapped(graphPtr->tkwin)) { /* The graph's window isn't displayed, so don't bother * drawing anything. By getting this far, we've at least * computed the coordinates of the graph's new layout. */ return; } /* Disable crosshairs before redisplaying to the screen */ Blt_DisableCrosshairs(graphPtr); /* * Create a pixmap the size of the window for double buffering. */ if (graphPtr->doubleBuffer) { drawable = Tk_GetPixmap(graphPtr->display, Tk_WindowId(graphPtr->tkwin), graphPtr->width, graphPtr->height, Tk_Depth(graphPtr->tkwin)); } else { drawable = Tk_WindowId(graphPtr->tkwin); } #ifdef WIN32 assert(drawable != None); #endif Blt_DrawGraph(graphPtr, drawable, graphPtr->backingStore && graphPtr->doubleBuffer); if (graphPtr->flags & DRAW_MARGINS) { XCopyArea(graphPtr->display, drawable, Tk_WindowId(graphPtr->tkwin), graphPtr->drawGC, 0, 0, graphPtr->width, graphPtr->height, 0, 0); } else { XCopyArea(graphPtr->display, drawable, Tk_WindowId(graphPtr->tkwin), graphPtr->drawGC, graphPtr->left, graphPtr->top, (graphPtr->right - graphPtr->left + 1), (graphPtr->bottom - graphPtr->top + 1), graphPtr->left, graphPtr->top); } if (graphPtr->doubleBuffer) { Tk_FreePixmap(graphPtr->display, drawable); } Blt_EnableCrosshairs(graphPtr); graphPtr->flags &= ~RESET_WORLD; UpdateMarginTraces(graphPtr); } /*LINTLIBRARY*/ int Blt_GraphInit(interp) Tcl_Interp *interp; { static Blt_CmdSpec cmdSpecs[] = { {"graph", GraphCmd,}, {"barchart", BarchartCmd,}, {"stripchart", StripchartCmd,}, }; bltBarElementUid = (Blt_Uid)Tk_GetUid("BarElement"); bltLineElementUid = (Blt_Uid)Tk_GetUid("LineElement"); bltStripElementUid = (Blt_Uid)Tk_GetUid("StripElement"); bltContourElementUid = (Blt_Uid)Tk_GetUid("ContourElement"); bltLineMarkerUid = (Blt_Uid)Tk_GetUid("LineMarker"); bltBitmapMarkerUid = (Blt_Uid)Tk_GetUid("BitmapMarker"); bltImageMarkerUid = (Blt_Uid)Tk_GetUid("ImageMarker"); bltTextMarkerUid = (Blt_Uid)Tk_GetUid("TextMarker"); bltPolygonMarkerUid = (Blt_Uid)Tk_GetUid("PolygonMarker"); bltWindowMarkerUid = (Blt_Uid)Tk_GetUid("WindowMarker"); bltXAxisUid = (Blt_Uid)Tk_GetUid("X"); bltYAxisUid = (Blt_Uid)Tk_GetUid("Y"); return Blt_InitCmds(interp, "blt", cmdSpecs, 3); } Graph * Blt_GetGraphFromWindowData(tkwin) Tk_Window tkwin; { Graph *graphPtr; while (tkwin != NULL) { graphPtr = (Graph *)Blt_GetWindowInstanceData(tkwin); if (graphPtr != NULL) { return graphPtr; } tkwin = Tk_Parent(tkwin); } return NULL; } int Blt_GraphType(graphPtr) Graph *graphPtr; { if (graphPtr->classUid == bltLineElementUid) { return GRAPH; } else if (graphPtr->classUid == bltBarElementUid) { return BARCHART; } else if (graphPtr->classUid == bltStripElementUid) { return STRIPCHART; } return 0; } blt-2.4z.orig/src/bltGraph.h0100644000175000017500000006065307542177233014473 0ustar dokodoko/* * bltGraph.h -- * * Copyright 1991-1998 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. */ #ifndef _BLT_GRAPH_H #define _BLT_GRAPH_H #include "bltInt.h" #include "bltHash.h" #include "bltBind.h" #include "bltChain.h" #include "bltPs.h" #include "bltTile.h" typedef struct GraphStruct Graph; typedef struct ElementStruct Element; typedef struct LegendStruct Legend; #include "bltGrAxis.h" #include "bltGrLegd.h" #define MARKER_UNDER 1 /* Draw markers designated to lie underneath * elements, grids, legend, etc. */ #define MARKER_ABOVE 0 /* Draw markers designated to rest above * elements, grids, legend, etc. */ #define PADX 2 /* Padding between labels/titles */ #define PADY 2 /* Padding between labels */ #define MINIMUM_MARGIN 20 /* Minimum margin size */ #define BOUND(x, lo, hi) \ (((x) > (hi)) ? (hi) : ((x) < (lo)) ? (lo) : (x)) /* * ------------------------------------------------------------------- * * Graph component structure definitions * * ------------------------------------------------------------------- */ #define PointInGraph(g,x,y) \ (((x) <= (g)->right) && ((x) >= (g)->left) && \ ((y) <= (g)->bottom) && ((y) >= (g)->top)) /* * ------------------------------------------------------------------- * * ClassType -- * * Enumerates the different types of graph elements this program * produces. An element can be either a line or a bar. * * ------------------------------------------------------------------- */ typedef enum { CLASS_UNKNOWN, CLASS_LINE_ELEMENT, CLASS_STRIP_ELEMENT, CLASS_BAR_ELEMENT, CLASS_BITMAP_MARKER, CLASS_IMAGE_MARKER, CLASS_LINE_MARKER, CLASS_POLYGON_MARKER, CLASS_TEXT_MARKER, CLASS_WINDOW_MARKER } ClassType; /* * Mask values used to selectively enable GRAPH or BARCHART entries in * the various configuration specs. */ #define GRAPH (TK_CONFIG_USER_BIT << 1) #define STRIPCHART (TK_CONFIG_USER_BIT << 2) #define BARCHART (TK_CONFIG_USER_BIT << 3) #define LINE_GRAPHS (GRAPH | STRIPCHART) #define ALL_GRAPHS (GRAPH | BARCHART | STRIPCHART) #define PEN_DELETE_PENDING (1<<0) #define ACTIVE_PEN (TK_CONFIG_USER_BIT << 6) #define NORMAL_PEN (TK_CONFIG_USER_BIT << 7) #define ALL_PENS (NORMAL_PEN | ACTIVE_PEN) /* * ------------------------------------------------------------------- * * FreqInfo -- * * ------------------------------------------------------------------- */ typedef struct { int freq; /* Number of occurrences of x-coordinate */ Axis2D axes; /* Indicates which x and y axis are mapped to * the x-value */ double sum; /* Sum of the ordinates of each duplicate * abscissa */ int count; double lastY; } FreqInfo; /* * ------------------------------------------------------------------- * * FreqKey -- * * * ------------------------------------------------------------------- */ typedef struct { double value; /* Duplicated abscissa */ Axis2D axes; /* Axis mapping of element */ } FreqKey; /* * BarModes -- * * Bar elements are displayed according to their x-y coordinates. * If two bars have the same abscissa (x-coordinate), the bar * segments will be drawn according to one of the following * modes: */ typedef enum BarModes { MODE_INFRONT, /* Each successive segment is drawn in * front of the previous. */ MODE_STACKED, /* Each successive segment is drawn * stacked above the previous. */ MODE_ALIGNED, /* Each successive segment is drawn * aligned to the previous from * right-to-left. */ MODE_OVERLAP /* Like "aligned", each successive segment * is drawn from right-to-left. In addition * the segments will overlap each other * by a small amount */ } BarMode; typedef struct PenStruct Pen; typedef struct MarkerStruct Marker; typedef Pen *(PenCreateProc) _ANSI_ARGS_((void)); typedef int (PenConfigureProc) _ANSI_ARGS_((Graph *graphPtr, Pen *penPtr)); typedef void (PenDestroyProc) _ANSI_ARGS_((Graph *graphPtr, Pen *penPtr)); struct PenStruct { char *name; /* Pen style identifier. If NULL pen * was statically allocated. */ Blt_Uid classUid; /* Type of pen */ char *typeId; /* String token identifying the type of pen */ unsigned int flags; /* Indicates if the pen element is active or * normal */ int refCount; /* Reference count for elements using * this pen. */ Blt_HashEntry *hashPtr; Tk_ConfigSpec *configSpecs; /* Configuration specifications */ PenConfigureProc *configProc; PenDestroyProc *destroyProc; }; typedef enum { PS_MONO_BACKGROUND, PS_MONO_FOREGROUND } MonoAttribute; /* * PostScript -- * * Structure contains information specific to the outputting of * PostScript commands to print the graph. * */ typedef struct { /* User configurable fields */ int decorations; /* If non-zero, print graph with * color background and 3D borders */ int reqWidth, reqHeight; /* If greater than zero, represents the * requested dimensions of the printed graph */ int reqPaperWidth; int reqPaperHeight; /* Requested dimensions for the PostScript * page. Can constrain the size of the graph * if the graph (plus padding) is larger than * the size of the page. */ Blt_Pad padX, padY; /* Requested padding on the exterior of the * graph. This forms the bounding box for * the page. */ PsColorMode colorMode; /* Selects the color mode for PostScript page * (0=monochrome, 1=greyscale, 2=color) */ char *colorVarName; /* If non-NULL, is the name of a Tcl array * variable containing X to PostScript color * translations */ char *fontVarName; /* If non-NULL, is the name of a Tcl array * variable containing X to PostScript font * translations */ int landscape; /* If non-zero, orient the page 90 degrees */ int center; /* If non-zero, center the graph on the page */ int maxpect; /* If non-zero, indicates to scale the graph * so that it fills the page (maintaining the * aspect ratio of the graph) */ int addPreview; /* If non-zero, generate a preview image and * add it to the PostScript output */ int footer; /* If non-zero, a footer with the title, date * and user will be added to the PostScript * output outside of the bounding box. */ int previewFormat; /* Format of EPS preview: * PS_PREVIEW_WMF, PS_PREVIEW_EPSI, or * PS_PREVIEW_TIFF. */ /* Computed fields */ int left, bottom; /* Bounding box of PostScript plot. */ int right, top; double pageScale; /* Scale of page. Set if "-maxpect" option * is set, otherwise 1.0. */ } PostScript; /* * ------------------------------------------------------------------- * * Grid * * Contains attributes of describing how to draw grids (at major * ticks) in the graph. Grids may be mapped to either/both x and * y axis. * * ------------------------------------------------------------------- */ typedef struct { GC gc; /* Graphics context for the grid. */ Axis2D axes; int hidden; /* If non-zero, grid isn't displayed. */ int minorGrid; /* If non-zero, draw grid line for minor * axis ticks too */ Blt_Dashes dashes; /* Dashstyle of the grid. This represents * an array of alternatingly drawn pixel * values. */ int lineWidth; /* Width of the grid lines */ XColor *colorPtr; /* Color of the grid lines */ struct GridSegments { Segment2D *segments; /* Array of line segments representing the * x or y grid lines */ int nSegments; /* # of axis segments. */ } x, y; } Grid; /* * ------------------------------------------------------------------- * * Crosshairs * * Contains the line segments positions and graphics context used * to simulate crosshairs (by XOR-ing) on the graph. * * ------------------------------------------------------------------- */ typedef struct CrosshairsStruct Crosshairs; typedef struct { short int width, height; /* Extents of the margin */ short int axesOffset; short int axesTitleLength; /* Width of the widest title to be shown. * Multiple titles are displayed in * another margin. This is the minimum * space requirement. */ unsigned int nAxes; /* Number of axes to be displayed */ Blt_Chain *axes; /* Extra axes associated with this margin */ char *varName; /* If non-NULL, name of variable to be * updated when the margin size changes */ int reqSize; /* Requested size of margin */ int site; /* Indicates where margin is located: * left/right/top/bottom. */ } Margin; #define MARGIN_NONE -1 #define MARGIN_BOTTOM 0 #define MARGIN_LEFT 1 #define MARGIN_TOP 2 #define MARGIN_RIGHT 3 #define rightMargin margins[MARGIN_RIGHT] #define leftMargin margins[MARGIN_LEFT] #define topMargin margins[MARGIN_TOP] #define bottomMargin margins[MARGIN_BOTTOM] /* * ------------------------------------------------------------------- * * Graph -- * * Top level structure containing everything pertaining to * the graph. * * ------------------------------------------------------------------- */ struct GraphStruct { unsigned int flags; /* Flags; see below for definitions. */ Tcl_Interp *interp; /* Interpreter associated with graph */ Tk_Window tkwin; /* Window that embodies the graph. NULL * means that the window has been * destroyed but the data structures * haven't yet been cleaned up. */ Display *display; /* Display containing widget; needed, * among other things, to release * resources after tkwin has already gone * away. */ Tcl_Command cmdToken; /* Token for graph's widget command. */ char *data; /* This value isn't used in C code. * It may be used in Tcl bindings to * associate extra data. */ Tk_Cursor cursor; int inset; /* Sum of focus highlight and 3-D * border. Indicates how far to * offset the graph from outside * edge of the window. */ int borderWidth; /* Width of the exterior border */ int relief; /* Relief of the exterior border */ Tk_3DBorder border; /* 3-D border used to delineate the plot * surface and outer edge of window */ int highlightWidth; /* Width in pixels of highlight to draw * around widget when it has the focus. * <= 0 means don't draw a highlight. */ XColor *highlightBgColor; /* Color for drawing traversal highlight * area when highlight is off. */ XColor *highlightColor; /* Color for drawing traversal highlight. */ char *title; short int titleX, titleY; TextStyle titleTextStyle; /* Graph title */ char *takeFocus; int reqWidth, reqHeight; /* Requested size of graph window */ int width, height; /* Size of graph window or PostScript * page */ Blt_HashTable penTable; /* Table of pens */ struct Component { Blt_HashTable table; /* Hash table of ids. */ Blt_Chain *displayList; /* Display list. */ Blt_HashTable tagTable; /* Table of bind tags. */ } elements, markers, axes; Blt_Uid classUid; /* Default element type */ Blt_BindTable bindTable; int nextMarkerId; /* Tracks next marker identifier available */ Blt_Chain *axisChain[4]; /* Chain of axes for each of the * margins. They're separate from the * margin structures to make it easier * to invert the X-Y axes by simply * switching chain pointers. */ Margin margins[4]; PostScript *postscript; /* PostScript options: see bltGrPS.c */ Legend *legend; /* Legend information: see bltGrLegd.c */ Crosshairs *crosshairs; /* Crosshairs information: see bltGrHairs.c */ Grid *gridPtr; /* Grid attribute information */ int halo; /* Maximum distance allowed between points * when searching for a point */ int inverted; /* If non-zero, indicates the x and y axis * positions should be inverted. */ Blt_Tile tile; GC drawGC; /* Used for drawing on the margins. This * includes the axis lines */ GC fillGC; /* Used to fill the background of the * margins. The fill is governed by * the background color or the tiled * pixmap. */ int plotBorderWidth; /* Width of interior 3-D border. */ int plotRelief; /* 3-d effect: TK_RELIEF_RAISED etc. */ XColor *plotBg; /* Color of plotting surface */ GC plotFillGC; /* Used to fill the plotting area with a * solid background color. The fill color * is stored in "plotBg". */ /* If non-zero, force plot to conform to aspect ratio W/H */ double aspect; short int left, right; /* Coordinates of plot bbox */ short int top, bottom; Blt_Pad padX; /* Vertical padding for plotarea */ int vRange, vOffset; /* Vertical axis range and offset from the * left side of the graph window. Used to * transform coordinates to vertical * axes. */ Blt_Pad padY; /* Horizontal padding for plotarea */ int hRange, hOffset; /* Horizontal axis range and offset from * the top of the graph window. Used to * transform horizontal axes */ double vScale, hScale; int doubleBuffer; /* If non-zero, draw the graph into a pixmap * first to reduce flashing. */ int backingStore; /* If non-zero, cache elements by drawing * them into a pixmap */ Pixmap backPixmap; /* Pixmap used to cache elements * displayed. If *backingStore* is * non-zero, each element is drawn * into this pixmap before it is * copied onto the screen. The pixmap * then acts as a cache (only the * pixmap is redisplayed if the none * of elements have changed). This is * done so that markers can be redrawn * quickly over elements without * redrawing each element. */ int backWidth, backHeight; /* Size of element backing store pixmap. */ /* * barchart specific information */ double baseline; /* Baseline from bar chart. */ double barWidth; /* Default width of each bar in graph units. * The default width is 1.0 units. */ BarMode mode; /* Mode describing how to display bars * with the same x-coordinates. Mode can * be "stack", "align", or "normal" */ FreqInfo *freqArr; /* Contains information about duplicate * x-values in bar elements (malloc-ed). * This information can also be accessed * by the frequency hash table */ Blt_HashTable freqTable; /* */ int nStacks; /* Number of entries in frequency array. * If zero, indicates nothing special needs * to be done for "stack" or "align" modes */ char *dataCmd; /* New data callback? */ }; /* * Bit flags definitions: * * All kinds of state information kept here. All these * things happen when the window is available to draw into * (DisplayGraph). Need the window width and height before * we can calculate graph layout (i.e. the screen coordinates * of the axes, elements, titles, etc). But we want to do this * only when we have to, not every time the graph is redrawn. * * Same goes for maintaining a pixmap to double buffer graph * elements. Need to mark when the pixmap needs to updated. * * * MAP_ITEM Indicates that the element/marker/axis * configuration has changed such that * its layout of the item (i.e. its * position in the graph window) needs * to be recalculated. * * MAP_ALL Indicates that the layout of the axes and * all elements and markers and the graph need * to be recalculated. Otherwise, the layout * of only those markers and elements that * have changed will be reset. * * GET_AXIS_GEOMETRY Indicates that the size of the axes needs * to be recalculated. * * RESET_AXES Flag to call to Blt_ResetAxes routine. * This routine recalculates the scale offset * (used for mapping coordinates) of each axis. * If an axis limit has changed, then it sets * flags to re-layout and redraw the entire * graph. This needs to happend before the axis * can compute transformations between graph and * screen coordinates. * * LAYOUT_NEEDED * * REDRAW_BACKING_STORE If set, redraw all elements into the pixmap * used for buffering elements. * * REDRAW_PENDING Non-zero means a DoWhenIdle handler has * already been queued to redraw this window. * * DRAW_LEGEND Non-zero means redraw the legend. If this is * the only DRAW_* flag, the legend display * routine is called instead of the graph * display routine. * * DRAW_MARGINS Indicates that the margins bordering * the plotting area need to be redrawn. * The possible reasons are: * * 1) an axis configuration changed * 2) an axis limit changed * 3) titles have changed * 4) window was resized. * * GRAPH_FOCUS */ #define MAP_ITEM (1<<0) /* 0x0001 */ #define MAP_ALL (1<<1) /* 0x0002 */ #define GET_AXIS_GEOMETRY (1<<2) /* 0x0004 */ #define RESET_AXES (1<<3) /* 0x0008 */ #define LAYOUT_NEEDED (1<<4) /* 0x0010 */ #define REDRAW_PENDING (1<<8) /* 0x0100 */ #define DRAW_LEGEND (1<<9) /* 0x0200 */ #define DRAW_MARGINS (1<<10)/* 0x0400 */ #define REDRAW_BACKING_STORE (1<<11)/* 0x0800 */ #define GRAPH_FOCUS (1<<12)/* 0x1000 */ #define DATA_CHANGED (1<<13)/* 0x2000 */ #define MAP_WORLD (MAP_ALL|RESET_AXES|GET_AXIS_GEOMETRY) #define REDRAW_WORLD (DRAW_MARGINS | DRAW_LEGEND) #define RESET_WORLD (REDRAW_WORLD | MAP_WORLD) /* * ---------------------- Forward declarations ------------------------ */ extern int Blt_CreatePostScript _ANSI_ARGS_((Graph *graphPtr)); extern int Blt_CreateCrosshairs _ANSI_ARGS_((Graph *graphPtr)); extern int Blt_CreateGrid _ANSI_ARGS_((Graph *graphPtr)); extern double Blt_InvHMap _ANSI_ARGS_((Graph *graphPtr, Axis *axisPtr, double x)); extern double Blt_InvVMap _ANSI_ARGS_((Graph *graphPtr, Axis *axisPtr, double x)); extern double Blt_HMap _ANSI_ARGS_((Graph *graphPtr, Axis *axisPtr, double x)); extern double Blt_VMap _ANSI_ARGS_((Graph *graphPtr, Axis *axisPtr, double y)); extern Point2D Blt_InvMap2D _ANSI_ARGS_((Graph *graphPtr, double x, double y, Axis2D *pairPtr)); extern Point2D Blt_Map2D _ANSI_ARGS_((Graph *graphPtr, double x, double y, Axis2D *pairPtr)); extern Graph *Blt_GetGraphFromWindowData _ANSI_ARGS_((Tk_Window tkwin)); extern void Blt_AdjustAxisPointers _ANSI_ARGS_((Graph *graphPtr)); extern int Blt_LineRectClip _ANSI_ARGS_((Extents2D *extsPtr, Point2D *p, Point2D *q)); extern int Blt_PolyRectClip _ANSI_ARGS_((Extents2D *extsPtr, Point2D *inputPts, int nInputPts, Point2D *outputPts)); extern void Blt_ComputeStacks _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_ConfigureCrosshairs _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_DestroyAxes _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_DestroyCrosshairs _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_DestroyGrid _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_DestroyElements _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_DestroyMarkers _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_DestroyPostScript _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_DrawAxes _ANSI_ARGS_((Graph *graphPtr, Drawable drawable)); extern void Blt_DrawAxisLimits _ANSI_ARGS_((Graph *graphPtr, Drawable drawable)); extern void Blt_DrawElements _ANSI_ARGS_((Graph *graphPtr, Drawable drawable)); extern void Blt_DrawActiveElements _ANSI_ARGS_((Graph *graphPtr, Drawable drawable)); extern void Blt_DrawGraph _ANSI_ARGS_((Graph *graphPtr, Drawable drawable, int backingStore)); extern void Blt_DrawGrid _ANSI_ARGS_((Graph *graphPtr, Drawable drawable)); extern void Blt_DrawMarkers _ANSI_ARGS_((Graph *graphPtr, Drawable drawable, int under)); extern void Blt_Draw2DSegments _ANSI_ARGS_((Display *display, Drawable drawable, GC gc, Segment2D *segments, int nSegments)); extern int Blt_GetCoordinate _ANSI_ARGS_((Tcl_Interp *interp, char *expr, double *valuePtr)); extern void Blt_InitFreqTable _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_LayoutGraph _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_LayoutMargins _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_EventuallyRedrawGraph _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_ResetAxes _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_ResetStacks _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_GraphExtents _ANSI_ARGS_((Graph *graphPtr, Extents2D *extsPtr)); extern void Blt_DisableCrosshairs _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_EnableCrosshairs _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_MapAxes _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_MapElements _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_MapGraph _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_MapMarkers _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_MapGrid _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_UpdateCrosshairs _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_DestroyPens _ANSI_ARGS_((Graph *graphPtr)); extern int Blt_GetPen _ANSI_ARGS_((Graph *graphPtr, char *name, Blt_Uid classUid, Pen **penPtrPtr)); extern Pen *Blt_BarPen _ANSI_ARGS_((char *penName)); extern Pen *Blt_LinePen _ANSI_ARGS_((char *penName)); extern Pen *Blt_CreatePen _ANSI_ARGS_((Graph *graphPtr, char *penName, Blt_Uid classUid, int nOpts, char **options)); extern int Blt_InitLinePens _ANSI_ARGS_((Graph *graphPtr)); extern int Blt_InitBarPens _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_FreePen _ANSI_ARGS_((Graph *graphPtr, Pen *penPtr)); extern int Blt_VirtualAxisOp _ANSI_ARGS_((Graph *graphPtr, Tcl_Interp *interp, int argc, char **argv)); extern int Blt_AxisOp _ANSI_ARGS_((Graph *graphPtr, int margin, int argc, char **argv)); extern int Blt_ElementOp _ANSI_ARGS_((Graph *graphPtr, Tcl_Interp *interp, int argc, char **argv, Blt_Uid classUid)); extern int Blt_GridOp _ANSI_ARGS_((Graph *graphPtr, Tcl_Interp *interp, int argc, char **argv)); extern int Blt_CrosshairsOp _ANSI_ARGS_((Graph *graphPtr, Tcl_Interp *interp, int argc, char **argv)); extern int Blt_MarkerOp _ANSI_ARGS_((Graph *graphPtr, Tcl_Interp *interp, int argc, char **argv)); extern int Blt_PenOp _ANSI_ARGS_((Graph *graphPtr, Tcl_Interp *interp, int argc, char **argv)); extern int Blt_PointInPolygon _ANSI_ARGS_((Point2D *samplePtr, Point2D *screenPts, int nScreenPts)); extern int Blt_RegionInPolygon _ANSI_ARGS_((Extents2D *extsPtr, Point2D *points, int nPoints, int enclosed)); extern int Blt_PointInSegments _ANSI_ARGS_((Point2D *samplePtr, Segment2D *segments, int nSegments, double halo)); extern int Blt_PostScriptOp _ANSI_ARGS_((Graph *graphPtr, Tcl_Interp *interp, int argc, char **argv)); extern int Blt_GraphUpdateNeeded _ANSI_ARGS_((Graph *graphPtr)); extern int Blt_DefaultAxes _ANSI_ARGS_((Graph *graphPtr)); extern Axis *Blt_GetFirstAxis _ANSI_ARGS_((Blt_Chain *chainPtr)); extern void Blt_UpdateAxisBackgrounds _ANSI_ARGS_((Graph *graphPtr)); extern void Blt_GetAxisSegments _ANSI_ARGS_((Graph *graphPtr, Axis *axisPtr, Segment2D **segPtrPtr, int *nSegmentsPtr)); extern Marker *Blt_NearestMarker _ANSI_ARGS_((Graph *graphPtr, int x, int y, int under)); extern Axis *Blt_NearestAxis _ANSI_ARGS_((Graph *graphPtr, int x, int y)); typedef ClientData (MakeTagProc) _ANSI_ARGS_((Graph *graphPtr, char *tagName)); extern MakeTagProc Blt_MakeElementTag; extern MakeTagProc Blt_MakeMarkerTag; extern MakeTagProc Blt_MakeAxisTag; extern Blt_BindTagProc Blt_GraphTags; extern Blt_BindTagProc Blt_AxisTags; extern int Blt_GraphType _ANSI_ARGS_((Graph *graphPtr)); /* ---------------------- Global declarations ------------------------ */ extern Blt_Uid bltBarElementUid; extern Blt_Uid bltLineElementUid; extern Blt_Uid bltStripElementUid; extern Blt_Uid bltLineMarkerUid; extern Blt_Uid bltBitmapMarkerUid; extern Blt_Uid bltImageMarkerUid; extern Blt_Uid bltTextMarkerUid; extern Blt_Uid bltPolygonMarkerUid; extern Blt_Uid bltWindowMarkerUid; extern Blt_Uid bltXAxisUid; extern Blt_Uid bltYAxisUid; #endif /* _BLT_GRAPH_H */ blt-2.4z.orig/src/bltHash.c0100644000175000017500000011174307524666006014306 0ustar dokodoko /* * bltHash.c -- * * * This module implements an in-memory hash table for the BLT * toolkit. Built upon the Tcl hash table, it adds pool * allocation 64-bit address handling, improved array hash * function. * * Copyright 2001 Silicon Metrics Corporation. * * 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. * * Silicon Metrics 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. * * Bob Jenkins, 1996. hash.c. Public Domain. * Bob Jenkins, 1997. lookup8.c. Public Domain. * * Copyright (c) 1991-1993 The Regents of the University of California. * Copyright (c) 1994 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * RCS: @(#) $Id: bltHash.c,v 1.10 2002/08/09 07:15:18 ghowlett Exp $ */ #include #include #include /* The following header is required for LP64 compilation */ #include #include "bltHash.h" /* * When there are this many entries per bucket, on average, rebuild * the hash table to make it larger. */ #define REBUILD_MULTIPLIER 3 #if (SIZEOF_VOID_P == 8) #define RANDOM_INDEX HashOneWord #define DOWNSHIFT_START 62 #else /* * The following macro takes a preliminary integer hash value and * produces an index into a hash tables bucket list. The idea is * to make it so that preliminary values that are arbitrarily similar * will end up in different buckets. The hash function was taken * from a random-number generator. */ #define RANDOM_INDEX(tablePtr, i) \ (((((long) (i))*1103515245) >> (tablePtr)->downShift) & (tablePtr)->mask) #define DOWNSHIFT_START 28 #endif /* * Procedure prototypes for static procedures in this file: */ static Blt_Hash HashArray _ANSI_ARGS_((CONST void *key, size_t length)); static Blt_HashEntry *ArrayFind _ANSI_ARGS_((Blt_HashTable *tablePtr, CONST void *key)); static Blt_HashEntry *ArrayCreate _ANSI_ARGS_((Blt_HashTable *tablePtr, CONST void *key, int *newPtr)); static Blt_HashEntry *BogusFind _ANSI_ARGS_((Blt_HashTable *tablePtr, CONST void *key)); static Blt_HashEntry *BogusCreate _ANSI_ARGS_((Blt_HashTable *tablePtr, CONST void *key, int *newPtr)); static Blt_Hash HashString _ANSI_ARGS_((CONST char *string)); static void RebuildTable _ANSI_ARGS_((Blt_HashTable *tablePtr)); static Blt_HashEntry *StringFind _ANSI_ARGS_((Blt_HashTable *tablePtr, CONST void *key)); static Blt_HashEntry *StringCreate _ANSI_ARGS_((Blt_HashTable *tablePtr, CONST void *key, int *newPtr)); static Blt_HashEntry *OneWordFind _ANSI_ARGS_((Blt_HashTable *tablePtr, CONST void *key)); static Blt_HashEntry *OneWordCreate _ANSI_ARGS_((Blt_HashTable *tablePtr, CONST void *key, int *newPtr)); #if (SIZEOF_VOID_P == 8) static Blt_Hash HashOneWord _ANSI_ARGS_((Blt_HashTable *tablePtr, CONST void *key)); #endif /* SIZEOF_VOID_P == 8 */ /* *---------------------------------------------------------------------- * * HashString -- * * Compute a one-word summary of a text string, which can be * used to generate a hash index. * * Results: * The return value is a one-word summary of the information in * string. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Blt_Hash HashString(register CONST char *string) /* String from which to * compute hash value. */ { register Blt_Hash result; register Blt_Hash c; /* * I tried a zillion different hash functions and asked many other * people for advice. Many people had their own favorite functions, * all different, but no-one had much idea why they were good ones. * I chose the one below (multiply by 9 and add new character) * because of the following reasons: * * 1. Multiplying by 10 is perfect for keys that are decimal strings, * and multiplying by 9 is just about as good. * 2. Times-9 is (shift-left-3) plus (old). This means that each * character's bits hang around in the low-order bits of the * hash value for ever, plus they spread fairly rapidly up to * the high-order bits to fill out the hash value. This seems * to work well both for decimal and non-decimal strings. */ result = 0; while ((c = *string++) != 0) { result += (result << 3) + c; } return (Blt_Hash)result; } /* *---------------------------------------------------------------------- * * StringFind -- * * Given a hash table with string keys, and a string key, find * the entry with a matching key. * * Results: * The return value is a token for the matching entry in the * hash table, or NULL if there was no matching entry. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Blt_HashEntry * StringFind( Blt_HashTable *tablePtr, /* Table in which to lookup entry. */ CONST void *key) /* Key to use to find matching entry. */ { Blt_Hash hval; register Blt_HashEntry *hPtr; size_t hindex; hval = HashString((char *)key); hindex = hval & tablePtr->mask; /* * Search all of the entries in the appropriate bucket. */ for (hPtr = tablePtr->buckets[hindex]; hPtr != NULL; hPtr = hPtr->nextPtr) { if (hPtr->hval == hval) { register CONST char *p1, *p2; for (p1 = key, p2 = hPtr->key.string; ; p1++, p2++) { if (*p1 != *p2) { break; } if (*p1 == '\0') { return hPtr; } } } } return NULL; } /* *---------------------------------------------------------------------- * * StringCreate -- * * Given a hash table with string keys, and a string key, find * the entry with a matching key. If there is no matching entry, * then create a new entry that does match. * * Results: * The return value is a pointer to the matching entry. If this * is a newly-created entry, then *newPtr will be set to a non-zero * value; otherwise *newPtr will be set to 0. If this is a new * entry the value stored in the entry will initially be 0. * * Side effects: * A new entry may be added to the hash table. * *---------------------------------------------------------------------- */ static Blt_HashEntry * StringCreate( Blt_HashTable *tablePtr, /* Table in which to lookup entry. */ CONST void *key, /* Key to use to find or create matching * entry. */ int *newPtr) /* Store info here telling whether a new * entry was created. */ { Blt_Hash hval; Blt_HashEntry **bucketPtr; register Blt_HashEntry *hPtr; size_t size, hindex; hval = HashString(key); hindex = hval & tablePtr->mask; /* * Search all of the entries in this bucket. */ for (hPtr = tablePtr->buckets[hindex]; hPtr != NULL; hPtr = hPtr->nextPtr) { if (hPtr->hval == hval) { register CONST char *p1, *p2; for (p1 = key, p2 = hPtr->key.string; ; p1++, p2++) { if (*p1 != *p2) { break; } if (*p1 == '\0') { *newPtr = FALSE; return hPtr; } } } } /* * Entry not found. Add a new one to the bucket. */ *newPtr = TRUE; size = sizeof(Blt_HashEntry) + strlen(key) - sizeof(Blt_HashKey) + 1; if (tablePtr->hPool != NULL) { hPtr = Blt_PoolAllocItem(tablePtr->hPool, size); } else { hPtr = Blt_Malloc(size); } bucketPtr = tablePtr->buckets + hindex; hPtr->nextPtr = *bucketPtr; hPtr->hval = hval; hPtr->clientData = 0; strcpy(hPtr->key.string, key); *bucketPtr = hPtr; tablePtr->numEntries++; /* * If the table has exceeded a decent size, rebuild it with many * more buckets. */ if (tablePtr->numEntries >= tablePtr->rebuildSize) { RebuildTable(tablePtr); } return hPtr; } #if (SIZEOF_VOID_P == 8) /* *---------------------------------------------------------------------- * * HashOneWord -- * * Compute a one-word hash value of a 64-bit word, which then can * be used to generate a hash index. * * From Knuth, it's a multiplicative hash. Multiplies an unsigned * 64-bit value with the golden ratio (sqrt(5) - 1) / 2. The * downshift value is 64 - n, when n is the log2 of the size of * the hash table. * * Results: * The return value is a one-word summary of the information in * 64 bit word. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Blt_Hash HashOneWord( Blt_HashTable *tablePtr, CONST void *key) { uint64_t a0, a1; uint64_t y0, y1; uint64_t y2, y3; uint64_t p1, p2; uint64_t result; /* Compute key * GOLDEN_RATIO in 128-bit arithmetic */ a0 = (uint64_t)key & 0x00000000FFFFFFFF; a1 = (uint64_t)key >> 32; y0 = a0 * 0x000000007f4a7c13; y1 = a0 * 0x000000009e3779b9; y2 = a1 * 0x000000007f4a7c13; y3 = a1 * 0x000000009e3779b9; y1 += y0 >> 32; /* Can't carry */ y1 += y2; /* Might carry */ if (y1 < y2) { y3 += (1LL << 32); /* Propagate */ } /* 128-bit product: p1 = loword, p2 = hiword */ p1 = ((y1 & 0x00000000FFFFFFFF) << 32) + (y0 & 0x00000000FFFFFFFF); p2 = y3 + (y1 >> 32); /* Left shift the value downward by the size of the table */ if (tablePtr->downShift > 0) { if (tablePtr->downShift < 64) { result = ((p2 << (64 - tablePtr->downShift)) | (p1 >> (tablePtr->downShift & 63))); } else { result = p2 >> (tablePtr->downShift & 63); } } else { result = p1; } /* Finally mask off the high bits */ return (Blt_Hash)(result & tablePtr->mask); } #endif /* SIZEOF_VOID_P == 8 */ /* *---------------------------------------------------------------------- * * OneWordFind -- * * Given a hash table with one-word keys, and a one-word key, * find the entry with a matching key. * * Results: * The return value is a token for the matching entry in the * hash table, or NULL if there was no matching entry. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Blt_HashEntry * OneWordFind( Blt_HashTable *tablePtr, /* Table in which to lookup entry. */ register CONST void *key) /* Key to use to find matching entry. */ { register Blt_HashEntry *hPtr; size_t hindex; hindex = RANDOM_INDEX(tablePtr, key); /* * Search all of the entries in the appropriate bucket. */ for (hPtr = tablePtr->buckets[hindex]; hPtr != NULL; hPtr = hPtr->nextPtr) { if (hPtr->key.oneWordValue == key) { return hPtr; } } return NULL; } /* *---------------------------------------------------------------------- * * OneWordCreate -- * * Given a hash table with one-word keys, and a one-word key, find * the entry with a matching key. If there is no matching entry, * then create a new entry that does match. * * Results: * The return value is a pointer to the matching entry. If this * is a newly-created entry, then *newPtr will be set to a non-zero * value; otherwise *newPtr will be set to 0. If this is a new * entry the value stored in the entry will initially be 0. * * Side effects: * A new entry may be added to the hash table. * *---------------------------------------------------------------------- */ static Blt_HashEntry * OneWordCreate( Blt_HashTable *tablePtr, /* Table in which to lookup entry. */ CONST void *key, /* Key to use to find or create matching * entry. */ int *newPtr) /* Store info here telling whether a new * entry was created. */ { Blt_HashEntry **bucketPtr; register Blt_HashEntry *hPtr; size_t hindex; hindex = RANDOM_INDEX(tablePtr, key); /* * Search all of the entries in this bucket. */ for (hPtr = tablePtr->buckets[hindex]; hPtr != NULL; hPtr = hPtr->nextPtr) { if (hPtr->key.oneWordValue == key) { *newPtr = FALSE; return hPtr; } } /* * Entry not found. Add a new one to the bucket. */ *newPtr = TRUE; if (tablePtr->hPool != NULL) { hPtr = Blt_PoolAllocItem(tablePtr->hPool, sizeof(Blt_HashEntry)); } else { hPtr = Blt_Malloc(sizeof(Blt_HashEntry)); } bucketPtr = tablePtr->buckets + hindex; hPtr->nextPtr = *bucketPtr; hPtr->hval = (Blt_Hash)key; hPtr->clientData = 0; hPtr->key.oneWordValue = (void *)key; /* CONST XXXX */ *bucketPtr = hPtr; tablePtr->numEntries++; /* * If the table has exceeded a decent size, rebuild it with many * more buckets. */ if (tablePtr->numEntries >= tablePtr->rebuildSize) { RebuildTable(tablePtr); } return hPtr; } #if (SIZEOF_VOID_P == 4) /* * -------------------------------------------------------------------- * * MIX32 -- * * Bob Jenkins, 1996. Public Domain. * * Mix 3 32/64-bit values reversibly. For every delta with one or * two bit set, and the deltas of all three high bits or all * three low bits, whether the original value of a,b,c is almost * all zero or is uniformly distributed, If mix() is run * forward or backward, at least 32 bits in a,b,c have at least * 1/4 probability of changing. * If mix() is run forward, every * bit of c will change between 1/3 and 2/3 of the time. (Well, * 22/100 and 78/100 for some 2-bit deltas.) mix() was built out * of 36 single-cycle latency instructions in a structure that * could supported 2x parallelism, like so: * * a -= b; * a -= c; x = (c>>13); * b -= c; a ^= x; * b -= a; x = (a<<8); * c -= a; b ^= x; * c -= b; x = (b>>13); * ... * * Unfortunately, superscalar Pentiums and Sparcs can't take * advantage of that parallelism. They've also turned some of * those single-cycle latency instructions into multi-cycle * latency instructions. Still, this is the fastest good hash I * could find. There were about 2^^68 to choose from. I only * looked at a billion or so. * * -------------------------------------------------------------------- */ #define MIX32(a,b,c) \ a -= b, a -= c, a ^= (c >> 13), \ b -= c, b -= a, b ^= (a << 8), \ c -= a, c -= b, c ^= (b >> 13), \ a -= b, a -= c, a ^= (c >> 12), \ b -= c, b -= a, b ^= (a << 16), \ c -= a, c -= b, c ^= (b >> 5), \ a -= b, a -= c, a ^= (c >> 3), \ b -= c, b -= a, b ^= (a << 10), \ c -= a, c -= b, c ^= (b >> 15) #define GOLDEN_RATIO32 0x9e3779b9 /* An arbitrary value */ /* * -------------------------------------------------------------------- * * HashArray -- * * Bob Jenkins, 1996. Public Domain. * * This works on all machines. Length has to be measured in * unsigned longs instead of bytes. It requires that * * o The key be an array of unsigned ints. * o All your machines have the same endianness * o The length be the number of unsigned ints in the key. * * -------------------------------------------------------------------- */ static Blt_Hash HashArray( CONST void *key, size_t length) /* Length of the key in 32-bit words */ { register uint32_t a, b, c, len; register uint32_t *arrayPtr = (uint32_t *)key; /* Set up the internal state */ len = length; a = b = GOLDEN_RATIO32; /* An arbitrary value */ c = 0; /* Previous hash value */ while (len >= 3) { /* Handle most of the key */ a += arrayPtr[0]; b += arrayPtr[1]; c += arrayPtr[2]; MIX32(a, b, c); arrayPtr += 3; len -= 3; } c += length; /* And now the last 2 words */ /* Note that all the case statements fall through */ switch(len) { /* c is reserved for the length */ case 2 : b += arrayPtr[1]; case 1 : a += arrayPtr[0]; /* case 0: nothing left to add */ } MIX32(a, b, c); return (Blt_Hash)c; } #endif /* SIZEOF_VOID_P == 4 */ #if (SIZEOF_VOID_P == 8) /* * -------------------------------------------------------------------- * * MIX64 -- * * Bob Jenkins, January 4 1997, Public Domain. You can use * this free for any purpose. It has no warranty. * * Returns a 64-bit value. Every bit of the key affects every * bit of the return value. No funnels. Every 1-bit and 2-bit * delta achieves avalanche. About 41+5len instructions. * * The best hash table sizes are powers of 2. There is no need * to do mod a prime (mod is sooo slow!). If you need less than * 64 bits, use a bitmask. For example, if you need only 10 * bits, do h = (h & hashmask(10)); In which case, the hash table * should have hashsize(10) elements. * * By Bob Jenkins, Jan 4 1997. bob_jenkins@burtleburtle.net. * You may use this code any way you wish, private, educational, * or commercial, as long as this whole comment accompanies it. * * See http://burtleburtle.net/bob/hash/evahash.html * Use for hash table lookup, or anything where one collision in * 2^^64 * is acceptable. Do NOT use for cryptographic purposes. * * -------------------------------------------------------------------- */ #define MIX64(a,b,c) \ a -= b, a -= c, a ^= (c >> 43), \ b -= c, b -= a, b ^= (a << 9), \ c -= a, c -= b, c ^= (b >> 8), \ a -= b, a -= c, a ^= (c >> 38), \ b -= c, b -= a, b ^= (a << 23), \ c -= a, c -= b, c ^= (b >> 5), \ a -= b, a -= c, a ^= (c >> 35), \ b -= c, b -= a, b ^= (a << 49), \ c -= a, c -= b, c ^= (b >> 11), \ a -= b, a -= c, a ^= (c >> 12), \ b -= c, b -= a, b ^= (a << 18), \ c -= a, c -= b, c ^= (b >> 22) #define GOLDEN_RATIO64 0x9e3779b97f4a7c13LL /* * -------------------------------------------------------------------- * * HashArray -- * * Bob Jenkins, January 4 1997, Public Domain. You can use * this free for any purpose. It has no warranty. * * This works on all machines. The length has to be measured in * 64 bit words, instead of bytes. It requires that * * o The key be an array of 64 bit words (unsigned longs). * o All your machines have the same endianness. * o The length be the number of 64 bit words in the key. * * -------------------------------------------------------------------- */ static Blt_Hash HashArray( CONST void *key, size_t length) /* Length of key in 32-bit words. */ { register uint64_t a, b, c, len; register uint32_t *iPtr = (uint32_t *)key; #ifdef WORDS_BIGENDIAN #define PACK(a,b) ((uint64_t)(b) | ((uint64_t)(a) << 32)) #else #define PACK(a,b) ((uint64_t)(a) | ((uint64_t)(b) << 32)) #endif /* Set up the internal state */ len = length; /* Length is the number of 64-bit words. */ a = b = GOLDEN_RATIO64; /* An arbitrary value */ c = 0; /* Previous hash value */ while (len >= 6) { /* Handle most of the key */ a += PACK(iPtr[0], iPtr[1]); b += PACK(iPtr[2], iPtr[3]); c += PACK(iPtr[4], iPtr[5]); MIX64(a,b,c); iPtr += 6; len -= 6; } c += length; /* And now the last 2 words */ /* Note that all the case statements fall through */ switch(len) { /* c is reserved for the length */ case 5 : case 4 : a += PACK(iPtr[0], iPtr[1]); b += PACK(iPtr[2], iPtr[3]); iPtr += 4; len -= 4; break; case 3 : case 2 : a += PACK(iPtr[0], iPtr[1]); iPtr += 2; len -= 2; /* case 0: nothing left to add */ } if (len > 0) { b += iPtr[0]; } MIX64(a,b,c); return (Blt_Hash)c; } #endif /* SIZEOF_VOID_P == 8 */ /* *---------------------------------------------------------------------- * * ArrayFind -- * * Given a hash table with array-of-int keys, and a key, find * the entry with a matching key. * * Results: * The return value is a token for the matching entry in the * hash table, or NULL if there was no matching entry. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Blt_HashEntry * ArrayFind( Blt_HashTable *tablePtr, /* Table in which to lookup entry. */ CONST void *key) /* Key to use to find matching entry. */ { Blt_Hash hval; register Blt_HashEntry *hPtr; size_t hindex; hval = HashArray(key, tablePtr->keyType); hindex = hval & tablePtr->mask; /* * Search all of the entries in the appropriate bucket. */ for (hPtr = tablePtr->buckets[hindex]; hPtr != NULL; hPtr = hPtr->nextPtr) { if (hPtr->hval == hval) { register unsigned int *iPtr1, *iPtr2; unsigned int count; for (iPtr1 = (uint32_t *)key, iPtr2 = (uint32_t *)hPtr->key.words, count = tablePtr->keyType; ; count--, iPtr1++, iPtr2++) { if (count == 0) { return hPtr; } if (*iPtr1 != *iPtr2) { break; } } } } return NULL; } /* *---------------------------------------------------------------------- * * ArrayCreate -- * * Given a hash table with one-word keys, and a one-word key, find * the entry with a matching key. If there is no matching entry, * then create a new entry that does match. * * Results: * The return value is a pointer to the matching entry. If this * is a newly-created entry, then *newPtr will be set to a non-zero * value; otherwise *newPtr will be set to 0. If this is a new * entry the value stored in the entry will initially be 0. * * Side effects: * A new entry may be added to the hash table. * *---------------------------------------------------------------------- */ static Blt_HashEntry * ArrayCreate( Blt_HashTable *tablePtr, /* Table in which to lookup entry. */ register CONST void *key, /* Key to use to find or create matching * entry. */ int *newPtr) /* Store info here telling whether a new * entry was created. */ { Blt_Hash hval; Blt_HashEntry **bucketPtr; int count; register Blt_HashEntry *hPtr; register uint32_t *iPtr1, *iPtr2; size_t size, hindex; hval = HashArray(key, tablePtr->keyType); hindex = hval & tablePtr->mask; /* * Search all of the entries in the appropriate bucket. */ for (hPtr = tablePtr->buckets[hindex]; hPtr != NULL; hPtr = hPtr->nextPtr) { if (hPtr->hval == hval) { for (iPtr1 = (uint32_t *)key, iPtr2 = (uint32_t *)hPtr->key.words, count = tablePtr->keyType; ; count--, iPtr1++, iPtr2++) { if (count == 0) { *newPtr = FALSE; return hPtr; } if (*iPtr1 != *iPtr2) { break; } } } } /* * Entry not found. Add a new one to the bucket. */ *newPtr = TRUE; /* We assume here that the size of the key is at least 2 words */ size = sizeof(Blt_HashEntry) + tablePtr->keyType * sizeof(uint32_t) - sizeof(Blt_HashKey); if (tablePtr->hPool != NULL) { hPtr = Blt_PoolAllocItem(tablePtr->hPool, size); } else { hPtr = Blt_Malloc(size); } bucketPtr = tablePtr->buckets + hindex; hPtr->nextPtr = *bucketPtr; hPtr->hval = hval; hPtr->clientData = 0; count = tablePtr->keyType; for (iPtr1 = (uint32_t *)key, iPtr2 = (uint32_t *)hPtr->key.words; count > 0; count--, iPtr1++, iPtr2++) { *iPtr2 = *iPtr1; } *bucketPtr = hPtr; tablePtr->numEntries++; /* * If the table has exceeded a decent size, rebuild it with many * more buckets. */ if (tablePtr->numEntries >= tablePtr->rebuildSize) { RebuildTable(tablePtr); } return hPtr; } /* *---------------------------------------------------------------------- * * BogusFind -- * * This procedure is invoked when an Blt_FindHashEntry is called * on a table that has been deleted. * * Results: * If panic returns (which it shouldn't) this procedure returns * NULL. * * Side effects: * Generates a panic. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static Blt_HashEntry * BogusFind( Blt_HashTable *tablePtr, /* Table in which to lookup entry. */ CONST void *key) /* Key to use to find matching entry. */ { Blt_Panic("called Blt_FindHashEntry on deleted table"); return NULL; } /* *---------------------------------------------------------------------- * * BogusCreate -- * * This procedure is invoked when an Blt_CreateHashEntry is called * on a table that has been deleted. * * Results: * If panic returns (which it shouldn't) this procedure returns * NULL. * * Side effects: * Generates a panic. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static Blt_HashEntry * BogusCreate( Blt_HashTable *tablePtr, /* Table in which to lookup entry. */ CONST void *key, /* Key to use to find or create matching * entry. */ int *newPtr) /* Store info here telling whether a new * entry was created. */ { Blt_Panic("called Blt_CreateHashEntry on deleted table"); return NULL; } /* *---------------------------------------------------------------------- * * RebuildTable -- * * This procedure is invoked when the ratio of entries to hash * buckets becomes too large. It creates a new table with a * larger bucket array and moves all of the entries into the * new table. * * Results: * None. * * Side effects: * Memory gets reallocated and entries get re-hashed to new * buckets. * *---------------------------------------------------------------------- */ static void RebuildTable(Blt_HashTable *tablePtr) /* Table to enlarge. */ { Blt_HashEntry **bucketPtr, **oldBuckets; register Blt_HashEntry **oldChainPtr, **endPtr; register Blt_HashEntry *hPtr, *nextPtr; size_t hindex; oldBuckets = tablePtr->buckets; endPtr = tablePtr->buckets + tablePtr->numBuckets; /* * Allocate and initialize the new bucket array, and set up * hashing constants for new array size. */ tablePtr->numBuckets <<= 2; tablePtr->buckets = Blt_Calloc(tablePtr->numBuckets, sizeof(Blt_HashEntry *)); tablePtr->rebuildSize <<= 2; tablePtr->downShift -= 2; tablePtr->mask = tablePtr->numBuckets - 1; /* * Move all of the existing entries into the new bucket array, * based on their hash values. */ if (tablePtr->keyType == BLT_ONE_WORD_KEYS) { /* * BLT_ONE_WORD_KEYS are handled slightly differently because * they use the current table size (number of buckets) to be * distributed. */ for (oldChainPtr = oldBuckets; oldChainPtr < endPtr; oldChainPtr++) { for (hPtr = *oldChainPtr; hPtr != NULL; hPtr = nextPtr) { nextPtr = hPtr->nextPtr; hindex = RANDOM_INDEX(tablePtr, hPtr->key.oneWordValue); bucketPtr = tablePtr->buckets + hindex; hPtr->nextPtr = *bucketPtr; *bucketPtr = hPtr; } } } else { for (oldChainPtr = oldBuckets; oldChainPtr < endPtr; oldChainPtr++) { for (hPtr = *oldChainPtr; hPtr != NULL; hPtr = nextPtr) { nextPtr = hPtr->nextPtr; hindex = hPtr->hval & tablePtr->mask; bucketPtr = tablePtr->buckets + hindex; hPtr->nextPtr = *bucketPtr; *bucketPtr = hPtr; } } } /* * Free up the old bucket array, if it was dynamically allocated. */ if (oldBuckets != tablePtr->staticBuckets) { Blt_Free(oldBuckets); } } /* Public hash table routines */ /* *---------------------------------------------------------------------- * * Blt_InitHashTable -- * * Given storage for a hash table, set up the fields to prepare * the hash table for use. * * Results: * None. * * Side effects: * TablePtr is now ready to be passed to Blt_FindHashEntry and * Blt_CreateHashEntry. * *---------------------------------------------------------------------- */ void Blt_InitHashTable( register Blt_HashTable *tablePtr, /* Pointer to table record, which * is supplied by the caller. */ size_t keyType) /* Type of keys to use in table. */ { #if (BLT_SMALL_HASH_TABLE != 4) Blt_Panic("Blt_InitHashTable: BLT_SMALL_HASH_TABLE is %d, not 4\n", BLT_SMALL_HASH_TABLE); #endif tablePtr->buckets = tablePtr->staticBuckets; tablePtr->numBuckets = BLT_SMALL_HASH_TABLE; tablePtr->staticBuckets[0] = tablePtr->staticBuckets[1] = 0; tablePtr->staticBuckets[2] = tablePtr->staticBuckets[3] = 0; tablePtr->numEntries = 0; tablePtr->rebuildSize = BLT_SMALL_HASH_TABLE * REBUILD_MULTIPLIER; tablePtr->downShift = DOWNSHIFT_START; /* The number of buckets is always a power of 2, so we can * generate the mask by simply subtracting 1 from the number of * buckets. */ tablePtr->mask = (Blt_Hash)(tablePtr->numBuckets - 1); tablePtr->keyType = keyType; switch (keyType) { case BLT_STRING_KEYS: /* NUL terminated string keys. */ tablePtr->findProc = StringFind; tablePtr->createProc = StringCreate; break; case BLT_ONE_WORD_KEYS: /* 32 or 64 bit atomic keys. */ tablePtr->findProc = OneWordFind; tablePtr->createProc = OneWordCreate; break; default: /* Structures/arrays. */ if (keyType == 0) { Blt_Panic("Blt_InitHashTable: Key size can't be %d, must be > 0\n", keyType); } tablePtr->findProc = ArrayFind; tablePtr->createProc = ArrayCreate; break; } tablePtr->hPool = NULL; } /* *---------------------------------------------------------------------- * * Blt_InitHashTableWithPool -- * * Given storage for a hash table, set up the fields to prepare * the hash table for use. The only difference between this * routine and Blt_InitHashTable is that is uses a pool allocator * to allocate memory for hash table entries. The type of pool * is either fixed or variable size (string) keys. * * Results: * None. * * Side effects: * TablePtr is now ready to be passed to Blt_FindHashEntry and * Blt_CreateHashEntry. * *---------------------------------------------------------------------- */ void Blt_InitHashTableWithPool( register Blt_HashTable *tablePtr, /* Pointer to table record, which * is supplied by the caller. */ size_t keyType) /* Type of keys to use in table. */ { Blt_InitHashTable(tablePtr, keyType); if (keyType == BLT_STRING_KEYS) { tablePtr->hPool = Blt_PoolCreate(BLT_VARIABLE_SIZE_ITEMS); } else { tablePtr->hPool = Blt_PoolCreate(BLT_FIXED_SIZE_ITEMS); } } /* *---------------------------------------------------------------------- * * Blt_DeleteHashEntry -- * * Remove a single entry from a hash table. * * Results: * None. * * Side effects: * The entry given by entryPtr is deleted from its table and * should never again be used by the caller. It is up to the * caller to free the clientData field of the entry, if that * is relevant. * *---------------------------------------------------------------------- */ void Blt_DeleteHashEntry( Blt_HashTable *tablePtr, Blt_HashEntry *entryPtr) { register Blt_HashEntry *prevPtr; Blt_HashEntry **bucketPtr; size_t hindex; if (tablePtr->keyType == BLT_ONE_WORD_KEYS) { hindex = RANDOM_INDEX(tablePtr, (CONST void *)entryPtr->hval); } else { hindex = (entryPtr->hval & tablePtr->mask); } bucketPtr = tablePtr->buckets + hindex; if (*bucketPtr == entryPtr) { *bucketPtr = entryPtr->nextPtr; } else { for (prevPtr = *bucketPtr; /*empty*/; prevPtr = prevPtr->nextPtr) { if (prevPtr == NULL) { Blt_Panic("malformed bucket chain in Blt_DeleteHashEntry"); } if (prevPtr->nextPtr == entryPtr) { prevPtr->nextPtr = entryPtr->nextPtr; break; } } } tablePtr->numEntries--; if (tablePtr->hPool != NULL) { Blt_PoolFreeItem(tablePtr->hPool, (char *)entryPtr); } else { Blt_Free(entryPtr); } } /* *---------------------------------------------------------------------- * * Blt_DeleteHashTable -- * * Free up everything associated with a hash table except for * the record for the table itself. * * Results: * None. * * Side effects: * The hash table is no longer useable. * *---------------------------------------------------------------------- */ void Blt_DeleteHashTable(Blt_HashTable *tablePtr) /* Table to delete. */ { /* * Free up all the entries in the table. */ if (tablePtr->hPool != NULL) { Blt_PoolDestroy(tablePtr->hPool); tablePtr->hPool = NULL; } else { register Blt_HashEntry *hPtr, *nextPtr; size_t i; for (i = 0; i < tablePtr->numBuckets; i++) { hPtr = tablePtr->buckets[i]; while (hPtr != NULL) { nextPtr = hPtr->nextPtr; Blt_Free(hPtr); hPtr = nextPtr; } } } /* * Free up the bucket array, if it was dynamically allocated. */ if (tablePtr->buckets != tablePtr->staticBuckets) { Blt_Free(tablePtr->buckets); } /* * Arrange for panics if the table is used again without * re-initialization. */ tablePtr->findProc = BogusFind; tablePtr->createProc = BogusCreate; } /* *---------------------------------------------------------------------- * * Blt_FirstHashEntry -- * * Locate the first entry in a hash table and set up a record * that can be used to step through all the remaining entries * of the table. * * Results: * The return value is a pointer to the first entry in tablePtr, * or NULL if tablePtr has no entries in it. The memory at * *searchPtr is initialized so that subsequent calls to * Blt_NextHashEntry will return all of the entries in the table, * one at a time. * * Side effects: * None. * *---------------------------------------------------------------------- */ Blt_HashEntry * Blt_FirstHashEntry( Blt_HashTable *tablePtr, /* Table to search. */ Blt_HashSearch *searchPtr) /* Place to store information about * progress through the table. */ { searchPtr->tablePtr = tablePtr; searchPtr->nextIndex = 0; searchPtr->nextEntryPtr = NULL; return Blt_NextHashEntry(searchPtr); } /* *---------------------------------------------------------------------- * * Blt_NextHashEntry -- * * Once a hash table enumeration has been initiated by calling * Blt_FirstHashEntry, this procedure may be called to return * successive elements of the table. * * Results: * The return value is the next entry in the hash table being * enumerated, or NULL if the end of the table is reached. * * Side effects: * None. * *---------------------------------------------------------------------- */ Blt_HashEntry * Blt_NextHashEntry(Blt_HashSearch *searchPtr) { Blt_HashEntry *hPtr; while (searchPtr->nextEntryPtr == NULL) { if (searchPtr->nextIndex >= searchPtr->tablePtr->numBuckets) { return NULL; } searchPtr->nextEntryPtr = searchPtr->tablePtr->buckets[searchPtr->nextIndex]; searchPtr->nextIndex++; } hPtr = searchPtr->nextEntryPtr; searchPtr->nextEntryPtr = hPtr->nextPtr; return hPtr; } /* *---------------------------------------------------------------------- * * Blt_HashStats -- * * Return statistics describing the layout of the hash table * in its hash buckets. * * Results: * The return value is a malloc-ed string containing information * about tablePtr. It is the caller's responsibility to free * this string. * * Side effects: * None. * *---------------------------------------------------------------------- */ char * Blt_HashStats(Blt_HashTable *tablePtr) /* Table for which to produce stats. */ { #define NUM_COUNTERS 10 size_t count[NUM_COUNTERS], overflow, i, j, max; double average, tmp; register Blt_HashEntry *hPtr; Blt_HashEntry **bucketPtr, **endPtr; char *result, *p; /* * Compute a histogram of bucket usage. */ for (i = 0; i < NUM_COUNTERS; i++) { count[i] = 0; } overflow = 0; average = 0.0; max = 0; endPtr = tablePtr->buckets + tablePtr->numBuckets; for (bucketPtr = tablePtr->buckets; bucketPtr < endPtr; bucketPtr++) { j = 0; for (hPtr = *bucketPtr; hPtr != NULL; hPtr = hPtr->nextPtr) { j++; } if (j > max) { max = j; } if (j < NUM_COUNTERS) { count[j]++; } else { overflow++; } tmp = j; average += (tmp+1.0)*(tmp/tablePtr->numEntries)/2.0; } /* * Print out the histogram and a few other pieces of information. */ result = Blt_Malloc((unsigned) ((NUM_COUNTERS*60) + 300)); #if SIZEOF_VOID_P == 8 sprintf(result, "%ld entries in table, %ld buckets\n", tablePtr->numEntries, tablePtr->numBuckets); #else sprintf(result, "%d entries in table, %d buckets\n", tablePtr->numEntries, tablePtr->numBuckets); #endif p = result + strlen(result); for (i = 0; i < NUM_COUNTERS; i++) { #if SIZEOF_VOID_P == 8 sprintf(p, "number of buckets with %ld entries: %ld\n", i, count[i]); #else sprintf(p, "number of buckets with %d entries: %d\n", i, count[i]); #endif p += strlen(p); } #if SIZEOF_VOID_P == 8 sprintf(p, "number of buckets with %d or more entries: %ld\n", NUM_COUNTERS, overflow); #else sprintf(p, "number of buckets with %d or more entries: %d\n", NUM_COUNTERS, overflow); #endif p += strlen(p); sprintf(p, "average search distance for entry: %.2f\n", average); p += strlen(p); #if SIZEOF_VOID_P == 8 sprintf(p, "maximum search distance for entry: %ld", max); #else sprintf(p, "maximum search distance for entry: %d", max); #endif return result; } blt-2.4z.orig/src/bltHash.h.in0100644000175000017500000001607307514140355014711 0ustar dokodoko /* * bltHash.h -- * * Copyright 2001 Silicon Metrics Corporation. * * 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. * * Silicon Metrics 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. * * Bob Jenkins, 1996. hash.c. Public Domain. * Bob Jenkins, 1997. lookup8.c. Public Domain. * * Copyright (c) 1991-1993 The Regents of the University of California. * Copyright (c) 1994 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * RCS: @(#) $Id: bltHash.h.in,v 1.5 2002/07/14 00:08:13 ghowlett Exp $ */ #ifndef BLT_HASH_H #define BLT_HASH_H 1 #ifndef BLT_INT_H #ifndef SIZEOF_LONG #define SIZEOF_LONG @SIZEOF_LONG@ #endif #ifndef SIZEOF_LONG_LONG #define SIZEOF_LONG_LONG @SIZEOF_LONG_LONG@ #endif #ifndef SIZEOF_INT #define SIZEOF_INT @SIZEOF_INT@ #endif #ifndef SIZEOF_VOID_P #define SIZEOF_VOID_P @SIZEOF_VOID_P@ #endif #ifndef HAVE_INTTYPES_H #if @HAVE_INTTYPES_H@ #define HAVE_INTTYPES_H 1 #endif #endif #endif /* !BLT_INT_H */ #ifdef HAVE_INTTYPES_H #include #else #if (SIZEOF_VOID_P == 8) #if (SIZEOF_LONG == 8) typedef signed long int64_t; typedef unsigned long uint64_t; #else typedef signed long long int64_t; typedef unsigned long long uint64_t; #endif /* SIZEOF_LONG == 8 */ #else #ifndef __CYGWIN__ typedef signed int int32_t; #endif /* __CYGWIN__ */ typedef unsigned int uint32_t; #endif /* SIZEOF_VOID_P == 8 */ #endif /* HAVE_INTTYPES_H */ #if (SIZEOF_VOID_P == 8) typedef uint64_t Blt_Hash; #else typedef uint32_t Blt_Hash; #endif /* SIZEOF_VOID_P == 8 */ #include "bltPool.h" /* * Acceptable key types for hash tables: */ #define BLT_STRING_KEYS 0 #define BLT_ONE_WORD_KEYS ((size_t)-1) /* * Forward declaration of Blt_HashTable. Needed by some C++ compilers * to prevent errors when the forward reference to Blt_HashTable is * encountered in the Blt_HashEntry structure. */ #ifdef __cplusplus struct Blt_HashTable; #endif typedef union { /* Key has one of these forms: */ void *oneWordValue; /* One-word value for key. */ unsigned long words[1]; /* Multiple integer words for key. * The actual size will be as large * as necessary for this table's * keys. */ char string[4]; /* String for key. The actual size * will be as large as needed to hold * the key. */ } Blt_HashKey; /* * Structure definition for an entry in a hash table. No-one outside * Blt should access any of these fields directly; use the macros * defined below. */ typedef struct Blt_HashEntry { struct Blt_HashEntry *nextPtr; /* Pointer to next entry in this * hash bucket, or NULL for end of * chain. */ Blt_Hash hval; ClientData clientData; /* Application stores something here * with Blt_SetHashValue. */ Blt_HashKey key; /* MUST BE LAST FIELD IN RECORD!! */ } Blt_HashEntry; /* * Structure definition for a hash table. Must be in blt.h so clients * can allocate space for these structures, but clients should never * access any fields in this structure. */ #define BLT_SMALL_HASH_TABLE 4 typedef struct Blt_HashTable { Blt_HashEntry **buckets; /* Pointer to bucket array. Each * element points to first entry in * bucket's hash chain, or NULL. */ Blt_HashEntry *staticBuckets[BLT_SMALL_HASH_TABLE]; /* Bucket array used for small tables * (to avoid mallocs and frees). */ size_t numBuckets; /* Total number of buckets allocated * at **buckets. */ size_t numEntries; /* Total number of entries present * in table. */ size_t rebuildSize; /* Enlarge table when numEntries gets * to be this large. */ Blt_Hash mask; /* Mask value used in hashing * function. */ unsigned int downShift; /* Shift count used in hashing * function. Designed to use high- * order bits of randomized keys. */ size_t keyType; /* Type of keys used in this table. * It's either BLT_STRING_KEYS, * BLT_ONE_WORD_KEYS, or an integer * giving the number of ints that * is the size of the key. */ Blt_HashEntry *(*findProc) _ANSI_ARGS_((struct Blt_HashTable *tablePtr, CONST void *key)); Blt_HashEntry *(*createProc) _ANSI_ARGS_((struct Blt_HashTable *tablePtr, CONST void *key, int *newPtr)); Blt_Pool hPool; /* Pointer to the pool allocator used * for entries in this hash table. If * NULL, the standard Tcl_Alloc, * Tcl_Free routines will be used * instead. */ } Blt_HashTable; /* * Structure definition for information used to keep track of searches * through hash tables: */ typedef struct { Blt_HashTable *tablePtr; /* Table being searched. */ unsigned long nextIndex; /* Index of next bucket to be * enumerated after present one. */ Blt_HashEntry *nextEntryPtr; /* Next entry to be enumerated in the * the current bucket. */ } Blt_HashSearch; /* * Macros for clients to use to access fields of hash entries: */ #define Blt_GetHashValue(h) ((h)->clientData) #define Blt_SetHashValue(h, value) ((h)->clientData = (ClientData)(value)) #define Blt_GetHashKey(tablePtr, h) \ ((void *) (((tablePtr)->keyType == BLT_ONE_WORD_KEYS) ? \ (void *)(h)->key.oneWordValue : (h)->key.string)) /* * Macros to use for clients to use to invoke find and create procedures * for hash tables: */ #define Blt_FindHashEntry(tablePtr, key) \ (*((tablePtr)->findProc))(tablePtr, key) #define Blt_CreateHashEntry(tablePtr, key, newPtr) \ (*((tablePtr)->createProc))(tablePtr, key, newPtr) EXTERN void Blt_InitHashTable _ANSI_ARGS_((Blt_HashTable *tablePtr, size_t keyType)); EXTERN void Blt_InitHashTableWithPool _ANSI_ARGS_((Blt_HashTable *tablePtr, size_t keyType)); EXTERN void Blt_DeleteHashTable _ANSI_ARGS_((Blt_HashTable *tablePtr)); EXTERN void Blt_DeleteHashEntry _ANSI_ARGS_((Blt_HashTable *tablePtr, Blt_HashEntry *entryPtr)); EXTERN Blt_HashEntry *Blt_FirstHashEntry _ANSI_ARGS_((Blt_HashTable *tablePtr, Blt_HashSearch *searchPtr)); EXTERN Blt_HashEntry *Blt_NextHashEntry _ANSI_ARGS_((Blt_HashSearch *srchPtr)); EXTERN char *Blt_HashStats _ANSI_ARGS_((Blt_HashTable *tablePtr)); #endif /* BLT_HASH_H */ blt-2.4z.orig/src/bltHierbox.c0100644000175000017500000074562307542237061015030 0ustar dokodoko /* * bltHierbox.c -- * * This module implements an hierarchy widget for the BLT toolkit. * * Copyright -1998 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 or 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. * * The "hierbox" widget was created by George A. Howlett. */ /* * TODO: * * BUGS: * 1. "open" operation should change scroll offset so that as many * new entries (up to half a screen) can be seen. * 2. "open" needs to adjust the scrolloffset so that the same entry * is seen at the same place. */ #include "bltInt.h" #ifndef NO_HIERBOX #include "bltBind.h" #include "bltImage.h" #include "bltHash.h" #include "bltChain.h" #include "bltList.h" #include "bltTile.h" #include #include #if HAVE_UTF #else #define Tcl_NumUtfChars(s,n) (((n) == -1) ? strlen((s)) : (n)) #define Tcl_UtfAtIndex(s,i) ((s) + (i)) #endif #define SEPARATOR_NONE ((char *)-1) #define SEPARATOR_LIST ((char *)NULL) #define APPEND (-1) /* * The macro below is used to modify a "char" value (e.g. by casting * it to an unsigned character) so that it can be used safely with * macros such as isspace. */ #define UCHAR(c) ((unsigned char) (c)) #define APPLY_BEFORE (1<<0) #define APPLY_OPEN_ONLY (1<<1) #define APPLY_RECURSE (1<<2) #define BUTTON_IPAD 1 #define BUTTON_SIZE 7 #define INSET_PAD 2 #define ICON_PADX 2 #define ICON_PADY 1 #define LABEL_PADX 3 #define LABEL_PADY 0 #define FOCUS_WIDTH 1 #define CLAMP(val,low,hi) \ (((val) < (low)) ? (low) : ((val) > (hi)) ? (hi) : (val)) #define ODD(x) ((x) | 0x01) #define TOGGLE(x, mask) \ (((x) & (mask)) ? ((x) & ~(mask)) : ((x) | (mask))) #define VPORTWIDTH(h) (Tk_Width((h)->tkwin) - 2 * (h)->inset) #define VPORTHEIGHT(h) (Tk_Height((h)->tkwin) - 2 * (h)->inset) #define WORLDX(h, sx) ((sx) - (h)->inset + (h)->xOffset) #define WORLDY(h, sy) ((sy) - (h)->inset + (h)->yOffset) #define SCREENX(h, wx) ((wx) - (h)->xOffset + (h)->inset) #define SCREENY(h, wy) ((wy) - (h)->yOffset + (h)->inset) #define LEVELWIDTH(d) (hboxPtr->levelInfo[(d)].width) #define LEVELX(d) (hboxPtr->levelInfo[(d)].x) #define GETFONT(h, f) (((f) == NULL) ? (h)->defFont : (f)) #define GETCOLOR(h, c) (((c) == NULL) ? (h)->defColor : (c)) /* * ---------------------------------------------------------------------------- * * Internal hierarchy widget flags: * * HIERBOX_LAYOUT The layout of the hierarchy needs to be * recomputed. * * HIERBOX_REDRAW A redraw request is pending for the widget. * * HIERBOX_XSCROLL X-scroll request is pending. * HIERBOX_YSCROLL Y-scroll request is pending. * HIERBOX_SCROLL Both X-scroll and Y-scroll requests are * pending. * * HIERBOX_FOCUS The widget is receiving keyboard events. * Draw the focus highlight border around the * widget. * * HIERBOX_DIRTY The hierarchy has changed, possibly invalidating * locations and pointers to entries. This widget * need to recompute its layout. * * HIERBOX_BORDERS The borders of the widget (highlight ring and * 3-D border) need to be redrawn. * * * Selection related flags: * * SELECTION_EXPORT Export the selection to X. * * SELECTION_PENDING A selection command idle task is pending. * * SELECTION_CLEAR Entry's selection flag is to be cleared. * * SELECTION_SET Entry's selection flag is to be set. * * SELECTION_TOGGLE Entry's selection flag is to be toggled. * * SELECTION_MASK Mask of selection set/clear/toggle flags. * * --------------------------------------------------------------------------- */ #define HIERBOX_LAYOUT (1<<0) #define HIERBOX_REDRAW (1<<1) #define HIERBOX_XSCROLL (1<<2) #define HIERBOX_YSCROLL (1<<3) #define HIERBOX_SCROLL (HIERBOX_XSCROLL | HIERBOX_YSCROLL) #define HIERBOX_FOCUS (1<<4) #define HIERBOX_DIRTY (1<<5) #define HIERBOX_BORDERS (1<<6) #define SELECTION_PENDING (1<<15) #define SELECTION_EXPORT (1<<16) #define SELECTION_CLEAR (1<<17) #define SELECTION_SET (1<<18) #define SELECTION_TOGGLE (SELECTION_SET | SELECTION_CLEAR) #define SELECTION_MASK (SELECTION_SET | SELECTION_CLEAR) /* * ------------------------------------------------------------------------- * * Internal entry flags: * * ENTRY_BUTTON Indicates that a button needs to be * drawn for this entry. * * ENTRY_OPEN Indicates that the entry is open and * its subentries should also be displayed. * * ENTRY_MAPPED Indicates that the entry is mapped (i.e. * can be viewed by opening or scrolling. * * BUTTON_AUTO * BUTTON_SHOW * BUTTON_MASK * * ------------------------------------------------------------------------- */ #define ENTRY_BUTTON (1<<0) #define ENTRY_OPEN (1<<2) #define ENTRY_MAPPED (1<<3) #define BUTTON_AUTO (1<<8) #define BUTTON_SHOW (1<<9) #define BUTTON_MASK (BUTTON_AUTO | BUTTON_SHOW) #define DEF_ENTRY_BACKGROUND (char *)NULL #define DEF_ENTRY_BG_MONO (char *)NULL #define DEF_ENTRY_BIND_TAGS "Entry all" #define DEF_ENTRY_BUTTON "auto" #define DEF_ENTRY_COMMAND (char *)NULL #define DEF_ENTRY_DATA (char *)NULL #define DEF_ENTRY_FOREGROUND (char *)NULL #define DEF_ENTRY_FG_MONO (char *)NULL #define DEF_ENTRY_FONT (char *)NULL #define DEF_ENTRY_ICONS (char *)NULL #define DEF_ENTRY_ACTIVE_ICONS (char *)NULL #define DEF_ENTRY_IMAGES (char *)NULL #define DEF_ENTRY_LABEL (char *)NULL #define DEF_ENTRY_SHADOW_COLOR (char *)NULL #define DEF_ENTRY_SHADOW_MONO (char *)NULL #define DEF_ENTRY_TEXT (char *)NULL #define DEF_BUTTON_ACTIVE_BACKGROUND RGB_WHITE #define DEF_BUTTON_ACTIVE_BG_MONO STD_ACTIVE_BG_MONO #define DEF_BUTTON_ACTIVE_FOREGROUND STD_ACTIVE_FOREGROUND #define DEF_BUTTON_ACTIVE_FG_MONO STD_ACTIVE_FG_MONO #define DEF_BUTTON_BORDERWIDTH "1" #if (TK_MAJOR_VERSION == 4) #define DEF_BUTTON_CLOSE_RELIEF "flat" #define DEF_BUTTON_OPEN_RELIEF "flat" #else #define DEF_BUTTON_CLOSE_RELIEF "solid" #define DEF_BUTTON_OPEN_RELIEF "solid" #endif #define DEF_BUTTON_IMAGES (char *)NULL #define DEF_BUTTON_NORMAL_BACKGROUND RGB_WHITE #define DEF_BUTTON_NORMAL_BG_MONO STD_NORMAL_BG_MONO #define DEF_BUTTON_NORMAL_FOREGROUND STD_NORMAL_FOREGROUND #define DEF_BUTTON_NORMAL_FG_MONO STD_NORMAL_FG_MONO #define DEF_BUTTON_SIZE "7" #define DEF_HIERBOX_ACTIVE_BACKGROUND RGB_LIGHTBLUE0 #define DEF_HIERBOX_ACTIVE_SELECT_BACKGROUND RGB_LIGHTBLUE1 #define DEF_HIERBOX_ACTIVE_BG_MONO STD_ACTIVE_BG_MONO #define DEF_HIERBOX_ACTIVE_FOREGROUND RGB_BLACK #define DEF_HIERBOX_ACTIVE_RELIEF "flat" #define DEF_HIERBOX_ACTIVE_STIPPLE "gray25" #define DEF_HIERBOX_ALLOW_DUPLICATES "yes" #define DEF_HIERBOX_BACKGROUND RGB_WHITE #define DEF_HIERBOX_BORDERWIDTH STD_BORDERWIDTH #define DEF_HIERBOX_COMMAND (char *)NULL #define DEF_HIERBOX_CURSOR (char *)NULL #define DEF_HIERBOX_DASHES "dot" #define DEF_HIERBOX_EXPORT_SELECTION "no" #define DEF_HIERBOX_FOREGROUND STD_NORMAL_FOREGROUND #define DEF_HIERBOX_FG_MONO STD_NORMAL_FG_MONO #define DEF_HIERBOX_FOCUS_DASHES "dot" #define DEF_HIERBOX_FOCUS_EDIT "no" #define DEF_HIERBOX_FOCUS_FOREGROUND STD_ACTIVE_FOREGROUND #define DEF_HIERBOX_FOCUS_FG_MONO STD_ACTIVE_FG_MONO #define DEF_HIERBOX_FONT STD_FONT #define DEF_HIERBOX_HEIGHT "400" #define DEF_HIERBOX_HIDE_ROOT "no" #define DEF_HIERBOX_HIGHLIGHT_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_HIERBOX_HIGHLIGHT_BG_MONO STD_NORMAL_BG_MONO #define DEF_HIERBOX_HIGHLIGHT_COLOR RGB_BLACK #define DEF_HIERBOX_HIGHLIGHT_WIDTH "2" #define DEF_HIERBOX_LINE_COLOR RGB_GREY50 #define DEF_HIERBOX_LINE_MONO STD_NORMAL_FG_MONO #define DEF_HIERBOX_LINE_SPACING "0" #define DEF_HIERBOX_LINE_WIDTH "1" #define DEF_HIERBOX_MAKE_PATH "no" #define DEF_HIERBOX_NORMAL_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_HIERBOX_NORMAL_FG_MONO STD_ACTIVE_FG_MONO #define DEF_HIERBOX_RELIEF "sunken" #define DEF_HIERBOX_SCROLL_INCREMENT "0" #define DEF_HIERBOX_SCROLL_MODE "hierbox" #define DEF_HIERBOX_SCROLL_TILE "yes" #define DEF_HIERBOX_SELECT_BACKGROUND RGB_LIGHTSKYBLUE1 #define DEF_HIERBOX_SELECT_BG_MONO STD_SELECT_BG_MONO #define DEF_HIERBOX_SELECT_BORDERWIDTH "1" #define DEF_HIERBOX_SELECT_CMD (char *)NULL #define DEF_HIERBOX_SELECT_FOREGROUND STD_SELECT_FOREGROUND #define DEF_HIERBOX_SELECT_FG_MONO STD_SELECT_FG_MONO #define DEF_HIERBOX_SELECT_MODE "single" #define DEF_HIERBOX_SELECT_RELIEF "flat" #define DEF_HIERBOX_SEPARATOR (char *)NULL #define DEF_HIERBOX_SHOW_ROOT "yes" #define DEF_HIERBOX_SORT_SELECTION "no" #define DEF_HIERBOX_TAKE_FOCUS "1" #define DEF_HIERBOX_TEXT_COLOR STD_NORMAL_FOREGROUND #define DEF_HIERBOX_TEXT_MONO STD_NORMAL_FG_MONO #define DEF_HIERBOX_TILE (char *)NULL #define DEF_HIERBOX_TRIMLEFT "" #define DEF_HIERBOX_WIDTH "200" typedef struct HierboxStruct Hierbox; typedef struct EntryStruct Entry; typedef struct TreeStruct Tree; typedef int (CompareProc) _ANSI_ARGS_((Tcl_Interp *interp, char *name, char *pattern)); typedef int (ApplyProc) _ANSI_ARGS_((Hierbox *hboxPtr, Tree * treePtr)); typedef Tree *(IterProc) _ANSI_ARGS_((Tree * treePtr, unsigned int mask)); extern Tk_CustomOption bltDashesOption; extern Tk_CustomOption bltDistanceOption; extern Tk_CustomOption bltShadowOption; extern Tk_CustomOption bltTileOption; extern Tk_CustomOption bltUidOption; static Tk_OptionParseProc StringToButton; static Tk_OptionPrintProc ButtonToString; static Tk_OptionParseProc StringToImages; static Tk_OptionPrintProc ImagesToString; static Tk_OptionParseProc StringToScrollMode; static Tk_OptionPrintProc ScrollModeToString; static Tk_OptionParseProc StringToSeparator; static Tk_OptionPrintProc SeparatorToString; /* * Contains a pointer to the widget that's currently being configured. * This is used in the custom configuration parse routine for images. */ static Hierbox *hierBox; static Tk_CustomOption imagesOption = { StringToImages, ImagesToString, (ClientData)&hierBox, }; static Tk_CustomOption buttonOption = { StringToButton, ButtonToString, (ClientData)0, }; static Tk_CustomOption scrollModeOption = { StringToScrollMode, ScrollModeToString, (ClientData)0, }; static Tk_CustomOption separatorOption = { StringToSeparator, SeparatorToString, (ClientData)0, }; /* * CachedImage -- * * Since instances of the same Tk image can be displayed in * different windows with possibly different color palettes, Tk * internally stores each instance in a linked list. But if * the instances are used in the same widget and therefore use * the same color palette, this adds a lot of overhead, * especially when deleting instances from the linked list. * * For the hierbox widget, we never need more than a single * instance of an image, regardless of how many times it's used. * So one solution is to cache the image, maintaining a reference * count for each image used in the widget. It's likely that the * hierarchy widget will use many instances of the same image * (for example the open/close icons). */ typedef struct CachedImageStruct { Tk_Image tkImage; /* The Tk image being cached. */ int refCount; /* Reference count for this image. */ short int width, height; /* Dimensions of the cached image. */ Blt_HashEntry *hashPtr; /* Hash table pointer to the image. */ } *CachedImage; #define ImageHeight(image) ((image)->height) #define ImageWidth(image) ((image)->width) #define ImageBits(image) ((image)->tkImage) /* * Tree -- * * Structure representing a general order tree. * */ struct TreeStruct { Blt_Uid nameId; /* String identifying the node within this * hierarchy. Does not necessarily have to * be unique. */ Entry *entryPtr; /* Points to the entry structure at this * node. */ Tree *parentPtr; /* Pointer to the parent node. * If NULL, this is the root node. */ Blt_Chain *chainPtr; /* Pointer to list of child nodes. The list * isn't allocated until the child nodes are * to be inserted. */ Blt_ChainLink *linkPtr; /* List link containing this node in parent. * This is used to remove the node from * its parent when destroying the node. */ short int level; /* The level of this node in the tree. */ }; /* * Entry -- * * Contains data-specific information how to represent the data * of a node of the hierarchy. * */ struct EntryStruct { int worldX, worldY; /* X-Y position in world coordinates * where the entry is positioned. */ short int width, height; /* Dimensions of the entry. */ int lineHeight; /* Length of the vertical line segment. */ unsigned int flags; /* Flags for this entry. For the * definitions of the various bit * fields see below. */ Blt_Uid dataUid; /* This value isn't used in C code. * It may be used in Tcl bindings to * associate extra data (other than * the label, image, or text) with the * entry. */ Blt_Uid tags; /* List of binding tags for this * entry. Blt_Uid, not a string, * because in the typical case most * entries will have the same * bintags. */ Blt_HashEntry *hashPtr; /* Points the hash entry containing this * entry. This is how the node index is * stored--as the key of the hash entry. */ Hierbox *hboxPtr; Blt_Uid openCmd, closeCmd; /* Tcl commands to invoke when entries * are opened or closed. They override * those specified globally. */ /* * Button information: */ short int buttonX, buttonY; /* X-Y coordinate offsets from to * upper left corner of the entry to * the upper-left corner of the * button. Used to pick the * button quickly */ CachedImage *icons; /* Tk images displayed for the entry. * The first image is the icon * displayed to the left of the * entry's label. The second is icon * displayed when entry is "open". */ GC iconGC; /* GC for drawing default bitmaps. */ short int iconWidth, iconHeight; /* Maximum dimensions for icons and * buttons for this entry. This is * used to align the button, icon, and * text. */ CachedImage *activeIcons; /* Tk images displayed for the entry. * The first image is the icon * displayed to the left of the * entry's label. The second is icon * displayed when entry is "open". */ short int levelX; /* X-coordinate offset of data image * or text for children nodes. */ /* * Label information: */ short int labelWidth, labelHeight; char *labelText; /* Text displayed right of the icon. */ Tk_Font labelFont; /* Font of label. Overrides global font * specification. */ XColor *labelColor; /* Color of label. Overrides default text color * specification. */ GC labelGC; Shadow labelShadow; /* * Data (text or image) information: */ Blt_Uid dataText; Tk_Font dataFont; XColor *dataColor; Shadow dataShadow; GC dataGC; CachedImage *images; }; static Tk_ConfigSpec entryConfigSpecs[] = { {TK_CONFIG_CUSTOM, "-activeicons", "activeIcons", "Icons", DEF_ENTRY_ICONS, Tk_Offset(Entry, activeIcons), TK_CONFIG_NULL_OK, &imagesOption}, {TK_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags", DEF_ENTRY_BIND_TAGS, Tk_Offset(Entry, tags), TK_CONFIG_NULL_OK, &bltUidOption}, {TK_CONFIG_CUSTOM, "-closecommand", "entryCloseCommand", "EntryCloseCommand", DEF_ENTRY_COMMAND, Tk_Offset(Entry, closeCmd), TK_CONFIG_NULL_OK, &bltUidOption}, {TK_CONFIG_CUSTOM, "-data", "data", "data", DEF_ENTRY_DATA, Tk_Offset(Entry, dataUid), TK_CONFIG_NULL_OK, &bltUidOption}, {TK_CONFIG_CUSTOM, "-button", "button", "Button", DEF_ENTRY_BUTTON, Tk_Offset(Entry, flags), TK_CONFIG_DONT_SET_DEFAULT, &buttonOption}, {TK_CONFIG_CUSTOM, "-icons", "icons", "Icons", DEF_ENTRY_ICONS, Tk_Offset(Entry, icons), TK_CONFIG_NULL_OK, &imagesOption}, {TK_CONFIG_CUSTOM, "-images", "images", "Images", DEF_ENTRY_IMAGES, Tk_Offset(Entry, images), TK_CONFIG_NULL_OK, &imagesOption}, {TK_CONFIG_STRING, "-label", "label", "Label", DEF_ENTRY_LABEL, Tk_Offset(Entry, labelText), 0}, {TK_CONFIG_COLOR, "-labelcolor", "labelColor", "LabelColor", DEF_ENTRY_FOREGROUND, Tk_Offset(Entry, labelColor), TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-labelcolor", "labelColor", "LabelColor", DEF_ENTRY_FG_MONO, Tk_Offset(Entry, labelColor), TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY}, {TK_CONFIG_FONT, "-labelfont", "labelFont", "LabelFont", DEF_ENTRY_FONT, Tk_Offset(Entry, labelFont), 0}, {TK_CONFIG_CUSTOM, "-labelshadow", "labelShadow", "LabelShadow", DEF_ENTRY_SHADOW_COLOR, Tk_Offset(Entry, labelShadow), TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY, &bltShadowOption}, {TK_CONFIG_CUSTOM, "-labelshadow", "labelShadow", "LabelShadow", DEF_ENTRY_SHADOW_MONO, Tk_Offset(Entry, labelShadow), TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY, &bltShadowOption}, {TK_CONFIG_CUSTOM, "-opencommand", "entryOpenCommand", "EntryOpenCommand", DEF_ENTRY_COMMAND, Tk_Offset(Entry, openCmd), TK_CONFIG_NULL_OK, &bltUidOption}, {TK_CONFIG_CUSTOM, "-text", "text", "Text", DEF_ENTRY_LABEL, Tk_Offset(Entry, dataText), TK_CONFIG_NULL_OK, &bltUidOption}, {TK_CONFIG_COLOR, "-textcolor", "textColor", "TextColor", DEF_ENTRY_FOREGROUND, Tk_Offset(Entry, dataColor), TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_FONT, "-textfont", "textFont", "TextFont", DEF_ENTRY_FONT, Tk_Offset(Entry, dataFont), 0}, {TK_CONFIG_CUSTOM, "-textshadow", "textShadow", "Shadow", DEF_ENTRY_SHADOW_COLOR, Tk_Offset(Entry, dataShadow), TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY, &bltShadowOption}, {TK_CONFIG_CUSTOM, "-textShadow", "textShadow", "Shadow", DEF_ENTRY_SHADOW_MONO, Tk_Offset(Entry, dataShadow), TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY, &bltShadowOption}, {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; /* * ButtonAttributes -- * * A button is the open/close indicator at the far left of the * entry. It is displayed as a plus or minus in a solid * colored box with optionally an border. It has both "active" * and "normal" colors. */ typedef struct { XColor *fgColor; /* Foreground color. */ Tk_3DBorder border; /* Background color. */ XColor *activeFgColor; /* Active foreground color. */ Tk_3DBorder activeBorder; /* Active background color. */ GC lineGC, normalGC, activeGC; int reqSize; int borderWidth; int openRelief, closeRelief; int width, height; CachedImage *images; } ButtonAttributes; /* * TextEdit -- * * This structure is shared by entries when their labels are * edited via the keyboard. It maintains the location of the * insertion cursor and the text selection for the editted entry. * The structure is shared since we need only one. The "focus" * entry should be the only entry receiving KeyPress/KeyRelease * events at any time. Information from the previously editted * entry is overwritten. * * Note that all the indices internally are in terms of bytes, * not characters. This is because UTF-8 strings may encode a * single character into a multi-byte sequence. To find the * respective character position * * n = Tcl_NumUtfChars(string, index); * * where n is the resulting character number. */ typedef struct { int active; int insertPos; /* Position of the cursor within the * array of bytes of the entry's label. */ int x, y; /* Offsets of the insertion cursolsr from the * start of the label. Used to draw the * the cursor relative to the entry. */ int width, height; /* Size of the insertion cursor symbol. */ int selAnchor; /* Fixed end of selection. Used to extend * the selection while maintaining the * other end of the selection. */ int selFirst; /* Position of the first character in the * selection. */ int selLast; /* Position of the last character in the * selection. */ int cursorOn; /* Indicates if the cursor is displayed. */ int onTime, offTime; /* Time in milliseconds to wait before * changing the cursor from off-to-on * and on-to-off. Setting offTime to 0 makes * the cursor steady. */ Tcl_TimerToken timerToken; /* Handle for a timer event called periodically * to blink the cursor. */ } TextEdit; /* * LevelInfo -- * */ typedef struct { int x; int width; } LevelInfo; /* * Hierbox -- * * Represents the hierarchy widget that contains one or more * entries. * * Entries are positioned in "world" coordinates, refering to * the virtual hierbox space. Coordinate 0,0 is the upper-left * of the hierarchy box and the bottom is the end of the last * entry. The widget's Tk window acts as view port into this * virtual space. The hierbox's xOffset and yOffset fields specify * the location of the view port in the virtual world. Scrolling * the viewport is therefore simply changing the xOffset and/or * yOffset fields and redrawing. * * Note that world coordinates are integers, not signed short * integers like X11 screen coordinates. It's very easy to * create a hierarchy that is more than 0x7FFF pixels high. * */ struct HierboxStruct { Tk_Window tkwin; /* Window that embodies the widget. * NULL means that the window has been * destroyed but the data structures * haven't yet been cleaned up.*/ Display *display; /* Display containing widget; needed, * among other things, to release * resources after tkwin has already * gone away. */ Tcl_Interp *interp; /* Interpreter associated with widget. */ Tcl_Command cmdToken; /* Token for widget's command. */ int flags; /* For bitfield definitions, see below */ int allowDuplicates; /* Allow duplicate entries. */ int autoCreate; /* Automatically create path entries * as needed. */ int exportSelection; /* Export the selection to X. */ int hideRoot; /* Don't display the root entry. */ int scrollTile; /* Adjust the tile along with viewport * offsets as the widget is * scrolled. */ int inset; /* Total width of all borders, * including traversal highlight and * 3-D border. Indicates how much * interior stuff must be offset from * outside edges to leave room for * borders. */ Tk_3DBorder border; /* 3D border surrounding the window * (viewport). */ int borderWidth; /* Width of 3D border. */ int relief; /* 3D border relief. */ int highlightWidth; /* Width in pixels of highlight to draw * around widget when it has the focus. * <= 0 means don't draw a highlight. */ XColor *highlightBgColor; /* Color for drawing traversal highlight * area when highlight is off. */ XColor *highlightColor; /* Color for drawing traversal highlight. */ Blt_Tile tile; /* Tiled background */ char *separator; /* Pathname separators */ char *trimLeft; /* Leading characters to trim from * pathnames */ /* * Entries are connected by horizontal and vertical lines. They * may be drawn dashed or solid. */ int lineWidth; /* Width of lines connecting entries */ int dashes; /* Dash on-off value. */ XColor *lineColor; /* Color of connecting lines. */ /* * Button Information: * * The button is the open/close indicator at the far left of the * entry. It is usually displayed as a plus or minus in a solid * colored box with optionally an border. It has both "active" * and "normal" colors. */ ButtonAttributes button; /* * Selection Information: * * The selection is the rectangle that contains a selected entry. * There may be many selected entries. It is displayed as a * solid colored box with optionally a 3D border. */ Tk_3DBorder selBorder; /* Background color of an highlighted entry.*/ int selRelief; /* Relief of selected items. Currently * is always raised. */ int selBorderWidth; /* Border width of a selected entry.*/ XColor *selFgColor; /* Text color of a selected entry. */ Tree *selAnchorPtr; /* Fixed end of selection (i.e. node * at which selection was started.) */ Blt_HashTable selectTable; Blt_Chain selectChain; int sortSelection; /* Indicates if the entries in the * selection should be sorted or * displayed in the order they were * selected. */ char *selectMode; /* Selection style. This value isn't * used in C code (it's just a place * holder), but for the widget's Tcl * bindings. */ char *selectCmd; /* Tcl script that's invoked whenever * the selection changes. */ int leader; /* Number of pixels padding between entries */ Tk_Cursor cursor; /* X Cursor */ int reqWidth, reqHeight; /* Requested dimensions of the widget's * window. */ GC lineGC; /* GC for drawing dotted line between * entries. */ XColor *activeFgColor; Tk_3DBorder activeBorder; XColor *focusColor; Blt_Dashes focusDashes; /* Dash on-off value. */ GC focusGC; /* Graphics context for the active label */ int focusEdit; /* Indicates if the label of the "focus" entry * can be editted. */ TextEdit labelEdit; Tree *activePtr; Tree *focusPtr; /* Pointer to node that's currently active. */ Tree *activeButtonPtr; /* Pointer to last active button */ /* Number of pixels to move for 1 scroll unit. */ int reqScrollX, reqScrollY; int xScrollUnits, yScrollUnits; /* Command strings to control horizontal and vertical scrollbars. */ char *xScrollCmdPrefix, *yScrollCmdPrefix; int scrollMode; /* Selects mode of scrolling: either * BLT_SCROLL_MODE_HIERBOX, * BLT_SCROLL_MODE_LISTBOX, or * BLT_SCROLL_MODE_CANVAS. */ /* * Total size of all "open" entries. This represents the range of * world coordinates. */ int worldWidth, worldHeight; int xOffset, yOffset; /* Translation between view port and * world origin. */ int minHeight; /* Minimum entry height. Used to * to compute what the y-scroll unit * should be. */ LevelInfo *levelInfo; /* * Scanning information: */ int scanAnchorX, scanAnchorY; /* Scan anchor in screen coordinates. */ int scanX, scanY; /* X-Y world coordinate where the scan * started. */ Blt_HashTable nodeTable; /* Table of node identifiers */ Blt_HashTable imageTable; /* Table of Tk images */ Tree *rootPtr; /* Root of hierarchy */ int depth; /* Maximum depth of the hierarchy. */ Tree **visibleArr; /* Array of visible entries */ int nVisible; /* Number of entries in the above array */ int nextSerial; char *openCmd, *closeCmd; /* Tcl commands to invoke when entries * are opened or closed. */ Tk_Font defFont; /* Specifies a default font for labels and * text data. It may be overridden for a * single entry by its -*font option. */ XColor *defColor; /* Global text color for labels. This * may be overridden by the -color * option for an individual entry. */ Pixmap iconBitmap, iconMask;/* Default icon bitmaps */ XColor *iconColor; char *takeFocus; char *sortCmd; /* Tcl command to invoke to sort entries */ ClientData clientData; Blt_BindTable bindTable; /* Binding information for entries. */ Blt_BindTable buttonBindTable; /* Binding information for buttons. */ }; static Tk_ConfigSpec buttonConfigSpecs[] = { {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Background", DEF_BUTTON_ACTIVE_BG_MONO, Tk_Offset(Hierbox, button.activeBorder), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Background", DEF_BUTTON_ACTIVE_BACKGROUND, Tk_Offset(Hierbox, button.activeBorder), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Foreground", DEF_BUTTON_ACTIVE_FOREGROUND, Tk_Offset(Hierbox, button.activeFgColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Foreground", DEF_BUTTON_ACTIVE_FG_MONO, Tk_Offset(Hierbox, button.activeFgColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_BUTTON_NORMAL_BACKGROUND, Tk_Offset(Hierbox, button.border), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_BUTTON_NORMAL_BG_MONO, Tk_Offset(Hierbox, button.border), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_CUSTOM, "-borderwidth", "borderWidth", "BorderWidth", DEF_BUTTON_BORDERWIDTH, Tk_Offset(Hierbox, button.borderWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_RELIEF, "-closerelief", "closeRelief", "Relief", DEF_BUTTON_CLOSE_RELIEF, Tk_Offset(Hierbox, button.closeRelief), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_BUTTON_NORMAL_FOREGROUND, Tk_Offset(Hierbox, button.fgColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_BUTTON_NORMAL_FG_MONO, Tk_Offset(Hierbox, button.fgColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_CUSTOM, "-images", "images", "Images", DEF_BUTTON_IMAGES, Tk_Offset(Hierbox, button.images), TK_CONFIG_NULL_OK, &imagesOption}, {TK_CONFIG_RELIEF, "-openrelief", "openRelief", "Relief", DEF_BUTTON_OPEN_RELIEF, Tk_Offset(Hierbox, button.openRelief), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-size", "size", "Size", DEF_BUTTON_SIZE, Tk_Offset(Hierbox, button.reqSize), 0, &bltDistanceOption}, {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "ActiveBackground", DEF_HIERBOX_ACTIVE_BACKGROUND, Tk_Offset(Hierbox, activeBorder), TK_CONFIG_COLOR_ONLY | TK_CONFIG_NULL_OK}, {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "ActiveBackground", DEF_HIERBOX_ACTIVE_BG_MONO, Tk_Offset(Hierbox, activeBorder), TK_CONFIG_MONO_ONLY | TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Foreground", DEF_HIERBOX_ACTIVE_FOREGROUND, Tk_Offset(Hierbox, activeFgColor), 0}, {TK_CONFIG_BOOLEAN, "-allowduplicates", "allowDuplicates", "AllowDuplicates", DEF_HIERBOX_ALLOW_DUPLICATES, Tk_Offset(Hierbox, allowDuplicates), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_BOOLEAN, "-autocreate", "autoCreate", "AutoCreate", DEF_HIERBOX_MAKE_PATH, Tk_Offset(Hierbox, autoCreate), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_HIERBOX_BACKGROUND, Tk_Offset(Hierbox, border), 0}, {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", DEF_HIERBOX_CURSOR, Tk_Offset(Hierbox, cursor), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-borderwidth", "borderWidth", "BorderWidth", DEF_HIERBOX_BORDERWIDTH, Tk_Offset(Hierbox, borderWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_STRING, "-closecommand", "closeCommand", "CloseCommand", DEF_HIERBOX_COMMAND, Tk_Offset(Hierbox, closeCmd), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-dashes", "dashes", "Dashes", DEF_HIERBOX_DASHES, Tk_Offset(Hierbox, dashes), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_BOOLEAN, "-exportselection", "exportSelection", "ExportSelection", DEF_HIERBOX_EXPORT_SELECTION, Tk_Offset(Hierbox, exportSelection), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_CUSTOM, "-focusdashes", "focusDashes", "FocusDashes", DEF_HIERBOX_FOCUS_DASHES, Tk_Offset(Hierbox, focusDashes), TK_CONFIG_NULL_OK, &bltDashesOption}, {TK_CONFIG_BOOLEAN, "-focusedit", "focusEdit", "FocusEdit", DEF_HIERBOX_FOCUS_EDIT, Tk_Offset(Hierbox, focusEdit), 0}, {TK_CONFIG_COLOR, "-focusforeground", "focusForeground", "FocusForeground", DEF_HIERBOX_FOCUS_FOREGROUND, Tk_Offset(Hierbox, focusColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-focusforeground", "focusForeground", "FocusForeground", DEF_HIERBOX_FOCUS_FG_MONO, Tk_Offset(Hierbox, focusColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_FONT, "-font", "font", "Font", DEF_HIERBOX_FONT, Tk_Offset(Hierbox, defFont), 0}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_HIERBOX_TEXT_COLOR, Tk_Offset(Hierbox, defColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_HIERBOX_TEXT_MONO, Tk_Offset(Hierbox, defColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_CUSTOM, "-height", "height", "Height", DEF_HIERBOX_HEIGHT, Tk_Offset(Hierbox, reqHeight), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_BOOLEAN, "-hideroot", "hideRoot", "HideRoot", DEF_HIERBOX_HIDE_ROOT, Tk_Offset(Hierbox, hideRoot), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", "HighlightBackground", DEF_HIERBOX_HIGHLIGHT_BACKGROUND, Tk_Offset(Hierbox, highlightBgColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", "HighlightBackground", DEF_HIERBOX_HIGHLIGHT_BG_MONO, Tk_Offset(Hierbox, highlightBgColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", DEF_HIERBOX_HIGHLIGHT_COLOR, Tk_Offset(Hierbox, highlightColor), 0}, {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", "HighlightThickness", DEF_HIERBOX_HIGHLIGHT_WIDTH, Tk_Offset(Hierbox, highlightWidth), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_COLOR, "-linecolor", "lineColor", "LineColor", DEF_HIERBOX_LINE_COLOR, Tk_Offset(Hierbox, lineColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-linecolor", "lineColor", "LineColor", DEF_HIERBOX_LINE_MONO, Tk_Offset(Hierbox, lineColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_CUSTOM, "-linespacing", "lineSpacing", "LineSpacing", DEF_HIERBOX_LINE_SPACING, Tk_Offset(Hierbox, leader), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-linewidth", "lineWidth", "LineWidth", DEF_HIERBOX_LINE_WIDTH, Tk_Offset(Hierbox, lineWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_STRING, "-opencommand", "openCommand", "OpenCommand", DEF_HIERBOX_COMMAND, Tk_Offset(Hierbox, openCmd), TK_CONFIG_NULL_OK}, {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_HIERBOX_RELIEF, Tk_Offset(Hierbox, relief), 0}, {TK_CONFIG_CUSTOM, "-scrollmode", "scrollMode", "ScrollMode", DEF_HIERBOX_SCROLL_MODE, Tk_Offset(Hierbox, scrollMode), TK_CONFIG_DONT_SET_DEFAULT, &scrollModeOption}, {TK_CONFIG_BOOLEAN, "-scrolltile", "scrollTile", "ScrollTile", DEF_HIERBOX_SCROLL_TILE, Tk_Offset(Hierbox, scrollTile), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground", DEF_HIERBOX_SELECT_BG_MONO, Tk_Offset(Hierbox, selBorder), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground", DEF_HIERBOX_SELECT_BACKGROUND, Tk_Offset(Hierbox, selBorder), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_CUSTOM, "-selectborderwidth", "selectBorderWidth", "BorderWidth", DEF_HIERBOX_SELECT_BORDERWIDTH, Tk_Offset(Hierbox, selBorderWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_STRING, "-selectcommand", "selectCommand", "SelectCommand", DEF_HIERBOX_SELECT_CMD, Tk_Offset(Hierbox, selectCmd), TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background", DEF_HIERBOX_SELECT_FG_MONO, Tk_Offset(Hierbox, selFgColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background", DEF_HIERBOX_SELECT_FOREGROUND, Tk_Offset(Hierbox, selFgColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_STRING, "-selectmode", "selectMode", "SelectMode", DEF_HIERBOX_SELECT_MODE, Tk_Offset(Hierbox, selectMode), TK_CONFIG_NULL_OK}, {TK_CONFIG_RELIEF, "-selectrelief", "selectRelief", "Relief", DEF_HIERBOX_SELECT_RELIEF, Tk_Offset(Hierbox, selRelief), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-separator", "separator", "Separator", DEF_HIERBOX_SEPARATOR, Tk_Offset(Hierbox, separator), TK_CONFIG_NULL_OK, &separatorOption}, {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", DEF_HIERBOX_TAKE_FOCUS, Tk_Offset(Hierbox, takeFocus), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-tile", "tile", "Tile", (char *)NULL, Tk_Offset(Hierbox, tile), TK_CONFIG_NULL_OK, &bltTileOption}, {TK_CONFIG_STRING, "-trimleft", "trimLeft", "Trim", DEF_HIERBOX_TRIMLEFT, Tk_Offset(Hierbox, trimLeft), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-width", "width", "Width", DEF_HIERBOX_WIDTH, Tk_Offset(Hierbox, reqWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand", (char *)NULL, Tk_Offset(Hierbox, xScrollCmdPrefix), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-xscrollincrement", "xScrollIncrement", "ScrollIncrement", DEF_HIERBOX_SCROLL_INCREMENT, Tk_Offset(Hierbox, reqScrollX), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand", (char *)NULL, Tk_Offset(Hierbox, yScrollCmdPrefix), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-yscrollincrement", "yScrollIncrement", "ScrollIncrement", DEF_HIERBOX_SCROLL_INCREMENT, Tk_Offset(Hierbox, reqScrollY), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; typedef struct { int x, y; /* Tracks the current world * coordinates as we traverse through * the tree. After a full-tree * traversal, the y-coordinate will be * the height of the virtual * hierarchy. */ int maxWidth; /* Maximum entry width. This is the * width of the virtual hierarchy. */ int labelOffset; int minHeight; /* Minimum entry height. Used to * to compute what the y-scroll unit * should be. */ int maxIconWidth; int level, depth; } LayoutInfo; #define DEF_ICON_WIDTH 16 #define DEF_ICON_HEIGHT 16 static unsigned char folderBits[] = { 0x00, 0x00, 0x7c, 0x00, 0x82, 0x00, 0x81, 0x3f, 0x41, 0x40, 0x3f, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00}; static unsigned char folderMaskBits[] = { 0x00, 0x00, 0x7c, 0x00, 0xfe, 0x00, 0xff, 0x3f, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00}; /* Forward Declarations */ static void DestroyHierbox _ANSI_ARGS_((DestroyData dataPtr)); static void HierboxEventProc _ANSI_ARGS_((ClientData clientdata, XEvent *eventPtr)); static void DrawButton _ANSI_ARGS_((Hierbox *hboxPtr, Tree * treePtr, Drawable drawable)); static void DisplayHierbox _ANSI_ARGS_((ClientData clientData)); static void HierboxInstCmdDeleteProc _ANSI_ARGS_((ClientData clientdata)); static int HierboxInstCmd _ANSI_ARGS_((ClientData clientdata, Tcl_Interp *interp, int argc, char **argv)); static void EventuallyRedraw _ANSI_ARGS_((Hierbox *hboxPtr)); static void SelectCmdProc _ANSI_ARGS_((ClientData clientData)); static void EventuallyInvokeSelectCmd _ANSI_ARGS_((Hierbox *hboxPtr)); static int ComputeVisibleEntries _ANSI_ARGS_((Hierbox *hboxPtr)); static int ConfigureEntry _ANSI_ARGS_((Hierbox *hboxPtr, Entry * entryPtr, int argc, char **argv, int flags)); static void ComputeLayout _ANSI_ARGS_((Hierbox *hboxPtr)); static CompareProc ExactCompare, GlobCompare, RegexpCompare; static ApplyProc SelectNode, GetSelectedLabels, CloseNode, SizeOfNode, IsSelectedNode, MapAncestors, FixUnmappedSelections, UnmapNode, SortNode, OpenNode; static IterProc NextNode, LastNode; static Tk_ImageChangedProc ImageChangedProc; static Blt_ChainCompareProc CompareNodesByTclCmd, CompareNodesByName; static Blt_BindPickProc PickButton, PickEntry; static Blt_BindTagProc GetTags; static Tk_SelectionProc SelectionProc; static Tk_LostSelProc LostSelection; static Tcl_CmdProc HierboxCmd; static Blt_TileChangedProc TileChangedProc; static Tcl_TimerProc LabelBlinkProc; static Tcl_FreeProc DestroyNode; /* *---------------------------------------------------------------------- * * StringToScrollMode -- * * Convert the string reprsenting a scroll mode, to its numeric * form. * * Results: * If the string is successfully converted, TCL_OK is returned. * Otherwise, TCL_ERROR is returned and an error message is left * in interpreter's result field. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToScrollMode(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* New legend position string */ char *widgRec; /* Widget record */ int offset; /* offset to XPoint structure */ { int *modePtr = (int *)(widgRec + offset); if ((string[0] == 'l') && (strcmp(string, "listbox") == 0)) { *modePtr = BLT_SCROLL_MODE_LISTBOX; } else if ((string[0] == 'h') && (strcmp(string, "hierbox") == 0)) { *modePtr = BLT_SCROLL_MODE_HIERBOX; } else if ((string[0] == 'c') && (strcmp(string, "canvas") == 0)) { *modePtr = BLT_SCROLL_MODE_CANVAS; } else { Tcl_AppendResult(interp, "bad scroll mode \"", string, "\": should be \"hierbox\", \"listbox\", or \"canvas\"", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * ScrollModeToString -- * * Results: * The string representation of the button boolean is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * ScrollModeToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget record */ int offset; /* offset of flags field in record */ Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */ { int mode = *(int *)(widgRec + offset); switch (mode) { case BLT_SCROLL_MODE_LISTBOX: return "listbox"; case BLT_SCROLL_MODE_HIERBOX: return "hierbox"; case BLT_SCROLL_MODE_CANVAS: return "canvas"; default: return "unknown scroll mode"; } } /* *---------------------------------------------------------------------- * * StringToButton -- * * Convert a string to one of three values. * 0 - false, no, off * 1 - true, yes, on * 2 - auto * Results: * If the string is successfully converted, TCL_OK is returned. * Otherwise, TCL_ERROR is returned and an error message is left in * interpreter's result field. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToButton(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* New legend position string */ char *widgRec; /* Widget record */ int offset; /* offset to XPoint structure */ { int *flags = (int *)(widgRec + offset); *flags &= ~BUTTON_MASK; if ((string[0] == 'a') && (strcmp(string, "auto") == 0)) { *flags |= BUTTON_AUTO; } else { int value; if (Tcl_GetBoolean(interp, string, &value) != TCL_OK) { return TCL_ERROR; } if (value) { *flags |= BUTTON_SHOW; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * ButtonToString -- * * Results: * The string representation of the button boolean is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * ButtonToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget record */ int offset; /* offset of flags field in record */ Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */ { unsigned int flags = *(int *)(widgRec + offset); switch (flags & BUTTON_MASK) { case 0: return "0"; case BUTTON_SHOW: return "1"; case BUTTON_AUTO: return "auto"; default: return "unknown button value"; } } /* *---------------------------------------------------------------------- * * ImageChangedProc * * * Results: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static void ImageChangedProc(clientData, x, y, width, height, imageWidth, imageHeight) ClientData clientData; int x, y, width, height; /* Not used. */ int imageWidth, imageHeight;/* Not used. */ { Hierbox *hboxPtr = clientData; hboxPtr->flags |= (HIERBOX_LAYOUT | HIERBOX_SCROLL); EventuallyRedraw(hboxPtr); } static CachedImage GetCachedImage(hboxPtr, interp, tkwin, name) Hierbox *hboxPtr; Tcl_Interp *interp; Tk_Window tkwin; char *name; { struct CachedImageStruct *imagePtr; int isNew; Blt_HashEntry *hPtr; hPtr = Blt_CreateHashEntry(&(hboxPtr->imageTable), (char *)name, &isNew); if (isNew) { Tk_Image tkImage; int width, height; tkImage = Tk_GetImage(interp, tkwin, name, ImageChangedProc, hboxPtr); if (tkImage == NULL) { Blt_DeleteHashEntry(&(hboxPtr->imageTable), hPtr); return NULL; } Tk_SizeOfImage(tkImage, &width, &height); imagePtr = Blt_Malloc(sizeof(struct CachedImageStruct)); imagePtr->tkImage = tkImage; imagePtr->hashPtr = hPtr; imagePtr->refCount = 1; imagePtr->width = width, imagePtr->height = height; Blt_SetHashValue(hPtr, imagePtr); } else { imagePtr = (struct CachedImageStruct *)Blt_GetHashValue(hPtr); imagePtr->refCount++; } return imagePtr; } static void FreeCachedImage(hboxPtr, imagePtr) Hierbox *hboxPtr; struct CachedImageStruct *imagePtr; { imagePtr->refCount--; if (imagePtr->refCount == 0) { Blt_DeleteHashEntry(&(hboxPtr->imageTable), imagePtr->hashPtr); Tk_FreeImage(imagePtr->tkImage); Blt_Free(imagePtr); } } /* *---------------------------------------------------------------------- * * StringToImages -- * * Convert a list of image names into Tk images. * * Results: * If the string is successfully converted, TCL_OK is returned. * Otherwise, TCL_ERROR is returned and an error message is left in * interpreter's result field. * *---------------------------------------------------------------------- */ static int StringToImages(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* New legend position string */ char *widgRec; /* Widget record */ int offset; /* offset to field in structure */ { Hierbox *hboxPtr = *(Hierbox **)clientData; CachedImage **imagePtrPtr = (CachedImage **) (widgRec + offset); CachedImage *imageArr; int result; result = TCL_OK; imageArr = NULL; if ((string != NULL) && (*string != '\0')) { int nNames; char **nameArr; if (Tcl_SplitList(interp, string, &nNames, &nameArr) != TCL_OK) { return TCL_ERROR; } if (nNames > 0) { register int i; imageArr = Blt_Malloc(sizeof(CachedImage *) * (nNames + 1)); assert(imageArr); for (i = 0; i < nNames; i++) { imageArr[i] = GetCachedImage(hboxPtr, interp, tkwin, nameArr[i]); if (imageArr[i] == NULL) { result = TCL_ERROR; break; } } Blt_Free(nameArr); imageArr[nNames] = NULL; } } if (*imagePtrPtr != NULL) { register CachedImage *imagePtr; for (imagePtr = *imagePtrPtr; *imagePtr != NULL; imagePtr++) { FreeCachedImage(hboxPtr, *imagePtr); } Blt_Free(*imagePtrPtr); } *imagePtrPtr = imageArr; return result; } /* *---------------------------------------------------------------------- * * ImagesToString -- * * Converts the image into its string representation (its name). * * Results: * The name of the image is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * ImagesToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget record */ int offset; /* offset of images array in record */ Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */ { CachedImage **imagePtrPtr = (CachedImage **) (widgRec + offset); Tcl_DString dString; char *result; Tcl_DStringInit(&dString); if (*imagePtrPtr != NULL) { register CachedImage *imagePtr; for (imagePtr = *imagePtrPtr; *imagePtr != NULL; imagePtr++) { Tcl_DStringAppendElement(&dString, Blt_NameOfImage((*imagePtr)->tkImage)); } } result = Blt_Strdup(Tcl_DStringValue(&dString)); Tcl_DStringFree(&dString); *freeProcPtr = (Tcl_FreeProc *)Blt_Free; return result; } /* *---------------------------------------------------------------------- * * StringToScrollmode -- * * Convert the string reprsenting a scroll mode, to its numeric * form. * * Results: * If the string is successfully converted, TCL_OK is returned. * Otherwise, TCL_ERROR is returned and an error message is left * in interpreter's result field. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToSeparator(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* String representing new value */ char *widgRec; /* Widget record */ int offset; /* offset in structure */ { char **sepPtr = (char **)(widgRec + offset); if ((*sepPtr != SEPARATOR_LIST) && (*sepPtr != SEPARATOR_NONE)) { Blt_Free(*sepPtr); } if ((string == NULL) || (*string == '\0')) { *sepPtr = SEPARATOR_LIST; } else if (strcmp(string, "none") == 0) { *sepPtr = SEPARATOR_NONE; } else { *sepPtr = Blt_Strdup(string); } return TCL_OK; } /* *---------------------------------------------------------------------- * * SeparatorToString -- * * Results: * The string representation of the separator is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * SeparatorToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget record */ int offset; /* offset of flags field in record */ Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */ { char *separator = *(char **)(widgRec + offset); if (separator == SEPARATOR_NONE) { return ""; } else if (separator == SEPARATOR_LIST) { return "list"; } return separator; } static int ApplyToTree(hboxPtr, rootPtr, proc, flags) Hierbox *hboxPtr; Tree *rootPtr; ApplyProc *proc; unsigned int flags; { if (flags & APPLY_BEFORE) { if ((*proc) (hboxPtr, rootPtr) != TCL_OK) { return TCL_ERROR; } } if (flags & APPLY_RECURSE) { if (!(flags & APPLY_OPEN_ONLY) || (rootPtr->entryPtr->flags & ENTRY_OPEN)) { Blt_ChainLink *linkPtr, *nextPtr; Tree *treePtr; for (linkPtr = Blt_ChainFirstLink(rootPtr->chainPtr); linkPtr != NULL; linkPtr = nextPtr) { /* Get the next link in the chain before calling * ApplyToTree. This is because ApplyToTree may * delete the node and its link. */ nextPtr = Blt_ChainNextLink(linkPtr); treePtr = Blt_ChainGetValue(linkPtr); if (ApplyToTree(hboxPtr, treePtr, proc, flags) != TCL_OK) { return TCL_ERROR; } } } } if ((flags & APPLY_BEFORE) == 0) { if ((*proc) (hboxPtr, rootPtr) != TCL_OK) { return TCL_ERROR; } } return TCL_OK; } static void ConfigureButtons(hboxPtr) Hierbox *hboxPtr; { ButtonAttributes *buttonPtr = &(hboxPtr->button); unsigned long gcMask; XGCValues gcValues; GC newGC; gcMask = GCForeground; gcValues.foreground = buttonPtr->fgColor->pixel; newGC = Tk_GetGC(hboxPtr->tkwin, gcMask, &gcValues); if (buttonPtr->normalGC != NULL) { Tk_FreeGC(hboxPtr->display, buttonPtr->normalGC); } buttonPtr->normalGC = newGC; gcMask = (GCForeground | GCLineWidth); gcValues.foreground = hboxPtr->lineColor->pixel; gcValues.line_width = hboxPtr->lineWidth; newGC = Tk_GetGC(hboxPtr->tkwin, gcMask, &gcValues); if (buttonPtr->lineGC != NULL) { Tk_FreeGC(hboxPtr->display, buttonPtr->lineGC); } buttonPtr->lineGC = newGC; gcMask = GCForeground; gcValues.foreground = buttonPtr->activeFgColor->pixel; newGC = Tk_GetGC(hboxPtr->tkwin, gcMask, &gcValues); if (buttonPtr->activeGC != NULL) { Tk_FreeGC(hboxPtr->display, buttonPtr->activeGC); } buttonPtr->activeGC = newGC; buttonPtr->width = buttonPtr->height = ODD(buttonPtr->reqSize); if (buttonPtr->images != NULL) { register int i; for (i = 0; i < 2; i++) { if (buttonPtr->images[i] == NULL) { break; } if (buttonPtr->width < ImageWidth(buttonPtr->images[i])) { buttonPtr->width = ImageWidth(buttonPtr->images[i]); } if (buttonPtr->height < ImageHeight(buttonPtr->images[i])) { buttonPtr->height = ImageHeight(buttonPtr->images[i]); } } } buttonPtr->width += 2 * buttonPtr->borderWidth; buttonPtr->height += 2 * buttonPtr->borderWidth; } static void DestroyEntry(entryPtr) Entry *entryPtr; { Hierbox *hboxPtr = entryPtr->hboxPtr; register CachedImage *imagePtr; Tk_FreeOptions(entryConfigSpecs, (char *)entryPtr, hboxPtr->display, 0); if (entryPtr->labelGC != NULL) { Tk_FreeGC(hboxPtr->display, entryPtr->labelGC); } if (entryPtr->dataGC != NULL) { Tk_FreeGC(hboxPtr->display, entryPtr->dataGC); } if (entryPtr->hashPtr != NULL) { Blt_DeleteHashEntry(&(hboxPtr->nodeTable), entryPtr->hashPtr); } if (entryPtr->dataShadow.color != NULL) { Tk_FreeColor(entryPtr->dataShadow.color); } if (entryPtr->labelShadow.color != NULL) { Tk_FreeColor(entryPtr->labelShadow.color); } if (entryPtr->iconGC != NULL) { Tk_FreeGC(hboxPtr->display, entryPtr->iconGC); } if (entryPtr->openCmd != NULL) { Blt_FreeUid(entryPtr->openCmd); } if (entryPtr->closeCmd != NULL) { Blt_FreeUid(entryPtr->closeCmd); } if (entryPtr->dataUid != NULL) { Blt_FreeUid(entryPtr->dataUid); } if (entryPtr->dataText != NULL) { Blt_FreeUid(entryPtr->dataText); } if (entryPtr->tags != NULL) { Blt_FreeUid(entryPtr->tags); } if (entryPtr->icons != NULL) { for (imagePtr = entryPtr->icons; *imagePtr != NULL; imagePtr++) { FreeCachedImage(hboxPtr, *imagePtr); } Blt_Free(entryPtr->icons); } if (entryPtr->activeIcons != NULL) { for (imagePtr = entryPtr->activeIcons; *imagePtr != NULL; imagePtr++) { FreeCachedImage(hboxPtr, *imagePtr); } Blt_Free(entryPtr->activeIcons); } if (entryPtr->images != NULL) { for (imagePtr = entryPtr->images; *imagePtr != NULL; imagePtr++) { FreeCachedImage(hboxPtr, *imagePtr); } Blt_Free(entryPtr->images); } Blt_Free(entryPtr); } /*ARGSUSED*/ static Tree * LastNode(treePtr, mask) register Tree *treePtr; unsigned int mask; { Blt_ChainLink *linkPtr; if (treePtr->parentPtr == NULL) { return NULL; /* The root is the first node. */ } linkPtr = Blt_ChainPrevLink(treePtr->linkPtr); if (linkPtr == NULL) { /* There are no siblings previous to this one, so pick the parent. */ return treePtr->parentPtr; } /* * Traverse down the right-most thread, in order to select the * next entry. Stop if we find a "closed" entry or reach a leaf. */ treePtr = Blt_ChainGetValue(linkPtr); while ((treePtr->entryPtr->flags & mask) == mask) { linkPtr = Blt_ChainLastLink(treePtr->chainPtr); if (linkPtr == NULL) { break; /* Found a leaf. */ } treePtr = Blt_ChainGetValue(linkPtr); } return treePtr; } static Tree * NextNode(treePtr, mask) Tree *treePtr; unsigned int mask; { Blt_ChainLink *linkPtr; if ((treePtr->entryPtr->flags & mask) == mask) { /* Pick the first sub-node. */ linkPtr = Blt_ChainFirstLink(treePtr->chainPtr); if (linkPtr != NULL) { return Blt_ChainGetValue(linkPtr); } } /* * Back up until we can find a level where we can pick a "next" entry. * For the last entry we'll thread our way back to the root. */ while (treePtr->parentPtr != NULL) { linkPtr = Blt_ChainNextLink(treePtr->linkPtr); if (linkPtr != NULL) { return Blt_ChainGetValue(linkPtr); } treePtr = treePtr->parentPtr; } return NULL; /* At root, no next node. */ } /*ARGSUSED*/ static Tree * EndNode(treePtr, mask) Tree *treePtr; unsigned int mask; { Blt_ChainLink *linkPtr; linkPtr = Blt_ChainLastLink(treePtr->chainPtr); while (linkPtr != NULL) { treePtr = Blt_ChainGetValue(linkPtr); if ((treePtr->entryPtr->flags & mask) != mask) { break; } linkPtr = Blt_ChainLastLink(treePtr->chainPtr); } return treePtr; } static void ExposeAncestors(treePtr) register Tree *treePtr; { treePtr = treePtr->parentPtr; while (treePtr != NULL) { treePtr->entryPtr->flags |= (ENTRY_OPEN | ENTRY_MAPPED); treePtr = treePtr->parentPtr; } } static int IsBefore(t1Ptr, t2Ptr) register Tree *t1Ptr, *t2Ptr; { int depth; register int i; Blt_ChainLink *linkPtr; Tree *treePtr; depth = MIN(t1Ptr->level, t2Ptr->level); if (depth == 0) { /* One of the nodes is root. */ if (t1Ptr->parentPtr == NULL) { return 1; } return 0; } /* * Traverse back from the deepest node, until the both nodes are at the * same depth. Check if the ancestor node found is the other node. */ for (i = t1Ptr->level; i > depth; i--) { t1Ptr = t1Ptr->parentPtr; } if (t1Ptr == t2Ptr) { return 0; } for (i = t2Ptr->level; i > depth; i--) { t2Ptr = t2Ptr->parentPtr; } if (t2Ptr == t1Ptr) { return 1; } /* * First find the mutual ancestor of both nodes. Look at each * preceding ancestor level-by-level for both nodes. Eventually * we'll find a node that's the parent of both ancestors. Then * find the first ancestor in the parent's list of subnodes. */ for (i = depth; i > 0; i--) { if (t1Ptr->parentPtr == t2Ptr->parentPtr) { break; } t1Ptr = t1Ptr->parentPtr; t2Ptr = t2Ptr->parentPtr; } for (linkPtr = Blt_ChainFirstLink(t1Ptr->parentPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { treePtr = Blt_ChainGetValue(linkPtr); if (treePtr == t1Ptr) { return 1; } else if (treePtr == t2Ptr) { return 0; } } assert(linkPtr != NULL); return 0; } static int IsAncestor(rootPtr, treePtr) Tree *rootPtr, *treePtr; { if (treePtr != NULL) { treePtr = treePtr->parentPtr; while (treePtr != NULL) { if (treePtr == rootPtr) { return 1; } treePtr = treePtr->parentPtr; } } return 0; } static int IsHidden(treePtr) register Tree *treePtr; { if (treePtr != NULL) { unsigned int mask; if (!(treePtr->entryPtr->flags & ENTRY_MAPPED)) { return TRUE; } treePtr = treePtr->parentPtr; mask = (ENTRY_OPEN | ENTRY_MAPPED); while (treePtr != NULL) { if ((treePtr->entryPtr->flags & mask) != mask) { return TRUE; } treePtr = treePtr->parentPtr; } } return FALSE; } static void SelectEntry(hboxPtr, treePtr) Hierbox *hboxPtr; Tree *treePtr; { int isNew; Blt_HashEntry *hPtr; hPtr = Blt_CreateHashEntry(&(hboxPtr->selectTable), (char *)treePtr, &isNew); if (isNew) { Blt_ChainLink *linkPtr; linkPtr = Blt_ChainAppend(&(hboxPtr->selectChain), treePtr); Blt_SetHashValue(hPtr, linkPtr); } } static void DeselectEntry(hboxPtr, treePtr) Hierbox *hboxPtr; Tree *treePtr; { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&(hboxPtr->selectTable), (char *)treePtr); if (hPtr != NULL) { Blt_ChainLink *linkPtr; linkPtr = (Blt_ChainLink *)Blt_GetHashValue(hPtr); Blt_ChainDeleteLink(&(hboxPtr->selectChain), linkPtr); Blt_DeleteHashEntry(&(hboxPtr->selectTable), hPtr); } } static void ClearSelection(hboxPtr) Hierbox *hboxPtr; { Blt_DeleteHashTable(&(hboxPtr->selectTable)); Blt_InitHashTable(&(hboxPtr->selectTable), BLT_ONE_WORD_KEYS); Blt_ChainReset(&(hboxPtr->selectChain)); EventuallyRedraw(hboxPtr); if (hboxPtr->selectCmd != NULL) { EventuallyInvokeSelectCmd(hboxPtr); } } static void PruneSelection(hboxPtr, rootPtr) Hierbox *hboxPtr; Tree *rootPtr; { Blt_ChainLink *linkPtr, *nextPtr; Tree *treePtr; int selectionChanged; selectionChanged = FALSE; for (linkPtr = Blt_ChainFirstLink(&(hboxPtr->selectChain)); linkPtr != NULL; linkPtr = nextPtr) { nextPtr = Blt_ChainNextLink(linkPtr); treePtr = Blt_ChainGetValue(linkPtr); if (IsAncestor(rootPtr, treePtr)) { DeselectEntry(hboxPtr, treePtr); selectionChanged = TRUE; } } if (selectionChanged) { EventuallyRedraw(hboxPtr); if (hboxPtr->selectCmd != NULL) { EventuallyInvokeSelectCmd(hboxPtr); } } } static int IsSelected(hboxPtr, treePtr) Hierbox *hboxPtr; Tree *treePtr; { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&(hboxPtr->selectTable), (char *)treePtr); return (hPtr != NULL); } static void GetFullPath(treePtr, separator, resultPtr) Tree *treePtr; char *separator; Tcl_DString *resultPtr; { char **nameArr; /* Used the stack the component names. */ register int i; int level; level = treePtr->level; nameArr = Blt_Malloc((level + 1) * sizeof(char *)); assert(nameArr); for (i = level; i >= 0; i--) { /* Save the name of each ancestor in the name array. */ nameArr[i] = treePtr->nameId; treePtr = treePtr->parentPtr; } Tcl_DStringInit(resultPtr); if ((separator == SEPARATOR_LIST) || (separator == SEPARATOR_NONE)) { for (i = 0; i <= level; i++) { Tcl_DStringAppendElement(resultPtr, nameArr[i]); } } else { Tcl_DStringAppend(resultPtr, nameArr[0], -1); if (strcmp(nameArr[0], separator) != 0) { Tcl_DStringAppend(resultPtr, separator, -1); } if (level > 0) { for (i = 1; i < level; i++) { Tcl_DStringAppend(resultPtr, nameArr[i], -1); Tcl_DStringAppend(resultPtr, separator, -1); } Tcl_DStringAppend(resultPtr, nameArr[i], -1); } } Blt_Free(nameArr); } static void InsertNode(parentPtr, position, nodePtr) Tree *parentPtr; /* Parent node where the new node will * be added. */ int position; /* Position in the parent of the new node. */ Tree *nodePtr; /* The node to be inserted. */ { Blt_ChainLink *linkPtr; /* * Create lists to contain subnodes as needed. We don't want to * unnecessarily allocate storage for leaves (of which there may * be many). */ if (parentPtr->chainPtr == NULL) { parentPtr->chainPtr = Blt_ChainCreate(); } linkPtr = Blt_ChainNewLink(); if (position == APPEND) { Blt_ChainAppendLink(parentPtr->chainPtr, linkPtr); } else { Blt_ChainLink *beforePtr; beforePtr = Blt_ChainGetNthLink(parentPtr->chainPtr, position); Blt_ChainLinkBefore(parentPtr->chainPtr, linkPtr, beforePtr); } nodePtr->level = parentPtr->level + 1; nodePtr->parentPtr = parentPtr; nodePtr->linkPtr = linkPtr; Blt_ChainSetValue(linkPtr, nodePtr); } static void DestroyNode(data) DestroyData data; { Tree *treePtr = (Tree *)data; if (treePtr->nameId != NULL) { Blt_FreeUid(treePtr->nameId); } if (treePtr->chainPtr != NULL) { Blt_ChainDestroy(treePtr->chainPtr); } if (treePtr->entryPtr != NULL) { DestroyEntry(treePtr->entryPtr); } treePtr->entryPtr = NULL; Blt_Free(treePtr); } /* *---------------------------------------------------------------------- * * CreateNode -- * * Creates and inserts a new node into the given tree at the * specified position. * * Results: * Returns a pointer to the newly created node. If an error * occurred, such as the entry could not be configured, NULL * is returned. * *---------------------------------------------------------------------- */ static Tree * CreateNode(hboxPtr, parentPtr, position, name) Hierbox *hboxPtr; /* Hierarchy widget record */ Tree *parentPtr; /* Pointer to parent node. */ int position; /* Position in node list to insert node. */ char *name; /* Name identifier for the new node. */ { Entry *entryPtr; Tree *treePtr; Blt_HashEntry *hPtr; int isNew; int serial; /* Create the entry structure */ entryPtr = Blt_Calloc(1, sizeof(Entry)); assert(entryPtr); entryPtr->flags |= (BUTTON_AUTO | ENTRY_MAPPED); entryPtr->hboxPtr = hboxPtr; if (name == NULL) { name = ""; } entryPtr->labelText = Blt_Strdup(name); if (ConfigureEntry(hboxPtr, entryPtr, 0, (char **)NULL, 0) != TCL_OK) { DestroyEntry(entryPtr); return NULL; } /* Create the container structure too */ treePtr = Blt_Calloc(1, sizeof(Tree)); assert(treePtr); treePtr->nameId = Blt_GetUid(name); treePtr->entryPtr = entryPtr; /* Generate a unique node serial number. */ do { serial = hboxPtr->nextSerial++; hPtr = Blt_CreateHashEntry(&(hboxPtr->nodeTable), (char *)serial, &isNew); } while (!isNew); Blt_SetHashValue(hPtr, treePtr); entryPtr->hashPtr = hPtr; if (parentPtr != NULL) { InsertNode(parentPtr, position, treePtr); } return treePtr; } /* *---------------------------------------------------------------------- * * FindComponent -- * * Searches for the given child node. The node is designated * by its node identifier string. * * Results: * If found, returns a node pointer. Otherwise NULL. * *---------------------------------------------------------------------- */ static Tree * FindComponent(parentPtr, name) Tree *parentPtr; char *name; { Blt_Uid nameId; nameId = Blt_FindUid(name); if (nameId != NULL) { register Tree *treePtr; Blt_ChainLink *linkPtr; /* The component identifier must already exist if the node exists. */ for (linkPtr = Blt_ChainFirstLink(parentPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { treePtr = Blt_ChainGetValue(linkPtr); if (nameId == treePtr->nameId) { return treePtr; } } } return NULL; } /* *---------------------------------------------------------------------- * * SkipSeparators -- * * Moves the character pointer past one of more separators. * * Results: * Returns the updates character pointer. * *---------------------------------------------------------------------- */ static char * SkipSeparators(path, separator, length) char *path, *separator; int length; { while ((*path == separator[0]) && (strncmp(path, separator, length) == 0)) { path += length; } return path; } /* *---------------------------------------------------------------------- * * SplitPath -- * * Returns the trailing component of the given path. Trailing * separators are ignored. * * Results: * Returns the string of the tail component. * *---------------------------------------------------------------------- */ static int SplitPath(hboxPtr, path, levelPtr, compPtrPtr) Hierbox *hboxPtr; char *path; int *levelPtr; char ***compPtrPtr; { int skipLen, pathLen; char *sep; int level, listSize; char **components; register char *p; skipLen = strlen(hboxPtr->separator); path = SkipSeparators(path, hboxPtr->separator, skipLen); pathLen = strlen(path); level = pathLen / skipLen; listSize = (level + 1) * sizeof(char *); components = Blt_Malloc(listSize + (pathLen + 1)); assert(components); p = (char *)components + listSize; strcpy(p, path); sep = strstr(p, hboxPtr->separator); level = 0; while ((*p != '\0') && (sep != NULL)) { *sep = '\0'; components[level++] = p; p = SkipSeparators(sep + skipLen, hboxPtr->separator, skipLen); sep = strstr(p, hboxPtr->separator); } if (*p != '\0') { components[level++] = p; } components[level] = NULL; *levelPtr = level; *compPtrPtr = components; return TCL_OK; } /* *---------------------------------------------------------------------- * * FindPath -- * * Finds the node designated by the given path. Each path * component is searched for as the tree is traversed. * * A leading character string is trimmed off the path if it * matches the one designated (see the -trimleft option). * * If no separator is designated (see the -separator * configuration option), the path is considered a Tcl list. * Otherwise the each component of the path is separated by a * character string. Leading and trailing separators are * ignored. Multiple separators are treated as one. * * Results: * Returns the pointer to the designated node. If any component * can't be found, NULL is returned. * *---------------------------------------------------------------------- */ static Tree * FindPath(hboxPtr, rootPtr, path) Hierbox *hboxPtr; Tree *rootPtr; char *path; { register char *p; int skip; char *sep; Tree *treePtr; char save; /* Trim off characters that we don't want */ if (hboxPtr->trimLeft != NULL) { register char *s; /* Trim off leading character string if one exists. */ for (p = path, s = hboxPtr->trimLeft; *s != '\0'; s++, p++) { if (*p != *s) { break; } } if (*s == '\0') { path = p; } } if (*path == '\0') { return rootPtr; } if (hboxPtr->separator == SEPARATOR_NONE) { return FindComponent(rootPtr, path); } if (hboxPtr->separator == SEPARATOR_LIST) { char **nameArr; int nComp; register int i; /* * No separator, so this must be a Tcl list of components. */ if (Tcl_SplitList(hboxPtr->interp, path, &nComp, &nameArr) != TCL_OK) { return NULL; } for (i = 0; i < nComp; i++) { treePtr = FindComponent(rootPtr, nameArr[i]); if (treePtr == NULL) { Blt_Free(nameArr); return NULL; } rootPtr = treePtr; } Blt_Free(nameArr); return rootPtr; } skip = strlen(hboxPtr->separator); path = SkipSeparators(path, hboxPtr->separator, skip); sep = strstr(path, hboxPtr->separator); p = path; treePtr = rootPtr; while ((*p != '\0') && (sep != NULL)) { save = *sep, *sep = '\0'; treePtr = FindComponent(treePtr, p); *sep = save; if (treePtr == NULL) { return NULL; /* Bad component name. */ } p = SkipSeparators(sep + skip, hboxPtr->separator, skip); sep = strstr(p, hboxPtr->separator); } if (*p != '\0') { treePtr = FindComponent(treePtr, p); if (treePtr == NULL) { return NULL; } } return treePtr; } /* *---------------------------------------------------------------------- * * NearestNode -- * * Finds the entry closest to the given screen X-Y coordinates * in the viewport. * * Results: * Returns the pointer to the closest node. If no node is * visible (nodes may be hidden), NULL is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static Tree * NearestNode(hboxPtr, x, y, selectOne) Hierbox *hboxPtr; int x, y; int selectOne; { register Tree *lastPtr, **treePtrPtr; register Entry *entryPtr; /* * We implicitly can pick only visible entries. So make sure that * the tree exists. */ if (hboxPtr->nVisible == 0) { return NULL; } /* * Since the entry positions were previously computed in world * coordinates, convert Y-coordinate from screen to world * coordinates too. */ y = WORLDY(hboxPtr, y); treePtrPtr = hboxPtr->visibleArr; lastPtr = *treePtrPtr; for ( /* empty */ ; *treePtrPtr != NULL; treePtrPtr++) { entryPtr = (*treePtrPtr)->entryPtr; /* * If the start of the next entry starts beyond the point, * use the last entry. */ if (entryPtr->worldY > y) { return (selectOne) ? lastPtr : NULL; } if (y < (entryPtr->worldY + entryPtr->height)) { return *treePtrPtr; /* Found it. */ } lastPtr = *treePtrPtr; } return (selectOne) ? lastPtr : NULL; } static Tree * GetNodeByIndex(hboxPtr, string) Hierbox *hboxPtr; char *string; { if (isdigit(UCHAR(string[0]))) { int serial; if (Tcl_GetInt(NULL, string, &serial) == TCL_OK) { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&(hboxPtr->nodeTable), (char *)serial); if (hPtr != NULL) { return (Tree *) Blt_GetHashValue(hPtr); } } } return NULL; } /* *---------------------------------------------------------------------- * * NodeToString -- * * Converts a node pointer in its string representation. The * string is the node's identifier number. * * Results: * The string representation of the node is returned. Note that * the string is stored statically, so that callers must save the * string before the next call to this routine overwrites the * static array again. * *---------------------------------------------------------------------- */ static char * NodeToString(hboxPtr, nodePtr) Hierbox *hboxPtr; Tree *nodePtr; { static char string[200]; int serial; /* Node table keys are integers. Convert them to strings. */ serial = (int)Blt_GetHashKey(&(hboxPtr->nodeTable), nodePtr->entryPtr->hashPtr); sprintf(string, "%d", serial); return string; } /* *---------------------------------------------------------------------- * * GetNode -- * * Converts a string into node pointer. The string may be in one * of the following forms: * * @x,y - Closest node to the specified X-Y position. * NNN - inode. * "active" - Currently active node. * "anchor" - anchor of selected region. * "mark" - mark of selected region. * "current" - Currently picked node in bindtable. * "focus" - The node currently with focus. * "root" - Root node. * "end" - Last open node in the entire hierarchy. * "next" - Next open node from the currently active * node. Wraps around back to top. * "last" - Previous open node from the currently active * node. Wraps around back to bottom. * "up" - Next open node from the currently active * node. Does not wrap around. * "down" - Previous open node from the currently active * node. Does not wrap around. * "nextsibling" - Next sibling of the current node. * "prevsibling" - Previous sibling of the current node. * "parent" - Parent of the current node. * "view.top" - Top of viewport. * "view.bottom" - Bottom of viewport. * @path - Absolute path to a node. * * Results: * If the string is successfully converted, TCL_OK is returned. * The pointer to the node is returned via treePtrPtr. * Otherwise, TCL_ERROR is returned and an error message is left * in interpreter's result field. * *---------------------------------------------------------------------- */ static int GetNode(hboxPtr, string, treePtrPtr) Hierbox *hboxPtr; char *string; Tree **treePtrPtr; { Tree *nodePtr; char c; Tree *fromPtr; c = string[0]; fromPtr = *treePtrPtr; nodePtr = NULL; if (isdigit(UCHAR(string[0]))) { nodePtr = GetNodeByIndex(hboxPtr, string); } else if ((c == 'e') && (strcmp(string, "end") == 0)) { nodePtr = EndNode(hboxPtr->rootPtr, ENTRY_OPEN | ENTRY_MAPPED); } else if ((c == 'a') && (strcmp(string, "anchor") == 0)) { nodePtr = hboxPtr->selAnchorPtr; } else if ((c == 'f') && (strcmp(string, "focus") == 0)) { nodePtr = hboxPtr->focusPtr; } else if ((c == 'r') && (strcmp(string, "root") == 0)) { nodePtr = hboxPtr->rootPtr; } else if ((c == 'p') && (strcmp(string, "parent") == 0)) { nodePtr = fromPtr; if (nodePtr->parentPtr != NULL) { nodePtr = nodePtr->parentPtr; } } else if ((c == 'c') && (strcmp(string, "current") == 0)) { /* Can't trust picked item, if entries have been added or deleted. */ if (!(hboxPtr->flags & HIERBOX_DIRTY)) { nodePtr = (Tree *) Blt_GetCurrentItem(hboxPtr->bindTable); if (nodePtr == NULL) { nodePtr = (Tree *)Blt_GetCurrentItem(hboxPtr->buttonBindTable); } } } else if ((c == 'u') && (strcmp(string, "up") == 0)) { nodePtr = LastNode(fromPtr, ENTRY_OPEN | ENTRY_MAPPED); if (nodePtr == NULL) { nodePtr = fromPtr; } if ((nodePtr == hboxPtr->rootPtr) && (hboxPtr->hideRoot)) { nodePtr = NextNode(hboxPtr->rootPtr, ENTRY_OPEN | ENTRY_MAPPED); } } else if ((c == 'd') && (strcmp(string, "down") == 0)) { nodePtr = NextNode(fromPtr, ENTRY_OPEN | ENTRY_MAPPED); if (nodePtr == NULL) { nodePtr = fromPtr; } if ((nodePtr == hboxPtr->rootPtr) && (hboxPtr->hideRoot)) { nodePtr = NextNode(hboxPtr->rootPtr, ENTRY_OPEN | ENTRY_MAPPED); } } else if (((c == 'l') && (strcmp(string, "last") == 0)) || ((c == 'p') && (strcmp(string, "prev") == 0))) { nodePtr = LastNode(fromPtr, ENTRY_OPEN | ENTRY_MAPPED); if (nodePtr == NULL) { nodePtr = EndNode(hboxPtr->rootPtr, ENTRY_OPEN | ENTRY_MAPPED); } if ((nodePtr == hboxPtr->rootPtr) && (hboxPtr->hideRoot)) { nodePtr = NextNode(hboxPtr->rootPtr, ENTRY_OPEN | ENTRY_MAPPED); } } else if ((c == 'n') && (strcmp(string, "next") == 0)) { nodePtr = NextNode(fromPtr, ENTRY_OPEN | ENTRY_MAPPED); if (nodePtr == NULL) { if (hboxPtr->hideRoot) { nodePtr = NextNode(hboxPtr->rootPtr, ENTRY_OPEN | ENTRY_MAPPED); } else { nodePtr = hboxPtr->rootPtr; } } } else if ((c == 'n') && (strcmp(string, "nextsibling") == 0)) { if (fromPtr->linkPtr != NULL) { Blt_ChainLink *linkPtr; linkPtr = Blt_ChainNextLink(fromPtr->linkPtr); if (linkPtr != NULL) { nodePtr = Blt_ChainGetValue(linkPtr); } } } else if ((c == 'p') && (strcmp(string, "prevsibling") == 0)) { if (fromPtr->linkPtr != NULL) { Blt_ChainLink *linkPtr; linkPtr = Blt_ChainPrevLink(fromPtr->linkPtr); if (linkPtr != NULL) { nodePtr = Blt_ChainGetValue(linkPtr); } } } else if ((c == 'v') && (strcmp(string, "view.top") == 0)) { if (hboxPtr->nVisible > 0) { nodePtr = hboxPtr->visibleArr[0]; } } else if ((c == 'v') && (strcmp(string, "view.bottom") == 0)) { if (hboxPtr->nVisible > 0) { nodePtr = hboxPtr->visibleArr[hboxPtr->nVisible - 1]; } } else if (c == '@') { int x, y; if (Blt_GetXY(hboxPtr->interp, hboxPtr->tkwin, string, &x, &y) == TCL_OK) { nodePtr = NearestNode(hboxPtr, x, y, TRUE); } else { nodePtr = FindPath(hboxPtr, hboxPtr->rootPtr, string + 1); } if (nodePtr == NULL) { Tcl_ResetResult(hboxPtr->interp); Tcl_AppendResult(hboxPtr->interp, "can't find node entry \"", string, "\" in \"", Tk_PathName(hboxPtr->tkwin), "\"", (char *)NULL); return TCL_ERROR; } } else { nodePtr = FindPath(hboxPtr, hboxPtr->rootPtr, string); if (nodePtr == NULL) { Tcl_ResetResult(hboxPtr->interp); Tcl_AppendResult(hboxPtr->interp, "can't find node entry \"", string, "\" in \"", Tk_PathName(hboxPtr->tkwin), "\"", (char *)NULL); return TCL_ERROR; } } *treePtrPtr = nodePtr; return TCL_OK; } /* *---------------------------------------------------------------------- * * StringToNode -- * * Like GetNode but also finds nodes by serial number. * If the string starts with a digit, it's converted into a * number and then looked-up in a hash table. This means that * serial identifiers take precedence over node names with * the contain only numbers. * * Results: * If the string is successfully converted, TCL_OK is returned. * The pointer to the node is returned via treePtrPtr. * Otherwise, TCL_ERROR is returned and an error message is left * in interpreter's result field. * *---------------------------------------------------------------------- */ static int StringToNode(hboxPtr, string, treePtrPtr) Hierbox *hboxPtr; char *string; Tree **treePtrPtr; { *treePtrPtr = hboxPtr->focusPtr; if (GetNode(hboxPtr, string, treePtrPtr) != TCL_OK) { return TCL_ERROR; } if (*treePtrPtr == NULL) { Tcl_ResetResult(hboxPtr->interp); Tcl_AppendResult(hboxPtr->interp, "can't find node entry \"", string, "\" in \"", Tk_PathName(hboxPtr->tkwin), "\"", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* * Preprocess the command string for percent substitution. */ static void PercentSubst(hboxPtr, treePtr, command, resultPtr) Hierbox *hboxPtr; Tree *treePtr; char *command; Tcl_DString *resultPtr; { Tcl_DString dString; register char *last, *p; /* * Get the full path name of the node, in case we need to * substitute for it. */ GetFullPath(treePtr, hboxPtr->separator, &dString); Tcl_DStringInit(resultPtr); for (last = p = command; *p != '\0'; p++) { if (*p == '%') { char *string; char buf[3]; if (p > last) { *p = '\0'; Tcl_DStringAppend(resultPtr, last, -1); *p = '%'; } switch (*(p + 1)) { case '%': /* Percent sign */ string = "%"; break; case 'W': /* Widget name */ string = Tk_PathName(hboxPtr->tkwin); break; case 'P': /* Full pathname */ string = Tcl_DStringValue(&dString); break; case 'p': /* Name of the node */ string = treePtr->nameId; break; case 'n': /* Node identifier */ string = NodeToString(hboxPtr, treePtr); break; default: if (*(p + 1) == '\0') { p--; } buf[0] = *p, buf[1] = *(p + 1), buf[2] = '\0'; string = buf; break; } Tcl_DStringAppend(resultPtr, string, -1); p++; last = p + 1; } } if (p > last) { *p = '\0'; Tcl_DStringAppend(resultPtr, last, -1); } Tcl_DStringFree(&dString); } /* *---------------------------------------------------------------------- * * CloseNode -- * * Closes the node. If a close Tcl command is specified (see the * "-close" option), it's invoked after the node is closed. * * Results: * If an error occurred when executing the Tcl proc, TCL_ERROR is * returned. Otherwise TCL_OK is returned. * *---------------------------------------------------------------------- */ static int CloseNode(hboxPtr, treePtr) Hierbox *hboxPtr; Tree *treePtr; { Entry *entryPtr = treePtr->entryPtr; char *command; int result; /* * The tricky part here is that the "close" command can delete * this node. So we'll preserve it until after we mark it closed. */ Tcl_Preserve(treePtr); /* * Invoke the entry's "close" command, if there is one. Otherwise * try the hierbox's global "close" command. */ command = (entryPtr->closeCmd != NULL) ? entryPtr->closeCmd : hboxPtr->closeCmd; result = TCL_OK; if ((entryPtr->flags & ENTRY_OPEN) && (command != NULL)) { Tcl_DString cmdString; PercentSubst(hboxPtr, treePtr, command, &cmdString); result = Tcl_GlobalEval(hboxPtr->interp, Tcl_DStringValue(&cmdString)); Tcl_DStringFree(&cmdString); } /* * Mark the entry closed, only after the Tcl proc callback. */ entryPtr->flags &= ~ENTRY_OPEN; Tcl_Release(treePtr); return result; } /* *---------------------------------------------------------------------- * * OpenNode -- * * Opens the node. If an open Tcl command is specified (see the * "-open" option), it's invoked after the node is opened. * * Results: * If an error occurred when executing the Tcl proc, TCL_ERROR is * returned. Otherwise TCL_OK is returned. * *---------------------------------------------------------------------- */ static int OpenNode(hboxPtr, treePtr) Hierbox *hboxPtr; Tree *treePtr; { Entry *entryPtr = treePtr->entryPtr; char *string; int result; /* * The tricky part here is that the "open" command can delete * this node. So we'll preserve it until after we mark it closed. */ Tcl_Preserve(treePtr); /* * Invoke the entry's "open" command, if there is one. Otherwise * try the hierbox's global "open" command. */ result = TCL_OK; string = (entryPtr->openCmd != NULL) ? entryPtr->openCmd : hboxPtr->openCmd; if (!(entryPtr->flags & ENTRY_OPEN) && (string != NULL)) { Tcl_DString dString; PercentSubst(hboxPtr, treePtr, string, &dString); result = Tcl_GlobalEval(hboxPtr->interp, Tcl_DStringValue(&dString)); Tcl_DStringFree(&dString); } /* * Mark the entry open, only after the Tcl proc callback has run. */ entryPtr->flags |= ENTRY_OPEN; Tcl_Release(treePtr); return result; } /* *---------------------------------------------------------------------- * * SelectNode -- * * Sets the selection flag for a node. The selection flag is * set/cleared/toggled based upon the flag set in the hierarchy * widget. * * Results: * Always returns TCL_OK. * *---------------------------------------------------------------------- */ static int SelectNode(hboxPtr, treePtr) Hierbox *hboxPtr; Tree *treePtr; { switch (hboxPtr->flags & SELECTION_MASK) { case SELECTION_CLEAR: DeselectEntry(hboxPtr, treePtr); break; case SELECTION_SET: SelectEntry(hboxPtr, treePtr); break; case SELECTION_TOGGLE: if (IsSelected(hboxPtr, treePtr)) { DeselectEntry(hboxPtr, treePtr); } else { SelectEntry(hboxPtr, treePtr); } break; } return TCL_OK; } /* *---------------------------------------------------------------------- * * SelectRange -- * * Sets the selection flag for a range of nodes. The range is * determined by two pointers which designate the first/last * nodes of the range. * * Results: * Always returns TCL_OK. * *---------------------------------------------------------------------- */ static int SelectRange(hboxPtr, fromPtr, toPtr) Hierbox *hboxPtr; Tree *fromPtr, *toPtr; { register Tree *treePtr; IterProc *proc; /* From the range determine the direction to select entries. */ proc = (IsBefore(toPtr, fromPtr)) ? LastNode : NextNode; for (treePtr = fromPtr; treePtr != NULL; treePtr = (*proc)(treePtr, ENTRY_OPEN | ENTRY_MAPPED)) { SelectNode(hboxPtr, treePtr); if (treePtr == toPtr) { break; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * IsSelectedNode -- * * Adds the name of the node the interpreter result if it is * currently selected. * * Results: * Always returns TCL_OK. * *---------------------------------------------------------------------- */ static int IsSelectedNode(hboxPtr, treePtr) Hierbox *hboxPtr; Tree *treePtr; { if (IsSelected(hboxPtr, treePtr)) { Tcl_AppendElement(hboxPtr->interp, NodeToString(hboxPtr, treePtr)); } return TCL_OK; } /* *---------------------------------------------------------------------- * * GetSelectedLabels -- * * This routine is invoked when the selection is exported. Each * selected entry is appended line-by-line to a dynamic string * passed via the clientData field of the hierarchy widget. * * Results: * Always returns TCL_OK. * *---------------------------------------------------------------------- */ static int GetSelectedLabels(hboxPtr, treePtr) Hierbox *hboxPtr; Tree *treePtr; { if (IsSelected(hboxPtr, treePtr)) { Tcl_DString *resultPtr = (Tcl_DString *) hboxPtr->clientData; Entry *entryPtr = treePtr->entryPtr; Tcl_DStringAppend(resultPtr, entryPtr->labelText, -1); Tcl_DStringAppend(resultPtr, "\n", -1); } return TCL_OK; } /* *---------------------------------------------------------------------- * * SizeOfNode -- * * Returns the number of children at the given node. The sum * is passed via the clientData field of the hierarchy widget. * * Results: * Always TCL_OK. * *---------------------------------------------------------------------- */ static int SizeOfNode(hboxPtr, treePtr) Hierbox *hboxPtr; Tree *treePtr; { int *sumPtr = (int *)&(hboxPtr->clientData); *sumPtr += Blt_ChainGetLength(treePtr->chainPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * CompareNodesByName -- * * Comparison routine (used by qsort) to sort a chain of subnodes. * A simple string comparison is performed on each node name. * * Results: * 1 is the first is greater, -1 is the second is greater, 0 * if equal. * *---------------------------------------------------------------------- */ static int CompareNodesByName(link1PtrPtr, link2PtrPtr) Blt_ChainLink **link1PtrPtr, **link2PtrPtr; { Tree *t1Ptr, *t2Ptr; t1Ptr = Blt_ChainGetValue(*link1PtrPtr); t2Ptr = Blt_ChainGetValue(*link2PtrPtr); return strcmp(t1Ptr->nameId, t2Ptr->nameId); } /* *---------------------------------------------------------------------- * * CompareNodesByTclCmd -- * * Comparison routine (used by qsort) to sort a list of subnodes. * A specified Tcl proc is invoked to compare the nodes. * * Results: * 1 is the first is greater, -1 is the second is greater, 0 * if equal. * *---------------------------------------------------------------------- */ static int CompareNodesByTclCmd(link1PtrPtr, link2PtrPtr) Blt_ChainLink **link1PtrPtr, **link2PtrPtr; { int result; Tree *t1Ptr, *t2Ptr; Hierbox *hboxPtr = hierBox; Tcl_Interp *interp = hboxPtr->interp; t1Ptr = Blt_ChainGetValue(*link1PtrPtr); t2Ptr = Blt_ChainGetValue(*link2PtrPtr); result = 0; /* Hopefully this will be Ok even if the * Tcl command fails to return the correct * result. */ if ((Tcl_VarEval(interp, hboxPtr->sortCmd, " ", Tk_PathName(hboxPtr->tkwin), " ", NodeToString(hboxPtr, t1Ptr), " ", NodeToString(hboxPtr, t2Ptr)) != TCL_OK) || (Tcl_GetInt(interp, Tcl_GetStringResult(interp), &result) != TCL_OK)) { Tcl_BackgroundError(interp); } Tcl_ResetResult(interp); return result; } /* *---------------------------------------------------------------------- * * SortNode -- * * Sorts the subnodes at a given node. * * Results: * Always returns TCL_OK. * *---------------------------------------------------------------------- */ static int SortNode(hboxPtr, treePtr) Hierbox *hboxPtr; Tree *treePtr; { if (treePtr->chainPtr != NULL) { if (hboxPtr->sortCmd != NULL) { hierBox = hboxPtr; Blt_ChainSort(treePtr->chainPtr, CompareNodesByTclCmd); } else { Blt_ChainSort(treePtr->chainPtr, CompareNodesByName); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * UnmapNode -- * * Unmaps the given node. The node will not be drawn. Ignore * unmapping of the root node (it makes no sense). * * Results: * Always returns TCL_OK. * *---------------------------------------------------------------------- */ static int UnmapNode(hboxPtr, treePtr) Hierbox *hboxPtr; Tree *treePtr; { if (treePtr != hboxPtr->rootPtr) { treePtr->entryPtr->flags &= ~ENTRY_MAPPED; } return TCL_OK; } /* *---------------------------------------------------------------------- * * MapAncestors -- * * If a node in mapped, then all its ancestors must be mapped also. * This routine traverses upwards and maps each unmapped ancestor. * It's assumed that for any mapped ancestor, all it's ancestors * will already be mapped too. * * Results: * Always returns TCL_OK. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int MapAncestors(hboxPtr, treePtr) Hierbox *hboxPtr; /* Not used. */ Tree *treePtr; { /* * Make sure that all the ancestors of this node are mapped too. */ treePtr = treePtr->parentPtr; while (treePtr != NULL) { if (treePtr->entryPtr->flags & ENTRY_MAPPED) { break; /* Assume ancestors are also mapped. */ } treePtr->entryPtr->flags |= ENTRY_MAPPED; treePtr = treePtr->parentPtr; } return TCL_OK; } /* *---------------------------------------------------------------------- * * MapNode -- * * Maps the given node. Only mapped nodes are drawn. * * Results: * Always returns TCL_OK. * *---------------------------------------------------------------------- */ static int MapNode(hboxPtr, treePtr) Hierbox *hboxPtr; Tree *treePtr; { treePtr->entryPtr->flags |= ENTRY_MAPPED; MapAncestors(hboxPtr, treePtr); return TCL_OK; } static int FixUnmappedSelections(hboxPtr, treePtr) Hierbox *hboxPtr; Tree *treePtr; { if (!(treePtr->entryPtr->flags & ENTRY_MAPPED)) { DeselectEntry(hboxPtr, treePtr); PruneSelection(hboxPtr, treePtr); if (IsAncestor(treePtr, hboxPtr->focusPtr)) { hboxPtr->focusPtr = treePtr->parentPtr; if (hboxPtr->focusPtr == NULL) { hboxPtr->focusPtr = hboxPtr->rootPtr; } Blt_SetFocusItem(hboxPtr->bindTable, hboxPtr->focusPtr, NULL); } } return TCL_OK; } static int DeleteNode(hboxPtr, treePtr) Hierbox *hboxPtr; Tree *treePtr; { /* * Indicate that the screen layout of the hierarchy may have changed * because the node was deleted. We don't want to access the * hboxPtr->visibleArr array if one of the nodes is bogus. */ hboxPtr->flags |= HIERBOX_DIRTY; if (treePtr == hboxPtr->activePtr) { hboxPtr->activePtr = treePtr->parentPtr; } if (treePtr == hboxPtr->activeButtonPtr) { hboxPtr->activeButtonPtr = NULL; } if (treePtr == hboxPtr->focusPtr) { hboxPtr->focusPtr = treePtr->parentPtr; Blt_SetFocusItem(hboxPtr->bindTable, hboxPtr->focusPtr, NULL); } if (treePtr == hboxPtr->selAnchorPtr) { hboxPtr->selAnchorPtr = NULL; } DeselectEntry(hboxPtr, treePtr); PruneSelection(hboxPtr, treePtr); if (treePtr->linkPtr != NULL) { /* Remove from parent's list */ Blt_ChainDeleteLink(treePtr->parentPtr->chainPtr, treePtr->linkPtr); treePtr->linkPtr = NULL; } /* * Node may still be in use, so we can't free it right now. We'll * mark the parent as NULL and remove it from the parent's list of * children. */ treePtr->parentPtr = NULL; Blt_DeleteBindings(hboxPtr->bindTable, treePtr); Blt_DeleteBindings(hboxPtr->buttonBindTable, treePtr); Tcl_EventuallyFree(treePtr, DestroyNode); return TCL_OK; } /* *---------------------------------------------------------------------- * * DestroyTree -- * * Recursively deletes the given node and all its subnodes. * * Results: * If successful, returns TCL_OK. Otherwise TCL_ERROR is * returned. * *---------------------------------------------------------------------- */ static int DestroyTree(hboxPtr, treePtr) Hierbox *hboxPtr; Tree *treePtr; { return ApplyToTree(hboxPtr, treePtr, DeleteNode, APPLY_RECURSE); } /*ARGSUSED*/ static void GetTags(table, object, context, list) Blt_BindTable table; /* Not used. */ ClientData object; ClientData context; /* Not used. */ Blt_List list; { Tree *treePtr; Blt_ListAppend(list, (char *)object, 0); treePtr = (Tree *) object; if (treePtr->entryPtr->tags != NULL) { int nNames; char **names; register char **p; if (Tcl_SplitList((Tcl_Interp *)NULL, treePtr->entryPtr->tags, &nNames, &names) == TCL_OK) { for (p = names; *p != NULL; p++) { Blt_ListAppend(list, Tk_GetUid(*p), 0); } Blt_Free(names); } } } /*ARGSUSED*/ static ClientData PickButton(clientData, x, y, contextPtr) ClientData clientData; int x, y; /* Screen coordinates of the test point. */ ClientData *contextPtr; /* Not used. */ { Hierbox *hboxPtr = clientData; Entry *entryPtr; Tree *treePtr; if (hboxPtr->flags & HIERBOX_DIRTY) { /* Can't trust selected entry, if entries have been added or deleted. */ if (hboxPtr->flags & HIERBOX_LAYOUT) { ComputeLayout(hboxPtr); } ComputeVisibleEntries(hboxPtr); } if (hboxPtr->nVisible == 0) { return (ClientData) 0; } treePtr = NearestNode(hboxPtr, x, y, FALSE); if (treePtr == NULL) { return (ClientData) 0; } entryPtr = treePtr->entryPtr; if (entryPtr->flags & ENTRY_BUTTON) { ButtonAttributes *buttonPtr = &(hboxPtr->button); int left, right, top, bottom; #define BUTTON_PAD 2 left = entryPtr->worldX + entryPtr->buttonX - BUTTON_PAD; right = left + buttonPtr->width + 2 * BUTTON_PAD; top = entryPtr->worldY + entryPtr->buttonY - BUTTON_PAD; bottom = top + buttonPtr->height + 2 * BUTTON_PAD; x = WORLDX(hboxPtr, x); y = WORLDY(hboxPtr, y); if ((x >= left) && (x < right) && (y >= top) && (y < bottom)) { return treePtr; } } return (ClientData) 0; } /*ARGSUSED*/ static ClientData PickEntry(clientData, x, y, contextPtr) ClientData clientData; int x, y; /* Screen coordinates of the test point. */ ClientData *contextPtr; /* Not used. */ { Hierbox *hboxPtr = clientData; Entry *entryPtr; Tree *treePtr; if (hboxPtr->flags & HIERBOX_DIRTY) { /* Can't trust selected entry, if entries have been added or deleted. */ if (hboxPtr->flags & HIERBOX_LAYOUT) { ComputeLayout(hboxPtr); } ComputeVisibleEntries(hboxPtr); } if (hboxPtr->nVisible == 0) { return (ClientData) 0; } treePtr = NearestNode(hboxPtr, x, y, FALSE); if (treePtr == NULL) { return (ClientData) 0; } entryPtr = treePtr->entryPtr; if (entryPtr->flags & ENTRY_BUTTON) { ButtonAttributes *buttonPtr = &(hboxPtr->button); int left, right, top, bottom; #define BUTTON_PAD 2 left = entryPtr->worldX + entryPtr->buttonX - BUTTON_PAD; right = left + buttonPtr->width + 2 * BUTTON_PAD; top = entryPtr->worldY + entryPtr->buttonY - BUTTON_PAD; bottom = top + buttonPtr->height + 2 * BUTTON_PAD; x = WORLDX(hboxPtr, x); y = WORLDY(hboxPtr, y); if ((x >= left) && (x < right) && (y >= top) && (y < bottom)) { return NULL; } } return treePtr; } static int ConfigureEntry(hboxPtr, entryPtr, argc, argv, flags) Hierbox *hboxPtr; Entry *entryPtr; int argc; char **argv; int flags; { GC newGC; XGCValues gcValues; unsigned long gcMask; int entryWidth, entryHeight; int width, height; Tk_Font font; XColor *colorPtr; hierBox = hboxPtr; if (Tk_ConfigureWidget(hboxPtr->interp, hboxPtr->tkwin, entryConfigSpecs, argc, argv, (char *)entryPtr, flags) != TCL_OK) { return TCL_ERROR; } entryPtr->iconWidth = entryPtr->iconHeight = 0; if (entryPtr->icons != NULL) { register int i; for (i = 0; i < 2; i++) { if (entryPtr->icons[i] == NULL) { break; } if (entryPtr->iconWidth < ImageWidth(entryPtr->icons[i])) { entryPtr->iconWidth = ImageWidth(entryPtr->icons[i]); } if (entryPtr->iconHeight < ImageHeight(entryPtr->icons[i])) { entryPtr->iconHeight = ImageHeight(entryPtr->icons[i]); } } } newGC = NULL; if ((entryPtr->icons == NULL) || (entryPtr->icons[0] == NULL)) { gcMask = GCClipMask | GCBackground; gcValues.clip_mask = hboxPtr->iconMask; gcValues.background = hboxPtr->iconColor->pixel; newGC = Tk_GetGC(hboxPtr->tkwin, gcMask, &gcValues); entryPtr->iconWidth = DEF_ICON_WIDTH; entryPtr->iconHeight = DEF_ICON_HEIGHT; } entryPtr->iconWidth += 2 * ICON_PADX; entryPtr->iconHeight += 2 * ICON_PADY; if (entryPtr->iconGC != NULL) { Tk_FreeGC(hboxPtr->display, entryPtr->iconGC); } entryPtr->iconGC = newGC; entryHeight = MAX(entryPtr->iconHeight, hboxPtr->button.height); entryWidth = 0; gcMask = GCForeground | GCFont; colorPtr = GETCOLOR(hboxPtr, entryPtr->labelColor); gcValues.foreground = colorPtr->pixel; font = GETFONT(hboxPtr, entryPtr->labelFont); gcValues.font = Tk_FontId(font); newGC = Tk_GetGC(hboxPtr->tkwin, gcMask, &gcValues); if (entryPtr->labelGC != NULL) { Tk_FreeGC(hboxPtr->display, entryPtr->labelGC); } entryPtr->labelGC = newGC; if (*entryPtr->labelText == '\0') { Tk_FontMetrics fontMetrics; Tk_GetFontMetrics(font, &fontMetrics); width = height = fontMetrics.linespace; } else { TextStyle ts; Blt_InitTextStyle(&ts); ts.shadow.offset = entryPtr->labelShadow.offset; ts.font = font; Blt_GetTextExtents(&ts, entryPtr->labelText, &width, &height); } width += 2 * (FOCUS_WIDTH + LABEL_PADX + hboxPtr->selBorderWidth); height += 2 * (FOCUS_WIDTH + LABEL_PADY + hboxPtr->selBorderWidth); width = ODD(width); height = ODD(height); entryWidth += width; if (entryHeight < height) { entryHeight = height; } entryPtr->labelWidth = width; entryPtr->labelHeight = height; width = height = 0; if (entryPtr->images != NULL) { register CachedImage *imagePtr; for (imagePtr = entryPtr->images; *imagePtr != NULL; imagePtr++) { width += ImageWidth(*imagePtr); if (height < ImageHeight(*imagePtr)) { height = ImageHeight(*imagePtr); } } } else if (entryPtr->dataText != NULL) { TextStyle ts; gcMask = GCForeground | GCFont; colorPtr = GETCOLOR(hboxPtr, entryPtr->dataColor); gcValues.foreground = colorPtr->pixel; font = GETFONT(hboxPtr, entryPtr->dataFont); gcValues.font = Tk_FontId(font); newGC = Tk_GetGC(hboxPtr->tkwin, gcMask, &gcValues); if (entryPtr->dataGC != NULL) { Tk_FreeGC(hboxPtr->display, entryPtr->dataGC); } entryPtr->dataGC = newGC; Blt_InitTextStyle(&ts); ts.font = font; ts.shadow.offset = entryPtr->dataShadow.offset; Blt_GetTextExtents(&ts, entryPtr->dataText, &width, &height); width += 2 * LABEL_PADX; height += 2 * LABEL_PADY; } entryWidth += width; if (entryHeight < height) { entryHeight = height; } entryPtr->width = entryWidth + 4; entryPtr->height = entryHeight + hboxPtr->leader; /* * Force the height of the entry to an even number. This is to * make the dots or the vertical line segments coincide with the * start of the horizontal lines. */ if (entryPtr->height & 0x01) { entryPtr->height++; } hboxPtr->flags |= HIERBOX_LAYOUT; EventuallyRedraw(hboxPtr); return TCL_OK; } /* * Hierbox Procedures */ /* *---------------------------------------------------------------------- * * EventuallyRedraw -- * * Queues a request to redraw the widget at the next idle point. * * Results: * None. * * Side effects: * Information gets redisplayed. Right now we don't do selective * redisplays: the whole window will be redrawn. * *---------------------------------------------------------------------- */ static void EventuallyRedraw(hboxPtr) Hierbox *hboxPtr; { if ((hboxPtr->tkwin != NULL) && !(hboxPtr->flags & HIERBOX_REDRAW)) { hboxPtr->flags |= HIERBOX_REDRAW; Tcl_DoWhenIdle(DisplayHierbox, hboxPtr); } } /* *---------------------------------------------------------------------- * * LabelBlinkProc -- * * This procedure is called as a timer handler to blink the * insertion cursor off and on. * * Results: * None. * * Side effects: * The cursor gets turned on or off, redisplay gets invoked, * and this procedure reschedules itself. * *---------------------------------------------------------------------- */ static void LabelBlinkProc(clientData) ClientData clientData; /* Pointer to record describing entry. */ { Hierbox *hboxPtr = clientData; TextEdit *editPtr = &(hboxPtr->labelEdit); int interval; if (!(hboxPtr->flags & HIERBOX_FOCUS) || (editPtr->offTime == 0)) { return; } if (editPtr->active) { editPtr->cursorOn ^= 1; interval = (editPtr->cursorOn) ? editPtr->onTime : editPtr->offTime; editPtr->timerToken = Tcl_CreateTimerHandler(interval, LabelBlinkProc, hboxPtr); EventuallyRedraw(hboxPtr); } } /* *---------------------------------------------------------------------- * * EventuallyInvokeSelectCmd -- * * Queues a request to execute the -selectcommand code associated * with the widget at the next idle point. Invoked whenever the * selection changes. * * Results: * None. * * Side effects: * Tcl code gets executed for some application-specific task. * *---------------------------------------------------------------------- */ static void EventuallyInvokeSelectCmd(hboxPtr) Hierbox *hboxPtr; { if (!(hboxPtr->flags & SELECTION_PENDING)) { hboxPtr->flags |= SELECTION_PENDING; Tcl_DoWhenIdle(SelectCmdProc, hboxPtr); } } /* * ---------------------------------------------------------------------- * * CreateHierbox -- * * ---------------------------------------------------------------------- */ static Hierbox * CreateHierbox(interp, tkwin) Tcl_Interp *interp; Tk_Window tkwin; { Hierbox *hboxPtr; hboxPtr = Blt_Calloc(1, sizeof(Hierbox)); assert(hboxPtr); Tk_SetClass(tkwin, "Hierbox"); hboxPtr->tkwin = tkwin; hboxPtr->display = Tk_Display(tkwin); hboxPtr->interp = interp; hboxPtr->leader = 0; hboxPtr->dashes = 1; hboxPtr->highlightWidth = 2; hboxPtr->selBorderWidth = 1; hboxPtr->borderWidth = 2; hboxPtr->relief = TK_RELIEF_SUNKEN; hboxPtr->selRelief = TK_RELIEF_FLAT; hboxPtr->scrollMode = BLT_SCROLL_MODE_HIERBOX; hboxPtr->button.closeRelief = hboxPtr->button.openRelief = TK_RELIEF_SOLID; hboxPtr->reqWidth = 200; hboxPtr->reqHeight = 400; hboxPtr->lineWidth = 1; hboxPtr->button.borderWidth = 1; hboxPtr->labelEdit.selAnchor = -1; hboxPtr->labelEdit.selFirst = hboxPtr->labelEdit.selLast = -1; hboxPtr->labelEdit.onTime = 600, hboxPtr->labelEdit.offTime = 300; Blt_ChainInit(&(hboxPtr->selectChain)); Blt_InitHashTable(&(hboxPtr->selectTable), BLT_ONE_WORD_KEYS); Blt_InitHashTable(&(hboxPtr->nodeTable), BLT_ONE_WORD_KEYS); Blt_InitHashTable(&(hboxPtr->imageTable), BLT_STRING_KEYS); hboxPtr->bindTable = Blt_CreateBindingTable(interp, tkwin, hboxPtr, PickEntry, GetTags); hboxPtr->buttonBindTable = Blt_CreateBindingTable(interp, tkwin, hboxPtr, PickButton, GetTags); #if (TK_MAJOR_VERSION > 4) Blt_SetWindowInstanceData(tkwin, hboxPtr); #endif return hboxPtr; } /* * ---------------------------------------------------------------------- * * DestroyHierbox -- * * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release * to clean up the internal structure of a Hierbox at a safe time * (when no-one is using it anymore). * * Results: * None. * * Side effects: * Everything associated with the widget is freed up. * * ---------------------------------------------------------------------- */ static void DestroyHierbox(dataPtr) DestroyData dataPtr; /* Pointer to the widget record. */ { Hierbox *hboxPtr = (Hierbox *)dataPtr; ButtonAttributes *buttonPtr = &(hboxPtr->button); Tk_FreeOptions(configSpecs, (char *)hboxPtr, hboxPtr->display, 0); if (hboxPtr->tkwin != NULL) { Tk_DeleteSelHandler(hboxPtr->tkwin, XA_PRIMARY, XA_STRING); } if (hboxPtr->lineGC != NULL) { Tk_FreeGC(hboxPtr->display, hboxPtr->lineGC); } if (hboxPtr->focusGC != NULL) { Blt_FreePrivateGC(hboxPtr->display, hboxPtr->focusGC); } if (hboxPtr->tile != NULL) { Blt_FreeTile(hboxPtr->tile); } if (hboxPtr->visibleArr != NULL) { Blt_Free(hboxPtr->visibleArr); } if (hboxPtr->levelInfo != NULL) { Blt_Free(hboxPtr->levelInfo); } if (hboxPtr->iconBitmap != None) { Tk_FreeBitmap(hboxPtr->display, hboxPtr->iconBitmap); } if (hboxPtr->iconMask != None) { Tk_FreeBitmap(hboxPtr->display, hboxPtr->iconMask); } if (hboxPtr->iconColor != NULL) { Tk_FreeColor(hboxPtr->iconColor); } if (buttonPtr->images != NULL) { register CachedImage *imagePtr; for (imagePtr = buttonPtr->images; *imagePtr != NULL; imagePtr++) { FreeCachedImage(hboxPtr, *imagePtr); } Blt_Free(buttonPtr->images); } if (buttonPtr->activeGC != NULL) { Tk_FreeGC(hboxPtr->display, buttonPtr->activeGC); } if (buttonPtr->normalGC != NULL) { Tk_FreeGC(hboxPtr->display, buttonPtr->normalGC); } if (buttonPtr->lineGC != NULL) { Tk_FreeGC(hboxPtr->display, buttonPtr->lineGC); } DestroyTree(hboxPtr, hboxPtr->rootPtr); Blt_DeleteHashTable(&(hboxPtr->nodeTable)); Blt_ChainReset(&(hboxPtr->selectChain)); Blt_DeleteHashTable(&(hboxPtr->selectTable)); Blt_DestroyBindingTable(hboxPtr->bindTable); Blt_DestroyBindingTable(hboxPtr->buttonBindTable); Blt_Free(hboxPtr); } /* * -------------------------------------------------------------- * * HierboxEventProc -- * * This procedure is invoked by the Tk dispatcher for various * events on hierarchy widgets. * * Results: * None. * * Side effects: * When the window gets deleted, internal structures get * cleaned up. When it gets exposed, it is redisplayed. * * -------------------------------------------------------------- */ static void HierboxEventProc(clientData, eventPtr) ClientData clientData; /* Information about window. */ XEvent *eventPtr; /* Information about event. */ { Hierbox *hboxPtr = clientData; if (eventPtr->type == Expose) { if (eventPtr->xexpose.count == 0) { EventuallyRedraw(hboxPtr); } } else if (eventPtr->type == ConfigureNotify) { hboxPtr->flags |= (HIERBOX_LAYOUT | HIERBOX_SCROLL); EventuallyRedraw(hboxPtr); } else if ((eventPtr->type == FocusIn) || (eventPtr->type == FocusOut)) { if (eventPtr->xfocus.detail != NotifyInferior) { TextEdit *editPtr = &(hboxPtr->labelEdit); if (eventPtr->type == FocusIn) { hboxPtr->flags |= HIERBOX_FOCUS; } else { hboxPtr->flags &= ~HIERBOX_FOCUS; } Tcl_DeleteTimerHandler(editPtr->timerToken); if ((editPtr->active) && (hboxPtr->flags & HIERBOX_FOCUS)) { editPtr->cursorOn = TRUE; if (editPtr->offTime != 0) { editPtr->timerToken = Tcl_CreateTimerHandler(editPtr->onTime, LabelBlinkProc, clientData); } } else { editPtr->cursorOn = FALSE; editPtr->timerToken = (Tcl_TimerToken) NULL; } EventuallyRedraw(hboxPtr); } } else if (eventPtr->type == DestroyNotify) { if (hboxPtr->tkwin != NULL) { hboxPtr->tkwin = NULL; Tcl_DeleteCommandFromToken(hboxPtr->interp, hboxPtr->cmdToken); } if (hboxPtr->flags & HIERBOX_REDRAW) { Tcl_CancelIdleCall(DisplayHierbox, hboxPtr); } if (hboxPtr->flags & SELECTION_PENDING) { Tcl_CancelIdleCall(SelectCmdProc, hboxPtr); } Tcl_EventuallyFree(hboxPtr, DestroyHierbox); } } /* Selection Procedures */ /* *---------------------------------------------------------------------- * * SelectionProc -- * * This procedure is called back by Tk when the selection is * requested by someone. It returns part or all of the selection * in a buffer provided by the caller. * * Results: * The return value is the number of non-NULL bytes stored at * buffer. Buffer is filled (or partially filled) with a * NUL-terminated string containing part or all of the * selection, as given by offset and maxBytes. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int SelectionProc(clientData, offset, buffer, maxBytes) ClientData clientData; /* Information about the widget. */ int offset; /* Offset within selection of first * character to be returned. */ char *buffer; /* Location in which to place * selection. */ int maxBytes; /* Maximum number of bytes to place * at buffer, not including terminating * NULL character. */ { Hierbox *hboxPtr = clientData; int size; Tcl_DString dString; if (!hboxPtr->exportSelection) { return -1; } /* * Retrieve the names of the selected entries. */ Tcl_DStringInit(&dString); if (hboxPtr->sortSelection) { hboxPtr->clientData = &dString; ApplyToTree(hboxPtr, hboxPtr->rootPtr, GetSelectedLabels, APPLY_RECURSE | APPLY_BEFORE | APPLY_OPEN_ONLY); } else { Blt_ChainLink *linkPtr; Tree *treePtr; for (linkPtr = Blt_ChainFirstLink(&(hboxPtr->selectChain)); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { treePtr = Blt_ChainGetValue(linkPtr); Tcl_DStringAppend(&dString, treePtr->entryPtr->labelText, -1); Tcl_DStringAppend(&dString, "\n", -1); } } size = Tcl_DStringLength(&dString) - offset; strncpy(buffer, Tcl_DStringValue(&dString) + offset, maxBytes); Tcl_DStringFree(&dString); buffer[maxBytes] = '\0'; return (size > maxBytes) ? maxBytes : size; } /* *---------------------------------------------------------------------- * * LostSelection -- * * This procedure is called back by Tk when the selection is grabbed * away. * * Results: * None. * * Side effects: * The existing selection is unhighlighted, and the window is * marked as not containing a selection. * *---------------------------------------------------------------------- */ static void LostSelection(clientData) ClientData clientData; /* Information about the widget. */ { Hierbox *hboxPtr = clientData; if ((hboxPtr->selAnchorPtr != NULL) && (hboxPtr->exportSelection)) { ClearSelection(hboxPtr); } } /* *---------------------------------------------------------------------- * * HierboxInstCmdDeleteProc -- * * This procedure is invoked when a widget command is deleted. If * the widget isn't already in the process of being destroyed, * this command destroys it. * * Results: * None. * * Side effects: * The widget is destroyed. * *---------------------------------------------------------------------- */ static void HierboxInstCmdDeleteProc(clientData) ClientData clientData; /* Pointer to widget record for widget. */ { Hierbox *hboxPtr = clientData; /* * This procedure could be invoked either because the window was * destroyed and the command was then deleted (in which case tkwin * is NULL) or because the command was deleted, and then this * procedure destroys the widget. */ if (hboxPtr->tkwin != NULL) { Tk_Window tkwin; tkwin = hboxPtr->tkwin; hboxPtr->tkwin = NULL; Tk_DestroyWindow(tkwin); #ifdef ITCL_NAMESPACES Itk_SetWidgetCommand(tkwin, (Tcl_Command) NULL); #endif /* ITCL_NAMESPACES */ } } /* *---------------------------------------------------------------------- * * TileChangedProc * * Stub for image change notifications. Since we immediately draw * the image into a pixmap, we don't care about image changes. * * It would be better if Tk checked for NULL proc pointers. * * Results: * None. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static void TileChangedProc(clientData, tile) ClientData clientData; Blt_Tile tile; /* Not used. */ { Hierbox *hboxPtr = clientData; if (hboxPtr->tkwin != NULL) { EventuallyRedraw(hboxPtr); } } /* * ---------------------------------------------------------------------- * * ConfigureHierbox -- * * This procedure is called to process an argv/argc list, plus * the Tk option database, in order to configure (or reconfigure) * the widget. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then interp->result contains an error message. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for hboxPtr; old resources get freed, if there * were any. The widget is redisplayed. * * ---------------------------------------------------------------------- */ static int ConfigureHierbox(interp, hboxPtr, argc, argv, flags) Tcl_Interp *interp; /* Interpreter to report errors back to. */ Hierbox *hboxPtr; /* Information about widget; may or may not * already have values for some fields. */ int argc; char **argv; int flags; { XGCValues gcValues; unsigned long gcMask; GC newGC; Tk_Uid nameId; Pixmap bitmap; hierBox = hboxPtr; if (Tk_ConfigureWidget(interp, hboxPtr->tkwin, configSpecs, argc, argv, (char *)hboxPtr, flags) != TCL_OK) { return TCL_ERROR; } if (Blt_ConfigModified(configSpecs, "-font", "-linespacing", "-width", "-height", "-hideroot", (char *)NULL)) { /* * These options change the layout of the box. Mark for * update. */ hboxPtr->flags |= (HIERBOX_LAYOUT | HIERBOX_SCROLL); } if ((hboxPtr->reqHeight != Tk_ReqHeight(hboxPtr->tkwin)) || (hboxPtr->reqWidth != Tk_ReqWidth(hboxPtr->tkwin))) { Tk_GeometryRequest(hboxPtr->tkwin, hboxPtr->reqWidth, hboxPtr->reqHeight); } gcMask = (GCForeground | GCLineWidth); gcValues.foreground = hboxPtr->lineColor->pixel; gcValues.line_width = hboxPtr->lineWidth; if (hboxPtr->dashes > 0) { gcMask |= (GCLineStyle | GCDashList); gcValues.line_style = LineOnOffDash; gcValues.dashes = hboxPtr->dashes; } newGC = Tk_GetGC(hboxPtr->tkwin, gcMask, &gcValues); if (hboxPtr->lineGC != NULL) { Tk_FreeGC(hboxPtr->display, hboxPtr->lineGC); } hboxPtr->lineGC = newGC; /* * GC for active label. Dashed outline. */ gcMask = GCForeground | GCLineStyle; gcValues.foreground = hboxPtr->focusColor->pixel; gcValues.line_style = (LineIsDashed(hboxPtr->focusDashes)) ? LineOnOffDash : LineSolid; newGC = Blt_GetPrivateGC(hboxPtr->tkwin, gcMask, &gcValues); if (LineIsDashed(hboxPtr->focusDashes)) { hboxPtr->focusDashes.offset = 2; Blt_SetDashes(hboxPtr->display, newGC, &(hboxPtr->focusDashes)); } if (hboxPtr->focusGC != NULL) { Blt_FreePrivateGC(hboxPtr->display, hboxPtr->focusGC); } hboxPtr->focusGC = newGC; if (hboxPtr->iconBitmap == None) { nameId = Tk_GetUid("HierboxFolder"); bitmap = Tk_GetBitmap(interp, hboxPtr->tkwin, nameId); if (bitmap == None) { if (Tk_DefineBitmap(interp, nameId, (char *)folderBits, DEF_ICON_WIDTH, DEF_ICON_HEIGHT) != TCL_OK) { return TCL_ERROR; } bitmap = Tk_GetBitmap(interp, hboxPtr->tkwin, nameId); if (bitmap == None) { return TCL_ERROR; } } hboxPtr->iconBitmap = bitmap; Tcl_ResetResult(interp); } if (hboxPtr->iconMask == None) { nameId = Tk_GetUid("HierboxFolderMask"); bitmap = Tk_GetBitmap(interp, hboxPtr->tkwin, nameId); if (bitmap == None) { if (Tk_DefineBitmap(interp, nameId, (char *)folderMaskBits, DEF_ICON_WIDTH, DEF_ICON_HEIGHT) != TCL_OK) { return TCL_ERROR; } bitmap = Tk_GetBitmap(interp, hboxPtr->tkwin, nameId); if (bitmap == None) { return TCL_ERROR; } } hboxPtr->iconMask = bitmap; Tcl_ResetResult(interp); } if (hboxPtr->iconColor == NULL) { hboxPtr->iconColor = Tk_GetColor(interp, hboxPtr->tkwin, Tk_GetUid("yellow")); if (hboxPtr->iconColor == NULL) { return TCL_ERROR; } } if (hboxPtr->tile != NULL) { Blt_SetTileChangedProc(hboxPtr->tile, TileChangedProc, hboxPtr); } ConfigureButtons(hboxPtr); hboxPtr->inset = hboxPtr->highlightWidth + hboxPtr->borderWidth + INSET_PAD; EventuallyRedraw(hboxPtr); return TCL_OK; } /* * ---------------------------------------------------------------------- * * ResetCoordinates -- * * Determines the maximum height of all visible entries. * * Results: * Returns 1 if beyond the last visible entry, 0 otherwise. * * Side effects: * The array of visible nodes is filled. * * ---------------------------------------------------------------------- */ static void ResetCoordinates(hboxPtr, treePtr, infoPtr) Hierbox *hboxPtr; Tree *treePtr; LayoutInfo *infoPtr; { Entry *entryPtr = treePtr->entryPtr; int width; /* * If the entry is hidden, then do nothing. * Otherwise, include it in the layout. */ entryPtr->worldY = infoPtr->y; if (!(entryPtr->flags & ENTRY_MAPPED)) { return; } treePtr->level = infoPtr->level; if (infoPtr->depth < infoPtr->level) { infoPtr->depth = infoPtr->level; } if ((entryPtr->flags & BUTTON_SHOW) || ((entryPtr->flags & BUTTON_AUTO) && (Blt_ChainGetLength(treePtr->chainPtr) > 0))) { entryPtr->flags |= ENTRY_BUTTON; } else { entryPtr->flags &= ~ENTRY_BUTTON; } if (entryPtr->height < infoPtr->minHeight) { infoPtr->minHeight = entryPtr->height; } /* * Note: The maximum entry width below does not take into account * the space for the icon (level offset). This has to be * deferred because it's dependent upon the maximum icon * size. */ width = infoPtr->x + entryPtr->width; if (width > infoPtr->maxWidth) { infoPtr->maxWidth = width; } if (infoPtr->maxIconWidth < entryPtr->iconWidth) { infoPtr->maxIconWidth = entryPtr->iconWidth; } entryPtr->lineHeight = -(infoPtr->y); infoPtr->y += entryPtr->height; if (entryPtr->flags & ENTRY_OPEN) { Blt_ChainLink *linkPtr; int labelOffset; Tree *bottomPtr; infoPtr->level++; labelOffset = infoPtr->labelOffset; infoPtr->labelOffset = 0; bottomPtr = treePtr; for (linkPtr = Blt_ChainFirstLink(treePtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { treePtr = Blt_ChainGetValue(linkPtr); if (treePtr->entryPtr->flags & ENTRY_MAPPED) { ResetCoordinates(hboxPtr, treePtr, infoPtr); bottomPtr = treePtr; } } infoPtr->level--; entryPtr->lineHeight += bottomPtr->entryPtr->worldY; entryPtr->levelX = infoPtr->labelOffset; infoPtr->labelOffset = labelOffset; } if (infoPtr->labelOffset < entryPtr->labelWidth) { infoPtr->labelOffset = entryPtr->labelWidth; } } /* * ---------------------------------------------------------------------- * * ComputeWidths -- * * Determines the maximum height of all visible entries. * * Results: * Returns 1 if beyond the last visible entry, 0 otherwise. * * Side effects: * The array of visible nodes is filled. * * ---------------------------------------------------------------------- */ static void ComputeWidths(hboxPtr, treePtr) Hierbox *hboxPtr; Tree *treePtr; { Entry *entryPtr = treePtr->entryPtr; if (!(entryPtr->flags & ENTRY_MAPPED)) { return; } if (entryPtr->iconWidth > LEVELWIDTH(treePtr->level + 1)) { LEVELWIDTH(treePtr->level + 1) = entryPtr->iconWidth; } if (entryPtr->flags & ENTRY_OPEN) { Blt_ChainLink *linkPtr; for (linkPtr = Blt_ChainFirstLink(treePtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { treePtr = Blt_ChainGetValue(linkPtr); if (treePtr->entryPtr->flags & ENTRY_MAPPED) { ComputeWidths(hboxPtr, treePtr); } } } } /* * ---------------------------------------------------------------------- * * ComputeLayout -- * * Recompute the layout when entries are opened/closed, * inserted/deleted, or when text attributes change (such as * font, linespacing). * * Results: * None. * * Side effects: * The world coordinates are set for all the opened entries. * * ---------------------------------------------------------------------- */ static void ComputeLayout(hboxPtr) Hierbox *hboxPtr; { LayoutInfo info; info.level = info.depth = 0; info.x = info.y = 0; info.maxWidth = hboxPtr->button.width; info.maxIconWidth = hboxPtr->button.width; info.minHeight = INT_MAX; info.labelOffset = 0; if (hboxPtr->hideRoot) { info.y = -(hboxPtr->rootPtr->entryPtr->height); } ResetCoordinates(hboxPtr, hboxPtr->rootPtr, &info); hboxPtr->xScrollUnits = info.maxIconWidth; hboxPtr->minHeight = hboxPtr->yScrollUnits = info.minHeight; if (hboxPtr->reqScrollX > 0) { hboxPtr->xScrollUnits = hboxPtr->reqScrollX; } if (hboxPtr->reqScrollY > 0) { hboxPtr->yScrollUnits = hboxPtr->reqScrollY; } hboxPtr->depth = info.depth + 1; hboxPtr->worldWidth = info.maxWidth + (hboxPtr->depth * info.maxIconWidth); if (hboxPtr->worldWidth < 1) { hboxPtr->worldWidth = 1; } hboxPtr->worldHeight = info.y; if (hboxPtr->worldHeight < 1) { hboxPtr->worldHeight = 1; } if (hboxPtr->yScrollUnits < 1) { hboxPtr->yScrollUnits = 1; } if (hboxPtr->xScrollUnits < 1) { hboxPtr->xScrollUnits = 1; } if (hboxPtr->levelInfo != NULL) { Blt_Free(hboxPtr->levelInfo); } hboxPtr->levelInfo = Blt_Calloc(hboxPtr->depth + 2, sizeof(LevelInfo)); assert(hboxPtr->levelInfo); ComputeWidths(hboxPtr, hboxPtr->rootPtr); { int sum, width; register int i; sum = 0; for (i = 0; i <= hboxPtr->depth; i++) { width = hboxPtr->levelInfo[i].width; width |= 0x01; hboxPtr->levelInfo[i].width = width; sum += width; hboxPtr->levelInfo[i + 1].x = sum; } } hboxPtr->flags &= ~HIERBOX_LAYOUT; } /* * ---------------------------------------------------------------------- * * ComputeVisibleEntries -- * * The entries visible in the viewport (the widget's window) are * inserted into the array of visible nodes. * * Results: * Returns 1 if beyond the last visible entry, 0 otherwise. * * Side effects: * The array of visible nodes is filled. * * ---------------------------------------------------------------------- */ static int ComputeVisibleEntries(hboxPtr) Hierbox *hboxPtr; { Entry *entryPtr; int height; Blt_ChainLink *linkPtr; register Tree *treePtr; int x, maxX; int nSlots; hboxPtr->xOffset = Blt_AdjustViewport(hboxPtr->xOffset, hboxPtr->worldWidth, VPORTWIDTH(hboxPtr), hboxPtr->xScrollUnits, hboxPtr->scrollMode); hboxPtr->yOffset = Blt_AdjustViewport(hboxPtr->yOffset, hboxPtr->worldHeight, VPORTHEIGHT(hboxPtr), hboxPtr->yScrollUnits, hboxPtr->scrollMode); height = VPORTHEIGHT(hboxPtr); /* Allocate worst case number of slots for entry array. */ nSlots = (height / hboxPtr->minHeight) + 3; if ((nSlots != hboxPtr->nVisible) && (hboxPtr->visibleArr != NULL)) { Blt_Free(hboxPtr->visibleArr); } hboxPtr->visibleArr = Blt_Calloc(nSlots, sizeof(Tree *)); assert(hboxPtr->visibleArr); hboxPtr->nVisible = 0; /* Find the node where the view port starts. */ treePtr = hboxPtr->rootPtr; entryPtr = treePtr->entryPtr; while ((entryPtr->worldY + entryPtr->height) <= hboxPtr->yOffset) { for (linkPtr = Blt_ChainLastLink(treePtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainPrevLink(linkPtr)) { treePtr = Blt_ChainGetValue(linkPtr); if (IsHidden(treePtr)) { continue; /* Ignore hidden entries. */ } entryPtr = treePtr->entryPtr; if (entryPtr->worldY <= hboxPtr->yOffset) { break; } } /* * If we can't find the starting node, then the view must be * scrolled down, but some nodes were deleted. Reset the view * back to the top and try again. */ if (linkPtr == NULL) { if (hboxPtr->yOffset == 0) { return TCL_OK; /* All entries are hidden. */ } hboxPtr->yOffset = 0; continue; } } height += hboxPtr->yOffset; maxX = 0; while (treePtr != NULL) { if (!IsHidden(treePtr)) { entryPtr = treePtr->entryPtr; /* * Compute and save the entry's X-coordinate now that we know * what the maximum level offset for the entire Hierbox is. */ entryPtr->worldX = LEVELX(treePtr->level); x = entryPtr->worldX + LEVELWIDTH(treePtr->level) + LEVELWIDTH(treePtr->level + 1) + entryPtr->width; if (x > maxX) { maxX = x; } if (entryPtr->worldY >= height) { break; } hboxPtr->visibleArr[hboxPtr->nVisible] = treePtr; hboxPtr->nVisible++; } treePtr = NextNode(treePtr, ENTRY_OPEN | ENTRY_MAPPED); } hboxPtr->worldWidth = maxX; /* * ------------------------------------------------------------------- * * Note: It's assumed that the view port always starts at or * over an entry. Check that a change in the hierarchy * (e.g. closing a node) hasn't left the viewport beyond * the last entry. If so, adjust the viewport to start * on the last entry. * * ------------------------------------------------------------------- */ if (hboxPtr->xOffset > (hboxPtr->worldWidth - hboxPtr->xScrollUnits)) { hboxPtr->xOffset = hboxPtr->worldWidth - hboxPtr->xScrollUnits; } if (hboxPtr->yOffset > (hboxPtr->worldHeight - hboxPtr->yScrollUnits)) { hboxPtr->yOffset = hboxPtr->worldHeight - hboxPtr->yScrollUnits; } hboxPtr->xOffset = Blt_AdjustViewport(hboxPtr->xOffset, hboxPtr->worldWidth, VPORTWIDTH(hboxPtr), hboxPtr->xScrollUnits, hboxPtr->scrollMode); hboxPtr->yOffset = Blt_AdjustViewport(hboxPtr->yOffset, hboxPtr->worldHeight, VPORTHEIGHT(hboxPtr), hboxPtr->yScrollUnits, hboxPtr->scrollMode); hboxPtr->flags &= ~HIERBOX_DIRTY; return TCL_OK; } static int GetCursorLocation(hboxPtr, treePtr) Hierbox *hboxPtr; Tree *treePtr; { TextEdit *editPtr = &(hboxPtr->labelEdit); int x, y; int maxLines; Tk_Font font; TextStyle ts; TextLayout *textPtr; Tk_FontMetrics fontMetrics; int nBytes; int sum; Entry *entryPtr; TextFragment *fragPtr; register int i; entryPtr = treePtr->entryPtr; font = GETFONT(hboxPtr, entryPtr->labelFont); memset(&ts, 0, sizeof(TextStyle)); ts.font = font; ts.justify = TK_JUSTIFY_LEFT; ts.shadow.offset = entryPtr->labelShadow.offset; textPtr = Blt_GetTextLayout(entryPtr->labelText, &ts); Tk_GetFontMetrics(font, &fontMetrics); maxLines = (textPtr->height / fontMetrics.linespace) - 1; sum = 0; x = y = 0; fragPtr = textPtr->fragArr; for (i = 0; i <= maxLines; i++) { /* Total the number of bytes on each line. Include newlines. */ nBytes = fragPtr->count + 1; if ((sum + nBytes) > editPtr->insertPos) { x += Tk_TextWidth(font, fragPtr->text, editPtr->insertPos - sum); break; } y += fontMetrics.linespace; sum += nBytes; fragPtr++; } editPtr->x = x; editPtr->y = y; editPtr->height = fontMetrics.linespace; editPtr->width = 3; Blt_Free(textPtr); return TCL_OK; } /* * --------------------------------------------------------------------------- * * DrawVerticals -- * * Draws vertical lines for the ancestor nodes. While the entry * of the ancestor may not be visible, its vertical line segment * does extent into the viewport. So walk back up the hierarchy * drawing lines until we get to the root. * * Results: * None. * * Side Effects: * Vertical lines are drawn for the ancestor nodes. * * --------------------------------------------------------------------------- */ static void DrawVerticals(hboxPtr, treePtr, drawable) Hierbox *hboxPtr; /* Widget record containing the attribute * information for buttons. */ Tree *treePtr; /* Entry to be drawn. */ Drawable drawable; /* Pixmap or window to draw into. */ { Entry *entryPtr; /* Entry to be drawn. */ int x1, y1, x2, y2; int height; int x, y; while (treePtr->parentPtr != NULL) { treePtr = treePtr->parentPtr; entryPtr = treePtr->entryPtr; /* * World X-coordinates are computed only for entries that are in * the current view port. So for each of the off-screen ancestor * nodes we must compute it here too. */ entryPtr->worldX = LEVELX(treePtr->level); x = SCREENX(hboxPtr, entryPtr->worldX); y = SCREENY(hboxPtr, entryPtr->worldY); height = MAX(entryPtr->iconHeight, hboxPtr->button.height); y += (height - hboxPtr->button.height) / 2; x1 = x2 = x + LEVELWIDTH(treePtr->level) + LEVELWIDTH(treePtr->level + 1) / 2; y1 = y + hboxPtr->button.height / 2; y2 = y1 + entryPtr->lineHeight; if ((treePtr == hboxPtr->rootPtr) && (hboxPtr->hideRoot)) { y1 += entryPtr->height; } /* * Clip the line's Y-coordinates at the window border. */ if (y1 < 0) { y1 = 0; } if (y2 > Tk_Height(hboxPtr->tkwin)) { y2 = Tk_Height(hboxPtr->tkwin); } if ((y1 < Tk_Height(hboxPtr->tkwin)) && (y2 > 0)) { XDrawLine(hboxPtr->display, drawable, hboxPtr->lineGC, x1, y1, x2, y2); } } } /* * --------------------------------------------------------------------------- * * DrawButton -- * * Draws a button for the given entry. The button is drawn * centered in the region immediately to the left of the origin * of the entry (computed in the layout routines). The height * and width of the button were previously calculated from the * average row height. * * button height = entry height - (2 * some arbitrary padding). * button width = button height. * * The button may have a border. The symbol (either a plus or * minus) is slight smaller than the width or height minus the * border. * * x,y origin of entry * * +---+ * | + | icon label * +---+ * closed * * |----|----| horizontal offset * * +---+ * | - | icon label * +---+ * open * * Results: * None. * * Side Effects: * A button is drawn for the entry. * * --------------------------------------------------------------------------- */ static void DrawButton(hboxPtr, treePtr, drawable) Hierbox *hboxPtr; /* Widget record containing the attribute * information for buttons. */ Tree *treePtr; /* Node of entry. */ Drawable drawable; /* Pixmap or window to draw into. */ { ButtonAttributes *buttonPtr = &(hboxPtr->button); Entry *entryPtr; int relief; Tk_3DBorder border; GC gc, lineGC; int x, y; CachedImage image; int width, height; entryPtr = treePtr->entryPtr; width = LEVELWIDTH(treePtr->level); height = MAX(entryPtr->iconHeight, buttonPtr->height); entryPtr->buttonX = (width - buttonPtr->width) / 2; entryPtr->buttonY = (height - buttonPtr->height) / 2; x = SCREENX(hboxPtr, entryPtr->worldX) + entryPtr->buttonX; y = SCREENY(hboxPtr, entryPtr->worldY) + entryPtr->buttonY; if (treePtr == hboxPtr->activeButtonPtr) { border = buttonPtr->activeBorder; lineGC = buttonPtr->activeGC; } else { border = buttonPtr->border; lineGC = buttonPtr->lineGC; } relief = (entryPtr->flags & ENTRY_OPEN) ? buttonPtr->openRelief : buttonPtr->closeRelief; /* * FIXME: Reliefs "flat" and "solid" the same, since there's no * "solid" in pre-8.0 releases. Should change this when we go to a * pure 8.x release. */ if (relief == TK_RELIEF_SOLID) { relief = TK_RELIEF_FLAT; } Blt_Fill3DRectangle(hboxPtr->tkwin, drawable, border, x, y, buttonPtr->width, buttonPtr->height, buttonPtr->borderWidth, relief); if (relief == TK_RELIEF_FLAT) { XDrawRectangle(hboxPtr->display, drawable, lineGC, x, y, buttonPtr->width - 1, buttonPtr->height - 1); } x += buttonPtr->borderWidth; y += buttonPtr->borderWidth; width = buttonPtr->width - (2 * buttonPtr->borderWidth); height = buttonPtr->height - (2 * buttonPtr->borderWidth); image = NULL; if (buttonPtr->images != NULL) { /* Open or close button image? */ image = buttonPtr->images[0]; if ((entryPtr->flags & ENTRY_OPEN) && (buttonPtr->images[1] != NULL)) { image = buttonPtr->images[1]; } } /* Image or rectangle? */ if (image != NULL) { Tk_RedrawImage(ImageBits(image), 0, 0, width, height, drawable, x, y); } else { XSegment segArr[2]; int count; gc = (treePtr == hboxPtr->activeButtonPtr) ? buttonPtr->activeGC : buttonPtr->normalGC; count = 1; segArr[0].y1 = segArr[0].y2 = y + height / 2; segArr[0].x1 = x + BUTTON_IPAD; #ifdef WIN32 segArr[0].x2 = x + width - BUTTON_IPAD; #else segArr[0].x2 = x + width - BUTTON_IPAD - 1; #endif if (!(entryPtr->flags & ENTRY_OPEN)) { segArr[1].x1 = segArr[1].x2 = x + width / 2; segArr[1].y1 = y + BUTTON_IPAD; #ifdef WIN32 segArr[1].y2 = y + height - BUTTON_IPAD; #else segArr[1].y2 = y + height - BUTTON_IPAD - 1; #endif count++; } XDrawSegments(hboxPtr->display, drawable, gc, segArr, count); } } static void DisplayIcon(hboxPtr, treePtr, x, y, drawable) Hierbox *hboxPtr; /* Widget record containing the attribute * information for buttons. */ Tree *treePtr; /* Node of entry. */ int x, y; Drawable drawable; /* Pixmap or window to draw into. */ { Entry *entryPtr = treePtr->entryPtr; int entryHeight; CachedImage image; int isActive; entryHeight = MAX(entryPtr->iconHeight, hboxPtr->button.height); isActive = (treePtr == hboxPtr->activePtr); image = NULL; if ((isActive) && (entryPtr->activeIcons != NULL)) { image = entryPtr->activeIcons[0]; if ((treePtr == hboxPtr->focusPtr) && (entryPtr->activeIcons[1] != NULL)) { image = entryPtr->activeIcons[1]; } } else if (entryPtr->icons != NULL) { /* Selected or normal icon? */ image = entryPtr->icons[0]; if ((treePtr == hboxPtr->focusPtr) && (entryPtr->icons[1] != NULL)) { image = entryPtr->icons[1]; } } if (image != NULL) { /* Image or default icon bitmap? */ int width, height; int top, bottom; int inset; int maxY; height = ImageHeight(image); width = ImageWidth(image); x += (LEVELWIDTH(treePtr->level + 1) - width) / 2; y += (entryHeight - height) / 2; inset = hboxPtr->inset - INSET_PAD; maxY = Tk_Height(hboxPtr->tkwin) - inset; top = 0; bottom = y + height; if (y < inset) { height += y - inset; top = -y + inset; y = inset; } else if (bottom >= maxY) { height = maxY - y; } Tk_RedrawImage(ImageBits(image), 0, top, width, height, drawable, x, y); } else { x += (LEVELWIDTH(treePtr->level + 1) - DEF_ICON_WIDTH) / 2; y += (entryHeight - DEF_ICON_HEIGHT) / 2; XSetClipOrigin(hboxPtr->display, entryPtr->iconGC, x, y); XCopyPlane(hboxPtr->display, hboxPtr->iconBitmap, drawable, entryPtr->iconGC, 0, 0, DEF_ICON_WIDTH, DEF_ICON_HEIGHT, x, y, 1); } } static void DrawData(hboxPtr, treePtr, x, y, entryHeight, drawable) Hierbox *hboxPtr; /* Widget record containing the attribute * information for buttons. */ Tree *treePtr; /* Node of entry. */ int x, y; int entryHeight; Drawable drawable; /* Pixmap or window to draw into. */ { Entry *entryPtr = treePtr->entryPtr; /* * Auxillary data: text string or images. */ if (entryPtr->images != NULL) { register CachedImage *imagePtr; int imageY; for (imagePtr = entryPtr->images; *imagePtr != NULL; imagePtr++) { imageY = y; if (ImageHeight(*imagePtr) < entryHeight) { imageY += (entryHeight - ImageHeight(*imagePtr)) / 2; } Tk_RedrawImage(ImageBits(*imagePtr), 0, 0, ImageWidth(*imagePtr), ImageHeight(*imagePtr), drawable, x, imageY); x += ImageWidth(*imagePtr); } } else if (entryPtr->dataText != NULL) { TextStyle ts; Tk_Font font; XColor *colorPtr; int width, height; font = GETFONT(hboxPtr, entryPtr->dataFont); colorPtr = GETCOLOR(hboxPtr, entryPtr->dataColor); y += hboxPtr->selBorderWidth + LABEL_PADY; Blt_SetDrawTextStyle(&ts, font, entryPtr->dataGC, colorPtr, hboxPtr->selFgColor, entryPtr->dataShadow.color, 0.0, TK_ANCHOR_NW, TK_JUSTIFY_LEFT, 0, entryPtr->dataShadow.offset); Blt_GetTextExtents(&ts, entryPtr->dataText, &width, &height); if (height < entryHeight) { y += (entryHeight - height) / 2; } Blt_DrawText(hboxPtr->tkwin, drawable, entryPtr->dataText, &ts, x, y); } } static int DrawLabel(hboxPtr, treePtr, x, y, drawable) Hierbox *hboxPtr; /* Widget record containing the attribute * information for buttons. */ Tree *treePtr; /* Node of entry. */ int x, y; Drawable drawable; /* Pixmap or window to draw into. */ { Entry *entryPtr = treePtr->entryPtr; TextEdit *editPtr = &(hboxPtr->labelEdit); TextStyle ts; int width, height; /* Width and height of label. */ Tk_Font font; int isSelected, isFocused; int entryHeight; entryHeight = MAX(entryPtr->iconHeight, hboxPtr->button.height); font = GETFONT(hboxPtr, entryPtr->labelFont); isFocused = ((treePtr == hboxPtr->focusPtr) && (hboxPtr->flags & HIERBOX_FOCUS)); isSelected = IsSelected(hboxPtr, treePtr); /* Includes padding, selection 3-D border, and focus outline. */ width = entryPtr->labelWidth; height = entryPtr->labelHeight; /* Center the label, if necessary, vertically along the entry row. */ if (height < entryHeight) { y += (entryHeight - height) / 2; } #ifdef notdef /* Normal background color */ Blt_Fill3DRectangle(hboxPtr->tkwin, drawable, hboxPtr->border, x, y, width, height, 0, TK_RELIEF_FLAT); #endif if (isFocused) { /* Focus outline */ XDrawRectangle(hboxPtr->display, drawable, hboxPtr->focusGC, x, y, width - 1, height - 1); } x += FOCUS_WIDTH; y += FOCUS_WIDTH; if (isSelected) { Blt_Fill3DRectangle(hboxPtr->tkwin, drawable, hboxPtr->selBorder, x, y, width - 2 * FOCUS_WIDTH, height - 2 * FOCUS_WIDTH, hboxPtr->selBorderWidth, hboxPtr->selRelief); } x += LABEL_PADX + hboxPtr->selBorderWidth; y += LABEL_PADY + hboxPtr->selBorderWidth; if (*entryPtr->labelText != '\0') { XColor *normalColor; normalColor = GETCOLOR(hboxPtr, entryPtr->labelColor); Blt_SetDrawTextStyle(&ts, font, entryPtr->labelGC, normalColor, hboxPtr->selFgColor, entryPtr->labelShadow.color, 0.0, TK_ANCHOR_NW, TK_JUSTIFY_LEFT, 0, entryPtr->labelShadow.offset); ts.state = (isSelected) ? STATE_ACTIVE : 0; Blt_DrawText(hboxPtr->tkwin, drawable, entryPtr->labelText, &ts, x, y); } if ((isFocused) && (hboxPtr->focusEdit) && (editPtr->cursorOn)) { int x1, y1, x2, y2; GetCursorLocation(hboxPtr, treePtr); x1 = x + editPtr->x; x2 = x1 + 3; y1 = y + editPtr->y - 1; y2 = y1 + editPtr->height - 1; XDrawLine(hboxPtr->display, drawable, entryPtr->labelGC, x1, y1, x1, y2); XDrawLine(hboxPtr->display, drawable, entryPtr->labelGC, x1 - 2, y1, x2, y1); XDrawLine(hboxPtr->display, drawable, entryPtr->labelGC, x1 - 2, y2, x2, y2); } return entryHeight; } /* * --------------------------------------------------------------------------- * * DrawEntry -- * * Draws a button for the given entry. Note that buttons should only * be drawn if the entry has sub-entries to be opened or closed. It's * the responsibility of the calling routine to ensure this. * * The button is drawn centered in the region immediately to the left * of the origin of the entry (computed in the layout routines). The * height and width of the button were previously calculated from the * average row height. * * button height = entry height - (2 * some arbitrary padding). * button width = button height. * * The button has a border. The symbol (either a plus or minus) is * slight smaller than the width or height minus the border. * * x,y origin of entry * * +---+ * | + | icon label * +---+ * closed * * |----|----| horizontal offset * * +---+ * | - | icon label * +---+ * open * * Results: * None. * * Side Effects: * A button is drawn for the entry. * * --------------------------------------------------------------------------- */ static void DrawEntry(hboxPtr, treePtr, drawable) Hierbox *hboxPtr; /* Widget record containing the attribute * information for buttons. */ Tree *treePtr; /* Node of entry to be drawn. */ Drawable drawable; /* Pixmap or window to draw into. */ { ButtonAttributes *buttonPtr = &(hboxPtr->button); int x, y; int width, height; int entryHeight; int buttonY; int x1, y1, x2, y2; Entry *entryPtr; entryPtr = treePtr->entryPtr; x = SCREENX(hboxPtr, entryPtr->worldX); y = SCREENY(hboxPtr, entryPtr->worldY); width = LEVELWIDTH(treePtr->level); height = MAX(entryPtr->iconHeight, buttonPtr->height); entryPtr->buttonX = (width - buttonPtr->width) / 2; entryPtr->buttonY = (height - buttonPtr->height) / 2; buttonY = y + entryPtr->buttonY; x1 = x + (width / 2); y1 = y2 = buttonY + (buttonPtr->height / 2); x2 = x1 + (LEVELWIDTH(treePtr->level) + LEVELWIDTH(treePtr->level + 1)) / 2; if ((treePtr->parentPtr != NULL) && (hboxPtr->lineWidth > 0)) { /* * For every node except root, draw a horizontal line from * the vertical bar to the middle of the icon. */ XDrawLine(hboxPtr->display, drawable, hboxPtr->lineGC, x1, y1, x2, y2); } if ((entryPtr->flags & ENTRY_OPEN) && (hboxPtr->lineWidth > 0)) { /* * Entry is open, draw vertical line. */ y2 = y1 + entryPtr->lineHeight; if (y2 > Tk_Height(hboxPtr->tkwin)) { y2 = Tk_Height(hboxPtr->tkwin); /* Clip line at window border. */ } XDrawLine(hboxPtr->display, drawable, hboxPtr->lineGC, x2, y1, x2, y2); } if ((entryPtr->flags & ENTRY_BUTTON) && (treePtr->parentPtr != NULL)) { /* * Except for root, draw a button for every entry that needs * one. The displayed button can be either a Tk image or a * rectangle with plus or minus sign. */ DrawButton(hboxPtr, treePtr, drawable); } x += LEVELWIDTH(treePtr->level); DisplayIcon(hboxPtr, treePtr, x, y, drawable); x += LEVELWIDTH(treePtr->level + 1) + 4; /* Entry label. */ entryHeight = DrawLabel(hboxPtr, treePtr, x, y, drawable); if (treePtr->parentPtr != NULL) { x += treePtr->parentPtr->entryPtr->levelX + LABEL_PADX; } else { x += width + entryPtr->labelWidth + LABEL_PADX; } /* Auxilary data */ DrawData(hboxPtr, treePtr, x, y, entryHeight, drawable); } static void DrawOuterBorders(hboxPtr, drawable) Hierbox *hboxPtr; Drawable drawable; { /* Draw 3D border just inside of the focus highlight ring. */ if ((hboxPtr->borderWidth > 0) && (hboxPtr->relief != TK_RELIEF_FLAT)) { Blt_Draw3DRectangle(hboxPtr->tkwin, drawable, hboxPtr->border, hboxPtr->highlightWidth, hboxPtr->highlightWidth, Tk_Width(hboxPtr->tkwin) - 2 * hboxPtr->highlightWidth, Tk_Height(hboxPtr->tkwin) - 2 * hboxPtr->highlightWidth, hboxPtr->borderWidth, hboxPtr->relief); } /* Draw focus highlight ring. */ if (hboxPtr->highlightWidth > 0) { XColor *color; GC gc; color = (hboxPtr->flags & HIERBOX_FOCUS) ? hboxPtr->highlightColor : hboxPtr->highlightBgColor; gc = Tk_GCForColor(color, drawable); Tk_DrawFocusHighlight(hboxPtr->tkwin, gc, hboxPtr->highlightWidth, drawable); } hboxPtr->flags &= ~HIERBOX_BORDERS; } /* * ---------------------------------------------------------------------- * * DisplayHierbox -- * * This procedure is invoked to display the widget. * * Recompute the layout of the text if necessary. This is * necessary if the world coordinate system has changed. * Specifically, the following may have occurred: * * 1. a text attribute has changed (font, linespacing, etc.). * 2. an entry's option changed, possibly resizing the entry. * * This is deferred to the display routine since potentially * many of these may occur. * * Set the vertical and horizontal scrollbars. This is done * here since the window width and height are needed for the * scrollbar calculations. * * Results: * None. * * Side effects: * The widget is redisplayed. * * ---------------------------------------------------------------------- */ static void DisplayHierbox(clientData) ClientData clientData; /* Information about widget. */ { Hierbox *hboxPtr = clientData; Pixmap drawable; hboxPtr->flags &= ~HIERBOX_REDRAW; if (hboxPtr->tkwin == NULL) { return; /* Window has been destroyed. */ } if (hboxPtr->flags & HIERBOX_LAYOUT) { /* * Recompute the layout when entries are opened/closed, * inserted/deleted, or when text attributes change * (such as font, linespacing). */ ComputeLayout(hboxPtr); } if (hboxPtr->flags & HIERBOX_SCROLL) { int width, height; /* Scrolling means that the view port has changed and that the * visible entries need to be recomputed. */ ComputeVisibleEntries(hboxPtr); Blt_PickCurrentItem(hboxPtr->bindTable); Blt_PickCurrentItem(hboxPtr->buttonBindTable); width = VPORTWIDTH(hboxPtr); height = VPORTHEIGHT(hboxPtr); if (hboxPtr->flags & HIERBOX_XSCROLL) { if (hboxPtr->xScrollCmdPrefix != NULL) { Blt_UpdateScrollbar(hboxPtr->interp, hboxPtr->xScrollCmdPrefix, (double)hboxPtr->xOffset / hboxPtr->worldWidth, (double)(hboxPtr->xOffset + width) / hboxPtr->worldWidth); } } if (hboxPtr->flags & HIERBOX_YSCROLL) { if (hboxPtr->yScrollCmdPrefix != NULL) { Blt_UpdateScrollbar(hboxPtr->interp, hboxPtr->yScrollCmdPrefix, (double)hboxPtr->yOffset / hboxPtr->worldHeight, (double)(hboxPtr->yOffset + height) / hboxPtr->worldHeight); } } hboxPtr->flags &= ~HIERBOX_SCROLL; } if (!Tk_IsMapped(hboxPtr->tkwin)) { return; } drawable = Tk_GetPixmap(hboxPtr->display, Tk_WindowId(hboxPtr->tkwin), Tk_Width(hboxPtr->tkwin), Tk_Height(hboxPtr->tkwin), Tk_Depth(hboxPtr->tkwin)); /* * Clear the background either by tiling a pixmap or filling with * a solid color. Tiling takes precedence. */ if (hboxPtr->tile != NULL) { if (hboxPtr->scrollTile) { Blt_SetTSOrigin(hboxPtr->tkwin, hboxPtr->tile, -hboxPtr->xOffset, -hboxPtr->yOffset); } else { Blt_SetTileOrigin(hboxPtr->tkwin, hboxPtr->tile, 0, 0); } Blt_TileRectangle(hboxPtr->tkwin, drawable, hboxPtr->tile, 0, 0, Tk_Width(hboxPtr->tkwin), Tk_Height(hboxPtr->tkwin)); } else { Blt_Fill3DRectangle(hboxPtr->tkwin, drawable, hboxPtr->border, 0, 0, Tk_Width(hboxPtr->tkwin), Tk_Height(hboxPtr->tkwin), 0, TK_RELIEF_FLAT); } if (hboxPtr->nVisible > 0) { register Tree **treePtrPtr; if (hboxPtr->activePtr != NULL) { int y, height; y = SCREENY(hboxPtr, hboxPtr->activePtr->entryPtr->worldY); height = MAX(hboxPtr->activePtr->entryPtr->iconHeight, hboxPtr->activePtr->entryPtr->labelHeight); Blt_Fill3DRectangle(hboxPtr->tkwin, drawable, hboxPtr->activeBorder, 0, y, Tk_Width(hboxPtr->tkwin), height, 0, TK_RELIEF_FLAT); } if (hboxPtr->lineWidth > 0) { DrawVerticals(hboxPtr, hboxPtr->visibleArr[0], drawable); } for (treePtrPtr = hboxPtr->visibleArr; *treePtrPtr != NULL; treePtrPtr++) { DrawEntry(hboxPtr, *treePtrPtr, drawable); } } DrawOuterBorders(hboxPtr, drawable); /* Now copy the new view to the window. */ XCopyArea(hboxPtr->display, drawable, Tk_WindowId(hboxPtr->tkwin), hboxPtr->lineGC, 0, 0, Tk_Width(hboxPtr->tkwin), Tk_Height(hboxPtr->tkwin), 0, 0); Tk_FreePixmap(hboxPtr->display, drawable); } /* *---------------------------------------------------------------------- * * SelectCmdProc -- * * Invoked at the next idle point whenever the current * selection changes. Executes some application-specific code * in the -selectcommand option. This provides a way for * applications to handle selection changes. * * Results: * None. * * Side effects: * Tcl code gets executed for some application-specific task. * *---------------------------------------------------------------------- */ static void SelectCmdProc(clientData) ClientData clientData; /* Information about widget. */ { Hierbox *hboxPtr = clientData; /* * Preserve the widget structure in case the "select" callback * destroys it. */ Tcl_Preserve(hboxPtr); if (hboxPtr->selectCmd != NULL) { hboxPtr->flags &= ~SELECTION_PENDING; if (Tcl_GlobalEval(hboxPtr->interp, hboxPtr->selectCmd) != TCL_OK) { Tcl_BackgroundError(hboxPtr->interp); } } Tcl_Release(hboxPtr); } /* * -------------------------------------------------------------- * * HierboxCmd -- * * This procedure is invoked to process the Tcl command that * corresponds to a widget managed by this module. See the user * documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * * -------------------------------------------------------------- */ /* ARGSUSED */ static int HierboxCmd(clientData, interp, argc, argv) ClientData clientData; /* Main window associated with interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { Hierbox *hboxPtr; Tk_Window tkwin; Tree *treePtr; Tcl_CmdInfo cmdInfo; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " pathName ?option value?...\"", (char *)NULL); return TCL_ERROR; } tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp), argv[1], (char *)NULL); if (tkwin == NULL) { return TCL_ERROR; } hboxPtr = CreateHierbox(interp, tkwin); if (Blt_ConfigureWidgetComponent(interp, tkwin, "button", "Button", buttonConfigSpecs, 0, (char **)NULL, (char *)hboxPtr, 0) != TCL_OK) { goto error; } if (ConfigureHierbox(interp, hboxPtr, argc - 2, argv + 2, 0) != TCL_OK) { goto error; } treePtr = CreateNode(hboxPtr, (Tree *) NULL, APPEND, hboxPtr->separator); if (treePtr == NULL) { goto error; } hboxPtr->rootPtr = hboxPtr->focusPtr = treePtr; hboxPtr->selAnchorPtr = NULL; Blt_SetFocusItem(hboxPtr->bindTable, hboxPtr->focusPtr, NULL); Tk_CreateSelHandler(tkwin, XA_PRIMARY, XA_STRING, SelectionProc, hboxPtr, XA_STRING); Tk_CreateEventHandler(tkwin, ExposureMask | StructureNotifyMask | FocusChangeMask, HierboxEventProc, hboxPtr); hboxPtr->cmdToken = Tcl_CreateCommand(interp, argv[1], HierboxInstCmd, hboxPtr, HierboxInstCmdDeleteProc); #ifdef ITCL_NAMESPACES Itk_SetWidgetCommand(hboxPtr->tkwin, hboxPtr->cmdToken); #endif /* * Invoke a procedure to initialize various bindings on hierbox * entries. If the procedure doesn't already exist, source it * from "$blt_library/bltHierbox.tcl". We deferred sourcing the file * until now so that the variable $blt_library could be set within a * script. */ if (!Tcl_GetCommandInfo(interp, "blt::Hierbox::Init", &cmdInfo)) { static char initCmd[] = { "source [file join $blt_library hierbox.tcl]" }; if (Tcl_GlobalEval(interp, initCmd) != TCL_OK) { char info[200]; sprintf(info, "\n (while loading bindings for %s)", argv[0]); Tcl_AddErrorInfo(interp, info); goto error; } } if (Tcl_VarEval(interp, "blt::Hierbox::Init ", argv[1], (char *)NULL) != TCL_OK) { goto error; } treePtr->entryPtr->flags = (ENTRY_MAPPED); if (OpenNode(hboxPtr, treePtr) != TCL_OK) { goto error; } Tcl_SetResult(interp, Tk_PathName(hboxPtr->tkwin), TCL_VOLATILE); return TCL_OK; error: Tk_DestroyWindow(tkwin); return TCL_ERROR; } /* * -------------------------------------------------------------- * * Hierbox operations * * -------------------------------------------------------------- */ /*ARGSUSED*/ static int FocusOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; char **argv; { if (argc == 3) { Tree *treePtr; treePtr = hboxPtr->focusPtr; if (GetNode(hboxPtr, argv[2], &treePtr) != TCL_OK) { return TCL_ERROR; } if ((treePtr != NULL) && (treePtr != hboxPtr->focusPtr)) { if (IsHidden(treePtr)) { /* Doesn't make sense to set focus to a node you can't see. */ ExposeAncestors(treePtr); } hboxPtr->flags |= (HIERBOX_LAYOUT | HIERBOX_SCROLL); hboxPtr->focusPtr = treePtr; hboxPtr->labelEdit.insertPos = strlen(treePtr->entryPtr->labelText); } EventuallyRedraw(hboxPtr); } Blt_SetFocusItem(hboxPtr->bindTable, hboxPtr->focusPtr, NULL); if (hboxPtr->focusPtr != NULL) { Tcl_SetResult(interp, NodeToString(hboxPtr, hboxPtr->focusPtr), TCL_VOLATILE); } return TCL_OK; } /* *---------------------------------------------------------------------- * * BboxOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int BboxOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tree *treePtr; register int i; Entry *entryPtr; char string[200]; int width, height, yBot; int left, top, right, bottom; int screen; if (hboxPtr->flags & HIERBOX_LAYOUT) { /* * The layout is dirty. Recompute it now, before we use the * world dimensions. But remember, the "bbox" operation isn't * valid for hidden entries (since they're not visible, they * don't have world coordinates). */ ComputeLayout(hboxPtr); } left = hboxPtr->worldWidth; top = hboxPtr->worldHeight; right = bottom = 0; screen = FALSE; if ((argc > 2) && (argv[2][0] == '-') && (strcmp(argv[2], "-screen") == 0)) { screen = TRUE; argc--, argv++; } for (i = 2; i < argc; i++) { if ((argv[i][0] == 'a') && (strcmp(argv[i], "all") == 0)) { left = top = 0; right = hboxPtr->worldWidth; bottom = hboxPtr->worldHeight; break; } treePtr = hboxPtr->focusPtr; if (GetNode(hboxPtr, argv[i], &treePtr) != TCL_OK) { return TCL_ERROR; } if ((treePtr == NULL) || (IsHidden(treePtr))) { continue; } entryPtr = treePtr->entryPtr; yBot = entryPtr->worldY + entryPtr->height; height = VPORTHEIGHT(hboxPtr); if ((yBot <= hboxPtr->yOffset) && (entryPtr->worldY >= (hboxPtr->yOffset + height))) { continue; } if (bottom < yBot) { bottom = yBot; } if (top > entryPtr->worldY) { top = entryPtr->worldY; } if (right < (entryPtr->worldX + entryPtr->width + LEVELWIDTH(treePtr->level))) { right = (entryPtr->worldX + entryPtr->width + LEVELWIDTH(treePtr->level)); } if (left > entryPtr->worldX) { left = entryPtr->worldX; } } if (screen) { width = VPORTWIDTH(hboxPtr); height = VPORTHEIGHT(hboxPtr); /* * Do a min-max text for the intersection of the viewport and * the computed bounding box. If there is no intersection, return * the empty string. */ if ((right < hboxPtr->xOffset) || (bottom < hboxPtr->yOffset) || (left >= (hboxPtr->xOffset + width)) || (top >= (hboxPtr->yOffset + height))) { return TCL_OK; } /* Otherwise clip the coordinates at the view port boundaries. */ if (left < hboxPtr->xOffset) { left = hboxPtr->xOffset; } else if (right > (hboxPtr->xOffset + width)) { right = hboxPtr->xOffset + width; } if (top < hboxPtr->yOffset) { top = hboxPtr->yOffset; } else if (bottom > (hboxPtr->yOffset + height)) { bottom = hboxPtr->yOffset + height; } left = SCREENX(hboxPtr, left), top = SCREENY(hboxPtr, top); right = SCREENX(hboxPtr, right), bottom = SCREENY(hboxPtr, bottom); } if ((left < right) && (top < bottom)) { sprintf(string, "%d %d %d %d", left, top, right - left, bottom - top); Tcl_SetResult(interp, string, TCL_VOLATILE); } return TCL_OK; } /* *---------------------------------------------------------------------- * * ButtonActivateOp -- * * Selects the button to appear active. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ButtonActivateOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tree *treePtr, *oldPtr; treePtr = hboxPtr->focusPtr; if (argv[3][0] == '\0') { treePtr = NULL; } else if (GetNode(hboxPtr, argv[3], &treePtr) != TCL_OK) { return TCL_ERROR; } oldPtr = hboxPtr->activeButtonPtr; hboxPtr->activeButtonPtr = treePtr; if (treePtr != oldPtr) { Drawable drawable; drawable = Tk_WindowId(hboxPtr->tkwin); if (oldPtr != NULL) { DrawButton(hboxPtr, oldPtr, drawable); } if (treePtr != NULL) { DrawButton(hboxPtr, treePtr, drawable); } DrawOuterBorders(hboxPtr, drawable); } return TCL_OK; } /* *---------------------------------------------------------------------- * * ButtonBindOp -- * * .t bind tag sequence command * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ButtonBindOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { ClientData object; /* * Individual entries are selected by inode only. All other * strings are interpreted as a binding tag. For example, if one * binds to "focus", it is assumed that this refers to a bind tag, * not the entry with focus. */ object = GetNodeByIndex(hboxPtr, argv[3]); if (object == 0) { object = (ClientData)Tk_GetUid(argv[3]); } return Blt_ConfigureBindings(interp, hboxPtr->buttonBindTable, object, argc - 4, argv + 4); } /* *---------------------------------------------------------------------- * * ButCgetOpOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ButtonCgetOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { return Tk_ConfigureValue(interp, hboxPtr->tkwin, buttonConfigSpecs, (char *)hboxPtr, argv[3], 0); } /* *---------------------------------------------------------------------- * * ButtonConfigureOp -- * * This procedure is called to process a list of configuration * options database, in order to reconfigure the one of more * entries in the widget. * * .h entryconfigure node node node node option value * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for hboxPtr; old resources get freed, if there * were any. The hypertext is redisplayed. * *---------------------------------------------------------------------- */ static int ButtonConfigureOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; char **argv; { /* Figure out where the option value pairs begin */ argc -= 3; argv += 3; if (argc == 0) { return Tk_ConfigureInfo(interp, hboxPtr->tkwin, buttonConfigSpecs, (char *)hboxPtr, (char *)NULL, 0); } else if (argc == 1) { return Tk_ConfigureInfo(interp, hboxPtr->tkwin, buttonConfigSpecs, (char *)hboxPtr, argv[0], 0); } if (Tk_ConfigureWidget(hboxPtr->interp, hboxPtr->tkwin, buttonConfigSpecs, argc, argv, (char *)hboxPtr, TK_CONFIG_ARGV_ONLY) != TCL_OK) { return TCL_ERROR; } ConfigureButtons(hboxPtr); EventuallyRedraw(hboxPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * ButtonOp -- * * This procedure handles button operations. * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ static Blt_OpSpec buttonOperSpecs[] = { {"activate", 1, (Blt_Op)ButtonActivateOp, 4, 4, "node",}, {"bind", 1, (Blt_Op)ButtonBindOp, 4, 6, "tagName ?sequence command?",}, {"cget", 2, (Blt_Op)ButtonCgetOp, 4, 4, "option",}, {"configure", 2, (Blt_Op)ButtonConfigureOp, 3, 0, "?option value?...",}, {"highlight", 1, (Blt_Op)ButtonActivateOp, 4, 4, "node",}, }; static int nButtonSpecs = sizeof(buttonOperSpecs) / sizeof(Blt_OpSpec); static int ButtonOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; char **argv; { Blt_Op proc; int result; proc = Blt_GetOp(interp, nButtonSpecs, buttonOperSpecs, BLT_OP_ARG2, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (hboxPtr, interp, argc, argv); return result; } /* *---------------------------------------------------------------------- * * CgetOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int CgetOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { return Tk_ConfigureValue(interp, hboxPtr->tkwin, configSpecs, (char *)hboxPtr, argv[2], 0); } /*ARGSUSED*/ static int CloseOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { Tree *rootPtr; unsigned int flags; register int i; flags = 0; if (argc > 2) { int length; length = strlen(argv[2]); if ((argv[2][0] == '-') && (length > 1) && (strncmp(argv[2], "-recurse", length) == 0)) { argv++, argc--; flags |= APPLY_RECURSE; } } for (i = 2; i < argc; i++) { rootPtr = hboxPtr->focusPtr; if (GetNode(hboxPtr, argv[i], &rootPtr) != TCL_OK) { return TCL_ERROR; } if (rootPtr == NULL) { continue; } /* * Clear any selected entries that may become hidden by * closing the node. */ PruneSelection(hboxPtr, rootPtr); /* * ----------------------------------------------------------- * * Check if either the "focus" entry or selection anchor * is in this hierarchy. Must move it or disable it before * we close the node. Otherwise it may be deleted by a Tcl * "close" script, and we'll be left pointing to a bogus * memory location. * * ----------------------------------------------------------- */ if (IsAncestor(rootPtr, hboxPtr->focusPtr)) { hboxPtr->focusPtr = rootPtr; Blt_SetFocusItem(hboxPtr->bindTable, hboxPtr->focusPtr, NULL); } if (IsAncestor(rootPtr, hboxPtr->selAnchorPtr)) { hboxPtr->selAnchorPtr = NULL; } if (IsAncestor(rootPtr, hboxPtr->activePtr)) { hboxPtr->activePtr = rootPtr; } if (ApplyToTree(hboxPtr, rootPtr, CloseNode, flags) != TCL_OK) { return TCL_ERROR; } } hboxPtr->flags |= (HIERBOX_LAYOUT | HIERBOX_SCROLL); EventuallyRedraw(hboxPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * ConfigureOp -- * * This procedure is called to process an argv/argc list, plus * the Tk option database, in order to configure (or reconfigure) * the widget. * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for hboxPtr; old resources get freed, if there * were any. The widget is redisplayed. * *---------------------------------------------------------------------- */ static int ConfigureOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; char **argv; { if (argc == 2) { return Tk_ConfigureInfo(interp, hboxPtr->tkwin, configSpecs, (char *)hboxPtr, (char *)NULL, 0); } else if (argc == 3) { return Tk_ConfigureInfo(interp, hboxPtr->tkwin, configSpecs, (char *)hboxPtr, argv[2], 0); } if (ConfigureHierbox(interp, hboxPtr, argc - 2, argv + 2, TK_CONFIG_ARGV_ONLY) != TCL_OK) { return TCL_ERROR; } EventuallyRedraw(hboxPtr); return TCL_OK; } /*ARGSUSED*/ static int CurselectionOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; /* Not used. */ int argc; /* Not used. */ char **argv; /* Not used. */ { if (hboxPtr->sortSelection) { ApplyToTree(hboxPtr, hboxPtr->rootPtr, IsSelectedNode, APPLY_RECURSE | APPLY_OPEN_ONLY | APPLY_BEFORE); } else { Blt_ChainLink *linkPtr; Tree *treePtr; for (linkPtr = Blt_ChainFirstLink(&(hboxPtr->selectChain)); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { treePtr = Blt_ChainGetValue(linkPtr); Tcl_AppendElement(interp, NodeToString(hboxPtr, treePtr)); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * ActivateOpOp -- * * Selects the tab to appear active. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ActivateOpOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tree *treePtr, *oldPtr; treePtr = hboxPtr->focusPtr; if (argv[3][0] == '\0') { treePtr = NULL; } else if (GetNode(hboxPtr, argv[3], &treePtr) != TCL_OK) { return TCL_ERROR; } oldPtr = hboxPtr->activePtr; hboxPtr->activePtr = treePtr; if (treePtr != oldPtr) { EventuallyRedraw(hboxPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * BindOp -- * * .t bind index sequence command * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int BindOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { ClientData item; /* * Individual entries are selected by inode only. All other strings * are interpreted as a binding tag. */ item = GetNodeByIndex(hboxPtr, argv[2]); if (item == 0) { item = (ClientData)Tk_GetUid(argv[2]); } return Blt_ConfigureBindings(interp, hboxPtr->bindTable, item, argc - 3, argv + 3); } /* *---------------------------------------------------------------------- * * CgetOpOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int CgetOpOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tree *treePtr; if (StringToNode(hboxPtr, argv[3], &treePtr) != TCL_OK) { return TCL_ERROR; } return Tk_ConfigureValue(interp, hboxPtr->tkwin, entryConfigSpecs, (char *)treePtr->entryPtr, argv[4], 0); } /* *---------------------------------------------------------------------- * * ConfigureOpOp -- * * This procedure is called to process a list of configuration * options database, in order to reconfigure the one of more * entries in the widget. * * .h entryconfigure node node node node option value * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for hboxPtr; old resources get freed, if there * were any. The hypertext is redisplayed. * *---------------------------------------------------------------------- */ static int ConfigureOpOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; char **argv; { int nIds, nOpts; char **options; register int i; Tree *treePtr; /* Figure out where the option value pairs begin */ argc -= 3; argv += 3; for (i = 0; i < argc; i++) { if (argv[i][0] == '-') { break; } if (StringToNode(hboxPtr, argv[i], &treePtr) != TCL_OK) { return TCL_ERROR; /* Can't find node. */ } } nIds = i; /* Number of element names specified */ nOpts = argc - i; /* Number of options specified */ options = argv + i; /* Start of options in argv */ for (i = 0; i < nIds; i++) { StringToNode(hboxPtr, argv[i], &treePtr); if (argc == 1) { return Tk_ConfigureInfo(interp, hboxPtr->tkwin, entryConfigSpecs, (char *)treePtr->entryPtr, (char *)NULL, 0); } else if (argc == 2) { return Tk_ConfigureInfo(interp, hboxPtr->tkwin, entryConfigSpecs, (char *)treePtr->entryPtr, argv[2], 0); } if (ConfigureEntry(hboxPtr, treePtr->entryPtr, nOpts, options, TK_CONFIG_ARGV_ONLY) != TCL_OK) { return TCL_ERROR; } } hboxPtr->flags |= (HIERBOX_LAYOUT | HIERBOX_SCROLL); EventuallyRedraw(hboxPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * IsHiddenOpOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int IsHiddenOpOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tree *treePtr; if (StringToNode(hboxPtr, argv[3], &treePtr) != TCL_OK) { return TCL_ERROR; } Blt_SetBooleanResult(interp, IsHidden(treePtr)); return TCL_OK; } /*ARGSUSED*/ static int IsBeforeOpOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tree *n1Ptr, *n2Ptr; if ((StringToNode(hboxPtr, argv[3], &n1Ptr) != TCL_OK) || (StringToNode(hboxPtr, argv[4], &n2Ptr) != TCL_OK)) { return TCL_ERROR; } Blt_SetBooleanResult(interp, IsBefore(n1Ptr, n2Ptr)); return TCL_OK; } static int ScreenToIndex(hboxPtr, x, y) Hierbox *hboxPtr; int x, y; { Tk_Font font; TextStyle ts; TextLayout *textPtr; Tk_FontMetrics fontMetrics; TextFragment *fragPtr; int nBytes; Entry *entryPtr; Tree *treePtr; int lineNum; register int i; treePtr = hboxPtr->focusPtr; entryPtr = treePtr->entryPtr; if (*entryPtr->labelText == '\0') { return 0; } /* * Compute the X-Y offsets of the screen point from the start of * label. Force the offsets to point within the label. */ x -= SCREENX(hboxPtr, entryPtr->worldX) + LABEL_PADX + hboxPtr->selBorderWidth; y -= SCREENY(hboxPtr, entryPtr->worldY) + LABEL_PADY + hboxPtr->selBorderWidth; x -= LEVELWIDTH(treePtr->level) + LEVELWIDTH(treePtr->level + 1) + 4; font = GETFONT(hboxPtr, entryPtr->labelFont); memset(&ts, 0, sizeof(TextStyle)); ts.font = font; ts.justify = TK_JUSTIFY_LEFT; ts.shadow.offset = entryPtr->labelShadow.offset; textPtr = Blt_GetTextLayout(entryPtr->labelText, &ts); if (y < 0) { y = 0; } else if (y >= textPtr->height) { y = textPtr->height - 1; } Tk_GetFontMetrics(font, &fontMetrics); lineNum = y / fontMetrics.linespace; fragPtr = textPtr->fragArr + lineNum; if (x < 0) { nBytes = 0; } else if (x >= textPtr->width) { nBytes = fragPtr->count; } else { int newX; /* Find the character underneath the pointer. */ nBytes = Tk_MeasureChars(font, fragPtr->text, fragPtr->count, x, 0, &newX); if ((newX < x) && (nBytes < fragPtr->count)) { double fract; int length, charSize; char *next; next = fragPtr->text + nBytes; #if HAVE_UTF { Tcl_UniChar dummy; length = Tcl_UtfToUniChar(next, &dummy); } #else length = 1; #endif charSize = Tk_TextWidth(font, next, length); fract = ((double)(x - newX) / (double)charSize); if (ROUND(fract)) { nBytes += length; } } } for (i = lineNum - 1; i >= 0; i--) { fragPtr--; nBytes += fragPtr->count + 1; } Blt_Free(textPtr); return nBytes; } /* *--------------------------------------------------------------------------- * * GetLabelIndex -- * * Parse an index into an entry and return either its value * or an error. * * Results: * A standard Tcl result. If all went well, then *indexPtr is * filled in with the character index (into entryPtr) corresponding to * string. The index value is guaranteed to lie between 0 and * the number of characters in the string, inclusive. If an * error occurs then an error message is left in the interp's result. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int GetLabelIndex(hboxPtr, entryPtr, string, indexPtr) Hierbox *hboxPtr; Entry *entryPtr; char *string; int *indexPtr; { Tcl_Interp *interp = hboxPtr->interp; TextEdit *editPtr = &(hboxPtr->labelEdit); char c; c = string[0]; if ((c == 'a') && (strcmp(string, "anchor") == 0)) { *indexPtr = editPtr->selAnchor; } else if ((c == 'e') && (strcmp(string, "end") == 0)) { *indexPtr = strlen(entryPtr->labelText); } else if ((c == 'i') && (strcmp(string, "insert") == 0)) { *indexPtr = editPtr->insertPos; } else if ((c == 's') && (strcmp(string, "sel.first") == 0)) { if (editPtr->selFirst < 0) { Tcl_AppendResult(interp, "nothing is selected", (char *)NULL); return TCL_ERROR; } *indexPtr = editPtr->selFirst; } else if ((c == 's') && (strcmp(string, "sel.last") == 0)) { if (editPtr->selLast < 0) { Tcl_AppendResult(interp, "nothing is selected", (char *)NULL); return TCL_ERROR; } *indexPtr = editPtr->selLast; } else if (c == '@') { int x, y; if (Blt_GetXY(interp, hboxPtr->tkwin, string, &x, &y) != TCL_OK) { return TCL_ERROR; } *indexPtr = ScreenToIndex(hboxPtr, x, y); } else if (isdigit((int)c)) { int number; int maxChars; if (Tcl_GetInt(interp, string, &number) != TCL_OK) { return TCL_ERROR; } /* Don't allow the index to point outside the label. */ maxChars = Tcl_NumUtfChars(entryPtr->labelText, -1); if (number < 0) { *indexPtr = 0; } else if (number > maxChars) { *indexPtr = strlen(entryPtr->labelText); } else { *indexPtr = Tcl_UtfAtIndex(entryPtr->labelText, number) - entryPtr->labelText; } } else { Tcl_AppendResult(interp, "bad label index \"", string, "\"", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * IndexOpOp -- * * Returns the numeric index of the given string. Indices can be * one of the following: * * "anchor" Selection anchor. * "end" End of the label. * "insert" Insertion cursor. * "sel.first" First character selected. * "sel.last" Last character selected. * @x,y Index at X-Y screen coordinate. * number Returns the same number. * * Results: * A standard Tcl result. If the argument does not represent a * valid label index, then TCL_ERROR is returned and the interpreter * result will contain an error message. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int IndexOpOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Entry *entryPtr; int nBytes, nChars; entryPtr = hboxPtr->focusPtr->entryPtr; if (GetLabelIndex(hboxPtr, entryPtr, argv[3], &nBytes) != TCL_OK) { return TCL_ERROR; } nChars = Tcl_NumUtfChars(entryPtr->labelText, nBytes); Tcl_SetResult(interp, Blt_Itoa(nChars), TCL_VOLATILE); return TCL_OK; } /* *---------------------------------------------------------------------- * * InsertOpOp -- * * Add new characters to the label of an entry. * * Results: * None. * * Side effects: * New information gets added to editPtr; it will be redisplayed * soon, but not necessarily immediately. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int InsertOpOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { Tree *treePtr; Entry *entryPtr; TextEdit *editPtr = &(hboxPtr->labelEdit); int oldSize, newSize; char *string; int extra; int insertPos; if (!hboxPtr->focusEdit) { return TCL_OK; /* Not in edit mode. */ } if (StringToNode(hboxPtr, argv[3], &treePtr) != TCL_OK) { return TCL_ERROR; } if (treePtr == NULL) { return TCL_OK; /* Not in edit mode. */ } entryPtr = treePtr->entryPtr; if (hboxPtr->focusPtr != treePtr) { hboxPtr->focusPtr = treePtr; editPtr->insertPos = strlen(entryPtr->labelText); editPtr->selAnchor = editPtr->selFirst = editPtr->selLast = -1; } if (GetLabelIndex(hboxPtr, entryPtr, argv[4], &insertPos) != TCL_OK) { return TCL_ERROR; } extra = strlen(argv[5]); if (extra == 0) { /* Nothing to insert. Move the cursor anyways. */ editPtr->insertPos = insertPos; EventuallyRedraw(hboxPtr); return TCL_OK; } oldSize = strlen(entryPtr->labelText); newSize = oldSize + extra; string = Blt_Malloc(sizeof(char) * (newSize + 1)); if (insertPos == oldSize) { /* Append */ strcpy(string, entryPtr->labelText); strcat(string, argv[5]); } else if (insertPos == 0) {/* Prepend */ strcpy(string, argv[5]); strcat(string, entryPtr->labelText); } else { /* Insert into existing. */ char *left, *right; char *p; left = entryPtr->labelText; right = left + insertPos; p = string; strncpy(p, left, insertPos); p += insertPos; strcpy(p, argv[5]); p += extra; strcpy(p, right); } /* * All indices from the start of the insertion to the end of the * string need to be updated. Simply move the indices down by the * number of characters added. */ if (editPtr->selFirst >= insertPos) { editPtr->selFirst += extra; } if (editPtr->selLast > insertPos) { editPtr->selLast += extra; } if ((editPtr->selAnchor > insertPos) || (editPtr->selFirst >= insertPos)) { editPtr->selAnchor += extra; } Blt_Free(entryPtr->labelText); entryPtr->labelText = string; editPtr->insertPos = insertPos + extra; GetCursorLocation(hboxPtr, treePtr); hboxPtr->flags |= (HIERBOX_LAYOUT | HIERBOX_SCROLL); EventuallyRedraw(hboxPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * DeleteOpOp -- * * Remove one or more characters from the label of an entry. * * Results: * None. * * Side effects: * Memory gets freed, the entry gets modified and (eventually) * redisplayed. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int DeleteOpOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { TextEdit *editPtr = &(hboxPtr->labelEdit); Tree *treePtr; Entry *entryPtr; int oldSize, newSize; int nDeleted; int first, last; char *string; char *p; if (!hboxPtr->focusEdit) { return TCL_OK; /* Not in edit mode. */ } if (StringToNode(hboxPtr, argv[3], &treePtr) != TCL_OK) { return TCL_ERROR; } if (treePtr == NULL) { return TCL_OK; /* Not in edit mode. */ } entryPtr = treePtr->entryPtr; if (hboxPtr->focusPtr != treePtr) { hboxPtr->focusPtr = treePtr; editPtr->insertPos = strlen(entryPtr->labelText); editPtr->selAnchor = editPtr->selFirst = editPtr->selLast = -1; } if ((GetLabelIndex(hboxPtr, entryPtr, argv[4], &first) != TCL_OK) || (GetLabelIndex(hboxPtr, entryPtr, argv[5], &last) != TCL_OK)) { return TCL_ERROR; } if (first >= last) { return TCL_OK; } if ((!hboxPtr->focusEdit) || (entryPtr == NULL)) { return TCL_OK; /* Not in edit mode. */ } oldSize = strlen(entryPtr->labelText); newSize = oldSize - (last - first); p = string = Blt_Malloc(sizeof(char) * (newSize + 1)); strncpy(p, entryPtr->labelText, first); p += first; strcpy(p, entryPtr->labelText + last); Blt_Free(entryPtr->labelText); entryPtr->labelText = string; nDeleted = last - first + 1; /* * Since deleting characters compacts the character array, we need to * update the various character indices according. It depends where * the index occurs in relation to range of deleted characters: * * before Ignore. * within Move the index back to the start of the deletion. * after Subtract off the deleted number of characters, * since the array has been compressed by that * many characters. * */ if (editPtr->selFirst >= first) { if (editPtr->selFirst >= last) { editPtr->selFirst -= nDeleted; } else { editPtr->selFirst = first; } } if (editPtr->selLast >= first) { if (editPtr->selLast >= last) { editPtr->selLast -= nDeleted; } else { editPtr->selLast = first; } } if (editPtr->selLast <= editPtr->selFirst) { editPtr->selFirst = editPtr->selLast = -1; /* Cut away the entire * selection. */ } if (editPtr->selAnchor >= first) { if (editPtr->selAnchor >= last) { editPtr->selAnchor -= nDeleted; } else { editPtr->selAnchor = first; } } if (editPtr->insertPos >= first) { if (editPtr->insertPos >= last) { editPtr->insertPos -= nDeleted; } else { editPtr->insertPos = first; } } hboxPtr->flags |= (HIERBOX_LAYOUT | HIERBOX_SCROLL); EventuallyRedraw(hboxPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * IsOpenOpOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int IsOpenOpOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tree *treePtr; if (StringToNode(hboxPtr, argv[3], &treePtr) != TCL_OK) { return TCL_ERROR; } Blt_SetBooleanResult(interp, (treePtr->entryPtr->flags & ENTRY_OPEN)); return TCL_OK; } /*ARGSUSED*/ static int ChildrenOpOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; char **argv; { Tree *parentPtr, *nodePtr; if (StringToNode(hboxPtr, argv[3], &parentPtr) != TCL_OK) { return TCL_ERROR; } if (argc == 4) { Blt_ChainLink *linkPtr; for (linkPtr = Blt_ChainFirstLink(parentPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { nodePtr = Blt_ChainGetValue(linkPtr); Tcl_AppendElement(interp, NodeToString(hboxPtr, nodePtr)); } } else if (argc == 6) { Blt_ChainLink *firstPtr, *lastPtr; int first, last; int nNodes; if ((Blt_GetPosition(interp, argv[4], &first) != TCL_OK) || (Blt_GetPosition(interp, argv[5], &last) != TCL_OK)) { return TCL_ERROR; } nNodes = Blt_ChainGetLength(parentPtr->chainPtr); if (nNodes == 0) { return TCL_OK; } if ((last == -1) || (last >= nNodes)) { last = nNodes - 1; } if ((first == -1) || (first >= nNodes)) { first = nNodes - 1; } firstPtr = Blt_ChainGetNthLink(parentPtr->chainPtr, first); lastPtr = Blt_ChainGetNthLink(parentPtr->chainPtr, last); if (first > last) { for ( /*empty*/ ; lastPtr != NULL; lastPtr = Blt_ChainPrevLink(lastPtr)) { nodePtr = Blt_ChainGetValue(lastPtr); Tcl_AppendElement(interp, NodeToString(hboxPtr, nodePtr)); if (lastPtr == firstPtr) { break; } } } else { for ( /*empty*/ ; firstPtr != NULL; firstPtr = Blt_ChainNextLink(firstPtr)) { nodePtr = Blt_ChainGetValue(firstPtr); Tcl_AppendElement(interp, NodeToString(hboxPtr, nodePtr)); if (firstPtr == lastPtr) { break; } } } } else { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ", argv[1], " ", argv[2], " index ?first last?", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * SizeOpOp -- * * Counts the number of entries at this node. * * Results: * A standard Tcl result. If an error occurred TCL_ERROR is * returned and interp->result will contain an error message. * Otherwise, TCL_OK is returned and interp->result contains * the number of entries. * *---------------------------------------------------------------------- */ static int SizeOpOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; char **argv; { int length; Tree *rootPtr; int *sumPtr = (int *)&(hboxPtr->clientData); length = strlen(argv[3]); if ((argv[3][0] == '-') && (length > 1) && (strncmp(argv[3], "-recurse", length) == 0)) { argv++, argc--; } if (argc == 3) { Tcl_AppendResult(interp, "missing node argument: should be \"", argv[0], " entry open node\"", (char *)NULL); return TCL_ERROR; } if (StringToNode(hboxPtr, argv[3], &rootPtr) != TCL_OK) { return TCL_ERROR; } *sumPtr = 0; if (ApplyToTree(hboxPtr, rootPtr, SizeOfNode, 0) != TCL_OK) { return TCL_ERROR; } Tcl_SetResult(interp, Blt_Itoa(*sumPtr), TCL_VOLATILE); return TCL_OK; } /* *---------------------------------------------------------------------- * * EntryOp -- * * This procedure handles entry operations. * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ static Blt_OpSpec entryOperSpecs[] = { {"activate", 1, (Blt_Op)ActivateOpOp, 4, 4, "node",}, {"cget", 2, (Blt_Op)CgetOpOp, 5, 5, "node option",}, {"children", 2, (Blt_Op)ChildrenOpOp, 4, 6, "node first last",}, {"configure", 2, (Blt_Op)ConfigureOpOp, 4, 0, "node ?node...? ?option value?...",}, {"delete", 1, (Blt_Op)DeleteOpOp, 6, 6, "node first last"}, {"highlight", 1, (Blt_Op)ActivateOpOp, 4, 4, "node",}, {"index", 3, (Blt_Op)IndexOpOp, 6, 6, "index"}, {"insert", 3, (Blt_Op)InsertOpOp, 6, 6, "node index string"}, {"isbefore", 3, (Blt_Op)IsBeforeOpOp, 5, 5, "node node",}, {"ishidden", 3, (Blt_Op)IsHiddenOpOp, 4, 4, "node",}, {"isopen", 3, (Blt_Op)IsOpenOpOp, 4, 4, "node",}, {"size", 1, (Blt_Op)SizeOpOp, 4, 5, "?-recurse? node",}, }; static int nEntrySpecs = sizeof(entryOperSpecs) / sizeof(Blt_OpSpec); static int EntryOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; char **argv; { Blt_Op proc; int result; proc = Blt_GetOp(interp, nEntrySpecs, entryOperSpecs, BLT_OP_ARG2, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (hboxPtr, interp, argc, argv); return result; } /*ARGSUSED*/ static int ExactCompare(interp, name, pattern) Tcl_Interp *interp; /* Not used. */ char *name; char *pattern; { return (strcmp(name, pattern) == 0); } /*ARGSUSED*/ static int GlobCompare(interp, name, pattern) Tcl_Interp *interp; /* Not used. */ char *name; char *pattern; { return Tcl_StringMatch(name, pattern); } static int RegexpCompare(interp, name, pattern) Tcl_Interp *interp; char *name; char *pattern; { return Tcl_RegExpMatch(interp, name, pattern); } /* *---------------------------------------------------------------------- * * FindOp -- * * Find one or more nodes based upon the pattern provided. * * Results: * A standard Tcl result. The interpreter result will contain a * list of the node serial identifiers. * *---------------------------------------------------------------------- */ static int FindOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; char **argv; { register Tree *treePtr; Tree *firstPtr, *lastPtr; int nMatches, maxMatches; char c; int length; CompareProc *compareProc; IterProc *nextProc; int invertMatch; /* normal search mode (matching entries) */ char *namePattern, *fullPattern; char *execCmd; register int i; int result; char *pattern; char *option; char *value; Tcl_DString dString, pathString; Blt_List optionList; register Blt_ListNode node; invertMatch = FALSE; maxMatches = 0; execCmd = namePattern = fullPattern = NULL; compareProc = ExactCompare; nextProc = NextNode; optionList = Blt_ListCreate(BLT_STRING_KEYS); /* * Step 1: Process flags for find operation. */ for (i = 2; i < argc; i++) { if (argv[i][0] != '-') { break; } option = argv[i] + 1; length = strlen(option); c = option[0]; if ((c == 'e') && (length > 2) && (strncmp(option, "exact", length) == 0)) { compareProc = ExactCompare; } else if ((c == 'g') && (strncmp(option, "glob", length) == 0)) { compareProc = GlobCompare; } else if ((c == 'r') && (strncmp(option, "regexp", length) == 0)) { compareProc = RegexpCompare; } else if ((c == 'n') && (length > 1) && (strncmp(option, "nonmatching", length) == 0)) { invertMatch = TRUE; } else if ((c == 'n') && (length > 1) && (strncmp(option, "name", length) == 0)) { if ((i + 1) == argc) { goto missingArg; } i++; namePattern = argv[i]; } else if ((c == 'f') && (strncmp(option, "full", length) == 0)) { if ((i + 1) == argc) { goto missingArg; } i++; fullPattern = argv[i]; } else if ((c == 'e') && (length > 2) && (strncmp(option, "exec", length) == 0)) { if ((i + 1) == argc) { goto missingArg; } i++; execCmd = argv[i]; } else if ((c == 'c') && (strncmp(option, "count", length) == 0)) { if ((i + 1) == argc) { goto missingArg; } i++; if (Tcl_GetInt(interp, argv[i], &maxMatches) != TCL_OK) { return TCL_ERROR; } if (maxMatches < 0) { Tcl_AppendResult(interp, "bad match count \"", argv[i], "\": should be a positive number", (char *)NULL); Blt_ListDestroy(optionList); return TCL_ERROR; } } else if ((option[0] == '-') && (option[1] == '\0')) { break; } else { /* * Verify that the switch is actually an node configuration * option. */ if (Tk_ConfigureValue(interp, hboxPtr->tkwin, entryConfigSpecs, (char *)hboxPtr->rootPtr->entryPtr, argv[i], 0) != TCL_OK) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, "bad find switch \"", argv[i], "\"", (char *)NULL); Blt_ListDestroy(optionList); return TCL_ERROR; } if ((i + 1) == argc) { goto missingArg; } /* Save the option in the list of configuration options */ node = Blt_ListGetNode(optionList, argv[i]); if (node == NULL) { node = Blt_ListCreateNode(optionList, argv[i]); Blt_ListAppendNode(optionList, node); } Blt_ListSetValue(node, argv[i + 1]); i++; } } if ((argc - i) > 2) { Blt_ListDestroy(optionList); Tcl_AppendResult(interp, "too many args", (char *)NULL); return TCL_ERROR; } /* * Step 2: Find the range of the search. Check the order of two * nodes and arrange the search accordingly. * * Note: Be careful to treat "end" as the end of all nodes, instead * of the end of visible nodes. That way, we can search the * entire tree, even if the last folder is closed. */ firstPtr = hboxPtr->rootPtr;/* Default to root node */ lastPtr = EndNode(firstPtr, 0); if (i < argc) { if ((argv[i][0] == 'e') && (strcmp(argv[i], "end") == 0)) { firstPtr = EndNode(hboxPtr->rootPtr, 0); } else if (StringToNode(hboxPtr, argv[i], &firstPtr) != TCL_OK) { return TCL_ERROR; } i++; } if (i < argc) { if ((argv[i][0] == 'e') && (strcmp(argv[i], "end") == 0)) { lastPtr = EndNode(hboxPtr->rootPtr, 0); } else if (StringToNode(hboxPtr, argv[i], &lastPtr) != TCL_OK) { return TCL_ERROR; } } if (IsBefore(lastPtr, firstPtr)) { nextProc = LastNode; } nMatches = 0; /* * Step 3: Search through the tree and look for nodes that match the * current pattern specifications. Save the name of each of * the matching nodes. */ Tcl_DStringInit(&dString); for (treePtr = firstPtr; treePtr != NULL; treePtr = (*nextProc) (treePtr, 0)) { if (namePattern != NULL) { result = (*compareProc) (interp, treePtr->nameId, namePattern); if (result == invertMatch) { goto nextNode; /* Failed to match */ } } if (fullPattern != NULL) { GetFullPath(treePtr, hboxPtr->separator, &pathString); result = (*compareProc) (interp, Tcl_DStringValue(&pathString), fullPattern); Tcl_DStringFree(&pathString); if (result == invertMatch) { goto nextNode; /* Failed to match */ } } for (node = Blt_ListFirstNode(optionList); node != NULL; node = Blt_ListNextNode(node)) { option = (char *)Blt_ListGetKey(node); Tcl_ResetResult(interp); if (Tk_ConfigureValue(interp, hboxPtr->tkwin, entryConfigSpecs, (char *)treePtr->entryPtr, option, 0) != TCL_OK) { goto error; /* This shouldn't happen. */ } pattern = (char *)Blt_ListGetValue(node); value = (char *)Tcl_GetStringResult(interp); result = (*compareProc) (interp, value, pattern); if (result == invertMatch) { goto nextNode; /* Failed to match */ } } /* * As unlikely as it sounds, the "exec" callback may delete this * node. We need to preverse it until we're not using it anymore * (i.e. no longer accessing its fields). */ Tcl_Preserve(treePtr); if (execCmd != NULL) { Tcl_DString cmdString; PercentSubst(hboxPtr, treePtr, execCmd, &cmdString); result = Tcl_GlobalEval(interp, Tcl_DStringValue(&cmdString)); Tcl_DStringFree(&cmdString); if (result != TCL_OK) { Tcl_Release(treePtr); goto error; } } /* Finally, save the matching node name. */ Tcl_DStringAppendElement(&dString, NodeToString(hboxPtr, treePtr)); Tcl_Release(treePtr); nMatches++; if ((nMatches == maxMatches) && (maxMatches > 0)) { break; } nextNode: if (treePtr == lastPtr) { break; } } Tcl_ResetResult(interp); Blt_ListDestroy(optionList); Tcl_DStringResult(interp, &dString); return TCL_OK; missingArg: Tcl_AppendResult(interp, "missing argument for find option \"", argv[i], "\"", (char *)NULL); error: Tcl_DStringFree(&dString); Blt_ListDestroy(optionList); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * GetOp -- * * Converts one or more node identifiers to its path component. * The path may be either the single entry name or the full path * of the entry. * * Results: * A standard Tcl result. The interpreter result will contain a * list of the convert names. * *---------------------------------------------------------------------- */ static int GetOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; char **argv; { int fullName; Tree *treePtr; Tcl_DString dString; Tcl_DString pathString; register int i; fullName = FALSE; if ((argc > 2) && (argv[2][0] == '-') && (strcmp(argv[2], "-full") == 0)) { fullName = TRUE; argv++, argc--; } Tcl_DStringInit(&dString); Tcl_DStringInit(&pathString); for (i = 2; i < argc; i++) { treePtr = hboxPtr->focusPtr; if (GetNode(hboxPtr, argv[i], &treePtr) != TCL_OK) { return TCL_ERROR; } if (treePtr == NULL) { Tcl_DStringAppendElement(&dString, ""); continue; } if (fullName) { GetFullPath(treePtr, hboxPtr->separator, &pathString); Tcl_DStringAppendElement(&dString, Tcl_DStringValue(&pathString)); } else { Tcl_DStringAppendElement(&dString, treePtr->nameId); } } Tcl_DStringFree(&pathString); Tcl_DStringResult(interp, &dString); return TCL_OK; } /* *---------------------------------------------------------------------- * * SearchAndApplyToTree -- * * Searches through the current tree and applies a procedure * to matching nodes. The search specification is taken from * the following command-line arguments: * * ?-exact? ?-glob? ?-regexp? ?-nonmatching? * ?-data string? * ?-name string? * ?-full string? * ?--? * ?inode...? * * Results: * A standard Tcl result. If the result is valid, and if the * nonmatchPtr is specified, it returns a boolean value * indicating whether or not the search was inverted. This * is needed to fix things properly for the "hide nonmatching" * case. * *---------------------------------------------------------------------- */ static int SearchAndApplyToTree(hboxPtr, interp, argc, argv, proc, nonMatchPtr) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; char **argv; ApplyProc *proc; int *nonMatchPtr; /* returns: inverted search indicator */ { CompareProc *compareProc; int invertMatch; /* normal search mode (matching entries) */ char *namePattern, *fullPattern; register int i; int length; int result; char *option, *pattern; char *value; Tree *treePtr; char c; Blt_List optionList; register Blt_ListNode node; optionList = Blt_ListCreate(BLT_STRING_KEYS); invertMatch = FALSE; namePattern = fullPattern = NULL; compareProc = ExactCompare; for (i = 2; i < argc; i++) { if (argv[i][0] != '-') { break; } option = argv[i] + 1; length = strlen(option); c = option[0]; if ((c == 'e') && (strncmp(option, "exact", length) == 0)) { compareProc = ExactCompare; } else if ((c == 'g') && (strncmp(option, "glob", length) == 0)) { compareProc = GlobCompare; } else if ((c == 'r') && (strncmp(option, "regexp", length) == 0)) { compareProc = RegexpCompare; } else if ((c == 'n') && (length > 1) && (strncmp(option, "nonmatching", length) == 0)) { invertMatch = TRUE; } else if ((c == 'f') && (strncmp(option, "full", length) == 0)) { if ((i + 1) == argc) { goto missingArg; } i++; fullPattern = argv[i]; } else if ((c == 'n') && (length > 1) && (strncmp(option, "name", length) == 0)) { if ((i + 1) == argc) { goto missingArg; } i++; namePattern = argv[i]; } else if ((option[0] == '-') && (option[1] == '\0')) { break; } else { /* * Verify that the switch is actually an entry configuration option. */ if (Tk_ConfigureValue(interp, hboxPtr->tkwin, entryConfigSpecs, (char *)hboxPtr->rootPtr->entryPtr, argv[i], 0) != TCL_OK) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, "bad switch \"", argv[i], "\": must be -exact, -glob, -regexp, -name, -full, or -nonmatching", (char *)NULL); return TCL_ERROR; } if ((i + 1) == argc) { goto missingArg; } /* Save the option in the list of configuration options */ node = Blt_ListGetNode(optionList, argv[i]); if (node == NULL) { node = Blt_ListCreateNode(optionList, argv[i]); Blt_ListAppendNode(optionList, node); } Blt_ListSetValue(node, argv[i + 1]); } } if ((namePattern != NULL) || (fullPattern != NULL) || (Blt_ListGetLength(optionList) > 0)) { /* * Search through the tree and look for nodes that match the * current spec. Apply the input procedure to each of the * matching nodes. */ for (treePtr = hboxPtr->rootPtr; treePtr != NULL; treePtr = NextNode(treePtr, 0)) { if (namePattern != NULL) { result = (*compareProc) (interp, treePtr->nameId, namePattern); if (result == invertMatch) { continue; /* Failed to match */ } } if (fullPattern != NULL) { Tcl_DString dString; GetFullPath(treePtr, hboxPtr->separator, &dString); result = (*compareProc) (interp, Tcl_DStringValue(&dString), fullPattern); Tcl_DStringFree(&dString); if (result == invertMatch) { continue; /* Failed to match */ } } for (node = Blt_ListFirstNode(optionList); node != NULL; node = Blt_ListNextNode(node)) { option = (char *)Blt_ListGetKey(node); Tcl_ResetResult(interp); if (Tk_ConfigureValue(interp, hboxPtr->tkwin, entryConfigSpecs, (char *)treePtr->entryPtr, option, 0) != TCL_OK) { return TCL_ERROR; /* This shouldn't happen. */ } pattern = (char *)Blt_ListGetValue(node); value = (char *)Tcl_GetStringResult(interp); result = (*compareProc) (interp, value, pattern); if (result == invertMatch) { continue; /* Failed to match */ } } /* Finally, apply the procedure to the node */ (*proc) (hboxPtr, treePtr); } Tcl_ResetResult(interp); Blt_ListDestroy(optionList); } /* * Apply the procedure to nodes that have been specified * individually. */ for ( /*empty*/ ; i < argc; i++) { if ((argv[i][0] == 'a') && (strcmp(argv[i], "all") == 0)) { return ApplyToTree(hboxPtr, hboxPtr->rootPtr, proc, APPLY_RECURSE); } if (StringToNode(hboxPtr, argv[i], &treePtr) != TCL_OK) { return TCL_ERROR; } if ((*proc) (hboxPtr, treePtr) != TCL_OK) { return TCL_ERROR; } } if (nonMatchPtr != NULL) { *nonMatchPtr = invertMatch; /* return "inverted search" status */ } return TCL_OK; missingArg: Blt_ListDestroy(optionList); Tcl_AppendResult(interp, "missing pattern for search option \"", argv[i], "\"", (char *)NULL); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * HideOp -- * * Hides one or more nodes. Nodes can be specified by their * inode, or by matching a name or data value pattern. By * default, the patterns are matched exactly. They can also * be matched using glob-style and regular expression rules. * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ static int HideOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; char **argv; { int status, nonmatching; status = SearchAndApplyToTree(hboxPtr, interp, argc, argv, UnmapNode, &nonmatching); if (status != TCL_OK) { return TCL_ERROR; } /* * If this was an inverted search, scan back through the * tree and make sure that the parents for all visible * nodes are also visible. After all, if a node is supposed * to be visible, its parent can't be hidden. */ if (nonmatching) { ApplyToTree(hboxPtr, hboxPtr->rootPtr, MapAncestors, APPLY_RECURSE); } /* * Make sure that selections arme cleared from any hidden * nodes. This wasn't done earlier--we had to delay it until * we fixed the visibility status for the parents. */ ApplyToTree(hboxPtr, hboxPtr->rootPtr, FixUnmappedSelections, APPLY_RECURSE); hboxPtr->flags |= (HIERBOX_LAYOUT | HIERBOX_SCROLL); EventuallyRedraw(hboxPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * ShowOp -- * * Mark one or more nodes to be exposed. Nodes can be specified * by their inode, or by matching a name or data value pattern. By * default, the patterns are matched exactly. They can also * be matched using glob-style and regular expression rules. * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ static int ShowOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; char **argv; { if (SearchAndApplyToTree(hboxPtr, interp, argc, argv, MapNode, (int *)NULL) != TCL_OK) { return TCL_ERROR; } hboxPtr->flags |= (HIERBOX_LAYOUT | HIERBOX_SCROLL); EventuallyRedraw(hboxPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * IndexOp -- * * Converts one of more words representing indices of the entries * in the hierarchy widget to their respective serial identifiers. * * Results: * A standard Tcl result. Interp->result will contain the * identifier of each inode found. If an inode could not be found, * then the serial identifier will be the empty string. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int IndexOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tree *nodePtr, *rootPtr; rootPtr = hboxPtr->focusPtr; if ((argv[2][0] == '-') && (strcmp(argv[2], "-at") == 0)) { if (StringToNode(hboxPtr, argv[3], &rootPtr) != TCL_OK) { return TCL_ERROR; } argv += 2, argc -= 2; } if (argc > 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " index ?-at index? index\"", (char *)NULL); return TCL_ERROR; } nodePtr = rootPtr; if ((GetNode(hboxPtr, argv[2], &nodePtr) == TCL_OK) && (nodePtr != NULL)) { Tcl_SetResult(interp, NodeToString(hboxPtr, nodePtr), TCL_VOLATILE); } else { Tcl_SetResult(interp, "", TCL_STATIC); } return TCL_OK; } /* *---------------------------------------------------------------------- * * InsertOp -- * * Add new entries into a hierarchy. If no node is specified, * new entries will be added to the root of the hierarchy. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int InsertOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tree *rootPtr, *nodePtr, *parentPtr; int position; int level, count; char *path; Tcl_DString dString; register int i, l; int nOpts; char **options; char **nameArr; rootPtr = hboxPtr->rootPtr; if ((argv[2][0] == '-') && (strcmp(argv[2], "-at") == 0)) { if (StringToNode(hboxPtr, argv[3], &rootPtr) != TCL_OK) { return TCL_ERROR; } argv += 2, argc -= 2; } if (Blt_GetPosition(hboxPtr->interp, argv[2], &position) != TCL_OK) { return TCL_ERROR; } argc -= 3, argv += 3; /* * Count the pathnames that follow. Count the arguments until we * spot one that looks like a configuration option (i.e. starts * with a minus ("-")). */ for (count = 0; count < argc; count++) { if (argv[count][0] == '-') { break; } } nOpts = argc - count; options = argv + count; Tcl_DStringInit(&dString); for (i = 0; i < count; i++) { path = argv[i]; if (hboxPtr->trimLeft != NULL) { register char *p, *s; /* Trim off leading character string if one exists. */ for (p = path, s = hboxPtr->trimLeft; *s != '\0'; s++, p++) { if (*p != *s) { break; } } if (*s == '\0') { path = p; } } /* * Split the path and find the parent node of the path. */ nameArr = &path; level = 1; if (hboxPtr->separator == SEPARATOR_LIST) { if (Tcl_SplitList(interp, path, &level, &nameArr) != TCL_OK) { goto error; } } else if (hboxPtr->separator != SEPARATOR_NONE) { if (SplitPath(hboxPtr, path, &level, &nameArr) != TCL_OK) { goto error; } } if (level == 0) { continue; /* Root already exists. */ } parentPtr = rootPtr; level--; for (l = 0; l < level; l++) { nodePtr = FindComponent(parentPtr, nameArr[l]); if (nodePtr == NULL) { if (!hboxPtr->autoCreate) { Tcl_AppendResult(interp, "can't find path component \"", nameArr[l], "\" in \"", path, "\"", (char *)NULL); goto error; } nodePtr = CreateNode(hboxPtr, parentPtr, APPEND, nameArr[l]); } parentPtr = nodePtr; } nodePtr = NULL; if (!hboxPtr->allowDuplicates) { nodePtr = FindComponent(parentPtr, nameArr[level]); } if (nodePtr == NULL) { nodePtr = CreateNode(hboxPtr, parentPtr, position, nameArr[level]); if (nodePtr == NULL) { goto error; } if (ConfigureEntry(hboxPtr, nodePtr->entryPtr, nOpts, options, TK_CONFIG_ARGV_ONLY) != TCL_OK) { DeleteNode(hboxPtr, nodePtr); goto error; } Tcl_DStringAppendElement(&dString, NodeToString(hboxPtr, nodePtr)); } else { if (ConfigureEntry(hboxPtr, nodePtr->entryPtr, nOpts, options, 0) != TCL_OK) { goto error; } } if (nameArr != &path) { Blt_Free(nameArr); } } hboxPtr->flags |= (HIERBOX_LAYOUT | HIERBOX_SCROLL | HIERBOX_DIRTY); EventuallyRedraw(hboxPtr); Tcl_DStringResult(hboxPtr->interp, &dString); return TCL_OK; error: if (nameArr != &path) { Blt_Free(nameArr); } Tcl_DStringFree(&dString); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * DeleteOp -- * * Deletes nodes from the hierarchy. Deletes either a range of * entries from a hierarchy or a single node (except root). * In all cases, nodes are removed recursively. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int DeleteOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tree *treePtr; Blt_ChainLink *linkPtr; Blt_ChainLink *firstPtr, *lastPtr, *nextPtr; if (argc == 2) { return TCL_OK; } if (StringToNode(hboxPtr, argv[2], &treePtr) != TCL_OK) { return TCL_ERROR; /* Node or path doesn't already exist */ } firstPtr = lastPtr = NULL; switch (argc) { case 3: /* * Delete a single hierarchy. If the node specified is root, * delete only the children. */ if (treePtr != hboxPtr->rootPtr) { DestroyTree(hboxPtr, treePtr); /* Don't delete root */ goto done; } firstPtr = Blt_ChainFirstLink(treePtr->chainPtr); lastPtr = Blt_ChainLastLink(treePtr->chainPtr); break; case 4: /* * Delete a single node from hierarchy specified by its * numeric position. */ { int position; if (Blt_GetPosition(interp, argv[3], &position) != TCL_OK) { return TCL_ERROR; } if (position >= Blt_ChainGetLength(treePtr->chainPtr)) { return TCL_OK; /* Bad first index */ } if (position == APPEND) { linkPtr = Blt_ChainLastLink(treePtr->chainPtr); } else { linkPtr = Blt_ChainGetNthLink(treePtr->chainPtr, position); } firstPtr = lastPtr = linkPtr; } break; case 5: /* * Delete range of nodes in hierarchy specified by first/last * positions. */ { int first, last; int nEntries; if ((Blt_GetPosition(interp, argv[3], &first) != TCL_OK) || (Blt_GetPosition(interp, argv[4], &last) != TCL_OK)) { return TCL_ERROR; } nEntries = Blt_ChainGetLength(treePtr->chainPtr); if (nEntries == 0) { return TCL_OK; } if (first == APPEND) { first = nEntries - 1; } if (first >= nEntries) { Tcl_AppendResult(interp, "first position \"", argv[3], " is out of range", (char *)NULL); return TCL_ERROR; } if ((last == APPEND) || (last >= nEntries)) { last = nEntries - 1; } if (first > last) { Tcl_AppendResult(interp, "bad range: \"", argv[3], " > ", argv[4], "\"", (char *)NULL); return TCL_ERROR; } firstPtr = Blt_ChainGetNthLink(treePtr->chainPtr, first); lastPtr = Blt_ChainGetNthLink(treePtr->chainPtr, last); } break; } for (linkPtr = firstPtr; linkPtr != NULL; linkPtr = nextPtr) { nextPtr = Blt_ChainNextLink(linkPtr); treePtr = Blt_ChainGetValue(linkPtr); DestroyTree(hboxPtr, treePtr); if (linkPtr == lastPtr) { break; } } done: hboxPtr->flags |= (HIERBOX_LAYOUT | HIERBOX_SCROLL); EventuallyRedraw(hboxPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * MoveOp -- * * Move an entry into a new location in the hierarchy. * * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int MoveOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tree *srcPtr, *destPtr, *parentPtr; char c; int action; #define MOVE_INTO (1<<0) #define MOVE_BEFORE (1<<1) #define MOVE_AFTER (1<<2) if (StringToNode(hboxPtr, argv[2], &srcPtr) != TCL_OK) { return TCL_ERROR; } c = argv[3][0]; if ((c == 'i') && (strcmp(argv[3], "into") == 0)) { action = MOVE_INTO; } else if ((c == 'b') && (strcmp(argv[3], "before") == 0)) { action = MOVE_BEFORE; } else if ((c == 'a') && (strcmp(argv[3], "after") == 0)) { action = MOVE_AFTER; } else { Tcl_AppendResult(interp, "bad position \"", argv[3], "\": should be into, before, or after", (char *)NULL); return TCL_ERROR; } if (StringToNode(hboxPtr, argv[4], &destPtr) != TCL_OK) { return TCL_ERROR; } /* Verify they aren't ancestors. */ if (IsAncestor(srcPtr, destPtr)) { Tcl_AppendResult(interp, "can't move node: \"", argv[2], "\" is an ancestor of \"", argv[4], "\"", (char *)NULL); return TCL_ERROR; } parentPtr = destPtr->parentPtr; if (parentPtr == NULL) { action = MOVE_INTO; } Blt_ChainUnlinkLink(srcPtr->parentPtr->chainPtr, srcPtr->linkPtr); switch (action) { case MOVE_INTO: Blt_ChainLinkBefore(destPtr->chainPtr, srcPtr->linkPtr, (Blt_ChainLink *) NULL); parentPtr = destPtr; break; case MOVE_BEFORE: Blt_ChainLinkBefore(parentPtr->chainPtr, srcPtr->linkPtr, destPtr->linkPtr); break; case MOVE_AFTER: Blt_ChainLinkAfter(parentPtr->chainPtr, srcPtr->linkPtr, destPtr->linkPtr); break; } srcPtr->parentPtr = parentPtr; srcPtr->level = parentPtr->level + 1; hboxPtr->flags |= (HIERBOX_LAYOUT | HIERBOX_SCROLL | HIERBOX_DIRTY); EventuallyRedraw(hboxPtr); return TCL_OK; } /*ARGSUSED*/ static int NearestOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { ButtonAttributes *buttonPtr = &(hboxPtr->button); int x, y; /* Screen coordinates of the test point. */ register Entry *entryPtr; register Tree *treePtr; if ((Tk_GetPixels(interp, hboxPtr->tkwin, argv[2], &x) != TCL_OK) || (Tk_GetPixels(interp, hboxPtr->tkwin, argv[3], &y) != TCL_OK)) { return TCL_ERROR; } if (hboxPtr->nVisible == 0) { return TCL_OK; } treePtr = NearestNode(hboxPtr, x, y, TRUE); if (treePtr == NULL) { return TCL_OK; } x = WORLDX(hboxPtr, x); y = WORLDY(hboxPtr, y); entryPtr = treePtr->entryPtr; if (argc > 4) { char *where; int labelX; where = ""; if (entryPtr->flags & ENTRY_BUTTON) { int buttonX, buttonY; buttonX = entryPtr->worldX + entryPtr->buttonX; buttonY = entryPtr->worldY + entryPtr->buttonY; if ((x >= buttonX) && (x < (buttonX + buttonPtr->width)) && (y >= buttonY) && (y < (buttonY + buttonPtr->height))) { where = "gadget"; } } labelX = entryPtr->worldX + LEVELWIDTH(treePtr->level); if ((x >= labelX) && (x < (labelX + LEVELWIDTH(treePtr->level + 1) + entryPtr->width))) { where = "select"; } if (Tcl_SetVar(interp, argv[4], where, TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } } Tcl_SetResult(interp, NodeToString(hboxPtr, treePtr), TCL_VOLATILE); return TCL_OK; } /*ARGSUSED*/ static int OpenOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { Tree *rootPtr; unsigned int flags; register int i; flags = 0; if (argc > 2) { int length; length = strlen(argv[2]); if ((argv[2][0] == '-') && (length > 1) && (strncmp(argv[2], "-recurse", length) == 0)) { argv++, argc--; flags |= APPLY_RECURSE; } } for (i = 2; i < argc; i++) { rootPtr = hboxPtr->focusPtr; if (GetNode(hboxPtr, argv[i], &rootPtr) != TCL_OK) { return TCL_ERROR; } if (rootPtr == NULL) { continue; } ExposeAncestors(rootPtr); /* Also make sure that all the ancestors * of this node are also not hidden. */ if (ApplyToTree(hboxPtr, rootPtr, OpenNode, flags) != TCL_OK) { return TCL_ERROR; } } hboxPtr->flags |= (HIERBOX_LAYOUT | HIERBOX_SCROLL); EventuallyRedraw(hboxPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * RangeOp -- * * Returns the node identifiers in a given range. * *---------------------------------------------------------------------- */ static int RangeOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; char **argv; { Tree *firstPtr, *lastPtr; register Tree *treePtr; unsigned int flags; int length; flags = 0; length = strlen(argv[2]); if ((argv[2][0] == '-') && (length > 1) && (strncmp(argv[2], "-open", length) == 0)) { argv++, argc--; flags |= ENTRY_OPEN; } if (StringToNode(hboxPtr, argv[2], &firstPtr) != TCL_OK) { return TCL_ERROR; } lastPtr = EndNode(firstPtr, flags); if (argc > 3) { if (StringToNode(hboxPtr, argv[3], &lastPtr) != TCL_OK) { return TCL_ERROR; } } if (flags & ENTRY_OPEN) { if (IsHidden(firstPtr)) { Tcl_AppendResult(interp, "first node \"", argv[2], "\" is hidden.", (char *)NULL); return TCL_ERROR; } if (IsHidden(lastPtr)) { Tcl_AppendResult(interp, "last node \"", argv[3], "\" is hidden.", (char *)NULL); return TCL_ERROR; } } /* * The relative order of the first/last markers determines the * direction. */ if (IsBefore(lastPtr, firstPtr)) { for (treePtr = lastPtr; treePtr != NULL; treePtr = LastNode(treePtr, flags)) { Tcl_AppendElement(interp, NodeToString(hboxPtr, treePtr)); if (treePtr == firstPtr) { break; } } } else { for (treePtr = firstPtr; treePtr != NULL; treePtr = NextNode(treePtr, flags)) { Tcl_AppendElement(interp, NodeToString(hboxPtr, treePtr)); if (treePtr == lastPtr) { break; } } } return TCL_OK; } /* *---------------------------------------------------------------------- * * ScanOp -- * * Implements the quick scan. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ScanOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { int x, y; char c; unsigned int length; int oper; #define SCAN_MARK 1 #define SCAN_DRAGTO 2 c = argv[2][0]; length = strlen(argv[2]); if ((c == 'm') && (strncmp(argv[2], "mark", length) == 0)) { oper = SCAN_MARK; } else if ((c == 'd') && (strncmp(argv[2], "dragto", length) == 0)) { oper = SCAN_DRAGTO; } else { Tcl_AppendResult(interp, "bad scan operation \"", argv[2], "\": should be either \"mark\" or \"dragto\"", (char *)NULL); return TCL_ERROR; } if ((Tk_GetPixels(interp, hboxPtr->tkwin, argv[3], &x) != TCL_OK) || (Tk_GetPixels(interp, hboxPtr->tkwin, argv[4], &y) != TCL_OK)) { return TCL_ERROR; } if (oper == SCAN_MARK) { hboxPtr->scanAnchorX = x; hboxPtr->scanAnchorY = y; hboxPtr->scanX = hboxPtr->xOffset; hboxPtr->scanY = hboxPtr->yOffset; } else { int worldX, worldY; int dx, dy; dx = hboxPtr->scanAnchorX - x; dy = hboxPtr->scanAnchorY - y; worldX = hboxPtr->scanX + (10 * dx); worldY = hboxPtr->scanY + (10 * dy); if (worldX < 0) { worldX = 0; } else if (worldX >= hboxPtr->worldWidth) { worldX = hboxPtr->worldWidth - hboxPtr->xScrollUnits; } if (worldY < 0) { worldY = 0; } else if (worldY >= hboxPtr->worldHeight) { worldY = hboxPtr->worldHeight - hboxPtr->yScrollUnits; } hboxPtr->xOffset = worldX; hboxPtr->yOffset = worldY; hboxPtr->flags |= (HIERBOX_LAYOUT | HIERBOX_SCROLL); EventuallyRedraw(hboxPtr); } return TCL_OK; } /*ARGSUSED*/ static int SeeOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { Entry *entryPtr; int width, height; int x, y; Tree *treePtr; Tk_Anchor anchor; int left, right, top, bottom; anchor = TK_ANCHOR_W; /* Default anchor is West */ if ((argv[2][0] == '-') && (strcmp(argv[2], "-anchor") == 0)) { if (argc == 3) { Tcl_AppendResult(interp, "missing \"-anchor\" argument", (char *)NULL); return TCL_ERROR; } if (Tk_GetAnchor(interp, argv[3], &anchor) != TCL_OK) { return TCL_ERROR; } argc -= 2, argv += 2; } if (argc == 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], "see ?-anchor anchor? index\"", (char *)NULL); return TCL_ERROR; } treePtr = hboxPtr->focusPtr; if (GetNode(hboxPtr, argv[2], &treePtr) != TCL_OK) { return TCL_ERROR; } if (treePtr == NULL) { return TCL_OK; } if (IsHidden(treePtr)) { ExposeAncestors(treePtr); hboxPtr->flags |= (HIERBOX_LAYOUT | HIERBOX_SCROLL); /* * If the entry wasn't previously exposed, its world coordinates * aren't likely to be valid. So re-compute the layout before * we try to see the viewport to the entry's location. */ ComputeLayout(hboxPtr); } entryPtr = treePtr->entryPtr; width = VPORTWIDTH(hboxPtr); height = VPORTHEIGHT(hboxPtr); /* * XVIEW: If the entry is left or right of the current view, adjust * the offset. If the entry is nearby, adjust the view just * a bit. Otherwise, center the entry. */ left = hboxPtr->xOffset; right = hboxPtr->xOffset + width; switch (anchor) { case TK_ANCHOR_W: case TK_ANCHOR_NW: case TK_ANCHOR_SW: x = 0; break; case TK_ANCHOR_E: case TK_ANCHOR_NE: case TK_ANCHOR_SE: x = entryPtr->worldX + entryPtr->width + LEVELWIDTH(treePtr->level) - width; break; default: if (entryPtr->worldX < left) { x = entryPtr->worldX; } else if ((entryPtr->worldX + entryPtr->width) > right) { x = entryPtr->worldX + entryPtr->width - width; } else { x = hboxPtr->xOffset; } break; } /* * YVIEW: If the entry is above or below the current view, adjust * the offset. If the entry is nearby, adjust the view just * a bit. Otherwise, center the entry. */ top = hboxPtr->yOffset; bottom = hboxPtr->yOffset + height; switch (anchor) { case TK_ANCHOR_N: y = hboxPtr->yOffset; break; case TK_ANCHOR_NE: case TK_ANCHOR_NW: y = entryPtr->worldY - (height / 2); break; case TK_ANCHOR_S: case TK_ANCHOR_SE: case TK_ANCHOR_SW: y = entryPtr->worldY + entryPtr->height - height; break; default: if (entryPtr->worldY < top) { y = entryPtr->worldY; } else if ((entryPtr->worldY + entryPtr->height) > bottom) { y = entryPtr->worldY + entryPtr->height - height; } else { y = hboxPtr->yOffset; } break; } if ((y != hboxPtr->yOffset) || (x != hboxPtr->xOffset)) { hboxPtr->xOffset = x; hboxPtr->yOffset = y; hboxPtr->flags |= (HIERBOX_SCROLL | HIERBOX_LAYOUT); } EventuallyRedraw(hboxPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * AnchorOpOp -- * * Sets the selection anchor to the element given by a index. * The selection anchor is the end of the selection that is fixed * while dragging out a selection with the mouse. The index * "anchor" may be used to refer to the anchor element. * * Results: * None. * * Side effects: * The selection changes. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int AnchorOpOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; /* Not used. */ int argc; /* Not used. */ char **argv; { Tree *nodePtr; nodePtr = hboxPtr->focusPtr; if (GetNode(hboxPtr, argv[3], &nodePtr) != TCL_OK) { return TCL_ERROR; } hboxPtr->selAnchorPtr = nodePtr; if (nodePtr != NULL) { Tcl_SetResult(interp, NodeToString(hboxPtr, nodePtr), TCL_VOLATILE); } EventuallyRedraw(hboxPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * ClearallOpOp * * Clears the entire selection. * * Results: * None. * * Side effects: * The selection changes. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ClearallOpOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { ClearSelection(hboxPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * IncludesOpOp * * Returns 1 if the element indicated by index is currently * selected, 0 if it isn't. * * Results: * None. * * Side effects: * The selection changes. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int IncludesOpOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tree *treePtr; treePtr = hboxPtr->focusPtr; if (GetNode(hboxPtr, argv[3], &treePtr) != TCL_OK) { return TCL_ERROR; } if (treePtr != NULL) { int bool; bool = IsSelected(hboxPtr, treePtr); Blt_SetBooleanResult(interp, bool); } return TCL_OK; } /*---------------------------------------------------------------------- * * MarkOpOp -- * * Sets the selection mark to the element given by a index. The * selection mark is the end of the selection that is not fixed * while dragging out a selection with the mouse. The index * "mark" may be used to refer to the anchor element. * * Results: * None. * * Side effects: * The selection changes. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int MarkOpOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; /* Not used. */ int argc; /* Not used. */ char **argv; { Tree *nodePtr; Blt_ChainLink *linkPtr, *nextPtr; Tree *selectPtr; nodePtr = hboxPtr->focusPtr; if (GetNode(hboxPtr, argv[3], &nodePtr) != TCL_OK) { return TCL_ERROR; } if (hboxPtr->selAnchorPtr == NULL) { Tcl_AppendResult(interp, "selection anchor must be set first", (char *)NULL); return TCL_ERROR; } /* Deselect entry from the list all the way back to the anchor. */ for (linkPtr = Blt_ChainLastLink(&(hboxPtr->selectChain)); linkPtr != NULL; linkPtr = nextPtr) { nextPtr = Blt_ChainPrevLink(linkPtr); selectPtr = Blt_ChainGetValue(linkPtr); if (selectPtr == hboxPtr->selAnchorPtr) { break; } DeselectEntry(hboxPtr, selectPtr); } if (nodePtr != NULL) { hboxPtr->flags &= ~SELECTION_MASK; hboxPtr->flags |= SELECTION_SET; SelectRange(hboxPtr, hboxPtr->selAnchorPtr, nodePtr); hboxPtr->flags &= ~SELECTION_MASK; Tcl_SetResult(interp, NodeToString(hboxPtr, nodePtr), TCL_VOLATILE); } EventuallyRedraw(hboxPtr); if (hboxPtr->selectCmd != NULL) { EventuallyInvokeSelectCmd(hboxPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * PresentOpOp * * Indicates if there is a selection present. * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int PresentOpOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { int bool; bool = (Blt_ChainGetLength(&(hboxPtr->selectChain)) > 0); Blt_SetBooleanResult(interp, bool); return TCL_OK; } /* *---------------------------------------------------------------------- * * SelectOpOp * * Selects, deselects, or toggles all of the elements in the * range between first and last, inclusive, without affecting the * selection state of elements outside that range. * * Results: * None. * * Side effects: * The selection changes. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int SelectOpOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tree *firstPtr, *lastPtr; hboxPtr->flags &= ~SELECTION_MASK; switch (argv[2][0]) { case 's': hboxPtr->flags |= SELECTION_SET; break; case 'c': hboxPtr->flags |= SELECTION_CLEAR; break; case 't': hboxPtr->flags |= SELECTION_TOGGLE; break; } if (StringToNode(hboxPtr, argv[3], &firstPtr) != TCL_OK) { return TCL_ERROR; } if ((IsHidden(firstPtr)) && !(hboxPtr->flags & SELECTION_CLEAR)) { Tcl_AppendResult(interp, "can't select hidden node \"", argv[3], "\"", (char *)NULL); return TCL_ERROR; } lastPtr = firstPtr; if (argc > 4) { if (StringToNode(hboxPtr, argv[4], &lastPtr) != TCL_OK) { return TCL_ERROR; } if ((IsHidden(lastPtr)) && !(hboxPtr->flags & SELECTION_CLEAR)) { Tcl_AppendResult(interp, "can't select hidden node \"", argv[4], "\"", (char *)NULL); return TCL_ERROR; } } if (firstPtr == lastPtr) { SelectNode(hboxPtr, firstPtr); } else { SelectRange(hboxPtr, firstPtr, lastPtr); } hboxPtr->flags &= ~SELECTION_MASK; if (hboxPtr->flags & SELECTION_EXPORT) { Tk_OwnSelection(hboxPtr->tkwin, XA_PRIMARY, LostSelection, hboxPtr); } EventuallyRedraw(hboxPtr); if (hboxPtr->selectCmd != NULL) { EventuallyInvokeSelectCmd(hboxPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * SelectionOp -- * * This procedure handles the individual options for text * selections. The selected text is designated by start and end * indices into the text pool. The selected segment has both a * anchored and unanchored ends. * * Results: * None. * * Side effects: * The selection changes. * *---------------------------------------------------------------------- */ static Blt_OpSpec selectionOperSpecs[] = { {"anchor", 1, (Blt_Op)AnchorOpOp, 4, 4, "index",}, {"clear", 5, (Blt_Op)SelectOpOp, 4, 5, "firstIndex ?lastIndex?",}, {"clearall", 6, (Blt_Op)ClearallOpOp, 3, 3, "",}, {"includes", 2, (Blt_Op)IncludesOpOp, 4, 4, "index",}, {"mark", 1, (Blt_Op)MarkOpOp, 4, 4, "index",}, {"present", 1, (Blt_Op)PresentOpOp, 3, 3, "",}, {"set", 1, (Blt_Op)SelectOpOp, 4, 5, "firstIndex ?lastIndex?",}, {"toggle", 1, (Blt_Op)SelectOpOp, 4, 5, "firstIndex ?lastIndex?",}, }; static int nSelectionSpecs = sizeof(selectionOperSpecs) / sizeof(Blt_OpSpec); static int SelectionOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; char **argv; { Blt_Op proc; int result; proc = Blt_GetOp(interp, nSelectionSpecs, selectionOperSpecs, BLT_OP_ARG2, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (hboxPtr, interp, argc, argv); return result; } /*ARGSUSED*/ static int SortOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { int length; Tree *rootPtr; register int i; unsigned int flags; flags = 0; hboxPtr->sortCmd = NULL; for (i = 2; i < argc; i++) { if (argv[i][0] != '-') { break; /* Found start of indices */ } length = strlen(argv[i]); if ((length > 1) && (strncmp(argv[i], "-recurse", length) == 0)) { flags |= APPLY_RECURSE; } else if ((length > 1) && (strncmp(argv[i], "-command", length) ==0)) { if ((i + 1) == argc) { Tcl_AppendResult(interp, "\"-command\" must be", " followed by comparison command", (char *)NULL); return TCL_ERROR; } i++; hboxPtr->sortCmd = argv[i]; } else if ((argv[i][1] == '-') && (argv[i][2] == '\0')) { break; /* Allow first index to start with a '-' */ } else { Tcl_AppendResult(interp, "bad switch \"", argv[i], "\": must be -command or -recurse", (char *)NULL); return TCL_ERROR; } } for ( /*empty*/ ; i < argc; i++) { if (StringToNode(hboxPtr, argv[i], &rootPtr) != TCL_OK) { return TCL_ERROR; } if (ApplyToTree(hboxPtr, rootPtr, SortNode, flags) != TCL_OK) { return TCL_ERROR; } } hboxPtr->flags |= HIERBOX_LAYOUT; EventuallyRedraw(hboxPtr); return TCL_OK; } /*ARGSUSED*/ static int ToggleOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { Tree *rootPtr; int result; rootPtr = hboxPtr->focusPtr; if (GetNode(hboxPtr, argv[2], &rootPtr) != TCL_OK) { return TCL_ERROR; } if (rootPtr == NULL) { return TCL_OK; } if (rootPtr->entryPtr->flags & ENTRY_OPEN) { PruneSelection(hboxPtr, rootPtr); if (IsAncestor(rootPtr, hboxPtr->focusPtr)) { hboxPtr->focusPtr = rootPtr; Blt_SetFocusItem(hboxPtr->bindTable, hboxPtr->focusPtr, NULL); } if (IsAncestor(rootPtr, hboxPtr->selAnchorPtr)) { hboxPtr->selAnchorPtr = NULL; } result = CloseNode(hboxPtr, rootPtr); } else { result = OpenNode(hboxPtr, rootPtr); } if (result != TCL_OK) { return TCL_ERROR; } hboxPtr->flags |= (HIERBOX_LAYOUT | HIERBOX_SCROLL); EventuallyRedraw(hboxPtr); return TCL_OK; } static int XViewOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; char **argv; { int width, worldWidth; width = VPORTWIDTH(hboxPtr); worldWidth = hboxPtr->worldWidth; if (argc == 2) { double fract; /* * Note that we are bounding the fractions between 0.0 and 1.0 * to support the "canvas"-style of scrolling. */ fract = (double)hboxPtr->xOffset / worldWidth; Tcl_AppendElement(interp, Blt_Dtoa(interp, CLAMP(fract, 0.0, 1.0))); fract = (double)(hboxPtr->xOffset + width) / worldWidth; Tcl_AppendElement(interp, Blt_Dtoa(interp, CLAMP(fract, 0.0, 1.0))); return TCL_OK; } if (Blt_GetScrollInfo(interp, argc - 2, argv + 2, &(hboxPtr->xOffset), worldWidth, width, hboxPtr->xScrollUnits, hboxPtr->scrollMode) != TCL_OK) { return TCL_ERROR; } hboxPtr->flags |= HIERBOX_XSCROLL; EventuallyRedraw(hboxPtr); return TCL_OK; } static int YViewOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; char **argv; { int height, worldHeight; height = VPORTHEIGHT(hboxPtr); worldHeight = hboxPtr->worldHeight; if (argc == 2) { double fract; /* Report first and last fractions */ fract = (double)hboxPtr->yOffset / worldHeight; Tcl_AppendElement(interp, Blt_Dtoa(interp, CLAMP(fract, 0.0, 1.0))); fract = (double)(hboxPtr->yOffset + height) / worldHeight; Tcl_AppendElement(interp, Blt_Dtoa(interp, CLAMP(fract, 0.0, 1.0))); return TCL_OK; } if (Blt_GetScrollInfo(interp, argc - 2, argv + 2, &(hboxPtr->yOffset), worldHeight, height, hboxPtr->yScrollUnits, hboxPtr->scrollMode) != TCL_OK) { return TCL_ERROR; } hboxPtr->flags |= HIERBOX_SCROLL; EventuallyRedraw(hboxPtr); return TCL_OK; } /* * -------------------------------------------------------------- * * HierboxInstCmd -- * * This procedure is invoked to process the "hierbox" command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * * -------------------------------------------------------------- */ static Blt_OpSpec operSpecs[] = { {"bbox", 2, (Blt_Op)BboxOp, 2, 0, "index...",}, {"bind", 2, (Blt_Op)BindOp, 3, 5, "tagName ?sequence command?",}, {"button", 2, (Blt_Op)ButtonOp, 2, 0, "args",}, {"cget", 2, (Blt_Op)CgetOp, 3, 3, "option",}, {"close", 2, (Blt_Op)CloseOp, 2, 0, "?-recurse? index...",}, {"configure", 2, (Blt_Op)ConfigureOp, 2, 0, "?option value?...",}, {"curselection", 2, (Blt_Op)CurselectionOp, 2, 2, "",}, {"delete", 1, (Blt_Op)DeleteOp, 2, 0, "?-recurse? index ?index...?",}, {"entry", 1, (Blt_Op)EntryOp, 2, 0, "oper args",}, {"find", 2, (Blt_Op)FindOp, 2, 0, "?flags...? ?firstIndex lastIndex?",}, {"focus", 2, (Blt_Op)FocusOp, 3, 3, "index",}, {"get", 1, (Blt_Op)GetOp, 2, 0, "?-full? index ?index...?",}, {"hide", 1, (Blt_Op)HideOp, 2, 0, "?-exact? ?-glob? ?-regexp? ?-nonmatching? ?-name string? ?-full string? ?-data string? ?--? ?index...?",}, {"index", 3, (Blt_Op)IndexOp, 3, 5, "?-at index? string",}, {"insert", 3, (Blt_Op)InsertOp, 3, 0, "?-at index? position label ?label...? ?option value?",}, {"move", 1, (Blt_Op)MoveOp, 5, 5, "index into|before|after index",}, {"nearest", 1, (Blt_Op)NearestOp, 4, 5, "x y ?varName?",}, {"open", 1, (Blt_Op)OpenOp, 2, 0, "?-recurse? index...",}, {"range", 1, (Blt_Op)RangeOp, 4, 5, "?-open? firstIndex lastIndex",}, {"scan", 2, (Blt_Op)ScanOp, 5, 5, "dragto|mark x y",}, {"see", 3, (Blt_Op)SeeOp, 3, 0, "?-anchor anchor? index",}, {"selection", 3, (Blt_Op)SelectionOp, 2, 0, "oper args",}, {"show", 2, (Blt_Op)ShowOp, 2, 0, "?-exact? ?-glob? ?-regexp? ?-nonmatching? ?-name string? ?-full string? ?-data string? ?--? ?index...?",}, {"sort", 2, (Blt_Op)SortOp, 2, 0, "?-recurse? ?-command string? index...",}, {"toggle", 1, (Blt_Op)ToggleOp, 3, 3, "index",}, {"xview", 1, (Blt_Op)XViewOp, 2, 5, "?moveto fract? ?scroll number what?",}, {"yview", 1, (Blt_Op)YViewOp, 2, 5, "?moveto fract? ?scroll number what?",}, }; static int nSpecs = sizeof(operSpecs) / sizeof(Blt_OpSpec); static int HierboxInstCmd(clientData, interp, argc, argv) ClientData clientData; /* Information about the widget. */ Tcl_Interp *interp; /* Interpreter to report errors back to. */ int argc; /* Number of arguments. */ char **argv; /* Vector of argument strings. */ { Blt_Op proc; Hierbox *hboxPtr = clientData; int result; proc = Blt_GetOp(interp, nSpecs, operSpecs, BLT_OP_ARG1, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } Tcl_Preserve(hboxPtr); result = (*proc) (hboxPtr, interp, argc, argv); Tcl_Release(hboxPtr); return result; } int Blt_HierboxInit(interp) Tcl_Interp *interp; { static Blt_CmdSpec cmdSpec = { "hierbox", HierboxCmd, }; if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) { return TCL_ERROR; } return TCL_OK; } #ifdef notdef /* Selection Procedures */ /* *---------------------------------------------------------------------- * * SelectTextBlock -- * * Modify the selection by moving its un-anchored end. This * could make the selection either larger or smaller. * * Results: * None. * * Side effects: * The selection changes. * *---------------------------------------------------------------------- */ static int SelectTextBlock(hboxPtr, to) Hierbox *hboxPtr; /* Information about widget. */ int to; /* Index of element that is to * become the "other" end of the * selection. */ { TextEdit *editPtr = &(hboxPtr->labelEdit); int first, last; /* If the anchor hasn't been set yet, assume the beginning of the label. */ if (editPtr->selAnchor < 0) { editPtr->selAnchor = 0; } if (editPtr->selAnchor <= to) { first = editPtr->selAnchor; last = to; } else { first = to; last = editPtr->selAnchor; } if ((editPtr->selFirst != first) || (editPtr->selLast != last)) { editPtr->selFirst = first, editPtr->selLast = last; EventuallyRedraw(hboxPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * ClearOpOp -- * * Clears the selection from the label. * * Results: * None. * * Side effects: * The selection changes. * *---------------------------------------------------------------------- */ static int ClearOpOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; char **argv; { TextEdit *editPtr = &(hboxPtr->labelEdit); if (editPtr->selFirst != -1) { editPtr->selFirst = editPtr->selLast = -1; EventuallyRedraw(hboxPtr); } return TCL_OK; } static int FromOpOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; char **argv; { TextEdit *editPtr = &(hboxPtr->labelEdit); int from; if (GetLabelIndex(hboxPtr, argv[3], &from) != TCL_OK) { return TCL_ERROR; } editPtr->selAnchor = from; return TCL_OK; } static int PresentOpOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; char **argv; { TextEdit *editPtr = &(hboxPtr->labelEdit); Tcl_AppendResult(interp, (editPtr->selFirst != -1) ? "0" : "1", (char *)NULL); return TCL_OK; } static int AdjustOpOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; char **argv; { TextEdit *editPtr = &(hboxPtr->labelEdit); int adjust; if (GetLabelIndex(hboxPtr, argv[3], &adjust) != TCL_OK) { return TCL_ERROR; } half1 = (editPtr->selFirst + editPtr->selLast) / 2; half2 = (editPtr->selFirst + editPtr->selLast + 1) / 2; if (adjust < half1) { editPtr->selAnchor = editPtr->selLast; } else if (adjust > half2) { editPtr->selAnchor = editPtr->selFirst; } result = SelectTextBlock(hboxPtr, adjust); return TCL_OK; } static int ToOpOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; char **argv; { int to; if (GetLabelIndex(hboxPtr, argv[3], &to) != TCL_OK) { return TCL_ERROR; } SelectTextBlock(hboxPtr, to); return TCL_OK; } static int RangeOpOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; char **argv; { TextEdit *editPtr = &(hboxPtr->labelEdit); int first, last; if (GetLabelIndex(hboxPtr, argv[4], &first) != TCL_OK) { return TCL_ERROR; } if (GetLabelIndex(hboxPtr, argv[5], &last) != TCL_OK) { return TCL_ERROR; } editPtr->selAnchor = first; return SelectTextBlock(hboxPtr, last); } /* *---------------------------------------------------------------------- * * SelectionOp -- * * This procedure handles the individual options for text * selections. The selected text is designated by a starting * and terminating index that points into the text. The selected * segment has both a anchored and unanchored ends. The following * selection operations are implemented: * * adjust index Resets either the first or last index * of the selection. * clear Clears the selection. Sets first/last * indices to -1. * from index Sets the index of the selection anchor. * present Return "1" if a selection is available, * "0" otherwise. * range first last Sets the selection. * to index Sets the index of the un-anchored end. * Results: * None. * * Side effects: * The selection changes. * *---------------------------------------------------------------------- */ static Blt_OpSpec entrySelectionOperSpecs[] = { {"adjust", 2, (Blt_Op)AdjustOpOp, 5, 5, "index",}, {"clear", 2, (Blt_Op)ClearOpOp, 4, 4, "",}, {"from", 1, (Blt_Op)FromOpOp, 5, 5, "index",}, {"present", 1, (Blt_Op)PresentOpOp, 4, 4, "",}, {"range", 1, (Blt_Op)RangeOpOp, 4, 5, "firstIndex lastIndex",}, {"to", 1, (Blt_Op)ToOpOp, 5, 5, "index",}, }; static int nEntrySelectionSpecs = sizeof(entrySelectionOperSpecs) / sizeof(Blt_OpSpec); static int EntrySelectionOp(hboxPtr, interp, argc, argv) Hierbox *hboxPtr; Tcl_Interp *interp; int argc; char **argv; { Blt_Op proc; int result; proc = Blt_GetOp(interp, nSelectionSpecs, selectionOperSpecs, BLT_OP_ARG2, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (hboxPtr, interp, argc, argv); return result; } #endif #endif /* NO_HIERBOX */ blt-2.4z.orig/src/bltHtext.c0100644000175000017500000037576307515237460014533 0ustar dokodoko/* * bltHtext.c -- * * This module implements a hypertext widget for the BLT toolkit. * * Copyright 1991-1998 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. * * The "htext" widget was created by George Howlett. */ /* * To do: * * 1) Fix scroll unit round off errors. * * 2) Better error checking. * * 3) Use html format. * * 4) The dimension of cavities using -relwidth and -relheight * should be 0 when computing initial estimates for the size * of the virtual text. */ #include "bltInt.h" #ifndef NO_HTEXT #include #include #include "bltTile.h" #include #include #define DEF_LINES_ALLOC 512 /* Default block of lines allocated */ #define CLAMP(val,low,hi) \ (((val) < (low)) ? (low) : ((val) > (hi)) ? (hi) : (val)) /* * Justify option values */ typedef enum { JUSTIFY_CENTER, JUSTIFY_TOP, JUSTIFY_BOTTOM } Justify; extern Tk_CustomOption bltFillOption; extern Tk_CustomOption bltPadOption; extern Tk_CustomOption bltDistanceOption; extern Tk_CustomOption bltTileOption; static int StringToWidth _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *string, char *widgRec, int flags)); static int StringToHeight _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *string, char *widgRec, int flags)); static char *WidthHeightToString _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, char *widgRec, int offset, Tcl_FreeProc **freeProc)); static Tk_CustomOption widthOption = { StringToWidth, WidthHeightToString, (ClientData)0 }; static Tk_CustomOption heightOption = { StringToHeight, WidthHeightToString, (ClientData)0 }; static int StringToJustify _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *string, char *widgRec, int offset)); static char *JustifyToString _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, char *widgRec, int offset, Tcl_FreeProc **freeProcPtr)); static Tk_CustomOption justifyOption = { StringToJustify, JustifyToString, (ClientData)0 }; static void EmbeddedWidgetGeometryProc _ANSI_ARGS_((ClientData, Tk_Window)); static void EmbeddedWidgetCustodyProc _ANSI_ARGS_((ClientData, Tk_Window)); static Tk_GeomMgr htextMgrInfo = { "htext", /* Name of geometry manager used by winfo */ EmbeddedWidgetGeometryProc, /* Procedure to for new geometry requests */ EmbeddedWidgetCustodyProc, /* Procedure when window is taken away */ }; /* * Line -- * * Structure to contain the contents of a single line of text and * the widgets on that line. * * Individual lines are not configurable, although changes to the * size of widgets do effect its values. */ typedef struct { int offset; /* Offset of line from y-origin (0) in * world coordinates */ int baseline; /* Baseline y-coordinate of the text */ short int width, height; /* Dimensions of the line */ int textStart, textEnd; /* Start and end indices of characters * forming the line in the text array */ Blt_Chain *chainPtr; /* Chain of embedded widgets on the line of * text */ } Line; typedef struct { int textStart; int textEnd; } Segment; typedef struct { int x, y; } Position; /* * Hypertext widget. */ typedef struct { Tk_Window tkwin; /* Window that embodies the widget. * NULL means that the window has been * destroyed but the data structures * haven't yet been cleaned up.*/ Display *display; /* Display containing widget; needed, * among other things, to release * resources after tkwin has already * gone away. */ Tcl_Interp *interp; /* Interpreter associated with widget. */ Tcl_Command cmdToken; /* Token for htext's widget command. */ int flags; /* User-configurable fields */ XColor *normalFg, *normalBg; Tk_Font font; /* Font for normal text. May affect the size * of the viewport if the width/height is * specified in columns/rows */ GC drawGC; /* Graphics context for normal text */ Blt_Tile tile; int tileOffsetPage; /* Set tile offset to top of page instead * of toplevel window */ GC fillGC; /* GC for clearing the window in the * designated background color. The * background color is the foreground * attribute in GC. */ int nRows, nColumns; /* # of characters of the current font * for a row or column of the viewport. * Used to determine the width and height * of the text window (i.e. viewport) */ int reqWidth, reqHeight; /* Requested dimensions of the viewport */ int maxWidth, maxHeight; /* Maximum dimensions allowed for the viewport, * regardless of the size of the text */ Tk_Cursor cursor; /* X Cursor */ char *fileName; /* If non-NULL, indicates the name of a * hypertext file to be read into the widget. * If NULL, the *text* field is considered * instead */ char *text; /* Hypertext to be loaded into the widget. This * value is ignored if *fileName* is non-NULL */ int specChar; /* Special character designating a TCL * command block in a hypertext file. */ int leader; /* # of pixels between lines */ char *yScrollCmdPrefix; /* Name of vertical scrollbar to invoke */ int yScrollUnits; /* # of pixels per vertical scroll */ char *xScrollCmdPrefix; /* Name of horizontal scroll bar to invoke */ int xScrollUnits; /* # of pixels per horizontal scroll */ int reqLineNum; /* Line requested by "goto" command */ /* * The view port is the width and height of the window and the * origin of the viewport (upper left corner) in world coordinates. */ int worldWidth, worldHeight;/* Size of view text in world coordinates */ int xOffset, yOffset; /* Position of viewport in world coordinates */ int pendingX, pendingY; /* New upper-left corner (origin) of * the viewport (not yet posted) */ int first, last; /* Range of lines displayed */ int lastWidth, lastHeight; /* Last known size of the window: saved to * recognize when the viewport is resized. */ Blt_HashTable widgetTable; /* Table of embedded widgets. */ /* * Selection display information: */ Tk_3DBorder selBorder; /* Border and background color */ int selBorderWidth; /* Border width */ XColor *selFgColor; /* Text foreground color */ GC selectGC; /* GC for drawing selected text */ int selAnchor; /* Fixed end of selection * (i.e. "selection to" operation will * use this as one end of the selection).*/ int selFirst; /* The index of first character in the * text array selected */ int selLast; /* The index of the last character selected */ int exportSelection; /* Non-zero means to export the internal text * selection to the X server. */ char *takeFocus; /* * Scanning information: */ XPoint scanMark; /* Anchor position of scan */ XPoint scanPt; /* x,y position where the scan started. */ char *charArr; /* Pool of characters representing the text * to be displayed */ int nChars; /* Length of the text pool */ Line *lineArr; /* Array of pointers to text lines */ int nLines; /* # of line entered into array. */ int arraySize; /* Size of array allocated. */ } HText; /* * Bit flags for the hypertext widget: */ #define REDRAW_PENDING (1<<0) /* A DoWhenIdle handler has already * been queued to redraw the window */ #define IGNORE_EXPOSURES (1<<1) /* Ignore exposure events in the text * window. Potentially many expose * events can occur while rearranging * embedded widgets during a single call to * the DisplayText. */ #define REQUEST_LAYOUT (1<<4) /* Something has happened which * requires the layout of text and * embedded widget positions to be * recalculated. The following * actions may cause this: * * 1) the contents of the hypertext * has changed by either the -file or * -text options. * * 2) a text attribute has changed * (line spacing, font, etc) * * 3) a embedded widget has been resized or * moved. * * 4) a widget configuration option has * changed. */ #define TEXT_DIRTY (1<<5) /* The layout was recalculated and the * size of the world (text layout) has * changed. */ #define GOTO_PENDING (1<<6) /* Indicates the starting text line * number has changed. To be reflected * the next time the widget is redrawn. */ #define WIDGET_APPENDED (1<<7) /* Indicates a embedded widget has just * been appended to the text. This is * used to determine when to add a * space to the text array */ #define DEF_HTEXT_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_HTEXT_BG_MONO STD_NORMAL_BG_MONO #define DEF_HTEXT_CURSOR "arrow" #define DEF_HTEXT_EXPORT_SELECTION "1" #define DEF_HTEXT_FOREGROUND STD_NORMAL_FOREGROUND #define DEF_HTEXT_FG_MONO STD_NORMAL_FG_MONO #define DEF_HTEXT_FILE_NAME (char *)NULL #define DEF_HTEXT_FONT STD_FONT #define DEF_HTEXT_HEIGHT "0" #define DEF_HTEXT_LINE_SPACING "1" #define DEF_HTEXT_MAX_HEIGHT (char *)NULL #define DEF_HTEXT_MAX_WIDTH (char *)NULL #define DEF_HTEXT_SCROLL_UNITS "10" #define DEF_HTEXT_SPEC_CHAR "0x25" #define DEF_HTEXT_SELECT_BORDERWIDTH STD_SELECT_BORDERWIDTH #define DEF_HTEXT_SELECT_BACKGROUND STD_SELECT_BACKGROUND #define DEF_HTEXT_SELECT_BG_MONO STD_SELECT_BG_MONO #define DEF_HTEXT_SELECT_FOREGROUND STD_SELECT_FOREGROUND #define DEF_HTEXT_SELECT_FG_MONO STD_SELECT_FG_MONO #define DEF_HTEXT_TAKE_FOCUS "1" #define DEF_HTEXT_TEXT (char *)NULL #define DEF_HTEXT_TILE_OFFSET "1" #define DEF_HTEXT_WIDTH "0" static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_COLOR, "-background", "background", "Background", DEF_HTEXT_BACKGROUND, Tk_Offset(HText, normalBg), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-background", "background", "Background", DEF_HTEXT_BG_MONO, Tk_Offset(HText, normalBg), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", DEF_HTEXT_CURSOR, Tk_Offset(HText, cursor), TK_CONFIG_NULL_OK}, {TK_CONFIG_BOOLEAN, "-exportselection", "exportSelection", "ExportSelection", DEF_HTEXT_EXPORT_SELECTION, Tk_Offset(HText, exportSelection), 0}, {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_STRING, "-file", "file", "File", DEF_HTEXT_FILE_NAME, Tk_Offset(HText, fileName), TK_CONFIG_NULL_OK}, {TK_CONFIG_FONT, "-font", "font", "Font", DEF_HTEXT_FONT, Tk_Offset(HText, font), 0}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_HTEXT_FOREGROUND, Tk_Offset(HText, normalFg), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_HTEXT_FG_MONO, Tk_Offset(HText, normalFg), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_CUSTOM, "-height", "height", "Height", DEF_HTEXT_HEIGHT, Tk_Offset(HText, reqHeight), TK_CONFIG_DONT_SET_DEFAULT, &heightOption}, {TK_CONFIG_CUSTOM, "-linespacing", "lineSpacing", "LineSpacing", DEF_HTEXT_LINE_SPACING, Tk_Offset(HText, leader), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-maxheight", "maxHeight", "MaxHeight", DEF_HTEXT_MAX_HEIGHT, Tk_Offset(HText, maxHeight), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-maxwidth", "maxWidth", "MaxWidth", DEF_HTEXT_MAX_WIDTH, Tk_Offset(HText, maxWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Background", DEF_HTEXT_SELECT_BG_MONO, Tk_Offset(HText, selBorder), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Background", DEF_HTEXT_SELECT_BACKGROUND, Tk_Offset(HText, selBorder), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_CUSTOM, "-selectborderwidth", "selectBorderWidth", "BorderWidth", DEF_HTEXT_SELECT_BORDERWIDTH, Tk_Offset(HText, selBorderWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Foreground", DEF_HTEXT_SELECT_FG_MONO, Tk_Offset(HText, selFgColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Foreground", DEF_HTEXT_SELECT_FOREGROUND, Tk_Offset(HText, selFgColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_INT, "-specialchar", "specialChar", "SpecialChar", DEF_HTEXT_SPEC_CHAR, Tk_Offset(HText, specChar), 0}, {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", DEF_HTEXT_TAKE_FOCUS, Tk_Offset(HText, takeFocus), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-tile", "tile", "Tile", (char *)NULL, Tk_Offset(HText, tile), TK_CONFIG_NULL_OK, &bltTileOption}, {TK_CONFIG_BOOLEAN, "-tileoffset", "tileOffset", "TileOffset", DEF_HTEXT_TILE_OFFSET, Tk_Offset(HText, tileOffsetPage), 0}, {TK_CONFIG_STRING, "-text", "text", "Text", DEF_HTEXT_TEXT, Tk_Offset(HText, text), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-width", "width", "Width", DEF_HTEXT_WIDTH, Tk_Offset(HText, reqWidth), TK_CONFIG_DONT_SET_DEFAULT, &widthOption}, {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand", (char *)NULL, Tk_Offset(HText, xScrollCmdPrefix), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-xscrollunits", "xScrollUnits", "ScrollUnits", DEF_HTEXT_SCROLL_UNITS, Tk_Offset(HText, xScrollUnits), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand", (char *)NULL, Tk_Offset(HText, yScrollCmdPrefix), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-yscrollunits", "yScrollUnits", "yScrollUnits", DEF_HTEXT_SCROLL_UNITS, Tk_Offset(HText, yScrollUnits), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; typedef struct { HText *htPtr; /* Pointer to parent's Htext structure */ Tk_Window tkwin; /* Widget window */ int flags; int x, y; /* Origin of embedded widget in text */ int cavityWidth, cavityHeight; /* Dimensions of the cavity * surrounding the embedded widget */ /* * Dimensions of the embedded widget. Compared against actual * embedded widget sizes when checking for resizing. */ int winWidth, winHeight; int precedingTextEnd; /* Index (in charArr) of the the last * character immediatedly preceding * the embedded widget */ int precedingTextWidth; /* Width of normal text preceding widget. */ Tk_Anchor anchor; Justify justify; /* Justification of region wrt to line */ /* * Requested dimensions of the cavity (includes padding). If non-zero, * it overrides the calculated dimension of the cavity. */ int reqCavityWidth, reqCavityHeight; /* * Relative dimensions of cavity wrt the size of the viewport. If * greater than 0.0. */ double relCavityWidth, relCavityHeight; int reqWidth, reqHeight; /* If non-zero, overrides the requested * dimension of the embedded widget */ double relWidth, relHeight; /* Relative dimensions of embedded * widget wrt the size of the viewport */ Blt_Pad padX, padY; /* Extra padding to frame around */ int ipadX, ipadY; /* internal padding for window */ int fill; /* Fill style flag */ } EmbeddedWidget; /* * Flag bits embedded widgets: */ #define WIDGET_VISIBLE (1<<2) /* Widget is currently visible in the * viewport. */ #define WIDGET_NOT_CHILD (1<<3) /* Widget is not a child of hypertext. */ /* * Defaults for embedded widgets: */ #define DEF_WIDGET_ANCHOR "center" #define DEF_WIDGET_FILL "none" #define DEF_WIDGET_HEIGHT "0" #define DEF_WIDGET_JUSTIFY "center" #define DEF_WIDGET_PAD_X "0" #define DEF_WIDGET_PAD_Y "0" #define DEF_WIDGET_REL_HEIGHT "0.0" #define DEF_WIDGET_REL_WIDTH "0.0" #define DEF_WIDGET_WIDTH "0" static Tk_ConfigSpec widgetConfigSpecs[] = { {TK_CONFIG_ANCHOR, "-anchor", (char *)NULL, (char *)NULL, DEF_WIDGET_ANCHOR, Tk_Offset(EmbeddedWidget, anchor), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-fill", (char *)NULL, (char *)NULL, DEF_WIDGET_FILL, Tk_Offset(EmbeddedWidget, fill), TK_CONFIG_DONT_SET_DEFAULT, &bltFillOption}, {TK_CONFIG_CUSTOM, "-cavityheight", (char *)NULL, (char *)NULL, DEF_WIDGET_HEIGHT, Tk_Offset(EmbeddedWidget, reqCavityHeight), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-cavitywidth", (char *)NULL, (char *)NULL, DEF_WIDGET_WIDTH, Tk_Offset(EmbeddedWidget, reqCavityWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-height", (char *)NULL, (char *)NULL, DEF_WIDGET_HEIGHT, Tk_Offset(EmbeddedWidget, reqHeight), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-justify", (char *)NULL, (char *)NULL, DEF_WIDGET_JUSTIFY, Tk_Offset(EmbeddedWidget, justify), TK_CONFIG_DONT_SET_DEFAULT, &justifyOption}, {TK_CONFIG_CUSTOM, "-padx", (char *)NULL, (char *)NULL, DEF_WIDGET_PAD_X, Tk_Offset(EmbeddedWidget, padX), TK_CONFIG_DONT_SET_DEFAULT, &bltPadOption}, {TK_CONFIG_CUSTOM, "-pady", (char *)NULL, (char *)NULL, DEF_WIDGET_PAD_Y, Tk_Offset(EmbeddedWidget, padY), TK_CONFIG_DONT_SET_DEFAULT, &bltPadOption}, {TK_CONFIG_DOUBLE, "-relcavityheight", (char *)NULL, (char *)NULL, DEF_WIDGET_REL_HEIGHT, Tk_Offset(EmbeddedWidget, relCavityHeight), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_DOUBLE, "-relcavitywidth", (char *)NULL, (char *)NULL, DEF_WIDGET_REL_WIDTH, Tk_Offset(EmbeddedWidget, relCavityWidth), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_DOUBLE, "-relheight", (char *)NULL, (char *)NULL, DEF_WIDGET_REL_HEIGHT, Tk_Offset(EmbeddedWidget, relHeight), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_DOUBLE, "-relwidth", (char *)NULL, (char *)NULL, DEF_WIDGET_REL_WIDTH, Tk_Offset(EmbeddedWidget, relWidth), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-width", (char *)NULL, (char *)NULL, DEF_WIDGET_WIDTH, Tk_Offset(EmbeddedWidget, reqWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; /* Forward Declarations */ static void DestroyText _ANSI_ARGS_((DestroyData dataPtr)); static void EmbeddedWidgetEventProc _ANSI_ARGS_((ClientData clientdata, XEvent *eventPtr)); static void DisplayText _ANSI_ARGS_((ClientData clientData)); static void TextDeleteCmdProc _ANSI_ARGS_((ClientData clientdata)); static Tcl_VarTraceProc TextVarProc; static Blt_TileChangedProc TileChangedProc; static Tk_LostSelProc TextLostSelection; static Tk_SelectionProc TextSelectionProc; static Tk_EventProc TextEventProc; static Tcl_CmdProc TextWidgetCmd; static Tcl_CmdProc TextCmd; /* end of Forward Declarations */ /* Custom options */ /* *---------------------------------------------------------------------- * * StringToJustify -- * * Converts the justification string into its numeric * representation. This configuration option affects how the * embedded widget is positioned with respect to the line on which * it sits. * * Valid style strings are: * * "top" Uppermost point of region is top of the line's * text * "center" Center point of region is line's baseline. * "bottom" Lowermost point of region is bottom of the * line's text * * Returns: * A standard Tcl result. If the value was not valid * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToJustify(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* Justification string */ char *widgRec; /* Structure record */ int offset; /* Offset of justify in record */ { Justify *justPtr = (Justify *)(widgRec + offset); unsigned int length; char c; c = string[0]; length = strlen(string); if ((c == 'c') && (strncmp(string, "center", length) == 0)) { *justPtr = JUSTIFY_CENTER; } else if ((c == 't') && (strncmp(string, "top", length) == 0)) { *justPtr = JUSTIFY_TOP; } else if ((c == 'b') && (strncmp(string, "bottom", length) == 0)) { *justPtr = JUSTIFY_BOTTOM; } else { Tcl_AppendResult(interp, "bad justification argument \"", string, "\": should be \"center\", \"top\", or \"bottom\"", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * NameOfJustify -- * * Returns the justification style string based upon the value. * * Results: * The static justification style string is returned. * *---------------------------------------------------------------------- */ static char * NameOfJustify(justify) Justify justify; { switch (justify) { case JUSTIFY_CENTER: return "center"; case JUSTIFY_TOP: return "top"; case JUSTIFY_BOTTOM: return "bottom"; default: return "unknown justification value"; } } /* *---------------------------------------------------------------------- * * JustifyToString -- * * Returns the justification style string based upon the value. * * Results: * The justification style string is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * JustifyToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Structure record */ int offset; /* Offset of justify record */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { Justify justify = *(Justify *)(widgRec + offset); return NameOfJustify(justify); } /* *---------------------------------------------------------------------- * * GetScreenDistance -- * * Converts the given string into the screen distance or number * of characters. The valid formats are * * N - pixels Nm - millimeters * Ni - inches Np - pica * Nc - centimeters N# - number of characters * * where N is a non-negative decimal number. * * Results: * A standard Tcl result. The screen distance and the number of * characters are returned. If the string can't be converted, * TCL_ERROR is returned and interp->result will contain an error * message. * *---------------------------------------------------------------------- */ static int GetScreenDistance(interp, tkwin, string, sizePtr, countPtr) Tcl_Interp *interp; Tk_Window tkwin; char *string; int *sizePtr; int *countPtr; { int nPixels, nChars; char *endPtr; /* Pointer to last character scanned */ double value; int rounded; value = strtod(string, &endPtr); if (endPtr == string) { Tcl_AppendResult(interp, "bad screen distance \"", string, "\"", (char *)NULL); return TCL_ERROR; } if (value < 0.0) { Tcl_AppendResult(interp, "screen distance \"", string, "\" must be non-negative value", (char *)NULL); return TCL_ERROR; } while (isspace(UCHAR(*endPtr))) { if (*endPtr == '\0') { break; } endPtr++; } nPixels = nChars = 0; rounded = ROUND(value); switch (*endPtr) { case '\0': /* Distance in pixels */ nPixels = rounded; break; case '#': /* Number of characters */ nChars = rounded; break; default: /* cm, mm, pica, inches */ if (Tk_GetPixels(interp, tkwin, string, &rounded) != TCL_OK) { return TCL_ERROR; } nPixels = rounded; break; } *sizePtr = nPixels; *countPtr = nChars; return TCL_OK; } /* *---------------------------------------------------------------------- * * StringToHeight -- * * Like TK_CONFIG_PIXELS, but adds an extra check for negative * values. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToHeight(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Window */ char *string; /* Pixel value string */ char *widgRec; /* Widget record */ int offset; /* Not used. */ { HText *htPtr = (HText *)widgRec; int height, nRows; if (GetScreenDistance(interp, tkwin, string, &height, &nRows) != TCL_OK) { return TCL_ERROR; } htPtr->nRows = nRows; htPtr->reqHeight = height; return TCL_OK; } /* *---------------------------------------------------------------------- * * StringToWidth -- * * Like TK_CONFIG_PIXELS, but adds an extra check for negative * values. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToWidth(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Window */ char *string; /* Pixel value string */ char *widgRec; /* Widget record */ int offset; /* Not used. */ { HText *htPtr = (HText *)widgRec; int width, nColumns; if (GetScreenDistance(interp, tkwin, string, &width, &nColumns) != TCL_OK) { return TCL_ERROR; } htPtr->nColumns = nColumns; htPtr->reqWidth = width; return TCL_OK; } /* *---------------------------------------------------------------------- * * WidthHeightToString -- * * Returns the string representing the positive pixel size. * * Results: * The pixel size string is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * WidthHeightToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Row/column structure record */ int offset; /* Offset of fill in Partition record */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { int pixels = *(int *)(widgRec + offset); char *result; char string[200]; sprintf(string, "%d", pixels); result = Blt_Strdup(string); if (result == NULL) { return "out of memory"; } *freeProcPtr = (Tcl_FreeProc *)Blt_Free; return result; } /* General routines */ /* *---------------------------------------------------------------------- * * EventuallyRedraw -- * * Queues a request to redraw the text window at the next idle * point. * * Results: * None. * * Side effects: * Information gets redisplayed. Right now we don't do selective * redisplays: the whole window will be redrawn. This doesn't * seem to hurt performance noticeably, but if it does then this * could be changed. * *---------------------------------------------------------------------- */ static void EventuallyRedraw(htPtr) HText *htPtr; /* Information about widget. */ { if ((htPtr->tkwin != NULL) && !(htPtr->flags & REDRAW_PENDING)) { htPtr->flags |= REDRAW_PENDING; Tcl_DoWhenIdle(DisplayText, htPtr); } } /* * -------------------------------------------------------------------- * * ResizeArray -- * * Reallocates memory to the new size given. New memory * is also cleared (zeros). * * Results: * Returns a pointer to the new object or NULL if an error occurred. * * Side Effects: * Memory is re/allocated. * * -------------------------------------------------------------------- */ static int ResizeArray(arrayPtr, elemSize, newSize, prevSize) char **arrayPtr; int elemSize; int newSize; int prevSize; { char *newPtr; if (newSize == prevSize) { return TCL_OK; } if (newSize == 0) { /* Free entire array */ Blt_Free(*arrayPtr); *arrayPtr = NULL; return TCL_OK; } newPtr = Blt_Calloc(elemSize, newSize); if (newPtr == NULL) { return TCL_ERROR; } if ((prevSize > 0) && (*arrayPtr != NULL)) { int size; size = MIN(prevSize, newSize) * elemSize; if (size > 0) { memcpy(newPtr, *arrayPtr, size); } Blt_Free(*arrayPtr); } *arrayPtr = newPtr; return TCL_OK; } /* * ---------------------------------------------------------------------- * * LineSearch -- * * Performs a binary search for the line of text located at some * world y-coordinate (not screen y-coordinate). The search is * inclusive of those lines from low to high. * * Results: * Returns the array index of the line found at the given * y-coordinate. If the y-coordinate is outside of the given range * of lines, -1 is returned. * * ---------------------------------------------------------------------- */ static int LineSearch(htPtr, yCoord, low, high) HText *htPtr; /* HText widget */ int yCoord; /* Search y-coordinate */ int low, high; /* Range of lines to search */ { int median; Line *linePtr; while (low <= high) { median = (low + high) >> 1; linePtr = htPtr->lineArr + median; if (yCoord < linePtr->offset) { high = median - 1; } else if (yCoord >= (linePtr->offset + linePtr->height)) { low = median + 1; } else { return median; } } return -1; } /* * ---------------------------------------------------------------------- * * IndexSearch -- * * Try to find what line contains a given text index. Performs * a binary search for the text line which contains the given index. * The search is inclusive of those lines from low and high. * * Results: * Returns the line number containing the given index. If the index * is outside the range of lines, -1 is returned. * * ---------------------------------------------------------------------- */ static int IndexSearch(htPtr, key, low, high) HText *htPtr; /* HText widget */ int key; /* Search index */ int low, high; /* Range of lines to search */ { int median; Line *linePtr; while (low <= high) { median = (low + high) >> 1; linePtr = htPtr->lineArr + median; if (key < linePtr->textStart) { high = median - 1; } else if (key > linePtr->textEnd) { low = median + 1; } else { return median; } } return -1; } /* * ---------------------------------------------------------------------- * * GetXYPosIndex -- * * Converts a string in the form "@x,y", where x and y are * window coordinates, to a text index. * * Window coordinates are first translated into world coordinates. * Any coordinate outside of the bounds of the virtual text is * silently set the nearest boundary. * * Results: * A standard Tcl result. If "string" is a valid index, then * *indexPtr is filled with the numeric index corresponding. * Otherwise an error message is left in interp->result. * * ---------------------------------------------------------------------- */ static int GetXYPosIndex(htPtr, string, indexPtr) HText *htPtr; char *string; int *indexPtr; { int x, y, curX, dummy; int textLength, textStart; int cindex, lindex; Line *linePtr; if (Blt_GetXY(htPtr->interp, htPtr->tkwin, string, &x, &y) != TCL_OK) { return TCL_ERROR; } /* Locate the line corresponding to the window y-coordinate position */ y += htPtr->yOffset; if (y < 0) { lindex = htPtr->first; } else if (y >= htPtr->worldHeight) { lindex = htPtr->last; } else { lindex = LineSearch(htPtr, y, 0, htPtr->nLines - 1); } if (lindex < 0) { Tcl_AppendResult(htPtr->interp, "can't find line at \"", string, "\"", (char *)NULL); return TCL_ERROR; } x += htPtr->xOffset; if (x < 0) { x = 0; } else if (x > htPtr->worldWidth) { x = htPtr->worldWidth; } linePtr = htPtr->lineArr + lindex; curX = 0; textStart = linePtr->textStart; textLength = linePtr->textEnd - linePtr->textStart; if (Blt_ChainGetLength(linePtr->chainPtr) > 0) { Blt_ChainLink *linkPtr; int deltaX; EmbeddedWidget *winPtr; for (linkPtr = Blt_ChainFirstLink(linePtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { winPtr = Blt_ChainGetValue(linkPtr); deltaX = winPtr->precedingTextWidth + winPtr->cavityWidth; if ((curX + deltaX) > x) { textLength = (winPtr->precedingTextEnd - textStart); break; } curX += deltaX; /* * Skip over the trailing space. It designates the position of * a embedded widget in the text */ textStart = winPtr->precedingTextEnd + 1; } } cindex = Tk_MeasureChars(htPtr->font, htPtr->charArr + textStart, textLength, 10000, DEF_TEXT_FLAGS, &dummy); *indexPtr = textStart + cindex; return TCL_OK; } /* *-------------------------------------------------------------- * * ParseIndex -- * * Parse a string representing a text index into numeric * value. A text index can be in one of the following forms. * * "anchor" - anchor position of the selection. * "sel.first" - index of the first character in the selection. * "sel.last" - index of the last character in the selection. * "page.top" - index of the first character on the page. * "page.bottom" - index of the last character on the page. * "@x,y" - x and y are window coordinates. * "number - raw index of text * "line.char" - line number and character position * * Results: * A standard Tcl result. If "string" is a valid index, then * *indexPtr is filled with the corresponding numeric index. * Otherwise an error message is left in interp->result. * * Side effects: * None. * *-------------------------------------------------------------- */ static int ParseIndex(htPtr, string, indexPtr) HText *htPtr; /* Text for which the index is being * specified. */ char *string; /* Numerical index into htPtr's element * list, or "end" to refer to last element. */ int *indexPtr; /* Where to store converted relief. */ { unsigned int length; char c; Tcl_Interp *interp = htPtr->interp; length = strlen(string); c = string[0]; if ((c == 'a') && (strncmp(string, "anchor", length) == 0)) { *indexPtr = htPtr->selAnchor; } else if ((c == 's') && (length > 4)) { if (strncmp(string, "sel.first", length) == 0) { *indexPtr = htPtr->selFirst; } else if (strncmp(string, "sel.last", length) == 0) { *indexPtr = htPtr->selLast; } else { goto badIndex; /* Not a valid index */ } if (*indexPtr < 0) { Tcl_AppendResult(interp, "bad index \"", string, "\": nothing selected in \"", Tk_PathName(htPtr->tkwin), "\"", (char *)NULL); return TCL_ERROR; } } else if ((c == 'p') && (length > 5) && (strncmp(string, "page.top", length) == 0)) { int first; first = htPtr->first; if (first < 0) { first = 0; } *indexPtr = htPtr->lineArr[first].textStart; } else if ((c == 'p') && (length > 5) && (strncmp(string, "page.bottom", length) == 0)) { *indexPtr = htPtr->lineArr[htPtr->last].textEnd; } else if (c == '@') { /* Screen position */ if (GetXYPosIndex(htPtr, string, indexPtr) != TCL_OK) { return TCL_ERROR; } } else { char *period; period = strchr(string, '.'); if (period == NULL) { /* Raw index */ int tindex; if ((string[0] == 'e') && (strcmp(string, "end") == 0)) { tindex = htPtr->nChars - 1; } else if (Tcl_GetInt(interp, string, &tindex) != TCL_OK) { goto badIndex; } if (tindex < 0) { tindex = 0; } else if (tindex > (htPtr->nChars - 1)) { tindex = htPtr->nChars - 1; } *indexPtr = tindex; } else { int lindex, cindex, offset; Line *linePtr; int result; *period = '\0'; result = TCL_OK; if ((string[0] == 'e') && (strcmp(string, "end") == 0)) { lindex = htPtr->nLines - 1; } else { result = Tcl_GetInt(interp, string, &lindex); } *period = '.'; /* Repair index string before returning */ if (result != TCL_OK) { goto badIndex; /* Bad line number */ } if (lindex < 0) { lindex = 0; /* Silently repair bad line numbers */ } if (htPtr->nChars == 0) { *indexPtr = 0; return TCL_OK; } if (lindex >= htPtr->nLines) { lindex = htPtr->nLines - 1; } linePtr = htPtr->lineArr + lindex; cindex = 0; if ((*(period + 1) != '\0')) { string = period + 1; if ((string[0] == 'e') && (strcmp(string, "end") == 0)) { cindex = linePtr->textEnd - linePtr->textStart; } else if (Tcl_GetInt(interp, string, &cindex) != TCL_OK) { goto badIndex; } } if (cindex < 0) { cindex = 0; /* Silently fix bogus indices */ } offset = 0; if (htPtr->nChars > 0) { offset = linePtr->textStart + cindex; if (offset > linePtr->textEnd) { offset = linePtr->textEnd; } } *indexPtr = offset; } } if (htPtr->nChars == 0) { *indexPtr = 0; } return TCL_OK; badIndex: /* * Some of the paths here leave messages in interp->result, so we * have to clear it out before storing our own message. */ Tcl_ResetResult(interp); Tcl_AppendResult(interp, "bad index \"", string, "\": \ should be one of the following: anchor, sel.first, sel.last, page.bottom, \ page.top, @x,y, index, line.char", (char *)NULL); return TCL_ERROR; } /* *-------------------------------------------------------------- * * GetIndex -- * * Get the index from a string representing a text index. * * * Results: * A standard Tcl result. If "string" is a valid index, then * *indexPtr is filled with the numeric index corresponding. * Otherwise an error message is left in interp->result. * * Side effects: * None. * *-------------------------------------------------------------- */ static int GetIndex(htPtr, string, indexPtr) HText *htPtr; /* Text for which the index is being * specified. */ char *string; /* Numerical index into htPtr's element * list, or "end" to refer to last element. */ int *indexPtr; /* Where to store converted relief. */ { int tindex; if (ParseIndex(htPtr, string, &tindex) != TCL_OK) { return TCL_ERROR; } *indexPtr = tindex; return TCL_OK; } /* * ---------------------------------------------------------------------- * * GetTextPosition -- * * Performs a binary search for the index located on line in * the text. The search is limited to those lines between * low and high inclusive. * * Results: * Returns the line number at the given Y coordinate. If position * does not correspond to any of the lines in the given the set, * -1 is returned. * * ---------------------------------------------------------------------- */ static int GetTextPosition(htPtr, tindex, lindexPtr, cindexPtr) HText *htPtr; int tindex; int *lindexPtr; int *cindexPtr; { int lindex, cindex; lindex = cindex = 0; if (htPtr->nChars > 0) { Line *linePtr; lindex = IndexSearch(htPtr, tindex, 0, htPtr->nLines - 1); if (lindex < 0) { char string[200]; sprintf(string, "can't determine line number from index \"%d\"", tindex); Tcl_AppendResult(htPtr->interp, string, (char *)NULL); return TCL_ERROR; } linePtr = htPtr->lineArr + lindex; if (tindex > linePtr->textEnd) { tindex = linePtr->textEnd; } cindex = tindex - linePtr->textStart; } *lindexPtr = lindex; *cindexPtr = cindex; return TCL_OK; } /* EmbeddedWidget Procedures */ /* *---------------------------------------------------------------------- * * GetEmbeddedWidgetWidth -- * * Returns the width requested by the embedded widget. The requested * space also includes any internal padding which has been designated * for this window. * * Results: * Returns the requested width of the embedded widget. * *---------------------------------------------------------------------- */ static int GetEmbeddedWidgetWidth(winPtr) EmbeddedWidget *winPtr; { int width; if (winPtr->reqWidth > 0) { width = winPtr->reqWidth; } else if (winPtr->relWidth > 0.0) { width = (int) ((double)Tk_Width(winPtr->htPtr->tkwin) * winPtr->relWidth + 0.5); } else { width = Tk_ReqWidth(winPtr->tkwin); } width += (2 * winPtr->ipadX); return width; } /* *---------------------------------------------------------------------- * * GetEmbeddedWidgetHeight -- * * Returns the height requested by the embedded widget. The requested * space also includes any internal padding which has been designated * for this window. * * Results: * Returns the requested height of the embedded widget. * *---------------------------------------------------------------------- */ static int GetEmbeddedWidgetHeight(winPtr) EmbeddedWidget *winPtr; { int height; if (winPtr->reqHeight > 0) { height = winPtr->reqHeight; } else if (winPtr->relHeight > 0.0) { height = (int)((double)Tk_Height(winPtr->htPtr->tkwin) * winPtr->relHeight + 0.5); } else { height = Tk_ReqHeight(winPtr->tkwin); } height += (2 * winPtr->ipadY); return height; } /* * -------------------------------------------------------------- * * EmbeddedWidgetEventProc -- * * This procedure is invoked by the Tk dispatcher for various * events on hypertext widgets. * * Results: * None. * * Side effects: * When the window gets deleted, internal structures get * cleaned up. When it gets exposed, it is redisplayed. * * -------------------------------------------------------------- */ static void EmbeddedWidgetEventProc(clientData, eventPtr) ClientData clientData; /* Information about the embedded widget. */ XEvent *eventPtr; /* Information about event. */ { EmbeddedWidget *winPtr = clientData; HText *htPtr; if ((winPtr == NULL) || (winPtr->tkwin == NULL)) { return; } htPtr = winPtr->htPtr; if (eventPtr->type == DestroyNotify) { Blt_HashEntry *hPtr; /* * Mark the widget as deleted by dereferencing the Tk window * pointer. Zero out the height and width to collapse the area * used by the widget. Redraw the window only if the widget is * currently visible. */ winPtr->htPtr->flags |= REQUEST_LAYOUT; if (Tk_IsMapped(winPtr->tkwin) && (winPtr->flags & WIDGET_VISIBLE)) { EventuallyRedraw(htPtr); } Tk_DeleteEventHandler(winPtr->tkwin, StructureNotifyMask, EmbeddedWidgetEventProc, winPtr); hPtr = Blt_FindHashEntry(&(htPtr->widgetTable), (char *)winPtr->tkwin); Blt_DeleteHashEntry(&(htPtr->widgetTable), hPtr); winPtr->cavityWidth = winPtr->cavityHeight = 0; winPtr->tkwin = NULL; } else if (eventPtr->type == ConfigureNotify) { /* * EmbeddedWidgets can't request new positions. Worry only about resizing. */ if (winPtr->winWidth != Tk_Width(winPtr->tkwin) || winPtr->winHeight != Tk_Height(winPtr->tkwin)) { EventuallyRedraw(htPtr); htPtr->flags |= REQUEST_LAYOUT; } } } /* *-------------------------------------------------------------- * * EmbeddedWidgetCustodyProc -- * * This procedure is invoked when a embedded widget has been * stolen by another geometry manager. The information and * memory associated with the embedded widget is released. * * Results: * None. * * Side effects: * Arranges for the widget formerly associated with the widget * to have its layout re-computed and arranged at the * next idle point. * *-------------------------------------------------------------- */ /* ARGSUSED */ static void EmbeddedWidgetCustodyProc(clientData, tkwin) ClientData clientData; /* Information about the former embedded widget. */ Tk_Window tkwin; /* Not used. */ { Blt_HashEntry *hPtr; EmbeddedWidget *winPtr = clientData; /* * Mark the widget as deleted by dereferencing the Tk window * pointer. Zero out the height and width to collapse the area * used by the widget. Redraw the window only if the widget is * currently visible. */ winPtr->htPtr->flags |= REQUEST_LAYOUT; if (Tk_IsMapped(winPtr->tkwin) && (winPtr->flags & WIDGET_VISIBLE)) { EventuallyRedraw(winPtr->htPtr); } Tk_DeleteEventHandler(winPtr->tkwin, StructureNotifyMask, EmbeddedWidgetEventProc, winPtr); hPtr = Blt_FindHashEntry(&(winPtr->htPtr->widgetTable), (char *)winPtr->tkwin); Blt_DeleteHashEntry(&(winPtr->htPtr->widgetTable), hPtr); winPtr->cavityWidth = winPtr->cavityHeight = 0; winPtr->tkwin = NULL; } /* *-------------------------------------------------------------- * * EmbeddedWidgetGeometryProc -- * * This procedure is invoked by Tk_GeometryRequest for * embedded widgets managed by the hypertext widget. * * Results: * None. * * Side effects: * Arranges for tkwin, and all its managed siblings, to * be repacked and drawn at the next idle point. * *-------------------------------------------------------------- */ /* ARGSUSED */ static void EmbeddedWidgetGeometryProc(clientData, tkwin) ClientData clientData; /* Information about window that got new * preferred geometry. */ Tk_Window tkwin; /* Other Tk-related information about the * window. */ { EmbeddedWidget *winPtr = clientData; winPtr->htPtr->flags |= REQUEST_LAYOUT; EventuallyRedraw(winPtr->htPtr); } /* * ---------------------------------------------------------------------- * * FindEmbeddedWidget -- * * Searches for a widget matching the path name given * If found, the pointer to the widget structure is returned, * otherwise NULL. * * Results: * The pointer to the widget structure. If not found, NULL. * * ---------------------------------------------------------------------- */ static EmbeddedWidget * FindEmbeddedWidget(htPtr, tkwin) HText *htPtr; /* Hypertext widget structure */ Tk_Window tkwin; /* Path name of embedded widget */ { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&(htPtr->widgetTable), (char *)tkwin); if (hPtr != NULL) { return (EmbeddedWidget *) Blt_GetHashValue(hPtr); } return NULL; } /* * ---------------------------------------------------------------------- * * CreateEmbeddedWidget -- * * This procedure creates and initializes a new embedded widget * in the hyper text widget. * * Results: * The return value is a pointer to a structure describing the * new embedded widget. If an error occurred, then the return * value is NULL and an error message is left in interp->result. * * Side effects: * Memory is allocated. EmbeddedWidget window is mapped. * Callbacks are set up for embedded widget resizes and geometry * requests. * * ---------------------------------------------------------------------- */ static EmbeddedWidget * CreateEmbeddedWidget(htPtr, name) HText *htPtr; /* Hypertext widget */ char *name; /* Name of embedded widget */ { EmbeddedWidget *winPtr; Tk_Window tkwin; Blt_HashEntry *hPtr; int isNew; tkwin = Tk_NameToWindow(htPtr->interp, name, htPtr->tkwin); if (tkwin == NULL) { return NULL; } if (Tk_Parent(tkwin) != htPtr->tkwin) { Tcl_AppendResult(htPtr->interp, "parent window of \"", name, "\" must be \"", Tk_PathName(htPtr->tkwin), "\"", (char *)NULL); return NULL; } hPtr = Blt_CreateHashEntry(&(htPtr->widgetTable), (char *)tkwin, &isNew); /* Check is the widget is already embedded into this widget */ if (!isNew) { Tcl_AppendResult(htPtr->interp, "\"", name, "\" is already appended to ", Tk_PathName(htPtr->tkwin), (char *)NULL); return NULL; } winPtr = Blt_Calloc(1, sizeof(EmbeddedWidget)); assert(winPtr); winPtr->flags = 0; winPtr->tkwin = tkwin; winPtr->htPtr = htPtr; winPtr->x = winPtr->y = 0; winPtr->fill = FILL_NONE; winPtr->justify = JUSTIFY_CENTER; winPtr->anchor = TK_ANCHOR_CENTER; Blt_SetHashValue(hPtr, winPtr); Tk_ManageGeometry(tkwin, &htextMgrInfo, winPtr); Tk_CreateEventHandler(tkwin, StructureNotifyMask, EmbeddedWidgetEventProc, winPtr); return winPtr; } /* * ---------------------------------------------------------------------- * * DestroyEmbeddedWidget -- * * This procedure is invoked by DestroyLine to clean up the * internal structure of a widget. * * Results: * None. * * Side effects: * Everything associated with the widget is freed up. * * ---------------------------------------------------------------------- */ static void DestroyEmbeddedWidget(winPtr) EmbeddedWidget *winPtr; { /* Destroy the embedded widget if it still exists */ if (winPtr->tkwin != NULL) { Blt_HashEntry *hPtr; Tk_DeleteEventHandler(winPtr->tkwin, StructureNotifyMask, EmbeddedWidgetEventProc, winPtr); hPtr = Blt_FindHashEntry(&(winPtr->htPtr->widgetTable), (char *)winPtr->tkwin); Blt_DeleteHashEntry(&(winPtr->htPtr->widgetTable), hPtr); Tk_DestroyWindow(winPtr->tkwin); } Blt_Free(winPtr); } /* Line Procedures */ /* * ---------------------------------------------------------------------- * * CreateLine -- * * This procedure creates and initializes a new line of text. * * Results: * The return value is a pointer to a structure describing the new * line of text. If an error occurred, then the return value is NULL * and an error message is left in interp->result. * * Side effects: * Memory is allocated. * * ---------------------------------------------------------------------- */ static Line * CreateLine(htPtr) HText *htPtr; { Line *linePtr; if (htPtr->nLines >= htPtr->arraySize) { if (htPtr->arraySize == 0) { htPtr->arraySize = DEF_LINES_ALLOC; } else { htPtr->arraySize += htPtr->arraySize; } if (ResizeArray((char **)&(htPtr->lineArr), sizeof(Line), htPtr->arraySize, htPtr->nLines) != TCL_OK) { return NULL; } } /* Initialize values in the new entry */ linePtr = htPtr->lineArr + htPtr->nLines; linePtr->offset = 0; linePtr->height = linePtr->width = 0; linePtr->textStart = 0; linePtr->textEnd = -1; linePtr->baseline = 0; linePtr->chainPtr = Blt_ChainCreate(); htPtr->nLines++; return linePtr; } /* * ---------------------------------------------------------------------- * * DestroyLine -- * * This procedure is invoked to clean up the internal structure * of a line. * * Results: * None. * * Side effects: * Everything associated with the line (text and widgets) is * freed up. * * ---------------------------------------------------------------------- */ static void DestroyLine(linePtr) Line *linePtr; { Blt_ChainLink *linkPtr; EmbeddedWidget *winPtr; /* Free the list of embedded widget structures */ for (linkPtr = Blt_ChainFirstLink(linePtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { winPtr = Blt_ChainGetValue(linkPtr); DestroyEmbeddedWidget(winPtr); } Blt_ChainDestroy(linePtr->chainPtr); } static void FreeText(htPtr) HText *htPtr; { int i; for (i = 0; i < htPtr->nLines; i++) { DestroyLine(htPtr->lineArr + i); } htPtr->nLines = 0; htPtr->nChars = 0; if (htPtr->charArr != NULL) { Blt_Free(htPtr->charArr); htPtr->charArr = NULL; } } /* Text Procedures */ /* * ---------------------------------------------------------------------- * * DestroyText -- * * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release * to clean up the internal structure of a HText at a safe time * (when no-one is using it anymore). * * Results: * None. * * Side effects: * Everything associated with the widget is freed up. * * ---------------------------------------------------------------------- */ static void DestroyText(dataPtr) DestroyData dataPtr; /* Info about hypertext widget. */ { HText *htPtr = (HText *)dataPtr; Tk_FreeOptions(configSpecs, (char *)htPtr, htPtr->display, 0); if (htPtr->drawGC != NULL) { Tk_FreeGC(htPtr->display, htPtr->drawGC); } if (htPtr->fillGC != NULL) { Tk_FreeGC(htPtr->display, htPtr->fillGC); } if (htPtr->tile != NULL) { Blt_FreeTile(htPtr->tile); } if (htPtr->selectGC != NULL) { Tk_FreeGC(htPtr->display, htPtr->selectGC); } FreeText(htPtr); if (htPtr->lineArr != NULL) { Blt_Free(htPtr->lineArr); } Blt_DeleteHashTable(&(htPtr->widgetTable)); Blt_Free(htPtr); } /* * -------------------------------------------------------------- * * TextEventProc -- * * This procedure is invoked by the Tk dispatcher for various * events on hypertext widgets. * * Results: * None. * * Side effects: * When the window gets deleted, internal structures get * cleaned up. When it gets exposed, it is redisplayed. * * -------------------------------------------------------------- */ static void TextEventProc(clientData, eventPtr) ClientData clientData; /* Information about window. */ XEvent *eventPtr; /* Information about event. */ { HText *htPtr = clientData; if (eventPtr->type == ConfigureNotify) { if ((htPtr->lastWidth != Tk_Width(htPtr->tkwin)) || (htPtr->lastHeight != Tk_Height(htPtr->tkwin))) { htPtr->flags |= (REQUEST_LAYOUT | TEXT_DIRTY); EventuallyRedraw(htPtr); } } else if (eventPtr->type == Expose) { /* * If the Expose event was synthetic (i.e. we manufactured it * ourselves during a redraw operation), toggle the bit flag * which controls redraws. */ if (eventPtr->xexpose.send_event) { htPtr->flags ^= IGNORE_EXPOSURES; return; } if ((eventPtr->xexpose.count == 0) && !(htPtr->flags & IGNORE_EXPOSURES)) { htPtr->flags |= TEXT_DIRTY; EventuallyRedraw(htPtr); } } else if (eventPtr->type == DestroyNotify) { if (htPtr->tkwin != NULL) { htPtr->tkwin = NULL; Tcl_DeleteCommandFromToken(htPtr->interp, htPtr->cmdToken); } if (htPtr->flags & REDRAW_PENDING) { Tcl_CancelIdleCall(DisplayText, htPtr); } Tcl_EventuallyFree(htPtr, DestroyText); } } /* *---------------------------------------------------------------------- * * TextDeleteCmdProc -- * * This procedure is invoked when a widget command is deleted. If * the widget isn't already in the process of being destroyed, * this command destroys it. * * Results: * None. * * Side effects: * The widget is destroyed. * *---------------------------------------------------------------------- */ static void TextDeleteCmdProc(clientData) ClientData clientData; /* Pointer to widget record for widget. */ { HText *htPtr = clientData; /* * This procedure could be invoked either because the window was * destroyed and the command was then deleted (in which case tkwin * is NULL) or because the command was deleted, and then this procedure * destroys the widget. */ if (htPtr->tkwin != NULL) { Tk_Window tkwin; tkwin = htPtr->tkwin; htPtr->tkwin = NULL; Tk_DestroyWindow(tkwin); #ifdef ITCL_NAMESPACES Itk_SetWidgetCommand(tkwin, (Tcl_Command) NULL); #endif /* ITCL_NAMESPACES */ } } /* *---------------------------------------------------------------------- * * TileChangedProc * * Stub for image change notifications. Since we immediately draw * the image into a pixmap, we don't care about image changes. * * It would be better if Tk checked for NULL proc pointers. * * Results: * None. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static void TileChangedProc(clientData, tile) ClientData clientData; Blt_Tile tile; /* Not used. */ { HText *htPtr = clientData; if (htPtr->tkwin != NULL) { EventuallyRedraw(htPtr); } } /* Configuration Procedures */ static void ResetTextInfo(htPtr) HText *htPtr; { htPtr->first = 0; htPtr->last = htPtr->nLines - 1; htPtr->selFirst = htPtr->selLast = -1; htPtr->selAnchor = 0; htPtr->pendingX = htPtr->pendingY = 0; htPtr->worldWidth = htPtr->worldHeight = 0; htPtr->xOffset = htPtr->yOffset = 0; } static Line * GetLastLine(htPtr) HText *htPtr; { if (htPtr->nLines == 0) { return CreateLine(htPtr); } return (htPtr->lineArr + (htPtr->nLines - 1)); } /* * ---------------------------------------------------------------------- * * ReadNamedFile -- * * Read the named file into a newly allocated buffer. * * Results: * Returns the size of the allocated buffer if the file was * read correctly. Otherwise -1 is returned and "interp->result" * will contain an error message. * * Side Effects: * If successful, the contents of "bufferPtr" will point * to the allocated buffer. * * ---------------------------------------------------------------------- */ static int ReadNamedFile(interp, fileName, bufferPtr) Tcl_Interp *interp; char *fileName; char **bufferPtr; { FILE *f; int nRead, fileSize; int count, bytesLeft; char *buffer; #if defined(_MSC_VER) || defined(__BORLANDC__) #define fstat _fstat #define stat _stat #ifdef _MSC_VER #define fileno _fileno #endif #endif /* _MSC_VER || __BORLANDC__ */ struct stat fileInfo; f = fopen(fileName, "r"); if (f == NULL) { Tcl_AppendResult(interp, "can't open \"", fileName, "\" for reading: ", Tcl_PosixError(interp), (char *)NULL); return -1; } if (fstat(fileno(f), &fileInfo) < 0) { Tcl_AppendResult(interp, "can't stat \"", fileName, "\": ", Tcl_PosixError(interp), (char *)NULL); fclose(f); return -1; } fileSize = fileInfo.st_size + 1; buffer = Blt_Malloc(sizeof(char) * fileSize); if (buffer == NULL) { fclose(f); return -1; /* Can't allocate memory for file buffer */ } count = 0; for (bytesLeft = fileInfo.st_size; bytesLeft > 0; bytesLeft -= nRead) { nRead = fread(buffer + count, sizeof(char), bytesLeft, f); if (nRead < 0) { Tcl_AppendResult(interp, "error reading \"", fileName, "\": ", Tcl_PosixError(interp), (char *)NULL); fclose(f); Blt_Free(buffer); return -1; } else if (nRead == 0) { break; } count += nRead; } fclose(f); buffer[count] = '\0'; *bufferPtr = buffer; return count; } /* * ---------------------------------------------------------------------- * * CollectCommand -- * * Collect the characters representing a Tcl command into a * given buffer. * * Results: * Returns the number of bytes examined. If an error occurred, * -1 is returned and "interp->result" will contain an error * message. * * Side Effects: * If successful, the "cmdArr" will be filled with the string * representing the Tcl command. * * ---------------------------------------------------------------------- */ static int CollectCommand(htPtr, inputArr, maxBytes, cmdArr) HText *htPtr; /* Widget record */ char inputArr[]; /* Array of bytes representing the htext input */ int maxBytes; /* Maximum number of bytes left in input */ char cmdArr[]; /* Output buffer to be filled with the Tcl * command */ { int c; int i; int state, count; /* Simply collect the all the characters until %% into a buffer */ state = count = 0; for (i = 0; i < maxBytes; i++) { c = inputArr[i]; if (c == htPtr->specChar) { state++; } else if ((state == 0) && (c == '\\')) { state = 3; } else { state = 0; } switch (state) { case 2: /* End of command block found */ cmdArr[count - 1] = '\0'; return i; case 4: /* Escaped block designator */ cmdArr[count] = c; state = 0; break; default: /* Add to command buffer */ cmdArr[count++] = c; break; } } Tcl_AppendResult(htPtr->interp, "premature end of TCL command block", (char *)NULL); return -1; } /* * ---------------------------------------------------------------------- * * ParseInput -- * * Parse the input to the HText structure into an array of lines. * Each entry contains the beginning index and end index of the * characters in the text array which comprise the line. * * |*|*|*|\n|T|h|i|s| |a| |l|i|n|e| |o|f| |t|e|x|t|.|\n|*|*|*| * ^ ^ * textStart textEnd * * Note that the end index contains the '\n'. * * Results: * Returns TCL_OK or error depending if the file was read correctly. * * ---------------------------------------------------------------------- */ static int ParseInput(interp, htPtr, input, nBytes) Tcl_Interp *interp; HText *htPtr; char input[]; int nBytes; { int c; int i; char *textArr; char *cmdArr; int count, nLines; int length; int state; Line *linePtr; linePtr = CreateLine(htPtr); if (linePtr == NULL) { return TCL_ERROR; /* Error allocating the line structure */ } /* Right now, we replace the text array instead of appending to it */ linePtr->textStart = 0; /* In the worst case, assume the entire input could be Tcl commands */ cmdArr = Blt_Malloc(sizeof(char) * (nBytes + 1)); textArr = Blt_Malloc(sizeof(char) * (nBytes + 1)); if (htPtr->charArr != NULL) { Blt_Free(htPtr->charArr); } htPtr->charArr = textArr; htPtr->nChars = 0; nLines = count = state = 0; htPtr->flags &= ~WIDGET_APPENDED; for (i = 0; i < nBytes; i++) { c = input[i]; if (c == htPtr->specChar) { state++; } else if (c == '\n') { state = -1; } else if ((state == 0) && (c == '\\')) { state = 3; } else { state = 0; } switch (state) { case 2: /* Block of Tcl commands found */ count--, i++; length = CollectCommand(htPtr, input + i, nBytes - i, cmdArr); if (length < 0) { goto error; } i += length; linePtr->textEnd = count; htPtr->nChars = count + 1; if (Tcl_Eval(interp, cmdArr) != TCL_OK) { goto error; } if (htPtr->flags & WIDGET_APPENDED) { /* Indicates the location a embedded widget in the text array */ textArr[count++] = ' '; htPtr->flags &= ~WIDGET_APPENDED; } state = 0; break; case 4: /* Escaped block designator */ textArr[count - 1] = c; state = 0; break; case -1: /* End of line or input */ linePtr->textEnd = count; textArr[count++] = '\n'; nLines++; linePtr = CreateLine(htPtr); if (linePtr == NULL) { goto error; } linePtr->textStart = count; state = 0; break; default: /* Default action, add to text buffer */ textArr[count++] = c; break; } } if (count > linePtr->textStart) { linePtr->textEnd = count; textArr[count++] = '\n';/* Every line must end with a '\n' */ nLines++; } Blt_Free(cmdArr); /* Reset number of lines allocated */ if (ResizeArray((char **)&(htPtr->lineArr), sizeof(Line), nLines, htPtr->arraySize) != TCL_OK) { Tcl_AppendResult(interp, "can't reallocate array of lines", (char *)NULL); return TCL_ERROR; } htPtr->nLines = htPtr->arraySize = nLines; /* and the size of the character array */ if (ResizeArray(&(htPtr->charArr), sizeof(char), count, nBytes) != TCL_OK) { Tcl_AppendResult(interp, "can't reallocate text character buffer", (char *)NULL); return TCL_ERROR; } htPtr->nChars = count; return TCL_OK; error: Blt_Free(cmdArr); return TCL_ERROR; } static int IncludeText(interp, htPtr, fileName) Tcl_Interp *interp; HText *htPtr; char *fileName; { char *buffer; int result; int nBytes; if ((htPtr->text == NULL) && (fileName == NULL)) { return TCL_OK; /* Empty text string */ } if (fileName != NULL) { nBytes = ReadNamedFile(interp, fileName, &buffer); if (nBytes < 0) { return TCL_ERROR; } } else { buffer = htPtr->text; nBytes = strlen(htPtr->text); } result = ParseInput(interp, htPtr, buffer, nBytes); if (fileName != NULL) { Blt_Free(buffer); } return result; } /* ARGSUSED */ static char * TextVarProc(clientData, interp, name1, name2, flags) ClientData clientData; /* Information about widget. */ Tcl_Interp *interp; /* Interpreter containing variable. */ char *name1; /* Name of variable. */ char *name2; /* Second part of variable name. */ int flags; /* Information about what happened. */ { HText *htPtr = clientData; HText *lasthtPtr; /* Check to see of this is the most recent trace */ lasthtPtr = (HText *)Tcl_VarTraceInfo2(interp, name1, name2, flags, TextVarProc, NULL); if (lasthtPtr != htPtr) { return NULL; /* Ignore all but most current trace */ } if (flags & TCL_TRACE_READS) { char c; c = name2[0]; if ((c == 'w') && (strcmp(name2, "widget") == 0)) { Tcl_SetVar2(interp, name1, name2, Tk_PathName(htPtr->tkwin), flags); } else if ((c == 'l') && (strcmp(name2, "line") == 0)) { char buf[80]; int lineNum; lineNum = htPtr->nLines - 1; if (lineNum < 0) { lineNum = 0; } sprintf(buf, "%d", lineNum); Tcl_SetVar2(interp, name1, name2, buf, flags); } else if ((c == 'i') && (strcmp(name2, "index") == 0)) { char buf[80]; sprintf(buf, "%d", htPtr->nChars - 1); Tcl_SetVar2(interp, name1, name2, buf, flags); } else if ((c == 'f') && (strcmp(name2, "file") == 0)) { char *fileName; fileName = htPtr->fileName; if (fileName == NULL) { fileName = ""; } Tcl_SetVar2(interp, name1, name2, fileName, flags); } else { return "?unknown?"; } } return NULL; } static char *varNames[] = { "widget", "line", "file", "index", (char *)NULL }; static void CreateTraces(htPtr) HText *htPtr; { char **ptr; static char globalCmd[] = "global htext"; /* * Make the traced variables global to the widget */ Tcl_Eval(htPtr->interp, globalCmd); for (ptr = varNames; *ptr != NULL; ptr++) { Tcl_TraceVar2(htPtr->interp, "htext", *ptr, (TCL_GLOBAL_ONLY | TCL_TRACE_READS), TextVarProc, htPtr); } } static void DeleteTraces(htPtr) HText *htPtr; { char **ptr; for (ptr = varNames; *ptr != NULL; ptr++) { Tcl_UntraceVar2(htPtr->interp, "htext", *ptr, (TCL_GLOBAL_ONLY | TCL_TRACE_READS), TextVarProc, htPtr); } } /* * ---------------------------------------------------------------------- * * ConfigureText -- * * This procedure is called to process an argv/argc list, plus * the Tk option database, in order to configure (or reconfigure) * a hypertext widget. * * The layout of the text must be calculated (by ComputeLayout) * whenever particular options change; -font, -file, -linespacing * and -text options. If the user has changes one of these options, * it must be detected so that the layout can be recomputed. Since the * coordinates of the layout are virtual, there is no need to adjust * them if physical window attributes (window size, etc.) * change. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then interp->result contains an error message. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for htPtr; old resources get freed, if there were any. * The hypertext is redisplayed. * * ---------------------------------------------------------------------- */ static int ConfigureText(interp, htPtr) Tcl_Interp *interp; /* Used for error reporting. */ HText *htPtr; /* Information about widget; may or may not * already have values for some fields. */ { XGCValues gcValues; unsigned long gcMask; GC newGC; if (Blt_ConfigModified(configSpecs, "-font", "-linespacing", "-file", "-text", "-width", "-height", (char *)NULL)) { /* * These options change the layout of the text. Width/height * and rows/columns may change a relatively sized window or cavity. */ htPtr->flags |= (REQUEST_LAYOUT | TEXT_DIRTY); /* Mark for update */ } gcMask = GCForeground | GCFont; gcValues.font = Tk_FontId(htPtr->font); gcValues.foreground = htPtr->normalFg->pixel; newGC = Tk_GetGC(htPtr->tkwin, gcMask, &gcValues); if (htPtr->drawGC != NULL) { Tk_FreeGC(htPtr->display, htPtr->drawGC); } htPtr->drawGC = newGC; gcValues.foreground = htPtr->selFgColor->pixel; newGC = Tk_GetGC(htPtr->tkwin, gcMask, &gcValues); if (htPtr->selectGC != NULL) { Tk_FreeGC(htPtr->display, htPtr->selectGC); } htPtr->selectGC = newGC; if (htPtr->xScrollUnits < 1) { htPtr->xScrollUnits = 1; } if (htPtr->yScrollUnits < 1) { htPtr->yScrollUnits = 1; } if (htPtr->tile != NULL) { Blt_SetTileChangedProc(htPtr->tile, TileChangedProc, htPtr); } gcValues.foreground = htPtr->normalBg->pixel; newGC = Tk_GetGC(htPtr->tkwin, gcMask, &gcValues); if (htPtr->fillGC != NULL) { Tk_FreeGC(htPtr->display, htPtr->fillGC); } htPtr->fillGC = newGC; if (htPtr->nColumns > 0) { htPtr->reqWidth = htPtr->nColumns * Tk_TextWidth(htPtr->font, "0", 1); } if (htPtr->nRows > 0) { Tk_FontMetrics fontMetrics; Tk_GetFontMetrics(htPtr->font, &fontMetrics); htPtr->reqHeight = htPtr->nRows * fontMetrics.linespace; } /* * If the either the -text or -file option changed, read in the * new text. The -text option supersedes any -file option. */ if (Blt_ConfigModified(configSpecs, "-file", "-text", (char *)NULL)) { int result; FreeText(htPtr); CreateTraces(htPtr); /* Create variable traces */ result = IncludeText(interp, htPtr, htPtr->fileName); DeleteTraces(htPtr); if (result == TCL_ERROR) { FreeText(htPtr); return TCL_ERROR; } ResetTextInfo(htPtr); } EventuallyRedraw(htPtr); return TCL_OK; } /* Layout Procedures */ /* * ----------------------------------------------------------------- * * TranslateAnchor -- * * Translate the coordinates of a given bounding box based * upon the anchor specified. The anchor indicates where * the given xy position is in relation to the bounding box. * * nw --- n --- ne * | | x,y ---+ * w center e | | * | | +-----+ * sw --- s --- se * * Results: * The translated coordinates of the bounding box are returned. * * ----------------------------------------------------------------- */ static XPoint TranslateAnchor(deltaX, deltaY, anchor) int deltaX, deltaY; /* Difference between outer and inner regions */ Tk_Anchor anchor; /* Direction of the anchor */ { XPoint point; point.x = point.y = 0; switch (anchor) { case TK_ANCHOR_NW: /* Upper left corner */ break; case TK_ANCHOR_W: /* Left center */ point.y = (deltaY / 2); break; case TK_ANCHOR_SW: /* Lower left corner */ point.y = deltaY; break; case TK_ANCHOR_N: /* Top center */ point.x = (deltaX / 2); break; case TK_ANCHOR_CENTER: /* Centered */ point.x = (deltaX / 2); point.y = (deltaY / 2); break; case TK_ANCHOR_S: /* Bottom center */ point.x = (deltaX / 2); point.y = deltaY; break; case TK_ANCHOR_NE: /* Upper right corner */ point.x = deltaX; break; case TK_ANCHOR_E: /* Right center */ point.x = deltaX; point.y = (deltaY / 2); break; case TK_ANCHOR_SE: /* Lower right corner */ point.x = deltaX; point.y = deltaY; break; } return point; } /* *---------------------------------------------------------------------- * * ComputeCavitySize -- * * Sets the width and height of the cavity based upon the * requested size of the embedded widget. The requested space also * includes any external padding which has been designated for * this window. * * Results: * None. * * Side Effects: * The size of the cavity is set in the embedded widget information * structure. These values can effect how the embedded widget is * packed into the master window. * *---------------------------------------------------------------------- */ static void ComputeCavitySize(winPtr) EmbeddedWidget *winPtr; { int width, height; int twiceBW; twiceBW = 2 * Tk_Changes(winPtr->tkwin)->border_width; if (winPtr->reqCavityWidth > 0) { width = winPtr->reqCavityWidth; } else if (winPtr->relCavityWidth > 0.0) { width = (int)((double)Tk_Width(winPtr->htPtr->tkwin) * winPtr->relCavityWidth + 0.5); } else { width = GetEmbeddedWidgetWidth(winPtr) + PADDING(winPtr->padX) + twiceBW; } winPtr->cavityWidth = width; if (winPtr->reqCavityHeight > 0) { height = winPtr->reqCavityHeight; } else if (winPtr->relCavityHeight > 0.0) { height = (int)((double)Tk_Height(winPtr->htPtr->tkwin) * winPtr->relCavityHeight + 0.5); } else { height = GetEmbeddedWidgetHeight(winPtr) + PADDING(winPtr->padY) + twiceBW; } winPtr->cavityHeight = height; } /* *---------------------------------------------------------------------- * * LayoutLine -- * * This procedure computes the total width and height needed * to contain the text and widgets for a particular line. * It also calculates the baseline of the text on the line with * respect to the other widgets on the line. * * Results: * None. * *---------------------------------------------------------------------- */ static void LayoutLine(htPtr, linePtr) HText *htPtr; Line *linePtr; { EmbeddedWidget *winPtr; int textStart, textLength; int maxAscent, maxDescent, maxHeight; int ascent, descent; int median; /* Difference of font ascent/descent values */ Blt_ChainLink *linkPtr; int x, y; int newX; Tk_FontMetrics fontMetrics; /* Initialize line defaults */ Tk_GetFontMetrics(htPtr->font, &fontMetrics); maxAscent = fontMetrics.ascent; maxDescent = fontMetrics.descent; median = fontMetrics.ascent - fontMetrics.descent; ascent = descent = 0; /* Suppress compiler warnings */ /* * Pass 1: Determine the maximum ascent (baseline) and descent * needed for the line. We'll need this for figuring the top, * bottom, and center anchors. */ for (linkPtr = Blt_ChainFirstLink(linePtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { winPtr = Blt_ChainGetValue(linkPtr); if (winPtr->tkwin == NULL) { continue; } ComputeCavitySize(winPtr); switch (winPtr->justify) { case JUSTIFY_TOP: ascent = fontMetrics.ascent + winPtr->padTop; descent = winPtr->cavityHeight - fontMetrics.ascent; break; case JUSTIFY_CENTER: ascent = (winPtr->cavityHeight + median) / 2; descent = (winPtr->cavityHeight - median) / 2; break; case JUSTIFY_BOTTOM: ascent = winPtr->cavityHeight - fontMetrics.descent; descent = fontMetrics.descent; break; } if (descent > maxDescent) { maxDescent = descent; } if (ascent > maxAscent) { maxAscent = ascent; } } maxHeight = maxAscent + maxDescent + htPtr->leader; x = 0; /* Always starts from x=0 */ y = 0; /* Suppress compiler warning */ textStart = linePtr->textStart; /* * Pass 2: Find the placements of the text and widgets along each * line. */ for (linkPtr = Blt_ChainFirstLink(linePtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { winPtr = Blt_ChainGetValue(linkPtr); if (winPtr->tkwin == NULL) { continue; } /* Get the width of the text leading to the widget. */ textLength = (winPtr->precedingTextEnd - textStart); if (textLength > 0) { Tk_MeasureChars(htPtr->font, htPtr->charArr + textStart, textLength, 10000, TK_AT_LEAST_ONE, &newX); winPtr->precedingTextWidth = newX; x += newX; } switch (winPtr->justify) { case JUSTIFY_TOP: y = maxAscent - fontMetrics.ascent; break; case JUSTIFY_CENTER: y = maxAscent - (winPtr->cavityHeight + median) / 2; break; case JUSTIFY_BOTTOM: y = maxAscent + fontMetrics.descent - winPtr->cavityHeight; break; } winPtr->x = x, winPtr->y = y; /* Skip over trailing space */ textStart = winPtr->precedingTextEnd + 1; x += winPtr->cavityWidth; } /* * This can be either the trailing piece of a line after the last widget * or the entire line if no widgets are embedded in it. */ textLength = (linePtr->textEnd - textStart) + 1; if (textLength > 0) { Tk_MeasureChars(htPtr->font, htPtr->charArr + textStart, textLength, 10000, DEF_TEXT_FLAGS, &newX); x += newX; } /* Update line parameters */ if ((linePtr->width != x) || (linePtr->height != maxHeight) || (linePtr->baseline != maxAscent)) { htPtr->flags |= TEXT_DIRTY; } linePtr->width = x; linePtr->height = maxHeight; linePtr->baseline = maxAscent; } /* *---------------------------------------------------------------------- * * ComputeLayout -- * * This procedure computes the total width and height needed * to contain the text and widgets from all the lines of text. * It merely sums the heights and finds the maximum width of * all the lines. The width and height are needed for scrolling. * * Results: * None. * *---------------------------------------------------------------------- */ static void ComputeLayout(htPtr) HText *htPtr; { int count; Line *linePtr; int height, width; width = height = 0; for (count = 0; count < htPtr->nLines; count++) { linePtr = htPtr->lineArr + count; linePtr->offset = height; LayoutLine(htPtr, linePtr); height += linePtr->height; if (linePtr->width > width) { width = linePtr->width; } } /* * Set changed flag if new layout changed size of virtual text. */ if ((height != htPtr->worldHeight) || (width != htPtr->worldWidth)) { htPtr->worldHeight = height, htPtr->worldWidth = width; htPtr->flags |= TEXT_DIRTY; } } /* Display Procedures */ /* * ---------------------------------------------------------------------- * * GetVisibleLines -- * * Calculates which lines are visible using the height * of the viewport and y offset from the top of the text. * * Results: * None. * * Side effects: * Only those line between first and last inclusive are * redrawn. * * ---------------------------------------------------------------------- */ static int GetVisibleLines(htPtr) HText *htPtr; { int topLine, bottomLine; int firstY, lastY; int lastLine; if (htPtr->nLines == 0) { htPtr->first = 0; htPtr->last = -1; return TCL_OK; } firstY = htPtr->pendingY; lastLine = htPtr->nLines - 1; /* First line */ topLine = LineSearch(htPtr, firstY, 0, lastLine); if (topLine < 0) { /* * This can't be. The y-coordinate offset must be corrupted. */ fprintf(stderr, "internal error: First position not found `%d'\n", firstY); return TCL_ERROR; } htPtr->first = topLine; /* * If there is less text than window space, the bottom line is the * last line of text. Otherwise search for the line at the bottom * of the window. */ lastY = firstY + Tk_Height(htPtr->tkwin) - 1; if (lastY < htPtr->worldHeight) { bottomLine = LineSearch(htPtr, lastY, topLine, lastLine); } else { bottomLine = lastLine; } if (bottomLine < 0) { /* * This can't be. The newY offset must be corrupted. */ fprintf(stderr, "internal error: Last position not found `%d'\n", lastY); #ifdef notdef fprintf(stderr, "worldHeight=%d,height=%d,top=%d,first=%d,last=%d\n", htPtr->worldHeight, Tk_Height(htPtr->tkwin), firstY, htPtr->lineArr[topLine].offset, htPtr->lineArr[lastLine].offset); #endif return TCL_ERROR; } htPtr->last = bottomLine; return TCL_OK; } /* * ---------------------------------------------------------------------- * * DrawSegment -- * * Draws a line segment, designated by the segment structure. * This routine handles the display of selected text by drawing * a raised 3D border underneath the selected text. * * Results: * None. * * Side effects: * The line segment is drawn on *draw*. * * ---------------------------------------------------------------------- */ static void DrawSegment(htPtr, draw, linePtr, x, y, segPtr) HText *htPtr; Drawable draw; Line *linePtr; int x, y; Segment *segPtr; { int lastX, curPos, nChars; int textLength; int selStart, selEnd, selLength; Tk_FontMetrics fontMetrics; #ifdef notdef fprintf(stderr, "DS select: first=%d,last=%d text: first=%d,last=%d\n", htPtr->selFirst, htPtr->selLast, segPtr->textStart, segPtr->textEnd); #endif textLength = (segPtr->textEnd - segPtr->textStart) + 1; if (textLength < 1) { return; } Tk_GetFontMetrics(htPtr->font, &fontMetrics); if ((segPtr->textEnd < htPtr->selFirst) || (segPtr->textStart > htPtr->selLast)) { /* No selected text */ Tk_DrawChars(htPtr->display, draw, htPtr->drawGC, htPtr->font, htPtr->charArr + segPtr->textStart, textLength - 1, x, y + linePtr->baseline); return; } /* * Text in a segment (with selected text) may have * up to three regions: * * 1) the text before the start the selection * 2) the selected text itself (drawn in a raised border) * 3) the text following the selection. */ selStart = segPtr->textStart; selEnd = segPtr->textEnd; if (htPtr->selFirst > segPtr->textStart) { selStart = htPtr->selFirst; } if (htPtr->selLast < segPtr->textEnd) { selEnd = htPtr->selLast; } selLength = (selEnd - selStart) + 1; lastX = x; curPos = segPtr->textStart; if (selStart > segPtr->textStart) { /* Text preceding selection */ nChars = (selStart - segPtr->textStart); Tk_MeasureChars(htPtr->font, htPtr->charArr + segPtr->textStart, nChars, 10000, DEF_TEXT_FLAGS, &lastX); lastX += x; Tk_DrawChars(htPtr->display, draw, htPtr->drawGC, htPtr->font, htPtr->charArr + segPtr->textStart, nChars, x, y + linePtr->baseline); curPos = selStart; } if (selLength > 0) { /* The selection itself */ int width, nextX; Tk_MeasureChars(htPtr->font, htPtr->charArr + selStart, selLength, 10000, DEF_TEXT_FLAGS, &nextX); nextX += x; width = (selEnd == linePtr->textEnd) ? htPtr->worldWidth - htPtr->xOffset - lastX : nextX - lastX; Blt_Fill3DRectangle(htPtr->tkwin, draw, htPtr->selBorder, lastX, y + linePtr->baseline - fontMetrics.ascent, width, fontMetrics.linespace, htPtr->selBorderWidth, TK_RELIEF_RAISED); Tk_DrawChars(htPtr->display, draw, htPtr->selectGC, htPtr->font, htPtr->charArr + selStart, selLength, lastX, y + linePtr->baseline); lastX = nextX; curPos = selStart + selLength; } nChars = segPtr->textEnd - curPos; if (nChars > 0) { /* Text following the selection */ Tk_DrawChars(htPtr->display, draw, htPtr->drawGC, htPtr->font, htPtr->charArr + curPos, nChars - 1, lastX, y + linePtr->baseline); } } /* * ---------------------------------------------------------------------- * * MoveEmbeddedWidget -- * * Move a embedded widget to a new location in the hypertext * parent window. If the window has no geometry (i.e. width, * or height is 0), simply unmap to window. * * Results: * None. * * Side effects: * Each embedded widget is moved to its new location, generating * Expose events in the parent for each embedded widget moved. * * ---------------------------------------------------------------------- */ static void MoveEmbeddedWidget(winPtr, offset) EmbeddedWidget *winPtr; int offset; { int winWidth, winHeight; int width, height; int deltaX, deltaY; int x, y; int intBW; winWidth = GetEmbeddedWidgetWidth(winPtr); winHeight = GetEmbeddedWidgetHeight(winPtr); if ((winWidth < 1) || (winHeight < 1)) { if (Tk_IsMapped(winPtr->tkwin)) { Tk_UnmapWindow(winPtr->tkwin); } return; } intBW = Tk_Changes(winPtr->tkwin)->border_width; x = (winPtr->x + intBW + winPtr->padLeft) - winPtr->htPtr->xOffset; y = offset + (winPtr->y + intBW + winPtr->padTop) - winPtr->htPtr->yOffset; width = winPtr->cavityWidth - (2 * intBW + PADDING(winPtr->padX)); if (width < 0) { width = 0; } if ((width < winWidth) || (winPtr->fill & FILL_X)) { winWidth = width; } deltaX = width - winWidth; height = winPtr->cavityHeight - (2 * intBW + PADDING(winPtr->padY)); if (height < 0) { height = 0; } if ((height < winHeight) || (winPtr->fill & FILL_Y)) { winHeight = height; } deltaY = height - winHeight; if ((deltaX > 0) || (deltaY > 0)) { XPoint point; point = TranslateAnchor(deltaX, deltaY, winPtr->anchor); x += point.x, y += point.y; } winPtr->winWidth = winWidth; winPtr->winHeight = winHeight; if ((x != Tk_X(winPtr->tkwin)) || (y != Tk_Y(winPtr->tkwin)) || (winWidth != Tk_Width(winPtr->tkwin)) || (winHeight != Tk_Height(winPtr->tkwin))) { Tk_MoveResizeWindow(winPtr->tkwin, x, y, winWidth, winHeight); } if (!Tk_IsMapped(winPtr->tkwin)) { Tk_MapWindow(winPtr->tkwin); } } /* * ---------------------------------------------------------------------- * * DrawPage -- * * This procedure displays the lines of text and moves the widgets * to their new positions. It draws lines with regard to * the direction of the scrolling. The idea here is to make the * text and buttons appear to move together. Otherwise you will * get a "jiggling" effect where the windows appear to bump into * the next line before that line is moved. In the worst case, where * every line has at least one widget, you can get an aquarium effect * (lines appear to ripple up). * * The text area may start between line boundaries (to accommodate * both variable height lines and constant scrolling). Subtract the * difference of the page offset and the line offset from the starting * coordinates. For horizontal scrolling, simply subtract the offset * of the viewport. The window will clip the top of the first line, * the bottom of the last line, whatever text extends to the left * or right of the viewport on any line. * * Results: * None. * * Side effects: * Commands are output to X to display the line in its current * mode. * * ---------------------------------------------------------------------- */ static void DrawPage(htPtr, deltaY) HText *htPtr; int deltaY; /* Change from previous Y coordinate */ { Line *linePtr; EmbeddedWidget *winPtr; Tk_Window tkwin = htPtr->tkwin; Segment sgmt; Pixmap pixmap; int forceCopy; int i; int lineNum; int x, y, lastY; Blt_ChainLink *linkPtr; int width, height; Display *display; display = htPtr->display; width = Tk_Width(tkwin); height = Tk_Height(tkwin); /* Create an off-screen pixmap for semi-smooth scrolling. */ pixmap = Tk_GetPixmap(display, Tk_WindowId(tkwin), width, height, Tk_Depth(tkwin)); x = -(htPtr->xOffset); y = -(htPtr->yOffset); if (htPtr->tile != NULL) { if (htPtr->tileOffsetPage) { Blt_SetTSOrigin(htPtr->tkwin, htPtr->tile, x, y); } else { Blt_SetTileOrigin(htPtr->tkwin, htPtr->tile, 0, 0); } Blt_TileRectangle(htPtr->tkwin, pixmap, htPtr->tile, 0, 0, width, height); } else { XFillRectangle(display, pixmap, htPtr->fillGC, 0, 0, width, height); } if (deltaY >= 0) { y += htPtr->lineArr[htPtr->first].offset; lineNum = htPtr->first; lastY = 0; } else { y += htPtr->lineArr[htPtr->last].offset; lineNum = htPtr->last; lastY = height; } forceCopy = 0; /* Draw each line */ for (i = htPtr->first; i <= htPtr->last; i++) { /* Initialize character position in text buffer to start */ linePtr = htPtr->lineArr + lineNum; sgmt.textStart = linePtr->textStart; sgmt.textEnd = linePtr->textEnd; /* Initialize X position */ x = -(htPtr->xOffset); for (linkPtr = Blt_ChainFirstLink(linePtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { winPtr = Blt_ChainGetValue(linkPtr); if (winPtr->tkwin != NULL) { winPtr->flags |= WIDGET_VISIBLE; MoveEmbeddedWidget(winPtr, linePtr->offset); } sgmt.textEnd = winPtr->precedingTextEnd - 1; if (sgmt.textEnd >= sgmt.textStart) { DrawSegment(htPtr, pixmap, linePtr, x, y, &sgmt); x += winPtr->precedingTextWidth; } /* Skip over the extra trailing space which designates the widget */ sgmt.textStart = winPtr->precedingTextEnd + 1; x += winPtr->cavityWidth; forceCopy++; } /* * This may be the text trailing the last widget or the entire * line if no widgets occur on it. */ sgmt.textEnd = linePtr->textEnd; if (sgmt.textEnd >= sgmt.textStart) { DrawSegment(htPtr, pixmap, linePtr, x, y, &sgmt); } /* Go to the top of the next line */ if (deltaY >= 0) { y += htPtr->lineArr[lineNum].height; lineNum++; } if ((forceCopy > 0) && !(htPtr->flags & TEXT_DIRTY)) { if (deltaY >= 0) { XCopyArea(display, pixmap, Tk_WindowId(tkwin), htPtr->drawGC, 0, lastY, width, y - lastY, 0, lastY); } else { XCopyArea(display, pixmap, Tk_WindowId(tkwin), htPtr->drawGC, 0, y, width, lastY - y, 0, y); } forceCopy = 0; /* Reset drawing flag */ lastY = y; /* Record last Y position */ } if ((deltaY < 0) && (lineNum > 0)) { --lineNum; y -= htPtr->lineArr[lineNum].height; } } /* * If the viewport was resized, draw the page in one operation. * Otherwise draw any left-over block of text (either at the top * or bottom of the page) */ if (htPtr->flags & TEXT_DIRTY) { XCopyArea(display, pixmap, Tk_WindowId(tkwin), htPtr->drawGC, 0, 0, width, height, 0, 0); } else if (lastY != y) { if (deltaY >= 0) { height -= lastY; XCopyArea(display, pixmap, Tk_WindowId(tkwin), htPtr->drawGC, 0, lastY, width, height, 0, lastY); } else { height = lastY; XCopyArea(display, pixmap, Tk_WindowId(tkwin), htPtr->drawGC, 0, 0, width, height, 0, 0); } } Tk_FreePixmap(display, pixmap); } static void SendBogusEvent(tkwin) Tk_Window tkwin; { #define DONTPROPAGATE 0 XEvent event; event.type = event.xexpose.type = Expose; event.xexpose.window = Tk_WindowId(tkwin); event.xexpose.display = Tk_Display(tkwin); event.xexpose.count = 0; event.xexpose.x = event.xexpose.y = 0; event.xexpose.width = Tk_Width(tkwin); event.xexpose.height = Tk_Height(tkwin); XSendEvent(Tk_Display(tkwin), Tk_WindowId(tkwin), DONTPROPAGATE, ExposureMask, &event); } /* * ---------------------------------------------------------------------- * * DisplayText -- * * This procedure is invoked to display a hypertext widget. * Many of the operations which might ordinarily be performed * elsewhere (e.g. in a configuration routine) are done here * because of the somewhat unusual interactions occurring between * the parent and embedded widgets. * * Recompute the layout of the text if necessary. This is * necessary if the world coordinate system has changed. * Specifically, the following may have occurred: * * 1. a text attribute has changed (font, linespacing, etc.). * 2. widget option changed (anchor, width, height). * 3. actual embedded widget was resized. * 4. new text string or file. * * This is deferred to the display routine since potentially * many of these may occur (especially embedded widget changes). * * Set the vertical and horizontal scrollbars (if they are * designated) by issuing a Tcl command. Done here since * the text window width and height are needed. * * If the viewport position or contents have changed in the * vertical direction, the now out-of-view embedded widgets * must be moved off the viewport. Since embedded widgets will * obscure the text window, it is imperative that the widgets * are moved off before we try to redraw text in the same area. * This is necessary only for vertical movements. Horizontal * embedded widget movements are handled automatically in the * page drawing routine. * * Get the new first and last line numbers for the viewport. * These line numbers may have changed because either a) * the viewport changed size or position, or b) the text * (embedded widget sizes or text attributes) have changed. * * If the viewport has changed vertically (i.e. the first or * last line numbers have changed), move the now out-of-view * embedded widgets off the viewport. * * Potentially many expose events may be generated when the * the individual embedded widgets are moved and/or resized. * These events need to be ignored. Since (I think) expose * events are guaranteed to happen in order, we can bracket * them by sending phony events (via XSendEvent). The phony * events turn on and off flags indicating which events * should be ignored. * * Finally, the page drawing routine is called. * * Results: * None. * * Side effects: * Commands are output to X to display the hypertext in its * current mode. * * ---------------------------------------------------------------------- */ static void DisplayText(clientData) ClientData clientData; /* Information about widget. */ { HText *htPtr = clientData; Tk_Window tkwin = htPtr->tkwin; int oldFirst; /* First line of old viewport */ int oldLast; /* Last line of old viewport */ int deltaY; /* Change in viewport in Y direction */ int reqWidth, reqHeight; #ifdef notdef fprintf(stderr, "calling DisplayText(%s)\n", Tk_PathName(htPtr->tkwin)); #endif htPtr->flags &= ~REDRAW_PENDING; if (tkwin == NULL) { return; /* Window has been destroyed */ } if (htPtr->flags & REQUEST_LAYOUT) { /* * Recompute the layout when widgets are created, deleted, * moved, or resized. Also when text attributes (such as * font, linespacing) have changed. */ ComputeLayout(htPtr); } htPtr->lastWidth = Tk_Width(tkwin); htPtr->lastHeight = Tk_Height(tkwin); /* * Check the requested width and height. We allow two modes: * 1) If the user requested value is greater than zero, use it. * 2) Otherwise, let the window be as big as the virtual text. * This could be too large to display, so constrain it by * the maxWidth and maxHeight values. * * In any event, we need to calculate the size of the virtual * text and then make a geometry request. This is so that widgets * whose size is relative to the master, will be set once. */ if (htPtr->reqWidth > 0) { reqWidth = htPtr->reqWidth; } else { reqWidth = MIN(htPtr->worldWidth, htPtr->maxWidth); if (reqWidth < 1) { reqWidth = 1; } } if (htPtr->reqHeight > 0) { reqHeight = htPtr->reqHeight; } else { reqHeight = MIN(htPtr->worldHeight, htPtr->maxHeight); if (reqHeight < 1) { reqHeight = 1; } } if ((reqWidth != Tk_ReqWidth(tkwin)) || (reqHeight != Tk_ReqHeight(tkwin))) { Tk_GeometryRequest(tkwin, reqWidth, reqHeight); EventuallyRedraw(htPtr); return; /* Try again with new geometry */ } if (!Tk_IsMapped(tkwin)) { return; } /* * Turn off layout requests here, after the text window has been * mapped. Otherwise, relative embedded widget size requests wrt * to the size of parent text window will be wrong. */ htPtr->flags &= ~REQUEST_LAYOUT; /* Is there a pending goto request? */ if (htPtr->flags & GOTO_PENDING) { htPtr->pendingY = htPtr->lineArr[htPtr->reqLineNum].offset; htPtr->flags &= ~GOTO_PENDING; } deltaY = htPtr->pendingY - htPtr->yOffset; oldFirst = htPtr->first, oldLast = htPtr->last; /* * If the viewport has changed size or position, or the text * and/or embedded widgets have changed, adjust the scrollbars to * new positions. */ if (htPtr->flags & TEXT_DIRTY) { int width, height; width = Tk_Width(htPtr->tkwin); height = Tk_Height(htPtr->tkwin); /* Reset viewport origin and world extents */ htPtr->xOffset = Blt_AdjustViewport(htPtr->pendingX, htPtr->worldWidth, width, htPtr->xScrollUnits, BLT_SCROLL_MODE_LISTBOX); htPtr->yOffset = Blt_AdjustViewport(htPtr->pendingY, htPtr->worldHeight, height, htPtr->yScrollUnits, BLT_SCROLL_MODE_LISTBOX); if (htPtr->xScrollCmdPrefix != NULL) { Blt_UpdateScrollbar(htPtr->interp, htPtr->xScrollCmdPrefix, (double)htPtr->xOffset / htPtr->worldWidth, (double)(htPtr->xOffset + width) / htPtr->worldWidth); } if (htPtr->yScrollCmdPrefix != NULL) { Blt_UpdateScrollbar(htPtr->interp, htPtr->yScrollCmdPrefix, (double)htPtr->yOffset / htPtr->worldHeight, (double)(htPtr->yOffset + height) / htPtr->worldHeight); } /* * Given a new viewport or text height, find the first and * last line numbers of the new viewport. */ if (GetVisibleLines(htPtr) != TCL_OK) { return; } } /* * This is a kludge: Send an expose event before and after * drawing the page of text. Since moving and resizing of the * embedded widgets will cause redundant expose events in the parent * window, the phony events will bracket them indicating no * action should be taken. */ SendBogusEvent(tkwin); /* * If either the position of the viewport has changed or the size * of width or height of the entire text have changed, move the * widgets from the previous viewport out of the current * viewport. Worry only about the vertical embedded widget movements. * The page is always draw at full width and the viewport will clip * the text. */ if ((htPtr->first != oldFirst) || (htPtr->last != oldLast)) { int offset; int i; int first, last; Blt_ChainLink *linkPtr; EmbeddedWidget *winPtr; /* Figure out which lines are now out of the viewport */ if ((htPtr->first > oldFirst) && (htPtr->first <= oldLast)) { first = oldFirst, last = htPtr->first; } else if ((htPtr->last < oldLast) && (htPtr->last >= oldFirst)) { first = htPtr->last, last = oldLast; } else { first = oldFirst, last = oldLast; } for (i = first; i <= last; i++) { offset = htPtr->lineArr[i].offset; for (linkPtr = Blt_ChainFirstLink(htPtr->lineArr[i].chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { winPtr = Blt_ChainGetValue(linkPtr); if (winPtr->tkwin != NULL) { MoveEmbeddedWidget(winPtr, offset); winPtr->flags &= ~WIDGET_VISIBLE; } } } } DrawPage(htPtr, deltaY); SendBogusEvent(tkwin); /* Reset flags */ htPtr->flags &= ~TEXT_DIRTY; } /* Selection Procedures */ /* *---------------------------------------------------------------------- * * TextSelectionProc -- * * This procedure is called back by Tk when the selection is * requested by someone. It returns part or all of the selection * in a buffer provided by the caller. * * Results: * The return value is the number of non-NULL bytes stored * at buffer. Buffer is filled (or partially filled) with a * NULL-terminated string containing part or all of the selection, * as given by offset and maxBytes. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TextSelectionProc(clientData, offset, buffer, maxBytes) ClientData clientData; /* Information about Text widget. */ int offset; /* Offset within selection of first * character to be returned. */ char *buffer; /* Location in which to place * selection. */ int maxBytes; /* Maximum number of bytes to place * at buffer, not including terminating * NULL character. */ { HText *htPtr = clientData; int size; if ((htPtr->selFirst < 0) || (!htPtr->exportSelection)) { return -1; } size = (htPtr->selLast - htPtr->selFirst) + 1 - offset; if (size > maxBytes) { size = maxBytes; } if (size <= 0) { return 0; /* huh? */ } strncpy(buffer, htPtr->charArr + htPtr->selFirst + offset, size); buffer[size] = '\0'; return size; } /* *---------------------------------------------------------------------- * * TextLostSelection -- * * This procedure is called back by Tk when the selection is * grabbed away from a Text widget. * * Results: * None. * * Side effects: * The existing selection is unhighlighted, and the window is * marked as not containing a selection. * *---------------------------------------------------------------------- */ static void TextLostSelection(clientData) ClientData clientData; /* Information about Text widget. */ { HText *htPtr = clientData; if ((htPtr->selFirst >= 0) && (htPtr->exportSelection)) { htPtr->selFirst = htPtr->selLast = -1; EventuallyRedraw(htPtr); } } /* *---------------------------------------------------------------------- * * SelectLine -- * * Modify the selection by moving both its anchored and un-anchored * ends. This could make the selection either larger or smaller. * * Results: * None. * * Side effects: * The selection changes. * *---------------------------------------------------------------------- */ static int SelectLine(htPtr, tindex) HText *htPtr; /* Information about widget. */ int tindex; /* Index of element that is to * become the "other" end of the * selection. */ { int selFirst, selLast; int lineNum; Line *linePtr; lineNum = IndexSearch(htPtr, tindex, 0, htPtr->nLines - 1); if (lineNum < 0) { char string[200]; sprintf(string, "can't determine line number from index \"%d\"", tindex); Tcl_AppendResult(htPtr->interp, string, (char *)NULL); return TCL_ERROR; } linePtr = htPtr->lineArr + lineNum; /* * Grab the selection if we don't own it already. */ if ((htPtr->exportSelection) && (htPtr->selFirst == -1)) { Tk_OwnSelection(htPtr->tkwin, XA_PRIMARY, TextLostSelection, htPtr); } selFirst = linePtr->textStart; selLast = linePtr->textEnd; htPtr->selAnchor = tindex; if ((htPtr->selFirst != selFirst) || (htPtr->selLast != selLast)) { htPtr->selFirst = selFirst; htPtr->selLast = selLast; EventuallyRedraw(htPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * SelectWord -- * * Modify the selection by moving both its anchored and un-anchored * ends. This could make the selection either larger or smaller. * * Results: * None. * * Side effects: * The selection changes. * *---------------------------------------------------------------------- */ static int SelectWord(htPtr, tindex) HText *htPtr; /* Information about widget. */ int tindex; /* Index of element that is to * become the "other" end of the * selection. */ { int selFirst, selLast; int i; for (i = tindex; i < htPtr->nChars; i++) { if (isspace(UCHAR(htPtr->charArr[i]))) { break; } } selLast = i - 1; for (i = tindex; i >= 0; i--) { if (isspace(UCHAR(htPtr->charArr[i]))) { break; } } selFirst = i + 1; if (selFirst > selLast) { selFirst = selLast = tindex; } /* * Grab the selection if we don't own it already. */ if ((htPtr->exportSelection) && (htPtr->selFirst == -1)) { Tk_OwnSelection(htPtr->tkwin, XA_PRIMARY, TextLostSelection, htPtr); } htPtr->selAnchor = tindex; if ((htPtr->selFirst != selFirst) || (htPtr->selLast != selLast)) { htPtr->selFirst = selFirst, htPtr->selLast = selLast; EventuallyRedraw(htPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * SelectTextBlock -- * * Modify the selection by moving its un-anchored end. This * could make the selection either larger or smaller. * * Results: * None. * * Side effects: * The selection changes. * *---------------------------------------------------------------------- */ static int SelectTextBlock(htPtr, tindex) HText *htPtr; /* Information about widget. */ int tindex; /* Index of element that is to * become the "other" end of the * selection. */ { int selFirst, selLast; /* * Grab the selection if we don't own it already. */ if ((htPtr->exportSelection) && (htPtr->selFirst == -1)) { Tk_OwnSelection(htPtr->tkwin, XA_PRIMARY, TextLostSelection, htPtr); } /* If the anchor hasn't been set yet, assume the beginning of the text*/ if (htPtr->selAnchor < 0) { htPtr->selAnchor = 0; } if (htPtr->selAnchor <= tindex) { selFirst = htPtr->selAnchor; selLast = tindex; } else { selFirst = tindex; selLast = htPtr->selAnchor; } if ((htPtr->selFirst != selFirst) || (htPtr->selLast != selLast)) { htPtr->selFirst = selFirst, htPtr->selLast = selLast; EventuallyRedraw(htPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * SelectOp -- * * This procedure handles the individual options for text * selections. The selected text is designated by start and end * indices into the text pool. The selected segment has both a * anchored and unanchored ends. The following selection * operations are implemented: * * "adjust" - resets either the first or last index * of the selection. * "clear" - clears the selection. Sets first/last * indices to -1. * "from" - sets the index of the selection anchor. * "line" - sets the first of last indices to the * start and end of the line at the * designated point. * "present" - return "1" if a selection is available, * "0" otherwise. * "range" - sets the first and last indices. * "to" - sets the index of the un-anchored end. * "word" - sets the first of last indices to the * start and end of the word at the * designated point. * Results: * None. * * Side effects: * The selection changes. * *---------------------------------------------------------------------- */ static int SelectOp(htPtr, interp, argc, argv) HText *htPtr; Tcl_Interp *interp; int argc; char **argv; { int iselection; unsigned int length; int result = TCL_OK; char c; length = strlen(argv[2]); c = argv[2][0]; if ((c == 'c') && (strncmp(argv[2], "clear", length) == 0)) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " selection clear\"", (char *)NULL); return TCL_ERROR; } if (htPtr->selFirst != -1) { htPtr->selFirst = htPtr->selLast = -1; EventuallyRedraw(htPtr); } return TCL_OK; } else if ((c == 'p') && (strncmp(argv[2], "present", length) == 0)) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " selection present\"", (char *)NULL); return TCL_ERROR; } Tcl_AppendResult(interp, (htPtr->selFirst != -1) ? "0" : "1", (char *)NULL); return TCL_OK; } else if ((c == 'r') && (strncmp(argv[2], "range", length) == 0)) { int selFirst, selLast; if (argc != 5) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " selection range first last\"", (char *)NULL); return TCL_ERROR; } if (GetIndex(htPtr, argv[3], &selFirst) != TCL_OK) { return TCL_ERROR; } if (GetIndex(htPtr, argv[4], &selLast) != TCL_OK) { return TCL_ERROR; } htPtr->selAnchor = selFirst; SelectTextBlock(htPtr, selLast); return TCL_OK; } if (argc != 4) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " selection ", argv[2], " index\"", (char *)NULL); return TCL_ERROR; } if (GetIndex(htPtr, argv[3], &iselection) != TCL_OK) { return TCL_ERROR; } if ((c == 'f') && (strncmp(argv[2], "from", length) == 0)) { htPtr->selAnchor = iselection; } else if ((c == 'a') && (strncmp(argv[2], "adjust", length) == 0)) { int half1, half2; half1 = (htPtr->selFirst + htPtr->selLast) / 2; half2 = (htPtr->selFirst + htPtr->selLast + 1) / 2; if (iselection < half1) { htPtr->selAnchor = htPtr->selLast; } else if (iselection > half2) { htPtr->selAnchor = htPtr->selFirst; } result = SelectTextBlock(htPtr, iselection); } else if ((c == 't') && (strncmp(argv[2], "to", length) == 0)) { result = SelectTextBlock(htPtr, iselection); } else if ((c == 'w') && (strncmp(argv[2], "word", length) == 0)) { result = SelectWord(htPtr, iselection); } else if ((c == 'l') && (strncmp(argv[2], "line", length) == 0)) { result = SelectLine(htPtr, iselection); } else { Tcl_AppendResult(interp, "bad selection operation \"", argv[2], "\": should be \"adjust\", \"clear\", \"from\", \"line\", \ \"present\", \"range\", \"to\", or \"word\"", (char *)NULL); return TCL_ERROR; } return result; } /* *---------------------------------------------------------------------- * * GotoOp -- * * Move the top line of the viewport to the new location based * upon the given line number. Force out-of-range requests to the * top or bottom of text. * * Results: * A standard Tcl result. If TCL_OK, interp->result contains the * current line number. * * Side effects: * At the next idle point, the text viewport will be move to the * new line. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int GotoOp(htPtr, interp, argc, argv) HText *htPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { int line; line = htPtr->first; if (argc == 3) { int tindex; if (GetIndex(htPtr, argv[2], &tindex) != TCL_OK) { return TCL_ERROR; } line = IndexSearch(htPtr, tindex, 0, htPtr->nLines - 1); if (line < 0) { char string[200]; sprintf(string, "can't determine line number from index \"%d\"", tindex); Tcl_AppendResult(htPtr->interp, string, (char *)NULL); return TCL_ERROR; } htPtr->reqLineNum = line; htPtr->flags |= TEXT_DIRTY; /* * Make only a request for a change in the viewport. Defer * the actual scrolling until the text layout is adjusted at * the next idle point. */ if (line != htPtr->first) { htPtr->flags |= GOTO_PENDING; EventuallyRedraw(htPtr); } } Tcl_SetResult(htPtr->interp, Blt_Itoa(line), TCL_VOLATILE); return TCL_OK; } static int XViewOp(htPtr, interp, argc, argv) HText *htPtr; Tcl_Interp *interp; int argc; char **argv; { int width, worldWidth; width = Tk_Width(htPtr->tkwin); worldWidth = htPtr->worldWidth; if (argc == 2) { double fract; /* Report first and last fractions */ fract = (double)htPtr->xOffset / worldWidth; Tcl_AppendElement(interp, Blt_Dtoa(interp, CLAMP(fract, 0.0, 1.0))); fract = (double)(htPtr->xOffset + width) / worldWidth; Tcl_AppendElement(interp, Blt_Dtoa(interp, CLAMP(fract, 0.0, 1.0))); return TCL_OK; } htPtr->pendingX = htPtr->xOffset; if (Blt_GetScrollInfo(interp, argc - 2, argv + 2, &(htPtr->pendingX), worldWidth, width, htPtr->xScrollUnits, BLT_SCROLL_MODE_LISTBOX) != TCL_OK) { return TCL_ERROR; } htPtr->flags |= TEXT_DIRTY; EventuallyRedraw(htPtr); return TCL_OK; } static int YViewOp(htPtr, interp, argc, argv) HText *htPtr; Tcl_Interp *interp; int argc; char **argv; { int height, worldHeight; height = Tk_Height(htPtr->tkwin); worldHeight = htPtr->worldHeight; if (argc == 2) { double fract; /* Report first and last fractions */ fract = (double)htPtr->yOffset / worldHeight; Tcl_AppendElement(interp, Blt_Dtoa(interp, CLAMP(fract, 0.0, 1.0))); fract = (double)(htPtr->yOffset + height) / worldHeight; Tcl_AppendElement(interp, Blt_Dtoa(interp, CLAMP(fract, 0.0, 1.0))); return TCL_OK; } htPtr->pendingY = htPtr->yOffset; if (Blt_GetScrollInfo(interp, argc - 2, argv + 2, &(htPtr->pendingY), worldHeight, height, htPtr->yScrollUnits, BLT_SCROLL_MODE_LISTBOX) != TCL_OK) { return TCL_ERROR; } htPtr->flags |= TEXT_DIRTY; EventuallyRedraw(htPtr); return TCL_OK; } /* * ---------------------------------------------------------------------- * * AppendOp -- * * This procedure embeds a Tk widget into the hypertext. * * Results: * A standard Tcl result. * * Side effects: * Memory is allocated. EmbeddedWidget gets configured. * * ---------------------------------------------------------------------- */ static int AppendOp(htPtr, interp, argc, argv) HText *htPtr; /* Hypertext widget */ Tcl_Interp *interp; /* Interpreter associated with widget */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { Line *linePtr; EmbeddedWidget *winPtr; winPtr = CreateEmbeddedWidget(htPtr, argv[2]); if (winPtr == NULL) { return TCL_ERROR; } if (Tk_ConfigureWidget(interp, htPtr->tkwin, widgetConfigSpecs, argc - 3, argv + 3, (char *)winPtr, 0) != TCL_OK) { return TCL_ERROR; } /* * Append widget to list of embedded widgets of the last line. */ linePtr = GetLastLine(htPtr); if (linePtr == NULL) { Tcl_AppendResult(htPtr->interp, "can't allocate line structure", (char *)NULL); return TCL_ERROR; } Blt_ChainAppend(linePtr->chainPtr, winPtr); linePtr->width += winPtr->cavityWidth; winPtr->precedingTextEnd = linePtr->textEnd; htPtr->flags |= (WIDGET_APPENDED | REQUEST_LAYOUT); EventuallyRedraw(htPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * WindowsOp -- * * Returns a list of all the pathNames of embedded widgets of the * HText widget. If a pattern argument is given, only the names * of windows matching it will be placed into the list. * * Results: * Standard Tcl result. If TCL_OK, interp->result will contain * the list of the embedded widget pathnames. Otherwise it will * contain an error message. * *---------------------------------------------------------------------- */ static int WindowsOp(htPtr, interp, argc, argv) HText *htPtr; /* Hypertext widget record */ Tcl_Interp *interp; /* Interpreter associated with widget */ int argc; char **argv; { EmbeddedWidget *winPtr; Blt_HashEntry *hPtr; Blt_HashSearch cursor; char *name; for (hPtr = Blt_FirstHashEntry(&(htPtr->widgetTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { winPtr = (EmbeddedWidget *)Blt_GetHashValue(hPtr); if (winPtr->tkwin == NULL) { fprintf(stderr, "window `%s' is null\n", Tk_PathName(Blt_GetHashKey(&(htPtr->widgetTable), hPtr))); continue; } name = Tk_PathName(winPtr->tkwin); if ((argc == 2) || (Tcl_StringMatch(name, argv[2]))) { Tcl_AppendElement(interp, name); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * CgetOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int CgetOp(htPtr, interp, argc, argv) HText *htPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { char *itemPtr; Tk_ConfigSpec *specsPtr; if ((argc > 2) && (argv[2][0] == '.')) { Tk_Window tkwin; EmbeddedWidget *winPtr; /* EmbeddedWidget window to be configured */ tkwin = Tk_NameToWindow(interp, argv[2], htPtr->tkwin); if (tkwin == NULL) { return TCL_ERROR; } winPtr = FindEmbeddedWidget(htPtr, tkwin); if (winPtr == NULL) { Tcl_AppendResult(interp, "window \"", argv[2], "\" is not managed by \"", argv[0], "\"", (char *)NULL); return TCL_ERROR; } specsPtr = widgetConfigSpecs; itemPtr = (char *)winPtr; argv++; } else { specsPtr = configSpecs; itemPtr = (char *)htPtr; } return Tk_ConfigureValue(interp, htPtr->tkwin, specsPtr, itemPtr, argv[2], 0); } /* *---------------------------------------------------------------------- * * ConfigureOp -- * * This procedure is called to process an argv/argc list, plus * the Tk option database, in order to configure (or reconfigure) * a hypertext widget. * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for htPtr; old resources get freed, if there were any. * The hypertext is redisplayed. * *---------------------------------------------------------------------- */ static int ConfigureOp(htPtr, interp, argc, argv) HText *htPtr; Tcl_Interp *interp; int argc; char **argv; { char *itemPtr; Tk_ConfigSpec *specsPtr; if ((argc > 2) && (argv[2][0] == '.')) { Tk_Window tkwin; EmbeddedWidget *winPtr; /* EmbeddedWidget window to be configured */ tkwin = Tk_NameToWindow(interp, argv[2], htPtr->tkwin); if (tkwin == NULL) { return TCL_ERROR; } winPtr = FindEmbeddedWidget(htPtr, tkwin); if (winPtr == NULL) { Tcl_AppendResult(interp, "window \"", argv[2], "\" is not managed by \"", argv[0], "\"", (char *)NULL); return TCL_ERROR; } specsPtr = widgetConfigSpecs; itemPtr = (char *)winPtr; argv++; argc--; } else { specsPtr = configSpecs; itemPtr = (char *)htPtr; } if (argc == 2) { return Tk_ConfigureInfo(interp, htPtr->tkwin, specsPtr, itemPtr, (char *)NULL, 0); } else if (argc == 3) { return Tk_ConfigureInfo(interp, htPtr->tkwin, specsPtr, itemPtr, argv[2], 0); } if (Tk_ConfigureWidget(interp, htPtr->tkwin, specsPtr, argc - 2, argv + 2, itemPtr, TK_CONFIG_ARGV_ONLY) != TCL_OK) { return TCL_ERROR; } if (itemPtr == (char *)htPtr) { /* Reconfigure the master */ if (ConfigureText(interp, htPtr) != TCL_OK) { return TCL_ERROR; } } else { htPtr->flags |= REQUEST_LAYOUT; } EventuallyRedraw(htPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * ScanOp -- * * Implements the quick scan for hypertext widgets. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ScanOp(htPtr, interp, argc, argv) HText *htPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { int x, y; char c; unsigned int length; if (Blt_GetXY(interp, htPtr->tkwin, argv[3], &x, &y) != TCL_OK) { return TCL_ERROR; } c = argv[2][0]; length = strlen(argv[2]); if ((c == 'm') && (strncmp(argv[2], "mark", length) == 0)) { htPtr->scanMark.x = x, htPtr->scanMark.y = y; htPtr->scanPt.x = htPtr->xOffset; htPtr->scanPt.y = htPtr->yOffset; } else if ((c == 'd') && (strncmp(argv[2], "dragto", length) == 0)) { int px, py; px = htPtr->scanPt.x - (10 * (x - htPtr->scanMark.x)); py = htPtr->scanPt.y - (10 * (y - htPtr->scanMark.y)); if (px < 0) { px = htPtr->scanPt.x = 0; htPtr->scanMark.x = x; } else if (px >= htPtr->worldWidth) { px = htPtr->scanPt.x = htPtr->worldWidth - htPtr->xScrollUnits; htPtr->scanMark.x = x; } if (py < 0) { py = htPtr->scanPt.y = 0; htPtr->scanMark.y = y; } else if (py >= htPtr->worldHeight) { py = htPtr->scanPt.y = htPtr->worldHeight - htPtr->yScrollUnits; htPtr->scanMark.y = y; } if ((py != htPtr->pendingY) || (px != htPtr->pendingX)) { htPtr->pendingX = px, htPtr->pendingY = py; htPtr->flags |= TEXT_DIRTY; EventuallyRedraw(htPtr); } } else { Tcl_AppendResult(interp, "bad scan operation \"", argv[2], "\": should be either \"mark\" or \"dragto\"", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * SearchOp -- * * Returns the linenumber of the next line matching the given * pattern within the range of lines provided. If the first * line number is greater than the last, the search is done in * reverse. * *---------------------------------------------------------------------- */ static int SearchOp(htPtr, interp, argc, argv) HText *htPtr; Tcl_Interp *interp; int argc; char **argv; { char *startPtr, *endPtr; char saved; Tcl_RegExp regExpToken; int iFirst, iLast; int matchStart, matchEnd; int match; regExpToken = Tcl_RegExpCompile(interp, argv[2]); if (regExpToken == NULL) { return TCL_ERROR; } iFirst = 0; iLast = htPtr->nChars; if (argc > 3) { if (GetIndex(htPtr, argv[3], &iFirst) != TCL_OK) { return TCL_ERROR; } } if (argc == 4) { if (GetIndex(htPtr, argv[4], &iLast) != TCL_OK) { return TCL_ERROR; } } if (iLast < iFirst) { return TCL_ERROR; } matchStart = matchEnd = -1; startPtr = htPtr->charArr + iFirst; endPtr = htPtr->charArr + (iLast + 1); saved = *endPtr; *endPtr = '\0'; /* Make the line a string by changing the * '\n' into a NUL byte before searching */ match = Tcl_RegExpExec(interp, regExpToken, startPtr, startPtr); *endPtr = saved; if (match < 0) { return TCL_ERROR; } else if (match > 0) { Tcl_RegExpRange(regExpToken, 0, &startPtr, &endPtr); if ((startPtr != NULL) || (endPtr != NULL)) { matchStart = startPtr - htPtr->charArr; matchEnd = endPtr - htPtr->charArr - 1; } } if (match > 0) { Tcl_AppendElement(interp, Blt_Itoa(matchStart)); Tcl_AppendElement(interp, Blt_Itoa(matchEnd)); } else { Tcl_ResetResult(interp); } return TCL_OK; } /* *---------------------------------------------------------------------- * * RangeOp -- * * Returns the characters designated by the range of elements. * *---------------------------------------------------------------------- */ static int RangeOp(htPtr, interp, argc, argv) HText *htPtr; Tcl_Interp *interp; int argc; char **argv; { char *startPtr, *endPtr; char saved; int textFirst, textLast; textFirst = htPtr->selFirst; textLast = htPtr->selLast; if (textFirst < 0) { textFirst = 0; textLast = htPtr->nChars - 1; } if (argc > 2) { if (GetIndex(htPtr, argv[2], &textFirst) != TCL_OK) { return TCL_ERROR; } } if (argc == 4) { if (GetIndex(htPtr, argv[3], &textLast) != TCL_OK) { return TCL_ERROR; } } if (textLast < textFirst) { Tcl_AppendResult(interp, "first index is greater than last", (char *)NULL); return TCL_ERROR; } startPtr = htPtr->charArr + textFirst; endPtr = htPtr->charArr + (textLast + 1); saved = *endPtr; *endPtr = '\0'; /* Make the line into a string by * changing the * '\n' into a '\0' * before copying */ Tcl_SetResult(interp, startPtr, TCL_VOLATILE); *endPtr = saved; return TCL_OK; } /* *---------------------------------------------------------------------- * * IndexOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int IndexOp(htPtr, interp, argc, argv) HText *htPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { int tindex; if (GetIndex(htPtr, argv[2], &tindex) != TCL_OK) { return TCL_ERROR; } Tcl_SetResult(interp, Blt_Itoa(tindex), TCL_VOLATILE); return TCL_OK; } /* *---------------------------------------------------------------------- * * LinePosOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int LinePosOp(htPtr, interp, argc, argv) HText *htPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { int line, cpos, tindex; char string[200]; if (GetIndex(htPtr, argv[2], &tindex) != TCL_OK) { return TCL_ERROR; } if (GetTextPosition(htPtr, tindex, &line, &cpos) != TCL_OK) { return TCL_ERROR; } sprintf(string, "%d.%d", line, cpos); Tcl_SetResult(interp, string, TCL_VOLATILE); return TCL_OK; } /* * -------------------------------------------------------------- * * TextWidgetCmd -- * * This procedure is invoked to process the Tcl command that * corresponds to a widget managed by this module. See the user * documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * * -------------------------------------------------------------- */ static Blt_OpSpec textOps[] = { {"append", 1, (Blt_Op)AppendOp, 3, 0, "window ?option value?...",}, {"cget", 2, (Blt_Op)CgetOp, 3, 3, "?window? option",}, {"configure", 2, (Blt_Op)ConfigureOp, 2, 0, "?window? ?option value?...",}, {"gotoline", 2, (Blt_Op)GotoOp, 2, 3, "?line?",}, {"index", 1, (Blt_Op)IndexOp, 3, 3, "string",}, {"linepos", 1, (Blt_Op)LinePosOp, 3, 3, "string",}, {"range", 2, (Blt_Op)RangeOp, 2, 4, "?from? ?to?",}, {"scan", 2, (Blt_Op)ScanOp, 4, 4, "oper @x,y",}, {"search", 3, (Blt_Op)SearchOp, 3, 5, "pattern ?from? ?to?",}, {"selection", 3, (Blt_Op)SelectOp, 3, 5, "oper ?index?",}, {"windows", 6, (Blt_Op)WindowsOp, 2, 3, "?pattern?",}, {"xview", 1, (Blt_Op)XViewOp, 2, 5, "?moveto fract? ?scroll number what?",}, {"yview", 1, (Blt_Op)YViewOp, 2, 5, "?moveto fract? ?scroll number what?",}, }; static int nTextOps = sizeof(textOps) / sizeof(Blt_OpSpec); static int TextWidgetCmd(clientData, interp, argc, argv) ClientData clientData; /* Information about hypertext widget. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { Blt_Op proc; int result; HText *htPtr = clientData; proc = Blt_GetOp(interp, nTextOps, textOps, BLT_OP_ARG1, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } Tcl_Preserve(htPtr); result = (*proc) (htPtr, interp, argc, argv); Tcl_Release(htPtr); return result; } /* * -------------------------------------------------------------- * * TextCmd -- * * This procedure is invoked to process the "htext" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * * -------------------------------------------------------------- */ /* ARGSUSED */ static int TextCmd(clientData, interp, argc, argv) ClientData clientData; /* Main window associated with interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { HText *htPtr; Screen *screenPtr; Tk_Window tkwin; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " pathName ?option value?...\"", (char *)NULL); return TCL_ERROR; } htPtr = Blt_Calloc(1, sizeof(HText)); assert(htPtr); tkwin = Tk_MainWindow(interp); tkwin = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *)NULL); if (tkwin == NULL) { Blt_Free(htPtr); return TCL_ERROR; } /* Initialize the new hypertext widget */ Tk_SetClass(tkwin, "Htext"); htPtr->tkwin = tkwin; htPtr->display = Tk_Display(tkwin); htPtr->interp = interp; htPtr->nLines = htPtr->arraySize = 0; htPtr->leader = 1; htPtr->xScrollUnits = htPtr->yScrollUnits = 10; htPtr->nRows = htPtr->nColumns = 0; htPtr->selFirst = htPtr->selLast = -1; htPtr->selAnchor = 0; htPtr->exportSelection = TRUE; htPtr->selBorderWidth = 2; screenPtr = Tk_Screen(htPtr->tkwin); htPtr->maxWidth = WidthOfScreen(screenPtr); htPtr->maxHeight = HeightOfScreen(screenPtr); Blt_InitHashTable(&(htPtr->widgetTable), BLT_ONE_WORD_KEYS); Tk_CreateSelHandler(tkwin, XA_PRIMARY, XA_STRING, TextSelectionProc, htPtr, XA_STRING); Tk_CreateEventHandler(tkwin, ExposureMask | StructureNotifyMask, TextEventProc, htPtr); #if (TK_MAJOR_VERSION > 4) Blt_SetWindowInstanceData(tkwin, htPtr); #endif /* * ----------------------------------------------------------------- * * Create the widget command before configuring the widget. This * is because the "-file" and "-text" options may have embedded * commands that self-reference the widget through the * "$blt_htext(widget)" variable. * * ------------------------------------------------------------------ */ htPtr->cmdToken = Tcl_CreateCommand(interp, argv[1], TextWidgetCmd, htPtr, TextDeleteCmdProc); #ifdef ITCL_NAMESPACES Itk_SetWidgetCommand(htPtr->tkwin, htPtr->cmdToken); #endif if ((Tk_ConfigureWidget(interp, htPtr->tkwin, configSpecs, argc - 2, argv + 2, (char *)htPtr, 0) != TCL_OK) || (ConfigureText(interp, htPtr) != TCL_OK)) { Tk_DestroyWindow(htPtr->tkwin); return TCL_ERROR; } Tcl_SetResult(interp, Tk_PathName(htPtr->tkwin), TCL_VOLATILE); return TCL_OK; } int Blt_HtextInit(interp) Tcl_Interp *interp; { static Blt_CmdSpec cmdSpec = {"htext", TextCmd,}; if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) { return TCL_ERROR; } return TCL_OK; } #endif /* NO_HTEXT */ blt-2.4z.orig/src/bltImage.c0100644000175000017500000022322607526635202014441 0ustar dokodoko /* * bltImage.c -- * * This module implements image processing procedures for the BLT * toolkit. * * Copyright 1997-1998 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. */ #include "bltInt.h" #include "bltImage.h" #include "bltHash.h" #include #ifndef WIN32 #include #endif #define CLAMP(c) ((((c) < 0.0) ? 0.0 : ((c) > 255.0) ? 255.0 : (c))) /* *---------------------------------------------------------------------- * * Blt_CreateColorImage -- * * Allocates a color image of a designated height and width. * * This routine will be augmented with other types of information * such as a color table, etc. * * Results: * Returns the new color image. * *---------------------------------------------------------------------- */ Blt_ColorImage Blt_CreateColorImage(width, height) int width, height; /* Dimensions of new image */ { struct ColorImage *imagePtr; size_t size; size = width * height; imagePtr = Blt_Malloc(sizeof(struct ColorImage)); assert(imagePtr); imagePtr->bits = Blt_Malloc(sizeof(Pix32) * size); assert(imagePtr->bits); imagePtr->width = width; imagePtr->height = height; return imagePtr; } /* *---------------------------------------------------------------------- * * Blt_FreeColorImage -- * * Deallocates the given color image. * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_FreeColorImage(imagePtr) struct ColorImage *imagePtr; { Blt_Free(imagePtr->bits); Blt_Free(imagePtr); } void Blt_GammaCorrectColorImage(src, newGamma) Blt_ColorImage src; double newGamma; { unsigned int nPixels; register Pix32 *srcPtr, *endPtr; register unsigned int i; double value; unsigned char lut[256]; double invGamma; invGamma = 1.0 / newGamma; for (i = 0; i < 256; i++) { value = 255.0 * pow((double)i / 255.0, invGamma); lut[i] = (unsigned char)CLAMP(value); } nPixels = Blt_ColorImageWidth(src) * Blt_ColorImageHeight(src); srcPtr = Blt_ColorImageBits(src); for (endPtr = srcPtr + nPixels; srcPtr < endPtr; srcPtr++) { srcPtr->Red = lut[srcPtr->Red]; srcPtr->Green = lut[srcPtr->Green]; srcPtr->Blue = lut[srcPtr->Blue]; } } /* *---------------------------------------------------------------------- * * Blt_ColorImageToGreyscale -- * * Converts a color image to PostScript grey scale (1 component) * output. Luminosity isn't computed using the old NTSC formula, * * Y = 0.299 * Red + 0.587 * Green + 0.114 * Blue * * but the following * * Y = 0.212671 * Red + 0.715160 * Green + 0.072169 * Blue * * which better represents contemporary monitors. * * Results: * The color image is converted to greyscale. * *---------------------------------------------------------------------- */ void Blt_ColorImageToGreyscale(image) Blt_ColorImage image; { register Pix32 *srcPtr, *endPtr; double Y; int nPixels; int width, height; width = Blt_ColorImageWidth(image); height = Blt_ColorImageHeight(image); nPixels = width * height; srcPtr = Blt_ColorImageBits(image); for (endPtr = srcPtr + nPixels; srcPtr < endPtr; srcPtr++) { Y = ((0.212671 * (double)srcPtr->Red) + (0.715160 * (double)srcPtr->Green) + (0.072169 * (double)srcPtr->Blue)); srcPtr->Red = srcPtr->Green = srcPtr->Blue = (unsigned char)CLAMP(Y); } } /* *---------------------------------------------------------------------- * * Blt_ColorImageToPhoto -- * * Translates a color image into a Tk photo. * * Results: * The photo is re-written with the new color image. * *---------------------------------------------------------------------- */ void Blt_ColorImageToPhoto(src, photo) Blt_ColorImage src; /* Image to use as source */ Tk_PhotoHandle photo; /* Photo to write color image into */ { Tk_PhotoImageBlock dest; int width, height; width = Blt_ColorImageWidth(src); height = Blt_ColorImageHeight(src); Tk_PhotoGetImage(photo, &dest); dest.pixelSize = sizeof(Pix32); dest.pitch = sizeof(Pix32) * width; dest.width = width; dest.height = height; dest.offset[0] = Tk_Offset(Pix32, Red); dest.offset[1] = Tk_Offset(Pix32, Green); dest.offset[2] = Tk_Offset(Pix32, Blue); dest.offset[3] = Tk_Offset(Pix32, Alpha); dest.pixelPtr = (unsigned char *)Blt_ColorImageBits(src); Tk_PhotoSetSize(photo, width, height); Tk_PhotoPutBlock(photo, &dest, 0, 0, width, height); } /* *---------------------------------------------------------------------- * * Blt_PhotoRegionToColorImage -- * * Create a photo to a color image. * * Results: * The new color image is returned. * *---------------------------------------------------------------------- */ Blt_ColorImage Blt_PhotoRegionToColorImage(photo, x, y, width, height) Tk_PhotoHandle photo; /* Source photo image to scale */ int x, y; int width, height; { Tk_PhotoImageBlock src; Blt_ColorImage image; register Pix32 *destPtr; register unsigned char *srcData; register int offset; unsigned int offR, offG, offB, offA; Tk_PhotoGetImage(photo, &src); if (x < 0) { x = 0; } if (y < 0) { y = 0; } if (width < 0) { width = src.width; } if (height < 0) { height = src.height; } if ((x + width) > src.width) { width = src.width - x; } if ((height + y) > src.height) { height = src.width - y; } image = Blt_CreateColorImage(width, height); destPtr = Blt_ColorImageBits(image); offset = (x * src.pixelSize) + (y * src.pitch); offR = src.offset[0]; offG = src.offset[1]; offB = src.offset[2]; offA = src.offset[3]; if (src.pixelSize == 4) { for (y = 0; y < height; y++) { srcData = src.pixelPtr + offset; for (x = 0; x < width; x++) { destPtr->Red = srcData[offR]; destPtr->Green = srcData[offG]; destPtr->Blue = srcData[offB]; destPtr->Alpha = srcData[offA]; srcData += src.pixelSize; destPtr++; } offset += src.pitch; } } else if (src.pixelSize == 3) { for (y = 0; y < height; y++) { srcData = src.pixelPtr + offset; for (x = 0; x < width; x++) { destPtr->Red = srcData[offR]; destPtr->Green = srcData[offG]; destPtr->Blue = srcData[offB]; /* No transparency information */ destPtr->Alpha = (unsigned char)-1; srcData += src.pixelSize; destPtr++; } offset += src.pitch; } } else { for (y = 0; y < height; y++) { srcData = src.pixelPtr + offset; for (x = 0; x < width; x++) { destPtr->Red = destPtr->Green = destPtr->Blue = srcData[offA]; /* No transparency information */ destPtr->Alpha = (unsigned char)-1; srcData += src.pixelSize; destPtr++; } offset += src.pitch; } } return image; } /* *---------------------------------------------------------------------- * * Blt_PhotoToColorImage -- * * Create a photo to a color image. * * Results: * The new color image is returned. * *---------------------------------------------------------------------- */ Blt_ColorImage Blt_PhotoToColorImage(photo) Tk_PhotoHandle photo; /* Source photo image to scale */ { Blt_ColorImage image; Tk_PhotoImageBlock src; int width, height; register Pix32 *destPtr; register int offset; register int x, y; register unsigned char *srcData; Tk_PhotoGetImage(photo, &src); width = src.width; height = src.height; image = Blt_CreateColorImage(width, height); destPtr = Blt_ColorImageBits(image); offset = 0; if (src.pixelSize == 4) { for (y = 0; y < height; y++) { srcData = src.pixelPtr + offset; for (x = 0; x < width; x++) { destPtr->Red = srcData[src.offset[0]]; destPtr->Green = srcData[src.offset[1]]; destPtr->Blue = srcData[src.offset[2]]; destPtr->Alpha = srcData[src.offset[3]]; srcData += src.pixelSize; destPtr++; } offset += src.pitch; } } else if (src.pixelSize == 3) { for (y = 0; y < height; y++) { srcData = src.pixelPtr + offset; for (x = 0; x < width; x++) { destPtr->Red = srcData[src.offset[0]]; destPtr->Green = srcData[src.offset[1]]; destPtr->Blue = srcData[src.offset[2]]; /* No transparency information */ destPtr->Alpha = (unsigned char)-1; srcData += src.pixelSize; destPtr++; } offset += src.pitch; } } else { for (y = 0; y < height; y++) { srcData = src.pixelPtr + offset; for (x = 0; x < width; x++) { destPtr->Red = destPtr->Green = destPtr->Blue = srcData[src.offset[0]]; /* No transparency information */ destPtr->Alpha = (unsigned char)-1; srcData += src.pixelSize; destPtr++; } offset += src.pitch; } } return image; } /* * filter function definitions */ static ResampleFilterProc DefaultFilter; static ResampleFilterProc BellFilter; static ResampleFilterProc BesselFilter; static ResampleFilterProc BoxFilter; static ResampleFilterProc BSplineFilter; static ResampleFilterProc CatRomFilter; static ResampleFilterProc DummyFilter; static ResampleFilterProc GaussianFilter; static ResampleFilterProc GiFilter; static ResampleFilterProc Lanczos3Filter; static ResampleFilterProc MitchellFilter; static ResampleFilterProc SincFilter; static ResampleFilterProc TriangleFilter; static Tk_ImageChangedProc TempImageChangedProc; static double DefaultFilter(x) double x; { if (x < 0.0) { x = -x; } if (x < 1.0) { /* f(x) = 2x^3 - 3x^2 + 1, -1 <= x <= 1 */ return (2.0 * x - 3.0) * x * x + 1.0; } return 0.0; } /* Just for testing */ static double DummyFilter(x) double x; { return FABS(x); } /* * * Finite filters in increasing order: * Box (constant) * Triangle (linear) * Bell * BSpline (cubic) * */ static double BoxFilter(x) double x; { if ((x < -0.5) || (x > 0.5)) { return 0.0; } return 1.0; } static double TriangleFilter(x) double x; { if (x < 0.0) { x = -x; } if (x < 1.0) { return (1.0 - x); } return 0.0; } static double BellFilter(x) double x; { if (x < 0.0) { x = -x; } if (x < 0.5) { return (0.75 - (x * x)); } if (x < 1.5) { x = (x - 1.5); return (0.5 * (x * x)); } return 0.0; } static double BSplineFilter(x) double x; { double x2; if (x < 0.0) { x = -x; } if (x < 1) { x2 = x * x; return ((.5 * x2 * x) - x2 + (2.0 / 3.0)); } else if (x < 2) { x = 2 - x; return ((x * x * x) / 6.0); } return 0.0; } /* * * Infinite Filters: * Sinc perfect lowpass filter * Bessel circularly symmetric 2-D filter * Gaussian * Lanczos3 * Mitchell */ static double SincFilter(x) double x; { x *= M_PI; if (x == 0.0) { return 1.0; } return (sin(x) / x); } static double BesselFilter(x) double x; { #ifdef NEED_DECL_J1 extern double j1 _ANSI_ARGS_((double value)); #endif /* * See Pratt "Digital Image Processing" p. 97 for Bessel functions * zeros are at approx x=1.2197, 2.2331, 3.2383, 4.2411, 5.2428, 6.2439, * 7.2448, 8.2454 */ #ifdef __BORLANDC__ return 0.0; #else return (x == 0.0) ? M_PI / 4.0 : j1(M_PI * x) / (x + x); #endif } #define SQRT_2PI 0.79788456080286541 /* sqrt(2.0 / M_PI) */ static double GaussianFilter(x) double x; { return exp(-2.0 * x * x) * SQRT_2PI; } static double Lanczos3Filter(x) double x; { if (x < 0) { x = -x; } if (x < 3.0) { return (SincFilter(x) * SincFilter(x / 3.0)); } return 0.0; } #define B 0.3333333333333333 /* (1.0 / 3.0) */ #define C 0.3333333333333333 /* (1.0 / 3.0) */ static double MitchellFilter(x) double x; { double x2; x2 = x * x; if (x < 0) { x = -x; } if (x < 1.0) { x = (((12.0 - 9.0 * B - 6.0 * C) * (x * x2)) + ((-18.0 + 12.0 * B + 6.0 * C) * x2) + (6.0 - 2 * B)); return (x / 6.0); } else if (x < 2.0) { x = (((-1.0 * B - 6.0 * C) * (x * x2)) + ((6.0 * B + 30.0 * C) * x2) + ((-12.0 * B - 48.0 * C) * x) + (8.0 * B + 24 * C)); return (x / 6.0); } return 0.0; } /* * Catmull-Rom spline */ static double CatRomFilter(x) double x; { if (x < -2.) { return 0.0; } if (x < -1.0) { return 0.5 * (4.0 + x * (8.0 + x * (5.0 + x))); } if (x < 0.0) { return 0.5 * (2.0 + x * x * (-5.0 + x * -3.0)); } if (x < 1.0) { return 0.5 * (2.0 + x * x * (-5.0 + x * 3.0)); } if (x < 2.0) { return 0.5 * (4.0 + x * (-8.0 + x * (5.0 - x))); } return 0.0; } /* approximation to the gaussian integral [x, inf) */ static double GiFilter(x) double x; { if (x > 1.5) { return 0.0; } else if (x < -1.5) { return 1.0; } else { #define I6 0.166666666666667 #define I4 0.25 #define I3 0.333333333333333 double x2 = x * x; double x3 = x2 * x; if (x > 0.5) { return .5625 - ( x3 * I6 - 3 * x2 * I4 + 1.125 * x); } else if (x > -0.5) { return 0.5 - (0.75 * x - x3 * I3); } else { return 0.4375 + (-x3 * I6 - 3 * x2 * I4 - 1.125 * x); } } } static ResampleFilter filterTable[] = { /* name, function, support */ {"bell", BellFilter, 1.5 }, {"bessel", BesselFilter, 3.2383 }, {"box", BoxFilter, 0.5 }, {"bspline", BSplineFilter, 2.0 }, {"catrom", CatRomFilter, 2.0 }, {"default", DefaultFilter, 1.0 }, {"dummy", DummyFilter, 0.5 }, {"gauss8", GaussianFilter, 8.0 }, {"gaussian", GaussianFilter, 1.25 }, {"gi", GiFilter, 1.25 }, {"lanczos3", Lanczos3Filter, 3.0 }, {"mitchell", MitchellFilter, 2.0 }, {"none", (ResampleFilterProc *)NULL, 0.0 }, {"sinc", SincFilter, 4.0 }, {"triangle", TriangleFilter, 1.0 }, }; static int nFilters = sizeof(filterTable) / sizeof(ResampleFilter); ResampleFilter *bltBoxFilterPtr = &(filterTable[1]); /* *---------------------------------------------------------------------- * * Blt_GetResampleFilter -- * * Finds a 1-D filter associated by the given filter name. * * Results: * A standard Tcl result. Returns TCL_OK is the filter was * found. The filter information (proc and support) is returned * via filterPtrPtr. Otherwise TCL_ERROR is returned and an error * message is left in interp->result. * *---------------------------------------------------------------------- */ int Blt_GetResampleFilter(interp, name, filterPtrPtr) Tcl_Interp *interp; char *name; ResampleFilter **filterPtrPtr; { ResampleFilter *filterPtr, *endPtr; endPtr = filterTable + nFilters; for (filterPtr = filterTable; filterPtr < endPtr; filterPtr++) { if (strcmp(name, filterPtr->name) == 0) { *filterPtrPtr = (filterPtr->proc == NULL) ? NULL : filterPtr; return TCL_OK; } } Tcl_AppendResult(interp, "can't find filter \"", name, "\"", (char *)NULL); return TCL_ERROR; } /* * Scaled integers are fixed point values. The upper 18 bits is the integer * portion, the lower 14 bits the fractional remainder. Must be careful * not to overflow the values (especially during multiplication). * * The following operations are defined: * * S * n Scaled integer times an integer. * S1 + S2 Scaled integer plus another scaled integer. * */ #define float2si(f) (int)((f) * 16384.0 + 0.5) #define uchar2si(b) (((int)(b)) << 14) #define si2int(s) (((s) + 8192) >> 14) #ifdef notdef typedef struct { int pixel; union Weight { int i; /* Fixed point, scaled integer. */ float f; } weight; } Sample; typedef struct { int count; /* Number of contributors */ Sample *samples; /* Array of contributors */ } Contribution; typedef struct { int pixel; union Weight { int i; /* Fixed point, scaled integer. */ float f; } weight; } Sample; #endif typedef union { int i; /* Fixed point, scaled integer. */ float f; } Weight; typedef struct { int count; /* Number of samples. */ int start; Weight weights[1]; /* Array of weights. */ } Sample; static size_t ComputeWeights(srcWidth, destWidth, filterPtr, samplePtrPtr) int srcWidth, destWidth; ResampleFilter *filterPtr; Sample **samplePtrPtr; { Sample *samples; double scale; int filterSize; double center; register Sample *s; register Weight *weight; register int x, i; register int left, right; /* filter bounds */ double factor, sum; size_t size; /* Pre-calculate filter contributions for a row */ scale = (double)destWidth / (double)srcWidth; if (scale < 1.0) { double radius, fscale; /* Downsample */ radius = filterPtr->support / scale; fscale = 1.0 / scale; filterSize = (int)(radius * 2 + 2); size = sizeof(Sample) + (filterSize - 1) * sizeof(Weight); samples = Blt_Calloc(destWidth, size); assert(samples); s = samples; for (x = 0; x < destWidth; x++) { center = (double)x * fscale; /* Determine bounds of filter and its density */ left = (int)(center - radius + 0.5); if (left < 0) { left = 0; } right = (int)(center + radius + 0.5); if (right >= srcWidth) { right = srcWidth - 1; } sum = 0.0; s->start = left; for (weight = s->weights, i = left; i <= right; i++, weight++) { weight->f = (float) (*filterPtr->proc) (((double)i + 0.5 - center) * scale); sum += weight->f; } s->count = right - left + 1; factor = (sum == 0.0) ? 1.0 : (1.0 / sum); for (weight = s->weights, i = left; i <= right; i++, weight++) { weight->f = (float)(weight->f * factor); weight->i = float2si(weight->f); } s = (Sample *)((char *)s + size); } } else { double fscale; /* Upsample */ filterSize = (int)(filterPtr->support * 2 + 2); size = sizeof(Sample) + (filterSize - 1) * sizeof(Weight); samples = Blt_Calloc(destWidth, size); assert(samples); fscale = 1.0 / scale; s = samples; for (x = 0; x < destWidth; x++) { center = (double)x * fscale; left = (int)(center - filterPtr->support + 0.5); if (left < 0) { left = 0; } right = (int)(center + filterPtr->support + 0.5); if (right >= srcWidth) { right = srcWidth - 1; } sum = 0.0; s->start = left; for (weight = s->weights, i = left; i <= right; i++, weight++) { weight->f = (float) (*filterPtr->proc) ((double)i - center + 0.5); sum += weight->f; } s->count = right - left + 1; factor = (sum == 0.0) ? 1.0 : (1.0 / sum); for (weight = s->weights, i = left; i <= right; i++, weight++) { weight->f = (float)(weight->f * factor); weight->i = float2si(weight->f); } s = (Sample *)((char *)s + size); } } *samplePtrPtr = samples; return size; } /* * The following macro converts a fixed-point scaled integer to a * byte, clamping the value between 0 and 255. */ #define SICLAMP(s) \ (unsigned char)(((s) < 0) ? 0 : ((s) > 4177920) ? 255 : (si2int(s))) static void ZoomImageVertically(src, dest, filterPtr) Blt_ColorImage src, dest; ResampleFilter *filterPtr; { Sample *samples, *s, *endPtr; int destWidth, destHeight; int red, green, blue, alpha; int srcWidth, srcHeight; register Pix32 *srcColumnPtr; register Pix32 *srcPtr, *destPtr; register Weight *weight; int x, i; size_t size; /* Size of sample. */ srcWidth = Blt_ColorImageWidth(src); srcHeight = Blt_ColorImageHeight(src); destWidth = Blt_ColorImageWidth(dest); destHeight = Blt_ColorImageHeight(dest); /* Pre-calculate filter contributions for a row */ size = ComputeWeights(srcHeight, destHeight, filterPtr, &samples); endPtr = (Sample *)((char *)samples + (destHeight * size)); /* Apply filter to zoom vertically from tmp to destination */ for (x = 0; x < srcWidth; x++) { srcColumnPtr = Blt_ColorImageBits(src) + x; destPtr = Blt_ColorImageBits(dest) + x; for (s = samples; s < endPtr; s = (Sample *)((char *)s + size)) { red = green = blue = alpha = 0; srcPtr = srcColumnPtr + (s->start * srcWidth); for (weight = s->weights, i = 0; i < s->count; i++, weight++) { red += srcPtr->Red * weight->i; green += srcPtr->Green * weight->i; blue += srcPtr->Blue * weight->i; alpha += srcPtr->Alpha * weight->i; srcPtr += srcWidth; } destPtr->Red = SICLAMP(red); destPtr->Green = SICLAMP(green); destPtr->Blue = SICLAMP(blue); destPtr->Alpha = SICLAMP(alpha); destPtr += destWidth; } } /* Free the memory allocated for filter weights */ Blt_Free(samples); } static void ZoomImageHorizontally(src, dest, filterPtr) Blt_ColorImage src, dest; ResampleFilter *filterPtr; { Sample *samples, *s, *endPtr; Weight *weight; int destWidth; int red, green, blue, alpha; int srcWidth, srcHeight; int y, i; register Pix32 *srcPtr, *destPtr; register Pix32 *srcRowPtr; size_t size; /* Size of sample. */ srcWidth = Blt_ColorImageWidth(src); srcHeight = Blt_ColorImageHeight(src); destWidth = Blt_ColorImageWidth(dest); /* Pre-calculate filter contributions for a row */ size = ComputeWeights(srcWidth, destWidth, filterPtr, &samples); endPtr = (Sample *)((char *)samples + (destWidth * size)); /* Apply filter to zoom horizontally from srcPtr to tmpPixels */ srcRowPtr = Blt_ColorImageBits(src); destPtr = Blt_ColorImageBits(dest); for (y = 0; y < srcHeight; y++) { for (s = samples; s < endPtr; s = (Sample *)((char *)s + size)) { red = green = blue = alpha = 0; srcPtr = srcRowPtr + s->start; for (weight = s->weights, i = 0; i < s->count; i++, weight++) { red += srcPtr->Red * weight->i; green += srcPtr->Green * weight->i; blue += srcPtr->Blue * weight->i; alpha += srcPtr->Alpha * weight->i; srcPtr++; } destPtr->Red = SICLAMP(red); destPtr->Green = SICLAMP(green); destPtr->Blue = SICLAMP(blue); destPtr->Alpha = SICLAMP(alpha); destPtr++; } srcRowPtr += srcWidth; } /* free the memory allocated for horizontal filter weights */ Blt_Free(samples); } /* *---------------------------------------------------------------------- * * Blt_ResampleColorImage -- * * Resamples a given color image using 1-D filters and returns * a new color image of the designated size. * * Results: * Returns the resampled color image. The original color image * is left intact. * *---------------------------------------------------------------------- */ Blt_ColorImage Blt_ResampleColorImage(src, width, height, horzFilterPtr, vertFilterPtr) Blt_ColorImage src; int width, height; ResampleFilter *horzFilterPtr, *vertFilterPtr; { Blt_ColorImage tmp, dest; /* * It's usually faster to zoom vertically last. This has to do * with the fact that images are stored in contiguous rows. */ tmp = Blt_CreateColorImage(width, Blt_ColorImageHeight(src)); ZoomImageHorizontally(src, tmp, horzFilterPtr); dest = Blt_CreateColorImage(width, height); ZoomImageVertically(tmp, dest, vertFilterPtr); Blt_FreeColorImage(tmp); return dest; } /* *---------------------------------------------------------------------- * * Blt_ResamplePhoto -- * * Resamples a Tk photo image using 1-D filters and writes the * image into another Tk photo. It is possible for the * source and destination to be the same photo. * * Results: * The designated destination photo will contain the resampled * color image. The original photo is left intact. * *---------------------------------------------------------------------- */ void Blt_ResamplePhoto(srcPhoto, x, y, width, height, destPhoto, horzFilterPtr, vertFilterPtr) Tk_PhotoHandle srcPhoto; /* Source photo image to scale */ int x, y; int width, height; Tk_PhotoHandle destPhoto; /* Resulting scaled photo image */ ResampleFilter *horzFilterPtr, *vertFilterPtr; { Blt_ColorImage srcImage, destImage; Tk_PhotoImageBlock dest; Tk_PhotoGetImage(destPhoto, &dest); srcImage = Blt_PhotoRegionToColorImage(srcPhoto, x, y, width, height); destImage = Blt_ResampleColorImage(srcImage, dest.width, dest.height, horzFilterPtr, vertFilterPtr); Blt_FreeColorImage(srcImage); Blt_ColorImageToPhoto(destImage, destPhoto); Blt_FreeColorImage(destImage); } /* *---------------------------------------------------------------------- * * Blt_ResizePhoto -- * * Scales the region of the source image to the size of the * destination image. This routine performs raw scaling of * the image and unlike Blt_ResamplePhoto does not handle * aliasing effects from subpixel sampling. It is possible * for the source and destination to be the same photo. * * Results: * The designated destination photo will contain the resampled * color image. The original photo is left intact. * *---------------------------------------------------------------------- */ void Blt_ResizePhoto(srcPhoto, x, y, width, height, destPhoto) Tk_PhotoHandle srcPhoto; /* Source photo image to scaled. */ register int x, y; /* Region of source photo to be * scaled. */ int width, height; Tk_PhotoHandle destPhoto; /* (out) Resulting scaled photo image. * Scaling factors are derived from * the destination photo's * dimensions. */ { double xScale, yScale; Blt_ColorImage destImage; Pix32 *destPtr; Tk_PhotoImageBlock src, dest; unsigned char *srcPtr, *srcRowPtr; int *mapX, *mapY; register int sx, sy; int left, right, top, bottom; Tk_PhotoGetImage(srcPhoto, &src); Tk_PhotoGetImage(destPhoto, &dest); left = x, top = y, right = x + width - 1, bottom = y + height - 1; destImage = Blt_CreateColorImage(dest.width, dest.height); xScale = (double)width / (double)dest.width; yScale = (double)height / (double)dest.height; mapX = (int *)Blt_Malloc(sizeof(int) * dest.width); mapY = (int *)Blt_Malloc(sizeof(int) * dest.height); for(x = 0; x < dest.width; x++) { sx = (int)(xScale * (double)(x + left)); if (sx > right) { sx = right; } mapX[x] = sx; } for(y = 0; y < dest.height; y++) { sy = (int)(yScale * (double)(y + top)); if (sy > bottom) { sy = bottom; } mapY[y] = sy; } destPtr = Blt_ColorImageBits(destImage); if (src.pixelSize == 4) { for (y = 0; y < dest.height; y++) { srcRowPtr = src.pixelPtr + (mapY[y] * src.pitch); for (x = 0; x < dest.width; x++) { srcPtr = srcRowPtr + (mapX[x] * src.pixelSize); destPtr->Red = srcPtr[src.offset[0]]; destPtr->Green = srcPtr[src.offset[1]]; destPtr->Blue = srcPtr[src.offset[2]]; destPtr->Alpha = srcPtr[src.offset[3]]; destPtr++; } } } else if (src.pixelSize == 3) { for (y = 0; y < dest.height; y++) { srcRowPtr = src.pixelPtr + (mapY[y] * src.pitch); for (x = 0; x < dest.width; x++) { srcPtr = srcRowPtr + (mapX[x] * src.pixelSize); destPtr->Red = srcPtr[src.offset[0]]; destPtr->Green = srcPtr[src.offset[1]]; destPtr->Blue = srcPtr[src.offset[2]]; destPtr->Alpha = (unsigned char)-1; destPtr++; } } } else { for (y = 0; y < dest.height; y++) { srcRowPtr = src.pixelPtr + (mapY[y] * src.pitch); for (x = 0; x < dest.width; x++) { srcPtr = srcRowPtr + (mapX[x] * src.pixelSize); destPtr->Red = destPtr->Green = destPtr->Blue = srcPtr[src.offset[0]]; destPtr->Alpha = (unsigned char)-1; destPtr++; } } } Blt_Free(mapX); Blt_Free(mapY); Blt_ColorImageToPhoto(destImage, destPhoto); Blt_FreeColorImage(destImage); } /* *---------------------------------------------------------------------- * * Blt_ResizeColorImage -- * * Scales the region of the source image to the size of the * destination image. This routine performs raw scaling of * the image and unlike Blt_ResamplePhoto does not perform * any antialiasing. * * Results: * Returns the new resized color image. The original image * is left intact. * *---------------------------------------------------------------------- */ Blt_ColorImage Blt_ResizeColorImage(src, x, y, width, height, destWidth, destHeight) Blt_ColorImage src; /* Source color image to be scaled. */ register int x, y; /* Region of source image to scaled. */ int width, height; int destWidth, destHeight; /* Requested dimensions of the scaled * image. */ { register int sx, sy; double xScale, yScale; Blt_ColorImage dest; Pix32 *srcPtr, *srcRowPtr, *destPtr; int *mapX, *mapY; int left, right, top, bottom; left = x, top = y; right = x + width - 1, bottom = y + height - 1; dest = Blt_CreateColorImage(destWidth, destHeight); xScale = (double)width / (double)destWidth; yScale = (double)height / (double)destHeight; mapX = (int *)Blt_Malloc(sizeof(int) * destWidth); mapY = (int *)Blt_Malloc(sizeof(int) * destHeight); for(x = 0; x < destWidth; x++) { sx = (int)(xScale * (double)(x + left)); if (sx > right) { sx = right; } mapX[x] = sx; } for(y = 0; y < destHeight; y++) { sy = (int)(yScale * (double)(y + top)); if (sy > bottom) { sy = bottom; } mapY[y] = sy; } destPtr = Blt_ColorImageBits(dest); for (y = 0; y < destHeight; y++) { srcRowPtr = Blt_ColorImageBits(src) + (Blt_ColorImageWidth(src) * mapY[y]); for (x = 0; x < destWidth; x++) { srcPtr = srcRowPtr + mapX[x]; destPtr->value = srcPtr->value; /* Copy the pixel. */ destPtr++; } } Blt_Free(mapX); Blt_Free(mapY); return dest; } /* *---------------------------------------------------------------------- * * Blt_ResizeColorSubimage -- * * Scales the region of the source image to the size of the * destination image. This routine performs raw scaling of * the image and unlike Blt_ResamplePhoto does not perform * any antialiasing. * * Results: * Returns the new resized color image. The original image * is left intact. * *---------------------------------------------------------------------- */ Blt_ColorImage Blt_ResizeColorSubimage( Blt_ColorImage src, /* Source color image to be scaled. */ int regionX, int regionY, /* Offset of subimage in destination. */ int regionWidth, /* Dimension of subimage. */ int regionHeight, int destWidth, int destHeight) /* Dimensions of the entire scaled image. */ { Blt_ColorImage dest; Pix32 *srcPtr, *srcRowPtr, *destPtr; double xScale, yScale; int *mapX, *mapY; int srcWidth, srcHeight; register int sx, sy; register int x, y; srcWidth = Blt_ColorImageWidth(src); srcHeight = Blt_ColorImageHeight(src); xScale = (double)srcWidth / (double)destWidth; yScale = (double)srcHeight / (double)destHeight; mapX = Blt_Malloc(sizeof(int) * regionWidth); mapY = Blt_Malloc(sizeof(int) * regionHeight); /* Precompute scaling factors for each row and column. */ for(x = 0; x < regionWidth; x++) { sx = (int)(xScale * (double)(x + regionX)); if (sx >= srcWidth) { sx = srcWidth - 1; } mapX[x] = sx; } for(y = 0; y < regionHeight; y++) { sy = (int)(yScale * (double)(y + regionY)); if (sy > srcHeight) { sy = srcHeight - 1; } mapY[y] = sy; } dest = Blt_CreateColorImage(regionWidth, regionHeight); destPtr = Blt_ColorImageBits(dest); for (y = 0; y < regionHeight; y++) { srcRowPtr = Blt_ColorImageBits(src) + (Blt_ColorImageWidth(src) * mapY[y]); for (x = 0; x < regionWidth; x++) { srcPtr = srcRowPtr + mapX[x]; destPtr->value = srcPtr->value; /* Copy the pixel. */ destPtr++; } } Blt_Free(mapX); Blt_Free(mapY); return dest; } /* * FIXME: Boundary handling could be better (pixels are replicated). * It's slow. Take boundary tests out of inner loop. */ Blt_ColorImage Blt_ConvolveColorImage(src, filterPtr) Blt_ColorImage src; Filter2D *filterPtr; { Blt_ColorImage dest; register Pix32 *srcPtr, *destPtr; #define MAXROWS 24 register int sx, sy, dx, dy; register int x, y; double red, green, blue; int width, height; int radius; register double *valuePtr; width = Blt_ColorImageWidth(src); height = Blt_ColorImageHeight(src); dest = Blt_CreateColorImage(width, height); radius = (int)filterPtr->support; if (radius < 1) { radius = 1; } destPtr = Blt_ColorImageBits(dest); for (dy = 0; dy < height; dy++) { for (dx = 0; dx < width; dx++) { red = green = blue = 0.0; valuePtr = filterPtr->kernel; for (sy = (dy - radius); sy <= (dy + radius); sy++) { y = sy; if (y < 0) { y = 0; } else if (y >= height) { y = height - 1; } for (sx = (dx - radius); sx <= (dx + radius); sx++) { x = sx; if (x < 0) { x = 0; } else if (sx >= width) { x = width - 1; } srcPtr = Blt_ColorImagePixel(src, x, y); red += *valuePtr * (double)srcPtr->Red; green += *valuePtr * (double)srcPtr->Green; blue += *valuePtr * (double)srcPtr->Blue; #ifdef notdef fprintf(stderr, "%d,%d = r=%f,g=%f,b=%f\n", x, y, red, green, blue); #endif valuePtr++; } } red /= filterPtr->sum; green /= filterPtr->sum; blue /= filterPtr->sum; destPtr->Red = (unsigned char)CLAMP(red); destPtr->Green = (unsigned char)CLAMP(green); destPtr->Blue = (unsigned char)CLAMP(blue); destPtr->Alpha = (unsigned char)-1; destPtr++; } } return dest; } /* *---------------------------------------------------------------------- * * Blt_SnapPhoto -- * * Takes a snapshot of an X drawable (pixmap or window) and * writes it to an existing Tk photo image. * * Results: * A standard Tcl result. * * Side Effects: * The named Tk photo is updated with the snapshot. * *---------------------------------------------------------------------- */ int Blt_SnapPhoto(interp, tkwin, drawable, x, y, width, height, destWidth, destHeight, photoName, inputGamma) Tcl_Interp *interp; /* Interpreter to report errors back to */ Tk_Window tkwin; Drawable drawable; /* Window or pixmap to be snapped */ int x, y; /* Offset of image from drawable origin. */ int width, height; /* Dimension of the drawable */ int destWidth, destHeight; /* Desired size of the Tk photo */ char *photoName; /* Name of an existing Tk photo image. */ double inputGamma; { Tk_PhotoHandle photo; /* The photo image to write into. */ Blt_ColorImage image; photo = Blt_FindPhoto(interp, photoName); if (photo == NULL) { Tcl_AppendResult(interp, "can't find photo \"", photoName, "\"", (char *)NULL); return TCL_ERROR; } image = Blt_DrawableToColorImage(tkwin, drawable, x, y, width, height, inputGamma); if (image == NULL) { Tcl_AppendResult(interp, "can't grab window or pixmap (possibly obscured?)", (char *)NULL); return TCL_ERROR; /* Can't grab window image */ } if ((destWidth != width) || (destHeight != height)) { Blt_ColorImage destImage; /* * The requested size for the destination image is different than * that of the source snapshot. Resample the image as necessary. * We'll use a cheap box filter. I'm assuming that the destination * image will typically be smaller than the original. */ destImage = Blt_ResampleColorImage(image, destWidth, destHeight, bltBoxFilterPtr, bltBoxFilterPtr); Blt_FreeColorImage(image); image = destImage; } Blt_ColorImageToPhoto(image, photo); Blt_FreeColorImage(image); return TCL_OK; } #if HAVE_JPEG /* *---------------------------------------------------------------------- * * Blt_JPEGToPhoto -- * * Reads a JPEG file and converts it into a Tk photo. * * Results: * A standard Tcl result. If successful, TCL_OK is returned * and the designated photo is re-written with the image. * Otherwise, TCL_ERROR is returned and interp->result will * contain an error message. * *---------------------------------------------------------------------- */ int Blt_JPEGToPhoto(interp, fileName, photo) Tcl_Interp *interp; char *fileName; Tk_PhotoHandle photo; /* The photo image to write into. */ { Blt_ColorImage image; image = Blt_JPEGToColorImage(interp, fileName); if (image == NULL) { return TCL_ERROR; } Blt_ColorImageToPhoto(image, photo); Blt_FreeColorImage(image); return TCL_OK; } #endif /* HAVE_JPEG */ /* * -------------------------------------------------------------------------- * * ShearY -- * * Shears a row horizontally. Antialiasing limited to filtering * two adjacent pixels. So the shear angle must be between +-45 * degrees. * * Results: * None. * * Side Effects: * The sheared image is drawn into the destination color image. * * -------------------------------------------------------------------------- */ static void ShearY(src, dest, y, offset, frac, bgColor) Blt_ColorImage src, dest; int y; /* Designates the row to be sheared */ int offset; /* Difference between of */ double frac; Pix32 bgColor; { Pix32 *srcPtr, *destPtr; Pix32 *srcRowPtr, *destRowPtr; register int x, dx; int destWidth; int srcWidth; int red, blue, green, alpha; int leftRed, leftGreen, leftBlue, leftAlpha; int oldLeftRed, oldLeftGreen, oldLeftBlue, oldLeftAlpha; int ifrac; srcWidth = Blt_ColorImageWidth(src); destWidth = Blt_ColorImageWidth(dest); destRowPtr = Blt_ColorImageBits(dest) + (y * destWidth); srcRowPtr = Blt_ColorImageBits(src) + (y * srcWidth); destPtr = destRowPtr; for (x = 0; x < offset; x++) { *destPtr++ = bgColor; } destPtr = destRowPtr + offset; srcPtr = srcRowPtr; dx = offset; oldLeftRed = uchar2si(bgColor.Red); oldLeftGreen = uchar2si(bgColor.Green); oldLeftBlue = uchar2si(bgColor.Blue); oldLeftAlpha = uchar2si(bgColor.Alpha); ifrac = float2si(frac); for (x = 0; x < srcWidth; x++, dx++) { /* Loop through row pixels */ leftRed = srcPtr->Red * ifrac; leftGreen = srcPtr->Green * ifrac; leftBlue = srcPtr->Blue * ifrac; leftAlpha = srcPtr->Alpha * ifrac; if ((dx >= 0) && (dx < destWidth)) { red = uchar2si(srcPtr->Red) - (leftRed - oldLeftRed); green = uchar2si(srcPtr->Green) - (leftGreen - oldLeftGreen); blue = uchar2si(srcPtr->Blue) - (leftBlue - oldLeftBlue); alpha = uchar2si(srcPtr->Alpha) - (leftAlpha - oldLeftAlpha); destPtr->Red = SICLAMP(red); destPtr->Green = SICLAMP(green); destPtr->Blue = SICLAMP(blue); destPtr->Alpha = SICLAMP(alpha); } oldLeftRed = leftRed; oldLeftGreen = leftGreen; oldLeftBlue = leftBlue; oldLeftAlpha = leftAlpha; srcPtr++, destPtr++; } x = srcWidth + offset; destPtr = Blt_ColorImageBits(dest) + (y * destWidth) + x; if (x < destWidth) { leftRed = uchar2si(bgColor.Red); leftGreen = uchar2si(bgColor.Green); leftBlue = uchar2si(bgColor.Blue); leftAlpha = uchar2si(bgColor.Alpha); red = leftRed + oldLeftRed - (bgColor.Red * ifrac); green = leftGreen + oldLeftGreen - (bgColor.Green * ifrac); blue = leftBlue + oldLeftBlue - (bgColor.Blue * ifrac); alpha = leftAlpha + oldLeftAlpha - (bgColor.Alpha * ifrac); destPtr->Red = SICLAMP(red); destPtr->Green = SICLAMP(green); destPtr->Blue = SICLAMP(blue); destPtr->Alpha = SICLAMP(alpha); destPtr++; } for (x++; x < destWidth; x++) { *destPtr++ = bgColor; } } /* * -------------------------------------------------------------------------- * * ShearX -- * * Shears a column. Antialiasing is limited to filtering two * adjacent pixels. So the shear angle must be between +-45 * degrees. * * Results: * None. * * Side Effects: * The sheared image is drawn into the destination color image. * * -------------------------------------------------------------------------- */ static void ShearX(src, dest, x, offset, frac, bgColor) Blt_ColorImage src, dest; int x; /* Column in source image to be sheared. */ int offset; /* Offset of */ double frac; /* Fraction of subpixel. */ Pix32 bgColor; { Pix32 *srcPtr, *destPtr; register int y, dy; #ifdef notef int srcWidth; int destWidth; #endif int destHeight; int srcHeight; int red, blue, green, alpha; int leftRed, leftGreen, leftBlue, leftAlpha; int oldLeftRed, oldLeftGreen, oldLeftBlue, oldLeftAlpha; int ifrac; #ifdef notdef srcWidth = Blt_ColorImageWidth(src); destWidth = Blt_ColorImageWidth(dest); #endif srcHeight = Blt_ColorImageHeight(src); destHeight = Blt_ColorImageHeight(dest); #ifdef notdef destPtr = Blt_ColorImageBits(dest) + x; #endif for (y = 0; y < offset; y++) { destPtr = Blt_ColorImagePixel(dest, x, y); *destPtr = bgColor; #ifdef notdef destPtr += destWidth; #endif } oldLeftRed = uchar2si(bgColor.Red); oldLeftGreen = uchar2si(bgColor.Green); oldLeftBlue = uchar2si(bgColor.Blue); oldLeftAlpha = uchar2si(bgColor.Alpha); #ifdef notdef destPtr = Blt_ColorImageBits(dest) + x + offset; srcPtr = Blt_ColorImageBits(src) + x; #endif dy = offset; ifrac = float2si(frac); for (y = 0; y < srcHeight; y++, dy++) { srcPtr = Blt_ColorImagePixel(src, x, y); leftRed = srcPtr->Red * ifrac; leftGreen = srcPtr->Green * ifrac; leftBlue = srcPtr->Blue * ifrac; leftAlpha = srcPtr->Alpha * ifrac; if ((dy >= 0) && (dy < destHeight)) { destPtr = Blt_ColorImagePixel(dest, x, dy); red = uchar2si(srcPtr->Red) - (leftRed - oldLeftRed); green = uchar2si(srcPtr->Green) - (leftGreen - oldLeftGreen); blue = uchar2si(srcPtr->Blue) - (leftBlue - oldLeftBlue); alpha = uchar2si(srcPtr->Alpha) - (leftAlpha - oldLeftAlpha); destPtr->Red = SICLAMP(red); destPtr->Green = SICLAMP(green); destPtr->Blue = SICLAMP(blue); destPtr->Alpha = SICLAMP(alpha); } oldLeftRed = leftRed; oldLeftGreen = leftGreen; oldLeftBlue = leftBlue; oldLeftAlpha = leftAlpha; #ifdef notdef srcPtr += srcWidth; destPtr += destWidth; #endif } y = srcHeight + offset; #ifdef notdef destPtr = Blt_ColorImageBits(dest) + (y * destWidth) + x + offset; #endif if (y < destHeight) { leftRed = uchar2si(bgColor.Red); leftGreen = uchar2si(bgColor.Green); leftBlue = uchar2si(bgColor.Blue); leftAlpha = uchar2si(bgColor.Alpha); destPtr = Blt_ColorImagePixel(dest, x, y); red = leftRed + oldLeftRed - (bgColor.Red * ifrac); green = leftGreen + oldLeftGreen - (bgColor.Green * ifrac); blue = leftBlue + oldLeftBlue - (bgColor.Blue * ifrac); alpha = leftAlpha + oldLeftAlpha - (bgColor.Alpha * ifrac); destPtr->Red = SICLAMP(red); destPtr->Green = SICLAMP(green); destPtr->Blue = SICLAMP(blue); destPtr->Alpha = SICLAMP(alpha); #ifdef notdef destPtr += destWidth; #endif } for (y++; y < destHeight; y++) { destPtr = Blt_ColorImagePixel(dest, x, y); *destPtr = bgColor; #ifdef notdef destPtr += destWidth; #endif } } /* * --------------------------------------------------------------------------- * * Rotate45 -- * * Rotates an image by a given angle. The angle must be in the * range -45.0 to 45.0 inclusive. Anti-aliasing filtering is * performed on two adjacent pixels, so the angle can't be so * great as to force a sheared pixel to occupy 3 destination * pixels. Performs a three shear rotation described below. * * Reference: Alan W. Paeth, "A Fast Algorithm for General Raster * Rotation", Graphics Gems, pp 179-195. * * * Results: * Returns a newly allocated rotated image. * * --------------------------------------------------------------------------- */ static Blt_ColorImage Rotate45(src, theta, bgColor) Blt_ColorImage src; double theta; Pix32 bgColor; { int tmpWidth, tmpHeight; int srcWidth, srcHeight; double sinTheta, cosTheta, tanTheta; double skewf; int skewi; Blt_ColorImage tmp1, tmp2, dest; register int x, y; sinTheta = sin(theta); cosTheta = cos(theta); tanTheta = tan(theta * 0.5); srcWidth = Blt_ColorImageWidth(src); srcHeight = Blt_ColorImageHeight(src); tmpWidth = srcWidth + (int)(srcHeight * FABS(tanTheta)); tmpHeight = srcHeight; /* 1st shear */ tmp1 = Blt_CreateColorImage(tmpWidth, tmpHeight); assert(tmp1); if (tanTheta >= 0.0) { /* Positive angle */ for (y = 0; y < tmpHeight; y++) { skewf = (y + 0.5) * tanTheta; skewi = (int)floor(skewf); ShearY(src, tmp1, y, skewi, skewf - skewi, bgColor); } } else { /* Negative angle */ for (y = 0; y < tmpHeight; y++) { skewf = ((y - srcHeight) + 0.5) * tanTheta; skewi = (int)floor(skewf); ShearY(src, tmp1, y, skewi, skewf - skewi, bgColor); } } tmpHeight = (int)(srcWidth * FABS(sinTheta) + srcHeight * cosTheta) + 1; tmp2 = Blt_CreateColorImage(tmpWidth, tmpHeight); assert(tmp2); /* 2nd shear */ if (sinTheta > 0.0) { /* Positive angle */ skewf = (srcWidth - 1) * sinTheta; } else { /* Negative angle */ skewf = (srcWidth - tmpWidth) * -sinTheta; } for (x = 0; x < tmpWidth; x++) { skewi = (int)floor(skewf); ShearX(tmp1, tmp2, x, skewi, skewf - skewi, bgColor); skewf -= sinTheta; } Blt_FreeColorImage(tmp1); /* 3rd shear */ tmpWidth = (int)(srcHeight * FABS(sinTheta) + srcWidth * cosTheta) + 1; dest = Blt_CreateColorImage(tmpWidth, tmpHeight); assert(dest); if (sinTheta >= 0.0) { /* Positive angle */ skewf = (srcWidth - 1) * sinTheta * -tanTheta; } else { /* Negative angle */ skewf = tanTheta * ((srcWidth - 1) * -sinTheta - (tmpHeight - 1)); } for (y = 0; y < tmpHeight; y++) { skewi = (int)floor(skewf); ShearY(tmp2, dest, y, skewi, skewf - skewi, bgColor); skewf += tanTheta; } Blt_FreeColorImage(tmp2); return dest; } /* * --------------------------------------------------------------------------- * * CopyColorImage -- * * Creates a copy of the given color image. * * Results: * Returns the new copy. * * --------------------------------------------------------------------------- */ static Blt_ColorImage CopyColorImage(src) Blt_ColorImage src; { unsigned int width, height; Pix32 *srcPtr, *destPtr; Blt_ColorImage dest; width = Blt_ColorImageWidth(src); height = Blt_ColorImageHeight(src); dest = Blt_CreateColorImage(width, height); srcPtr = Blt_ColorImageBits(src); destPtr = Blt_ColorImageBits(dest); memcpy(destPtr, srcPtr, width * height * sizeof(Pix32)); return dest; } /* * --------------------------------------------------------------------------- * * Rotate90 -- * * Rotates the given color image by 90 degrees. This is part * of the special case right-angle rotations that do not create * subpixel aliasing. * * Results: * Returns a newly allocated, rotated color image. * * --------------------------------------------------------------------------- */ static Blt_ColorImage Rotate90(src) Blt_ColorImage src; { int width, height, offset; Pix32 *srcPtr, *destPtr; Blt_ColorImage dest; register int x, y; height = Blt_ColorImageWidth(src); width = Blt_ColorImageHeight(src); srcPtr = Blt_ColorImageBits(src); dest = Blt_CreateColorImage(width, height); offset = (height - 1) * width; for (x = 0; x < width; x++) { destPtr = Blt_ColorImageBits(dest) + offset + x; for (y = 0; y < height; y++) { *destPtr = *srcPtr++; destPtr -= width; } } return dest; } /* * --------------------------------------------------------------------------- * * Rotate180 -- * * Rotates the given color image by 180 degrees. This is one of * the special case orthogonal rotations that do not create * subpixel aliasing. * * Results: * Returns a newly allocated, rotated color image. * * --------------------------------------------------------------------------- */ static Blt_ColorImage Rotate180(src) Blt_ColorImage src; { int width, height, offset; Pix32 *srcPtr, *destPtr; Blt_ColorImage dest; register int x, y; width = Blt_ColorImageWidth(src); height = Blt_ColorImageHeight(src); dest = Blt_CreateColorImage(width, height); srcPtr = Blt_ColorImageBits(src); offset = (height - 1) * width; for (y = 0; y < height; y++) { destPtr = Blt_ColorImageBits(dest) + offset + width - 1; for (x = 0; x < width; x++) { *destPtr-- = *srcPtr++; } offset -= width; } return dest; } /* * --------------------------------------------------------------------------- * * Rotate270 -- * * Rotates the given color image by 270 degrees. This is part * of the special case right-angle rotations that do not create * subpixel aliasing. * * Results: * Returns a newly allocated, rotated color image. * * --------------------------------------------------------------------------- */ static Blt_ColorImage Rotate270(src) Blt_ColorImage src; { int width, height; Pix32 *srcPtr, *destPtr; Blt_ColorImage dest; register int x, y; height = Blt_ColorImageWidth(src); width = Blt_ColorImageHeight(src); dest = Blt_CreateColorImage(width, height); srcPtr = Blt_ColorImageBits(src); for (x = width - 1; x >= 0; x--) { destPtr = Blt_ColorImageBits(dest) + x; for (y = 0; y < height; y++) { *destPtr = *srcPtr++; destPtr += width; } } return dest; } /* *---------------------------------------------------------------------- * * Blt_RotateColorImage -- * * Rotates a color image by a given # of degrees. * * Results: * Returns a newly allocated, rotated color image. * *---------------------------------------------------------------------- */ Blt_ColorImage Blt_RotateColorImage(src, angle) Blt_ColorImage src; double angle; { Blt_ColorImage dest, tmp; int quadrant; tmp = src; /* Suppress compiler warning. */ /* Make the angle positive between 0 and 360 degrees. */ angle = FMOD(angle, 360.0); if (angle < 0.0) { angle += 360.0; } quadrant = ROTATE_0; if ((angle > 45.0) && (angle <= 135.0)) { quadrant = ROTATE_90; angle -= 90.0; } else if ((angle > 135.0) && (angle <= 225.0)) { quadrant = ROTATE_180; angle -= 180.0; } else if ((angle > 225.0) && (angle <= 315.0)) { quadrant = ROTATE_270; angle -= 270.0; } else if (angle > 315.0) { angle -= 360.0; } /* * If necessary, create a temporary image that's been rotated * by a right-angle. We'll then rotate this color image between * -45 to 45 degrees to arrive at its final angle. */ switch (quadrant) { case ROTATE_270: /* 270 degrees */ tmp = Rotate270(src); break; case ROTATE_90: /* 90 degrees */ tmp = Rotate90(src); break; case ROTATE_180: /* 180 degrees */ tmp = Rotate180(src); break; case ROTATE_0: /* 0 degrees */ if (angle == 0.0) { tmp = CopyColorImage(src); /* Make a copy of the source. */ } break; } assert((angle >= -45.0) && (angle <= 45.0)); dest = tmp; if (angle != 0.0) { double theta; Pix32 *srcPtr; Pix32 bgColor; /* FIXME: pick up background blending color from somewhere */ srcPtr = Blt_ColorImageBits(src); bgColor = *srcPtr; bgColor.Red = bgColor.Green = bgColor.Blue = 0xFF; bgColor.Alpha = 0x00; /* Transparent background */ theta = (angle / 180.0) * M_PI; dest = Rotate45(tmp, theta, bgColor); if (tmp != src) { Blt_FreeColorImage(tmp); } } return dest; } #define NC 256 enum ColorIndices { RED, GREEN, BLUE }; #define R0 (cubePtr->r0) #define R1 (cubePtr->r1) #define G0 (cubePtr->g0) #define G1 (cubePtr->g1) #define B0 (cubePtr->b0) #define B1 (cubePtr->b1) typedef struct { int r0, r1; /* min, max values: * min exclusive max inclusive */ int g0, g1; int b0, b1; int vol; } Cube; /* *---------------------------------------------------------------------- * * Histogram is in elements 1..HISTSIZE along each axis, * element 0 is for base or marginal value * NB: these must start out 0! *---------------------------------------------------------------------- */ typedef struct { long int wt[33][33][33]; /* # pixels in voxel */ long int mR[33][33][33]; /* Sum over voxel of red pixel values */ long int mG[33][33][33]; /* Sum over voxel of green pixel values */ long int mB[33][33][33]; /* Sum over voxel of blue pixel values */ long int gm2[33][33][33]; /* Variance */ } ColorImageStatistics; /* * Build 3-D color histogram of counts, R/G/B, c^2 */ static ColorImageStatistics * GetColorImageStatistics(image) Blt_ColorImage image; { register int r, g, b; #define MAX_INTENSITIES 256 unsigned int sqr[MAX_INTENSITIES]; int numPixels; Pix32 *srcPtr, *endPtr; register int i; ColorImageStatistics *s; s = Blt_Calloc(1, sizeof(ColorImageStatistics)); assert(s); /* Precompute table of squares. */ for (i = 0; i < MAX_INTENSITIES; i++) { sqr[i] = i * i; } numPixels = Blt_ColorImageWidth(image) * Blt_ColorImageHeight(image); for (srcPtr = Blt_ColorImageBits(image), endPtr = srcPtr + numPixels; srcPtr < endPtr; srcPtr++) { /* * Reduce the number of bits (5) per color component. This * will keep the table size (2^15) reasonable without perceptually * affecting the final image. */ r = (srcPtr->Red >> 3) + 1; g = (srcPtr->Green >> 3) + 1; b = (srcPtr->Blue >> 3) + 1; s->wt[r][g][b] += 1; s->mR[r][g][b] += srcPtr->Red; s->mG[r][g][b] += srcPtr->Green; s->mB[r][g][b] += srcPtr->Blue; s->gm2[r][g][b] += sqr[srcPtr->Red] + sqr[srcPtr->Green] + sqr[srcPtr->Blue]; } return s; } /* *---------------------------------------------------------------------- * At conclusion of the histogram step, we can interpret * wt[r][g][b] = sum over voxel of P(c) * mR[r][g][b] = sum over voxel of r*P(c) , similarly for mG, mB * m2[r][g][b] = sum over voxel of c^2*P(c) * Actually each of these should be divided by 'size' to give the usual * interpretation of P() as ranging from 0 to 1, but we needn't do that here. *---------------------------------------------------------------------- */ /* *---------------------------------------------------------------------- We now convert histogram into moments so that we can rapidly calculate * the sums of the above quantities over any desired box. *---------------------------------------------------------------------- */ static void M3d(s) /* compute cumulative moments. */ ColorImageStatistics *s; { register unsigned char i, r, g, b, r0; long int line, rLine, gLine, bLine; long int area[33], rArea[33], gArea[33], bArea[33]; unsigned int line2, area2[33]; for (r = 1, r0 = 0; r <= 32; r++, r0++) { for (i = 0; i <= 32; ++i) { area2[i] = area[i] = rArea[i] = gArea[i] = bArea[i] = 0; } for (g = 1; g <= 32; g++) { line2 = line = rLine = gLine = bLine = 0; for (b = 1; b <= 32; b++) { /* ind1 = RGBIndex(r, g, b); */ line += s->wt[r][g][b]; rLine += s->mR[r][g][b]; gLine += s->mG[r][g][b]; bLine += s->mB[r][g][b]; line2 += s->gm2[r][g][b]; area[b] += line; rArea[b] += rLine; gArea[b] += gLine; bArea[b] += bLine; area2[b] += line2; /* ind2 = ind1 - 1089; [r0][g][b] */ s->wt[r][g][b] = s->wt[r0][g][b] + area[b]; s->mR[r][g][b] = s->mR[r0][g][b] + rArea[b]; s->mG[r][g][b] = s->mG[r0][g][b] + gArea[b]; s->mB[r][g][b] = s->mB[r0][g][b] + bArea[b]; s->gm2[r][g][b] = s->gm2[r0][g][b] + area2[b]; } } } } /* *---------------------------------------------------------------------- * * Compute sum over a box of any given statistic * *---------------------------------------------------------------------- */ static INLINE long int Volume(cubePtr, m) Cube *cubePtr; long int m[33][33][33]; { return (m[R1][G1][B1] - m[R1][G1][B0] - m[R1][G0][B1] + m[R1][G0][B0] - m[R0][G1][B1] + m[R0][G1][B0] + m[R0][G0][B1] - m[R0][G0][B0]); } /* *---------------------------------------------------------------------- * * The next two routines allow a slightly more efficient * calculation of Volume() for a proposed subbox of a given box. * The sum of Top() and Bottom() is the Volume() of a subbox split * in the given direction and with the specified new upper * bound. * *---------------------------------------------------------------------- */ /* Compute part of Volume(cubePtr, mmt) that doesn't depend on r1, g1, or b1 */ /* (depending on dir) */ static long int Bottom(cubePtr, dir, m) Cube *cubePtr; unsigned char dir; long int m[33][33][33]; /* Moment */ { switch (dir) { case RED: return -m[R0][G1][B1] + m[R0][G1][B0] + m[R0][G0][B1] - m[R0][G0][B0]; case GREEN: return -m[R1][G0][B1] + m[R1][G0][B0] + m[R0][G0][B1] - m[R0][G0][B0]; case BLUE: return -m[R1][G1][B0] + m[R1][G0][B0] + m[R0][G1][B0] - m[R0][G0][B0]; } return 0; } /* *---------------------------------------------------------------------- * * Compute remainder of Volume(cubePtr, mmt), substituting pos for * r1, g1, or b1 (depending on dir) * *---------------------------------------------------------------------- */ static long int Top(cubePtr, dir, pos, m) Cube *cubePtr; unsigned char dir; int pos; long int m[33][33][33]; { switch (dir) { case RED: return (m[pos][G1][B1] - m[pos][G1][B0] - m[pos][G0][B1] + m[pos][G0][B0]); case GREEN: return (m[R1][pos][B1] - m[R1][pos][B0] - m[R0][pos][B1] + m[R0][pos][B0]); case BLUE: return (m[R1][G1][pos] - m[R1][G0][pos] - m[R0][G1][pos] + m[R0][G0][pos]); } return 0; } /* *---------------------------------------------------------------------- * * Compute the weighted variance of a box NB: as with the raw * statistics, this is really the (variance * size) * *---------------------------------------------------------------------- */ static double Variance(cubePtr, s) Cube *cubePtr; ColorImageStatistics *s; { double dR, dG, dB, xx; dR = Volume(cubePtr, s->mR); dG = Volume(cubePtr, s->mG); dB = Volume(cubePtr, s->mB); xx = (s->gm2[R1][G1][B1] - s->gm2[R1][G1][B0] - s->gm2[R1][G0][B1] + s->gm2[R1][G0][B0] - s->gm2[R0][G1][B1] + s->gm2[R0][G1][B0] + s->gm2[R0][G0][B1] - s->gm2[R0][G0][B0]); return (xx - (dR * dR + dG * dG + dB * dB) / Volume(cubePtr, s->wt)); } /* *---------------------------------------------------------------------- * * We want to minimize the sum of the variances of two subboxes. * The sum(c^2) terms can be ignored since their sum over both * subboxes is the same (the sum for the whole box) no matter * where we split. The remaining terms have a minus sign in * the variance formula, so we drop the minus sign and MAXIMIZE * the sum of the two terms. * *---------------------------------------------------------------------- */ static double Maximize(cubePtr, dir, first, last, cut, rWhole, gWhole, bWhole, wWhole, s) Cube *cubePtr; unsigned char dir; int first, last, *cut; long int rWhole, gWhole, bWhole, wWhole; ColorImageStatistics *s; { register long int rHalf, gHalf, bHalf, wHalf; long int rBase, gBase, bBase, wBase; register int i; register double temp, max; rBase = Bottom(cubePtr, dir, s->mR); gBase = Bottom(cubePtr, dir, s->mG); bBase = Bottom(cubePtr, dir, s->mB); wBase = Bottom(cubePtr, dir, s->wt); max = 0.0; *cut = -1; for (i = first; i < last; i++) { rHalf = rBase + Top(cubePtr, dir, i, s->mR); gHalf = gBase + Top(cubePtr, dir, i, s->mG); bHalf = bBase + Top(cubePtr, dir, i, s->mB); wHalf = wBase + Top(cubePtr, dir, i, s->wt); /* Now half_x is sum over lower half of box, if split at i */ if (wHalf == 0) { /* subbox could be empty of pixels! */ continue; /* never split into an empty box */ } else { temp = ((double)rHalf * rHalf + (float)gHalf * gHalf + (double)bHalf * bHalf) / wHalf; } rHalf = rWhole - rHalf; gHalf = gWhole - gHalf; bHalf = bWhole - bHalf; wHalf = wWhole - wHalf; if (wHalf == 0) { /* Subbox could be empty of pixels! */ continue; /* never split into an empty box */ } else { temp += ((double)rHalf * rHalf + (float)gHalf * gHalf + (double)bHalf * bHalf) / wHalf; } if (temp > max) { max = temp; *cut = i; } } return max; } /* *---------------------------------------------------------------------- *---------------------------------------------------------------------- */ static int Cut(set1, set2, s) Cube *set1, *set2; ColorImageStatistics *s; { unsigned char dir; int rCut, gCut, bCut; double rMax, gMax, bMax; long int rWhole, gWhole, bWhole, wWhole; rWhole = Volume(set1, s->mR); gWhole = Volume(set1, s->mG); bWhole = Volume(set1, s->mB); wWhole = Volume(set1, s->wt); rMax = Maximize(set1, RED, set1->r0 + 1, set1->r1, &rCut, rWhole, gWhole, bWhole, wWhole, s); gMax = Maximize(set1, GREEN, set1->g0 + 1, set1->g1, &gCut, rWhole, gWhole, bWhole, wWhole, s); bMax = Maximize(set1, BLUE, set1->b0 + 1, set1->b1, &bCut, rWhole, gWhole, bWhole, wWhole, s); if ((rMax >= gMax) && (rMax >= bMax)) { dir = RED; if (rCut < 0) { return 0; /* can't split the box */ } } else { dir = ((gMax >= rMax) && (gMax >= bMax)) ? GREEN : BLUE; } set2->r1 = set1->r1; set2->g1 = set1->g1; set2->b1 = set1->b1; switch (dir) { case RED: set2->r0 = set1->r1 = rCut; set2->g0 = set1->g0; set2->b0 = set1->b0; break; case GREEN: set2->g0 = set1->g1 = gCut; set2->r0 = set1->r0; set2->b0 = set1->b0; break; case BLUE: set2->b0 = set1->b1 = bCut; set2->r0 = set1->r0; set2->g0 = set1->g0; break; } set1->vol = (set1->r1 - set1->r0) * (set1->g1 - set1->g0) * (set1->b1 - set1->b0); set2->vol = (set2->r1 - set2->r0) * (set2->g1 - set2->g0) * (set2->b1 - set2->b0); return 1; } static int SplitColorSpace(s, cubes, nColors) ColorImageStatistics *s; Cube *cubes; int nColors; { double *vv, temp; register int i; register int n, k; vv = Blt_Malloc(sizeof(double) * nColors); assert(vv); cubes[0].r0 = cubes[0].g0 = cubes[0].b0 = 0; cubes[0].r1 = cubes[0].g1 = cubes[0].b1 = 32; for (i = 1, n = 0; i < nColors; i++) { if (Cut(cubes + n, cubes + i, s)) { /* * Volume test ensures we won't try to cut one-cell box */ vv[n] = vv[i] = 0.0; if (cubes[n].vol > 1) { vv[n] = Variance(cubes + n, s); } if (cubes[i].vol > 1) { vv[i] = Variance(cubes + i, s); } } else { vv[n] = 0.0; /* don't try to split this box again */ i--; /* didn't create box i */ } n = 0; temp = vv[0]; for (k = 1; k <= i; k++) { if (vv[k] > temp) { temp = vv[k]; n = k; } } if (temp <= 0.0) { i++; fprintf(stderr, "Only got %d boxes\n", i); break; } } Blt_Free(vv); return i; } /* *---------------------------------------------------------------------- *-------------------------------------------------------------------- */ static void Mark(cubePtr, label, tag) Cube *cubePtr; int label; unsigned int tag[33][33][33]; { register int r, g, b; for (r = R0 + 1; r <= R1; r++) { for (g = G0 + 1; g <= G1; g++) { for (b = B0 + 1; b <= B1; b++) { tag[r][g][b] = label; } } } } static unsigned int * CreateColorLookupTable(s, cubes, nColors) ColorImageStatistics *s; Cube *cubes; int nColors; { unsigned int *lut; Pix32 color; unsigned int red, green, blue; unsigned int weight; register Cube *cubePtr; register int i; lut = Blt_Calloc(sizeof(unsigned int), 33 * 33 * 33); assert(lut); color.Alpha = (unsigned char)-1; for (cubePtr = cubes, i = 0; i < nColors; i++, cubePtr++) { weight = Volume(cubePtr, s->wt); if (weight) { red = (Volume(cubePtr, s->mR) / weight) * (NC + 1); green = (Volume(cubePtr, s->mG) / weight) * (NC + 1); blue = (Volume(cubePtr, s->mB) / weight) * (NC + 1); } else { fprintf(stderr, "bogus box %d\n", i); red = green = blue = 0; } color.Red = red >> 8; color.Green = green >> 8; color.Blue = blue >> 8; Mark(cubePtr, color.value, lut); } return lut; } static void MapColors(src, dest, lut) Blt_ColorImage src, dest; unsigned int lut[33][33][33]; { /* Apply the color lookup table against the original image */ int width, height; int count; Pix32 *srcPtr, *destPtr, *endPtr; unsigned char alpha; width = Blt_ColorImageWidth(src); height = Blt_ColorImageHeight(src); count = width * height; srcPtr = Blt_ColorImageBits(src); destPtr = Blt_ColorImageBits(dest); for (endPtr = destPtr + count; destPtr < endPtr; srcPtr++, destPtr++) { alpha = srcPtr->Alpha; destPtr->value = lut[srcPtr->Red>>3][srcPtr->Green>>3][srcPtr->Blue>>3]; destPtr->Alpha = alpha; } } /* *---------------------------------------------------------------------- * * Blt_QuantizeColorImage -- * * C Implementation of Wu's Color Quantizer (v. 2) (see Graphics Gems * vol. II, pp. 126-133) * * Author: Xiaolin Wu * Dept. of Computer Science Univ. of Western * Ontario London, Ontario * N6A 5B7 * wu@csd.uwo.ca * * Algorithm: * Greedy orthogonal bipartition of RGB space for variance * minimization aided by inclusion-exclusion tricks. For * speed no nearest neighbor search is done. Slightly * better performance can be expected by more * sophisticated but more expensive versions. * * The author thanks Tom Lane at Tom_Lane@G.GP.CS.CMU.EDU for much of * additional documentation and a cure to a previous bug. * * Free to distribute, comments and suggestions are appreciated. * *---------------------------------------------------------------------- */ int Blt_QuantizeColorImage(src, dest, reduceColors) Blt_ColorImage src, dest; /* Source and destination images. */ int reduceColors; /* Reduced number of colors. */ { Cube *cubes; ColorImageStatistics *statistics; int nColors; unsigned int *lut; /* * Allocated a structure to hold color statistics. */ statistics = GetColorImageStatistics(src); M3d(statistics); cubes = Blt_Malloc(sizeof(Cube) * reduceColors); assert(cubes); nColors = SplitColorSpace(statistics, cubes, reduceColors); assert(nColors <= reduceColors); lut = CreateColorLookupTable(statistics, cubes, nColors); Blt_Free(statistics); Blt_Free(cubes); MapColors(src, dest, lut); Blt_Free(lut); return TCL_OK; } Region2D * Blt_SetRegion(x, y, width, height, regionPtr) int x, y, width, height; Region2D *regionPtr; { regionPtr->left = x; regionPtr->top = y; regionPtr->right = x + width - 1; regionPtr->bottom = y + height - 1; return regionPtr; } /* * Each call to Tk_GetImage returns a pointer to one of the following * structures, which is used as a token by clients (widgets) that * display images. */ typedef struct TkImageStruct { Tk_Window tkwin; /* Window passed to Tk_GetImage (needed to * "re-get" the image later if the manager * changes). */ Display *display; /* Display for tkwin. Needed because when * the image is eventually freed tkwin may * not exist anymore. */ struct TkImageMasterStruct *masterPtr; /* Master for this image (identifiers image * manager, for example). */ ClientData instanceData; /* One word argument to pass to image manager * when dealing with this image instance. */ Tk_ImageChangedProc *changeProc; /* Code in widget to call when image changes * in a way that affects redisplay. */ ClientData widgetClientData; /* Argument to pass to changeProc. */ struct Image *nextPtr; /* Next in list of all image instances * associated with the same name. */ } TkImage; /* * For each image master there is one of the following structures, * which represents a name in the image table and all of the images * instantiated from it. Entries in mainPtr->imageTable point to * these structures. */ typedef struct TkImageMasterStruct { Tk_ImageType *typePtr; /* Information about image type. NULL means * that no image manager owns this image: the * image was deleted. */ ClientData masterData; /* One-word argument to pass to image mgr * when dealing with the master, as opposed * to instances. */ int width, height; /* Last known dimensions for image. */ Blt_HashTable *tablePtr; /* Pointer to hash table containing image * (the imageTable field in some TkMainInfo * structure). */ Blt_HashEntry *hPtr; /* Hash entry in mainPtr->imageTable for * this structure (used to delete the hash * entry). */ TkImage *instancePtr; /* Pointer to first in list of instances * derived from this name. */ } TkImageMaster; typedef struct TkPhotoMasterStruct TkPhotoMaster; typedef struct TkColorTableStruct TkColorTable; typedef struct TkPhotoInstanceStruct { TkPhotoMaster *masterPtr; /* Pointer to master for image. */ Display *display; /* Display for windows using this instance. */ Colormap colormap; /* The image may only be used in windows with * this particular colormap. */ struct TkPhotoInstanceStruct *nextPtr; /* Pointer to the next instance in the list * of instances associated with this master. */ int refCount; /* Number of instances using this structure. */ Tk_Uid palette; /* Palette for these particular instances. */ double outputGamma; /* Gamma value for these instances. */ Tk_Uid defaultPalette; /* Default palette to use if a palette * is not specified for the master. */ TkColorTable *colorTablePtr; /* Pointer to information about colors * allocated for image display in windows * like this one. */ Pixmap pixels; /* X pixmap containing dithered image. */ int width, height; /* Dimensions of the pixmap. */ char *error; /* Error image, used in dithering. */ XImage *imagePtr; /* Image structure for converted pixels. */ XVisualInfo visualInfo; /* Information about the visual that these * windows are using. */ GC gc; /* Graphics context for writing images * to the pixmap. */ } TkPhotoInstance; /* * ---------------------------------------------------------------------- * * Tk_ImageDeleted -- * * Is there any other way to determine if an image has been * deleted? * * Results: * Returns 1 if the image has been deleted, 0 otherwise. * * ---------------------------------------------------------------------- */ /*LINTLIBRARY*/ int Tk_ImageIsDeleted(tkImage) Tk_Image tkImage; /* Token for image. */ { TkImage *imagePtr = (TkImage *) tkImage; if (imagePtr->masterPtr == NULL) { return TRUE; } return (imagePtr->masterPtr->typePtr == NULL); } /*LINTLIBRARY*/ Tk_ImageMaster Tk_ImageGetMaster(tkImage) Tk_Image tkImage; /* Token for image. */ { TkImage *imagePtr = (TkImage *)tkImage; return (Tk_ImageMaster) imagePtr->masterPtr; } /*LINTLIBRARY*/ Tk_ImageType * Tk_ImageGetType(tkImage) Tk_Image tkImage; /* Token for image. */ { TkImage *imagePtr = (TkImage *)tkImage; return imagePtr->masterPtr->typePtr; } /*LINTLIBRARY*/ Pixmap Tk_ImageGetPhotoPixmap(tkImage) Tk_Image tkImage; /* Token for image. */ { TkImage *imagePtr = (TkImage *)tkImage; if (strcmp(imagePtr->masterPtr->typePtr->name, "photo") == 0) { TkPhotoInstance *instPtr = (TkPhotoInstance *)imagePtr->instanceData; return instPtr->pixels; } return None; } /*LINTLIBRARY*/ GC Tk_ImageGetPhotoGC(photoImage) Tk_Image photoImage; /* Token for image. */ { TkImage *imagePtr = (TkImage *) photoImage; if (strcmp(imagePtr->masterPtr->typePtr->name, "photo") == 0) { TkPhotoInstance *instPtr = (TkPhotoInstance *)imagePtr->instanceData; return instPtr->gc; } return NULL; } /* *---------------------------------------------------------------------- * * TempImageChangedProc * * The image is over-written each time it's resized. We always * resample from the color image we saved when the photo image * was specified (-image option). So we only worry if the image * is deleted. * * Results: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static void TempImageChangedProc(clientData, x, y, width, height, imageWidth, imageHeight) ClientData clientData; int x, y, width, height; /* Not used. */ int imageWidth, imageHeight;/* Not used. */ { #ifdef notdef fprintf(stderr, "should be redrawing temp image\n"); #endif } Tk_Image Blt_CreateTemporaryImage(interp, tkwin, clientData) Tcl_Interp *interp; Tk_Window tkwin; ClientData clientData; { Tk_Image token; char *name; /* Contains image name. */ if (Tcl_Eval(interp, "image create photo") != TCL_OK) { return NULL; } name = (char *)Tcl_GetStringResult(interp); token = Tk_GetImage(interp, tkwin, name, TempImageChangedProc, clientData); if (token == NULL) { return NULL; } return token; } int Blt_DestroyTemporaryImage(interp, tkImage) Tcl_Interp *interp; Tk_Image tkImage; { if (tkImage != NULL) { if (Tcl_VarEval(interp, "image delete ", Blt_NameOfImage(tkImage), (char *)NULL) != TCL_OK) { return TCL_ERROR; } Tk_FreeImage(tkImage); } return TCL_OK; } char * Blt_NameOfImage(tkImage) Tk_Image tkImage; { Tk_ImageMaster master; master = Tk_ImageGetMaster(tkImage); return Tk_NameOfImage(master); } blt-2.4z.orig/src/bltImage.h0100644000175000017500000002436107527076110014443 0ustar dokodoko/* * bltImage.h -- * * Copyright 1993-1998 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. */ #include #ifndef WIN32 #include #endif #ifndef _BLT_IMAGE_H #define _BLT_IMAGE_H #define DIV255(i) ((((i) + 1) + (((i) + 1) >> 8) ) >> 8) #define GAMMA (1.0) #define ROTATE_0 0 #define ROTATE_90 1 #define ROTATE_180 2 #define ROTATE_270 3 /* *---------------------------------------------------------------------- * * Pix32 -- * * A union representing either a pixel as a RGB triplet or a * single word value. * *---------------------------------------------------------------------- */ typedef union { unsigned int value; /* Lookup table address */ struct RGBA { unsigned char red; /* Red intensity 0..255 */ unsigned char green; /* Green intensity 0.255 */ unsigned char blue; /* Blue intensity 0..255 */ unsigned char alpha; /* Alpha-channel for compositing. 0..255 */ } rgba; unsigned char channel[4]; } Pix32; #define Red rgba.red #define Blue rgba.blue #define Green rgba.green #define Alpha rgba.alpha typedef struct { XColor exact, best; double error; unsigned int freq; int allocated; int index; } ColorInfo; /* *---------------------------------------------------------------------- * * ColorTable -- * * For colormap-ed visuals, this structure contains color lookup * information needed to translate RGB triplets to pixel indices. * * This structure isn't needed for TrueColor or Monochrome visuals. * * DirectColor: * Pixel values for each color channel * StaticColor, PsuedoColor, StaticGray, and GrayScale: * Red represents the 8-bit color. Green and Blue pixel * values are unused. * *---------------------------------------------------------------------- */ typedef struct ColorTableStruct { double outputGamma; /* Gamma correction value */ Display *display; /* Display of colortable. Used to free * colors allocated. */ XVisualInfo visualInfo; /* Visual information for window displaying * the image. */ Colormap colorMap; /* Colormap used. This may be the default * colormap, or an allocated private map. */ int flags; unsigned int red[256], green[256], blue[256]; /* Array of allocated pixels in colormap */ ColorInfo colorInfo[256]; ColorInfo *sortedColors[256]; int nUsedColors, nFreeColors; int nPixels; /* Number of colors in the quantized image */ unsigned long int pixelValues[256]; unsigned int *lut; /* Color lookup table. Used to collect * frequencies of colors and later * colormap indices */ } *ColorTable; #define PRIVATE_COLORMAP 1 #define RGBIndex(r,g,b) (((r)<<10) + ((r)<<6) + (r) + ((g) << 5) + (g) + (b)) /* *---------------------------------------------------------------------- * * Blt_ColorImage -- * * The structure below represents a color image. Each pixel * occupies a 32-bit word of memory: one byte for each of the * red, green, and blue color intensities, and another for * alpha-channel image compositing (e.g. transparency). * *---------------------------------------------------------------------- */ typedef struct ColorImage { int width, height; /* Dimensions of the image */ Pix32 *bits; /* Array of pixels representing the image. */ } *Blt_ColorImage; /* * Blt_ColorImage is supposed to be an opaque type. * Use the macros below to access its members. */ #define Blt_ColorImageHeight(c) ((c)->height) #define Blt_ColorImageWidth(c) ((c)->width) #define Blt_ColorImageBits(c) ((c)->bits) #define Blt_ColorImagePixel(c, x, y) ((c)->bits + ((c)->width * (y)) + (x)) /* *---------------------------------------------------------------------- * * ResampleFilterProc -- * * A function implementing a 1-D filter. * *---------------------------------------------------------------------- */ typedef double (ResampleFilterProc) _ANSI_ARGS_((double value)); /* *---------------------------------------------------------------------- * * ResampleFilter -- * * Contains information about a 1-D filter (its support and * the procedure implementing the filter). * *---------------------------------------------------------------------- */ typedef struct { char *name; /* Name of the filter */ ResampleFilterProc *proc; /* 1-D filter procedure. */ double support; /* Width of 1-D filter */ } ResampleFilter; extern ResampleFilter *bltBoxFilterPtr; /* The ubiquitous box filter */ /* *---------------------------------------------------------------------- * * Filter2D -- * * Defines a convolution mask for a 2-D filter. Used to smooth or * enhance images. * *---------------------------------------------------------------------- */ typedef struct { double support; /* Radius of filter */ double sum, scale; /* Sum of kernel */ double *kernel; /* Array of values (malloc-ed) representing * the discrete 2-D filter. */ } Filter2D; /* Prototypes of image routines */ extern void Blt_ColorImageToGreyscale _ANSI_ARGS_((Blt_ColorImage image)); extern void Blt_ColorImageToPhoto _ANSI_ARGS_((Blt_ColorImage image, Tk_PhotoHandle photo)); extern Pixmap Blt_ColorImageToPixmap _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, Blt_ColorImage image, ColorTable *colorTablePtr)); extern Blt_ColorImage Blt_ConvolveColorImage _ANSI_ARGS_(( Blt_ColorImage srcImage, Filter2D *filter)); extern Blt_ColorImage Blt_CreateColorImage _ANSI_ARGS_((int width,int height)); extern Blt_ColorImage Blt_DrawableToColorImage _ANSI_ARGS_((Tk_Window tkwin, Drawable drawable, int x, int y, int width, int height, double inputGamma)); extern int Blt_GetResampleFilter _ANSI_ARGS_((Tcl_Interp *interp, char *filterName, ResampleFilter **filterPtrPtr)); extern void Blt_FreeColorImage _ANSI_ARGS_((Blt_ColorImage image)); #if HAVE_JPEG extern Blt_ColorImage Blt_JPEGToColorImage _ANSI_ARGS_((Tcl_Interp *interp, char *fileName)); #endif extern Blt_ColorImage Blt_PhotoToColorImage _ANSI_ARGS_(( Tk_PhotoHandle photo)); extern Blt_ColorImage Blt_PhotoRegionToColorImage _ANSI_ARGS_(( Tk_PhotoHandle photo, int x, int y, int width, int height)); extern int Blt_QuantizeColorImage _ANSI_ARGS_((Blt_ColorImage src, Blt_ColorImage dest, int nColors)); extern Blt_ColorImage Blt_ResampleColorImage _ANSI_ARGS_((Blt_ColorImage image, int destWidth, int destHeight, ResampleFilter *horzFilterPtr, ResampleFilter *vertFilterPtr)); extern void Blt_ResamplePhoto _ANSI_ARGS_((Tk_PhotoHandle srcPhoto, int x, int y, int width, int height, Tk_PhotoHandle destPhoto, ResampleFilter *horzFilterPtr, ResampleFilter *vertFilterPtr)); extern Blt_ColorImage Blt_ResizeColorImage _ANSI_ARGS_((Blt_ColorImage src, int x, int y, int width, int height, int destWidth, int destHeight)); extern Blt_ColorImage Blt_ResizeColorSubimage _ANSI_ARGS_((Blt_ColorImage src, int x, int y, int width, int height, int destWidth, int destHeight)); extern Blt_ColorImage Blt_RotateColorImage _ANSI_ARGS_((Blt_ColorImage image, double theta)); extern void Blt_ResizePhoto _ANSI_ARGS_((Tk_PhotoHandle srcPhoto, int x, int y, int width, int height, Tk_PhotoHandle destPhoto)); extern int Blt_SnapPhoto _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, Drawable drawable, int x, int y, int width, int height, int destWidth, int destHeight, char *photoName, double inputGamma)); extern void Blt_ImageRegion _ANSI_ARGS_((Blt_ColorImage image, Region2D *regionPtr)); extern Region2D *Blt_ColorImageRegion _ANSI_ARGS_((Blt_ColorImage image, Region2D *regionPtr)); extern Region2D *Blt_SetRegion _ANSI_ARGS_((int x, int y, int width, int height, Region2D *regionPtr)); extern ColorTable Blt_CreateColorTable _ANSI_ARGS_((Tk_Window tkwin)); extern ColorTable Blt_DirectColorTable _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, Blt_ColorImage image)); extern ColorTable Blt_PseudoColorTable _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, Blt_ColorImage image)); extern void Blt_FreeColorTable _ANSI_ARGS_((ColorTable colorTable)); /* Missing routines from the Tk photo C API */ extern int Tk_ImageIsDeleted _ANSI_ARGS_((Tk_Image tkImage)); extern Tk_ImageMaster Tk_ImageGetMaster _ANSI_ARGS_((Tk_Image tkImage)); extern Tk_ImageType *Tk_ImageGetType _ANSI_ARGS_((Tk_Image tkImage)); extern Pixmap Tk_ImageGetPhotoPixmap _ANSI_ARGS_((Tk_Image photoImage)); extern GC Tk_ImageGetPhotoGC _ANSI_ARGS_((Tk_Image photoImage)); extern char *Blt_NameOfImage _ANSI_ARGS_((Tk_Image tkImage)); extern Tk_Image Blt_CreateTemporaryImage _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, ClientData clientData)); extern int Blt_DestroyTemporaryImage _ANSI_ARGS_((Tcl_Interp *interp, Tk_Image tkImage)); extern GC Blt_GetBitmapGC _ANSI_ARGS_((Tk_Window tkwin)); extern Pixmap Blt_PhotoImageMask _ANSI_ARGS_((Tk_Window tkwin, Tk_PhotoImageBlock src)); extern Pixmap Blt_RotateBitmap _ANSI_ARGS_((Tk_Window tkwin, Pixmap bitmap, int width, int height, double theta, int *widthPtr, int *heightPtr)); extern Pixmap Blt_ScaleBitmap _ANSI_ARGS_((Tk_Window tkwin, Pixmap srcBitmap, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight)); extern Pixmap Blt_ScaleRotateBitmapRegion _ANSI_ARGS_((Tk_Window tkwin, Pixmap srcBitmap, unsigned int srcWidth, unsigned int srcHeight, int regionX, int regionY, unsigned int regionWidth, unsigned int regionHeight, unsigned int virtWidth, unsigned int virtHeight, double theta)); #endif /*_BLT_IMAGE_H*/ blt-2.4z.orig/src/bltInit.c0100644000175000017500000004440307537277501014326 0ustar dokodoko /* * bltInit.c -- * * This module initials the BLT toolkit, registering its commands * with the Tcl/Tk interpreter. * * Copyright 1991-1998 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. */ #include #define EXACT 1 #ifndef BLT_LIBRARY #ifdef WIN32 #define BLT_LIBRARY "c:/Program Files/Tcl/lib/blt"##BLT_VERSION #else #define BLT_LIBRARY "unknown" #endif #endif double bltNaN; #if (TCL_MAJOR_VERSION > 7) Tcl_Obj *bltEmptyStringObjPtr; #endif static Tcl_MathProc MinMathProc, MaxMathProc; static int tclLoaded = FALSE; #ifndef TCL_ONLY static int tkLoaded = FALSE; #endif static char libPath[1024] = { BLT_LIBRARY }; /* * Script to set the BLT library path in the variable global "blt_library" * * Checks the usual locations for a file (bltGraph.pro) from the BLT * library. The places searched in order are * * $BLT_LIBRARY * $BLT_LIBRARY/blt2.4 * $BLT_LIBRARY/.. * $BLT_LIBRARY/../blt2.4 * $blt_libPath * $blt_libPath/blt2.4 * $blt_libPath/.. * $blt_libPath/../blt2.4 * $tcl_library * $tcl_library/blt2.4 * $tcl_library/.. * $tcl_library/../blt2.4 * $env(TCL_LIBRARY) * $env(TCL_LIBRARY)/blt2.4 * $env(TCL_LIBRARY)/.. * $env(TCL_LIBRARY)/../blt2.4 * * The Tcl variable "blt_library" is set to the discovered path. * If the file wasn't found, no error is returned. The actual * usage of $blt_library is purposely deferred so that it can be * set from within a script. */ /* FIXME: Change this to a namespace procedure in 3.0 */ static char initScript[] = {"\n\ global blt_library blt_libPath blt_version tcl_library env\n\ set blt_library {}\n\ set path {}\n\ foreach var { env(BLT_LIBRARY) blt_libPath tcl_library env(TCL_LIBRARY) } { \n\ if { ![info exists $var] } { \n\ continue \n\ } \n\ set path [set $var] \n\ if { [file readable [file join $path bltGraph.pro]] } { \n\ set blt_library $path\n\ break \n\ } \n\ set path [file join $path blt$blt_version ] \n\ if { [file readable [file join $path bltGraph.pro]] } { \n\ set blt_library $path\n\ break \n\ } \n\ set path [file dirname [set $var]] \n\ if { [file readable [file join $path bltGraph.pro]] } { \n\ set blt_library $path\n\ break \n\ } \n\ set path [file join $path blt$blt_version ] \n\ if { [file readable [file join $path bltGraph.pro]] } { \n\ set blt_library $path\n\ break \n\ } \n\ } \n\ if { $blt_library != \"\" } { \n\ global auto_path \n\ lappend auto_path $blt_library \n\ }\n\ unset var path\n\ \n" }; static Tcl_AppInitProc *tclCmds[] = { #ifndef NO_BGEXEC Blt_BgexecInit, #endif #ifndef NO_DEBUG Blt_DebugInit, #endif #ifndef NO_WATCH Blt_WatchInit, #endif #ifndef NO_VECTOR Blt_VectorInit, #endif #ifndef NO_SPLINE Blt_SplineInit, #endif #ifndef NO_TREE Blt_TreeInit, #endif #ifndef NO_DDE Blt_DdeInit, #endif #ifndef NO_CRC32 Blt_Crc32Init, #endif (Tcl_AppInitProc *) NULL }; #ifndef TCL_ONLY static Tcl_AppInitProc *tkCmds[] = { #ifndef NO_GRAPH Blt_GraphInit, #endif #ifndef NO_TABLE Blt_TableInit, #endif #ifndef NO_HIERBOX Blt_HierboxInit, #endif #ifndef NO_TABSET Blt_TabsetInit, #endif #ifndef NO_TABNOTEBOOK Blt_TabnotebookInit, #endif #ifndef NO_HTEXT Blt_HtextInit, #endif #ifndef NO_BUSY Blt_BusyInit, #endif #ifndef NO_WINOP Blt_WinopInit, #endif #ifndef NO_BITMAP Blt_BitmapInit, #endif #ifndef NO_DRAGDROP Blt_DragDropInit, #endif #ifndef NO_DND Blt_DndInit, #endif #ifndef NO_CONTAINER Blt_ContainerInit, #endif #ifndef NO_BELL Blt_BeepInit, #endif #ifndef NO_CUTBUFFER Blt_CutbufferInit, #endif #ifndef NO_PRINTER Blt_PrinterInit, #endif #ifndef NO_TILEFRAME Blt_FrameInit, #endif #ifndef NO_TILEBUTTON Blt_ButtonInit, #endif #ifndef NO_TILESCROLLBAR Blt_ScrollbarInit, #endif #ifndef NO_TREEVIEW Blt_TreeViewInit, #endif #if (BLT_MAJOR_VERSION == 3) #ifndef NO_MOUNTAIN Blt_MountainInit, #endif #endif #ifndef NO_TED Blt_TedInit, #endif (Tcl_AppInitProc *) NULL }; #endif /* TCL_ONLY */ #ifdef WIN32 /* *---------------------------------------------------------------------- * * DllMain -- * * This wrapper function is used by Windows to invoke the * initialization code for the DLL. * * Results: * Returns TRUE; * * Side effects: * None. * *---------------------------------------------------------------------- */ BOOL APIENTRY DllMain( HINSTANCE hInst, /* Library instance handle. */ DWORD reason, /* Reason this function is being called. */ LPVOID reserved) /* Not used. */ { return TRUE; } BOOL APIENTRY DllEntryPoint(hInst, reason, reserved) HINSTANCE hInst; /* Library instance handle. */ DWORD reason; /* Reason this function is being called. */ LPVOID reserved; /* Not used. */ { return DllMain(hInst, reason, reserved); } #endif /* WIN32 */ #ifdef __BORLANDC__ static double MakeNaN(void) { union Real { struct DoubleWord { int lo, hi; } doubleWord; double number; } real; real.doubleWord.lo = real.doubleWord.hi = 0x7FFFFFFF; return real.number; } #endif /* __BORLANDC__ */ #ifdef _MSC_VER static double MakeNaN(void) { return sqrt(-1.0); /* Generate IEEE 754 Quiet Not-A-Number. */ } #endif /* _MSC_VER */ #if !defined(__BORLANDC__) && !defined(_MSC_VER) static double MakeNaN(void) { return 0.0 / 0.0; /* Generate IEEE 754 Not-A-Number. */ } #endif /* !__BORLANDC__ && !_MSC_VER */ /* ARGSUSED */ static int MinMathProc(clientData, interp, argsPtr, resultPtr) ClientData clientData; /* Not used. */ Tcl_Interp *interp; Tcl_Value *argsPtr; Tcl_Value *resultPtr; { Tcl_Value *op1Ptr, *op2Ptr; op1Ptr = argsPtr, op2Ptr = argsPtr + 1; if ((op1Ptr->type == TCL_INT) && (op2Ptr->type == TCL_INT)) { resultPtr->intValue = MIN(op1Ptr->intValue, op2Ptr->intValue); resultPtr->type = TCL_INT; } else { double a, b; a = (op1Ptr->type == TCL_INT) ? (double)op1Ptr->intValue : op1Ptr->doubleValue; b = (op2Ptr->type == TCL_INT) ? (double)op2Ptr->intValue : op2Ptr->doubleValue; resultPtr->doubleValue = MIN(a, b); resultPtr->type = TCL_DOUBLE; } return TCL_OK; } /*ARGSUSED*/ static int MaxMathProc(clientData, interp, argsPtr, resultPtr) ClientData clientData; /* Not Used. */ Tcl_Interp *interp; Tcl_Value *argsPtr; Tcl_Value *resultPtr; { Tcl_Value *op1Ptr, *op2Ptr; op1Ptr = argsPtr, op2Ptr = argsPtr + 1; if ((op1Ptr->type == TCL_INT) && (op2Ptr->type == TCL_INT)) { resultPtr->intValue = MAX(op1Ptr->intValue, op2Ptr->intValue); resultPtr->type = TCL_INT; } else { double a, b; a = (op1Ptr->type == TCL_INT) ? (double)op1Ptr->intValue : op1Ptr->doubleValue; b = (op2Ptr->type == TCL_INT) ? (double)op2Ptr->intValue : op2Ptr->doubleValue; resultPtr->doubleValue = MAX(a, b); resultPtr->type = TCL_DOUBLE; } return TCL_OK; } static int SetLibraryPath(interp) Tcl_Interp *interp; { Tcl_DString dString; CONST char *value; Tcl_DStringInit(&dString); Tcl_DStringAppend(&dString, libPath, -1); #ifdef WIN32 { HKEY key; DWORD result; #ifndef BLT_REGISTRY_KEY #define BLT_REGISTRY_KEY "Software\\BLT\\" BLT_VERSION "\\" TCL_VERSION #endif result = RegOpenKeyEx( HKEY_LOCAL_MACHINE, /* Parent key. */ BLT_REGISTRY_KEY, /* Path to sub-key. */ 0, /* Reserved. */ KEY_READ, /* Security access mask. */ &key); /* Resulting key.*/ if (result == ERROR_SUCCESS) { DWORD size; /* Query once to get the size of the string needed */ result = RegQueryValueEx(key, "BLT_LIBRARY", NULL, NULL, NULL, &size); if (result == ERROR_SUCCESS) { Tcl_DStringSetLength(&dString, size); /* And again to collect the string. */ RegQueryValueEx(key, "BLT_LIBRARY", NULL, NULL, (LPBYTE)Tcl_DStringValue(&dString), &size); RegCloseKey(key); } } } #endif /* WIN32 */ value = Tcl_SetVar(interp, "blt_libPath", Tcl_DStringValue(&dString), TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG); Tcl_DStringFree(&dString); if (value == NULL) { return TCL_ERROR; } return TCL_OK; } #if (TCL_MAJOR_VERSION > 7) /*LINTLIBRARY*/ EXPORT int Blt_Init(interp) Tcl_Interp *interp; /* Interpreter to add extra commands */ { if (!tclLoaded) { register Tcl_AppInitProc **p; Tcl_Namespace *nsPtr; Tcl_ValueType args[2]; /* * Check that the versions of Tcl that have been loaded are * the same ones that BLT was compiled against. */ if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, EXACT) == NULL) { return TCL_ERROR; } /* Set the "blt_version", "blt_patchLevel", and "blt_libPath" Tcl * variables. We'll use them in the following script. */ if ((Tcl_SetVar(interp, "blt_version", BLT_VERSION, TCL_GLOBAL_ONLY) == NULL) || (Tcl_SetVar(interp, "blt_patchLevel", BLT_PATCH_LEVEL, TCL_GLOBAL_ONLY) == NULL)) { return TCL_ERROR; } if (SetLibraryPath(interp) != TCL_OK) { return TCL_ERROR; } if (Tcl_Eval(interp, initScript) != TCL_OK) { return TCL_ERROR; } nsPtr = Tcl_CreateNamespace(interp, "blt", NULL, (Tcl_NamespaceDeleteProc *) NULL); if (nsPtr == NULL) { return TCL_ERROR; } /* Initialize the BLT commands that only require Tcl. */ for (p = tclCmds; *p != NULL; p++) { if ((**p) (interp) != TCL_OK) { Tcl_DeleteNamespace(nsPtr); return TCL_ERROR; } } args[0] = args[1] = TCL_EITHER; Tcl_CreateMathFunc(interp, "min", 2, args, MinMathProc, (ClientData)0); Tcl_CreateMathFunc(interp, "max", 2, args, MaxMathProc, (ClientData)0); Blt_RegisterArrayObj(interp); bltEmptyStringObjPtr = Tcl_NewStringObj("", -1); bltNaN = MakeNaN(); if (Tcl_PkgProvide(interp, "BLT", BLT_VERSION) != TCL_OK) { return TCL_ERROR; } tclLoaded = TRUE; } #ifndef TCL_ONLY if (!tkLoaded) { register Tcl_AppInitProc **p; Tcl_Namespace *nsPtr; #if (TCL_VERSION_NUMBER >= _VERSION(8,1,0)) if (Tcl_PkgPresent(interp, "Tk", TK_VERSION, EXACT) == NULL) { return TCL_OK; } #else if (Tcl_PkgRequire(interp, "Tk", TK_VERSION, EXACT) == NULL) { Tcl_ResetResult(interp); return TCL_OK; } #endif nsPtr = Tcl_CreateNamespace(interp, "blt::tile", NULL, (Tcl_NamespaceDeleteProc *) NULL); if (nsPtr == NULL) { return TCL_ERROR; } nsPtr = Tcl_FindNamespace(interp, "blt", (Tcl_Namespace *)NULL, TCL_LEAVE_ERR_MSG); if (nsPtr == NULL) { return TCL_ERROR; } /* Initialize the BLT commands that only use Tk too. */ for (p = tkCmds; *p != NULL; p++) { if ((**p) (interp) != TCL_OK) { Tcl_DeleteNamespace(nsPtr); return TCL_ERROR; } } Blt_InitEpsCanvasItem(interp); tkLoaded = TRUE; } #endif return TCL_OK; } #else /*LINTLIBRARY*/ EXPORT int Blt_Init(interp) Tcl_Interp *interp; /* Interpreter to add extra commands */ { if (!tclLoaded) { register Tcl_AppInitProc **p; Tcl_ValueType args[2]; /* * Check that the versions of Tcl that have been loaded are * the same ones that BLT was compiled against. */ if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, EXACT) == NULL) { return TCL_ERROR; } /* Set the "blt_version", "blt_patchLevel", and "blt_libPath" Tcl * variables. We'll use them in the following script. */ if ((Tcl_SetVar(interp, "blt_version", BLT_VERSION, TCL_GLOBAL_ONLY) == NULL) || (Tcl_SetVar(interp, "blt_patchLevel", BLT_PATCH_LEVEL, TCL_GLOBAL_ONLY) == NULL)) { return TCL_ERROR; } if (SetLibraryPath(interp) != TCL_OK) { return TCL_ERROR; } if (Tcl_Eval(interp, initScript) != TCL_OK) { return TCL_ERROR; } /* Initialize the BLT commands that only require Tcl. */ for (p = tclCmds; *p != NULL; p++) { if ((**p) (interp) != TCL_OK) { return TCL_ERROR; } } args[0] = args[1] = TCL_EITHER; Tcl_CreateMathFunc(interp, "min", 2, args, MinMathProc, (ClientData)0); Tcl_CreateMathFunc(interp, "max", 2, args, MaxMathProc, (ClientData)0); bltNaN = MakeNaN(); if (Tcl_PkgProvide(interp, "BLT", BLT_VERSION) != TCL_OK) { return TCL_ERROR; } tclLoaded = TRUE; } #ifndef TCL_ONLY if (!tkLoaded) { register Tcl_AppInitProc **p; #if (TCL_VERSION_NUMBER >= _VERSION(8,1,0)) if (Tcl_PkgPresent(interp, "Tk", TK_VERSION, EXACT) == NULL) { return TCL_OK; } #else if (Tcl_PkgRequire(interp, "Tk", TK_VERSION, EXACT) == NULL) { Tcl_ResetResult(interp); return TCL_OK; } #endif /* Initialize the BLT commands that use Tk too. */ for (p = tkCmds; *p != NULL; p++) { if ((**p) (interp) != TCL_OK) { return TCL_ERROR; } } Blt_InitEpsCanvasItem(interp); tkLoaded = TRUE; } #endif return TCL_OK; } #endif /* TCL_MAJOR_VERION >= 8 */ /*LINTLIBRARY*/ EXPORT int Blt_SafeInit(interp) Tcl_Interp *interp; /* Interpreter to add extra commands */ { return Blt_Init(interp); } /* *---------------------------------------------------------------------- * * Blt_InitCmd -- * * Given the name of a command, return a pointer to the * clientData field of the command. * * Results: * A standard TCL result. If the command is found, TCL_OK * is returned and clientDataPtr points to the clientData * field of the command (if the clientDataPtr in not NULL). * * Side effects: * If the command is found, clientDataPtr is set to the address * of the clientData of the command. If not found, an error * message is left in interp->result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ Tcl_Command Blt_InitCmd(interp, nsName, specPtr) Tcl_Interp *interp; char *nsName; Blt_CmdSpec *specPtr; { char *cmdPath; Tcl_DString dString; Tcl_Command cmdToken; Tcl_DStringInit(&dString); #if HAVE_NAMESPACES if (nsName != NULL) { Tcl_DStringAppend(&dString, nsName, -1); } Tcl_DStringAppend(&dString, "::", -1); #endif /* HAVE_NAMESPACES */ Tcl_DStringAppend(&dString, specPtr->name, -1); cmdPath = Tcl_DStringValue(&dString); cmdToken = Tcl_FindCommand(interp, cmdPath, (Tcl_Namespace *)NULL, 0); if (cmdToken != NULL) { Tcl_DStringFree(&dString); return cmdToken; /* Assume command was already initialized */ } cmdToken = Tcl_CreateCommand(interp, cmdPath, specPtr->cmdProc, specPtr->clientData, specPtr->cmdDeleteProc); Tcl_DStringFree(&dString); #if (HAVE_NAMESPACES) && (TCL_MAJOR_VERSION > 7) { Tcl_Namespace *nsPtr; int dontResetList = 0; nsPtr = Tcl_FindNamespace(interp, nsName, (Tcl_Namespace *)NULL, TCL_LEAVE_ERR_MSG); if (nsPtr == NULL) { return NULL; } if (Tcl_Export(interp, nsPtr, specPtr->name, dontResetList) != TCL_OK) { return NULL; } } #endif /* TCL_MAJOR_VERSION > 7 */ return cmdToken; } #if (TCL_MAJOR_VERSION > 7) /* *---------------------------------------------------------------------- * * Blt_InitObjCmd -- * * Given the name of a command, return a pointer to the * clientData field of the command. * * Results: * A standard TCL result. If the command is found, TCL_OK * is returned and clientDataPtr points to the clientData * field of the command (if the clientDataPtr in not NULL). * * Side effects: * If the command is found, clientDataPtr is set to the address * of the clientData of the command. If not found, an error * message is left in interp->result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ Tcl_Command Blt_InitObjCmd(interp, nsName, specPtr) Tcl_Interp *interp; char *nsName; Blt_ObjCmdSpec *specPtr; { char *cmdPath; Tcl_DString dString; Tcl_Command cmdToken; Tcl_Namespace *nsPtr; Tcl_DStringInit(&dString); if (nsName != NULL) { Tcl_DStringAppend(&dString, nsName, -1); } Tcl_DStringAppend(&dString, "::", -1); Tcl_DStringAppend(&dString, specPtr->name, -1); cmdPath = Tcl_DStringValue(&dString); cmdToken = Tcl_FindCommand(interp, cmdPath, (Tcl_Namespace *)NULL, 0); if (cmdToken != NULL) { Tcl_DStringFree(&dString); return cmdToken; /* Assume command was already initialized */ } cmdToken = Tcl_CreateObjCommand(interp, cmdPath, (Tcl_ObjCmdProc *)specPtr->cmdProc, specPtr->clientData, specPtr->cmdDeleteProc); Tcl_DStringFree(&dString); nsPtr = Tcl_FindNamespace(interp, nsName, (Tcl_Namespace *)NULL, TCL_LEAVE_ERR_MSG); if (nsPtr == NULL) { return NULL; } if (Tcl_Export(interp, nsPtr, specPtr->name, FALSE) != TCL_OK) { return NULL; } return cmdToken; } #endif /* TCL_MAJOR_VERSION > 7 */ /* *---------------------------------------------------------------------- * * Blt_InitCmds -- * * Given the name of a command, return a pointer to the * clientData field of the command. * * Results: * A standard TCL result. If the command is found, TCL_OK * is returned and clientDataPtr points to the clientData * field of the command (if the clientDataPtr in not NULL). * * Side effects: * If the command is found, clientDataPtr is set to the address * of the clientData of the command. If not found, an error * message is left in interp->result. * *---------------------------------------------------------------------- */ int Blt_InitCmds(interp, nsName, specPtr, nCmds) Tcl_Interp *interp; char *nsName; Blt_CmdSpec *specPtr; int nCmds; { Blt_CmdSpec *endPtr; for (endPtr = specPtr + nCmds; specPtr < endPtr; specPtr++) { if (Blt_InitCmd(interp, nsName, specPtr) == NULL) { return TCL_ERROR; } } return TCL_OK; } blt-2.4z.orig/src/bltInt.h0100644000175000017500000006505407530772130014156 0ustar dokodoko /* * bltInt.h -- * * Copyright 1993-1998 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. */ #ifndef _BLT_INT_H #define _BLT_INT_H #ifdef WIN32 #define STRICT #define WIN32_LEAN_AND_MEAN #include #undef STRICT #undef WIN32_LEAN_AND_MEAN #include #endif /* WIN32 */ #define USE_NON_CONST #include #define USE_COMPOSITELESS_PHOTO_PUT_BLOCK #include #define _VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) #define TCL_VERSION_NUMBER _VERSION(TCL_MAJOR_VERSION, TCL_MINOR_VERSION, TCL_RELEASE_SERIAL) #define TK_VERSION_NUMBER _VERSION(TK_MAJOR_VERSION, TK_MINOR_VERSION, TK_RELEASE_SERIAL) #include "bltTkInt.h" #include #include #if defined(WIN32) && !defined(__GNUC__) #include "bltWinConfig.h" #else #include "bltConfig.h" #endif #ifdef WIN32 #ifndef EXPORT #if defined(_MSC_VER) || defined(__BORLANDC__) #define EXPORT __declspec(dllexport) #else #define EXPORT #endif /* _MSC_VER || __BORLANDC__ */ #endif /* EXPORT */ /* Misc. definitions */ #define NO_CUTBUFFER 1 #define NO_TILESCROLLBAR 1 #define NO_DND 1 #ifndef __GNUC__ #ifdef O_NONBLOCK #define O_NONBLOCK 1 #endif #endif /* __GNUC__ */ #endif /* WIN32 */ #include "blt.h" #include "bltNsUtil.h" #ifdef HAVE_STDLIB_H #include #endif /* HAVE_STDLIB_H */ #ifdef HAVE_STRING_H #include #endif /* HAVE_STRING_H */ #ifdef HAVE_ERRNO_H #include #endif /* HAVE_ERRNO_H */ #ifdef HAVE_CTYPE_H #include #endif /* HAVE_CTYPE_H */ #ifdef HAVE_MEMORY_H #include #endif /* HAVE_MEMORY_H */ #ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #ifdef HAVE_LIMITS_H #include #endif #include "bltMath.h" #undef INLINE #ifdef __GNUC__ #define INLINE inline #else #define INLINE #endif #undef EXPORT #define EXPORT #undef VARARGS #ifdef __cplusplus #define ANYARGS (...) #define VARARGS(first) (first, ...) #define VARARGS2(first, second) (first, second, ...) #else #define ANYARGS () #define VARARGS(first) () #define VARARGS2(first, second) () #endif /* __cplusplus */ #undef MIN #define MIN(a,b) (((a)<(b))?(a):(b)) #undef MAX #define MAX(a,b) (((a)>(b))?(a):(b)) #undef MIN3 #define MIN3(a,b,c) (((a)<(b))?(((a)<(c))?(a):(c)):(((b)<(c))?(b):(c))) #undef MAX3 #define MAX3(a,b,c) (((a)>(b))?(((a)>(c))?(a):(c)):(((b)>(c))?(b):(c))) #define TRUE 1 #define FALSE 0 /* * The macro below is used to modify a "char" value (e.g. by casting * it to an unsigned character) so that it can be used safely with * macros such as isspace. */ #define UCHAR(c) ((unsigned char) (c)) #undef panic #define panic(mesg) Blt_Panic("%s:%d %s", __FILE__, __LINE__, (mesg)) /* * Since the Tcl/Tk distribution doesn't perform any asserts, dynamic * loading can fail to find the __assert function. As a workaround, * we'll include our own. */ #undef assert #ifdef NDEBUG #define assert(EX) ((void)0) #else extern void Blt_Assert _ANSI_ARGS_((char *expr, char *file, int line)); #ifdef __STDC__ #define assert(EX) (void)((EX) || (Blt_Assert(#EX, __FILE__, __LINE__), 0)) #else #define assert(EX) (void)((EX) || (Blt_Assert("EX", __FILE__, __LINE__), 0)) #endif /* __STDC__ */ #endif /* NDEBUG */ #if (TCL_MAJOR_VERSION >= 8) extern Tcl_Obj *bltEmptyStringObjPtr; #endif /* TCL_MAJOR_VERSION >= 8 */ /* * ---------------------------------------------------------------------- * * Blt_CmdSpec -- * * ---------------------------------------------------------------------- */ typedef struct { char *name; /* Name of command */ Tcl_CmdProc *cmdProc; Tcl_CmdDeleteProc *cmdDeleteProc; ClientData clientData; } Blt_CmdSpec; #if (TCL_MAJOR_VERSION >= 8) /* * ---------------------------------------------------------------------- * * Blt_CmdSpec -- * * ---------------------------------------------------------------------- */ typedef struct { char *name; /* Name of command */ Tcl_ObjCmdProc *cmdProc; Tcl_CmdDeleteProc *cmdDeleteProc; ClientData clientData; } Blt_ObjCmdSpec; #endif /* TCL_MAJOR_VERSION >= 8 */ /* * ---------------------------------------------------------------------- * * Blt_Op -- * * Generic function prototype of CmdOptions. * * ---------------------------------------------------------------------- */ typedef int (*Blt_Op) _ANSI_ARGS_(ANYARGS); /* * ---------------------------------------------------------------------- * * Blt_OpSpec -- * * Structure to specify a set of operations for a Tcl command. * This is passed to the Blt_GetOp procedure to look * for a function pointer associated with the operation name. * * ---------------------------------------------------------------------- */ typedef struct { char *name; /* Name of operation */ int minChars; /* Minimum # characters to disambiguate */ Blt_Op proc; int minArgs; /* Minimum # args required */ int maxArgs; /* Maximum # args required */ 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; #define BLT_OP_LINEAR_SEARCH 1 #define BLT_OP_BINARY_SEARCH 0 extern Blt_Op Blt_GetOp _ANSI_ARGS_((Tcl_Interp *interp, int nSpecs, Blt_OpSpec *specArr, int operPos, int argc, char **argv, int flags)); #if (TCL_VERSION_NUMBER >= _VERSION(8,0,0)) extern Blt_Op Blt_GetOpFromObj _ANSI_ARGS_((Tcl_Interp *interp, int nSpecs, Blt_OpSpec *specArr, int operPos, int objc, Tcl_Obj *CONST *objv, int flags)); #endif /* * ---------------------------------------------------------------------- * * Assume we need to declare free if there's no stdlib.h or malloc.h * * ---------------------------------------------------------------------- */ #if !defined(HAVE_STDLIB_H) && !defined(HAVE_MALLOC_H) extern void free _ANSI_ARGS_((void *)); #endif #define free(x) abc123(x) extern int Blt_DictionaryCompare _ANSI_ARGS_((char *s1, char *s2)); EXTERN void Blt_Panic _ANSI_ARGS_(TCL_VARARGS(char *, args)); extern void Blt_Draw3DRectangle _ANSI_ARGS_((Tk_Window tkwin, Drawable drawable, Tk_3DBorder border, int x, int y, int width, int height, int borderWidth, int relief)); extern void Blt_Fill3DRectangle _ANSI_ARGS_((Tk_Window tkwin, Drawable drawable, Tk_3DBorder border, int x, int y, int width, int height, int borderWidth, int relief)); #ifdef notdef #define Blt_Fill3DRectangle Tk_Fill3DRectangle #define Blt_Draw3DRectangle Tk_Draw3DRectangle #endif /* ---------------------------------------------------------------- */ #define PIXELS_NONNEGATIVE 0 #define PIXELS_POSITIVE 1 #define PIXELS_ANY 2 #define COUNT_NONNEGATIVE 0 #define COUNT_POSITIVE 1 #define COUNT_ANY 2 #define BLT_SCROLL_MODE_CANVAS (1<<0) #define BLT_SCROLL_MODE_LISTBOX (1<<1) #define BLT_SCROLL_MODE_HIERBOX (1<<2) #define RGB_ANTIQUEWHITE1 "#ffefdb" #define RGB_BISQUE1 "#ffe4c4" #define RGB_BISQUE2 "#eed5b7" #define RGB_BISQUE3 "#cdb79e" #define RGB_BLACK "#000000" #define RGB_BLUE "#0000ff" #define RGB_GREEN "#00ff00" #define RGB_GREY "#b0b0b0" #define RGB_GREY15 "#262626" #define RGB_GREY50 "#7f7f7f" #define RGB_GREY64 "#a3a3a3" #define RGB_GREY70 "#b3b3b3" #define RGB_GREY75 "#bfbfbf" #define RGB_GREY77 "#c3c3c3" #define RGB_GREY82 "#d1d1d1" #define RGB_GREY85 "#d9d9d9" #define RGB_GREY90 "#e5e5e5" #define RGB_GREY95 "#f2f2f2" #define RGB_LIGHTBLUE0 "#e4f7ff" #define RGB_LIGHTBLUE1 "#bfefff" #define RGB_LIGHTBLUE2 "#b2dfee" #define RGB_LIGHTSKYBLUE1 "#b0e2ff" #define RGB_MAROON "#b03060" #define RGB_NAVYBLUE "#000080" #define RGB_PINK "#ffc0cb" #define RGB_BISQUE1 "#ffe4c4" #define RGB_RED "#ff0000" #define RGB_WHITE "#ffffff" #define RGB_YELLOW "#ffff00" #ifdef OLD_TK_COLORS #define STD_NORMAL_BACKGROUND RGB_BISQUE1 #define STD_ACTIVE_BACKGROUND RGB_BISQUE2 #define STD_SELECT_BACKGROUND RGB_LIGHTBLUE1 #define STD_DISABLE_FOREGROUND RGB_GREY64 #else #define STD_NORMAL_BACKGROUND RGB_GREY85 #define STD_ACTIVE_BACKGROUND RGB_GREY64 #define STD_SELECT_BACKGROUND RGB_LIGHTBLUE1 #define STD_DISABLE_FOREGROUND RGB_GREY64 #endif /* OLD_TK_COLORS */ #define STD_ACTIVE_BG_MONO RGB_BLACK #define STD_ACTIVE_FOREGROUND RGB_BLACK #define STD_ACTIVE_FG_MONO RGB_WHITE #define STD_BORDERWIDTH "2" #define STD_FONT "*-Helvetica-Medium-R-Normal-*-12-120-*" #define STD_FONT_HUGE "*-Helvetica-Medium-R-Normal-*-18-180-*" #define STD_FONT_LARGE "*-Helvetica-Medium-R-Normal-*-14-140-*" #define STD_FONT_SMALL "*-Helvetica-Medium-R-Normal-*-10-100-*" #define STD_INDICATOR_COLOR RGB_MAROON #define STD_NORMAL_BG_MONO RGB_WHITE #define STD_NORMAL_FOREGROUND RGB_BLACK #define STD_NORMAL_FG_MONO RGB_BLACK #define STD_SELECT_BG_MONO RGB_BLACK #define STD_SELECT_BORDERWIDTH "2" #define STD_SELECT_FOREGROUND RGB_BLACK #define STD_SELECT_FG_MONO RGB_WHITE #define STD_SHADOW_COLOR RGB_GREY64 #define STD_SHADOW_MONO RGB_BLACK #define LineWidth(w) (((w) > 1) ? (w) : 0) #ifdef TCL_UTF_MAX #define HAVE_UTF 1 extern FILE *Blt_OpenUtfFile _ANSI_ARGS_((char *fileName, char *mode)); #define fopen(f,m) Blt_OpenUtfFile((f),(m)); #else #define HAVE_UTF 0 #endif /* TCL_UTF_MAX */ typedef char *DestroyData; #ifndef TK_RELIEF_SOLID #define TK_RELIEF_SOLID TK_RELIEF_FLAT #endif /* * Tcl/Tk Backward compatibility section. */ #if (TCL_MAJOR_VERSION > 7) #define NO_FLAGS 0 #define Blt_FindPhoto(interp, name) Tk_FindPhoto(interp, name) #else #define Tcl_GetStringResult(interp) ((interp)->result) #define Blt_FindPhoto(interp, name) Tk_FindPhoto(name) #define Tcl_DeleteCommandFromToken(interp, token) \ Tcl_DeleteCommand(interp, Tcl_GetCommandName(interp, token)) /* *-------------------------------------------------------------- * * The definitions below provide foreward compatibility for * functions and types related to event handling that used to * be in Tk but have moved to Tcl. * *-------------------------------------------------------------- */ #define Tcl_IdleProc Tk_IdleProc #define Tcl_FileProc Tk_FileProc #define Tcl_TimerProc Tk_TimerProc #define Tcl_TimerToken Tk_TimerToken #define Tcl_BackgroundError Tk_BackgroundError #define Tcl_CancelIdleCall Tk_CancelIdleCall #define Tcl_CreateTimerHandler Tk_CreateTimerHandler #define Tcl_DeleteTimerHandler Tk_DeleteTimerHandler #define Tcl_DoOneEvent Tk_DoOneEvent #define Tcl_DoWhenIdle Tk_DoWhenIdle #define Tcl_Sleep Tk_Sleep /* Additional stuff that has moved to Tcl: */ #define Tcl_AfterCmd Tk_AfterCmd #define Tcl_EventuallyFree Tk_EventuallyFree #define Tcl_FreeProc Tk_FreeProc #define Tcl_Preserve Tk_Preserve #define Tcl_Release Tk_Release #endif /* TCL_MAJOR_VERSION > 7 */ typedef int (QSortCompareProc) _ANSI_ARGS_((const void *, const void *)); /* * ---------------------------------------------------------------------- * * Blt_Pad -- * * Specifies vertical and horizontal padding. * * Padding can be specified on a per side basis. The fields * side1 and side2 refer to the opposite sides, either * horizontally or vertically. * * side1 side2 * ----- ----- * x | left right * y | top bottom * * ---------------------------------------------------------------------- */ typedef struct { short int side1, side2; } Blt_Pad; #define padLeft padX.side1 #define padRight padX.side2 #define padTop padY.side1 #define padBottom padY.side2 #define PADDING(x) ((x).side1 + (x).side2) /* * ---------------------------------------------------------------------- * * The following enumerated values are used as bit flags. * FILL_NONE Neither coordinate plane is specified * FILL_X Horizontal plane. * FILL_Y Vertical plane. * FILL_BOTH Both vertical and horizontal planes. * * ---------------------------------------------------------------------- */ #define FILL_NONE 0 #define FILL_X 1 #define FILL_Y 2 #define FILL_BOTH 3 /* * ---------------------------------------------------------------------- * * Blt_Dashes -- * * List of dash values (maximum 11 based upon PostScript limit). * * ---------------------------------------------------------------------- */ typedef struct { unsigned char values[12]; int offset; } Blt_Dashes; #define LineIsDashed(d) ((d).values[0] != 0) extern void Blt_SetDashes _ANSI_ARGS_((Display *display, GC gc, Blt_Dashes *dashesPtr)); extern Blt_Dashes *Blt_GetDashes _ANSI_ARGS_((GC gc)); /* * ------------------------------------------------------------------- * * Point2D -- * * 2-D coordinate. * * ------------------------------------------------------------------- */ typedef struct { double x, y; } Point2D; /* * ------------------------------------------------------------------- * * Point3D -- * * 3-D coordinate. * * ------------------------------------------------------------------- */ typedef struct { double x, y, z; } Point3D; /* * ------------------------------------------------------------------- * * Segment2D -- * * 2-D line segment. * * ------------------------------------------------------------------- */ typedef struct { Point2D p, q; /* The two end points of the segment. */ } Segment2D; /* * ------------------------------------------------------------------- * * Dim2D -- * * 2-D dimension. * * ------------------------------------------------------------------- */ typedef struct { short int width, height; } Dim2D; /* *---------------------------------------------------------------------- * * Region2D -- * * 2-D region. Used to copy parts of images. * *---------------------------------------------------------------------- */ typedef struct { int left, right, top, bottom; } Region2D; #define RegionWidth(r) ((r)->right - (r)->left + 1) #define RegionHeight(r) ((r)->bottom - (r)->top + 1) typedef struct { double left, right, top, bottom; } Extents2D; typedef struct { double left, right, top, bottom, front, back; } Extents3D; #define PointInRegion(e,x,y) \ (((x) <= (e)->right) && ((x) >= (e)->left) && \ ((y) <= (e)->bottom) && ((y) >= (e)->top)) #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)) /* ------------------------------------------------------------------- * * ColorPair -- * * Holds a pair of foreground, background colors. * * ------------------------------------------------------------------- */ typedef struct { XColor *fgColor, *bgColor; } ColorPair; #define COLOR_NONE (XColor *)0 #define COLOR_DEFAULT (XColor *)1 #define COLOR_ALLOW_DEFAULTS 1 extern int Blt_GetColorPair _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, char *fgColor, char *bgColor, ColorPair *pairPtr, int colorFlag)); extern void Blt_FreeColorPair _ANSI_ARGS_((ColorPair *pairPtr)); #define STATE_NORMAL 0 #define STATE_ACTIVE (1<<0) #define STATE_DISABLED (1<<1) #define STATE_EMPHASIS (1<<2) #define ARROW_LEFT (0) #define ARROW_UP (1) #define ARROW_RIGHT (2) #define ARROW_DOWN (3) #define ARROW_OFFSET 4 #define STD_ARROW_HEIGHT 3 #define STD_ARROW_WIDTH ((2 * (ARROW_OFFSET - 1)) + 1) #include "bltText.h" /* * ---------------------------------------------------------------------- * * X11/Xosdefs.h requires XNOSTDHDRS be set for some systems. * This is a guess. If I can't find STDC headers or unistd.h, * assume that this is non-POSIX and non-STDC environment. * (needed for Encore Umax 3.4 ?) * * ---------------------------------------------------------------------- */ #if !defined(STDC_HEADERS) && !defined(HAVE_UNISTD_H) #define XNOSTDHDRS 1 #endif extern char *Blt_Itoa _ANSI_ARGS_((int value)); extern char *Blt_Utoa _ANSI_ARGS_((unsigned int value)); extern char *Blt_Dtoa _ANSI_ARGS_((Tcl_Interp *interp, double value)); extern Tcl_Command Blt_InitCmd _ANSI_ARGS_((Tcl_Interp *interp, char *namespace, Blt_CmdSpec *specPtr)); #if (TCL_VERSION_NUMBER >= _VERSION(8,0,0)) extern Tcl_Command Blt_InitObjCmd _ANSI_ARGS_((Tcl_Interp *interp, char *namespace, Blt_ObjCmdSpec *specPtr)); #if (TCL_VERSION_NUMBER < _VERSION(8,1,0)) extern char *Tcl_GetString _ANSI_ARGS_((Tcl_Obj *objPtr)); extern int Tcl_EvalObjv _ANSI_ARGS_((Tcl_Interp *interp, int objc, Tcl_Obj **objv, int flags)); extern int Tcl_WriteObj _ANSI_ARGS_((Tcl_Channel channel, Tcl_Obj *objPtr)); extern char *Tcl_SetVar2Ex _ANSI_ARGS_((Tcl_Interp *interp, char *part1, char *part2, Tcl_Obj *objPtr, int flags)); extern Tcl_Obj *Tcl_GetVar2Ex _ANSI_ARGS_((Tcl_Interp *interp, char *part1, char *part2, int flags)); #endif /* TCL_VERSION_NUMBER < 8.2.0 */ #endif /* TCL_VERSION_NUMBER >= 8.0.0 */ extern int Blt_InitCmds _ANSI_ARGS_((Tcl_Interp *interp, char *namespace, Blt_CmdSpec *specPtr, int nCmds)); extern int Blt_NaturalSpline _ANSI_ARGS_((Point2D *origPts, int nOrigPts, Point2D *intpPts, int nIntpPts)); extern int Blt_QuadraticSpline _ANSI_ARGS_((Point2D *origPts, int nOrigPts, Point2D *intpPts, int nIntpPts)); extern int Blt_SimplifyLine _ANSI_ARGS_((Point2D *origPts, int low, int high, double tolerance, int indices[])); extern int Blt_NaturalParametricSpline _ANSI_ARGS_((Point2D *origPts, int nOrigPts, Extents2D *extsPtr, int isClosed, Point2D *intpPts, int nIntpPts)); extern int Blt_CatromParametricSpline _ANSI_ARGS_((Point2D *origPts, int nOrigPts, Point2D *intpPts, int nIntpPts)); extern int Blt_StringToFlag _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *string, char *widgRec, int flags)); extern char *Blt_FlagToString _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, char *string, int offset, Tcl_FreeProc **freeProc)); extern void Blt_InitHexTable _ANSI_ARGS_((char *table)); extern GC Blt_GetPrivateGC _ANSI_ARGS_((Tk_Window tkwin, unsigned long gcMask, XGCValues *valuePtr)); extern GC Blt_GetPrivateGCFromDrawable _ANSI_ARGS_((Display *display, Drawable drawable, unsigned long gcMask, XGCValues *valuePtr)); extern void Blt_FreePrivateGC _ANSI_ARGS_((Display *display, GC gc)); extern Tk_Window Blt_FindChild _ANSI_ARGS_((Tk_Window parent, char *name)); extern Tk_Window Blt_FirstChild _ANSI_ARGS_((Tk_Window parent)); extern Tk_Window Blt_NextChild _ANSI_ARGS_((Tk_Window tkwin)); extern void Blt_RelinkWindow _ANSI_ARGS_((Tk_Window tkwin, Tk_Window newParent, int x, int y)); extern Tk_Window Blt_Toplevel _ANSI_ARGS_((Tk_Window tkwin)); extern int Blt_GetPixels _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, char *string, int check, int *valuePtr)); extern int Blt_GetPosition _ANSI_ARGS_((Tcl_Interp *interp, char *string, int *indexPtr)); extern int Blt_GetCount _ANSI_ARGS_((Tcl_Interp *interp, char *string, int check, int *valuePtr)); extern char *Blt_NameOfFill _ANSI_ARGS_((int fill)); extern int Blt_GetXY _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, char *string, int *x, int *y)); extern Point2D Blt_GetProjection _ANSI_ARGS_((int x, int y, Point2D *p, Point2D *q)); extern void Blt_DrawArrow _ANSI_ARGS_((Display *display, Drawable drawable, GC gc, int x, int y, int arrowHeight, int orientation)); extern Tk_OptionParseProc Blt_StringToEnum; extern Tk_OptionPrintProc Blt_EnumToString; extern int Blt_ConfigModified _ANSI_ARGS_(TCL_VARARGS(Tk_ConfigSpec *, specs)); extern void Blt_DStringAppendElements _ANSI_ARGS_(TCL_VARARGS(Tcl_DString *, args)); extern void Blt_MakeTransparentWindowExist _ANSI_ARGS_((Tk_Window tkwin, Window parent, int isBusy)); extern Window Blt_GetParent _ANSI_ARGS_((Display *display, Window tkwin)); extern void Blt_GetBoundingBox _ANSI_ARGS_((int width, int height, double theta, double *widthPtr, double *heightPtr, Point2D *points)); extern void Blt_InitEpsCanvasItem _ANSI_ARGS_((Tcl_Interp *interp)); extern void Blt_TranslateAnchor _ANSI_ARGS_((int x, int y, int width, int height, Tk_Anchor anchor, int *transXPtr, int *transYPtr)); extern Point2D Blt_TranslatePoint _ANSI_ARGS_((Point2D *pointPtr, int width, int height, Tk_Anchor anchor)); extern int Blt_ConfigureWidgetComponent _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, char *name, char *class, Tk_ConfigSpec *specs, int argc, char **argv, char *widgRec, int flags)); extern void Blt_HSV _ANSI_ARGS_((XColor *colorPtr, double *huePtr, double *valPtr, double *satPtr)); extern void Blt_RGB _ANSI_ARGS_((double hue, double sat, double val, XColor *colorPtr)); extern int Blt_ParseFlag _ANSI_ARGS_((ClientData, Tcl_Interp *, Tk_Window, char *, char *, int)); extern char *Blt_FlagPrint _ANSI_ARGS_((ClientData, Tk_Window, char *, int, Tcl_FreeProc **)); extern int Blt_MaxRequestSize _ANSI_ARGS_((Display *display, unsigned int elemSize)); extern Window Blt_GetRealWindowId _ANSI_ARGS_((Tk_Window tkwin)); extern int Blt_RootX _ANSI_ARGS_((Tk_Window tkwin)); extern int Blt_RootY _ANSI_ARGS_((Tk_Window tkwin)); extern void Blt_RootCoordinates _ANSI_ARGS_((Tk_Window tkwin, int x, int y, int *rootXPtr, int *rootYPtr)); extern void Blt_MapToplevel _ANSI_ARGS_((Tk_Window tkwin)); extern void Blt_UnmapToplevel _ANSI_ARGS_((Tk_Window tkwin)); extern void Blt_RaiseToplevel _ANSI_ARGS_((Tk_Window tkwin)); extern void Blt_LowerToplevel _ANSI_ARGS_((Tk_Window tkwin)); extern void Blt_ResizeToplevel _ANSI_ARGS_((Tk_Window tkwin, int width, int height)); extern void Blt_MoveToplevel _ANSI_ARGS_((Tk_Window tkwin, int x, int y)); extern void Blt_MoveResizeToplevel _ANSI_ARGS_((Tk_Window tkwin, int x, int y, int width, int height)); extern ClientData Blt_GetWindowInstanceData _ANSI_ARGS_((Tk_Window tkwin)); extern void Blt_SetWindowInstanceData _ANSI_ARGS_((Tk_Window tkwin, ClientData instanceData)); extern void Blt_DeleteWindowInstanceData _ANSI_ARGS_((Tk_Window tkwin)); extern int Blt_AdjustViewport _ANSI_ARGS_((int offset, int worldSize, int windowSize, int scrollUnits, int scrollMode)); extern int Blt_GetScrollInfo _ANSI_ARGS_((Tcl_Interp *interp, int argc, char **argv, int *offsetPtr, int worldSize, int windowSize, int scrollUnits, int scrollMode)); #if (TK_MAJOR_VERSION >= 8) extern int Blt_GetScrollInfoFromObj _ANSI_ARGS_((Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv, int *offsetPtr, int worldSize, int windowSize, int scrollUnits, int scrollMode)); #endif extern void Blt_UpdateScrollbar _ANSI_ARGS_((Tcl_Interp *interp, char *scrollCmd, double firstFract, double lastFract)); extern int Blt_ReparentWindow _ANSI_ARGS_((Display *display, Window window, Window newParent, int x, int y)); #if defined(HAVE_JPEGLIB_H) || defined(HAVE_IJL_H) #define HAVE_JPEG 1 extern int Blt_JPEGToPhoto _ANSI_ARGS_((Tcl_Interp *interp, char *fileName, Tk_PhotoHandle photo)); #endif /* HAVE_JPEGLIB_H || HAVE_IJL_H */ #define Blt_SetBooleanResult(i, b) \ Tcl_SetResult((i), (b) ? "1" : "0", TCL_STATIC) /* * Define this if you want to be able to tile to the main window "." * This will cause a conflict with Tk if you try to compile and link * statically. */ #undef TILE_MAINWINDOW #ifdef WIN32 #if (TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION == 0) #else #define NO_DDE 1 #endif #else #define NO_DDE 1 #define NO_PRINTER 1 #endif /* WIN32 */ #if (TCL_MAJOR_VERSION == 7) #define NO_TREE 1 #define NO_ARRAY 1 #define NO_TREEVIEW 1 #endif /* #define NO_TED */ #ifndef NO_BEEP extern Tcl_AppInitProc Blt_BeepInit; #endif #ifndef NO_BGEXEC extern Tcl_AppInitProc Blt_BgexecInit; #endif #ifndef NO_BITMAP extern Tcl_AppInitProc Blt_BitmapInit; #endif #ifndef NO_BUSY extern Tcl_AppInitProc Blt_BusyInit; #endif #ifndef NO_CONTAINER extern Tcl_AppInitProc Blt_ContainerInit; #endif #ifndef NO_CRC32 extern Tcl_AppInitProc Blt_Crc32Init; #endif #ifndef NO_CUTBUFFER extern Tcl_AppInitProc Blt_CutbufferInit; #endif #ifndef NO_DEBUG extern Tcl_AppInitProc Blt_DebugInit; #endif #ifndef NO_DRAGDROP extern Tcl_AppInitProc Blt_DragDropInit; #endif #ifndef NO_DND extern Tcl_AppInitProc Blt_DndInit; #endif #ifndef NO_GRAPH extern Tcl_AppInitProc Blt_GraphInit; #endif #ifndef NO_HIERBOX extern Tcl_AppInitProc Blt_HierboxInit; #endif #ifndef NO_HIERTABLE extern Tcl_AppInitProc Blt_HiertableInit; #endif #ifndef NO_HTEXT extern Tcl_AppInitProc Blt_HtextInit; #endif #ifdef WIN32 #ifndef NO_PRINTER extern Tcl_AppInitProc Blt_PrinterInit; #endif #endif #ifndef NO_TABLE extern Tcl_AppInitProc Blt_TableInit; #endif #ifndef NO_VECTOR extern Tcl_AppInitProc Blt_VectorInit; #endif #ifndef NO_WINOP extern Tcl_AppInitProc Blt_WinopInit; #endif #ifndef NO_WATCH extern Tcl_AppInitProc Blt_WatchInit; #endif #ifndef NO_SPLINE extern Tcl_AppInitProc Blt_SplineInit; #endif #ifndef NO_TABSET extern Tcl_AppInitProc Blt_TabsetInit; #endif #ifndef NO_TABNOTEBOOK extern Tcl_AppInitProc Blt_TabnotebookInit; #endif #ifndef NO_TREE extern Tcl_AppInitProc Blt_TreeInit; #endif #ifndef NO_TREEVIEW extern Tcl_AppInitProc Blt_TreeViewInit; #endif #ifndef NO_TILEFRAME extern Tcl_AppInitProc Blt_FrameInit; #endif #ifndef NO_TILEBUTTON extern Tcl_AppInitProc Blt_ButtonInit; #endif #ifndef NO_TILESCROLLBAR extern Tcl_AppInitProc Blt_ScrollbarInit; #endif #if (BLT_MAJOR_VERSION == 3) #ifndef NO_MOUNTAIN extern Tcl_AppInitProc Blt_MountainInit; #endif #endif #ifndef NO_TED extern Tcl_AppInitProc Blt_TedInit; #endif #ifndef NO_DDE extern Tcl_AppInitProc Blt_DdeInit; #endif typedef void *(Blt_MallocProc) _ANSI_ARGS_((size_t size)); typedef void *(Blt_CallocProc) _ANSI_ARGS_((int nElem, size_t size)); typedef void *(Blt_ReallocProc) _ANSI_ARGS_((void *ptr, size_t size)); typedef void (Blt_FreeProc) _ANSI_ARGS_((void *ptr)); EXTERN Blt_MallocProc *Blt_MallocProcPtr; EXTERN Blt_FreeProc *Blt_FreeProcPtr; EXTERN Blt_ReallocProc *Blt_ReallocProcPtr; #define Blt_Malloc(size) (*Blt_MallocProcPtr)(size) #define Blt_Free (*Blt_FreeProcPtr) #define Blt_Realloc(ptr, size) (*Blt_ReallocProcPtr)(ptr, size) EXTERN char *Blt_Strdup _ANSI_ARGS_((CONST char *ptr)); EXTERN void *Blt_Calloc _ANSI_ARGS_((unsigned int nElem, size_t size)); #ifdef WIN32 #include "bltWin.h" #endif #ifndef WIN32 #define PurifyPrintf printf #endif /* WIN32 */ #endif /*_BLT_INT_H*/ blt-2.4z.orig/src/bltInterp.h0100644000175000017500000003554707403601146014666 0ustar dokodoko/* * bltInterp.h -- * * Excerpts from tclInt.h. Used to examine interpreter internals. * Needed by the former (now obsoleted) TclParse* functions. * * Copyright (c) 1987-1993 The Regents of the University of California. * Copyright (c) 1993-1997 Lucent Technologies. * Copyright (c) 1994-1998 Sun Microsystems, Inc. * */ /* *---------------------------------------------------------------- * Data structures related to command parsing. These are used in * tclParse.c and its clients. *---------------------------------------------------------------- */ /* * The following data structure is used by various parsing procedures * to hold information about where to store the results of parsing * (e.g. the substituted contents of a quoted argument, or the result * of a nested command). At any given time, the space available * for output is fixed, but a procedure may be called to expand the * space available if the current space runs out. */ typedef struct ParseValueStruct ParseValue; struct ParseValueStruct { char *buffer; /* Address of first character in * output buffer. */ char *next; /* Place to store next character in * output buffer. */ char *end; /* Address of the last usable character * in the buffer. */ void (*expandProc) _ANSI_ARGS_((ParseValue *pvPtr, int needed)); /* Procedure to call when space runs out; * it will make more space. */ ClientData clientData; /* Arbitrary information for use of * expandProc. */ }; /* * The definitions for the LiteralTable and LiteralEntry structures. Each * interpreter contains a LiteralTable. It is used to reduce the storage * needed for all the Tcl objects that hold the literals of scripts compiled * by the interpreter. A literal's object is shared by all the ByteCodes * that refer to the literal. Each distinct literal has one LiteralEntry * entry in the LiteralTable. A literal table is a specialized hash table * that is indexed by the literal's string representation, which may contain * null characters. * * Note that we reduce the space needed for literals by sharing literal * objects both within a ByteCode (each ByteCode contains a local * LiteralTable) and across all an interpreter's ByteCodes (with the * interpreter's global LiteralTable). */ typedef struct LiteralEntryStruct LiteralEntry; struct LiteralEntryStruct { LiteralEntry *nextPtr; /* Points to next entry in this * hash bucket or NULL if end of * chain. */ Tcl_Obj *objPtr; /* Points to Tcl object that * holds the literal's bytes and * length. */ int refCount; /* If in an interpreter's global * literal table, the number of * ByteCode structures that share * the literal object; the literal * entry can be freed when refCount * drops to 0. If in a local literal * table, -1. */ }; typedef struct { LiteralEntry **buckets; /* Pointer to bucket array. Each * element points to first entry in * bucket's hash chain, or NULL. */ LiteralEntry *staticBuckets[TCL_SMALL_HASH_TABLE]; /* Bucket array used for small * tables to avoid mallocs and * frees. */ int numBuckets; /* Total number of buckets allocated * at **buckets. */ int numEntries; /* Total number of entries present * in table. */ int rebuildSize; /* Enlarge table when numEntries * gets to be this large. */ int mask; /* Mask value used in hashing * function. */ } LiteralTable; /* * The following structure defines for each Tcl interpreter various * statistics-related information about the bytecode compiler and * interpreter's operation in that interpreter. */ #ifdef TCL_COMPILE_STATS typedef struct { long numExecutions; /* Number of ByteCodes executed. */ long numCompilations; /* Number of ByteCodes created. */ long numByteCodesFreed; /* Number of ByteCodes destroyed. */ long instructionCount[256]; /* Number of times each instruction was * executed. */ double totalSrcBytes; /* Total source bytes ever compiled. */ double totalByteCodeBytes; /* Total bytes for all ByteCodes. */ double currentSrcBytes; /* Src bytes for all current ByteCodes. */ double currentByteCodeBytes;/* Code bytes in all current ByteCodes. */ long srcCount[32]; /* Source size distribution: # of srcs of * size [2**(n-1)..2**n), n in [0..32). */ long byteCodeCount[32]; /* ByteCode size distribution. */ long lifetimeCount[32]; /* ByteCode lifetime distribution (ms). */ double currentInstBytes; /* Instruction bytes-current ByteCodes. */ double currentLitBytes; /* Current literal bytes. */ double currentExceptBytes; /* Current exception table bytes. */ double currentAuxBytes; /* Current auxiliary information bytes. */ double currentCmdMapBytes; /* Current src<->code map bytes. */ long numLiteralsCreated; /* Total literal objects ever compiled. */ double totalLitStringBytes; /* Total string bytes in all literals. */ double currentLitStringBytes; /* String bytes in current literals. */ long literalCount[32]; /* Distribution of literal string sizes. */ } ByteCodeStats; #endif /* TCL_COMPILE_STATS */ /* *---------------------------------------------------------------- * Data structures and procedures related to TclHandles, which * are a very lightweight method of preserving enough information * to determine if an arbitrary malloc'd block has been deleted. *---------------------------------------------------------------- */ typedef VOID **TclHandle; /* * The following fills in dummy types for structure refered to * internally by the Tcl interpreter. Since we don't need the actual * size of the structures (they are only pointer references), we'll * simply provide empty opaque types. * */ typedef struct CallFrameStruct CallFrame; typedef struct NamespaceStruct Namespace; typedef struct ActiveVarTraceStruct ActiveVarTrace; typedef struct ProcStruct Proc; typedef struct TraceStruct Trace; typedef struct TclRegexpStruct TclRegexp; typedef struct ExecEnvStruct ExecEnv; /* *---------------------------------------------------------------- * This structure defines an interpreter, which is a collection of * commands plus other state information related to interpreting * commands, such as variable storage. Primary responsibility for * this data structure is in tclBasic.c, but almost every Tcl * source file uses something in here. *---------------------------------------------------------------- */ typedef struct { /* * Note: the first three fields must match exactly the fields in * a Tcl_Interp struct (see tcl.h). If you change one, be sure to * change the other. * * The interpreter's result is held in both the string and the * objResultPtr fields. These fields hold, respectively, the result's * string or object value. The interpreter's result is always in the * result field if that is non-empty, otherwise it is in objResultPtr. * The two fields are kept consistent unless some C code sets * interp->result directly. Programs should not access result and * objResultPtr directly; instead, they should always get and set the * result using procedures such as Tcl_SetObjResult, Tcl_GetObjResult, * and Tcl_GetStringResult. See the SetResult man page for details. */ char *result; /* If the last command returned a string * result, this points to it. Should not be * accessed directly; see comment above. */ Tcl_FreeProc *freeProc; /* Zero means a string result is statically * allocated. TCL_DYNAMIC means string * result was allocated with ckalloc and * should be freed with ckfree. Other values * give address of procedure to invoke to * free the string result. Tcl_Eval must * free it before executing next command. */ int errorLine; /* When TCL_ERROR is returned, this gives * the line number in the command where the * error occurred (1 means first line). */ Tcl_Obj *objResultPtr; /* If the last command returned an object * result, this points to it. Should not be * accessed directly; see comment above. */ TclHandle handle; /* Handle used to keep track of when this * interp is deleted. */ Namespace *globalNsPtr; /* The interpreter's global namespace. */ Tcl_HashTable *hiddenCmdTablePtr; /* Hash table used by tclBasic.c to keep * track of hidden commands on a per-interp * basis. */ ClientData interpInfo; /* Information used by tclInterp.c to keep * track of master/slave interps on * a per-interp basis. */ Tcl_HashTable mathFuncTable;/* Contains all the math functions currently * defined for the interpreter. Indexed by * strings (function names); values have * type (MathFunc *). */ /* * Information related to procedures and variables. See tclProc.c * and tclvar.c for usage. */ int numLevels; /* Keeps track of how many nested calls to * Tcl_Eval are in progress for this * interpreter. It's used to delay deletion * of the table until all Tcl_Eval * invocations are completed. */ int maxNestingDepth; /* If numLevels exceeds this value then Tcl * assumes that infinite recursion has * occurred and it generates an error. */ CallFrame *framePtr; /* Points to top-most in stack of all nested * procedure invocations. NULL means there * are no active procedures. */ CallFrame *varFramePtr; /* Points to the call frame whose variables * are currently in use (same as framePtr * unless an "uplevel" command is * executing). NULL means no procedure is * active or "uplevel 0" is executing. */ ActiveVarTrace *activeTracePtr; /* First in list of active traces for * interp, or NULL if no active traces. */ int returnCode; /* Completion code to return if current * procedure exits with TCL_RETURN code. */ char *errorInfo; /* Value to store in errorInfo if returnCode * is TCL_ERROR. Malloc'ed, may be NULL */ char *errorCode; /* Value to store in errorCode if returnCode * is TCL_ERROR. Malloc'ed, may be NULL */ /* * Information used by Tcl_AppendResult to keep track of partial * results. See Tcl_AppendResult code for details. */ char *appendResult; /* Storage space for results generated * by Tcl_AppendResult. Malloc-ed. NULL * means not yet allocated. */ int appendAvl; /* Total amount of space available at * partialResult. */ int appendUsed; /* Number of non-null bytes currently * stored at partialResult. */ /* * A cache of compiled regular expressions. See Tcl_RegExpCompile * in tclUtil.c for details. THIS CACHE IS OBSOLETE and is only * retained for backward compatibility with Tcl_RegExpCompile. * New code should use the object interface so the Tcl_Obj caches * the compiled expression. */ #define NUM_REGEXPS 5 char *patterns[NUM_REGEXPS];/* Strings corresponding to compiled * regular expression patterns. NULL * means that this slot isn't used. * Malloc-ed. */ int patLengths[NUM_REGEXPS];/* Number of non-null characters in * corresponding entry in patterns. * -1 means entry isn't used. */ TclRegexp *regexps[NUM_REGEXPS]; /* Compiled forms of above strings. Also * malloc-ed, or NULL if not in use yet. */ /* * Information about packages. Used only in tclPkg.c. */ Tcl_HashTable packageTable; /* Describes all of the packages loaded * in or available to this interpreter. * Keys are package names, values are * (Package *) pointers. */ char *packageUnknown; /* Command to invoke during "package * require" commands for packages that * aren't described in packageTable. * Malloc'ed, may be NULL. */ /* * Miscellaneous information: */ int cmdCount; /* Total number of times a command procedure * has been called for this interpreter. */ int evalFlags; /* Flags to control next call to Tcl_Eval. * Normally zero, but may be set before * calling Tcl_Eval. See below for valid * values. */ int termOffset; /* Offset of character just after last one * compiled or executed by Tcl_EvalObj. */ LiteralTable literalTable; /* Contains LiteralEntry's describing all * Tcl objects holding literals of scripts * compiled by the interpreter. Indexed by * the string representations of literals. * Used to avoid creating duplicate * objects. */ int compileEpoch; /* Holds the current "compilation epoch" * for this interpreter. This is * incremented to invalidate existing * ByteCodes when, e.g., a command with a * compile procedure is redefined. */ Proc *compiledProcPtr; /* If a procedure is being compiled, a * pointer to its Proc structure; otherwise, * this is NULL. Set by ObjInterpProc in * tclProc.c and used by tclCompile.c to * process local variables appropriately. */ char *scriptFile; /* NULL means there is no nested source * command active; otherwise this points to * the name of the file being sourced (it's * not malloc-ed: it points to an argument * to Tcl_EvalFile. */ int flags; /* Various flag bits. See below. */ long randSeed; /* Seed used for rand() function. */ Trace *tracePtr; /* List of traces for this interpreter. */ Tcl_HashTable *assocData; /* Hash table for associating data with * this interpreter. Cleaned up when * this interpreter is deleted. */ ExecEnv *execEnvPtr; /* Execution environment for Tcl bytecode * execution. Contains a pointer to the * Tcl evaluation stack. */ Tcl_Obj *emptyObjPtr; /* Points to an object holding an empty * string. Returned by Tcl_ObjSetVar2 when * variable traces change a variable in a * gross way. */ char resultSpace[TCL_RESULT_SIZE + 1]; /* Static space holding small results. */ Tcl_ThreadId threadId; /* ID of thread that owns the interpreter */ /* * Statistical information about the bytecode compiler and interpreter's * operation. */ #ifdef TCL_COMPILE_STATS ByteCodeStats stats; /* Holds compilation and execution * statistics for this interpreter. */ #endif /* TCL_COMPILE_STATS */ } Interp; /* * EvalFlag bits for Interp structures: * * TCL_BRACKET_TERM 1 means that the current script is terminated by * a close bracket rather than the end of the string. * TCL_ALLOW_EXCEPTIONS 1 means it's OK for the script to terminate with * a code other than TCL_OK or TCL_ERROR; 0 means * codes other than these should be turned into errors. */ #define TCL_BRACKET_TERM 1 #define TCL_ALLOW_EXCEPTIONS 4 blt-2.4z.orig/src/bltList.c0100644000175000017500000003423707542177233014337 0ustar dokodoko/* * bltList.c -- * * The module implements generic linked lists. * * Copyright 1991-1998 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. */ #include "bltInt.h" #include "bltList.h" static struct Blt_ListNodeStruct * FindString(listPtr, key) struct Blt_ListStruct *listPtr; /* List to search */ CONST char *key; /* Key to match */ { register struct Blt_ListNodeStruct *nodePtr; char c; c = key[0]; for (nodePtr = listPtr->headPtr; nodePtr != NULL; nodePtr = nodePtr->nextPtr) { if ((c == nodePtr->key.string[0]) && (strcmp(key, nodePtr->key.string) == 0)) { return nodePtr; } } return NULL; } static Blt_ListNode FindOneWord(listPtr, key) struct Blt_ListStruct *listPtr; /* List to search */ CONST char *key; /* Key to match */ { register struct Blt_ListNodeStruct *nodePtr; for (nodePtr = listPtr->headPtr; nodePtr != NULL; nodePtr = nodePtr->nextPtr) { if (key == nodePtr->key.oneWordValue) { return nodePtr; } } return NULL; } static Blt_ListNode FindArray(listPtr, key) struct Blt_ListStruct *listPtr; /* List to search */ CONST char *key; /* Key to match */ { register struct Blt_ListNodeStruct *nodePtr; int nBytes; nBytes = sizeof(int) * listPtr->type; for (nodePtr = listPtr->headPtr; nodePtr != NULL; nodePtr = nodePtr->nextPtr) { if (memcmp(key, nodePtr->key.words, nBytes) == 0) { return nodePtr; } } return NULL; } /* *---------------------------------------------------------------------- * * FreeNode -- * * Free the memory allocated for the node. * * Results: * None. * *---------------------------------------------------------------------- */ static void FreeNode(nodePtr) struct Blt_ListNodeStruct *nodePtr; { Blt_Free(nodePtr); } /* *---------------------------------------------------------------------- * * Blt_ListCreate -- * * Creates a new linked list structure and initializes its pointers * * Results: * Returns a pointer to the newly created list structure. * *---------------------------------------------------------------------- */ /*LINTLIBRARY*/ Blt_List Blt_ListCreate(type) int type; { struct Blt_ListStruct *listPtr; listPtr = Blt_Malloc(sizeof(struct Blt_ListStruct)); if (listPtr != NULL) { Blt_ListInit(listPtr, type); } return listPtr; } /* *---------------------------------------------------------------------- * * Blt_ListCreateNode -- * * Creates a list node holder. This routine does not insert * the node into the list, nor does it no attempt to maintain * consistency of the keys. For example, more than one node * may use the same key. * * Results: * The return value is the pointer to the newly created node. * * Side Effects: * The key is not copied, only the Uid is kept. It is assumed * this key will not change in the life of the node. * *---------------------------------------------------------------------- */ /*LINTLIBRARY*/ Blt_ListNode Blt_ListCreateNode(listPtr, key) struct Blt_ListStruct *listPtr; CONST char *key; /* Unique key to reference object */ { register struct Blt_ListNodeStruct *nodePtr; int keySize; if (listPtr->type == BLT_STRING_KEYS) { keySize = strlen(key) + 1; } else if (listPtr->type == BLT_ONE_WORD_KEYS) { keySize = sizeof(int); } else { keySize = sizeof(int) * listPtr->type; } nodePtr = Blt_Calloc(1, sizeof(struct Blt_ListNodeStruct) + keySize - 4); assert(nodePtr); nodePtr->clientData = NULL; nodePtr->nextPtr = nodePtr->prevPtr = NULL; nodePtr->listPtr = listPtr; switch (listPtr->type) { case BLT_STRING_KEYS: strcpy(nodePtr->key.string, key); break; case BLT_ONE_WORD_KEYS: nodePtr->key.oneWordValue = key; break; default: memcpy(nodePtr->key.words, key, keySize); break; } return nodePtr; } /* *---------------------------------------------------------------------- * * Blt_ListReset -- * * Removes all the entries from a list, removing pointers to the * objects and keys (not the objects or keys themselves). The * node counter is reset to zero. * * Results: * None. * *---------------------------------------------------------------------- */ /*LINTLIBRARY*/ void Blt_ListReset(listPtr) struct Blt_ListStruct *listPtr; /* List to clear */ { if (listPtr != NULL) { register struct Blt_ListNodeStruct *oldPtr; register struct Blt_ListNodeStruct *nodePtr = listPtr->headPtr; while (nodePtr != NULL) { oldPtr = nodePtr; nodePtr = nodePtr->nextPtr; FreeNode(oldPtr); } Blt_ListInit(listPtr, listPtr->type); } } /* *---------------------------------------------------------------------- * * Blt_ListDestroy * * Frees all list structures * * Results: * Returns a pointer to the newly created list structure. * *---------------------------------------------------------------------- */ /*LINTLIBRARY*/ void Blt_ListDestroy(listPtr) struct Blt_ListStruct *listPtr; { if (listPtr != NULL) { Blt_ListReset(listPtr); Blt_Free(listPtr); } } /* *---------------------------------------------------------------------- * * Blt_ListInit -- * * Initializes a linked list. * * Results: * None. * *---------------------------------------------------------------------- */ /*LINTLIBRARY*/ void Blt_ListInit(listPtr, type) struct Blt_ListStruct *listPtr; int type; { listPtr->nNodes = 0; listPtr->headPtr = listPtr->tailPtr = NULL; listPtr->type = type; } /* *---------------------------------------------------------------------- * * Blt_ListLinkAfter -- * * Inserts an node following a given node. * * Results: * None. * *---------------------------------------------------------------------- */ /*LINTLIBRARY*/ void Blt_ListLinkAfter(listPtr, nodePtr, afterPtr) struct Blt_ListStruct *listPtr; struct Blt_ListNodeStruct *nodePtr; struct Blt_ListNodeStruct *afterPtr; { if (listPtr->headPtr == NULL) { listPtr->tailPtr = listPtr->headPtr = nodePtr; } else { if (afterPtr == NULL) { /* Prepend to the front of the list */ nodePtr->nextPtr = listPtr->headPtr; nodePtr->prevPtr = NULL; listPtr->headPtr->prevPtr = nodePtr; listPtr->headPtr = nodePtr; } else { nodePtr->nextPtr = afterPtr->nextPtr; nodePtr->prevPtr = afterPtr; if (afterPtr == listPtr->tailPtr) { listPtr->tailPtr = nodePtr; } else { afterPtr->nextPtr->prevPtr = nodePtr; } afterPtr->nextPtr = nodePtr; } } nodePtr->listPtr = listPtr; listPtr->nNodes++; } /* *---------------------------------------------------------------------- * * Blt_ListLinkBefore -- * * Inserts an node preceding a given node. * * Results: * None. * *---------------------------------------------------------------------- */ /*LINTLIBRARY*/ void Blt_ListLinkBefore(listPtr, nodePtr, beforePtr) struct Blt_ListStruct *listPtr; /* List to contain new node */ struct Blt_ListNodeStruct *nodePtr; /* New node to be inserted */ struct Blt_ListNodeStruct *beforePtr; /* Node to link before */ { if (listPtr->headPtr == NULL) { listPtr->tailPtr = listPtr->headPtr = nodePtr; } else { if (beforePtr == NULL) { /* Append onto the end of the list */ nodePtr->nextPtr = NULL; nodePtr->prevPtr = listPtr->tailPtr; listPtr->tailPtr->nextPtr = nodePtr; listPtr->tailPtr = nodePtr; } else { nodePtr->prevPtr = beforePtr->prevPtr; nodePtr->nextPtr = beforePtr; if (beforePtr == listPtr->headPtr) { listPtr->headPtr = nodePtr; } else { beforePtr->prevPtr->nextPtr = nodePtr; } beforePtr->prevPtr = nodePtr; } } nodePtr->listPtr = listPtr; listPtr->nNodes++; } /* *---------------------------------------------------------------------- * * Blt_ListUnlinkNode -- * * Unlinks an node from the given list. The node itself is * not deallocated, but only removed from the list. * * Results: * None. * *---------------------------------------------------------------------- */ /*LINTLIBRARY*/ void Blt_ListUnlinkNode(nodePtr) struct Blt_ListNodeStruct *nodePtr; { struct Blt_ListStruct *listPtr; listPtr = nodePtr->listPtr; if (listPtr != NULL) { if (listPtr->headPtr == nodePtr) { listPtr->headPtr = nodePtr->nextPtr; } if (listPtr->tailPtr == nodePtr) { listPtr->tailPtr = nodePtr->prevPtr; } if (nodePtr->nextPtr != NULL) { nodePtr->nextPtr->prevPtr = nodePtr->prevPtr; } if (nodePtr->prevPtr != NULL) { nodePtr->prevPtr->nextPtr = nodePtr->nextPtr; } nodePtr->listPtr = NULL; listPtr->nNodes--; } } /* *---------------------------------------------------------------------- * * Blt_ListGetNode -- * * Find the first node matching the key given. * * Results: * Returns the pointer to the node. If no node matching * the key given is found, then NULL is returned. * *---------------------------------------------------------------------- */ /*LINTLIBRARY*/ Blt_ListNode Blt_ListGetNode(listPtr, key) struct Blt_ListStruct *listPtr; /* List to search */ CONST char *key; /* Key to match */ { if (listPtr != NULL) { switch (listPtr->type) { case BLT_STRING_KEYS: return FindString(listPtr, key); case BLT_ONE_WORD_KEYS: return FindOneWord(listPtr, key); default: return FindArray(listPtr, key); } } return NULL; } /* *---------------------------------------------------------------------- * * Blt_ListDeleteNode -- * * Unlinks and deletes the given node. * * Results: * None. * *---------------------------------------------------------------------- */ /*LINTLIBRARY*/ void Blt_ListDeleteNode(nodePtr) struct Blt_ListNodeStruct *nodePtr; { Blt_ListUnlinkNode(nodePtr); FreeNode(nodePtr); } /* *---------------------------------------------------------------------- * * Blt_ListDeleteNodeByKey -- * * Find the node and free the memory allocated for the node. * * Results: * None. * *---------------------------------------------------------------------- */ /*LINTLIBRARY*/ void Blt_ListDeleteNodeByKey(listPtr, key) struct Blt_ListStruct *listPtr; CONST char *key; { struct Blt_ListNodeStruct *nodePtr; nodePtr = Blt_ListGetNode(listPtr, key); if (nodePtr != NULL) { Blt_ListDeleteNode(nodePtr); } } /*LINTLIBRARY*/ Blt_ListNode Blt_ListAppend(listPtr, key, clientData) struct Blt_ListStruct *listPtr; CONST char *key; ClientData clientData; { struct Blt_ListNodeStruct *nodePtr; nodePtr = Blt_ListCreateNode(listPtr, key); Blt_ListSetValue(nodePtr, clientData); Blt_ListAppendNode(listPtr, nodePtr); return nodePtr; } /*LINTLIBRARY*/ Blt_ListNode Blt_ListPrepend(listPtr, key, clientData) struct Blt_ListStruct *listPtr; CONST char *key; ClientData clientData; { struct Blt_ListNodeStruct *nodePtr; nodePtr = Blt_ListCreateNode(listPtr, key); Blt_ListSetValue(nodePtr, clientData); Blt_ListPrependNode(listPtr, nodePtr); return nodePtr; } /* *---------------------------------------------------------------------- * * Blt_ListGetNthNode -- * * Find the node based upon a given position in list. * * Results: * Returns the pointer to the node, if that numbered element * exists. Otherwise NULL. * *---------------------------------------------------------------------- */ /*LINTLIBRARY*/ Blt_ListNode Blt_ListGetNthNode(listPtr, position, direction) struct Blt_ListStruct *listPtr; /* List to traverse */ int position; /* Index of node to select from front * or back of the list. */ int direction; { register struct Blt_ListNodeStruct *nodePtr; if (listPtr != NULL) { if (direction > 0) { for (nodePtr = listPtr->headPtr; nodePtr != NULL; nodePtr = nodePtr->nextPtr) { if (position == 0) { return nodePtr; } position--; } } else { for (nodePtr = listPtr->tailPtr; nodePtr != NULL; nodePtr = nodePtr->prevPtr) { if (position == 0) { return nodePtr; } position--; } } } return NULL; } /* *---------------------------------------------------------------------- * * Blt_ListSort -- * * Find the node based upon a given position in list. * * Results: * Returns the pointer to the node, if that numbered element * exists. Otherwise NULL. * *---------------------------------------------------------------------- */ /*LINTLIBRARY*/ void Blt_ListSort(listPtr, proc) struct Blt_ListStruct *listPtr; /* List to traverse */ Blt_ListCompareProc *proc; { struct Blt_ListNodeStruct **nodeArr; register struct Blt_ListNodeStruct *nodePtr; register int i; if (listPtr->nNodes < 2) { return; } nodeArr = Blt_Malloc(sizeof(Blt_List) * (listPtr->nNodes + 1)); if (nodeArr == NULL) { return; /* Out of memory. */ } i = 0; for (nodePtr = listPtr->headPtr; nodePtr != NULL; nodePtr = nodePtr->nextPtr) { nodeArr[i++] = nodePtr; } qsort((char *)nodeArr, listPtr->nNodes, sizeof(struct Blt_ListNodeStruct *), (QSortCompareProc *)proc); /* Rethread the list. */ nodePtr = nodeArr[0]; listPtr->headPtr = nodePtr; nodePtr->prevPtr = NULL; for (i = 1; i < listPtr->nNodes; i++) { nodePtr->nextPtr = nodeArr[i]; nodePtr->nextPtr->prevPtr = nodePtr; nodePtr = nodePtr->nextPtr; } listPtr->tailPtr = nodePtr; nodePtr->nextPtr = NULL; Blt_Free(nodeArr); } blt-2.4z.orig/src/bltList.h0100644000175000017500000001074207542177233014337 0ustar dokodoko/* * bltList.h -- * * Copyright 1993-1998 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. */ #ifndef _BLT_LIST_H #define _BLT_LIST_H typedef struct Blt_ListStruct *Blt_List; typedef struct Blt_ListNodeStruct *Blt_ListNode; /* * A Blt_ListNode is the container structure for the Blt_List. */ struct Blt_ListNodeStruct { struct Blt_ListNodeStruct *prevPtr; /* Link to the previous node */ struct Blt_ListNodeStruct *nextPtr; /* Link to the next node */ ClientData clientData; /* Pointer to the data object */ struct Blt_ListStruct *listPtr; /* List to eventually insert node */ union { /* Key has one of these forms: */ CONST char *oneWordValue; /* One-word value for key. */ int *words[1]; /* Multiple integer words for key. * The actual size will be as large * as necessary for this table's * keys. */ char string[4]; /* String for key. The actual size * will be as large as needed to hold * the key. */ } key; /* MUST BE LAST FIELD IN RECORD!! */ }; typedef int (Blt_ListCompareProc) _ANSI_ARGS_((Blt_ListNode *node1Ptr, Blt_ListNode *node2Ptr)); /* * A Blt_List is a doubly chained list structure. */ struct Blt_ListStruct { struct Blt_ListNodeStruct *headPtr; /* Pointer to first element in list */ struct Blt_ListNodeStruct *tailPtr; /* Pointer to last element in list */ int nNodes; /* Number of node currently in the list. */ int type; /* Type of keys in list. */ }; EXTERN void Blt_ListInit _ANSI_ARGS_((Blt_List list, int type)); EXTERN void Blt_ListReset _ANSI_ARGS_((Blt_List list)); EXTERN Blt_List Blt_ListCreate _ANSI_ARGS_((int type)); EXTERN void Blt_ListDestroy _ANSI_ARGS_((Blt_List list)); EXTERN Blt_ListNode Blt_ListCreateNode _ANSI_ARGS_((Blt_List list, CONST char *key)); EXTERN void Blt_ListDeleteNode _ANSI_ARGS_((Blt_ListNode node)); EXTERN Blt_ListNode Blt_ListAppend _ANSI_ARGS_((Blt_List list, CONST char *key, ClientData clientData)); EXTERN Blt_ListNode Blt_ListPrepend _ANSI_ARGS_((Blt_List list, CONST char *key, ClientData clientData)); EXTERN void Blt_ListLinkAfter _ANSI_ARGS_((Blt_List list, Blt_ListNode node, Blt_ListNode afterNode)); EXTERN void Blt_ListLinkBefore _ANSI_ARGS_((Blt_List list, Blt_ListNode node, Blt_ListNode beforeNode)); EXTERN void Blt_ListUnlinkNode _ANSI_ARGS_((Blt_ListNode node)); EXTERN Blt_ListNode Blt_ListGetNode _ANSI_ARGS_((Blt_List list, CONST char *key)); EXTERN void Blt_ListDeleteNodeByKey _ANSI_ARGS_((Blt_List list, CONST char *key)); EXTERN Blt_ListNode Blt_ListGetNthNode _ANSI_ARGS_((Blt_List list, int position, int direction)); EXTERN void Blt_ListSort _ANSI_ARGS_((Blt_List list, Blt_ListCompareProc * proc)); #define Blt_ListGetLength(list) \ (((list) == NULL) ? 0 : ((struct Blt_ListStruct *)list)->nNodes) #define Blt_ListFirstNode(list) \ (((list) == NULL) ? NULL : ((struct Blt_ListStruct *)list)->headPtr) #define Blt_ListLastNode(list) \ (((list) == NULL) ? NULL : ((struct Blt_ListStruct *)list)->tailPtr) #define Blt_ListPrevNode(node) ((node)->prevPtr) #define Blt_ListNextNode(node) ((node)->nextPtr) #define Blt_ListGetKey(node) \ (((node)->listPtr->type == BLT_STRING_KEYS) \ ? (node)->key.string : (node)->key.oneWordValue) #define Blt_ListGetValue(node) ((node)->clientData) #define Blt_ListSetValue(node, value) \ ((node)->clientData = (ClientData)(value)) #define Blt_ListAppendNode(list, node) \ (Blt_ListLinkBefore((list), (node), (Blt_ListNode)NULL)) #define Blt_ListPrependNode(list, node) \ (Blt_ListLinkAfter((list), (node), (Blt_ListNode)NULL)) #endif /* _BLT_LIST_H */ blt-2.4z.orig/src/bltMath.h0100644000175000017500000001231007520126772014304 0ustar dokodoko /* * bltMath.h -- * * Copyright 1993-1998 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. */ #ifndef _BLT_MATH_H #define _BLT_MATH_H #include #ifdef HAVE_FLOAT_H #include #endif #ifdef HAVE_IEEEFP_H #include #endif /* HAVE_IEEEFP_H */ #ifndef M_PI #define M_PI 3.14159265358979323846 #endif /* M_PI */ #ifndef M_PI_2 #define M_PI_2 1.57079632679489661923 #endif #ifndef M_SQRT2 #define M_SQRT2 1.41421356237309504880 #endif /* M_SQRT2 */ #ifndef M_SQRT1_2 #define M_SQRT1_2 0.70710678118654752440 #endif /* M_SQRT1_2 */ #ifndef SHRT_MAX #define SHRT_MAX 0x7FFF #endif /* SHRT_MAX */ #ifndef SHRT_MIN #define SHRT_MIN -(SHRT_MAX) #endif /* SHRT_MAX */ #ifndef USHRT_MAX #define USHRT_MAX 0xFFFF #endif /* USHRT_MAX */ #ifndef INT_MAX #define INT_MAX 2147483647 #endif /* INT_MAX */ #ifndef HAVE_FLOAT_H /* * ---------------------------------------------------------------------- * * DBL_MIN, DBL_MAX -- * * DBL_MAX and DBL_MIN are the largest and smaller double * precision numbers that can be represented by the floating * point hardware. If the compiler is ANSI, they can be found in * float.h. Otherwise, we use HUGE_VAL or HUGE to determine * them. * * ---------------------------------------------------------------------- */ /* * Don't want to include __infinity (definition of HUGE_VAL (SC1.x)) */ #ifdef sun #define DBL_MAX 1.7976931348623157E+308 #define DBL_MIN 2.2250738585072014E-308 #define DBL_EPSILON 2.2204460492503131e-16 #else #ifndef DBL_EPSILON #define DBL_EPSILON BLT_DBL_EPSILON #endif #ifdef HUGE_VAL #define DBL_MAX HUGE_VAL #define DBL_MIN (1/HUGE_VAL) #else #ifdef HUGE #define DBL_MAX HUGE #define DBL_MIN (1/HUGE) #else /* * Punt: Assume relatively small values */ #define DBL_MAX 3.40282347E+38 #define DBL_MIN 1.17549435E-38 #endif /*HUGE*/ #endif /*HUGE_VAL*/ #endif /*sun*/ #endif /*!HAVE_FLOAT_H*/ /* * ---------------------------------------------------------------------- * * The following are macros replacing math library functions: * "fabs", "fmod", "abs", "rint", and "exp10". * * Although many of these routines may exist in your math * library, they aren't used in libtcl.a or libtk.a. This makes * it difficult to dynamically load the BLT library as a shared * object unless the math library is also shared (which isn't * true on several systems). We can avoid the problem by * replacing the "exotic" math routines with macros. * * ---------------------------------------------------------------------- */ #undef ABS #define ABS(x) (((x)<0)?(-(x)):(x)) #undef EXP10 #define EXP10(x) (pow(10.0,(x))) #undef FABS #define FABS(x) (((x)<0.0)?(-(x)):(x)) #undef SIGN #define SIGN(x) (((x) < 0.0) ? -1 : 1) /* * Be careful when using the next two macros. They both assume the floating * point number is less than the size of an int. That means, for example, you * can't use these macros with numbers bigger than than 2^31-1. */ #undef FMOD #define FMOD(x,y) ((x)-(((int)((x)/(y)))*y)) #undef ROUND #define ROUND(x) ((int)((x) + (((x)<0.0) ? -0.5 : 0.5))) #ifdef HAVE_FINITE #define FINITE(x) finite(x) #else #ifdef HAVE_ISFINITE #define FINITE(x) isfinite(x) #else #ifdef HAVE_ISNAN #define FINITE(x) (!isnan(x)) #else #define FINITE(x) (TRUE) #endif /* HAVE_ISNAN */ #endif /* HAVE_ISFINITE */ #endif /* HAVE_FINITE */ extern double bltNaN; #define DEFINED(x) (!isnan(x)) #define UNDEFINED(x) (isnan(x)) #define VALUE_UNDEFINED bltNaN /* * ---------------------------------------------------------------------- * * On some systems "strdup" and "strcasecmp" are in the C library, * but have no declarations in the C header files. Make sure we * supply them here. * * ---------------------------------------------------------------------- */ #ifdef NEED_DECL_STRDUP extern char *strdup _ANSI_ARGS_((CONST char *s)); #endif /* NEED_DECL_STRDUP */ #ifndef HAVE_STRTOLOWER extern void strtolower _ANSI_ARGS_((char *s)); #endif /* HAVE_STRTOLOWER */ #ifdef NEED_DECL_DRAND48 extern double drand48 _ANSI_ARGS_((void)); extern void srand48 _ANSI_ARGS_((long seed)); #endif /* NEED_DECL_DRAND48 */ #ifdef NEED_DECL_STRCASECMP extern int strcasecmp _ANSI_ARGS_((CONST char *s1, CONST char *s2)); #endif /* NEED_DECL_STRCASECMP */ #endif /* BLT_MATH_H */ blt-2.4z.orig/src/bltNsUtil.c0100644000175000017500000004547707542177233014652 0ustar dokodoko/* * bltNsUtil.c -- * * This module implements utility procedures for namespaces * in the BLT toolkit. * * Copyright 1991-1998 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. */ #include "bltInt.h" #include "bltList.h" /* Namespace related routines */ typedef struct { char *result; Tcl_FreeProc *freeProc; int errorLine; Tcl_HashTable commandTable; Tcl_HashTable mathFuncTable; Tcl_HashTable globalTable; /* This is the only field we care about */ int nLevels; int maxNestingDepth; } TclInterp; /* * ---------------------------------------------------------------------- * * Blt_GetVariableNamespace -- * * Returns the namespace context of the vector variable. If NULL, * this indicates that the variable is local to the call frame. * * Note the ever-dangerous manner in which we get this information. * All of these structures are "private". Now who's calling Tcl * an "extension" language? * * Results: * Returns the context of the namespace in an opaque type. * * ---------------------------------------------------------------------- */ #if (TCL_MAJOR_VERSION == 7) #ifdef ITCL_NAMESPACES struct VarTrace; struct ArraySearch; struct NamespCacheRef; typedef struct VarStruct Var; struct VarStruct { int valueLength; int valueSpace; union { char *string; Tcl_HashTable *tablePtr; Var *upvarPtr; } value; Tcl_HashEntry *hPtr; int refCount; struct VarTrace *tracePtr; struct ArraySearch *searchPtr; int flags; /* >>>>>>>>>> stuff for [incr Tcl] namespaces <<<<<<<<<< */ char *name; int protection; Itcl_Namespace *namesp; struct NamespCacheRef *cacheInfo; } Var; Tcl_Namespace * Tcl_FindNamespace(interp, name) Tcl_Interp *interp; char *name; { Itcl_Namespace nsToken; if (Itcl_FindNamesp(interp, name, 0, &nsToken) != TCL_OK) { Tcl_ResetResult(interp); return NULL; } return (Tcl_Namespace *) nsToken; } Tcl_Namespace * Tcl_GetGlobalNamespace(interp) Tcl_Interp *interp; { return (Tcl_Namespace *) Itcl_GetGlobalNamesp(interp); } Tcl_Namespace * Tcl_GetCurrentNamespace(interp) Tcl_Interp *interp; { return (Tcl_Namespace *) Itcl_GetActiveNamesp(interp); } Tcl_Namespace * Blt_GetCommandNamespace(interp, cmdToken) Tcl_Interp *interp; Tcl_Command cmdToken; { return (Tcl_Namespace *)interp; } Tcl_Namespace * Blt_GetVariableNamespace(interp, name) Tcl_Interp *interp; CONST char *name; { Tcl_Var varToken; Var *varPtr; if (Itcl_FindVariable(interp, name, 0, &varToken) != TCL_OK) { return NULL; } varPtr = (Var *) varToken; if (varPtr == NULL) { return NULL; } return (Tcl_Namespace *) varPtr->namesp; } Tcl_CallFrame * Blt_EnterNamespace(interp, nsPtr) Tcl_Interp *interp; Tcl_Namespace *nsPtr; { Itcl_Namespace nsToken = (Itcl_Namespace) nsPtr; return (Tcl_CallFrame *) Itcl_ActivateNamesp(interp, nsToken); } void Blt_LeaveNamespace(interp, framePtr) Tcl_Interp *interp; Tcl_CallFrame *framePtr; { Itcl_DeactivateNamesp(interp, (Itcl_ActiveNamespace) framePtr); } #else Tcl_Namespace * Blt_GetCommandNamespace(interp, cmdToken) Tcl_Interp *interp; Tcl_Command cmdToken; { return (Tcl_Namespace *)interp; } Tcl_Namespace * Blt_GetVariableNamespace(interp, name) Tcl_Interp *interp; CONST char *name; { TclInterp *iPtr = (TclInterp *) interp; return (Tcl_Namespace *) Tcl_FindHashEntry(&(iPtr->globalTable), (char *)name); } Tcl_CallFrame * Blt_EnterNamespace(interp, nsPtr) Tcl_Interp *interp; Tcl_Namespace *nsPtr; /* Not used. */ { return NULL; } void Blt_LeaveNamespace(interp, framePtr) Tcl_Interp *interp; Tcl_CallFrame *framePtr; { /* empty */ } Tcl_Namespace * Tcl_GetGlobalNamespace(interp) Tcl_Interp *interp; { return (Tcl_Namespace *) interp; } Tcl_Namespace * Tcl_GetCurrentNamespace(interp) Tcl_Interp *interp; { return (Tcl_Namespace *) interp; } Tcl_Namespace * Tcl_FindNamespace(interp, name) Tcl_Interp *interp; char *name; { return (Tcl_Namespace *) interp; } #endif /* ITCL_NAMESPACES */ #else /* * A Command structure exists for each command in a namespace. The * Tcl_Command opaque type actually refers to these structures. */ typedef struct CompileProcStruct CompileProc; typedef struct ImportRefStruct ImportRef; typedef struct { Tcl_HashEntry *hPtr; /* Pointer to the hash table entry that * refers to this command. The hash table is * either a namespace's command table or an * interpreter's hidden command table. This * pointer is used to get a command's name * from its Tcl_Command handle. NULL means * that the hash table entry has been * removed already (this can happen if * deleteProc causes the command to be * deleted or recreated). */ Tcl_Namespace *nsPtr; /* Points to the namespace containing this * command. */ int refCount; /* 1 if in command hashtable plus 1 for each * reference from a CmdName Tcl object * representing a command's name in a * ByteCode instruction sequence. This * structure can be freed when refCount * becomes zero. */ int cmdEpoch; /* Incremented to invalidate any references * that point to this command when it is * renamed, deleted, hidden, or exposed. */ CompileProc *compileProc; /* Procedure called to compile command. NULL * if no compile proc exists for command. */ Tcl_ObjCmdProc *objProc; /* Object-based command procedure. */ ClientData objClientData; /* Arbitrary value passed to object proc. */ Tcl_CmdProc *proc; /* String-based command procedure. */ ClientData clientData; /* Arbitrary value passed to string proc. */ Tcl_CmdDeleteProc *deleteProc; /* Procedure invoked when deleting command * to, e.g., free all client data. */ ClientData deleteData; /* Arbitrary value passed to deleteProc. */ int deleted; /* Means that the command is in the process * of being deleted (its deleteProc is * currently executing). Other attempts to * delete the command should be ignored. */ ImportRef *importRefPtr; /* List of each imported Command created in * another namespace when this command is * imported. These imported commands * redirect invocations back to this * command. The list is used to remove all * those imported commands when deleting * this "real" command. */ } Command; struct VarTrace; struct ArraySearch; typedef struct VarStruct Var; struct VarStruct { union { Tcl_Obj *objPtr; Tcl_HashTable *tablePtr; Var *linkPtr; } value; char *name; Tcl_Namespace *nsPtr; Tcl_HashEntry *hPtr; int refCount; struct VarTrace *tracePtr; struct ArraySearch *searchPtr; int flags; }; extern Var *TclLookupVar _ANSI_ARGS_((Tcl_Interp *interp, CONST char *part1, CONST char *part2, int flags, char *mesg, int p1Flags, int p2Flags, Var ** varPtrPtr)); #define VAR_SCALAR 0x1 #define VAR_ARRAY 0x2 #define VAR_LINK 0x4 #define VAR_UNDEFINED 0x8 #define VAR_IN_HASHTABLE 0x10 #define VAR_TRACE_ACTIVE 0x20 #define VAR_ARRAY_ELEMENT 0x40 #define VAR_NAMESPACE_VAR 0x80 #define VAR_ARGUMENT 0x100 #define VAR_TEMPORARY 0x200 #define VAR_RESOLVED 0x400 Tcl_HashTable * Blt_GetArrayVariableTable(interp, varName, flags) Tcl_Interp *interp; CONST char *varName; int flags; { Var *varPtr, *arrayPtr; varPtr = TclLookupVar(interp, varName, (char *)NULL, flags, "read", FALSE, FALSE, &arrayPtr); if ((varPtr == NULL) || ((varPtr->flags & VAR_ARRAY) == 0)) { return NULL; } return varPtr->value.tablePtr; } Tcl_Namespace * Blt_GetVariableNamespace(interp, name) Tcl_Interp *interp; CONST char *name; { Var *varPtr; varPtr = (Var *)Tcl_FindNamespaceVar(interp, (char *)name, (Tcl_Namespace *)NULL, 0); if (varPtr == NULL) { return NULL; } return varPtr->nsPtr; } /*ARGSUSED*/ Tcl_Namespace * Blt_GetCommandNamespace(interp, cmdToken) Tcl_Interp *interp; /* Not used. */ Tcl_Command cmdToken; { Command *cmdPtr = (Command *)cmdToken; return (Tcl_Namespace *)cmdPtr->nsPtr; } Tcl_CallFrame * Blt_EnterNamespace(interp, nsPtr) Tcl_Interp *interp; Tcl_Namespace *nsPtr; { Tcl_CallFrame *framePtr; framePtr = Blt_Malloc(sizeof(Tcl_CallFrame)); assert(framePtr); if (Tcl_PushCallFrame(interp, framePtr, (Tcl_Namespace *)nsPtr, 0) != TCL_OK) { Blt_Free(framePtr); return NULL; } return framePtr; } void Blt_LeaveNamespace(interp, framePtr) Tcl_Interp *interp; Tcl_CallFrame *framePtr; { Tcl_PopCallFrame(interp); Blt_Free(framePtr); } #endif /* TCL_MAJOR_VERSION == 7 */ int Blt_ParseQualifiedName(interp, qualName, nsPtrPtr, namePtrPtr) Tcl_Interp *interp; CONST char *qualName; Tcl_Namespace **nsPtrPtr; CONST char **namePtrPtr; { register char *p, *colon; Tcl_Namespace *nsPtr; colon = NULL; p = (char *)(qualName + strlen(qualName)); while (--p > qualName) { if ((*p == ':') && (*(p - 1) == ':')) { p++; /* just after the last "::" */ colon = p - 2; break; } } if (colon == NULL) { *nsPtrPtr = NULL; *namePtrPtr = (char *)qualName; return TCL_OK; } *colon = '\0'; if (qualName[0] == '\0') { nsPtr = Tcl_GetGlobalNamespace(interp); } else { nsPtr = Tcl_FindNamespace(interp, (char *)qualName, (Tcl_Namespace *)NULL, 0); } *colon = ':'; if (nsPtr == NULL) { return TCL_ERROR; } *nsPtrPtr = nsPtr; *namePtrPtr = p; return TCL_OK; } char * Blt_GetQualifiedName(nsPtr, name, resultPtr) Tcl_Namespace *nsPtr; CONST char *name; Tcl_DString *resultPtr; { Tcl_DStringInit(resultPtr); #if (TCL_MAJOR_VERSION > 7) if ((nsPtr->fullName[0] != ':') || (nsPtr->fullName[1] != ':') || (nsPtr->fullName[2] != '\0')) { Tcl_DStringAppend(resultPtr, nsPtr->fullName, -1); } #endif Tcl_DStringAppend(resultPtr, "::", -1); Tcl_DStringAppend(resultPtr, (char *)name, -1); return Tcl_DStringValue(resultPtr); } #if (TCL_MAJOR_VERSION > 7) typedef struct { Tcl_HashTable clientTable; /* Original clientdata and delete procedure. */ ClientData origClientData; Tcl_NamespaceDeleteProc *origDeleteProc; } Callback; static Tcl_CmdProc NamespaceDeleteCmd; static Tcl_NamespaceDeleteProc NamespaceDeleteNotify; #define NS_DELETE_CMD "#NamespaceDeleteNotifier" /*ARGSUSED*/ static int NamespaceDeleteCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* */ int argc; char **argv; { Tcl_AppendResult(interp, "command \"", argv[0], "\" shouldn't be invoked", (char *)NULL); return TCL_ERROR; } static void NamespaceDeleteNotify(clientData) ClientData clientData; { Blt_List list; Blt_ListNode node; Tcl_CmdDeleteProc *deleteProc; list = (Blt_List)clientData; for (node = Blt_ListFirstNode(list); node != NULL; node = Blt_ListNextNode(node)) { deleteProc = (Tcl_CmdDeleteProc *)Blt_ListGetValue(node); clientData = (ClientData)Blt_ListGetKey(node); (*deleteProc) (clientData); } Blt_ListDestroy(list); } void Blt_DestroyNsDeleteNotify(interp, nsPtr, clientData) Tcl_Interp *interp; Tcl_Namespace *nsPtr; ClientData clientData; { Blt_List list; Blt_ListNode node; char *string; Tcl_CmdInfo cmdInfo; string = Blt_Malloc(sizeof(nsPtr->fullName) + strlen(NS_DELETE_CMD) + 4); strcpy(string, nsPtr->fullName); strcat(string, "::"); strcat(string, NS_DELETE_CMD); if (!Tcl_GetCommandInfo(interp, string, &cmdInfo)) { goto done; } list = (Blt_List)cmdInfo.clientData; node = Blt_ListGetNode(list, clientData); if (node != NULL) { Blt_ListDeleteNode(node); } done: Blt_Free(string); } int Blt_CreateNsDeleteNotify(interp, nsPtr, clientData, deleteProc) Tcl_Interp *interp; Tcl_Namespace *nsPtr; ClientData clientData; Tcl_CmdDeleteProc *deleteProc; { Blt_List list; char *string; Tcl_CmdInfo cmdInfo; string = Blt_Malloc(sizeof(nsPtr->fullName) + strlen(NS_DELETE_CMD) + 4); strcpy(string, nsPtr->fullName); strcat(string, "::"); strcat(string, NS_DELETE_CMD); if (!Tcl_GetCommandInfo(interp, string, &cmdInfo)) { list = Blt_ListCreate(BLT_ONE_WORD_KEYS); Blt_CreateCommand(interp, string, NamespaceDeleteCmd, list, NamespaceDeleteNotify); } else { list = (Blt_List)cmdInfo.clientData; } Blt_Free(string); Blt_ListAppend(list, clientData, (ClientData)deleteProc); return TCL_OK; } #endif /* TCL_MAJOR_VERSION > 7 */ #if (TCL_VERSION_NUMBER < _VERSION(8,0,0)) /* *---------------------------------------------------------------------- * * Blt_CreateCommand -- * * Like Tcl_CreateCommand, but creates command in current namespace * instead of global, if one isn't defined. Not a problem with * [incr Tcl] namespaces. * * Results: * The return value is a token for the command, which can * be used in future calls to Tcl_GetCommandName. * *---------------------------------------------------------------------- */ Tcl_Command Blt_CreateCommand(interp, cmdName, proc, clientData, deleteProc) Tcl_Interp *interp; /* Token for command interpreter returned by * a previous call to Tcl_CreateInterp. */ CONST char *cmdName; /* Name of command. If it contains namespace * qualifiers, the new command is put in the * specified namespace; otherwise it is put * in the global namespace. */ Tcl_CmdProc *proc; /* Procedure to associate with cmdName. */ ClientData clientData; /* Arbitrary value passed to string proc. */ Tcl_CmdDeleteProc *deleteProc; /* If not NULL, gives a procedure to call * when this command is deleted. */ { return Tcl_CreateCommand(interp, (char *)cmdName, proc, clientData, deleteProc); } /*ARGSUSED*/ Tcl_Command Tcl_FindCommand(interp, cmdName, nsPtr, flags) Tcl_Interp *interp; char *cmdName; Tcl_Namespace *nsPtr; /* Not used. */ int flags; /* Not used. */ { Tcl_HashEntry *hPtr; TclInterp *iPtr = (TclInterp *) interp; hPtr = Tcl_FindHashEntry(&iPtr->commandTable, cmdName); if (hPtr == NULL) { return NULL; } return (Tcl_Command) Tcl_GetHashValue(hPtr); } #endif /* TCL_MAJOR_VERSION <= 7 */ #if (TCL_VERSION_NUMBER >= _VERSION(8,0,0)) /* *---------------------------------------------------------------------- * * Blt_CreateCommand -- * * Like Tcl_CreateCommand, but creates command in current namespace * instead of global, if one isn't defined. Not a problem with * [incr Tcl] namespaces. * * Results: * The return value is a token for the command, which can * be used in future calls to Tcl_GetCommandName. * *---------------------------------------------------------------------- */ Tcl_Command Blt_CreateCommand(interp, cmdName, proc, clientData, deleteProc) Tcl_Interp *interp; /* Token for command interpreter returned by * a previous call to Tcl_CreateInterp. */ CONST char *cmdName; /* Name of command. If it contains namespace * qualifiers, the new command is put in the * specified namespace; otherwise it is put * in the global namespace. */ Tcl_CmdProc *proc; /* Procedure to associate with cmdName. */ ClientData clientData; /* Arbitrary value passed to string proc. */ Tcl_CmdDeleteProc *deleteProc; /* If not NULL, gives a procedure to call * when this command is deleted. */ { register CONST char *p; p = cmdName + strlen(cmdName); while (--p > cmdName) { if ((*p == ':') && (*(p - 1) == ':')) { p++; /* just after the last "::" */ break; } } if (cmdName == p) { Tcl_DString dString; Tcl_Namespace *nsPtr; Tcl_Command cmdToken; Tcl_DStringInit(&dString); nsPtr = Tcl_GetCurrentNamespace(interp); Tcl_DStringAppend(&dString, nsPtr->fullName, -1); Tcl_DStringAppend(&dString, "::", -1); Tcl_DStringAppend(&dString, cmdName, -1); cmdToken = Tcl_CreateCommand(interp, Tcl_DStringValue(&dString), proc, clientData, deleteProc); Tcl_DStringFree(&dString); return cmdToken; } return Tcl_CreateCommand(interp, (char *)cmdName, proc, clientData, deleteProc); } /* *---------------------------------------------------------------------- * * Blt_CreateCommandObj -- * * Like Tcl_CreateCommand, but creates command in current namespace * instead of global, if one isn't defined. Not a problem with * [incr Tcl] namespaces. * * Results: * The return value is a token for the command, which can * be used in future calls to Tcl_GetCommandName. * *---------------------------------------------------------------------- */ Tcl_Command Blt_CreateCommandObj(interp, cmdName, proc, clientData, deleteProc) Tcl_Interp *interp; /* Token for command interpreter returned by * a previous call to Tcl_CreateInterp. */ CONST char *cmdName; /* Name of command. If it contains namespace * qualifiers, the new command is put in the * specified namespace; otherwise it is put * in the global namespace. */ Tcl_ObjCmdProc *proc; /* Procedure to associate with cmdName. */ ClientData clientData; /* Arbitrary value passed to string proc. */ Tcl_CmdDeleteProc *deleteProc; /* If not NULL, gives a procedure to call * when this command is deleted. */ { register CONST char *p; p = cmdName + strlen(cmdName); while (--p > cmdName) { if ((*p == ':') && (*(p - 1) == ':')) { p++; /* just after the last "::" */ break; } } if (cmdName == p) { Tcl_DString dString; Tcl_Namespace *nsPtr; Tcl_Command cmdToken; Tcl_DStringInit(&dString); nsPtr = Tcl_GetCurrentNamespace(interp); Tcl_DStringAppend(&dString, nsPtr->fullName, -1); Tcl_DStringAppend(&dString, "::", -1); Tcl_DStringAppend(&dString, cmdName, -1); cmdToken = Tcl_CreateObjCommand(interp, Tcl_DStringValue(&dString), proc, clientData, deleteProc); Tcl_DStringFree(&dString); return cmdToken; } return Tcl_CreateObjCommand(interp, (char *)cmdName, proc, clientData, deleteProc); } #endif /* TCL_VERSION_NUMBER < 8.0.0 */ blt-2.4z.orig/src/bltNsUtil.h0100644000175000017500000000762307515460664014651 0ustar dokodoko/* * bltNsUtil.h -- * * Copyright 1993-1998 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. */ #ifndef BLT_NS_UTIL_H #define BLT_NS_UTIL_H 1 #if defined(ITCL_NAMESPACES) || (TCL_MAJOR_VERSION >= 8) #define HAVE_NAMESPACES 1 #else #define HAVE_NAMESPACES 0 #endif #if (TCL_MAJOR_VERSION <= 7) /* * Namespaces and callframes don't exist before Tcl version 8.0. * We'll define them as opaque pointers. In reality, they * point to the interpreter token. */ typedef struct Tcl_NamespaceStruct Tcl_Namespace; typedef struct Tcl_CallFrameStruct *Tcl_CallFrame; #endif #ifndef TCL_NAMESPACE_ONLY #define TCL_NAMESPACE_ONLY TCL_GLOBAL_ONLY #endif EXTERN Tcl_Command Tcl_FindCommand _ANSI_ARGS_((Tcl_Interp *interp, char *name, Tcl_Namespace *nsPtr, int flags)); #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) /* * Namespace procedures not prototyped defined in Tcl.h */ EXTERN Tcl_Namespace *Tcl_GetCurrentNamespace _ANSI_ARGS_((Tcl_Interp *interp)); EXTERN Tcl_Namespace *Tcl_GetGlobalNamespace _ANSI_ARGS_((Tcl_Interp *interp)); #if (TCL_MAJOR_VERSION >= 8) EXTERN Tcl_Namespace *Tcl_CreateNamespace _ANSI_ARGS_((Tcl_Interp *interp, char *name, ClientData clientData, Tcl_NamespaceDeleteProc *nsDelProc)); EXTERN void Tcl_DeleteNamespace _ANSI_ARGS_((Tcl_Namespace *nsPtr)); EXTERN Tcl_Namespace *Tcl_FindNamespace _ANSI_ARGS_((Tcl_Interp *interp, char *name, Tcl_Namespace *context, int flags)); EXTERN int Tcl_Export _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Namespace *nsPtr, char *name, int resetFlag)); EXTERN Tcl_Var Tcl_FindNamespaceVar _ANSI_ARGS_((Tcl_Interp *interp, char *name, Tcl_Namespace *contextNsPtr, int flags)); EXTERN void Tcl_PopCallFrame _ANSI_ARGS_((Tcl_Interp *interp)); EXTERN int Tcl_PushCallFrame _ANSI_ARGS_((Tcl_Interp *interp, Tcl_CallFrame * framePtr, Tcl_Namespace *nsPtr, int isProcCallFrame)); extern Tcl_HashTable *Blt_GetArrayVariableTable _ANSI_ARGS_(( Tcl_Interp *interp, CONST char *varName, int flags)); #endif /* TCL_MAJOR_VERSION >= 8 */ /* * Auxillary procedures */ EXTERN Tcl_Namespace *Blt_GetVariableNamespace _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName)); EXTERN Tcl_Namespace *Blt_GetCommandNamespace _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Command cmdToken)); EXTERN Tcl_CallFrame *Blt_EnterNamespace _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Namespace *nsPtr)); EXTERN void Blt_LeaveNamespace _ANSI_ARGS_((Tcl_Interp *interp, Tcl_CallFrame * framePtr)); EXTERN int Blt_ParseQualifiedName _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, Tcl_Namespace **nsPtrPtr, CONST char **namePtr)); EXTERN char *Blt_GetQualifiedName _ANSI_ARGS_((Tcl_Namespace *nsPtr, CONST char *name, Tcl_DString *resultPtr)); EXTERN Tcl_Command Blt_CreateCommand _ANSI_ARGS_((Tcl_Interp *interp, CONST char *cmdName, Tcl_CmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc)); #endif /* BLT_NS_UTIL_H */ blt-2.4z.orig/src/bltObjConfig.c0100644000175000017500000017262407542177233015267 0ustar dokodoko/* * bltObjConfig.c -- * * This file contains the Tk_ConfigureWidget procedure. THIS FILE * IS HERE FOR BACKWARD COMPATIBILITY; THE NEW CONFIGURATION * PACKAGE SHOULD BE USED FOR NEW PROJECTS. * * 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. * * RCS: @(#) $Id: bltObjConfig.c,v 1.22 2002/09/18 22:30:51 ghowlett Exp $ */ #include "bltInt.h" #if (TK_VERSION_NUMBER >= _VERSION(8,0,0)) #if defined(__STDC__) #include #else #include #endif #include "bltObjConfig.h" #include "bltTile.h" #if (TK_VERSION_NUMBER < _VERSION(8,1,0)) /* *---------------------------------------------------------------------- * * Tk_GetAnchorFromObj -- * * Return a Tk_Anchor value based on the value of the objPtr. * * Results: * The return value is a standard Tcl result. If an error occurs during * conversion, an error message is left in the interpreter's result * unless "interp" is NULL. * * Side effects: * The object gets converted by Tcl_GetIndexFromObj. * *---------------------------------------------------------------------- */ int Tk_GetAnchorFromObj(interp, objPtr, anchorPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Obj *objPtr; /* The object we are trying to get the * value from. */ Tk_Anchor *anchorPtr; /* Where to place the Tk_Anchor that * corresponds to the string value of * objPtr. */ { return Tk_GetAnchor(interp, Tcl_GetString(objPtr), anchorPtr); } /* *---------------------------------------------------------------------- * * Tk_GetJustifyFromObj -- * * Return a Tk_Justify value based on the value of the objPtr. * * Results: * The return value is a standard Tcl result. If an error occurs during * conversion, an error message is left in the interpreter's result * unless "interp" is NULL. * * Side effects: * The object gets converted by Tcl_GetIndexFromObj. * *---------------------------------------------------------------------- */ int Tk_GetJustifyFromObj(interp, objPtr, justifyPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Obj *objPtr; /* The object we are trying to get the * value from. */ Tk_Justify *justifyPtr; /* Where to place the Tk_Justify that * corresponds to the string value of * objPtr. */ { return Tk_GetJustify(interp, Tcl_GetString(objPtr), justifyPtr); } /* *---------------------------------------------------------------------- * * Tk_GetReliefFromObj -- * * Return an integer value based on the value of the objPtr. * * Results: * The return value is a standard Tcl result. If an error occurs during * conversion, an error message is left in the interpreter's result * unless "interp" is NULL. * * Side effects: * The object gets converted by Tcl_GetIndexFromObj. * *---------------------------------------------------------------------- */ int Tk_GetReliefFromObj(interp, objPtr, reliefPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Obj *objPtr; /* The object we are trying to get the * value from. */ int *reliefPtr; /* Where to place the answer. */ { return Tk_GetRelief(interp, Tcl_GetString(objPtr), reliefPtr); } /* *---------------------------------------------------------------------- * * Tk_GetMMFromObj -- * * Attempt to return an mm value from the Tcl object "objPtr". If the * object is not already an mm value, an attempt will be made to convert * it to one. * * Results: * The return value is a standard Tcl object result. If an error occurs * during conversion, an error message is left in the interpreter's * result unless "interp" is NULL. * * Side effects: * If the object is not already a pixel, the conversion will free * any old internal representation. * *---------------------------------------------------------------------- */ int Tk_GetMMFromObj(interp, tkwin, objPtr, doublePtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ Tk_Window tkwin; Tcl_Obj *objPtr; /* The object from which to get mms. */ double *doublePtr; /* Place to store resulting millimeters. */ { return Tk_GetScreenMM(interp, tkwin, Tcl_GetString(objPtr), doublePtr); } /* *---------------------------------------------------------------------- * * Tk_GetPixelsFromObj -- * * Attempt to return a pixel value from the Tcl object "objPtr". If the * object is not already a pixel value, an attempt will be made to convert * it to one. * * Results: * The return value is a standard Tcl object result. If an error occurs * during conversion, an error message is left in the interpreter's * result unless "interp" is NULL. * * Side effects: * If the object is not already a pixel, the conversion will free * any old internal representation. * *---------------------------------------------------------------------- */ int Tk_GetPixelsFromObj(interp, tkwin, objPtr, intPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ Tk_Window tkwin; Tcl_Obj *objPtr; /* The object from which to get pixels. */ int *intPtr; /* Place to store resulting pixels. */ { return Tk_GetPixels(interp, tkwin, Tcl_GetString(objPtr), intPtr); } /* *---------------------------------------------------------------------- * * Tk_Alloc3DBorderFromObj -- * * Given a Tcl_Obj *, map the value to a corresponding * Tk_3DBorder structure based on the tkwin given. * * Results: * The return value is a token for a data structure describing a * 3-D border. This token may be passed to procedures such as * Blt_Draw3DRectangle and Tk_Free3DBorder. If an error prevented * the border from being created then NULL is returned and an error * message will be left in the interp's result. * * Side effects: * The border is added to an internal database with a reference * count. For each call to this procedure, there should eventually * be a call to FreeBorderObjProc so that the database is * cleaned up when borders aren't in use anymore. * *---------------------------------------------------------------------- */ Tk_3DBorder Tk_Alloc3DBorderFromObj(interp, tkwin, objPtr) Tcl_Interp *interp; /* Interp for error results. */ Tk_Window tkwin; /* Need the screen the border is used on.*/ Tcl_Obj *objPtr; /* Object giving name of color for window * background. */ { return Tk_Get3DBorder(interp, tkwin, Tcl_GetString(objPtr)); } /* *---------------------------------------------------------------------- * * Tk_AllocBitmapFromObj -- * * Given a Tcl_Obj *, map the value to a corresponding * Pixmap structure based on the tkwin given. * * Results: * The return value is the X identifer for the desired bitmap * (i.e. a Pixmap with a single plane), unless string couldn't be * parsed correctly. In this case, None is returned and an error * message is left in the interp's result. The caller should never * modify the bitmap that is returned, and should eventually call * Tk_FreeBitmapFromObj when the bitmap is no longer needed. * * Side effects: * The bitmap is added to an internal database with a reference count. * For each call to this procedure, there should eventually be a call * to Tk_FreeBitmapFromObj, so that the database can be cleaned up * when bitmaps aren't needed anymore. * *---------------------------------------------------------------------- */ Pixmap Tk_AllocBitmapFromObj(interp, tkwin, objPtr) Tcl_Interp *interp; /* Interp for error results. This may * be NULL. */ Tk_Window tkwin; /* Need the screen the bitmap is used on.*/ Tcl_Obj *objPtr; /* Object describing bitmap; see manual * entry for legal syntax of string value. */ { return Tk_GetBitmap(interp, tkwin, Tcl_GetString(objPtr)); } /* *--------------------------------------------------------------------------- * * Tk_AllocFontFromObj -- * * Given a string description of a font, map the description to a * corresponding Tk_Font that represents the font. * * Results: * The return value is token for the font, or NULL if an error * prevented the font from being created. If NULL is returned, an * error message will be left in interp's result object. * * Side effects: * The font is added to an internal database with a reference * count. For each call to this procedure, there should eventually * be a call to Tk_FreeFont() or Tk_FreeFontFromObj() so that the * database is cleaned up when fonts aren't in use anymore. * *--------------------------------------------------------------------------- */ Tk_Font Tk_AllocFontFromObj(interp, tkwin, objPtr) Tcl_Interp *interp; /* Interp for database and error return. */ Tk_Window tkwin; /* For screen on which font will be used. */ Tcl_Obj *objPtr; /* Object describing font, as: named font, * native format, or parseable string. */ { return Tk_GetFont(interp, tkwin, Tcl_GetString(objPtr)); } /* *---------------------------------------------------------------------- * * Tk_AllocCursorFromObj -- * * Given a Tcl_Obj *, map the value to a corresponding * Tk_Cursor structure based on the tkwin given. * * Results: * The return value is the X identifer for the desired cursor, * unless objPtr couldn't be parsed correctly. In this case, * None is returned and an error message is left in the interp's result. * The caller should never modify the cursor that is returned, and * should eventually call Tk_FreeCursorFromObj when the cursor is no * longer needed. * * Side effects: * The cursor is added to an internal database with a reference count. * For each call to this procedure, there should eventually be a call * to Tk_FreeCursorFromObj, so that the database can be cleaned up * when cursors aren't needed anymore. * *---------------------------------------------------------------------- */ Tk_Cursor Tk_AllocCursorFromObj(interp, tkwin, objPtr) Tcl_Interp *interp; /* Interp for error results. */ Tk_Window tkwin; /* Window in which the cursor will be used.*/ Tcl_Obj *objPtr; /* Object describing cursor; see manual * entry for description of legal * syntax of this obj's string rep. */ { return Tk_GetCursor(interp, tkwin, Tcl_GetString(objPtr)); } /* *---------------------------------------------------------------------- * * Tk_AllocColorFromObj -- * * Given a Tcl_Obj *, map the value to a corresponding * XColor structure based on the tkwin given. * * Results: * The return value is a pointer to an XColor structure that * indicates the red, blue, and green intensities for the color * given by the string in objPtr, and also specifies a pixel value * to use to draw in that color. If an error occurs, NULL is * returned and an error message will be left in interp's result * (unless interp is NULL). * * Side effects: * The color is added to an internal database with a reference count. * For each call to this procedure, there should eventually be a call * to Tk_FreeColorFromObj so that the database is cleaned up when colors * aren't in use anymore. * *---------------------------------------------------------------------- */ XColor * Tk_AllocColorFromObj(interp, tkwin, objPtr) Tcl_Interp *interp; /* Used only for error reporting. If NULL, * then no messages are provided. */ Tk_Window tkwin; /* Window in which the color will be used.*/ Tcl_Obj *objPtr; /* Object that describes the color; string * value is a color name such as "red" or * "#ff0000".*/ { char *string; string = Tcl_GetString(objPtr); return Tk_GetColor(interp, tkwin, Tk_GetUid(string)); } #endif /* 8.0 */ /* *-------------------------------------------------------------- * * Blt_GetPosition -- * * Convert a string representing a numeric position. * A position can be in one of the following forms. * * number - number of the item in the hierarchy, indexed * from zero. * "end" - last position in the hierarchy. * * Results: * A standard Tcl result. If "string" is a valid index, then * *indexPtr is filled with the corresponding numeric index. * If "end" was selected then *indexPtr is set to -1. * Otherwise an error message is left in interp->result. * * Side effects: * None. * *-------------------------------------------------------------- */ int Blt_GetPositionFromObj(interp, objPtr, indexPtr) Tcl_Interp *interp; /* Interpreter to report results back * to. */ Tcl_Obj *objPtr; /* Tcl_Obj representation of the index. * Can be an integer or "end" to refer * to the last index. */ int *indexPtr; /* Holds the converted index. */ { char *string; string = Tcl_GetString(objPtr); if ((string[0] == 'e') && (strcmp(string, "end") == 0)) { *indexPtr = -1; /* Indicates last position in hierarchy. */ } else { int position; if (Tcl_GetIntFromObj(interp, objPtr, &position) != TCL_OK) { return TCL_ERROR; } if (position < 0) { Tcl_AppendResult(interp, "bad position \"", string, "\"", (char *)NULL); return TCL_ERROR; } *indexPtr = position; } return TCL_OK; } /* *---------------------------------------------------------------------- * * Blt_GetPixelsFromObj -- * * Like Tk_GetPixelsFromObj, but checks for negative, zero. * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ int Blt_GetPixelsFromObj(interp, tkwin, objPtr, check, valuePtr) Tcl_Interp *interp; Tk_Window tkwin; Tcl_Obj *objPtr; int check; /* Can be PIXELS_POSITIVE, PIXELS_NONNEGATIVE, * or PIXELS_ANY, */ int *valuePtr; { int length; if (Tk_GetPixelsFromObj(interp, tkwin, objPtr, &length) != TCL_OK) { return TCL_ERROR; } if (length >= SHRT_MAX) { Tcl_AppendResult(interp, "bad distance \"", Tcl_GetString(objPtr), "\": too big to represent", (char *)NULL); return TCL_ERROR; } switch (check) { case PIXELS_NONNEGATIVE: if (length < 0) { Tcl_AppendResult(interp, "bad distance \"", Tcl_GetString(objPtr), "\": can't be negative", (char *)NULL); return TCL_ERROR; } break; case PIXELS_POSITIVE: if (length <= 0) { Tcl_AppendResult(interp, "bad distance \"", Tcl_GetString(objPtr), "\": must be positive", (char *)NULL); return TCL_ERROR; } break; case PIXELS_ANY: break; } *valuePtr = length; return TCL_OK; } int Blt_GetPadFromObj(interp, tkwin, objPtr, padPtr) Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Window */ Tcl_Obj *objPtr; /* Pixel value string */ Blt_Pad *padPtr; { int side1, side2; int objc; Tcl_Obj **objv; if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { return TCL_ERROR; } if ((objc < 1) || (objc > 2)) { Tcl_AppendResult(interp, "wrong # elements in padding list", (char *)NULL); return TCL_ERROR; } if (Blt_GetPixelsFromObj(interp, tkwin, objv[0], PIXELS_NONNEGATIVE, &side1) != TCL_OK) { return TCL_ERROR; } side2 = side1; if ((objc > 1) && (Blt_GetPixelsFromObj(interp, tkwin, objv[1], PIXELS_NONNEGATIVE, &side2) != TCL_OK)) { return TCL_ERROR; } /* Don't update the pad structure until we know both values are okay. */ padPtr->side1 = side1; padPtr->side2 = side2; return TCL_OK; } int Blt_GetShadowFromObj(interp, tkwin, objPtr, shadowPtr) Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Window */ Tcl_Obj *objPtr; /* Pixel value string */ Shadow *shadowPtr; { XColor *colorPtr; int dropOffset; int objc; Tcl_Obj **objv; if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { return TCL_ERROR; } if (objc > 2) { Tcl_AppendResult(interp, "wrong # elements in drop shadow value", (char *)NULL); return TCL_ERROR; } dropOffset = 0; colorPtr = NULL; if (objc > 0) { colorPtr = Tk_AllocColorFromObj(interp, tkwin, objv[0]); if (colorPtr == NULL) { return TCL_ERROR; } dropOffset = 1; if (objc == 2) { if (Blt_GetPixelsFromObj(interp, tkwin, objv[1], PIXELS_NONNEGATIVE, &dropOffset) != TCL_OK) { Tk_FreeColor(colorPtr); return TCL_ERROR; } } } if (shadowPtr->color != NULL) { Tk_FreeColor(shadowPtr->color); } shadowPtr->color = colorPtr; shadowPtr->offset = dropOffset; return TCL_OK; } int Blt_GetStateFromObj(interp, objPtr, statePtr) Tcl_Interp *interp; /* Interpreter to send results back to */ Tcl_Obj *objPtr; /* Pixel value string */ int *statePtr; { char *string; string = Tcl_GetString(objPtr); if (strcmp(string, "normal") == 0) { *statePtr = STATE_NORMAL; } else if (strcmp(string, "disabled") == 0) { *statePtr = STATE_DISABLED; } else if (strcmp(string, "active") == 0) { *statePtr = STATE_ACTIVE; } else { Tcl_AppendResult(interp, "bad state \"", string, "\": should be normal, active, or disabled", (char *)NULL); return TCL_ERROR; } return TCL_OK; } char * Blt_NameOfState(state) int state; { switch (state) { case STATE_ACTIVE: return "active"; case STATE_DISABLED: return "disabled"; case STATE_NORMAL: return "normal"; default: return "???"; } } #ifdef notdef /* Replace this routine when Tcl_Obj-based * configuration comes on-line */ /* *---------------------------------------------------------------------- * * Blt_NameOfFill -- * * Converts the integer representing the fill style into a string. * *---------------------------------------------------------------------- */ char * Blt_NameOfFill(fill) int fill; { switch (fill) { case FILL_X: return "x"; case FILL_Y: return "y"; case FILL_NONE: return "none"; case FILL_BOTH: return "both"; default: return "unknown value"; } } #endif /* *---------------------------------------------------------------------- * * Blt_GetFillFromObj -- * * Converts the fill style string into its numeric representation. * * Valid style strings are: * * "none" Use neither plane. * "x" X-coordinate plane. * "y" Y-coordinate plane. * "both" Use both coordinate planes. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ int Blt_GetFillFromObj(interp, objPtr, fillPtr) Tcl_Interp *interp; /* Interpreter to send results back to */ Tcl_Obj *objPtr; /* Fill style string */ int *fillPtr; { int length; char c; char *string; string = Tcl_GetStringFromObj(objPtr, &length); c = string[0]; if ((c == 'n') && (strncmp(string, "none", length) == 0)) { *fillPtr = FILL_NONE; } else if ((c == 'x') && (strncmp(string, "x", length) == 0)) { *fillPtr = FILL_X; } else if ((c == 'y') && (strncmp(string, "y", length) == 0)) { *fillPtr = FILL_Y; } else if ((c == 'b') && (strncmp(string, "both", length) == 0)) { *fillPtr = FILL_BOTH; } else { Tcl_AppendResult(interp, "bad argument \"", string, "\": should be \"none\", \"x\", \"y\", or \"both\"", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * Blt_GetDashesFromObj -- * * Converts a Tcl list of dash values into a dash list ready for * use with XSetDashes. * * A valid list dash values can have zero through 11 elements * (PostScript limit). Values must be between 1 and 255. Although * a list of 0 (like the empty string) means no dashes. * * Results: * A standard Tcl result. If the list represented a valid dash * list TCL_OK is returned and *dashesPtr* will contain the * valid dash list. Otherwise, TCL_ERROR is returned and * interp->result will contain an error message. * * *---------------------------------------------------------------------- */ int Blt_GetDashesFromObj(interp, objPtr, dashesPtr) Tcl_Interp *interp; Tcl_Obj *objPtr; Blt_Dashes *dashesPtr; { char *string; string = Tcl_GetString(objPtr); if ((string == NULL) || (*string == '\0')) { dashesPtr->values[0] = 0; } else if (strcmp(string, "dash") == 0) { /* 5 2 */ dashesPtr->values[0] = 5; dashesPtr->values[1] = 2; dashesPtr->values[2] = 0; } else if (strcmp(string, "dot") == 0) { /* 1 */ dashesPtr->values[0] = 1; dashesPtr->values[1] = 0; } else if (strcmp(string, "dashdot") == 0) { /* 2 4 2 */ dashesPtr->values[0] = 2; dashesPtr->values[1] = 4; dashesPtr->values[2] = 2; dashesPtr->values[3] = 0; } else if (strcmp(string, "dashdotdot") == 0) { /* 2 4 2 2 */ 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; int value; register int i; if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { return TCL_ERROR; } if (objc > 11) { /* This is the postscript limit */ Tcl_AppendResult(interp, "too many values in dash list \"", string, "\"", (char *)NULL); return TCL_ERROR; } for (i = 0; i < objc; i++) { if (Tcl_GetIntFromObj(interp, objv[i], &value) != TCL_OK) { return TCL_ERROR; } /* * Backward compatibility: * Allow list of 0 to turn off dashes */ if ((value == 0) && (objc == 1)) { break; } if ((value < 1) || (value > 255)) { Tcl_AppendResult(interp, "dash value \"", Tcl_GetString(objv[i]), "\" is out of range", (char *)NULL); return TCL_ERROR; } dashesPtr->values[i] = (unsigned char)value; } /* Make sure the array ends with a NUL byte */ dashesPtr->values[i] = 0; } return TCL_OK; } char * Blt_NameOfSide(side) int side; { switch (side) { case SIDE_LEFT: return "left"; case SIDE_RIGHT: return "right"; case SIDE_BOTTOM: return "bottom"; case SIDE_TOP: return "top"; } return "unknown side value"; } /* *---------------------------------------------------------------------- * * Blt_GetSideFromObj -- * * Converts the fill style string into its numeric representation. * * Valid style strings are "left", "right", "top", or "bottom". * *---------------------------------------------------------------------- */ /*ARGSUSED */ int Blt_GetSideFromObj(interp, objPtr, sidePtr) Tcl_Interp *interp; /* Interpreter to send results back to */ Tcl_Obj *objPtr; /* Value string */ int *sidePtr; /* (out) Token representing side: * either SIDE_LEFT, SIDE_RIGHT, * SIDE_TOP, or SIDE_BOTTOM. */ { char c; int length; char *string; string = Tcl_GetStringFromObj(objPtr, &length); c = string[0]; if ((c == 'l') && (strncmp(string, "left", length) == 0)) { *sidePtr = SIDE_LEFT; } else if ((c == 'r') && (strncmp(string, "right", length) == 0)) { *sidePtr = SIDE_RIGHT; } else if ((c == 't') && (strncmp(string, "top", length) == 0)) { *sidePtr = SIDE_TOP; } else if ((c == 'b') && (strncmp(string, "bottom", length) == 0)) { *sidePtr = SIDE_BOTTOM; } else { Tcl_AppendResult(interp, "bad side \"", string, "\": should be left, right, top, or bottom", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * Blt_StringToEnum -- * * Converts the string into its enumerated type. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ int Blt_ObjToEnum(clientData, interp, tkwin, objPtr, widgRec, offset) ClientData clientData; /* Vectors of valid strings. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ Tcl_Obj *objPtr; char *widgRec; /* Widget record. */ int offset; /* Offset of field in record */ { int *enumPtr = (int *)(widgRec + offset); char c; register char **p; register int i; int count; char *string; string = Tcl_GetString(objPtr); c = string[0]; count = 0; for (p = (char **)clientData; *p != NULL; p++) { if ((c == p[0][0]) && (strcmp(string, *p) == 0)) { *enumPtr = count; return TCL_OK; } count++; } *enumPtr = -1; Tcl_AppendResult(interp, "bad value \"", string, "\": should be ", (char *)NULL); p = (char **)clientData; if (count > 0) { Tcl_AppendResult(interp, p[0], (char *)NULL); } for (i = 1; i < (count - 1); i++) { Tcl_AppendResult(interp, " ", p[i], ", ", (char *)NULL); } if (count > 1) { Tcl_AppendResult(interp, " or ", p[count - 1], ".", (char *)NULL); } return TCL_ERROR; } /* *---------------------------------------------------------------------- * * Blt_EnumToObj -- * * Returns the string associated with the enumerated type. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ Tcl_Obj * Blt_EnumToObj(clientData, interp, tkwin, widgRec, offset) ClientData clientData; /* List of strings. */ Tcl_Interp *interp; Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget record */ int offset; /* Offset of field in widget record */ { int value = *(int *)(widgRec + offset); char **strings = (char **)clientData; char **p; int count; count = 0; for (p = strings; *p != NULL; p++) { if (value == count) { return Tcl_NewStringObj(*p, -1); } count++; } return Tcl_NewStringObj("unknown value", -1); } /* Configuration option helper routines */ /* *-------------------------------------------------------------- * * DoConfig -- * * This procedure applies a single configuration option * to a widget record. * * Results: * A standard Tcl return value. * * Side effects: * WidgRec is modified as indicated by specPtr and value. * The old value is recycled, if that is appropriate for * the value type. * *-------------------------------------------------------------- */ static int DoConfig(interp, tkwin, specPtr, objPtr, widgRec) Tcl_Interp *interp; /* Interpreter for error reporting. */ Tk_Window tkwin; /* Window containing widget (needed to * set up X resources). */ Blt_ConfigSpec *specPtr; /* Specifier to apply. */ Tcl_Obj *objPtr; /* Value to use to fill in widgRec. */ char *widgRec; /* Record whose fields are to be * modified. Values must be properly * initialized. */ { char *ptr; int objIsEmpty; objIsEmpty = FALSE; if (objPtr == NULL) { objIsEmpty = TRUE; } else if (specPtr->specFlags & BLT_CONFIG_NULL_OK) { int length; if (objPtr->bytes != NULL) { length = objPtr->length; } else { Tcl_GetStringFromObj(objPtr, &length); } objIsEmpty = (length == 0); } do { ptr = widgRec + specPtr->offset; switch (specPtr->type) { case BLT_CONFIG_ANCHOR: { Tk_Anchor anchor; if (Tk_GetAnchorFromObj(interp, objPtr, &anchor) != TCL_OK) { return TCL_ERROR; } *(Tk_Anchor *)ptr = anchor; } break; case BLT_CONFIG_BITMAP: { Pixmap newBitmap, oldBitmap; if (objIsEmpty) { newBitmap = None; } else { newBitmap = Tk_AllocBitmapFromObj(interp, tkwin, objPtr); if (newBitmap == None) { return TCL_ERROR; } } oldBitmap = *(Pixmap *)ptr; if (oldBitmap != None) { Tk_FreeBitmap(Tk_Display(tkwin), oldBitmap); } *(Pixmap *)ptr = newBitmap; } break; case BLT_CONFIG_BOOLEAN: { int newBool; if (Tcl_GetBooleanFromObj(interp, objPtr, &newBool) != TCL_OK) { return TCL_ERROR; } *(int *)ptr = newBool; } break; case BLT_CONFIG_BORDER: { Tk_3DBorder newBorder, oldBorder; if (objIsEmpty) { newBorder = NULL; } else { newBorder = Tk_Alloc3DBorderFromObj(interp, tkwin, objPtr); if (newBorder == NULL) { return TCL_ERROR; } } oldBorder = *(Tk_3DBorder *)ptr; if (oldBorder != NULL) { Tk_Free3DBorder(oldBorder); } *(Tk_3DBorder *)ptr = newBorder; } break; case BLT_CONFIG_CAP_STYLE: { int cap; Tk_Uid value; value = Tk_GetUid(Tcl_GetString(objPtr)); if (Tk_GetCapStyle(interp, value, &cap) != TCL_OK) { return TCL_ERROR; } *(int *)ptr = cap; } break; case BLT_CONFIG_COLOR: { XColor *newColor, *oldColor; if (objIsEmpty) { newColor = NULL; } else { newColor = Tk_AllocColorFromObj(interp, tkwin, objPtr); if (newColor == NULL) { return TCL_ERROR; } } oldColor = *(XColor **)ptr; if (oldColor != NULL) { Tk_FreeColor(oldColor); } *(XColor **)ptr = newColor; } break; case BLT_CONFIG_CURSOR: case BLT_CONFIG_ACTIVE_CURSOR: { Tk_Cursor newCursor, oldCursor; if (objIsEmpty) { newCursor = None; } else { newCursor = Tk_AllocCursorFromObj(interp, tkwin, objPtr); if (newCursor == None) { return TCL_ERROR; } } oldCursor = *(Tk_Cursor *)ptr; if (oldCursor != None) { Tk_FreeCursor(Tk_Display(tkwin), oldCursor); } *(Tk_Cursor *)ptr = newCursor; if (specPtr->type == BLT_CONFIG_ACTIVE_CURSOR) { Tk_DefineCursor(tkwin, newCursor); } } break; case BLT_CONFIG_CUSTOM: { if ((*(char **)ptr != NULL) && (specPtr->customPtr->freeProc != NULL)) { (*specPtr->customPtr->freeProc) (specPtr->customPtr->clientData, Tk_Display(tkwin), widgRec, specPtr->offset); *(char **)ptr = NULL; } if (objIsEmpty) { *(char **)ptr = NULL; } else { int result; result = (*specPtr->customPtr->parseProc) (specPtr->customPtr->clientData, interp, tkwin, objPtr, widgRec, specPtr->offset); if (result != TCL_OK) { return TCL_ERROR; } } } break; case BLT_CONFIG_DOUBLE: { double newDouble; if (Tcl_GetDoubleFromObj(interp, objPtr, &newDouble) != TCL_OK) { return TCL_ERROR; } *(double *)ptr = newDouble; } break; case BLT_CONFIG_FONT: { Tk_Font newFont, oldFont; if (objIsEmpty) { newFont = NULL; } else { newFont = Tk_AllocFontFromObj(interp, tkwin, objPtr); if (newFont == NULL) { return TCL_ERROR; } } oldFont = *(Tk_Font *)ptr; if (oldFont != NULL) { Tk_FreeFont(oldFont); } *(Tk_Font *)ptr = newFont; } break; case BLT_CONFIG_INT: { int newInt; if (Tcl_GetIntFromObj(interp, objPtr, &newInt) != TCL_OK) { return TCL_ERROR; } *(int *)ptr = newInt; } break; case BLT_CONFIG_JOIN_STYLE: { int join; Tk_Uid value; value = Tk_GetUid(Tcl_GetString(objPtr)); if (Tk_GetJoinStyle(interp, value, &join) != TCL_OK) { return TCL_ERROR; } *(int *)ptr = join; } break; case BLT_CONFIG_JUSTIFY: { Tk_Justify justify; if (Tk_GetJustifyFromObj(interp, objPtr, &justify) != TCL_OK) { return TCL_ERROR; } *(Tk_Justify *)ptr = justify; } break; case BLT_CONFIG_MM: { double mm; if (Tk_GetMMFromObj(interp, tkwin, objPtr, &mm) != TCL_OK) { return TCL_ERROR; } *(double *)ptr = mm; } break; case BLT_CONFIG_PIXELS: { int pixels; if (Tk_GetPixelsFromObj(interp, tkwin, objPtr, &pixels) != TCL_OK) { return TCL_ERROR; } *(int *)ptr = pixels; } break; case BLT_CONFIG_RELIEF: { int relief; if (Tk_GetReliefFromObj(interp, objPtr, &relief) != TCL_OK) { return TCL_ERROR; } *(int *)ptr = relief; } break; case BLT_CONFIG_STRING: { char *oldString, *newString; if (objIsEmpty) { newString = NULL; } else { newString = (char *)Blt_Strdup(Tcl_GetString(objPtr)); } oldString = *(char **)ptr; if (oldString != NULL) { Blt_Free(oldString); } *(char **)ptr = newString; } break; case BLT_CONFIG_UID: if (objIsEmpty) { *(Tk_Uid *)ptr = NULL; } else { *(Tk_Uid *)ptr = Tk_GetUid(Tcl_GetString(objPtr)); } break; case BLT_CONFIG_WINDOW: { Tk_Window tkwin2; if (objIsEmpty) { tkwin2 = None; } else { char *path; path = Tcl_GetString(objPtr); tkwin2 = Tk_NameToWindow(interp, path, tkwin); if (tkwin2 == NULL) { return TCL_ERROR; } } *(Tk_Window *)ptr = tkwin2; } break; case BLT_CONFIG_BITFLAG: { int bool; unsigned int flag; if (Tcl_GetBooleanFromObj(interp, objPtr, &bool) != TCL_OK) { return TCL_ERROR; } flag = (unsigned int)specPtr->customPtr; *(int *)ptr &= ~flag; if (bool) { *(int *)ptr |= flag; } } break; case BLT_CONFIG_DASHES: if (Blt_GetDashesFromObj(interp, objPtr, (Blt_Dashes *)ptr) != TCL_OK) { return TCL_ERROR; } break; case BLT_CONFIG_DISTANCE: { int newPixels; if (Blt_GetPixelsFromObj(interp, tkwin, objPtr, PIXELS_NONNEGATIVE, &newPixels) != TCL_OK) { return TCL_ERROR; } *(int *)ptr = newPixels; } break; case BLT_CONFIG_FILL: if (Blt_GetFillFromObj(interp, objPtr, (int *)ptr) != TCL_OK) { return TCL_ERROR; } break; case BLT_CONFIG_FLOAT: { double newDouble; if (Tcl_GetDoubleFromObj(interp, objPtr, &newDouble) != TCL_OK) { return TCL_ERROR; } *(float *)ptr = (float)newDouble; } break; case BLT_CONFIG_LIST: { char **argv; int argc; if (Tcl_SplitList(interp, Tcl_GetString(objPtr), &argc, &argv) != TCL_OK) { return TCL_ERROR; } *(char ***)ptr = argv; } break; case BLT_CONFIG_LISTOBJ: { Tcl_Obj **objv; Tcl_Obj *listObjPtr; int objc; if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { return TCL_ERROR; } listObjPtr = Tcl_NewListObj(objc, objv); Tcl_IncrRefCount(listObjPtr); *(Tcl_Obj **)ptr = listObjPtr; } break; case BLT_CONFIG_PAD: if (Blt_GetPadFromObj(interp, tkwin, objPtr, (Blt_Pad *)ptr) != TCL_OK) { return TCL_ERROR; } break; case BLT_CONFIG_POS_DISTANCE: { int newPixels; if (Blt_GetPixelsFromObj(interp, tkwin, objPtr, PIXELS_POSITIVE, &newPixels) != TCL_OK) { return TCL_ERROR; } *(int *)ptr = newPixels; } break; case BLT_CONFIG_SHADOW: { Shadow *shadowPtr = (Shadow *)ptr; if ((shadowPtr != NULL) && (shadowPtr->color != NULL)) { Tk_FreeColor(shadowPtr->color); } if (Blt_GetShadowFromObj(interp, tkwin, objPtr, shadowPtr) != TCL_OK) { return TCL_ERROR; } } break; case BLT_CONFIG_STATE: { if (Blt_GetStateFromObj(interp, objPtr, (int *)ptr) != TCL_OK) { return TCL_ERROR; } } break; case BLT_CONFIG_TILE: { Blt_Tile newTile, oldTile; if (objIsEmpty) { newTile = None; } else { if (Blt_GetTile(interp, tkwin, Tcl_GetString(objPtr), &newTile) != TCL_OK) { return TCL_ERROR; } } oldTile = *(Blt_Tile *)ptr; if (oldTile != NULL) { Blt_FreeTile(oldTile); } *(Blt_Tile *)ptr = newTile; } break; case BLT_CONFIG_SIDE: if (Blt_GetSideFromObj(interp, objPtr, (int *)ptr) != TCL_OK) { return TCL_ERROR; } break; default: { char buf[200]; sprintf(buf, "bad config table: unknown type %d", specPtr->type); Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_ERROR; } } specPtr++; } while ((specPtr->switchName == NULL) && (specPtr->type != BLT_CONFIG_END)); return TCL_OK; } /* *---------------------------------------------------------------------- * * FormatConfigValue -- * * This procedure formats the current value of a configuration * option. * * Results: * The return value is the formatted value of the option given * by specPtr and widgRec. If the value is static, so that it * need not be freed, *freeProcPtr will be set to NULL; otherwise * *freeProcPtr will be set to the address of a procedure to * free the result, and the caller must invoke this procedure * when it is finished with the result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Obj * FormatConfigValue(interp, tkwin, specPtr, widgRec) Tcl_Interp *interp; /* Interpreter for use in real conversions. */ Tk_Window tkwin; /* Window corresponding to widget. */ Blt_ConfigSpec *specPtr; /* Pointer to information describing option. * Must not point to a synonym option. */ char *widgRec; /* Pointer to record holding current * values of info for widget. */ { char *ptr; char *string; ptr = widgRec + specPtr->offset; string = ""; switch (specPtr->type) { case BLT_CONFIG_ANCHOR: string = Tk_NameOfAnchor(*(Tk_Anchor *)ptr); break; case BLT_CONFIG_BITMAP: if (*(Pixmap *)ptr != None) { string = Tk_NameOfBitmap(Tk_Display(tkwin), *(Pixmap *)ptr); } break; case BLT_CONFIG_BOOLEAN: return Tcl_NewBooleanObj(*(int *)ptr); case BLT_CONFIG_BORDER: if (*(Tk_3DBorder *)ptr != NULL) { string = Tk_NameOf3DBorder(*(Tk_3DBorder *)ptr); } break; case BLT_CONFIG_CAP_STYLE: string = Tk_NameOfCapStyle(*(int *)ptr); break; case BLT_CONFIG_COLOR: if (*(XColor **)ptr != NULL) { string = Tk_NameOfColor(*(XColor **)ptr); } break; case BLT_CONFIG_CURSOR: case BLT_CONFIG_ACTIVE_CURSOR: if (*(Tk_Cursor *)ptr != None) { string = Tk_NameOfCursor(Tk_Display(tkwin), *(Tk_Cursor *)ptr); } break; case BLT_CONFIG_CUSTOM: return (*specPtr->customPtr->printProc)(specPtr->customPtr->clientData, interp, tkwin, widgRec, specPtr->offset); case BLT_CONFIG_DOUBLE: return Tcl_NewDoubleObj(*(double *)ptr); case BLT_CONFIG_FONT: if (*(Tk_Font *)ptr != NULL) { string = Tk_NameOfFont(*(Tk_Font *)ptr); } break; case BLT_CONFIG_INT: return Tcl_NewIntObj(*(int *)ptr); case BLT_CONFIG_JOIN_STYLE: string = Tk_NameOfJoinStyle(*(int *)ptr); break; case BLT_CONFIG_JUSTIFY: string = Tk_NameOfJustify(*(Tk_Justify *)ptr); break; case BLT_CONFIG_MM: return Tcl_NewDoubleObj(*(double *)ptr); case BLT_CONFIG_PIXELS: return Tcl_NewIntObj(*(int *)ptr); case BLT_CONFIG_RELIEF: string = Tk_NameOfRelief(*(int *)ptr); break; case BLT_CONFIG_STRING: case BLT_CONFIG_UID: if (*(char **)ptr != NULL) { string = *(char **)ptr; } break; case BLT_CONFIG_BITFLAG: { unsigned int flag; flag = (*(int *)ptr) & (unsigned int)specPtr->customPtr; return Tcl_NewBooleanObj((flag != 0)); } case BLT_CONFIG_DASHES: { unsigned char *p; Tcl_Obj *listObjPtr; Blt_Dashes *dashesPtr = (Blt_Dashes *)ptr; listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); for(p = dashesPtr->values; *p != 0; p++) { Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewIntObj(*p)); } return listObjPtr; } case BLT_CONFIG_DISTANCE: case BLT_CONFIG_POS_DISTANCE: return Tcl_NewIntObj(*(int *)ptr); case BLT_CONFIG_FILL: string = Blt_NameOfFill(*(int *)ptr); break; case BLT_CONFIG_FLOAT: { double x = *(double *)ptr; return Tcl_NewDoubleObj(x); } case BLT_CONFIG_LIST: { Tcl_Obj *objPtr, *listObjPtr; char **p; listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); for (p = *(char ***)ptr; *p != NULL; p++) { objPtr = Tcl_NewStringObj(*p, -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } return listObjPtr; } case BLT_CONFIG_LISTOBJ: return *(Tcl_Obj **)ptr; case BLT_CONFIG_PAD: { Blt_Pad *padPtr = (Blt_Pad *)ptr; Tcl_Obj *objPtr, *listObjPtr; listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); objPtr = Tcl_NewIntObj(padPtr->side1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); objPtr = Tcl_NewIntObj(padPtr->side2); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); return listObjPtr; } case BLT_CONFIG_SHADOW: { Shadow *shadowPtr = (Shadow *)ptr; Tcl_Obj *objPtr, *listObjPtr; if (shadowPtr->color != NULL) { listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); objPtr = Tcl_NewStringObj(Tk_NameOfColor(shadowPtr->color), -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); objPtr = Tcl_NewIntObj(shadowPtr->offset); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); return listObjPtr; } } case BLT_CONFIG_STATE: string = Blt_NameOfState(*(int *)ptr); break; case BLT_CONFIG_TILE: string = Blt_NameOfTile((Blt_Tile)ptr); break; case BLT_CONFIG_SIDE: string = Blt_NameOfSide(*(int *)ptr); break; default: string = "?? unknown type ??"; } return Tcl_NewStringObj(string, -1); } /* *-------------------------------------------------------------- * * FormatConfigInfo -- * * Create a valid Tcl list holding the configuration information * for a single configuration option. * * Results: * A Tcl list, dynamically allocated. The caller is expected to * arrange for this list to be freed eventually. * * Side effects: * Memory is allocated. * *-------------------------------------------------------------- */ static Tcl_Obj * FormatConfigInfo(interp, tkwin, specPtr, widgRec) Tcl_Interp *interp; /* Interpreter to use for things * like floating-point precision. */ Tk_Window tkwin; /* Window corresponding to widget. */ register Blt_ConfigSpec *specPtr; /* Pointer to information describing * option. */ char *widgRec; /* Pointer to record holding current * values of info for widget. */ { Tcl_Obj *objv[5]; Tcl_Obj *listObjPtr; register int i; for (i = 0; i < 5; i++) { objv[i] = bltEmptyStringObjPtr; } if (specPtr->switchName != NULL) { objv[0] = Tcl_NewStringObj(specPtr->switchName, -1); } if (specPtr->dbName != NULL) { objv[1] = Tcl_NewStringObj(specPtr->dbName, -1); } if (specPtr->type == BLT_CONFIG_SYNONYM) { listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); Tcl_ListObjAppendElement(interp, listObjPtr, objv[0]); Tcl_ListObjAppendElement(interp, listObjPtr, objv[1]); return listObjPtr; } if (specPtr->dbClass != NULL) { objv[2] = Tcl_NewStringObj(specPtr->dbClass, -1); } if (specPtr->defValue != NULL) { objv[3] = Tcl_NewStringObj(specPtr->defValue, -1); } objv[4] = FormatConfigValue(interp, tkwin, specPtr, widgRec); return Tcl_NewListObj(5, objv); } /* *-------------------------------------------------------------- * * FindConfigSpec -- * * Search through a table of configuration specs, looking for * one that matches a given switchName. * * Results: * The return value is a pointer to the matching entry, or NULL * if nothing matched. In that case an error message is left * in the interp's result. * * Side effects: * None. * *-------------------------------------------------------------- */ static Blt_ConfigSpec * FindConfigSpec(interp, specs, objPtr, needFlags, hateFlags) Tcl_Interp *interp; /* Used for reporting errors. */ Blt_ConfigSpec *specs; /* Pointer to table of configuration * specifications for a widget. */ Tcl_Obj *objPtr; /* Name (suitable for use in a "config" * command) identifying particular option. */ int needFlags; /* Flags that must be present in matching * entry. */ int hateFlags; /* Flags that must NOT be present in * matching entry. */ { register Blt_ConfigSpec *specPtr; register char c; /* First character of current argument. */ Blt_ConfigSpec *matchPtr; /* Matching spec, or NULL. */ int length; char *string; string = Tcl_GetStringFromObj(objPtr, &length); c = string[1]; matchPtr = NULL; for (specPtr = specs; specPtr->type != BLT_CONFIG_END; specPtr++) { if (specPtr->switchName == NULL) { continue; } if ((specPtr->switchName[1] != c) || (strncmp(specPtr->switchName, string, length) != 0)) { continue; } if (((specPtr->specFlags & needFlags) != needFlags) || (specPtr->specFlags & hateFlags)) { continue; } if (specPtr->switchName[length] == 0) { matchPtr = specPtr; goto gotMatch; } if (matchPtr != NULL) { if (interp != NULL) { Tcl_AppendResult(interp, "ambiguous option \"", string, "\"", (char *)NULL); } return (Blt_ConfigSpec *)NULL; } matchPtr = specPtr; } if (matchPtr == NULL) { if (interp != NULL) { Tcl_AppendResult(interp, "unknown option \"", string, "\"", (char *)NULL); } return (Blt_ConfigSpec *)NULL; } /* * Found a matching entry. If it's a synonym, then find the * entry that it's a synonym for. */ gotMatch: specPtr = matchPtr; if (specPtr->type == BLT_CONFIG_SYNONYM) { for (specPtr = specs; ; specPtr++) { if (specPtr->type == BLT_CONFIG_END) { if (interp != NULL) { Tcl_AppendResult(interp, "couldn't find synonym for option \"", string, "\"", (char *) NULL); } return (Blt_ConfigSpec *) NULL; } if ((specPtr->dbName == matchPtr->dbName) && (specPtr->type != BLT_CONFIG_SYNONYM) && ((specPtr->specFlags & needFlags) == needFlags) && !(specPtr->specFlags & hateFlags)) { break; } } } return specPtr; } /* Public routines */ /* *-------------------------------------------------------------- * * Blt_ConfigureWidgetFromObj -- * * Process command-line options and database options to * fill in fields of a widget record with resources and * other parameters. * * Results: * A standard Tcl return value. In case of an error, * the interp's result will hold an error message. * * Side effects: * The fields of widgRec get filled in with information * from argc/argv and the option database. Old information * in widgRec's fields gets recycled. * *-------------------------------------------------------------- */ int Blt_ConfigureWidgetFromObj(interp, tkwin, specs, objc, objv, widgRec, flags) Tcl_Interp *interp; /* Interpreter for error reporting. */ Tk_Window tkwin; /* Window containing widget (needed to * set up X resources). */ Blt_ConfigSpec *specs; /* Describes legal options. */ int objc; /* Number of elements in argv. */ Tcl_Obj *CONST *objv; /* Command-line options. */ char *widgRec; /* Record whose fields are to be * modified. Values must be properly * initialized. */ int flags; /* Used to specify additional flags * that must be present in config specs * for them to be considered. Also, * may have BLT_CONFIG_ARGV_ONLY set. */ { register Blt_ConfigSpec *specPtr; int needFlags; /* Specs must contain this set of flags * or else they are not considered. */ int hateFlags; /* If a spec contains any bits here, it's * not considered. */ if (tkwin == NULL) { /* * Either we're not really in Tk, or the main window was destroyed and * we're on our way out of the application */ Tcl_AppendResult(interp, "NULL main window", (char *)NULL); return TCL_ERROR; } needFlags = flags & ~(BLT_CONFIG_USER_BIT - 1); if (Tk_Depth(tkwin) <= 1) { hateFlags = BLT_CONFIG_COLOR_ONLY; } else { hateFlags = BLT_CONFIG_MONO_ONLY; } /* * Pass one: scan through all the option specs, replacing strings * with Tk_Uid structs (if this hasn't been done already) and * clearing the BLT_CONFIG_OPTION_SPECIFIED flags. */ for (specPtr = specs; specPtr->type != BLT_CONFIG_END; specPtr++) { if (!(specPtr->specFlags & INIT) && (specPtr->switchName != NULL)) { if (specPtr->dbName != NULL) { specPtr->dbName = Tk_GetUid(specPtr->dbName); } if (specPtr->dbClass != NULL) { specPtr->dbClass = Tk_GetUid(specPtr->dbClass); } if (specPtr->defValue != NULL) { specPtr->defValue = Tk_GetUid(specPtr->defValue); } } specPtr->specFlags = (specPtr->specFlags & ~BLT_CONFIG_OPTION_SPECIFIED) | INIT; } /* * Pass two: scan through all of the arguments, processing those * that match entries in the specs. */ while (objc > 0) { specPtr = FindConfigSpec(interp, specs, objv[0], needFlags, hateFlags); if (specPtr == NULL) { return TCL_ERROR; } /* Process the entry. */ if (objc < 2) { Tcl_AppendResult(interp, "value for \"", Tcl_GetString(objv[0]), "\" missing", (char *) NULL); return TCL_ERROR; } if (DoConfig(interp, tkwin, specPtr, objv[1], widgRec) != TCL_OK) { char msg[100]; sprintf(msg, "\n (processing \"%.40s\" option)", specPtr->switchName); Tcl_AddErrorInfo(interp, msg); return TCL_ERROR; } specPtr->specFlags |= BLT_CONFIG_OPTION_SPECIFIED; objc -= 2, objv += 2; } /* * Pass three: scan through all of the specs again; if no * command-line argument matched a spec, then check for info * in the option database. If there was nothing in the * database, then use the default. */ if (!(flags & BLT_CONFIG_OBJV_ONLY)) { Tcl_Obj *objPtr; for (specPtr = specs; specPtr->type != BLT_CONFIG_END; specPtr++) { if ((specPtr->specFlags & BLT_CONFIG_OPTION_SPECIFIED) || (specPtr->switchName == NULL) || (specPtr->type == BLT_CONFIG_SYNONYM)) { continue; } if (((specPtr->specFlags & needFlags) != needFlags) || (specPtr->specFlags & hateFlags)) { continue; } objPtr = NULL; if (specPtr->dbName != NULL) { Tk_Uid value; value = Tk_GetOption(tkwin, specPtr->dbName, specPtr->dbClass); if (value != NULL) { objPtr = Tcl_NewStringObj(value, -1); } } if (objPtr != NULL) { if (DoConfig(interp, tkwin, specPtr, objPtr, widgRec) != TCL_OK) { char msg[200]; sprintf(msg, "\n (%s \"%.50s\" in widget \"%.50s\")", "database entry for", specPtr->dbName, Tk_PathName(tkwin)); Tcl_AddErrorInfo(interp, msg); return TCL_ERROR; } } else { if (specPtr->defValue != NULL) { objPtr = Tcl_NewStringObj(specPtr->defValue, -1); } else { objPtr = NULL; } if ((objPtr != NULL) && !(specPtr->specFlags & BLT_CONFIG_DONT_SET_DEFAULT)) { if (DoConfig(interp, tkwin, specPtr, objPtr, widgRec) != TCL_OK) { char msg[200]; sprintf(msg, "\n (%s \"%.50s\" in widget \"%.50s\")", "default value for", specPtr->dbName, Tk_PathName(tkwin)); Tcl_AddErrorInfo(interp, msg); return TCL_ERROR; } } } } } return TCL_OK; } /* *-------------------------------------------------------------- * * Blt_ConfigureInfoFromObj -- * * Return information about the configuration options * for a window, and their current values. * * Results: * Always returns TCL_OK. The interp's result will be modified * hold a description of either a single configuration option * available for "widgRec" via "specs", or all the configuration * options available. In the "all" case, the result will * available for "widgRec" via "specs". The result will * be a list, each of whose entries describes one option. * Each entry will itself be a list containing the option's * name for use on command lines, database name, database * class, default value, and current value (empty string * if none). For options that are synonyms, the list will * contain only two values: name and synonym name. If the * "name" argument is non-NULL, then the only information * returned is that for the named argument (i.e. the corresponding * entry in the overall list is returned). * * Side effects: * None. * *-------------------------------------------------------------- */ int Blt_ConfigureInfoFromObj(interp, tkwin, specs, widgRec, objPtr, flags) Tcl_Interp *interp; /* Interpreter for error reporting. */ Tk_Window tkwin; /* Window corresponding to widgRec. */ Blt_ConfigSpec *specs; /* Describes legal options. */ char *widgRec; /* Record whose fields contain current * values for options. */ Tcl_Obj *objPtr; /* If non-NULL, indicates a single option * whose info is to be returned. Otherwise * info is returned for all options. */ int flags; /* Used to specify additional flags * that must be present in config specs * for them to be considered. */ { register Blt_ConfigSpec *specPtr; int needFlags, hateFlags; char *string; Tcl_Obj *listObjPtr, *valueObjPtr; needFlags = flags & ~(BLT_CONFIG_USER_BIT - 1); if (Tk_Depth(tkwin) <= 1) { hateFlags = BLT_CONFIG_COLOR_ONLY; } else { hateFlags = BLT_CONFIG_MONO_ONLY; } /* * If information is only wanted for a single configuration * spec, then handle that one spec specially. */ Tcl_SetResult(interp, (char *)NULL, TCL_STATIC); if (objPtr != NULL) { specPtr = FindConfigSpec(interp, specs, objPtr, needFlags, hateFlags); if (specPtr == NULL) { return TCL_ERROR; } valueObjPtr = FormatConfigInfo(interp, tkwin, specPtr, widgRec); Tcl_SetObjResult(interp, valueObjPtr); return TCL_OK; } /* * Loop through all the specs, creating a big list with all * their information. */ string = NULL; /* Suppress compiler warning. */ if (objPtr != NULL) { string = Tcl_GetString(objPtr); } listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); for (specPtr = specs; specPtr->type != BLT_CONFIG_END; specPtr++) { if ((objPtr != NULL) && (specPtr->switchName != string)) { continue; } if (((specPtr->specFlags & needFlags) != needFlags) || (specPtr->specFlags & hateFlags)) { continue; } if (specPtr->switchName == NULL) { continue; } valueObjPtr = FormatConfigInfo(interp, tkwin, specPtr, widgRec); Tcl_ListObjAppendElement(interp, listObjPtr, valueObjPtr); } Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * Blt_ConfigureValueFromObj -- * * This procedure returns the current value of a configuration * option for a widget. * * Results: * The return value is a standard Tcl completion code (TCL_OK or * TCL_ERROR). The interp's result will be set to hold either the value * of the option given by objPtr (if TCL_OK is returned) or * an error message (if TCL_ERROR is returned). * * Side effects: * None. * *---------------------------------------------------------------------- */ int Blt_ConfigureValueFromObj(interp, tkwin, specs, widgRec, objPtr, flags) Tcl_Interp *interp; /* Interpreter for error reporting. */ Tk_Window tkwin; /* Window corresponding to widgRec. */ Blt_ConfigSpec *specs; /* Describes legal options. */ char *widgRec; /* Record whose fields contain current * values for options. */ Tcl_Obj *objPtr; /* Gives the command-line name for the * option whose value is to be returned. */ int flags; /* Used to specify additional flags * that must be present in config specs * for them to be considered. */ { Blt_ConfigSpec *specPtr; int needFlags, hateFlags; needFlags = flags & ~(BLT_CONFIG_USER_BIT - 1); if (Tk_Depth(tkwin) <= 1) { hateFlags = BLT_CONFIG_COLOR_ONLY; } else { hateFlags = BLT_CONFIG_MONO_ONLY; } specPtr = FindConfigSpec(interp, specs, objPtr, needFlags, hateFlags); if (specPtr == NULL) { return TCL_ERROR; } objPtr = FormatConfigValue(interp, tkwin, specPtr, widgRec); Tcl_SetObjResult(interp, objPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * Blt_FreeObjOptions -- * * Free up all resources associated with configuration options. * * Results: * None. * * Side effects: * Any resource in widgRec that is controlled by a configuration * option (e.g. a Tk_3DBorder or XColor) is freed in the appropriate * fashion. * *---------------------------------------------------------------------- */ void Blt_FreeObjOptions(specs, widgRec, display, needFlags) Blt_ConfigSpec *specs; /* Describes legal options. */ char *widgRec; /* Record whose fields contain current * values for options. */ Display *display; /* X display; needed for freeing some * resources. */ int needFlags; /* Used to specify additional flags * that must be present in config specs * for them to be considered. */ { register Blt_ConfigSpec *specPtr; char *ptr; for (specPtr = specs; specPtr->type != BLT_CONFIG_END; specPtr++) { if ((specPtr->specFlags & needFlags) != needFlags) { continue; } ptr = widgRec + specPtr->offset; switch (specPtr->type) { case BLT_CONFIG_STRING: if (*((char **) ptr) != NULL) { Blt_Free(*((char **) ptr)); *((char **) ptr) = NULL; } break; case BLT_CONFIG_COLOR: if (*((XColor **) ptr) != NULL) { Tk_FreeColor(*((XColor **) ptr)); *((XColor **) ptr) = NULL; } break; case BLT_CONFIG_FONT: Tk_FreeFont(*((Tk_Font *) ptr)); *((Tk_Font *) ptr) = NULL; break; case BLT_CONFIG_BITMAP: if (*((Pixmap *) ptr) != None) { Tk_FreeBitmap(display, *((Pixmap *) ptr)); *((Pixmap *) ptr) = None; } break; case BLT_CONFIG_BORDER: if (*((Tk_3DBorder *) ptr) != NULL) { Tk_Free3DBorder(*((Tk_3DBorder *) ptr)); *((Tk_3DBorder *) ptr) = NULL; } break; case BLT_CONFIG_CURSOR: case BLT_CONFIG_ACTIVE_CURSOR: if (*((Tk_Cursor *) ptr) != None) { Tk_FreeCursor(display, *((Tk_Cursor *) ptr)); *((Tk_Cursor *) ptr) = None; } break; case BLT_CONFIG_LISTOBJ: Tcl_DecrRefCount(*(Tcl_Obj **)ptr); break; case BLT_CONFIG_LIST: { char **argv; argv = *(char ***)ptr; if (argv != NULL) { Blt_Free(argv); *(char ***)ptr = NULL; } } break; case BLT_CONFIG_TILE: if ((Blt_Tile)ptr != NULL) { Blt_FreeTile((Blt_Tile)ptr); *(Blt_Tile *)ptr = NULL; } break; case BLT_CONFIG_CUSTOM: if ((*(char **)ptr != NULL) && (specPtr->customPtr->freeProc != NULL)) { (*specPtr->customPtr->freeProc)(specPtr->customPtr->clientData, display, widgRec, specPtr->offset); *(char **)ptr = NULL; } break; } } } /* *---------------------------------------------------------------------- * * Blt_ObjConfigModified -- * * Given the configuration specifications and one or more option * patterns (terminated by a NULL), indicate if any of the matching * configuration options has been reset. * * Results: * Returns 1 if one of the options has changed, 0 otherwise. * *---------------------------------------------------------------------- */ int Blt_ObjConfigModified TCL_VARARGS_DEF(Blt_ConfigSpec *, arg1) { va_list argList; Blt_ConfigSpec *specs; register Blt_ConfigSpec *specPtr; register char *option; specs = TCL_VARARGS_START(Blt_ConfigSpec *, arg1, argList); while ((option = va_arg(argList, char *)) != NULL) { for (specPtr = specs; specPtr->type != BLT_CONFIG_END; specPtr++) { if ((Tcl_StringMatch(specPtr->switchName, option)) && (specPtr->specFlags & BLT_CONFIG_OPTION_SPECIFIED)) { va_end(argList); return 1; } } } va_end(argList); return 0; } /* *---------------------------------------------------------------------- * * Blt_ConfigureComponentFromObj -- * * Configures a component of a widget. This is useful for * widgets that have multiple components which aren't uniquely * identified by a Tk_Window. It allows us, for example, set * resources for axes of the graph widget. The graph really has * only one window, but its convenient to specify components in a * hierarchy of options. * * *graph.x.logScale yes * *graph.Axis.logScale yes * *graph.temperature.scaleSymbols yes * *graph.Element.scaleSymbols yes * * This is really a hack to work around the limitations of the Tk * resource database. It creates a temporary window, needed to * call Tk_ConfigureWidget, using the name of the component. * * Results: * A standard Tcl result. * * Side Effects: * A temporary window is created merely to pass to Tk_ConfigureWidget. * *---------------------------------------------------------------------- */ int Blt_ConfigureComponentFromObj(interp, parent, name, className, specsPtr, objc, objv, widgRec, flags) Tcl_Interp *interp; Tk_Window parent; /* Window to associate with component */ char *name; /* Name of component */ char *className; Blt_ConfigSpec *specsPtr; int objc; Tcl_Obj *CONST *objv; char *widgRec; int flags; { Tk_Window tkwin; int result; char *tmpName; int isTemporary = FALSE; tmpName = Blt_Strdup(name); /* Window name can't start with an upper case letter */ tmpName[0] = tolower(name[0]); /* * Create component if a child window by the component's name * doesn't already exist. */ tkwin = Blt_FindChild(parent, tmpName); if (tkwin == NULL) { tkwin = Tk_CreateWindow(interp, parent, tmpName, (char *)NULL); isTemporary = TRUE; } if (tkwin == NULL) { Tcl_AppendResult(interp, "can't find window in \"", Tk_PathName(parent), "\"", (char *)NULL); return TCL_ERROR; } assert(Tk_Depth(tkwin) == Tk_Depth(parent)); Blt_Free(tmpName); Tk_SetClass(tkwin, className); result = Blt_ConfigureWidgetFromObj(interp, tkwin, specsPtr, objc, objv, widgRec, flags); if (isTemporary) { Tk_DestroyWindow(tkwin); } return result; } /* *-------------------------------------------------------------- * * Blt_ObjIsOption -- * * Indicates whether objPtr is a valid configuration option * such as -background. * * Results: * Returns 1 is a matching option is found and 0 otherwise. * *-------------------------------------------------------------- */ int Blt_ObjIsOption(specs, objPtr, flags) Blt_ConfigSpec *specs; /* Describes legal options. */ Tcl_Obj *objPtr; /* Command-line option name. */ int flags; /* Used to specify additional flags * that must be present in config specs * for them to be considered. Also, * may have BLT_CONFIG_ARGV_ONLY set. */ { register Blt_ConfigSpec *specPtr; int needFlags; /* Specs must contain this set of flags * or else they are not considered. */ needFlags = flags & ~(BLT_CONFIG_USER_BIT - 1); specPtr = FindConfigSpec((Tcl_Interp *)NULL, specs, objPtr, needFlags, 0); return (specPtr != NULL); } #endif /* TK_VERSION_NUMBER >= 8.1.0 */ blt-2.4z.orig/src/bltObjConfig.h0100644000175000017500000002241107542177233015260 0ustar dokodoko/* * bltObjConfig.h -- * * This file contains the Tcl_Obj based versions of the old * Tk_ConfigureWidget procedures. * * 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. * */ #ifndef BLT_OBJCONFIG_H #define BLT_OBJCONFIG_H /* * This is a Tcl_Obj based replacement for the widget configuration * functions in Tk. * * What not use the new Tk_Option interface? * * There were design changes in the new Tk_Option interface that * make it unwieldy. * * o You have to dynamically allocate, store, and deallocate * your option table. * o The Tk_FreeConfigOptions routine requires a tkwin argument. * Unfortunately, most widgets save the display pointer and * deference their tkwin when the window is destroyed. * o There's no TK_CONFIG_CUSTOM functionality. This means that * save special options must be saved as strings by * Tk_ConfigureWidget and processed later, thus losing the * benefits of Tcl_Objs. It also make error handling * problematic, since you don't pick up certain errors like * * .widget configure -myoption bad -myoption good * * You will never see the first "bad" value. * o Especially compared to the former Tk_ConfigureWidget calls, * the new interface is overly complex. If there was a big * performance win, it might be worth the effort. But let's * face it, this biggest wins are in processing custom options * values with thousands of elements. Most common resources * (font, color, etc) have string tokens anyways. * * On the other hand, the replacement functions in this file fell * into place quite easily both from the aspect of API writer and * user. The biggest benefit is that you don't need to change lots * of working code just to get the benefits of Tcl_Objs. * */ #define SIDE_LEFT (0) #define SIDE_TOP (1) #define SIDE_RIGHT (2) #define SIDE_BOTTOM (3) #define SIDE_HORIZONTAL(s) (!((s) & 0x1)) #define SIDE_VERTICAL(s) ((s) & 0x1) #ifndef Blt_Offset #ifdef offsetof #define Blt_Offset(type, field) ((int) offsetof(type, field)) #else #define Blt_Offset(type, field) ((int) ((char *) &((type *) 0)->field)) #endif #endif /* Blt_Offset */ typedef int (Blt_OptionParseProc) _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr, char *widgRec, int offset)); typedef Tcl_Obj *(Blt_OptionPrintProc) _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *widgRec, int offset)); typedef void (Blt_OptionFreeProc) _ANSI_ARGS_((ClientData clientData, Display *display, char *widgRec, int offset)); typedef struct Blt_CustomOption { Blt_OptionParseProc *parseProc; /* Procedure to call to parse an * option and store it in converted * form. */ Blt_OptionPrintProc *printProc; /* Procedure to return a printable * string describing an existing * option. */ Blt_OptionFreeProc *freeProc; /* Procedure to free the value. */ ClientData clientData; /* Arbitrary one-word value used by * option parser: passed to * parseProc and printProc. */ } Blt_CustomOption; /* * Structure used to specify information for Tk_ConfigureWidget. Each * structure gives complete information for one option, including * how the option is specified on the command line, where it appears * in the option database, etc. */ typedef struct { int type; /* Type of option, such as BLT_CONFIG_COLOR; * see definitions below. Last option in * table must have type BLT_CONFIG_END. */ char *switchName; /* Switch used to specify option in argv. * NULL means this spec is part of a group. */ Tk_Uid dbName; /* Name for option in option database. */ Tk_Uid dbClass; /* Class for option in database. */ Tk_Uid defValue; /* Default value for option if not * specified in command line or database. */ int offset; /* Where in widget record to store value; * use Tk_Offset macro to generate values * for this. */ int specFlags; /* Any combination of the values defined * below; other bits are used internally * by tkConfig.c. */ Blt_CustomOption *customPtr; /* If type is BLT_CONFIG_CUSTOM then this is * a pointer to info about how to parse and * print the option. Otherwise it is * irrelevant. */ } Blt_ConfigSpec; /* * Type values for Blt_ConfigSpec structures. See the user * documentation for details. */ typedef enum { BLT_CONFIG_ACTIVE_CURSOR, BLT_CONFIG_ANCHOR, BLT_CONFIG_BITMAP, BLT_CONFIG_BOOLEAN, BLT_CONFIG_BORDER, BLT_CONFIG_CAP_STYLE, BLT_CONFIG_COLOR, BLT_CONFIG_CURSOR, BLT_CONFIG_CUSTOM, BLT_CONFIG_DOUBLE, BLT_CONFIG_FONT, BLT_CONFIG_INT, BLT_CONFIG_JOIN_STYLE, BLT_CONFIG_JUSTIFY, BLT_CONFIG_MM, BLT_CONFIG_PIXELS, BLT_CONFIG_RELIEF, BLT_CONFIG_STRING, BLT_CONFIG_SYNONYM, BLT_CONFIG_UID, BLT_CONFIG_WINDOW, BLT_CONFIG_BITFLAG, BLT_CONFIG_DASHES, BLT_CONFIG_DISTANCE, /* */ BLT_CONFIG_FILL, BLT_CONFIG_FLOAT, BLT_CONFIG_LIST, BLT_CONFIG_LISTOBJ, BLT_CONFIG_PAD, BLT_CONFIG_POS_DISTANCE, /* */ BLT_CONFIG_SHADOW, /* */ BLT_CONFIG_SIDE, BLT_CONFIG_STATE, BLT_CONFIG_TILE, BLT_CONFIG_END } Blt_ConfigTypes; /* * Possible values for flags argument to Tk_ConfigureWidget: */ #define BLT_CONFIG_OBJV_ONLY 1 #define BLT_CONFIG_OBJS 0x80 /* * Possible flag values for Blt_ConfigSpec structures. Any bits at * or above BLT_CONFIG_USER_BIT may be used by clients for selecting * certain entries. Before changing any values here, coordinate with * tkOldConfig.c (internal-use-only flags are defined there). */ #define BLT_CONFIG_NULL_OK 1 #define BLT_CONFIG_COLOR_ONLY 2 #define BLT_CONFIG_MONO_ONLY 4 #define BLT_CONFIG_DONT_SET_DEFAULT 8 #define BLT_CONFIG_OPTION_SPECIFIED 0x10 #define BLT_CONFIG_USER_BIT 0x100 /* * Values for "flags" field of Blt_ConfigSpec structures. Be sure * to coordinate these values with those defined in tk.h * (BLT_CONFIG_COLOR_ONLY, etc.). There must not be overlap! * * INIT - Non-zero means (char *) things have been * converted to Tk_Uid's. */ #define INIT 0x20 EXTERN int Blt_ConfigureInfoFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, Blt_ConfigSpec *specs, char *widgRec, Tcl_Obj *objPtr, int flags)); EXTERN int Blt_ConfigureValueFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, Blt_ConfigSpec *specs, char * widgRec, Tcl_Obj *objPtr, int flags)); EXTERN int Blt_ConfigureWidgetFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, Blt_ConfigSpec *specs, int objc, Tcl_Obj *CONST *objv, char *widgRec, int flags)); EXTERN int Blt_ConfigureComponentFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, char *name, char *className, Blt_ConfigSpec *specs, int objc, Tcl_Obj *CONST *objv, char *widgRec, int flags)); EXTERN int Blt_ObjConfigModified _ANSI_ARGS_(TCL_VARARGS(Blt_ConfigSpec *, specs)); EXTERN void Blt_FreeObjOptions _ANSI_ARGS_((Blt_ConfigSpec *specs, char *widgRec, Display *display, int needFlags)); EXTERN int Blt_ObjIsOption _ANSI_ARGS_((Blt_ConfigSpec *specs, Tcl_Obj *objPtr, int flags)); EXTERN int Blt_GetPositionFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, int *indexPtr)); EXTERN int Blt_GetPixelsFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr, int flags, int *valuePtr)); EXTERN int Blt_GetPadFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr, Blt_Pad *padPtr)); EXTERN int Blt_GetShadowFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr, Shadow *shadowPtr)); EXTERN int Blt_GetStateFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, int *statePtr)); EXTERN int Blt_GetFillFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, int *fillPtr)); EXTERN int Blt_GetDashesFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, Blt_Dashes *dashesPtr)); #if ((TK_VERSION_NUMBER >= _VERSION(8,0,0)) && \ (TK_VERSION_NUMBER < _VERSION(8,1,0))) EXTERN int Tk_GetAnchorFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, Tk_Anchor *anchorPtr)); EXTERN int Tk_GetJustifyFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, Tk_Justify *justifyPtr)); EXTERN int Tk_GetReliefFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, int *reliefPtr)); EXTERN int Tk_GetMMFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr, double *doublePtr)); EXTERN int Tk_GetPixelsFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr, int *intPtr)); EXTERN Tk_3DBorder Tk_Alloc3DBorderFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr)); EXTERN Pixmap Tk_AllocBitmapFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr)); EXTERN Tk_Font Tk_AllocFontFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr)); EXTERN Tk_Cursor Tk_AllocCursorFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr)); EXTERN XColor *Tk_AllocColorFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr)); #endif /* 8.0 */ #endif /* BLT_OBJCONFIG_H */ blt-2.4z.orig/src/bltParse.c0100644000175000017500000004276207513466370014501 0ustar dokodoko/* * tclParse.c -- * * Contains a collection of procedures that are used to parse Tcl * commands or parts of commands (like quoted strings or nested * sub-commands). * * 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. * * Copyright (c) 1987-1993 The Regents of the University of California. * Copyright (c) 19941998 Sun Microsystems, Inc. * */ #include #if (TCL_VERSION_NUMBER >= _VERSION(8,1,0)) #include "bltInterp.h" /* * 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 UCHAR(c) ((unsigned char) (c)) #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)]) /* *-------------------------------------------------------------- * * Blt_ParseNestedCmd -- * * This procedure parses a nested Tcl command between * brackets, returning the result of the command. * * Results: * The return value is a standard Tcl result, which is * TCL_OK unless there was an error while executing the * nested command. If an error occurs then interp->result * contains a standard error message. *TermPtr is filled * in with the address of the character just after the * last one processed; this is usually the character just * after the matching close-bracket, or the null character * at the end of the string if the close-bracket was missing * (a missing close bracket is an error). The result returned * by the command is stored in standard fashion in *parsePtr, * null-terminated, with parsePtr->next pointing to the null * character. * * Side effects: * The storage space at *parsePtr may be expanded. * *-------------------------------------------------------------- */ int Blt_ParseNestedCmd(interp, string, flags, termPtr, parsePtr) Tcl_Interp *interp; /* Interpreter to use for nested command * evaluations and error messages. */ char *string; /* Character just after opening bracket. */ int flags; /* Flags to pass to nested Tcl_Eval. */ char **termPtr; /* Store address of terminating character * here. */ ParseValue *parsePtr; /* Information about where to place * result of command. */ { int result, length, shortfall; Interp *iPtr = (Interp *) interp; iPtr->evalFlags = flags | TCL_BRACKET_TERM; result = Tcl_Eval(interp, string); *termPtr = (string + iPtr->termOffset); if (result != TCL_OK) { /* * The increment below results in slightly cleaner message in * the errorInfo variable (the close-bracket will appear). */ if (**termPtr == ']') { *termPtr += 1; } return result; } (*termPtr) += 1; length = strlen(iPtr->result); shortfall = length + 1 - (parsePtr->end - parsePtr->next); if (shortfall > 0) { (*parsePtr->expandProc) (parsePtr, shortfall); } strcpy(parsePtr->next, iPtr->result); parsePtr->next += length; Tcl_FreeResult(interp); iPtr->result = iPtr->resultSpace; iPtr->resultSpace[0] = '\0'; return TCL_OK; } /* *-------------------------------------------------------------- * * Blt_ParseBraces -- * * This procedure scans the information between matching * curly braces. * * Results: * The return value is a standard Tcl result, which is * TCL_OK unless there was an error while parsing string. * If an error occurs then interp->result contains a * standard error message. *TermPtr is filled * in with the address of the character just after the * last one successfully processed; this is usually the * character just after the matching close-brace. The * information between curly braces is stored in standard * fashion in *parsePtr, null-terminated with parsePtr->next * pointing to the terminating null character. * * Side effects: * The storage space at *parsePtr may be expanded. * *-------------------------------------------------------------- */ int Blt_ParseBraces(interp, string, termPtr, parsePtr) Tcl_Interp *interp; /* Interpreter to use for nested command * evaluations and error messages. */ char *string; /* Character just after opening bracket. */ char **termPtr; /* Store address of terminating character * here. */ ParseValue *parsePtr; /* Information about where to place * result of command. */ { int level; register char *src, *dest, *end; register char c; 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; } /* *-------------------------------------------------------------- * * Blt_ExpandParseValue -- * * This procedure is commonly used as the value of the * expandProc in a ParseValue. It uses malloc to allocate * more space for the result of a parse. * * Results: * The buffer space in *parsePtr is reallocated to something * larger, and if parsePtr->clientData is non-zero the old * buffer is freed. Information is copied from the old * buffer to the new one. * * Side effects: * None. * *-------------------------------------------------------------- */ void Blt_ExpandParseValue(parsePtr, needed) ParseValue *parsePtr; /* Information about buffer that * must be expanded. If the clientData * in the structure is non-zero, it * means that the current buffer is * dynamically allocated. */ int needed; /* Minimum amount of additional space * to allocate. */ { int size; char *buffer; /* * Either double the size of the buffer or add enough new space * to meet the demand, whichever produces a larger new buffer. */ size = (parsePtr->end - parsePtr->buffer) + 1; if (size < needed) { size += needed; } else { size += size; } buffer = Blt_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) { Blt_Free(parsePtr->buffer); } parsePtr->buffer = buffer; parsePtr->end = buffer + size - 1; parsePtr->clientData = (ClientData)1; } /* *-------------------------------------------------------------- * * Blt_ParseQuotes -- * * This procedure parses a double-quoted string such as a * quoted Tcl command argument or a quoted value in a Tcl * expression. This procedure is also used to parse array * element names within parentheses, or anything else that * needs all the substitutions that happen in quotes. * * Results: * The return value is a standard Tcl result, which is * TCL_OK unless there was an error while parsing the * quoted string. If an error occurs then interp->result * contains a standard error message. *TermPtr is filled * in with the address of the character just after the * last one successfully processed; this is usually the * character just after the matching close-quote. The * fully-substituted contents of the quotes are stored in * standard fashion in *parsePtr, null-terminated with * parsePtr->next pointing to the terminating null character. * * Side effects: * The buffer space in parsePtr may be enlarged by calling its * expandProc. * *-------------------------------------------------------------- */ int Blt_ParseQuotes(interp, string, termChar, flags, termPtr, parsePtr) Tcl_Interp *interp; /* Interpreter to use for nested command * evaluations and error messages. */ char *string; /* Character just after opening double- * quote. */ int termChar; /* Character that terminates "quoted" string * (usually double-quote, but sometimes * right-paren or something else). */ int flags; /* Flags to pass to nested Tcl_Eval calls. */ char **termPtr; /* Store address of terminating character * here. */ ParseValue *parsePtr; /* Information about where to place * fully-substituted result of parse. */ { register char *src, *dest, c; 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 = Blt_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') { char buf[30]; Tcl_ResetResult(interp); sprintf(buf, "missing %c", termChar); Tcl_SetResult(interp, buf, TCL_VOLATILE); *termPtr = string - 1; return TCL_ERROR; } else { goto copy; } } } #endif /* TCL_VERSION_NUMBER >= _VERSION(8,1,0) */ blt-2.4z.orig/src/bltPool.c0100644000175000017500000003460207423400503014314 0ustar dokodoko/* * bltPool.c -- * * Copyright 2001 Silicon Metrics, 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. * * Silicon Metrics 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. */ #include "bltInt.h" #include "bltPool.h" /* * Blt_Pool -- * * Implements a pool memory allocator. * * + It's faster allocating memory since malloc/free are called * only a fraction of the normal times. Fixed size items can * be reused without deallocating/reallocating memory. * + You don't have the extra 8-16 byte overhead per malloc. * - Memory is freed only when the entire pool is destroyed. * - Memory is allocated in chunks. More memory is allocated * than used. * 0 Depending upon allocation/deallocation patterns, locality * may be improved or degraded. * * The pool is a chain of malloc'ed blocks. * * +---------+ +---------+ +---------+ * NULL<-| nextPtr |<-| nextPtr |<-| nextPtr |<- headPtr * |---------| |---------| |---------| * | chunk1 | | chunk2 | | chunk3 | * +---------+ | | | | * +---------+ | | * | | * | | * +---------+ * * Each chunk contains an integral number of fixed size items. * The number of items doubles until a maximum size is reached * (each subsequent new chunk will be the maximum). Chunks * are allocated only when needed (no more space is available * in the last chunk). * * The chain of blocks is only freed when the entire pool is * destroyed. * * A freelist of unused items also maintained. Each freed item * is prepended to a free list. Before allocating new chunks * the freelist is examined to see if an unused items exist. * * chunk1 chunk2 chunk3 * +---------+ +---------+ +---------+ * NULL<-| unused | | | | | * +----^----+ +---------+ +---------+ * | unused |<-| unused |<-| unused | * +---------+ +---------+ +----^----+ * | | | | | unused | * +---------+ | | +----^----+ * | | | | | * +---------+ +----|----+ * | usused |<- freePtr * +---------+ */ #define POOL_MAX_CHUNK_SIZE ((1<<16) - sizeof(Blt_PoolChain)) #ifndef ALIGN #define ALIGN(a) \ (((size_t)a + (sizeof(void *) - 1)) & (~(sizeof(void *) - 1))) #endif /* ALIGN */ static Blt_PoolAllocProc VariablePoolAllocItem; static Blt_PoolFreeProc VariablePoolFreeItem; static Blt_PoolAllocProc FixedPoolAllocItem; static Blt_PoolFreeProc FixedPoolFreeItem; static Blt_PoolAllocProc StringPoolAllocItem; static Blt_PoolFreeProc StringPoolFreeItem; /* *---------------------------------------------------------------------- * * VariablePoolAllocItem -- * * Returns a new item. First check if there is any more space * left in the current chunk. If there isn't then next check * the free list for unused items. Finally allocate a new * chunk and return its first item. * * Results: * Returns a new (possible reused) item. * * Side Effects: * A new memory chunk may be allocated. * *---------------------------------------------------------------------- */ static void * VariablePoolAllocItem(poolPtr, size) struct Blt_PoolStruct *poolPtr; size_t size; /* Number of bytes to allocate. */ { Blt_PoolChain *chainPtr; void *memPtr; size = ALIGN(size); if (size >= POOL_MAX_CHUNK_SIZE) { /* * Handle oversized requests by allocating a chunk to hold the * single item and immediately placing it into the in-use list. */ chainPtr = Blt_Malloc(sizeof(Blt_PoolChain) + size); if (poolPtr->headPtr == NULL) { poolPtr->headPtr = chainPtr; } else { chainPtr->nextPtr = poolPtr->headPtr->nextPtr; poolPtr->headPtr->nextPtr = chainPtr; } memPtr = (void *)chainPtr; } else { if (poolPtr->bytesLeft >= size) { poolPtr->bytesLeft -= size; memPtr = (char *)(poolPtr->headPtr + 1) + poolPtr->bytesLeft; } else { poolPtr->waste += poolPtr->bytesLeft; /* Create a new block of items and prepend it to the in-use list */ poolPtr->bytesLeft = POOL_MAX_CHUNK_SIZE; /* Allocate the requested chunk size, plus the header */ chainPtr = Blt_Malloc(sizeof(Blt_PoolChain) + poolPtr->bytesLeft); chainPtr->nextPtr = poolPtr->headPtr; poolPtr->headPtr = chainPtr; /* Peel off a new item. */ poolPtr->bytesLeft -= size; memPtr = (char *)(chainPtr + 1) + poolPtr->bytesLeft; } } return memPtr; } /* *---------------------------------------------------------------------- * * VariablePoolFreeItem -- * * Placeholder for freeProc routine. The pool memory is * not reclaimed or freed until the entire pool is released. * * Results: * None. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static void VariablePoolFreeItem(poolPtr, item) struct Blt_PoolStruct *poolPtr; void *item; { /* Does nothing */ } /* *---------------------------------------------------------------------- * * StringPoolAllocItem -- * * Returns a new item. First check if there is any more space * left in the current chunk. If there isn't then next check * the free list for unused items. Finally allocate a new * chunk and return its first item. * * Results: * Returns a new (possible reused) item. * * Side Effects: * A new memory chunk may be allocated. * *---------------------------------------------------------------------- */ static void * StringPoolAllocItem(poolPtr, size) struct Blt_PoolStruct *poolPtr; size_t size; /* Number of bytes to allocate. */ { Blt_PoolChain *chainPtr; void *memPtr; if (size >= POOL_MAX_CHUNK_SIZE) { /* * Handle oversized requests by allocating a chunk to hold the * single item and immediately placing it into the in-use list. */ chainPtr = Blt_Malloc(sizeof(Blt_PoolChain) + size); if (poolPtr->headPtr == NULL) { poolPtr->headPtr = chainPtr; } else { chainPtr->nextPtr = poolPtr->headPtr->nextPtr; poolPtr->headPtr->nextPtr = chainPtr; } memPtr = (void *)chainPtr; } else { if (poolPtr->bytesLeft >= size) { poolPtr->bytesLeft -= size; memPtr = (char *)(poolPtr->headPtr + 1) + poolPtr->bytesLeft; } else { poolPtr->waste += poolPtr->bytesLeft; /* Create a new block of items and prepend it to the * in-use list */ poolPtr->bytesLeft = POOL_MAX_CHUNK_SIZE; /* Allocate the requested chunk size, plus the header */ chainPtr = Blt_Malloc(sizeof(Blt_PoolChain) + poolPtr->bytesLeft); chainPtr->nextPtr = poolPtr->headPtr; poolPtr->headPtr = chainPtr; /* Peel off a new item. */ poolPtr->bytesLeft -= size; memPtr = (char *)(chainPtr + 1) + poolPtr->bytesLeft; } } return memPtr; } /* *---------------------------------------------------------------------- * * StringPoolFreeItem -- * * Placeholder for freeProc routine. String pool memory is * not reclaimed or freed until the entire pool is released. * * Results: * None. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static void StringPoolFreeItem(poolPtr, item) struct Blt_PoolStruct *poolPtr; void *item; { /* Does nothing */ } /* * The fixed size pool is a chain of malloc'ed blocks. * * +---------+ +---------+ +---------+ * NULL<-| nextPtr |<-| nextPtr |<-| nextPtr |<- headPtr * |---------| |---------| |---------| * | chunk1 | | chunk2 | | chunk3 | * +---------+ | | | | * +---------+ | | * | | * | | * +---------+ * * Each chunk contains an integral number of fixed size items. * The number of items doubles until a maximum size is reached * (each subsequent new chunk will be the maximum). Chunks * are allocated only when needed (no more space is available * in the last chunk). * * The chain of blocks is only freed when the entire pool is * destroyed. * * A freelist of unused items also maintained. Each freed item * is prepended to a free list. Before allocating new chunks * the freelist is examined to see if an unused items exist. * * chunk1 chunk2 chunk3 * +---------+ +---------+ +---------+ * NULL<-| unused | | | | | * +----^----+ +---------+ +---------+ * | unused |<-| unused |<-| unused | * +---------+ +---------+ +----^----+ * | | | | | unused | * +---------+ | | +----^----+ * | | | | | * +---------+ +----|----+ * | usused |<- freePtr * +---------+ */ /* *---------------------------------------------------------------------- * * FixedPoolFreeItem -- * * Returns a new item. First check if there is any more space * left in the current chunk. If there isn't then next check * the free list for unused items. Finally allocate a new * chunk and return its first item. * * Results: * Returns a new (possible reused) item. * * Side Effects: * A new memory chunk may be allocated. * *---------------------------------------------------------------------- */ static void * FixedPoolAllocItem(poolPtr, size) struct Blt_PoolStruct *poolPtr; size_t size; { Blt_PoolChain *chainPtr; void *newPtr; size = ALIGN(size); if (poolPtr->itemSize == 0) { poolPtr->itemSize = size; } assert(size == poolPtr->itemSize); if (poolPtr->bytesLeft > 0) { poolPtr->bytesLeft -= poolPtr->itemSize; newPtr = (char *)(poolPtr->headPtr + 1) + poolPtr->bytesLeft; } else if (poolPtr->freePtr != NULL) { /* Reuse from the free list. */ /* Reuse items on the free list */ chainPtr = poolPtr->freePtr; poolPtr->freePtr = chainPtr->nextPtr; newPtr = (void *)chainPtr; } else { /* Allocate another block. */ /* Create a new block of items and prepend it to the in-use list */ poolPtr->bytesLeft = poolPtr->itemSize * (1 << poolPtr->poolSize); if (poolPtr->bytesLeft < POOL_MAX_CHUNK_SIZE) { poolPtr->poolSize++; /* Keep doubling the size of the new * chunk up to a maximum size. */ } /* Allocate the requested chunk size, plus the header */ chainPtr = Blt_Malloc(sizeof(Blt_PoolChain) + poolPtr->bytesLeft); chainPtr->nextPtr = poolPtr->headPtr; poolPtr->headPtr = chainPtr; /* Peel off a new item. */ poolPtr->bytesLeft -= poolPtr->itemSize; newPtr = (char *)(poolPtr->headPtr + 1) + poolPtr->bytesLeft; } return newPtr; } /* *---------------------------------------------------------------------- * * FixedPoolFreeItem -- * * Frees an item. The actual memory is not freed. The item * instead is prepended to a freelist where it may be reclaimed * and used again. * * Results: * None. * * Side Effects: * Item is placed on the pool's free list. * *---------------------------------------------------------------------- */ static void FixedPoolFreeItem(poolPtr, item) struct Blt_PoolStruct *poolPtr; void *item; { Blt_PoolChain *chainPtr = (Blt_PoolChain *)item; /* Prepend the newly deallocated item to the free list. */ chainPtr->nextPtr = poolPtr->freePtr; poolPtr->freePtr = chainPtr; } /* *---------------------------------------------------------------------- * * Blt_PoolCreate -- * * Creates a new memory pool for fixed-size/variable-size/string * items. * * Results: * Returns a pointer to the newly allocated pool. * *---------------------------------------------------------------------- */ Blt_Pool Blt_PoolCreate(type) int type; { struct Blt_PoolStruct *poolPtr; poolPtr = Blt_Malloc(sizeof(struct Blt_PoolStruct)); switch (type) { case BLT_VARIABLE_SIZE_ITEMS: poolPtr->allocProc = VariablePoolAllocItem; poolPtr->freeProc = VariablePoolFreeItem; break; case BLT_FIXED_SIZE_ITEMS: poolPtr->allocProc = FixedPoolAllocItem; poolPtr->freeProc = FixedPoolFreeItem; break; case BLT_STRING_ITEMS: poolPtr->allocProc = StringPoolAllocItem; poolPtr->freeProc = StringPoolFreeItem; break; } poolPtr->headPtr = poolPtr->freePtr = NULL; poolPtr->waste = poolPtr->bytesLeft = 0; poolPtr->poolSize = poolPtr->itemSize = 0; return poolPtr; } /* *---------------------------------------------------------------------- * * Blt_PoolDestroy -- * * Destroys the given memory pool. The chain of allocated blocks * are freed. The is the only time that memory is actually freed. * * Results: * None. * * Side Effects: * All memory used by the pool is freed. * *---------------------------------------------------------------------- */ void Blt_PoolDestroy(poolPtr) struct Blt_PoolStruct *poolPtr; { register Blt_PoolChain *chainPtr, *nextPtr; for (chainPtr = poolPtr->headPtr; chainPtr != NULL; chainPtr = nextPtr) { nextPtr = chainPtr->nextPtr; Blt_Free(chainPtr); } Blt_Free(poolPtr); } blt-2.4z.orig/src/bltPool.h0100644000175000017500000000224007414137335014324 0ustar dokodoko#ifndef BLT_POOL_H #define BLT_POOL_H typedef struct Blt_PoolChainStruct { struct Blt_PoolChainStruct *nextPtr; } Blt_PoolChain; #define BLT_STRING_ITEMS 0 #define BLT_FIXED_SIZE_ITEMS 1 #define BLT_VARIABLE_SIZE_ITEMS 2 typedef struct Blt_PoolStruct *Blt_Pool; typedef void *(Blt_PoolAllocProc) _ANSI_ARGS_((Blt_Pool pool, size_t size)); typedef void (Blt_PoolFreeProc) _ANSI_ARGS_((Blt_Pool pool, void *item)); struct Blt_PoolStruct { Blt_PoolChain *headPtr; /* Chain of malloc'ed chunks. */ Blt_PoolChain *freePtr; /* List of deleted items. This is only used * for fixed size items. */ size_t poolSize; /* Log2 of # of items in the current block. */ size_t itemSize; /* Size of an item. */ size_t bytesLeft; /* # of bytes left in the current chunk. */ size_t waste; Blt_PoolAllocProc *allocProc; Blt_PoolFreeProc *freeProc; }; EXTERN Blt_Pool Blt_PoolCreate _ANSI_ARGS_((int type)); EXTERN void Blt_PoolDestroy _ANSI_ARGS_((Blt_Pool pool)); #define Blt_PoolAllocItem(poolPtr, n) (*((poolPtr)->allocProc))(poolPtr, n) #define Blt_PoolFreeItem(poolPtr, item) (*((poolPtr)->freeProc))(poolPtr, item) #endif /* BLT_POOL_H */ blt-2.4z.orig/src/bltPs.c0100644000175000017500000012244507542177233014005 0ustar dokodoko /* * bltPs.c -- * * This module implements general PostScript conversion routines. * * Copyright 1991-1998 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. */ #include "bltInt.h" #include "bltPs.h" #include #include #if defined(__STDC__) #include #else #include #endif #define PS_MAXPATH 1500 /* Maximum number of components in a PostScript * (level 1) path. */ PsToken Blt_GetPsToken(interp, tkwin) Tcl_Interp *interp; Tk_Window tkwin; { struct PsTokenStruct *tokenPtr; tokenPtr = Blt_Malloc(sizeof(struct PsTokenStruct)); assert(tokenPtr); tokenPtr->fontVarName = tokenPtr->colorVarName = NULL; tokenPtr->interp = interp; tokenPtr->tkwin = tkwin; tokenPtr->colorMode = PS_MODE_COLOR; Tcl_DStringInit(&(tokenPtr->dString)); return tokenPtr; } void Blt_ReleasePsToken(tokenPtr) struct PsTokenStruct *tokenPtr; { Tcl_DStringFree(&(tokenPtr->dString)); Blt_Free(tokenPtr); } char * Blt_PostScriptFromToken(tokenPtr) struct PsTokenStruct *tokenPtr; { return Tcl_DStringValue(&(tokenPtr->dString)); } char * Blt_ScratchBufferFromToken(tokenPtr) struct PsTokenStruct *tokenPtr; { return tokenPtr->scratchArr; } void Blt_AppendToPostScript TCL_VARARGS_DEF(PsToken, arg1) { va_list argList; struct PsTokenStruct *tokenPtr; char *string; tokenPtr = TCL_VARARGS_START(struct PsTokenStruct, arg1, argList); for (;;) { string = va_arg(argList, char *); if (string == NULL) { break; } Tcl_DStringAppend(&(tokenPtr->dString), string, -1); } } void Blt_FormatToPostScript TCL_VARARGS_DEF(PsToken, arg1) { va_list argList; struct PsTokenStruct *tokenPtr; char *fmt; tokenPtr = TCL_VARARGS_START(struct PsTokenStruct, arg1, argList); fmt = va_arg(argList, char *); vsprintf(tokenPtr->scratchArr, fmt, argList); va_end(argList); Tcl_DStringAppend(&(tokenPtr->dString), tokenPtr->scratchArr, -1); } int Blt_FileToPostScript(tokenPtr, fileName) struct PsTokenStruct *tokenPtr; char *fileName; { Tcl_Channel channel; Tcl_DString dString; Tcl_Interp *interp; char *buf; char *libDir; int nBytes; interp = tokenPtr->interp; buf = tokenPtr->scratchArr; /* * Read in a standard prolog file from file and append it to the * PostScript output stored in the Tcl_DString in tokenPtr. */ libDir = (char *)Tcl_GetVar(interp, "blt_library", TCL_GLOBAL_ONLY); if (libDir == NULL) { Tcl_AppendResult(interp, "couldn't find BLT script library:", "global variable \"blt_library\" doesn't exist", (char *)NULL); return TCL_ERROR; } Tcl_DStringInit(&dString); Tcl_DStringAppend(&dString, libDir, -1); Tcl_DStringAppend(&dString, "/", -1); Tcl_DStringAppend(&dString, fileName, -1); fileName = Tcl_DStringValue(&dString); Blt_AppendToPostScript(tokenPtr, "\n% including file \"", fileName, "\"\n\n", (char *)NULL); channel = Tcl_OpenFileChannel(interp, fileName, "r", 0); if (channel == NULL) { Tcl_AppendResult(interp, "couldn't open prologue file \"", fileName, "\": ", Tcl_PosixError(interp), (char *)NULL); return TCL_ERROR; } for(;;) { nBytes = Tcl_Read(channel, buf, PSTOKEN_BUFSIZ); if (nBytes < 0) { Tcl_AppendResult(interp, "error reading prologue file \"", fileName, "\": ", Tcl_PosixError(interp), (char *)NULL); Tcl_Close(interp, channel); Tcl_DStringFree(&dString); return TCL_ERROR; } if (nBytes == 0) { break; } buf[nBytes] = '\0'; Blt_AppendToPostScript(tokenPtr, buf, (char *)NULL); } Tcl_DStringFree(&dString); Tcl_Close(interp, channel); return TCL_OK; } /* *---------------------------------------------------------------------- * * XColorToPostScript -- * * Convert the a XColor (from its RGB values) to a PostScript * command. If a Tk color map variable exists, it will be * consulted for a PostScript translation based upon the color * name. * * Maps an X color intensity (0 to 2^16-1) to a floating point * value [0..1]. Many versions of Tk don't properly handle the * the lower 8 bits of the color intensity, so we can only * consider the upper 8 bits. * * Results: * The string representing the color mode is returned. * *---------------------------------------------------------------------- */ static void XColorToPostScript(tokenPtr, colorPtr) struct PsTokenStruct *tokenPtr; XColor *colorPtr; /* Color value to be converted */ { /* * Shift off the lower byte before dividing because some versions * of Tk don't fill the lower byte correctly. */ Blt_FormatToPostScript(tokenPtr, "%g %g %g", ((double)(colorPtr->red >> 8) / 255.0), ((double)(colorPtr->green >> 8) / 255.0), ((double)(colorPtr->blue >> 8) / 255.0)); } void Blt_BackgroundToPostScript(tokenPtr, colorPtr) struct PsTokenStruct *tokenPtr; XColor *colorPtr; { /* If the color name exists in Tcl array variable, use that translation */ if (tokenPtr->colorVarName != NULL) { CONST char *psColor; psColor = Tcl_GetVar2(tokenPtr->interp, tokenPtr->colorVarName, Tk_NameOfColor(colorPtr), 0); if (psColor != NULL) { Blt_AppendToPostScript(tokenPtr, " ", psColor, "\n", (char *)NULL); return; } } XColorToPostScript(tokenPtr, colorPtr); Blt_AppendToPostScript(tokenPtr, " SetBgColor\n", (char *)NULL); } void Blt_ForegroundToPostScript(tokenPtr, colorPtr) struct PsTokenStruct *tokenPtr; XColor *colorPtr; { /* If the color name exists in Tcl array variable, use that translation */ if (tokenPtr->colorVarName != NULL) { CONST char *psColor; psColor = Tcl_GetVar2(tokenPtr->interp, tokenPtr->colorVarName, Tk_NameOfColor(colorPtr), 0); if (psColor != NULL) { Blt_AppendToPostScript(tokenPtr, " ", psColor, "\n", (char *)NULL); return; } } XColorToPostScript(tokenPtr, colorPtr); Blt_AppendToPostScript(tokenPtr, " SetFgColor\n", (char *)NULL); } /* *---------------------------------------------------------------------- * * ReverseBits -- * * Convert a byte from a X image into PostScript image order. * This requires not only the nybbles to be reversed but also * their bit values. * * Results: * The converted byte is returned. * *---------------------------------------------------------------------- */ INLINE static unsigned char ReverseBits(byte) register 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; } /* *---------------------------------------------------------------------- * * ByteToHex -- * * Convert a byte to its ASCII hexidecimal equivalent. * * Results: * The converted 2 ASCII character string is returned. * *---------------------------------------------------------------------- */ INLINE static void ByteToHex(byte, string) register unsigned char byte; char *string; { static char hexDigits[] = "0123456789ABCDEF"; string[0] = hexDigits[byte >> 4]; string[1] = hexDigits[byte & 0x0F]; } #ifdef WIN32 /* * ------------------------------------------------------------------------- * * Blt_BitmapDataToPostScript -- * * Output a PostScript image string of the given bitmap image. * It is assumed the image is one bit deep and a zero value * indicates an off-pixel. To convert to PostScript, the bits * need to be reversed from the X11 image order. * * Results: * None. * * Side Effects: * The PostScript image string is appended. * * ------------------------------------------------------------------------- */ void Blt_BitmapDataToPostScript( struct PsTokenStruct *tokenPtr, Display *display, Pixmap bitmap, int width, int height) { register unsigned char byte; register int x, y, bitPos; unsigned long pixel; int byteCount; char string[10]; unsigned char *srcBits, *srcPtr; int bytesPerRow; srcBits = Blt_GetBitmapData(display, bitmap, width, height, &bytesPerRow); if (srcBits == NULL) { OutputDebugString("Can't get bitmap data"); return; } Blt_AppendToPostScript(tokenPtr, "\t<", (char *)NULL); byteCount = bitPos = 0; /* Suppress compiler warning */ for (y = height - 1; y >= 0; y--) { srcPtr = srcBits + (bytesPerRow * y); byte = 0; for (x = 0; x < width; x++) { bitPos = x % 8; pixel = (*srcPtr & (0x80 >> bitPos)); if (pixel) { byte |= (unsigned char)(1 << bitPos); } if (bitPos == 7) { byte = ReverseBits(byte); ByteToHex(byte, string); string[2] = '\0'; byteCount++; srcPtr++; byte = 0; if (byteCount >= 30) { string[2] = '\n'; string[3] = '\t'; string[4] = '\0'; byteCount = 0; } Blt_AppendToPostScript(tokenPtr, string, (char *)NULL); } } /* x */ if (bitPos != 7) { byte = ReverseBits(byte); ByteToHex(byte, string); string[2] = '\0'; Blt_AppendToPostScript(tokenPtr, string, (char *)NULL); byteCount++; } } /* y */ Blt_Free(srcBits); Blt_AppendToPostScript(tokenPtr, ">\n", (char *)NULL); } #else /* * ------------------------------------------------------------------------- * * Blt_BitmapDataToPostScript -- * * Output a PostScript image string of the given bitmap image. * It is assumed the image is one bit deep and a zero value * indicates an off-pixel. To convert to PostScript, the bits * need to be reversed from the X11 image order. * * Results: * None. * * Side Effects: * The PostScript image string is appended to interp->result. * * ------------------------------------------------------------------------- */ void Blt_BitmapDataToPostScript(tokenPtr, display, bitmap, width, height) struct PsTokenStruct *tokenPtr; Display *display; Pixmap bitmap; int width, height; { register unsigned char byte = 0; register int x, y, bitPos; unsigned long pixel; XImage *imagePtr; int byteCount; char string[10]; imagePtr = XGetImage(display, bitmap, 0, 0, width, height, 1, ZPixmap); Blt_AppendToPostScript(tokenPtr, "\t<", (char *)NULL); byteCount = bitPos = 0; /* Suppress compiler warning */ for (y = 0; y < height; y++) { byte = 0; for (x = 0; x < width; x++) { pixel = XGetPixel(imagePtr, x, y); bitPos = x % 8; byte |= (unsigned char)(pixel << bitPos); if (bitPos == 7) { byte = ReverseBits(byte); ByteToHex(byte, string); string[2] = '\0'; byteCount++; byte = 0; if (byteCount >= 30) { string[2] = '\n'; string[3] = '\t'; string[4] = '\0'; byteCount = 0; } Blt_AppendToPostScript(tokenPtr, string, (char *)NULL); } } /* x */ if (bitPos != 7) { byte = ReverseBits(byte); ByteToHex(byte, string); string[2] = '\0'; Blt_AppendToPostScript(tokenPtr, string, (char *)NULL); byteCount++; } } /* y */ Blt_AppendToPostScript(tokenPtr, ">\n", (char *)NULL); XDestroyImage(imagePtr); } #endif /* WIN32 */ /* *---------------------------------------------------------------------- * * Blt_ColorImageToPsData -- * * Converts a color image to PostScript RGB (3 components) * or Greyscale (1 component) output. With 3 components, we * assume the "colorimage" operator is available. * * Note that the image converted from bottom to top, to conform * to the PostScript coordinate system. * * Results: * The PostScript data comprising the color image is written * into the dynamic string. * *---------------------------------------------------------------------- */ int Blt_ColorImageToPsData(image, nComponents, resultPtr, prefix) Blt_ColorImage image; int nComponents; Tcl_DString *resultPtr; char *prefix; { char string[10]; register int count; register int x, y; register Pix32 *pixelPtr; unsigned char byte; int width, height; int offset; int nLines; width = Blt_ColorImageWidth(image); height = Blt_ColorImageHeight(image); nLines = 0; count = 0; offset = (height - 1) * width; if (nComponents == 3) { for (y = (height - 1); y >= 0; y--) { pixelPtr = Blt_ColorImageBits(image) + offset; for (x = 0; x < width; x++, pixelPtr++) { if (count == 0) { Tcl_DStringAppend(resultPtr, prefix, -1); Tcl_DStringAppend(resultPtr, " ", -1); } count += 6; ByteToHex(pixelPtr->Red, string); ByteToHex(pixelPtr->Green, string + 2); ByteToHex(pixelPtr->Blue, string + 4); string[6] = '\0'; if (count >= 60) { string[6] = '\n'; string[7] = '\0'; count = 0; nLines++; } Tcl_DStringAppend(resultPtr, string, -1); } offset -= width; } } else if (nComponents == 1) { for (y = (height - 1); y >= 0; y--) { pixelPtr = Blt_ColorImageBits(image) + offset; for (x = 0; x < width; x++, pixelPtr++) { if (count == 0) { Tcl_DStringAppend(resultPtr, prefix, -1); Tcl_DStringAppend(resultPtr, " ", -1); } count += 2; byte = ~(pixelPtr->Red); ByteToHex(byte, string); string[2] = '\0'; if (count >= 60) { string[2] = '\n'; string[3] = '\0'; count = 0; nLines++; } Tcl_DStringAppend(resultPtr, string, -1); } offset -= width; } } if (count != 0) { Tcl_DStringAppend(resultPtr, "\n", -1); nLines++; } return nLines; } /* *---------------------------------------------------------------------- * * NameOfAtom -- * * Wrapper routine for Tk_GetAtomName. Returns NULL instead of * "?bad atom?" if the atom can't be found. * * Results: * The name of the atom is returned if found. Otherwise NULL. * *---------------------------------------------------------------------- */ static char * NameOfAtom(tkwin, atom) Tk_Window tkwin; Atom atom; { char *result; result = Tk_GetAtomName(tkwin, atom); if ((result[0] == '?') && (strcmp(result, "?bad atom?") == 0)) { return NULL; } return result; } typedef struct { char *alias; char *fontName; } FontMap; static FontMap psFontMap[] = { {"Arial", "Helvetica",}, {"AvantGarde", "AvantGarde",}, {"Courier New", "Courier",}, {"Courier", "Courier",}, {"Geneva", "Helvetica",}, {"Helvetica", "Helvetica",}, {"Monaco", "Courier",}, {"New Century Schoolbook", "NewCenturySchlbk",}, {"New York", "Times",}, {"Palatino", "Palatino",}, {"Symbol", "Symbol",}, {"Times New Roman", "Times",}, {"Times Roman", "Times",}, {"Times", "Times",}, {"Utopia", "Utopia",}, {"ZapfChancery", "ZapfChancery",}, {"ZapfDingbats", "ZapfDingbats",}, }; static int nFontNames = (sizeof(psFontMap) / sizeof(FontMap)); #ifndef WIN32 /* * ----------------------------------------------------------------- * * XFontStructToPostScript -- * * Map X11 font to a PostScript font. Currently, only fonts whose * FOUNDRY property are "Adobe" are converted. Simply gets the * XA_FULL_NAME and XA_FAMILY properties and pieces together a * PostScript fontname. * * Results: * Returns the mapped PostScript font name if one is possible. * Otherwise returns NULL. * * ----------------------------------------------------------------- */ static char * XFontStructToPostScript(tkwin, fontPtr) Tk_Window tkwin; /* Window to query for atoms */ XFontStruct *fontPtr; /* Font structure to map to name */ { Atom atom; char *fullName, *family, *foundry; register char *src, *dest; int familyLen; char *start; static char string[200]; /* What size? */ if (XGetFontProperty(fontPtr, XA_FULL_NAME, &atom) == False) { return NULL; } fullName = NameOfAtom(tkwin, atom); if (fullName == NULL) { return NULL; } family = foundry = NULL; if (XGetFontProperty(fontPtr, Tk_InternAtom(tkwin, "FOUNDRY"), &atom)) { foundry = NameOfAtom(tkwin, atom); } if (XGetFontProperty(fontPtr, XA_FAMILY_NAME, &atom)) { family = NameOfAtom(tkwin, atom); } /* * Try to map the font only if the foundry is Adobe */ if ((foundry == NULL) || (family == NULL)) { return NULL; } src = NULL; familyLen = strlen(family); if (strncasecmp(fullName, family, familyLen) == 0) { src = fullName + familyLen; } if (strcmp(foundry, "Adobe") != 0) { register int i; if (strncasecmp(family, "itc ", 4) == 0) { family += 4; /* Throw out the "itc" prefix */ } for (i = 0; i < nFontNames; i++) { if (strcasecmp(family, psFontMap[i].alias) == 0) { family = psFontMap[i].fontName; } } if (i == nFontNames) { family = "Helvetica"; /* Default to a known font */ } } /* * PostScript font name is in the form - */ sprintf(string, "%s-", family); dest = start = string + strlen(string); /* * Append the type face (part of the full name trailing the family name) * to the the PostScript font name, removing any spaces or dashes * * ex. " Bold Italic" ==> "BoldItalic" */ if (src != NULL) { while (*src != '\0') { if ((*src != ' ') && (*src != '-')) { *dest++ = *src; } src++; } } if (dest == start) { --dest; /* Remove '-' to leave just the family name */ } *dest = '\0'; /* Make a valid string */ return string; } #endif /* !WIN32 */ /* * ------------------------------------------------------------------- * Routines to convert X drawing functions to PostScript commands. * ------------------------------------------------------------------- */ void Blt_ClearBackgroundToPostScript(tokenPtr) struct PsTokenStruct *tokenPtr; { Blt_AppendToPostScript(tokenPtr, " 1.0 1.0 1.0 SetBgColor\n", (char *)NULL); } void Blt_CapStyleToPostScript(tokenPtr, capStyle) struct PsTokenStruct *tokenPtr; int capStyle; { /* * X11:not last = 0, butt = 1, round = 2, projecting = 3 * PS: butt = 0, round = 1, projecting = 2 */ if (capStyle > 0) { capStyle--; } Blt_FormatToPostScript(tokenPtr, "%d setlinecap\n", capStyle); } void Blt_JoinStyleToPostScript(tokenPtr, joinStyle) struct PsTokenStruct *tokenPtr; int joinStyle; { /* * miter = 0, round = 1, bevel = 2 */ Blt_FormatToPostScript(tokenPtr, "%d setlinejoin\n", joinStyle); } void Blt_LineWidthToPostScript(tokenPtr, lineWidth) struct PsTokenStruct *tokenPtr; int lineWidth; { if (lineWidth < 1) { lineWidth = 1; } Blt_FormatToPostScript(tokenPtr, "%d setlinewidth\n", lineWidth); } void Blt_LineDashesToPostScript(tokenPtr, dashesPtr) struct PsTokenStruct *tokenPtr; Blt_Dashes *dashesPtr; { Blt_AppendToPostScript(tokenPtr, "[ ", (char *)NULL); if (dashesPtr != NULL) { unsigned char *p; for (p = dashesPtr->values; *p != 0; p++) { Blt_FormatToPostScript(tokenPtr, " %d", *p); } } Blt_AppendToPostScript(tokenPtr, "] 0 setdash\n", (char *)NULL); } void Blt_LineAttributesToPostScript(tokenPtr, colorPtr, lineWidth, dashesPtr, capStyle, joinStyle) struct PsTokenStruct *tokenPtr; XColor *colorPtr; int lineWidth; Blt_Dashes *dashesPtr; int capStyle, joinStyle; { Blt_JoinStyleToPostScript(tokenPtr, joinStyle); Blt_CapStyleToPostScript(tokenPtr, capStyle); Blt_ForegroundToPostScript(tokenPtr, colorPtr); Blt_LineWidthToPostScript(tokenPtr, lineWidth); Blt_LineDashesToPostScript(tokenPtr, dashesPtr); Blt_AppendToPostScript(tokenPtr, "/DashesProc {} def\n", (char *)NULL); } void Blt_RectangleToPostScript(tokenPtr, x, y, width, height) struct PsTokenStruct *tokenPtr; double x, y; int width, height; { Blt_FormatToPostScript(tokenPtr, "%g %g %d %d Box fill\n\n", x, y, width, height); } void Blt_RegionToPostScript(tokenPtr, x, y, width, height) struct PsTokenStruct *tokenPtr; double x, y; int width, height; { Blt_FormatToPostScript(tokenPtr, "%g %g %d %d Box\n\n", x, y, width, height); } void Blt_PathToPostScript(tokenPtr, screenPts, nScreenPts) struct PsTokenStruct *tokenPtr; register Point2D *screenPts; int nScreenPts; { register Point2D *pointPtr, *endPtr; pointPtr = screenPts; Blt_FormatToPostScript(tokenPtr, "newpath %g %g moveto\n", pointPtr->x, pointPtr->y); pointPtr++; endPtr = screenPts + nScreenPts; while (pointPtr < endPtr) { Blt_FormatToPostScript(tokenPtr, "%g %g lineto\n", pointPtr->x, pointPtr->y); pointPtr++; } } void Blt_PolygonToPostScript(tokenPtr, screenPts, nScreenPts) struct PsTokenStruct *tokenPtr; Point2D *screenPts; int nScreenPts; { Blt_PathToPostScript(tokenPtr, screenPts, nScreenPts); Blt_FormatToPostScript(tokenPtr, "%g %g ", screenPts[0].x, screenPts[0].y); Blt_AppendToPostScript(tokenPtr, " lineto closepath Fill\n", (char *)NULL); } void Blt_SegmentsToPostScript(tokenPtr, segPtr, nSegments) struct PsTokenStruct *tokenPtr; register XSegment *segPtr; int nSegments; { register int i; for (i = 0; i < nSegments; i++, segPtr++) { Blt_FormatToPostScript(tokenPtr, "%d %d moveto\n", segPtr->x1, segPtr->y1); Blt_FormatToPostScript(tokenPtr, " %d %d lineto\n", segPtr->x2, segPtr->y2); Blt_AppendToPostScript(tokenPtr, "DashesProc stroke\n", (char *)NULL); } } void Blt_RectanglesToPostScript(tokenPtr, rectArr, nRects) struct PsTokenStruct *tokenPtr; XRectangle rectArr[]; int nRects; { register int i; for (i = 0; i < nRects; i++) { Blt_RectangleToPostScript(tokenPtr, (double)rectArr[i].x, (double)rectArr[i].y, (int)rectArr[i].width, (int)rectArr[i].height); } } #ifndef TK_RELIEF_SOLID #define TK_RELIEF_SOLID -1 /* Set the an impossible value. */ #endif /* TK_RELIEF_SOLID */ void Blt_Draw3DRectangleToPostScript(tokenPtr, border, x, y, width, height, borderWidth, relief) struct PsTokenStruct *tokenPtr; Tk_3DBorder border; /* Token for border to draw. */ double x, y; /* Coordinates of rectangle */ int width, height; /* Region to be drawn. */ int borderWidth; /* Desired width for border, in pixels. */ int relief; /* Should be either TK_RELIEF_RAISED or * TK_RELIEF_SUNKEN; indicates position of * interior of window relative to exterior. */ { TkBorder *borderPtr = (TkBorder *) border; XColor lightColor, darkColor; XColor *lightColorPtr, *darkColorPtr; XColor *topColor, *bottomColor; Point2D points[7]; int twiceWidth = (borderWidth * 2); if ((width < twiceWidth) || (height < twiceWidth)) { return; } if ((relief == TK_RELIEF_SOLID) || (borderPtr->lightColor == NULL) || (borderPtr->darkColor == NULL)) { if (relief == TK_RELIEF_SOLID) { darkColor.red = darkColor.blue = darkColor.green = 0x00; lightColor.red = lightColor.blue = lightColor.green = 0x00; relief = TK_RELIEF_SUNKEN; } else { Screen *screenPtr; lightColor = *borderPtr->bgColor; screenPtr = Tk_Screen(tokenPtr->tkwin); if (lightColor.pixel == WhitePixelOfScreen(screenPtr)) { darkColor.red = darkColor.blue = darkColor.green = 0x00; } else { darkColor.red = darkColor.blue = darkColor.green = 0xFF; } } lightColorPtr = &lightColor; darkColorPtr = &darkColor; } else { lightColorPtr = borderPtr->lightColor; darkColorPtr = borderPtr->darkColor; } /* * Handle grooves and ridges with recursive calls. */ if ((relief == TK_RELIEF_GROOVE) || (relief == TK_RELIEF_RIDGE)) { int halfWidth, insideOffset; halfWidth = borderWidth / 2; insideOffset = borderWidth - halfWidth; Blt_Draw3DRectangleToPostScript(tokenPtr, border, (double)x, (double)y, width, height, halfWidth, (relief == TK_RELIEF_GROOVE) ? TK_RELIEF_SUNKEN : TK_RELIEF_RAISED); Blt_Draw3DRectangleToPostScript(tokenPtr, 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; } if (relief == TK_RELIEF_RAISED) { topColor = lightColorPtr; bottomColor = darkColorPtr; } else if (relief == TK_RELIEF_SUNKEN) { topColor = darkColorPtr; bottomColor = lightColorPtr; } else { topColor = bottomColor = borderPtr->bgColor; } Blt_BackgroundToPostScript(tokenPtr, bottomColor); Blt_RectangleToPostScript(tokenPtr, x, y + height - borderWidth, width, borderWidth); Blt_RectangleToPostScript(tokenPtr, x + width - borderWidth, y, borderWidth, height); 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) { Blt_BackgroundToPostScript(tokenPtr, topColor); } Blt_PolygonToPostScript(tokenPtr, points, 7); } void Blt_Fill3DRectangleToPostScript(tokenPtr, border, x, y, width, height, borderWidth, relief) struct PsTokenStruct *tokenPtr; Tk_3DBorder border; /* Token for border to draw. */ double x, y; /* Coordinates of top-left of border area */ int width, height; /* Dimension of border to be drawn. */ int borderWidth; /* Desired width for border, in pixels. */ int relief; /* Should be either TK_RELIEF_RAISED or * TK_RELIEF_SUNKEN; indicates position of * interior of window relative to exterior. */ { TkBorder *borderPtr = (TkBorder *) border; /* * I'm assuming that the rectangle is to be drawn as a background. * Setting the pen color as foreground or background only affects * the plot when the colormode option is "monochrome". */ Blt_BackgroundToPostScript(tokenPtr, borderPtr->bgColor); Blt_RectangleToPostScript(tokenPtr, x, y, width, height); Blt_Draw3DRectangleToPostScript(tokenPtr, border, x, y, width, height, borderWidth, relief); } void Blt_StippleToPostScript(tokenPtr, display, bitmap) struct PsTokenStruct *tokenPtr; Display *display; Pixmap bitmap; { int width, height; Tk_SizeOfBitmap(display, bitmap, &width, &height); Blt_FormatToPostScript(tokenPtr, "gsave\n clip\n %d %d\n", width, height); Blt_BitmapDataToPostScript(tokenPtr, display, bitmap, width, height); Blt_AppendToPostScript(tokenPtr, " StippleFill\ngrestore\n", (char *)NULL); } /* *---------------------------------------------------------------------- * * Blt_ColorImageToPostScript -- * * Translates a color image into 3 component RGB PostScript output. * Uses PS Language Level 2 operator "colorimage". * * Results: * The dynamic string will contain the PostScript output. * *---------------------------------------------------------------------- */ void Blt_ColorImageToPostScript(tokenPtr, image, x, y) struct PsTokenStruct *tokenPtr; Blt_ColorImage image; double x, y; { int width, height; int tmpSize; width = Blt_ColorImageWidth(image); height = Blt_ColorImageHeight(image); tmpSize = width; if (tokenPtr->colorMode == PS_MODE_COLOR) { tmpSize *= 3; } Blt_FormatToPostScript(tokenPtr, "\n/tmpStr %d string def\n", tmpSize); Blt_AppendToPostScript(tokenPtr, "gsave\n", (char *)NULL); Blt_FormatToPostScript(tokenPtr, " %g %g translate\n", x, y); Blt_FormatToPostScript(tokenPtr, " %d %d scale\n", width, height); Blt_FormatToPostScript(tokenPtr, " %d %d 8\n", width, height); Blt_FormatToPostScript(tokenPtr, " [%d 0 0 %d 0 %d] ", width, -height, height); Blt_AppendToPostScript(tokenPtr, "{\n currentfile tmpStr readhexstring pop\n } ", (char *)NULL); if (tokenPtr->colorMode != PS_MODE_COLOR) { Blt_AppendToPostScript(tokenPtr, "image\n", (char *)NULL); Blt_ColorImageToGreyscale(image); Blt_ColorImageToPsData(image, 1, &(tokenPtr->dString), " "); } else { Blt_AppendToPostScript(tokenPtr, "false 3 colorimage\n", (char *)NULL); Blt_ColorImageToPsData(image, 3, &(tokenPtr->dString), " "); } Blt_AppendToPostScript(tokenPtr, "\ngrestore\n\n", (char *)NULL); } /* *---------------------------------------------------------------------- * * Blt_WindowToPostScript -- * * Converts a Tk window to PostScript. If the window could not * be "snapped", then a grey rectangle is drawn in its place. * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_WindowToPostScript(tokenPtr, tkwin, x, y) struct PsTokenStruct *tokenPtr; Tk_Window tkwin; double x, y; { Blt_ColorImage image; int width, height; width = Tk_Width(tkwin); height = Tk_Height(tkwin); image = Blt_DrawableToColorImage(tkwin, Tk_WindowId(tkwin), 0, 0, width, height, GAMMA); if (image == NULL) { /* Can't grab window image so paint the window area grey */ Blt_AppendToPostScript(tokenPtr, "% Can't grab window \"", Tk_PathName(tkwin), "\"\n", (char *)NULL); Blt_AppendToPostScript(tokenPtr, "0.5 0.5 0.5 SetBgColor\n", (char *)NULL); Blt_RectangleToPostScript(tokenPtr, x, y, width, height); return; } Blt_ColorImageToPostScript(tokenPtr, image, x, y); Blt_FreeColorImage(image); } /* * ------------------------------------------------------------------------- * * Blt_PhotoToPostScript -- * * Output a PostScript image string of the given photo image. * The photo is first converted into a color image and then * translated into PostScript. * * Results: * None. * * Side Effects: * The PostScript output representing the photo is appended to * the tokenPtr's dynamic string. * * ------------------------------------------------------------------------- */ void Blt_PhotoToPostScript(tokenPtr, photo, x, y) struct PsTokenStruct *tokenPtr; Tk_PhotoHandle photo; double x, y; /* Origin of photo image */ { Blt_ColorImage image; image = Blt_PhotoToColorImage(photo); Blt_ColorImageToPostScript(tokenPtr, image, x, y); Blt_FreeColorImage(image); } /* * ----------------------------------------------------------------- * * Blt_FontToPostScript -- * * Map the Tk font to a PostScript font and point size. * * If a Tcl array variable was specified, each element should be * indexed by the X11 font name and contain a list of 1-2 * elements; the PostScript font name and the desired point size. * The point size may be omitted and the X font point size will * be used. * * Otherwise, if the foundry is "Adobe", we try to do a plausible * mapping looking at the full name of the font and building a * string in the form of "Family-TypeFace". * * Returns: * None. * * Side Effects: * PostScript commands are output to change the type and the * point size of the current font. * * ----------------------------------------------------------------- */ void Blt_FontToPostScript(tokenPtr, font) struct PsTokenStruct *tokenPtr; Tk_Font font; /* Tk font to query about */ { XFontStruct *fontPtr = (XFontStruct *)font; Tcl_Interp *interp = tokenPtr->interp; char *fontName; double pointSize; #if (TK_MAJOR_VERSION > 4) Tk_Uid family; register int i; #endif /* TK_MAJOR_VERSION > 4 */ fontName = Tk_NameOfFont(font); pointSize = 12.0; /* * Use the font variable information if it exists. */ if (tokenPtr->fontVarName != NULL) { char *fontInfo; fontInfo = (char *)Tcl_GetVar2(interp, tokenPtr->fontVarName, fontName, 0); if (fontInfo != NULL) { int nProps; char **propArr = NULL; if (Tcl_SplitList(interp, fontInfo, &nProps, &propArr) == TCL_OK) { int newSize; fontName = propArr[0]; if ((nProps == 2) && (Tcl_GetInt(interp, propArr[1], &newSize) == TCL_OK)) { pointSize = (double)newSize; } } Blt_FormatToPostScript(tokenPtr, "%g /%s SetFont\n", pointSize, fontName); if (propArr != (char **)NULL) { Blt_Free(propArr); } return; } } #if (TK_MAJOR_VERSION > 4) /* * Otherwise do a quick test to see if it's a PostScript font. * Tk_PostScriptFontName will silently generate a bogus PostScript * font description, so we have to check to see if this is really a * PostScript font. */ family = ((TkFont *) fontPtr)->fa.family; for (i = 0; i < nFontNames; i++) { if (strncasecmp(psFontMap[i].alias, family, strlen(psFontMap[i].alias)) == 0) { Tcl_DString dString; Tcl_DStringInit(&dString); pointSize = (double)Tk_PostscriptFontName(font, &dString); fontName = Tcl_DStringValue(&dString); Blt_FormatToPostScript(tokenPtr, "%g /%s SetFont\n", pointSize, fontName); Tcl_DStringFree(&dString); return; } } #endif /* TK_MAJOR_VERSION > 4 */ /* * Can't find it. Try to use the current point size. */ fontName = NULL; pointSize = 12.0; #ifndef WIN32 #if (TK_MAJOR_VERSION > 4) /* Can you believe what I have to go through to get an XFontStruct? */ fontPtr = XLoadQueryFont(Tk_Display(tokenPtr->tkwin), Tk_NameOfFont(font)); #endif if (fontPtr != NULL) { unsigned long fontProp; if (XGetFontProperty(fontPtr, XA_POINT_SIZE, &fontProp) != False) { pointSize = (double)fontProp / 10.0; } fontName = XFontStructToPostScript(tokenPtr->tkwin, fontPtr); #if (TK_MAJOR_VERSION > 4) XFreeFont(Tk_Display(tokenPtr->tkwin), fontPtr); #endif /* TK_MAJOR_VERSION > 4 */ } #endif /* !WIN32 */ if ((fontName == NULL) || (fontName[0] == '\0')) { fontName = "Helvetica-Bold"; /* Defaulting to a known PS font */ } Blt_FormatToPostScript(tokenPtr, "%g /%s SetFont\n", pointSize, fontName); } static void TextLayoutToPostScript(tokenPtr, x, y, textPtr) struct PsTokenStruct *tokenPtr; int x, y; TextLayout *textPtr; { char *src, *dst, *end; int count; /* Counts the # of bytes written to * the intermediate scratch buffer. */ TextFragment *fragPtr; int i; unsigned char c; #if HAVE_UTF Tcl_UniChar ch; #endif int limit; limit = PSTOKEN_BUFSIZ - 4; /* High water mark for the scratch * buffer. */ fragPtr = textPtr->fragArr; for (i = 0; i < textPtr->nFrags; i++, fragPtr++) { if (fragPtr->count < 1) { continue; } Blt_AppendToPostScript(tokenPtr, "(", (char *)NULL); count = 0; dst = tokenPtr->scratchArr; src = fragPtr->text; end = fragPtr->text + fragPtr->count; while (src < end) { if (count > limit) { /* Don't let the scatch buffer overflow */ dst = tokenPtr->scratchArr; dst[count] = '\0'; Blt_AppendToPostScript(tokenPtr, dst, (char *)NULL); count = 0; } #if HAVE_UTF /* * INTL: For now we just treat the characters as binary * data and display the lower byte. Eventually this should * be revised to handle international postscript fonts. */ src += Tcl_UtfToUniChar(src, &ch); c = (unsigned char)(ch & 0xff); #else c = *src++; #endif if ((c == '\\') || (c == '(') || (c == ')')) { /* * If special PostScript characters characters "\", "(", * and ")" are contained in the text string, prepend * backslashes to them. */ *dst++ = '\\'; *dst++ = c; count += 2; } else if ((c < ' ') || (c > '~')) { /* * Present non-printable characters in their octal * representation. */ sprintf(dst, "\\%03o", c); dst += 4; count += 4; } else { *dst++ = c; count++; } } tokenPtr->scratchArr[count] = '\0'; Blt_AppendToPostScript(tokenPtr, tokenPtr->scratchArr, (char *)NULL); Blt_FormatToPostScript(tokenPtr, ") %d %d %d DrawAdjText\n", fragPtr->width, x + fragPtr->x, y + fragPtr->y); } } /* * ----------------------------------------------------------------- * * Blt_TextToPostScript -- * * Output PostScript commands to print a text string. The string * may be rotated at any arbitrary angle, and placed according * the anchor type given. The anchor indicates how to interpret * the window coordinates as an anchor for the text bounding box. * * Results: * None. * * Side Effects: * Text string is drawn using the given font and GC on the graph * window at the given coordinates, anchor, and rotation * * ----------------------------------------------------------------- */ void Blt_TextToPostScript(tokenPtr, string, tsPtr, x, y) struct PsTokenStruct *tokenPtr; char *string; /* String to convert to PostScript */ TextStyle *tsPtr; /* Text attribute information */ double x, y; /* Window coordinates where to print text */ { double theta; double rotWidth, rotHeight; TextLayout *textPtr; Point2D anchorPos; if ((string == NULL) || (*string == '\0')) { /* Empty string, do nothing */ return; } theta = FMOD(tsPtr->theta, (double)360.0); textPtr = Blt_GetTextLayout(string, tsPtr); Blt_GetBoundingBox(textPtr->width, textPtr->height, theta, &rotWidth, &rotHeight, (Point2D *)NULL); /* * Find the center of the bounding box */ anchorPos.x = x, anchorPos.y = y; anchorPos = Blt_TranslatePoint(&anchorPos, ROUND(rotWidth), ROUND(rotHeight), tsPtr->anchor); anchorPos.x += (rotWidth * 0.5); anchorPos.y += (rotHeight * 0.5); /* Initialize text (sets translation and rotation) */ Blt_FormatToPostScript(tokenPtr, "%d %d %g %g %g BeginText\n", textPtr->width, textPtr->height, tsPtr->theta, anchorPos.x, anchorPos.y); Blt_FontToPostScript(tokenPtr, tsPtr->font); /* All coordinates are now relative to what was set by BeginText */ if ((tsPtr->shadow.offset > 0) && (tsPtr->shadow.color != NULL)) { Blt_ForegroundToPostScript(tokenPtr, tsPtr->shadow.color); TextLayoutToPostScript(tokenPtr, tsPtr->shadow.offset, tsPtr->shadow.offset, textPtr); } Blt_ForegroundToPostScript(tokenPtr, (tsPtr->state & STATE_ACTIVE) ? tsPtr->activeColor : tsPtr->color); TextLayoutToPostScript(tokenPtr, 0, 0, textPtr); Blt_Free(textPtr); Blt_AppendToPostScript(tokenPtr, "EndText\n", (char *)NULL); } /* * ----------------------------------------------------------------- * * Blt_LineToPostScript -- * * Outputs PostScript commands to print a multi-segmented line. * It assumes a procedure DashesProc was previously defined. * * Results: * None. * * Side Effects: * Segmented line is printed. * * ----------------------------------------------------------------- */ void Blt_LineToPostScript(tokenPtr, pointPtr, nPoints) struct PsTokenStruct *tokenPtr; register XPoint *pointPtr; int nPoints; { register int i; if (nPoints <= 0) { return; } Blt_FormatToPostScript(tokenPtr, " newpath %d %d moveto\n", pointPtr->x, pointPtr->y); pointPtr++; for (i = 1; i < (nPoints - 1); i++, pointPtr++) { Blt_FormatToPostScript(tokenPtr, " %d %d lineto\n", pointPtr->x, pointPtr->y); if ((i % PS_MAXPATH) == 0) { Blt_FormatToPostScript(tokenPtr, "DashesProc stroke\n newpath %d %d moveto\n", pointPtr->x, pointPtr->y); } } Blt_FormatToPostScript(tokenPtr, " %d %d lineto\n", pointPtr->x, pointPtr->y); Blt_AppendToPostScript(tokenPtr, "DashesProc stroke\n", (char *)NULL); } void Blt_BitmapToPostScript(tokenPtr, display, bitmap, scaleX, scaleY) struct PsTokenStruct *tokenPtr; Display *display; Pixmap bitmap; /* Bitmap to be converted to PostScript */ double scaleX, scaleY; { int width, height; double scaledWidth, scaledHeight; Tk_SizeOfBitmap(display, bitmap, &width, &height); scaledWidth = (double)width * scaleX; scaledHeight = (double)height * scaleY; Blt_AppendToPostScript(tokenPtr, " gsave\n", (char *)NULL); Blt_FormatToPostScript(tokenPtr, " %g %g translate\n", scaledWidth * -0.5, scaledHeight * 0.5); Blt_FormatToPostScript(tokenPtr, " %g %g scale\n", scaledWidth, -scaledHeight); Blt_FormatToPostScript(tokenPtr, " %d %d true [%d 0 0 %d 0 %d] {", width, height, width, -height, height); Blt_BitmapDataToPostScript(tokenPtr, display, bitmap, width, height); Blt_AppendToPostScript(tokenPtr, " } imagemask\n grestore\n", (char *)NULL); } void Blt_2DSegmentsToPostScript(psToken, segPtr, nSegments) PsToken psToken; register Segment2D *segPtr; int nSegments; { register Segment2D *endPtr; for (endPtr = segPtr + nSegments; segPtr < endPtr; segPtr++) { Blt_FormatToPostScript(psToken, "%g %g moveto\n", segPtr->p.x, segPtr->p.y); Blt_FormatToPostScript(psToken, " %g %g lineto\n", segPtr->q.x, segPtr->q.y); Blt_AppendToPostScript(psToken, "DashesProc stroke\n", (char *)NULL); } } blt-2.4z.orig/src/bltPs.h0100644000175000017500000001246507525066175014015 0ustar dokodoko/* * bltPs.h -- * * Copyright 1993-1998 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. */ #ifndef _BLT_PS_H #define _BLT_PS_H #include "bltImage.h" typedef enum { PS_MODE_MONOCHROME, PS_MODE_GREYSCALE, PS_MODE_COLOR } PsColorMode; typedef struct PsTokenStruct *PsToken; struct PsTokenStruct { Tcl_Interp *interp; /* Interpreter to report errors to. */ Tk_Window tkwin; /* Tk_Window used to get font and color * information */ Tcl_DString dString; /* Dynamic string used to contain the * PostScript generated. */ char *fontVarName; /* Name of a Tcl array variable to convert * X font names to PostScript fonts. */ char *colorVarName; /* Name of a Tcl array variable to convert * X color names to PostScript. */ PsColorMode colorMode; /* Mode: color or greyscale */ #define PSTOKEN_BUFSIZ ((BUFSIZ*2)-1) /* * Utility space for building strings. Currently used to create * PostScript output for the "postscript" command. */ char scratchArr[PSTOKEN_BUFSIZ+1]; }; extern PsToken Blt_GetPsToken _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin)); extern void Blt_ReleasePsToken _ANSI_ARGS_((PsToken psToken)); extern char *Blt_PostScriptFromToken _ANSI_ARGS_((PsToken psToken)); extern char *Blt_ScratchBufferFromToken _ANSI_ARGS_((PsToken psToken)); extern void Blt_AppendToPostScript _ANSI_ARGS_(TCL_VARARGS(PsToken, psToken)); extern void Blt_FormatToPostScript _ANSI_ARGS_(TCL_VARARGS(PsToken, psToken)); extern void Blt_Draw3DRectangleToPostScript _ANSI_ARGS_((PsToken psToken, Tk_3DBorder border, double x, double y, int width, int height, int borderWidth, int relief)); extern void Blt_Fill3DRectangleToPostScript _ANSI_ARGS_((PsToken psToken, Tk_3DBorder border, double x, double y, int width, int height, int borderWidth, int relief)); extern void Blt_BackgroundToPostScript _ANSI_ARGS_((PsToken psToken, XColor *colorPtr)); extern void Blt_BitmapDataToPostScript _ANSI_ARGS_((PsToken psToken, Display *display, Pixmap bitmap, int width, int height)); extern void Blt_ClearBackgroundToPostScript _ANSI_ARGS_((PsToken psToken)); extern int Blt_ColorImageToPsData _ANSI_ARGS_((Blt_ColorImage image, int nComponents, Tcl_DString * resultPtr, char *prefix)); extern void Blt_ColorImageToPostScript _ANSI_ARGS_((PsToken psToken, Blt_ColorImage image, double x, double y)); extern void Blt_ForegroundToPostScript _ANSI_ARGS_((PsToken psToken, XColor *colorPtr)); extern void Blt_FontToPostScript _ANSI_ARGS_((PsToken psToken, Tk_Font font)); extern void Blt_WindowToPostScript _ANSI_ARGS_((PsToken psToken, Tk_Window tkwin, double x, double y)); extern void Blt_LineDashesToPostScript _ANSI_ARGS_((PsToken psToken, Blt_Dashes *dashesPtr)); extern void Blt_LineWidthToPostScript _ANSI_ARGS_((PsToken psToken, int lineWidth)); extern void Blt_PathToPostScript _ANSI_ARGS_((PsToken psToken, Point2D *screenPts, int nScreenPts)); extern void Blt_PhotoToPostScript _ANSI_ARGS_((PsToken psToken, Tk_PhotoHandle photoToken, double x, double y)); extern void Blt_PolygonToPostScript _ANSI_ARGS_((PsToken psToken, Point2D *screenPts, int nScreenPts)); extern void Blt_LineToPostScript _ANSI_ARGS_((PsToken psToken, XPoint *pointArr, int nPoints)); extern void Blt_TextToPostScript _ANSI_ARGS_((PsToken psToken, char *string, TextStyle *attrPtr, double x, double y)); extern void Blt_RectangleToPostScript _ANSI_ARGS_((PsToken psToken, double x, double y, int width, int height)); extern void Blt_RegionToPostScript _ANSI_ARGS_((PsToken psToken, double x, double y, int width, int height)); extern void Blt_RectanglesToPostScript _ANSI_ARGS_((PsToken psToken, XRectangle *rectArr, int nRects)); extern void Blt_BitmapToPostScript _ANSI_ARGS_((PsToken psToken, Display *display, Pixmap bitmap, double scaleX, double scaleY)); extern void Blt_SegmentsToPostScript _ANSI_ARGS_((PsToken psToken, XSegment *segArr, int nSegs)); extern void Blt_StippleToPostScript _ANSI_ARGS_((PsToken psToken, Display *display, Pixmap bitmap)); extern void Blt_LineAttributesToPostScript _ANSI_ARGS_((PsToken psToken, XColor *colorPtr, int lineWidth, Blt_Dashes *dashesPtr, int capStyle, int joinStyle)); extern int Blt_FileToPostScript _ANSI_ARGS_((PsToken psToken, char *fileName)); extern void Blt_2DSegmentsToPostScript _ANSI_ARGS_((PsToken psToken, Segment2D *segments, int nSegments)); #endif /* BLT_PS_H */ blt-2.4z.orig/src/bltScrollbar.c0100644000175000017500000013075007515370776015353 0ustar dokodoko /* * tkScrollbar.c -- * * This module implements a scrollbar widgets for the Tk * toolkit. A scrollbar displays a slider and two arrows; * mouse clicks on features within the scrollbar cause * scrolling commands to be invoked. * * Copyright (c) 1990-1994 The Regents of the University of California. * Copyright (c) 1994-1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * SCCS: @(#) tkScrollbar.c 1.79 96/02/15 18:52:40 */ #include "bltInt.h" #ifndef NO_TILESCROLLBAR #include "bltTile.h" extern Tk_CustomOption bltTileOption; #define NORMAL_BG "#d9d9d9" #define ACTIVE_BG "#ececec" #define SELECT_BG "#c3c3c3" #define TROUGH "#c3c3c3" #define INDICATOR "#b03060" #define DISABLED "#a3a3a3" /* * Defaults for scrollbars: */ #define DEF_SCROLLBAR_ACTIVE_BACKGROUND ACTIVE_BG #define DEF_SCROLLBAR_ACTIVE_BG_MONO RGB_BLACK #define DEF_SCROLLBAR_ACTIVE_RELIEF "raised" #define DEF_SCROLLBAR_BACKGROUND NORMAL_BG #define DEF_SCROLLBAR_BG_MONO RGB_WHITE #define DEF_SCROLLBAR_BORDERWIDTH "2" #define DEF_SCROLLBAR_COMMAND "" #define DEF_SCROLLBAR_CURSOR "" #define DEF_SCROLLBAR_EL_BORDERWIDTH "-1" #define DEF_SCROLLBAR_HIGHLIGHT_BG NORMAL_BG #define DEF_SCROLLBAR_HIGHLIGHT RGB_BLACK #define DEF_SCROLLBAR_HIGHLIGHT_WIDTH "2" #define DEF_SCROLLBAR_JUMP "0" #define DEF_SCROLLBAR_ORIENT "vertical" #define DEF_SCROLLBAR_RELIEF "sunken" #define DEF_SCROLLBAR_REPEAT_DELAY "300" #define DEF_SCROLLBAR_REPEAT_INTERVAL "100" #define DEF_SCROLLBAR_TAKE_FOCUS (char *)NULL #define DEF_SCROLLBAR_TROUGH_COLOR TROUGH #define DEF_SCROLLBAR_TROUGH_MONO RGB_WHITE #define DEF_SCROLLBAR_WIDTH "15" /* * A data structure of the following type is kept for each scrollbar * widget managed by this file: */ typedef struct { Tk_Window tkwin; /* Window that embodies the scrollbar. NULL * means that the window has been destroyed * but the data structures haven't yet been * cleaned up.*/ Display *display; /* Display containing widget. Used, among * other things, so that resources can be * freed even after tkwin has gone away. */ Tcl_Interp *interp; /* Interpreter associated with scrollbar. */ Tcl_Command widgetCmd; /* Token for scrollbar's widget command. */ Tk_Uid orientUid; /* Orientation for window ("vertical" or * "horizontal"). */ int vertical; /* Non-zero means vertical orientation * requested, zero means horizontal. */ int width; /* Desired narrow dimension of scrollbar, * in pixels. */ char *command; /* Command prefix to use when invoking * scrolling commands. NULL means don't * invoke commands. Malloc'ed. */ int commandSize; /* Number of non-NULL bytes in command. */ int repeatDelay; /* How long to wait before auto-repeating * on scrolling actions (in ms). */ int repeatInterval; /* Interval between autorepeats (in ms). */ int jump; /* Value of -jump option. */ /* * Information used when displaying widget: */ int borderWidth; /* Width of 3-D borders. */ Tk_3DBorder bgBorder; /* Used for drawing background (all flat * surfaces except for trough). */ Tk_3DBorder activeBorder; /* For drawing backgrounds when active (i.e. * when mouse is positioned over element). */ XColor *troughColorPtr; /* Color for drawing trough. */ GC troughGC; /* For drawing trough. */ GC copyGC; /* Used for copying from pixmap onto screen. */ int relief; /* Indicates whether window as a whole is * raised, sunken, or flat. */ int highlightWidth; /* Width in pixels of highlight to draw * around widget when it has the focus. * <= 0 means don't draw a highlight. */ XColor *highlightBgColorPtr; /* Color for drawing traversal highlight * area when highlight is off. */ XColor *highlightColorPtr; /* Color for drawing traversal highlight. */ int inset; /* Total width of all borders, including * traversal highlight and 3-D border. * Indicates how much interior stuff must * be offset from outside edges to leave * room for borders. */ int elementBorderWidth; /* Width of border to draw around elements * inside scrollbar (arrows and slider). * -1 means use borderWidth. */ int arrowLength; /* Length of arrows along long dimension of * scrollbar, including space for a small gap * between the arrow and the slider. * Recomputed on window size changes. */ int sliderFirst; /* Pixel coordinate of top or left edge * of slider area, including border. */ int sliderLast; /* Coordinate of pixel just after bottom * or right edge of slider area, including * border. */ int activeField; /* Names field to be displayed in active * colors, such as TOP_ARROW, or 0 for * no field. */ int activeRelief; /* Value of -activeRelief option: relief * to use for active element. */ /* * Information describing the application related to the scrollbar. * This information is provided by the application by invoking the * "set" widget command. This information can now be provided in * two ways: the "old" form (totalUnits, windowUnits, firstUnit, * and lastUnit), or the "new" form (firstFraction and lastFraction). * FirstFraction and lastFraction will always be valid, but * the old-style information is only valid if the NEW_STYLE_COMMANDS * flag is 0. */ int totalUnits; /* Total dimension of application, in * units. Valid only if the NEW_STYLE_COMMANDS * flag isn't set. */ int windowUnits; /* Maximum number of units that can be * displayed in the window at once. Valid * only if the NEW_STYLE_COMMANDS flag isn't * set. */ int firstUnit; /* Number of last unit visible in * application's window. Valid only if the * NEW_STYLE_COMMANDS flag isn't set. */ int lastUnit; /* Index of last unit visible in window. * Valid only if the NEW_STYLE_COMMANDS * flag isn't set. */ double firstFraction; /* Position of first visible thing in window, * specified as a fraction between 0 and * 1.0. */ double lastFraction; /* Position of last visible thing in window, * specified as a fraction between 0 and * 1.0. */ /* * Miscellaneous information: */ Tk_Cursor cursor; /* Current cursor for window, or None. */ char *takeFocus; /* Value of -takefocus option; not used in * the C code, but used by keyboard traversal * scripts. Malloc'ed, but may be NULL. */ int flags; /* Various flags; see below for * definitions. */ Blt_Tile tile, activeTile; } Scrollbar; /* * Legal values for "activeField" field of Scrollbar structures. These * are also the return values from the ScrollbarPosition procedure. */ #define OUTSIDE 0 #define TOP_ARROW 1 #define TOP_GAP 2 #define SLIDER 3 #define BOTTOM_GAP 4 #define BOTTOM_ARROW 5 /* * Flag bits for scrollbars: * * REDRAW_PENDING: Non-zero means a DoWhenIdle handler * has already been queued to redraw * this window. * NEW_STYLE_COMMANDS: Non-zero means the new style of commands * should be used to communicate with the * widget: ".t yview scroll 2 lines", instead * of ".t yview 40", for example. * GOT_FOCUS: Non-zero means this window has the input * focus. */ #define REDRAW_PENDING 1 #define NEW_STYLE_COMMANDS 2 #define GOT_FOCUS 4 /* * Minimum slider length, in pixels (designed to make sure that the slider * is always easy to grab with the mouse). */ #define MIN_SLIDER_LENGTH 8 /* * Information used for argv parsing. */ static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", DEF_SCROLLBAR_ACTIVE_BACKGROUND, Tk_Offset(Scrollbar, activeBorder), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", DEF_SCROLLBAR_ACTIVE_BG_MONO, Tk_Offset(Scrollbar, activeBorder), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_RELIEF, "-activerelief", "activeRelief", "Relief", DEF_SCROLLBAR_ACTIVE_RELIEF, Tk_Offset(Scrollbar, activeRelief), 0}, {TK_CONFIG_CUSTOM, "-activetile", "activeTile", "Tile", (char *)NULL, Tk_Offset(Scrollbar, activeTile), TK_CONFIG_NULL_OK, &bltTileOption}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_SCROLLBAR_BACKGROUND, Tk_Offset(Scrollbar, bgBorder), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_SCROLLBAR_BG_MONO, Tk_Offset(Scrollbar, bgBorder), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", DEF_SCROLLBAR_BORDERWIDTH, Tk_Offset(Scrollbar, borderWidth), 0}, {TK_CONFIG_STRING, "-command", "command", "Command", DEF_SCROLLBAR_COMMAND, Tk_Offset(Scrollbar, command), TK_CONFIG_NULL_OK}, {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", DEF_SCROLLBAR_CURSOR, Tk_Offset(Scrollbar, cursor), TK_CONFIG_NULL_OK}, {TK_CONFIG_PIXELS, "-elementborderwidth", "elementBorderWidth", "BorderWidth", DEF_SCROLLBAR_EL_BORDERWIDTH, Tk_Offset(Scrollbar, elementBorderWidth), 0}, {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", "HighlightBackground", DEF_SCROLLBAR_HIGHLIGHT_BG, Tk_Offset(Scrollbar, highlightBgColorPtr), 0}, {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", DEF_SCROLLBAR_HIGHLIGHT, Tk_Offset(Scrollbar, highlightColorPtr), 0}, {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", "HighlightThickness", DEF_SCROLLBAR_HIGHLIGHT_WIDTH, Tk_Offset(Scrollbar, highlightWidth), 0}, {TK_CONFIG_BOOLEAN, "-jump", "jump", "Jump", DEF_SCROLLBAR_JUMP, Tk_Offset(Scrollbar, jump), 0}, {TK_CONFIG_UID, "-orient", "orient", "Orient", DEF_SCROLLBAR_ORIENT, Tk_Offset(Scrollbar, orientUid), 0}, {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_SCROLLBAR_RELIEF, Tk_Offset(Scrollbar, relief), 0}, {TK_CONFIG_INT, "-repeatdelay", "repeatDelay", "RepeatDelay", DEF_SCROLLBAR_REPEAT_DELAY, Tk_Offset(Scrollbar, repeatDelay), 0}, {TK_CONFIG_INT, "-repeatinterval", "repeatInterval", "RepeatInterval", DEF_SCROLLBAR_REPEAT_INTERVAL, Tk_Offset(Scrollbar, repeatInterval), 0}, {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", DEF_SCROLLBAR_TAKE_FOCUS, Tk_Offset(Scrollbar, takeFocus), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-tile", "tile", "Tile", (char *)NULL, Tk_Offset(Scrollbar, tile), TK_CONFIG_NULL_OK, &bltTileOption}, {TK_CONFIG_COLOR, "-troughcolor", "troughColor", "Background", DEF_SCROLLBAR_TROUGH_COLOR, Tk_Offset(Scrollbar, troughColorPtr), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-troughcolor", "troughColor", "Background", DEF_SCROLLBAR_TROUGH_MONO, Tk_Offset(Scrollbar, troughColorPtr), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_PIXELS, "-width", "width", "Width", DEF_SCROLLBAR_WIDTH, Tk_Offset(Scrollbar, width), 0}, {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; /* * Forward declarations for procedures defined later in this file: */ static void ComputeScrollbarGeometry _ANSI_ARGS_(( Scrollbar *scrollPtr)); static int ConfigureScrollbar _ANSI_ARGS_((Tcl_Interp *interp, Scrollbar *scrollPtr, int argc, char **argv, int flags)); static void DestroyScrollbar _ANSI_ARGS_((DestroyData *memPtr)); static void DisplayScrollbar _ANSI_ARGS_((ClientData clientData)); static void EventuallyRedraw _ANSI_ARGS_((Scrollbar *scrollPtr)); static void ScrollbarCmdDeletedProc _ANSI_ARGS_(( ClientData clientData)); static void ScrollbarEventProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); static int ScrollbarPosition _ANSI_ARGS_((Scrollbar *scrollPtr, int x, int y)); static int ScrollbarWidgetCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *, int argc, char **argv)); /* *-------------------------------------------------------------- * * ScrollbarCmd -- * * This procedure is invoked to process the "scrollbar" Tcl * command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ /*ARGSUSED*/ static int ScrollbarCmd(clientData, interp, argc, argv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { register Scrollbar *scrollPtr; Tk_Window tkwin; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " pathName ?options?\"", (char *)NULL); return TCL_ERROR; } tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp), argv[1], (char *)NULL); if (tkwin == NULL) { return TCL_ERROR; } /* * Initialize fields that won't be initialized by ConfigureScrollbar, * or which ConfigureScrollbar expects to have reasonable values * (e.g. resource pointers). */ scrollPtr = Blt_Malloc(sizeof(Scrollbar)); scrollPtr->tkwin = tkwin; scrollPtr->display = Tk_Display(tkwin); scrollPtr->interp = interp; scrollPtr->widgetCmd = Tcl_CreateCommand(interp, Tk_PathName(scrollPtr->tkwin), ScrollbarWidgetCmd, (ClientData)scrollPtr, ScrollbarCmdDeletedProc); #ifdef ITCL_NAMESPACES Itk_SetWidgetCommand(scrollPtr->tkwin, scrollPtr->widgetCmd); #endif /* ITCL_NAMESPACES */ scrollPtr->orientUid = NULL; scrollPtr->vertical = 0; scrollPtr->width = 0; scrollPtr->command = NULL; scrollPtr->commandSize = 0; scrollPtr->repeatDelay = 0; scrollPtr->repeatInterval = 0; scrollPtr->borderWidth = 0; scrollPtr->bgBorder = NULL; scrollPtr->activeBorder = NULL; scrollPtr->troughColorPtr = NULL; scrollPtr->troughGC = None; scrollPtr->copyGC = None; scrollPtr->relief = TK_RELIEF_FLAT; scrollPtr->highlightWidth = 0; scrollPtr->highlightBgColorPtr = NULL; scrollPtr->highlightColorPtr = NULL; scrollPtr->inset = 0; scrollPtr->elementBorderWidth = -1; scrollPtr->arrowLength = 0; scrollPtr->sliderFirst = 0; scrollPtr->sliderLast = 0; scrollPtr->activeField = 0; scrollPtr->activeRelief = TK_RELIEF_RAISED; scrollPtr->totalUnits = 0; scrollPtr->windowUnits = 0; scrollPtr->firstUnit = 0; scrollPtr->lastUnit = 0; scrollPtr->firstFraction = 0.0; scrollPtr->lastFraction = 0.0; scrollPtr->cursor = None; scrollPtr->takeFocus = NULL; scrollPtr->flags = 0; scrollPtr->tile = scrollPtr->activeTile = NULL; Tk_SetClass(scrollPtr->tkwin, "Scrollbar"); Tk_CreateEventHandler(scrollPtr->tkwin, ExposureMask | StructureNotifyMask | FocusChangeMask, ScrollbarEventProc, (ClientData)scrollPtr); if (ConfigureScrollbar(interp, scrollPtr, argc - 2, argv + 2, 0) != TCL_OK) { goto error; } Tcl_SetResult(interp, Tk_PathName(scrollPtr->tkwin), TCL_VOLATILE); return TCL_OK; error: Tk_DestroyWindow(scrollPtr->tkwin); return TCL_ERROR; } /* *-------------------------------------------------------------- * * ScrollbarWidgetCmd -- * * This procedure is invoked to process the Tcl command * that corresponds to a widget managed by this module. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ static int ScrollbarWidgetCmd(clientData, interp, argc, argv) ClientData clientData; /* Information about scrollbar * widget. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { register Scrollbar *scrollPtr = clientData; char string[200]; int result = TCL_OK; size_t length; int c; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " option ?arg arg ...?\"", (char *)NULL); return TCL_ERROR; } Tcl_Preserve((ClientData)scrollPtr); c = argv[1][0]; length = strlen(argv[1]); if ((c == 'a') && (strncmp(argv[1], "activate", length) == 0)) { if (argc == 2) { switch (scrollPtr->activeField) { case TOP_ARROW: Tcl_SetResult(interp, "arrow1", TCL_STATIC); break; case SLIDER: Tcl_SetResult(interp, "slider", TCL_STATIC); break; case BOTTOM_ARROW: Tcl_SetResult(interp, "arrow2", TCL_STATIC); break; } goto done; } if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " activate element\"", (char *)NULL); goto error; } c = argv[2][0]; length = strlen(argv[2]); if ((c == 'a') && (strcmp(argv[2], "arrow1") == 0)) { scrollPtr->activeField = TOP_ARROW; } else if ((c == 'a') && (strcmp(argv[2], "arrow2") == 0)) { scrollPtr->activeField = BOTTOM_ARROW; } else if ((c == 's') && (strncmp(argv[2], "slider", length) == 0)) { scrollPtr->activeField = SLIDER; } else { scrollPtr->activeField = OUTSIDE; } EventuallyRedraw(scrollPtr); } else if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) && (length >= 2)) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " cget option\"", (char *)NULL); goto error; } result = Tk_ConfigureValue(interp, scrollPtr->tkwin, configSpecs, (char *)scrollPtr, argv[2], 0); } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) && (length >= 2)) { if (argc == 2) { result = Tk_ConfigureInfo(interp, scrollPtr->tkwin, configSpecs, (char *)scrollPtr, (char *)NULL, 0); } else if (argc == 3) { result = Tk_ConfigureInfo(interp, scrollPtr->tkwin, configSpecs, (char *)scrollPtr, argv[2], 0); } else { result = ConfigureScrollbar(interp, scrollPtr, argc - 2, argv + 2, TK_CONFIG_ARGV_ONLY); } } else if ((c == 'd') && (strncmp(argv[1], "delta", length) == 0)) { int xDelta, yDelta, pixels, barWidth; double fraction; if (argc != 4) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " delta xDelta yDelta\"", (char *)NULL); goto error; } if ((Tcl_GetInt(interp, argv[2], &xDelta) != TCL_OK) || (Tcl_GetInt(interp, argv[3], &yDelta) != TCL_OK)) { goto error; } if (scrollPtr->vertical) { pixels = yDelta; barWidth = Tk_Height(scrollPtr->tkwin) - 1 - 2 * (scrollPtr->arrowLength + scrollPtr->inset); } else { pixels = xDelta; barWidth = Tk_Width(scrollPtr->tkwin) - 1 - 2 * (scrollPtr->arrowLength + scrollPtr->inset); } if (barWidth == 0) { fraction = 0.0; } else { fraction = ((double)pixels / (double)barWidth); } sprintf(interp->result, "%g", fraction); } else if ((c == 'f') && (strncmp(argv[1], "fraction", length) == 0)) { int x, y, pos, barWidth; double fraction; if (argc != 4) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " fraction x y\"", (char *)NULL); goto error; } if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { goto error; } if (scrollPtr->vertical) { pos = y - (scrollPtr->arrowLength + scrollPtr->inset); barWidth = Tk_Height(scrollPtr->tkwin) - 1 - 2 * (scrollPtr->arrowLength + scrollPtr->inset); } else { pos = x - (scrollPtr->arrowLength + scrollPtr->inset); barWidth = Tk_Width(scrollPtr->tkwin) - 1 - 2 * (scrollPtr->arrowLength + scrollPtr->inset); } if (barWidth == 0) { fraction = 0.0; } else { fraction = ((double)pos / (double)barWidth); } if (fraction < 0) { fraction = 0; } else if (fraction > 1.0) { fraction = 1.0; } sprintf(string, "%g", fraction); Tcl_SetResult(interp, string, TCL_VOLATILE); } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) { if (argc != 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " get\"", (char *)NULL); goto error; } if (scrollPtr->flags & NEW_STYLE_COMMANDS) { char first[TCL_DOUBLE_SPACE], last[TCL_DOUBLE_SPACE]; Tcl_PrintDouble(interp, scrollPtr->firstFraction, first); Tcl_PrintDouble(interp, scrollPtr->lastFraction, last); Tcl_AppendResult(interp, first, " ", last, (char *)NULL); } else { sprintf(string, "%d %d %d %d", scrollPtr->totalUnits, scrollPtr->windowUnits, scrollPtr->firstUnit, scrollPtr->lastUnit); Tcl_SetResult(interp, string, TCL_VOLATILE); } } else if ((c == 'i') && (strncmp(argv[1], "identify", length) == 0)) { int x, y, thing; if (argc != 4) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " identify x y\"", (char *)NULL); goto error; } if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { goto error; } thing = ScrollbarPosition(scrollPtr, x, y); switch (thing) { case TOP_ARROW: Tcl_SetResult(interp, "arrow1", TCL_STATIC); break; case TOP_GAP: Tcl_SetResult(interp, "trough1", TCL_STATIC); break; case SLIDER: Tcl_SetResult(interp, "slider", TCL_STATIC); break; case BOTTOM_GAP: Tcl_SetResult(interp, "trough2", TCL_STATIC); break; case BOTTOM_ARROW: Tcl_SetResult(interp, "arrow2", TCL_STATIC); break; } } else if ((c == 's') && (strncmp(argv[1], "set", length) == 0)) { int totalUnits, windowUnits, firstUnit, lastUnit; if (argc == 4) { double first, last; if (Tcl_GetDouble(interp, argv[2], &first) != TCL_OK) { goto error; } if (Tcl_GetDouble(interp, argv[3], &last) != TCL_OK) { goto error; } if (first < 0) { scrollPtr->firstFraction = 0; } else if (first > 1.0) { scrollPtr->firstFraction = 1.0; } else { scrollPtr->firstFraction = first; } if (last < scrollPtr->firstFraction) { scrollPtr->lastFraction = scrollPtr->firstFraction; } else if (last > 1.0) { scrollPtr->lastFraction = 1.0; } else { scrollPtr->lastFraction = last; } scrollPtr->flags |= NEW_STYLE_COMMANDS; } else if (argc == 6) { if (Tcl_GetInt(interp, argv[2], &totalUnits) != TCL_OK) { goto error; } if (totalUnits < 0) { totalUnits = 0; } if (Tcl_GetInt(interp, argv[3], &windowUnits) != TCL_OK) { goto error; } if (windowUnits < 0) { windowUnits = 0; } if (Tcl_GetInt(interp, argv[4], &firstUnit) != TCL_OK) { goto error; } if (Tcl_GetInt(interp, argv[5], &lastUnit) != TCL_OK) { goto error; } if (totalUnits > 0) { if (lastUnit < firstUnit) { lastUnit = firstUnit; } } else { firstUnit = lastUnit = 0; } scrollPtr->totalUnits = totalUnits; scrollPtr->windowUnits = windowUnits; scrollPtr->firstUnit = firstUnit; scrollPtr->lastUnit = lastUnit; if (scrollPtr->totalUnits == 0) { scrollPtr->firstFraction = 0.0; scrollPtr->lastFraction = 1.0; } else { scrollPtr->firstFraction = ((double)firstUnit) / totalUnits; scrollPtr->lastFraction = ((double)(lastUnit + 1)) / totalUnits; } scrollPtr->flags &= ~NEW_STYLE_COMMANDS; } else { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " set firstFraction lastFraction\" or \"", argv[0], " set totalUnits windowUnits firstUnit lastUnit\"", (char *)NULL); goto error; } ComputeScrollbarGeometry(scrollPtr); EventuallyRedraw(scrollPtr); } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": must be activate, cget, configure, delta, fraction, ", "get, identify, or set", (char *)NULL); goto error; } done: Tcl_Release((ClientData)scrollPtr); return result; error: Tcl_Release((ClientData)scrollPtr); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * DestroyScrollbar -- * * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release * to clean up the internal structure of a scrollbar at a safe time * (when no-one is using it anymore). * * Results: * None. * * Side effects: * Everything associated with the scrollbar is freed up. * *---------------------------------------------------------------------- */ static void DestroyScrollbar(memPtr) DestroyData *memPtr; /* Info about scrollbar widget. */ { register Scrollbar *scrollPtr = (Scrollbar *)memPtr; /* * Free up all the stuff that requires special handling, then * let Tk_FreeOptions handle all the standard option-related * stuff. */ if (scrollPtr->troughGC != None) { Tk_FreeGC(scrollPtr->display, scrollPtr->troughGC); } if (scrollPtr->copyGC != None) { Tk_FreeGC(scrollPtr->display, scrollPtr->copyGC); } if (scrollPtr->activeTile != NULL) { Blt_FreeTile(scrollPtr->activeTile); } if (scrollPtr->tile != NULL) { Blt_FreeTile(scrollPtr->tile); } Tk_FreeOptions(configSpecs, (char *)scrollPtr, scrollPtr->display, 0); Blt_Free(scrollPtr); } /* *---------------------------------------------------------------------- * * TileChangedProc * * Routine for tile change notifications. * * Results: * None. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static void TileChangedProc(clientData, tile) ClientData clientData; Blt_Tile tile; /* Not used. */ { Scrollbar *scrollPtr = clientData; if (scrollPtr->tkwin != NULL) { EventuallyRedraw(scrollPtr); } } /* *---------------------------------------------------------------------- * * ConfigureScrollbar -- * * This procedure is called to process an argv/argc list, plus * the Tk option database, in order to configure (or * reconfigure) a scrollbar widget. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then interp->result contains an error message. * * Side effects: * Configuration information, such as colors, border width, * etc. get set for scrollPtr; old resources get freed, * if there were any. * *---------------------------------------------------------------------- */ static int ConfigureScrollbar(interp, scrollPtr, argc, argv, flags) Tcl_Interp *interp; /* Used for error reporting. */ register Scrollbar *scrollPtr; /* Information about widget; may or * may not already have values for * some fields. */ int argc; /* Number of valid entries in argv. */ char **argv; /* Arguments. */ int flags; /* Flags to pass to * Tk_ConfigureWidget. */ { size_t length; XGCValues gcValues; GC new; if (Tk_ConfigureWidget(interp, scrollPtr->tkwin, configSpecs, argc, argv, (char *)scrollPtr, flags) != TCL_OK) { return TCL_ERROR; } /* * A few options need special processing, such as parsing the * orientation or setting the background from a 3-D border. */ length = strlen(scrollPtr->orientUid); if (strncmp(scrollPtr->orientUid, "vertical", length) == 0) { scrollPtr->vertical = 1; } else if (strncmp(scrollPtr->orientUid, "horizontal", length) == 0) { scrollPtr->vertical = 0; } else { Tcl_AppendResult(interp, "bad orientation \"", scrollPtr->orientUid, "\": must be vertical or horizontal", (char *)NULL); return TCL_ERROR; } if (scrollPtr->command != NULL) { scrollPtr->commandSize = strlen(scrollPtr->command); } else { scrollPtr->commandSize = 0; } if (scrollPtr->activeTile != NULL) { Blt_SetTileChangedProc(scrollPtr->activeTile, TileChangedProc, (ClientData)scrollPtr); } if (scrollPtr->tile != NULL) { Blt_SetTileChangedProc(scrollPtr->tile, TileChangedProc, (ClientData)scrollPtr); } Tk_SetBackgroundFromBorder(scrollPtr->tkwin, scrollPtr->bgBorder); gcValues.foreground = scrollPtr->troughColorPtr->pixel; new = Tk_GetGC(scrollPtr->tkwin, GCForeground, &gcValues); if (scrollPtr->troughGC != None) { Tk_FreeGC(scrollPtr->display, scrollPtr->troughGC); } scrollPtr->troughGC = new; if (scrollPtr->copyGC == None) { gcValues.graphics_exposures = False; scrollPtr->copyGC = Tk_GetGC(scrollPtr->tkwin, GCGraphicsExposures, &gcValues); } /* * Register the desired geometry for the window (leave enough space * for the two arrows plus a minimum-size slider, plus border around * the whole window, if any). Then arrange for the window to be * redisplayed. */ ComputeScrollbarGeometry(scrollPtr); EventuallyRedraw(scrollPtr); return TCL_OK; } /* *-------------------------------------------------------------- * * DisplayScrollbar -- * * This procedure redraws the contents of a scrollbar window. * It is invoked as a do-when-idle handler, so it only runs * when there's nothing else for the application to do. * * Results: * None. * * Side effects: * Information appears on the screen. * *-------------------------------------------------------------- */ static void DisplayScrollbar(clientData) ClientData clientData; /* Information about window. */ { register Scrollbar *scrollPtr = clientData; register Tk_Window tkwin = scrollPtr->tkwin; XPoint points[7]; Tk_3DBorder border; int relief, width, elementBorderWidth; Pixmap pixmap; Blt_Tile tile; if ((scrollPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { goto done; } if (scrollPtr->vertical) { width = Tk_Width(tkwin) - 2 * scrollPtr->inset; } else { width = Tk_Height(tkwin) - 2 * scrollPtr->inset; } elementBorderWidth = scrollPtr->elementBorderWidth; if (elementBorderWidth < 0) { elementBorderWidth = scrollPtr->borderWidth; } /* * In order to avoid screen flashes, this procedure redraws * the scrollbar in a pixmap, then copies the pixmap to the * screen in a single operation. This means that there's no * point in time where the on-sreen image has been cleared. */ pixmap = Tk_GetPixmap(scrollPtr->display, Tk_WindowId(tkwin), Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin)); if (scrollPtr->highlightWidth != 0) { GC gc; if (scrollPtr->flags & GOT_FOCUS) { gc = Tk_GCForColor(scrollPtr->highlightColorPtr, pixmap); } else { gc = Tk_GCForColor(scrollPtr->highlightBgColorPtr, pixmap); } Tk_DrawFocusHighlight(tkwin, gc, scrollPtr->highlightWidth, pixmap); } Blt_Draw3DRectangle(tkwin, pixmap, scrollPtr->bgBorder, scrollPtr->highlightWidth, scrollPtr->highlightWidth, Tk_Width(tkwin) - 2 * scrollPtr->highlightWidth, Tk_Height(tkwin) - 2 * scrollPtr->highlightWidth, scrollPtr->borderWidth, scrollPtr->relief); if (scrollPtr->tile != NULL) { Blt_SetTileOrigin(tkwin, scrollPtr->tile, 0, 0); Blt_TileRectangle(tkwin, pixmap, scrollPtr->tile, scrollPtr->inset, scrollPtr->inset, (unsigned)(Tk_Width(tkwin) - 2 * scrollPtr->inset), (unsigned)(Tk_Height(tkwin) - 2 * scrollPtr->inset)); } else { XFillRectangle(scrollPtr->display, pixmap, scrollPtr->troughGC, scrollPtr->inset, scrollPtr->inset, (unsigned)(Tk_Width(tkwin) - 2 * scrollPtr->inset), (unsigned)(Tk_Height(tkwin) - 2 * scrollPtr->inset)); } /* * Draw the top or left arrow. The coordinates of the polygon * points probably seem odd, but they were carefully chosen with * respect to X's rules for filling polygons. These point choices * cause the arrows to just fill the narrow dimension of the * scrollbar and be properly centered. */ tile = NULL; if (scrollPtr->activeField == TOP_ARROW) { border = scrollPtr->activeBorder; relief = scrollPtr->activeField == TOP_ARROW ? scrollPtr->activeRelief : TK_RELIEF_RAISED; if (scrollPtr->activeTile != NULL) { Blt_SetTileOrigin(tkwin, scrollPtr->activeTile, 0, 0); tile = scrollPtr->activeTile; } } else { border = scrollPtr->bgBorder; relief = TK_RELIEF_RAISED; if (scrollPtr->tile != NULL) { tile = scrollPtr->tile; } } if (scrollPtr->vertical) { points[0].x = scrollPtr->inset - 1; points[0].y = scrollPtr->arrowLength + scrollPtr->inset - 1; points[1].x = width + scrollPtr->inset; points[1].y = points[0].y; points[2].x = width / 2 + scrollPtr->inset; points[2].y = scrollPtr->inset - 1; } else { points[0].x = scrollPtr->arrowLength + scrollPtr->inset - 1; points[0].y = scrollPtr->inset - 1; points[1].x = scrollPtr->inset; points[1].y = width / 2 + scrollPtr->inset; points[2].x = points[0].x; points[2].y = width + scrollPtr->inset; } #ifdef notdef if (tile != NULL) { Blt_TilePolygon(tkwin, pixmap, tile, points, 3); Tk_Draw3DPolygon(tkwin, pixmap, border, points, 3, elementBorderWidth, relief); } else { Tk_Fill3DPolygon(tkwin, pixmap, border, points, 3, elementBorderWidth, relief); } #else Blt_Fill3DRectangle(tkwin, pixmap, border, scrollPtr->inset, scrollPtr->inset, width, width, elementBorderWidth, relief); Blt_DrawArrow(scrollPtr->display, pixmap, scrollPtr->copyGC, scrollPtr->inset + width / 2, scrollPtr->inset + width / 2, STD_ARROW_HEIGHT, (scrollPtr->vertical) ? ARROW_UP : ARROW_LEFT); #endif /* * Display the bottom or right arrow. */ tile = NULL; if (scrollPtr->activeField == BOTTOM_ARROW) { border = scrollPtr->activeBorder; relief = scrollPtr->activeField == BOTTOM_ARROW ? scrollPtr->activeRelief : TK_RELIEF_RAISED; if (scrollPtr->activeTile != NULL) { Blt_SetTileOrigin(tkwin, scrollPtr->activeTile, 0, 0); tile = scrollPtr->activeTile; } } else { border = scrollPtr->bgBorder; relief = TK_RELIEF_RAISED; if (scrollPtr->tile != NULL) { tile = scrollPtr->tile; } } if (scrollPtr->vertical) { points[0].x = scrollPtr->inset; points[0].y = Tk_Height(tkwin) - scrollPtr->arrowLength - scrollPtr->inset + 1; points[1].x = width / 2 + scrollPtr->inset; points[1].y = Tk_Height(tkwin) - scrollPtr->inset; points[2].x = width + scrollPtr->inset; points[2].y = points[0].y; } else { points[0].x = Tk_Width(tkwin) - scrollPtr->arrowLength - scrollPtr->inset + 1; points[0].y = scrollPtr->inset - 1; points[1].x = points[0].x; points[1].y = width + scrollPtr->inset; points[2].x = Tk_Width(tkwin) - scrollPtr->inset; points[2].y = width / 2 + scrollPtr->inset; } #ifdef notdef if (tile != NULL) { Blt_TilePolygon(tkwin, pixmap, tile, points, 3); Tk_Draw3DPolygon(tkwin, pixmap, border, points, 3, elementBorderWidth, relief); } else { Tk_Fill3DPolygon(tkwin, pixmap, border, points, 3, elementBorderWidth, relief); } #else Blt_Fill3DRectangle(tkwin, pixmap, border, Tk_Width(tkwin) - (width + scrollPtr->inset), Tk_Height(tkwin) - (width + scrollPtr->inset), width, width, elementBorderWidth, relief); Blt_DrawArrow(scrollPtr->display, pixmap, scrollPtr->copyGC, Tk_Width(tkwin) - (scrollPtr->inset + width / 2) - 1, Tk_Height(tkwin) - (scrollPtr->inset + width / 2) - 1, STD_ARROW_HEIGHT, (scrollPtr->vertical) ? ARROW_DOWN : ARROW_RIGHT); #endif /* * Display the slider. */ tile = NULL; if (scrollPtr->activeField == SLIDER) { border = scrollPtr->activeBorder; relief = scrollPtr->activeField == SLIDER ? scrollPtr->activeRelief : TK_RELIEF_RAISED; if (scrollPtr->activeTile != NULL) { Blt_SetTileOrigin(tkwin, scrollPtr->activeTile, 0, 0); tile = scrollPtr->activeTile; } } else { border = scrollPtr->bgBorder; relief = TK_RELIEF_RAISED; if (scrollPtr->tile != NULL) { tile = scrollPtr->tile; } } if (scrollPtr->vertical) { if (tile != NULL) { Blt_TileRectangle(tkwin, pixmap, tile, scrollPtr->inset, scrollPtr->sliderFirst, width - 1, scrollPtr->sliderLast - scrollPtr->sliderFirst - 1); Blt_Draw3DRectangle(tkwin, pixmap, border, scrollPtr->inset, scrollPtr->sliderFirst, width, scrollPtr->sliderLast - scrollPtr->sliderFirst, elementBorderWidth, relief); } else { Blt_Fill3DRectangle(tkwin, pixmap, border, scrollPtr->inset, scrollPtr->sliderFirst, width, scrollPtr->sliderLast - scrollPtr->sliderFirst, elementBorderWidth, relief); } } else { if (tile != NULL) { Blt_TileRectangle(tkwin, pixmap, tile, scrollPtr->sliderFirst, scrollPtr->inset, scrollPtr->sliderLast - scrollPtr->sliderFirst - 1, width - 1); Blt_Draw3DRectangle(tkwin, pixmap, border, scrollPtr->sliderFirst, scrollPtr->inset, scrollPtr->sliderLast - scrollPtr->sliderFirst, width, elementBorderWidth, relief); } else { Blt_Fill3DRectangle(tkwin, pixmap, border, scrollPtr->sliderFirst, scrollPtr->inset, scrollPtr->sliderLast - scrollPtr->sliderFirst, width, elementBorderWidth, relief); } } /* * Copy the information from the off-screen pixmap onto the screen, * then delete the pixmap. */ XCopyArea(scrollPtr->display, pixmap, Tk_WindowId(tkwin), scrollPtr->copyGC, 0, 0, (unsigned)Tk_Width(tkwin), (unsigned)Tk_Height(tkwin), 0, 0); Tk_FreePixmap(scrollPtr->display, pixmap); done: scrollPtr->flags &= ~REDRAW_PENDING; } /* *-------------------------------------------------------------- * * ScrollbarEventProc -- * * This procedure is invoked by the Tk dispatcher for various * events on scrollbars. * * Results: * None. * * Side effects: * When the window gets deleted, internal structures get * cleaned up. When it gets exposed, it is redisplayed. * *-------------------------------------------------------------- */ static void ScrollbarEventProc(clientData, eventPtr) ClientData clientData; /* Information about window. */ XEvent *eventPtr; /* Information about event. */ { Scrollbar *scrollPtr = clientData; if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) { EventuallyRedraw(scrollPtr); } else if (eventPtr->type == DestroyNotify) { if (scrollPtr->tkwin != NULL) { scrollPtr->tkwin = NULL; Tcl_DeleteCommandFromToken(scrollPtr->interp,scrollPtr->widgetCmd); } if (scrollPtr->flags & REDRAW_PENDING) { Tcl_CancelIdleCall(DisplayScrollbar, (ClientData)scrollPtr); } Tcl_EventuallyFree((ClientData)scrollPtr, (Tcl_FreeProc *)DestroyScrollbar); } else if (eventPtr->type == ConfigureNotify) { ComputeScrollbarGeometry(scrollPtr); EventuallyRedraw(scrollPtr); } else if (eventPtr->type == FocusIn) { if (eventPtr->xfocus.detail != NotifyInferior) { scrollPtr->flags |= GOT_FOCUS; if (scrollPtr->highlightWidth > 0) { EventuallyRedraw(scrollPtr); } } } else if (eventPtr->type == FocusOut) { if (eventPtr->xfocus.detail != NotifyInferior) { scrollPtr->flags &= ~GOT_FOCUS; if (scrollPtr->highlightWidth > 0) { EventuallyRedraw(scrollPtr); } } } } /* *---------------------------------------------------------------------- * * ScrollbarCmdDeletedProc -- * * This procedure is invoked when a widget command is deleted. If * the widget isn't already in the process of being destroyed, * this command destroys it. * * Results: * None. * * Side effects: * The widget is destroyed. * *---------------------------------------------------------------------- */ static void ScrollbarCmdDeletedProc(clientData) ClientData clientData; /* Pointer to widget record for widget. */ { Scrollbar *scrollPtr = clientData; Tk_Window tkwin = scrollPtr->tkwin; /* * This procedure could be invoked either because the window was * destroyed and the command was then deleted (in which case tkwin * is NULL) or because the command was deleted, and then this procedure * destroys the widget. */ if (tkwin != NULL) { #ifdef ITCL_NAMESPACES Itk_SetWidgetCommand(scrollPtr->tkwin, (Tcl_Command) NULL); #endif scrollPtr->tkwin = NULL; Tk_DestroyWindow(tkwin); } } /* *---------------------------------------------------------------------- * * ComputeScrollbarGeometry -- * * After changes in a scrollbar's size or configuration, this * procedure recomputes various geometry information used in * displaying the scrollbar. * * Results: * None. * * Side effects: * The scrollbar will be displayed differently. * *---------------------------------------------------------------------- */ static void ComputeScrollbarGeometry(scrollPtr) register Scrollbar *scrollPtr; /* Scrollbar whose geometry may * have changed. */ { int width, fieldLength; if (scrollPtr->highlightWidth < 0) { scrollPtr->highlightWidth = 0; } scrollPtr->inset = scrollPtr->highlightWidth + scrollPtr->borderWidth; width = (scrollPtr->vertical) ? Tk_Width(scrollPtr->tkwin) : Tk_Height(scrollPtr->tkwin); scrollPtr->arrowLength = width - 2 * scrollPtr->inset + 1; fieldLength = (scrollPtr->vertical ? Tk_Height(scrollPtr->tkwin) : Tk_Width(scrollPtr->tkwin)) - 2 * (scrollPtr->arrowLength + scrollPtr->inset); if (fieldLength < 0) { fieldLength = 0; } scrollPtr->sliderFirst = fieldLength * scrollPtr->firstFraction; scrollPtr->sliderLast = fieldLength * scrollPtr->lastFraction; /* * Adjust the slider so that some piece of it is always * displayed in the scrollbar and so that it has at least * a minimal width (so it can be grabbed with the mouse). */ if (scrollPtr->sliderFirst > (fieldLength - 2 * scrollPtr->borderWidth)) { scrollPtr->sliderFirst = fieldLength - 2 * scrollPtr->borderWidth; } if (scrollPtr->sliderFirst < 0) { scrollPtr->sliderFirst = 0; } if (scrollPtr->sliderLast < (scrollPtr->sliderFirst + MIN_SLIDER_LENGTH)) { scrollPtr->sliderLast = scrollPtr->sliderFirst + MIN_SLIDER_LENGTH; } if (scrollPtr->sliderLast > fieldLength) { scrollPtr->sliderLast = fieldLength; } scrollPtr->sliderFirst += scrollPtr->arrowLength + scrollPtr->inset; scrollPtr->sliderLast += scrollPtr->arrowLength + scrollPtr->inset; /* * Register the desired geometry for the window (leave enough space * for the two arrows plus a minimum-size slider, plus border around * the whole window, if any). Then arrange for the window to be * redisplayed. */ if (scrollPtr->vertical) { Tk_GeometryRequest(scrollPtr->tkwin, scrollPtr->width + 2 * scrollPtr->inset, 2 * (scrollPtr->arrowLength + scrollPtr->borderWidth + scrollPtr->inset)); } else { Tk_GeometryRequest(scrollPtr->tkwin, 2 * (scrollPtr->arrowLength + scrollPtr->borderWidth + scrollPtr->inset), scrollPtr->width + 2 * scrollPtr->inset); } Tk_SetInternalBorder(scrollPtr->tkwin, scrollPtr->inset); } /* *-------------------------------------------------------------- * * ScrollbarPosition -- * * Determine the scrollbar element corresponding to a * given position. * * Results: * One of TOP_ARROW, TOP_GAP, etc., indicating which element * of the scrollbar covers the position given by (x, y). If * (x,y) is outside the scrollbar entirely, then OUTSIDE is * returned. * * Side effects: * None. * *-------------------------------------------------------------- */ static int ScrollbarPosition(scrollPtr, x, y) register Scrollbar *scrollPtr; /* Scrollbar widget record. */ int x, y; /* Coordinates within scrollPtr's * window. */ { int length, width, tmp; if (scrollPtr->vertical) { length = Tk_Height(scrollPtr->tkwin); width = Tk_Width(scrollPtr->tkwin); } else { tmp = x; x = y; y = tmp; length = Tk_Width(scrollPtr->tkwin); width = Tk_Height(scrollPtr->tkwin); } if ((x < scrollPtr->inset) || (x >= (width - scrollPtr->inset)) || (y < scrollPtr->inset) || (y >= (length - scrollPtr->inset))) { return OUTSIDE; } /* * All of the calculations in this procedure mirror those in * DisplayScrollbar. Be sure to keep the two consistent. */ if (y < (scrollPtr->inset + scrollPtr->arrowLength)) { return TOP_ARROW; } if (y < scrollPtr->sliderFirst) { return TOP_GAP; } if (y < scrollPtr->sliderLast) { return SLIDER; } if (y >= (length - (scrollPtr->arrowLength + scrollPtr->inset))) { return BOTTOM_ARROW; } return BOTTOM_GAP; } /* *-------------------------------------------------------------- * * EventuallyRedraw -- * * Arrange for one or more of the fields of a scrollbar * to be redrawn. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static void EventuallyRedraw(scrollPtr) register Scrollbar *scrollPtr; /* Information about widget. */ { if ((scrollPtr->tkwin == NULL) || (!Tk_IsMapped(scrollPtr->tkwin))) { return; } if ((scrollPtr->flags & REDRAW_PENDING) == 0) { Tcl_DoWhenIdle(DisplayScrollbar, (ClientData)scrollPtr); scrollPtr->flags |= REDRAW_PENDING; } } int Blt_ScrollbarInit(interp) Tcl_Interp *interp; { static Blt_CmdSpec cmdSpec = { #if HAVE_NAMESPACES "scrollbar", ScrollbarCmd, #else "tilescrollbar", ScrollbarCmd, #endif /* HAVE_NAMESPACES */ }; if (Blt_InitCmd(interp, "blt::tile", &cmdSpec) == NULL) { return TCL_ERROR; } return TCL_OK; } #endif /* NO_TILESCROLLBAR */ blt-2.4z.orig/src/bltSpline.c0100644000175000017500000011543207515237461014653 0ustar dokodoko#include "bltInt.h" 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] static Tcl_CmdProc SplineCmd; /* * ----------------------------------------------------------------------- * * 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(points, nPoints, key, foundPtr) Point2D points[]; /* Contains the abscissas of the data * points of interpolation. */ int nPoints; /* Dimension of x. */ double key; /* Value whose relative position in * x is to be located. */ int *foundPtr; /* (out) Returns 1 if s is found in * x and 0 otherwise. */ { int high, low, mid; low = 0; high = nPoints - 1; while (high >= low) { 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(p, q, m1, m2, epsilon) Point2D *p; /* Coordinates of one of the points of * interpolation */ Point2D *q; /* Coordinates of one of the points of * interpolation */ double m1; /* Derivative condition at point P */ double m2; /* Derivative condition at point Q */ double epsilon; /* Error tolerance used to distinguish * cases when m1 or m2 is relatively * close to the slope or twice the * slope of the line segment joining * the points P and Q. If * epsilon is not 0.0, then epsilon * should be greater than or equal to * machine epsilon. */ { double slope; /* Calculate the slope of the line joining P and Q. */ slope = (q->y - p->y) / (q->x - p->x); if (slope != 0.0) { double relerr; double mref, mref1, mref2, prod1, prod2; prod1 = slope * m1; prod2 = slope * m2; /* Find the absolute values of the slopes slope, m1, and m2. */ mref = FABS(slope); mref1 = FABS(m1); mref2 = FABS(m2); /* * If the relative deviation of m1 or m2 from slope is less than * epsilon, then choose case 2 or case 3. */ relerr = epsilon * mref; if ((FABS(slope - m1) > relerr) && (FABS(slope - m2) > relerr) && (prod1 >= 0.0) && (prod2 >= 0.0)) { double prod; 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; } } /* * ----------------------------------------------------------------------- * * QuadCases -- * * 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(p, q, m1, m2, param, which) Point2D *p, *q; double m1, m2; double param[]; int which; { if ((which == 3) || (which == 4)) { /* Parameters used in both 3 and 4 */ double mbar1, mbar2, mbar3, c1, d1, h1, j1, k1; c1 = p->x + (q->y - p->y) / m1; d1 = q->x + (p->y - q->y) / m2; h1 = c1 * 2.0 - p->x; j1 = d1 * 2.0 - q->x; mbar1 = (q->y - p->y) / (h1 - p->x); 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; 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. */ 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. */ double ztwo; Z1 = (p->y - q->y + m2 * q->x - m1 * p->x) / (m2 - m1); 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(p, q, m1, m2, epsilon, param) Point2D *p, *q; double m1, m2; double epsilon; double param[]; { int ncase; ncase = QuadChoose(p, q, m1, m2, epsilon); QuadCases(p, q, m1, m2, param, ncase); return ncase; } /* * ----------------------------------------------------------------------- * * QuadGetImage -- * * ----------------------------------------------------------------------- */ INLINE static double QuadGetImage(p1, p2, p3, x1, x2, x3) double p1, p2, p3; double x1, x2, x3; { double A, B, C; double y; A = x1 - x2; B = x2 - x3; C = x1 - x3; y = (p1 * (A * A) + p2 * 2.0 * B * A + p3 * (B * B)) / (C * C); return y; } /* * ----------------------------------------------------------------------- * * QuadSpline -- * * 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). * * Results: * The image of the spline at x. * * ----------------------------------------------------------------------- */ static void QuadSpline(intp, left, right, param, ncase) Point2D *intp; /* Value at which spline is evaluated */ Point2D *left; /* Point to the left of the data point to * be evaluated */ Point2D *right; /* Point to the right of the data point to * be evaluated */ double param[]; /* Parameters of the spline */ int ncase; /* Controls the evaluation of the * spline by indicating whether one or * two knots were placed in the * interval (leftX,rightX) */ { 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; } /* * ----------------------------------------------------------------------- * * QuadSlopes -- * * 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. * * Results: * The output array "m" is filled with the derivates at each * data point. * * ----------------------------------------------------------------------- */ static void QuadSlopes(points, m, nPoints) Point2D points[]; double *m; /* (out) To be filled with the first * derivative at each data point. */ int nPoints; /* Number of data points (dimension of * x, y, and m). */ { double xbar, xmid, xhat, ydif1, ydif2; double yxmid; double m1, m2; double m1s, m2s; register int i, n, l; m1s = m2s = m1 = m2 = 0; 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. */ ydif1 = points[i].y - points[l].y; 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) { m1s = m1, m2s = m2; /* Save slopes of starting point */ } /* * 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. */ xbar = ydif2 / m1 + points[i].x; 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. */ xbar = -ydif1 / m2 + points[i].x; 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 { xmid = (points[i].x + points[n].x) / 2.0; 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 { xmid = (points[0].x + points[1].x) / 2.0; 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(origPts, nOrigPts, intpPts, nIntpPts, m, epsilon) Point2D origPts[]; int nOrigPts; Point2D intpPts[]; int nIntpPts; double *m; /* Slope of the spline at each point * of interpolation. */ double epsilon; /* Relative error tolerance (see choose) */ { int error; register int i, j; double param[10]; int ncase; int start, end; int l, p; register int n; int found; /* Initialize indices and set error result */ error = 0; l = nOrigPts - 1; p = l - 1; ncase = 1; /* * Determine if abscissas of new vector are non-decreasing. */ for (j = 1; j < nIntpPts; j++) { if (intpPts[j].x < intpPts[j - 1].x) { return 2; } } /* * Determine if any of the points in xval are LESS than the * abscissa of the first data point. */ for (start = 0; start < nIntpPts; start++) { if (intpPts[start].x >= origPts[0].x) { break; } } /* * Determine if any of the points in xval are GREATER than the * abscissa of the l data point. */ for (end = nIntpPts - 1; end >= 0; end--) { if (intpPts[end].x <= origPts[l].x) { break; } } if (start > 0) { error = 1; /* Set error value to indicate that * extrapolation has occurred. */ /* * 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 (j = 0; j < (start - 1); j++) { QuadSpline(intpPts + j, origPts, origPts + 1, param, ncase); } if (nIntpPts == 1) { return error; } } if ((nIntpPts == 1) && (end != (nIntpPts - 1))) { goto noExtrapolation; } /* * Search locates the interval in which the first in-range * point of evaluation lies. */ i = Search(origPts, nOrigPts, intpPts[start].x, &found); n = i + 1; if (n >= nOrigPts) { n = nOrigPts - 1; i = 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[i].y; start++; if (start >= nIntpPts) { return error; } } while (intpPts[start - 1].x == intpPts[start].x); for (;;) { if (intpPts[start].x < origPts[n].x) { break; /* Break out of for-loop */ } if (intpPts[start].x == origPts[n].x) { do { intpPts[start].y = origPts[n].y; start++; if (start >= nIntpPts) { return error; } } while (intpPts[start].x == intpPts[start - 1].x); } i++; n++; } } /* * Calculate the images of all the points which lie within * range of the data. */ if ((i > 0) || (error != 1)) { ncase = QuadSelect(origPts + i, origPts + n, m[i], m[n], epsilon, param); } for (j = start; j <= end; j++) { /* * 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[j].x == origPts[n].x) { intpPts[j].y = origPts[n].y; continue; } else if (intpPts[j].x > origPts[n].x) { double delta; /* Determine that the routine is in the correct part of the spline. */ do { i++, n++; delta = intpPts[j].x - origPts[n].x; } while (delta > 0.0); if (delta < 0.0) { ncase = QuadSelect(origPts + i, origPts + n, m[i], m[n], epsilon, param); } else if (delta == 0.0) { intpPts[j].y = origPts[n].y; continue; } } QuadSpline(intpPts + j, origPts + i, origPts + n, param, ncase); } if (end == (nIntpPts - 1)) { return error; } if ((n == l) && (intpPts[end].x != origPts[l].x)) { goto noExtrapolation; } error = 1; /* Set error value to indicate that * extrapolation has occurred. */ 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 (j = (end + 1); j < nIntpPts; j++) { QuadSpline(intpPts + j, origPts + p, origPts + l, param, ncase); } return error; } /* * ----------------------------------------------------------------------- * * Shape preserving quadratic splines * by D.F.Mcallister & J.A.Roulier * Coded by S.L.Dodd & M.Roulier * N.C.State University * * ----------------------------------------------------------------------- */ /* * Driver routine for quadratic spline package * On input-- * X,Y Contain n-long arrays of data (x is increasing) * XM Contains m-long array of x values (increasing) * eps Relative error tolerance * n Number of input data points * m Number of output data points * On output-- * work Contains the value of the first derivative at each data point * ym Contains the interpolated spline value at each data point */ int Blt_QuadraticSpline(origPts, nOrigPts, intpPts, nIntpPts) Point2D origPts[]; int nOrigPts; Point2D intpPts[]; int nIntpPts; { double epsilon; double *work; int result; work = Blt_Malloc(nOrigPts * sizeof(double)); assert(work); epsilon = 0.0; /* TBA: adjust error via command-line option */ /* allocate space for vectors used in calculation */ QuadSlopes(origPts, work, nOrigPts); result = QuadEval(origPts, nOrigPts, intpPts, nIntpPts, work, epsilon); Blt_Free(work); if (result > 1) { return FALSE; } return TRUE; } /* * ------------------------------------------------------------------------ * * Reference: * Numerical Analysis, R. Burden, J. Faires and A. Reynolds. * Prindle, Weber & Schmidt 1981 pp 112 * * Parameters: * origPts - vector of points, assumed to be sorted along x. * intpPts - vector of new points. * * ------------------------------------------------------------------------ */ int Blt_NaturalSpline(origPts, nOrigPts, intpPts, nIntpPts) Point2D origPts[]; int nOrigPts; Point2D intpPts[]; int nIntpPts; { Cubic2D *eq; Point2D *iPtr, *endPtr; TriDiagonalMatrix *A; double *dx; /* vector of deltas in x */ double x, dy, alpha; int isKnot; register int i, j, n; dx = Blt_Malloc(sizeof(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. */ A = Blt_Malloc(sizeof(TriDiagonalMatrix) * nOrigPts); if (A == NULL) { Blt_Free(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]; } eq = Blt_Malloc(sizeof(Cubic2D) * nOrigPts); if (eq == NULL) { Blt_Free(A); Blt_Free(dx); return FALSE; } 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]); } Blt_Free(A); Blt_Free(dx); endPtr = intpPts + nIntpPts; /* Now calculate the new values */ for (iPtr = intpPts; iPtr < endPtr; iPtr++) { iPtr->y = 0.0; x = iPtr->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) { iPtr->y = origPts[i].y; } else { i--; x -= origPts[i].x; iPtr->y = origPts[i].y + x * (eq[i].b + x * (eq[i].c + x * eq[i].d)); } } Blt_Free(eq); return TRUE; } static Blt_OpSpec splineOps[] = { {"natural", 1, (Blt_Op)Blt_NaturalSpline, 6, 6, "x y splx sply",}, {"quadratic", 1, (Blt_Op)Blt_QuadraticSpline, 6, 6, "x y splx sply",}, }; static int nSplineOps = sizeof(splineOps) / sizeof(Blt_OpSpec); /*ARGSUSED*/ static int SplineCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; int argc; char **argv; { Blt_Op proc; Blt_Vector *x, *y, *splX, *splY; double *xArr, *yArr; register int i; Point2D *origPts, *intpPts; int nOrigPts, nIntpPts; proc = Blt_GetOp(interp, nSplineOps, splineOps, BLT_OP_ARG1, argc, argv,0); if (proc == NULL) { return TCL_ERROR; } if ((Blt_GetVector(interp, argv[2], &x) != TCL_OK) || (Blt_GetVector(interp, argv[3], &y) != TCL_OK) || (Blt_GetVector(interp, argv[4], &splX) != TCL_OK)) { return TCL_ERROR; } nOrigPts = Blt_VecLength(x); if (nOrigPts < 3) { Tcl_AppendResult(interp, "length of vector \"", argv[2], "\" is < 3", (char *)NULL); return TCL_ERROR; } for (i = 1; i < nOrigPts; i++) { if (Blt_VecData(x)[i] < Blt_VecData(x)[i - 1]) { Tcl_AppendResult(interp, "x vector \"", argv[2], "\" must be monotonically increasing", (char *)NULL); return TCL_ERROR; } } /* Check that all the data points aren't the same. */ if (Blt_VecData(x)[i - 1] <= Blt_VecData(x)[0]) { Tcl_AppendResult(interp, "x vector \"", argv[2], "\" must be monotonically increasing", (char *)NULL); return TCL_ERROR; } if (nOrigPts != Blt_VecLength(y)) { Tcl_AppendResult(interp, "vectors \"", argv[2], "\" and \"", argv[3], " have different lengths", (char *)NULL); return TCL_ERROR; } nIntpPts = Blt_VecLength(splX); if (Blt_GetVector(interp, argv[5], &splY) != TCL_OK) { /* * If the named vector to hold the ordinates of the spline * doesn't exist, create one the same size as the vector * containing the abscissas. */ if (Blt_CreateVector(interp, argv[5], nIntpPts, &splY) != TCL_OK) { return TCL_ERROR; } } else if (nIntpPts != Blt_VecLength(splY)) { /* * The x and y vectors differ in size. Make the number of ordinates * the same as the number of abscissas. */ if (Blt_ResizeVector(splY, nIntpPts) != TCL_OK) { return TCL_ERROR; } } origPts = Blt_Malloc(sizeof(Point2D) * nOrigPts); if (origPts == NULL) { Tcl_AppendResult(interp, "can't allocate \"", Blt_Itoa(nOrigPts), "\" points", (char *)NULL); return TCL_ERROR; } intpPts = Blt_Malloc(sizeof(Point2D) * nIntpPts); if (intpPts == NULL) { Tcl_AppendResult(interp, "can't allocate \"", Blt_Itoa(nIntpPts), "\" points", (char *)NULL); Blt_Free(origPts); return TCL_ERROR; } xArr = Blt_VecData(x); yArr = Blt_VecData(y); for (i = 0; i < nOrigPts; i++) { origPts[i].x = xArr[i]; origPts[i].y = yArr[i]; } xArr = Blt_VecData(splX); yArr = Blt_VecData(splY); for (i = 0; i < nIntpPts; i++) { intpPts[i].x = xArr[i]; intpPts[i].y = yArr[i]; } if (!(*proc) (origPts, nOrigPts, intpPts, nIntpPts)) { Tcl_AppendResult(interp, "error generating spline for \"", Blt_NameOfVector(splY), "\"", (char *)NULL); Blt_Free(origPts); Blt_Free(intpPts); return TCL_ERROR; } yArr = Blt_VecData(splY); for (i = 0; i < nIntpPts; i++) { yArr[i] = intpPts[i].y; } Blt_Free(origPts); Blt_Free(intpPts); /* Finally update the vector. The size of the vector hasn't * changed, just the data. Reset the vector using TCL_STATIC to * indicate this. */ if (Blt_ResetVector(splY, Blt_VecData(splY), Blt_VecLength(splY), Blt_VecSize(splY), TCL_STATIC) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } int Blt_SplineInit(interp) Tcl_Interp *interp; { static Blt_CmdSpec cmdSpec = {"spline", SplineCmd,}; if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) { return TCL_ERROR; } return TCL_OK; } #define SQR(x) ((x)*(x)) 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(A, n) TriDiagonalMatrix A[]; int n; { int i; double m_ij, m_n, m_nn, d; if (n < 1) { return FALSE; /* Dimension should be at least 1 */ } d = A[0][1]; /* D_{0,0} = A_{0,0} */ if (d <= 0.0) { return FALSE; /* 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 FALSE; /* 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 FALSE; } } return TRUE; } /* * 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(A, spline, nIntervals) TriDiagonalMatrix A[]; CubicSpline spline[]; int nIntervals; { int i; double x, y; int n, m; n = nIntervals - 2; m = nIntervals - 1; /* Division by transpose of C : b = C^{-T} * b */ x = spline[m].x; y = spline[m].y; for (i = 0; i < n; i++) { spline[i + 1].x -= A[i][2] * spline[i].x; /* C_{i,i+1} * x(i) */ spline[i + 1].y -= A[i][2] * spline[i].y; /* C_{i,i+1} * x(i) */ x -= A[i][0] * spline[i].x; /* C_{i,n-1} * x(i) */ y -= A[i][0] * spline[i].y; /* C_{i,n-1} * x(i) */ } if (n >= 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 (i = 0; i < nIntervals; i++) { spline[i].x /= A[i][1]; spline[i].y /= A[i][1]; } /* Division by C: b = C^{-1} * b */ x = spline[m].x; y = spline[m].y; if (n >= 0) { /* C_{n-2,n-1} * x_{n-1} */ spline[n].x -= A[n][0] * x; spline[n].y -= A[n][0] * y; } for (i = (n - 1); i >= 0; i--) { /* C_{i,i+1} * x_{i+1} + C_{i,n-1} * x_{n-1} */ spline[i].x -= A[i][2] * spline[i + 1].x + A[i][0] * x; spline[i].y -= A[i][2] * spline[i + 1].y + A[i][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(points, nPoints, isClosed, unitX, unitY) Point2D points[]; int nPoints; /* Number of points (nPoints>=3) */ int isClosed; /* CLOSED_CONTOUR or OPEN_CONTOUR */ double unitX, unitY; /* Unit length in x and y (norm=1) */ { CubicSpline *spline; register CubicSpline *s1, *s2; int n, i; double norm, dx, dy; TriDiagonalMatrix *A; /* The tri-diagonal matrix is saved here. */ spline = Blt_Malloc(sizeof(CubicSpline) * nPoints); if (spline == NULL) { return NULL; } A = Blt_Malloc(sizeof(TriDiagonalMatrix) * nPoints); if (A == NULL) { Blt_Free(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 ... */ Blt_Free(A); Blt_Free(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; } Blt_Free( 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(origPts, nOrigPts, intpPts, nIntpPts, spline) Point2D origPts[]; int nOrigPts; Point2D intpPts[]; int nIntpPts; CubicSpline spline[]; { double t, tSkip, tMax; Point2D p, q; double d, hx, dx0, dx01, hy, dy0, dy01; register int i, j, count; /* Sum the lengths of all the segments (intervals). */ tMax = 0.0; for (i = 0; i < nOrigPts - 1; i++) { tMax += spline[i].t; } /* Need a better way of doing this... */ /* The distance between interpolated points */ tSkip = (1. - 1e-7) * tMax / (nIntpPts - 1); t = 0.0; /* Spline parameter value. */ q = origPts[0]; count = 0; intpPts[count++] = q; /* First point. */ t += tSkip; for (i = 0, j = 1; j < nOrigPts; i++, j++) { d = spline[i].t; /* Interval length */ p = q; q = origPts[i+1]; hx = (q.x - p.x) / d; hy = (q.y - p.y) / d; dx0 = (spline[j].x + 2 * spline[i].x) / 6.0; dy0 = (spline[j].y + 2 * spline[i].y) / 6.0; dx01 = (spline[j].x - spline[i].x) / (6.0 * d); dy01 = (spline[j].y - spline[i].y) / (6.0 * d); while (t <= spline[i].t) { /* t in current interval ? */ p.x += t * (hx + (t - d) * (dx0 + t * dx01)); p.y += t * (hy + (t - d) * (dy0 + t * dy01)); intpPts[count++] = p; t += tSkip; } /* Parameter t relative to start of next interval */ t -= spline[i].t; } return count; } /* * Generate a cubic spline curve through the points (x_i,y_i) which are * stored in the linked list p_cntr. * The spline is defined as a 2d-function s(t) = (x(t),y(t)), where the * parameter t is the length of the linear stroke. */ int Blt_NaturalParametricSpline(origPts, nOrigPts, extsPtr, isClosed, intpPts, nIntpPts) Point2D origPts[]; int nOrigPts; Extents2D *extsPtr; int isClosed; Point2D *intpPts; int nIntpPts; { double unitX, unitY; /* To define norm (x,y)-plane */ CubicSpline *spline; int result; if (nOrigPts < 3) { return 0; } if (isClosed) { origPts[nOrigPts].x = origPts[0].x; origPts[nOrigPts].y = origPts[0].y; nOrigPts++; } /* Width and height of the grid is used at unit length (2d-norm) */ unitX = extsPtr->right - extsPtr->left; 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, */ spline = CubicSlopes(origPts, nOrigPts, isClosed, unitX, unitY); if (spline == NULL) { return 0; } result= CubicEval(origPts, nOrigPts, intpPts, nIntpPts, spline); Blt_Free(spline); return result; } static void CatromCoeffs(p, a, b, c, d) Point2D *p; Point2D *a, *b, *c, *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; } /* *---------------------------------------------------------------------- * * Blt_ParametricCatromSpline -- * * Computes a spline based upon the data points, returning a new * (larger) coordinate array or points. * * Results: * None. * *---------------------------------------------------------------------- */ int Blt_CatromParametricSpline(points, nPoints, intpPts, nIntpPts) Point2D *points; int nPoints; Point2D *intpPts; int nIntpPts; { register int i; Point2D *origPts; double t; int interval; Point2D a, b, c, d; assert(nPoints > 0); /* * 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. */ origPts = Blt_Malloc((nPoints + 4) * sizeof(Point2D)); memcpy(origPts + 1, points, sizeof(Point2D) * nPoints); origPts[0] = origPts[1]; origPts[nPoints + 2] = origPts[nPoints + 1] = origPts[nPoints]; for (i = 0; i < nIntpPts; i++) { interval = (int)intpPts[i].x; t = intpPts[i].y; assert(interval < nPoints); CatromCoeffs(origPts + interval, &a, &b, &c, &d); intpPts[i].x = (d.x + t * (c.x + t * (b.x + t * a.x))) / 2.0; intpPts[i].y = (d.y + t * (c.y + t * (b.y + t * a.y))) / 2.0; } Blt_Free(origPts); return 1; } blt-2.4z.orig/src/bltSwitch.c0100644000175000017500000003524507505147041014656 0ustar dokodoko/* * bltSwitch.c -- * * This module implements command/argument switch parsing * procedures for the BLT toolkit. * * Copyright 1991-1998 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. */ #include "bltInt.h" #if defined(__STDC__) #include #else #include #endif #include "bltSwitch.h" /* *-------------------------------------------------------------- * * FindSwitchSpec -- * * Search through a table of configuration specs, looking for * one that matches a given argvName. * * Results: * The return value is a pointer to the matching entry, or NULL * if nothing matched. In that case an error message is left * in the interp's result. * * Side effects: * None. * *-------------------------------------------------------------- */ static Blt_SwitchSpec * FindSwitchSpec(interp, specs, name, needFlags, hateFlags) Tcl_Interp *interp; /* Used for reporting errors. */ Blt_SwitchSpec *specs; /* Pointer to table of configuration * specifications for a widget. */ char *name; /* Name (suitable for use in a "switch" * command) identifying particular option. */ int needFlags; /* Flags that must be present in matching * entry. */ int hateFlags; /* Flags that must NOT be present in * matching entry. */ { register Blt_SwitchSpec *specPtr; register char c; /* First character of current argument. */ Blt_SwitchSpec *matchPtr; /* Matching spec, or NULL. */ size_t length; c = name[1]; length = strlen(name); matchPtr = NULL; for (specPtr = specs; specPtr->type != BLT_SWITCH_END; specPtr++) { if (specPtr->switchName == NULL) { continue; } if ((specPtr->switchName[1] != c) || (strncmp(specPtr->switchName, name, length) != 0)) { continue; } if (((specPtr->flags & needFlags) != needFlags) || (specPtr->flags & hateFlags)) { continue; } if (specPtr->switchName[length] == 0) { return specPtr; /* Stop on a perfect match. */ } if (matchPtr != NULL) { Tcl_AppendResult(interp, "ambiguous option \"", name, "\"", (char *) NULL); return (Blt_SwitchSpec *) NULL; } matchPtr = specPtr; } if (matchPtr == NULL) { Tcl_AppendResult(interp, "unknown option \"", name, "\"", (char *)NULL); return (Blt_SwitchSpec *) NULL; } return matchPtr; } /* *-------------------------------------------------------------- * * DoSwitch -- * * This procedure applies a single configuration option * to a widget record. * * Results: * A standard Tcl return value. * * Side effects: * WidgRec is modified as indicated by specPtr and value. * The old value is recycled, if that is appropriate for * the value type. * *-------------------------------------------------------------- */ static int DoSwitch(interp, specPtr, string, record) Tcl_Interp *interp; /* Interpreter for error reporting. */ Blt_SwitchSpec *specPtr; /* Specifier to apply. */ char *string; /* Value to use to fill in widgRec. */ ClientData record; /* Record whose fields are to be * modified. Values must be properly * initialized. */ { char *ptr; int isNull; int count; isNull = ((*string == '\0') && (specPtr->flags & BLT_SWITCH_NULL_OK)); do { ptr = (char *)record + specPtr->offset; switch (specPtr->type) { case BLT_SWITCH_BOOLEAN: if (Tcl_GetBoolean(interp, string, (int *)ptr) != TCL_OK) { return TCL_ERROR; } break; case BLT_SWITCH_INT: if (Tcl_GetInt(interp, string, (int *)ptr) != TCL_OK) { return TCL_ERROR; } break; case BLT_SWITCH_INT_NONNEGATIVE: if (Tcl_GetInt(interp, string, &count) != TCL_OK) { return TCL_ERROR; } if (count < 0) { Tcl_AppendResult(interp, "bad value \"", string, "\": ", "can't be negative", (char *)NULL); return TCL_ERROR; } *((int *)ptr) = count; break; case BLT_SWITCH_INT_POSITIVE: if (Tcl_GetInt(interp, string, &count) != TCL_OK) { return TCL_ERROR; } if (count <= 0) { Tcl_AppendResult(interp, "bad value \"", string, "\": ", "must be positive", (char *)NULL); return TCL_ERROR; } *((int *)ptr) = count; break; case BLT_SWITCH_DOUBLE: if (Tcl_GetDouble(interp, string, (double *)ptr) != TCL_OK) { return TCL_ERROR; } break; case BLT_SWITCH_STRING: { char *old, *new, **strPtr; strPtr = (char **)ptr; if (isNull) { new = NULL; } else { new = Blt_Strdup(string); } old = *strPtr; if (old != NULL) { Blt_Free(old); } *strPtr = new; } break; case BLT_SWITCH_LIST: if (Tcl_SplitList(interp, string, &count, (char ***)ptr) != TCL_OK) { return TCL_ERROR; } break; case BLT_SWITCH_CUSTOM: if ((*specPtr->customPtr->parseProc) \ (specPtr->customPtr->clientData, interp, specPtr->switchName, string, record, specPtr->offset) != TCL_OK) { return TCL_ERROR; } break; default: Tcl_AppendResult(interp, "bad switch table: unknown type \"", Blt_Itoa(specPtr->type), "\"", (char *)NULL); return TCL_ERROR; } specPtr++; } while ((specPtr->switchName == NULL) && (specPtr->type != BLT_SWITCH_END)); return TCL_OK; } /* *-------------------------------------------------------------- * * Blt_ProcessSwitches -- * * Process command-line options and database options to * fill in fields of a widget record with resources and * other parameters. * * Results: * Returns the number of arguments comsumed by parsing the * command line. If an error occurred, -1 will be returned * and an error messages can be found as the interpreter * result. * * Side effects: * The fields of widgRec get filled in with information * from argc/argv and the option database. Old information * in widgRec's fields gets recycled. * *-------------------------------------------------------------- */ int Blt_ProcessSwitches(interp, specs, argc, argv, record, flags) Tcl_Interp *interp; /* Interpreter for error reporting. */ Blt_SwitchSpec *specs; /* Describes legal options. */ int argc; /* Number of elements in argv. */ char **argv; /* Command-line options. */ char *record; /* Record whose fields are to be * modified. Values must be properly * initialized. */ int flags; /* Used to specify additional flags * that must be present in switch specs * for them to be considered. Also, * may have BLT_SWITCH_ARGV_ONLY set. */ { register int count; char *arg; register Blt_SwitchSpec *specPtr; int needFlags; /* Specs must contain this set of flags * or else they are not considered. */ int hateFlags; /* If a spec contains any bits here, it's * not considered. */ needFlags = flags & ~(BLT_SWITCH_USER_BIT - 1); hateFlags = 0; /* * Pass 1: Clear the change flags on all the specs so that we * can check it later. */ for (specPtr = specs; specPtr->type != BLT_SWITCH_END; specPtr++) { specPtr->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. */ for (count = 0; count < argc; count++) { arg = argv[count]; if (flags & BLT_SWITCH_OBJV_PARTIAL) { if ((arg[0] != '-') || ((arg[1] == '-') && (argv[2] == '\0'))) { /* * If the argument doesn't start with a '-' (not a switch) * or is '--', stop processing and return the number of * arguments comsumed. */ return count; } } specPtr = FindSwitchSpec(interp, specs, arg, needFlags, hateFlags); if (specPtr == NULL) { return -1; } if (specPtr->type == BLT_SWITCH_FLAG) { char *ptr; ptr = record + specPtr->offset; *((int *)ptr) |= specPtr->value; } else if (specPtr->type == BLT_SWITCH_VALUE) { char *ptr; ptr = record + specPtr->offset; *((int *)ptr) = specPtr->value; } else { if ((count + 1) == argc) { Tcl_AppendResult(interp, "value for \"", arg, "\" missing", (char *) NULL); return -1; } count++; if (DoSwitch(interp, specPtr, argv[count], record) != TCL_OK) { char msg[100]; sprintf(msg, "\n (processing \"%.40s\" option)", specPtr->switchName); Tcl_AddErrorInfo(interp, msg); return -1; } } specPtr->flags |= BLT_SWITCH_SPECIFIED; } return count; } #if (TCL_VERSION_NUMBER >= _VERSION(8,0,0)) /* *-------------------------------------------------------------- * * Blt_ProcessObjSwitches -- * * Process command-line options and database options to * fill in fields of a widget record with resources and * other parameters. * * Results: * Returns the number of arguments comsumed by parsing the * command line. If an error occurred, -1 will be returned * and an error messages can be found as the interpreter * result. * * Side effects: * The fields of widgRec get filled in with information * from argc/argv and the option database. Old information * in widgRec's fields gets recycled. * *-------------------------------------------------------------- */ int Blt_ProcessObjSwitches(interp, specs, objc, objv, record, flags) Tcl_Interp *interp; /* Interpreter for error reporting. */ Blt_SwitchSpec *specs; /* Describes legal options. */ int objc; /* Number of elements in argv. */ Tcl_Obj *CONST *objv; /* Command-line options. */ char *record; /* Record whose fields are to be * modified. Values must be properly * initialized. */ int flags; /* Used to specify additional flags * that must be present in switch specs * for them to be considered. Also, * may have BLT_SWITCH_ARGV_ONLY set. */ { register Blt_SwitchSpec *specPtr; register int count; int needFlags; /* Specs must contain this set of flags * or else they are not considered. */ int hateFlags; /* If a spec contains any bits here, it's * not considered. */ needFlags = flags & ~(BLT_SWITCH_USER_BIT - 1); hateFlags = 0; /* * Pass 1: Clear the change flags on all the specs so that we * can check it later. */ for (specPtr = specs; specPtr->type != BLT_SWITCH_END; specPtr++) { specPtr->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. */ for (count = 0; count < objc; count++) { char *arg; arg = Tcl_GetString(objv[count]); if (flags & BLT_SWITCH_OBJV_PARTIAL) { if ((arg[0] != '-') || ((arg[1] == '-') && (arg[2] == '\0'))) { /* * If the argument doesn't start with a '-' (not a switch) * or is '--', stop processing and return the number of * arguments comsumed. */ return count; } } specPtr = FindSwitchSpec(interp, specs, arg, needFlags, hateFlags); if (specPtr == NULL) { return -1; } if (specPtr->type == BLT_SWITCH_FLAG) { char *ptr; ptr = record + specPtr->offset; *((int *)ptr) |= specPtr->value; } else if (specPtr->type == BLT_SWITCH_VALUE) { char *ptr; ptr = record + specPtr->offset; *((int *)ptr) = specPtr->value; } else { count++; if (count == objc) { Tcl_AppendResult(interp, "value for \"", arg, "\" missing", (char *) NULL); return -1; } arg = Tcl_GetString(objv[count]); if (DoSwitch(interp, specPtr, arg, record) != TCL_OK) { char msg[100]; sprintf(msg, "\n (processing \"%.40s\" option)", specPtr->switchName); Tcl_AddErrorInfo(interp, msg); return -1; } } specPtr->flags |= BLT_SWITCH_SPECIFIED; } return count; } #endif /* *---------------------------------------------------------------------- * * Blt_FreeSwitches -- * * Free up all resources associated with switch options. * * Results: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ void Blt_FreeSwitches(specs, record, needFlags) Blt_SwitchSpec *specs; /* Describes legal options. */ char *record; /* Record whose fields contain current * values for options. */ int needFlags; /* Used to specify additional flags * that must be present in config specs * for them to be considered. */ { register Blt_SwitchSpec *specPtr; for (specPtr = specs; specPtr->type != BLT_SWITCH_END; specPtr++) { if ((specPtr->flags & needFlags) == needFlags) { char *ptr; ptr = record + specPtr->offset; switch (specPtr->type) { case BLT_SWITCH_STRING: case BLT_SWITCH_LIST: if (*((char **) ptr) != NULL) { Blt_Free(*((char **) ptr)); *((char **) ptr) = NULL; } break; case BLT_SWITCH_CUSTOM: if ((*(char **)ptr != NULL) && (specPtr->customPtr->freeProc != NULL)) { (*specPtr->customPtr->freeProc)(*(char **)ptr); *((char **) ptr) = NULL; } break; default: break; } } } } /* *---------------------------------------------------------------------- * * Blt_SwitchModified -- * * Given the configuration specifications and one or more option * patterns (terminated by a NULL), indicate if any of the matching * configuration options has been reset. * * Results: * Returns 1 if one of the options has changed, 0 otherwise. * *---------------------------------------------------------------------- */ int Blt_SwitchChanged TCL_VARARGS_DEF(Blt_SwitchSpec *, arg1) { va_list argList; Blt_SwitchSpec *specs; register Blt_SwitchSpec *specPtr; register char *switchName; specs = TCL_VARARGS_START(Blt_SwitchSpec *, arg1, argList); while ((switchName = va_arg(argList, char *)) != NULL) { for (specPtr = specs; specPtr->type != BLT_SWITCH_END; specPtr++) { if ((Tcl_StringMatch(specPtr->switchName, switchName)) && (specPtr->flags & BLT_SWITCH_SPECIFIED)) { va_end(argList); return 1; } } } va_end(argList); return 0; } blt-2.4z.orig/src/bltSwitch.h0100644000175000017500000000542007542177233014662 0ustar dokodoko#ifdef offsetof #define Blt_Offset(type, field) ((int) offsetof(type, field)) #else #define Blt_Offset(type, field) ((int) ((char *) &((type *) 0)->field)) #endif typedef int (Blt_SwitchParseProc) _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, char *switchName, char *value, char *record, int offset)); typedef void (Blt_SwitchFreeProc) _ANSI_ARGS_((char *ptr)); 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_INT, BLT_SWITCH_INT_POSITIVE, BLT_SWITCH_INT_NONNEGATIVE, BLT_SWITCH_DOUBLE, BLT_SWITCH_STRING, BLT_SWITCH_LIST, BLT_SWITCH_FLAG, 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. */ char *switchName; /* Switch used to specify option in argv. * NULL means this spec is part of a group. */ 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. */ 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. */ int value; } Blt_SwitchSpec; #define BLT_SWITCH_ARGV_ONLY (1<<0) #define BLT_SWITCH_OBJV_ONLY (1<<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) extern int Blt_ProcessSwitches _ANSI_ARGS_((Tcl_Interp *interp, Blt_SwitchSpec *specs, int argc, char **argv, char *record, int flags)); extern void Blt_FreeSwitches _ANSI_ARGS_((Blt_SwitchSpec *specs, char *record, int flags)); extern int Blt_SwitchChanged _ANSI_ARGS_(TCL_VARARGS(Blt_SwitchSpec *, specs)); #if (TCL_VERSION_NUMBER >= _VERSION(8,0,0)) extern int Blt_ProcessObjSwitches _ANSI_ARGS_((Tcl_Interp *interp, Blt_SwitchSpec *specPtr, int objc, Tcl_Obj *CONST *objv, char *record, int flags)); #endif blt-2.4z.orig/src/bltTable.c0100644000175000017500000044131407552651714014453 0ustar dokodoko/* * bltTable.c -- * * This module implements a table-based geometry manager * for the BLT toolkit. * * Copyright 1993-1998 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. * * The "table" geometry manager was created by George Howlett. */ /* * To do: * * 3) No way to detect if widget is already a container of another * geometry manager. This one is especially bad with toplevel * widgets, causing the window manager to lock-up trying to handle the * myriads of resize requests. * * Note: This problem continues in Tk 8.x. It's possible for a widget * to be a container for two different geometry managers. Each manager * will set its own requested geometry for the container widget. The * winner sets the geometry last (sometimes ad infinitum). * * 7) Relative sizing of partitions? * */ #include "bltInt.h" #include "bltTable.h" #define TABLE_THREAD_KEY "BLT Table Data" #define TABLE_DEF_PAD 0 /* * Default values for widget attributes. */ #define DEF_TABLE_ANCHOR "center" #define DEF_TABLE_COLUMNS "0" #define DEF_TABLE_FILL "none" #define DEF_TABLE_PAD "0" #define DEF_TABLE_PROPAGATE "1" #define DEF_TABLE_RESIZE "both" #define DEF_TABLE_ROWS "0" #define DEF_TABLE_SPAN "1" #define DEF_TABLE_CONTROL "normal" #define DEF_TABLE_WEIGHT "1.0" #define ENTRY_DEF_PAD 0 #define ENTRY_DEF_ANCHOR TK_ANCHOR_CENTER #define ENTRY_DEF_FILL FILL_NONE #define ENTRY_DEF_SPAN 1 #define ENTRY_DEF_CONTROL CONTROL_NORMAL #define ENTRY_DEF_IPAD 0 #define ROWCOL_DEF_RESIZE (RESIZE_BOTH | RESIZE_VIRGIN) #define ROWCOL_DEF_PAD 0 #define ROWCOL_DEF_WEIGHT 1.0 static Blt_Uid rowUid, columnUid; static void WidgetGeometryProc _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin)); static void WidgetCustodyProc _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin)); static Tk_GeomMgr tableMgrInfo = { "table", /* Name of geometry manager used by winfo */ WidgetGeometryProc, /* Procedure to for new geometry requests */ WidgetCustodyProc, /* Procedure when widget is taken away */ }; static int StringToLimits _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *string, char *widgRec, int offset)); static char *LimitsToString _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, char *widgRec, int offset, Tcl_FreeProc **freeProcPtr)); static Tk_CustomOption limitsOption = { StringToLimits, LimitsToString, (ClientData)0 }; static int StringToResize _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *string, char *widgRec, int offset)); static char *ResizeToString _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, char *widgRec, int offset, Tcl_FreeProc **freeProcPtr)); static Tk_CustomOption resizeOption = { StringToResize, ResizeToString, (ClientData)0 }; static int StringToControl _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *string, char *widgRec, int offset)); static char *ControlToString _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, char *widgRec, int offset, Tcl_FreeProc **freeProcPtr)); static Tk_CustomOption controlOption = { StringToControl, ControlToString, (ClientData)0 }; extern Tk_CustomOption bltPadOption; extern Tk_CustomOption bltFillOption; extern Tk_CustomOption bltDistanceOption; static Tk_ConfigSpec rowConfigSpecs[] = { {TK_CONFIG_CUSTOM, "-height", (char *)NULL, (char *)NULL, (char *)NULL, Tk_Offset(RowColumn, reqSize), TK_CONFIG_NULL_OK, &limitsOption}, {TK_CONFIG_CUSTOM, "-pady", (char *)NULL, (char *)NULL, DEF_TABLE_PAD, Tk_Offset(RowColumn, pad), TK_CONFIG_DONT_SET_DEFAULT, &bltPadOption}, {TK_CONFIG_CUSTOM, "-resize", (char *)NULL, (char *)NULL, DEF_TABLE_RESIZE, Tk_Offset(RowColumn, resize), TK_CONFIG_DONT_SET_DEFAULT, &resizeOption}, {TK_CONFIG_DOUBLE, "-weight", (char *)NULL, (char *)NULL, DEF_TABLE_WEIGHT, Tk_Offset(RowColumn, weight), TK_CONFIG_NULL_OK | TK_CONFIG_DONT_SET_DEFAULT, &limitsOption}, {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} }; static Tk_ConfigSpec columnConfigSpecs[] = { {TK_CONFIG_CUSTOM, "-padx", (char *)NULL, (char *)NULL, DEF_TABLE_PAD, Tk_Offset(RowColumn, pad), TK_CONFIG_DONT_SET_DEFAULT, &bltPadOption}, {TK_CONFIG_CUSTOM, "-resize", (char *)NULL, (char *)NULL, DEF_TABLE_RESIZE, Tk_Offset(RowColumn, resize), TK_CONFIG_DONT_SET_DEFAULT, &resizeOption}, {TK_CONFIG_DOUBLE, "-weight", (char *)NULL, (char *)NULL, DEF_TABLE_WEIGHT, Tk_Offset(RowColumn, weight), TK_CONFIG_NULL_OK | TK_CONFIG_DONT_SET_DEFAULT, &limitsOption}, {TK_CONFIG_CUSTOM, "-width", (char *)NULL, (char *)NULL, (char *)NULL, Tk_Offset(RowColumn, reqSize), TK_CONFIG_NULL_OK, &limitsOption}, {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} }; static Tk_ConfigSpec entryConfigSpecs[] = { {TK_CONFIG_ANCHOR, "-anchor", (char *)NULL, (char *)NULL, DEF_TABLE_ANCHOR, Tk_Offset(Entry, anchor), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_INT, "-columnspan", "columnSpan", (char *)NULL, DEF_TABLE_SPAN, Tk_Offset(Entry, column.span), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-columncontrol", "columnControl", (char *)NULL, DEF_TABLE_CONTROL, Tk_Offset(Entry, column.control), TK_CONFIG_DONT_SET_DEFAULT, &controlOption}, {TK_CONFIG_SYNONYM, "-cspan", "columnSpan", (char *)NULL, (char *)NULL, Tk_Offset(Entry, column.span), 0}, {TK_CONFIG_SYNONYM, "-ccontrol", "columnControl", (char *)NULL, (char *)NULL, Tk_Offset(Entry, column.control), 0}, {TK_CONFIG_CUSTOM, "-fill", (char *)NULL, (char *)NULL, DEF_TABLE_FILL, Tk_Offset(Entry, fill), TK_CONFIG_DONT_SET_DEFAULT, &bltFillOption}, {TK_CONFIG_SYNONYM, "-height", "reqHeight", (char *)NULL, (char *)NULL, Tk_Offset(Entry, reqHeight), 0}, {TK_CONFIG_CUSTOM, "-padx", (char *)NULL, (char *)NULL, (char *)NULL, Tk_Offset(Entry, padX), 0, &bltPadOption}, {TK_CONFIG_CUSTOM, "-pady", (char *)NULL, (char *)NULL, (char *)NULL, Tk_Offset(Entry, padY), 0, &bltPadOption}, {TK_CONFIG_CUSTOM, "-ipadx", (char *)NULL, (char *)NULL, (char *)NULL, Tk_Offset(Entry, ipadX), 0, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-ipady", (char *)NULL, (char *)NULL, (char *)NULL, Tk_Offset(Entry, ipadY), 0, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-reqheight", "reqHeight", (char *)NULL, (char *)NULL, Tk_Offset(Entry, reqHeight), TK_CONFIG_NULL_OK, &limitsOption}, {TK_CONFIG_CUSTOM, "-reqwidth", "reqWidth", (char *)NULL, (char *)NULL, Tk_Offset(Entry, reqWidth), TK_CONFIG_NULL_OK, &limitsOption}, {TK_CONFIG_INT, "-rowspan", "rowSpan", (char *)NULL, DEF_TABLE_SPAN, Tk_Offset(Entry, row.span), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-rowcontrol", "rowControl", (char *)NULL, DEF_TABLE_CONTROL, Tk_Offset(Entry, row.control), TK_CONFIG_DONT_SET_DEFAULT, &controlOption}, {TK_CONFIG_SYNONYM, "-rspan", "rowSpan", (char *)NULL, (char *)NULL, Tk_Offset(Entry, row.span), 0}, {TK_CONFIG_SYNONYM, "-rcontrol", "rowControl", (char *)NULL, (char *)NULL, Tk_Offset(Entry, row.control), 0}, {TK_CONFIG_SYNONYM, "-width", "reqWidth", (char *)NULL, (char *)NULL, Tk_Offset(Entry, reqWidth), 0}, {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} }; static Tk_ConfigSpec tableConfigSpecs[] = { {TK_CONFIG_CUSTOM, "-padx", (char *)NULL, (char *)NULL, DEF_TABLE_PAD, Tk_Offset(Table, padX), TK_CONFIG_DONT_SET_DEFAULT, &bltPadOption}, {TK_CONFIG_CUSTOM, "-pady", (char *)NULL, (char *)NULL, DEF_TABLE_PAD, Tk_Offset(Table, padY), TK_CONFIG_DONT_SET_DEFAULT, &bltPadOption}, {TK_CONFIG_BOOLEAN, "-propagate", (char *)NULL, (char *)NULL, DEF_TABLE_PROPAGATE, Tk_Offset(Table, propagate), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-reqheight", (char *)NULL, (char *)NULL, (char *)NULL, Tk_Offset(Table, reqHeight), TK_CONFIG_NULL_OK, &limitsOption}, {TK_CONFIG_CUSTOM, "-reqwidth", (char *)NULL, (char *)NULL, (char *)NULL, Tk_Offset(Table, reqWidth), TK_CONFIG_NULL_OK, &limitsOption}, {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} }; /* * Forward declarations */ static void ArrangeTable _ANSI_ARGS_((ClientData clientData)); static void DestroyTable _ANSI_ARGS_((DestroyData dataPtr)); static void DestroyEntry _ANSI_ARGS_((Entry * entryPtr)); static void TableEventProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); static void BinEntry _ANSI_ARGS_((Table *tablePtr, Entry * entryPtr)); static RowColumn *InitSpan _ANSI_ARGS_((PartitionInfo * infoPtr, int start, int span)); static EntrySearchProc FindEntry; static Tcl_CmdProc TableCmd; static Tcl_InterpDeleteProc TableInterpDeleteProc; static Tk_EventProc WidgetEventProc; /* * ---------------------------------------------------------------------------- * * StringToLimits -- * * Converts the list of elements into zero or more pixel values which * determine the range of pixel values possible. An element can be in * any form accepted by Tk_GetPixels. The list has a different meaning * based upon the number of elements. * * # of elements: * * 0 - the limits are reset to the defaults. * 1 - the minimum and maximum values are set to this * value, freezing the range at a single value. * 2 - first element is the minimum, the second is the * maximum. * 3 - first element is the minimum, the second is the * maximum, and the third is the nominal value. * * Any element may be the empty string which indicates the default. * * Results: * The return value is a standard Tcl result. The min and max fields * of the range are set. * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToLimits(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Widget of table */ char *string; /* New width list */ char *widgRec; /* Widget record */ int offset; /* Offset of limits */ { Limits *limitsPtr = (Limits *)(widgRec + offset); char **elemArr; int nElem; int limArr[3]; Tk_Window winArr[3]; int flags; elemArr = NULL; nElem = 0; /* Initialize limits to default values */ limArr[2] = LIMITS_NOM; limArr[1] = LIMITS_MAX; limArr[0] = LIMITS_MIN; winArr[0] = winArr[1] = winArr[2] = NULL; flags = 0; if (string != NULL) { int size; int i; if (Tcl_SplitList(interp, string, &nElem, &elemArr) != TCL_OK) { return TCL_ERROR; } if (nElem > 3) { Tcl_AppendResult(interp, "wrong # limits \"", string, "\"", (char *)NULL); goto error; } for (i = 0; i < nElem; i++) { if (elemArr[i][0] == '\0') { continue; /* Empty string: use default value */ } flags |= (LIMITS_SET_BIT << i); if ((elemArr[i][0] == '.') && ((elemArr[i][1] == '\0') || isalpha(UCHAR(elemArr[i][1])))) { Tk_Window tkwin2; /* Widget specified: save pointer to widget */ tkwin2 = Tk_NameToWindow(interp, elemArr[i], tkwin); if (tkwin2 == NULL) { goto error; } winArr[i] = tkwin2; } else { if (Tk_GetPixels(interp, tkwin, elemArr[i], &size) != TCL_OK) { goto error; } if ((size < LIMITS_MIN) || (size > LIMITS_MAX)) { Tcl_AppendResult(interp, "bad limits \"", string, "\"", (char *)NULL); goto error; } limArr[i] = size; } } Blt_Free(elemArr); } /* * Check the limits specified. We can't check the requested * size of widgets. */ switch (nElem) { case 1: flags |= (LIMITS_SET_MIN | LIMITS_SET_MAX); if (winArr[0] == NULL) { limArr[1] = limArr[0]; /* Set minimum and maximum to value */ } else { winArr[1] = winArr[0]; } break; case 2: if ((winArr[0] == NULL) && (winArr[1] == NULL) && (limArr[1] < limArr[0])) { Tcl_AppendResult(interp, "bad range \"", string, "\": min > max", (char *)NULL); return TCL_ERROR; /* Minimum is greater than maximum */ } break; case 3: if ((winArr[0] == NULL) && (winArr[1] == NULL)) { if (limArr[1] < limArr[0]) { Tcl_AppendResult(interp, "bad range \"", string, "\": min > max", (char *)NULL); return TCL_ERROR; /* Minimum is greater than maximum */ } if ((winArr[2] == NULL) && ((limArr[2] < limArr[0]) || (limArr[2] > limArr[1]))) { Tcl_AppendResult(interp, "nominal value \"", string, "\" out of range", (char *)NULL); return TCL_ERROR; /* Nominal is outside of range defined * by minimum and maximum */ } } break; } limitsPtr->min = limArr[0]; limitsPtr->max = limArr[1]; limitsPtr->nom = limArr[2]; limitsPtr->wMin = winArr[0]; limitsPtr->wMax = winArr[1]; limitsPtr->wNom = winArr[2]; limitsPtr->flags = flags; return TCL_OK; error: Blt_Free(elemArr); return TCL_ERROR; } /* * ---------------------------------------------------------------------------- * * ResetLimits -- * * Resets the limits to their default values. * * Results: * None. * * ---------------------------------------------------------------------------- */ INLINE static void ResetLimits(limitsPtr) Limits *limitsPtr; /* Limits to be imposed on the value */ { limitsPtr->flags = 0; limitsPtr->min = LIMITS_MIN; limitsPtr->max = LIMITS_MAX; limitsPtr->nom = LIMITS_NOM; limitsPtr->wNom = limitsPtr->wMax = limitsPtr->wMin = NULL; } /* * ---------------------------------------------------------------------------- * * GetBoundedWidth -- * * Bounds a given width value to the limits described in the limit * structure. The initial starting value may be overridden by the * nominal value in the limits. * * Results: * Returns the constrained value. * * ---------------------------------------------------------------------------- */ static int GetBoundedWidth(width, limitsPtr) int width; /* Initial value to be constrained */ Limits *limitsPtr; /* Limits to be imposed on the value */ { /* * Check widgets for requested width values; */ if (limitsPtr->wMin != NULL) { limitsPtr->min = Tk_ReqWidth(limitsPtr->wMin); } if (limitsPtr->wMax != NULL) { limitsPtr->max = Tk_ReqWidth(limitsPtr->wMax); } if (limitsPtr->wNom != NULL) { limitsPtr->nom = Tk_ReqWidth(limitsPtr->wNom); } if (limitsPtr->flags & LIMITS_SET_NOM) { width = limitsPtr->nom; /* Override initial value */ } if (width < limitsPtr->min) { width = limitsPtr->min; /* Bounded by minimum value */ } else if (width > limitsPtr->max) { width = limitsPtr->max; /* Bounded by maximum value */ } return width; } /* * ---------------------------------------------------------------------------- * * GetBoundedHeight -- * * Bounds a given value to the limits described in the limit * structure. The initial starting value may be overridden by the * nominal value in the limits. * * Results: * Returns the constrained value. * * ---------------------------------------------------------------------------- */ static int GetBoundedHeight(height, limitsPtr) int height; /* Initial value to be constrained */ Limits *limitsPtr; /* Limits to be imposed on the value */ { /* * Check widgets for requested height values; */ if (limitsPtr->wMin != NULL) { limitsPtr->min = Tk_ReqHeight(limitsPtr->wMin); } if (limitsPtr->wMax != NULL) { limitsPtr->max = Tk_ReqHeight(limitsPtr->wMax); } if (limitsPtr->wNom != NULL) { limitsPtr->nom = Tk_ReqHeight(limitsPtr->wNom); } if (limitsPtr->flags & LIMITS_SET_NOM) { height = limitsPtr->nom;/* Override initial value */ } if (height < limitsPtr->min) { height = limitsPtr->min;/* Bounded by minimum value */ } else if (height > limitsPtr->max) { height = limitsPtr->max;/* Bounded by maximum value */ } return height; } /* * ---------------------------------------------------------------------------- * * NameOfLimits -- * * Convert the values into a list representing the limits. * * Results: * The static string representation of the limits is returned. * * ---------------------------------------------------------------------------- */ static char * NameOfLimits(limitsPtr) Limits *limitsPtr; { Tcl_DString buffer; #define STRING_SPACE 200 static char string[STRING_SPACE + 1]; Tcl_DStringInit(&buffer); if (limitsPtr->wMin != NULL) { Tcl_DStringAppendElement(&buffer, Tk_PathName(limitsPtr->wMin)); } else if (limitsPtr->flags & LIMITS_SET_MIN) { Tcl_DStringAppendElement(&buffer, Blt_Itoa(limitsPtr->min)); } else { Tcl_DStringAppendElement(&buffer, ""); } if (limitsPtr->wMax != NULL) { Tcl_DStringAppendElement(&buffer, Tk_PathName(limitsPtr->wMax)); } else if (limitsPtr->flags & LIMITS_SET_MAX) { Tcl_DStringAppendElement(&buffer, Blt_Itoa(limitsPtr->max)); } else { Tcl_DStringAppendElement(&buffer, ""); } if (limitsPtr->wNom != NULL) { Tcl_DStringAppendElement(&buffer, Tk_PathName(limitsPtr->wNom)); } else if (limitsPtr->flags & LIMITS_SET_NOM) { Tcl_DStringAppendElement(&buffer, Blt_Itoa(limitsPtr->nom)); } else { Tcl_DStringAppendElement(&buffer, ""); } strncpy(string, Tcl_DStringValue(&buffer), STRING_SPACE); string[STRING_SPACE] = '\0'; return string; } /* * ---------------------------------------------------------------------------- * * LimitsToString -- * * Convert the limits of the pixel values allowed into a list. * * Results: * The string representation of the limits is returned. * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ static char * LimitsToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Row/column structure record */ int offset; /* Offset of widget RowColumn record */ Tcl_FreeProc **freeProcPtr; /* Memory deallocation routine */ { Limits *limitsPtr = (Limits *)(widgRec + offset); return NameOfLimits(limitsPtr); } /* * ---------------------------------------------------------------------------- * * StringToResize -- * * Converts the resize mode into its numeric representation. Valid * mode strings are "none", "expand", "shrink", or "both". * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToResize(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* Resize style string */ char *widgRec; /* Entry structure record */ int offset; /* Offset of style in record */ { int *resizePtr = (int *)(widgRec + offset); unsigned int length; char c; c = string[0]; length = strlen(string); if ((c == 'n') && (strncmp(string, "none", length) == 0)) { *resizePtr = RESIZE_NONE; } else if ((c == 'b') && (strncmp(string, "both", length) == 0)) { *resizePtr = RESIZE_BOTH; } else if ((c == 'e') && (strncmp(string, "expand", length) == 0)) { *resizePtr = RESIZE_EXPAND; } else if ((c == 's') && (strncmp(string, "shrink", length) == 0)) { *resizePtr = RESIZE_SHRINK; } else { Tcl_AppendResult(interp, "bad resize argument \"", string, "\": should be \"none\", \"expand\", \"shrink\", or \"both\"", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* * ---------------------------------------------------------------------------- * * NameOfResize -- * * Converts the resize value into its string representation. * * Results: * Returns a pointer to the static name string. * * ---------------------------------------------------------------------------- */ static char * NameOfResize(resize) int resize; { switch (resize & RESIZE_BOTH) { case RESIZE_NONE: return "none"; case RESIZE_EXPAND: return "expand"; case RESIZE_SHRINK: return "shrink"; case RESIZE_BOTH: return "both"; default: return "unknown resize value"; } } /* * ---------------------------------------------------------------------------- * * ResizeToString -- * * Returns resize mode string based upon the resize flags. * * Results: * The resize mode string is returned. * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ static char * ResizeToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Row/column structure record */ int offset; /* Offset of resize in RowColumn record */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { int resize = *(int *)(widgRec + offset); return NameOfResize(resize); } /* * ---------------------------------------------------------------------------- * * StringToControl -- * * Converts the control string into its numeric representation. * Valid control strings are "none", "normal", and "full". * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToControl(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* Control style string */ char *widgRec; /* Entry structure record */ int offset; /* Offset of style in record */ { double *controlPtr = (double *)(widgRec + offset); unsigned int length; int bool; char c; c = string[0]; length = strlen(string); if (Tcl_GetBoolean(NULL, string, &bool) == TCL_OK) { *controlPtr = bool; return TCL_OK; } if ((c == 'n') && (length > 1) && (strncmp(string, "normal", length) == 0)) { *controlPtr = CONTROL_NORMAL; } else if ((c == 'n') && (length > 1) && (strncmp(string, "none", length) == 0)) { *controlPtr = CONTROL_NONE; } else if ((c == 'f') && (strncmp(string, "full", length) == 0)) { *controlPtr = CONTROL_FULL; } else { double control; if ((Tcl_GetDouble(interp, string, &control) != TCL_OK) || (control < 0.0)) { Tcl_AppendResult(interp, "bad control argument \"", string, "\": should be \"normal\", \"none\", or \"full\"", (char *)NULL); return TCL_ERROR; } *controlPtr = control; } return TCL_OK; } /* * ---------------------------------------------------------------------------- * * NameOfControl -- * * Converts the control value into its string representation. * * Results: * Returns a pointer to the static name string. * * ---------------------------------------------------------------------------- */ static char * NameOfControl(control) double control; { if (control == CONTROL_NORMAL) { return "normal"; } else if (control == CONTROL_NONE) { return "none"; } else if (control == CONTROL_FULL) { return "full"; } else { static char string[TCL_DOUBLE_SPACE + 1]; sprintf(string, "%g", control); return string; } } /* * ---------------------------------------------------------------------------- * * ControlToString -- * * Returns control mode string based upon the control flags. * * Results: * The control mode string is returned. * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ static char * ControlToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Row/column structure record */ int offset; /* Offset of control in RowColumn record */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { double control = *(double *)(widgRec + offset); return NameOfControl(control); } static void EventuallyArrangeTable(tablePtr) Table *tablePtr; { if (!(tablePtr->flags & ARRANGE_PENDING)) { tablePtr->flags |= ARRANGE_PENDING; Tcl_DoWhenIdle(ArrangeTable, tablePtr); } } /* * ---------------------------------------------------------------------------- * * TableEventProc -- * * This procedure is invoked by the Tk event handler when the * container widget is reconfigured or destroyed. * * The table will be rearranged at the next idle point if the * container widget has been resized or moved. There's a * distinction made between parent and non-parent container * arrangements. If the container is moved and it's the parent * of the widgets, they're are moved automatically. If it's * not the parent, those widgets need to be moved manually. * This can be a performance hit in rare cases where we're * scrolling the container (by moving the window) and there * are lots of non-child widgets arranged insided. * * Results: * None. * * Side effects: * Arranges for the table associated with tkwin to have its * layout re-computed and drawn at the next idle point. * * ---------------------------------------------------------------------------- */ static void TableEventProc(clientData, eventPtr) ClientData clientData; /* Information about widget */ XEvent *eventPtr; /* Information about event */ { register Table *tablePtr = clientData; if (eventPtr->type == ConfigureNotify) { if ((tablePtr->container.width != Tk_Width(tablePtr->tkwin)) || (tablePtr->container.height != Tk_Height(tablePtr->tkwin)) || (tablePtr->flags & NON_PARENT)) { EventuallyArrangeTable(tablePtr); } } else if (eventPtr->type == DestroyNotify) { if (tablePtr->flags & ARRANGE_PENDING) { Tcl_CancelIdleCall(ArrangeTable, tablePtr); } tablePtr->tkwin = NULL; Tcl_EventuallyFree(tablePtr, DestroyTable); } } /* * ---------------------------------------------------------------------------- * * WidgetEventProc -- * * This procedure is invoked by the Tk event handler when * StructureNotify events occur in a widget managed by the table. * For example, when a managed widget is destroyed, it frees the * corresponding entry structure and arranges for the table * layout to be re-computed at the next idle point. * * Results: * None. * * Side effects: * If the managed widget was deleted, the Entry structure gets * cleaned up and the table is rearranged. * * ---------------------------------------------------------------------------- */ static void WidgetEventProc(clientData, eventPtr) ClientData clientData; /* Pointer to Entry structure for widget * referred to by eventPtr. */ XEvent *eventPtr; /* Describes what just happened. */ { Entry *entryPtr = (Entry *) clientData; Table *tablePtr = entryPtr->tablePtr; if (eventPtr->type == ConfigureNotify) { int borderWidth; tablePtr->flags |= REQUEST_LAYOUT; borderWidth = Tk_Changes(entryPtr->tkwin)->border_width; if (entryPtr->borderWidth != borderWidth) { entryPtr->borderWidth = borderWidth; EventuallyArrangeTable(tablePtr); } } else if (eventPtr->type == DestroyNotify) { entryPtr->tkwin = NULL; DestroyEntry(entryPtr); tablePtr->flags |= REQUEST_LAYOUT; EventuallyArrangeTable(tablePtr); } } /* * ---------------------------------------------------------------------------- * * WidgetCustodyProc -- * * This procedure is invoked when a widget has been stolen by * another geometry manager. The information and memory * associated with the widget is released. * * Results: * None. * * Side effects: * Arranges for the table to have its layout re-arranged at the * next idle point. * * ---------------------------------------------------------------------------- */ /* ARGSUSED */ static void WidgetCustodyProc(clientData, tkwin) ClientData clientData; /* Information about the widget */ Tk_Window tkwin; /* Not used. */ { Entry *entryPtr = (Entry *) clientData; Table *tablePtr = entryPtr->tablePtr; if (Tk_IsMapped(entryPtr->tkwin)) { Tk_UnmapWindow(entryPtr->tkwin); } Tk_UnmaintainGeometry(entryPtr->tkwin, tablePtr->tkwin); entryPtr->tkwin = NULL; DestroyEntry(entryPtr); tablePtr->flags |= REQUEST_LAYOUT; EventuallyArrangeTable(tablePtr); } /* * ---------------------------------------------------------------------------- * * WidgetGeometryProc -- * * This procedure is invoked by Tk_GeometryRequest for widgets * managed by the table geometry manager. * * Results: * None. * * Side effects: * Arranges for the table to have its layout re-computed and * re-arranged at the next idle point. * * ---------------------------------------------------------------------------- */ /* ARGSUSED */ static void WidgetGeometryProc(clientData, tkwin) ClientData clientData; /* Information about widget that got new * preferred geometry. */ Tk_Window tkwin; /* Other Tk-related information about the * widget. */ { Entry *entryPtr = (Entry *) clientData; entryPtr->tablePtr->flags |= REQUEST_LAYOUT; EventuallyArrangeTable(entryPtr->tablePtr); } /* * ---------------------------------------------------------------------------- * * FindEntry -- * * Searches for the table entry corresponding to the given * widget. * * Results: * If a structure associated with the widget exists, a pointer to * that structure is returned. Otherwise NULL. * * ---------------------------------------------------------------------------- */ static Entry * FindEntry(tablePtr, tkwin) Table *tablePtr; Tk_Window tkwin; /* Widget associated with table entry */ { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&(tablePtr->entryTable), (char *)tkwin); if (hPtr == NULL) { return NULL; } return (Entry *) Blt_GetHashValue(hPtr); } static int GetEntry(interp, tablePtr, string, entryPtrPtr) Tcl_Interp *interp; Table *tablePtr; char *string; Entry **entryPtrPtr; { Tk_Window tkwin; Entry *entryPtr; tkwin = Tk_NameToWindow(interp, string, tablePtr->tkwin); if (tkwin == NULL) { return TCL_ERROR; } entryPtr = FindEntry(tablePtr, tkwin); if (entryPtr == NULL) { Tcl_AppendResult(interp, "\"", Tk_PathName(tkwin), "\" is not managed by any table", (char *)NULL); return TCL_ERROR; } *entryPtrPtr = entryPtr; return TCL_OK; } /* * ---------------------------------------------------------------------------- * * CreateEntry -- * * This procedure creates and initializes a new Entry structure * to hold a widget. A valid widget has a parent widget that is * either a) the container widget itself or b) a mutual ancestor * of the container widget. * * Results: * Returns a pointer to the new structure describing the new * widget entry. If an error occurred, then the return * value is NULL and an error message is left in interp->result. * * Side effects: * Memory is allocated and initialized for the Entry structure. * * ---------------------------------------------------------------------------- */ static Entry * CreateEntry(tablePtr, tkwin) Table *tablePtr; Tk_Window tkwin; { register Entry *entryPtr; int dummy; Tk_Window parent, ancestor; /* * Check that this widget can be managed by this table. A valid * widget has a parent widget that either * * 1) is the container widget, or * 2) is a mutual ancestor of the container widget. */ ancestor = Tk_Parent(tkwin); for (parent = tablePtr->tkwin; (parent != ancestor) && (!Tk_IsTopLevel(parent)); parent = Tk_Parent(parent)) { /* empty */ } if (ancestor != parent) { Tcl_AppendResult(tablePtr->interp, "can't manage \"", Tk_PathName(tkwin), "\" in table \"", Tk_PathName(tablePtr->tkwin), "\"", (char *)NULL); return NULL; } entryPtr = Blt_Calloc(1, sizeof(Entry)); assert(entryPtr); /* Initialize the entry structure */ entryPtr->tkwin = tkwin; entryPtr->tablePtr = tablePtr; entryPtr->borderWidth = Tk_Changes(tkwin)->border_width; entryPtr->fill = ENTRY_DEF_FILL; entryPtr->row.control = entryPtr->column.control = ENTRY_DEF_CONTROL; entryPtr->anchor = ENTRY_DEF_ANCHOR; entryPtr->row.span = entryPtr->column.span = ENTRY_DEF_SPAN; ResetLimits(&(entryPtr->reqWidth)); ResetLimits(&(entryPtr->reqHeight)); /* * Add the entry to the following data structures. * * 1) A chain of widgets managed by the table. * 2) A hash table of widgets managed by the table. */ entryPtr->linkPtr = Blt_ChainAppend(tablePtr->chainPtr, entryPtr); entryPtr->hashPtr = Blt_CreateHashEntry(&(tablePtr->entryTable), (char *)tkwin, &dummy); Blt_SetHashValue(entryPtr->hashPtr, entryPtr); Tk_CreateEventHandler(tkwin, StructureNotifyMask, WidgetEventProc, entryPtr); Tk_ManageGeometry(tkwin, &tableMgrInfo, (ClientData)entryPtr); return entryPtr; } /* * ---------------------------------------------------------------------------- * * DestroyEntry -- * * Removes the Entry structure from the hash table and frees * the memory allocated by it. If the table is still in use * (i.e. was not called from DestoryTable), remove its entries * from the lists of row and column sorted partitions. * * Results: * None. * * Side effects: * Everything associated with the entry is freed up. * * ---------------------------------------------------------------------------- */ static void DestroyEntry(entryPtr) Entry *entryPtr; { Table *tablePtr = entryPtr->tablePtr; if (entryPtr->row.linkPtr != NULL) { Blt_ChainDeleteLink(entryPtr->row.chainPtr, entryPtr->row.linkPtr); } if (entryPtr->column.linkPtr != NULL) { Blt_ChainDeleteLink(entryPtr->column.chainPtr, entryPtr->column.linkPtr); } if (entryPtr->linkPtr != NULL) { Blt_ChainDeleteLink(tablePtr->chainPtr, entryPtr->linkPtr); } if (entryPtr->tkwin != NULL) { Tk_DeleteEventHandler(entryPtr->tkwin, StructureNotifyMask, WidgetEventProc, (ClientData)entryPtr); Tk_ManageGeometry(entryPtr->tkwin, (Tk_GeomMgr *)NULL, (ClientData)entryPtr); if ((tablePtr->tkwin != NULL) && (Tk_Parent(entryPtr->tkwin) != tablePtr->tkwin)) { Tk_UnmaintainGeometry(entryPtr->tkwin, tablePtr->tkwin); } if (Tk_IsMapped(entryPtr->tkwin)) { Tk_UnmapWindow(entryPtr->tkwin); } } if (entryPtr->hashPtr != NULL) { Blt_DeleteHashEntry(&(tablePtr->entryTable), entryPtr->hashPtr); } Blt_Free(entryPtr); } /* * ---------------------------------------------------------------------------- * * ConfigureEntry -- * * This procedure is called to process an argv/argc list, plus * the Tk option database, in order to configure (or reconfigure) * one or more entries. Entries hold information about widgets * managed by the table geometry manager. * * Note: You can query only one widget at a time. But several * can be reconfigured at once. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then interp->result contains an error message. * * Side effects: * The table layout is recomputed and rearranged at the next idle * point. * * ---------------------------------------------------------------------------- */ static int ConfigureEntry(tablePtr, interp, entryPtr, argc, argv) Table *tablePtr; Tcl_Interp *interp; Entry *entryPtr; int argc; /* Option-value arguments */ char **argv; { int oldRowSpan, oldColSpan; if (entryPtr->tablePtr != tablePtr) { Tcl_AppendResult(interp, "widget \"", Tk_PathName(entryPtr->tkwin), "\" does not belong to table \"", Tk_PathName(tablePtr->tkwin), "\"", (char *)NULL); return TCL_ERROR; } if (argc == 0) { return Tk_ConfigureInfo(interp, entryPtr->tkwin, entryConfigSpecs, (char *)entryPtr, (char *)NULL, 0); } else if (argc == 1) { return Tk_ConfigureInfo(interp, entryPtr->tkwin, entryConfigSpecs, (char *)entryPtr, argv[0], 0); } oldRowSpan = entryPtr->row.span; oldColSpan = entryPtr->column.span; if (Tk_ConfigureWidget(interp, entryPtr->tkwin, entryConfigSpecs, argc, argv, (char *)entryPtr, TK_CONFIG_ARGV_ONLY) != TCL_OK) { return TCL_ERROR; } if ((entryPtr->column.span < 1) || (entryPtr->column.span > USHRT_MAX)) { Tcl_AppendResult(interp, "bad column span specified for \"", Tk_PathName(entryPtr->tkwin), "\"", (char *)NULL); return TCL_ERROR; } if ((entryPtr->row.span < 1) || (entryPtr->row.span > USHRT_MAX)) { Tcl_AppendResult(interp, "bad row span specified for \"", Tk_PathName(entryPtr->tkwin), "\"", (char *)NULL); return TCL_ERROR; } if ((oldColSpan != entryPtr->column.span) || (oldRowSpan != entryPtr->row.span)) { BinEntry(tablePtr, entryPtr); } return TCL_OK; } /* * ---------------------------------------------------------------------------- * * PrintEntry -- * * Returns the name, position and options of a widget in the table. * * Results: * Returns a standard Tcl result. A list of the widget * attributes is left in interp->result. * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ static void PrintEntry(entryPtr, resultPtr) Entry *entryPtr; Tcl_DString *resultPtr; { char string[200]; sprintf(string, " %d,%d ", entryPtr->row.rcPtr->index, entryPtr->column.rcPtr->index); Tcl_DStringAppend(resultPtr, string, -1); Tcl_DStringAppend(resultPtr, Tk_PathName(entryPtr->tkwin), -1); if (entryPtr->ipadX != ENTRY_DEF_PAD) { Tcl_DStringAppend(resultPtr, " -ipadx ", -1); Tcl_DStringAppend(resultPtr, Blt_Itoa(entryPtr->ipadX), -1); } if (entryPtr->ipadY != ENTRY_DEF_PAD) { Tcl_DStringAppend(resultPtr, " -ipady ", -1); Tcl_DStringAppend(resultPtr, Blt_Itoa(entryPtr->ipadY), -1); } if (entryPtr->row.span != ENTRY_DEF_SPAN) { Tcl_DStringAppend(resultPtr, " -rowspan ", -1); Tcl_DStringAppend(resultPtr, Blt_Itoa(entryPtr->row.span), -1); } if (entryPtr->column.span != ENTRY_DEF_SPAN) { Tcl_DStringAppend(resultPtr, " -columnspan ", -1); Tcl_DStringAppend(resultPtr, Blt_Itoa(entryPtr->column.span), -1); } if (entryPtr->anchor != ENTRY_DEF_ANCHOR) { Tcl_DStringAppend(resultPtr, " -anchor ", -1); Tcl_DStringAppend(resultPtr, Tk_NameOfAnchor(entryPtr->anchor), -1); } if ((entryPtr->padLeft != ENTRY_DEF_PAD) || (entryPtr->padRight != ENTRY_DEF_PAD)) { Tcl_DStringAppend(resultPtr, " -padx ", -1); sprintf(string, "{%d %d}", entryPtr->padLeft, entryPtr->padRight); Tcl_DStringAppend(resultPtr, string, -1); } if ((entryPtr->padTop != ENTRY_DEF_PAD) || (entryPtr->padBottom != ENTRY_DEF_PAD)) { Tcl_DStringAppend(resultPtr, " -pady ", -1); sprintf(string, "{%d %d}", entryPtr->padTop, entryPtr->padBottom); Tcl_DStringAppend(resultPtr, string, -1); } if (entryPtr->fill != ENTRY_DEF_FILL) { Tcl_DStringAppend(resultPtr, " -fill ", -1); Tcl_DStringAppend(resultPtr, Blt_NameOfFill(entryPtr->fill), -1); } if (entryPtr->column.control != ENTRY_DEF_CONTROL) { Tcl_DStringAppend(resultPtr, " -columncontrol ", -1); Tcl_DStringAppend(resultPtr, NameOfControl(entryPtr->column.control), -1); } if (entryPtr->row.control != ENTRY_DEF_CONTROL) { Tcl_DStringAppend(resultPtr, " -rowcontrol ", -1); Tcl_DStringAppend(resultPtr, NameOfControl(entryPtr->row.control), -1); } if ((entryPtr->reqWidth.nom != LIMITS_NOM) || (entryPtr->reqWidth.min != LIMITS_MIN) || (entryPtr->reqWidth.max != LIMITS_MAX)) { Tcl_DStringAppend(resultPtr, " -reqwidth {", -1); Tcl_DStringAppend(resultPtr, NameOfLimits(&(entryPtr->reqWidth)), -1); Tcl_DStringAppend(resultPtr, "}", -1); } if ((entryPtr->reqHeight.nom != LIMITS_NOM) || (entryPtr->reqHeight.min != LIMITS_MIN) || (entryPtr->reqHeight.max != LIMITS_MAX)) { Tcl_DStringAppend(resultPtr, " -reqheight {", -1); Tcl_DStringAppend(resultPtr, NameOfLimits(&(entryPtr->reqHeight)), -1); Tcl_DStringAppend(resultPtr, "}", -1); } } /* * ---------------------------------------------------------------------------- * * InfoEntry -- * * Returns the name, position and options of a widget in the table. * * Results: * Returns a standard Tcl result. A list of the widget * attributes is left in interp->result. * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ static int InfoEntry(interp, tablePtr, entryPtr) Tcl_Interp *interp; Table *tablePtr; Entry *entryPtr; { Tcl_DString dString; if (entryPtr->tablePtr != tablePtr) { Tcl_AppendResult(interp, "widget \"", Tk_PathName(entryPtr->tkwin), "\" does not belong to table \"", Tk_PathName(tablePtr->tkwin), "\"", (char *)NULL); return TCL_ERROR; } Tcl_DStringInit(&dString); PrintEntry(entryPtr, &dString); Tcl_DStringResult(interp, &dString); return TCL_OK; } /* * ---------------------------------------------------------------------------- * * CreateRowColumn -- * * Creates and initializes a structure that manages the size of a * row or column in the table. There will be one of these * structures allocated for each row and column in the table, * regardless if a widget is contained in it or not. * * Results: * Returns a pointer to the newly allocated row or column * structure. * * ---------------------------------------------------------------------------- */ static RowColumn * CreateRowColumn() { RowColumn *rcPtr; rcPtr = Blt_Malloc(sizeof(RowColumn)); rcPtr->resize = ROWCOL_DEF_RESIZE; ResetLimits(&(rcPtr->reqSize)); rcPtr->nomSize = LIMITS_NOM; rcPtr->pad.side1 = rcPtr->pad.side2 = ROWCOL_DEF_PAD; rcPtr->size = rcPtr->index = rcPtr->minSpan = 0; rcPtr->weight = ROWCOL_DEF_WEIGHT; return rcPtr; } static PartitionInfo * ParseRowColumn2(tablePtr, string, numberPtr) Table *tablePtr; char *string; int *numberPtr; { char c; int n; PartitionInfo *infoPtr; c = tolower(string[0]); if (c == 'c') { infoPtr = &(tablePtr->columnInfo); } else if (c == 'r') { infoPtr = &(tablePtr->rowInfo); } else { Tcl_AppendResult(tablePtr->interp, "bad index \"", string, "\": must start with \"r\" or \"c\"", (char *)NULL); return NULL; } /* Handle row or column configuration queries */ if (Tcl_GetInt(tablePtr->interp, string + 1, &n) != TCL_OK) { return NULL; } *numberPtr = (int)n; return infoPtr; } static PartitionInfo * ParseRowColumn(tablePtr, string, numberPtr) Table *tablePtr; char *string; int *numberPtr; { int n; PartitionInfo *infoPtr; infoPtr = ParseRowColumn2(tablePtr, string, &n); if (infoPtr == NULL) { return NULL; } if ((n < 0) || (n >= Blt_ChainGetLength(infoPtr->chainPtr))) { Tcl_AppendResult(tablePtr->interp, "bad ", infoPtr->type, " index \"", string, "\"", (char *)NULL); return NULL; } *numberPtr = (int)n; return infoPtr; } /* * ---------------------------------------------------------------------------- * * GetRowColumn -- * * Gets the designated row or column from the table. If the row * or column index is greater than the size of the table, new * rows/columns will be automatically allocated. * * Results: * Returns a pointer to the row or column structure. * * ---------------------------------------------------------------------------- */ static RowColumn * GetRowColumn(infoPtr, n) PartitionInfo *infoPtr; int n; { Blt_ChainLink *linkPtr; RowColumn *rcPtr; register int i; for (i = Blt_ChainGetLength(infoPtr->chainPtr); i <= n; i++) { rcPtr = CreateRowColumn(); rcPtr->index = i; rcPtr->linkPtr = Blt_ChainAppend(infoPtr->chainPtr, (ClientData)rcPtr); } linkPtr = Blt_ChainGetNthLink(infoPtr->chainPtr, n); if (linkPtr == NULL) { return NULL; } return Blt_ChainGetValue(linkPtr); } /* * ---------------------------------------------------------------------------- * * DeleteRowColumn -- * * Deletes a span of rows/columns from the table. The number of * rows/columns to be deleted is given by span. * * Results: * None. * * Side effects: * The size of the column partition array may be extended and * initialized. * * ---------------------------------------------------------------------------- */ static void DeleteRowColumn(tablePtr, infoPtr, rcPtr) Table *tablePtr; PartitionInfo *infoPtr; RowColumn *rcPtr; { Blt_ChainLink *linkPtr, *nextPtr; Entry *entryPtr; /* * Remove any entries that start in the row/column to be deleted. * They point to memory that will be freed. */ if (infoPtr->type == rowUid) { for (linkPtr = Blt_ChainFirstLink(tablePtr->chainPtr); linkPtr != NULL; linkPtr = nextPtr) { nextPtr = Blt_ChainNextLink(linkPtr); entryPtr = Blt_ChainGetValue(linkPtr); if (entryPtr->row.rcPtr->index == rcPtr->index) { DestroyEntry(entryPtr); } } } else { for (linkPtr = Blt_ChainFirstLink(tablePtr->chainPtr); linkPtr != NULL; linkPtr = nextPtr) { nextPtr = Blt_ChainNextLink(linkPtr); entryPtr = Blt_ChainGetValue(linkPtr); if (entryPtr->column.rcPtr->index == rcPtr->index) { DestroyEntry(entryPtr); } } } } /* * ---------------------------------------------------------------------------- * * ConfigureRowColumn -- * * This procedure is called to process an argv/argc list in order * to configure a row or column in the table geometry manager. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then interp->result holds an error message. * * Side effects: * Partition configuration options (bounds, resize flags, etc) * get set. New partitions may be created as necessary. The * table is recalculated and arranged at the next idle point. * * ---------------------------------------------------------------------------- */ static int ConfigureRowColumn(tablePtr, infoPtr, pattern, argc, argv) Table *tablePtr; /* Table to be configured */ PartitionInfo *infoPtr; char *pattern; int argc; char **argv; { RowColumn *rcPtr; register Blt_ChainLink *linkPtr; char string[200]; int nMatches; nMatches = 0; for (linkPtr = Blt_ChainFirstLink(infoPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); sprintf(string, "%c%d", pattern[0], rcPtr->index); if (Tcl_StringMatch(string, pattern)) { if (argc == 0) { return Tk_ConfigureInfo(tablePtr->interp, tablePtr->tkwin, infoPtr->configSpecs, (char *)rcPtr, NULL, 0); } else if (argc == 1) { return Tk_ConfigureInfo(tablePtr->interp, tablePtr->tkwin, infoPtr->configSpecs, (char *)rcPtr, argv[0], 0); } else { if (Tk_ConfigureWidget(tablePtr->interp, tablePtr->tkwin, infoPtr->configSpecs, argc, argv, (char *)rcPtr, TK_CONFIG_ARGV_ONLY) != TCL_OK) { return TCL_ERROR; } } nMatches++; } } if (nMatches == 0) { int n; /* * We found no existing partitions matching this pattern, so * see if this designates an new partition (one beyond the * current range). */ if ((Tcl_GetInt(NULL, pattern + 1, &n) != TCL_OK) || (n < 0)) { Tcl_AppendResult(tablePtr->interp, "pattern \"", pattern, "\" matches no ", infoPtr->type, " in table \"", Tk_PathName(tablePtr->tkwin), "\"", (char *)NULL); return TCL_ERROR; } rcPtr = GetRowColumn(infoPtr, n); assert(rcPtr); if (Tk_ConfigureWidget(tablePtr->interp, tablePtr->tkwin, infoPtr->configSpecs, argc, argv, (char *)rcPtr, TK_CONFIG_ARGV_ONLY) != TCL_OK) { return TCL_ERROR; } } EventuallyArrangeTable(tablePtr); return TCL_OK; } static void PrintRowColumn(interp, infoPtr, rcPtr, resultPtr) Tcl_Interp *interp; PartitionInfo *infoPtr; RowColumn *rcPtr; Tcl_DString *resultPtr; { char string[200]; char *padFmt, *sizeFmt; if (infoPtr->type == rowUid) { padFmt = " -pady {%d %d}"; sizeFmt = " -height {%s}"; } else { padFmt = " -padx {%d %d}"; sizeFmt = " -width {%s}"; } if (rcPtr->resize != ROWCOL_DEF_RESIZE) { Tcl_DStringAppend(resultPtr, " -resize ", -1); Tcl_DStringAppend(resultPtr, NameOfResize(rcPtr->resize), -1); } if ((rcPtr->pad.side1 != ROWCOL_DEF_PAD) || (rcPtr->pad.side2 != ROWCOL_DEF_PAD)) { sprintf(string, padFmt, rcPtr->pad.side1, rcPtr->pad.side2); Tcl_DStringAppend(resultPtr, string, -1); } if (rcPtr->weight != ROWCOL_DEF_WEIGHT) { Tcl_DStringAppend(resultPtr, " -weight ", -1); Tcl_DStringAppend(resultPtr, Blt_Dtoa(interp, rcPtr->weight), -1); } if ((rcPtr->reqSize.min != LIMITS_MIN) || (rcPtr->reqSize.nom != LIMITS_NOM) || (rcPtr->reqSize.max != LIMITS_MAX)) { sprintf(string, sizeFmt, NameOfLimits(&(rcPtr->reqSize))); Tcl_DStringAppend(resultPtr, string, -1); } } /* * ---------------------------------------------------------------------------- * * InfoRowColumn -- * * Returns the options of a partition in the table. * * Results: * Returns a standard Tcl result. A list of the partition * attributes is left in interp->result. * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ static int InfoRowColumn(tablePtr, interp, pattern) Table *tablePtr; Tcl_Interp *interp; char *pattern; { RowColumn *rcPtr; char string[200]; PartitionInfo *infoPtr; char c; Blt_ChainLink *linkPtr, *lastPtr; Tcl_DString dString; c = pattern[0]; if ((c == 'r') || (c == 'R')) { infoPtr = &(tablePtr->rowInfo); } else { infoPtr = &(tablePtr->columnInfo); } Tcl_DStringInit(&dString); lastPtr = Blt_ChainLastLink(infoPtr->chainPtr); for (linkPtr = Blt_ChainFirstLink(infoPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); sprintf(string, "%c%d", infoPtr->type[0], rcPtr->index); if (Tcl_StringMatch(string, pattern)) { Tcl_DStringAppend(&dString, string, -1); PrintRowColumn(interp, infoPtr, rcPtr, &dString); if (linkPtr != lastPtr) { Tcl_DStringAppend(&dString, " \\\n", -1); } else { Tcl_DStringAppend(&dString, "\n", -1); } } } Tcl_DStringResult(interp, &dString); return TCL_OK; } /* * ---------------------------------------------------------------------------- * * InitSpan -- * * Checks the size of the column partitions and extends the size * if a larger array is needed. * * Results: * Returns 1 if the column exists. Otherwise 0 is returned and * interp->result contains an error message. * * Side effects: * The size of the column partition array may be extended and * initialized. * * ---------------------------------------------------------------------------- */ static RowColumn * InitSpan(infoPtr, start, span) PartitionInfo *infoPtr; int start, span; { int length; RowColumn *rcPtr; register int i; Blt_ChainLink *linkPtr; length = Blt_ChainGetLength(infoPtr->chainPtr); for (i = length; i < (start + span); i++) { rcPtr = CreateRowColumn(); rcPtr->index = i; rcPtr->linkPtr = Blt_ChainAppend(infoPtr->chainPtr, (ClientData)rcPtr); } linkPtr = Blt_ChainGetNthLink(infoPtr->chainPtr, start); return Blt_ChainGetValue(linkPtr); } /* * ---------------------------------------------------------------------------- * * Blt_GetTable -- * * Searches for a table associated by the path name of the widget * container. * * Errors may occur because * 1) pathName isn't a valid for any Tk widget, or * 2) there's no table associated with that widget as a container. * * Results: * If a table entry exists, a pointer to the Table structure is * returned. Otherwise NULL is returned. * * ---------------------------------------------------------------------------- */ /*LINTLIBRARY*/ int Blt_GetTable(dataPtr, interp, pathName, tablePtrPtr) TableInterpData *dataPtr; /* Interpreter-specific data. */ Tcl_Interp *interp; /* Interpreter to report errors back to. */ char *pathName; /* Path name of the container widget. */ Table **tablePtrPtr; { Blt_HashEntry *hPtr; Tk_Window tkwin; tkwin = Tk_NameToWindow(interp, pathName, Tk_MainWindow(interp)); if (tkwin == NULL) { return TCL_ERROR; } hPtr = Blt_FindHashEntry(&(dataPtr->tableTable), (char *)tkwin); if (hPtr == NULL) { Tcl_AppendResult(interp, "no table associated with widget \"", pathName, "\"", (char *)NULL); return TCL_ERROR; } *tablePtrPtr = (Table *)Blt_GetHashValue(hPtr); return TCL_OK; } /* * ---------------------------------------------------------------------------- * * CreateTable -- * * This procedure creates and initializes a new Table structure * with tkwin as its container widget. The internal structures * associated with the table are initialized. * * Results: * Returns the pointer to the new Table structure describing the * new table geometry manager. If an error occurred, the return * value will be NULL and an error message is left in * interp->result. * * Side effects: * Memory is allocated and initialized, an event handler is set * up to watch tkwin, etc. * * ---------------------------------------------------------------------------- */ static Table * CreateTable(dataPtr, interp, pathName) TableInterpData *dataPtr; Tcl_Interp *interp; /* Interpreter associated with table. */ char *pathName; /* Path name of the container widget to be * associated with the new table. */ { register Table *tablePtr; Tk_Window tkwin; int dummy; Blt_HashEntry *hPtr; tkwin = Tk_NameToWindow(interp, pathName, Tk_MainWindow(interp)); if (tkwin == NULL) { return NULL; } tablePtr = Blt_Calloc(1, sizeof(Table)); assert(tablePtr); tablePtr->tkwin = tkwin; tablePtr->interp = interp; tablePtr->rowInfo.type = rowUid; tablePtr->rowInfo.configSpecs = rowConfigSpecs; tablePtr->rowInfo.chainPtr = Blt_ChainCreate(); tablePtr->columnInfo.type = columnUid; tablePtr->columnInfo.configSpecs = columnConfigSpecs; tablePtr->columnInfo.chainPtr = Blt_ChainCreate(); tablePtr->propagate = TRUE; tablePtr->arrangeProc = ArrangeTable; Blt_InitHashTable(&(tablePtr->entryTable), BLT_ONE_WORD_KEYS); tablePtr->findEntryProc = FindEntry; ResetLimits(&(tablePtr->reqWidth)); ResetLimits(&(tablePtr->reqHeight)); tablePtr->chainPtr = Blt_ChainCreate(); tablePtr->rowInfo.list = Blt_ListCreate(BLT_ONE_WORD_KEYS); tablePtr->columnInfo.list = Blt_ListCreate(BLT_ONE_WORD_KEYS); Tk_CreateEventHandler(tablePtr->tkwin, StructureNotifyMask, TableEventProc, (ClientData)tablePtr); hPtr = Blt_CreateHashEntry(&(dataPtr->tableTable), (char *)tkwin, &dummy); tablePtr->hashPtr = hPtr; tablePtr->tablePtr = &(dataPtr->tableTable); Blt_SetHashValue(hPtr, (ClientData)tablePtr); return tablePtr; } /* * ---------------------------------------------------------------------------- * * ConfigureTable -- * * This procedure is called to process an argv/argc list in order * to configure the table geometry manager. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then interp->result contains an error message. * * Side effects: * Table configuration options (-padx, -pady, etc.) get set. The * table is recalculated and arranged at the next idle point. * * ---------------------------------------------------------------------------- */ static int ConfigureTable(tablePtr, interp, argc, argv) Table *tablePtr; /* Table to be configured */ Tcl_Interp *interp; /* Interpreter to report results back to */ int argc; char **argv; /* Option-value pairs */ { if (argc == 0) { return Tk_ConfigureInfo(interp, tablePtr->tkwin, tableConfigSpecs, (char *)tablePtr, (char *)NULL, 0); } else if (argc == 1) { return Tk_ConfigureInfo(interp, tablePtr->tkwin, tableConfigSpecs, (char *)tablePtr, argv[0], 0); } if (Tk_ConfigureWidget(interp, tablePtr->tkwin, tableConfigSpecs, argc, argv, (char *)tablePtr, TK_CONFIG_ARGV_ONLY) != TCL_OK) { return TCL_ERROR; } /* Arrange for the table layout to be computed at the next idle point. */ tablePtr->flags |= REQUEST_LAYOUT; EventuallyArrangeTable(tablePtr); return TCL_OK; } static void PrintTable(tablePtr, resultPtr) Table *tablePtr; Tcl_DString *resultPtr; { char string[200]; if ((tablePtr->padLeft != TABLE_DEF_PAD) || (tablePtr->padRight != TABLE_DEF_PAD)) { sprintf(string, " -padx {%d %d}", tablePtr->padLeft, tablePtr->padRight); Tcl_DStringAppend(resultPtr, string, -1); } if ((tablePtr->padTop != TABLE_DEF_PAD) || (tablePtr->padBottom != TABLE_DEF_PAD)) { sprintf(string, " -pady {%d %d}", tablePtr->padTop, tablePtr->padBottom); Tcl_DStringAppend(resultPtr, string, -1); } if (!tablePtr->propagate) { Tcl_DStringAppend(resultPtr, " -propagate no", -1); } if ((tablePtr->reqWidth.min != LIMITS_MIN) || (tablePtr->reqWidth.nom != LIMITS_NOM) || (tablePtr->reqWidth.max != LIMITS_MAX)) { Tcl_DStringAppend(resultPtr, " -reqwidth {%s}", -1); Tcl_DStringAppend(resultPtr, NameOfLimits(&(tablePtr->reqWidth)), -1); } if ((tablePtr->reqHeight.min != LIMITS_MIN) || (tablePtr->reqHeight.nom != LIMITS_NOM) || (tablePtr->reqHeight.max != LIMITS_MAX)) { Tcl_DStringAppend(resultPtr, " -reqheight {%s}", -1); Tcl_DStringAppend(resultPtr, NameOfLimits(&(tablePtr->reqHeight)), -1); } } /* * ---------------------------------------------------------------------------- * * DestroyPartitions -- * * Clear each of the lists managing the entries. The entries in * the lists of row and column spans are themselves lists which * need to be cleared. * * ---------------------------------------------------------------------------- */ static void DestroyPartitions(infoPtr) PartitionInfo *infoPtr; { if (infoPtr->list != NULL) { Blt_Chain *chainPtr; Blt_ListNode node; for (node = Blt_ListFirstNode(infoPtr->list); node != NULL; node = Blt_ListNextNode(node)) { chainPtr = (Blt_Chain *)Blt_ListGetValue(node); if (chainPtr != NULL) { Blt_ChainDestroy(chainPtr); } } Blt_ListDestroy(infoPtr->list); } if (infoPtr->chainPtr != NULL) { Blt_ChainLink *linkPtr; RowColumn *rcPtr; for (linkPtr = Blt_ChainFirstLink(infoPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); Blt_Free(rcPtr); } Blt_ChainDestroy(infoPtr->chainPtr); } } /* * ---------------------------------------------------------------------------- * * DestroyTable -- * * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release to * clean up the Table structure at a safe time (when no-one is using * it anymore). * * Results: * None. * * Side effects: * Everything associated with the table geometry manager is freed up. * * ---------------------------------------------------------------------------- */ static void DestroyTable(dataPtr) DestroyData dataPtr; /* Table structure */ { Blt_ChainLink *linkPtr; Entry *entryPtr; Table *tablePtr = (Table *)dataPtr; /* Release the chain of entries. */ for (linkPtr = Blt_ChainFirstLink(tablePtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { entryPtr = Blt_ChainGetValue(linkPtr); entryPtr->linkPtr = NULL; /* Don't disrupt this chain of entries */ DestroyEntry(entryPtr); } Blt_ChainDestroy(tablePtr->chainPtr); DestroyPartitions(&(tablePtr->rowInfo)); DestroyPartitions(&(tablePtr->columnInfo)); Blt_DeleteHashTable(&(tablePtr->entryTable)); if (tablePtr->hashPtr != NULL) { Blt_DeleteHashEntry(tablePtr->tablePtr, tablePtr->hashPtr); } Blt_Free(tablePtr); } /* * ---------------------------------------------------------------------------- * * BinEntry -- * * Adds the entry to the lists of both row and column spans. The * layout of the table is done in order of partition spans, from * shorted to longest. The widgets spanning a particular number of * partitions are stored in a linked list. Each list is in turn, * contained within a master list. * * Results: * None. * * Side effects: * The entry is added to both the lists of row and columns spans. * This will effect the layout of the widgets. * * ---------------------------------------------------------------------------- */ static void BinEntry(tablePtr, entryPtr) Table *tablePtr; Entry *entryPtr; { Blt_ListNode node; Blt_List list; Blt_Chain *chainPtr; int key; /* * Remove the entry from both row and column lists. It will be * re-inserted into the table at the new position. */ if (entryPtr->column.linkPtr != NULL) { Blt_ChainUnlinkLink(entryPtr->column.chainPtr, entryPtr->column.linkPtr); } if (entryPtr->row.linkPtr != NULL) { Blt_ChainUnlinkLink(entryPtr->row.chainPtr, entryPtr->row.linkPtr); } list = tablePtr->rowInfo.list; key = 0; /* Initialize key to bogus span */ for (node = Blt_ListFirstNode(list); node != NULL; node = Blt_ListNextNode(node)) { key = (int)Blt_ListGetKey(node); if (entryPtr->row.span <= key) { break; } } if (key != entryPtr->row.span) { Blt_ListNode newNode; /* * Create a new list (bucket) to hold entries of that size * span and and link it into the list of buckets. */ newNode = Blt_ListCreateNode(list, (char *)entryPtr->row.span); Blt_ListSetValue(newNode, (char *)Blt_ChainCreate()); Blt_ListLinkBefore(list, newNode, node); node = newNode; } chainPtr = (Blt_Chain *) Blt_ListGetValue(node); if (entryPtr->row.linkPtr == NULL) { entryPtr->row.linkPtr = Blt_ChainAppend(chainPtr, entryPtr); } else { Blt_ChainLinkBefore(chainPtr, entryPtr->row.linkPtr, NULL); } entryPtr->row.chainPtr = chainPtr; list = tablePtr->columnInfo.list; key = 0; for (node = Blt_ListFirstNode(list); node != NULL; node = Blt_ListNextNode(node)) { key = (int)Blt_ListGetKey(node); if (entryPtr->column.span <= key) { break; } } if (key != entryPtr->column.span) { Blt_ListNode newNode; /* * Create a new list (bucket) to hold entries of that size * span and and link it into the list of buckets. */ newNode = Blt_ListCreateNode(list, (char *)entryPtr->column.span); Blt_ListSetValue(newNode, (char *)Blt_ChainCreate()); Blt_ListLinkBefore(list, newNode, node); node = newNode; } chainPtr = (Blt_Chain *) Blt_ListGetValue(node); /* Add the new entry to the span bucket */ if (entryPtr->column.linkPtr == NULL) { entryPtr->column.linkPtr = Blt_ChainAppend(chainPtr, entryPtr); } else { Blt_ChainLinkBefore(chainPtr, entryPtr->column.linkPtr, NULL); } entryPtr->column.chainPtr = chainPtr; } /* * ---------------------------------------------------------------------------- * * ParseIndex -- * * Parse the entry index string and return the row and column * numbers in their respective parameters. The format of a table * entry index is row,column where row is the row number and * column is the column number. Rows and columns are numbered * starting from zero. * * Results: * Returns a standard Tcl result. If TCL_OK is returned, the row * and column numbers are returned via rowPtr and columnPtr * respectively. * * ---------------------------------------------------------------------------- */ static int ParseIndex(interp, string, rowPtr, columnPtr) Tcl_Interp *interp; char *string; int *rowPtr, *columnPtr; { char *comma; long row, column; int result; comma = strchr(string, ','); if (comma == NULL) { Tcl_AppendResult(interp, "bad index \"", string, "\": should be \"row,column\"", (char *)NULL); return TCL_ERROR; } *comma = '\0'; result = ((Tcl_ExprLong(interp, string, &row) != TCL_OK) || (Tcl_ExprLong(interp, comma + 1, &column) != TCL_OK)); *comma = ','; /* Repair the argument */ if (result) { return TCL_ERROR; } if ((row < 0) || (row > (long)USHRT_MAX)) { Tcl_AppendResult(interp, "bad index \"", string, "\": row is out of range", (char *)NULL); return TCL_ERROR; } if ((column < 0) || (column > (long)USHRT_MAX)) { Tcl_AppendResult(interp, "bad index \"", string, "\": column is out of range", (char *)NULL); return TCL_ERROR; } *rowPtr = (int)row; *columnPtr = (int)column; return TCL_OK; } /* * ---------------------------------------------------------------------------- * * ManageEntry -- * * Inserts the given widget into the table at a given row and * column position. The widget can already be managed by this or * another table. The widget will be simply moved to the new * location in this table. * * The new widget is inserted into both a hash table (this is * used to locate the information associated with the widget) and * a list (used to indicate relative ordering of widgets). * * Results: * Returns a standard Tcl result. If an error occurred, TCL_ERROR is * returned and an error message is left in interp->result. * * Side Effects: * The table is re-computed and arranged at the next idle point. * * ---------------------------------------------------------------------------- */ static int ManageEntry(interp, tablePtr, tkwin, row, column, argc, argv) Tcl_Interp *interp; Table *tablePtr; Tk_Window tkwin; int row, column; int argc; char **argv; { Entry *entryPtr; int result = TCL_OK; entryPtr = FindEntry(tablePtr, tkwin); if ((entryPtr != NULL) && (entryPtr->tablePtr != tablePtr)) { /* The entry for the widget already exists. If it's * managed by another table, delete it. */ DestroyEntry(entryPtr); entryPtr = NULL; } if (entryPtr == NULL) { entryPtr = CreateEntry(tablePtr, tkwin); if (entryPtr == NULL) { return TCL_ERROR; } } if (argc > 0) { result = Tk_ConfigureWidget(tablePtr->interp, entryPtr->tkwin, entryConfigSpecs, argc, argv, (char *)entryPtr, TK_CONFIG_ARGV_ONLY); } if ((entryPtr->column.span < 1) || (entryPtr->row.span < 1)) { Tcl_AppendResult(tablePtr->interp, "bad span specified for \"", Tk_PathName(tkwin), "\"", (char *)NULL); DestroyEntry(entryPtr); return TCL_ERROR; } entryPtr->column.rcPtr = InitSpan(&(tablePtr->columnInfo), column, entryPtr->column.span); entryPtr->row.rcPtr = InitSpan(&(tablePtr->rowInfo), row, entryPtr->row.span); /* * Insert the entry into both the row and column layout lists */ BinEntry(tablePtr, entryPtr); return result; } /* * ---------------------------------------------------------------------------- * * BuildTable -- * * Processes an argv/argc list of table entries to add and * configure new widgets into the table. A table entry consists * of the widget path name, table index, and optional * configuration options. The first argument in the argv list is * the name of the table. If no table exists for the given * widget, a new one is created. * * Results: * Returns a standard Tcl result. If an error occurred, * TCL_ERROR is returned and an error message is left in * interp->result. * * Side Effects: * Memory is allocated, a new table is possibly created, etc. * The table is re-computed and arranged at the next idle point. * * ---------------------------------------------------------------------------- */ static int BuildTable(tablePtr, interp, argc, argv) Table *tablePtr; /* Table to manage new widgets */ Tcl_Interp *interp; /* Interpreter to report errors back to */ int argc; /* */ char **argv; /* List of widgets, indices, and options */ { Tk_Window tkwin; int row, column; int nextRow, nextColumn; register int i; /* Process any options specific to the table */ for (i = 2; i < argc; i += 2) { if (argv[i][0] != '-') { break; } } if (i > argc) { i = argc; } if (i > 2) { if (ConfigureTable(tablePtr, interp, i - 2, argv + 2) != TCL_OK) { return TCL_ERROR; } } nextRow = tablePtr->nRows; nextColumn = 0; argc -= i, argv += i; while (argc > 0) { /* * Allow the name of the widget and row/column index to be * specified in any order. */ if (argv[0][0] == '.') { tkwin = Tk_NameToWindow(interp, argv[0], tablePtr->tkwin); if (tkwin == NULL) { return TCL_ERROR; } if ((argc == 1) || (argv[1][0] == '-')) { /* No row,column index, use defaults instead */ row = nextRow, column = nextColumn; argc--, argv++; } else { if (ParseIndex(interp, argv[1], &row, &column) != TCL_OK) { return TCL_ERROR; /* Invalid row,column index */ } /* Skip over the widget pathname and table index. */ argc -= 2, argv += 2; } } else { if (ParseIndex(interp, argv[0], &row, &column) != TCL_OK) { return TCL_ERROR; } if (argc == 1) { Tcl_AppendResult(interp, "missing widget pathname after \"", argv[0], "\"", (char *)NULL); return TCL_ERROR; } tkwin = Tk_NameToWindow(interp, argv[1], tablePtr->tkwin); if (tkwin == NULL) { return TCL_ERROR; } /* Skip over the widget pathname and table index. */ argc -= 2, argv += 2; } /* Find the end of the widget's option-value pairs */ for (i = 0; i < argc; i += 2) { if (argv[i][0] != '-') { break; } } if (i > argc) { i = argc; } if (ManageEntry(interp, tablePtr, tkwin, row, column, i, argv) != TCL_OK) { return TCL_ERROR; } nextColumn = column + 1; argc -= i, argv += i; } /* Arrange for the new table layout to be calculated. */ tablePtr->flags |= REQUEST_LAYOUT; EventuallyArrangeTable(tablePtr); Tcl_SetResult(interp, Tk_PathName(tablePtr->tkwin), TCL_VOLATILE); return TCL_OK; } /* * ---------------------------------------------------------------------------- * * ParseItem -- * * Parses a string representing an item in the table. An item * may be one of the following: * Rn - Row index, where n is the index of row * Cn - Column index, where n is the index of column * r,c - Cell index, where r is the row index and c * is the column index. * * Results: * Returns a standard Tcl result. If no error occurred, TCL_OK * is returned. *RowPtr* will return the row index. *ColumnPtr* * will return the column index. If the row or column index is * not applicable, -1 is returned via *rowPtr* or *columnPtr*. * * ---------------------------------------------------------------------------- */ static int ParseItem(tablePtr, string, rowPtr, columnPtr) Table *tablePtr; char *string; int *rowPtr, *columnPtr; { char c; long partNum; c = tolower(string[0]); *rowPtr = *columnPtr = -1; if (c == 'r') { if (Tcl_ExprLong(tablePtr->interp, string + 1, &partNum) != TCL_OK) { return TCL_ERROR; } if ((partNum < 0) || (partNum >= tablePtr->nRows)) { Tcl_AppendResult(tablePtr->interp, "row index \"", string, "\" is out of range", (char *)NULL); return TCL_ERROR; } *rowPtr = (int)partNum; } else if (c == 'c') { if (Tcl_ExprLong(tablePtr->interp, string + 1, &partNum) != TCL_OK) { return TCL_ERROR; } if ((partNum < 0) || (partNum >= tablePtr->nColumns)) { Tcl_AppendResult(tablePtr->interp, "column index \"", string, "\" is out of range", (char *)NULL); return TCL_ERROR; } *columnPtr = (int)partNum; } else { if (ParseIndex(tablePtr->interp, string, rowPtr, columnPtr) != TCL_OK) { return TCL_ERROR; /* Invalid row,column index */ } if ((*rowPtr < 0) || (*rowPtr >= tablePtr->nRows) || (*columnPtr < 0) || (*columnPtr >= tablePtr->nColumns)) { Tcl_AppendResult(tablePtr->interp, "index \"", string, "\" is out of range", (char *)NULL); return TCL_ERROR; } } return TCL_OK; } /* * ---------------------------------------------------------------------------- * * TranslateAnchor -- * * Translate the coordinates of a given bounding box based upon * the anchor specified. The anchor indicates where the given xy * position is in relation to the bounding box. * * nw --- n --- ne * | | x,y ---+ * w center e | | * | | +-----+ * sw --- s --- se * * Results: * The translated coordinates of the bounding box are returned. * * ---------------------------------------------------------------------------- */ static void TranslateAnchor(dx, dy, anchor, xPtr, yPtr) int dx, dy; /* Difference between outer and inner regions */ Tk_Anchor anchor; /* Direction of the anchor */ int *xPtr, *yPtr; { int x, y; x = y = 0; switch (anchor) { case TK_ANCHOR_NW: /* Upper left corner */ break; case TK_ANCHOR_W: /* Left center */ y = (dy / 2); break; case TK_ANCHOR_SW: /* Lower left corner */ y = dy; break; case TK_ANCHOR_N: /* Top center */ x = (dx / 2); break; case TK_ANCHOR_CENTER: /* Centered */ x = (dx / 2); y = (dy / 2); break; case TK_ANCHOR_S: /* Bottom center */ x = (dx / 2); y = dy; break; case TK_ANCHOR_NE: /* Upper right corner */ x = dx; break; case TK_ANCHOR_E: /* Right center */ x = dx; y = (dy / 2); break; case TK_ANCHOR_SE: /* Lower right corner */ x = dx; y = dy; break; } *xPtr = (*xPtr) + x; *yPtr = (*yPtr) + y; } /* * ---------------------------------------------------------------------------- * * GetReqWidth -- * * Returns the width requested by the widget starting in the * given entry. The requested space also includes any internal * padding which has been designated for this widget. * * The requested width of the widget is always bounded by the limits * set in entryPtr->reqWidth. * * Results: * Returns the requested width of the widget. * * ---------------------------------------------------------------------------- */ static int GetReqWidth(entryPtr) Entry *entryPtr; { int width; width = Tk_ReqWidth(entryPtr->tkwin) + (2 * entryPtr->ipadX); width = GetBoundedWidth(width, &(entryPtr->reqWidth)); return width; } /* * ---------------------------------------------------------------------------- * * GetReqHeight -- * * Returns the height requested by the widget starting in the * given entry. The requested space also includes any internal * padding which has been designated for this widget. * * The requested height of the widget is always bounded by the * limits set in entryPtr->reqHeight. * * Results: * Returns the requested height of the widget. * * ---------------------------------------------------------------------------- */ static int GetReqHeight(entryPtr) Entry *entryPtr; { int height; height = Tk_ReqHeight(entryPtr->tkwin) + (2 * entryPtr->ipadY); height = GetBoundedHeight(height, &(entryPtr->reqHeight)); return height; } /* * ---------------------------------------------------------------------------- * * GetTotalSpan -- * * Sums the row/column space requirements for the entire table. * * Results: * Returns the space currently used in the span of partitions. * * ---------------------------------------------------------------------------- */ static int GetTotalSpan(infoPtr) PartitionInfo *infoPtr; { register int spaceUsed; Blt_ChainLink *linkPtr; RowColumn *rcPtr; /* Start of partitions */ spaceUsed = 0; for (linkPtr = Blt_ChainFirstLink(infoPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); spaceUsed += rcPtr->size; } return spaceUsed; } /* * ---------------------------------------------------------------------------- * * GetSpan -- * * Determines the space used by rows/columns for an entry. * * Results: * Returns the space currently used in the span of partitions. * * ---------------------------------------------------------------------------- */ static int GetSpan(infoPtr, entryPtr) PartitionInfo *infoPtr; Entry *entryPtr; { RowColumn *startPtr; register int spaceUsed; int count; Blt_ChainLink *linkPtr; RowColumn *rcPtr; /* Start of partitions */ int span; /* Number of partitions spanned */ if (infoPtr->type == rowUid) { rcPtr = entryPtr->row.rcPtr; span = entryPtr->row.span; } else { rcPtr = entryPtr->column.rcPtr; span = entryPtr->column.span; } count = spaceUsed = 0; linkPtr = rcPtr->linkPtr; startPtr = Blt_ChainGetValue(linkPtr); for ( /*empty*/ ; (linkPtr != NULL) && (count < span); linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); spaceUsed += rcPtr->size; count++; } /* * Subtract off the padding on either side of the span, since the * widget can't grow into it. */ spaceUsed -= (startPtr->pad.side1 + rcPtr->pad.side2 + infoPtr->ePad); return spaceUsed; } /* * ---------------------------------------------------------------------------- * * GrowSpan -- * * Expand the span by the amount of the extra space needed. This * procedure is used in LayoutPartitions to grow the partitions * to their minimum nominal size, starting from a zero width and * height space. * * This looks more complicated than it really is. The idea is to * make the size of the partitions correspond to the smallest * entry spans. For example, if widget A is in column 1 and * widget B spans both columns 0 and 1, any extra space needed to * fit widget B should come from column 0. * * On the first pass we try to add space to partitions which have * not been touched yet (i.e. have no nominal size). Since the * row and column lists are sorted in ascending order of the * number of rows or columns spanned, the space is distributed * amongst the smallest spans first. * * The second pass handles the case of widgets which have the * same span. For example, if A and B, which span the same * number of partitions are the only widgets to span column 1, * column 1 would grow to contain the bigger of the two slices of * space. * * If there is still extra space after the first two passes, this * means that there were no partitions of with no widget spans or * the same order span that could be expanded. The third pass * will try to remedy this by parcelling out the left over space * evenly among the rest of the partitions. * * On each pass, we have to keep iterating over the span, evenly * doling out slices of extra space, because we may hit partition * limits as space is donated. In addition, if there are left * over pixels because of round-off, this will distribute them as * evenly as possible. For the worst case, it will take *span* * passes to expand the span. * * Results: * None. * * Side Effects: * The partitions in the span may be expanded. * * ---------------------------------------------------------------------------- */ static void GrowSpan(infoPtr, entryPtr, growth) PartitionInfo *infoPtr; Entry *entryPtr; int growth; /* The amount of extra space needed to * grow the span. */ { register RowColumn *rcPtr; Blt_ChainLink *linkPtr; int spaceLeft, ration; int nOpen; /* # of partitions with space available */ register int n; RowColumn *startPtr; /* Starting (column/row) partition */ int span; /* Number of partitions in the span */ if (infoPtr->type == rowUid) { startPtr = entryPtr->row.rcPtr; span = entryPtr->row.span; } else { startPtr = entryPtr->column.rcPtr; span = entryPtr->column.span; } /* * ------------------------------------------------------------------------ * * Pass 1: First add space to rows/columns that haven't determined * their nominal sizes yet. * * ------------------------------------------------------------------------ */ nOpen = 0; /* Find out how many partitions have no size yet */ linkPtr = startPtr->linkPtr; for (n = 0; n < span; n++) { rcPtr = Blt_ChainGetValue(linkPtr); if ((rcPtr->nomSize == LIMITS_NOM) && (rcPtr->maxSize > rcPtr->size)) { nOpen++; } linkPtr = Blt_ChainNextLink(linkPtr); } while ((nOpen > 0) && (growth > 0)) { ration = growth / nOpen; if (ration == 0) { ration = 1; } linkPtr = startPtr->linkPtr; for (n = 0; (n < span) && (growth > 0); n++) { rcPtr = Blt_ChainGetValue(linkPtr); spaceLeft = rcPtr->maxSize - rcPtr->size; if ((rcPtr->nomSize == LIMITS_NOM) && (spaceLeft > 0)) { if (ration < spaceLeft) { growth -= ration; rcPtr->size += ration; } else { growth -= spaceLeft; rcPtr->size += spaceLeft; nOpen--; } rcPtr->minSpan = span; rcPtr->control = entryPtr; } linkPtr = Blt_ChainNextLink(linkPtr); } } /* * ------------------------------------------------------------------------ * * Pass 2: Add space to partitions which have the same minimum span * * ------------------------------------------------------------------------ */ nOpen = 0; linkPtr = startPtr->linkPtr; for (n = 0; n < span; n++) { rcPtr = Blt_ChainGetValue(linkPtr); if ((rcPtr->minSpan == span) && (rcPtr->maxSize > rcPtr->size)) { nOpen++; } linkPtr = Blt_ChainNextLink(linkPtr); } while ((nOpen > 0) && (growth > 0)) { ration = growth / nOpen; if (ration == 0) { ration = 1; } linkPtr = startPtr->linkPtr; for (n = 0; (n < span) && (growth > 0); n++) { rcPtr = Blt_ChainGetValue(linkPtr); spaceLeft = rcPtr->maxSize - rcPtr->size; if ((rcPtr->minSpan == span) && (spaceLeft > 0)) { if (ration < spaceLeft) { growth -= ration; rcPtr->size += ration; } else { growth -= spaceLeft; rcPtr->size += spaceLeft; nOpen--; } rcPtr->control = entryPtr; } linkPtr = Blt_ChainNextLink(linkPtr); } } /* * ------------------------------------------------------------------------ * * Pass 3: Try to expand all the partitions with space still available * * ------------------------------------------------------------------------ */ /* Find out how many partitions still have space available */ nOpen = 0; linkPtr = startPtr->linkPtr; for (n = 0; n < span; n++) { rcPtr = Blt_ChainGetValue(linkPtr); if ((rcPtr->resize & RESIZE_EXPAND) && (rcPtr->maxSize > rcPtr->size)) { nOpen++; } /* Set the nominal size of the row/column. */ rcPtr->nomSize = rcPtr->size; linkPtr = Blt_ChainNextLink(linkPtr); } while ((nOpen > 0) && (growth > 0)) { ration = growth / nOpen; if (ration == 0) { ration = 1; } linkPtr = startPtr->linkPtr; for (n = 0; (n < span) && (growth > 0); n++) { rcPtr = Blt_ChainGetValue(linkPtr); linkPtr = Blt_ChainNextLink(linkPtr); if (!(rcPtr->resize & RESIZE_EXPAND)) { continue; } spaceLeft = rcPtr->maxSize - rcPtr->size; if (spaceLeft > 0) { if (ration < spaceLeft) { growth -= ration; rcPtr->size += ration; } else { growth -= spaceLeft; rcPtr->size += spaceLeft; nOpen--; } rcPtr->nomSize = rcPtr->size; rcPtr->control = entryPtr; } } } } /* * ---------------------------------------------------------------------------- * * AdjustPartitions -- * * Adjust the span by the amount of the extra space needed. If * the amount (adjustSpace) is negative, shrink the span, * otherwise expand it. Size constraints on the partitions may * prevent any or all of the spacing adjustments. * * This is very much like the GrowSpan procedure, but in this * case we are shrinking or expanding all the (row or column) * partitions. It uses a two pass approach, first giving space to * partitions which not are smaller/larger than their nominal * sizes. This is because constraints on the partitions may cause * resizing to be non-linear. * * If there is still extra space, this means that all partitions * are at least to their nominal sizes. The second pass will try * to add/remove the left over space evenly among all the * partitions which still have space available. * * Results: * None. * * Side Effects: * The size of the partitions in the span may be increased or * decreased. * * ---------------------------------------------------------------------------- */ static void AdjustPartitions(infoPtr, adjustment) PartitionInfo *infoPtr; /* Array of (column/row) partitions */ int adjustment; /* The amount of extra space to grow or shrink * the span. If negative, it represents the * amount of space to remove */ { register RowColumn *rcPtr; int ration; /* Amount of space to ration to each * row/column. */ int delta; /* Amount of space needed */ int spaceLeft; /* Amount of space still available */ int size; /* Amount of space requested for a particular * row/column. */ int nOpen; /* Number of rows/columns that still can * be adjusted. */ Blt_Chain *chainPtr; Blt_ChainLink *linkPtr; double totalWeight; chainPtr = infoPtr->chainPtr; /* * ------------------------------------------------------------------------ * * Pass 1: First adjust the size of rows/columns that still haven't * reached their nominal size. * * ------------------------------------------------------------------------ */ delta = adjustment; nOpen = 0; totalWeight = 0.0; for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); if (rcPtr->weight > 0.0) { if (delta < 0) { spaceLeft = rcPtr->size - rcPtr->nomSize; } else { spaceLeft = rcPtr->nomSize - rcPtr->size; } if (spaceLeft > 0) { nOpen++; totalWeight += rcPtr->weight; } } } while ((nOpen > 0) && (totalWeight > 0.0) && (delta != 0)) { ration = (int)(delta / totalWeight); if (ration == 0) { ration = (delta > 0) ? 1 : -1; } for (linkPtr = Blt_ChainFirstLink(chainPtr); (linkPtr != NULL) && (delta != 0); linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); if (rcPtr->weight > 0.0) { spaceLeft = rcPtr->nomSize - rcPtr->size; if (((delta > 0) && (spaceLeft > 0)) || ((delta < 0) && (spaceLeft < 0))) { size = (int)(ration * rcPtr->weight); if (size > delta) { size = delta; } if (ABS(size) < ABS(spaceLeft)) { delta -= size; rcPtr->size += size; } else { delta -= spaceLeft; rcPtr->size += spaceLeft; nOpen--; totalWeight -= rcPtr->weight; } } } } } /* * ------------------------------------------------------------------------ * * Pass 2: Adjust the partitions with space still available * * ------------------------------------------------------------------------ */ nOpen = 0; totalWeight = 0.0; for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); if (rcPtr->weight > 0.0) { if (delta > 0) { spaceLeft = rcPtr->maxSize - rcPtr->size; } else { spaceLeft = rcPtr->size - rcPtr->minSize; } if (spaceLeft > 0) { nOpen++; totalWeight += rcPtr->weight; } } } while ((nOpen > 0) && (totalWeight > 0.0) && (delta != 0)) { ration = (int)(delta / totalWeight); if (ration == 0) { ration = (delta > 0) ? 1 : -1; } linkPtr = Blt_ChainFirstLink(chainPtr); for ( /*empty*/ ; (linkPtr != NULL) && (delta != 0); linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); if (rcPtr->weight > 0.0) { if (delta > 0) { spaceLeft = rcPtr->maxSize - rcPtr->size; } else { spaceLeft = rcPtr->minSize - rcPtr->size; } if (((delta > 0) && (spaceLeft > 0)) || ((delta < 0) && (spaceLeft < 0))) { size = (int)(ration * rcPtr->weight); if (size > delta) { size = delta; } if (ABS(size) < ABS(spaceLeft)) { delta -= size; rcPtr->size += size; } else { delta -= spaceLeft; rcPtr->size += spaceLeft; nOpen--; totalWeight -= rcPtr->weight; } } } } } } /* * ---------------------------------------------------------------------------- * * ResetPartitions -- * * Sets/resets the size of each row and column partition to the * minimum limit of the partition (this is usually zero). This * routine gets called when new widgets are added, deleted, or * resized. * * Results: * None. * * Side Effects: * The size of each partition is re-initialized to its minimum * size. * * ---------------------------------------------------------------------------- */ static void ResetPartitions(tablePtr, infoPtr, limitsProc) Table *tablePtr; PartitionInfo *infoPtr; LimitsProc *limitsProc; { register RowColumn *rcPtr; register Blt_ChainLink *linkPtr; int pad, size; for (linkPtr = Blt_ChainFirstLink(infoPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); /* * The constraint procedure below also has the desired * side-effect of setting the minimum, maximum, and nominal * values to the requested size of its associated widget (if * one exists). */ size = (*limitsProc) (0, &(rcPtr->reqSize)); pad = PADDING(rcPtr->pad) + infoPtr->ePad; if (rcPtr->reqSize.flags & LIMITS_SET_NOM) { /* * This could be done more cleanly. We want to ensure * that the requested nominal size is not overridden when * determining the normal sizes. So temporarily fix min * and max to the nominal size and reset them back later. */ rcPtr->minSize = rcPtr->maxSize = rcPtr->size = rcPtr->nomSize = size + pad; } else { /* The range defaults to 0..MAXINT */ rcPtr->minSize = rcPtr->reqSize.min + pad; rcPtr->maxSize = rcPtr->reqSize.max + pad; rcPtr->nomSize = LIMITS_NOM; rcPtr->size = pad; } rcPtr->minSpan = 0; rcPtr->control = NULL; rcPtr->count = 0; } } /* * ---------------------------------------------------------------------------- * * SetNominalSizes * * Sets the normal sizes for each partition. The partition size * is the requested widget size plus an amount of padding. In * addition, adjust the min/max bounds of the partition depending * upon the resize flags (whether the partition can be expanded * or shrunk from its normal size). * * Results: * Returns the total space needed for the all the partitions. * * Side Effects: * The nominal size of each partition is set. This is later used * to determine how to shrink or grow the table if the container * can't be resized to accommodate the exact size requirements * of all the partitions. * * ---------------------------------------------------------------------------- */ static int SetNominalSizes(tablePtr, infoPtr) Table *tablePtr; PartitionInfo *infoPtr; { register RowColumn *rcPtr; Blt_ChainLink *linkPtr; int pad, size, total; total = 0; for (linkPtr = Blt_ChainFirstLink(infoPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); pad = PADDING(rcPtr->pad) + infoPtr->ePad; /* * Restore the real bounds after temporarily setting nominal * size. These values may have been set in ResetPartitions to * restrict the size of the paritition to the requested range. */ rcPtr->minSize = rcPtr->reqSize.min + pad; rcPtr->maxSize = rcPtr->reqSize.max + pad; size = rcPtr->size; if (size > rcPtr->maxSize) { size = rcPtr->maxSize; } else if (size < rcPtr->minSize) { size = rcPtr->minSize; } if ((infoPtr->ePad > 0) && (size < tablePtr->editPtr->minSize)) { size = tablePtr->editPtr->minSize; } rcPtr->nomSize = rcPtr->size = size; /* * If a partition can't be resized (to either expand or * shrink), hold its respective limit at its normal size. */ if (!(rcPtr->resize & RESIZE_EXPAND)) { rcPtr->maxSize = rcPtr->nomSize; } if (!(rcPtr->resize & RESIZE_SHRINK)) { rcPtr->minSize = rcPtr->nomSize; } if (rcPtr->control == NULL) { /* If a row/column contains no entries, then its size * should be locked. */ if (rcPtr->resize & RESIZE_VIRGIN) { rcPtr->maxSize = rcPtr->minSize = size; } else { if (!(rcPtr->resize & RESIZE_EXPAND)) { rcPtr->maxSize = size; } if (!(rcPtr->resize & RESIZE_SHRINK)) { rcPtr->minSize = size; } } rcPtr->nomSize = size; } total += rcPtr->nomSize; } return total; } /* * ---------------------------------------------------------------------------- * * LockPartitions * * Sets the maximum size of a row or column, if the partition * has a widget that controls it. * * Results: * None. * * ---------------------------------------------------------------------------- */ static void LockPartitions(infoPtr) PartitionInfo *infoPtr; { register RowColumn *rcPtr; Blt_ChainLink *linkPtr; for (linkPtr = Blt_ChainFirstLink(infoPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); if (rcPtr->control != NULL) { /* Partition is controlled by this widget */ rcPtr->maxSize = rcPtr->size; } } } /* * ---------------------------------------------------------------------------- * * LayoutPartitions -- * * Calculates the normal space requirements for both the row and * column partitions. Each widget is added in order of the * number of rows or columns spanned, which defines the space * needed among in the partitions spanned. * * Results: * None. * * Side Effects: * * The sum of normal sizes set here will be used as the normal size * for the container widget. * * ---------------------------------------------------------------------------- */ static void LayoutPartitions(tablePtr) Table *tablePtr; { register Blt_ListNode node; Blt_Chain *chainPtr; Blt_ChainLink *linkPtr; register Entry *entryPtr; int needed, used, total; PartitionInfo *infoPtr; infoPtr = &(tablePtr->columnInfo); ResetPartitions(tablePtr, infoPtr, GetBoundedWidth); for (node = Blt_ListFirstNode(infoPtr->list); node != NULL; node = Blt_ListNextNode(node)) { chainPtr = (Blt_Chain *) Blt_ListGetValue(node); for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { entryPtr = Blt_ChainGetValue(linkPtr); if (entryPtr->column.control != CONTROL_FULL) { continue; } needed = GetReqWidth(entryPtr) + PADDING(entryPtr->padX) + 2 * (entryPtr->borderWidth + tablePtr->eEntryPad); if (needed <= 0) { continue; } used = GetSpan(infoPtr, entryPtr); if (needed > used) { GrowSpan(infoPtr, entryPtr, needed - used); } } } LockPartitions(infoPtr); for (node = Blt_ListFirstNode(infoPtr->list); node != NULL; node = Blt_ListNextNode(node)) { chainPtr = (Blt_Chain *) Blt_ListGetValue(node); for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { entryPtr = Blt_ChainGetValue(linkPtr); needed = GetReqWidth(entryPtr) + PADDING(entryPtr->padX) + 2 * (entryPtr->borderWidth + tablePtr->eEntryPad); if (entryPtr->column.control >= 0.0) { needed = (int)(needed * entryPtr->column.control); } if (needed <= 0) { continue; } used = GetSpan(infoPtr, entryPtr); if (needed > used) { GrowSpan(infoPtr, entryPtr, needed - used); } } } total = SetNominalSizes(tablePtr, infoPtr); tablePtr->normal.width = GetBoundedWidth(total, &(tablePtr->reqWidth)) + PADDING(tablePtr->padX) + 2 * (tablePtr->eTablePad + Tk_InternalBorderWidth(tablePtr->tkwin)); infoPtr = &(tablePtr->rowInfo); ResetPartitions(tablePtr, infoPtr, GetBoundedHeight); for (node = Blt_ListFirstNode(infoPtr->list); node != NULL; node = Blt_ListNextNode(node)) { chainPtr = (Blt_Chain *) Blt_ListGetValue(node); for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { entryPtr = Blt_ChainGetValue(linkPtr); if (entryPtr->row.control != CONTROL_FULL) { continue; } needed = GetReqHeight(entryPtr) + PADDING(entryPtr->padY) + 2 * (entryPtr->borderWidth + tablePtr->eEntryPad); if (needed <= 0) { continue; } used = GetSpan(infoPtr, entryPtr); if (needed > used) { GrowSpan(infoPtr, entryPtr, needed - used); } } } LockPartitions(&(tablePtr->rowInfo)); for (node = Blt_ListFirstNode(infoPtr->list); node != NULL; node = Blt_ListNextNode(node)) { chainPtr = Blt_ChainGetValue(node); for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { entryPtr = Blt_ChainGetValue(linkPtr); needed = GetReqHeight(entryPtr) + PADDING(entryPtr->padY) + 2 * (entryPtr->borderWidth + tablePtr->eEntryPad); if (entryPtr->row.control >= 0.0) { needed = (int)(needed * entryPtr->row.control); } if (needed <= 0) { continue; } used = GetSpan(infoPtr, entryPtr); if (needed > used) { GrowSpan(infoPtr, entryPtr, needed - used); } } } total = SetNominalSizes(tablePtr, infoPtr); tablePtr->normal.height = GetBoundedHeight(total, &(tablePtr->reqHeight)) + PADDING(tablePtr->padY) + 2 * (tablePtr->eTablePad + Tk_InternalBorderWidth(tablePtr->tkwin)); } /* * ---------------------------------------------------------------------------- * * ArrangeEntries * * Places each widget at its proper location. First determines * the size and position of the each widget. It then considers the * following: * * 1. translation of widget position its parent widget. * 2. fill style * 3. anchor * 4. external and internal padding * 5. widget size must be greater than zero * * Results: * None. * * Side Effects: * The size of each partition is re-initialized its minimum size. * * ---------------------------------------------------------------------------- */ static void ArrangeEntries(tablePtr) Table *tablePtr; /* Table widget structure */ { register Blt_ChainLink *linkPtr; register Entry *entryPtr; register int spanWidth, spanHeight; int x, y; int winWidth, winHeight; int dx, dy; int maxX, maxY; int extra; maxX = tablePtr->container.width - (Tk_InternalBorderWidth(tablePtr->tkwin) + tablePtr->padRight + tablePtr->eTablePad); maxY = tablePtr->container.height - (Tk_InternalBorderWidth(tablePtr->tkwin) + tablePtr->padBottom + tablePtr->eTablePad); for (linkPtr = Blt_ChainFirstLink(tablePtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { entryPtr = Blt_ChainGetValue(linkPtr); x = entryPtr->column.rcPtr->offset + entryPtr->column.rcPtr->pad.side1 + entryPtr->padLeft + Tk_Changes(entryPtr->tkwin)->border_width + tablePtr->eEntryPad; y = entryPtr->row.rcPtr->offset + entryPtr->row.rcPtr->pad.side1 + entryPtr->padTop + Tk_Changes(entryPtr->tkwin)->border_width + tablePtr->eEntryPad; /* * Unmap any widgets that start beyond of the right edge of * the container. */ if ((x >= maxX) || (y >= maxY)) { if (Tk_IsMapped(entryPtr->tkwin)) { if (Tk_Parent(entryPtr->tkwin) != tablePtr->tkwin) { Tk_UnmaintainGeometry(entryPtr->tkwin, tablePtr->tkwin); } Tk_UnmapWindow(entryPtr->tkwin); } continue; } extra = 2 * (entryPtr->borderWidth + tablePtr->eEntryPad); spanWidth = GetSpan(&(tablePtr->columnInfo), entryPtr) - (extra + PADDING(entryPtr->padX)); spanHeight = GetSpan(&(tablePtr->rowInfo), entryPtr) - (extra + PADDING(entryPtr->padY)); winWidth = GetReqWidth(entryPtr); winHeight = GetReqHeight(entryPtr); /* * * Compare the widget's requested size to the size of the span. * * 1) If the widget is larger than the span or if the fill flag * is set, make the widget the size of the span. Check that the * new size is within the bounds set for the widget. * * 2) Otherwise, position the widget in the space according to its * anchor. * */ if ((spanWidth <= winWidth) || (entryPtr->fill & FILL_X)) { winWidth = spanWidth; if (winWidth > entryPtr->reqWidth.max) { winWidth = entryPtr->reqWidth.max; } } if ((spanHeight <= winHeight) || (entryPtr->fill & FILL_Y)) { winHeight = spanHeight; if (winHeight > entryPtr->reqHeight.max) { winHeight = entryPtr->reqHeight.max; } } dx = dy = 0; if (spanWidth > winWidth) { dx = (spanWidth - winWidth); } if (spanHeight > winHeight) { dy = (spanHeight - winHeight); } if ((dx > 0) || (dy > 0)) { TranslateAnchor(dx, dy, entryPtr->anchor, &x, &y); } /* * Clip the widget at the bottom and/or right edge of the * container. */ if (winWidth > (maxX - x)) { winWidth = (maxX - x); } if (winHeight > (maxY - y)) { winHeight = (maxY - y); } /* * If the widget is too small (i.e. it has only an external * border) then unmap it. */ if ((winWidth < 1) || (winHeight < 1)) { if (Tk_IsMapped(entryPtr->tkwin)) { if (tablePtr->tkwin != Tk_Parent(entryPtr->tkwin)) { Tk_UnmaintainGeometry(entryPtr->tkwin, tablePtr->tkwin); } Tk_UnmapWindow(entryPtr->tkwin); } continue; } /* * Resize and/or move the widget as necessary. */ entryPtr->x = x; entryPtr->y = y; if (tablePtr->tkwin != Tk_Parent(entryPtr->tkwin)) { Tk_MaintainGeometry(entryPtr->tkwin, tablePtr->tkwin, x, y, winWidth, winHeight); } else { if ((x != Tk_X(entryPtr->tkwin)) || (y != Tk_Y(entryPtr->tkwin)) || (winWidth != Tk_Width(entryPtr->tkwin)) || (winHeight != Tk_Height(entryPtr->tkwin))) { Tk_MoveResizeWindow(entryPtr->tkwin, x, y, winWidth, winHeight); } if (!Tk_IsMapped(entryPtr->tkwin)) { Tk_MapWindow(entryPtr->tkwin); } } } } /* * ---------------------------------------------------------------------------- * * ArrangeTable -- * * * Results: * None. * * Side Effects: * The widgets in the table are possibly resized and redrawn. * * ---------------------------------------------------------------------------- */ static void ArrangeTable(clientData) ClientData clientData; { Table *tablePtr = clientData; int width, height; int offset; int padX, padY; int outerPad; RowColumn *columnPtr, *rowPtr; Blt_ChainLink *linkPtr; #ifdef notdef fprintf(stderr, "ArrangeTable(%s)\n", Tk_PathName(tablePtr->tkwin)); #endif Tcl_Preserve(tablePtr); tablePtr->flags &= ~ARRANGE_PENDING; tablePtr->rowInfo.ePad = tablePtr->columnInfo.ePad = tablePtr->eTablePad = tablePtr->eEntryPad = 0; if (tablePtr->editPtr != NULL) { tablePtr->rowInfo.ePad = tablePtr->columnInfo.ePad = tablePtr->editPtr->gridLineWidth; tablePtr->eTablePad = tablePtr->editPtr->gridLineWidth; tablePtr->eEntryPad = tablePtr->editPtr->entryPad; } /* * If the table has no children anymore, then don't do anything at * all: just leave the container widget's size as-is. */ if ((Blt_ChainGetLength(tablePtr->chainPtr) == 0) || (tablePtr->tkwin == NULL)) { Tcl_Release(tablePtr); return; } if (tablePtr->flags & REQUEST_LAYOUT) { tablePtr->flags &= ~REQUEST_LAYOUT; LayoutPartitions(tablePtr); } /* * Initially, try to fit the partitions exactly into the container * by resizing the container. If the widget's requested size is * different, send a request to the container widget's geometry * manager to resize. */ if ((tablePtr->propagate) && ((tablePtr->normal.width != Tk_ReqWidth(tablePtr->tkwin)) || (tablePtr->normal.height != Tk_ReqHeight(tablePtr->tkwin)))) { Tk_GeometryRequest(tablePtr->tkwin, tablePtr->normal.width, tablePtr->normal.height); EventuallyArrangeTable(tablePtr); Tcl_Release(tablePtr); return; } /* * Save the width and height of the container so we know when its * size has changed during ConfigureNotify events. */ tablePtr->container.width = Tk_Width(tablePtr->tkwin); tablePtr->container.height = Tk_Height(tablePtr->tkwin); outerPad = 2 * (Tk_InternalBorderWidth(tablePtr->tkwin) + tablePtr->eTablePad); padX = outerPad + tablePtr->columnInfo.ePad + PADDING(tablePtr->padX); padY = outerPad + tablePtr->rowInfo.ePad + PADDING(tablePtr->padY); width = GetTotalSpan(&(tablePtr->columnInfo)) + padX; height = GetTotalSpan(&(tablePtr->rowInfo)) + padY; /* * If the previous geometry request was not fulfilled (i.e. the * size of the container is different from partitions' space * requirements), try to adjust size of the partitions to fit the * widget. */ if (tablePtr->container.width != width) { AdjustPartitions(&(tablePtr->columnInfo), tablePtr->container.width - width); width = GetTotalSpan(&(tablePtr->columnInfo)) + padX; } if (tablePtr->container.height != height) { AdjustPartitions(&(tablePtr->rowInfo), tablePtr->container.height - height); height = GetTotalSpan(&(tablePtr->rowInfo)) + padY; } /* * If after adjusting the size of the partitions the space * required does not equal the size of the widget, do one of the * following: * * 1) If it's smaller, center the table in the widget. * 2) If it's bigger, clip the partitions that extend beyond * the edge of the container. * * Set the row and column offsets (including the container's * internal border width). To be used later when positioning the * widgets. */ offset = Tk_InternalBorderWidth(tablePtr->tkwin) + tablePtr->padLeft + tablePtr->eTablePad; if (width < tablePtr->container.width) { offset += (tablePtr->container.width - width) / 2; } for (linkPtr = Blt_ChainFirstLink(tablePtr->columnInfo.chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { columnPtr = Blt_ChainGetValue(linkPtr); columnPtr->offset = offset + tablePtr->columnInfo.ePad; offset += columnPtr->size; } offset = Tk_InternalBorderWidth(tablePtr->tkwin) + tablePtr->padTop + tablePtr->eTablePad; if (height < tablePtr->container.height) { offset += (tablePtr->container.height - height) / 2; } for (linkPtr = Blt_ChainFirstLink(tablePtr->rowInfo.chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rowPtr = Blt_ChainGetValue(linkPtr); rowPtr->offset = offset + tablePtr->rowInfo.ePad; offset += rowPtr->size; } ArrangeEntries(tablePtr); if (tablePtr->editPtr != NULL) { /* Redraw the editor */ (*tablePtr->editPtr->drawProc) (tablePtr->editPtr); } Tcl_Release(tablePtr); } /* * ---------------------------------------------------------------------------- * * ArrangeOp -- * * Forces layout of the table geometry manager. This is useful * mostly for debugging the geometry manager. You can get the * geometry manager to calculate the normal (requested) width and * height of each row and column. Otherwise, you need to first * withdraw the container widget, invoke "update", and then query * the geometry manager. * * Results: * Returns a standard Tcl result. If the table is successfully * rearranged, TCL_OK is returned. Otherwise, TCL_ERROR is returned * and an error message is left in interp->result. * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ static int ArrangeOp(dataPtr, interp, argc, argv) TableInterpData *dataPtr; /* Interpreter-specific data. */ Tcl_Interp *interp; /* Interpreter to report errors to */ int argc; char **argv; /* Path name of container associated with * the table */ { Table *tablePtr; if (Blt_GetTable(dataPtr, interp, argv[2], &tablePtr) != TCL_OK) { return TCL_ERROR; } tablePtr->flags |= REQUEST_LAYOUT; ArrangeTable(tablePtr); return TCL_OK; } /* * ---------------------------------------------------------------------------- * * CgetOp -- * * Returns the name, position and options of a widget in the table. * * Results: * Returns a standard Tcl result. A list of the widget attributes * is left in interp->result. * * -------------------------------------------------------------------------- */ /*ARGSUSED*/ static int CgetOp(dataPtr, interp, argc, argv) TableInterpData *dataPtr; /* Interpreter-specific data. */ Tcl_Interp *interp; int argc; char **argv; { Table *tablePtr; int length; char c; int n; PartitionInfo *infoPtr; if (Blt_GetTable(dataPtr, interp, argv[2], &tablePtr) != TCL_OK) { return TCL_ERROR; } if (argc == 4) { return Tk_ConfigureValue(interp, tablePtr->tkwin, tableConfigSpecs, (char *)tablePtr, argv[3], 0); } c = argv[3][0]; length = strlen(argv[3]); if (c == '.') { /* Configure widget */ Entry *entryPtr; if (GetEntry(interp, tablePtr, argv[3], &entryPtr) != TCL_OK) { return TCL_ERROR; } return Tk_ConfigureValue(interp, entryPtr->tkwin, entryConfigSpecs, (char *)entryPtr, argv[4], 0); } else if ((c == 'c') && (strncmp(argv[3], "container", length) == 0)) { return Tk_ConfigureValue(interp, tablePtr->tkwin, tableConfigSpecs, (char *)tablePtr, argv[4], 0); } infoPtr = ParseRowColumn(tablePtr, argv[3], &n); if (infoPtr == NULL) { return TCL_ERROR; } return Tk_ConfigureValue(interp, tablePtr->tkwin, infoPtr->configSpecs, (char *)GetRowColumn(infoPtr, n), argv[4], 0); } /* * ---------------------------------------------------------------------------- * * ConfigureOp -- * * Returns the name, position and options of a widget in the table. * * Results: * Returns a standard Tcl result. A list of the table configuration * option information is left in interp->result. * * -------------------------------------------------------------------------- */ /*ARGSUSED*/ static int ConfigureOp(dataPtr, interp, argc, argv) TableInterpData *dataPtr; /* Interpreter-specific data. */ Tcl_Interp *interp; int argc; char **argv; { Table *tablePtr; int length; char c1, c2; int count; int result; char **items; register int i; if (Blt_GetTable(dataPtr, interp, argv[2], &tablePtr) != TCL_OK) { return TCL_ERROR; } /* * Find the end of the items. Search until we see an option (-). */ argc -= 3, argv += 3; for (count = 0; count < argc; count++) { if (argv[count][0] == '-') { break; } } items = argv; /* Save the start of the item list */ argc -= count; /* Move beyond the items to the options */ argv += count; result = TCL_ERROR; /* Suppress compiler warning */ if (count == 0) { result = ConfigureTable(tablePtr, interp, argc, argv); } for (i = 0; i < count; i++) { c1 = items[i][0]; c2 = items[i][1]; length = strlen(items[i]); if (c1 == '.') { /* Configure widget */ Entry *entryPtr; if (GetEntry(interp, tablePtr, items[i], &entryPtr) != TCL_OK) { return TCL_ERROR; } result = ConfigureEntry(tablePtr, interp, entryPtr, argc, argv); } else if ((c1 == 'r') || (c1 == 'R')) { result = ConfigureRowColumn(tablePtr, &(tablePtr->rowInfo), items[i], argc, argv); } else if ((c1 == 'c') && (c2 == 'o') && (strncmp(argv[3], "container", length) == 0)) { result = ConfigureTable(tablePtr, interp, argc, argv); } else if ((c1 == 'c') || (c1 == 'C')) { result = ConfigureRowColumn(tablePtr, &(tablePtr->columnInfo), items[i], argc, argv); } else { Tcl_AppendResult(interp, "unknown item \"", items[i], "\": should be widget, row or column index, or \"container\"", (char *)NULL); return TCL_ERROR; } if (result == TCL_ERROR) { break; } if ((i + 1) < count) { Tcl_AppendResult(interp, "\n", (char *)NULL); } } tablePtr->flags |= REQUEST_LAYOUT; EventuallyArrangeTable(tablePtr); return result; } /* * ---------------------------------------------------------------------------- * * DeleteOp -- * * Deletes the specified rows and/or columns from the table. * Note that the row/column indices can be fixed only after * all the deletions have occurred. * * table delete .f r0 r1 r4 c0 * * Results: * Returns a standard Tcl result. * * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ static int DeleteOp(dataPtr, interp, argc, argv) TableInterpData *dataPtr; /* Interpreter-specific data. */ Tcl_Interp *interp; int argc; char **argv; { Table *tablePtr; char c; Blt_ChainLink *linkPtr, *nextPtr; PartitionInfo *infoPtr; char string[200]; int matches; register int i; RowColumn *rcPtr; if (Blt_GetTable(dataPtr, interp, argv[2], &tablePtr) != TCL_OK) { return TCL_ERROR; } for (i = 3; i < argc; i++) { c = tolower(argv[i][0]); if ((c != 'r') && (c != 'c')) { Tcl_AppendResult(interp, "bad index \"", argv[i], "\": must start with \"r\" or \"c\"", (char *)NULL); return TCL_ERROR; } } matches = 0; for (i = 3; i < argc; i++) { c = tolower(argv[i][0]); infoPtr = (c == 'r') ? &(tablePtr->rowInfo) : &(tablePtr->columnInfo); for (linkPtr = Blt_ChainFirstLink(infoPtr->chainPtr); linkPtr != NULL; linkPtr = nextPtr) { nextPtr = Blt_ChainNextLink(linkPtr); rcPtr = Blt_ChainGetValue(linkPtr); sprintf(string, "%c%d", argv[i][0], rcPtr->index); if (Tcl_StringMatch(string, argv[i])) { matches++; DeleteRowColumn(tablePtr, infoPtr, rcPtr); Blt_ChainDeleteLink(infoPtr->chainPtr, linkPtr); } } } if (matches > 0) { /* Fix indices */ i = 0; for (linkPtr = Blt_ChainFirstLink(tablePtr->columnInfo.chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); rcPtr->index = i++; } i = 0; for (linkPtr = Blt_ChainFirstLink(tablePtr->rowInfo.chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); rcPtr->index = i++; } tablePtr->flags |= REQUEST_LAYOUT; EventuallyArrangeTable(tablePtr); } return TCL_OK; } /* * ---------------------------------------------------------------------------- * * JoinOp -- * * Joins the specified span of rows/columns together into a * partition. The row/column indices can be fixed only after * all the deletions have occurred. * * table join .f r0 r3 * table join .f c2 c4 * Results: * Returns a standard Tcl result. * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ static int JoinOp(dataPtr, interp, argc, argv) TableInterpData *dataPtr; /* Interpreter-specific data. */ Tcl_Interp *interp; int argc; char **argv; { Table *tablePtr; Blt_ChainLink *linkPtr, *nextPtr, *fromPtr; PartitionInfo *infoPtr, *info2Ptr; Entry *entryPtr; int from, to; /* Indices marking the span of * partitions to be joined together. */ int start, end; /* Entry indices. */ register int i; RowColumn *rcPtr; if (Blt_GetTable(dataPtr, interp, argv[2], &tablePtr) != TCL_OK) { return TCL_ERROR; } infoPtr = ParseRowColumn(tablePtr, argv[3], &from); if (infoPtr == NULL) { return TCL_ERROR; } info2Ptr = ParseRowColumn(tablePtr, argv[4], &to); if (info2Ptr == NULL) { return TCL_ERROR; } if (infoPtr != info2Ptr) { Tcl_AppendResult(interp, "\"from\" and \"to\" must both be rows or columns", (char *)NULL); return TCL_ERROR; } if (from >= to) { return TCL_OK; /* No-op. */ } fromPtr = Blt_ChainGetNthLink(infoPtr->chainPtr, from); rcPtr = Blt_ChainGetValue(fromPtr); /* * --------------------------------------------------------------- * * Reduce the span of all entries that currently cross any of the * trailing rows/columns. Also, if the entry starts in one of * these rows/columns, moved it to the designated "joined" * row/column. * * --------------------------------------------------------------- */ if (infoPtr->type == rowUid) { for (linkPtr = Blt_ChainFirstLink(tablePtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { entryPtr = Blt_ChainGetValue(linkPtr); start = entryPtr->row.rcPtr->index + 1; end = entryPtr->row.rcPtr->index + entryPtr->row.span - 1; if ((end < from) || ((start > to))) { continue; } entryPtr->row.span -= to - start + 1; if (start >= from) {/* Entry starts in a trailing partition. */ entryPtr->row.rcPtr = rcPtr; } } } else { for (linkPtr = Blt_ChainFirstLink(tablePtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { entryPtr = Blt_ChainGetValue(linkPtr); start = entryPtr->column.rcPtr->index + 1; end = entryPtr->column.rcPtr->index + entryPtr->column.span - 1; if ((end < from) || ((start > to))) { continue; } entryPtr->column.span -= to - start + 1; if (start >= from) {/* Entry starts in a trailing partition. */ entryPtr->column.rcPtr = rcPtr; } } } linkPtr = Blt_ChainNextLink(fromPtr); for (i = from + 1; i <= to; i++) { nextPtr = Blt_ChainNextLink(linkPtr); rcPtr = Blt_ChainGetValue(linkPtr); DeleteRowColumn(tablePtr, infoPtr, rcPtr); Blt_ChainDeleteLink(infoPtr->chainPtr, linkPtr); linkPtr = nextPtr; } i = 0; for (linkPtr = Blt_ChainFirstLink(infoPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); rcPtr->index = i++; } tablePtr->flags |= REQUEST_LAYOUT; EventuallyArrangeTable(tablePtr); return TCL_OK; } /* * ---------------------------------------------------------------------------- * * ExtentsOp -- * * Returns a list of all the pathnames of the widgets managed by * a table. The table is determined from the name of the * container widget associated with the table. * * table extents .frame r0 c0 container * * Results: * Returns a standard Tcl result. If no error occurred, TCL_OK is * returned and a list of widgets managed by the table is left in * interp->result. * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ static int ExtentsOp(dataPtr, interp, argc, argv) TableInterpData *dataPtr; /* Interpreter-specific data. */ Tcl_Interp *interp; /* Interpreter to return results to. */ int argc; /* # of arguments */ char **argv; /* Command line arguments. */ { Table *tablePtr; Blt_ChainLink *linkPtr; RowColumn *rcPtr; RowColumn *c1Ptr, *r1Ptr, *c2Ptr, *r2Ptr; PartitionInfo *infoPtr; int x, y, width, height; char string[200]; char c; if (Blt_GetTable(dataPtr, interp, argv[2], &tablePtr) != TCL_OK) { return TCL_ERROR; } c = tolower(argv[3][0]); if (c == 'r') { infoPtr = &(tablePtr->rowInfo); } else if (c == 'c') { infoPtr = &(tablePtr->columnInfo); } else { Tcl_AppendResult(interp, "unknown item \"", argv[3], "\": should be widget, row, or column", (char *)NULL); return TCL_ERROR; } for (linkPtr = Blt_ChainFirstLink(infoPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); sprintf(string, "%c%d", argv[3][0], rcPtr->index); if (Tcl_StringMatch(string, argv[3])) { if (c == 'r') { r1Ptr = r2Ptr = rcPtr; c1Ptr = GetRowColumn(&(tablePtr->columnInfo), 0); c2Ptr = GetRowColumn(&(tablePtr->columnInfo), tablePtr->nColumns - 1); } else { c1Ptr = c2Ptr = rcPtr; r1Ptr = GetRowColumn(&(tablePtr->rowInfo), 0); r2Ptr = GetRowColumn(&(tablePtr->rowInfo), tablePtr->nRows - 1); } x = c1Ptr->offset; y = r1Ptr->offset; width = c2Ptr->offset + c2Ptr->size - x; height = r2Ptr->offset + r2Ptr->size - y; sprintf(string, "%c%d %d %d %d %d\n", argv[3][0], rcPtr->index, x, y, width, height); Tcl_AppendResult(interp, string, (char *)NULL); } } return TCL_OK; } /* * ---------------------------------------------------------------------------- * * ForgetOp -- * * Processes an argv/argc list of widget names and purges their * entries from their respective tables. The widgets are unmapped and * the tables are rearranged at the next idle point. Note that all * the named widgets do not need to exist in the same table. * * Results: * Returns a standard Tcl result. If an error occurred, TCL_ERROR is * returned and an error message is left in interp->result. * * Side Effects: * Memory is deallocated (the entry is destroyed), etc. The * affected tables are is re-computed and arranged at the next idle * point. * * ---------------------------------------------------------------------------- */ static int ForgetOp(dataPtr, interp, argc, argv) TableInterpData *dataPtr; /* Interpreter-specific data. */ Tcl_Interp *interp; int argc; char **argv; { Entry *entryPtr; register int i; Blt_HashEntry *hPtr; Blt_HashSearch cursor; Table *tablePtr; Tk_Window tkwin, mainWindow; tablePtr = NULL; mainWindow = Tk_MainWindow(interp); for (i = 2; i < argc; i++) { entryPtr = NULL; tkwin = Tk_NameToWindow(interp, argv[i], mainWindow); if (tkwin == NULL) { return TCL_ERROR; } for (hPtr = Blt_FirstHashEntry(&(dataPtr->tableTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tablePtr = (Table *)Blt_GetHashValue(hPtr); if (tablePtr->interp != interp) { continue; } entryPtr = FindEntry(tablePtr, tkwin); if (entryPtr != NULL) { break; } } if (entryPtr == NULL) { Tcl_AppendResult(interp, "\"", argv[i], "\" is not managed by any table", (char *)NULL); return TCL_ERROR; } if (Tk_IsMapped(entryPtr->tkwin)) { Tk_UnmapWindow(entryPtr->tkwin); } /* Arrange for the call back here in the loop, because the * widgets may not belong to the same table. */ tablePtr->flags |= REQUEST_LAYOUT; EventuallyArrangeTable(tablePtr); DestroyEntry(entryPtr); } return TCL_OK; } /* * ---------------------------------------------------------------------------- * * InfoOp -- * * Returns the options of a widget or partition in the table. * * Results: * Returns a standard Tcl result. A list of the widget attributes * is left in interp->result. * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ static int InfoOp(dataPtr, interp, argc, argv) TableInterpData *dataPtr; /* Interpreter-specific data. */ Tcl_Interp *interp; int argc; char **argv; { Table *tablePtr; int result; char c; register int i; if (Blt_GetTable(dataPtr, interp, argv[2], &tablePtr) != TCL_OK) { return TCL_ERROR; } for (i = 3; i < argc; i++) { c = argv[i][0]; if (c == '.') { /* Entry information */ Entry *entryPtr; if (GetEntry(interp, tablePtr, argv[i], &entryPtr) != TCL_OK) { return TCL_ERROR; } result = InfoEntry(interp, tablePtr, entryPtr); } else if ((c == 'r') || (c == 'R') || (c == 'c') || (c == 'C')) { result = InfoRowColumn(tablePtr, interp, argv[i]); } else { Tcl_AppendResult(interp, "unknown item \"", argv[i], "\": should be widget, row, or column", (char *)NULL); return TCL_ERROR; } if (result != TCL_OK) { return TCL_ERROR; } if ((i + 1) < argc) { Tcl_AppendResult(interp, "\n", (char *)NULL); } } return TCL_OK; } /* * ---------------------------------------------------------------------------- * * InsertOp -- * * Inserts a span of rows/columns into the table. * * table insert .f r0 2 * table insert .f c0 5 * * Results: * Returns a standard Tcl result. A list of the widget * attributes is left in interp->result. * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ static int InsertOp(dataPtr, interp, argc, argv) TableInterpData *dataPtr; /* Interpreter-specific data. */ Tcl_Interp *interp; int argc; char **argv; { Table *tablePtr; long int span; int before; PartitionInfo *infoPtr; RowColumn *rcPtr; register int i; Blt_ChainLink *beforePtr, *linkPtr; int linkBefore; if (Blt_GetTable(dataPtr, interp, argv[2], &tablePtr) != TCL_OK) { return TCL_ERROR; } linkBefore = TRUE; if (argv[3][0] == '-') { if (strcmp(argv[3], "-before") == 0) { linkBefore = TRUE; argv++; argc--; } else if (strcmp(argv[3], "-after") == 0) { linkBefore = FALSE; argv++; argc--; } } if (argc == 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], "insert ", argv[2], "row|column ?span?", (char *)NULL); return TCL_ERROR; } infoPtr = ParseRowColumn(tablePtr, argv[3], &before); if (infoPtr == NULL) { return TCL_ERROR; } span = 1; if ((argc > 4) && (Tcl_ExprLong(interp, argv[4], &span) != TCL_OK)) { return TCL_ERROR; } if (span < 1) { Tcl_AppendResult(interp, "span value \"", argv[4], "\" can't be negative", (char *)NULL); return TCL_ERROR; } beforePtr = Blt_ChainGetNthLink(infoPtr->chainPtr, before); /* * Insert the new rows/columns from the designated point in the * chain. */ for (i = 0; i < span; i++) { rcPtr = CreateRowColumn(); linkPtr = Blt_ChainNewLink(); Blt_ChainSetValue(linkPtr, rcPtr); if (linkBefore) { Blt_ChainLinkBefore(infoPtr->chainPtr, linkPtr, beforePtr); } else { Blt_ChainLinkAfter(infoPtr->chainPtr, linkPtr, beforePtr); } rcPtr->linkPtr = linkPtr; } i = 0; for (linkPtr = Blt_ChainFirstLink(infoPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); /* Reset the indices of the trailing rows/columns. */ rcPtr->index = i++; } tablePtr->flags |= REQUEST_LAYOUT; EventuallyArrangeTable(tablePtr); return TCL_OK; } /* * ---------------------------------------------------------------------------- * * SplitOp -- * * Splits a single row/column into multiple partitions. Any * widgets that span this row/column will be automatically * corrected to include the new rows/columns. * * table split .f r0 3 * table split .f c2 2 * Results: * Returns a standard Tcl result. A list of the widget * attributes is left in interp->result. * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ static int SplitOp(dataPtr, interp, argc, argv) TableInterpData *dataPtr; /* Interpreter-specific data. */ Tcl_Interp *interp; int argc; char **argv; { Table *tablePtr; int number, split; int start, end; PartitionInfo *infoPtr; RowColumn *rcPtr; register int i; Blt_ChainLink *afterPtr, *linkPtr; Entry *entryPtr; if (Blt_GetTable(dataPtr, interp, argv[2], &tablePtr) != TCL_OK) { return TCL_ERROR; } infoPtr = ParseRowColumn(tablePtr, argv[3], &number); if (infoPtr == NULL) { return TCL_ERROR; } split = 2; if (argc > 4) { if (Tcl_GetInt(interp, argv[4], &split) != TCL_OK) { return TCL_ERROR; } } if (split < 2) { Tcl_AppendResult(interp, "bad split value \"", argv[4], "\": should be 2 or greater", (char *)NULL); return TCL_ERROR; } afterPtr = Blt_ChainGetNthLink(infoPtr->chainPtr, number); /* * Append (split - 1) additional rows/columns starting * from the current point in the chain. */ for (i = 1; i < split; i++) { rcPtr = CreateRowColumn(); linkPtr = Blt_ChainNewLink(); Blt_ChainSetValue(linkPtr, rcPtr); Blt_ChainLinkAfter(infoPtr->chainPtr, linkPtr, afterPtr); rcPtr->linkPtr = linkPtr; } /* * Also increase the span of all entries that span this * row/column by split - 1. */ if (infoPtr->type == rowUid) { for (linkPtr = Blt_ChainFirstLink(tablePtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { entryPtr = Blt_ChainGetValue(linkPtr); start = entryPtr->row.rcPtr->index; end = entryPtr->row.rcPtr->index + entryPtr->row.span; if ((start <= number) && (number < end)) { entryPtr->row.span += (split - 1); } } } else { for (linkPtr = Blt_ChainFirstLink(tablePtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { entryPtr = Blt_ChainGetValue(linkPtr); start = entryPtr->column.rcPtr->index; end = entryPtr->column.rcPtr->index + entryPtr->column.span; if ((start <= number) && (number < end)) { entryPtr->column.span += (split - 1); } } } /* * Be careful to renumber the rows or columns only after * processing each entry. Otherwise row/column numbering * will be out of sync with the index. */ i = number; for (linkPtr = afterPtr; linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); rcPtr->index = i++; /* Renumber the trailing indices. */ } tablePtr->flags |= REQUEST_LAYOUT; EventuallyArrangeTable(tablePtr); return TCL_OK; } /* * ---------------------------------------------------------------------- * * RowColumnSearch -- * * Searches for the row or column designated by an x or y * coordinate. * * Results: * Returns a pointer to the row/column containing the given point. * If no row/column contains the coordinate, NULL is returned. * * ---------------------------------------------------------------------- */ static RowColumn * RowColumnSearch(infoPtr, x) PartitionInfo *infoPtr; int x; /* Search coordinate */ { Blt_ChainLink *linkPtr; RowColumn *rcPtr; for (linkPtr = Blt_ChainFirstLink(infoPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); if (x > (rcPtr->offset + rcPtr->size)) { break; /* Too far, can't find row/column. */ } if (x > rcPtr->offset) { return rcPtr; } } return NULL; } /* *---------------------------------------------------------------------- * * LocateOp -- * * * Returns the row,column index given a screen coordinate. * * Results: * Returns a standard Tcl result. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int LocateOp(dataPtr, interp, argc, argv) TableInterpData *dataPtr; /* Interpreter-specific data. */ Tcl_Interp *interp; int argc; char **argv; { int x, y; RowColumn *rowPtr, *columnPtr; Table *tablePtr; if (Blt_GetTable(dataPtr, interp, argv[2], &tablePtr) != TCL_OK) { return TCL_ERROR; } if (Blt_GetPixels(interp, tablePtr->tkwin, argv[3], PIXELS_ANY, &x) != TCL_OK) { return TCL_ERROR; } if (Blt_GetPixels(interp, tablePtr->tkwin, argv[4], PIXELS_ANY, &y) != TCL_OK) { return TCL_ERROR; } rowPtr = RowColumnSearch(&(tablePtr->rowInfo), y); if (rowPtr == NULL) { return TCL_OK; } columnPtr = RowColumnSearch(&(tablePtr->columnInfo), x); if (columnPtr == NULL) { return TCL_OK; } Tcl_AppendElement(interp, Blt_Itoa(rowPtr->index)); Tcl_AppendElement(interp, Blt_Itoa(columnPtr->index)); return TCL_OK; } /* * ---------------------------------------------------------------------------- * * ContainersOp -- * * Returns a list of tables currently in use. A table is * associated by the name of its container widget. All tables * matching a given pattern are included in this list. If no * pattern is present (argc == 0), all tables are included. * * Results: * Returns a standard Tcl result. If no error occurred, TCL_OK is * returned and a list of tables is left in interp->result. * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ static int ContainersOp(dataPtr, interp, argc, argv) TableInterpData *dataPtr; /* Interpreter-specific data. */ Tcl_Interp *interp; /* Interpreter to return list of names to */ int argc; char **argv; /* Contains 0-1 arguments: search pattern */ { Blt_HashEntry *hPtr; Blt_HashSearch cursor; register Table *tablePtr; char *pattern; pattern = NULL; if (argc > 2) { if (argv[2][0] == '-') { unsigned int length; length = strlen(argv[2]); if ((length > 1) && (argv[2][1] == 'p') && (strncmp(argv[2], "-pattern", length) == 0)) { pattern = argv[3]; goto search; } else if ((length > 1) && (argv[2][1] == 's') && (strncmp(argv[2], "-slave", length) == 0)) { Tk_Window tkwin; if (argc != 4) { Tcl_AppendResult(interp, "needs widget argument for \"", argv[2], "\"", (char *)NULL); return TCL_ERROR; } tkwin = Tk_NameToWindow(interp, argv[3], Tk_MainWindow(interp)); if (tkwin == NULL) { return TCL_ERROR; } for (hPtr = Blt_FirstHashEntry(&(dataPtr->tableTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tablePtr = (Table *)Blt_GetHashValue(hPtr); if (FindEntry(tablePtr, tkwin) != NULL) { Tcl_AppendElement(interp, Tk_PathName(tablePtr->tkwin)); } } return TCL_OK; } else { Tcl_AppendResult(interp, "bad switch \"", argv[2], "\" : \ should be \"-pattern\", or \"-slave\"", (char *)NULL); return TCL_ERROR; } } else { pattern = argv[2]; } } search: for (hPtr = Blt_FirstHashEntry(&(dataPtr->tableTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tablePtr = (Table *)Blt_GetHashValue(hPtr); if (tablePtr->interp == interp) { if ((pattern == NULL) || (Tcl_StringMatch(Tk_PathName(tablePtr->tkwin), pattern))) { Tcl_AppendElement(interp, Tk_PathName(tablePtr->tkwin)); } } } return TCL_OK; } /* * ---------------------------------------------------------------------------- * * SaveOp -- * * Returns a list of all the commands necessary to rebuild the * the table. This includes the layout of the widgets and any * row, column, or table options set. * * Results: * Returns a standard Tcl result. If no error occurred, TCL_OK is * returned and a list of widget path names is left in interp->result. * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ static int SaveOp(dataPtr, interp, argc, argv) TableInterpData *dataPtr; /* Interpreter-specific data. */ Tcl_Interp *interp; int argc; char **argv; { Table *tablePtr; Blt_ChainLink *linkPtr, *lastPtr; Entry *entryPtr; PartitionInfo *infoPtr; RowColumn *rcPtr; Tcl_DString dString; int start, last; if (Blt_GetTable(dataPtr, interp, argv[2], &tablePtr) != TCL_OK) { return TCL_ERROR; } Tcl_DStringInit(&dString); Tcl_DStringAppend(&dString, "\n# Table widget layout\n\n", -1); Tcl_DStringAppend(&dString, argv[0], -1); Tcl_DStringAppend(&dString, " ", -1); Tcl_DStringAppend(&dString, Tk_PathName(tablePtr->tkwin), -1); Tcl_DStringAppend(&dString, " \\\n", -1); lastPtr = Blt_ChainLastLink(tablePtr->chainPtr); for (linkPtr = Blt_ChainFirstLink(tablePtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { entryPtr = Blt_ChainGetValue(linkPtr); PrintEntry(entryPtr, &dString); if (linkPtr != lastPtr) { Tcl_DStringAppend(&dString, " \\\n", -1); } } Tcl_DStringAppend(&dString, "\n\n# Row configuration options\n\n", -1); infoPtr = &(tablePtr->rowInfo); for (linkPtr = Blt_ChainFirstLink(infoPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); start = Tcl_DStringLength(&dString); Tcl_DStringAppend(&dString, argv[0], -1); Tcl_DStringAppend(&dString, " configure ", -1); Tcl_DStringAppend(&dString, Tk_PathName(tablePtr->tkwin), -1); Tcl_DStringAppend(&dString, " r", -1); Tcl_DStringAppend(&dString, Blt_Itoa(rcPtr->index), -1); last = Tcl_DStringLength(&dString); PrintRowColumn(interp, infoPtr, rcPtr, &dString); if (Tcl_DStringLength(&dString) == last) { Tcl_DStringSetLength(&dString, start); } else { Tcl_DStringAppend(&dString, "\n", -1); } } Tcl_DStringAppend(&dString, "\n\n# Column configuration options\n\n", -1); infoPtr = &(tablePtr->columnInfo); for (linkPtr = Blt_ChainFirstLink(infoPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); start = Tcl_DStringLength(&dString); Tcl_DStringAppend(&dString, argv[0], -1); Tcl_DStringAppend(&dString, " configure ", -1); Tcl_DStringAppend(&dString, Tk_PathName(tablePtr->tkwin), -1); Tcl_DStringAppend(&dString, " c", -1); Tcl_DStringAppend(&dString, Blt_Itoa(rcPtr->index), -1); last = Tcl_DStringLength(&dString); PrintRowColumn(interp, infoPtr, rcPtr, &dString); if (Tcl_DStringLength(&dString) == last) { Tcl_DStringSetLength(&dString, start); } else { Tcl_DStringAppend(&dString, "\n", -1); } } start = Tcl_DStringLength(&dString); Tcl_DStringAppend(&dString, "\n\n# Table configuration options\n\n", -1); Tcl_DStringAppend(&dString, argv[0], -1); Tcl_DStringAppend(&dString, " configure ", -1); Tcl_DStringAppend(&dString, Tk_PathName(tablePtr->tkwin), -1); last = Tcl_DStringLength(&dString); PrintTable(tablePtr, &dString); if (Tcl_DStringLength(&dString) == last) { Tcl_DStringSetLength(&dString, start); } else { Tcl_DStringAppend(&dString, "\n", -1); } Tcl_DStringResult(interp, &dString); return TCL_OK; } /* * ---------------------------------------------------------------------------- * * SearchOp -- * * Returns a list of all the pathnames of the widgets managed by * a table geometry manager. The table is given by the path name of a * container widget associated with the table. * * Results: * Returns a standard Tcl result. If no error occurred, TCL_OK is * returned and a list of widget path names is left in interp->result. * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ static int SearchOp(dataPtr, interp, argc, argv) TableInterpData *dataPtr; /* Interpreter-specific data. */ Tcl_Interp *interp; /* Interpreter to return list of names to */ int argc; /* Number of arguments */ char **argv; /* Contains 1-2 arguments: pathname of container * widget associated with the table and search * pattern */ { Table *tablePtr; Blt_ChainLink *linkPtr; Entry *entryPtr; int rspan, cspan, rstart, cstart; char *pattern; char c; int flags; register int i; #define MATCH_PATTERN (1<<0) /* Find widgets whose path names * match a given pattern */ #define MATCH_INDEX_SPAN (1<<1) /* Find widgets that span index */ #define MATCH_INDEX_START (1<<2) /* Find widgets that start at index */ if (Blt_GetTable(dataPtr, interp, argv[2], &tablePtr) != TCL_OK) { return TCL_ERROR; } flags = 0; pattern = NULL; rspan = cspan = rstart = cstart = 0; /* Parse switches and arguments first */ for (i = 3; i < argc; i += 2) { if (argv[i][0] == '-') { unsigned int length; if ((i + 1) == argc) { Tcl_AppendResult(interp, "switch \"", argv[i], "\" needs value", (char *)NULL); return TCL_ERROR; } length = strlen(argv[i]); c = argv[i][1]; if ((c == 'p') && (length > 1) && (strncmp(argv[3], "-pattern", length) == 0)) { flags |= MATCH_PATTERN; pattern = argv[4]; } else if ((c == 's') && (length > 2) && (strncmp(argv[i], "-start", length) == 0)) { flags |= MATCH_INDEX_START; if (ParseItem(tablePtr, argv[i + 1], &rstart, &cstart) != TCL_OK) { return TCL_ERROR; } } else if ((c == 's') && (length > 2) && (strncmp(argv[i], "-span", length) == 0)) { flags |= MATCH_INDEX_SPAN; if (ParseItem(tablePtr, argv[4], &rspan, &cspan) != TCL_OK) { return TCL_ERROR; } } else { Tcl_AppendResult(interp, "bad switch \"", argv[3], "\" : \ should be \"-pattern\", \"-span\", or \"-start\"", (char *)NULL); return TCL_ERROR; } } else { if ((i + 1) == argc) { pattern = argv[i]; flags |= MATCH_PATTERN; } } } /* Then try to match entries with the search criteria */ for (linkPtr = Blt_ChainFirstLink(tablePtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { entryPtr = Blt_ChainGetValue(linkPtr); if ((flags & MATCH_PATTERN) && (pattern != NULL)) { if (Tcl_StringMatch(Tk_PathName(entryPtr->tkwin), pattern)) { goto match; } } if (flags & MATCH_INDEX_SPAN) { if ((rspan >= 0) && ((entryPtr->row.rcPtr->index <= rspan) || ((entryPtr->row.rcPtr->index + entryPtr->row.span) > rspan))) { goto match; } if ((cspan >= 0) && ((entryPtr->column.rcPtr->index <= cspan) || ((entryPtr->column.rcPtr->index + entryPtr->column.span) > cspan))) { goto match; } } if (flags & MATCH_INDEX_START) { if ((rstart >= 0) && (entryPtr->row.rcPtr->index == rstart)) { goto match; } if ((cstart >= 0) && (entryPtr->column.rcPtr->index == cstart)) { goto match; } } continue; match: Tcl_AppendElement(interp, Tk_PathName(entryPtr->tkwin)); } return TCL_OK; } /* * ---------------------------------------------------------------------------- * * Table operations. * * The fields for Blt_OpSpec are as follows: * * - operation name * - minimum number of characters required to disambiguate the operation name. * - function associated with operation. * - minimum number of arguments required. * - maximum number of arguments allowed (0 indicates no limit). * - usage string * * ---------------------------------------------------------------------------- */ static Blt_OpSpec operSpecs[] = { {"arrange", 1, (Blt_Op)ArrangeOp, 3, 3, "container",}, {"cget", 2, (Blt_Op)CgetOp, 4, 5, "container ?row|column|widget? option",}, {"configure", 3, (Blt_Op)ConfigureOp, 3, 0, "container ?row|column|widget?... ?option value?...",}, {"containers", 3, (Blt_Op)ContainersOp, 2, 4, "?switch? ?arg?",}, {"delete", 1, (Blt_Op)DeleteOp, 3, 0, "container row|column ?row|column?",}, {"extents", 1, (Blt_Op)ExtentsOp, 4, 4, "container row|column|widget",}, {"forget", 1, (Blt_Op)ForgetOp, 3, 0, "widget ?widget?...",}, {"info", 3, (Blt_Op)InfoOp, 3, 0, "container ?row|column|widget?...",}, {"insert", 3, (Blt_Op)InsertOp, 4, 6, "container ?-before|-after? row|column ?count?",}, {"join", 1, (Blt_Op)JoinOp, 5, 5, "container first last",}, {"locate", 2, (Blt_Op)LocateOp, 5, 5, "container x y",}, {"save", 2, (Blt_Op)SaveOp, 3, 3, "container",}, {"search", 2, (Blt_Op)SearchOp, 3, 0, "container ?switch arg?...",}, {"split", 2, (Blt_Op)SplitOp, 4, 5, "container row|column div",}, }; static int nSpecs = sizeof(operSpecs) / sizeof(Blt_OpSpec); /* * ---------------------------------------------------------------------------- * * TableCmd -- * * This procedure is invoked to process the Tcl command that * corresponds to the table geometry manager. See the user * documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * * ---------------------------------------------------------------------------- */ static int TableCmd(clientData, interp, argc, argv) ClientData clientData; /* Interpreter-specific data. */ Tcl_Interp *interp; int argc; char **argv; { TableInterpData *dataPtr = clientData; Blt_Op proc; int result; if ((argc > 1) && (argv[1][0] == '.')) { Table *tablePtr; if (Blt_GetTable(clientData, interp, argv[1], &tablePtr) != TCL_OK) { Tcl_ResetResult(interp); tablePtr = CreateTable(dataPtr, interp, argv[1]); if (tablePtr == NULL) { return TCL_ERROR; } } return BuildTable(tablePtr, interp, argc, argv); } proc = Blt_GetOp(interp, nSpecs, operSpecs, BLT_OP_ARG1, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (dataPtr, interp, argc, argv); return result; } /* * ----------------------------------------------------------------------- * * TableInterpDeleteProc -- * * This is called when the interpreter hosting the table command * is destroyed. * * Results: * None. * * Side effects: * Destroys all the hash table maintaining the names of the table * geomtry managers. * * ------------------------------------------------------------------------ */ /* ARGSUSED */ static void TableInterpDeleteProc(clientData, interp) ClientData clientData; /* Thread-specific data. */ Tcl_Interp *interp; { TableInterpData *dataPtr = clientData; Blt_HashEntry *hPtr; Blt_HashSearch cursor; Table *tablePtr; for (hPtr = Blt_FirstHashEntry(&(dataPtr->tableTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tablePtr = (Table *)Blt_GetHashValue(hPtr); tablePtr->hashPtr = NULL; DestroyTable((DestroyData)tablePtr); } Blt_DeleteHashTable(&(dataPtr->tableTable)); Tcl_DeleteAssocData(interp, TABLE_THREAD_KEY); Blt_Free(dataPtr); } static TableInterpData * GetTableInterpData(interp) Tcl_Interp *interp; { TableInterpData *dataPtr; Tcl_InterpDeleteProc *proc; dataPtr = (TableInterpData *) Tcl_GetAssocData(interp, TABLE_THREAD_KEY, &proc); if (dataPtr == NULL) { dataPtr = Blt_Malloc(sizeof(TableInterpData)); assert(dataPtr); Tcl_SetAssocData(interp, TABLE_THREAD_KEY, TableInterpDeleteProc, dataPtr); Blt_InitHashTable(&(dataPtr->tableTable), BLT_ONE_WORD_KEYS); } return dataPtr; } /* * ---------------------------------------------------------------------------- * * Blt_TableInit -- * * This procedure is invoked to initialize the Tcl command that * corresponds to the table geometry manager. * * Results: * None. * * Side effects: * Creates the new command and adds an entry into a global Tcl * associative array. * * --------------------------------------------------------------------------- */ int Blt_TableInit(interp) Tcl_Interp *interp; { static Blt_CmdSpec cmdSpec = {"table", TableCmd, }; TableInterpData *dataPtr; dataPtr = GetTableInterpData(interp); cmdSpec.clientData = dataPtr; if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) { return TCL_ERROR; } rowUid = (Blt_Uid)Tk_GetUid("row"); columnUid = (Blt_Uid)Tk_GetUid("column"); return TCL_OK; } blt-2.4z.orig/src/bltTable.h0100644000175000017500000003030607454200643014443 0ustar dokodoko/* * bltTable.h -- * * This module implements a table-based geometry manager * for the BLT toolkit. * * Copyright 1993-1998 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. * * The table geometry manager was created by George Howlett. */ #ifndef _BLT_TABLE_H #define _BLT_TABLE_H #include "bltChain.h" #include "bltHash.h" #include "bltList.h" typedef struct { Blt_HashTable tableTable; /* Hash table of table structures keyed by * the address of the reference Tk window */ } TableInterpData; typedef struct EditorStruct Editor; typedef void (EditorDrawProc) _ANSI_ARGS_((Editor *editor)); typedef void (EditorDestroyProc) _ANSI_ARGS_((DestroyData destroyData)); struct EditorStruct { int gridLineWidth; int buttonHeight; int entryPad; int minSize; /* Minimum size to allow any partition */ EditorDrawProc *drawProc; EditorDestroyProc *destroyProc; }; #define nRows rowInfo.chainPtr->nLinks #define nColumns columnInfo.chainPtr->nLinks /* * Limits -- * * Defines the bounding of a size (width or height) in the table. * It may be related to the partition, entry, or table size. The * widget pointers are used to associate sizes with the requested * size of other widgets. */ typedef struct { int flags; /* Flags indicate whether using default * values for limits or not. See flags * below. */ int max, min; /* Values for respective limits. */ int nom; /* Nominal starting value. */ Tk_Window wMax, wMin; /* If non-NULL, represents widgets whose * requested sizes will be set as limits. */ Tk_Window wNom; /* If non-NULL represents widget whose * requested size will be the nominal * size. */ } Limits; #define LIMITS_SET_BIT 1 #define LIMITS_SET_MIN (LIMITS_SET_BIT<<0) #define LIMITS_SET_MAX (LIMITS_SET_BIT<<1) #define LIMITS_SET_NOM (LIMITS_SET_BIT<<2) #define LIMITS_MIN 0 /* Default minimum limit */ #define LIMITS_MAX SHRT_MAX/* Default maximum limit */ #define LIMITS_NOM -1000 /* Default nomimal value. Indicates if a * partition has received any space yet */ typedef int (LimitsProc) _ANSI_ARGS_((int value, Limits *limitsPtr)); /* * Resize -- * * These flags indicate in what ways each partition in a table * can be resized from its default dimensions. The normal size of * a row/column is the minimum amount of space needed to hold the * widgets that span it. The table may then be stretched or * shrunk depending if the container is larger or smaller than * the table. This can occur if 1) the user resizes the toplevel * widget, or 2) the container is in turn packed into a larger * widget and the "fill" option is set. * * RESIZE_NONE - No resizing from normal size. * RESIZE_EXPAND - Do not allow the size to decrease. * The size may increase however. * RESIZE_SHRINK - Do not allow the size to increase. * The size may decrease however. * RESIZE_BOTH - Allow the size to increase or * decrease from the normal size. * RESIZE_VIRGIN - Special case of the resize flag. Used to * indicate the initial state of the flag. * Empty rows/columns are treated differently * if this row/column is set. */ #define RESIZE_NONE 0 #define RESIZE_EXPAND (1<<0) #define RESIZE_SHRINK (1<<1) #define RESIZE_BOTH (RESIZE_EXPAND | RESIZE_SHRINK) #define RESIZE_VIRGIN (1<<2) /* * Control -- */ #define CONTROL_NORMAL 1.0 /* Consider the widget when * calculating the row heights and * column widths. */ #define CONTROL_NONE 0.0 /* Ignore the widget. The height and * width of the rows/columns spanned * by this widget will not affected by * the size of the widget. */ #define CONTROL_FULL -1.0 /* Consider only this widget when * determining the column widths * and row heights of the partitions * it spans. */ #define EXCL_PAD 0 #define INCL_PAD 1 typedef struct TableStruct Table; typedef struct RowColumnStruct RowColumn; /* * Entry -- * * An entry holds a widget and describes how the widget should * appear in a range of cells. * 1. padding. * 2. how many rows/columns the entry spans. * 3. size bounds for the widget. * * Several entries may start at the same cell in * the table, but a entry can hold only one widget. */ typedef struct { Tk_Window tkwin; /* Widget to be managed. */ Table *tablePtr; /* Table managing this widget */ int borderWidth; /* The external border width of * the widget. This is needed to check if * Tk_Changes(tkwin)->border_width changes. */ int manageWhenNeeded; /* If non-zero, allow joint custody of * the widget. This is for cases * where the same widget may be shared * between two different tables * (e.g. same graph on two different * notebook pages). Claim the widget * only when the table is * mapped. Don't destroy the entry if * the table loses custody of the * widget. */ Limits reqWidth, reqHeight; /* Bounds for width and height requests * made by the widget. */ struct PositionInfo { RowColumn *rcPtr; /* Row or column where this entry starts. */ int span; /* Number of rows or columns spanned. */ double control; /* Weight of widget in the row or column. */ Blt_ChainLink *linkPtr; /* Link to widget in the chain of spans */ Blt_Chain *chainPtr; /* Pointer to the chain of spans. */ } row, column; Tk_Anchor anchor; /* Anchor type: indicates how the * widget is positioned if extra space * is available in the entry */ Blt_Pad padX; /* Extra padding placed left and right of the * widget. */ Blt_Pad padY; /* Extra padding placed above and below the * widget */ int ipadX, ipadY; /* Extra padding added to the interior of * the widget (i.e. adds to the requested * size of the widget) */ int fill; /* Indicates how the widget should * fill the span of cells it occupies. */ int x, y; /* Origin of widget wrt container. */ Blt_ChainLink *linkPtr; /* Pointer into list of entries. */ Blt_HashEntry *hashPtr; /* Pointer into table of entries. */ } Entry; /* * RowColumn -- * * Creates a definable space (row or column) in the table. It may * have both requested minimum or maximum values which constrain * the size of it. */ struct RowColumnStruct { int index; /* Index of row or column */ int size; /* Current size of the partition. This size * is bounded by minSize and maxSize. */ /* * nomSize and size perform similar duties. I need to keep track * of the amount of space allocated to the partition (using size). * But at the same time, I need to indicate that space can be * parcelled out to this partition. If a nominal size was set for * this partition, I don't want to add space. */ int nomSize; /* The nominal size (neither expanded * nor shrunk) of the partition based * upon the requested sizes of the * widgets spanning this partition. */ int minSize, maxSize; /* Size constraints on the partition */ int offset; /* Offset of the partition (in pixels) * from the origin of the container. */ int minSpan; /* Minimum spanning widget in * partition. Used for bookkeeping * when growing a span of partitions * */ double weight; /* Weight of row or column */ Entry *control; /* Pointer to the entry that is * determining the size of this * partition. This is used to know * when a partition is occupied. */ int resize; /* Indicates if the partition should * shrink or expand from its nominal * size. */ Blt_Pad pad; /* Pads the partition beyond its nominal * size */ Limits reqSize; /* Requested bounds for the size of * the partition. The partition will * not expand or shrink beyond these * limits, regardless of how it was * specified (max widget size). This * includes any extra padding which * may be specified. */ int maxSpan; /* Maximum spanning widget to consider * when growing a span of partitions. * A value of zero indicates that all * spans should be considered. */ int count; Blt_ChainLink *linkPtr; }; #define DEF_TBL_RESIZE "both" #define DEF_TBL_PAD "0" #define DEF_TBL_MAXSPAN "0" /* * This is the default number of elements in the statically * pre-allocated column and row arrays. This number should reflect a * useful number of row and columns, which fit most applications. */ #define DEF_ARRAY_SIZE 32 typedef Entry *(EntrySearchProc) _ANSI_ARGS_((Table *tablePtr, Tk_Window tkwin)); /* * PartitionInfo -- * * Manages the rows or columns of the table. Contains * a chain of partitions (representing the individiual * rows or columns). * */ typedef struct PartitionInfo { char *type; /* String identifying the type of * partition: "row" or "column". */ Blt_Chain *chainPtr; Blt_List list; /* Linked list of bins of widgets * keyed by increasing span. */ Tk_ConfigSpec *configSpecs; int reqLength; int ePad; /* Extra padding for row/column * needed to display editor marks */ } PartitionInfo; /* * Table structure */ struct TableStruct { int flags; /* See the flags definitions below. */ Tk_Window tkwin; /* The container widget into which * other widgets are arranged. */ Tcl_Interp *interp; /* Interpreter associated with all * widgets */ Blt_Chain *chainPtr; /* Chain of entries in the table. */ Blt_HashTable entryTable; /* Table of entries. Serves as a * directory to look up entries from * widget their names. */ Blt_Pad padX, padY; int propagate; /* If non-zero, the table will make a * geometry request on behalf of the * container widget. */ int eTablePad, eEntryPad; PartitionInfo columnInfo; PartitionInfo rowInfo; /* Manages row and column partitions */ Dim2D container; /* Last known dimenion of the container. */ Dim2D normal; /* Normal dimensions of the table */ Limits reqWidth, reqHeight; /* Constraints on the table's normal * width and height */ Editor *editPtr; /* If non-NULL, indicates that the * table is currently being edited */ Tcl_IdleProc *arrangeProc; EntrySearchProc *findEntryProc; Blt_HashEntry *hashPtr; /* Used to delete the table from its * hashtable. */ Blt_HashTable *tablePtr; }; /* * Table flags definitions */ #define ARRANGE_PENDING (1<<0) /* A call to ArrangeTable is * pending. This flag allows multiple * layout changes to be requested * before the table is actually * reconfigured. */ #define REQUEST_LAYOUT (1<<1) /* Get the requested sizes of the * widgets before expanding/shrinking * the size of the container. It's * necessary to recompute the layout * every time a partition or entry is * added, reconfigured, or deleted, * but not when the container is * resized. */ #define NON_PARENT (1<<2) /* The table is managing widgets that * arern't children of the container. * This requires that they are * manually moved when the container * is moved (a definite performance * hit). */ /* * Forward declarations */ extern int Blt_GetTable _ANSI_ARGS_((TableInterpData *dataPtr, Tcl_Interp *interp, char *pathName, Table **tablePtrPtr)); #endif /* _BLT_TABLE_H */ blt-2.4z.orig/src/bltTabnotebook.c0100644000175000017500000047060407542177233015675 0ustar dokodoko/* * bltTabnotebook.c -- * * This module implements a tab notebook widget for the BLT toolkit. * * Copyright 1998 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 or 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. * * Tabnotebook widget created by George A. Howlett (gah@bell-labs.com) * */ #include "bltInt.h" #ifndef NO_TABNOTEBOOK #include "bltBind.h" #include "bltChain.h" #include "bltHash.h" #include "bltTile.h" #if (TK_MAJOR_VERSION == 4) #define TK_REPARENTED 0x2000 #endif #define INVALID_FAIL 0 #define INVALID_OK 1 /* * The macro below is used to modify a "char" value (e.g. by casting * it to an unsigned character) so that it can be used safely with * macros such as isspace. */ #define CLAMP(val,low,hi) \ (((val) < (low)) ? (low) : ((val) > (hi)) ? (hi) : (val)) #define GAP 3 #define SELECT_PADX 4 #define SELECT_PADY 2 #define OUTER_PAD 2 #define LABEL_PAD 1 #define LABEL_PADX 2 #define LABEL_PADY 2 #define IMAGE_PAD 1 #define CORNER_OFFSET 3 #define TAB_SCROLL_OFFSET 10 #define SLANT_NONE 0 #define SLANT_LEFT 1 #define SLANT_RIGHT 2 #define SLANT_BOTH (SLANT_LEFT | SLANT_RIGHT) #define END (-1) #define ODD(x) ((x) | 0x01) #define TABWIDTH(s, t) \ ((s)->side & SIDE_VERTICAL) ? (t)->height : (t)->width) #define TABHEIGHT(s, t) \ ((s)->side & SIDE_VERTICAL) ? (t)->height : (t)->width) #define VPORTWIDTH(s) \ (((s)->side & SIDE_HORIZONTAL) ? (Tk_Width((s)->tkwin) - 2 * (s)->inset) : \ (Tk_Height((s)->tkwin) - 2 * (s)->inset)) #define VPORTHEIGHT(s) \ (((s)->side & SIDE_VERTICAL) ? (Tk_Width((s)->tkwin) - 2 * (s)->inset) : \ (Tk_Height((s)->tkwin) - 2 * (s)->inset)) #define GETATTR(t,attr) \ (((t)->attr != NULL) ? (t)->attr : (t)->nbPtr->defTabStyle.attr) /* * ---------------------------------------------------------------------------- * * Internal widget flags: * * TNB_LAYOUT The layout of the widget needs to be * recomputed. * * TNB_REDRAW A redraw request is pending for the widget. * * TNB_SCROLL A scroll request is pending. * * TNB_FOCUS The widget is receiving keyboard events. * Draw the focus highlight border around the * widget. * * TNB_MULTIPLE_TIER Notebook is using multiple tiers. * * TNB_STATIC Notebook does not scroll. * * --------------------------------------------------------------------------- */ #define TNB_LAYOUT (1<<0) #define TNB_REDRAW (1<<1) #define TNB_SCROLL (1<<2) #define TNB_FOCUS (1<<4) #define TNB_STATIC (1<<8) #define TNB_MULTIPLE_TIER (1<<9) #define PERFORATION_ACTIVE (1<<10) #define SIDE_TOP (1<<0) #define SIDE_RIGHT (1<<1) #define SIDE_LEFT (1<<2) #define SIDE_BOTTOM (1<<3) #define SIDE_VERTICAL (SIDE_LEFT | SIDE_RIGHT) #define SIDE_HORIZONTAL (SIDE_TOP | SIDE_BOTTOM) #define TAB_LABEL (ClientData)0 #define TAB_PERFORATION (ClientData)1 #define DEF_TNB_ACTIVE_BACKGROUND RGB_GREY90 #define DEF_TNB_ACTIVE_BG_MONO STD_ACTIVE_BG_MONO #define DEF_TNB_ACTIVE_FOREGROUND STD_ACTIVE_FOREGROUND #define DEF_TNB_ACTIVE_FG_MONO STD_ACTIVE_FG_MONO #define DEF_TNB_BG_MONO STD_NORMAL_BG_MONO #define DEF_TNB_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_TNB_BORDERWIDTH "1" #define DEF_TNB_COMMAND (char *)NULL #define DEF_TNB_CURSOR (char *)NULL #define DEF_TNB_DASHES "1" #define DEF_TNB_FOREGROUND STD_NORMAL_FOREGROUND #define DEF_TNB_FG_MONO STD_NORMAL_FG_MONO #define DEF_TNB_FONT STD_FONT #define DEF_TNB_GAP "3" #define DEF_TNB_HEIGHT "0" #define DEF_TNB_HIGHLIGHT_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_TNB_HIGHLIGHT_BG_MONO STD_NORMAL_BG_MONO #define DEF_TNB_HIGHLIGHT_COLOR RGB_BLACK #define DEF_TNB_HIGHLIGHT_WIDTH "2" #define DEF_TNB_NORMAL_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_TNB_NORMAL_FG_MONO STD_ACTIVE_FG_MONO #define DEF_TNB_OUTER_PAD "3" #define DEF_TNB_RELIEF "sunken" #define DEF_TNB_ROTATE "0.0" #define DEF_TNB_SCROLL_INCREMENT "0" #define DEF_TNB_SELECT_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_TNB_SELECT_BG_MONO STD_SELECT_BG_MONO #define DEF_TNB_SELECT_BORDERWIDTH "1" #define DEF_TNB_SELECT_CMD (char *)NULL #define DEF_TNB_SELECT_FOREGROUND STD_SELECT_FOREGROUND #define DEF_TNB_SELECT_FG_MONO STD_SELECT_FG_MONO #define DEF_TNB_SELECT_MODE "multiple" #define DEF_TNB_SELECT_RELIEF "raised" #define DEF_TNB_SELECT_PAD "5" #define DEF_TNB_SHADOW_COLOR RGB_BLACK #define DEF_TNB_SIDE "top" #define DEF_TNB_SLANT "none" #define DEF_TNB_TAB_BACKGROUND RGB_GREY82 #define DEF_TNB_TAB_BG_MONO STD_SELECT_BG_MONO #define DEF_TNB_TAB_RELIEF "raised" #define DEF_TNB_TAKE_FOCUS "1" #define DEF_TNB_TEXT_COLOR STD_NORMAL_FOREGROUND #define DEF_TNB_TEXT_MONO STD_NORMAL_FG_MONO #define DEF_TNB_TEXT_SIDE "left" #define DEF_TNB_TIERS "1" #define DEF_TNB_TILE (char *)NULL #define DEF_TNB_WIDTH "0" #define DEF_TNB_SAME_WIDTH "yes" #define DEF_TNB_TEAROFF "yes" #define DEF_TNB_PAGE_WIDTH "0" #define DEF_TNB_PAGE_HEIGHT "0" #define DEF_TAB_ACTIVE_BG (char *)NULL #define DEF_TAB_ACTIVE_FG (char *)NULL #define DEF_TAB_ANCHOR "center" #define DEF_TAB_BG (char *)NULL #define DEF_TAB_COMMAND (char *)NULL #define DEF_TAB_DATA (char *)NULL #define DEF_TAB_FG (char *)NULL #define DEF_TAB_FILL "none" #define DEF_TAB_FONT (char *)NULL #define DEF_TAB_HEIGHT "0" #define DEF_TAB_IMAGE (char *)NULL #define DEF_TAB_IPAD "0" #define DEF_TAB_PAD "3" #define DEF_TAB_PERF_COMMAND (char *)NULL #define DEF_TAB_SELECT_BG (char *)NULL #define DEF_TAB_SELECT_BORDERWIDTH "1" #define DEF_TAB_SELECT_CMD (char *)NULL #define DEF_TAB_SELECT_FG (char *)NULL #define DEF_TAB_SHADOW (char *)NULL #define DEF_TAB_STATE "normal" #define DEF_TAB_STIPPLE "BLT" #define DEF_TAB_BIND_TAGS "all" #define DEF_TAB_TEXT (char *)NULL #define DEF_TAB_VISUAL (char *)NULL #define DEF_TAB_WIDTH "0" #define DEF_TAB_WINDOW (char *)NULL typedef struct NotebookStruct Notebook; static void EmbeddedWidgetGeometryProc _ANSI_ARGS_((ClientData, Tk_Window)); static void EmbeddedWidgetCustodyProc _ANSI_ARGS_((ClientData, Tk_Window)); static Tk_GeomMgr tabMgrInfo = { "notebook", /* Name of geometry manager used by winfo */ EmbeddedWidgetGeometryProc, /* Procedure to for new geometry requests */ EmbeddedWidgetCustodyProc, /* Procedure when window is taken away */ }; extern Tk_CustomOption bltDashesOption; extern Tk_CustomOption bltFillOption; extern Tk_CustomOption bltDistanceOption; extern Tk_CustomOption bltPositiveDistanceOption; extern Tk_CustomOption bltPositiveCountOption; extern Tk_CustomOption bltListOption; extern Tk_CustomOption bltPadOption; extern Tk_CustomOption bltShadowOption; extern Tk_CustomOption bltStateOption; extern Tk_CustomOption bltTileOption; extern Tk_CustomOption bltUidOption; static int StringToImage _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *string, char *widgRec, int offset)); static char *ImageToString _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, char *widgRec, int offset, Tcl_FreeProc **freeProcPtrPtr)); static int StringToWindow _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *string, char *widgRec, int offset)); static char *WindowToString _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, char *widgRec, int offset, Tcl_FreeProc **freeProcPtrPtr)); static int StringToSide _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *string, char *widgRec, int offset)); static char *SideToString _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, char *widgRec, int offset, Tcl_FreeProc **freeProcPtrPtr)); static int StringToSlant _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *string, char *widgRec, int offset)); static char *SlantToString _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, char *widgRec, int offset, Tcl_FreeProc **freeProcPtrPtr)); /* * Contains a pointer to the widget that's currently being configured. * This is used in the custom configuration parse routine for images. */ static Notebook *lastNotebookInstance; static Tk_CustomOption imageOption = { StringToImage, ImageToString, (ClientData)&lastNotebookInstance, }; static Tk_CustomOption sideOption = { StringToSide, SideToString, (ClientData)0, }; static Tk_CustomOption windowOption = { StringToWindow, WindowToString, (ClientData)0, }; static Tk_CustomOption slantOption = { StringToSlant, SlantToString, (ClientData)0, }; /* * TabImage -- * * When multiple instances of an image are displayed in the * same widget, this can be inefficient in terms of both memory * and time. We only need one instance of each image, regardless * of number of times we use it. And searching/deleting instances * can be very slow as the list gets large. * * The workaround, employed below, is to maintain a hash table of * images that maintains a reference count for each image. */ typedef struct TabImageStruct { int refCount; /* Reference counter for this image. */ Tk_Image tkImage; /* The Tk image being cached. */ int width, height; /* Dimensions of the cached image. */ Blt_HashEntry *hashPtr; /* Hash table pointer to the image. */ } *TabImage; #define ImageHeight(image) ((image)->height) #define ImageWidth(image) ((image)->width) #define ImageBits(image) ((image)->tkImage) #define TAB_VISIBLE (1<<0) #define TAB_REDRAW (1<<2) typedef struct { char *name; /* Identifier for tab entry */ int state; /* State of the tab: Disabled, active, or * normal. */ unsigned int flags; int tier; /* Index of tier [1..numTiers] containing * this tab. */ int worldX, worldY; /* Position of the tab in world coordinates. */ int worldWidth, worldHeight;/* Dimensions of the tab, corrected for * orientation (-side). It includes the * border, padding, label, etc. */ int screenX, screenY; short int screenWidth, screenHeight; /* */ Notebook *nbPtr; /* Notebook that includes this * tab. Needed for callbacks can pass * only a tab pointer. */ Blt_Uid tags; /* * Tab label: */ Blt_Uid text; /* String displayed as the tab's label. */ TabImage image; /* Image displayed as the label. */ short int textWidth, textHeight; short int labelWidth, labelHeight; Blt_Pad iPadX, iPadY; /* Internal padding around the text */ Tk_Font font; /* * Normal: */ XColor *textColor; /* Text color */ Tk_3DBorder border; /* Background color and border for tab.*/ /* * Selected: Tab is currently selected. */ XColor *selColor; /* Selected text color */ Tk_3DBorder selBorder; /* 3D border of selected folder. */ /* * Active: Mouse passes over the tab. */ Tk_3DBorder activeBorder; /* Active background color. */ XColor *activeFgColor; /* Active text color */ Shadow shadow; Pixmap stipple; /* Stipple for outline of embedded window * when torn off. */ /* * Embedded widget information: */ Tk_Window tkwin; /* Widget to be mapped when the tab is * selected. If NULL, don't make * space for the page. */ int reqWidth, reqHeight; /* If non-zero, overrides the * requested dimensions of the * embedded widget. */ Tk_Window container; /* The window containing the embedded * widget. Does not necessarily have * to be the parent. */ Tk_Anchor anchor; /* Anchor: indicates how the embedded * widget is positioned within the * extra space on the page. */ Blt_Pad padX, padY; /* Padding around embedded widget */ int fill; /* Indicates how the window should * fill the page. */ /* * Auxillary information: */ Blt_Uid command; /* Command (malloc-ed) invoked when the tab * is selected */ Blt_Uid data; /* This value isn't used in C code. * It may be used by clients in Tcl bindings * to associate extra data (other than the * label or name) with the tab. */ Blt_ChainLink *linkPtr; /* Pointer to where the tab resides in the * list of tabs. */ Blt_Uid perfCommand; /* Command (malloc-ed) invoked when the tab * is selected */ GC textGC; GC backGC; Blt_Tile tile; } Tab; static Tk_ConfigSpec tabConfigSpecs[] = { {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "ActiveBackground", DEF_TAB_ACTIVE_BG, Tk_Offset(Tab, activeBorder), TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "ActiveForeground", DEF_TAB_ACTIVE_FG, Tk_Offset(Tab, activeFgColor), TK_CONFIG_NULL_OK}, {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", DEF_TAB_ANCHOR, Tk_Offset(Tab, anchor), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_TAB_BG, Tk_Offset(Tab, border), TK_CONFIG_NULL_OK}, {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags", DEF_TAB_BIND_TAGS, Tk_Offset(Tab, tags), TK_CONFIG_NULL_OK, &bltUidOption}, {TK_CONFIG_CUSTOM, "-command", "command", "Command", DEF_TAB_COMMAND, Tk_Offset(Tab, command), TK_CONFIG_NULL_OK, &bltUidOption}, {TK_CONFIG_CUSTOM, "-data", "data", "data", DEF_TAB_DATA, Tk_Offset(Tab, data), TK_CONFIG_NULL_OK, &bltUidOption}, {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_CUSTOM, "-fill", "fill", "Fill", DEF_TAB_FILL, Tk_Offset(Tab, fill), TK_CONFIG_DONT_SET_DEFAULT, &bltFillOption}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_TAB_FG, Tk_Offset(Tab, textColor), TK_CONFIG_NULL_OK}, {TK_CONFIG_FONT, "-font", "font", "Font", DEF_TAB_FONT, Tk_Offset(Tab, font), 0}, {TK_CONFIG_CUSTOM, "-image", "image", "image", DEF_TAB_IMAGE, Tk_Offset(Tab, image), TK_CONFIG_NULL_OK, &imageOption}, {TK_CONFIG_CUSTOM, "-ipadx", "iPadX", "PadX", DEF_TAB_IPAD, Tk_Offset(Tab, iPadX), TK_CONFIG_DONT_SET_DEFAULT, &bltPadOption}, {TK_CONFIG_CUSTOM, "-ipady", "iPadY", "PadY", DEF_TAB_IPAD, Tk_Offset(Tab, iPadY), TK_CONFIG_DONT_SET_DEFAULT, &bltPadOption}, {TK_CONFIG_CUSTOM, "-padx", "padX", "PadX", DEF_TAB_PAD, Tk_Offset(Tab, padX), 0, &bltPadOption}, {TK_CONFIG_CUSTOM, "-pady", "padY", "PadY", DEF_TAB_PAD, Tk_Offset(Tab, padY), 0, &bltPadOption}, {TK_CONFIG_CUSTOM, "-perforationcommand", "perforationcommand", "PerforationCommand", DEF_TAB_PERF_COMMAND, Tk_Offset(Tab, perfCommand), TK_CONFIG_NULL_OK, &bltUidOption}, {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Background", DEF_TAB_SELECT_BG, Tk_Offset(Tab, selBorder), TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Foreground", DEF_TAB_SELECT_FG, Tk_Offset(Tab, selColor), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-shadow", "shadow", "Shadow", DEF_TAB_SHADOW, Tk_Offset(Tab, shadow), TK_CONFIG_NULL_OK, &bltShadowOption}, {TK_CONFIG_CUSTOM, "-state", "state", "State", DEF_TAB_STATE, Tk_Offset(Tab, state), TK_CONFIG_DONT_SET_DEFAULT, &bltStateOption}, {TK_CONFIG_BITMAP, "-stipple", "stipple", "Stipple", DEF_TAB_STIPPLE, Tk_Offset(Tab, stipple), 0}, {TK_CONFIG_CUSTOM, "-tile", "tile", "Tile", (char *)NULL, Tk_Offset(Tab, tile), TK_CONFIG_NULL_OK, &bltTileOption}, {TK_CONFIG_CUSTOM, "-text", "Text", "Text", DEF_TAB_TEXT, Tk_Offset(Tab, text), TK_CONFIG_NULL_OK, &bltUidOption}, {TK_CONFIG_CUSTOM, "-window", "window", "Window", DEF_TAB_WINDOW, Tk_Offset(Tab, tkwin), TK_CONFIG_NULL_OK, &windowOption}, {TK_CONFIG_CUSTOM, "-windowheight", "windowHeight", "WindowHeight", DEF_TAB_HEIGHT, Tk_Offset(Tab, reqHeight), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-windowwidth", "windowWidth", "WindowWidth", DEF_TAB_WIDTH, Tk_Offset(Tab, reqWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; /* * TabAttributes -- */ typedef struct { Tk_Window tkwin; /* Default window to map pages. */ int reqWidth, reqHeight; /* Requested tab size. */ int constWidth; int borderWidth; /* Width of 3D border around the tab's * label. */ int pad; /* Extra padding of a tab entry */ XColor *activeFgColor; /* Active foreground. */ Tk_3DBorder activeBorder; /* Active background. */ XColor *selColor; /* Selected foreground. */ Tk_Font font; XColor *textColor; Tk_3DBorder border; /* Normal background. */ Tk_3DBorder selBorder; /* Selected background. */ Blt_Dashes dashes; GC normalGC, activeGC; int relief; char *command; char *perfCommand; /* Command (malloc-ed) invoked when the tab * is selected */ double rotate; int textSide; } TabAttributes; struct NotebookStruct { Tk_Window tkwin; /* Window that embodies the widget. * NULL means that the window has been * destroyed but the data structures * haven't yet been cleaned up.*/ Display *display; /* Display containing widget; needed, * among other things, to release * resources after tkwin has already * gone away. */ Tcl_Interp *interp; /* Interpreter associated with widget. */ Tcl_Command cmdToken; /* Token for widget's command. */ unsigned int flags; /* For bitfield definitions, see below */ int inset; /* Total width of all borders, including * traversal highlight and 3-D border. * Indicates how much interior stuff must * be offset from outside edges to leave * room for borders. */ int inset2; /* Total width of 3-D folder border + corner, * Indicates how much interior stuff must * be offset from outside edges of folder.*/ int yPad; /* Extra offset for selected tab. Only * for single tiers. */ int pageTop; /* Offset from top of notebook to the * start of the page. */ Tk_Cursor cursor; /* X Cursor */ Tk_3DBorder border; /* 3D border surrounding the window. */ int borderWidth; /* Width of 3D border. */ int relief; /* 3D border relief. */ XColor *shadowColor; /* Shadow color around folder. */ /* * Focus highlight ring */ int highlightWidth; /* Width in pixels of highlight to draw * around widget when it has the focus. * <= 0 means don't draw a highlight. */ XColor *highlightBgColor; /* Color for drawing traversal highlight * area when highlight is off. */ XColor *highlightColor; /* Color for drawing traversal highlight. */ GC highlightGC; /* GC for focus highlight. */ char *takeFocus; /* Says whether to select this widget during * tab traveral operations. This value isn't * used in C code, but for the widget's Tcl * bindings. */ int side; /* Orientation of the notebook: either * SIDE_LEFT, SIDE_RIGHT, SIDE_TOP, or * SIDE_BOTTOM. */ int slant; int overlap; int gap; int tabWidth, tabHeight; int xSelectPad, ySelectPad; /* Padding around label of the selected tab. */ int outerPad; /* Padding around the exterior of the notebook * and folder. */ TabAttributes defTabStyle; /* Global attribute information specific to * tabs. */ Blt_Tile tile; int reqWidth, reqHeight; /* Requested dimensions of the notebook * window. */ int pageWidth, pageHeight; /* Dimensions of a page in the folder. */ int reqPageWidth, reqPageHeight; /* Requested dimensions of a page. */ int lastX, lastY; /* * Scrolling information: */ int worldWidth; int scrollOffset; /* Offset of viewport in world coordinates. */ char *scrollCmdPrefix; /* Command strings to control scrollbar.*/ int scrollUnits; /* Smallest unit of scrolling for tabs. */ /* * Scanning information: */ int scanAnchor; /* Scan anchor in screen coordinates. */ int scanOffset; /* Offset of the start of the scan in world * coordinates.*/ int corner; /* Number of pixels to offset next point * when drawing corners of the folder. */ int reqTiers; /* Requested number of tiers. Zero means to * dynamically scroll if there are too many * tabs to be display on a single tier. */ int nTiers; /* Actual number of tiers. */ Blt_HashTable imageTable; Tab *selectPtr; /* The currently selected tab. * (i.e. its page is displayed). */ Tab *activePtr; /* Tab last located under the pointer. * It is displayed with its active * foreground/background colors. */ Tab *focusPtr; /* Tab currently receiving focus. */ Tab *startPtr; /* The first tab on the first tier. */ Blt_Chain *chainPtr; /* List of tab entries. Used to * arrange placement of tabs. */ Blt_HashTable tabTable; /* Hash table of tab entries. Used for * lookups of tabs by name. */ int nextId; int nVisible; /* Number of tabs that are currently visible * in the view port. */ Blt_BindTable bindTable; /* Tab binding information */ Blt_HashTable tagTable; /* Table of bind tags. */ int tearoff; }; static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "activeBackground", DEF_TNB_ACTIVE_BACKGROUND, Tk_Offset(Notebook, defTabStyle.activeBorder), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "activeBackground", DEF_TNB_ACTIVE_BG_MONO, Tk_Offset(Notebook, defTabStyle.activeBorder), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "activeForeground", DEF_TNB_ACTIVE_FOREGROUND, Tk_Offset(Notebook, defTabStyle.activeFgColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "activeForeground", DEF_TNB_ACTIVE_FG_MONO, Tk_Offset(Notebook, defTabStyle.activeFgColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_TNB_BG_MONO, Tk_Offset(Notebook, border), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_TNB_BACKGROUND, Tk_Offset(Notebook, border), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", DEF_TNB_CURSOR, Tk_Offset(Notebook, cursor), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-borderwidth", "borderWidth", "BorderWidth", DEF_TNB_BORDERWIDTH, Tk_Offset(Notebook, borderWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-dashes", "dashes", "Dashes", DEF_TNB_DASHES, Tk_Offset(Notebook, defTabStyle.dashes), TK_CONFIG_NULL_OK, &bltDashesOption}, {TK_CONFIG_SYNONYM, "-fg", "tabForeground", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_FONT, "-font", "font", "Font", DEF_TNB_FONT, Tk_Offset(Notebook, defTabStyle.font), 0}, {TK_CONFIG_SYNONYM, "-foreground", "tabForeground", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_PIXELS, "-gap", "gap", "Gap", DEF_TNB_GAP, Tk_Offset(Notebook, gap), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-height", "height", "Height", DEF_TNB_HEIGHT, Tk_Offset(Notebook, reqHeight), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", "HighlightBackground", DEF_TNB_HIGHLIGHT_BACKGROUND, Tk_Offset(Notebook, highlightBgColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", "HighlightBackground", DEF_TNB_HIGHLIGHT_BG_MONO, Tk_Offset(Notebook, highlightBgColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", DEF_TNB_HIGHLIGHT_COLOR, Tk_Offset(Notebook, highlightColor), 0}, {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", "HighlightThickness", DEF_TNB_HIGHLIGHT_WIDTH, Tk_Offset(Notebook, highlightWidth), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-outerpad", "outerPad", "OuterPad", DEF_TNB_OUTER_PAD, Tk_Offset(Notebook, outerPad), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-pageheight", "pageHeight", "PageHeight", DEF_TNB_PAGE_HEIGHT, Tk_Offset(Notebook, reqPageHeight), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-pagewidth", "pageWidth", "PageWidth", DEF_TNB_PAGE_WIDTH, Tk_Offset(Notebook, reqPageWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_STRING, "-perforationcommand", "perforationcommand", "PerforationCommand", DEF_TAB_PERF_COMMAND, Tk_Offset(Notebook, defTabStyle.perfCommand), TK_CONFIG_NULL_OK, &bltUidOption}, {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_TNB_RELIEF, Tk_Offset(Notebook, relief), 0}, {TK_CONFIG_DOUBLE, "-rotate", "rotate", "Rotate", DEF_TNB_ROTATE, Tk_Offset(Notebook, defTabStyle.rotate), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_BOOLEAN, "-samewidth", "sameWidth", "SameWidth", DEF_TNB_SAME_WIDTH, Tk_Offset(Notebook, defTabStyle.constWidth), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_STRING, "-scrollcommand", "scrollCommand", "ScrollCommand", (char *)NULL, Tk_Offset(Notebook, scrollCmdPrefix), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-scrollincrement", "scrollIncrement", "ScrollIncrement", DEF_TNB_SCROLL_INCREMENT, Tk_Offset(Notebook, scrollUnits), TK_CONFIG_DONT_SET_DEFAULT, &bltPositiveDistanceOption}, {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground", DEF_TNB_SELECT_BG_MONO, Tk_Offset(Notebook, defTabStyle.selBorder), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground", DEF_TNB_SELECT_BACKGROUND, Tk_Offset(Notebook, defTabStyle.selBorder), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_STRING, "-selectcommand", "selectCommand", "SelectCommand", DEF_TNB_SELECT_CMD, Tk_Offset(Notebook, defTabStyle.command), TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background", DEF_TNB_SELECT_FG_MONO, Tk_Offset(Notebook, defTabStyle.selColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background", DEF_TNB_SELECT_FOREGROUND, Tk_Offset(Notebook, defTabStyle.selColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_CUSTOM, "-selectpad", "selectPad", "SelectPad", DEF_TNB_SELECT_PAD, Tk_Offset(Notebook, xSelectPad), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_COLOR, "-shadowcolor", "shadowColor", "ShadowColor", DEF_TNB_SHADOW_COLOR, Tk_Offset(Notebook, shadowColor), 0}, {TK_CONFIG_CUSTOM, "-side", "side", "side", DEF_TNB_SIDE, Tk_Offset(Notebook, side), TK_CONFIG_DONT_SET_DEFAULT, &sideOption}, {TK_CONFIG_CUSTOM, "-slant", "slant", "Slant", DEF_TNB_SLANT, Tk_Offset(Notebook, slant), TK_CONFIG_DONT_SET_DEFAULT, &slantOption}, {TK_CONFIG_BORDER, "-tabbackground", "tabBackground", "Background", DEF_TNB_TAB_BG_MONO, Tk_Offset(Notebook, defTabStyle.border), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_BORDER, "-tabbackground", "tabBackground", "Background", DEF_TNB_TAB_BACKGROUND, Tk_Offset(Notebook, defTabStyle.border), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_CUSTOM, "-tabborderwidth", "tabBorderWidth", "BorderWidth", DEF_TNB_BORDERWIDTH, Tk_Offset(Notebook, defTabStyle.borderWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_COLOR, "-tabforeground", "tabForeground", "Foreground", DEF_TNB_TEXT_COLOR, Tk_Offset(Notebook, defTabStyle.textColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-tabforeground", "tabForeground", "Foreground", DEF_TNB_TEXT_MONO, Tk_Offset(Notebook, defTabStyle.textColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_RELIEF, "-tabrelief", "tabRelief", "TabRelief", DEF_TNB_TAB_RELIEF, Tk_Offset(Notebook, defTabStyle.relief), 0}, {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", DEF_TNB_TAKE_FOCUS, Tk_Offset(Notebook, takeFocus), TK_CONFIG_NULL_OK}, {TK_CONFIG_BOOLEAN, "-tearoff", "tearoff", "Tearoff", DEF_TNB_TEAROFF, Tk_Offset(Notebook, tearoff), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-textside", "textSide", "TextSide", DEF_TNB_TEXT_SIDE, Tk_Offset(Notebook, defTabStyle.textSide), TK_CONFIG_DONT_SET_DEFAULT, &sideOption}, {TK_CONFIG_CUSTOM, "-tiers", "tiers", "Tiers", DEF_TNB_TIERS, Tk_Offset(Notebook, reqTiers), TK_CONFIG_DONT_SET_DEFAULT, &bltPositiveCountOption}, {TK_CONFIG_CUSTOM, "-tile", "tile", "Tile", (char *)NULL, Tk_Offset(Notebook, tile), TK_CONFIG_NULL_OK, &bltTileOption}, {TK_CONFIG_CUSTOM, "-width", "width", "Width", DEF_TNB_WIDTH, Tk_Offset(Notebook, reqWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; /* Forward Declarations */ static void DestroyNotebook _ANSI_ARGS_((DestroyData dataPtr)); static void DestroyTearoff _ANSI_ARGS_((DestroyData dataPtr)); static void EmbeddedWidgetEventProc _ANSI_ARGS_((ClientData clientdata, XEvent *eventPtr)); static void TearoffEventProc _ANSI_ARGS_((ClientData clientdata, XEvent *eventPtr)); static void NotebookEventProc _ANSI_ARGS_((ClientData clientdata, XEvent *eventPtr)); static void DrawLabel _ANSI_ARGS_((Notebook *nbPtr, Tab *tabPtr, Drawable drawable)); static void DrawFolder _ANSI_ARGS_((Notebook *nbPtr, Tab *tabPtr, Drawable drawable)); static void DisplayNotebook _ANSI_ARGS_((ClientData clientData)); static void DisplayTearoff _ANSI_ARGS_((ClientData clientData)); static void NotebookInstDeletedCmd _ANSI_ARGS_((ClientData clientdata)); static int NotebookInstCmd _ANSI_ARGS_((ClientData clientdata, Tcl_Interp *interp, int argc, char **argv)); static void GetWindowRectangle _ANSI_ARGS_((Tab *tabPtr, Tk_Window parent, int tearOff, XRectangle *rectPtr)); static void ArrangeWindow _ANSI_ARGS_((Tk_Window tkwin, XRectangle *rectPtr, int force)); static void EventuallyRedraw _ANSI_ARGS_((Notebook *nbPtr)); static void EventuallyRedrawTearoff _ANSI_ARGS_((Tab *tabPtr)); static void ComputeLayout _ANSI_ARGS_((Notebook *nbPtr)); static void DrawOuterBorders _ANSI_ARGS_((Notebook *nbPtr, Drawable drawable)); static Tk_ImageChangedProc ImageChangedProc; static Blt_TileChangedProc TileChangedProc; static Blt_BindTagProc GetTags; static Blt_BindPickProc PickTab; static Tcl_IdleProc AdoptWindow; static Tcl_CmdProc NotebookCmd; static ClientData MakeTag(nbPtr, tagName) Notebook *nbPtr; char *tagName; { Blt_HashEntry *hPtr; int isNew; hPtr = Blt_CreateHashEntry(&(nbPtr->tagTable), tagName, &isNew); assert(hPtr); return Blt_GetHashKey(&(nbPtr->tagTable), hPtr); } /* *---------------------------------------------------------------------- * * WorldToScreen -- * * Converts world coordinates to screen coordinates. Note that * the world view is always tabs up. * * Results: * The screen coordinates are returned via *xScreenPtr and *yScreenPtr. * *---------------------------------------------------------------------- */ static void WorldToScreen(nbPtr, x, y, xScreenPtr, yScreenPtr) Notebook *nbPtr; int x, y; int *xScreenPtr, *yScreenPtr; { int sx, sy; sx = sy = 0; /* Suppress compiler warning. */ /* Translate world X-Y to screen coordinates */ /* * Note that the world X-coordinate is translated by the selected label's * X padding. This is done only to keep the scroll range is between * 0.0 and 1.0, rather adding/subtracting the pad in various locations. * It may be changed back in the future. */ x += (nbPtr->inset + nbPtr->xSelectPad - nbPtr->scrollOffset); y += nbPtr->inset + nbPtr->yPad; switch (nbPtr->side) { case SIDE_TOP: sx = x, sy = y; /* Do nothing */ break; case SIDE_RIGHT: sx = Tk_Width(nbPtr->tkwin) - y; sy = x; break; case SIDE_LEFT: sx = y, sy = x; /* Flip coordinates */ break; case SIDE_BOTTOM: sx = x; sy = Tk_Height(nbPtr->tkwin) - y; break; } *xScreenPtr = sx; *yScreenPtr = sy; } /* *---------------------------------------------------------------------- * * EventuallyRedraw -- * * Queues a request to redraw the widget at the next idle point. * * Results: * None. * * Side effects: * Information gets redisplayed. Right now we don't do selective * redisplays: the whole window will be redrawn. * *---------------------------------------------------------------------- */ static void EventuallyRedraw(nbPtr) Notebook *nbPtr; { if ((nbPtr->tkwin != NULL) && !(nbPtr->flags & TNB_REDRAW)) { nbPtr->flags |= TNB_REDRAW; Tcl_DoWhenIdle(DisplayNotebook, nbPtr); } } /* *---------------------------------------------------------------------- * * EventuallyRedrawTearoff -- * * Queues a request to redraw the tearoff at the next idle point. * * Results: * None. * * Side effects: * Information gets redisplayed. Right now we don't do selective * redisplays: the whole window will be redrawn. * *---------------------------------------------------------------------- */ static void EventuallyRedrawTearoff(tabPtr) Tab *tabPtr; { if ((tabPtr->tkwin != NULL) && !(tabPtr->flags & TAB_REDRAW)) { tabPtr->flags |= TAB_REDRAW; Tcl_DoWhenIdle(DisplayTearoff, tabPtr); } } /* *---------------------------------------------------------------------- * * ImageChangedProc * * This routine is called whenever an image displayed in a tab * changes. In this case, we assume that everything will change * and queue a request to re-layout and redraw the entire notebook. * * Results: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static void ImageChangedProc(clientData, x, y, width, height, imageWidth, imageHeight) ClientData clientData; int x, y, width, height; /* Not used. */ int imageWidth, imageHeight;/* Not used. */ { Notebook *nbPtr = clientData; nbPtr->flags |= (TNB_LAYOUT | TNB_SCROLL); EventuallyRedraw(nbPtr); } /* *---------------------------------------------------------------------- * * GetImage -- * * This is a wrapper procedure for Tk_GetImage. The problem is * that if the same image is used repeatedly in the same widget, * the separate instances are saved in a linked list. This makes * it especially slow to destroy the widget. As a workaround, * this routine hashes the image and maintains a reference count * for it. * * Results: * Returns a pointer to the new image. * *---------------------------------------------------------------------- */ static TabImage GetImage(nbPtr, interp, tkwin, name) Notebook *nbPtr; Tcl_Interp *interp; Tk_Window tkwin; char *name; { struct TabImageStruct *imagePtr; int isNew; Blt_HashEntry *hPtr; hPtr = Blt_CreateHashEntry(&(nbPtr->imageTable), name, &isNew); if (isNew) { Tk_Image tkImage; int width, height; tkImage = Tk_GetImage(interp, tkwin, name, ImageChangedProc, nbPtr); if (tkImage == NULL) { Blt_DeleteHashEntry(&(nbPtr->imageTable), hPtr); return NULL; } Tk_SizeOfImage(tkImage, &width, &height); imagePtr = Blt_Malloc(sizeof(struct TabImageStruct)); imagePtr->tkImage = tkImage; imagePtr->hashPtr = hPtr; imagePtr->refCount = 1; imagePtr->width = width; imagePtr->height = height; Blt_SetHashValue(hPtr, imagePtr); } else { imagePtr = (struct TabImageStruct *)Blt_GetHashValue(hPtr); imagePtr->refCount++; } return imagePtr; } /* *---------------------------------------------------------------------- * * FreeImage -- * * Releases the image if it's not being used anymore by this * widget. Note there may be several uses of the same image * by many tabs. * * Results: * None. * * Side Effects: * The reference count is decremented and the image is freed * is it's not being used anymore. * *---------------------------------------------------------------------- */ static void FreeImage(nbPtr, imagePtr) Notebook *nbPtr; struct TabImageStruct *imagePtr; { imagePtr->refCount--; if (imagePtr->refCount == 0) { Blt_DeleteHashEntry(&(nbPtr->imageTable), imagePtr->hashPtr); Tk_FreeImage(imagePtr->tkImage); Blt_Free(imagePtr); } } /* *---------------------------------------------------------------------- * * StringToImage -- * * Converts an image name into a Tk image token. * * Results: * If the string is successfully converted, TCL_OK is returned. * Otherwise, TCL_ERROR is returned and an error message is left * in interpreter's result field. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToImage(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Contains a pointer to the notebook containing * this image. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Window associated with the notebook. */ char *string; /* String representation */ char *widgRec; /* Widget record */ int offset; /* Offset to field in structure */ { Notebook *nbPtr = *(Notebook **)clientData; TabImage *imagePtr = (TabImage *) (widgRec + offset); TabImage image; image = NULL; if ((string != NULL) && (*string != '\0')) { image = GetImage(nbPtr, interp, tkwin, string); if (image == NULL) { return TCL_ERROR; } } if (*imagePtr != NULL) { FreeImage(nbPtr, *imagePtr); } *imagePtr = image; return TCL_OK; } /* *---------------------------------------------------------------------- * * ImageToString -- * * Converts the Tk image back to its string representation (i.e. * its name). * * Results: * The name of the image is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * ImageToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Pointer to notebook containing image. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget record */ int offset; /* Offset of field in record */ Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */ { Notebook *nbPtr = *(Notebook **)clientData; TabImage *imagePtr = (TabImage *) (widgRec + offset); if (*imagePtr == NULL) { return ""; } return Blt_GetHashKey(&(nbPtr->imageTable), (*imagePtr)->hashPtr); } /* *---------------------------------------------------------------------- * * StringToWindow -- * * Converts a window name into Tk window. * * Results: * If the string is successfully converted, TCL_OK is returned. * Otherwise, TCL_ERROR is returned and an error message is left * in interpreter's result field. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToWindow(clientData, interp, parent, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window parent; /* Parent window */ char *string; /* String representation. */ char *widgRec; /* Widget record */ int offset; /* Offset to field in structure */ { Tab *tabPtr = (Tab *)widgRec; Tk_Window *tkwinPtr = (Tk_Window *)(widgRec + offset); Tk_Window old, tkwin; Notebook *nbPtr; old = *tkwinPtr; tkwin = NULL; nbPtr = tabPtr->nbPtr; if ((string != NULL) && (*string != '\0')) { tkwin = Tk_NameToWindow(interp, string, parent); if (tkwin == NULL) { return TCL_ERROR; } if (tkwin == old) { return TCL_OK; } /* * Allow only widgets that are children of the notebook to be * embedded into the page. This way we can make assumptions about * the window based upon its parent; either it's the notebook window * or it has been torn off. */ parent = Tk_Parent(tkwin); if (parent != nbPtr->tkwin) { Tcl_AppendResult(interp, "can't manage \"", Tk_PathName(tkwin), "\" in notebook \"", Tk_PathName(nbPtr->tkwin), "\"", (char *)NULL); return TCL_ERROR; } Tk_ManageGeometry(tkwin, &tabMgrInfo, tabPtr); Tk_CreateEventHandler(tkwin, StructureNotifyMask, EmbeddedWidgetEventProc, tabPtr); /* * We need to make the window to exist immediately. If the * window is torn off (placed into another container window), * the timing between the container and the its new child * (this window) gets tricky. This should work for Tk 4.2. */ Tk_MakeWindowExist(tkwin); } if (old != NULL) { if (tabPtr->container != NULL) { Tcl_EventuallyFree(tabPtr, DestroyTearoff); } Tk_DeleteEventHandler(old, StructureNotifyMask, EmbeddedWidgetEventProc, tabPtr); Tk_ManageGeometry(old, (Tk_GeomMgr *) NULL, tabPtr); Tk_UnmapWindow(old); } *tkwinPtr = tkwin; return TCL_OK; } /* *---------------------------------------------------------------------- * * WindowToString -- * * Converts the Tk window back to its string representation (i.e. * its name). * * Results: * The name of the window is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * WindowToString(clientData, parent, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window parent; /* Not used. */ char *widgRec; /* Widget record */ int offset; /* Offset of field in record */ Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */ { Tk_Window tkwin = *(Tk_Window *)(widgRec + offset); if (tkwin == NULL) { return ""; } return Tk_PathName(tkwin); } /* *---------------------------------------------------------------------- * * StringToSide -- * * Converts "left", "right", "top", "bottom", into a numeric token * designating the side of the notebook which to display tabs. * * Results: * If the string is successfully converted, TCL_OK is returned. * Otherwise, TCL_ERROR is returned and an error message is left * in interpreter's result field. * *---------------------------------------------------------------------- */ /*ARGSUSED */ static int StringToSide(clientData, interp, parent, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window parent; /* Parent window */ char *string; /* Option value string */ char *widgRec; /* Widget record */ int offset; /* offset to field in structure */ { int *sidePtr = (int *)(widgRec + offset); char c; unsigned int length; c = string[0]; length = strlen(string); if ((c == 'l') && (strncmp(string, "left", length) == 0)) { *sidePtr = SIDE_LEFT; } else if ((c == 'r') && (strncmp(string, "right", length) == 0)) { *sidePtr = SIDE_RIGHT; } else if ((c == 't') && (strncmp(string, "top", length) == 0)) { *sidePtr = SIDE_TOP; } else if ((c == 'b') && (strncmp(string, "bottom", length) == 0)) { *sidePtr = SIDE_BOTTOM; } else { Tcl_AppendResult(interp, "bad side \"", string, "\": should be left, right, top, or bottom", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * SideToString -- * * Converts the window into its string representation (its name). * * Results: * The name of the window is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * SideToString(clientData, parent, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window parent; /* Not used. */ char *widgRec; /* Widget record */ int offset; /* offset of windows array in record */ Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */ { int side = *(int *)(widgRec + offset); switch (side) { case SIDE_LEFT: return "left"; case SIDE_RIGHT: return "right"; case SIDE_BOTTOM: return "bottom"; case SIDE_TOP: return "top"; } return "unknown side value"; } /* *---------------------------------------------------------------------- * * StringToSlant -- * * Converts the slant style string into its numeric representation. * * Valid style strings are: * * "none" Both sides are straight. * "left" Left side is slanted. * "right" Right side is slanted. * "both" Both sides are slanted. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToSlant(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* String representation of attribute. */ char *widgRec; /* Widget record */ int offset; /* Offset of field in widget record. */ { int *slantPtr = (int *)(widgRec + offset); unsigned int length; char c; c = string[0]; length = strlen(string); if ((c == 'n') && (strncmp(string, "none", length) == 0)) { *slantPtr = SLANT_NONE; } else if ((c == 'l') && (strncmp(string, "left", length) == 0)) { *slantPtr = SLANT_LEFT; } else if ((c == 'r') && (strncmp(string, "right", length) == 0)) { *slantPtr = SLANT_RIGHT; } else if ((c == 'b') && (strncmp(string, "both", length) == 0)) { *slantPtr = SLANT_BOTH; } else { Tcl_AppendResult(interp, "bad argument \"", string, "\": should be \"none\", \"left\", \"right\", or \"both\"", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * SlantToString -- * * Returns the slant style string based upon the slant flags. * * Results: * The slant style string is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * SlantToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget structure record. */ int offset; /* Offset of field in widget record. */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { int slant = *(int *)(widgRec + offset); switch (slant) { case SLANT_LEFT: return "left"; case SLANT_RIGHT: return "right"; case SLANT_NONE: return "none"; case SLANT_BOTH: return "both"; default: return "unknown value"; } } static int WorldY(tabPtr) Tab *tabPtr; { int tier; tier = tabPtr->nbPtr->nTiers - tabPtr->tier; return tier * tabPtr->nbPtr->tabHeight; } static int TabIndex(nbPtr, tabPtr) Notebook *nbPtr; Tab *tabPtr; { Tab *t2Ptr; int count; Blt_ChainLink *linkPtr; count = 0; for (linkPtr = Blt_ChainFirstLink(nbPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { t2Ptr = Blt_ChainGetValue(linkPtr); if (t2Ptr == tabPtr) { return count; } count++; } return -1; } /* * ---------------------------------------------------------------------- * * RenumberTiers -- * * In multi-tier mode, we need to find the start of the tier * containing the newly selected tab. * * Tiers are draw from the last tier to the first, so that * the the lower-tiered tabs will partially cover the bottoms * of tab directly above it. This simplifies the drawing of * tabs because we don't worry how tabs are clipped by their * neighbors. * * In addition, tabs are re-marked with the correct tier number. * * Results: * None. * * Side Effects: * Renumbering the tab's tier will change the vertical placement * of the tab (i.e. shift tiers). * * ---------------------------------------------------------------------- */ static void RenumberTiers(nbPtr, tabPtr) Notebook *nbPtr; Tab *tabPtr; { int tier; Tab *prevPtr; Blt_ChainLink *linkPtr, *lastPtr; nbPtr->focusPtr = nbPtr->selectPtr = tabPtr; Blt_SetFocusItem(nbPtr->bindTable, nbPtr->focusPtr, NULL); tier = tabPtr->tier; for (linkPtr = Blt_ChainPrevLink(tabPtr->linkPtr); linkPtr != NULL; linkPtr = lastPtr) { lastPtr = Blt_ChainPrevLink(linkPtr); prevPtr = Blt_ChainGetValue(linkPtr); if ((prevPtr == NULL) || (prevPtr->tier != tier)) { break; } tabPtr = prevPtr; } nbPtr->startPtr = tabPtr; for (linkPtr = Blt_ChainFirstLink(nbPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); tabPtr->tier = (tabPtr->tier - tier + 1); if (tabPtr->tier < 1) { tabPtr->tier += nbPtr->nTiers; } tabPtr->worldY = WorldY(tabPtr); } } /* *---------------------------------------------------------------------- * * PickTab -- * * Searches the tab located within the given screen X-Y coordinates * in the viewport. Note that tabs overlap slightly, so that its * important to search from the innermost tier out. * * Results: * Returns the pointer to the tab. If the pointer isn't contained * by any tab, NULL is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static ClientData PickTab(clientData, x, y, contextPtr) ClientData clientData; int x, y; /* Screen coordinates to test. */ ClientData *contextPtr; { Notebook *nbPtr = clientData; Tab *tabPtr; Blt_ChainLink *linkPtr; if (contextPtr != NULL) { *contextPtr = NULL; } tabPtr = nbPtr->selectPtr; if ((nbPtr->tearoff) && (tabPtr != NULL) && (tabPtr->container == NULL) && (tabPtr->tkwin != NULL)) { int top, bottom, left, right; int sx, sy; /* Check first for perforation on the selected tab. */ WorldToScreen(nbPtr, tabPtr->worldX + 2, tabPtr->worldY + tabPtr->worldHeight + 4, &sx, &sy); if (nbPtr->side & SIDE_HORIZONTAL) { left = sx - 2; right = left + tabPtr->screenWidth; top = sy - 4; bottom = sy + 4; } else { left = sx - 4; right = sx + 4; top = sy - 2; bottom = top + tabPtr->screenHeight; } if ((x >= left) && (y >= top) && (x < right) && (y < bottom)) { if (contextPtr != NULL) { *contextPtr = TAB_PERFORATION; } return nbPtr->selectPtr; } } for (linkPtr = Blt_ChainFirstLink(nbPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); if (!(tabPtr->flags & TAB_VISIBLE)) { continue; } if ((x >= tabPtr->screenX) && (y >= tabPtr->screenY) && (x <= (tabPtr->screenX + tabPtr->screenWidth)) && (y < (tabPtr->screenY + tabPtr->screenHeight))) { if (contextPtr != NULL) { *contextPtr = TAB_LABEL; } return tabPtr; } } return NULL; } static Tab * TabLeft(tabPtr) Tab *tabPtr; { Blt_ChainLink *linkPtr; linkPtr = Blt_ChainPrevLink(tabPtr->linkPtr); if (linkPtr != NULL) { Tab *newPtr; newPtr = Blt_ChainGetValue(linkPtr); /* Move only if the next tab is on another tier. */ if (newPtr->tier == tabPtr->tier) { tabPtr = newPtr; } } return tabPtr; } static Tab * TabRight(tabPtr) Tab *tabPtr; { Blt_ChainLink *linkPtr; linkPtr = Blt_ChainNextLink(tabPtr->linkPtr); if (linkPtr != NULL) { Tab *newPtr; newPtr = Blt_ChainGetValue(linkPtr); /* Move only if the next tab is on another tier. */ if (newPtr->tier == tabPtr->tier) { tabPtr = newPtr; } } return tabPtr; } static Tab * TabUp(tabPtr) Tab *tabPtr; { if (tabPtr != NULL) { Notebook *nbPtr; int x, y; int worldX, worldY; nbPtr = tabPtr->nbPtr; worldX = tabPtr->worldX + (tabPtr->worldWidth / 2); worldY = tabPtr->worldY - (nbPtr->tabHeight / 2); WorldToScreen(nbPtr, worldX, worldY, &x, &y); tabPtr = (Tab *)PickTab(nbPtr, x, y, NULL); if (tabPtr == NULL) { /* * We might have inadvertly picked the gap between two tabs, * so if the first pick fails, try again a little to the left. */ WorldToScreen(nbPtr, worldX + nbPtr->gap, worldY, &x, &y); tabPtr = (Tab *)PickTab(nbPtr, x, y, NULL); } if ((tabPtr == NULL) && (nbPtr->focusPtr->tier < (nbPtr->nTiers - 1))) { worldY -= nbPtr->tabHeight; WorldToScreen(nbPtr, worldX, worldY, &x, &y); tabPtr = (Tab *)PickTab(nbPtr, x, y, NULL); } if (tabPtr == NULL) { tabPtr = nbPtr->focusPtr; } } return tabPtr; } static Tab * TabDown(tabPtr) Tab *tabPtr; { if (tabPtr != NULL) { Notebook *nbPtr; int x, y; int worldX, worldY; nbPtr = tabPtr->nbPtr; worldX = tabPtr->worldX + (tabPtr->worldWidth / 2); worldY = tabPtr->worldY + (3 * nbPtr->tabHeight) / 2; WorldToScreen(nbPtr, worldX, worldY, &x, &y); tabPtr = (Tab *)PickTab(nbPtr, x, y, NULL); if (tabPtr == NULL) { /* * We might have inadvertly picked the gap between two tabs, * so if the first pick fails, try again a little to the left. */ WorldToScreen(nbPtr, worldX - nbPtr->gap, worldY, &x, &y); tabPtr = (Tab *)PickTab(nbPtr, x, y, NULL); } if ((tabPtr == NULL) && (nbPtr->focusPtr->tier > 2)) { worldY += nbPtr->tabHeight; WorldToScreen(nbPtr, worldX, worldY, &x, &y); tabPtr = (Tab *)PickTab(nbPtr, x, y, NULL); } if (tabPtr == NULL) { tabPtr = nbPtr->focusPtr; } } return tabPtr; } /* *---------------------------------------------------------------------- * * GetTab -- * * Converts a string representing a tab index into a tab pointer. * The index may be in one of the following forms: * * number Tab at position in the list of tabs. * @x,y Tab closest to the specified X-Y screen coordinates. * "active" Tab mouse is located over. * "focus" Tab is the widget's focus. * "select" Currently selected tab. * "right" Next tab from the focus tab. * "left" Previous tab from the focus tab. * "up" Next tab from the focus tab. * "down" Previous tab from the focus tab. * "end" Last tab in list. * * Results: * If the string is successfully converted, TCL_OK is returned. * The pointer to the node is returned via tabPtrPtr. * Otherwise, TCL_ERROR is returned and an error message is left * in interpreter's result field. * *---------------------------------------------------------------------- */ static int GetTab(nbPtr, string, tabPtrPtr, allowNull) Notebook *nbPtr; char *string; Tab **tabPtrPtr; int allowNull; /* Allow NULL tabPtr */ { Tab *tabPtr; Blt_ChainLink *linkPtr; int position; char c; c = string[0]; tabPtr = NULL; if (nbPtr->focusPtr == NULL) { nbPtr->focusPtr = nbPtr->selectPtr; Blt_SetFocusItem(nbPtr->bindTable, nbPtr->focusPtr, NULL); } if ((isdigit(UCHAR(c))) && (Tcl_GetInt(nbPtr->interp, string, &position) == TCL_OK)) { linkPtr = Blt_ChainGetNthLink(nbPtr->chainPtr, position); if (linkPtr == NULL) { Tcl_AppendResult(nbPtr->interp, "can't find tab \"", string, "\" in \"", Tk_PathName(nbPtr->tkwin), "\": no such index", (char *)NULL); return TCL_ERROR; } tabPtr = Blt_ChainGetValue(linkPtr); } else if ((c == 'a') && (strcmp(string, "active") == 0)) { tabPtr = nbPtr->activePtr; } else if ((c == 'c') && (strcmp(string, "current") == 0)) { tabPtr = (Tab *)Blt_GetCurrentItem(nbPtr->bindTable); } else if ((c == 's') && (strcmp(string, "select") == 0)) { tabPtr = nbPtr->selectPtr; } else if ((c == 'f') && (strcmp(string, "focus") == 0)) { tabPtr = nbPtr->focusPtr; } else if ((c == 'u') && (strcmp(string, "up") == 0)) { switch (nbPtr->side) { case SIDE_LEFT: case SIDE_RIGHT: tabPtr = TabLeft(nbPtr->focusPtr); break; case SIDE_BOTTOM: tabPtr = TabDown(nbPtr->focusPtr); break; case SIDE_TOP: tabPtr = TabUp(nbPtr->focusPtr); break; } } else if ((c == 'd') && (strcmp(string, "down") == 0)) { switch (nbPtr->side) { case SIDE_LEFT: case SIDE_RIGHT: tabPtr = TabRight(nbPtr->focusPtr); break; case SIDE_BOTTOM: tabPtr = TabUp(nbPtr->focusPtr); break; case SIDE_TOP: tabPtr = TabDown(nbPtr->focusPtr); break; } } else if ((c == 'l') && (strcmp(string, "left") == 0)) { switch (nbPtr->side) { case SIDE_LEFT: tabPtr = TabUp(nbPtr->focusPtr); break; case SIDE_RIGHT: tabPtr = TabDown(nbPtr->focusPtr); break; case SIDE_BOTTOM: case SIDE_TOP: tabPtr = TabLeft(nbPtr->focusPtr); break; } } else if ((c == 'r') && (strcmp(string, "right") == 0)) { switch (nbPtr->side) { case SIDE_LEFT: tabPtr = TabDown(nbPtr->focusPtr); break; case SIDE_RIGHT: tabPtr = TabUp(nbPtr->focusPtr); break; case SIDE_BOTTOM: case SIDE_TOP: tabPtr = TabRight(nbPtr->focusPtr); break; } } else if ((c == 'e') && (strcmp(string, "end") == 0)) { linkPtr = Blt_ChainLastLink(nbPtr->chainPtr); if (linkPtr != NULL) { tabPtr = Blt_ChainGetValue(linkPtr); } } else if (c == '@') { int x, y; if (Blt_GetXY(nbPtr->interp, nbPtr->tkwin, string, &x, &y) != TCL_OK) { return TCL_ERROR; } tabPtr = (Tab *)PickTab(nbPtr, x, y, NULL); } else { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&(nbPtr->tabTable), string); if (hPtr != NULL) { tabPtr = (Tab *)Blt_GetHashValue(hPtr); } } *tabPtrPtr = tabPtr; Tcl_ResetResult(nbPtr->interp); if ((!allowNull) && (tabPtr == NULL)) { Tcl_AppendResult(nbPtr->interp, "can't find tab \"", string, "\" in \"", Tk_PathName(nbPtr->tkwin), "\"", (char *)NULL); return TCL_ERROR; } return TCL_OK; } static Tab * NextOrLastTab(tabPtr) Tab *tabPtr; { if (tabPtr->linkPtr != NULL) { Blt_ChainLink *linkPtr; linkPtr = Blt_ChainNextLink(tabPtr->linkPtr); if (linkPtr == NULL) { linkPtr = Blt_ChainPrevLink(tabPtr->linkPtr); } if (linkPtr != NULL) { return Blt_ChainGetValue(linkPtr); } } return NULL; } /* * -------------------------------------------------------------- * * EmbeddedWidgetEventProc -- * * This procedure is invoked by the Tk dispatcher for various * events on embedded widgets contained in the notebook. * * Results: * None. * * Side effects: * When an embedded widget gets deleted, internal structures get * cleaned up. When it gets resized, the notebook is redisplayed. * * -------------------------------------------------------------- */ static void EmbeddedWidgetEventProc(clientData, eventPtr) ClientData clientData; /* Information about the tab window. */ XEvent *eventPtr; /* Information about event. */ { Tab *tabPtr = clientData; if ((tabPtr == NULL) || (tabPtr->tkwin == NULL)) { return; } switch (eventPtr->type) { case ConfigureNotify: /* * If the window's requested size changes, redraw the window. * But only if it's currently the selected page. */ if ((tabPtr->container == NULL) && (Tk_IsMapped(tabPtr->tkwin)) && (tabPtr->nbPtr->selectPtr == tabPtr)) { EventuallyRedraw(tabPtr->nbPtr); } break; case DestroyNotify: /* * Mark the tab as deleted by dereferencing the Tk window * pointer. Redraw the window only if the tab is currently * visible. */ if ((Tk_IsMapped(tabPtr->tkwin)) && (tabPtr->nbPtr->selectPtr == tabPtr)) { EventuallyRedraw(tabPtr->nbPtr); } Tk_DeleteEventHandler(tabPtr->tkwin, StructureNotifyMask, EmbeddedWidgetEventProc, tabPtr); tabPtr->tkwin = NULL; break; } } /* * ---------------------------------------------------------------------- * * EmbeddedWidgetCustodyProc -- * * This procedure is invoked when a tab window has been * stolen by another geometry manager. The information and * memory associated with the tab window is released. * * Results: * None. * * Side effects: * Arranges for the widget formerly associated with the tab * window to have its layout re-computed and arranged at the * next idle point. * * --------------------------------------------------------------------- */ /* ARGSUSED */ static void EmbeddedWidgetCustodyProc(clientData, tkwin) ClientData clientData; /* Information about the former tab window. */ Tk_Window tkwin; /* Not used. */ { Tab *tabPtr = clientData; Notebook *nbPtr; if ((tabPtr == NULL) || (tabPtr->tkwin == NULL)) { return; } nbPtr = tabPtr->nbPtr; if (tabPtr->container != NULL) { Tcl_EventuallyFree(tabPtr, DestroyTearoff); } /* * Mark the tab as deleted by dereferencing the Tk window * pointer. Redraw the window only if the tab is currently * visible. */ if (tabPtr->tkwin != NULL) { if (Tk_IsMapped(tabPtr->tkwin) && (nbPtr->selectPtr == tabPtr)) { nbPtr->flags |= (TNB_LAYOUT | TNB_SCROLL); EventuallyRedraw(nbPtr); } Tk_DeleteEventHandler(tabPtr->tkwin, StructureNotifyMask, EmbeddedWidgetEventProc, tabPtr); tabPtr->tkwin = NULL; } } /* * ------------------------------------------------------------------------- * * EmbeddedWidgetGeometryProc -- * * This procedure is invoked by Tk_GeometryRequest for tab * windows managed by the widget. * * Results: * None. * * Side effects: * Arranges for tkwin, and all its managed siblings, to be * repacked and drawn at the next idle point. * * ------------------------------------------------------------------------ */ /* ARGSUSED */ static void EmbeddedWidgetGeometryProc(clientData, tkwin) ClientData clientData; /* Information about window that got new * preferred geometry. */ Tk_Window tkwin; /* Other Tk-related information about the * window. */ { Tab *tabPtr = clientData; if ((tabPtr == NULL) || (tabPtr->tkwin == NULL)) { fprintf(stderr, "%s: line %d \"tkwin is null\"", __FILE__, __LINE__); return; } tabPtr->nbPtr->flags |= (TNB_LAYOUT | TNB_SCROLL); EventuallyRedraw(tabPtr->nbPtr); } /* * ---------------------------------------------------------------------- * * DestroyTab -- * * ---------------------------------------------------------------------- */ static void DestroyTab(nbPtr, tabPtr) Notebook *nbPtr; Tab *tabPtr; { Blt_HashEntry *hPtr; if (tabPtr->flags & TAB_REDRAW) { Tcl_CancelIdleCall(DisplayTearoff, tabPtr); } if (tabPtr->container != NULL) { Tk_DestroyWindow(tabPtr->container); } if (tabPtr->tkwin != NULL) { Tk_ManageGeometry(tabPtr->tkwin, (Tk_GeomMgr *)NULL, tabPtr); Tk_DeleteEventHandler(tabPtr->tkwin, StructureNotifyMask, EmbeddedWidgetEventProc, tabPtr); if (Tk_IsMapped(tabPtr->tkwin)) { Tk_UnmapWindow(tabPtr->tkwin); } } if (tabPtr == nbPtr->activePtr) { nbPtr->activePtr = NULL; } if (tabPtr == nbPtr->selectPtr) { nbPtr->selectPtr = NextOrLastTab(tabPtr); } if (tabPtr == nbPtr->focusPtr) { nbPtr->focusPtr = nbPtr->selectPtr; Blt_SetFocusItem(nbPtr->bindTable, nbPtr->focusPtr, NULL); } if (tabPtr == nbPtr->startPtr) { nbPtr->startPtr = NULL; } Tk_FreeOptions(tabConfigSpecs, (char *)tabPtr, nbPtr->display, 0); if (tabPtr->text != NULL) { Blt_FreeUid(tabPtr->text); } hPtr = Blt_FindHashEntry(&(nbPtr->tabTable), tabPtr->name); assert(hPtr); Blt_DeleteHashEntry(&(nbPtr->tabTable), hPtr); if (tabPtr->image != NULL) { FreeImage(nbPtr, tabPtr->image); } if (tabPtr->name != NULL) { Blt_Free(tabPtr->name); } if (tabPtr->textGC != NULL) { Tk_FreeGC(nbPtr->display, tabPtr->textGC); } if (tabPtr->backGC != NULL) { Tk_FreeGC(nbPtr->display, tabPtr->backGC); } if (tabPtr->command != NULL) { Blt_FreeUid(tabPtr->command); } if (tabPtr->linkPtr != NULL) { Blt_ChainDeleteLink(nbPtr->chainPtr, tabPtr->linkPtr); } if (tabPtr->tags != NULL) { Blt_FreeUid(tabPtr->tags); } Blt_DeleteBindings(nbPtr->bindTable, tabPtr); Blt_Free(tabPtr); } /* * ---------------------------------------------------------------------- * * CreateTab -- * * Creates a new tab structure. A tab contains information about * the state of the tab and its embedded window. * * Results: * Returns a pointer to the new tab structure. * * ---------------------------------------------------------------------- */ static Tab * CreateTab(nbPtr) Notebook *nbPtr; { Tab *tabPtr; Blt_HashEntry *hPtr; int isNew; char string[200]; tabPtr = Blt_Calloc(1, sizeof(Tab)); assert(tabPtr); tabPtr->nbPtr = nbPtr; sprintf(string, "tab%d", nbPtr->nextId++); tabPtr->name = Blt_Strdup(string); tabPtr->text = Blt_GetUid(string); tabPtr->fill = FILL_NONE; tabPtr->anchor = TK_ANCHOR_CENTER; tabPtr->container = NULL; tabPtr->state = STATE_NORMAL; hPtr = Blt_CreateHashEntry(&(nbPtr->tabTable), string, &isNew); Blt_SetHashValue(hPtr, tabPtr); return tabPtr; } /* *---------------------------------------------------------------------- * * TileChangedProc * * Stub for image change notifications. Since we immediately draw * the image into a pixmap, we don't really care about image changes. * * It would be better if Tk checked for NULL proc pointers. * * Results: * None. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static void TileChangedProc(clientData, tile) ClientData clientData; Blt_Tile tile; /* Not used. */ { Notebook *nbPtr = clientData; if (nbPtr->tkwin != NULL) { EventuallyRedraw(nbPtr); } } static int ConfigureTab(nbPtr, tabPtr) Notebook *nbPtr; Tab *tabPtr; { GC newGC; XGCValues gcValues; unsigned long gcMask; int labelWidth, labelHeight; Tk_Font font; Tk_3DBorder border; font = GETATTR(tabPtr, font); labelWidth = labelHeight = 0; if (tabPtr->text != NULL) { TextStyle ts; double rotWidth, rotHeight; Blt_InitTextStyle(&ts); ts.font = font; ts.shadow.offset = tabPtr->shadow.offset; ts.padX.side1 = ts.padX.side2 = 2; Blt_GetTextExtents(&ts, tabPtr->text, &labelWidth, &labelHeight); Blt_GetBoundingBox(labelWidth, labelHeight, nbPtr->defTabStyle.rotate, &rotWidth, &rotHeight, (Point2D *)NULL); labelWidth = ROUND(rotWidth); labelHeight = ROUND(rotHeight); } tabPtr->textWidth = (short int)labelWidth; tabPtr->textHeight = (short int)labelHeight; if (tabPtr->image != NULL) { int width, height; width = ImageWidth(tabPtr->image) + 2 * IMAGE_PAD; height = ImageHeight(tabPtr->image) + 2 * IMAGE_PAD; if (nbPtr->defTabStyle.textSide & SIDE_VERTICAL) { labelWidth += width; labelHeight = MAX(labelHeight, height); } else { labelHeight += height; labelWidth = MAX(labelWidth, width); } } labelWidth += PADDING(tabPtr->iPadX); labelHeight += PADDING(tabPtr->iPadY); tabPtr->labelWidth = ODD(labelWidth); tabPtr->labelHeight = ODD(labelHeight); newGC = NULL; if (tabPtr->text != NULL) { XColor *colorPtr; gcMask = GCForeground | GCFont; colorPtr = GETATTR(tabPtr, textColor); gcValues.foreground = colorPtr->pixel; gcValues.font = Tk_FontId(font); newGC = Tk_GetGC(nbPtr->tkwin, gcMask, &gcValues); } if (tabPtr->textGC != NULL) { Tk_FreeGC(nbPtr->display, tabPtr->textGC); } tabPtr->textGC = newGC; gcMask = GCForeground | GCStipple | GCFillStyle; gcValues.fill_style = FillStippled; border = GETATTR(tabPtr, border); gcValues.foreground = Tk_3DBorderColor(border)->pixel; gcValues.stipple = tabPtr->stipple; newGC = Tk_GetGC(nbPtr->tkwin, gcMask, &gcValues); if (tabPtr->backGC != NULL) { Tk_FreeGC(nbPtr->display, tabPtr->backGC); } tabPtr->backGC = newGC; /* * GC for tiled background. */ if (tabPtr->tile != NULL) { Blt_SetTileChangedProc(tabPtr->tile, TileChangedProc, nbPtr); } if (tabPtr->flags & TAB_VISIBLE) { EventuallyRedraw(nbPtr); } return TCL_OK; } /* * -------------------------------------------------------------- * * TearoffEventProc -- * * This procedure is invoked by the Tk dispatcher for various * events on the tearoff widget. * * Results: * None. * * Side effects: * When the tearoff gets deleted, internal structures get * cleaned up. When it gets resized or exposed, it's redisplayed. * * -------------------------------------------------------------- */ static void TearoffEventProc(clientData, eventPtr) ClientData clientData; /* Information about the tab window. */ XEvent *eventPtr; /* Information about event. */ { Tab *tabPtr = clientData; if ((tabPtr == NULL) || (tabPtr->tkwin == NULL) || (tabPtr->container == NULL)) { return; } switch (eventPtr->type) { case Expose: if (eventPtr->xexpose.count == 0) { EventuallyRedrawTearoff(tabPtr); } break; case ConfigureNotify: EventuallyRedrawTearoff(tabPtr); break; case DestroyNotify: if (tabPtr->flags & TAB_REDRAW) { tabPtr->flags &= ~TAB_REDRAW; Tcl_CancelIdleCall(DisplayTearoff, clientData); } Tk_DestroyWindow(tabPtr->container); tabPtr->container = NULL; break; } } /* * ---------------------------------------------------------------------------- * * GetReqWidth -- * * Returns the width requested by the embedded tab window and * any requested padding around it. This represents the requested * width of the page. * * Results: * Returns the requested width of the page. * * ---------------------------------------------------------------------------- */ static int GetReqWidth(tabPtr) Tab *tabPtr; { int width; if (tabPtr->reqWidth > 0) { width = tabPtr->reqWidth; } else { width = Tk_ReqWidth(tabPtr->tkwin); } width += PADDING(tabPtr->padX) + 2 * Tk_Changes(tabPtr->tkwin)->border_width; if (width < 1) { width = 1; } return width; } /* * ---------------------------------------------------------------------------- * * GetReqHeight -- * * Returns the height requested by the window and padding around * the window. This represents the requested height of the page. * * Results: * Returns the requested height of the page. * * ---------------------------------------------------------------------------- */ static int GetReqHeight(tabPtr) Tab *tabPtr; { int height; if (tabPtr->reqHeight > 0) { height = tabPtr->reqHeight; } else { height = Tk_ReqHeight(tabPtr->tkwin); } height += PADDING(tabPtr->padY) + 2 * Tk_Changes(tabPtr->tkwin)->border_width; if (height < 1) { height = 1; } return height; } /* * ---------------------------------------------------------------------------- * * TranslateAnchor -- * * Translate the coordinates of a given bounding box based upon the * anchor specified. The anchor indicates where the given xy position * is in relation to the bounding box. * * nw --- n --- ne * | | x,y ---+ * w center e | | * | | +-----+ * sw --- s --- se * * Results: * The translated coordinates of the bounding box are returned. * * ---------------------------------------------------------------------------- */ static void TranslateAnchor(dx, dy, anchor, xPtr, yPtr) int dx, dy; /* Difference between outer and inner regions */ Tk_Anchor anchor; /* Direction of the anchor */ int *xPtr, *yPtr; { int x, y; x = y = 0; switch (anchor) { case TK_ANCHOR_NW: /* Upper left corner */ break; case TK_ANCHOR_W: /* Left center */ y = (dy / 2); break; case TK_ANCHOR_SW: /* Lower left corner */ y = dy; break; case TK_ANCHOR_N: /* Top center */ x = (dx / 2); break; case TK_ANCHOR_CENTER: /* Centered */ x = (dx / 2); y = (dy / 2); break; case TK_ANCHOR_S: /* Bottom center */ x = (dx / 2); y = dy; break; case TK_ANCHOR_NE: /* Upper right corner */ x = dx; break; case TK_ANCHOR_E: /* Right center */ x = dx; y = (dy / 2); break; case TK_ANCHOR_SE: /* Lower right corner */ x = dx; y = dy; break; } *xPtr = (*xPtr) + x; *yPtr = (*yPtr) + y; } static void GetWindowRectangle(tabPtr, parent, tearoff, rectPtr) Tab *tabPtr; Tk_Window parent; int tearoff; XRectangle *rectPtr; { int pad; Notebook *nbPtr; int cavityWidth, cavityHeight; int width, height; int dx, dy; int x, y; nbPtr = tabPtr->nbPtr; pad = nbPtr->inset + nbPtr->inset2; if (!tearoff) { switch (nbPtr->side) { case SIDE_RIGHT: case SIDE_BOTTOM: x = nbPtr->inset + nbPtr->inset2; y = nbPtr->inset + nbPtr->inset2; break; case SIDE_LEFT: x = nbPtr->pageTop; y = nbPtr->inset + nbPtr->inset2; break; case SIDE_TOP: x = nbPtr->inset + nbPtr->inset2; y = nbPtr->pageTop; break; } if (nbPtr->side & SIDE_VERTICAL) { cavityWidth = Tk_Width(nbPtr->tkwin) - (nbPtr->pageTop + pad); cavityHeight = Tk_Height(nbPtr->tkwin) - (2 * pad); } else { cavityWidth = Tk_Width(nbPtr->tkwin) - (2 * pad); cavityHeight = Tk_Height(nbPtr->tkwin) - (nbPtr->pageTop + pad); } } else { x = nbPtr->inset + nbPtr->inset2; #define TEAR_OFF_TAB_SIZE 5 y = nbPtr->inset + nbPtr->inset2 + nbPtr->yPad + nbPtr->outerPad + TEAR_OFF_TAB_SIZE; cavityWidth = Tk_Width(parent) - (2 * pad); cavityHeight = Tk_Height(parent) - (y + pad); } cavityWidth -= PADDING(tabPtr->padX); cavityHeight -= PADDING(tabPtr->padY); if (cavityWidth < 1) { cavityWidth = 1; } if (cavityHeight < 1) { cavityHeight = 1; } width = GetReqWidth(tabPtr); height = GetReqHeight(tabPtr); /* * Resize the embedded window is of the following is true: * * 1) It's been torn off. * 2) The -fill option (horizontal or vertical) is set. * 3) the window is bigger than the cavity. */ if ((tearoff) || (cavityWidth < width) || (tabPtr->fill & FILL_X)) { width = cavityWidth; } if ((tearoff) || (cavityHeight < height) || (tabPtr->fill & FILL_Y)) { height = cavityHeight; } dx = (cavityWidth - width); dy = (cavityHeight - height); if ((dx > 0) || (dy > 0)) { TranslateAnchor(dx, dy, tabPtr->anchor, &x, &y); } /* Remember that X11 windows must be at least 1 pixel. */ if (width < 1) { width = 1; } if (height < 1) { height = 1; } rectPtr->x = (short)(x + tabPtr->padLeft); rectPtr->y = (short)(y + tabPtr->padTop); rectPtr->width = (short)width; rectPtr->height = (short)height; } static void ArrangeWindow(tkwin, rectPtr, force) Tk_Window tkwin; XRectangle *rectPtr; int force; { if ((force) || (rectPtr->x != Tk_X(tkwin)) || (rectPtr->y != Tk_Y(tkwin)) || (rectPtr->width != Tk_Width(tkwin)) || (rectPtr->height != Tk_Height(tkwin))) { Tk_MoveResizeWindow(tkwin, rectPtr->x, rectPtr->y, rectPtr->width, rectPtr->height); } if (!Tk_IsMapped(tkwin)) { Tk_MapWindow(tkwin); } } /*ARGSUSED*/ static void GetTags(table, object, context, list) Blt_BindTable table; ClientData object; ClientData context; Blt_List list; { Tab *tabPtr = (Tab *)object; Notebook *nbPtr; nbPtr = (Notebook *)table->clientData; if (context == TAB_PERFORATION) { Blt_ListAppend(list, MakeTag(nbPtr, "Perforation"), 0); } else if (context == TAB_LABEL) { Blt_ListAppend(list, MakeTag(nbPtr, tabPtr->name), 0); if (tabPtr->tags != NULL) { int nNames; char **names; register char **p; /* * This is a space/time trade-off in favor of space. The tags * are stored as character strings in a hash table. That way, * tabs can share the strings. It's likely that they will. The * down side is that the same string is split over and over again. */ if (Tcl_SplitList((Tcl_Interp *)NULL, tabPtr->tags, &nNames, &names) == TCL_OK) { for (p = names; *p != NULL; p++) { Blt_ListAppend(list, MakeTag(nbPtr, *p), 0); } Blt_Free(names); } } } } /* * -------------------------------------------------------------- * * NotebookEventProc -- * * This procedure is invoked by the Tk dispatcher for various * events on notebook widgets. * * Results: * None. * * Side Effects: * When the window gets deleted, internal structures get * cleaned up. When it gets exposed, it is redisplayed. * * -------------------------------------------------------------- */ static void NotebookEventProc(clientData, eventPtr) ClientData clientData; /* Information about window. */ XEvent *eventPtr; /* Information about event. */ { Notebook *nbPtr = clientData; switch (eventPtr->type) { case Expose: if (eventPtr->xexpose.count == 0) { EventuallyRedraw(nbPtr); } break; case ConfigureNotify: nbPtr->flags |= (TNB_LAYOUT | TNB_SCROLL); EventuallyRedraw(nbPtr); break; case FocusIn: case FocusOut: if (eventPtr->xfocus.detail != NotifyInferior) { if (eventPtr->type == FocusIn) { nbPtr->flags |= TNB_FOCUS; } else { nbPtr->flags &= ~TNB_FOCUS; } EventuallyRedraw(nbPtr); } break; case DestroyNotify: if (nbPtr->tkwin != NULL) { nbPtr->tkwin = NULL; Tcl_DeleteCommandFromToken(nbPtr->interp, nbPtr->cmdToken); } if (nbPtr->flags & TNB_REDRAW) { Tcl_CancelIdleCall(DisplayNotebook, nbPtr); } Tcl_EventuallyFree(nbPtr, DestroyNotebook); break; } } /* * ---------------------------------------------------------------------- * * DestroyNotebook -- * * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release * to clean up the internal structure of the widget at a safe * time (when no-one is using it anymore). * * Results: * None. * * Side Effects: * Everything associated with the widget is freed up. * * ---------------------------------------------------------------------- */ static void DestroyNotebook(dataPtr) DestroyData dataPtr; /* Pointer to the widget record. */ { Notebook *nbPtr = (Notebook *)dataPtr; Tab *tabPtr; Blt_ChainLink *linkPtr; if (nbPtr->highlightGC != NULL) { Tk_FreeGC(nbPtr->display, nbPtr->highlightGC); } if (nbPtr->tile != NULL) { Blt_FreeTile(nbPtr->tile); } if (nbPtr->defTabStyle.activeGC != NULL) { Blt_FreePrivateGC(nbPtr->display, nbPtr->defTabStyle.activeGC); } for (linkPtr = Blt_ChainFirstLink(nbPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); tabPtr->linkPtr = NULL; DestroyTab(nbPtr, tabPtr); } Blt_ChainDestroy(nbPtr->chainPtr); Blt_DestroyBindingTable(nbPtr->bindTable); Blt_DeleteHashTable(&(nbPtr->tabTable)); Blt_DeleteHashTable(&(nbPtr->tagTable)); Tk_FreeOptions(configSpecs, (char *)nbPtr, nbPtr->display, 0); Blt_Free(nbPtr); } /* * ---------------------------------------------------------------------- * * CreateNotebook -- * * ---------------------------------------------------------------------- */ static Notebook * CreateNotebook(interp, tkwin) Tcl_Interp *interp; Tk_Window tkwin; { Notebook *nbPtr; nbPtr = Blt_Calloc(1, sizeof(Notebook)); assert(nbPtr); Tk_SetClass(tkwin, "Tabnotebook"); nbPtr->tkwin = tkwin; nbPtr->display = Tk_Display(tkwin); nbPtr->interp = interp; nbPtr->flags |= (TNB_LAYOUT | TNB_SCROLL); nbPtr->side = SIDE_TOP; nbPtr->borderWidth = nbPtr->highlightWidth = 2; nbPtr->ySelectPad = SELECT_PADY; nbPtr->xSelectPad = SELECT_PADX; nbPtr->relief = TK_RELIEF_SUNKEN; nbPtr->defTabStyle.relief = TK_RELIEF_RAISED; nbPtr->defTabStyle.borderWidth = 1; nbPtr->defTabStyle.constWidth = TRUE; nbPtr->defTabStyle.textSide = SIDE_LEFT; nbPtr->scrollUnits = 2; nbPtr->corner = CORNER_OFFSET; nbPtr->gap = GAP; nbPtr->outerPad = OUTER_PAD; nbPtr->slant = SLANT_NONE; nbPtr->overlap = 0; nbPtr->tearoff = TRUE; nbPtr->bindTable = Blt_CreateBindingTable(interp, tkwin, nbPtr, PickTab, GetTags); nbPtr->chainPtr = Blt_ChainCreate(); Blt_InitHashTable(&(nbPtr->tabTable), BLT_STRING_KEYS); Blt_InitHashTable(&(nbPtr->imageTable), BLT_STRING_KEYS); Blt_InitHashTable(&(nbPtr->tagTable), BLT_STRING_KEYS); #if (TK_MAJOR_VERSION > 4) Blt_SetWindowInstanceData(tkwin, nbPtr); #endif return nbPtr; } /* * ---------------------------------------------------------------------- * * ConfigureNotebook -- * * This procedure is called to process an argv/argc list, plus * the Tk option database, in order to configure (or reconfigure) * the widget. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then interp->result contains an error message. * * Side Effects: * Configuration information, such as text string, colors, font, * etc. get set for nbPtr; old resources get freed, if there * were any. The widget is redisplayed. * * ---------------------------------------------------------------------- */ static int ConfigureNotebook(interp, nbPtr, argc, argv, flags) Tcl_Interp *interp; /* Interpreter to report errors. */ Notebook *nbPtr; /* Information about widget; may or * may not already have values for * some fields. */ int argc; char **argv; int flags; { XGCValues gcValues; unsigned long gcMask; GC newGC; lastNotebookInstance = nbPtr; if (Tk_ConfigureWidget(interp, nbPtr->tkwin, configSpecs, argc, argv, (char *)nbPtr, flags) != TCL_OK) { return TCL_ERROR; } if (Blt_ConfigModified(configSpecs, "-width", "-height", "-side", "-gap", "-slant", (char *)NULL)) { nbPtr->flags |= (TNB_LAYOUT | TNB_SCROLL); } if ((nbPtr->reqHeight > 0) && (nbPtr->reqWidth > 0)) { Tk_GeometryRequest(nbPtr->tkwin, nbPtr->reqWidth, nbPtr->reqHeight); } /* * GC for focus highlight. */ gcMask = GCForeground; gcValues.foreground = nbPtr->highlightColor->pixel; newGC = Tk_GetGC(nbPtr->tkwin, gcMask, &gcValues); if (nbPtr->highlightGC != NULL) { Tk_FreeGC(nbPtr->display, nbPtr->highlightGC); } nbPtr->highlightGC = newGC; /* * GC for tiled background. */ if (nbPtr->tile != NULL) { Blt_SetTileChangedProc(nbPtr->tile, TileChangedProc, nbPtr); } /* * GC for active line. */ gcMask = GCForeground | GCLineWidth | GCLineStyle | GCCapStyle; gcValues.foreground = nbPtr->defTabStyle.activeFgColor->pixel; gcValues.line_width = 0; gcValues.cap_style = CapProjecting; gcValues.line_style = (LineIsDashed(nbPtr->defTabStyle.dashes)) ? LineOnOffDash : LineSolid; newGC = Blt_GetPrivateGC(nbPtr->tkwin, gcMask, &gcValues); if (LineIsDashed(nbPtr->defTabStyle.dashes)) { nbPtr->defTabStyle.dashes.offset = 2; Blt_SetDashes(nbPtr->display, newGC, &(nbPtr->defTabStyle.dashes)); } if (nbPtr->defTabStyle.activeGC != NULL) { Blt_FreePrivateGC(nbPtr->display, nbPtr->defTabStyle.activeGC); } nbPtr->defTabStyle.activeGC = newGC; nbPtr->defTabStyle.rotate = FMOD(nbPtr->defTabStyle.rotate, 360.0); if (nbPtr->defTabStyle.rotate < 0.0) { nbPtr->defTabStyle.rotate += 360.0; } nbPtr->inset = nbPtr->highlightWidth + nbPtr->borderWidth + nbPtr->outerPad; if (Blt_ConfigModified(configSpecs, "-font", "-*foreground", "-rotate", "-*background", "-side", (char *)NULL)) { Blt_ChainLink *linkPtr; Tab *tabPtr; for (linkPtr = Blt_ChainFirstLink(nbPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); ConfigureTab(nbPtr, tabPtr); } nbPtr->flags |= (TNB_LAYOUT | TNB_SCROLL); } nbPtr->inset2 = nbPtr->defTabStyle.borderWidth + nbPtr->corner; EventuallyRedraw(nbPtr); return TCL_OK; } /* * -------------------------------------------------------------- * * Notebook operations * * -------------------------------------------------------------- */ /* *---------------------------------------------------------------------- * * ActivateOp -- * * Selects the tab to appear active. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ActivateOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tab *tabPtr; if (argv[2][0] == '\0') { tabPtr = NULL; } else if (GetTab(nbPtr, argv[2], &tabPtr, INVALID_OK) != TCL_OK) { return TCL_ERROR; } if ((tabPtr != NULL) && (tabPtr->state == STATE_DISABLED)) { tabPtr = NULL; } if (tabPtr != nbPtr->activePtr) { nbPtr->activePtr = tabPtr; EventuallyRedraw(nbPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * BindOp -- * * .t bind index sequence command * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int BindOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { if (argc == 2) { Blt_HashEntry *hPtr; Blt_HashSearch cursor; char *tagName; for (hPtr = Blt_FirstHashEntry(&(nbPtr->tagTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tagName = Blt_GetHashKey(&(nbPtr->tagTable), hPtr); Tcl_AppendElement(interp, tagName); } return TCL_OK; } return Blt_ConfigureBindings(interp, nbPtr->bindTable, MakeTag(nbPtr, argv[2]), argc - 3, argv + 3); } /* *---------------------------------------------------------------------- * * CgetOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int CgetOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { lastNotebookInstance = nbPtr; return Tk_ConfigureValue(interp, nbPtr->tkwin, configSpecs, (char *)nbPtr, argv[2], 0); } /* *---------------------------------------------------------------------- * * ConfigureOp -- * * This procedure is called to process an argv/argc list, plus * the Tk option database, in order to configure (or reconfigure) * the widget. * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side Effects: * Configuration information, such as text string, colors, font, * etc. get set for nbPtr; old resources get freed, if there * were any. The widget is redisplayed. * *---------------------------------------------------------------------- */ static int ConfigureOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; int argc; char **argv; { lastNotebookInstance = nbPtr; if (argc == 2) { return Tk_ConfigureInfo(interp, nbPtr->tkwin, configSpecs, (char *)nbPtr, (char *)NULL, 0); } else if (argc == 3) { return Tk_ConfigureInfo(interp, nbPtr->tkwin, configSpecs, (char *)nbPtr, argv[2], 0); } if (ConfigureNotebook(interp, nbPtr, argc - 2, argv + 2, TK_CONFIG_ARGV_ONLY) != TCL_OK) { return TCL_ERROR; } EventuallyRedraw(nbPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * DeleteOp -- * * Deletes tab from the set. Deletes either a range of * tabs or a single node. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int DeleteOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tab *firstPtr, *lastPtr; lastPtr = NULL; if (GetTab(nbPtr, argv[2], &firstPtr, INVALID_FAIL) != TCL_OK) { return TCL_ERROR; } if ((argc == 4) && (GetTab(nbPtr, argv[3], &lastPtr, INVALID_FAIL) != TCL_OK)) { return TCL_ERROR; } if (lastPtr == NULL) { DestroyTab(nbPtr, firstPtr); } else { Tab *tabPtr; Blt_ChainLink *linkPtr, *nextLinkPtr; tabPtr = NULL; /* Suppress compiler warning. */ /* Make sure that the first tab is before the last. */ for (linkPtr = firstPtr->linkPtr; linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); if (tabPtr == lastPtr) { break; } } if (tabPtr != lastPtr) { return TCL_OK; } linkPtr = firstPtr->linkPtr; while (linkPtr != NULL) { nextLinkPtr = Blt_ChainNextLink(linkPtr); tabPtr = Blt_ChainGetValue(linkPtr); DestroyTab(nbPtr, tabPtr); linkPtr = nextLinkPtr; if (tabPtr == lastPtr) { break; } } } nbPtr->flags |= (TNB_LAYOUT | TNB_SCROLL); EventuallyRedraw(nbPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * FocusOp -- * * Selects the tab to get focus. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int FocusOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tab *tabPtr; if (GetTab(nbPtr, argv[2], &tabPtr, INVALID_FAIL) != TCL_OK) { return TCL_ERROR; } if (tabPtr != NULL) { nbPtr->focusPtr = tabPtr; Blt_SetFocusItem(nbPtr->bindTable, nbPtr->focusPtr, NULL); EventuallyRedraw(nbPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * IndexOp -- * * Converts a string representing a tab index. * * Results: * A standard Tcl result. Interp->result will contain the * identifier of each index found. If an index could not be found, * then the serial identifier will be the empty string. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int IndexOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; int argc; char **argv; { Tab *tabPtr; if (GetTab(nbPtr, argv[2], &tabPtr, INVALID_OK) != TCL_OK) { return TCL_ERROR; } if (tabPtr != NULL) { Tcl_SetResult(interp, Blt_Itoa(TabIndex(nbPtr, tabPtr)), TCL_VOLATILE); } return TCL_OK; } /* *---------------------------------------------------------------------- * * IdOp -- * * Converts a tab index into the tab identifier. * * Results: * A standard Tcl result. Interp->result will contain the * identifier of each index found. If an index could not be found, * then the serial identifier will be the empty string. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int IdOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tab *tabPtr; if (GetTab(nbPtr, argv[2], &tabPtr, INVALID_OK) != TCL_OK) { return TCL_ERROR; } if (tabPtr == NULL) { Tcl_SetResult(interp, "", TCL_STATIC); } else { Tcl_SetResult(interp, tabPtr->name, TCL_VOLATILE); } return TCL_OK; } /* *---------------------------------------------------------------------- * * InsertOp -- * * Add new entries into a tab set. * * .t insert end label option-value label option-value... * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int InsertOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tab *tabPtr; Blt_ChainLink *linkPtr, *beforeLinkPtr; char c; c = argv[2][0]; if ((c == 'e') && (strcmp(argv[2], "end") == 0)) { beforeLinkPtr = NULL; } else if (isdigit(UCHAR(c))) { int position; if (Tcl_GetInt(interp, argv[2], &position) != TCL_OK) { return TCL_ERROR; } if (position < 0) { beforeLinkPtr = Blt_ChainFirstLink(nbPtr->chainPtr); } else if (position > Blt_ChainGetLength(nbPtr->chainPtr)) { beforeLinkPtr = NULL; } else { beforeLinkPtr = Blt_ChainGetNthLink(nbPtr->chainPtr, position); } } else { Tab *beforePtr; if (GetTab(nbPtr, argv[2], &beforePtr, INVALID_FAIL) != TCL_OK) { return TCL_ERROR; } beforeLinkPtr = beforePtr->linkPtr; } nbPtr->flags |= (TNB_LAYOUT | TNB_SCROLL); EventuallyRedraw(nbPtr); tabPtr = CreateTab(nbPtr); if (tabPtr == NULL) { return TCL_ERROR; } lastNotebookInstance = nbPtr; if (Blt_ConfigureWidgetComponent(interp, nbPtr->tkwin, tabPtr->name, "Tab", tabConfigSpecs, argc - 3, argv + 3, (char *)tabPtr, 0) != TCL_OK) { DestroyTab(nbPtr, tabPtr); return TCL_ERROR; } if (ConfigureTab(nbPtr, tabPtr) != TCL_OK) { DestroyTab(nbPtr, tabPtr); return TCL_ERROR; } linkPtr = Blt_ChainNewLink(); if (beforeLinkPtr == NULL) { Blt_ChainAppendLink(nbPtr->chainPtr, linkPtr); } else { Blt_ChainLinkBefore(nbPtr->chainPtr, linkPtr, beforeLinkPtr); } tabPtr->linkPtr = linkPtr; Blt_ChainSetValue(linkPtr, tabPtr); Tcl_SetResult(interp, tabPtr->name, TCL_VOLATILE); return TCL_OK; } /* * Preprocess the command string for percent substitution. */ static void PercentSubst(nbPtr, tabPtr, command, resultPtr) Notebook *nbPtr; Tab *tabPtr; char *command; Tcl_DString *resultPtr; { register char *last, *p; /* * Get the full path name of the node, in case we need to * substitute for it. */ Tcl_DStringInit(resultPtr); for (last = p = command; *p != '\0'; p++) { if (*p == '%') { char *string; char buf[3]; if (p > last) { *p = '\0'; Tcl_DStringAppend(resultPtr, last, -1); *p = '%'; } switch (*(p + 1)) { case '%': /* Percent sign */ string = "%"; break; case 'W': /* Widget name */ string = Tk_PathName(nbPtr->tkwin); break; case 'i': /* Tab Index */ string = Blt_Itoa(TabIndex(nbPtr, tabPtr)); break; case 'n': /* Tab name */ string = tabPtr->name; break; default: if (*(p + 1) == '\0') { p--; } buf[0] = *p, buf[1] = *(p + 1), buf[2] = '\0'; string = buf; break; } Tcl_DStringAppend(resultPtr, string, -1); p++; last = p + 1; } } if (p > last) { *p = '\0'; Tcl_DStringAppend(resultPtr, last, -1); } } /* *---------------------------------------------------------------------- * * InvokeOp -- * * This procedure is called to invoke a selection command. * * .h invoke index * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side Effects: * Configuration information, such as text string, colors, font, * etc. get set; old resources get freed, if there were any. * The widget is redisplayed if needed. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int InvokeOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { Tab *tabPtr; char *command; if (GetTab(nbPtr, argv[2], &tabPtr, INVALID_OK) != TCL_OK) { return TCL_ERROR; } if ((tabPtr == NULL) || (tabPtr->state == STATE_DISABLED)) { return TCL_OK; } Tcl_Preserve(tabPtr); command = GETATTR(tabPtr, command); if (command != NULL) { Tcl_DString dString; int result; PercentSubst(nbPtr, tabPtr, command, &dString); result = Tcl_GlobalEval(nbPtr->interp, Tcl_DStringValue(&dString)); Tcl_DStringFree(&dString); if (result != TCL_OK) { return TCL_ERROR; } } Tcl_Release(tabPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * MoveOp -- * * Moves a tab to a new location. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int MoveOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tab *tabPtr, *linkPtr; int before; if (GetTab(nbPtr, argv[2], &tabPtr, INVALID_OK) != TCL_OK) { return TCL_ERROR; } if ((tabPtr == NULL) || (tabPtr->state == STATE_DISABLED)) { return TCL_OK; } if ((argv[3][0] == 'b') && (strcmp(argv[3], "before") == 0)) { before = 1; } else if ((argv[3][0] == 'a') && (strcmp(argv[3], "after") == 0)) { before = 0; } else { Tcl_AppendResult(interp, "bad key word \"", argv[3], "\": should be \"after\" or \"before\"", (char *)NULL); return TCL_ERROR; } if (GetTab(nbPtr, argv[4], &linkPtr, INVALID_FAIL) != TCL_OK) { return TCL_ERROR; } if (tabPtr == linkPtr) { return TCL_OK; } Blt_ChainUnlinkLink(nbPtr->chainPtr, tabPtr->linkPtr); if (before) { Blt_ChainLinkBefore(nbPtr->chainPtr, tabPtr->linkPtr, linkPtr->linkPtr); } else { Blt_ChainLinkAfter(nbPtr->chainPtr, tabPtr->linkPtr, linkPtr->linkPtr); } nbPtr->flags |= (TNB_LAYOUT | TNB_SCROLL); EventuallyRedraw(nbPtr); return TCL_OK; } /*ARGSUSED*/ static int NearestOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { int x, y; /* Screen coordinates of the test point. */ Tab *tabPtr; if ((Tk_GetPixels(interp, nbPtr->tkwin, argv[2], &x) != TCL_OK) || (Tk_GetPixels(interp, nbPtr->tkwin, argv[3], &y) != TCL_OK)) { return TCL_ERROR; } if (nbPtr->nVisible > 0) { tabPtr = (Tab *)PickTab(nbPtr, x, y, NULL); if (tabPtr != NULL) { Tcl_SetResult(interp, tabPtr->name, TCL_VOLATILE); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * SelectOp -- * * This procedure is called to selecta tab. * * .h select index * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side Effects: * Configuration information, such as text string, colors, font, * etc. get set; old resources get freed, if there were any. * The widget is redisplayed if needed. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int SelectOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { Tab *tabPtr; if (GetTab(nbPtr, argv[2], &tabPtr, INVALID_OK) != TCL_OK) { return TCL_ERROR; } if ((tabPtr == NULL) || (tabPtr->state == STATE_DISABLED)) { return TCL_OK; } if ((nbPtr->selectPtr != NULL) && (nbPtr->selectPtr != tabPtr) && (nbPtr->selectPtr->tkwin != NULL)) { if (nbPtr->selectPtr->container == NULL) { if (Tk_IsMapped(nbPtr->selectPtr->tkwin)) { Tk_UnmapWindow(nbPtr->selectPtr->tkwin); } } else { /* Redraw now unselected container. */ EventuallyRedrawTearoff(nbPtr->selectPtr); } } nbPtr->selectPtr = tabPtr; if ((nbPtr->nTiers > 1) && (tabPtr->tier != nbPtr->startPtr->tier)) { RenumberTiers(nbPtr, tabPtr); Blt_PickCurrentItem(nbPtr->bindTable); } nbPtr->flags |= (TNB_SCROLL); if (tabPtr->container != NULL) { EventuallyRedrawTearoff(tabPtr); } EventuallyRedraw(nbPtr); return TCL_OK; } static int ViewOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; int argc; char **argv; { int width; width = VPORTWIDTH(nbPtr); if (argc == 2) { double fract; /* * Note: we are bounding the fractions between 0.0 and 1.0 to * support the "canvas"-style of scrolling. */ fract = (double)nbPtr->scrollOffset / nbPtr->worldWidth; Tcl_AppendElement(interp, Blt_Dtoa(interp, CLAMP(fract, 0.0, 1.0))); fract = (double)(nbPtr->scrollOffset + width) / nbPtr->worldWidth; Tcl_AppendElement(interp, Blt_Dtoa(interp, CLAMP(fract, 0.0, 1.0))); return TCL_OK; } if (Blt_GetScrollInfo(interp, argc - 2, argv + 2, &(nbPtr->scrollOffset), nbPtr->worldWidth, width, nbPtr->scrollUnits, BLT_SCROLL_MODE_CANVAS) != TCL_OK) { return TCL_ERROR; } nbPtr->flags |= TNB_SCROLL; EventuallyRedraw(nbPtr); return TCL_OK; } static void AdoptWindow(clientData) ClientData clientData; { Tab *tabPtr = clientData; int x, y; Notebook *nbPtr = tabPtr->nbPtr; x = nbPtr->inset + nbPtr->inset2 + tabPtr->padLeft; #define TEAR_OFF_TAB_SIZE 5 y = nbPtr->inset + nbPtr->inset2 + nbPtr->yPad + nbPtr->outerPad + TEAR_OFF_TAB_SIZE + tabPtr->padTop; Blt_RelinkWindow(tabPtr->tkwin, tabPtr->container, x, y); Tk_MapWindow(tabPtr->tkwin); } static void DestroyTearoff(dataPtr) DestroyData dataPtr; { Tab *tabPtr = (Tab *)dataPtr; if (tabPtr->container != NULL) { Notebook *nbPtr; Tk_Window tkwin; nbPtr = tabPtr->nbPtr; tkwin = tabPtr->container; if (tabPtr->flags & TAB_REDRAW) { Tcl_CancelIdleCall(DisplayTearoff, tabPtr); } Tk_DeleteEventHandler(tkwin, StructureNotifyMask, TearoffEventProc, tabPtr); if (tabPtr->tkwin != NULL) { XRectangle rect; GetWindowRectangle(tabPtr, nbPtr->tkwin, FALSE, &rect); Blt_RelinkWindow(tabPtr->tkwin, nbPtr->tkwin, rect.x, rect.y); if (tabPtr == nbPtr->selectPtr) { ArrangeWindow(tabPtr->tkwin, &rect, TRUE); } else { Tk_UnmapWindow(tabPtr->tkwin); } } Tk_DestroyWindow(tkwin); tabPtr->container = NULL; } } static int CreateTearoff(nbPtr, name, tabPtr) Notebook *nbPtr; char *name; Tab *tabPtr; { Tk_Window tkwin; int width, height; tkwin = Tk_CreateWindowFromPath(nbPtr->interp, nbPtr->tkwin, name, (char *)NULL); if (tkwin == NULL) { return TCL_ERROR; } tabPtr->container = tkwin; if (Tk_WindowId(tkwin) == None) { Tk_MakeWindowExist(tkwin); } Tk_SetClass(tkwin, "Tearoff"); Tk_CreateEventHandler(tkwin, (ExposureMask | StructureNotifyMask), TearoffEventProc, tabPtr); if (Tk_WindowId(tabPtr->tkwin) == None) { Tk_MakeWindowExist(tabPtr->tkwin); } width = Tk_Width(tabPtr->tkwin); if (width < 2) { width = (tabPtr->reqWidth > 0) ? tabPtr->reqWidth : Tk_ReqWidth(tabPtr->tkwin); } width += PADDING(tabPtr->padX) + 2 * Tk_Changes(tabPtr->tkwin)->border_width; width += 2 * (nbPtr->inset2 + nbPtr->inset); #define TEAR_OFF_TAB_SIZE 5 height = Tk_Height(tabPtr->tkwin); if (height < 2) { height = (tabPtr->reqHeight > 0) ? tabPtr->reqHeight : Tk_ReqHeight(tabPtr->tkwin); } height += PADDING(tabPtr->padY) + 2 * Tk_Changes(tabPtr->tkwin)->border_width; height += nbPtr->inset + nbPtr->inset2 + nbPtr->yPad + TEAR_OFF_TAB_SIZE + nbPtr->outerPad; Tk_GeometryRequest(tkwin, width, height); Tk_UnmapWindow(tabPtr->tkwin); /* Tk_MoveWindow(tabPtr->tkwin, 0, 0); */ Tcl_SetResult(nbPtr->interp, Tk_PathName(tkwin), TCL_VOLATILE); #ifdef WIN32 AdoptWindow(tabPtr); #else Tcl_DoWhenIdle(AdoptWindow, tabPtr); #endif return TCL_OK; } /* *---------------------------------------------------------------------- * * TabCgetOp -- * * .h tab cget index option * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TabCgetOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tab *tabPtr; if (GetTab(nbPtr, argv[3], &tabPtr, INVALID_FAIL) != TCL_OK) { return TCL_ERROR; } lastNotebookInstance = nbPtr; return Tk_ConfigureValue(interp, nbPtr->tkwin, tabConfigSpecs, (char *)tabPtr, argv[4], 0); } /* *---------------------------------------------------------------------- * * TabConfigureOp -- * * This procedure is called to process a list of configuration * options database, in order to reconfigure the options for * one or more tabs in the widget. * * .h tab configure index ?index...? ?option value?... * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side Effects: * Configuration information, such as text string, colors, font, * etc. get set; old resources get freed, if there were any. * The widget is redisplayed if needed. * *---------------------------------------------------------------------- */ static int TabConfigureOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; int argc; char **argv; { int nTabs, nOpts, result; char **options; register int i; Tab *tabPtr; /* Figure out where the option value pairs begin */ argc -= 3; argv += 3; for (i = 0; i < argc; i++) { if (argv[i][0] == '-') { break; } if (GetTab(nbPtr, argv[i], &tabPtr, INVALID_FAIL) != TCL_OK) { return TCL_ERROR; /* Can't find node. */ } } nTabs = i; /* Number of tab indices specified */ nOpts = argc - i; /* Number of options specified */ options = argv + i; /* Start of options in argv */ for (i = 0; i < nTabs; i++) { GetTab(nbPtr, argv[i], &tabPtr, INVALID_FAIL); if (argc == 1) { return Tk_ConfigureInfo(interp, nbPtr->tkwin, tabConfigSpecs, (char *)tabPtr, (char *)NULL, 0); } else if (argc == 2) { return Tk_ConfigureInfo(interp, nbPtr->tkwin, tabConfigSpecs, (char *)tabPtr, argv[2], 0); } Tcl_Preserve(tabPtr); lastNotebookInstance = nbPtr; result = Tk_ConfigureWidget(interp, nbPtr->tkwin, tabConfigSpecs, nOpts, options, (char *)tabPtr, TK_CONFIG_ARGV_ONLY); if (result == TCL_OK) { result = ConfigureTab(nbPtr, tabPtr); } Tcl_Release(tabPtr); if (result == TCL_ERROR) { return TCL_ERROR; } if (tabPtr->flags & TAB_VISIBLE) { nbPtr->flags |= (TNB_LAYOUT | TNB_SCROLL); EventuallyRedraw(nbPtr); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * TabDockallOp -- * * .h tab dockall * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TabDockallOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; /* Not used. */ { Tab *tabPtr; Blt_ChainLink *linkPtr; for (linkPtr = Blt_ChainFirstLink(nbPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); if (tabPtr->container != NULL) { Tcl_EventuallyFree(tabPtr, DestroyTearoff); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * TabNamesOp -- * * .h tab names pattern * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TabNamesOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; /* Not used. */ { Tab *tabPtr; Blt_ChainLink *linkPtr; if (argc == 3) { for (linkPtr = Blt_ChainFirstLink(nbPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); Tcl_AppendElement(interp, tabPtr->name); } } else { register int i; for (linkPtr = Blt_ChainFirstLink(nbPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); for (i = 3; i < argc; i++) { if (Tcl_StringMatch(tabPtr->name, argv[i])) { Tcl_AppendElement(interp, tabPtr->name); break; } } } } return TCL_OK; } /* *---------------------------------------------------------------------- * * TabTearoffOp -- * * .h tab tearoff index ?title? * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TabTearoffOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tab *tabPtr; int result; Tk_Window tkwin; if (GetTab(nbPtr, argv[3], &tabPtr, INVALID_OK) != TCL_OK) { return TCL_ERROR; } if ((tabPtr == NULL) || (tabPtr->tkwin == NULL) || (tabPtr->state == STATE_DISABLED)) { return TCL_OK; /* No-op */ } if (argc == 4) { Tk_Window parent; parent = (tabPtr->container == NULL) ? nbPtr->tkwin : tabPtr->container; Tcl_SetResult(nbPtr->interp, Tk_PathName(parent), TCL_VOLATILE); return TCL_OK; } Tcl_Preserve(tabPtr); result = TCL_OK; tkwin = Tk_NameToWindow(interp, argv[4], nbPtr->tkwin); Tcl_ResetResult(interp); if (tabPtr->container != NULL) { Tcl_EventuallyFree(tabPtr, DestroyTearoff); } if ((tkwin != nbPtr->tkwin) && (tabPtr->container == NULL)) { result = CreateTearoff(nbPtr, argv[4], tabPtr); } Tcl_Release(tabPtr); EventuallyRedraw(nbPtr); return result; } /* *---------------------------------------------------------------------- * * TabOp -- * * This procedure handles tab operations. * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ static Blt_OpSpec tabOps[] = { {"cget", 2, (Blt_Op)TabCgetOp, 5, 5, "nameOrIndex option",}, {"configure", 2, (Blt_Op)TabConfigureOp, 4, 0, "nameOrIndex ?option value?...",}, {"dockall", 1, (Blt_Op)TabDockallOp, 3, 3, "" }, {"names", 1, (Blt_Op)TabNamesOp, 3, 0, "?pattern...?",}, {"tearoff", 1, (Blt_Op)TabTearoffOp, 4, 5, "index ?parent?",}, }; static int nTabOps = sizeof(tabOps) / sizeof(Blt_OpSpec); static int TabOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; int argc; char **argv; { Blt_Op proc; int result; proc = Blt_GetOp(interp, nTabOps, tabOps, BLT_OP_ARG2, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (nbPtr, interp, argc, argv); return result; } /* *---------------------------------------------------------------------- * * PerforationActivateOp -- * * This procedure is called to highlight the perforation. * * .h perforation highlight boolean * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int PerforationActivateOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { int bool; if (Tcl_GetBoolean(interp, argv[3], &bool) != TCL_OK) { return TCL_ERROR; } if (bool) { nbPtr->flags |= PERFORATION_ACTIVE; } else { nbPtr->flags &= ~PERFORATION_ACTIVE; } EventuallyRedraw(nbPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * PerforationInvokeOp -- * * This procedure is called to invoke a perforation command. * * .t perforation invoke * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int PerforationInvokeOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { if (nbPtr->selectPtr != NULL) { char *cmd; cmd = GETATTR(nbPtr->selectPtr, perfCommand); if (cmd != NULL) { Tcl_DString dString; int result; PercentSubst(nbPtr, nbPtr->selectPtr, cmd, &dString); Tcl_Preserve(nbPtr); result = Tcl_GlobalEval(interp, Tcl_DStringValue(&dString)); Tcl_Release(nbPtr); Tcl_DStringFree(&dString); if (result != TCL_OK) { return TCL_ERROR; } } } return TCL_OK; } /* *---------------------------------------------------------------------- * * PerforationOp -- * * This procedure handles tab operations. * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ static Blt_OpSpec perforationOps[] = { {"activate", 1, (Blt_Op)PerforationActivateOp, 4, 4, "boolean" }, {"invoke", 1, (Blt_Op)PerforationInvokeOp, 3, 3, "",}, }; static int nPerforationOps = sizeof(perforationOps) / sizeof(Blt_OpSpec); static int PerforationOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; int argc; char **argv; { Blt_Op proc; int result; proc = Blt_GetOp(interp, nPerforationOps, perforationOps, BLT_OP_ARG2, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (nbPtr, interp, argc, argv); return result; } /* *---------------------------------------------------------------------- * * ScanOp -- * * Implements the quick scan. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ScanOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { int x, y; char c; unsigned int length; int oper; #define SCAN_MARK 1 #define SCAN_DRAGTO 2 c = argv[2][0]; length = strlen(argv[2]); if ((c == 'm') && (strncmp(argv[2], "mark", length) == 0)) { oper = SCAN_MARK; } else if ((c == 'd') && (strncmp(argv[2], "dragto", length) == 0)) { oper = SCAN_DRAGTO; } else { Tcl_AppendResult(interp, "bad scan operation \"", argv[2], "\": should be either \"mark\" or \"dragto\"", (char *)NULL); return TCL_ERROR; } if ((Tk_GetPixels(interp, nbPtr->tkwin, argv[3], &x) != TCL_OK) || (Tk_GetPixels(interp, nbPtr->tkwin, argv[4], &y) != TCL_OK)) { return TCL_ERROR; } if (oper == SCAN_MARK) { if (nbPtr->side & SIDE_VERTICAL) { nbPtr->scanAnchor = y; } else { nbPtr->scanAnchor = x; } nbPtr->scanOffset = nbPtr->scrollOffset; } else { int offset, delta; if (nbPtr->side & SIDE_VERTICAL) { delta = nbPtr->scanAnchor - y; } else { delta = nbPtr->scanAnchor - x; } offset = nbPtr->scanOffset + (10 * delta); offset = Blt_AdjustViewport(offset, nbPtr->worldWidth, VPORTWIDTH(nbPtr), nbPtr->scrollUnits, BLT_SCROLL_MODE_CANVAS); nbPtr->scrollOffset = offset; nbPtr->flags |= TNB_SCROLL; EventuallyRedraw(nbPtr); } return TCL_OK; } /*ARGSUSED*/ static int SeeOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { Tab *tabPtr; if (GetTab(nbPtr, argv[2], &tabPtr, INVALID_OK) != TCL_OK) { return TCL_ERROR; } if (tabPtr != NULL) { int left, right, width; width = VPORTWIDTH(nbPtr); left = nbPtr->scrollOffset + nbPtr->xSelectPad; right = nbPtr->scrollOffset + width - nbPtr->xSelectPad; /* If the tab is partially obscured, scroll so that it's * entirely in view. */ if (tabPtr->worldX < left) { nbPtr->scrollOffset = tabPtr->worldX; if (TabIndex(nbPtr, tabPtr) > 0) { nbPtr->scrollOffset -= TAB_SCROLL_OFFSET; } } else if ((tabPtr->worldX + tabPtr->worldWidth) >= right) { Blt_ChainLink *linkPtr; nbPtr->scrollOffset = tabPtr->worldX + tabPtr->worldWidth - (width - 2 * nbPtr->xSelectPad); linkPtr = Blt_ChainNextLink(tabPtr->linkPtr); if (linkPtr != NULL) { Tab *nextPtr; nextPtr = Blt_ChainGetValue(linkPtr); if (nextPtr->tier == tabPtr->tier) { nbPtr->scrollOffset += TAB_SCROLL_OFFSET; } } } nbPtr->flags |= TNB_SCROLL; EventuallyRedraw(nbPtr); } return TCL_OK; } /*ARGSUSED*/ static int SizeOp(nbPtr, interp, argc, argv) Notebook *nbPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; /* Not used. */ { Tcl_SetResult(interp, Blt_Itoa(Blt_ChainGetLength(nbPtr->chainPtr)), TCL_VOLATILE); return TCL_OK; } static int CountTabs(nbPtr) Notebook *nbPtr; { int count; int width, height; Blt_ChainLink *linkPtr; register Tab *tabPtr; register int pageWidth, pageHeight; int labelWidth, labelHeight; int tabWidth, tabHeight; pageWidth = pageHeight = 0; count = 0; labelWidth = labelHeight = 0; /* * Pass 1: Figure out the maximum area needed for a label and a * page. Both the label and page dimensions are adjusted * for orientation. In addition, reset the visibility * flags and reorder the tabs. */ for (linkPtr = Blt_ChainFirstLink(nbPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); /* Reset visibility flag and order of tabs. */ tabPtr->flags &= ~TAB_VISIBLE; count++; if (tabPtr->tkwin != NULL) { width = GetReqWidth(tabPtr); if (pageWidth < width) { pageWidth = width; } height = GetReqHeight(tabPtr); if (pageHeight < height) { pageHeight = height; } } if (labelWidth < tabPtr->labelWidth) { labelWidth = tabPtr->labelWidth; } if (labelHeight < tabPtr->labelHeight) { labelHeight = tabPtr->labelHeight; } } nbPtr->overlap = 0; /* * Pass 2: Set the individual sizes of each tab. This is different * for constant and variable width tabs. Add the extra space * needed for slanted tabs, now that we know maximum tab * height. */ if (nbPtr->defTabStyle.constWidth) { int slant; tabWidth = 2 * nbPtr->inset2; tabHeight = nbPtr->inset2 /* + 4 */; if (nbPtr->side & SIDE_VERTICAL) { tabWidth += labelHeight; tabHeight += labelWidth; slant = labelWidth; } else { tabWidth += labelWidth; tabHeight += labelHeight; slant = labelHeight; } if (nbPtr->slant & SLANT_LEFT) { tabWidth += slant; nbPtr->overlap += tabHeight / 2; } if (nbPtr->slant & SLANT_RIGHT) { tabWidth += slant; nbPtr->overlap += tabHeight / 2; } for (linkPtr = Blt_ChainFirstLink(nbPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); tabPtr->worldWidth = tabWidth; tabPtr->worldHeight = tabHeight; } } else { int slant; tabWidth = tabHeight = 0; for (linkPtr = Blt_ChainFirstLink(nbPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); width = 2 * nbPtr->inset2; height = nbPtr->inset2 /* + 4 */; if (nbPtr->side & SIDE_VERTICAL) { width += tabPtr->labelHeight; height += labelWidth; slant = labelWidth; } else { width += tabPtr->labelWidth; height += labelHeight; slant = labelHeight; } width += (nbPtr->slant & SLANT_LEFT) ? slant : nbPtr->corner; width += (nbPtr->slant & SLANT_RIGHT) ? slant : nbPtr->corner; tabPtr->worldWidth = width; /* + 2 * (nbPtr->corner + nbPtr->xSelectPad) */ ; tabPtr->worldHeight = height; if (tabWidth < width) { tabWidth = width; } if (tabHeight < height) { tabHeight = height; } } if (nbPtr->slant & SLANT_LEFT) { nbPtr->overlap += tabHeight / 2; } if (nbPtr->slant & SLANT_RIGHT) { nbPtr->overlap += tabHeight / 2; } } nbPtr->tabWidth = tabWidth; nbPtr->tabHeight = tabHeight; /* * Let the user override any page dimension. */ nbPtr->pageWidth = pageWidth; nbPtr->pageHeight = pageHeight; if (nbPtr->reqPageWidth > 0) { nbPtr->pageWidth = nbPtr->reqPageWidth; } if (nbPtr->reqPageHeight > 0) { nbPtr->pageHeight = nbPtr->reqPageHeight; } return count; } static void WidenTabs(nbPtr, startPtr, nTabs, adjustment) Notebook *nbPtr; Tab *startPtr; int nTabs; int adjustment; { register Tab *tabPtr; register int i; int ration; Blt_ChainLink *linkPtr; int x; x = startPtr->tier; while (adjustment > 0) { ration = adjustment / nTabs; if (ration == 0) { ration = 1; } linkPtr = startPtr->linkPtr; for (i = 0; (linkPtr != NULL) && (i < nTabs) && (adjustment > 0); i++) { tabPtr = Blt_ChainGetValue(linkPtr); adjustment -= ration; tabPtr->worldWidth += ration; assert(x == tabPtr->tier); linkPtr = Blt_ChainNextLink(linkPtr); } } /* * Go back and reset the world X-coordinates of the tabs, * now that their widths have changed. */ x = 0; linkPtr = startPtr->linkPtr; for (i = 0; (i < nTabs) && (linkPtr != NULL); i++) { tabPtr = Blt_ChainGetValue(linkPtr); tabPtr->worldX = x; x += tabPtr->worldWidth + nbPtr->gap - nbPtr->overlap; linkPtr = Blt_ChainNextLink(linkPtr); } } static void AdjustTabSizes(nbPtr, nTabs) Notebook *nbPtr; int nTabs; { int tabsPerTier; int total, count, extra; Tab *startPtr, *nextPtr; Blt_ChainLink *linkPtr; register Tab *tabPtr; int x, maxWidth; tabsPerTier = (nTabs + (nbPtr->nTiers - 1)) / nbPtr->nTiers; x = 0; maxWidth = 0; if (nbPtr->defTabStyle.constWidth) { register int i; linkPtr = Blt_ChainFirstLink(nbPtr->chainPtr); count = 1; while (linkPtr != NULL) { for (i = 0; i < tabsPerTier; i++) { tabPtr = Blt_ChainGetValue(linkPtr); tabPtr->tier = count; tabPtr->worldX = x; x += tabPtr->worldWidth + nbPtr->gap - nbPtr->overlap; linkPtr = Blt_ChainNextLink(linkPtr); if (x > maxWidth) { maxWidth = x; } if (linkPtr == NULL) { goto done; } } count++; x = 0; } } done: /* Add to tab widths to fill out row. */ if (((nTabs % tabsPerTier) != 0) && (nbPtr->defTabStyle.constWidth)) { return; } startPtr = NULL; count = total = 0; for (linkPtr = Blt_ChainFirstLink(nbPtr->chainPtr); linkPtr != NULL; /*empty*/ ) { tabPtr = Blt_ChainGetValue(linkPtr); if (startPtr == NULL) { startPtr = tabPtr; } count++; total += tabPtr->worldWidth + nbPtr->gap - nbPtr->overlap; linkPtr = Blt_ChainNextLink(linkPtr); if (linkPtr != NULL) { nextPtr = Blt_ChainGetValue(linkPtr); if (tabPtr->tier == nextPtr->tier) { continue; } } total += nbPtr->overlap; extra = nbPtr->worldWidth - total; assert(count > 0); if (extra > 0) { WidenTabs(nbPtr, startPtr, count, extra); } count = total = 0; startPtr = NULL; } } /* * * tabWidth = textWidth + gap + (2 * (pad + outerBW)); * * tabHeight = textHeight + 2 * (pad + outerBW) + topMargin; * */ static void ComputeLayout(nbPtr) Notebook *nbPtr; { int width; Blt_ChainLink *linkPtr; Tab *tabPtr; int x, extra; int nTiers, nTabs; nbPtr->nTiers = 0; nbPtr->pageTop = 0; nbPtr->worldWidth = 1; nbPtr->yPad = 0; nTabs = CountTabs(nbPtr); if (nTabs == 0) { return; } /* Reset the pointers to the selected and starting tab. */ if (nbPtr->selectPtr == NULL) { linkPtr = Blt_ChainFirstLink(nbPtr->chainPtr); if (linkPtr != NULL) { nbPtr->selectPtr = Blt_ChainGetValue(linkPtr); } } if (nbPtr->startPtr == NULL) { nbPtr->startPtr = nbPtr->selectPtr; } if (nbPtr->focusPtr == NULL) { nbPtr->focusPtr = nbPtr->selectPtr; Blt_SetFocusItem(nbPtr->bindTable, nbPtr->focusPtr, NULL); } if (nbPtr->side & SIDE_VERTICAL) { width = Tk_Height(nbPtr->tkwin) - 2 * (nbPtr->corner + nbPtr->xSelectPad); } else { width = Tk_Width(nbPtr->tkwin) - (2 * nbPtr->inset) - nbPtr->xSelectPad - nbPtr->corner; } nbPtr->flags |= TNB_STATIC; if (nbPtr->reqTiers > 1) { int total, maxWidth; /* Static multiple tier mode. */ /* Sum tab widths and determine the number of tiers needed. */ nTiers = 1; total = x = 0; for (linkPtr = Blt_ChainFirstLink(nbPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); if ((x + tabPtr->worldWidth) > width) { nTiers++; x = 0; } tabPtr->worldX = x; tabPtr->tier = nTiers; extra = tabPtr->worldWidth + nbPtr->gap - nbPtr->overlap; total += extra, x += extra; } maxWidth = width; if (nTiers > nbPtr->reqTiers) { /* * The tabs do not fit into the requested number of tiers. * Go into scrolling mode. */ width = ((total + nbPtr->tabWidth) / nbPtr->reqTiers); x = 0; nTiers = 1; for (linkPtr = Blt_ChainFirstLink(nbPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); tabPtr->tier = nTiers; /* * Keep adding tabs to a tier until we overfill it. */ tabPtr->worldX = x; x += tabPtr->worldWidth + nbPtr->gap - nbPtr->overlap; if (x > width) { nTiers++; if (x > maxWidth) { maxWidth = x; } x = 0; } } nbPtr->flags &= ~TNB_STATIC; } nbPtr->worldWidth = maxWidth; nbPtr->nTiers = nTiers; if (nTiers > 1) { AdjustTabSizes(nbPtr, nTabs); } if (nbPtr->flags & TNB_STATIC) { nbPtr->worldWidth = VPORTWIDTH(nbPtr); } else { /* Do you add an offset ? */ nbPtr->worldWidth += (nbPtr->xSelectPad + nbPtr->corner); } nbPtr->worldWidth += nbPtr->overlap; if (nbPtr->selectPtr != NULL) { RenumberTiers(nbPtr, nbPtr->selectPtr); } } else { /* * Scrollable single tier mode. */ nTiers = 1; x = 0; for (linkPtr = Blt_ChainFirstLink(nbPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); tabPtr->tier = nTiers; tabPtr->worldX = x; tabPtr->worldY = 0; x += tabPtr->worldWidth + nbPtr->gap - nbPtr->overlap; } nbPtr->worldWidth = x + nbPtr->corner - nbPtr->gap + nbPtr->xSelectPad + nbPtr->overlap; nbPtr->flags &= ~TNB_STATIC; } if (nTiers == 1) { nbPtr->yPad = nbPtr->ySelectPad; } nbPtr->nTiers = nTiers; nbPtr->pageTop = nbPtr->inset + nbPtr->yPad /* + 4 */ + (nbPtr->nTiers * nbPtr->tabHeight) + nbPtr->inset2; if (nbPtr->side & SIDE_VERTICAL) { for (linkPtr = Blt_ChainFirstLink(nbPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); tabPtr->screenWidth = (short int)nbPtr->tabHeight; tabPtr->screenHeight = (short int)tabPtr->worldWidth; } } else { for (linkPtr = Blt_ChainFirstLink(nbPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); tabPtr->screenWidth = (short int)tabPtr->worldWidth; tabPtr->screenHeight = (short int)nbPtr->tabHeight; } } } static void ComputeVisibleTabs(nbPtr) Notebook *nbPtr; { int nVisibleTabs; register Tab *tabPtr; Blt_ChainLink *linkPtr; nbPtr->nVisible = 0; if (Blt_ChainGetLength(nbPtr->chainPtr) == 0) { return; } nVisibleTabs = 0; if (nbPtr->flags & TNB_STATIC) { /* Static multiple tier mode. */ for (linkPtr = Blt_ChainFirstLink(nbPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); tabPtr->flags |= TAB_VISIBLE; nVisibleTabs++; } } else { int width, offset; /* * Scrollable (single or multiple) tier mode. */ offset = nbPtr->scrollOffset - (nbPtr->outerPad + nbPtr->xSelectPad); width = VPORTWIDTH(nbPtr) + nbPtr->scrollOffset + 2 * nbPtr->outerPad; for (linkPtr = Blt_ChainFirstLink(nbPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); if ((tabPtr->worldX >= width) || ((tabPtr->worldX + tabPtr->worldWidth) < offset)) { tabPtr->flags &= ~TAB_VISIBLE; } else { tabPtr->flags |= TAB_VISIBLE; nVisibleTabs++; } } } for (linkPtr = Blt_ChainFirstLink(nbPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); tabPtr->screenX = tabPtr->screenY = -1000; if (tabPtr->flags & TAB_VISIBLE) { WorldToScreen(nbPtr, tabPtr->worldX, tabPtr->worldY, &(tabPtr->screenX), &(tabPtr->screenY)); switch (nbPtr->side) { case SIDE_RIGHT: tabPtr->screenX -= nbPtr->tabHeight; break; case SIDE_BOTTOM: tabPtr->screenY -= nbPtr->tabHeight; break; } } } nbPtr->nVisible = nVisibleTabs; Blt_PickCurrentItem(nbPtr->bindTable); } static void Draw3DFolder(nbPtr, tabPtr, drawable, side, pointArr, nPoints) Notebook *nbPtr; Tab *tabPtr; Drawable drawable; int side; XPoint pointArr[]; int nPoints; { GC gc; int relief, borderWidth; Tk_3DBorder border; if (tabPtr == nbPtr->selectPtr) { border = GETATTR(tabPtr, selBorder); } else if (tabPtr->border != NULL) { border = tabPtr->border; } else { border = nbPtr->defTabStyle.border; } relief = nbPtr->defTabStyle.relief; if ((side == SIDE_RIGHT) || (side == SIDE_TOP)) { borderWidth = -nbPtr->defTabStyle.borderWidth; if (relief == TK_RELIEF_SUNKEN) { relief = TK_RELIEF_RAISED; } else if (relief == TK_RELIEF_RAISED) { relief = TK_RELIEF_SUNKEN; } } else { borderWidth = nbPtr->defTabStyle.borderWidth; } { int i; #ifndef notdef int dx, dy; int oldType, newType; int start; dx = pointArr[0].x - pointArr[1].x; dy = pointArr[0].y - pointArr[1].y; oldType = ((dy < 0) || (dx > 0)); start = 0; for (i = 1; i < nPoints; i++) { dx = pointArr[i - 1].x - pointArr[i].x; dy = pointArr[i - 1].y - pointArr[i].y; newType = ((dy < 0) || (dx > 0)); if (newType != oldType) { if (oldType) { gc = Tk_GCForColor(nbPtr->shadowColor, drawable); } else { gc = Tk_3DBorderGC(nbPtr->tkwin, border, TK_3D_FLAT_GC); } XDrawLines(nbPtr->display, drawable, gc, pointArr + start, i - start, CoordModeOrigin); start = i - 1; oldType = newType; } } if (start != i) { if (oldType) { gc = Tk_GCForColor(nbPtr->shadowColor, drawable); } else { gc = Tk_3DBorderGC(nbPtr->tkwin, border, TK_3D_FLAT_GC); } XDrawLines(nbPtr->display, drawable, gc, pointArr + start, i - start, CoordModeOrigin); } #else /* Draw the outline of the folder. */ gc = Tk_GCForColor(nbPtr->shadowColor, drawable); XDrawLines(nbPtr->display, drawable, gc, pointArr, nPoints, CoordModeOrigin); #endif } /* And the folder itself. */ if (tabPtr->tile != NULL) { #ifdef notdef Tk_Fill3DPolygon(nbPtr->tkwin, drawable, border, pointArr, nPoints, borderWidth, relief); #endif Blt_TilePolygon(nbPtr->tkwin, drawable, tabPtr->tile, pointArr, nPoints); #ifdef notdef Tk_Draw3DPolygon(nbPtr->tkwin, drawable, border, pointArr, nPoints, borderWidth, relief); #endif } else { Tk_Fill3DPolygon(nbPtr->tkwin, drawable, border, pointArr, nPoints, borderWidth, relief); } } /* * x,y * |1|2|3| 4 |3|2|1| * * 1. tab border width * 2. corner offset * 3. label pad * 4. label width * * */ static void DrawLabel(nbPtr, tabPtr, drawable) Notebook *nbPtr; Tab *tabPtr; Drawable drawable; { int x, y, dx, dy; int tx, ty, ix, iy; int imgWidth, imgHeight; int active, selected; XColor *fgColor, *bgColor; Tk_3DBorder border; GC gc; if (!(tabPtr->flags & TAB_VISIBLE)) { return; } x = tabPtr->screenX; y = tabPtr->screenY; active = (nbPtr->activePtr == tabPtr); selected = (nbPtr->selectPtr == tabPtr); fgColor = GETATTR(tabPtr, textColor); border = GETATTR(tabPtr, border); if (selected) { border = GETATTR(tabPtr, selBorder); } bgColor = Tk_3DBorderColor(border); if (active) { Tk_3DBorder activeBorder; activeBorder = GETATTR(tabPtr, activeBorder); bgColor = Tk_3DBorderColor(activeBorder); } dx = (tabPtr->screenWidth - tabPtr->labelWidth) / 2; dy = (tabPtr->screenHeight - tabPtr->labelHeight) / 2; /* * The label position is computed with screen coordinates. This * is because both text and image components are oriented in * screen space, and not according to the orientation of the tabs * themselves. That's why we have to consider the side when * correcting for left/right slants. */ switch (nbPtr->side) { case SIDE_TOP: case SIDE_BOTTOM: if (nbPtr->slant == SLANT_LEFT) { x += nbPtr->overlap; } else if (nbPtr->slant == SLANT_RIGHT) { x -= nbPtr->overlap; } break; case SIDE_LEFT: case SIDE_RIGHT: if (nbPtr->slant == SLANT_LEFT) { y += nbPtr->overlap; } else if (nbPtr->slant == SLANT_RIGHT) { y -= nbPtr->overlap; } break; } /* * Draw the active or normal background color over the entire * label area. This includes both the tab's text and image. * The rectangle should be 2 pixels wider/taller than this * area. So if the label consists of just an image, we get an * halo around the image when the tab is active. */ gc = Tk_GCForColor(bgColor, drawable); XFillRectangle(nbPtr->display, drawable, gc, x + dx, y + dy, tabPtr->labelWidth, tabPtr->labelHeight); if ((nbPtr->flags & TNB_FOCUS) && (nbPtr->focusPtr == tabPtr)) { XDrawRectangle(nbPtr->display, drawable, nbPtr->defTabStyle.activeGC, x + dx, y + dy, tabPtr->labelWidth - 1, tabPtr->labelHeight - 1); } tx = ty = ix = iy = 0; /* Suppress compiler warning. */ imgWidth = imgHeight = 0; if (tabPtr->image != NULL) { imgWidth = ImageWidth(tabPtr->image); imgHeight = ImageHeight(tabPtr->image); } switch (nbPtr->defTabStyle.textSide) { case SIDE_LEFT: tx = x + dx + tabPtr->iPadX.side1; ty = y + (tabPtr->screenHeight - tabPtr->textHeight) / 2; ix = tx + tabPtr->textWidth + IMAGE_PAD; iy = y + (tabPtr->screenHeight - imgHeight) / 2; break; case SIDE_RIGHT: ix = x + dx + tabPtr->iPadX.side1 + IMAGE_PAD; iy = y + (tabPtr->screenHeight - imgHeight) / 2; tx = ix + imgWidth; ty = y + (tabPtr->screenHeight - tabPtr->textHeight) / 2; break; case SIDE_BOTTOM: iy = y + dy + tabPtr->iPadY.side1 + IMAGE_PAD; ix = x + (tabPtr->screenWidth - imgWidth) / 2; ty = iy + imgHeight; tx = x + (tabPtr->screenWidth - tabPtr->textWidth) / 2; break; case SIDE_TOP: tx = x + (tabPtr->screenWidth - tabPtr->textWidth) / 2; ty = y + dy + tabPtr->iPadY.side1 + IMAGE_PAD; ix = x + (tabPtr->screenWidth - imgWidth) / 2; iy = ty + tabPtr->textHeight; break; } if (tabPtr->image != NULL) { Tk_RedrawImage(ImageBits(tabPtr->image), 0, 0, imgWidth, imgHeight, drawable, ix, iy); } if (tabPtr->text != NULL) { TextStyle ts; XColor *activeColor; activeColor = fgColor; if (selected) { activeColor = GETATTR(tabPtr, selColor); } else if (active) { activeColor = GETATTR(tabPtr, activeFgColor); } Blt_SetDrawTextStyle(&ts, GETATTR(tabPtr, font), tabPtr->textGC, fgColor, activeColor, tabPtr->shadow.color, nbPtr->defTabStyle.rotate, TK_ANCHOR_NW, TK_JUSTIFY_LEFT, 0, tabPtr->shadow.offset); ts.state = tabPtr->state; ts.border = border; ts.padX.side1 = ts.padX.side2 = 2; if (selected || active) { ts.state |= STATE_ACTIVE; } Blt_DrawText(nbPtr->tkwin, drawable, tabPtr->text, &ts, tx, ty); } } static void DrawPerforation(nbPtr, tabPtr, drawable) Notebook *nbPtr; Tab *tabPtr; Drawable drawable; { XPoint pointArr[2]; int x, y; int segmentWidth, max; Tk_3DBorder border, perfBorder; if ((tabPtr->container != NULL) || (tabPtr->tkwin == NULL)) { return; } WorldToScreen(nbPtr, tabPtr->worldX + 2, tabPtr->worldY + tabPtr->worldHeight + 2, &x, &y); border = GETATTR(tabPtr, selBorder); segmentWidth = 3; if (nbPtr->flags & PERFORATION_ACTIVE) { perfBorder = GETATTR(tabPtr, activeBorder); } else { perfBorder = GETATTR(tabPtr, selBorder); } if (nbPtr->side & SIDE_HORIZONTAL) { pointArr[0].x = x; pointArr[0].y = pointArr[1].y = y; max = tabPtr->screenX + tabPtr->screenWidth - 2; Blt_Fill3DRectangle(nbPtr->tkwin, drawable, perfBorder, x - 2, y - 4, tabPtr->screenWidth, 8, 0, TK_RELIEF_FLAT); while (pointArr[0].x < max) { pointArr[1].x = pointArr[0].x + segmentWidth; if (pointArr[1].x > max) { pointArr[1].x = max; } Tk_Draw3DPolygon(nbPtr->tkwin, drawable, border, pointArr, 2, 1, TK_RELIEF_RAISED); pointArr[0].x += 2 * segmentWidth; } } else { pointArr[0].x = pointArr[1].x = x; pointArr[0].y = y; max = tabPtr->screenY + tabPtr->screenHeight - 2; Blt_Fill3DRectangle(nbPtr->tkwin, drawable, perfBorder, x - 4, y - 2, 8, tabPtr->screenHeight, 0, TK_RELIEF_FLAT); while (pointArr[0].y < max) { pointArr[1].y = pointArr[0].y + segmentWidth; if (pointArr[1].y > max) { pointArr[1].y = max; } Tk_Draw3DPolygon(nbPtr->tkwin, drawable, border, pointArr, 2, 1, TK_RELIEF_RAISED); pointArr[0].y += 2 * segmentWidth; } } } #define NextPoint(px, py) \ pointPtr->x = (px), pointPtr->y = (py), pointPtr++, nPoints++ #define EndPoint(px, py) \ pointPtr->x = (px), pointPtr->y = (py), nPoints++ #define BottomLeft(px, py) \ NextPoint((px) + nbPtr->corner, (py)), \ NextPoint((px), (py) - nbPtr->corner) #define TopLeft(px, py) \ NextPoint((px), (py) + nbPtr->corner), \ NextPoint((px) + nbPtr->corner, (py)) #define TopRight(px, py) \ NextPoint((px) - nbPtr->corner, (py)), \ NextPoint((px), (py) + nbPtr->corner) #define BottomRight(px, py) \ NextPoint((px), (py) - nbPtr->corner), \ NextPoint((px) - nbPtr->corner, (py)) /* * From the left edge: * * |a|b|c|d|e| f |d|e|g|h| i |h|g|e|d|f| j |e|d|c|b|a| * * a. highlight ring * b. notebook 3D border * c. outer gap * d. page border * e. page corner * f. gap + select pad * g. label pad x (worldX) * h. internal pad x * i. label width * j. rest of page width * * worldX, worldY * | * | * * 4+ . . +5 * 3+ +6 * . . * . . * 1+. . .2+ +7 . . . .+8 * 0+ +9 * . . * . . *13+ +10 * 12+-------------------------+11 * */ static void DrawFolder(nbPtr, tabPtr, drawable) Notebook *nbPtr; Tab *tabPtr; Drawable drawable; { XPoint pointArr[16]; XPoint *pointPtr; int width, height; int left, bottom, right, top, yBot, yTop; int x, y; register int i; int nPoints; width = VPORTWIDTH(nbPtr); height = VPORTHEIGHT(nbPtr); x = tabPtr->worldX; y = tabPtr->worldY; nPoints = 0; pointPtr = pointArr; /* Remember these are all world coordinates. */ /* * x Left side of tab. * y Top of tab. * yTop Top of folder. * yBot Bottom of the tab. * left Left side of the folder. * right Right side of the folder. * top Top of folder. * bottom Bottom of folder. */ left = nbPtr->scrollOffset - nbPtr->xSelectPad; right = left + width; yTop = y + tabPtr->worldHeight; yBot = nbPtr->pageTop - (nbPtr->inset + nbPtr->yPad); top = yBot - nbPtr->inset2 /* - 4 */; if (nbPtr->pageHeight == 0) { bottom = yBot + 2 * nbPtr->corner; } else { bottom = height - nbPtr->yPad - 1; } if (tabPtr != nbPtr->selectPtr) { /* * Case 1: Unselected tab * * * 3+ . . +4 * 2+ +5 * . . * 1+ +6 * 0+ . . +7 * */ if (nbPtr->slant & SLANT_LEFT) { NextPoint(x, yBot); NextPoint(x, yTop); NextPoint(x + nbPtr->tabHeight, y); } else { BottomLeft(x, yBot); TopLeft(x, y); } x += tabPtr->worldWidth; if (nbPtr->slant & SLANT_RIGHT) { NextPoint(x - nbPtr->tabHeight, y); NextPoint(x, yTop); NextPoint(x, yBot); } else { TopRight(x, y); BottomRight(x, yBot); } } else if (!(tabPtr->flags & TAB_VISIBLE)) { /* * Case 2: Selected tab not visible in viewport. Draw folder only. * * * 3+ . . +4 * 2+ +5 * . . * 1+ +6 * 0+------+7 * */ TopLeft(left, top); TopRight(right, top); BottomRight(right, bottom); BottomLeft(left, bottom); } else { int flags; int tabWidth; x -= nbPtr->xSelectPad; y -= nbPtr->yPad; tabWidth = tabPtr->worldWidth + 2 * nbPtr->xSelectPad; #define CLIP_NONE 0 #define CLIP_LEFT (1<<0) #define CLIP_RIGHT (1<<1) flags = 0; if (x < left) { flags |= CLIP_LEFT; } if ((x + tabWidth) > right) { flags |= CLIP_RIGHT; } switch (flags) { case CLIP_NONE: /* * worldX, worldY * | * * 4+ . . +5 * 3+ +6 * . . * . . * 1+. . .2+---------+7 . . . .+8 * 0+ +9 * . . * . . *13+ +10 * 12+ . . . . . . . . . . . . +11 */ if (x < (left + nbPtr->corner)) { NextPoint(left, top); } else { TopLeft(left, top); } if (nbPtr->slant & SLANT_LEFT) { NextPoint(x, yTop); NextPoint(x + nbPtr->tabHeight + nbPtr->yPad, y); } else { NextPoint(x, top); TopLeft(x, y); } x += tabWidth; if (nbPtr->slant & SLANT_RIGHT) { NextPoint(x - nbPtr->tabHeight - nbPtr->yPad, y); NextPoint(x, yTop); } else { TopRight(x, y); NextPoint(x, top); } if (x > (right - nbPtr->corner)) { NextPoint(right, top + nbPtr->corner); } else { TopRight(right, top); } BottomRight(right, bottom); BottomLeft(left, bottom); break; case CLIP_LEFT: /* * worldX, worldY * | * * 4+ . . +5 * 3+ +6 * . . * . . * 2+--------+7 . . . .+8 * 1+ . . . +0 +9 * . . * . . * 13+ +10 * 12+ . . . .+11 */ NextPoint(left, yBot); if (nbPtr->slant & SLANT_LEFT) { NextPoint(x, yBot); NextPoint(x, yTop); NextPoint(x + nbPtr->tabHeight + nbPtr->yPad, y); } else { BottomLeft(x, yBot); TopLeft(x, y); } x += tabWidth; if (nbPtr->slant & SLANT_RIGHT) { NextPoint(x - nbPtr->tabHeight - nbPtr->yPad, y); NextPoint(x, yTop); NextPoint(x, top); } else { TopRight(x, y); NextPoint(x, top); } if (x > (right - nbPtr->corner)) { NextPoint(right, top + nbPtr->corner); } else { TopRight(right, top); } BottomRight(right, bottom); BottomLeft(left, bottom); break; case CLIP_RIGHT: /* * worldX, worldY * | * * 9+ . . +10 * 8+ +11 * . . * . . * 6+ . . . .7+---------+12 * 5+ 0+ . . . +13 * . . * . . * 4+ +1 * 3+ . . . +2 */ NextPoint(right, yBot); BottomRight(right, bottom); BottomLeft(left, bottom); if (x < (left + nbPtr->corner)) { NextPoint(left, top); } else { TopLeft(left, top); } NextPoint(x, top); if (nbPtr->slant & SLANT_LEFT) { NextPoint(x, yTop); NextPoint(x + nbPtr->tabHeight + nbPtr->yPad, y); } else { TopLeft(x, y); } x += tabWidth; if (nbPtr->slant & SLANT_RIGHT) { NextPoint(x - nbPtr->tabHeight - nbPtr->yPad, y); NextPoint(x, yTop); NextPoint(x, yBot); } else { TopRight(x, y); BottomRight(x, yBot); } break; case (CLIP_LEFT | CLIP_RIGHT): /* * worldX, worldY * | * * 4+ . . . . . . . . +5 * 3+ +6 * . . * . . * 1+---------------------+7 * 2+ 0+ +9 .+8 * . . * . . * 13+ +10 * 12+ . . . +11 */ NextPoint(left, yBot); if (nbPtr->slant & SLANT_LEFT) { NextPoint(x, yBot); NextPoint(x, yTop); NextPoint(x + nbPtr->tabHeight + nbPtr->yPad, y); } else { BottomLeft(x, yBot); TopLeft(x, y); } x += tabPtr->worldWidth; if (nbPtr->slant & SLANT_RIGHT) { NextPoint(x - nbPtr->tabHeight - nbPtr->yPad, y); NextPoint(x, yTop); NextPoint(x, yBot); } else { TopRight(x, y); BottomRight(x, yBot); } NextPoint(right, yBot); BottomRight(right, bottom); BottomLeft(left, bottom); break; } } EndPoint(pointArr[0].x, pointArr[0].y); for (i = 0; i < nPoints; i++) { WorldToScreen(nbPtr, pointArr[i].x, pointArr[i].y, &x, &y); pointArr[i].x = x; pointArr[i].y = y; } Draw3DFolder(nbPtr, tabPtr, drawable, nbPtr->side, pointArr, nPoints); DrawLabel(nbPtr, tabPtr, drawable); if (tabPtr->container != NULL) { XRectangle rect; /* Draw a rectangle covering the spot representing the window */ GetWindowRectangle(tabPtr, nbPtr->tkwin, FALSE, &rect); XFillRectangles(nbPtr->display, drawable, tabPtr->backGC, &rect, 1); } } static void DrawOuterBorders(nbPtr, drawable) Notebook *nbPtr; Drawable drawable; { /* * Draw 3D border just inside of the focus highlight ring. We * draw the border even if the relief is flat so that any tabs * that hang over the edge will be clipped. */ if (nbPtr->borderWidth > 0) { Blt_Draw3DRectangle(nbPtr->tkwin, drawable, nbPtr->border, nbPtr->highlightWidth, nbPtr->highlightWidth, Tk_Width(nbPtr->tkwin) - 2 * nbPtr->highlightWidth, Tk_Height(nbPtr->tkwin) - 2 * nbPtr->highlightWidth, nbPtr->borderWidth, nbPtr->relief); } /* Draw focus highlight ring. */ if (nbPtr->highlightWidth > 0) { XColor *color; GC gc; color = (nbPtr->flags & TNB_FOCUS) ? nbPtr->highlightColor : nbPtr->highlightBgColor; gc = Tk_GCForColor(color, drawable); Tk_DrawFocusHighlight(nbPtr->tkwin, gc, nbPtr->highlightWidth, drawable); } } /* * ---------------------------------------------------------------------- * * DisplayNotebook -- * * This procedure is invoked to display the widget. * * Recomputes the layout of the widget if necessary. This is * necessary if the world coordinate system has changed. * Sets the vertical and horizontal scrollbars. This is done * here since the window width and height are needed for the * scrollbar calculations. * * Results: * None. * * Side effects: * The widget is redisplayed. * * ---------------------------------------------------------------------- */ static void DisplayNotebook(clientData) ClientData clientData; /* Information about widget. */ { Notebook *nbPtr = clientData; Pixmap drawable; int width, height; nbPtr->flags &= ~TNB_REDRAW; if (nbPtr->tkwin == NULL) { return; /* Window has been destroyed. */ } if (nbPtr->flags & TNB_LAYOUT) { ComputeLayout(nbPtr); nbPtr->flags &= ~TNB_LAYOUT; } if ((nbPtr->reqHeight == 0) || (nbPtr->reqWidth == 0)) { width = height = 0; if (nbPtr->side & SIDE_VERTICAL) { height = nbPtr->worldWidth; } else { width = nbPtr->worldWidth; } if (nbPtr->reqWidth > 0) { width = nbPtr->reqWidth; } else if (nbPtr->pageWidth > 0) { width = nbPtr->pageWidth; } if (nbPtr->reqHeight > 0) { height = nbPtr->reqHeight; } else if (nbPtr->pageHeight > 0) { height = nbPtr->pageHeight; } if (nbPtr->side & SIDE_VERTICAL) { width += nbPtr->pageTop + nbPtr->inset + nbPtr->inset2; height += nbPtr->inset + nbPtr->inset2; } else { height += nbPtr->pageTop + nbPtr->inset + nbPtr->inset2; width += nbPtr->inset + nbPtr->inset2; } if ((Tk_ReqWidth(nbPtr->tkwin) != width) || (Tk_ReqHeight(nbPtr->tkwin) != height)) { Tk_GeometryRequest(nbPtr->tkwin, width, height); } } if (nbPtr->flags & TNB_SCROLL) { width = VPORTWIDTH(nbPtr); nbPtr->scrollOffset = Blt_AdjustViewport(nbPtr->scrollOffset, nbPtr->worldWidth, width, nbPtr->scrollUnits, BLT_SCROLL_MODE_CANVAS); if (nbPtr->scrollCmdPrefix != NULL) { Blt_UpdateScrollbar(nbPtr->interp, nbPtr->scrollCmdPrefix, (double)nbPtr->scrollOffset / nbPtr->worldWidth, (double)(nbPtr->scrollOffset + width) / nbPtr->worldWidth); } ComputeVisibleTabs(nbPtr); nbPtr->flags &= ~TNB_SCROLL; } if (!Tk_IsMapped(nbPtr->tkwin)) { return; } height = Tk_Height(nbPtr->tkwin); drawable = Tk_GetPixmap(nbPtr->display, Tk_WindowId(nbPtr->tkwin), Tk_Width(nbPtr->tkwin), Tk_Height(nbPtr->tkwin), Tk_Depth(nbPtr->tkwin)); /* * Clear the background either by tiling a pixmap or filling with * a solid color. Tiling takes precedence. */ if (nbPtr->tile != NULL) { Blt_SetTileOrigin(nbPtr->tkwin, nbPtr->tile, 0, 0); Blt_TileRectangle(nbPtr->tkwin, drawable, nbPtr->tile, 0, 0, Tk_Width(nbPtr->tkwin), height); } else { Blt_Fill3DRectangle(nbPtr->tkwin, drawable, nbPtr->border, 0, 0, Tk_Width(nbPtr->tkwin), height, 0, TK_RELIEF_FLAT); } if (nbPtr->nVisible > 0) { register int i; register Tab *tabPtr; Blt_ChainLink *linkPtr; linkPtr = nbPtr->startPtr->linkPtr; for (i = 0; i < Blt_ChainGetLength(nbPtr->chainPtr); i++) { linkPtr = Blt_ChainPrevLink(linkPtr); if (linkPtr == NULL) { linkPtr = Blt_ChainLastLink(nbPtr->chainPtr); } tabPtr = Blt_ChainGetValue(linkPtr); if ((tabPtr != nbPtr->selectPtr) && (tabPtr->flags & TAB_VISIBLE)) { DrawFolder(nbPtr, tabPtr, drawable); } } DrawFolder(nbPtr, nbPtr->selectPtr, drawable); if (nbPtr->tearoff) { DrawPerforation(nbPtr, nbPtr->selectPtr, drawable); } if ((nbPtr->selectPtr->tkwin != NULL) && (nbPtr->selectPtr->container == NULL)) { XRectangle rect; GetWindowRectangle(nbPtr->selectPtr, nbPtr->tkwin, FALSE, &rect); ArrangeWindow(nbPtr->selectPtr->tkwin, &rect, 0); } } DrawOuterBorders(nbPtr, drawable); XCopyArea(nbPtr->display, drawable, Tk_WindowId(nbPtr->tkwin), nbPtr->highlightGC, 0, 0, Tk_Width(nbPtr->tkwin), height, 0, 0); Tk_FreePixmap(nbPtr->display, drawable); } /* * From the left edge: * * |a|b|c|d|e| f |d|e|g|h| i |h|g|e|d|f| j |e|d|c|b|a| * * a. highlight ring * b. notebook 3D border * c. outer gap * d. page border * e. page corner * f. gap + select pad * g. label pad x (worldX) * h. internal pad x * i. label width * j. rest of page width * * worldX, worldY * | * | * * 4+ . . +5 * 3+ +6 * . . * . . * 1+. . .2+ +7 . . . .+8 * 0+ +9 * . . * . . *13+ +10 * 12+-------------------------+11 * */ static void DisplayTearoff(clientData) ClientData clientData; { Notebook *nbPtr; Tab *tabPtr; Drawable drawable; XPoint pointArr[16]; XPoint *pointPtr; int width, height; int left, bottom, right, top; int x, y; int nPoints; Tk_Window tkwin; Tk_Window parent; XRectangle rect; tabPtr = clientData; if (tabPtr == NULL) { return; } tabPtr->flags &= ~TAB_REDRAW; nbPtr = tabPtr->nbPtr; if (nbPtr->tkwin == NULL) { return; } tkwin = tabPtr->container; drawable = Tk_WindowId(tkwin); /* * Clear the background either by tiling a pixmap or filling with * a solid color. Tiling takes precedence. */ if (nbPtr->tile != NULL) { Blt_SetTileOrigin(tkwin, nbPtr->tile, 0, 0); Blt_TileRectangle(tkwin, drawable, nbPtr->tile, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin)); } else { Blt_Fill3DRectangle(tkwin, drawable, nbPtr->border, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); } width = Tk_Width(tkwin) - 2 * nbPtr->inset; height = Tk_Height(tkwin) - 2 * nbPtr->inset; x = nbPtr->inset + nbPtr->gap + nbPtr->corner; y = nbPtr->inset; left = nbPtr->inset; right = nbPtr->inset + width; top = nbPtr->inset + nbPtr->corner + nbPtr->xSelectPad; bottom = nbPtr->inset + height; /* * worldX, worldY * | * * 4+ . . +5 * 3+ +6 * . . * . . * 1+. . .2+ +7 . . . .+8 * 0+ +9 * . . * . . *13+ +10 * 12+-------------------------+11 */ nPoints = 0; pointPtr = pointArr; TopLeft(left, top); NextPoint(x, top); TopLeft(x, y); x += tabPtr->worldWidth; TopRight(x, y); NextPoint(x, top); TopRight(right, top); BottomRight(right, bottom); BottomLeft(left, bottom); EndPoint(pointArr[0].x, pointArr[0].y); Draw3DFolder(nbPtr, tabPtr, drawable, SIDE_TOP, pointArr, nPoints); parent = (tabPtr->container == NULL) ? nbPtr->tkwin : tabPtr->container; GetWindowRectangle(tabPtr, parent, TRUE, &rect); ArrangeWindow(tabPtr->tkwin, &rect, TRUE); /* Draw 3D border. */ if ((nbPtr->borderWidth > 0) && (nbPtr->relief != TK_RELIEF_FLAT)) { Blt_Draw3DRectangle(tkwin, drawable, nbPtr->border, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), nbPtr->borderWidth, nbPtr->relief); } } /* * -------------------------------------------------------------- * * NotebookCmd -- * * This procedure is invoked to process the "notebook" command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * * -------------------------------------------------------------- */ static Blt_OpSpec notebookOps[] = { {"activate", 1, (Blt_Op)ActivateOp, 3, 3, "index",}, {"bind", 1, (Blt_Op)BindOp, 2, 5, "index ?sequence command?",}, {"cget", 2, (Blt_Op)CgetOp, 3, 3, "option",}, {"configure", 2, (Blt_Op)ConfigureOp, 2, 0, "?option value?...",}, {"delete", 1, (Blt_Op)DeleteOp, 2, 0, "first ?last?",}, {"focus", 1, (Blt_Op)FocusOp, 3, 3, "index",}, {"highlight", 1, (Blt_Op)ActivateOp, 3, 3, "index",}, {"id", 2, (Blt_Op)IdOp, 3, 3, "index",}, {"index", 3, (Blt_Op)IndexOp, 3, 5, "string",}, {"insert", 3, (Blt_Op)InsertOp, 3, 0, "index ?option value?",}, {"invoke", 3, (Blt_Op)InvokeOp, 3, 3, "index",}, {"move", 1, (Blt_Op)MoveOp, 5, 5, "name after|before index",}, {"nearest", 1, (Blt_Op)NearestOp, 4, 4, "x y",}, {"perforation", 1, (Blt_Op)PerforationOp, 2, 0, "args",}, {"scan", 2, (Blt_Op)ScanOp, 5, 5, "dragto|mark x y",}, {"see", 3, (Blt_Op)SeeOp, 3, 3, "index",}, {"select", 3, (Blt_Op)SelectOp, 3, 3, "index",}, {"size", 2, (Blt_Op)SizeOp, 2, 2, "",}, {"tab", 1, (Blt_Op)TabOp, 2, 0, "oper args",}, {"view", 1, (Blt_Op)ViewOp, 2, 5, "?moveto fract? ?scroll number what?",}, }; static int nNotebookOps = sizeof(notebookOps) / sizeof(Blt_OpSpec); static int NotebookInstCmd(clientData, interp, argc, argv) ClientData clientData; /* Information about the widget. */ Tcl_Interp *interp; /* Interpreter to report errors back to. */ int argc; /* Number of arguments. */ char **argv; /* Vector of argument strings. */ { Blt_Op proc; Notebook *nbPtr = clientData; int result; proc = Blt_GetOp(interp, nNotebookOps, notebookOps, BLT_OP_ARG1, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } Tcl_Preserve(nbPtr); result = (*proc) (nbPtr, interp, argc, argv); Tcl_Release(nbPtr); return result; } /* *---------------------------------------------------------------------- * * NotebookInstDeletedCmd -- * * This procedure can be called if the window was destroyed * (tkwin will be NULL) and the command was deleted * automatically. In this case, we need to do nothing. * * Otherwise this routine was called because the command was * deleted. Then we need to clean-up and destroy the widget. * * Results: * None. * * Side Effects: * The widget is destroyed. * *---------------------------------------------------------------------- */ static void NotebookInstDeletedCmd(clientData) ClientData clientData; /* Pointer to widget record for widget. */ { Notebook *nbPtr = clientData; if (nbPtr->tkwin != NULL) { Tk_Window tkwin; tkwin = nbPtr->tkwin; nbPtr->tkwin = NULL; Tk_DestroyWindow(tkwin); #ifdef ITCL_NAMESPACES Itk_SetWidgetCommand(tkwin, (Tcl_Command) NULL); #endif /* ITCL_NAMESPACES */ } } /* * ------------------------------------------------------------------------ * * NotebookCmd -- * * This procedure is invoked to process the Tcl command that * corresponds to a widget managed by this module. See the user * documentation for details on what it does. * * Results: * A standard Tcl result. * * Side Effects: * See the user documentation. * * ----------------------------------------------------------------------- */ /* ARGSUSED */ static int NotebookCmd(clientData, interp, argc, argv) ClientData clientData; /* Main window associated with interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { Notebook *nbPtr; Tk_Window tkwin; unsigned int mask; Tcl_CmdInfo cmdInfo; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " pathName ?option value?...\"", (char *)NULL); return TCL_ERROR; } tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp), argv[1], (char *)NULL); if (tkwin == NULL) { return TCL_ERROR; } nbPtr = CreateNotebook(interp, tkwin); if (ConfigureNotebook(interp, nbPtr, argc - 2, argv + 2, 0) != TCL_OK) { Tk_DestroyWindow(nbPtr->tkwin); return TCL_ERROR; } mask = (ExposureMask | StructureNotifyMask | FocusChangeMask); Tk_CreateEventHandler(tkwin, mask, NotebookEventProc, nbPtr); nbPtr->cmdToken = Tcl_CreateCommand(interp, argv[1], NotebookInstCmd, nbPtr, NotebookInstDeletedCmd); #ifdef ITCL_NAMESPACES Itk_SetWidgetCommand(nbPtr->tkwin, nbPtr->cmdToken); #endif /* * Try to invoke a procedure to initialize various bindings on * tabs. Source the file containing the procedure now if the * procedure isn't currently defined. We deferred this to now so * that the user could set the variable "blt_library" within the * script. */ if (!Tcl_GetCommandInfo(interp, "blt::TabnotebookInit", &cmdInfo)) { static char initCmd[] = "source [file join $blt_library tabnotebook.tcl]"; if (Tcl_GlobalEval(interp, initCmd) != TCL_OK) { char info[200]; sprintf(info, "\n (while loading bindings for %s)", argv[0]); Tcl_AddErrorInfo(interp, info); Tk_DestroyWindow(nbPtr->tkwin); return TCL_ERROR; } } if (Tcl_VarEval(interp, "blt::TabnotebookInit ", argv[1], (char *)NULL) != TCL_OK) { Tk_DestroyWindow(nbPtr->tkwin); return TCL_ERROR; } Tcl_SetResult(interp, Tk_PathName(nbPtr->tkwin), TCL_VOLATILE); return TCL_OK; } int Blt_TabnotebookInit(interp) Tcl_Interp *interp; { static Blt_CmdSpec cmdSpec = { "tabnotebook", NotebookCmd, }; if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) { return TCL_ERROR; } return TCL_OK; } #endif /* NO_TABNOTEBOOK */ blt-2.4z.orig/src/bltTabset.c0100644000175000017500000050124107542177233014640 0ustar dokodoko/* * bltTabset.c -- * * This module implements a tabset widget for the BLT toolkit. * * Copyright 1998 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 or 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. * * Tabset widget created by George A. Howlett (gah@bell-labs.com) * */ #include "bltInt.h" #ifndef NO_TABSET #include "bltBind.h" #include "bltChain.h" #include "bltHash.h" #include "bltTile.h" #if (TK_MAJOR_VERSION == 4) #define TK_REPARENTED 0x2000 #endif #define INVALID_FAIL 0 #define INVALID_OK 1 /* * The macro below is used to modify a "char" value (e.g. by casting * it to an unsigned character) so that it can be used safely with * macros such as isspace. */ #define CLAMP(val,low,hi) \ (((val) < (low)) ? (low) : ((val) > (hi)) ? (hi) : (val)) #define GAP 3 #define SELECT_PADX 4 #define SELECT_PADY 2 #define OUTER_PAD 2 #define LABEL_PAD 1 #define LABEL_PADX 2 #define LABEL_PADY 2 #define IMAGE_PAD 1 #define CORNER_OFFSET 3 #define TAB_SCROLL_OFFSET 10 #define SLANT_NONE 0 #define SLANT_LEFT 1 #define SLANT_RIGHT 2 #define SLANT_BOTH (SLANT_LEFT | SLANT_RIGHT) #define END (-1) #define ODD(x) ((x) | 0x01) #define TABWIDTH(s, t) \ ((s)->side & SIDE_VERTICAL) ? (t)->height : (t)->width) #define TABHEIGHT(s, t) \ ((s)->side & SIDE_VERTICAL) ? (t)->height : (t)->width) #define VPORTWIDTH(s) \ (((s)->side & SIDE_HORIZONTAL) ? (Tk_Width((s)->tkwin) - 2 * (s)->inset) : \ (Tk_Height((s)->tkwin) - 2 * (s)->inset)) #define VPORTHEIGHT(s) \ (((s)->side & SIDE_VERTICAL) ? (Tk_Width((s)->tkwin) - 2 * (s)->inset) : \ (Tk_Height((s)->tkwin) - 2 * (s)->inset)) #define GETATTR(t,attr) \ (((t)->attr != NULL) ? (t)->attr : (t)->setPtr->defTabStyle.attr) /* * ---------------------------------------------------------------------------- * * Internal widget flags: * * TABSET_LAYOUT The layout of the widget needs to be * recomputed. * * TABSET_REDRAW A redraw request is pending for the widget. * * TABSET_SCROLL A scroll request is pending. * * TABSET_FOCUS The widget is receiving keyboard events. * Draw the focus highlight border around the * widget. * * TABSET_MULTIPLE_TIER Tabset is using multiple tiers. * * TABSET_STATIC Tabset does not scroll. * * --------------------------------------------------------------------------- */ #define TABSET_LAYOUT (1<<0) #define TABSET_REDRAW (1<<1) #define TABSET_SCROLL (1<<2) #define TABSET_FOCUS (1<<4) #define TABSET_STATIC (1<<8) #define TABSET_MULTIPLE_TIER (1<<9) #define PERFORATION_ACTIVE (1<<10) #define SIDE_TOP (1<<0) #define SIDE_RIGHT (1<<1) #define SIDE_LEFT (1<<2) #define SIDE_BOTTOM (1<<3) #define SIDE_VERTICAL (SIDE_LEFT | SIDE_RIGHT) #define SIDE_HORIZONTAL (SIDE_TOP | SIDE_BOTTOM) #define TAB_LABEL (ClientData)0 #define TAB_PERFORATION (ClientData)1 #define DEF_TABSET_ACTIVE_BACKGROUND RGB_GREY90 #define DEF_TABSET_ACTIVE_BG_MONO STD_ACTIVE_BG_MONO #define DEF_TABSET_ACTIVE_FOREGROUND STD_ACTIVE_FOREGROUND #define DEF_TABSET_ACTIVE_FG_MONO STD_ACTIVE_FG_MONO #define DEF_TABSET_BG_MONO STD_NORMAL_BG_MONO #define DEF_TABSET_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_TABSET_BORDERWIDTH "1" #define DEF_TABSET_COMMAND (char *)NULL #define DEF_TABSET_CURSOR (char *)NULL #define DEF_TABSET_DASHES "1" #define DEF_TABSET_FOREGROUND STD_NORMAL_FOREGROUND #define DEF_TABSET_FG_MONO STD_NORMAL_FG_MONO #define DEF_TABSET_FONT STD_FONT #define DEF_TABSET_GAP "3" #define DEF_TABSET_HEIGHT "0" #define DEF_TABSET_HIGHLIGHT_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_TABSET_HIGHLIGHT_BG_MONO STD_NORMAL_BG_MONO #define DEF_TABSET_HIGHLIGHT_COLOR RGB_BLACK #define DEF_TABSET_HIGHLIGHT_WIDTH "2" #define DEF_TABSET_NORMAL_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_TABSET_NORMAL_FG_MONO STD_ACTIVE_FG_MONO #define DEF_TABSET_OUTER_PAD "3" #define DEF_TABSET_RELIEF "sunken" #define DEF_TABSET_ROTATE "0.0" #define DEF_TABSET_SCROLL_INCREMENT "0" #define DEF_TABSET_SELECT_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_TABSET_SELECT_BG_MONO STD_SELECT_BG_MONO #define DEF_TABSET_SELECT_BORDERWIDTH "1" #define DEF_TABSET_SELECT_CMD (char *)NULL #define DEF_TABSET_SELECT_FOREGROUND STD_SELECT_FOREGROUND #define DEF_TABSET_SELECT_FG_MONO STD_SELECT_FG_MONO #define DEF_TABSET_SELECT_MODE "multiple" #define DEF_TABSET_SELECT_RELIEF "raised" #define DEF_TABSET_SELECT_PAD "5" #define DEF_TABSET_SHADOW_COLOR RGB_BLACK #define DEF_TABSET_SIDE "top" #define DEF_TABSET_SLANT "none" #define DEF_TABSET_TAB_BACKGROUND RGB_GREY82 #define DEF_TABSET_TAB_BG_MONO STD_SELECT_BG_MONO #define DEF_TABSET_TAB_RELIEF "raised" #define DEF_TABSET_TAKE_FOCUS "1" #define DEF_TABSET_TEXT_COLOR STD_NORMAL_FOREGROUND #define DEF_TABSET_TEXT_MONO STD_NORMAL_FG_MONO #define DEF_TABSET_TEXT_SIDE "left" #define DEF_TABSET_TIERS "1" #define DEF_TABSET_TILE (char *)NULL #define DEF_TABSET_WIDTH "0" #define DEF_TABSET_SAME_WIDTH "yes" #define DEF_TABSET_TEAROFF "yes" #define DEF_TABSET_PAGE_WIDTH "0" #define DEF_TABSET_PAGE_HEIGHT "0" #define DEF_TAB_ACTIVE_BG (char *)NULL #define DEF_TAB_ACTIVE_FG (char *)NULL #define DEF_TAB_ANCHOR "center" #define DEF_TAB_BG (char *)NULL #define DEF_TAB_COMMAND (char *)NULL #define DEF_TAB_DATA (char *)NULL #define DEF_TAB_FG (char *)NULL #define DEF_TAB_FILL "none" #define DEF_TAB_FONT (char *)NULL #define DEF_TAB_HEIGHT "0" #define DEF_TAB_IMAGE (char *)NULL #define DEF_TAB_IPAD "0" #define DEF_TAB_PAD "3" #define DEF_TAB_PERF_COMMAND (char *)NULL #define DEF_TAB_SELECT_BG (char *)NULL #define DEF_TAB_SELECT_BORDERWIDTH "1" #define DEF_TAB_SELECT_CMD (char *)NULL #define DEF_TAB_SELECT_FG (char *)NULL #define DEF_TAB_SHADOW (char *)NULL #define DEF_TAB_STATE "normal" #define DEF_TAB_STIPPLE "BLT" #define DEF_TAB_BIND_TAGS "all" #define DEF_TAB_TEXT (char *)NULL #define DEF_TAB_VISUAL (char *)NULL #define DEF_TAB_WIDTH "0" #define DEF_TAB_WINDOW (char *)NULL typedef struct TabsetStruct Tabset; static void EmbeddedWidgetGeometryProc _ANSI_ARGS_((ClientData, Tk_Window)); static void EmbeddedWidgetCustodyProc _ANSI_ARGS_((ClientData, Tk_Window)); static Tk_GeomMgr tabMgrInfo = { "tabset", /* Name of geometry manager used by winfo */ EmbeddedWidgetGeometryProc, /* Procedure to for new geometry requests */ EmbeddedWidgetCustodyProc, /* Procedure when window is taken away */ }; extern Tk_CustomOption bltDashesOption; extern Tk_CustomOption bltFillOption; extern Tk_CustomOption bltDistanceOption; extern Tk_CustomOption bltPositiveDistanceOption; extern Tk_CustomOption bltPositiveCountOption; extern Tk_CustomOption bltListOption; extern Tk_CustomOption bltPadOption; extern Tk_CustomOption bltShadowOption; extern Tk_CustomOption bltStateOption; extern Tk_CustomOption bltTileOption; extern Tk_CustomOption bltUidOption; static int StringToImage _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *string, char *widgRec, int offset)); static char *ImageToString _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, char *widgRec, int offset, Tcl_FreeProc **freeProcPtrPtr)); static int StringToWindow _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *string, char *widgRec, int offset)); static char *WindowToString _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, char *widgRec, int offset, Tcl_FreeProc **freeProcPtrPtr)); static int StringToSide _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *string, char *widgRec, int offset)); static char *SideToString _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, char *widgRec, int offset, Tcl_FreeProc **freeProcPtrPtr)); static int StringToSlant _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *string, char *widgRec, int offset)); static char *SlantToString _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, char *widgRec, int offset, Tcl_FreeProc **freeProcPtrPtr)); /* * Contains a pointer to the widget that's currently being configured. * This is used in the custom configuration parse routine for images. */ static Tabset *tabSet; static Tk_CustomOption imageOption = { StringToImage, ImageToString, (ClientData)&tabSet, }; static Tk_CustomOption sideOption = { StringToSide, SideToString, (ClientData)0, }; static Tk_CustomOption windowOption = { StringToWindow, WindowToString, (ClientData)0, }; static Tk_CustomOption slantOption = { StringToSlant, SlantToString, (ClientData)0, }; /* * TabImage -- * * When multiple instances of an image are displayed in the * same widget, this can be inefficient in terms of both memory * and time. We only need one instance of each image, regardless * of number of times we use it. And searching/deleting instances * can be very slow as the list gets large. * * The workaround, employed below, is to maintain a hash table of * images that maintains a reference count for each image. */ typedef struct TabImageStruct { int refCount; /* Reference counter for this image. */ Tk_Image tkImage; /* The Tk image being cached. */ int width, height; /* Dimensions of the cached image. */ Blt_HashEntry *hashPtr; /* Hash table pointer to the image. */ } *TabImage; #define ImageHeight(image) ((image)->height) #define ImageWidth(image) ((image)->width) #define ImageBits(image) ((image)->tkImage) #define TAB_VISIBLE (1<<0) #define TAB_REDRAW (1<<2) typedef struct { char *name; /* Identifier for tab entry */ int state; /* State of the tab: Disabled, active, or * normal. */ unsigned int flags; int tier; /* Index of tier [1..numTiers] containing * this tab. */ int worldX, worldY; /* Position of the tab in world coordinates. */ int worldWidth, worldHeight;/* Dimensions of the tab, corrected for * orientation (-side). It includes the * border, padding, label, etc. */ int screenX, screenY; short int screenWidth, screenHeight; /* */ Tabset *setPtr; /* Tabset that includes this * tab. Needed for callbacks can pass * only a tab pointer. */ Blt_Uid tags; /* * Tab label: */ Blt_Uid text; /* String displayed as the tab's label. */ TabImage image; /* Image displayed as the label. */ short int textWidth, textHeight; short int labelWidth, labelHeight; Blt_Pad iPadX, iPadY; /* Internal padding around the text */ Tk_Font font; /* * Normal: */ XColor *textColor; /* Text color */ Tk_3DBorder border; /* Background color and border for tab.*/ /* * Selected: Tab is currently selected. */ XColor *selColor; /* Selected text color */ Tk_3DBorder selBorder; /* 3D border of selected folder. */ /* * Active: Mouse passes over the tab. */ Tk_3DBorder activeBorder; /* Active background color. */ XColor *activeFgColor; /* Active text color */ Shadow shadow; Pixmap stipple; /* Stipple for outline of embedded window * when torn off. */ /* * Embedded widget information: */ Tk_Window tkwin; /* Widget to be mapped when the tab is * selected. If NULL, don't make * space for the page. */ int reqWidth, reqHeight; /* If non-zero, overrides the * requested dimensions of the * embedded widget. */ Tk_Window container; /* The window containing the embedded * widget. Does not necessarily have * to be the parent. */ Tk_Anchor anchor; /* Anchor: indicates how the embedded * widget is positioned within the * extra space on the page. */ Blt_Pad padX, padY; /* Padding around embedded widget */ int fill; /* Indicates how the window should * fill the page. */ /* * Auxillary information: */ Blt_Uid command; /* Command (malloc-ed) invoked when the tab * is selected */ Blt_Uid data; /* This value isn't used in C code. * It may be used by clients in Tcl bindings * to associate extra data (other than the * label or name) with the tab. */ Blt_ChainLink *linkPtr; /* Pointer to where the tab resides in the * list of tabs. */ Blt_Uid perfCommand; /* Command (malloc-ed) invoked when the tab * is selected */ GC textGC; GC backGC; Blt_Tile tile; } Tab; static Tk_ConfigSpec tabConfigSpecs[] = { {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "ActiveBackground", DEF_TAB_ACTIVE_BG, Tk_Offset(Tab, activeBorder), TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "ActiveForeground", DEF_TAB_ACTIVE_FG, Tk_Offset(Tab, activeFgColor), TK_CONFIG_NULL_OK}, {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", DEF_TAB_ANCHOR, Tk_Offset(Tab, anchor), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_TAB_BG, Tk_Offset(Tab, border), TK_CONFIG_NULL_OK}, {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags", DEF_TAB_BIND_TAGS, Tk_Offset(Tab, tags), TK_CONFIG_NULL_OK, &bltUidOption}, {TK_CONFIG_CUSTOM, "-command", "command", "Command", DEF_TAB_COMMAND, Tk_Offset(Tab, command), TK_CONFIG_NULL_OK, &bltUidOption}, {TK_CONFIG_CUSTOM, "-data", "data", "data", DEF_TAB_DATA, Tk_Offset(Tab, data), TK_CONFIG_NULL_OK, &bltUidOption}, {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_CUSTOM, "-fill", "fill", "Fill", DEF_TAB_FILL, Tk_Offset(Tab, fill), TK_CONFIG_DONT_SET_DEFAULT, &bltFillOption}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_TAB_FG, Tk_Offset(Tab, textColor), TK_CONFIG_NULL_OK}, {TK_CONFIG_FONT, "-font", "font", "Font", DEF_TAB_FONT, Tk_Offset(Tab, font), 0}, {TK_CONFIG_CUSTOM, "-image", "image", "image", DEF_TAB_IMAGE, Tk_Offset(Tab, image), TK_CONFIG_NULL_OK, &imageOption}, {TK_CONFIG_CUSTOM, "-ipadx", "iPadX", "PadX", DEF_TAB_IPAD, Tk_Offset(Tab, iPadX), TK_CONFIG_DONT_SET_DEFAULT, &bltPadOption}, {TK_CONFIG_CUSTOM, "-ipady", "iPadY", "PadY", DEF_TAB_IPAD, Tk_Offset(Tab, iPadY), TK_CONFIG_DONT_SET_DEFAULT, &bltPadOption}, {TK_CONFIG_CUSTOM, "-padx", "padX", "PadX", DEF_TAB_PAD, Tk_Offset(Tab, padX), 0, &bltPadOption}, {TK_CONFIG_CUSTOM, "-pady", "padY", "PadY", DEF_TAB_PAD, Tk_Offset(Tab, padY), 0, &bltPadOption}, {TK_CONFIG_CUSTOM, "-perforationcommand", "perforationcommand", "PerforationCommand", DEF_TAB_PERF_COMMAND, Tk_Offset(Tab, perfCommand), TK_CONFIG_NULL_OK, &bltUidOption}, {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Background", DEF_TAB_SELECT_BG, Tk_Offset(Tab, selBorder), TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Foreground", DEF_TAB_SELECT_FG, Tk_Offset(Tab, selColor), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-shadow", "shadow", "Shadow", DEF_TAB_SHADOW, Tk_Offset(Tab, shadow), TK_CONFIG_NULL_OK, &bltShadowOption}, {TK_CONFIG_CUSTOM, "-state", "state", "State", DEF_TAB_STATE, Tk_Offset(Tab, state), TK_CONFIG_DONT_SET_DEFAULT, &bltStateOption}, {TK_CONFIG_BITMAP, "-stipple", "stipple", "Stipple", DEF_TAB_STIPPLE, Tk_Offset(Tab, stipple), 0}, {TK_CONFIG_CUSTOM, "-text", "Text", "Text", DEF_TAB_TEXT, Tk_Offset(Tab, text), TK_CONFIG_NULL_OK, &bltUidOption}, {TK_CONFIG_CUSTOM, "-window", "window", "Window", DEF_TAB_WINDOW, Tk_Offset(Tab, tkwin), TK_CONFIG_NULL_OK, &windowOption}, {TK_CONFIG_CUSTOM, "-windowheight", "windowHeight", "WindowHeight", DEF_TAB_HEIGHT, Tk_Offset(Tab, reqHeight), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-windowwidth", "windowWidth", "WindowWidth", DEF_TAB_WIDTH, Tk_Offset(Tab, reqWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; /* * TabAttributes -- */ typedef struct { Tk_Window tkwin; /* Default window to map pages. */ int reqWidth, reqHeight; /* Requested tab size. */ int constWidth; int borderWidth; /* Width of 3D border around the tab's * label. */ int pad; /* Extra padding of a tab entry */ XColor *activeFgColor; /* Active foreground. */ Tk_3DBorder activeBorder; /* Active background. */ XColor *selColor; /* Selected foreground. */ Tk_Font font; XColor *textColor; Tk_3DBorder border; /* Normal background. */ Tk_3DBorder selBorder; /* Selected background. */ Blt_Dashes dashes; GC normalGC, activeGC; int relief; char *command; char *perfCommand; /* Command (malloc-ed) invoked when the tab * is selected */ double rotate; int textSide; } TabAttributes; struct TabsetStruct { Tk_Window tkwin; /* Window that embodies the widget. * NULL means that the window has been * destroyed but the data structures * haven't yet been cleaned up.*/ Display *display; /* Display containing widget; needed, * among other things, to release * resources after tkwin has already * gone away. */ Tcl_Interp *interp; /* Interpreter associated with widget. */ Tcl_Command cmdToken; /* Token for widget's command. */ unsigned int flags; /* For bitfield definitions, see below */ int inset; /* Total width of all borders, including * traversal highlight and 3-D border. * Indicates how much interior stuff must * be offset from outside edges to leave * room for borders. */ int inset2; /* Total width of 3-D folder border + corner, * Indicates how much interior stuff must * be offset from outside edges of folder.*/ int yPad; /* Extra offset for selected tab. Only * for single tiers. */ int pageTop; /* Offset from top of tabset to the * start of the page. */ Tk_Cursor cursor; /* X Cursor */ Tk_3DBorder border; /* 3D border surrounding the window. */ int borderWidth; /* Width of 3D border. */ int relief; /* 3D border relief. */ XColor *shadowColor; /* Shadow color around folder. */ /* * Focus highlight ring */ int highlightWidth; /* Width in pixels of highlight to draw * around widget when it has the focus. * <= 0 means don't draw a highlight. */ XColor *highlightBgColor; /* Color for drawing traversal highlight * area when highlight is off. */ XColor *highlightColor; /* Color for drawing traversal highlight. */ GC highlightGC; /* GC for focus highlight. */ char *takeFocus; /* Says whether to select this widget during * tab traveral operations. This value isn't * used in C code, but for the widget's Tcl * bindings. */ int side; /* How tabset is oriented: either SIDE_LEFT, * SIDE_RIGHT, SIDE_TOP, or SIDE_BOTTOM. */ int slant; int overlap; int gap; int tabWidth, tabHeight; int xSelectPad, ySelectPad; /* Padding around label of the selected tab. */ int outerPad; /* Padding around the exterior of the tabset * and folder. */ TabAttributes defTabStyle; /* Global attribute information specific to * tabs. */ Blt_Tile tile; int reqWidth, reqHeight; /* Requested dimensions of the tabset * window. */ int pageWidth, pageHeight; /* Dimensions of a page in the folder. */ int reqPageWidth, reqPageHeight; /* Requested dimensions of a page. */ int lastX, lastY; /* * Scrolling information: */ int worldWidth; int scrollOffset; /* Offset of viewport in world coordinates. */ char *scrollCmdPrefix; /* Command strings to control scrollbar.*/ int scrollUnits; /* Smallest unit of scrolling for tabs. */ /* * Scanning information: */ int scanAnchor; /* Scan anchor in screen coordinates. */ int scanOffset; /* Offset of the start of the scan in world * coordinates.*/ int corner; /* Number of pixels to offset next point * when drawing corners of the folder. */ int reqTiers; /* Requested number of tiers. Zero means to * dynamically scroll if there are too many * tabs to be display on a single tier. */ int nTiers; /* Actual number of tiers. */ Blt_HashTable imageTable; Tab *selectPtr; /* The currently selected tab. * (i.e. its page is displayed). */ Tab *activePtr; /* Tab last located under the pointer. * It is displayed with its active * foreground/background colors. */ Tab *focusPtr; /* Tab currently receiving focus. */ Tab *startPtr; /* The first tab on the first tier. */ Blt_Chain *chainPtr; /* List of tab entries. Used to * arrange placement of tabs. */ Blt_HashTable tabTable; /* Hash table of tab entries. Used for * lookups of tabs by name. */ int nVisible; /* Number of tabs that are currently visible * in the view port. */ Blt_BindTable bindTable; /* Tab binding information */ Blt_HashTable tagTable; /* Table of bind tags. */ int tearoff; }; static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "activeBackground", DEF_TABSET_ACTIVE_BACKGROUND, Tk_Offset(Tabset, defTabStyle.activeBorder), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "activeBackground", DEF_TABSET_ACTIVE_BG_MONO, Tk_Offset(Tabset, defTabStyle.activeBorder), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "activeForeground", DEF_TABSET_ACTIVE_FOREGROUND, Tk_Offset(Tabset, defTabStyle.activeFgColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "activeForeground", DEF_TABSET_ACTIVE_FG_MONO, Tk_Offset(Tabset, defTabStyle.activeFgColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_TABSET_BG_MONO, Tk_Offset(Tabset, border), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_TABSET_BACKGROUND, Tk_Offset(Tabset, border), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", DEF_TABSET_CURSOR, Tk_Offset(Tabset, cursor), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-borderwidth", "borderWidth", "BorderWidth", DEF_TABSET_BORDERWIDTH, Tk_Offset(Tabset, borderWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-dashes", "dashes", "Dashes", DEF_TABSET_DASHES, Tk_Offset(Tabset, defTabStyle.dashes), TK_CONFIG_NULL_OK, &bltDashesOption}, {TK_CONFIG_SYNONYM, "-fg", "tabForeground", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_FONT, "-font", "font", "Font", DEF_TABSET_FONT, Tk_Offset(Tabset, defTabStyle.font), 0}, {TK_CONFIG_SYNONYM, "-foreground", "tabForeground", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_PIXELS, "-gap", "gap", "Gap", DEF_TABSET_GAP, Tk_Offset(Tabset, gap), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-height", "height", "Height", DEF_TABSET_HEIGHT, Tk_Offset(Tabset, reqHeight), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", "HighlightBackground", DEF_TABSET_HIGHLIGHT_BACKGROUND, Tk_Offset(Tabset, highlightBgColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", "HighlightBackground", DEF_TABSET_HIGHLIGHT_BG_MONO, Tk_Offset(Tabset, highlightBgColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", DEF_TABSET_HIGHLIGHT_COLOR, Tk_Offset(Tabset, highlightColor), 0}, {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", "HighlightThickness", DEF_TABSET_HIGHLIGHT_WIDTH, Tk_Offset(Tabset, highlightWidth), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-outerpad", "outerPad", "OuterPad", DEF_TABSET_OUTER_PAD, Tk_Offset(Tabset, outerPad), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-pageheight", "pageHeight", "PageHeight", DEF_TABSET_PAGE_HEIGHT, Tk_Offset(Tabset, reqPageHeight), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-pagewidth", "pageWidth", "PageWidth", DEF_TABSET_PAGE_WIDTH, Tk_Offset(Tabset, reqPageWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_STRING, "-perforationcommand", "perforationcommand", "PerforationCommand", DEF_TAB_PERF_COMMAND, Tk_Offset(Tabset, defTabStyle.perfCommand), TK_CONFIG_NULL_OK, &bltUidOption}, {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_TABSET_RELIEF, Tk_Offset(Tabset, relief), 0}, {TK_CONFIG_DOUBLE, "-rotate", "rotate", "Rotate", DEF_TABSET_ROTATE, Tk_Offset(Tabset, defTabStyle.rotate), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_BOOLEAN, "-samewidth", "sameWidth", "SameWidth", DEF_TABSET_SAME_WIDTH, Tk_Offset(Tabset, defTabStyle.constWidth), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_STRING, "-scrollcommand", "scrollCommand", "ScrollCommand", (char *)NULL, Tk_Offset(Tabset, scrollCmdPrefix), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-scrollincrement", "scrollIncrement", "ScrollIncrement", DEF_TABSET_SCROLL_INCREMENT, Tk_Offset(Tabset, scrollUnits), TK_CONFIG_DONT_SET_DEFAULT, &bltPositiveDistanceOption}, {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground", DEF_TABSET_SELECT_BG_MONO, Tk_Offset(Tabset, defTabStyle.selBorder), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground", DEF_TABSET_SELECT_BACKGROUND, Tk_Offset(Tabset, defTabStyle.selBorder), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_STRING, "-selectcommand", "selectCommand", "SelectCommand", DEF_TABSET_SELECT_CMD, Tk_Offset(Tabset, defTabStyle.command), TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background", DEF_TABSET_SELECT_FG_MONO, Tk_Offset(Tabset, defTabStyle.selColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background", DEF_TABSET_SELECT_FOREGROUND, Tk_Offset(Tabset, defTabStyle.selColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_CUSTOM, "-selectpad", "selectPad", "SelectPad", DEF_TABSET_SELECT_PAD, Tk_Offset(Tabset, xSelectPad), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_COLOR, "-shadowcolor", "shadowColor", "ShadowColor", DEF_TABSET_SHADOW_COLOR, Tk_Offset(Tabset, shadowColor), 0}, {TK_CONFIG_CUSTOM, "-side", "side", "side", DEF_TABSET_SIDE, Tk_Offset(Tabset, side), TK_CONFIG_DONT_SET_DEFAULT, &sideOption}, {TK_CONFIG_CUSTOM, "-slant", "slant", "Slant", DEF_TABSET_SLANT, Tk_Offset(Tabset, slant), TK_CONFIG_DONT_SET_DEFAULT, &slantOption}, {TK_CONFIG_BORDER, "-tabbackground", "tabBackground", "Background", DEF_TABSET_TAB_BG_MONO, Tk_Offset(Tabset, defTabStyle.border), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_BORDER, "-tabbackground", "tabBackground", "Background", DEF_TABSET_TAB_BACKGROUND, Tk_Offset(Tabset, defTabStyle.border), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_CUSTOM, "-tabborderwidth", "tabBorderWidth", "BorderWidth", DEF_TABSET_BORDERWIDTH, Tk_Offset(Tabset, defTabStyle.borderWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_COLOR, "-tabforeground", "tabForeground", "Foreground", DEF_TABSET_TEXT_COLOR, Tk_Offset(Tabset, defTabStyle.textColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-tabforeground", "tabForeground", "Foreground", DEF_TABSET_TEXT_MONO, Tk_Offset(Tabset, defTabStyle.textColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_RELIEF, "-tabrelief", "tabRelief", "TabRelief", DEF_TABSET_TAB_RELIEF, Tk_Offset(Tabset, defTabStyle.relief), 0}, {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", DEF_TABSET_TAKE_FOCUS, Tk_Offset(Tabset, takeFocus), TK_CONFIG_NULL_OK}, {TK_CONFIG_BOOLEAN, "-tearoff", "tearoff", "Tearoff", DEF_TABSET_TEAROFF, Tk_Offset(Tabset, tearoff), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-textside", "textSide", "TextSide", DEF_TABSET_TEXT_SIDE, Tk_Offset(Tabset, defTabStyle.textSide), TK_CONFIG_DONT_SET_DEFAULT, &sideOption}, {TK_CONFIG_CUSTOM, "-tiers", "tiers", "Tiers", DEF_TABSET_TIERS, Tk_Offset(Tabset, reqTiers), TK_CONFIG_DONT_SET_DEFAULT, &bltPositiveCountOption}, {TK_CONFIG_CUSTOM, "-tile", "tile", "Tile", (char *)NULL, Tk_Offset(Tabset, tile), TK_CONFIG_NULL_OK, &bltTileOption}, {TK_CONFIG_CUSTOM, "-width", "width", "Width", DEF_TABSET_WIDTH, Tk_Offset(Tabset, reqWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; /* Forward Declarations */ static void DestroyTabset _ANSI_ARGS_((DestroyData dataPtr)); static void DestroyTearoff _ANSI_ARGS_((DestroyData dataPtr)); static void EmbeddedWidgetEventProc _ANSI_ARGS_((ClientData clientdata, XEvent *eventPtr)); static void TearoffEventProc _ANSI_ARGS_((ClientData clientdata, XEvent *eventPtr)); static void TabsetEventProc _ANSI_ARGS_((ClientData clientdata, XEvent *eventPtr)); static void DrawLabel _ANSI_ARGS_((Tabset *setPtr, Tab *tabPtr, Drawable drawable)); static void DrawFolder _ANSI_ARGS_((Tabset *setPtr, Tab *tabPtr, Drawable drawable)); static void DisplayTabset _ANSI_ARGS_((ClientData clientData)); static void DisplayTearoff _ANSI_ARGS_((ClientData clientData)); static void TabsetInstDeletedCmd _ANSI_ARGS_((ClientData clientdata)); static int TabsetInstCmd _ANSI_ARGS_((ClientData clientdata, Tcl_Interp *interp, int argc, char **argv)); static void GetWindowRectangle _ANSI_ARGS_((Tab *tabPtr, Tk_Window parent, int tearOff, XRectangle *rectPtr)); static void ArrangeWindow _ANSI_ARGS_((Tk_Window tkwin, XRectangle *rectPtr, int force)); static void EventuallyRedraw _ANSI_ARGS_((Tabset *setPtr)); static void EventuallyRedrawTearoff _ANSI_ARGS_((Tab *tabPtr)); static void ComputeLayout _ANSI_ARGS_((Tabset *setPtr)); static void DrawOuterBorders _ANSI_ARGS_((Tabset *setPtr, Drawable drawable)); static Tk_ImageChangedProc ImageChangedProc; static Blt_TileChangedProc TileChangedProc; static Blt_BindTagProc GetTags; static Blt_BindPickProc PickTab; static Tcl_IdleProc AdoptWindow; static Tcl_CmdProc TabsetCmd; static ClientData MakeTag(setPtr, tagName) Tabset *setPtr; char *tagName; { Blt_HashEntry *hPtr; int isNew; hPtr = Blt_CreateHashEntry(&(setPtr->tagTable), tagName, &isNew); assert(hPtr); return Blt_GetHashKey(&(setPtr->tagTable), hPtr); } /* *---------------------------------------------------------------------- * * WorldToScreen -- * * Converts world coordinates to screen coordinates. Note that * the world view is always tabs up. * * Results: * The screen coordinates are returned via *xScreenPtr and *yScreenPtr. * *---------------------------------------------------------------------- */ static void WorldToScreen(setPtr, x, y, xScreenPtr, yScreenPtr) Tabset *setPtr; int x, y; int *xScreenPtr, *yScreenPtr; { int sx, sy; sx = sy = 0; /* Suppress compiler warning. */ /* Translate world X-Y to screen coordinates */ /* * Note that the world X-coordinate is translated by the selected label's * X padding. This is done only to keep the scroll range is between * 0.0 and 1.0, rather adding/subtracting the pad in various locations. * It may be changed back in the future. */ x += (setPtr->inset + setPtr->xSelectPad - setPtr->scrollOffset); y += setPtr->inset + setPtr->yPad; switch (setPtr->side) { case SIDE_TOP: sx = x, sy = y; /* Do nothing */ break; case SIDE_RIGHT: sx = Tk_Width(setPtr->tkwin) - y; sy = x; break; case SIDE_LEFT: sx = y, sy = x; /* Flip coordinates */ break; case SIDE_BOTTOM: sx = x; sy = Tk_Height(setPtr->tkwin) - y; break; } *xScreenPtr = sx; *yScreenPtr = sy; } /* *---------------------------------------------------------------------- * * EventuallyRedraw -- * * Queues a request to redraw the widget at the next idle point. * * Results: * None. * * Side effects: * Information gets redisplayed. Right now we don't do selective * redisplays: the whole window will be redrawn. * *---------------------------------------------------------------------- */ static void EventuallyRedraw(setPtr) Tabset *setPtr; { if ((setPtr->tkwin != NULL) && !(setPtr->flags & TABSET_REDRAW)) { setPtr->flags |= TABSET_REDRAW; Tcl_DoWhenIdle(DisplayTabset, setPtr); } } /* *---------------------------------------------------------------------- * * EventuallyRedrawTearoff -- * * Queues a request to redraw the tearoff at the next idle point. * * Results: * None. * * Side effects: * Information gets redisplayed. Right now we don't do selective * redisplays: the whole window will be redrawn. * *---------------------------------------------------------------------- */ static void EventuallyRedrawTearoff(tabPtr) Tab *tabPtr; { if ((tabPtr->tkwin != NULL) && !(tabPtr->flags & TAB_REDRAW)) { tabPtr->flags |= TAB_REDRAW; Tcl_DoWhenIdle(DisplayTearoff, tabPtr); } } /* *---------------------------------------------------------------------- * * ImageChangedProc * * This routine is called whenever an image displayed in a tab * changes. In this case, we assume that everything will change * and queue a request to re-layout and redraw the entire tabset. * * Results: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static void ImageChangedProc(clientData, x, y, width, height, imageWidth, imageHeight) ClientData clientData; int x, y, width, height; /* Not used. */ int imageWidth, imageHeight;/* Not used. */ { Tabset *setPtr = clientData; setPtr->flags |= (TABSET_LAYOUT | TABSET_SCROLL); EventuallyRedraw(setPtr); } /* *---------------------------------------------------------------------- * * GetImage -- * * This is a wrapper procedure for Tk_GetImage. The problem is * that if the same image is used repeatedly in the same widget, * the separate instances are saved in a linked list. This makes * it especially slow to destroy the widget. As a workaround, * this routine hashes the image and maintains a reference count * for it. * * Results: * Returns a pointer to the new image. * *---------------------------------------------------------------------- */ static TabImage GetImage(setPtr, interp, tkwin, name) Tabset *setPtr; Tcl_Interp *interp; Tk_Window tkwin; char *name; { struct TabImageStruct *imagePtr; int isNew; Blt_HashEntry *hPtr; hPtr = Blt_CreateHashEntry(&(setPtr->imageTable), (char *)name, &isNew); if (isNew) { Tk_Image tkImage; int width, height; tkImage = Tk_GetImage(interp, tkwin, name, ImageChangedProc, setPtr); if (tkImage == NULL) { Blt_DeleteHashEntry(&(setPtr->imageTable), hPtr); return NULL; } Tk_SizeOfImage(tkImage, &width, &height); imagePtr = Blt_Malloc(sizeof(struct TabImageStruct)); imagePtr->tkImage = tkImage; imagePtr->hashPtr = hPtr; imagePtr->refCount = 1; imagePtr->width = width; imagePtr->height = height; Blt_SetHashValue(hPtr, imagePtr); } else { imagePtr = Blt_GetHashValue(hPtr); imagePtr->refCount++; } return imagePtr; } /* *---------------------------------------------------------------------- * * FreeImage -- * * Releases the image if it's not being used anymore by this * widget. Note there may be several uses of the same image * by many tabs. * * Results: * None. * * Side Effects: * The reference count is decremented and the image is freed * is it's not being used anymore. * *---------------------------------------------------------------------- */ static void FreeImage(setPtr, imagePtr) Tabset *setPtr; struct TabImageStruct *imagePtr; { imagePtr->refCount--; if (imagePtr->refCount == 0) { Blt_DeleteHashEntry(&(setPtr->imageTable), imagePtr->hashPtr); Tk_FreeImage(imagePtr->tkImage); Blt_Free(imagePtr); } } /* *---------------------------------------------------------------------- * * StringToImage -- * * Converts an image name into a Tk image token. * * Results: * If the string is successfully converted, TCL_OK is returned. * Otherwise, TCL_ERROR is returned and an error message is left * in interpreter's result field. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToImage(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Contains a pointer to the tabset containing * this image. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Window associated with the tabset. */ char *string; /* String representation */ char *widgRec; /* Widget record */ int offset; /* Offset to field in structure */ { Tabset *setPtr = *(Tabset **)clientData; TabImage *imagePtr = (TabImage *) (widgRec + offset); TabImage image; image = NULL; if ((string != NULL) && (*string != '\0')) { image = GetImage(setPtr, interp, tkwin, string); if (image == NULL) { return TCL_ERROR; } } if (*imagePtr != NULL) { FreeImage(setPtr, *imagePtr); } *imagePtr = image; return TCL_OK; } /* *---------------------------------------------------------------------- * * ImageToString -- * * Converts the Tk image back to its string representation (i.e. * its name). * * Results: * The name of the image is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * ImageToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Pointer to tabset containing image. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget record */ int offset; /* Offset of field in record */ Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */ { Tabset *setPtr = *(Tabset **)clientData; TabImage *imagePtr = (TabImage *) (widgRec + offset); if (*imagePtr == NULL) { return ""; } return Blt_GetHashKey(&(setPtr->imageTable), (*imagePtr)->hashPtr); } /* *---------------------------------------------------------------------- * * StringToWindow -- * * Converts a window name into Tk window. * * Results: * If the string is successfully converted, TCL_OK is returned. * Otherwise, TCL_ERROR is returned and an error message is left * in interpreter's result field. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToWindow(clientData, interp, parent, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window parent; /* Parent window */ char *string; /* String representation. */ char *widgRec; /* Widget record */ int offset; /* Offset to field in structure */ { Tab *tabPtr = (Tab *)widgRec; Tk_Window *tkwinPtr = (Tk_Window *)(widgRec + offset); Tk_Window old, tkwin; Tabset *setPtr; old = *tkwinPtr; tkwin = NULL; setPtr = tabPtr->setPtr; if ((string != NULL) && (*string != '\0')) { tkwin = Tk_NameToWindow(interp, string, parent); if (tkwin == NULL) { return TCL_ERROR; } if (tkwin == old) { return TCL_OK; } /* * Allow only widgets that are children of the tabset to be * embedded into the page. This way we can make assumptions about * the window based upon its parent; either it's the tabset window * or it has been torn off. */ parent = Tk_Parent(tkwin); if (parent != setPtr->tkwin) { Tcl_AppendResult(interp, "can't manage \"", Tk_PathName(tkwin), "\" in tabset \"", Tk_PathName(setPtr->tkwin), "\"", (char *)NULL); return TCL_ERROR; } Tk_ManageGeometry(tkwin, &tabMgrInfo, tabPtr); Tk_CreateEventHandler(tkwin, StructureNotifyMask, EmbeddedWidgetEventProc, tabPtr); /* * We need to make the window to exist immediately. If the * window is torn off (placed into another container window), * the timing between the container and the its new child * (this window) gets tricky. This should work for Tk 4.2. */ Tk_MakeWindowExist(tkwin); } if (old != NULL) { if (tabPtr->container != NULL) { Tcl_EventuallyFree(tabPtr, DestroyTearoff); } Tk_DeleteEventHandler(old, StructureNotifyMask, EmbeddedWidgetEventProc, tabPtr); Tk_ManageGeometry(old, (Tk_GeomMgr *) NULL, tabPtr); Tk_UnmapWindow(old); } *tkwinPtr = tkwin; return TCL_OK; } /* *---------------------------------------------------------------------- * * WindowToString -- * * Converts the Tk window back to its string representation (i.e. * its name). * * Results: * The name of the window is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * WindowToString(clientData, parent, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window parent; /* Not used. */ char *widgRec; /* Widget record */ int offset; /* Offset of field in record */ Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */ { Tk_Window tkwin = *(Tk_Window *)(widgRec + offset); if (tkwin == NULL) { return ""; } return Tk_PathName(tkwin); } /* *---------------------------------------------------------------------- * * StringToSide -- * * Converts "left", "right", "top", "bottom", into a numeric token * designating the side of the tabset which to display tabs. * * Results: * If the string is successfully converted, TCL_OK is returned. * Otherwise, TCL_ERROR is returned and an error message is left * in interpreter's result field. * *---------------------------------------------------------------------- */ /*ARGSUSED */ static int StringToSide(clientData, interp, parent, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window parent; /* Parent window */ char *string; /* Option value string */ char *widgRec; /* Widget record */ int offset; /* offset to field in structure */ { int *sidePtr = (int *)(widgRec + offset); char c; unsigned int length; c = string[0]; length = strlen(string); if ((c == 'l') && (strncmp(string, "left", length) == 0)) { *sidePtr = SIDE_LEFT; } else if ((c == 'r') && (strncmp(string, "right", length) == 0)) { *sidePtr = SIDE_RIGHT; } else if ((c == 't') && (strncmp(string, "top", length) == 0)) { *sidePtr = SIDE_TOP; } else if ((c == 'b') && (strncmp(string, "bottom", length) == 0)) { *sidePtr = SIDE_BOTTOM; } else { Tcl_AppendResult(interp, "bad side \"", string, "\": should be left, right, top, or bottom", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * SideToString -- * * Converts the window into its string representation (its name). * * Results: * The name of the window is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * SideToString(clientData, parent, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window parent; /* Not used. */ char *widgRec; /* Widget record */ int offset; /* offset of windows array in record */ Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */ { int side = *(int *)(widgRec + offset); switch (side) { case SIDE_LEFT: return "left"; case SIDE_RIGHT: return "right"; case SIDE_BOTTOM: return "bottom"; case SIDE_TOP: return "top"; } return "unknown side value"; } /* *---------------------------------------------------------------------- * * StringToSlant -- * * Converts the slant style string into its numeric representation. * * Valid style strings are: * * "none" Both sides are straight. * "left" Left side is slanted. * "right" Right side is slanted. * "both" Both sides are slanted. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToSlant(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* String representation of attribute. */ char *widgRec; /* Widget record */ int offset; /* Offset of field in widget record. */ { int *slantPtr = (int *)(widgRec + offset); unsigned int length; char c; c = string[0]; length = strlen(string); if ((c == 'n') && (strncmp(string, "none", length) == 0)) { *slantPtr = SLANT_NONE; } else if ((c == 'l') && (strncmp(string, "left", length) == 0)) { *slantPtr = SLANT_LEFT; } else if ((c == 'r') && (strncmp(string, "right", length) == 0)) { *slantPtr = SLANT_RIGHT; } else if ((c == 'b') && (strncmp(string, "both", length) == 0)) { *slantPtr = SLANT_BOTH; } else { Tcl_AppendResult(interp, "bad argument \"", string, "\": should be \"none\", \"left\", \"right\", or \"both\"", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * SlantToString -- * * Returns the slant style string based upon the slant flags. * * Results: * The slant style string is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static char * SlantToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Widget structure record. */ int offset; /* Offset of field in widget record. */ Tcl_FreeProc **freeProcPtr; /* Not used. */ { int slant = *(int *)(widgRec + offset); switch (slant) { case SLANT_LEFT: return "left"; case SLANT_RIGHT: return "right"; case SLANT_NONE: return "none"; case SLANT_BOTH: return "both"; default: return "unknown value"; } } static int WorldY(tabPtr) Tab *tabPtr; { int tier; tier = tabPtr->setPtr->nTiers - tabPtr->tier; return tier * tabPtr->setPtr->tabHeight; } static int TabIndex(setPtr, tabPtr) Tabset *setPtr; Tab *tabPtr; { Tab *t2Ptr; int count; Blt_ChainLink *linkPtr; count = 0; for (linkPtr = Blt_ChainFirstLink(setPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { t2Ptr = Blt_ChainGetValue(linkPtr); if (t2Ptr == tabPtr) { return count; } count++; } return -1; } /* * ---------------------------------------------------------------------- * * RenumberTiers -- * * In multi-tier mode, we need to find the start of the tier * containing the newly selected tab. * * Tiers are draw from the last tier to the first, so that * the the lower-tiered tabs will partially cover the bottoms * of tab directly above it. This simplifies the drawing of * tabs because we don't worry how tabs are clipped by their * neighbors. * * In addition, tabs are re-marked with the correct tier number. * * Results: * None. * * Side Effects: * Renumbering the tab's tier will change the vertical placement * of the tab (i.e. shift tiers). * * ---------------------------------------------------------------------- */ static void RenumberTiers(setPtr, tabPtr) Tabset *setPtr; Tab *tabPtr; { int tier; Tab *prevPtr; Blt_ChainLink *linkPtr, *lastPtr; setPtr->focusPtr = setPtr->selectPtr = tabPtr; Blt_SetFocusItem(setPtr->bindTable, setPtr->focusPtr, NULL); tier = tabPtr->tier; for (linkPtr = Blt_ChainPrevLink(tabPtr->linkPtr); linkPtr != NULL; linkPtr = lastPtr) { lastPtr = Blt_ChainPrevLink(linkPtr); prevPtr = Blt_ChainGetValue(linkPtr); if ((prevPtr == NULL) || (prevPtr->tier != tier)) { break; } tabPtr = prevPtr; } setPtr->startPtr = tabPtr; for (linkPtr = Blt_ChainFirstLink(setPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); tabPtr->tier = (tabPtr->tier - tier + 1); if (tabPtr->tier < 1) { tabPtr->tier += setPtr->nTiers; } tabPtr->worldY = WorldY(tabPtr); } } /* * ---------------------------------------------------------------------- * * TabExists -- * * Searches for a tab based upon its name. * * Results: * Returns TRUE if the tab exists, FALSE otherwise. * * ---------------------------------------------------------------------- */ static int TabExists(setPtr, string) Tabset *setPtr; char *string; { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&(setPtr->tabTable), string); return (hPtr != NULL); } /* * ---------------------------------------------------------------------- * * GetTabByName -- * * Searches for a tab based upon its name. * * Results: * A standard Tcl result. An error message is generated if * the tab can't be found. * * Side Effects: * If the tab is found, *tabPtrPtr will contain the pointer to the * tab structure. * * ---------------------------------------------------------------------- */ static int GetTabByName(setPtr, string, tabPtrPtr) Tabset *setPtr; char *string; Tab **tabPtrPtr; { Blt_HashEntry *hPtr; *tabPtrPtr = NULL; hPtr = Blt_FindHashEntry(&(setPtr->tabTable), string); if (hPtr != NULL) { *tabPtrPtr = (Tab *)Blt_GetHashValue(hPtr); return TCL_OK; } Tcl_AppendResult(setPtr->interp, "can't find tab named \"", string, "\" in \"", Tk_PathName(setPtr->tkwin), "\"", (char *)NULL); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * PickTab -- * * Searches the tab located within the given screen X-Y coordinates * in the viewport. Note that tabs overlap slightly, so that its * important to search from the innermost tier out. * * Results: * Returns the pointer to the tab. If the pointer isn't contained * by any tab, NULL is returned. * *---------------------------------------------------------------------- */ static ClientData PickTab(clientData, x, y, contextPtr) ClientData clientData; int x, y; /* Screen coordinates to test. */ ClientData *contextPtr; /* (out) If non-NULL, will contain the * context of the tab selected. */ { Tabset *setPtr = clientData; /* Tabset widget record. */ Tab *tabPtr; Blt_ChainLink *linkPtr; tabPtr = setPtr->selectPtr; if ((setPtr->tearoff) && (tabPtr != NULL) && (tabPtr->container == NULL) && (tabPtr->tkwin != NULL)) { int top, bottom, left, right; int sx, sy; /* Check first for perforation on the selected tab. */ WorldToScreen(setPtr, tabPtr->worldX + 2, tabPtr->worldY + tabPtr->worldHeight + 4, &sx, &sy); if (setPtr->side & SIDE_HORIZONTAL) { left = sx - 2; right = left + tabPtr->screenWidth; top = sy - 4; bottom = sy + 4; } else { left = sx - 4; right = sx + 4; top = sy - 2; bottom = top + tabPtr->screenHeight; } if ((x >= left) && (y >= top) && (x < right) && (y < bottom)) { if (contextPtr != NULL) { *contextPtr = TAB_PERFORATION; } return tabPtr; } } for (linkPtr = Blt_ChainFirstLink(setPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); if (!(tabPtr->flags & TAB_VISIBLE)) { continue; } if ((x >= tabPtr->screenX) && (y >= tabPtr->screenY) && (x <= (tabPtr->screenX + tabPtr->screenWidth)) && (y < (tabPtr->screenY + tabPtr->screenHeight))) { if (contextPtr != NULL) { *contextPtr = TAB_LABEL; } return tabPtr; } } return NULL; } static Tab * TabLeft(tabPtr) Tab *tabPtr; { if (tabPtr != NULL) { Blt_ChainLink *linkPtr; linkPtr = Blt_ChainPrevLink(tabPtr->linkPtr); if (linkPtr != NULL) { Tab *newPtr; newPtr = Blt_ChainGetValue(linkPtr); /* Move only if the next tab is on another tier. */ if (newPtr->tier == tabPtr->tier) { tabPtr = newPtr; } } } return tabPtr; } static Tab * TabRight(tabPtr) Tab *tabPtr; { if (tabPtr != NULL) { Blt_ChainLink *linkPtr; linkPtr = Blt_ChainNextLink(tabPtr->linkPtr); if (linkPtr != NULL) { Tab *newPtr; newPtr = Blt_ChainGetValue(linkPtr); /* Move only if the next tab is on another tier. */ if (newPtr->tier == tabPtr->tier) { tabPtr = newPtr; } } } return tabPtr; } static Tab * TabUp(tabPtr) Tab *tabPtr; { if (tabPtr != NULL) { Tabset *setPtr; int x, y; int worldX, worldY; setPtr = tabPtr->setPtr; worldX = tabPtr->worldX + (tabPtr->worldWidth / 2); worldY = tabPtr->worldY - (setPtr->tabHeight / 2); WorldToScreen(setPtr, worldX, worldY, &x, &y); tabPtr = PickTab(setPtr, x, y, NULL); if (tabPtr == NULL) { /* * We might have inadvertly picked the gap between two tabs, * so if the first pick fails, try again a little to the left. */ WorldToScreen(setPtr, worldX + setPtr->gap, worldY, &x, &y); tabPtr = PickTab(setPtr, x, y, NULL); } if ((tabPtr == NULL) && (setPtr->focusPtr->tier < (setPtr->nTiers - 1))) { WorldToScreen(setPtr, worldX, worldY - setPtr->tabHeight, &x, &y); tabPtr = PickTab(setPtr, x, y, NULL); } if (tabPtr == NULL) { tabPtr = setPtr->focusPtr; } } return tabPtr; } static Tab * TabDown(tabPtr) Tab *tabPtr; { if (tabPtr != NULL) { Tabset *setPtr; int x, y; int worldX, worldY; setPtr = tabPtr->setPtr; worldX = tabPtr->worldX + (tabPtr->worldWidth / 2); worldY = tabPtr->worldY + (3 * setPtr->tabHeight) / 2; WorldToScreen(setPtr, worldX, worldY, &x, &y); tabPtr = PickTab(setPtr, x, y, NULL); if (tabPtr == NULL) { /* * We might have inadvertly picked the gap between two tabs, * so if the first pick fails, try again a little to the left. */ WorldToScreen(setPtr, worldX - setPtr->gap, worldY, &x, &y); tabPtr = PickTab(setPtr, x, y, NULL); } if ((tabPtr == NULL) && (setPtr->focusPtr->tier > 2)) { WorldToScreen(setPtr, worldX, worldY + setPtr->tabHeight, &x, &y); tabPtr = PickTab(setPtr, x, y, NULL); } if (tabPtr == NULL) { tabPtr = setPtr->focusPtr; } } return tabPtr; } /* *---------------------------------------------------------------------- * * GetTabByIndex -- * * Converts a string representing a tab index into a tab pointer. * The index may be in one of the following forms: * * number Tab at position in the list of tabs. * @x,y Tab closest to the specified X-Y screen coordinates. * "active" Tab mouse is located over. * "focus" Tab is the widget's focus. * "select" Currently selected tab. * "right" Next tab from the focus tab. * "left" Previous tab from the focus tab. * "up" Next tab from the focus tab. * "down" Previous tab from the focus tab. * "end" Last tab in list. * * Results: * If the string is successfully converted, TCL_OK is returned. * The pointer to the node is returned via tabPtrPtr. * Otherwise, TCL_ERROR is returned and an error message is left * in interpreter's result field. * *---------------------------------------------------------------------- */ static int GetTabByIndex(setPtr, string, tabPtrPtr, allowNull) Tabset *setPtr; char *string; Tab **tabPtrPtr; int allowNull; /* Allow NULL tabPtr */ { Tab *tabPtr; Blt_ChainLink *linkPtr; int position; char c; c = string[0]; tabPtr = NULL; if (setPtr->focusPtr == NULL) { setPtr->focusPtr = setPtr->selectPtr; Blt_SetFocusItem(setPtr->bindTable, setPtr->focusPtr, NULL); } if ((isdigit(UCHAR(c))) && (Tcl_GetInt(setPtr->interp, string, &position) == TCL_OK)) { linkPtr = Blt_ChainGetNthLink(setPtr->chainPtr, position); if (linkPtr == NULL) { Tcl_AppendResult(setPtr->interp, "can't find tab \"", string, "\" in \"", Tk_PathName(setPtr->tkwin), "\": no such index", (char *)NULL); return TCL_ERROR; } tabPtr = Blt_ChainGetValue(linkPtr); } else if ((c == 'a') && (strcmp(string, "active") == 0)) { tabPtr = setPtr->activePtr; } else if ((c == 'c') && (strcmp(string, "current") == 0)) { tabPtr = (Tab *)Blt_GetCurrentItem(setPtr->bindTable); } else if ((c == 's') && (strcmp(string, "select") == 0)) { tabPtr = setPtr->selectPtr; } else if ((c == 'f') && (strcmp(string, "focus") == 0)) { tabPtr = setPtr->focusPtr; } else if ((c == 'u') && (strcmp(string, "up") == 0)) { switch (setPtr->side) { case SIDE_LEFT: case SIDE_RIGHT: tabPtr = TabLeft(setPtr->focusPtr); break; case SIDE_BOTTOM: tabPtr = TabDown(setPtr->focusPtr); break; case SIDE_TOP: tabPtr = TabUp(setPtr->focusPtr); break; } } else if ((c == 'd') && (strcmp(string, "down") == 0)) { switch (setPtr->side) { case SIDE_LEFT: case SIDE_RIGHT: tabPtr = TabRight(setPtr->focusPtr); break; case SIDE_BOTTOM: tabPtr = TabUp(setPtr->focusPtr); break; case SIDE_TOP: tabPtr = TabDown(setPtr->focusPtr); break; } } else if ((c == 'l') && (strcmp(string, "left") == 0)) { switch (setPtr->side) { case SIDE_LEFT: tabPtr = TabUp(setPtr->focusPtr); break; case SIDE_RIGHT: tabPtr = TabDown(setPtr->focusPtr); break; case SIDE_BOTTOM: case SIDE_TOP: tabPtr = TabLeft(setPtr->focusPtr); break; } } else if ((c == 'r') && (strcmp(string, "right") == 0)) { switch (setPtr->side) { case SIDE_LEFT: tabPtr = TabDown(setPtr->focusPtr); break; case SIDE_RIGHT: tabPtr = TabUp(setPtr->focusPtr); break; case SIDE_BOTTOM: case SIDE_TOP: tabPtr = TabRight(setPtr->focusPtr); break; } } else if ((c == 'e') && (strcmp(string, "end") == 0)) { linkPtr = Blt_ChainLastLink(setPtr->chainPtr); if (linkPtr != NULL) { tabPtr = Blt_ChainGetValue(linkPtr); } } else if (c == '@') { int x, y; if (Blt_GetXY(setPtr->interp, setPtr->tkwin, string, &x, &y) != TCL_OK) { return TCL_ERROR; } tabPtr = PickTab(setPtr, x, y, NULL); } else { Tcl_AppendResult(setPtr->interp, "can't find tab \"", string, "\" in \"", Tk_PathName(setPtr->tkwin), "\"", (char *)NULL); return TCL_ERROR; } *tabPtrPtr = tabPtr; Tcl_ResetResult(setPtr->interp); if ((!allowNull) && (tabPtr == NULL)) { Tcl_AppendResult(setPtr->interp, "can't find tab \"", string, "\" in \"", Tk_PathName(setPtr->tkwin), "\"", (char *)NULL); return TCL_ERROR; } return TCL_OK; } static Tab * NextOrLastTab(tabPtr) Tab *tabPtr; { if (tabPtr->linkPtr != NULL) { Blt_ChainLink *linkPtr; linkPtr = Blt_ChainNextLink(tabPtr->linkPtr); if (linkPtr == NULL) { linkPtr = Blt_ChainPrevLink(tabPtr->linkPtr); } if (linkPtr != NULL) { return Blt_ChainGetValue(linkPtr); } } return NULL; } /* * -------------------------------------------------------------- * * EmbeddedWidgetEventProc -- * * This procedure is invoked by the Tk dispatcher for various * events on embedded widgets contained in the tabset. * * Results: * None. * * Side effects: * When an embedded widget gets deleted, internal structures get * cleaned up. When it gets resized, the tabset is redisplayed. * * -------------------------------------------------------------- */ static void EmbeddedWidgetEventProc(clientData, eventPtr) ClientData clientData; /* Information about the tab window. */ XEvent *eventPtr; /* Information about event. */ { Tab *tabPtr = clientData; if ((tabPtr == NULL) || (tabPtr->tkwin == NULL)) { return; } switch (eventPtr->type) { case ConfigureNotify: /* * If the window's requested size changes, redraw the window. * But only if it's currently the selected page. */ if ((tabPtr->container == NULL) && (Tk_IsMapped(tabPtr->tkwin)) && (tabPtr->setPtr->selectPtr == tabPtr)) { EventuallyRedraw(tabPtr->setPtr); } break; case DestroyNotify: /* * Mark the tab as deleted by dereferencing the Tk window * pointer. Redraw the window only if the tab is currently * visible. */ if ((Tk_IsMapped(tabPtr->tkwin)) && (tabPtr->setPtr->selectPtr == tabPtr)) { EventuallyRedraw(tabPtr->setPtr); } Tk_DeleteEventHandler(tabPtr->tkwin, StructureNotifyMask, EmbeddedWidgetEventProc, tabPtr); tabPtr->tkwin = NULL; break; } } /* * ---------------------------------------------------------------------- * * EmbeddedWidgetCustodyProc -- * * This procedure is invoked when a tab window has been * stolen by another geometry manager. The information and * memory associated with the tab window is released. * * Results: * None. * * Side effects: * Arranges for the widget formerly associated with the tab * window to have its layout re-computed and arranged at the * next idle point. * * --------------------------------------------------------------------- */ /* ARGSUSED */ static void EmbeddedWidgetCustodyProc(clientData, tkwin) ClientData clientData; /* Information about the former tab window. */ Tk_Window tkwin; /* Not used. */ { Tab *tabPtr = clientData; Tabset *setPtr; if ((tabPtr == NULL) || (tabPtr->tkwin == NULL)) { return; } setPtr = tabPtr->setPtr; if (tabPtr->container != NULL) { Tcl_EventuallyFree(tabPtr, DestroyTearoff); } /* * Mark the tab as deleted by dereferencing the Tk window * pointer. Redraw the window only if the tab is currently * visible. */ if (tabPtr->tkwin != NULL) { if (Tk_IsMapped(tabPtr->tkwin) && (setPtr->selectPtr == tabPtr)) { setPtr->flags |= (TABSET_LAYOUT | TABSET_SCROLL); EventuallyRedraw(setPtr); } Tk_DeleteEventHandler(tabPtr->tkwin, StructureNotifyMask, EmbeddedWidgetEventProc, tabPtr); tabPtr->tkwin = NULL; } } /* * ------------------------------------------------------------------------- * * EmbeddedWidgetGeometryProc -- * * This procedure is invoked by Tk_GeometryRequest for tab * windows managed by the widget. * * Results: * None. * * Side effects: * Arranges for tkwin, and all its managed siblings, to be * repacked and drawn at the next idle point. * * ------------------------------------------------------------------------ */ /* ARGSUSED */ static void EmbeddedWidgetGeometryProc(clientData, tkwin) ClientData clientData; /* Information about window that got new * preferred geometry. */ Tk_Window tkwin; /* Other Tk-related information about the * window. */ { Tab *tabPtr = clientData; if ((tabPtr == NULL) || (tabPtr->tkwin == NULL)) { fprintf(stderr, "%s: line %d \"tkwin is null\"", __FILE__, __LINE__); return; } tabPtr->setPtr->flags |= (TABSET_LAYOUT | TABSET_SCROLL); EventuallyRedraw(tabPtr->setPtr); } /* * ---------------------------------------------------------------------- * * DestroyTab -- * * ---------------------------------------------------------------------- */ static void DestroyTab(setPtr, tabPtr) Tabset *setPtr; Tab *tabPtr; { Blt_HashEntry *hPtr; if (tabPtr->flags & TAB_REDRAW) { Tcl_CancelIdleCall(DisplayTearoff, tabPtr); } if (tabPtr->container != NULL) { Tk_DestroyWindow(tabPtr->container); } if (tabPtr->tkwin != NULL) { Tk_ManageGeometry(tabPtr->tkwin, (Tk_GeomMgr *)NULL, tabPtr); Tk_DeleteEventHandler(tabPtr->tkwin, StructureNotifyMask, EmbeddedWidgetEventProc, tabPtr); if (Tk_IsMapped(tabPtr->tkwin)) { Tk_UnmapWindow(tabPtr->tkwin); } } if (tabPtr == setPtr->activePtr) { setPtr->activePtr = NULL; } if (tabPtr == setPtr->selectPtr) { setPtr->selectPtr = NextOrLastTab(tabPtr); } if (tabPtr == setPtr->focusPtr) { setPtr->focusPtr = setPtr->selectPtr; Blt_SetFocusItem(setPtr->bindTable, setPtr->focusPtr, NULL); } if (tabPtr == setPtr->startPtr) { setPtr->startPtr = NULL; } Tk_FreeOptions(tabConfigSpecs, (char *)tabPtr, setPtr->display, 0); if (tabPtr->text != NULL) { Blt_FreeUid(tabPtr->text); } hPtr = Blt_FindHashEntry(&(setPtr->tabTable), tabPtr->name); assert(hPtr); Blt_DeleteHashEntry(&(setPtr->tabTable), hPtr); if (tabPtr->image != NULL) { FreeImage(setPtr, tabPtr->image); } if (tabPtr->name != NULL) { Blt_Free(tabPtr->name); } if (tabPtr->textGC != NULL) { Tk_FreeGC(setPtr->display, tabPtr->textGC); } if (tabPtr->backGC != NULL) { Tk_FreeGC(setPtr->display, tabPtr->backGC); } if (tabPtr->command != NULL) { Blt_FreeUid(tabPtr->command); } if (tabPtr->linkPtr != NULL) { Blt_ChainDeleteLink(setPtr->chainPtr, tabPtr->linkPtr); } if (tabPtr->tags != NULL) { Blt_FreeUid(tabPtr->tags); } Blt_DeleteBindings(setPtr->bindTable, tabPtr); Blt_Free(tabPtr); } /* * ---------------------------------------------------------------------- * * CreateTab -- * * Creates a new tab structure. A tab contains information about * the state of the tab and its embedded window. * * Results: * Returns a pointer to the new tab structure. * * ---------------------------------------------------------------------- */ static Tab * CreateTab(setPtr, name) Tabset *setPtr; char *name; { Tab *tabPtr; Blt_HashEntry *hPtr; int isNew; tabPtr = Blt_Calloc(1, sizeof(Tab)); assert(tabPtr); tabPtr->setPtr = setPtr; tabPtr->name = Blt_Strdup(name); tabPtr->text = Blt_GetUid(name); tabPtr->fill = FILL_NONE; tabPtr->anchor = TK_ANCHOR_CENTER; tabPtr->container = NULL; tabPtr->state = STATE_NORMAL; hPtr = Blt_CreateHashEntry(&(setPtr->tabTable), name, &isNew); Blt_SetHashValue(hPtr, tabPtr); return tabPtr; } /* *---------------------------------------------------------------------- * * TileChangedProc * * Stub for image change notifications. Since we immediately draw * the image into a pixmap, we don't really care about image changes. * * It would be better if Tk checked for NULL proc pointers. * * Results: * None. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static void TileChangedProc(clientData, tile) ClientData clientData; Blt_Tile tile; /* Not used. */ { Tabset *setPtr = clientData; if (setPtr->tkwin != NULL) { EventuallyRedraw(setPtr); } } static int ConfigureTab(setPtr, tabPtr) Tabset *setPtr; Tab *tabPtr; { GC newGC; XGCValues gcValues; unsigned long gcMask; int labelWidth, labelHeight; Tk_Font font; Tk_3DBorder border; font = GETATTR(tabPtr, font); labelWidth = labelHeight = 0; if (tabPtr->text != NULL) { TextStyle ts; double rotWidth, rotHeight; Blt_InitTextStyle(&ts); ts.font = font; ts.shadow.offset = tabPtr->shadow.offset; ts.padX.side1 = ts.padX.side2 = 2; Blt_GetTextExtents(&ts, tabPtr->text, &labelWidth, &labelHeight); Blt_GetBoundingBox(labelWidth, labelHeight, setPtr->defTabStyle.rotate, &rotWidth, &rotHeight, (Point2D *)NULL); labelWidth = ROUND(rotWidth); labelHeight = ROUND(rotHeight); } tabPtr->textWidth = (short int)labelWidth; tabPtr->textHeight = (short int)labelHeight; if (tabPtr->image != NULL) { int width, height; width = ImageWidth(tabPtr->image) + 2 * IMAGE_PAD; height = ImageHeight(tabPtr->image) + 2 * IMAGE_PAD; if (setPtr->defTabStyle.textSide & SIDE_VERTICAL) { labelWidth += width; labelHeight = MAX(labelHeight, height); } else { labelHeight += height; labelWidth = MAX(labelWidth, width); } } labelWidth += PADDING(tabPtr->iPadX); labelHeight += PADDING(tabPtr->iPadY); tabPtr->labelWidth = ODD(labelWidth); tabPtr->labelHeight = ODD(labelHeight); newGC = NULL; if (tabPtr->text != NULL) { XColor *colorPtr; gcMask = GCForeground | GCFont; colorPtr = GETATTR(tabPtr, textColor); gcValues.foreground = colorPtr->pixel; gcValues.font = Tk_FontId(font); newGC = Tk_GetGC(setPtr->tkwin, gcMask, &gcValues); } if (tabPtr->textGC != NULL) { Tk_FreeGC(setPtr->display, tabPtr->textGC); } tabPtr->textGC = newGC; gcMask = GCForeground | GCStipple | GCFillStyle; gcValues.fill_style = FillStippled; border = GETATTR(tabPtr, border); gcValues.foreground = Tk_3DBorderColor(border)->pixel; gcValues.stipple = tabPtr->stipple; newGC = Tk_GetGC(setPtr->tkwin, gcMask, &gcValues); if (tabPtr->backGC != NULL) { Tk_FreeGC(setPtr->display, tabPtr->backGC); } tabPtr->backGC = newGC; /* * GC for tiled background. */ if (tabPtr->tile != NULL) { Blt_SetTileChangedProc(tabPtr->tile, TileChangedProc, setPtr); } if (tabPtr->flags & TAB_VISIBLE) { EventuallyRedraw(setPtr); } return TCL_OK; } /* * -------------------------------------------------------------- * * TearoffEventProc -- * * This procedure is invoked by the Tk dispatcher for various * events on the tearoff widget. * * Results: * None. * * Side effects: * When the tearoff gets deleted, internal structures get * cleaned up. When it gets resized or exposed, it's redisplayed. * * -------------------------------------------------------------- */ static void TearoffEventProc(clientData, eventPtr) ClientData clientData; /* Information about the tab window. */ XEvent *eventPtr; /* Information about event. */ { Tab *tabPtr = clientData; if ((tabPtr == NULL) || (tabPtr->tkwin == NULL) || (tabPtr->container == NULL)) { return; } switch (eventPtr->type) { case Expose: if (eventPtr->xexpose.count == 0) { EventuallyRedrawTearoff(tabPtr); } break; case ConfigureNotify: EventuallyRedrawTearoff(tabPtr); break; case DestroyNotify: if (tabPtr->flags & TAB_REDRAW) { tabPtr->flags &= ~TAB_REDRAW; Tcl_CancelIdleCall(DisplayTearoff, clientData); } Tk_DestroyWindow(tabPtr->container); tabPtr->container = NULL; break; } } /* * ---------------------------------------------------------------------------- * * GetReqWidth -- * * Returns the width requested by the embedded tab window and * any requested padding around it. This represents the requested * width of the page. * * Results: * Returns the requested width of the page. * * ---------------------------------------------------------------------------- */ static int GetReqWidth(tabPtr) Tab *tabPtr; { int width; if (tabPtr->reqWidth > 0) { width = tabPtr->reqWidth; } else { width = Tk_ReqWidth(tabPtr->tkwin); } width += PADDING(tabPtr->padX) + 2 * Tk_Changes(tabPtr->tkwin)->border_width; if (width < 1) { width = 1; } return width; } /* * ---------------------------------------------------------------------------- * * GetReqHeight -- * * Returns the height requested by the window and padding around * the window. This represents the requested height of the page. * * Results: * Returns the requested height of the page. * * ---------------------------------------------------------------------------- */ static int GetReqHeight(tabPtr) Tab *tabPtr; { int height; if (tabPtr->reqHeight > 0) { height = tabPtr->reqHeight; } else { height = Tk_ReqHeight(tabPtr->tkwin); } height += PADDING(tabPtr->padY) + 2 * Tk_Changes(tabPtr->tkwin)->border_width; if (height < 1) { height = 1; } return height; } /* * ---------------------------------------------------------------------------- * * TranslateAnchor -- * * Translate the coordinates of a given bounding box based upon the * anchor specified. The anchor indicates where the given xy position * is in relation to the bounding box. * * nw --- n --- ne * | | x,y ---+ * w center e | | * | | +-----+ * sw --- s --- se * * Results: * The translated coordinates of the bounding box are returned. * * ---------------------------------------------------------------------------- */ static void TranslateAnchor(dx, dy, anchor, xPtr, yPtr) int dx, dy; /* Difference between outer and inner regions */ Tk_Anchor anchor; /* Direction of the anchor */ int *xPtr, *yPtr; { int x, y; x = y = 0; switch (anchor) { case TK_ANCHOR_NW: /* Upper left corner */ break; case TK_ANCHOR_W: /* Left center */ y = (dy / 2); break; case TK_ANCHOR_SW: /* Lower left corner */ y = dy; break; case TK_ANCHOR_N: /* Top center */ x = (dx / 2); break; case TK_ANCHOR_CENTER: /* Centered */ x = (dx / 2); y = (dy / 2); break; case TK_ANCHOR_S: /* Bottom center */ x = (dx / 2); y = dy; break; case TK_ANCHOR_NE: /* Upper right corner */ x = dx; break; case TK_ANCHOR_E: /* Right center */ x = dx; y = (dy / 2); break; case TK_ANCHOR_SE: /* Lower right corner */ x = dx; y = dy; break; } *xPtr = (*xPtr) + x; *yPtr = (*yPtr) + y; } static void GetWindowRectangle(tabPtr, parent, tearoff, rectPtr) Tab *tabPtr; Tk_Window parent; int tearoff; XRectangle *rectPtr; { int pad; Tabset *setPtr; int cavityWidth, cavityHeight; int width, height; int dx, dy; int x, y; setPtr = tabPtr->setPtr; pad = setPtr->inset + setPtr->inset2; if (!tearoff) { switch (setPtr->side) { case SIDE_RIGHT: case SIDE_BOTTOM: x = setPtr->inset + setPtr->inset2; y = setPtr->inset + setPtr->inset2; break; case SIDE_LEFT: x = setPtr->pageTop; y = setPtr->inset + setPtr->inset2; break; case SIDE_TOP: x = setPtr->inset + setPtr->inset2; y = setPtr->pageTop; break; } if (setPtr->side & SIDE_VERTICAL) { cavityWidth = Tk_Width(setPtr->tkwin) - (setPtr->pageTop + pad); cavityHeight = Tk_Height(setPtr->tkwin) - (2 * pad); } else { cavityWidth = Tk_Width(setPtr->tkwin) - (2 * pad); cavityHeight = Tk_Height(setPtr->tkwin) - (setPtr->pageTop + pad); } } else { x = setPtr->inset + setPtr->inset2; #define TEAR_OFF_TAB_SIZE 5 y = setPtr->inset + setPtr->inset2 + setPtr->yPad + setPtr->outerPad + TEAR_OFF_TAB_SIZE; cavityWidth = Tk_Width(parent) - (2 * pad); cavityHeight = Tk_Height(parent) - (y + pad); } cavityWidth -= PADDING(tabPtr->padX); cavityHeight -= PADDING(tabPtr->padY); if (cavityWidth < 1) { cavityWidth = 1; } if (cavityHeight < 1) { cavityHeight = 1; } width = GetReqWidth(tabPtr); height = GetReqHeight(tabPtr); /* * Resize the embedded window is of the following is true: * * 1) It's been torn off. * 2) The -fill option (horizontal or vertical) is set. * 3) the window is bigger than the cavity. */ if ((tearoff) || (cavityWidth < width) || (tabPtr->fill & FILL_X)) { width = cavityWidth; } if ((tearoff) || (cavityHeight < height) || (tabPtr->fill & FILL_Y)) { height = cavityHeight; } dx = (cavityWidth - width); dy = (cavityHeight - height); if ((dx > 0) || (dy > 0)) { TranslateAnchor(dx, dy, tabPtr->anchor, &x, &y); } /* Remember that X11 windows must be at least 1 pixel. */ if (width < 1) { width = 1; } if (height < 1) { height = 1; } rectPtr->x = (short)(x + tabPtr->padLeft); rectPtr->y = (short)(y + tabPtr->padTop); rectPtr->width = (short)width; rectPtr->height = (short)height; } static void ArrangeWindow(tkwin, rectPtr, force) Tk_Window tkwin; XRectangle *rectPtr; int force; { if ((force) || (rectPtr->x != Tk_X(tkwin)) || (rectPtr->y != Tk_Y(tkwin)) || (rectPtr->width != Tk_Width(tkwin)) || (rectPtr->height != Tk_Height(tkwin))) { Tk_MoveResizeWindow(tkwin, rectPtr->x, rectPtr->y, rectPtr->width, rectPtr->height); } if (!Tk_IsMapped(tkwin)) { Tk_MapWindow(tkwin); } } /*ARGSUSED*/ static void GetTags(table, object, context, list) Blt_BindTable table; ClientData object; ClientData context; /* Not used. */ Blt_List list; { Tab *tabPtr = (Tab *)object; Tabset *setPtr; setPtr = (Tabset *)table->clientData; if (context == TAB_PERFORATION) { Blt_ListAppend(list, MakeTag(setPtr, "Perforation"), 0); } else if (context == TAB_LABEL) { Blt_ListAppend(list, MakeTag(setPtr, tabPtr->name), 0); if (tabPtr->tags != NULL) { int nNames; char **names; register char **p; /* * This is a space/time trade-off in favor of space. The tags * are stored as character strings in a hash table. That way, * tabs can share the strings. It's likely that they will. The * down side is that the same string is split over an over again. */ if (Tcl_SplitList((Tcl_Interp *)NULL, tabPtr->tags, &nNames, &names) == TCL_OK) { for (p = names; *p != NULL; p++) { Blt_ListAppend(list, MakeTag(setPtr, *p), 0); } Blt_Free(names); } } } } /* * -------------------------------------------------------------- * * TabsetEventProc -- * * This procedure is invoked by the Tk dispatcher for various * events on tabset widgets. * * Results: * None. * * Side Effects: * When the window gets deleted, internal structures get * cleaned up. When it gets exposed, it is redisplayed. * * -------------------------------------------------------------- */ static void TabsetEventProc(clientData, eventPtr) ClientData clientData; /* Information about window. */ XEvent *eventPtr; /* Information about event. */ { Tabset *setPtr = clientData; switch (eventPtr->type) { case Expose: if (eventPtr->xexpose.count == 0) { EventuallyRedraw(setPtr); } break; case ConfigureNotify: setPtr->flags |= (TABSET_LAYOUT | TABSET_SCROLL); EventuallyRedraw(setPtr); break; case FocusIn: case FocusOut: if (eventPtr->xfocus.detail != NotifyInferior) { if (eventPtr->type == FocusIn) { setPtr->flags |= TABSET_FOCUS; } else { setPtr->flags &= ~TABSET_FOCUS; } EventuallyRedraw(setPtr); } break; case DestroyNotify: if (setPtr->tkwin != NULL) { setPtr->tkwin = NULL; Tcl_DeleteCommandFromToken(setPtr->interp, setPtr->cmdToken); } if (setPtr->flags & TABSET_REDRAW) { Tcl_CancelIdleCall(DisplayTabset, setPtr); } Tcl_EventuallyFree(setPtr, DestroyTabset); break; } } /* * ---------------------------------------------------------------------- * * DestroyTabset -- * * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release * to clean up the internal structure of the widget at a safe * time (when no-one is using it anymore). * * Results: * None. * * Side Effects: * Everything associated with the widget is freed up. * * ---------------------------------------------------------------------- */ static void DestroyTabset(dataPtr) DestroyData dataPtr; /* Pointer to the widget record. */ { Tabset *setPtr = (Tabset *)dataPtr; Tab *tabPtr; Blt_ChainLink *linkPtr; if (setPtr->highlightGC != NULL) { Tk_FreeGC(setPtr->display, setPtr->highlightGC); } if (setPtr->tile != NULL) { Blt_FreeTile(setPtr->tile); } if (setPtr->defTabStyle.activeGC != NULL) { Blt_FreePrivateGC(setPtr->display, setPtr->defTabStyle.activeGC); } for (linkPtr = Blt_ChainFirstLink(setPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); tabPtr->linkPtr = NULL; DestroyTab(setPtr, tabPtr); } Blt_ChainDestroy(setPtr->chainPtr); Blt_DestroyBindingTable(setPtr->bindTable); Blt_DeleteHashTable(&(setPtr->tabTable)); Blt_DeleteHashTable(&(setPtr->tagTable)); Tk_FreeOptions(configSpecs, (char *)setPtr, setPtr->display, 0); Blt_Free(setPtr); } /* * ---------------------------------------------------------------------- * * CreateTabset -- * * ---------------------------------------------------------------------- */ static Tabset * CreateTabset(interp, tkwin) Tcl_Interp *interp; Tk_Window tkwin; { Tabset *setPtr; setPtr = Blt_Calloc(1, sizeof(Tabset)); assert(setPtr); Tk_SetClass(tkwin, "Tabset"); setPtr->tkwin = tkwin; setPtr->display = Tk_Display(tkwin); setPtr->interp = interp; setPtr->flags |= (TABSET_LAYOUT | TABSET_SCROLL); setPtr->side = SIDE_TOP; setPtr->borderWidth = setPtr->highlightWidth = 2; setPtr->ySelectPad = SELECT_PADY; setPtr->xSelectPad = SELECT_PADX; setPtr->relief = TK_RELIEF_SUNKEN; setPtr->defTabStyle.relief = TK_RELIEF_RAISED; setPtr->defTabStyle.borderWidth = 1; setPtr->defTabStyle.constWidth = TRUE; setPtr->defTabStyle.textSide = SIDE_LEFT; setPtr->scrollUnits = 2; setPtr->corner = CORNER_OFFSET; setPtr->gap = GAP; setPtr->outerPad = OUTER_PAD; setPtr->slant = SLANT_NONE; setPtr->overlap = 0; setPtr->tearoff = TRUE; setPtr->bindTable = Blt_CreateBindingTable(interp, tkwin, setPtr, PickTab, GetTags); setPtr->chainPtr = Blt_ChainCreate(); Blt_InitHashTable(&(setPtr->tabTable), BLT_STRING_KEYS); Blt_InitHashTable(&(setPtr->imageTable), BLT_STRING_KEYS); Blt_InitHashTable(&(setPtr->tagTable), BLT_STRING_KEYS); #if (TK_MAJOR_VERSION > 4) Blt_SetWindowInstanceData(tkwin, setPtr); #endif return setPtr; } /* * ---------------------------------------------------------------------- * * ConfigureTabset -- * * This procedure is called to process an argv/argc list, plus * the Tk option database, in order to configure (or reconfigure) * the widget. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then interp->result contains an error message. * * Side Effects: * Configuration information, such as text string, colors, font, * etc. get set for setPtr; old resources get freed, if there * were any. The widget is redisplayed. * * ---------------------------------------------------------------------- */ static int ConfigureTabset(interp, setPtr, argc, argv, flags) Tcl_Interp *interp; /* Interpreter to report errors. */ Tabset *setPtr; /* Information about widget; may or * may not already have values for * some fields. */ int argc; char **argv; int flags; { XGCValues gcValues; unsigned long gcMask; GC newGC; tabSet = setPtr; if (Tk_ConfigureWidget(interp, setPtr->tkwin, configSpecs, argc, argv, (char *)setPtr, flags) != TCL_OK) { return TCL_ERROR; } if (Blt_ConfigModified(configSpecs, "-width", "-height", "-side", "-gap", "-slant", (char *)NULL)) { setPtr->flags |= (TABSET_LAYOUT | TABSET_SCROLL); } if ((setPtr->reqHeight > 0) && (setPtr->reqWidth > 0)) { Tk_GeometryRequest(setPtr->tkwin, setPtr->reqWidth, setPtr->reqHeight); } /* * GC for focus highlight. */ gcMask = GCForeground; gcValues.foreground = setPtr->highlightColor->pixel; newGC = Tk_GetGC(setPtr->tkwin, gcMask, &gcValues); if (setPtr->highlightGC != NULL) { Tk_FreeGC(setPtr->display, setPtr->highlightGC); } setPtr->highlightGC = newGC; /* * GC for tiled background. */ if (setPtr->tile != NULL) { Blt_SetTileChangedProc(setPtr->tile, TileChangedProc, setPtr); } /* * GC for active line. */ gcMask = GCForeground | GCLineWidth | GCLineStyle | GCCapStyle; gcValues.foreground = setPtr->defTabStyle.activeFgColor->pixel; gcValues.line_width = 0; gcValues.cap_style = CapProjecting; gcValues.line_style = (LineIsDashed(setPtr->defTabStyle.dashes)) ? LineOnOffDash : LineSolid; newGC = Blt_GetPrivateGC(setPtr->tkwin, gcMask, &gcValues); if (LineIsDashed(setPtr->defTabStyle.dashes)) { setPtr->defTabStyle.dashes.offset = 2; Blt_SetDashes(setPtr->display, newGC, &(setPtr->defTabStyle.dashes)); } if (setPtr->defTabStyle.activeGC != NULL) { Blt_FreePrivateGC(setPtr->display, setPtr->defTabStyle.activeGC); } setPtr->defTabStyle.activeGC = newGC; setPtr->defTabStyle.rotate = FMOD(setPtr->defTabStyle.rotate, 360.0); if (setPtr->defTabStyle.rotate < 0.0) { setPtr->defTabStyle.rotate += 360.0; } setPtr->inset = setPtr->highlightWidth + setPtr->borderWidth + setPtr->outerPad; if (Blt_ConfigModified(configSpecs, "-font", "-*foreground", "-rotate", "-*background", "-side", (char *)NULL)) { Blt_ChainLink *linkPtr; Tab *tabPtr; for (linkPtr = Blt_ChainFirstLink(setPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); ConfigureTab(setPtr, tabPtr); } setPtr->flags |= (TABSET_LAYOUT | TABSET_SCROLL); } setPtr->inset2 = setPtr->defTabStyle.borderWidth + setPtr->corner; EventuallyRedraw(setPtr); return TCL_OK; } /* * -------------------------------------------------------------- * * Tabset operations * * -------------------------------------------------------------- */ /* *---------------------------------------------------------------------- * * ActivateOp -- * * Selects the tab to appear active. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ActivateOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tab *tabPtr, *oldPtr, *selPtr; Drawable drawable; if (argv[2][0] == '\0') { tabPtr = NULL; } else if (GetTabByIndex(setPtr, argv[2], &tabPtr, INVALID_OK) != TCL_OK) { return TCL_ERROR; } if ((tabPtr != NULL) && (tabPtr->state == STATE_DISABLED)) { tabPtr = NULL; } oldPtr = setPtr->activePtr; setPtr->activePtr = tabPtr; drawable = Tk_WindowId(setPtr->tkwin); if (tabPtr != oldPtr) { int redraw; selPtr = setPtr->selectPtr; redraw = FALSE; if (oldPtr != NULL) { if ((selPtr != NULL) && ((oldPtr == TabLeft(selPtr)) || (oldPtr == TabRight(selPtr)))) { redraw = TRUE; } if ((selPtr != NULL) && (oldPtr->tier == 2) && (oldPtr->worldX + oldPtr->worldWidth) >= (selPtr->worldX) && (oldPtr->worldX < (selPtr->worldX + selPtr->worldWidth))) { redraw = TRUE; } else { DrawLabel(setPtr, oldPtr, drawable); } } if ((tabPtr != NULL) && (!redraw)) { if ((selPtr != NULL) && ((tabPtr == TabLeft(selPtr)) || (tabPtr == TabRight(selPtr)))) { redraw = TRUE; } if ((selPtr != NULL) && (tabPtr->tier == 2) && (tabPtr->worldX + tabPtr->worldWidth) >= (selPtr->worldX) && (tabPtr->worldX < (selPtr->worldX + selPtr->worldWidth))) { redraw = TRUE; } else { DrawLabel(setPtr, tabPtr, drawable); } } DrawOuterBorders(setPtr, drawable); if (redraw) { EventuallyRedraw(setPtr); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * BindOp -- * * .t bind index sequence command * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int BindOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { if (argc == 2) { Blt_HashEntry *hPtr; Blt_HashSearch cursor; char *tagName; for (hPtr = Blt_FirstHashEntry(&(setPtr->tagTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tagName = Blt_GetHashKey(&(setPtr->tagTable), hPtr); Tcl_AppendElement(interp, tagName); } return TCL_OK; } return Blt_ConfigureBindings(interp, setPtr->bindTable, MakeTag(setPtr, argv[2]), argc - 3, argv + 3); } /* *---------------------------------------------------------------------- * * CgetOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int CgetOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { tabSet = setPtr; return Tk_ConfigureValue(interp, setPtr->tkwin, configSpecs, (char *)setPtr, argv[2], 0); } /* *---------------------------------------------------------------------- * * ConfigureOp -- * * This procedure is called to process an argv/argc list, plus * the Tk option database, in order to configure (or reconfigure) * the widget. * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side Effects: * Configuration information, such as text string, colors, font, * etc. get set for setPtr; old resources get freed, if there * were any. The widget is redisplayed. * *---------------------------------------------------------------------- */ static int ConfigureOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; int argc; char **argv; { tabSet = setPtr; if (argc == 2) { return Tk_ConfigureInfo(interp, setPtr->tkwin, configSpecs, (char *)setPtr, (char *)NULL, 0); } else if (argc == 3) { return Tk_ConfigureInfo(interp, setPtr->tkwin, configSpecs, (char *)setPtr, argv[2], 0); } if (ConfigureTabset(interp, setPtr, argc - 2, argv + 2, TK_CONFIG_ARGV_ONLY) != TCL_OK) { return TCL_ERROR; } EventuallyRedraw(setPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * DeleteOp -- * * Deletes tab from the set. Deletes either a range of * tabs or a single node. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int DeleteOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tab *firstPtr, *lastPtr; lastPtr = NULL; if (GetTabByIndex(setPtr, argv[2], &firstPtr, INVALID_FAIL) != TCL_OK) { return TCL_ERROR; } if ((argc == 4) && (GetTabByIndex(setPtr, argv[3], &lastPtr, INVALID_FAIL) != TCL_OK)) { return TCL_ERROR; } if (lastPtr == NULL) { DestroyTab(setPtr, firstPtr); } else { Tab *tabPtr; Blt_ChainLink *linkPtr, *nextLinkPtr; tabPtr = NULL; /* Suppress compiler warning. */ /* Make sure that the first tab is before the last. */ for (linkPtr = firstPtr->linkPtr; linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); if (tabPtr == lastPtr) { break; } } if (tabPtr != lastPtr) { return TCL_OK; } linkPtr = firstPtr->linkPtr; while (linkPtr != NULL) { nextLinkPtr = Blt_ChainNextLink(linkPtr); tabPtr = Blt_ChainGetValue(linkPtr); DestroyTab(setPtr, tabPtr); linkPtr = nextLinkPtr; if (tabPtr == lastPtr) { break; } } } setPtr->flags |= (TABSET_LAYOUT | TABSET_SCROLL); EventuallyRedraw(setPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * FocusOp -- * * Selects the tab to get focus. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int FocusOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tab *tabPtr; if (GetTabByIndex(setPtr, argv[2], &tabPtr, INVALID_FAIL) != TCL_OK) { return TCL_ERROR; } if (tabPtr != NULL) { setPtr->focusPtr = tabPtr; Blt_SetFocusItem(setPtr->bindTable, setPtr->focusPtr, NULL); EventuallyRedraw(setPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * IndexOp -- * * Converts a string representing a tab index. * * Results: * A standard Tcl result. Interp->result will contain the * identifier of each index found. If an index could not be found, * then the serial identifier will be the empty string. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int IndexOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; int argc; char **argv; { Tab *tabPtr; int search; #define SEARCH_NAMES 1 #define SEARCH_INDICES 2 search = SEARCH_INDICES; if (argc == 4) { if (strcmp(argv[2], "-index") == 0) { search = SEARCH_INDICES; } else if (strcmp(argv[2], "-name") == 0) { search = SEARCH_NAMES; } else { Tcl_AppendResult(interp, "bad switch \"", argv[2], "\": should be \"-index\" or \"-name\"", (char *)NULL); return TCL_ERROR; } argv++; } if (search == SEARCH_INDICES) { if (GetTabByIndex(setPtr, argv[2], &tabPtr, INVALID_OK) != TCL_OK) { return TCL_ERROR; } } else { if (GetTabByName(setPtr, argv[2], &tabPtr) != TCL_OK) { return TCL_ERROR; } } if (tabPtr == NULL) { Tcl_SetResult(interp, "", TCL_STATIC); } else { Tcl_SetResult(interp, Blt_Itoa(TabIndex(setPtr, tabPtr)), TCL_VOLATILE); } return TCL_OK; } /* *---------------------------------------------------------------------- * * GetOp -- * * Converts a tab index into the tab identifier. * * Results: * A standard Tcl result. Interp->result will contain the * identifier of each index found. If an index could not be found, * then the serial identifier will be the empty string. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int GetOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tab *tabPtr; if (GetTabByIndex(setPtr, argv[2], &tabPtr, INVALID_OK) != TCL_OK) { return TCL_ERROR; } if (tabPtr == NULL) { Tcl_SetResult(interp, "", TCL_STATIC); } else { Tcl_SetResult(interp, tabPtr->name, TCL_VOLATILE); } return TCL_OK; } /* *---------------------------------------------------------------------- * * InsertOp -- * * Add new entries into a tab set. * * .t insert end label option-value label option-value... * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int InsertOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tab *tabPtr; register int i; char **options; Blt_ChainLink *linkPtr, *beforeLinkPtr; int start, count; char c; c = argv[2][0]; if ((c == 'e') && (strcmp(argv[2], "end") == 0)) { beforeLinkPtr = NULL; } else if (isdigit(UCHAR(c))) { int position; if (Tcl_GetInt(interp, argv[2], &position) != TCL_OK) { return TCL_ERROR; } if (position < 0) { beforeLinkPtr = Blt_ChainFirstLink(setPtr->chainPtr); } else if (position > Blt_ChainGetLength(setPtr->chainPtr)) { beforeLinkPtr = NULL; } else { beforeLinkPtr = Blt_ChainGetNthLink(setPtr->chainPtr, position); } } else { Tab *beforePtr; if (GetTabByIndex(setPtr, argv[2], &beforePtr, INVALID_FAIL) != TCL_OK) { return TCL_ERROR; } beforeLinkPtr = beforePtr->linkPtr; } tabSet = setPtr; setPtr->flags |= (TABSET_LAYOUT | TABSET_SCROLL); EventuallyRedraw(setPtr); for (i = 3; i < argc; /*empty*/ ) { if (TabExists(setPtr, argv[i])) { Tcl_AppendResult(setPtr->interp, "tab \"", argv[i], "\" already exists in \"", Tk_PathName(setPtr->tkwin), "\"", (char *)NULL); return TCL_ERROR; } tabPtr = CreateTab(setPtr, argv[i]); if (tabPtr == NULL) { return TCL_ERROR; } /* * Count the option-value pairs that follow. Count until we * spot one that doesn't look like a configuration option (i.e. * doesn't start with a minus "-"). */ i++; start = i; for ( /*empty*/ ; i < argc; i += 2) { if (argv[i][0] != '-') { break; } } count = i - start; options = argv + start; if (Blt_ConfigureWidgetComponent(interp, setPtr->tkwin, tabPtr->name, "Tab", tabConfigSpecs, count, options, (char *)tabPtr, 0) != TCL_OK) { DestroyTab(setPtr, tabPtr); return TCL_ERROR; } if (ConfigureTab(setPtr, tabPtr) != TCL_OK) { DestroyTab(setPtr, tabPtr); return TCL_ERROR; } linkPtr = Blt_ChainNewLink(); if (beforeLinkPtr == NULL) { Blt_ChainAppendLink(setPtr->chainPtr, linkPtr); } else { Blt_ChainLinkBefore(setPtr->chainPtr, linkPtr, beforeLinkPtr); } tabPtr->linkPtr = linkPtr; Blt_ChainSetValue(linkPtr, tabPtr); } return TCL_OK; } /* * Preprocess the command string for percent substitution. */ static void PercentSubst(setPtr, tabPtr, command, resultPtr) Tabset *setPtr; Tab *tabPtr; char *command; Tcl_DString *resultPtr; { register char *last, *p; /* * Get the full path name of the node, in case we need to * substitute for it. */ Tcl_DStringInit(resultPtr); for (last = p = command; *p != '\0'; p++) { if (*p == '%') { char *string; char buf[3]; if (p > last) { *p = '\0'; Tcl_DStringAppend(resultPtr, last, -1); *p = '%'; } switch (*(p + 1)) { case '%': /* Percent sign */ string = "%"; break; case 'W': /* Widget name */ string = Tk_PathName(setPtr->tkwin); break; case 'i': /* Tab Index */ string = Blt_Itoa(TabIndex(setPtr, tabPtr)); break; case 'n': /* Tab name */ string = tabPtr->name; break; default: if (*(p + 1) == '\0') { p--; } buf[0] = *p, buf[1] = *(p + 1), buf[2] = '\0'; string = buf; break; } Tcl_DStringAppend(resultPtr, string, -1); p++; last = p + 1; } } if (p > last) { *p = '\0'; Tcl_DStringAppend(resultPtr, last, -1); } } /* *---------------------------------------------------------------------- * * InvokeOp -- * * This procedure is called to invoke a selection command. * * .h invoke index * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side Effects: * Configuration information, such as text string, colors, font, * etc. get set; old resources get freed, if there were any. * The widget is redisplayed if needed. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int InvokeOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { Tab *tabPtr; char *command; if (GetTabByIndex(setPtr, argv[2], &tabPtr, INVALID_FAIL) != TCL_OK) { return TCL_ERROR; } if ((tabPtr == NULL) || (tabPtr->state == STATE_DISABLED)) { return TCL_OK; } Tcl_Preserve(tabPtr); command = GETATTR(tabPtr, command); if (command != NULL) { Tcl_DString dString; int result; PercentSubst(setPtr, tabPtr, command, &dString); result = Tcl_GlobalEval(setPtr->interp, Tcl_DStringValue(&dString)); Tcl_DStringFree(&dString); if (result != TCL_OK) { return TCL_ERROR; } } Tcl_Release(tabPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * MoveOp -- * * Moves a tab to a new location. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int MoveOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tab *tabPtr, *linkPtr; int before; if (GetTabByIndex(setPtr, argv[2], &tabPtr, INVALID_FAIL) != TCL_OK) { return TCL_ERROR; } if ((tabPtr == NULL) || (tabPtr->state == STATE_DISABLED)) { return TCL_OK; } if ((argv[3][0] == 'b') && (strcmp(argv[3], "before") == 0)) { before = 1; } else if ((argv[3][0] == 'a') && (strcmp(argv[3], "after") == 0)) { before = 0; } else { Tcl_AppendResult(interp, "bad key word \"", argv[3], "\": should be \"after\" or \"before\"", (char *)NULL); return TCL_ERROR; } if (GetTabByIndex(setPtr, argv[4], &linkPtr, INVALID_FAIL) != TCL_OK) { return TCL_ERROR; } if (tabPtr == linkPtr) { return TCL_OK; } Blt_ChainUnlinkLink(setPtr->chainPtr, tabPtr->linkPtr); if (before) { Blt_ChainLinkBefore(setPtr->chainPtr, tabPtr->linkPtr, linkPtr->linkPtr); } else { Blt_ChainLinkAfter(setPtr->chainPtr, tabPtr->linkPtr, linkPtr->linkPtr); } setPtr->flags |= (TABSET_LAYOUT | TABSET_SCROLL); EventuallyRedraw(setPtr); return TCL_OK; } /*ARGSUSED*/ static int NearestOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { int x, y; /* Screen coordinates of the test point. */ Tab *tabPtr; if ((Tk_GetPixels(interp, setPtr->tkwin, argv[2], &x) != TCL_OK) || (Tk_GetPixels(interp, setPtr->tkwin, argv[3], &y) != TCL_OK)) { return TCL_ERROR; } if (setPtr->nVisible > 0) { tabPtr = PickTab(setPtr, x, y, NULL); if (tabPtr != NULL) { Tcl_SetResult(interp, tabPtr->name, TCL_VOLATILE); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * SelectOp -- * * This procedure is called to selecta tab. * * .h select index * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side Effects: * Configuration information, such as text string, colors, font, * etc. get set; old resources get freed, if there were any. * The widget is redisplayed if needed. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int SelectOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { Tab *tabPtr; if (GetTabByIndex(setPtr, argv[2], &tabPtr, INVALID_OK) != TCL_OK) { return TCL_ERROR; } if ((tabPtr == NULL) || (tabPtr->state == STATE_DISABLED)) { return TCL_OK; } if ((setPtr->selectPtr != NULL) && (setPtr->selectPtr != tabPtr) && (setPtr->selectPtr->tkwin != NULL)) { if (setPtr->selectPtr->container == NULL) { if (Tk_IsMapped(setPtr->selectPtr->tkwin)) { Tk_UnmapWindow(setPtr->selectPtr->tkwin); } } else { /* Redraw now unselected container. */ EventuallyRedrawTearoff(setPtr->selectPtr); } } setPtr->selectPtr = tabPtr; if ((setPtr->nTiers > 1) && (tabPtr->tier != setPtr->startPtr->tier)) { RenumberTiers(setPtr, tabPtr); Blt_PickCurrentItem(setPtr->bindTable); } setPtr->flags |= (TABSET_SCROLL); if (tabPtr->container != NULL) { EventuallyRedrawTearoff(tabPtr); } EventuallyRedraw(setPtr); return TCL_OK; } static int ViewOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; int argc; char **argv; { int width; width = VPORTWIDTH(setPtr); if (argc == 2) { double fract; /* * Note: we are bounding the fractions between 0.0 and 1.0 to * support the "canvas"-style of scrolling. */ fract = (double)setPtr->scrollOffset / setPtr->worldWidth; Tcl_AppendElement(interp, Blt_Dtoa(interp, CLAMP(fract, 0.0, 1.0))); fract = (double)(setPtr->scrollOffset + width) / setPtr->worldWidth; Tcl_AppendElement(interp, Blt_Dtoa(interp, CLAMP(fract, 0.0, 1.0))); return TCL_OK; } if (Blt_GetScrollInfo(interp, argc - 2, argv + 2, &(setPtr->scrollOffset), setPtr->worldWidth, width, setPtr->scrollUnits, BLT_SCROLL_MODE_CANVAS) != TCL_OK) { return TCL_ERROR; } setPtr->flags |= TABSET_SCROLL; EventuallyRedraw(setPtr); return TCL_OK; } static void AdoptWindow(clientData) ClientData clientData; { Tab *tabPtr = clientData; int x, y; Tabset *setPtr = tabPtr->setPtr; x = setPtr->inset + setPtr->inset2 + tabPtr->padLeft; #define TEAR_OFF_TAB_SIZE 5 y = setPtr->inset + setPtr->inset2 + setPtr->yPad + setPtr->outerPad + TEAR_OFF_TAB_SIZE + tabPtr->padTop; Blt_RelinkWindow(tabPtr->tkwin, tabPtr->container, x, y); Tk_MapWindow(tabPtr->tkwin); } static void DestroyTearoff(dataPtr) DestroyData dataPtr; { Tab *tabPtr = (Tab *)dataPtr; if (tabPtr->container != NULL) { Tabset *setPtr; Tk_Window tkwin; setPtr = tabPtr->setPtr; tkwin = tabPtr->container; if (tabPtr->flags & TAB_REDRAW) { Tcl_CancelIdleCall(DisplayTearoff, tabPtr); } Tk_DeleteEventHandler(tkwin, StructureNotifyMask, TearoffEventProc, tabPtr); if (tabPtr->tkwin != NULL) { XRectangle rect; GetWindowRectangle(tabPtr, setPtr->tkwin, FALSE, &rect); Blt_RelinkWindow(tabPtr->tkwin, setPtr->tkwin, rect.x, rect.y); if (tabPtr == setPtr->selectPtr) { ArrangeWindow(tabPtr->tkwin, &rect, TRUE); } else { Tk_UnmapWindow(tabPtr->tkwin); } } Tk_DestroyWindow(tkwin); tabPtr->container = NULL; } } static int CreateTearoff(setPtr, name, tabPtr) Tabset *setPtr; char *name; Tab *tabPtr; { Tk_Window tkwin; int width, height; tkwin = Tk_CreateWindowFromPath(setPtr->interp, setPtr->tkwin, name, (char *)NULL); if (tkwin == NULL) { return TCL_ERROR; } tabPtr->container = tkwin; if (Tk_WindowId(tkwin) == None) { Tk_MakeWindowExist(tkwin); } Tk_SetClass(tkwin, "Tearoff"); Tk_CreateEventHandler(tkwin, (ExposureMask | StructureNotifyMask), TearoffEventProc, tabPtr); if (Tk_WindowId(tabPtr->tkwin) == None) { Tk_MakeWindowExist(tabPtr->tkwin); } width = Tk_Width(tabPtr->tkwin); if (width < 2) { width = (tabPtr->reqWidth > 0) ? tabPtr->reqWidth : Tk_ReqWidth(tabPtr->tkwin); } width += PADDING(tabPtr->padX) + 2 * Tk_Changes(tabPtr->tkwin)->border_width; width += 2 * (setPtr->inset2 + setPtr->inset); #define TEAR_OFF_TAB_SIZE 5 height = Tk_Height(tabPtr->tkwin); if (height < 2) { height = (tabPtr->reqHeight > 0) ? tabPtr->reqHeight : Tk_ReqHeight(tabPtr->tkwin); } height += PADDING(tabPtr->padY) + 2 * Tk_Changes(tabPtr->tkwin)->border_width; height += setPtr->inset + setPtr->inset2 + setPtr->yPad + TEAR_OFF_TAB_SIZE + setPtr->outerPad; Tk_GeometryRequest(tkwin, width, height); Tk_UnmapWindow(tabPtr->tkwin); /* Tk_MoveWindow(tabPtr->tkwin, 0, 0); */ Tcl_SetResult(setPtr->interp, Tk_PathName(tkwin), TCL_VOLATILE); #ifdef WIN32 AdoptWindow(tabPtr); #else Tcl_DoWhenIdle(AdoptWindow, tabPtr); #endif return TCL_OK; } /* *---------------------------------------------------------------------- * * TabCgetOp -- * * .h tab cget index option * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TabCgetOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tab *tabPtr; if (GetTabByName(setPtr, argv[3], &tabPtr) != TCL_OK) { return TCL_ERROR; } tabSet = setPtr; return Tk_ConfigureValue(interp, setPtr->tkwin, tabConfigSpecs, (char *)tabPtr, argv[4], 0); } /* *---------------------------------------------------------------------- * * TabConfigureOp -- * * This procedure is called to process a list of configuration * options database, in order to reconfigure the options for * one or more tabs in the widget. * * .h tab configure index ?index...? ?option value?... * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side Effects: * Configuration information, such as text string, colors, font, * etc. get set; old resources get freed, if there were any. * The widget is redisplayed if needed. * *---------------------------------------------------------------------- */ static int TabConfigureOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; int argc; char **argv; { int nTabs, nOpts, result; char **options; register int i; Tab *tabPtr; /* Figure out where the option value pairs begin */ argc -= 3; argv += 3; for (i = 0; i < argc; i++) { if (argv[i][0] == '-') { break; } if (GetTabByName(setPtr, argv[i], &tabPtr) != TCL_OK) { return TCL_ERROR; /* Can't find node. */ } } nTabs = i; /* Number of tab indices specified */ nOpts = argc - i; /* Number of options specified */ options = argv + i; /* Start of options in argv */ for (i = 0; i < nTabs; i++) { GetTabByName(setPtr, argv[i], &tabPtr); if (argc == 1) { return Tk_ConfigureInfo(interp, setPtr->tkwin, tabConfigSpecs, (char *)tabPtr, (char *)NULL, 0); } else if (argc == 2) { return Tk_ConfigureInfo(interp, setPtr->tkwin, tabConfigSpecs, (char *)tabPtr, argv[2], 0); } tabSet = setPtr; Tcl_Preserve(tabPtr); result = Tk_ConfigureWidget(interp, setPtr->tkwin, tabConfigSpecs, nOpts, options, (char *)tabPtr, TK_CONFIG_ARGV_ONLY); if (result == TCL_OK) { result = ConfigureTab(setPtr, tabPtr); } Tcl_Release(tabPtr); if (result == TCL_ERROR) { return TCL_ERROR; } if (tabPtr->flags & TAB_VISIBLE) { setPtr->flags |= (TABSET_LAYOUT | TABSET_SCROLL); EventuallyRedraw(setPtr); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * TabDockallOp -- * * .h tab dockall * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TabDockallOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; /* Not used. */ { Tab *tabPtr; Blt_ChainLink *linkPtr; for (linkPtr = Blt_ChainFirstLink(setPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); if (tabPtr->container != NULL) { Tcl_EventuallyFree(tabPtr, DestroyTearoff); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * TabPageHeight -- * * .h tab pageheight * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TabPageHeight(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; /* Not used. */ { Tcl_SetResult(interp, Blt_Itoa(VPORTHEIGHT(setPtr)), TCL_VOLATILE); return TCL_OK; } /* *---------------------------------------------------------------------- * * TabPageWidth -- * * .h tab pagewidth * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TabPageWidth(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; /* Not used. */ { Tcl_SetResult(interp, Blt_Itoa(VPORTWIDTH(setPtr)), TCL_VOLATILE); return TCL_OK; } /* *---------------------------------------------------------------------- * * TabNamesOp -- * * .h tab names pattern * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TabNamesOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; /* Not used. */ { Tab *tabPtr; Blt_ChainLink *linkPtr; if (argc == 3) { for (linkPtr = Blt_ChainFirstLink(setPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); Tcl_AppendElement(interp, tabPtr->name); } } else { register int i; for (linkPtr = Blt_ChainFirstLink(setPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); for (i = 3; i < argc; i++) { if (Tcl_StringMatch(tabPtr->name, argv[i])) { Tcl_AppendElement(interp, tabPtr->name); break; } } } } return TCL_OK; } /* *---------------------------------------------------------------------- * * TabTearoffOp -- * * .h tab tearoff index ?title? * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TabTearoffOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tab *tabPtr; int result; Tk_Window tkwin; if (GetTabByIndex(setPtr, argv[3], &tabPtr, INVALID_OK) != TCL_OK) { return TCL_ERROR; } if ((tabPtr == NULL) || (tabPtr->tkwin == NULL) || (tabPtr->state == STATE_DISABLED)) { return TCL_OK; /* No-op */ } if (argc == 4) { Tk_Window parent; parent = (tabPtr->container == NULL) ? setPtr->tkwin : tabPtr->container; Tcl_SetResult(setPtr->interp, Tk_PathName(parent), TCL_VOLATILE); return TCL_OK; } Tcl_Preserve(tabPtr); result = TCL_OK; tkwin = Tk_NameToWindow(interp, argv[4], setPtr->tkwin); Tcl_ResetResult(interp); if (tabPtr->container != NULL) { Tcl_EventuallyFree(tabPtr, DestroyTearoff); } if ((tkwin != setPtr->tkwin) && (tabPtr->container == NULL)) { result = CreateTearoff(setPtr, argv[4], tabPtr); } Tcl_Release(tabPtr); EventuallyRedraw(setPtr); return result; } /* *---------------------------------------------------------------------- * * TabOp -- * * This procedure handles tab operations. * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ static Blt_OpSpec tabOps[] = { {"cget", 2, (Blt_Op)TabCgetOp, 5, 5, "nameOrIndex option",}, {"configure", 2, (Blt_Op)TabConfigureOp, 4, 0, "nameOrIndex ?option value?...",}, {"dockall", 1, (Blt_Op)TabDockallOp, 3, 3, "" }, {"names", 1, (Blt_Op)TabNamesOp, 3, 0, "?pattern...?",}, {"pageheight", 5, (Blt_Op)TabPageHeight, 3, 3, "", }, {"pagewidth", 5, (Blt_Op)TabPageWidth, 3, 3, "", }, {"tearoff", 1, (Blt_Op)TabTearoffOp, 4, 5, "index ?parent?",}, }; static int nTabOps = sizeof(tabOps) / sizeof(Blt_OpSpec); static int TabOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; int argc; char **argv; { Blt_Op proc; int result; proc = Blt_GetOp(interp, nTabOps, tabOps, BLT_OP_ARG2, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (setPtr, interp, argc, argv); return result; } /* *---------------------------------------------------------------------- * * PerforationActivateOp -- * * This procedure is called to activate (highlight) the * perforation. * * .h perforation activate boolean * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int PerforationActivateOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { int bool; if (Tcl_GetBoolean(interp, argv[3], &bool) != TCL_OK) { return TCL_ERROR; } if (bool) { setPtr->flags |= PERFORATION_ACTIVE; } else { setPtr->flags &= ~PERFORATION_ACTIVE; } EventuallyRedraw(setPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * PerforationInvokeOp -- * * This procedure is called to invoke a perforation command. * * .t perforation invoke * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int PerforationInvokeOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { if (setPtr->selectPtr != NULL) { char *cmd; cmd = GETATTR(setPtr->selectPtr, perfCommand); if (cmd != NULL) { Tcl_DString dString; int result; PercentSubst(setPtr, setPtr->selectPtr, cmd, &dString); Tcl_Preserve(setPtr); result = Tcl_GlobalEval(interp, Tcl_DStringValue(&dString)); Tcl_Release(setPtr); Tcl_DStringFree(&dString); if (result != TCL_OK) { return TCL_ERROR; } } } return TCL_OK; } /* *---------------------------------------------------------------------- * * PerforationOp -- * * This procedure handles tab operations. * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ static Blt_OpSpec perforationOps[] = { {"activate", 1, (Blt_Op)PerforationActivateOp, 4, 4, "boolean" }, {"invoke", 1, (Blt_Op)PerforationInvokeOp, 3, 3, "",}, }; static int nPerforationOps = sizeof(perforationOps) / sizeof(Blt_OpSpec); static int PerforationOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; int argc; char **argv; { Blt_Op proc; int result; proc = Blt_GetOp(interp, nPerforationOps, perforationOps, BLT_OP_ARG2, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (setPtr, interp, argc, argv); return result; } /* *---------------------------------------------------------------------- * * ScanOp -- * * Implements the quick scan. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ScanOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { int x, y; char c; unsigned int length; int oper; #define SCAN_MARK 1 #define SCAN_DRAGTO 2 c = argv[2][0]; length = strlen(argv[2]); if ((c == 'm') && (strncmp(argv[2], "mark", length) == 0)) { oper = SCAN_MARK; } else if ((c == 'd') && (strncmp(argv[2], "dragto", length) == 0)) { oper = SCAN_DRAGTO; } else { Tcl_AppendResult(interp, "bad scan operation \"", argv[2], "\": should be either \"mark\" or \"dragto\"", (char *)NULL); return TCL_ERROR; } if ((Tk_GetPixels(interp, setPtr->tkwin, argv[3], &x) != TCL_OK) || (Tk_GetPixels(interp, setPtr->tkwin, argv[4], &y) != TCL_OK)) { return TCL_ERROR; } if (oper == SCAN_MARK) { if (setPtr->side & SIDE_VERTICAL) { setPtr->scanAnchor = y; } else { setPtr->scanAnchor = x; } setPtr->scanOffset = setPtr->scrollOffset; } else { int offset, delta; if (setPtr->side & SIDE_VERTICAL) { delta = setPtr->scanAnchor - y; } else { delta = setPtr->scanAnchor - x; } offset = setPtr->scanOffset + (10 * delta); offset = Blt_AdjustViewport(offset, setPtr->worldWidth, VPORTWIDTH(setPtr), setPtr->scrollUnits, BLT_SCROLL_MODE_CANVAS); setPtr->scrollOffset = offset; setPtr->flags |= TABSET_SCROLL; EventuallyRedraw(setPtr); } return TCL_OK; } /*ARGSUSED*/ static int SeeOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { Tab *tabPtr; if (GetTabByIndex(setPtr, argv[2], &tabPtr, INVALID_OK) != TCL_OK) { return TCL_ERROR; } if (tabPtr != NULL) { int left, right, width; width = VPORTWIDTH(setPtr); left = setPtr->scrollOffset + setPtr->xSelectPad; right = setPtr->scrollOffset + width - setPtr->xSelectPad; /* If the tab is partially obscured, scroll so that it's * entirely in view. */ if (tabPtr->worldX < left) { setPtr->scrollOffset = tabPtr->worldX - TAB_SCROLL_OFFSET; } else if ((tabPtr->worldX + tabPtr->worldWidth) >= right) { Blt_ChainLink *linkPtr; setPtr->scrollOffset = tabPtr->worldX + tabPtr->worldWidth - (width - 2 * setPtr->xSelectPad); linkPtr = Blt_ChainNextLink(tabPtr->linkPtr); if (linkPtr != NULL) { Tab *nextPtr; nextPtr = Blt_ChainGetValue(linkPtr); if (nextPtr->tier == tabPtr->tier) { setPtr->scrollOffset += TAB_SCROLL_OFFSET; } } } setPtr->flags |= TABSET_SCROLL; EventuallyRedraw(setPtr); } return TCL_OK; } /*ARGSUSED*/ static int SizeOp(setPtr, interp, argc, argv) Tabset *setPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; /* Not used. */ { Tcl_SetResult(interp, Blt_Itoa(Blt_ChainGetLength(setPtr->chainPtr)), TCL_VOLATILE); return TCL_OK; } static int CountTabs(setPtr) Tabset *setPtr; { int count; int width, height; Blt_ChainLink *linkPtr; register Tab *tabPtr; register int pageWidth, pageHeight; int labelWidth, labelHeight; int tabWidth, tabHeight; pageWidth = pageHeight = 0; count = 0; labelWidth = labelHeight = 0; /* * Pass 1: Figure out the maximum area needed for a label and a * page. Both the label and page dimensions are adjusted * for orientation. In addition, reset the visibility * flags and reorder the tabs. */ for (linkPtr = Blt_ChainFirstLink(setPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); /* Reset visibility flag and order of tabs. */ tabPtr->flags &= ~TAB_VISIBLE; count++; if (tabPtr->tkwin != NULL) { width = GetReqWidth(tabPtr); if (pageWidth < width) { pageWidth = width; } height = GetReqHeight(tabPtr); if (pageHeight < height) { pageHeight = height; } } if (labelWidth < tabPtr->labelWidth) { labelWidth = tabPtr->labelWidth; } if (labelHeight < tabPtr->labelHeight) { labelHeight = tabPtr->labelHeight; } } setPtr->overlap = 0; /* * Pass 2: Set the individual sizes of each tab. This is different * for constant and variable width tabs. Add the extra space * needed for slanted tabs, now that we know maximum tab * height. */ if (setPtr->defTabStyle.constWidth) { int slant; tabWidth = 2 * setPtr->inset2; tabHeight = setPtr->inset2 /* + 4 */; if (setPtr->side & SIDE_VERTICAL) { tabWidth += labelHeight; tabHeight += labelWidth; slant = labelWidth; } else { tabWidth += labelWidth; tabHeight += labelHeight; slant = labelHeight; } if (setPtr->slant & SLANT_LEFT) { tabWidth += slant; setPtr->overlap += tabHeight / 2; } if (setPtr->slant & SLANT_RIGHT) { tabWidth += slant; setPtr->overlap += tabHeight / 2; } for (linkPtr = Blt_ChainFirstLink(setPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); tabPtr->worldWidth = tabWidth; tabPtr->worldHeight = tabHeight; } } else { int slant; tabWidth = tabHeight = 0; for (linkPtr = Blt_ChainFirstLink(setPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); width = 2 * setPtr->inset2; height = setPtr->inset2 /* + 4 */; if (setPtr->side & SIDE_VERTICAL) { width += tabPtr->labelHeight; height += labelWidth; slant = labelWidth; } else { width += tabPtr->labelWidth; height += labelHeight; slant = labelHeight; } width += (setPtr->slant & SLANT_LEFT) ? slant : setPtr->corner; width += (setPtr->slant & SLANT_RIGHT) ? slant : setPtr->corner; tabPtr->worldWidth = width; /* + 2 * (setPtr->corner + setPtr->xSelectPad) */ ; tabPtr->worldHeight = height; if (tabWidth < width) { tabWidth = width; } if (tabHeight < height) { tabHeight = height; } } if (setPtr->slant & SLANT_LEFT) { setPtr->overlap += tabHeight / 2; } if (setPtr->slant & SLANT_RIGHT) { setPtr->overlap += tabHeight / 2; } } setPtr->tabWidth = tabWidth; setPtr->tabHeight = tabHeight; /* * Let the user override any page dimension. */ setPtr->pageWidth = pageWidth; setPtr->pageHeight = pageHeight; if (setPtr->reqPageWidth > 0) { setPtr->pageWidth = setPtr->reqPageWidth; } if (setPtr->reqPageHeight > 0) { setPtr->pageHeight = setPtr->reqPageHeight; } return count; } static void WidenTabs(setPtr, startPtr, nTabs, adjustment) Tabset *setPtr; Tab *startPtr; int nTabs; int adjustment; { register Tab *tabPtr; register int i; int ration; Blt_ChainLink *linkPtr; int x; x = startPtr->tier; while (adjustment > 0) { ration = adjustment / nTabs; if (ration == 0) { ration = 1; } linkPtr = startPtr->linkPtr; for (i = 0; (linkPtr != NULL) && (i < nTabs) && (adjustment > 0); i++) { tabPtr = Blt_ChainGetValue(linkPtr); adjustment -= ration; tabPtr->worldWidth += ration; assert(x == tabPtr->tier); linkPtr = Blt_ChainNextLink(linkPtr); } } /* * Go back and reset the world X-coordinates of the tabs, * now that their widths have changed. */ x = 0; linkPtr = startPtr->linkPtr; for (i = 0; (i < nTabs) && (linkPtr != NULL); i++) { tabPtr = Blt_ChainGetValue(linkPtr); tabPtr->worldX = x; x += tabPtr->worldWidth + setPtr->gap - setPtr->overlap; linkPtr = Blt_ChainNextLink(linkPtr); } } static void AdjustTabSizes(setPtr, nTabs) Tabset *setPtr; int nTabs; { int tabsPerTier; int total, count, extra; Tab *startPtr, *nextPtr; Blt_ChainLink *linkPtr; register Tab *tabPtr; int x, maxWidth; tabsPerTier = (nTabs + (setPtr->nTiers - 1)) / setPtr->nTiers; x = 0; maxWidth = 0; if (setPtr->defTabStyle.constWidth) { register int i; linkPtr = Blt_ChainFirstLink(setPtr->chainPtr); count = 1; while (linkPtr != NULL) { for (i = 0; i < tabsPerTier; i++) { tabPtr = Blt_ChainGetValue(linkPtr); tabPtr->tier = count; tabPtr->worldX = x; x += tabPtr->worldWidth + setPtr->gap - setPtr->overlap; linkPtr = Blt_ChainNextLink(linkPtr); if (x > maxWidth) { maxWidth = x; } if (linkPtr == NULL) { goto done; } } count++; x = 0; } } done: /* Add to tab widths to fill out row. */ if (((nTabs % tabsPerTier) != 0) && (setPtr->defTabStyle.constWidth)) { return; } startPtr = NULL; count = total = 0; for (linkPtr = Blt_ChainFirstLink(setPtr->chainPtr); linkPtr != NULL; /*empty*/ ) { tabPtr = Blt_ChainGetValue(linkPtr); if (startPtr == NULL) { startPtr = tabPtr; } count++; total += tabPtr->worldWidth + setPtr->gap - setPtr->overlap; linkPtr = Blt_ChainNextLink(linkPtr); if (linkPtr != NULL) { nextPtr = Blt_ChainGetValue(linkPtr); if (tabPtr->tier == nextPtr->tier) { continue; } } total += setPtr->overlap; extra = setPtr->worldWidth - total; assert(count > 0); if (extra > 0) { WidenTabs(setPtr, startPtr, count, extra); } count = total = 0; startPtr = NULL; } } /* * * tabWidth = textWidth + gap + (2 * (pad + outerBW)); * * tabHeight = textHeight + 2 * (pad + outerBW) + topMargin; * */ static void ComputeLayout(setPtr) Tabset *setPtr; { int width; Blt_ChainLink *linkPtr; Tab *tabPtr; int x, extra; int nTiers, nTabs; setPtr->nTiers = 0; setPtr->pageTop = 0; setPtr->worldWidth = 1; setPtr->yPad = 0; nTabs = CountTabs(setPtr); if (nTabs == 0) { return; } /* Reset the pointers to the selected and starting tab. */ if (setPtr->selectPtr == NULL) { linkPtr = Blt_ChainFirstLink(setPtr->chainPtr); if (linkPtr != NULL) { setPtr->selectPtr = Blt_ChainGetValue(linkPtr); } } if (setPtr->startPtr == NULL) { setPtr->startPtr = setPtr->selectPtr; } if (setPtr->focusPtr == NULL) { setPtr->focusPtr = setPtr->selectPtr; Blt_SetFocusItem(setPtr->bindTable, setPtr->focusPtr, NULL); } if (setPtr->side & SIDE_VERTICAL) { width = Tk_Height(setPtr->tkwin) - 2 * (setPtr->corner + setPtr->xSelectPad); } else { width = Tk_Width(setPtr->tkwin) - (2 * setPtr->inset) - setPtr->xSelectPad - setPtr->corner; } setPtr->flags |= TABSET_STATIC; if (setPtr->reqTiers > 1) { int total, maxWidth; /* Static multiple tier mode. */ /* Sum tab widths and determine the number of tiers needed. */ nTiers = 1; total = x = 0; for (linkPtr = Blt_ChainFirstLink(setPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); if ((x + tabPtr->worldWidth) > width) { nTiers++; x = 0; } tabPtr->worldX = x; tabPtr->tier = nTiers; extra = tabPtr->worldWidth + setPtr->gap - setPtr->overlap; total += extra, x += extra; } maxWidth = width; if (nTiers > setPtr->reqTiers) { /* * The tabs do not fit into the requested number of tiers. * Go into scrolling mode. */ width = ((total + setPtr->tabWidth) / setPtr->reqTiers); x = 0; nTiers = 1; for (linkPtr = Blt_ChainFirstLink(setPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); tabPtr->tier = nTiers; /* * Keep adding tabs to a tier until we overfill it. */ tabPtr->worldX = x; x += tabPtr->worldWidth + setPtr->gap - setPtr->overlap; if (x > width) { nTiers++; if (x > maxWidth) { maxWidth = x; } x = 0; } } setPtr->flags &= ~TABSET_STATIC; } setPtr->worldWidth = maxWidth; setPtr->nTiers = nTiers; if (nTiers > 1) { AdjustTabSizes(setPtr, nTabs); } if (setPtr->flags & TABSET_STATIC) { setPtr->worldWidth = VPORTWIDTH(setPtr); } else { /* Do you add an offset ? */ setPtr->worldWidth += (setPtr->xSelectPad + setPtr->corner); } setPtr->worldWidth += setPtr->overlap; if (setPtr->selectPtr != NULL) { RenumberTiers(setPtr, setPtr->selectPtr); } } else { /* * Scrollable single tier mode. */ nTiers = 1; x = 0; for (linkPtr = Blt_ChainFirstLink(setPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); tabPtr->tier = nTiers; tabPtr->worldX = x; tabPtr->worldY = 0; x += tabPtr->worldWidth + setPtr->gap - setPtr->overlap; } setPtr->worldWidth = x + setPtr->corner - setPtr->gap + setPtr->xSelectPad + setPtr->overlap; setPtr->flags &= ~TABSET_STATIC; } if (nTiers == 1) { setPtr->yPad = setPtr->ySelectPad; } setPtr->nTiers = nTiers; setPtr->pageTop = setPtr->inset + setPtr->yPad /* + 4 */ + (setPtr->nTiers * setPtr->tabHeight) + setPtr->inset2; if (setPtr->side & SIDE_VERTICAL) { for (linkPtr = Blt_ChainFirstLink(setPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); tabPtr->screenWidth = (short int)setPtr->tabHeight; tabPtr->screenHeight = (short int)tabPtr->worldWidth; } } else { for (linkPtr = Blt_ChainFirstLink(setPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); tabPtr->screenWidth = (short int)tabPtr->worldWidth; tabPtr->screenHeight = (short int)setPtr->tabHeight; } } } static void ComputeVisibleTabs(setPtr) Tabset *setPtr; { int nVisibleTabs; register Tab *tabPtr; Blt_ChainLink *linkPtr; setPtr->nVisible = 0; if (Blt_ChainGetLength(setPtr->chainPtr) == 0) { return; } nVisibleTabs = 0; if (setPtr->flags & TABSET_STATIC) { /* Static multiple tier mode. */ for (linkPtr = Blt_ChainFirstLink(setPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); tabPtr->flags |= TAB_VISIBLE; nVisibleTabs++; } } else { int width, offset; /* * Scrollable (single or multiple) tier mode. */ offset = setPtr->scrollOffset - (setPtr->outerPad + setPtr->xSelectPad); width = VPORTWIDTH(setPtr) + setPtr->scrollOffset + 2 * setPtr->outerPad; for (linkPtr = Blt_ChainFirstLink(setPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); if ((tabPtr->worldX >= width) || ((tabPtr->worldX + tabPtr->worldWidth) < offset)) { tabPtr->flags &= ~TAB_VISIBLE; } else { tabPtr->flags |= TAB_VISIBLE; nVisibleTabs++; } } } for (linkPtr = Blt_ChainFirstLink(setPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tabPtr = Blt_ChainGetValue(linkPtr); tabPtr->screenX = tabPtr->screenY = -1000; if (tabPtr->flags & TAB_VISIBLE) { WorldToScreen(setPtr, tabPtr->worldX, tabPtr->worldY, &(tabPtr->screenX), &(tabPtr->screenY)); switch (setPtr->side) { case SIDE_RIGHT: tabPtr->screenX -= setPtr->tabHeight; break; case SIDE_BOTTOM: tabPtr->screenY -= setPtr->tabHeight; break; } } } setPtr->nVisible = nVisibleTabs; Blt_PickCurrentItem(setPtr->bindTable); } static void Draw3DFolder(setPtr, tabPtr, drawable, side, pointArr, nPoints) Tabset *setPtr; Tab *tabPtr; Drawable drawable; int side; XPoint pointArr[]; int nPoints; { GC gc; int relief, borderWidth; Tk_3DBorder border; if (tabPtr == setPtr->selectPtr) { border = GETATTR(tabPtr, selBorder); } else { border = tabPtr->border; if (border == NULL) { border = setPtr->defTabStyle.border; } } relief = setPtr->defTabStyle.relief; if ((side == SIDE_RIGHT) || (side == SIDE_TOP)) { borderWidth = -setPtr->defTabStyle.borderWidth; if (relief == TK_RELIEF_SUNKEN) { relief = TK_RELIEF_RAISED; } else if (relief == TK_RELIEF_RAISED) { relief = TK_RELIEF_SUNKEN; } } else { borderWidth = setPtr->defTabStyle.borderWidth; } /* Draw the outline of the folder. */ gc = Tk_GCForColor(setPtr->shadowColor, drawable); XDrawLines(setPtr->display, drawable, gc, pointArr, nPoints, CoordModeOrigin); /* And the folder itself. */ if (tabPtr->tile != NULL) { Blt_TilePolygon(setPtr->tkwin, drawable, tabPtr->tile, pointArr, nPoints); Tk_Draw3DPolygon(setPtr->tkwin, drawable, border, pointArr, nPoints, borderWidth, relief); } else { Tk_Fill3DPolygon(setPtr->tkwin, drawable, border, pointArr, nPoints, borderWidth, relief); } } /* * x,y * |1|2|3| 4 |3|2|1| * * 1. tab border width * 2. corner offset * 3. label pad * 4. label width * * */ static void DrawLabel(setPtr, tabPtr, drawable) Tabset *setPtr; Tab *tabPtr; Drawable drawable; { int x, y, dx, dy; int tx, ty, ix, iy; int imgWidth, imgHeight; int active, selected; XColor *fgColor, *bgColor; Tk_3DBorder border; GC gc; if (!(tabPtr->flags & TAB_VISIBLE)) { return; } x = tabPtr->screenX; y = tabPtr->screenY; active = (setPtr->activePtr == tabPtr); selected = (setPtr->selectPtr == tabPtr); fgColor = GETATTR(tabPtr, textColor); border = GETATTR(tabPtr, border); if (selected) { border = GETATTR(tabPtr, selBorder); } bgColor = Tk_3DBorderColor(border); if (active) { Tk_3DBorder activeBorder; activeBorder = GETATTR(tabPtr, activeBorder); bgColor = Tk_3DBorderColor(activeBorder); } dx = (tabPtr->screenWidth - tabPtr->labelWidth) / 2; dy = (tabPtr->screenHeight - tabPtr->labelHeight) / 2; /* * The label position is computed with screen coordinates. This * is because both text and image components are oriented in * screen coordinate space, and not according to the orientation * of the tabs themselves. That's why we have to consider the * side when correcting for left/right slants. */ switch (setPtr->side) { case SIDE_TOP: case SIDE_BOTTOM: if (setPtr->slant == SLANT_LEFT) { x += setPtr->overlap; } else if (setPtr->slant == SLANT_RIGHT) { x -= setPtr->overlap; } break; case SIDE_LEFT: case SIDE_RIGHT: if (setPtr->slant == SLANT_LEFT) { y += setPtr->overlap; } else if (setPtr->slant == SLANT_RIGHT) { y -= setPtr->overlap; } break; } /* * Draw the active or normal background color over the entire * label area. This includes both the tab's text and image. * The rectangle should be 2 pixels wider/taller than this * area. So if the label consists of just an image, we get an * halo around the image when the tab is active. */ gc = Tk_GCForColor(bgColor, drawable); XFillRectangle(setPtr->display, drawable, gc, x + dx, y + dy, tabPtr->labelWidth, tabPtr->labelHeight); if ((setPtr->flags & TABSET_FOCUS) && (setPtr->focusPtr == tabPtr)) { XDrawRectangle(setPtr->display, drawable, setPtr->defTabStyle.activeGC, x + dx, y + dy, tabPtr->labelWidth - 1, tabPtr->labelHeight - 1); } tx = ty = ix = iy = 0; /* Suppress compiler warning. */ imgWidth = imgHeight = 0; if (tabPtr->image != NULL) { imgWidth = ImageWidth(tabPtr->image); imgHeight = ImageHeight(tabPtr->image); } switch (setPtr->defTabStyle.textSide) { case SIDE_LEFT: tx = x + dx + tabPtr->iPadX.side1; ty = y + (tabPtr->screenHeight - tabPtr->textHeight) / 2; ix = tx + tabPtr->textWidth + IMAGE_PAD; iy = y + (tabPtr->screenHeight - imgHeight) / 2; break; case SIDE_RIGHT: ix = x + dx + tabPtr->iPadX.side1 + IMAGE_PAD; iy = y + (tabPtr->screenHeight - imgHeight) / 2; tx = ix + imgWidth; ty = y + (tabPtr->screenHeight - tabPtr->textHeight) / 2; break; case SIDE_BOTTOM: iy = y + dy + tabPtr->iPadY.side1 + IMAGE_PAD; ix = x + (tabPtr->screenWidth - imgWidth) / 2; ty = iy + imgHeight; tx = x + (tabPtr->screenWidth - tabPtr->textWidth) / 2; break; case SIDE_TOP: tx = x + (tabPtr->screenWidth - tabPtr->textWidth) / 2; ty = y + dy + tabPtr->iPadY.side1 + IMAGE_PAD; ix = x + (tabPtr->screenWidth - imgWidth) / 2; iy = ty + tabPtr->textHeight; break; } if (tabPtr->image != NULL) { Tk_RedrawImage(ImageBits(tabPtr->image), 0, 0, imgWidth, imgHeight, drawable, ix, iy); } if (tabPtr->text != NULL) { TextStyle ts; XColor *activeColor; activeColor = fgColor; if (selected) { activeColor = GETATTR(tabPtr, selColor); } else if (active) { activeColor = GETATTR(tabPtr, activeFgColor); } Blt_SetDrawTextStyle(&ts, GETATTR(tabPtr, font), tabPtr->textGC, fgColor, activeColor, tabPtr->shadow.color, setPtr->defTabStyle.rotate, TK_ANCHOR_NW, TK_JUSTIFY_LEFT, 0, tabPtr->shadow.offset); ts.state = tabPtr->state; ts.border = border; ts.padX.side1 = ts.padX.side2 = 2; if ((selected) || (active)) { ts.state |= STATE_ACTIVE; } Blt_DrawText(setPtr->tkwin, drawable, tabPtr->text, &ts, tx, ty); } } static void DrawPerforation(setPtr, tabPtr, drawable) Tabset *setPtr; Tab *tabPtr; Drawable drawable; { XPoint pointArr[2]; int x, y; int segmentWidth, max; Tk_3DBorder border, perfBorder; if ((tabPtr->container != NULL) || (tabPtr->tkwin == NULL)) { return; } WorldToScreen(setPtr, tabPtr->worldX + 2, tabPtr->worldY + tabPtr->worldHeight + 2, &x, &y); border = GETATTR(tabPtr, selBorder); segmentWidth = 3; if (setPtr->flags & PERFORATION_ACTIVE) { perfBorder = GETATTR(tabPtr, activeBorder); } else { perfBorder = GETATTR(tabPtr, selBorder); } if (setPtr->side & SIDE_HORIZONTAL) { pointArr[0].x = x; pointArr[0].y = pointArr[1].y = y; max = tabPtr->screenX + tabPtr->screenWidth - 2; Blt_Fill3DRectangle(setPtr->tkwin, drawable, perfBorder, x - 2, y - 4, tabPtr->screenWidth, 8, 0, TK_RELIEF_FLAT); while (pointArr[0].x < max) { pointArr[1].x = pointArr[0].x + segmentWidth; if (pointArr[1].x > max) { pointArr[1].x = max; } Tk_Draw3DPolygon(setPtr->tkwin, drawable, border, pointArr, 2, 1, TK_RELIEF_RAISED); pointArr[0].x += 2 * segmentWidth; } } else { pointArr[0].x = pointArr[1].x = x; pointArr[0].y = y; max = tabPtr->screenY + tabPtr->screenHeight - 2; Blt_Fill3DRectangle(setPtr->tkwin, drawable, perfBorder, x - 4, y - 2, 8, tabPtr->screenHeight, 0, TK_RELIEF_FLAT); while (pointArr[0].y < max) { pointArr[1].y = pointArr[0].y + segmentWidth; if (pointArr[1].y > max) { pointArr[1].y = max; } Tk_Draw3DPolygon(setPtr->tkwin, drawable, border, pointArr, 2, 1, TK_RELIEF_RAISED); pointArr[0].y += 2 * segmentWidth; } } } #define NextPoint(px, py) \ pointPtr->x = (px), pointPtr->y = (py), pointPtr++, nPoints++ #define EndPoint(px, py) \ pointPtr->x = (px), pointPtr->y = (py), nPoints++ #define BottomLeft(px, py) \ NextPoint((px) + setPtr->corner, (py)), \ NextPoint((px), (py) - setPtr->corner) #define TopLeft(px, py) \ NextPoint((px), (py) + setPtr->corner), \ NextPoint((px) + setPtr->corner, (py)) #define TopRight(px, py) \ NextPoint((px) - setPtr->corner, (py)), \ NextPoint((px), (py) + setPtr->corner) #define BottomRight(px, py) \ NextPoint((px), (py) - setPtr->corner), \ NextPoint((px) - setPtr->corner, (py)) /* * From the left edge: * * |a|b|c|d|e| f |d|e|g|h| i |h|g|e|d|f| j |e|d|c|b|a| * * a. highlight ring * b. tabset 3D border * c. outer gap * d. page border * e. page corner * f. gap + select pad * g. label pad x (worldX) * h. internal pad x * i. label width * j. rest of page width * * worldX, worldY * | * | * * 4+ . . +5 * 3+ +6 * . . * . . * 1+. . .2+ +7 . . . .+8 * 0+ +9 * . . * . . *13+ +10 * 12+-------------------------+11 * */ static void DrawFolder(setPtr, tabPtr, drawable) Tabset *setPtr; Tab *tabPtr; Drawable drawable; { XPoint pointArr[16]; XPoint *pointPtr; int width, height; int left, bottom, right, top, yBot, yTop; int x, y; register int i; int nPoints; width = VPORTWIDTH(setPtr); height = VPORTHEIGHT(setPtr); x = tabPtr->worldX; y = tabPtr->worldY; nPoints = 0; pointPtr = pointArr; /* Remember these are all world coordinates. */ /* * x Left side of tab. * y Top of tab. * yTop Top of folder. * yBot Bottom of the tab. * left Left side of the folder. * right Right side of the folder. * top Top of folder. * bottom Bottom of folder. */ left = setPtr->scrollOffset - setPtr->xSelectPad; right = left + width; yTop = y + tabPtr->worldHeight; yBot = setPtr->pageTop - (setPtr->inset + setPtr->yPad); top = yBot - setPtr->inset2 /* - 4 */; if (setPtr->pageHeight == 0) { bottom = yBot + 2 * setPtr->corner; } else { bottom = height - setPtr->yPad - 1; } if (tabPtr != setPtr->selectPtr) { /* * Case 1: Unselected tab * * * 3+ . . +4 * 2+ +5 * . . * 1+ +6 * 0+ . . +7 * */ if (setPtr->slant & SLANT_LEFT) { NextPoint(x, yBot); NextPoint(x, yTop); NextPoint(x + setPtr->tabHeight, y); } else { BottomLeft(x, yBot); TopLeft(x, y); } x += tabPtr->worldWidth; if (setPtr->slant & SLANT_RIGHT) { NextPoint(x - setPtr->tabHeight, y); NextPoint(x, yTop); NextPoint(x, yBot); } else { TopRight(x, y); BottomRight(x, yBot); } } else if (!(tabPtr->flags & TAB_VISIBLE)) { /* * Case 2: Selected tab not visible in viewport. Draw folder only. * * * 3+ . . +4 * 2+ +5 * . . * 1+ +6 * 0+------+7 * */ TopLeft(left, top); TopRight(right, top); BottomRight(right, bottom); BottomLeft(left, bottom); } else { int flags; int tabWidth; x -= setPtr->xSelectPad; y -= setPtr->yPad; tabWidth = tabPtr->worldWidth + 2 * setPtr->xSelectPad; #define CLIP_NONE 0 #define CLIP_LEFT (1<<0) #define CLIP_RIGHT (1<<1) flags = 0; if (x < left) { flags |= CLIP_LEFT; } if ((x + tabWidth) > right) { flags |= CLIP_RIGHT; } switch (flags) { case CLIP_NONE: /* * worldX, worldY * | * * 4+ . . +5 * 3+ +6 * . . * . . * 1+. . .2+ +7 . . . .+8 * 0+ +9 * . . * . . *13+ +10 * 12+-------------------------+11 */ if (x < (left + setPtr->corner)) { NextPoint(left, top); } else { TopLeft(left, top); } if (setPtr->slant & SLANT_LEFT) { NextPoint(x, yTop); NextPoint(x + setPtr->tabHeight + setPtr->yPad, y); } else { NextPoint(x, top); TopLeft(x, y); } x += tabWidth; if (setPtr->slant & SLANT_RIGHT) { NextPoint(x - setPtr->tabHeight - setPtr->yPad, y); NextPoint(x, yTop); } else { TopRight(x, y); NextPoint(x, top); } if (x > (right - setPtr->corner)) { NextPoint(right, top + setPtr->corner); } else { TopRight(right, top); } BottomRight(right, bottom); BottomLeft(left, bottom); break; case CLIP_LEFT: /* * worldX, worldY * | * * 4+ . . +5 * 3+ +6 * . . * . . * 2+ +7 . . . .+8 * 1+ . . . +0 +9 * . . * . . * 13+ +10 * 12+--------+11 */ NextPoint(left, yBot); if (setPtr->slant & SLANT_LEFT) { NextPoint(x, yBot); NextPoint(x, yTop); NextPoint(x + setPtr->tabHeight + setPtr->yPad, y); } else { BottomLeft(x, yBot); TopLeft(x, y); } x += tabWidth; if (setPtr->slant & SLANT_RIGHT) { NextPoint(x - setPtr->tabHeight - setPtr->yPad, y); NextPoint(x, yTop); NextPoint(x, top); } else { TopRight(x, y); NextPoint(x, top); } if (x > (right - setPtr->corner)) { NextPoint(right, top + setPtr->corner); } else { TopRight(right, top); } /* TopRight(right, top); */ BottomRight(right, bottom); BottomLeft(left, bottom); break; case CLIP_RIGHT: /* * worldX, worldY * | * * 9+ . . +10 * 8+ +11 * . . * . . * 6+ . . . .7+ +12 * 5+ 0+ . . . +13 * . . * . . * 4+ +1 * 3+-------+2 */ NextPoint(right, yBot); BottomRight(right, bottom); BottomLeft(left, bottom); /* TopLeft(left, top); */ if (x < (left + setPtr->corner)) { NextPoint(left, top); } else { TopLeft(left, top); } NextPoint(x, top); if (setPtr->slant & SLANT_LEFT) { NextPoint(x, yTop); NextPoint(x + setPtr->tabHeight + setPtr->yPad, y); } else { TopLeft(x, y); } x += tabWidth; if (setPtr->slant & SLANT_RIGHT) { NextPoint(x - setPtr->tabHeight - setPtr->yPad, y); NextPoint(x, yTop); NextPoint(x, yBot); } else { TopRight(x, y); BottomRight(x, yBot); } break; case (CLIP_LEFT | CLIP_RIGHT): /* * worldX, worldY * | * * 4+ . . . . . . . . +5 * 3+ +6 * . . * . . * 1+ +7 * 2+ 0+ +9 .+8 * . . * . . * 13+ +10 * 12+-------+11 */ NextPoint(left, yBot); if (setPtr->slant & SLANT_LEFT) { NextPoint(x, yBot); NextPoint(x, yTop); NextPoint(x + setPtr->tabHeight + setPtr->yPad, y); } else { BottomLeft(x, yBot); TopLeft(x, y); } x += tabPtr->worldWidth; if (setPtr->slant & SLANT_RIGHT) { NextPoint(x - setPtr->tabHeight - setPtr->yPad, y); NextPoint(x, yTop); NextPoint(x, yBot); } else { TopRight(x, y); BottomRight(x, yBot); } NextPoint(right, yBot); BottomRight(right, bottom); BottomLeft(left, bottom); break; } } EndPoint(pointArr[0].x, pointArr[0].y); for (i = 0; i < nPoints; i++) { WorldToScreen(setPtr, pointArr[i].x, pointArr[i].y, &x, &y); pointArr[i].x = x; pointArr[i].y = y; } Draw3DFolder(setPtr, tabPtr, drawable, setPtr->side, pointArr, nPoints); DrawLabel(setPtr, tabPtr, drawable); if (tabPtr->container != NULL) { XRectangle rect; /* Draw a rectangle covering the spot representing the window */ GetWindowRectangle(tabPtr, setPtr->tkwin, FALSE, &rect); XFillRectangles(setPtr->display, drawable, tabPtr->backGC, &rect, 1); } } static void DrawOuterBorders(setPtr, drawable) Tabset *setPtr; Drawable drawable; { /* * Draw 3D border just inside of the focus highlight ring. We * draw the border even if the relief is flat so that any tabs * that hang over the edge will be clipped. */ if (setPtr->borderWidth > 0) { Blt_Draw3DRectangle(setPtr->tkwin, drawable, setPtr->border, setPtr->highlightWidth, setPtr->highlightWidth, Tk_Width(setPtr->tkwin) - 2 * setPtr->highlightWidth, Tk_Height(setPtr->tkwin) - 2 * setPtr->highlightWidth, setPtr->borderWidth, setPtr->relief); } /* Draw focus highlight ring. */ if (setPtr->highlightWidth > 0) { XColor *color; GC gc; color = (setPtr->flags & TABSET_FOCUS) ? setPtr->highlightColor : setPtr->highlightBgColor; gc = Tk_GCForColor(color, drawable); Tk_DrawFocusHighlight(setPtr->tkwin, gc, setPtr->highlightWidth, drawable); } } /* * ---------------------------------------------------------------------- * * DisplayTabset -- * * This procedure is invoked to display the widget. * * Recomputes the layout of the widget if necessary. This is * necessary if the world coordinate system has changed. * Sets the vertical and horizontal scrollbars. This is done * here since the window width and height are needed for the * scrollbar calculations. * * Results: * None. * * Side effects: * The widget is redisplayed. * * ---------------------------------------------------------------------- */ static void DisplayTabset(clientData) ClientData clientData; /* Information about widget. */ { Tabset *setPtr = clientData; Pixmap drawable; int width, height; setPtr->flags &= ~TABSET_REDRAW; if (setPtr->tkwin == NULL) { return; /* Window has been destroyed. */ } if (setPtr->flags & TABSET_LAYOUT) { ComputeLayout(setPtr); setPtr->flags &= ~TABSET_LAYOUT; } if ((setPtr->reqHeight == 0) || (setPtr->reqWidth == 0)) { width = height = 0; if (setPtr->side & SIDE_VERTICAL) { height = setPtr->worldWidth; } else { width = setPtr->worldWidth; } if (setPtr->reqWidth > 0) { width = setPtr->reqWidth; } else if (setPtr->pageWidth > 0) { width = setPtr->pageWidth; } if (setPtr->reqHeight > 0) { height = setPtr->reqHeight; } else if (setPtr->pageHeight > 0) { height = setPtr->pageHeight; } if (setPtr->side & SIDE_VERTICAL) { width += setPtr->pageTop + setPtr->inset + setPtr->inset2; height += (setPtr->inset + setPtr->inset2); } else { height += setPtr->pageTop + setPtr->inset + setPtr->inset2; width += (setPtr->inset + setPtr->inset2); } if ((Tk_ReqWidth(setPtr->tkwin) != width) || (Tk_ReqHeight(setPtr->tkwin) != height)) { Tk_GeometryRequest(setPtr->tkwin, width, height); } } if (setPtr->flags & TABSET_SCROLL) { width = VPORTWIDTH(setPtr); setPtr->scrollOffset = Blt_AdjustViewport(setPtr->scrollOffset, setPtr->worldWidth, width, setPtr->scrollUnits, BLT_SCROLL_MODE_CANVAS); if (setPtr->scrollCmdPrefix != NULL) { Blt_UpdateScrollbar(setPtr->interp, setPtr->scrollCmdPrefix, (double)setPtr->scrollOffset / setPtr->worldWidth, (double)(setPtr->scrollOffset + width) / setPtr->worldWidth); } ComputeVisibleTabs(setPtr); setPtr->flags &= ~TABSET_SCROLL; } if (!Tk_IsMapped(setPtr->tkwin)) { return; } height = Tk_Height(setPtr->tkwin); drawable = Tk_GetPixmap(setPtr->display, Tk_WindowId(setPtr->tkwin), Tk_Width(setPtr->tkwin), Tk_Height(setPtr->tkwin), Tk_Depth(setPtr->tkwin)); /* * Clear the background either by tiling a pixmap or filling with * a solid color. Tiling takes precedence. */ if (setPtr->tile != NULL) { Blt_SetTileOrigin(setPtr->tkwin, setPtr->tile, 0, 0); Blt_TileRectangle(setPtr->tkwin, drawable, setPtr->tile, 0, 0, Tk_Width(setPtr->tkwin), height); } else { Blt_Fill3DRectangle(setPtr->tkwin, drawable, setPtr->border, 0, 0, Tk_Width(setPtr->tkwin), height, 0, TK_RELIEF_FLAT); } if (setPtr->nVisible > 0) { register int i; register Tab *tabPtr; Blt_ChainLink *linkPtr; linkPtr = setPtr->startPtr->linkPtr; for (i = 0; i < Blt_ChainGetLength(setPtr->chainPtr); i++) { linkPtr = Blt_ChainPrevLink(linkPtr); if (linkPtr == NULL) { linkPtr = Blt_ChainLastLink(setPtr->chainPtr); } tabPtr = Blt_ChainGetValue(linkPtr); if ((tabPtr != setPtr->selectPtr) && (tabPtr->flags & TAB_VISIBLE)) { DrawFolder(setPtr, tabPtr, drawable); } } DrawFolder(setPtr, setPtr->selectPtr, drawable); if (setPtr->tearoff) { DrawPerforation(setPtr, setPtr->selectPtr, drawable); } if ((setPtr->selectPtr->tkwin != NULL) && (setPtr->selectPtr->container == NULL)) { XRectangle rect; GetWindowRectangle(setPtr->selectPtr, setPtr->tkwin, FALSE, &rect); ArrangeWindow(setPtr->selectPtr->tkwin, &rect, 0); } } DrawOuterBorders(setPtr, drawable); XCopyArea(setPtr->display, drawable, Tk_WindowId(setPtr->tkwin), setPtr->highlightGC, 0, 0, Tk_Width(setPtr->tkwin), height, 0, 0); Tk_FreePixmap(setPtr->display, drawable); } /* * From the left edge: * * |a|b|c|d|e| f |d|e|g|h| i |h|g|e|d|f| j |e|d|c|b|a| * * a. highlight ring * b. tabset 3D border * c. outer gap * d. page border * e. page corner * f. gap + select pad * g. label pad x (worldX) * h. internal pad x * i. label width * j. rest of page width * * worldX, worldY * | * | * * 4+ . . +5 * 3+ +6 * . . * . . * 1+. . .2+ +7 . . . .+8 * 0+ +9 * . . * . . *13+ +10 * 12+-------------------------+11 * */ static void DisplayTearoff(clientData) ClientData clientData; { Tabset *setPtr; Tab *tabPtr; Drawable drawable; XPoint pointArr[16]; XPoint *pointPtr; int width, height; int left, bottom, right, top; int x, y; int nPoints; Tk_Window tkwin; Tk_Window parent; XRectangle rect; tabPtr = clientData; if (tabPtr == NULL) { return; } tabPtr->flags &= ~TAB_REDRAW; setPtr = tabPtr->setPtr; if (setPtr->tkwin == NULL) { return; } tkwin = tabPtr->container; drawable = Tk_WindowId(tkwin); /* * Clear the background either by tiling a pixmap or filling with * a solid color. Tiling takes precedence. */ if (setPtr->tile != NULL) { Blt_SetTileOrigin(tkwin, setPtr->tile, 0, 0); Blt_TileRectangle(tkwin, drawable, setPtr->tile, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin)); } else { Blt_Fill3DRectangle(tkwin, drawable, setPtr->border, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); } width = Tk_Width(tkwin) - 2 * setPtr->inset; height = Tk_Height(tkwin) - 2 * setPtr->inset; x = setPtr->inset + setPtr->gap + setPtr->corner; y = setPtr->inset; left = setPtr->inset; right = setPtr->inset + width; top = setPtr->inset + setPtr->corner + setPtr->xSelectPad; bottom = setPtr->inset + height; /* * worldX, worldY * | * * 4+ . . +5 * 3+ +6 * . . * . . * 1+. . .2+ +7 . . . .+8 * 0+ +9 * . . * . . *13+ +10 * 12+-------------------------+11 */ nPoints = 0; pointPtr = pointArr; TopLeft(left, top); NextPoint(x, top); TopLeft(x, y); x += tabPtr->worldWidth; TopRight(x, y); NextPoint(x, top); TopRight(right, top); BottomRight(right, bottom); BottomLeft(left, bottom); EndPoint(pointArr[0].x, pointArr[0].y); Draw3DFolder(setPtr, tabPtr, drawable, SIDE_TOP, pointArr, nPoints); parent = (tabPtr->container == NULL) ? setPtr->tkwin : tabPtr->container; GetWindowRectangle(tabPtr, parent, TRUE, &rect); ArrangeWindow(tabPtr->tkwin, &rect, TRUE); /* Draw 3D border. */ if ((setPtr->borderWidth > 0) && (setPtr->relief != TK_RELIEF_FLAT)) { Blt_Draw3DRectangle(tkwin, drawable, setPtr->border, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), setPtr->borderWidth, setPtr->relief); } } /* * -------------------------------------------------------------- * * TabsetCmd -- * * This procedure is invoked to process the "tabset" command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * * -------------------------------------------------------------- */ static Blt_OpSpec tabsetOps[] = { {"activate", 1, (Blt_Op)ActivateOp, 3, 3, "index",}, {"bind", 1, (Blt_Op)BindOp, 2, 5, "index ?sequence command?",}, {"cget", 2, (Blt_Op)CgetOp, 3, 3, "option",}, {"configure", 2, (Blt_Op)ConfigureOp, 2, 0, "?option value?...",}, {"delete", 1, (Blt_Op)DeleteOp, 2, 0, "first ?last?",}, {"focus", 1, (Blt_Op)FocusOp, 3, 3, "index",}, {"get", 1, (Blt_Op)GetOp, 3, 3, "index",}, {"highlight", 1, (Blt_Op)ActivateOp, 3, 3, "index",}, {"index", 3, (Blt_Op)IndexOp, 3, 5, "string",}, {"insert", 3, (Blt_Op)InsertOp, 3, 0, "index name ?name...? ?option value?",}, {"invoke", 3, (Blt_Op)InvokeOp, 3, 3, "index",}, {"move", 1, (Blt_Op)MoveOp, 5, 5, "name after|before index",}, {"nearest", 1, (Blt_Op)NearestOp, 4, 4, "x y",}, {"perforation", 1, (Blt_Op)PerforationOp, 2, 0, "args",}, {"scan", 2, (Blt_Op)ScanOp, 5, 5, "dragto|mark x y",}, {"see", 3, (Blt_Op)SeeOp, 3, 3, "index",}, {"select", 3, (Blt_Op)SelectOp, 3, 3, "index",}, {"size", 2, (Blt_Op)SizeOp, 2, 2, "",}, {"tab", 1, (Blt_Op)TabOp, 2, 0, "oper args",}, {"view", 1, (Blt_Op)ViewOp, 2, 5, "?moveto fract? ?scroll number what?",}, }; static int nTabsetOps = sizeof(tabsetOps) / sizeof(Blt_OpSpec); static int TabsetInstCmd(clientData, interp, argc, argv) ClientData clientData; /* Information about the widget. */ Tcl_Interp *interp; /* Interpreter to report errors back to. */ int argc; /* Number of arguments. */ char **argv; /* Vector of argument strings. */ { Blt_Op proc; Tabset *setPtr = clientData; int result; proc = Blt_GetOp(interp, nTabsetOps, tabsetOps, BLT_OP_ARG1, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } Tcl_Preserve(setPtr); result = (*proc) (setPtr, interp, argc, argv); Tcl_Release(setPtr); return result; } /* *---------------------------------------------------------------------- * * TabsetInstDeletedCmd -- * * This procedure can be called if the window was destroyed * (tkwin will be NULL) and the command was deleted * automatically. In this case, we need to do nothing. * * Otherwise this routine was called because the command was * deleted. Then we need to clean-up and destroy the widget. * * Results: * None. * * Side Effects: * The widget is destroyed. * *---------------------------------------------------------------------- */ static void TabsetInstDeletedCmd(clientData) ClientData clientData; /* Pointer to widget record for widget. */ { Tabset *setPtr = clientData; if (setPtr->tkwin != NULL) { Tk_Window tkwin; tkwin = setPtr->tkwin; setPtr->tkwin = NULL; Tk_DestroyWindow(tkwin); #ifdef ITCL_NAMESPACES Itk_SetWidgetCommand(tkwin, (Tcl_Command) NULL); #endif /* ITCL_NAMESPACES */ } } /* * ------------------------------------------------------------------------ * * TabsetCmd -- * * This procedure is invoked to process the Tcl command that * corresponds to a widget managed by this module. See the user * documentation for details on what it does. * * Results: * A standard Tcl result. * * Side Effects: * See the user documentation. * * ----------------------------------------------------------------------- */ /* ARGSUSED */ static int TabsetCmd(clientData, interp, argc, argv) ClientData clientData; /* Main window associated with interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { Tabset *setPtr; Tk_Window tkwin; unsigned int mask; Tcl_CmdInfo cmdInfo; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " pathName ?option value?...\"", (char *)NULL); return TCL_ERROR; } tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp), argv[1], (char *)NULL); if (tkwin == NULL) { return TCL_ERROR; } setPtr = CreateTabset(interp, tkwin); if (ConfigureTabset(interp, setPtr, argc - 2, argv + 2, 0) != TCL_OK) { Tk_DestroyWindow(setPtr->tkwin); return TCL_ERROR; } mask = (ExposureMask | StructureNotifyMask | FocusChangeMask); Tk_CreateEventHandler(tkwin, mask, TabsetEventProc, setPtr); setPtr->cmdToken = Tcl_CreateCommand(interp, argv[1], TabsetInstCmd, setPtr, TabsetInstDeletedCmd); #ifdef ITCL_NAMESPACES Itk_SetWidgetCommand(setPtr->tkwin, setPtr->cmdToken); #endif /* * Try to invoke a procedure to initialize various bindings on * tabs. Source the file containing the procedure now if the * procedure isn't currently defined. We deferred this to now so * that the user could set the variable "blt_library" within the * script. */ if (!Tcl_GetCommandInfo(interp, "blt::TabsetInit", &cmdInfo)) { static char initCmd[] = "source [file join $blt_library tabset.tcl]"; if (Tcl_GlobalEval(interp, initCmd) != TCL_OK) { char info[200]; sprintf(info, "\n (while loading bindings for %s)", argv[0]); Tcl_AddErrorInfo(interp, info); Tk_DestroyWindow(setPtr->tkwin); return TCL_ERROR; } } if (Tcl_VarEval(interp, "blt::TabsetInit ", argv[1], (char *)NULL) != TCL_OK) { Tk_DestroyWindow(setPtr->tkwin); return TCL_ERROR; } Tcl_SetResult(interp, Tk_PathName(setPtr->tkwin), TCL_VOLATILE); return TCL_OK; } int Blt_TabsetInit(interp) Tcl_Interp *interp; { static Blt_CmdSpec cmdSpec = { "tabset", TabsetCmd, }; if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) { return TCL_ERROR; } return TCL_OK; } #endif /* NO_TABSET */ blt-2.4z.orig/src/bltTed.c0100644000175000017500000016027707471015210014127 0ustar dokodoko/* * bltTed.c -- * * This module implements an editor for the table geometry * manager in the BLT toolkit. * * Copyright 1995 by AT&T Bell Laboratories. * 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 AT&T Bell Laboratories any of their entities not be used * in advertising or publicity pertaining to distribution of the * software without specific, written prior permission. * * AT&T disclaims all warranties with regard to this software, including * all implied warranties of merchantability and fitness. In no event * shall AT&T 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. * * Table editor was created by George Howlett. */ #include "bltInt.h" #include "bltTable.h" extern Tk_CustomOption bltDistanceOption; extern Tk_CustomOption bltDashesOption; typedef struct TedStruct Ted; #define TABLE_THREAD_KEY "BLT Table Data" typedef struct { Blt_HashTable tableTable; /* Hash table of table structures keyed by * the address of the reference Tk window */ } TableData; typedef struct { int flags; Tcl_Interp *interp; Tk_Window tkwin; /* Entry window */ Entry *entryPtr; /* Entry it represents */ Table *tablePtr; /* Table where it can be found */ Ted *tedPtr; /* Table editor */ int mapped; /* Indicates if the debugging windows are * mapped */ } EntryRep; typedef struct { Tk_Font font; XColor *widgetColor; XColor *cntlColor; XColor *normalFg, *normalBg; XColor *activeFg, *activeBg; Tk_Cursor cursor; /* Cursor to display inside of this window */ Pixmap stipple; GC drawGC; /* GC to draw grid, outlines */ GC fillGC; /* GC to fill entry area */ GC widgetFillGC; /* GC to fill widget area */ GC cntlGC; /* GC to fill rectangles */ } EntryAttributes; typedef struct { int count; XRectangle *array; } Rectangles; struct TedStruct { int gridLineWidth; /* Width of grid lines */ int buttonHeight; /* Height of row/column buttons */ int cavityPad; /* Extra padding to add to entry cavity */ int minSize; /* Minimum size for partitions */ EditorDrawProc *drawProc; EditorDestroyProc *destroyProc; Display *display; Tk_Font font; Table *tablePtr; /* Pointer to table being debugged */ Tcl_Interp *interp; int flags; Tk_Window tkwin; /* Grid window */ Tk_Window input; /* InputOnly window to receive events */ int inputIsSibling; /* Form the grid */ XSegment *segArr; int nSegs; XRectangle *padRectArr; int nPadRects; XRectangle *widgetPadRectArr; int nWidgetPadRects; XRectangle *cntlRectArr; int nCntlRects; XRectangle *rectArr; int nRects; XRectangle activeRectArr[5]; int spanActive; GC rectGC; /* GC to fill rectangles */ GC drawGC; /* GC to draw grid, outlines */ GC fillGC; /* GC to fill window */ GC spanGC; /* GC to fill spans */ GC padRectGC; /* GC to draw padding */ Tk_3DBorder border; /* Border to use with buttons */ int relief; int borderWidth; /* Border width of buttons */ XColor *normalBg; XColor *padColor; XColor *gridColor; XColor *buttonColor; XColor *spanColor; Pixmap padStipple; Pixmap spanStipple; Blt_Dashes dashes; char *fileName; /* If non-NULL, indicates name of file * to write final table output to */ int mapped; /* Indicates if the debugging windows are * mapped */ int gripSize; int doubleBuffer; Tk_Cursor cursor; Blt_Chain *chainPtr; int nextWindowId; EntryAttributes attributes; /* Entry attributes */ }; #define REDRAW_PENDING (1<<0) /* A DoWhenIdle handler has already * been queued to redraw the window */ #define LAYOUT_PENDING (1<<1) /* * * * |Cavity|1|2| * * */ #define DEF_ENTRY_ACTIVE_BG_MONO RGB_BLACK #define DEF_ENTRY_ACTIVE_FG_MONO RGB_WHITE #define DEF_ENTRY_ACTIVE_BACKGROUND RGB_BLACK #define DEF_ENTRY_ACTIVE_FOREGROUND RGB_WHITE #define DEF_ENTRY_CURSOR (char *)NULL #define DEF_ENTRY_FONT "*-Courier-Bold-R-Normal-*-100-*" #define DEF_ENTRY_NORMAL_BACKGROUND RGB_BLUE #define DEF_ENTRY_NORMAL_BG_MONO RGB_BLACK #define DEF_ENTRY_NORMAL_FOREGROUND RGB_WHITE #define DEF_ENTRY_NORMAL_FG_MONO RGB_WHITE #define DEF_ENTRY_WIDGET_BACKGROUND RGB_GREEN #define DEF_ENTRY_CONTROL_BACKGROUND RGB_YELLOW #define DEF_ENTRY_WIDGET_BG_MONO RGB_BLACK #define DEF_ENTRY_STIPPLE "gray50" #define DEF_GRID_BACKGROUND RGB_WHITE #define DEF_GRID_BG_MONO RGB_WHITE #define DEF_GRID_CURSOR "crosshair" #define DEF_GRID_DASHES (char *)NULL #define DEF_GRID_FOREGROUND RGB_BLACK #define DEF_GRID_FG_MONO RGB_BLACK #define DEF_GRID_FONT "*-Courier-Bold-R-Normal-*-100-*" #define DEF_GRID_LINE_WIDTH "1" #define DEF_GRID_PAD_COLOR RGB_RED #define DEF_GRID_PAD_MONO RGB_BLACK #define DEF_GRID_PAD_STIPPLE "gray25" #define DEF_GRID_PAD_CAVITY "0" #define DEF_GRID_PAD_MIN "8" #define DEF_ROWCOL_BACKGROUND RGB_RED #define DEF_ROWCOL_BG_MONO RGB_BLACK #define DEF_ROWCOL_BORDER_COLOR RGB_RED #define DEF_ROWCOL_BORDER_MONO RGB_BLACK #define DEF_ROWCOL_BORDERWIDTH "2" #define DEF_ROWCOL_HEIGHT "8" #define DEF_ROWCOL_RELIEF "raised" #define DEF_SPAN_STIPPLE "gray50" #define DEF_SPAN_COLOR RGB_BLACK #define DEF_SPAN_MONO RGB_BLACK #define DEF_SPAN_GRIP_SIZE "5" #define DEF_GRID_DOUBLE_BUFFER "1" static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_BORDER, "-bg", "tedBorder", (char *)NULL, DEF_ROWCOL_BORDER_COLOR, Tk_Offset(Ted, border), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-bg", "tedBorder", (char *)NULL, DEF_ROWCOL_BORDER_MONO, Tk_Offset(Ted, border), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-background", "tedBackground", (char *)NULL, DEF_GRID_BACKGROUND, Tk_Offset(Ted, normalBg), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-background", "tedBackground", (char *)NULL, DEF_GRID_BG_MONO, Tk_Offset(Ted, normalBg), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_CURSOR, "-cursor", "cursor", (char *)NULL, DEF_GRID_CURSOR, Tk_Offset(Ted, cursor), TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-gridcolor", "gridColor", (char *)NULL, DEF_GRID_FOREGROUND, Tk_Offset(Ted, gridColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-gridcolor", "gridColor", (char *)NULL, DEF_GRID_FG_MONO, Tk_Offset(Ted, gridColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-buttoncolor", "buttonColor", (char *)NULL, DEF_ROWCOL_BACKGROUND, Tk_Offset(Ted, buttonColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-buttoncolor", "buttonColor", (char *)NULL, DEF_ROWCOL_BG_MONO, Tk_Offset(Ted, buttonColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-padcolor", "padColor", (char *)NULL, DEF_GRID_PAD_COLOR, Tk_Offset(Ted, padColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-padcolor", "padColor", (char *)NULL, DEF_GRID_PAD_MONO, Tk_Offset(Ted, padColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_BITMAP, "-padstipple", "padStipple", (char *)NULL, DEF_GRID_PAD_STIPPLE, Tk_Offset(Ted, padStipple), TK_CONFIG_NULL_OK}, {TK_CONFIG_FONT, "-font", "font", (char *)NULL, DEF_GRID_FONT, Tk_Offset(Ted, font), 0}, {TK_CONFIG_CUSTOM, "-gridlinewidth", "gridLineWidth", (char *)NULL, DEF_GRID_LINE_WIDTH, Tk_Offset(Ted, gridLineWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-buttonheight", "buttonHeight", (char *)NULL, DEF_ROWCOL_HEIGHT, Tk_Offset(Ted, buttonHeight), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-cavitypad", "cavityPad", (char *)NULL, DEF_GRID_PAD_CAVITY, Tk_Offset(Ted, cavityPad), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-minsize", "minSize", (char *)NULL, DEF_GRID_PAD_MIN, Tk_Offset(Ted, minSize), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-dashes", "dashes", (char *)NULL, DEF_GRID_DASHES, Tk_Offset(Ted, dashes), TK_CONFIG_NULL_OK, &bltDashesOption}, {TK_CONFIG_RELIEF, "-relief", "relief", (char *)NULL, DEF_ROWCOL_RELIEF, Tk_Offset(Ted, relief), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_CUSTOM, "-borderwidth", "borderWidth", (char *)NULL, DEF_ROWCOL_BORDERWIDTH, Tk_Offset(Ted, borderWidth), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_CURSOR, "-entrycursor", "entryCursor", (char *)NULL, DEF_ENTRY_CURSOR, Tk_Offset(Ted, attributes.cursor), TK_CONFIG_NULL_OK}, {TK_CONFIG_FONT, "-entryfont", "entryFont", (char *)NULL, DEF_ENTRY_FONT, Tk_Offset(Ted, attributes.font), 0}, {TK_CONFIG_BITMAP, "-entrystipple", "entryStipple", (char *)NULL, DEF_ENTRY_STIPPLE, Tk_Offset(Ted, attributes.stipple), TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-widgetbackground", "widgetBackground", (char *)NULL, DEF_ENTRY_WIDGET_BACKGROUND, Tk_Offset(Ted, attributes.widgetColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-widgetbackground", "widgetBackground", (char *)NULL, DEF_ENTRY_WIDGET_BG_MONO, Tk_Offset(Ted, attributes.widgetColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-controlbackground", "controlBackground", (char *)NULL, DEF_ENTRY_CONTROL_BACKGROUND, Tk_Offset(Ted, attributes.cntlColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-controlbackground", "controlBackground", (char *)NULL, DEF_ENTRY_WIDGET_BG_MONO, Tk_Offset(Ted, attributes.cntlColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-entrybackground", "entryBackground", (char *)NULL, DEF_ENTRY_NORMAL_BACKGROUND, Tk_Offset(Ted, attributes.normalBg), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-entrybackground", "entryBackground", (char *)NULL, DEF_ENTRY_NORMAL_BG_MONO, Tk_Offset(Ted, attributes.normalBg), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-entryactivebackground", "entryActiveBackground", (char *)NULL, DEF_ENTRY_ACTIVE_BACKGROUND, Tk_Offset(Ted, attributes.activeBg), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-entryactivebackground", "entryActiveBackground", (char *)NULL, DEF_ENTRY_ACTIVE_BG_MONO, Tk_Offset(Ted, attributes.activeBg), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-entryactiveforeground", "entryActiveForeground", (char *)NULL, DEF_ENTRY_ACTIVE_FOREGROUND, Tk_Offset(Ted, attributes.activeFg), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-entryactiveforeground", "entryActiveForeground", (char *)NULL, DEF_ENTRY_ACTIVE_FG_MONO, Tk_Offset(Ted, attributes.activeFg), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-entryforeground", "entryForeground", (char *)NULL, DEF_ENTRY_NORMAL_FOREGROUND, Tk_Offset(Ted, attributes.normalFg), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-entryforeground", "entryForeground", (char *)NULL, DEF_ENTRY_NORMAL_FG_MONO, Tk_Offset(Ted, attributes.normalFg), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-spancolor", "spanColor", (char *)NULL, DEF_SPAN_COLOR, Tk_Offset(Ted, spanColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-spancolor", "spanColor", (char *)NULL, DEF_SPAN_MONO, Tk_Offset(Ted, spanColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_BITMAP, "-spanstipple", "spanStipple", (char *)NULL, DEF_SPAN_STIPPLE, Tk_Offset(Ted, spanStipple), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-gripsize", "gripSize", (char *)NULL, DEF_SPAN_GRIP_SIZE, Tk_Offset(Ted, gripSize), TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption}, {TK_CONFIG_BOOLEAN, "-dbl", "doubleBuffer", (char *)NULL, DEF_GRID_DOUBLE_BUFFER, Tk_Offset(Ted, doubleBuffer), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} }; static void DrawEditor _ANSI_ARGS_((Editor *editor)); static void DestroyEditor _ANSI_ARGS_((DestroyData destroyData)); static void DisplayTed _ANSI_ARGS_((ClientData clientData)); static void DestroyTed _ANSI_ARGS_((DestroyData destroyData)); static void DisplayEntry _ANSI_ARGS_((ClientData clientData)); static void DestroyEntry _ANSI_ARGS_((DestroyData destoryData)); static Tcl_CmdProc TedCmd; static Tk_EventProc EntryEventProc; static Tk_EventProc TedEventProc; /* *---------------------------------------------------------------------- * * EventuallyRedraw -- * * Queues a request to redraw the text window at the next idle * point. * * Results: * None. * * Side effects: * Information gets redisplayed. Right now we don't do selective * redisplays: the whole window will be redrawn. This doesn't * seem to hurt performance noticeably, but if it does then this * could be changed. * *---------------------------------------------------------------------- */ static void EventuallyRedraw(tedPtr) Ted *tedPtr; /* Information about editor. */ { if ((tedPtr->tkwin != NULL) && !(tedPtr->flags & REDRAW_PENDING)) { tedPtr->flags |= REDRAW_PENDING; Tcl_DoWhenIdle(DisplayTed, tedPtr); } } /* *---------------------------------------------------------------------- * * EventuallyRedraw -- * * Queues a request to redraw the text window at the next idle * point. * * Results: * None. * * Side effects: * Information gets redisplayed. Right now we don't do selective * redisplays: the whole window will be redrawn. This doesn't * seem to hurt performance noticeably, but if it does then this * could be changed. * *---------------------------------------------------------------------- */ static void EventuallyRedrawEntry(repPtr) EntryRep *repPtr; /* Information about editor. */ { if ((repPtr->tkwin != NULL) && !(repPtr->flags & REDRAW_PENDING)) { repPtr->flags |= REDRAW_PENDING; Tcl_DoWhenIdle(DisplayEntry, repPtr); } } /* * -------------------------------------------------------------- * * EntryEventProc -- * * This procedure is invoked by the Tk dispatcher for various * events on the editing grid for the table. * * Results: * None. * * Side effects: * When the window gets deleted, internal structures get * cleaned up. When it gets exposed, it is redisplayed. * * -------------------------------------------------------------- */ static void EntryEventProc(clientData, eventPtr) ClientData clientData; /* Information about window. */ XEvent *eventPtr; /* Information about event. */ { EntryRep *repPtr = (EntryRep *) clientData; if (eventPtr->type == ConfigureNotify) { EventuallyRedrawEntry(repPtr); } else if (eventPtr->type == Expose) { if (eventPtr->xexpose.count == 0) { EventuallyRedrawEntry(repPtr); } } else if (eventPtr->type == DestroyNotify) { repPtr->tkwin = NULL; if (repPtr->flags & REDRAW_PENDING) { Tcl_CancelIdleCall(DisplayEntry, repPtr); } Tcl_EventuallyFree(repPtr, DestroyEntry); } } /* * -------------------------------------------------------------- * * TedEventProc -- * * This procedure is invoked by the Tk dispatcher for various * events on the editing grid for the table. * * Results: * None. * * Side effects: * When the window gets deleted, internal structures get * cleaned up. When it gets exposed, it is redisplayed. * * -------------------------------------------------------------- */ static void TedEventProc(clientData, eventPtr) ClientData clientData; /* Information about window. */ XEvent *eventPtr; /* Information about event. */ { Ted *tedPtr = (Ted *) clientData; if (eventPtr->type == ConfigureNotify) { EventuallyRedraw(tedPtr); } else if (eventPtr->type == Expose) { if (eventPtr->xexpose.count == 0) { EventuallyRedraw(tedPtr); } } else if (eventPtr->type == DestroyNotify) { tedPtr->tkwin = NULL; if (tedPtr->flags & REDRAW_PENDING) { Tcl_CancelIdleCall(DisplayTed, tedPtr); } Tcl_EventuallyFree(tedPtr, DestroyTed); } } /* * ---------------------------------------------------------------------------- * * CreateGrid -- * * ---------------------------------------------------------------------------- */ static int CreateGrid(tedPtr) Ted *tedPtr; { Tcl_Interp *interp; Tk_Window tkwin; Tk_Window master; /* * Create a sibling window to cover the master window. It will * be stacked just above the master window. */ interp = tedPtr->tablePtr->interp; master = tedPtr->tablePtr->tkwin; tkwin = Tk_CreateWindow(interp, master, "ted_%output%", (char *)NULL); if (tkwin == NULL) { return TCL_ERROR; } Tk_SetClass(tkwin, "BltTed"); Tk_CreateEventHandler(tkwin, ExposureMask | StructureNotifyMask, TedEventProc, tedPtr); Tk_MoveResizeWindow(tkwin, 0, 0, Tk_Width(master), Tk_Height(master)); Tk_RestackWindow(tkwin, Below, (Tk_Window)NULL); Tk_MapWindow(tkwin); tedPtr->tkwin = tkwin; return TCL_OK; } /* * ---------------------------------------------------------------------------- * * CreateEventWindow -- * * ---------------------------------------------------------------------------- */ static int CreateEventWindow(tedPtr) Ted *tedPtr; { Tcl_Interp *interp; Tk_Window tkwin; Tk_Window master; Tk_Window parent; interp = tedPtr->tablePtr->interp; master = tedPtr->tablePtr->tkwin; /* * Create an InputOnly window which sits above the table to * collect and dispatch user events. */ if (Tk_IsTopLevel(master)) { /* * If master is a top-level window, it's also the parent of * the widgets (it can't have a sibling). * In this case, the InputOnly window is a child of the * master instead of a sibling. */ parent = master; tkwin = Tk_CreateWindow(interp, parent, "ted_%input%", (char *)NULL); if (tkwin != NULL) { Tk_ResizeWindow(tkwin, Tk_Width(parent), Tk_Height(parent)); } tedPtr->inputIsSibling = 0; } else { char *namePtr; /* Name of InputOnly window. */ parent = Tk_Parent(master); namePtr = Blt_Malloc(strlen(Tk_Name(master)) + 5); sprintf(namePtr, "ted_%s", Tk_Name(master)); tkwin = Tk_CreateWindow(interp, parent, namePtr, (char *)NULL); Blt_Free(namePtr); if (tkwin != NULL) { Tk_MoveResizeWindow(tkwin, Tk_X(master), Tk_Y(master), Tk_Width(master), Tk_Height(master)); } tedPtr->inputIsSibling = 1; } if (tkwin == NULL) { return TCL_ERROR; } Blt_MakeTransparentWindowExist(tkwin, Tk_WindowId(parent), TRUE); Tk_RestackWindow(tkwin, Above, (Tk_Window)NULL); Tk_MapWindow(tkwin); tedPtr->input = tkwin; return TCL_OK; } /* * ---------------------------------------------------------------------------- * * CreateEntry -- * * ---------------------------------------------------------------------------- */ static int CreateEntry(tedPtr, entryPtr) Ted *tedPtr; Entry *entryPtr; { Tk_Window tkwin, master; char string[200]; EntryRep *repPtr; Blt_ChainLink *linkPtr; repPtr = Blt_Calloc(1, sizeof(EntryRep)); assert(repPtr); repPtr->tablePtr = tedPtr->tablePtr; repPtr->tedPtr = tedPtr; repPtr->interp = tedPtr->interp; repPtr->entryPtr = entryPtr; repPtr->mapped = 0; /* * Create a sibling window to cover the master window. It will * be stacked just above the master window. */ master = tedPtr->tablePtr->tkwin; sprintf(string, "bltTed%d", tedPtr->nextWindowId); tedPtr->nextWindowId++; tkwin = Tk_CreateWindow(tedPtr->interp, master, string, (char *)NULL); if (tkwin == NULL) { Blt_Free(repPtr); return TCL_ERROR; } Tk_SetClass(tkwin, "BltTed"); Tk_CreateEventHandler(tkwin, ExposureMask | StructureNotifyMask, EntryEventProc, repPtr); repPtr->tkwin = tkwin; linkPtr = Blt_ChainNewLink(); Blt_ChainSetValue(linkPtr, repPtr); Blt_ChainLinkAfter(tedPtr->chainPtr, linkPtr, (Blt_ChainLink *)NULL); return TCL_OK; } /* * ---------------------------------------------------------------------------- * * DestroyEntry -- * * ---------------------------------------------------------------------------- */ static void DestroyEntry(data) DestroyData data; { EntryRep *repPtr = (EntryRep *)data; Blt_ChainLink *linkPtr; Entry *entryPtr; for (linkPtr = Blt_ChainFirstLink(repPtr->tedPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { entryPtr = Blt_ChainGetValue(linkPtr); if (entryPtr == repPtr->entryPtr) { Blt_ChainDeleteLink(repPtr->tedPtr->chainPtr, linkPtr); Blt_Free(repPtr); return; } } } /* * ---------------------------------------------------------------------------- * * DisplayEntry -- * * ---------------------------------------------------------------------------- */ static void DisplayEntry(clientData) ClientData clientData; { EntryRep *repPtr = (EntryRep *) clientData; Ted *tedPtr; Entry *entryPtr; Tk_Window tkwin; int x, y, width, height; repPtr->flags &= ~REDRAW_PENDING; if ((repPtr->tkwin == NULL) || (repPtr->entryPtr == NULL)) { return; } if (!Tk_IsMapped(repPtr->tkwin)) { return; } tedPtr = repPtr->tedPtr; entryPtr = repPtr->entryPtr; tkwin = repPtr->tkwin; /* * Check if the entry size and position. * Move and resize the window accordingly. */ x = Tk_X(entryPtr->tkwin) - (entryPtr->padLeft + tedPtr->cavityPad); y = Tk_Y(entryPtr->tkwin) - (entryPtr->padTop + tedPtr->cavityPad); width = Tk_Width(entryPtr->tkwin) + PADDING(entryPtr->padX) + (2 * tedPtr->cavityPad); height = Tk_Height(entryPtr->tkwin) + PADDING(entryPtr->padY) + (2 * tedPtr->cavityPad); if ((Tk_X(tkwin) != x) || (Tk_Y(tkwin) != y) || (Tk_Width(tkwin) != width) || (Tk_Height(tkwin) != height)) { Tk_MoveResizeWindow(tkwin, x, y, width, height); Tk_RestackWindow(tkwin, Above, (Tk_Window)NULL); } /* Clear the background of the entry */ XFillRectangle(Tk_Display(tkwin), Tk_WindowId(tkwin), tedPtr->attributes.fillGC, 0, 0, width, height); /* Draw the window */ x = entryPtr->padLeft + tedPtr->cavityPad; y = entryPtr->padTop + tedPtr->cavityPad; XFillRectangle(Tk_Display(tkwin), Tk_WindowId(tkwin), tedPtr->attributes.widgetFillGC, x, y, Tk_Width(entryPtr->tkwin), Tk_Height(entryPtr->tkwin)); XDrawRectangle(Tk_Display(tkwin), Tk_WindowId(tkwin), tedPtr->attributes.drawGC, x, y, Tk_Width(entryPtr->tkwin), Tk_Height(entryPtr->tkwin)); } /* * ---------------------------------------------------------------------------- * * FindEditor -- * * Searches for a table associated with the window given by its * pathname. This window represents the master window of the table. * * Errors may occur because * 1) pathName does not represent a valid Tk window or * 2) the window is not associated with any table as its master. * * Results: * If a table entry exists, a pointer to the Table structure is * returned. Otherwise NULL is returned. * * ---------------------------------------------------------------------------- */ static Ted * FindEditor(clientData, interp, pathName) ClientData clientData; /* Thread-specific data. */ Tcl_Interp *interp; /* Interpreter to report errors back to */ char *pathName; /* Path name of the master window */ { Table *tablePtr; if (Blt_GetTable(clientData, interp, pathName, &tablePtr) != TCL_OK) { return NULL; } if (tablePtr->editPtr == NULL) { Tcl_AppendResult(interp, "no editor exists for table \"", Tk_PathName(tablePtr->tkwin), "\"", (char *)NULL); return NULL; } return (Ted *) tablePtr->editPtr; } /* * ---------------------------------------------------------------------------- * * CreateTed -- * * ---------------------------------------------------------------------------- */ static Ted * CreateTed(tablePtr, interp) Table *tablePtr; Tcl_Interp *interp; { Ted *tedPtr; tedPtr = Blt_Calloc(1, sizeof(Ted)); assert(tedPtr); tedPtr->nextWindowId = 0; tedPtr->interp = interp; tedPtr->tablePtr = tablePtr; tedPtr->gridLineWidth = 1; tedPtr->buttonHeight = 0; tedPtr->cavityPad = 0; tedPtr->minSize = 3; tedPtr->gripSize = 5; tedPtr->drawProc = DrawEditor; tedPtr->destroyProc = DestroyEditor; tedPtr->display = Tk_Display(tablePtr->tkwin); tedPtr->relief = TK_RELIEF_RAISED; tedPtr->borderWidth = 2; tedPtr->doubleBuffer = 1; tedPtr->chainPtr = Blt_ChainCreate(); /* Create the grid window */ if (CreateGrid(tedPtr) != TCL_OK) { return NULL; } /* Create an InputOnly window to collect user events */ if (CreateEventWindow(tedPtr) != TCL_OK) { return NULL; } tablePtr->editPtr = (Editor *)tedPtr; return tedPtr; } /* * ---------------------------------------------------------------------------- * * DestroyTed -- * * ---------------------------------------------------------------------------- */ static void DestroyTed(freeProcData) DestroyData freeProcData; { Ted *tedPtr = (Ted *) freeProcData; if (tedPtr->rectArr != NULL) { Blt_Free(tedPtr->rectArr); } if (tedPtr->segArr != NULL) { Blt_Free(tedPtr->segArr); } if (tedPtr->fillGC != NULL) { Tk_FreeGC(tedPtr->display, tedPtr->fillGC); } if (tedPtr->drawGC != NULL) { Tk_FreeGC(tedPtr->display, tedPtr->drawGC); } if (tedPtr->rectGC != NULL) { Tk_FreeGC(tedPtr->display, tedPtr->rectGC); } if (tedPtr->padRectGC != NULL) { Tk_FreeGC(tedPtr->display, tedPtr->padRectGC); } /* Is this save ? */ tedPtr->tablePtr->editPtr = NULL; Blt_Free(tedPtr); } /* * ---------------------------------------------------------------------------- * * ConfigureTed -- * * This procedure is called to process an argv/argc list in order to * configure the table geometry manager. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then interp->result contains an error message. * * Side effects: * Table configuration options (padx, pady, rows, columns, etc) get * set. The table is recalculated and arranged at the next idle * point. * * ---------------------------------------------------------------------------- */ static int ConfigureTed(tedPtr, argc, argv, flags) Ted *tedPtr; int argc; char **argv; /* Option-value pairs */ int flags; { XGCValues gcValues; GC newGC; unsigned long gcMask; if (Tk_ConfigureWidget(tedPtr->interp, tedPtr->tkwin, configSpecs, argc, argv, (char *)tedPtr, flags) != TCL_OK) { return TCL_ERROR; } /* GC for filling background of edit window */ gcMask = GCForeground; gcValues.foreground = tedPtr->normalBg->pixel; newGC = Tk_GetGC(tedPtr->tkwin, gcMask, &gcValues); if (tedPtr->fillGC != NULL) { Tk_FreeGC(tedPtr->display, tedPtr->fillGC); } tedPtr->fillGC = newGC; /* GC for drawing grid lines */ gcMask = (GCForeground | GCBackground | GCLineWidth | GCLineStyle | GCCapStyle | GCJoinStyle | GCFont); gcValues.font = Tk_FontId(tedPtr->font); gcValues.foreground = tedPtr->gridColor->pixel; gcValues.background = tedPtr->normalBg->pixel; gcValues.line_width = LineWidth(tedPtr->gridLineWidth); gcValues.cap_style = CapRound; gcValues.join_style = JoinRound; gcValues.line_style = LineSolid; if (LineIsDashed(tedPtr->dashes)) { gcValues.line_style = LineOnOffDash; } newGC = Blt_GetPrivateGC(tedPtr->tkwin, gcMask, &gcValues); if (tedPtr->drawGC != NULL) { Blt_FreePrivateGC(tedPtr->display, tedPtr->drawGC); } if (LineIsDashed(tedPtr->dashes)) { XSetDashes(tedPtr->display, newGC, 0, (CONST char *)tedPtr->dashes.values, strlen((char *)tedPtr->dashes.values)); } tedPtr->drawGC = newGC; /* GC for button rectangles */ gcMask = GCForeground; gcValues.foreground = tedPtr->buttonColor->pixel; newGC = Tk_GetGC(tedPtr->tkwin, gcMask, &gcValues); if (tedPtr->rectGC != NULL) { Tk_FreeGC(tedPtr->display, tedPtr->rectGC); } tedPtr->rectGC = newGC; /* GC for button rectangles */ gcMask = GCForeground; gcValues.foreground = tedPtr->padColor->pixel; if (tedPtr->padStipple != None) { gcMask |= GCStipple | GCFillStyle; gcValues.stipple = tedPtr->padStipple; gcValues.fill_style = FillStippled; } newGC = Tk_GetGC(tedPtr->tkwin, gcMask, &gcValues); if (tedPtr->padRectGC != NULL) { Tk_FreeGC(tedPtr->display, tedPtr->padRectGC); } tedPtr->padRectGC = newGC; /* GC for filling entrys */ gcMask = GCForeground; gcValues.foreground = tedPtr->attributes.normalBg->pixel; if (tedPtr->attributes.stipple != None) { gcMask |= GCStipple | GCFillStyle; gcValues.stipple = tedPtr->attributes.stipple; gcValues.fill_style = FillStippled; } newGC = Tk_GetGC(tedPtr->tkwin, gcMask, &gcValues); if (tedPtr->attributes.fillGC != NULL) { Tk_FreeGC(tedPtr->display, tedPtr->attributes.fillGC); } tedPtr->attributes.fillGC = newGC; /* GC for drawing entrys */ gcMask = GCForeground | GCBackground | GCFont; gcValues.foreground = tedPtr->attributes.normalFg->pixel; gcValues.background = tedPtr->attributes.normalBg->pixel; gcValues.font = Tk_FontId(tedPtr->attributes.font); newGC = Tk_GetGC(tedPtr->tkwin, gcMask, &gcValues); if (tedPtr->attributes.drawGC != NULL) { Blt_FreePrivateGC(tedPtr->display, tedPtr->attributes.drawGC); } tedPtr->attributes.drawGC = newGC; /* GC for filling widget rectangles */ gcMask = GCForeground; gcValues.foreground = tedPtr->attributes.widgetColor->pixel; newGC = Tk_GetGC(tedPtr->tkwin, gcMask, &gcValues); if (tedPtr->attributes.widgetFillGC != NULL) { Tk_FreeGC(tedPtr->display, tedPtr->attributes.widgetFillGC); } tedPtr->attributes.widgetFillGC = newGC; gcMask = GCForeground; gcValues.foreground = tedPtr->attributes.cntlColor->pixel; newGC = Tk_GetGC(tedPtr->tkwin, gcMask, &gcValues); if (tedPtr->attributes.cntlGC != NULL) { Tk_FreeGC(tedPtr->display, tedPtr->attributes.cntlGC); } tedPtr->attributes.cntlGC = newGC; /* GC for filling span rectangle */ gcMask = GCForeground; gcValues.foreground = tedPtr->spanColor->pixel; if (tedPtr->spanStipple != None) { gcMask |= GCStipple | GCFillStyle; gcValues.stipple = tedPtr->spanStipple; gcValues.fill_style = FillStippled; } newGC = Tk_GetGC(tedPtr->tkwin, gcMask, &gcValues); if (tedPtr->spanGC != NULL) { Tk_FreeGC(tedPtr->display, tedPtr->spanGC); } tedPtr->spanGC = newGC; /* Define cursor for grid events */ if (tedPtr->cursor != None) { Tk_DefineCursor(tedPtr->input, tedPtr->cursor); } else { Tk_UndefineCursor(tedPtr->input); } return TCL_OK; } static void LayoutGrid(tedPtr) Ted *tedPtr; { int needed; XSegment *segArr; Table *tablePtr; Blt_ChainLink *linkPtr; RowColumn *rcPtr; int startX, endX; int startY, endY; int count; tablePtr = tedPtr->tablePtr; if (tedPtr->segArr != NULL) { Blt_Free(tedPtr->segArr); tedPtr->segArr = NULL; } tedPtr->nSegs = 0; if ((tablePtr->nRows == 0) || (tablePtr->nColumns == 0)) { return; } needed = tablePtr->nRows + tablePtr->nColumns + 2; segArr = Blt_Calloc(needed, sizeof(XSegment)); if (segArr == NULL) { return; } linkPtr = Blt_ChainFirstLink(tablePtr->columnInfo.chainPtr); rcPtr = Blt_ChainGetValue(linkPtr); startX = rcPtr->offset - tedPtr->gridLineWidth; linkPtr = Blt_ChainLastLink(tablePtr->columnInfo.chainPtr); rcPtr = Blt_ChainGetValue(linkPtr); endX = rcPtr->offset + rcPtr->size - 1; linkPtr = Blt_ChainFirstLink(tablePtr->rowInfo.chainPtr); rcPtr = Blt_ChainGetValue(linkPtr); startY = rcPtr->offset - tedPtr->gridLineWidth; linkPtr = Blt_ChainLastLink(tablePtr->rowInfo.chainPtr); rcPtr = Blt_ChainGetValue(linkPtr); endY = rcPtr->offset + rcPtr->size - 1; count = 0; /* Reset segment counter */ for (linkPtr = Blt_ChainFirstLink(tablePtr->rowInfo.chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); segArr[count].x1 = startX; segArr[count].x2 = endX; segArr[count].y1 = segArr[count].y2 = rcPtr->offset - tedPtr->gridLineWidth; count++; } segArr[count].x1 = startX; segArr[count].x2 = endX; segArr[count].y1 = segArr[count].y2 = endY; count++; for (linkPtr = Blt_ChainFirstLink(tablePtr->columnInfo.chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); segArr[count].y1 = startY; segArr[count].y2 = endY; segArr[count].x1 = segArr[count].x2 = rcPtr->offset - tedPtr->gridLineWidth; count++; } segArr[count].x1 = segArr[count].x2 = endX; segArr[count].y1 = startY; segArr[count].y2 = endY; count++; assert(count == needed); if (tedPtr->segArr != NULL) { Blt_Free(tedPtr->segArr); } tedPtr->segArr = segArr; tedPtr->nSegs = count; } static void LayoutPads(tedPtr) Ted *tedPtr; { int needed; XRectangle *rectArr, *rectPtr; Table *tablePtr; Blt_ChainLink *linkPtr; RowColumn *rcPtr; int startX, endX; int startY, endY; int count; tablePtr = tedPtr->tablePtr; if (tedPtr->padRectArr != NULL) { Blt_Free(tedPtr->padRectArr); tedPtr->padRectArr = NULL; } tedPtr->nPadRects = 0; if ((tablePtr->nRows == 0) || (tablePtr->nColumns == 0)) { return; } needed = 2 * (tablePtr->nRows + tablePtr->nColumns); rectArr = Blt_Calloc(needed, sizeof(XRectangle)); if (rectArr == NULL) { return; } linkPtr = Blt_ChainFirstLink(tablePtr->columnInfo.chainPtr); rcPtr = Blt_ChainGetValue(linkPtr); startX = rcPtr->offset; linkPtr = Blt_ChainLastLink(tablePtr->columnInfo.chainPtr); rcPtr = Blt_ChainGetValue(linkPtr); endX = (rcPtr->offset + rcPtr->size); linkPtr = Blt_ChainFirstLink(tablePtr->rowInfo.chainPtr); rcPtr = Blt_ChainGetValue(linkPtr); startY = rcPtr->offset; linkPtr = Blt_ChainLastLink(tablePtr->rowInfo.chainPtr); rcPtr = Blt_ChainGetValue(linkPtr); endY = (rcPtr->offset + rcPtr->size); count = 0; /* Reset segment counter */ rectPtr = rectArr; for (linkPtr = Blt_ChainFirstLink(tablePtr->rowInfo.chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); if (rcPtr->pad.side1 > 0) { rectPtr->x = startX; rectPtr->y = rcPtr->offset; rectPtr->height = rcPtr->pad.side1; rectPtr->width = endX - startX - 1; rectPtr++, count++; } if (rcPtr->pad.side2 > 0) { rectPtr->x = startX; rectPtr->y = rcPtr->offset + rcPtr->size - rcPtr->pad.side2 - 1; rectPtr->height = rcPtr->pad.side2; rectPtr->width = endX - startX - 1; rectPtr++, count++; } } for (linkPtr = Blt_ChainFirstLink(tablePtr->columnInfo.chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); if (rcPtr->pad.side1 > 0) { rectPtr->x = rcPtr->offset; rectPtr->y = startY; rectPtr->height = endY - startY - 1; rectPtr->width = rcPtr->pad.side1; rectPtr++, count++; } if (rcPtr->pad.side2 > 0) { rectPtr->x = rcPtr->offset + rcPtr->size - rcPtr->pad.side2; rectPtr->y = startY; rectPtr->height = endY - startY - 1; rectPtr->width = rcPtr->pad.side2; rectPtr++, count++; } } if (count == 0) { Blt_Free(rectArr); return; } tedPtr->padRectArr = rectArr; tedPtr->nPadRects = count; } static void LayoutEntries(tedPtr) Ted *tedPtr; { Entry *entryPtr; XRectangle *rectArr; int needed; int count; Blt_ChainLink *linkPtr; if (tedPtr->widgetPadRectArr != NULL) { Blt_Free(tedPtr->widgetPadRectArr); tedPtr->widgetPadRectArr = NULL; } tedPtr->nWidgetPadRects = 0; needed = Blt_ChainGetLength(tedPtr->tablePtr->chainPtr); rectArr = Blt_Calloc(needed, sizeof(XRectangle)); if (rectArr == NULL) { return; } /* Draw any entry windows */ count = 0; for (linkPtr = Blt_ChainFirstLink(tedPtr->tablePtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { entryPtr = Blt_ChainGetValue(linkPtr); if ((PADDING(entryPtr->padX) + PADDING(entryPtr->padY)) == 0) { continue; } rectArr[count].x = Tk_X(entryPtr->tkwin) - entryPtr->padLeft; rectArr[count].y = Tk_Y(entryPtr->tkwin) - entryPtr->padTop; rectArr[count].width = Tk_Width(entryPtr->tkwin) + PADDING(entryPtr->padX); rectArr[count].height = Tk_Height(entryPtr->tkwin) + PADDING(entryPtr->padY); count++; } if (count == 0) { Blt_Free(rectArr); return; } tedPtr->widgetPadRectArr = rectArr; tedPtr->nWidgetPadRects = count; } static void LayoutControlEntries(tedPtr) Ted *tedPtr; { Entry *entryPtr; XRectangle *rectArr; int needed; int count; Table *tablePtr = tedPtr->tablePtr; Blt_ChainLink *linkPtr; RowColumn *rcPtr; if (tedPtr->cntlRectArr != NULL) { Blt_Free(tedPtr->cntlRectArr); tedPtr->cntlRectArr = NULL; } tedPtr->nCntlRects = 0; needed = (tablePtr->nRows + tablePtr->nColumns); rectArr = Blt_Calloc(needed, sizeof(XRectangle)); if (rectArr == NULL) { return; } /* Draw any entry windows */ count = 0; for (linkPtr = Blt_ChainFirstLink(tablePtr->columnInfo.chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); entryPtr = rcPtr->control; if (entryPtr != NULL) { rectArr[count].x = Tk_X(entryPtr->tkwin) - entryPtr->padLeft; rectArr[count].y = Tk_Y(entryPtr->tkwin) - entryPtr->padTop; rectArr[count].width = Tk_Width(entryPtr->tkwin) + PADDING(entryPtr->padX); rectArr[count].height = Tk_Height(entryPtr->tkwin) + PADDING(entryPtr->padY); count++; } } for (linkPtr = Blt_ChainFirstLink(tablePtr->rowInfo.chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); entryPtr = rcPtr->control; if (entryPtr != NULL) { rectArr[count].x = Tk_X(entryPtr->tkwin) - entryPtr->padLeft; rectArr[count].y = Tk_Y(entryPtr->tkwin) - entryPtr->padTop; rectArr[count].width = Tk_Width(entryPtr->tkwin) + PADDING(entryPtr->padX); rectArr[count].height = Tk_Height(entryPtr->tkwin) + PADDING(entryPtr->padY); count++; } } if (count == 0) { Blt_Free(rectArr); return; } tedPtr->cntlRectArr = rectArr; tedPtr->nCntlRects = count; } static void LayoutButtons(tedPtr) Ted *tedPtr; { int needed; XRectangle *rectArr; Table *tablePtr; Blt_ChainLink *linkPtr; RowColumn *rcPtr; int count; tablePtr = tedPtr->tablePtr; if ((tablePtr->nRows == 0) || (tablePtr->nColumns == 0)) { if (tedPtr->rectArr != NULL) { Blt_Free(tedPtr->rectArr); } tedPtr->rectArr = NULL; tedPtr->nRects = 0; return; /* Nothing to display, empty table */ } needed = 2 * (tablePtr->nRows + tablePtr->nColumns); rectArr = Blt_Calloc(needed, sizeof(XRectangle)); if (rectArr == NULL) { return; /* Can't allocate rectangles */ } count = 0; for (linkPtr = Blt_ChainFirstLink(tablePtr->rowInfo.chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); rectArr[count].x = 0; rectArr[count].y = rcPtr->offset - rcPtr->pad.side1; rectArr[count].width = tedPtr->buttonHeight; rectArr[count].height = rcPtr->size - 2; count++; rectArr[count].x = Tk_Width(tedPtr->tkwin) - tedPtr->buttonHeight; rectArr[count].y = rcPtr->offset - rcPtr->pad.side1; rectArr[count].width = tedPtr->buttonHeight; rectArr[count].height = rcPtr->size - 2; count++; } for (linkPtr = Blt_ChainFirstLink(tablePtr->columnInfo.chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rcPtr = Blt_ChainGetValue(linkPtr); rectArr[count].x = rcPtr->offset - rcPtr->pad.side1; rectArr[count].y = 0; rectArr[count].width = rcPtr->size - 2; rectArr[count].height = tedPtr->buttonHeight; count++; rectArr[count].x = rcPtr->offset - rcPtr->pad.side1; rectArr[count].y = Tk_Height(tedPtr->tkwin) - tedPtr->buttonHeight; rectArr[count].width = rcPtr->size - 2; rectArr[count].height = tedPtr->buttonHeight; count++; } assert(count == needed); if (tedPtr->rectArr != NULL) { Blt_Free(tedPtr->rectArr); } tedPtr->rectArr = rectArr; tedPtr->nRects = count; } static void DisplayTed(clientData) ClientData clientData; { Ted *tedPtr = (Ted *) clientData; Tk_Window master; Tk_Window tkwin; Blt_ChainLink *linkPtr; EntryRep *repPtr; Drawable drawable; Pixmap pixmap; #ifdef notdef fprintf(stderr, "display grid\n"); #endif tedPtr->flags &= ~REDRAW_PENDING; if (!Tk_IsMapped(tedPtr->tkwin)) { return; } /* * Check if the master window has changed size and resize the * grid and input windows accordingly. */ master = tedPtr->tablePtr->tkwin; if ((Tk_Width(master) != Tk_Width(tedPtr->tkwin)) || (Tk_Height(master) != Tk_Height(tedPtr->tkwin))) { #ifdef notdef fprintf(stderr, "resizing windows\n"); #endif Tk_ResizeWindow(tedPtr->tkwin, Tk_Width(master), Tk_Height(master)); Tk_ResizeWindow(tedPtr->input, Tk_Width(master), Tk_Height(master)); if (tedPtr->inputIsSibling) { Tk_MoveWindow(tedPtr->input, Tk_X(master), Tk_X(master)); } tedPtr->flags |= LAYOUT_PENDING; } if (tedPtr->flags & LAYOUT_PENDING) { #ifdef notdef fprintf(stderr, "layout of grid\n"); #endif LayoutPads(tedPtr); LayoutEntries(tedPtr); LayoutControlEntries(tedPtr); LayoutGrid(tedPtr); LayoutButtons(tedPtr); tedPtr->flags &= ~LAYOUT_PENDING; } tkwin = tedPtr->tkwin; pixmap = None; /* Suppress compiler warning. */ drawable = Tk_WindowId(tkwin); if (tedPtr->doubleBuffer) { /* Create an off-screen pixmap for semi-smooth scrolling. */ pixmap = Tk_GetPixmap(tedPtr->display, Tk_WindowId(tkwin), Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin)); drawable = pixmap; } /* Clear the background of the grid */ XFillRectangle(Tk_Display(tkwin), drawable, tedPtr->fillGC, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin)); /* Draw the row and column buttons */ if (tedPtr->nRects > 0) { int i; for (i = 0; i < tedPtr->nRects; i++) { Blt_Fill3DRectangle(tkwin, drawable, tedPtr->border, tedPtr->rectArr[i].x, tedPtr->rectArr[i].y, tedPtr->rectArr[i].width, tedPtr->rectArr[i].height, tedPtr->borderWidth, tedPtr->relief); } #ifdef notdef XFillRectangles(tedPtr->display, drawable, tedPtr->rectGC, tedPtr->rectArr, tedPtr->nRects); XDrawRectangles(tedPtr->display, drawable, tedPtr->drawGC, tedPtr->rectArr, tedPtr->nRects); #endif } if (tedPtr->nPadRects > 0) { XFillRectangles(tedPtr->display, drawable, tedPtr->padRectGC, tedPtr->padRectArr, tedPtr->nPadRects); } if (tedPtr->spanActive) { XFillRectangles(tedPtr->display, drawable, tedPtr->spanGC, tedPtr->activeRectArr, 1); XFillRectangles(tedPtr->display, drawable, tedPtr->drawGC, tedPtr->activeRectArr + 1, 4); } if (tedPtr->nWidgetPadRects > 0) { XFillRectangles(tedPtr->display, drawable, tedPtr->attributes.fillGC, tedPtr->widgetPadRectArr, tedPtr->nWidgetPadRects); } if (tedPtr->nCntlRects > 0) { XFillRectangles(tedPtr->display, drawable, tedPtr->attributes.cntlGC, tedPtr->cntlRectArr, tedPtr->nCntlRects); } /* Draw the grid lines */ if (tedPtr->nSegs > 0) { XDrawSegments(tedPtr->display, drawable, tedPtr->drawGC, tedPtr->segArr, tedPtr->nSegs); } #ifndef notdef /* Draw any entry windows */ for (linkPtr = Blt_ChainFirstLink(tedPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { repPtr = Blt_ChainGetValue(linkPtr); if (repPtr->mapped) { DisplayEntry(repPtr); } } #endif if (tedPtr->doubleBuffer) { XCopyArea(tedPtr->display, drawable, Tk_WindowId(tkwin), tedPtr->fillGC, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, 0); Tk_FreePixmap(tedPtr->display, pixmap); } } static void DrawEditor(editPtr) Editor *editPtr; { Ted *tedPtr = (Ted *) editPtr; tedPtr->flags |= LAYOUT_PENDING; if ((tedPtr->tkwin != NULL) && !(tedPtr->flags & REDRAW_PENDING)) { tedPtr->flags |= REDRAW_PENDING; #ifdef notdef fprintf(stderr, "from draw editor\n"); #endif Tcl_DoWhenIdle(DisplayTed, tedPtr); } } static void DestroyEditor(destroyData) DestroyData destroyData; { Ted *tedPtr = (Ted *) destroyData; tedPtr->tkwin = NULL; if (tedPtr->flags & REDRAW_PENDING) { Tcl_CancelIdleCall(DisplayTed, tedPtr); } Tcl_EventuallyFree(tedPtr, DestroyTed); } /* * ---------------------------------------------------------------------------- * * EditOp -- * * Processes an argv/argc list of table entries to add and configure * new widgets into the table. A table entry consists of the * window path name, table index, and optional configuration options. * The first argument in the argv list is the name of the table. If * no table exists for the given window, a new one is created. * * Results: * Returns a standard Tcl result. If an error occurred, TCL_ERROR is * returned and an error message is left in interp->result. * * Side Effects: * Memory is allocated, a new master table is possibly created, etc. * The table is re-computed and arranged at the next idle point. * * ---------------------------------------------------------------------------- */ static int EditOp(dataPtr, interp, argc, argv) TableInterpData *dataPtr; /* Interpreter-specific data. */ Tcl_Interp *interp; /* Interpreter to return list of names to */ int argc; /* Number of arguments */ char **argv; { Table *tablePtr; Ted *tedPtr; if (Blt_GetTable(dataPtr, interp, argv[2], &tablePtr) != TCL_OK) { return TCL_ERROR; } if (tablePtr->editPtr != NULL) { /* Already editing this table */ tedPtr = (Ted *) tablePtr->editPtr; } else { tedPtr = CreateTed(tablePtr, interp); if (tedPtr == NULL) { return TCL_ERROR; } } if (ConfigureTed(tedPtr, argc - 3, argv + 3, 0) != TCL_OK) { tedPtr->tkwin = NULL; if (tedPtr->flags & REDRAW_PENDING) { Tcl_CancelIdleCall(DisplayTed, tedPtr); } Tcl_EventuallyFree(tedPtr, DestroyTed); return TCL_ERROR; } /* Rearrange the table */ if (!(tablePtr->flags & ARRANGE_PENDING)) { tablePtr->flags |= ARRANGE_PENDING; Tcl_DoWhenIdle(tablePtr->arrangeProc, tablePtr); } interp->result = Tk_PathName(tedPtr->tkwin); tedPtr->flags |= LAYOUT_PENDING; EventuallyRedraw(tedPtr); return TCL_OK; } /* * ---------------------------------------------------------------------------- * * CgetCmd -- * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then interp->result contains an error message. * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ static int CgetOp(dataPtr, interp, argc, argv) TableInterpData *dataPtr; /* Interpreter-specific data. */ Tcl_Interp *interp; /* Interpreter to report results back to */ int argc; /* Not used. */ char **argv; /* Option-value pairs */ { Ted *tedPtr; tedPtr = FindEditor(dataPtr, interp, argv[2]); if (tedPtr == NULL) { return TCL_ERROR; } return Tk_ConfigureValue(interp, tedPtr->tkwin, configSpecs, (char *)tedPtr, argv[3], 0); } /* * ---------------------------------------------------------------------------- * * ConfigureCmd -- * * This procedure is called to process an argv/argc list in order to * configure the table geometry manager. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then interp->result contains an error message. * * Side effects: * Table configuration options (padx, pady, rows, columns, etc) get * set. The table is recalculated and arranged at the next idle * point. * * ---------------------------------------------------------------------------- */ static int ConfigureOp(dataPtr, interp, argc, argv) TableInterpData *dataPtr; /* Interpreter-specific data. */ Tcl_Interp *interp; /* Interpreter to report results back to */ int argc; char **argv; /* Option-value pairs */ { Ted *tedPtr; tedPtr = FindEditor(dataPtr, interp, argv[2]); if (tedPtr == NULL) { return TCL_ERROR; } if (argc == 3) { return Tk_ConfigureInfo(interp, tedPtr->tkwin, configSpecs, (char *)tedPtr, (char *)NULL, 0); } else if (argc == 4) { return Tk_ConfigureInfo(interp, tedPtr->tkwin, configSpecs, (char *)tedPtr, argv[3], 0); } if (ConfigureTed(tedPtr, argc - 3, argv + 3, TK_CONFIG_ARGV_ONLY) != TCL_OK) { return TCL_ERROR; } EventuallyRedraw(tedPtr); return TCL_OK; } /* * ---------------------------------------------------------------------------- * * SelectOp -- * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ static int SelectOp(dataPtr, interp, argc, argv) TableInterpData *dataPtr; /* Interpreter-specific data. */ Tcl_Interp *interp; /* Interpreter to return list of names to */ int argc; /* Not used. */ char **argv; { Table *tablePtr; Ted *tedPtr; Entry *entryPtr; int active; int x, y, width, height; int ix, iy; Blt_ChainLink *linkPtr; Tk_Window tkwin; /* ted select master @x,y */ tkwin = Tk_MainWindow(interp); tedPtr = FindEditor(dataPtr, interp, argv[2]); if (tedPtr == NULL) { return TCL_ERROR; } if (Blt_GetXY(interp, tkwin, argv[3], &ix, &iy) != TCL_OK) { return TCL_ERROR; } tablePtr = tedPtr->tablePtr; active = 0; for (linkPtr = Blt_ChainFirstLink(tablePtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { entryPtr = Blt_ChainGetValue(linkPtr); x = entryPtr->x - entryPtr->padX.side1; y = entryPtr->y - entryPtr->padY.side1; width = Tk_Width(entryPtr->tkwin) + PADDING(entryPtr->padX); height = Tk_Height(entryPtr->tkwin) + PADDING(entryPtr->padY); if ((ix >= x) && (ix <= (x + width)) && (iy >= y) && (iy <= (y + height))) { int left, right, top, bottom; int last; int grip; RowColumn *rcPtr; last = entryPtr->column.rcPtr->index + entryPtr->column.span - 1; linkPtr = Blt_ChainGetNthLink(tablePtr->columnInfo.chainPtr, last); rcPtr = Blt_ChainGetValue(linkPtr); /* Calculate the span rectangle */ left = (entryPtr->column.rcPtr->offset - entryPtr->column.rcPtr->pad.side1); right = (rcPtr->offset - rcPtr->pad.side1) + rcPtr->size; top = (entryPtr->row.rcPtr->offset - entryPtr->row.rcPtr->pad.side1); last = entryPtr->row.rcPtr->index + entryPtr->row.span - 1; linkPtr = Blt_ChainGetNthLink(tablePtr->rowInfo.chainPtr, last); rcPtr = Blt_ChainGetValue(linkPtr); bottom = (rcPtr->offset - rcPtr->pad.side1) + rcPtr->size; tedPtr->activeRectArr[0].x = left; tedPtr->activeRectArr[0].y = top; tedPtr->activeRectArr[0].width = (right - left); tedPtr->activeRectArr[0].height = (bottom - top); grip = tedPtr->gripSize; tedPtr->activeRectArr[1].x = (left + right - grip) / 2; tedPtr->activeRectArr[1].y = top; tedPtr->activeRectArr[1].width = grip - 1; tedPtr->activeRectArr[1].height = grip - 1; tedPtr->activeRectArr[2].x = left; tedPtr->activeRectArr[2].y = (top + bottom - grip) / 2; tedPtr->activeRectArr[2].width = grip - 1; tedPtr->activeRectArr[2].height = grip - 1; tedPtr->activeRectArr[3].x = (left + right - grip) / 2; tedPtr->activeRectArr[3].y = bottom - grip; tedPtr->activeRectArr[3].width = grip - 1; tedPtr->activeRectArr[3].height = grip - 1; tedPtr->activeRectArr[4].x = right - grip; tedPtr->activeRectArr[4].y = (top + bottom - grip) / 2; tedPtr->activeRectArr[4].width = grip - 1; tedPtr->activeRectArr[4].height = grip - 1; interp->result = Tk_PathName(entryPtr->tkwin); active = 1; break; } } if ((active) || (active != tedPtr->spanActive)) { tedPtr->spanActive = active; EventuallyRedraw(tedPtr); } return TCL_OK; } /* * ---------------------------------------------------------------------------- * * EditOp -- * * Processes an argv/argc list of table entries to add and configure * new widgets into the table. A table entry consists of the * window path name, table index, and optional configuration options. * The first argument in the argv list is the name of the table. If * no table exists for the given window, a new one is created. * * Results: * Returns a standard Tcl result. If an error occurred, TCL_ERROR is * returned and an error message is left in interp->result. * * Side Effects: * Memory is allocated, a new master table is possibly created, etc. * The table is re-computed and arranged at the next idle point. * * ---------------------------------------------------------------------------- */ static int RepOp(dataPtr, interp, argc, argv) TableInterpData *dataPtr; /* Interpreter-specific data. */ Tcl_Interp *interp; /* Interpreter to return list of names to */ int argc; /* Number of arguments */ char **argv; { Tk_Window tkwin; Table *tablePtr; Ted *tedPtr; /* ted rep master index */ tkwin = Tk_NameToWindow(interp, argv[3], Tk_MainWindow(interp)); if (tkwin == NULL) { return TCL_ERROR; } if (Blt_GetTable(dataPtr, interp, argv[2], &tablePtr) != TCL_OK) { return TCL_ERROR; } if (tablePtr->editPtr != NULL) { /* Already editing this table */ tedPtr = (Ted *) tablePtr->editPtr; } else { tedPtr = CreateTed(tablePtr, interp); if (tedPtr == NULL) { return TCL_ERROR; } } if (ConfigureTed(tedPtr, argc - 3, argv + 3, 0) != TCL_OK) { tedPtr->tkwin = NULL; if (tedPtr->flags & REDRAW_PENDING) { Tcl_CancelIdleCall(DisplayTed, tedPtr); } Tcl_EventuallyFree(tedPtr, DestroyTed); return TCL_ERROR; } /* Rearrange the table */ if (!(tablePtr->flags & ARRANGE_PENDING)) { tablePtr->flags |= ARRANGE_PENDING; Tcl_DoWhenIdle(tablePtr->arrangeProc, tablePtr); } interp->result = Tk_PathName(tedPtr->tkwin); tedPtr->flags |= LAYOUT_PENDING; EventuallyRedraw(tedPtr); return TCL_OK; } /* * ---------------------------------------------------------------------------- * * Command options for the table editor. * * The fields for Blt_OperSpec are as follows: * * - option name * - minimum number of characters required to disambiguate the option name. * - function associated with command option. * - minimum number of arguments required. * - maximum number of arguments allowed (0 indicates no limit). * - usage string * * ---------------------------------------------------------------------------- */ static Blt_OpSpec opSpecs[] = { {"cget", 2, (Blt_Op)CgetOp, 4, 4, "master option",}, {"configure", 2, (Blt_Op)ConfigureOp, 3, 0, "master ?option...?",}, {"edit", 1, (Blt_Op)EditOp, 3, 0, "master ?options...?",}, {"rep", 1, (Blt_Op)RepOp, 2, 0, "master index ?options...?",}, {"select", 1, (Blt_Op)SelectOp, 4, 0, "master @x,y",}, /* {"forget", 1, (Blt_Op)ForgetOp, 3, 0, "master ?master...?",}, {"index", 1, (Blt_Op)IndexOp, 3, 0, "master ?item...?",}, */ }; static int nSpecs = sizeof(opSpecs) / sizeof(Blt_OpSpec); /* * ---------------------------------------------------------------------------- * * TedCmd -- * * This procedure is invoked to process the Tcl command that * corresponds to the table geometry manager. See the user * documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * * ---------------------------------------------------------------------------- */ static int TedCmd(clientData, interp, argc, argv) ClientData clientData; /* Thread-specific data. */ Tcl_Interp *interp; int argc; char **argv; { Blt_Op proc; int result; proc = Blt_GetOp(interp, nSpecs, opSpecs, BLT_OP_ARG1, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (clientData, interp, argc, argv); return result; } static TableData * GetTableInterpData(interp) Tcl_Interp *interp; { TableData *dataPtr; Tcl_InterpDeleteProc *proc; dataPtr = (TableData *)Tcl_GetAssocData(interp, TABLE_THREAD_KEY, &proc); assert(dataPtr); return dataPtr; } /* * ---------------------------------------------------------------------------- * * Blt_TedInit -- * * This procedure is invoked to initialize the Tcl command that * corresponds to the table geometry manager. * * Results: * None. * * Side effects: * Creates the new command and adds an entry into a global Tcl * associative array. * * --------------------------------------------------------------------------- */ int Blt_TedInit(interp) Tcl_Interp *interp; { static Blt_CmdSpec cmdSpec = {"ted", TedCmd, }; TableData *dataPtr; dataPtr = GetTableInterpData(interp); cmdSpec.clientData = dataPtr; if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) { return TCL_ERROR; } return TCL_OK; } blt-2.4z.orig/src/bltText.c0100644000175000017500000006227207526260720014344 0ustar dokodoko /* * bltText.c -- * * This module implements multi-line, rotate-able text for the BLT toolkit. * * Copyright 1993-1998 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. */ #include "bltInt.h" #include #include "bltImage.h" #define WINDEBUG 0 static Blt_HashTable bitmapGCTable; static int initialized; static void DrawTextLayout(display, drawable, gc, font, x, y, textPtr) Display *display; Drawable drawable; GC gc; Tk_Font font; register int x, y; /* Origin of text */ TextLayout *textPtr; { register TextFragment *fragPtr; register int i; fragPtr = textPtr->fragArr; for (i = 0; i < textPtr->nFrags; i++, fragPtr++) { #if HAVE_UTF Tk_DrawChars(display, drawable, gc, font, fragPtr->text, fragPtr->count, x + fragPtr->x, y + fragPtr->y); #else XDrawString(display, drawable, gc, x + fragPtr->x, y + fragPtr->y, fragPtr->text, fragPtr->count); #endif /*HAVE_UTF*/ } } /* * ----------------------------------------------------------------- * * Blt_GetTextLayout -- * * Get the extents of a possibly multiple-lined text string. * * Results: * Returns via *widthPtr* and *heightPtr* the dimensions of * the text string. * * ----------------------------------------------------------------- */ TextLayout * Blt_GetTextLayout(string, tsPtr) char string[]; TextStyle *tsPtr; { int maxHeight, maxWidth; int count; /* Count # of characters on each line */ int nFrags; int width; /* Running dimensions of the text */ TextFragment *fragPtr; TextLayout *textPtr; int lineHeight; int size; register char *p; register int i; Tk_FontMetrics fontMetrics; Tk_GetFontMetrics(tsPtr->font, &fontMetrics); lineHeight = fontMetrics.linespace + tsPtr->leader + tsPtr->shadow.offset; nFrags = 0; for (p = string; *p != '\0'; p++) { if (*p == '\n') { nFrags++; } } if ((p != string) && (*(p - 1) != '\n')) { nFrags++; } size = sizeof(TextLayout) + (sizeof(TextFragment) * (nFrags - 1)); textPtr = Blt_Calloc(1, size); textPtr->nFrags = nFrags; nFrags = count = 0; width = maxWidth = 0; maxHeight = tsPtr->padTop; fragPtr = textPtr->fragArr; for (p = string; *p != '\0'; p++) { if (*p == '\n') { if (count > 0) { width = Tk_TextWidth(tsPtr->font, string, count) + tsPtr->shadow.offset; if (width > maxWidth) { maxWidth = width; } } fragPtr->width = width; fragPtr->count = count; fragPtr->y = maxHeight + fontMetrics.ascent; fragPtr->text = string; fragPtr++; nFrags++; maxHeight += lineHeight; string = p + 1; /* Start the string on the next line */ count = 0; /* Reset to indicate the start of a new line */ continue; } count++; } if (nFrags < textPtr->nFrags) { width = Tk_TextWidth(tsPtr->font, string, count) + tsPtr->shadow.offset; if (width > maxWidth) { maxWidth = width; } fragPtr->width = width; fragPtr->count = count; fragPtr->y = maxHeight + fontMetrics.ascent; fragPtr->text = string; maxHeight += lineHeight; nFrags++; } maxHeight += tsPtr->padBottom; maxWidth += PADDING(tsPtr->padX); fragPtr = textPtr->fragArr; for (i = 0; i < nFrags; i++, fragPtr++) { switch (tsPtr->justify) { default: case TK_JUSTIFY_LEFT: /* No offset for left justified text strings */ fragPtr->x = tsPtr->padLeft; break; case TK_JUSTIFY_RIGHT: fragPtr->x = (maxWidth - fragPtr->width) - tsPtr->padRight; break; case TK_JUSTIFY_CENTER: fragPtr->x = (maxWidth - fragPtr->width) / 2; break; } } textPtr->width = maxWidth; textPtr->height = maxHeight - tsPtr->leader; return textPtr; } /* * ----------------------------------------------------------------- * * Blt_GetTextExtents -- * * Get the extents of a possibly multiple-lined text string. * * Results: * Returns via *widthPtr* and *heightPtr* the dimensions of * the text string. * * ----------------------------------------------------------------- */ void Blt_GetTextExtents(tsPtr, string, widthPtr, heightPtr) TextStyle *tsPtr; char *string; int *widthPtr, *heightPtr; { int count; /* Count # of characters on each line */ int width, height; int w, lineHeight; register char *p; Tk_FontMetrics fontMetrics; if (string == NULL) { return; /* NULL string? */ } Tk_GetFontMetrics(tsPtr->font, &fontMetrics); lineHeight = fontMetrics.linespace + tsPtr->leader + tsPtr->shadow.offset; count = 0; width = height = 0; for (p = string; *p != '\0'; p++) { if (*p == '\n') { if (count > 0) { w = Tk_TextWidth(tsPtr->font, string, count) + tsPtr->shadow.offset; if (w > width) { width = w; } } height += lineHeight; string = p + 1; /* Start the string on the next line */ count = 0; /* Reset to indicate the start of a new line */ continue; } count++; } if ((count > 0) && (*(p - 1) != '\n')) { height += lineHeight; w = Tk_TextWidth(tsPtr->font, string, count) + tsPtr->shadow.offset; if (w > width) { width = w; } } *widthPtr = width + PADDING(tsPtr->padX); *heightPtr = height + PADDING(tsPtr->padY); } /* * ----------------------------------------------------------------- * * Blt_GetBoundingBox * * 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 Blt_GetBoundingBox(width, height, theta, rotWidthPtr, rotHeightPtr, bbox) int width, height; /* Unrotated region */ double theta; /* Rotation of box */ double *rotWidthPtr, *rotHeightPtr; /* (out) Bounding box region */ Point2D *bbox; /* (out) Points of the rotated box */ { register int i; double sinTheta, cosTheta; double xMax, yMax; register double x, y; Point2D corner[4]; theta = FMOD(theta, 360.0); if (FMOD(theta, (double)90.0) == 0.0) { int ll, ur, ul, lr; double rotWidth, rotHeight; int quadrant; /* Handle right-angle rotations specifically */ quadrant = (int)(theta / 90.0); switch (quadrant) { case ROTATE_270: /* 270 degrees */ ul = 3, ur = 0, lr = 1, ll = 2; rotWidth = (double)height; rotHeight = (double)width; break; case ROTATE_90: /* 90 degrees */ ul = 1, ur = 2, lr = 3, ll = 0; rotWidth = (double)height; rotHeight = (double)width; break; case ROTATE_180: /* 180 degrees */ ul = 2, ur = 3, lr = 0, ll = 1; rotWidth = (double)width; rotHeight = (double)height; break; default: case ROTATE_0: /* 0 degrees */ ul = 0, ur = 1, lr = 2, ll = 3; rotWidth = (double)width; rotHeight = (double)height; break; } if (bbox != NULL) { x = rotWidth * 0.5; 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 */ 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; theta = (-theta / 180.0) * M_PI; sinTheta = sin(theta), cosTheta = cos(theta); xMax = yMax = 0.0; /* Rotate the four corners and find the maximum X and Y coordinates */ for (i = 0; i < 4; i++) { x = (corner[i].x * cosTheta) - (corner[i].y * sinTheta); y = (corner[i].x * sinTheta) + (corner[i].y * cosTheta); if (x > xMax) { xMax = x; } if (y > yMax) { yMax = y; } if (bbox != NULL) { bbox[i].x = x; bbox[i].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_TranslateAnchor -- * * Translate the coordinates of a given bounding box based * upon the anchor specified. The anchor indicates where * the given xy position is in relation to the bounding box. * * nw --- n --- ne * | | * w center e * | | * sw --- s --- 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. * * ----------------------------------------------------------------- */ void Blt_TranslateAnchor(x, y, width, height, anchor, transXPtr, transYPtr) int x, y; /* Window coordinates of anchor */ int width, height; /* Extents of the bounding box */ Tk_Anchor anchor; /* Direction of the anchor */ int *transXPtr, *transYPtr; { switch (anchor) { case TK_ANCHOR_NW: /* Upper left corner */ break; case TK_ANCHOR_W: /* Left center */ y -= (height / 2); break; case TK_ANCHOR_SW: /* Lower left corner */ y -= height; break; case TK_ANCHOR_N: /* Top center */ x -= (width / 2); break; case TK_ANCHOR_CENTER: /* Center */ x -= (width / 2); y -= (height / 2); break; case TK_ANCHOR_S: /* Bottom center */ x -= (width / 2); y -= height; break; case TK_ANCHOR_NE: /* Upper right corner */ x -= width; break; case TK_ANCHOR_E: /* Right center */ x -= width; y -= (height / 2); break; case TK_ANCHOR_SE: /* Lower right corner */ x -= width; y -= height; break; } *transXPtr = x; *transYPtr = y; } /* * ----------------------------------------------------------------- * * Blt_TranslatePoint -- * * Translate the coordinates of a given bounding box based * upon the anchor specified. The anchor indicates where * the given xy position is in relation to the bounding box. * * nw --- n --- ne * | | * w center e * | | * sw --- s --- 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 Blt_TranslatePoint(pointPtr, width, height, anchor) Point2D *pointPtr; /* Window coordinates of anchor */ int width, height; /* Extents of the bounding box */ Tk_Anchor anchor; /* Direction of the anchor */ { Point2D trans; trans = *pointPtr; switch (anchor) { case TK_ANCHOR_NW: /* Upper left corner */ break; case TK_ANCHOR_W: /* Left center */ trans.y -= (height * 0.5); break; case TK_ANCHOR_SW: /* Lower left corner */ trans.y -= height; break; case TK_ANCHOR_N: /* Top center */ trans.x -= (width * 0.5); break; case TK_ANCHOR_CENTER: /* Center */ trans.x -= (width * 0.5); trans.y -= (height * 0.5); break; case TK_ANCHOR_S: /* Bottom center */ trans.x -= (width * 0.5); trans.y -= height; break; case TK_ANCHOR_NE: /* Upper right corner */ trans.x -= width; break; case TK_ANCHOR_E: /* Right center */ trans.x -= width; trans.y -= (height * 0.5); break; case TK_ANCHOR_SE: /* Lower right corner */ trans.x -= width; trans.y -= height; break; } return trans; } /* * ----------------------------------------------------------------- * * Blt_CreateTextBitmap -- * * Draw a bitmap, using the the given window coordinates * as an anchor for the text bounding box. * * Results: * Returns the bitmap representing the text string. * * Side Effects: * Bitmap is drawn using the given font and GC in the * drawable at the given coordinates, anchor, and rotation. * * ----------------------------------------------------------------- */ Pixmap Blt_CreateTextBitmap(tkwin, textPtr, tsPtr, bmWidthPtr, bmHeightPtr) Tk_Window tkwin; TextLayout *textPtr; /* Text string to draw */ TextStyle *tsPtr; /* Text attributes: rotation, color, font, * linespacing, justification, etc. */ int *bmWidthPtr; int *bmHeightPtr; /* Extents of rotated text string */ { int width, height; Pixmap bitmap; Display *display; Window root; GC gc; #ifdef WIN32 HDC hDC; TkWinDCState state; #endif display = Tk_Display(tkwin); width = textPtr->width; height = textPtr->height; /* Create a temporary bitmap to contain the text string */ root = RootWindow(display, Tk_ScreenNumber(tkwin)); bitmap = Tk_GetPixmap(display, root, width, height, 1); assert(bitmap != None); if (bitmap == None) { return None; /* Can't allocate pixmap. */ } /* Clear the pixmap and draw the text string into it */ gc = Blt_GetBitmapGC(tkwin); #ifdef WIN32 hDC = TkWinGetDrawableDC(display, bitmap, &state); PatBlt(hDC, 0, 0, width, height, WHITENESS); TkWinReleaseDrawableDC(bitmap, hDC, &state); #else XSetForeground(display, gc, 0); XFillRectangle(display, bitmap, gc, 0, 0, width, height); #endif /* WIN32 */ XSetFont(display, gc, Tk_FontId(tsPtr->font)); XSetForeground(display, gc, 1); DrawTextLayout(display, bitmap, gc, tsPtr->font, 0, 0, textPtr); #ifdef WIN32 /* * Under Win32 when drawing into a bitmap, the bits are * reversed. Which is why we are inverting the bitmap here. */ hDC = TkWinGetDrawableDC(display, bitmap, &state); PatBlt(hDC, 0, 0, width, height, DSTINVERT); TkWinReleaseDrawableDC(bitmap, hDC, &state); #endif if (tsPtr->theta != 0.0) { Pixmap rotBitmap; /* Replace the text pixmap with a rotated one */ rotBitmap = Blt_RotateBitmap(tkwin, bitmap, width, height, tsPtr->theta, bmWidthPtr, bmHeightPtr); assert(rotBitmap); if (rotBitmap != None) { Tk_FreePixmap(display, bitmap); return rotBitmap; } } *bmWidthPtr = textPtr->width, *bmHeightPtr = textPtr->height; return bitmap; } /*LINTLIBRARY*/ void Blt_InitTextStyle(tsPtr) TextStyle *tsPtr; { /* Initialize these attributes to zero */ tsPtr->activeColor = (XColor *)NULL; tsPtr->anchor = TK_ANCHOR_CENTER; tsPtr->color = (XColor *)NULL; tsPtr->font = NULL; tsPtr->justify = TK_JUSTIFY_CENTER; tsPtr->leader = 0; tsPtr->padLeft = tsPtr->padRight = 0; tsPtr->padTop = tsPtr->padBottom = 0; tsPtr->shadow.color = (XColor *)NULL; tsPtr->shadow.offset = 0; tsPtr->state = 0; tsPtr->theta = 0.0; } void Blt_SetDrawTextStyle(tsPtr, font, gc, normalColor, activeColor, shadowColor, theta, anchor, justify, leader, shadowOffset) TextStyle *tsPtr; Tk_Font font; GC gc; XColor *normalColor, *activeColor, *shadowColor; double theta; Tk_Anchor anchor; Tk_Justify justify; int leader, shadowOffset; { Blt_InitTextStyle(tsPtr); tsPtr->activeColor = activeColor; tsPtr->anchor = anchor; tsPtr->color = normalColor; tsPtr->font = font; tsPtr->gc = gc; tsPtr->justify = justify; tsPtr->leader = leader; tsPtr->shadow.color = shadowColor; tsPtr->shadow.offset = shadowOffset; tsPtr->theta = theta; } void Blt_SetPrintTextStyle(tsPtr, font, fgColor, activeColor, shadowColor, theta, anchor, justify, leader, shadowOffset) TextStyle *tsPtr; Tk_Font font; XColor *fgColor, *activeColor, *shadowColor; double theta; Tk_Anchor anchor; Tk_Justify justify; int leader, shadowOffset; { Blt_InitTextStyle(tsPtr); tsPtr->color = fgColor; tsPtr->activeColor = activeColor; tsPtr->shadow.color = shadowColor; tsPtr->font = font; tsPtr->theta = theta; tsPtr->anchor = anchor; tsPtr->justify = justify; tsPtr->leader = leader; tsPtr->shadow.offset = shadowOffset; } /* * ----------------------------------------------------------------- * * Blt_DrawTextLayout -- * * Draw a text string, possibly rotated, using the the given * window coordinates as an anchor for the text bounding box. * If the text is not rotated, simply use the X text drawing * routines. Otherwise, generate a bitmap of the rotated text. * * Results: * Returns the x-coordinate to the right of the text. * * Side Effects: * Text string is drawn using the given font and GC at the * the given window coordinates. * * The Stipple, FillStyle, and TSOrigin fields of the GC are * modified for rotated text. This assumes the GC is private, * *not* shared (via Tk_GetGC) * * ----------------------------------------------------------------- */ void Blt_DrawTextLayout(tkwin, drawable, textPtr, tsPtr, x, y) Tk_Window tkwin; Drawable drawable; TextLayout *textPtr; TextStyle *tsPtr; /* Text attribute information */ int x, y; /* Window coordinates to draw text */ { int width, height; double theta; Display *display; Pixmap bitmap; int active; display = Tk_Display(tkwin); theta = FMOD(tsPtr->theta, (double)360.0); if (theta < 0.0) { theta += 360.0; } active = tsPtr->state & STATE_ACTIVE; if (theta == 0.0) { /* * This is the easy case of no rotation. Simply draw the text * using the standard drawing routines. Handle offset printing * for engraved (disabled) and shadowed text. */ width = textPtr->width, height = textPtr->height; Blt_TranslateAnchor(x, y, width, height, tsPtr->anchor, &x, &y); if (tsPtr->state & (STATE_DISABLED | STATE_EMPHASIS)) { TkBorder *borderPtr = (TkBorder *) tsPtr->border; XColor *color1, *color2; color1 = borderPtr->lightColor, color2 = borderPtr->darkColor; if (tsPtr->state & STATE_EMPHASIS) { XColor *hold; hold = color1, color1 = color2, color2 = hold; } if (color1 != NULL) { XSetForeground(display, tsPtr->gc, color1->pixel); } DrawTextLayout(display, drawable, tsPtr->gc, tsPtr->font, x + 1, y + 1, textPtr); if (color2 != NULL) { XSetForeground(display, tsPtr->gc, color2->pixel); } DrawTextLayout(display, drawable, tsPtr->gc, tsPtr->font, x, y, textPtr); /* Reset the foreground color back to its original setting, * so not to invalidate the GC cache. */ XSetForeground(display, tsPtr->gc, tsPtr->color->pixel); return; /* Done */ } if ((tsPtr->shadow.offset > 0) && (tsPtr->shadow.color != NULL)) { XSetForeground(display, tsPtr->gc, tsPtr->shadow.color->pixel); DrawTextLayout(display, drawable, tsPtr->gc, tsPtr->font, x + tsPtr->shadow.offset, y + tsPtr->shadow.offset, textPtr); XSetForeground(display, tsPtr->gc, tsPtr->color->pixel); } if (active) { XSetForeground(display, tsPtr->gc, tsPtr->activeColor->pixel); } DrawTextLayout(display, drawable, tsPtr->gc, tsPtr->font, x, y, textPtr); if (active) { XSetForeground(display, tsPtr->gc, tsPtr->color->pixel); } return; /* Done */ } #ifdef WIN32 if (Blt_DrawRotatedText(display, drawable, x, y, theta, tsPtr, textPtr)) { return; } #endif /* * Rotate the text by writing the text into a bitmap and rotating * the bitmap. Set the clip mask and origin in the GC first. And * make sure we restore the GC because it may be shared. */ tsPtr->theta = theta; bitmap = Blt_CreateTextBitmap(tkwin, textPtr, tsPtr, &width, &height); if (bitmap == None) { return; } Blt_TranslateAnchor(x, y, width, height, tsPtr->anchor, &x, &y); #ifdef notdef theta = FMOD(theta, (double)90.0); #endif XSetClipMask(display, tsPtr->gc, bitmap); if (tsPtr->state & (STATE_DISABLED | STATE_EMPHASIS)) { TkBorder *borderPtr = (TkBorder *) tsPtr->border; XColor *color1, *color2; color1 = borderPtr->lightColor, color2 = borderPtr->darkColor; if (tsPtr->state & STATE_EMPHASIS) { XColor *hold; hold = color1, color1 = color2, color2 = hold; } if (color1 != NULL) { XSetForeground(display, tsPtr->gc, color1->pixel); } XSetClipOrigin(display, tsPtr->gc, x + 1, y + 1); XCopyPlane(display, bitmap, drawable, tsPtr->gc, 0, 0, width, height, x + 1, y + 1, 1); if (color2 != NULL) { XSetForeground(display, tsPtr->gc, color2->pixel); } XSetClipOrigin(display, tsPtr->gc, x, y); XCopyPlane(display, bitmap, drawable, tsPtr->gc, 0, 0, width, height, x, y, 1); XSetForeground(display, tsPtr->gc, tsPtr->color->pixel); } else { if ((tsPtr->shadow.offset > 0) && (tsPtr->shadow.color != NULL)) { XSetClipOrigin(display, tsPtr->gc, x + tsPtr->shadow.offset, y + tsPtr->shadow.offset); XSetForeground(display, tsPtr->gc, tsPtr->shadow.color->pixel); XCopyPlane(display, bitmap, drawable, tsPtr->gc, 0, 0, width, height, x + tsPtr->shadow.offset, y + tsPtr->shadow.offset, 1); XSetForeground(display, tsPtr->gc, tsPtr->color->pixel); } if (active) { XSetForeground(display, tsPtr->gc, tsPtr->activeColor->pixel); } XSetClipOrigin(display, tsPtr->gc, x, y); XCopyPlane(display, bitmap, drawable, tsPtr->gc, 0, 0, width, height, x, y, 1); if (active) { XSetForeground(display, tsPtr->gc, tsPtr->color->pixel); } } XSetClipMask(display, tsPtr->gc, None); Tk_FreePixmap(display, bitmap); } void Blt_DrawText2(tkwin, drawable, string, tsPtr, x, y, areaPtr) Tk_Window tkwin; Drawable drawable; char string[]; TextStyle *tsPtr; /* Text attribute information */ int x, y; /* Window coordinates to draw text */ Dim2D *areaPtr; { TextLayout *textPtr; int width, height; double theta; if ((string == NULL) || (*string == '\0')) { return; /* Empty string, do nothing */ } textPtr = Blt_GetTextLayout(string, tsPtr); Blt_DrawTextLayout(tkwin, drawable, textPtr, tsPtr, x, y); theta = FMOD(tsPtr->theta, (double)360.0); if (theta < 0.0) { theta += 360.0; } width = textPtr->width; height = textPtr->height; if (theta != 0.0) { double rotWidth, rotHeight; Blt_GetBoundingBox(width, height, theta, &rotWidth, &rotHeight, (Point2D *)NULL); width = ROUND(rotWidth); height = ROUND(rotHeight); } areaPtr->width = width; areaPtr->height = height; Blt_Free(textPtr); } void Blt_DrawText(tkwin, drawable, string, tsPtr, x, y) Tk_Window tkwin; Drawable drawable; char string[]; TextStyle *tsPtr; /* Text attribute information */ int x, y; /* Window coordinates to draw text */ { TextLayout *textPtr; if ((string == NULL) || (*string == '\0')) { return; /* Empty string, do nothing */ } textPtr = Blt_GetTextLayout(string, tsPtr); Blt_DrawTextLayout(tkwin, drawable, textPtr, tsPtr, x, y); Blt_Free(textPtr); } GC Blt_GetBitmapGC(tkwin) Tk_Window tkwin; { int isNew; GC gc; Display *display; Blt_HashEntry *hPtr; if (!initialized) { Blt_InitHashTable(&bitmapGCTable, BLT_ONE_WORD_KEYS); initialized = TRUE; } display = Tk_Display(tkwin); hPtr = Blt_CreateHashEntry(&bitmapGCTable, (char *)display, &isNew); if (isNew) { Pixmap bitmap; XGCValues gcValues; unsigned long gcMask; Window root; root = RootWindow(display, Tk_ScreenNumber(tkwin)); bitmap = Tk_GetPixmap(display, root, 1, 1, 1); gcValues.foreground = gcValues.background = 0; gcMask = (GCForeground | GCBackground); gc = Blt_GetPrivateGCFromDrawable(display, bitmap, gcMask, &gcValues); Tk_FreePixmap(display, bitmap); Blt_SetHashValue(hPtr, gc); } else { gc = (GC)Blt_GetHashValue(hPtr); } return gc; } void Blt_ResetTextStyle(tkwin, tsPtr) Tk_Window tkwin; TextStyle *tsPtr; { GC newGC; XGCValues gcValues; unsigned long gcMask; gcMask = GCFont; gcValues.font = Tk_FontId(tsPtr->font); if (tsPtr->color != NULL) { gcMask |= GCForeground; gcValues.foreground = tsPtr->color->pixel; } newGC = Tk_GetGC(tkwin, gcMask, &gcValues); if (tsPtr->gc != NULL) { Tk_FreeGC(Tk_Display(tkwin), tsPtr->gc); } tsPtr->gc = newGC; } void Blt_FreeTextStyle(display, tsPtr) Display *display; TextStyle *tsPtr; { if (tsPtr->gc != NULL) { Tk_FreeGC(display, tsPtr->gc); } } blt-2.4z.orig/src/bltText.h0100644000175000017500000001652307341077634014354 0ustar dokodoko/* * bltText.h -- * * Copyright 1993-1998 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. */ #ifndef _BLT_TEXT_H #define _BLT_TEXT_H #if (TK_MAJOR_VERSION == 4) /* * The following structure is used by Tk_GetFontMetrics() to return * information about the properties of a Tk_Font. */ typedef struct { int ascent; /* The amount in pixels that the tallest * letter sticks up above the baseline, plus * any extra blank space added by the designer * of the font. */ int descent; /* The largest amount in pixels that any * letter sticks below the baseline, plus any * extra blank space added by the designer of * the font. */ int linespace; /* The sum of the ascent and descent. How * far apart two lines of text in the same * font should be placed so that none of the * characters in one line overlap any of the * characters in the other line. */ } Tk_FontMetrics; typedef XFontStruct *Tk_Font; #define Tk_FontId(font) ((font)->fid) #define Tk_TextWidth(font, str, len) (XTextWidth((font),(str),(len))) #define Tk_GetFontMetrics(font, fmPtr) \ ((fmPtr)->ascent = (font)->ascent, \ (fmPtr)->descent = (font)->descent, \ (fmPtr)->linespace = (font)->ascent + (font)->descent) #define Tk_NameOfFont(font) (Tk_NameOfFontStruct(font)) #define Tk_DrawChars(dpy, draw, gc, font, str, len, x, y) \ TkDisplayChars((dpy),(draw),(gc),(font),(str),(len),(x),(y), 0, DEF_TEXT_FLAGS) #define Tk_MeasureChars(font, text, len, maxPixels, flags, lenPtr) \ TkMeasureChars((font),(text), (len), 0, maxPixels, 0,(flags), (lenPtr)) extern int TkMeasureChars _ANSI_ARGS_((Tk_Font font, char *source, int maxChars, int startX, int maxX, int tabOrigin, int flags, int *nextXPtr)); extern void TkDisplayChars _ANSI_ARGS_((Display *display, Drawable drawable, GC gc, Tk_Font font, char *string, int length, int x, int y, int tabOrigin, int flags)); /* * FLAGS passed to TkMeasureChars: */ #define TK_WHOLE_WORDS (1<<0) #define TK_AT_LEAST_ONE (1<<1) #define TK_PARTIAL_OK (1<<2) #define TK_IGNORE_NEWLINES (1<<3) #define TK_IGNORE_TABS (1<<4) #define NO_FLAGS 0 #endif /* TK_MAJOR_VERSION == 4 */ #define DEF_TEXT_FLAGS (TK_PARTIAL_OK | TK_IGNORE_NEWLINES) /* * ---------------------------------------------------------------------- * * TextFragment -- * * ---------------------------------------------------------------------- */ typedef struct { char *text; /* Text to be displayed */ short int x, y; /* X-Y offset of the baseline from the * upper-left corner of the bbox. */ short int sx, sy; /* See bltWinUtil.c */ short int count; /* Number of bytes in text. The actual * character count may differ because of * multi-byte UTF encodings. */ short int width; /* Width of segment in pixels. This * information is used to draw * PostScript strings the same width * as X. */ } TextFragment; /* * ---------------------------------------------------------------------- * * TextLayout -- * * ---------------------------------------------------------------------- */ typedef struct { int nFrags; /* # fragments of text */ short int width, height; /* Dimensions of text bounding box */ TextFragment fragArr[1]; /* Information about each fragment of text */ } TextLayout; typedef struct { XColor *color; int offset; } Shadow; /* * ---------------------------------------------------------------------- * * TextStyle -- * * Represents a convenient structure to hold text attributes * which determine how a text string is to be displayed on the * window, or drawn with PostScript commands. The alternative * is to pass lots of parameters to the drawing and printing * routines. This seems like a more efficient and less cumbersome * way of passing parameters. * * ---------------------------------------------------------------------- */ typedef struct { unsigned int state; /* If non-zero, indicates to draw text * in the active color */ short int width, height; /* Extents of text */ XColor *color; /* Normal color */ XColor *activeColor; /* Active color */ Tk_Font font; /* Font to use to draw text */ Tk_3DBorder border; /* Background color of text. This is also * used for drawing disabled text. */ Shadow shadow; /* Drop shadow color and offset */ Tk_Justify justify; /* Justification of the text string. This * only matters if the text is composed * of multiple lines. */ GC gc; /* GC used to draw the text */ double theta; /* Rotation of text in degrees. */ Tk_Anchor anchor; /* Indicates how the text is anchored around * its x and y coordinates. */ Blt_Pad padX, padY; /* # pixels padding of around text region */ short int leader; /* # pixels spacing between lines of text */ } TextStyle; extern TextLayout *Blt_GetTextLayout _ANSI_ARGS_((char *string, TextStyle *stylePtr)); extern void Blt_GetTextExtents _ANSI_ARGS_((TextStyle *stylePtr, char *text, int *widthPtr, int *heightPtr)); extern void Blt_InitTextStyle _ANSI_ARGS_((TextStyle *stylePtr)); extern void Blt_ResetTextStyle _ANSI_ARGS_((Tk_Window tkwin, TextStyle *stylePtr)); extern void Blt_FreeTextStyle _ANSI_ARGS_((Display *display, TextStyle *stylePtr)); extern void Blt_SetDrawTextStyle _ANSI_ARGS_((TextStyle *stylePtr, Tk_Font font, GC gc, XColor *normalColor, XColor *activeColor, XColor *shadowColor, double theta, Tk_Anchor anchor, Tk_Justify justify, int leader, int shadowOffset)); extern void Blt_SetPrintTextStyle _ANSI_ARGS_((TextStyle *stylePtr, Tk_Font font, XColor *fgColor, XColor *bgColor, XColor *shadowColor, double theta, Tk_Anchor anchor, Tk_Justify justify, int leader, int shadowOffset)); extern void Blt_DrawText _ANSI_ARGS_((Tk_Window tkwin, Drawable drawable, char *string, TextStyle *stylePtr, int x, int y)); extern void Blt_DrawTextLayout _ANSI_ARGS_((Tk_Window tkwin, Drawable drawable, TextLayout *textPtr, TextStyle *stylePtr, int x, int y)); extern void Blt_DrawText2 _ANSI_ARGS_((Tk_Window tkwin, Drawable drawable, char *string, TextStyle *stylePtr, int x, int y, Dim2D * dimPtr)); extern Pixmap Blt_CreateTextBitmap _ANSI_ARGS_((Tk_Window tkwin, TextLayout *textPtr, TextStyle *stylePtr, int *widthPtr, int *heightPtr)); extern int Blt_DrawRotatedText _ANSI_ARGS_((Display *display, Drawable drawable, int x, int y, double theta, TextStyle *stylePtr, TextLayout *textPtr)); #endif /* _BLT_TEXT_H */ blt-2.4z.orig/src/bltTile.c0100644000175000017500000010540407535720323014310 0ustar dokodoko/* * bltTile.c -- * * This module manages images for tiled backgrounds for the BLT toolkit. * * Copyright 1995-1998 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. */ #include "bltInt.h" #include "bltChain.h" #include "bltHash.h" #include "bltImage.h" #include #include "bltTile.h" #define TILE_THREAD_KEY "BLT Tile Data" #define TILE_MAGIC ((unsigned int) 0x46170277) typedef struct { Blt_HashTable tileTable; /* Hash table of tile structures keyed by * the name of the image. */ Tcl_Interp *interp; } TileInterpData; typedef struct { char *name; /* Name of image used to generate the pixmap.*/ Display *display; /* Display where pixmap was created. */ int flags; /* See definitions below. */ Tcl_Interp *interp; Blt_HashEntry *hashPtr; /* Pointer to hash table location */ Blt_HashTable *tablePtr; Pixmap pixmap; /* Pixmap generated from image. */ Pixmap mask; /* Monochrome pixmap used as * transparency mask. */ GC gc; /* GC */ Tk_Image tkImage; /* Tk image token. */ Blt_Chain *clients; /* Chain of clients sharing this tile. */ int width, height; } Tile; #define NOTIFY_PENDING 1 /* If set, indicates that the image * associated with the tile has been * updated or deleted. The tile pixmap * will be changed and the clients of the * tile will be notified (if they supplied * a TileChangedProc routine. */ typedef struct Blt_TileClientStruct { unsigned int magic; Tk_Window tkwin; /* Client window. */ int xOrigin, yOrigin; /* Tiling origin in relation to the * client window. */ Blt_TileChangedProc *notifyProc; /* If non-NULL, routine to * call to when tile image changes. */ ClientData clientData; /* Data to pass to when calling the above * routine. */ Tile *tilePtr; /* Pointer to actual tile information */ Blt_ChainLink *linkPtr; /* Pointer to client entry in the server's * client list. Used to delete the client */ } TileClient; typedef struct { Display *display; Tk_Uid nameId; int depth; } TileKey; static TileInterpData *GetTileInterpData _ANSI_ARGS_((Tcl_Interp *interp)); static Tcl_IdleProc UpdateTile; static Tk_ImageChangedProc ImageChangedProc; static Tcl_InterpDeleteProc TileInterpDeleteProc; static void DestroyClient _ANSI_ARGS_((TileClient *clientPtr)); static void DestroyTile _ANSI_ARGS_((Tile *tilePtr)); /* *---------------------------------------------------------------------- * * RedrawTile -- * * Generates a pixmap and draws the tile image into it. Also * a tranparency mask is possibly generated from the image. * * Results: * None. * *---------------------------------------------------------------------- */ static void RedrawTile(tkwin, tilePtr) Tk_Window tkwin; Tile *tilePtr; { GC newGC; Tk_PhotoHandle photo; XGCValues gcValues; int width, height; unsigned int gcMask; Tk_SizeOfImage(tilePtr->tkImage, &width, &height); Tk_MakeWindowExist(tkwin); if ((width != tilePtr->width) || (height != tilePtr->height)) { Pixmap pixmap; /* * Create the new pixmap *before* destroying the old one. I don't * why this happens, but if you delete the old pixmap first, the * old pixmap sometimes gets used in the client's GCs. I suspect * it has something to do with the way Tk reallocates X resource * identifiers. */ pixmap = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin), width, height, Tk_Depth(tkwin)); if (tilePtr->pixmap != None) { Tk_FreePixmap(Tk_Display(tkwin), tilePtr->pixmap); } tilePtr->pixmap = pixmap; } Tk_RedrawImage(tilePtr->tkImage, 0, 0, width, height, tilePtr->pixmap, 0, 0); gcMask = (GCTile | GCFillStyle); gcValues.fill_style = FillTiled; gcValues.tile = tilePtr->pixmap; newGC = Tk_GetGC(tkwin, gcMask, &gcValues); if (tilePtr->gc != NULL) { Tk_FreeGC(Tk_Display(tkwin), tilePtr->gc); } tilePtr->gc = newGC; tilePtr->width = width; tilePtr->height = height; if (tilePtr->mask != None) { #ifdef WIN32 Tk_FreePixmap(Tk_Display(tkwin), tilePtr->mask); #else XFreePixmap(Tk_Display(tkwin), tilePtr->mask); #endif /* WIN32 */ tilePtr->mask = None; } photo = Blt_FindPhoto(tilePtr->interp, Blt_NameOfImage(tilePtr->tkImage)); if (photo != NULL) { Tk_PhotoImageBlock src; Tk_PhotoGetImage(photo, &src); if ((src.offset[3] < src.pixelSize) && (src.offset[3] >= 0)) { tilePtr->mask = Blt_PhotoImageMask(tkwin, src); } } } /* *---------------------------------------------------------------------- * * UpdateTile -- * * It would be better if Tk checked for NULL proc pointers. * * Results: * None. * *---------------------------------------------------------------------- */ static void UpdateTile(clientData) ClientData clientData; { Tile *tilePtr = (Tile *)clientData; TileClient *clientPtr; Blt_ChainLink *linkPtr; tilePtr->flags &= ~NOTIFY_PENDING; if (Tk_ImageIsDeleted(tilePtr->tkImage)) { if (tilePtr->pixmap != None) { Tk_FreePixmap(tilePtr->display, tilePtr->pixmap); } tilePtr->pixmap = None; } else { /* Pick any client window to generate the new pixmap. */ linkPtr = Blt_ChainFirstLink(tilePtr->clients); clientPtr = Blt_ChainGetValue(linkPtr); RedrawTile(clientPtr->tkwin, tilePtr); } /* Notify each of the tile's clients that the pixmap has changed. */ for (linkPtr = Blt_ChainFirstLink(tilePtr->clients); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { clientPtr = Blt_ChainGetValue(linkPtr); if (clientPtr->notifyProc != NULL) { (*clientPtr->notifyProc) (clientPtr->clientData, clientPtr); } } } /* *---------------------------------------------------------------------- * * ImageChangedProc * * The Tk image has changed or been deleted, redraw the pixmap * tile. * * Note: As of Tk 4.2 (rechecked in 8.3), if you redraw Tk * images from a Tk_ImageChangedProc you'll get a * coredump. As a workaround, we have to simulate * how the Tk widgets use images and redraw within * an idle event. * * Results: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static void ImageChangedProc(clientData, x, y, width, height, imageWidth, imageHeight) ClientData clientData; int x, y, width, height; /* Not used. */ int imageWidth, imageHeight; /* Not used. */ { Tile *tilePtr = (Tile *) clientData; if (!(tilePtr->flags & NOTIFY_PENDING)) { Tcl_DoWhenIdle(UpdateTile, tilePtr); tilePtr->flags |= NOTIFY_PENDING; } } /* *---------------------------------------------------------------------- * * DestroyTile -- * * Deletes the core tile structure, including the pixmap * representing the tile. * * Results: * None. * *---------------------------------------------------------------------- */ static void DestroyTile(Tile *tilePtr) { Blt_ChainLink *linkPtr; TileClient *clientPtr; if (tilePtr->flags & NOTIFY_PENDING) { Tcl_CancelIdleCall(UpdateTile, tilePtr); } for (linkPtr = Blt_ChainFirstLink(tilePtr->clients); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { clientPtr = Blt_ChainGetValue(linkPtr); Blt_Free(clientPtr); } Blt_ChainDestroy(tilePtr->clients); if (tilePtr->hashPtr != NULL) { Blt_DeleteHashEntry(tilePtr->tablePtr, tilePtr->hashPtr); } if (tilePtr->pixmap != None) { Tk_FreePixmap(tilePtr->display, tilePtr->pixmap); } Tk_FreeImage(tilePtr->tkImage); if (tilePtr->gc != NULL) { Tk_FreeGC(tilePtr->display, tilePtr->gc); } if (tilePtr->name != NULL) { Blt_Free(tilePtr->name); } Blt_Free(tilePtr); } /* *---------------------------------------------------------------------- * * CreateTile -- * * Creates a tile server. A tile server manages a single image, * possibly shared by several clients. Clients will be updated * (if requested) by the server if the image changes, so they * know to redraw themselves. For X11 the image is drawn into a * pixmap that is used in a new GC as its tile. For Windows we * have to do the tiling ourselves by redrawing the image across * the drawing area (see Blt_TileRectangle and Blt_TilePolygon). * * Results: * Returns a pointer to the new tile server. If the image name * does not represent a Tk image, NULL is returned. * *---------------------------------------------------------------------- */ static Tile * CreateTile( Tcl_Interp *interp, Tk_Window tkwin, char *imageName) { Tile *tilePtr; Tk_Image tkImage; tilePtr = Blt_Calloc(1, sizeof(Tile)); assert(tilePtr); /* * Get the image. Funnel all change notifications to a single routine. */ tkImage = Tk_GetImage(interp, tkwin, imageName, ImageChangedProc, tilePtr); if (tkImage == NULL) { Blt_Free(tilePtr); return NULL; } /* * Initialize the tile server. */ tilePtr->display = Tk_Display(tkwin); tilePtr->interp = interp; tilePtr->name = Blt_Strdup(imageName); tilePtr->clients = Blt_ChainCreate(); tilePtr->tkImage = tkImage; RedrawTile(tkwin, tilePtr); return tilePtr; } /* *---------------------------------------------------------------------- * * DestroyClient -- * * Removes the client from the servers's list of clients and * memory used by the client token is released. When the last * client is deleted, the server is also removed. * * Results: * None. * *---------------------------------------------------------------------- */ static void DestroyClient(TileClient *clientPtr) { Tile *tilePtr; tilePtr = clientPtr->tilePtr; /* Remove the client from the server's list */ if (clientPtr->linkPtr != NULL) { Blt_ChainDeleteLink(tilePtr->clients, clientPtr->linkPtr); } if (Blt_ChainGetLength(tilePtr->clients) == 0) { /* * If there are no more clients of the tile, then remove the * pixmap, image, and the server record. */ DestroyTile(tilePtr); } Blt_Free(clientPtr); } /* *---------------------------------------------------------------------- * * CreateClient -- * * Returns a token to a tile (possibly shared by many clients). * A client uses the token to query or display the tile. Clients * request tiles by their image names. Each tile is known by its * display, screen depth, and image name. The tile server tracks * what clients are using the tile and notifies them (via a * callback) whenever the tile changes. If no server exists * already, one is created on-the-fly. * * Results: * A pointer to the newly created client (i.e. tile). * *---------------------------------------------------------------------- */ static TileClient * CreateClient( Tcl_Interp *interp, Tk_Window tkwin, char *name) { TileClient *clientPtr; Tile *tilePtr; TileInterpData *dataPtr; Blt_HashEntry *hPtr; int isNew; TileKey key; dataPtr = GetTileInterpData(interp); key.nameId = Tk_GetUid(name); key.display = Tk_Display(tkwin); key.depth = Tk_Depth(tkwin); hPtr = Blt_CreateHashEntry(&dataPtr->tileTable, (char *)&key, &isNew); if (isNew) { tilePtr = CreateTile(interp, tkwin, name); if (tilePtr == NULL) { Blt_DeleteHashEntry(&(dataPtr->tileTable), hPtr); return NULL; } tilePtr->hashPtr = hPtr; tilePtr->tablePtr = &(dataPtr->tileTable); Blt_SetHashValue(hPtr, tilePtr); } else { tilePtr = Blt_GetHashValue(hPtr); } clientPtr = Blt_Calloc(1, sizeof(TileClient)); assert(clientPtr); /* Initialize client information. */ clientPtr->magic = TILE_MAGIC; clientPtr->tkwin = tkwin; clientPtr->linkPtr = Blt_ChainAppend(tilePtr->clients, clientPtr); clientPtr->tilePtr = tilePtr; return clientPtr; } /* * ----------------------------------------------------------------------- * * TileInterpDeleteProc -- * * This is called when the interpreter is deleted. All the tiles * are specific to that interpreter are destroyed. * * Results: * None. * * Side effects: * Destroys the tile table. * * ------------------------------------------------------------------------ */ /* ARGSUSED */ static void TileInterpDeleteProc( ClientData clientData, /* Thread-specific data. */ Tcl_Interp *interp) { TileInterpData *dataPtr = clientData; Blt_HashEntry *hPtr; Blt_HashSearch cursor; Tile *tilePtr; for (hPtr = Blt_FirstHashEntry(&(dataPtr->tileTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tilePtr = Blt_GetHashValue(hPtr); tilePtr->hashPtr = NULL; DestroyTile(tilePtr); } Blt_DeleteHashTable(&(dataPtr->tileTable)); Tcl_DeleteAssocData(interp, TILE_THREAD_KEY); Blt_Free(dataPtr); } static TileInterpData * GetTileInterpData(interp) Tcl_Interp *interp; { TileInterpData *dataPtr; Tcl_InterpDeleteProc *proc; dataPtr = (TileInterpData *) Tcl_GetAssocData(interp, TILE_THREAD_KEY, &proc); if (dataPtr == NULL) { dataPtr = Blt_Malloc(sizeof(TileInterpData)); assert(dataPtr); dataPtr->interp = interp; Tcl_SetAssocData(interp, TILE_THREAD_KEY, TileInterpDeleteProc, dataPtr); Blt_InitHashTable(&(dataPtr->tileTable), sizeof(TileKey)/sizeof(int)); } return dataPtr; } /* Public API for tiles. */ /* *---------------------------------------------------------------------- * * Blt_GetTile * * Convert the named image into a tile. * * Results: * If the image is valid, a new tile is returned. If the name * does not represent a proper image, an error message is left in * interp->result. * *---------------------------------------------------------------------- */ /*LINTLIBRARY*/ int Blt_GetTile( Tcl_Interp *interp, /* Interpreter to report results back to */ Tk_Window tkwin, /* Window on the same display as tile */ char *imageName, /* Name of image */ Blt_Tile *tokenPtr) /* (out) Returns the allocated tile token. */ { TileClient *clientPtr; clientPtr = CreateClient(interp, tkwin, imageName); if (clientPtr == NULL) { return TCL_ERROR; } *tokenPtr = clientPtr; return TCL_OK; } /* *---------------------------------------------------------------------- * * Blt_FreeTile * * Release the resources associated with the tile. * * Results: * None. * * Side Effects: * Memory and X resources are freed. Bookkeeping information * about the tile (i.e. width, height, and name) is discarded. * *---------------------------------------------------------------------- */ /*LINTLIBRARY*/ void Blt_FreeTile(TileClient *clientPtr) /* Tile to be deleted */ { if ((clientPtr == NULL) || (clientPtr->magic != TILE_MAGIC)) { return; /* No tile */ } DestroyClient(clientPtr); } /* *---------------------------------------------------------------------- * * Blt_NameOfTile * * Returns the name of the image from which the tile was * generated. * * Results: * The name of the image is returned. The name is not unique. * Many tiles may use the same image. * *---------------------------------------------------------------------- */ /*LINTLIBRARY*/ char * Blt_NameOfTile(TileClient *clientPtr) /* Tile to query */ { if (clientPtr == NULL) { return ""; } if (clientPtr->magic != TILE_MAGIC) { return "not a tile"; } return clientPtr->tilePtr->name; } /* *---------------------------------------------------------------------- * * Blt_PixmapOfTile * * Returns the pixmap of the tile. * * Results: * The X pixmap used as the tile is returned. * *---------------------------------------------------------------------- */ /*LINTLIBRARY*/ Pixmap Blt_PixmapOfTile(TileClient *clientPtr) /* Tile to query */ { if ((clientPtr == NULL) || (clientPtr->magic != TILE_MAGIC)) { return None; } return clientPtr->tilePtr->pixmap; } /* *---------------------------------------------------------------------- * * Blt_SizeOfTile * * Returns the width and height of the tile. * * Results: * The width and height of the tile are returned. * *---------------------------------------------------------------------- */ /*LINTLIBRARY*/ void Blt_SizeOfTile( TileClient *clientPtr, /* Tile to query */ int *widthPtr, int *heightPtr) /* Returned dimensions of the tile (out) */ { if ((clientPtr == NULL) || (clientPtr->magic != TILE_MAGIC)) { *widthPtr = *heightPtr = 0; return; /* No tile given. */ } *widthPtr = clientPtr->tilePtr->width; *heightPtr = clientPtr->tilePtr->height; } /* *---------------------------------------------------------------------- * * Blt_SetTileChangedProc * * Sets the routine to called when an image changes. * * Results: * None. * * Side Effects: * The designated routine will be called the next time the * image associated with the tile changes. * *---------------------------------------------------------------------- */ /*LINTLIBRARY*/ void Blt_SetTileChangedProc( TileClient *clientPtr, /* Tile to query */ Blt_TileChangedProc *notifyProc, ClientData clientData) { if ((clientPtr != NULL) && (clientPtr->magic == TILE_MAGIC)) { clientPtr->notifyProc = notifyProc; clientPtr->clientData = clientData; } } /* *---------------------------------------------------------------------- * * Blt_SetTileOrigin -- * * Set the pattern origin of the tile to a common point (i.e. the * origin (0,0) of the top level window) so that tiles from two * different widgets will match up. This done by setting the * GCTileStipOrigin field is set to the translated origin of the * toplevel window in the hierarchy. * * Results: * None. * * Side Effects: * The GCTileStipOrigin is reset in the GC. This will cause the * tile origin to change when the GC is used for drawing. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ void Blt_SetTileOrigin( Tk_Window tkwin, TileClient *clientPtr, int x, int y) { while (!Tk_IsTopLevel(tkwin)) { x += Tk_X(tkwin) + Tk_Changes(tkwin)->border_width; y += Tk_Y(tkwin) + Tk_Changes(tkwin)->border_width; tkwin = Tk_Parent(tkwin); } XSetTSOrigin(Tk_Display(tkwin), clientPtr->tilePtr->gc, -x, -y); clientPtr->xOrigin = -x; clientPtr->yOrigin = -y; } void Blt_SetTSOrigin( Tk_Window tkwin, TileClient *clientPtr, int x, int y) { XSetTSOrigin(Tk_Display(tkwin), clientPtr->tilePtr->gc, x, y); clientPtr->xOrigin = x; clientPtr->yOrigin = y; } #ifdef WIN32 static int tkpWinRopModes[] = { R2_BLACK, /* GXclear */ R2_MASKPEN, /* GXand */ R2_MASKPENNOT, /* GXandReverse */ R2_COPYPEN, /* GXcopy */ R2_MASKNOTPEN, /* GXandInverted */ R2_NOT, /* GXnoop */ R2_XORPEN, /* GXxor */ R2_MERGEPEN, /* GXor */ R2_NOTMERGEPEN, /* GXnor */ R2_NOTXORPEN, /* GXequiv */ R2_NOT, /* GXinvert */ R2_MERGEPENNOT, /* GXorReverse */ R2_NOTCOPYPEN, /* GXcopyInverted */ R2_MERGENOTPEN, /* GXorInverted */ R2_NOTMASKPEN, /* GXnand */ R2_WHITE /* GXset */ }; #define MASKPAT 0x00E20746 /* dest = (src & pat) | (!src & dst) */ #define COPYFG 0x00CA0749 /* dest = (pat & src) | (!pat & dst) */ #define COPYBG 0x00AC0744 /* dest = (!pat & src) | (pat & dst) */ static void TileRegion( HDC srcDC, /* Source device context. */ HDC destDC, /* Destination device context. */ HDC maskDC, /* If non-NULL, device context of the * mask tile mask. */ TileClient *clientPtr, int x, int y, int width, int height) { Tile *tilePtr = clientPtr->tilePtr; int destX, destY; int destWidth, destHeight; int srcX, srcY; int startX, startY; /* Starting upper left corner of region. */ int delta; int left, top, right, bottom; startX = x; if (x < clientPtr->xOrigin) { delta = (clientPtr->xOrigin - x) % tilePtr->width; if (delta > 0) { startX -= (tilePtr->width - delta); } } else if (x > clientPtr->xOrigin) { delta = (x - clientPtr->xOrigin) % tilePtr->width; if (delta > 0) { startX -= delta; } } startY = y; if (y < clientPtr->yOrigin) { delta = (clientPtr->yOrigin - y) % tilePtr->height; if (delta > 0) { startY -= (tilePtr->height - delta); } } else if (y >= clientPtr->yOrigin) { delta = (y - clientPtr->yOrigin) % tilePtr->height; if (delta > 0) { startY -= delta; } } #ifdef notdef PurifyPrintf("tile is (%d,%d,%d,%d)\n", clientPtr->xOrigin, clientPtr->yOrigin, tilePtr->width, tilePtr->height); PurifyPrintf("region is (%d,%d,%d,%d)\n", x, y, width, height); PurifyPrintf("starting at %d,%d\n", startX, startY); #endif left = x; right = x + width; top = y; bottom = y + height; for (y = startY; y < bottom; y += tilePtr->height) { srcY = 0; destY = y; destHeight = tilePtr->height; if (y < top) { srcY = (top - y); destHeight = tilePtr->height - srcY; destY = top; } if ((destY + destHeight) > bottom) { destHeight = (bottom - destY); } for (x = startX; x < right; x += tilePtr->width) { srcX = 0; destX = x; destWidth = tilePtr->width; if (x < left) { srcX = (left - x); destWidth = tilePtr->width - srcX; destX = left; } if ((destX + destWidth) > right) { destWidth = (right - destX); } #ifdef notdef PurifyPrintf("drawing pattern (%d,%d,%d,%d) at %d,%d\n", srcX , srcY, destWidth, destHeight, destX, destY); #endif if (tilePtr->mask != None) { /* With transparency. */ #ifdef notdef HDC maskDC; TkWinDCState maskState; maskDC = TkWinGetDrawableDC(tilePtr->display, tilePtr->mask, &maskState); SetBkColor(destDC, RGB(255, 255, 255)); SetTextColor(destDC, RGB(0, 0, 0)); #endif BitBlt(destDC, destX, destY, destWidth, destHeight, maskDC, 0, 0, SRCAND); BitBlt(destDC, destX, destY, destWidth, destHeight, srcDC, srcX, srcY, SRCPAINT); #ifdef notdef TkWinReleaseDrawableDC(tilePtr->mask, maskDC, &maskState); #endif } else { /* Opaque tile. */ BitBlt(destDC, destX, destY, destWidth, destHeight, srcDC, srcX, srcY, SRCCOPY); } } } } void Blt_TilePolygon( Tk_Window tkwin, Drawable drawable, TileClient *clientPtr, XPoint pointArr[], int nPoints) { HBITMAP oldBitmap; HDC hDC, memDC; HRGN hRgn; POINT *p, *winPts; Region2D bbox; Tile *tilePtr; TkWinDCState state; TkWinDrawable *twdPtr; XPoint *endPtr, *pointPtr; int fillMode; int width, height; if (drawable == None) { return; } tilePtr = clientPtr->tilePtr; /* Determine the bounding box of the polygon. */ bbox.left = bbox.right = pointArr[0].x; bbox.top = bbox.bottom = pointArr[0].y; endPtr = pointArr + nPoints; for (pointPtr = pointArr; pointPtr < endPtr; pointPtr++) { if (pointPtr->x < bbox.left) { bbox.left = pointPtr->x; } if (pointPtr->x > bbox.right) { bbox.right = pointPtr->x; } if (pointPtr->y < bbox.top) { bbox.top = pointPtr->y; } if (pointPtr->y > bbox.bottom) { bbox.bottom = pointPtr->y; } } width = bbox.right - bbox.left + 1; height = bbox.bottom - bbox.top + 1; /* Allocate and fill an array of POINTS to create the polygon path. */ p = winPts = Blt_Malloc(sizeof(POINT) * nPoints); for (pointPtr = pointArr; pointPtr < endPtr; pointPtr++) { p->x = pointPtr->x - bbox.left; p->y = pointPtr->y - bbox.top; p++; } hDC = TkWinGetDrawableDC(Tk_Display(tkwin), drawable, &state); SetROP2(hDC, tkpWinRopModes[tilePtr->gc->function]); fillMode = (tilePtr->gc->fill_rule == EvenOddRule) ? ALTERNATE : WINDING; /* Use the polygon as a clip path. */ LPtoDP(hDC, winPts, nPoints); hRgn = CreatePolygonRgn(winPts, nPoints, fillMode); SelectClipRgn(hDC, hRgn); OffsetClipRgn(hDC, bbox.left, bbox.top); Blt_Free(winPts); twdPtr = (TkWinDrawable *)tilePtr->pixmap; memDC = CreateCompatibleDC(hDC); oldBitmap = SelectBitmap(memDC, twdPtr->bitmap.handle); /* Tile the bounding box. */ if (tilePtr->mask != None) { TkWinDCState maskState; HDC maskDC; maskDC = TkWinGetDrawableDC(tilePtr->display, tilePtr->mask, &maskState); SetBkColor(hDC, RGB(255, 255, 255)); SetTextColor(hDC, RGB(0, 0, 0)); TileRegion(memDC, hDC, maskDC, clientPtr, bbox.left, bbox.top, width, height); TkWinReleaseDrawableDC(tilePtr->mask, maskDC, &maskState); } else { TileRegion(memDC, hDC, NULL, clientPtr, bbox.left, bbox.top, width, height); } SelectBitmap(memDC, oldBitmap); DeleteDC(memDC); SelectClipRgn(hDC, NULL); DeleteRgn(hRgn); TkWinReleaseDrawableDC(drawable, hDC, &state); } void Blt_TileRectangle( Tk_Window tkwin, Drawable drawable, TileClient *clientPtr, int x, int y, unsigned int width, unsigned int height) { HBITMAP oldBitmap; HDC hDC, memDC; Tile *tilePtr; TkWinDCState state; TkWinDrawable *twdPtr; if (drawable == None) { return; } tilePtr = clientPtr->tilePtr; hDC = TkWinGetDrawableDC(Tk_Display(tkwin), drawable, &state); SetROP2(hDC, tkpWinRopModes[tilePtr->gc->function]); twdPtr = (TkWinDrawable *)tilePtr->pixmap; memDC = CreateCompatibleDC(hDC); oldBitmap = SelectBitmap(memDC, twdPtr->bitmap.handle); /* Tile the bounding box. */ if (tilePtr->mask != None) { TkWinDCState maskState; HDC maskDC; maskDC = TkWinGetDrawableDC(tilePtr->display, tilePtr->mask, &maskState); SetBkColor(hDC, RGB(255, 255, 255)); SetTextColor(hDC, RGB(0, 0, 0)); TileRegion(memDC, hDC, maskDC, clientPtr, x, y, width, height); TkWinReleaseDrawableDC(tilePtr->mask, maskDC, &maskState); } else { TileRegion(memDC, hDC, NULL, clientPtr, x, y, width, height); } SelectBitmap(memDC, oldBitmap); DeleteDC(memDC); TkWinReleaseDrawableDC(drawable, hDC, &state); } void Blt_TileRectangles( Tk_Window tkwin, Drawable drawable, TileClient *clientPtr, XRectangle rectArr[], int nRectangles) { HBITMAP oldBitmap; HDC hDC, memDC; Tile *tilePtr; TkWinDCState state; TkWinDrawable *twdPtr; XRectangle *rectPtr, *endPtr; if (drawable == None) { return; } tilePtr = clientPtr->tilePtr; hDC = TkWinGetDrawableDC(Tk_Display(tkwin), drawable, &state); SetROP2(hDC, tkpWinRopModes[tilePtr->gc->function]); twdPtr = (TkWinDrawable *)tilePtr->pixmap; memDC = CreateCompatibleDC(hDC); oldBitmap = SelectBitmap(memDC, twdPtr->bitmap.handle); endPtr = rectArr + nRectangles; /* Tile the bounding box. */ if (tilePtr->mask != None) { TkWinDCState maskState; HDC maskDC; maskDC = TkWinGetDrawableDC(tilePtr->display, tilePtr->mask, &maskState); SetBkColor(hDC, RGB(255, 255, 255)); SetTextColor(hDC, RGB(0, 0, 0)); for (rectPtr = rectArr; rectPtr < endPtr; rectPtr++) { TileRegion(memDC, hDC, maskDC, clientPtr, (int)rectPtr->x, (int)rectPtr->y, (int)rectPtr->width, (int)rectPtr->height); } TkWinReleaseDrawableDC(tilePtr->mask, maskDC, &maskState); } else { for (rectPtr = rectArr; rectPtr < endPtr; rectPtr++) { TileRegion(memDC, hDC, NULL, clientPtr, (int)rectPtr->x, (int)rectPtr->y, (int)rectPtr->width, (int)rectPtr->height); } } SelectBitmap(memDC, oldBitmap); DeleteDC(memDC); TkWinReleaseDrawableDC(drawable, hDC, &state); } #else /* *---------------------------------------------------------------------- * * RectangleMask -- * * Creates a rectangular mask also stippled by the mask of the * tile. This is used to draw the tiled polygon images with * transparent areas. * * Results: * A bitmap mask is returned. * *---------------------------------------------------------------------- */ static Pixmap RectangleMask(display, drawable, x, y, width, height, mask, xOrigin, yOrigin) Display *display; Drawable drawable; int x, y; unsigned int width, height; Pixmap mask; int xOrigin, yOrigin; { GC gc; Pixmap bitmap; XGCValues gcValues; unsigned long gcMask; bitmap = Tk_GetPixmap(display, drawable, width, height, 1); gcMask = (GCForeground | GCBackground | GCFillStyle | GCTileStipXOrigin | GCTileStipYOrigin | GCStipple); gcValues.foreground = 0x1; gcValues.background = 0x0; gcValues.fill_style = FillOpaqueStippled; gcValues.ts_x_origin = xOrigin - x; gcValues.ts_y_origin = yOrigin - y; gcValues.stipple = mask; gc = XCreateGC(display, bitmap, gcMask, &gcValues); XFillRectangle(display, bitmap, gc, 0, 0, width, height); Blt_FreePrivateGC(display, gc); return bitmap; } /* *---------------------------------------------------------------------- * * Blt_TileRectangle -- * * Draws a rectangle filled by a tiled image. This differs from * the normal XFillRectangle call in that we also try to handle * a transparency mask. * * Results: * None. * * Side Effects: * Draws the rectangle. * *---------------------------------------------------------------------- */ void Blt_TileRectangle( Tk_Window tkwin, Drawable drawable, TileClient *clientPtr, int x, int y, unsigned int width, unsigned int height) { Tile *tilePtr; Display *display; display = Tk_Display(tkwin); tilePtr = clientPtr->tilePtr; if (clientPtr->tilePtr->mask != None) { Pixmap mask; mask = RectangleMask(display, drawable, x, y, width, height, tilePtr->mask, clientPtr->xOrigin, clientPtr->yOrigin); XSetClipMask(display, tilePtr->gc, mask); XSetClipOrigin(display, tilePtr->gc, x, y); XFillRectangle(display, drawable, tilePtr->gc, x, y, width, height); XSetClipMask(display, tilePtr->gc, None); XSetClipOrigin(display, tilePtr->gc, 0, 0); Tk_FreePixmap(display, mask); } else { XFillRectangle(display, drawable, tilePtr->gc, x, y, width, height); } } /* *---------------------------------------------------------------------- * * Blt_TileRectangles -- * * Draws rectangles filled by a tiled image. This differs from * the normal XFillRectangles call in that we also try to handle * a transparency mask. * * Results: * None. * * Side Effects: * Draws the given rectangles. * *---------------------------------------------------------------------- */ void Blt_TileRectangles( Tk_Window tkwin, Drawable drawable, TileClient *clientPtr, XRectangle rectArr[], int nRectangles) { Tile *tilePtr; tilePtr = clientPtr->tilePtr; if (tilePtr->mask != None) { XRectangle *rectPtr, *endPtr; endPtr = rectArr + nRectangles; for (rectPtr = rectArr; rectPtr < endPtr; rectPtr++) { Blt_TileRectangle(tkwin, drawable, clientPtr, rectPtr->x, rectPtr->y, rectPtr->width, rectPtr->height); } } else { XFillRectangles(Tk_Display(tkwin), drawable, tilePtr->gc, rectArr, nRectangles); } } /* *---------------------------------------------------------------------- * * PolygonMask -- * * Creates a polygon shaped mask also stippled by the mask * of the tile. This is used to draw the tiled polygon images * with transparent areas. * * Results: * A bitmap mask is returned. * *---------------------------------------------------------------------- */ static Pixmap PolygonMask(display, pointArr, nPoints, regionPtr, mask, xOrigin, yOrigin) Display *display; XPoint *pointArr; int nPoints; Region2D *regionPtr; Pixmap mask; int xOrigin, yOrigin; { unsigned int width, height; Pixmap bitmap; GC gc; XPoint *destArr; register XPoint *srcPtr, *destPtr, *endPtr; width = regionPtr->right - regionPtr->left + 1; height = regionPtr->bottom - regionPtr->top + 1; bitmap = Tk_GetPixmap(display, DefaultRootWindow(display), width, height, 1); destArr = Blt_Malloc(sizeof(XPoint) * nPoints); endPtr = destArr + nPoints; srcPtr = pointArr; for (destPtr = destArr; destPtr < endPtr; destPtr++) { destPtr->x = srcPtr->x - regionPtr->left; destPtr->y = srcPtr->y - regionPtr->top; srcPtr++; } gc = XCreateGC(display, bitmap, 0, NULL); XFillRectangle(display, bitmap, gc, 0, 0, width, height); XSetForeground(display, gc, 0x01); XSetFillStyle(display, gc, FillStippled); XSetTSOrigin(display, gc, xOrigin - regionPtr->left, yOrigin - regionPtr->top); XSetStipple(display, gc, mask); XFillPolygon(display, bitmap, gc, destArr, nPoints, Complex, CoordModeOrigin); XFreeGC(display, gc); Blt_Free(destArr); return bitmap; } /* *---------------------------------------------------------------------- * * Blt_TilePolygon -- * * Draws a polygon filled by a tiled image. This differs from * the normal XFillPolygon call in that we also try to handle * a transparency mask. * * Results: * None. * * Side Effects: * Draws the polygon. * *---------------------------------------------------------------------- */ void Blt_TilePolygon( Tk_Window tkwin, Drawable drawable, TileClient *clientPtr, XPoint pointArr[], int nPoints) { Tile *tilePtr; Display *display; display = Tk_Display(tkwin); tilePtr = clientPtr->tilePtr; if (tilePtr->mask != None) { XPoint *pointPtr, *endPtr; Region2D region; Pixmap mask; /* Determine the bounding box of the polygon. */ pointPtr = pointArr; region.left = region.right = pointPtr->x; region.top = region.bottom = pointPtr->y; endPtr = pointArr + nPoints; for (pointPtr = pointArr; pointPtr < endPtr; pointPtr++) { if (region.left > pointPtr->x) { region.left = pointPtr->x; } else if (region.right < pointPtr->x) { region.right = pointPtr->x; } if (region.top > pointPtr->y) { region.top = pointPtr->y; } else if (region.bottom < pointPtr->y) { region.bottom = pointPtr->y; } } mask = PolygonMask(display, pointArr, nPoints, ®ion, tilePtr->mask, clientPtr->xOrigin, clientPtr->yOrigin); XSetClipMask(display, tilePtr->gc, mask); XSetClipOrigin(display, tilePtr->gc, region.left, region.top); XFillPolygon(display, drawable, tilePtr->gc, pointArr, nPoints, Complex, CoordModeOrigin); XSetClipMask(display, tilePtr->gc, None); XSetClipOrigin(display, tilePtr->gc, 0, 0); Tk_FreePixmap(display, mask); } else { XFillPolygon(display, drawable, tilePtr->gc, pointArr, nPoints, Complex, CoordModeOrigin); } } #endif blt-2.4z.orig/src/bltTile.h0100644000175000017500000000467607526500126014323 0ustar dokodoko/* * bltTile.h -- * * Copyright 1995-1998 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. */ #ifndef BLT_TILE_H #define BLT_TILE_H #define TILE_THREAD_KEY "BLT Tile Data" #define TILE_MAGIC ((unsigned int) 0x46170277) typedef struct Blt_TileClientStruct *Blt_Tile; /* Opaque type for tiles */ typedef void (Blt_TileChangedProc) _ANSI_ARGS_((ClientData clientData, Blt_Tile tile)); extern int Blt_GetTile _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, char *imageName, Blt_Tile *tilePtr)); extern void Blt_FreeTile _ANSI_ARGS_((Blt_Tile tile)); extern char *Blt_NameOfTile _ANSI_ARGS_((Blt_Tile tile)); extern void Blt_SetTileChangedProc _ANSI_ARGS_((Blt_Tile tile, Blt_TileChangedProc *changeProc, ClientData clientData)); extern void Blt_TileRectangle _ANSI_ARGS_((Tk_Window tkwin, Drawable drawable, Blt_Tile tile, int x, int y, unsigned int width, unsigned int height)); extern void Blt_TileRectangles _ANSI_ARGS_((Tk_Window tkwin, Drawable drawable, Blt_Tile tile, XRectangle *rectArr, int nRects)); extern void Blt_TilePolygon _ANSI_ARGS_((Tk_Window tkwin, Drawable drawable, Blt_Tile tile, XPoint *pointArr, int nPoints)); extern Pixmap Blt_PixmapOfTile _ANSI_ARGS_((Blt_Tile tile)); extern void Blt_SizeOfTile _ANSI_ARGS_((Blt_Tile tile, int *widthPtr, int *heightPtr)); extern void Blt_SetTileOrigin _ANSI_ARGS_((Tk_Window tkwin, Blt_Tile tile, int x, int y)); extern void Blt_SetTSOrigin _ANSI_ARGS_((Tk_Window tkwin, Blt_Tile tile, int x, int y)); #endif /* BLT_TILE_H */ blt-2.4z.orig/src/bltTkInt.h0100644000175000017500000002007407403601147014444 0ustar dokodoko/* * bltTkInt.h -- * * Contains copies of internal Tk structures. * * Copyright 1993-1998 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. */ #ifndef _BLT_TKINT_H #define _BLT_TKINT_H typedef struct { Tk_Uid family; /* Font family. The most important field. */ int pointsize; /* Pointsize of font, 0 for default size, or * negative number meaning pixel size. */ int weight; /* Weight flag; see below for def'n. */ int slant; /* Slant flag; see below for def'n. */ int underline; /* Non-zero for underline font. */ int overstrike; /* Non-zero for overstrike font. */ } TkFontAttributes; typedef struct { int ascent; /* From baseline to top of font. */ int descent; /* From baseline to bottom of font. */ int maxWidth; /* Width of widest character in font. */ int fixed; /* Non-zero if this is a fixed-width font, * 0 otherwise. */ } TkFontMetrics; typedef struct TkFontStruct { /* * Fields used and maintained exclusively by generic code. */ #if (TK_VERSION_NUMBER >= _VERSION(8,1,0)) int resourceRefCount; /* Number of active uses of this font (each * active use corresponds to a call to * Tk_AllocFontFromTable or Tk_GetFont). * If this count is 0, then this TkFont * structure is no longer valid and it isn't * present in a hash table: it is being * kept around only because there are objects * referring to it. The structure is freed * when resourceRefCount and objRefCount * are both 0. */ int objRefCount; /* The number of Tcl objects that reference * this structure. */ #else int refCount; /* Number of users of the TkFont. */ #endif Tcl_HashEntry *cacheHashPtr;/* Entry in font cache for this structure, * used when deleting it. */ Tcl_HashEntry *namedHashPtr;/* Pointer to hash table entry that * corresponds to the named font that the * tkfont was based on, or NULL if the tkfont * was not based on a named font. */ #if (TK_VERSION_NUMBER >= _VERSION(8,1,0)) Screen *screen; /* The screen where this font is valid. */ #endif /* TK_VERSION_NUMBER >= 8.1.0 */ int tabWidth; /* Width of tabs in this font (pixels). */ int underlinePos; /* Offset from baseline to origin of * underline bar (used for drawing underlines * on a non-underlined font). */ int underlineHeight; /* Height of underline bar (used for drawing * underlines on a non-underlined font). */ /* * Fields in the generic font structure that are filled in by * platform-specific code. */ Font fid; /* For backwards compatibility with XGCValues * structures. Remove when TkGCValues is * implemented. */ TkFontAttributes fa; /* Actual font attributes obtained when the * the font was created, as opposed to the * desired attributes passed in to * TkpGetFontFromAttributes(). The desired * metrics can be determined from the string * that was used to create this font. */ TkFontMetrics fm; /* Font metrics determined when font was * created. */ #if (TK_VERSION_NUMBER >= _VERSION(8,1,0)) struct TkFontStruct *nextPtr; /* Points to the next TkFont structure with * the same name. All fonts with the * same name (but different displays) are * chained together off a single entry in * a hash table. */ #endif /* TK_VERSION_NUMBER >= 8.1.0 */ } TkFont; /* * This structure is used by the Mac and Window porting layers as * the internal representation of a clip_mask in a GC. */ typedef struct TkRegionStruct *TkRegion; typedef struct { int type; /* One of TKP_CLIP_PIXMAP or TKP_CLIP_REGION */ union { Pixmap pixmap; TkRegion region; } value; } TkpClipMask; #define TKP_CLIP_PIXMAP 0 #define TKP_CLIP_REGION 1 #ifdef WIN32 /* * The TkWinDrawable is the internal implementation of an X Drawable (either * a Window or a Pixmap). The following constants define the valid Drawable * types. */ #define TWD_BITMAP 1 #define TWD_WINDOW 2 #define TWD_WINDC 3 typedef struct TkWindowStruct TkWindow; typedef struct { int type; HWND handle; TkWindow *winPtr; } TkWinWindow; typedef struct { int type; HBITMAP handle; Colormap colormap; int depth; } TkWinBitmap; typedef struct { int type; HDC hdc; } TkWinDC; typedef union { int type; TkWinWindow window; TkWinBitmap bitmap; TkWinDC winDC; } TkWinDrawable; /* * The TkWinDCState is used to save the state of a device context * so that it can be restored later. */ typedef struct { HPALETTE palette; int bkmode; /* This field was added in Tk * 8.3.1. Be careful that you don't * use this structure in a context * where its size is important. */ } TkWinDCState; extern HDC TkWinGetDrawableDC(Display *display, Drawable drawable, TkWinDCState * state); extern HDC TkWinReleaseDrawableDC(Drawable drawable, HDC dc, TkWinDCState * state); extern HWND Tk_GetHWND _ANSI_ARGS_((Window window)); extern HINSTANCE Tk_GetHINSTANCE _ANSI_ARGS_((void)); extern Window Tk_AttachHWND _ANSI_ARGS_((Tk_Window tkwin, HWND hWnd)); #endif /* WIN32 */ /* * The Border structure used internally by the Tk_3D* routines. * The following is a copy of it from tk3d.c. */ typedef struct TkBorderStruct { 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 refCount; /* Number of different users of * this border. */ #if (TK_VERSION_NUMBER >= _VERSION(8,1,0)) int objRefCount; /* The number of Tcl objects that reference * this structure. */ #endif /* TK_VERSION_NUMBER >= 8.1.0 */ XColor *bgColor; /* Background color (intensity between * lightColorPtr and darkColorPtr). */ XColor *darkColor; /* Color for darker areas (must free when * deleting structure). NULL means shadows * haven't been allocated yet.*/ XColor *lightColor; /* 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 TkBorderStruct *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; #endif /* BLT_TKINT_H */ blt-2.4z.orig/src/bltTree.c0100644000175000017500000023546507545511454014331 0ustar dokodoko /* * bltTree.c -- * * Copyright 1998-1999 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 or 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. * * The "tree" data object was created by George A. Howlett. */ #include "bltInt.h" /* TODO: * traces and notifiers should be in one list in tree object. * notifier is always fired. * incorporate first/next tag routines ? */ #ifndef NO_TREE #include "bltTree.h" static Tcl_InterpDeleteProc TreeInterpDeleteProc; static Blt_TreeApplyProc SizeApplyProc; static Tcl_IdleProc NotifyIdleProc; #define TREE_THREAD_KEY "BLT Tree Data" #define TREE_MAGIC ((unsigned int) 0x46170277) #define TREE_DESTROYED (1<<0) typedef struct Blt_TreeNodeStruct Node; typedef struct Blt_TreeClientStruct TreeClient; typedef struct Blt_TreeObjectStruct TreeObject; typedef struct Blt_TreeValueStruct Value; /* * Blt_TreeValue -- * * Tree nodes contain heterogeneous data fields, represented as a * chain of these structures. Each field contains the key of the * field (Blt_TreeKey) and the value (Tcl_Obj) containing the * actual data representations. * */ struct Blt_TreeValueStruct { Blt_TreeKey key; /* String identifying the data field */ Tcl_Obj *objPtr; /* Data representation. */ Blt_Tree owner; /* Non-NULL if privately owned. */ Blt_TreeValue next; /* Next value in the chain. */ }; #include #include /* The following header is required for LP64 compilation */ #include #include "bltHash.h" static void TreeDestroyValues _ANSI_ARGS_((Blt_TreeNode node)); static Value *TreeFindValue _ANSI_ARGS_((Blt_TreeNode node, Blt_TreeKey key)); static Value *TreeCreateValue _ANSI_ARGS_((Blt_TreeNode node, Blt_TreeKey key, int *newPtr)); static int TreeDeleteValue _ANSI_ARGS_((Blt_TreeNode node, Blt_TreeValue value)); static Value *TreeFirstValue _ANSI_ARGS_((Blt_TreeNode, Blt_TreeKeySearch *searchPtr)); static Value *TreeNextValue _ANSI_ARGS_((Blt_TreeKeySearch *srchPtr)); /* * When there are this many entries per bucket, on average, rebuild * the hash table to make it larger. */ #define REBUILD_MULTIPLIER 3 #if (SIZEOF_VOID_P == 8) #define RANDOM_INDEX(i) HashOneWord(mask, downshift, i) #define BITSPERWORD 64 #else #define START_LOGSIZE 5 /* Initial hash table size is 32. */ #define MAX_LIST_VALUES 20 /* Convert to hash table when node * value list gets bigger than this * many values. */ /* * The following macro takes a preliminary integer hash value and * produces an index into a hash tables bucket list. The idea is * to make it so that preliminary values that are arbitrarily similar * will end up in different buckets. The hash function was taken * from a random-number generator. */ #define RANDOM_INDEX(i) \ (((((long) (i))*1103515245) >> downshift) & mask) #define BITSPERWORD 32 #endif #define DOWNSHIFT_START (BITSPERWORD - 2) /* * Procedure prototypes for static procedures in this file: */ #if (SIZEOF_VOID_P == 8) static Blt_Hash HashOneWord _ANSI_ARGS_((uint64_t mask, unsigned int downshift, CONST void *key)); #endif /* SIZEOF_VOID_P == 8 */ /* * The hash table below is used to keep track of all the Blt_TreeKeys * created so far. */ static Blt_HashTable keyTable; static int keyTableInitialized = 0; typedef struct { Blt_HashTable treeTable; /* Table of trees. */ unsigned int nextId; Tcl_Interp *interp; } TreeInterpData; typedef struct { Tcl_Interp *interp; ClientData clientData; Blt_TreeKey key; unsigned int mask; Blt_TreeNotifyEventProc *proc; Blt_TreeNotifyEvent event; int notifyPending; } EventHandler; typedef struct { ClientData clientData; char *keyPattern; char *withTag; Node *nodePtr; unsigned int mask; Blt_TreeTraceProc *proc; TreeClient *clientPtr; Blt_ChainLink *linkPtr; } TraceHandler; /* * -------------------------------------------------------------- * * GetTreeInterpData -- * * Creates or retrieves data associated with tree data objects * for a particular thread. We're using Tcl_GetAssocData rather * than the Tcl thread routines so BLT can work with pre-8.0 * Tcl versions that don't have thread support. * * Results: * Returns a pointer to the tree interpreter data. * * -------------------------------------------------------------- */ static TreeInterpData * GetTreeInterpData(Tcl_Interp *interp) { Tcl_InterpDeleteProc *proc; TreeInterpData *dataPtr; dataPtr = (TreeInterpData *) Tcl_GetAssocData(interp, TREE_THREAD_KEY, &proc); if (dataPtr == NULL) { dataPtr = Blt_Malloc(sizeof(TreeInterpData)); assert(dataPtr); dataPtr->interp = interp; Tcl_SetAssocData(interp, TREE_THREAD_KEY, TreeInterpDeleteProc, dataPtr); Blt_InitHashTable(&dataPtr->treeTable, BLT_STRING_KEYS); } return dataPtr; } /* * -------------------------------------------------------------- * * NewNode -- * * Creates a new node in the tree without installing it. The * number of nodes in the tree is incremented and a unique serial * number is generated for the node. * * Also, all nodes have a label. If no label was provided (name * is NULL) then automatically generate one in the form "nodeN" * where N is the serial number of the node. * * Results: * Returns a pointer to the new node. * * -------------------------------------------------------------- */ static Node * NewNode(TreeObject *treeObjPtr, CONST char *name, int inode) { Node *nodePtr; /* Create the node structure */ nodePtr = Blt_PoolAllocItem(treeObjPtr->nodePool, sizeof(Node)); nodePtr->inode = inode; nodePtr->treeObject = treeObjPtr; nodePtr->parent = NULL; nodePtr->depth = 0; nodePtr->flags = 0; nodePtr->next = nodePtr->prev = NULL; nodePtr->first = nodePtr->last = NULL; nodePtr->nChildren = 0; nodePtr->values = NULL; nodePtr->logSize = 0; nodePtr->nValues = 0; nodePtr->label = NULL; if (name != NULL) { nodePtr->label = Blt_TreeGetKey(name); } treeObjPtr->nNodes++; return nodePtr; } /* *---------------------------------------------------------------------- * * ReleaseTagTable -- * *---------------------------------------------------------------------- */ static void ReleaseTagTable(Blt_TreeTagTable *tablePtr) { tablePtr->refCount--; if (tablePtr->refCount <= 0) { Blt_HashEntry *hPtr; Blt_HashSearch cursor; for(hPtr = Blt_FirstHashEntry(&tablePtr->tagTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { Blt_TreeTagEntry *tPtr; tPtr = Blt_GetHashValue(hPtr); Blt_DeleteHashTable(&tPtr->nodeTable); Blt_Free(tPtr); } Blt_DeleteHashTable(&tablePtr->tagTable); Blt_Free(tablePtr); } } /* * ---------------------------------------------------------------------- * * ResetDepths -- * * Called after moving a node, resets the depths of each node * for the entire branch (node and it's decendants). * * Results: * None. * * ---------------------------------------------------------------------- */ static void ResetDepths( Node *nodePtr, /* Root node. */ int depth) /* Depth of the node. */ { nodePtr->depth = depth; /* Also reset the depth for each descendant node. */ for (nodePtr = nodePtr->first; nodePtr != NULL; nodePtr = nodePtr->next) { ResetDepths(nodePtr, depth + 1); } } /* *---------------------------------------------------------------------- * * LinkBefore -- * * Inserts a link preceding a given link. * * Results: * None. * *---------------------------------------------------------------------- */ static void LinkBefore( Node *parentPtr, /* Parent to hold the new entry. */ Node *nodePtr, /* New node to be inserted. */ Node *beforePtr) /* Node to link before. */ { if (parentPtr->first == NULL) { parentPtr->last = parentPtr->first = nodePtr; } else if (beforePtr == NULL) { /* Append onto the end of the chain */ nodePtr->next = NULL; nodePtr->prev = parentPtr->last; parentPtr->last->next = nodePtr; parentPtr->last = nodePtr; } else { nodePtr->prev = beforePtr->prev; nodePtr->next = beforePtr; if (beforePtr == parentPtr->first) { parentPtr->first = nodePtr; } else { beforePtr->prev->next = nodePtr; } beforePtr->prev = nodePtr; } parentPtr->nChildren++; nodePtr->parent = parentPtr; } /* *---------------------------------------------------------------------- * * UnlinkNode -- * * Unlinks a link from the chain. The link is not deallocated, * but only removed from the chain. * * Results: * None. * *---------------------------------------------------------------------- */ static void UnlinkNode(Node *nodePtr) { Node *parentPtr; int unlinked; /* Indicates if the link is actually * removed from the chain. */ parentPtr = nodePtr->parent; unlinked = FALSE; if (parentPtr->first == nodePtr) { parentPtr->first = nodePtr->next; unlinked = TRUE; } if (parentPtr->last == nodePtr) { parentPtr->last = nodePtr->prev; unlinked = TRUE; } if (nodePtr->next != NULL) { nodePtr->next->prev = nodePtr->prev; unlinked = TRUE; } if (nodePtr->prev != NULL) { nodePtr->prev->next = nodePtr->next; unlinked = TRUE; } if (unlinked) { parentPtr->nChildren--; } nodePtr->prev = nodePtr->next = NULL; } /* * -------------------------------------------------------------- * * FreeNode -- * * Unlinks a given node from the tree, removes its data, and * frees memory allocated to the node. * * Results: * None. * * -------------------------------------------------------------- */ static void FreeNode(TreeObject *treeObjPtr, Node *nodePtr) { Blt_HashEntry *hPtr; /* * Destroy any data fields associated with this node. */ TreeDestroyValues(nodePtr); UnlinkNode(nodePtr); treeObjPtr->nNodes--; hPtr = Blt_FindHashEntry(&treeObjPtr->nodeTable, (char *)nodePtr->inode); assert(hPtr); Blt_DeleteHashEntry(&treeObjPtr->nodeTable, hPtr); Blt_PoolFreeItem(treeObjPtr->nodePool, (char *)nodePtr); } /* * -------------------------------------------------------------- * * NewTreeObject -- * * Creates and initializes a new tree object. Trees always * contain a root node, so one is allocated here. * * Results: * Returns a pointer to the new tree object is successful, NULL * otherwise. If a tree can't be generated, interp->result will * contain an error message. * * -------------------------------------------------------------- */ static TreeObject * NewTreeObject(TreeInterpData *dataPtr, Tcl_Interp *interp, CONST char *treeName) { TreeObject *treeObjPtr; int isNew; Blt_HashEntry *hPtr; treeObjPtr = Blt_Calloc(1, sizeof(TreeObject)); if (treeObjPtr == NULL) { Tcl_AppendResult(interp, "can't allocate tree", (char *)NULL); return NULL; } treeObjPtr->name = Blt_Strdup(treeName); treeObjPtr->interp = interp; treeObjPtr->valuePool = Blt_PoolCreate(BLT_FIXED_SIZE_ITEMS); treeObjPtr->nodePool = Blt_PoolCreate(BLT_FIXED_SIZE_ITEMS); treeObjPtr->clients = Blt_ChainCreate(); treeObjPtr->depth = 1; treeObjPtr->notifyFlags = 0; Blt_InitHashTableWithPool(&treeObjPtr->nodeTable, BLT_ONE_WORD_KEYS); hPtr = Blt_CreateHashEntry(&treeObjPtr->nodeTable, (char *)0, &isNew); treeObjPtr->root = NewNode(treeObjPtr, treeName, 0); Blt_SetHashValue(hPtr, treeObjPtr->root); treeObjPtr->tablePtr = &dataPtr->treeTable; treeObjPtr->hashPtr = Blt_CreateHashEntry(treeObjPtr->tablePtr, treeName, &isNew); Blt_SetHashValue(treeObjPtr->hashPtr, treeObjPtr); return treeObjPtr; } static TreeObject * FindTreeInNamespace( TreeInterpData *dataPtr, /* Interpreter-specific data. */ Tcl_Namespace *nsPtr, CONST char *treeName) { Tcl_DString dString; char *name; Blt_HashEntry *hPtr; name = Blt_GetQualifiedName(nsPtr, treeName, &dString); hPtr = Blt_FindHashEntry(&dataPtr->treeTable, name); Tcl_DStringFree(&dString); if (hPtr != NULL) { return Blt_GetHashValue(hPtr); } return NULL; } /* * ---------------------------------------------------------------------- * * GetTreeObject -- * * Searches for the tree object associated by the name given. * * Results: * Returns a pointer to the tree if found, otherwise NULL. * * ---------------------------------------------------------------------- */ static TreeObject * GetTreeObject(Tcl_Interp *interp, CONST char *name, int flags) { CONST char *treeName; Tcl_Namespace *nsPtr; /* Namespace associated with the tree object. * If NULL, indicates to look in first the * current namespace and then the global * for the tree. */ TreeInterpData *dataPtr; /* Interpreter-specific data. */ TreeObject *treeObjPtr; treeObjPtr = NULL; if (Blt_ParseQualifiedName(interp, name, &nsPtr, &treeName) != TCL_OK) { Tcl_AppendResult(interp, "can't find namespace in \"", name, "\"", (char *)NULL); return NULL; } dataPtr = GetTreeInterpData(interp); if (nsPtr != NULL) { treeObjPtr = FindTreeInNamespace(dataPtr, nsPtr, treeName); } else { if (flags & NS_SEARCH_CURRENT) { /* Look first in the current namespace. */ nsPtr = Tcl_GetCurrentNamespace(interp); treeObjPtr = FindTreeInNamespace(dataPtr, nsPtr, treeName); } if ((treeObjPtr == NULL) && (flags & NS_SEARCH_GLOBAL)) { nsPtr = Tcl_GetGlobalNamespace(interp); treeObjPtr = FindTreeInNamespace(dataPtr, nsPtr, treeName); } } return treeObjPtr; } /* * ---------------------------------------------------------------------- * * TeardownTree -- * * Destroys an entire branch. This is a special purpose routine * used to speed up the final clean up of the tree. * * Results: * None. * * ---------------------------------------------------------------------- */ static void TeardownTree(TreeObject *treeObjPtr, Node *nodePtr) { if (nodePtr->first != NULL) { Node *childPtr, *nextPtr; for (childPtr = nodePtr->first; childPtr != NULL; childPtr = nextPtr) { nextPtr = childPtr->next; TeardownTree(treeObjPtr, childPtr); } } if (nodePtr->values != NULL) { TreeDestroyValues(nodePtr); } Blt_PoolFreeItem(treeObjPtr->nodePool, (char *)nodePtr); } static void DestroyTreeObject(TreeObject *treeObjPtr) { Blt_ChainLink *linkPtr; TreeClient *clientPtr; treeObjPtr->flags |= TREE_DESTROYED; treeObjPtr->nNodes = 0; /* Remove the remaining clients. */ for (linkPtr = Blt_ChainFirstLink(treeObjPtr->clients); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { clientPtr = Blt_ChainGetValue(linkPtr); Blt_ChainDestroy(clientPtr->events); Blt_ChainDestroy(clientPtr->traces); Blt_Free(clientPtr); } Blt_ChainDestroy(treeObjPtr->clients); TeardownTree(treeObjPtr, treeObjPtr->root); Blt_PoolDestroy(treeObjPtr->nodePool); Blt_PoolDestroy(treeObjPtr->valuePool); Blt_DeleteHashTable(&treeObjPtr->nodeTable); if (treeObjPtr->hashPtr != NULL) { /* Remove the entry from the global tree table. */ Blt_DeleteHashEntry(treeObjPtr->tablePtr, treeObjPtr->hashPtr); if ((treeObjPtr->tablePtr->numEntries == 0) && (keyTableInitialized)) { keyTableInitialized = FALSE; Blt_DeleteHashTable(&keyTable); } } if (treeObjPtr->name != NULL) { Blt_Free(treeObjPtr->name); } Blt_Free(treeObjPtr); } /* * ----------------------------------------------------------------------- * * TreeInterpDeleteProc -- * * This is called when the interpreter hosting the tree object * is deleted from the interpreter. * * Results: * None. * * Side effects: * Destroys all remaining trees and removes the hash table * used to register tree names. * * ------------------------------------------------------------------------ */ /* ARGSUSED */ static void TreeInterpDeleteProc( ClientData clientData, /* Interpreter-specific data. */ Tcl_Interp *interp) { TreeInterpData *dataPtr = clientData; Blt_HashEntry *hPtr; Blt_HashSearch cursor; TreeObject *treeObjPtr; for (hPtr = Blt_FirstHashEntry(&dataPtr->treeTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { treeObjPtr = (TreeObject *)Blt_GetHashValue(hPtr); treeObjPtr->hashPtr = NULL; DestroyTreeObject(treeObjPtr); } if (keyTableInitialized) { keyTableInitialized = FALSE; Blt_DeleteHashTable(&keyTable); } Blt_DeleteHashTable(&dataPtr->treeTable); Tcl_DeleteAssocData(interp, TREE_THREAD_KEY); Blt_Free(dataPtr); } /* *---------------------------------------------------------------------- * * NotifyIdleProc -- * * Used to invoke event handler routines at some idle point. * This routine is called from the Tcl event loop. Errors * generated by the event handler routines are backgrounded. * * Results: * None. * *---------------------------------------------------------------------- */ static void NotifyIdleProc(ClientData clientData) { EventHandler *notifyPtr = clientData; int result; notifyPtr->notifyPending = FALSE; notifyPtr->mask |= TREE_NOTIFY_ACTIVE; result = (*notifyPtr->proc)(notifyPtr->clientData, ¬ifyPtr->event); notifyPtr->mask &= ~TREE_NOTIFY_ACTIVE; if (result != TCL_OK) { Tcl_BackgroundError(notifyPtr->interp); } } /* *---------------------------------------------------------------------- * * CheckEventHandlers -- * * Traverses the list of client event callbacks and checks * if one matches the given event. A client may trigger an * action that causes the tree to notify it. The can be * prevented by setting the TREE_NOTIFY_FOREIGN_ONLY bit in * the event handler. * * If a matching handler is found, a callback may be called either * immediately or at the next idle time depending upon the * TREE_NOTIFY_WHENIDLE bit. * * Since a handler routine may trigger yet another call to * itself, callbacks are ignored while the event handler is * executing. * * Results: * None. * *---------------------------------------------------------------------- */ static void CheckEventHandlers( TreeClient *clientPtr, int isSource, /* Indicates if the client is the source * of the event. */ Blt_TreeNotifyEvent *eventPtr) { Blt_ChainLink *linkPtr, *nextPtr; EventHandler *notifyPtr; eventPtr->tree = clientPtr; for (linkPtr = Blt_ChainFirstLink(clientPtr->events); linkPtr != NULL; linkPtr = nextPtr) { nextPtr = Blt_ChainNextLink(linkPtr); notifyPtr = Blt_ChainGetValue(linkPtr); if ((notifyPtr->mask & TREE_NOTIFY_ACTIVE) || (notifyPtr->mask & eventPtr->type) == 0) { continue; /* Ignore callbacks that are generated * inside of a notify handler routine. */ } if ((isSource) && (notifyPtr->mask & TREE_NOTIFY_FOREIGN_ONLY)) { continue; /* Don't notify yourself. */ } if (notifyPtr->mask & TREE_NOTIFY_WHENIDLE) { if (!notifyPtr->notifyPending) { notifyPtr->notifyPending = TRUE; notifyPtr->event = *eventPtr; Tcl_DoWhenIdle(NotifyIdleProc, notifyPtr); } } else { int result; notifyPtr->mask |= TREE_NOTIFY_ACTIVE; result = (*notifyPtr->proc) (notifyPtr->clientData, eventPtr); notifyPtr->mask &= ~TREE_NOTIFY_ACTIVE; if (result != TCL_OK) { Tcl_BackgroundError(notifyPtr->interp); } } } } /* *---------------------------------------------------------------------- * * NotifyClients -- * * Traverses the list of clients for a particular tree and * notifies each client that an event occurred. Clients * indicate interest in a particular event through a bit * flag. * *---------------------------------------------------------------------- */ static void NotifyClients( TreeClient *sourcePtr, TreeObject *treeObjPtr, Node *nodePtr, int eventFlag) { Blt_ChainLink *linkPtr; Blt_TreeNotifyEvent event; TreeClient *clientPtr; int isSource; event.type = eventFlag; event.inode = nodePtr->inode; /* * Issue callbacks to each client indicating that a new node has * been created. */ for (linkPtr = Blt_ChainFirstLink(treeObjPtr->clients); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { clientPtr = Blt_ChainGetValue(linkPtr); isSource = (clientPtr == sourcePtr); CheckEventHandlers(clientPtr, isSource, &event); } } static void FreeValue(Node *nodePtr, Value *valuePtr) { if (valuePtr->objPtr != NULL) { Tcl_DecrRefCount(valuePtr->objPtr); } Blt_PoolFreeItem(nodePtr->treeObject->valuePool, valuePtr); } /* Public Routines */ /* *---------------------------------------------------------------------- * * Blt_TreeGetKey -- * * Given a string, returns a unique identifier for the string. * *---------------------------------------------------------------------- */ Blt_TreeKey Blt_TreeGetKey(string) CONST char *string; /* String to convert. */ { Blt_HashEntry *hPtr; int isNew; if (!keyTableInitialized) { Blt_InitHashTable(&keyTable, BLT_STRING_KEYS); keyTableInitialized = 1; } hPtr = Blt_CreateHashEntry(&keyTable, string, &isNew); return (Blt_TreeKey)Blt_GetHashKey(&keyTable, hPtr); } /* *---------------------------------------------------------------------- * * Blt_TreeCreateNode -- * * Creates a new node in the given parent node. The name and * position in the parent are also provided. * *---------------------------------------------------------------------- */ Blt_TreeNode Blt_TreeCreateNode( TreeClient *clientPtr, /* The tree client that is creating * this node. If NULL, indicates to * trigger notify events on behalf of * the initiating client also. */ Node *parentPtr, /* Parent node where the new node will * be inserted. */ CONST char *name, /* Name of node. */ int pos) /* Position in the parent's list of children * where to insert the new node. */ { Blt_HashEntry *hPtr; Node *beforePtr; Node *nodePtr; /* Node to be inserted. */ TreeObject *treeObjPtr; int inode; int isNew; treeObjPtr = parentPtr->treeObject; /* Generate an unique serial number for this node. */ do { inode = treeObjPtr->nextInode++; hPtr = Blt_CreateHashEntry(&treeObjPtr->nodeTable,(char *)inode, &isNew); } while (!isNew); nodePtr = NewNode(treeObjPtr, name, inode); Blt_SetHashValue(hPtr, nodePtr); if ((pos == -1) || (pos >= (int)parentPtr->nChildren)) { beforePtr = NULL; } else { beforePtr = parentPtr->first; while ((pos > 0) && (beforePtr != NULL)) { pos--; beforePtr = beforePtr->next; } } LinkBefore(parentPtr, nodePtr, beforePtr); nodePtr->depth = parentPtr->depth + 1; /* * Issue callbacks to each client indicating that a new node has * been created. */ NotifyClients(clientPtr, treeObjPtr, nodePtr, TREE_NOTIFY_CREATE); return nodePtr; } /* *---------------------------------------------------------------------- * * Blt_TreeCreateNodeWithId -- * * Like Blt_TreeCreateNode, but provides a specific id to use * for the node. If the tree already contains a node by that * id, NULL is returned. * *---------------------------------------------------------------------- */ Blt_TreeNode Blt_TreeCreateNodeWithId( TreeClient *clientPtr, Node *parentPtr, /* Parent node where the new node will * be inserted. */ CONST char *name, /* Name of node. */ int inode, /* Requested id of the new node. If a * node by this id already exists in the * tree, no node is created. */ int position) /* Position in the parent's list of children * where to insert the new node. */ { Blt_HashEntry *hPtr; Node *beforePtr; Node *nodePtr; /* Node to be inserted. */ TreeObject *treeObjPtr; int isNew; treeObjPtr = parentPtr->treeObject; hPtr = Blt_CreateHashEntry(&treeObjPtr->nodeTable,(char *)inode, &isNew); if (!isNew) { return NULL; } nodePtr = NewNode(treeObjPtr, name, inode); Blt_SetHashValue(hPtr, nodePtr); if ((position == -1) || (position >= (int)parentPtr->nChildren)) { beforePtr = NULL; } else { beforePtr = parentPtr->first; while ((position > 0) && (beforePtr != NULL)) { position--; beforePtr = beforePtr->next; } } LinkBefore(parentPtr, nodePtr, beforePtr); nodePtr->depth = parentPtr->depth + 1; /* * Issue callbacks to each client indicating that a new node has * been created. */ NotifyClients(clientPtr, treeObjPtr, nodePtr, TREE_NOTIFY_CREATE); return nodePtr; } /* *---------------------------------------------------------------------- * * Blt_TreeMoveNode -- * * Move an entry into a new location in the hierarchy. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ int Blt_TreeMoveNode( TreeClient *clientPtr, Node *nodePtr, Node *parentPtr, Node *beforePtr) { TreeObject *treeObjPtr = nodePtr->treeObject; int newDepth; if (nodePtr == beforePtr) { return TCL_ERROR; } if ((beforePtr != NULL) && (beforePtr->parent != parentPtr)) { return TCL_ERROR; } if (nodePtr->parent == NULL) { return TCL_ERROR; /* Can't move root. */ } /* Verify that the node isn't an ancestor of the new parent. */ if (Blt_TreeIsAncestor(nodePtr, parentPtr)) { return TCL_ERROR; } UnlinkNode(nodePtr); /* * Relink the node as a child of the new parent. */ LinkBefore(parentPtr, nodePtr, beforePtr); newDepth = parentPtr->depth + 1; if (nodePtr->depth != newDepth) { /* Reset the depths of all descendant nodes. */ ResetDepths(nodePtr, newDepth); } /* * Issue callbacks to each client indicating that a node has * been moved. */ NotifyClients(clientPtr, treeObjPtr, nodePtr, TREE_NOTIFY_MOVE); return TCL_OK; } int Blt_TreeDeleteNode(TreeClient *clientPtr, Node *nodePtr) { TreeObject *treeObjPtr = nodePtr->treeObject; Node *childPtr, *nextPtr; /* In depth-first order, delete each descendant node. */ for (childPtr = nodePtr->first; childPtr != NULL; childPtr = nextPtr) { nextPtr = childPtr->next; Blt_TreeDeleteNode(clientPtr, childPtr); } /* * Issue callbacks to each client indicating that the node can * no longer be used. */ NotifyClients(clientPtr, treeObjPtr, nodePtr, TREE_NOTIFY_DELETE); /* Now remove the actual node. */ FreeNode(treeObjPtr, nodePtr); return TCL_OK; } Blt_TreeNode Blt_TreeGetNode(TreeClient *clientPtr, unsigned int inode) { TreeObject *treeObjPtr = clientPtr->treeObject; Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&treeObjPtr->nodeTable, (char *)inode); if (hPtr != NULL) { return (Blt_TreeNode)Blt_GetHashValue(hPtr); } return NULL; } Blt_TreeTrace Blt_TreeCreateTrace( TreeClient *clientPtr, Node *nodePtr, CONST char *keyPattern, CONST char *tagName, unsigned int mask, Blt_TreeTraceProc *proc, ClientData clientData) { TraceHandler *tracePtr; tracePtr = Blt_Calloc(1, sizeof (TraceHandler)); assert(tracePtr); tracePtr->linkPtr = Blt_ChainAppend(clientPtr->traces, tracePtr); if (keyPattern != NULL) { tracePtr->keyPattern = Blt_Strdup(keyPattern); } if (tagName != NULL) { tracePtr->withTag = Blt_Strdup(tagName); } tracePtr->clientPtr = clientPtr; tracePtr->proc = proc; tracePtr->clientData = clientData; tracePtr->mask = mask; tracePtr->nodePtr = nodePtr; return (Blt_TreeTrace)tracePtr; } void Blt_TreeDeleteTrace(Blt_TreeTrace trace) { TraceHandler *tracePtr = (TraceHandler *)trace; Blt_ChainDeleteLink(tracePtr->clientPtr->traces, tracePtr->linkPtr); if (tracePtr->keyPattern != NULL) { Blt_Free(tracePtr->keyPattern); } if (tracePtr->withTag != NULL) { Blt_Free(tracePtr->withTag); } Blt_Free(tracePtr); } void Blt_TreeRelabelNode(TreeClient *clientPtr, Node *nodePtr, CONST char *string) { nodePtr->label = Blt_TreeGetKey(string); /* * Issue callbacks to each client indicating that a new node has * been created. */ NotifyClients(clientPtr, clientPtr->treeObject, nodePtr, TREE_NOTIFY_RELABEL); } void Blt_TreeRelabelNode2(Node *nodePtr, CONST char *string) { nodePtr->label = Blt_TreeGetKey(string); } /* *---------------------------------------------------------------------- * * Blt_TreeFindChild -- * * Searches for the named node in a parent's chain of siblings. * * * Results: * If found, the child node is returned, otherwise NULL. * *---------------------------------------------------------------------- */ Blt_TreeNode Blt_TreeFindChild(Node *parentPtr, CONST char *string) { Blt_TreeKey label; register Node *nodePtr; label = Blt_TreeGetKey(string); for (nodePtr = parentPtr->first; nodePtr != NULL; nodePtr = nodePtr->next) { if (label == nodePtr->label) { return nodePtr; } } return NULL; } /* *---------------------------------------------------------------------- * * Blt_TreeNodePosition -- * * Returns the position of the node in its parent's list of * children. The root's position is 0. * *---------------------------------------------------------------------- */ int Blt_TreeNodePosition(Node *nodePtr) { Node *parentPtr; int count; count = 0; parentPtr = nodePtr->parent; if (parentPtr != NULL) { Node *childPtr; for (childPtr = parentPtr->first; childPtr != NULL; childPtr = childPtr->next) { if (nodePtr == childPtr) { break; } count++; } } return count; } /* *---------------------------------------------------------------------- * * Blt_TreePrevNode -- * * Returns the "previous" node in the tree. This node (in * depth-first order) is its parent, if the node has no siblings * that are previous to it. Otherwise it is the last descendant * of the last sibling. In this case, descend the sibling's * hierarchy, using the last child at any ancestor, with we * we find a leaf. * *---------------------------------------------------------------------- */ Blt_TreeNode Blt_TreePrevNode(Node *rootPtr, Node *nodePtr) { Node *prevPtr; if (nodePtr == rootPtr) { return NULL; /* The root is the first node. */ } prevPtr = nodePtr->prev; if (prevPtr == NULL) { /* There are no siblings previous to this one, so pick the parent. */ return nodePtr->parent; } /* * Traverse down the right-most thread, in order to select the * next entry. Stop when we reach a leaf. */ nodePtr = prevPtr; while ((prevPtr = nodePtr->last) != NULL) { nodePtr = prevPtr; } return nodePtr; } /* *---------------------------------------------------------------------- * * Blt_TreeNextNode -- * * Returns the "next" node in relation to the given node. * The next node (in depth-first order) is either the first * child of the given node the next sibling if the node has * no children (the node is a leaf). If the given node is the * last sibling, then try it's parent next sibling. Continue * until we either find a next sibling for some ancestor or * we reach the root node. In this case the current node is * the last node in the tree. * *---------------------------------------------------------------------- */ Blt_TreeNode Blt_TreeNextNode(Node *rootPtr, Node *nodePtr) { Node *nextPtr; /* Pick the first sub-node. */ nextPtr = nodePtr->first; if (nextPtr != NULL) { return nextPtr; } /* * Back up until we can find a level where we can pick a * "next sibling". For the last entry we'll thread our * way back to the root. */ while (nodePtr != rootPtr) { nextPtr = nodePtr->next; if (nextPtr != NULL) { return nextPtr; } nodePtr = nodePtr->parent; } return NULL; /* At root, no next node. */ } int Blt_TreeIsBefore(Node *n1Ptr, Node *n2Ptr) { int depth; register int i; Node *nodePtr; if (n1Ptr == n2Ptr) { return FALSE; } depth = MIN(n1Ptr->depth, n2Ptr->depth); if (depth == 0) { /* One of the nodes is root. */ return (n1Ptr->parent == NULL); } /* * Traverse back from the deepest node, until both nodes are at * the same depth. Check if this ancestor node is the same for * both nodes. */ for (i = n1Ptr->depth; i > depth; i--) { n1Ptr = n1Ptr->parent; } if (n1Ptr == n2Ptr) { return FALSE; } for (i = n2Ptr->depth; i > depth; i--) { n2Ptr = n2Ptr->parent; } if (n2Ptr == n1Ptr) { return TRUE; } /* * First find the mutual ancestor of both nodes. Look at each * preceding ancestor level-by-level for both nodes. Eventually * we'll find a node that's the parent of both ancestors. Then * find the first ancestor in the parent's list of subnodes. */ for (i = depth; i > 0; i--) { if (n1Ptr->parent == n2Ptr->parent) { break; } n1Ptr = n1Ptr->parent; n2Ptr = n2Ptr->parent; } for (nodePtr = n1Ptr->parent->first; nodePtr != NULL; nodePtr = nodePtr->next) { if (nodePtr == n1Ptr) { return TRUE; } else if (nodePtr == n2Ptr) { return FALSE; } } return FALSE; } static void CallTraces( Tcl_Interp *interp, TreeClient *sourcePtr, /* Client holding a reference to the * tree. If NULL, indicates to * execute all handlers, including * those of the caller. */ TreeObject *treeObjPtr, /* Tree that was changed. */ Node *nodePtr, /* Node that received the event. */ Blt_TreeKey key, unsigned int flags) { Blt_ChainLink *l1Ptr, *l2Ptr; TreeClient *clientPtr; TraceHandler *tracePtr; for(l1Ptr = Blt_ChainFirstLink(treeObjPtr->clients); l1Ptr != NULL; l1Ptr = Blt_ChainNextLink(l1Ptr)) { clientPtr = Blt_ChainGetValue(l1Ptr); for(l2Ptr = Blt_ChainFirstLink(clientPtr->traces); l2Ptr != NULL; l2Ptr = Blt_ChainNextLink(l2Ptr)) { tracePtr = Blt_ChainGetValue(l2Ptr); if ((tracePtr->keyPattern != NULL) && (!Tcl_StringMatch(key, tracePtr->keyPattern))) { continue; /* Key pattern doesn't match. */ } if ((tracePtr->withTag != NULL) && (!Blt_TreeHasTag(clientPtr, nodePtr, tracePtr->withTag))) { continue; /* Doesn't have the tag. */ } if ((tracePtr->mask & flags) == 0) { continue; /* Flags don't match. */ } if ((clientPtr == sourcePtr) && (tracePtr->mask & TREE_TRACE_FOREIGN_ONLY)) { continue; /* This client initiated the trace. */ } if ((tracePtr->nodePtr != NULL) && (tracePtr->nodePtr != nodePtr)) { continue; /* Nodes don't match. */ } nodePtr->flags |= TREE_TRACE_ACTIVE; if ((*tracePtr->proc) (tracePtr->clientData, treeObjPtr->interp, nodePtr, key, flags) != TCL_OK) { if (interp != NULL) { Tcl_BackgroundError(interp); } } nodePtr->flags &= ~TREE_TRACE_ACTIVE; } } } static Value * GetTreeValue( Tcl_Interp *interp, TreeClient *clientPtr, Node *nodePtr, Blt_TreeKey key) { register Value *valuePtr; valuePtr = TreeFindValue(nodePtr, key); if (valuePtr == NULL) { if (interp != NULL) { Tcl_AppendResult(interp, "can't find field \"", key, "\"", (char *)NULL); } return NULL; } if ((valuePtr->owner != NULL) && (valuePtr->owner != clientPtr)) { if (interp != NULL) { Tcl_AppendResult(interp, "can't access private field \"", key, "\"", (char *)NULL); } return NULL; } return valuePtr; } int Blt_TreePrivateValue( Tcl_Interp *interp, TreeClient *clientPtr, Node *nodePtr, Blt_TreeKey key) { Value *valuePtr; valuePtr = TreeFindValue(nodePtr, key); if (valuePtr == NULL) { if (interp != NULL) { Tcl_AppendResult(interp, "can't find field \"", key, "\"", (char *)NULL); } return TCL_ERROR; } valuePtr->owner = clientPtr; return TCL_OK; } int Blt_TreePublicValue( Tcl_Interp *interp, TreeClient *clientPtr, Node *nodePtr, Blt_TreeKey key) { Value *valuePtr; valuePtr = TreeFindValue(nodePtr, key); if (valuePtr == NULL) { if (interp != NULL) { Tcl_AppendResult(interp, "can't find field \"", key, "\"", (char *)NULL); } return TCL_ERROR; } if (valuePtr->owner != clientPtr) { if (interp != NULL) { Tcl_AppendResult(interp, "not the owner of \"", key, "\"", (char *)NULL); } return TCL_ERROR; } valuePtr->owner = NULL; return TCL_OK; } int Blt_TreeValueExistsByKey(clientPtr, nodePtr, key) TreeClient *clientPtr; Node *nodePtr; Blt_TreeKey key; { register Value *valuePtr; valuePtr = GetTreeValue((Tcl_Interp *)NULL, clientPtr, nodePtr, key); if (valuePtr == NULL) { return FALSE; } return TRUE; } int Blt_TreeGetValueByKey( Tcl_Interp *interp, TreeClient *clientPtr, Node *nodePtr, Blt_TreeKey key, Tcl_Obj **objPtrPtr) { register Value *valuePtr; TreeObject *treeObjPtr = nodePtr->treeObject; valuePtr = GetTreeValue(interp, clientPtr, nodePtr, key); if (valuePtr == NULL) { return TCL_ERROR; } *objPtrPtr = valuePtr->objPtr; if (!(nodePtr->flags & TREE_TRACE_ACTIVE)) { CallTraces(interp, clientPtr, treeObjPtr, nodePtr, key, TREE_TRACE_READ); } return TCL_OK; } int Blt_TreeSetValueByKey( Tcl_Interp *interp, TreeClient *clientPtr, Node *nodePtr, /* Node to be updated. */ Blt_TreeKey key, /* Identifies the field key. */ Tcl_Obj *objPtr) /* New value of field. */ { TreeObject *treeObjPtr = nodePtr->treeObject; Value *valuePtr; unsigned int flags; int isNew; assert(objPtr != NULL); valuePtr = TreeCreateValue(nodePtr, key, &isNew); if ((valuePtr->owner != NULL) && (valuePtr->owner != clientPtr)) { if (interp != NULL) { Tcl_AppendResult(interp, "can't set private field \"", key, "\"", (char *)NULL); } return TCL_ERROR; } if (objPtr != valuePtr->objPtr) { Tcl_IncrRefCount(objPtr); if (valuePtr->objPtr != NULL) { Tcl_DecrRefCount(valuePtr->objPtr); } valuePtr->objPtr = objPtr; } flags = TREE_TRACE_WRITE; if (isNew) { flags |= TREE_TRACE_CREATE; } if (!(nodePtr->flags & TREE_TRACE_ACTIVE)) { CallTraces(interp, clientPtr, treeObjPtr, nodePtr, valuePtr->key, flags); } return TCL_OK; } int Blt_TreeUnsetValueByKey( Tcl_Interp *interp, TreeClient *clientPtr, Node *nodePtr, /* Node to be updated. */ Blt_TreeKey key) /* Name of field in node. */ { TreeObject *treeObjPtr = nodePtr->treeObject; Value *valuePtr; valuePtr = TreeFindValue(nodePtr, key); if (valuePtr == NULL) { return TCL_OK; /* It's okay to unset values that don't * exist in the node. */ } if ((valuePtr->owner != NULL) && (valuePtr->owner != clientPtr)) { if (interp != NULL) { Tcl_AppendResult(interp, "can't unset private field \"", key, "\"", (char *)NULL); } return TCL_ERROR; } TreeDeleteValue(nodePtr, valuePtr); CallTraces(interp, clientPtr, treeObjPtr, nodePtr, key, TREE_TRACE_UNSET); return TCL_OK; } static int ParseParentheses( Tcl_Interp *interp, CONST char *string, char **leftPtr, char **rightPtr) { register char *p; char *left, *right; left = right = NULL; for (p = (char *)string; *p != '\0'; p++) { if (*p == '(') { left = p; } else if (*p == ')') { right = p; } } if (left != right) { if (((left != NULL) && (right == NULL)) || ((left == NULL) && (right != NULL)) || (left > right) || (right != (p - 1))) { if (interp != NULL) { Tcl_AppendResult(interp, "bad array specification \"", string, "\"", (char *)NULL); } return TCL_ERROR; } } *leftPtr = left; *rightPtr = right; return TCL_OK; } int Blt_TreeGetValue( Tcl_Interp *interp, TreeClient *clientPtr, Node *nodePtr, CONST char *string, /* String identifying the field in node. */ Tcl_Obj **objPtrPtr) { char *left, *right; int result; if (ParseParentheses(interp, string, &left, &right) != TCL_OK) { return TCL_ERROR; } if (left != NULL) { *left = *right = '\0'; result = Blt_TreeGetArrayValue(interp, clientPtr, nodePtr, string, left + 1, objPtrPtr); *left = '(', *right = ')'; } else { result = Blt_TreeGetValueByKey(interp, clientPtr, nodePtr, Blt_TreeGetKey(string), objPtrPtr); } return result; } int Blt_TreeSetValue( Tcl_Interp *interp, TreeClient *clientPtr, Node *nodePtr, /* Node to be updated. */ CONST char *string, /* String identifying the field in node. */ Tcl_Obj *valueObjPtr) /* New value of field. If NULL, field * is deleted. */ { char *left, *right; int result; if (ParseParentheses(interp, string, &left, &right) != TCL_OK) { return TCL_ERROR; } if (left != NULL) { *left = *right = '\0'; result = Blt_TreeSetArrayValue(interp, clientPtr, nodePtr, string, left + 1, valueObjPtr); *left = '(', *right = ')'; } else { result = Blt_TreeSetValueByKey(interp, clientPtr, nodePtr, Blt_TreeGetKey(string), valueObjPtr); } return result; } int Blt_TreeUnsetValue( Tcl_Interp *interp, TreeClient *clientPtr, Node *nodePtr, /* Node to be updated. */ CONST char *string) /* String identifying the field in node. */ { char *left, *right; int result; if (ParseParentheses(interp, string, &left, &right) != TCL_OK) { return TCL_ERROR; } if (left != NULL) { *left = *right = '\0'; result = Blt_TreeUnsetArrayValue(interp, clientPtr, nodePtr, string, left + 1); *left = '(', *right = ')'; } else { result = Blt_TreeUnsetValueByKey(interp, clientPtr, nodePtr, Blt_TreeGetKey(string)); } return result; } int Blt_TreeValueExists(TreeClient *clientPtr, Node *nodePtr, CONST char *string) { char *left, *right; int result; if (ParseParentheses((Tcl_Interp *)NULL, string, &left, &right) != TCL_OK) { return FALSE; } if (left != NULL) { *left = *right = '\0'; result = Blt_TreeArrayValueExists(clientPtr, nodePtr, string, left + 1); *left = '(', *right = ')'; } else { result = Blt_TreeValueExistsByKey(clientPtr, nodePtr, Blt_TreeGetKey(string)); } return result; } Blt_TreeKey Blt_TreeFirstKey( TreeClient *clientPtr, Node *nodePtr, Blt_TreeKeySearch *iterPtr) { Value *valuePtr; valuePtr = TreeFirstValue(nodePtr, iterPtr); if (valuePtr == NULL) { return NULL; } while ((valuePtr->owner != NULL) && (valuePtr->owner != clientPtr)) { valuePtr = TreeNextValue(iterPtr); if (valuePtr == NULL) { return NULL; } } return valuePtr->key; } Blt_TreeKey Blt_TreeNextKey(TreeClient *clientPtr, Blt_TreeKeySearch *iterPtr) { Value *valuePtr; valuePtr = TreeNextValue(iterPtr); if (valuePtr == NULL) { return NULL; } while ((valuePtr->owner != NULL) && (valuePtr->owner != clientPtr)) { valuePtr = TreeNextValue(iterPtr); if (valuePtr == NULL) { return NULL; } } return valuePtr->key; } int Blt_TreeIsAncestor(Node *n1Ptr, Node *n2Ptr) { if (n2Ptr != NULL) { n2Ptr = n2Ptr->parent; while (n2Ptr != NULL) { if (n2Ptr == n1Ptr) { return TRUE; } n2Ptr = n2Ptr->parent; } } return FALSE; } /* *---------------------------------------------------------------------- * * Blt_TreeSortNode -- * * Sorts the subnodes at a given node. * * Results: * Always returns TCL_OK. * *---------------------------------------------------------------------- */ int Blt_TreeSortNode( TreeClient *clientPtr, Node *nodePtr, Blt_TreeCompareNodesProc *proc) { Node **nodeArr; Node *childPtr; int nNodes; register Node **p; nNodes = nodePtr->nChildren; if (nNodes < 2) { return TCL_OK; } nodeArr = Blt_Malloc((nNodes + 1) * sizeof(Node *)); if (nodeArr == NULL) { return TCL_ERROR; /* Out of memory. */ } for (p = nodeArr, childPtr = nodePtr->first; childPtr != NULL; childPtr = childPtr->next, p++) { *p = childPtr; } *p = NULL; qsort((char *)nodeArr, nNodes, sizeof(Node *), (QSortCompareProc *)proc); for (p = nodeArr; *p != NULL; p++) { UnlinkNode(*p); LinkBefore(nodePtr, *p, (Blt_TreeNode)NULL); } Blt_Free(nodeArr); NotifyClients(clientPtr, nodePtr->treeObject, nodePtr, TREE_NOTIFY_SORT); return TCL_OK; } #define TEST_RESULT(result) \ switch (result) { \ case TCL_CONTINUE: \ return TCL_OK; \ case TCL_OK: \ break; \ default: \ return (result); \ } int Blt_TreeApply( Node *nodePtr, /* Root node of subtree. */ Blt_TreeApplyProc *proc, /* Procedure to call for each node. */ ClientData clientData) /* One-word of data passed when calling * proc. */ { Node *childPtr, *nextPtr; int result; for (childPtr = nodePtr->first; childPtr != NULL; childPtr = nextPtr) { /* * Get the next link in the chain before calling Blt_TreeApply * recursively. This is because the apply callback may delete * the node and its link. */ nextPtr = childPtr->next; result = Blt_TreeApply(childPtr, proc, clientData); TEST_RESULT(result); } return (*proc) (nodePtr, clientData, TREE_POSTORDER); } int Blt_TreeApplyDFS( Node *nodePtr, /* Root node of subtree. */ Blt_TreeApplyProc *proc, /* Procedure to call for each node. */ ClientData clientData, /* One-word of data passed when calling * proc. */ int order) /* Order of traversal. */ { Node *childPtr, *nextPtr; int result; if (order & TREE_PREORDER) { result = (*proc) (nodePtr, clientData, TREE_PREORDER); TEST_RESULT(result); } childPtr = nodePtr->first; if (order & TREE_INORDER) { if (childPtr != NULL) { result = Blt_TreeApplyDFS(childPtr, proc, clientData, order); TEST_RESULT(result); childPtr = childPtr->next; } result = (*proc) (nodePtr, clientData, TREE_INORDER); TEST_RESULT(result); } for (/* empty */; childPtr != NULL; childPtr = nextPtr) { /* * Get the next link in the chain before calling * Blt_TreeApply recursively. This is because the * apply callback may delete the node and its link. */ nextPtr = childPtr->next; result = Blt_TreeApplyDFS(childPtr, proc, clientData, order); TEST_RESULT(result); } if (order & TREE_POSTORDER) { return (*proc) (nodePtr, clientData, TREE_POSTORDER); } return TCL_OK; } int Blt_TreeApplyBFS(nodePtr, proc, clientData) Node *nodePtr; /* Root node of subtree. */ Blt_TreeApplyProc *proc; /* Procedure to call for each node. */ ClientData clientData; /* One-word of data passed when calling * proc. */ { Blt_Chain *queuePtr; Blt_ChainLink *linkPtr, *nextPtr; Node *childPtr; int result; queuePtr = Blt_ChainCreate(); linkPtr = Blt_ChainAppend(queuePtr, nodePtr); while (linkPtr != NULL) { nodePtr = Blt_ChainGetValue(linkPtr); /* Add the children to the queue. */ for (childPtr = nodePtr->first; childPtr != NULL; childPtr = childPtr->next) { Blt_ChainAppend(queuePtr, childPtr); } /* Process the node. */ result = (*proc) (nodePtr, clientData, TREE_BREADTHFIRST); switch (result) { case TCL_CONTINUE: Blt_ChainDestroy(queuePtr); return TCL_OK; case TCL_OK: break; default: Blt_ChainDestroy(queuePtr); return result; } /* Remove the node from the queue. */ nextPtr = Blt_ChainNextLink(linkPtr); Blt_ChainDeleteLink(queuePtr, linkPtr); linkPtr = nextPtr; } Blt_ChainDestroy(queuePtr); return TCL_OK; } static TreeClient * NewTreeClient(TreeObject *treeObjPtr) { TreeClient *clientPtr; clientPtr = Blt_Calloc(1, sizeof(TreeClient)); if (clientPtr != NULL) { Blt_TreeTagTable *tablePtr; clientPtr->magic = TREE_MAGIC; clientPtr->linkPtr = Blt_ChainAppend(treeObjPtr->clients, clientPtr); clientPtr->events = Blt_ChainCreate(); clientPtr->traces = Blt_ChainCreate(); clientPtr->treeObject = treeObjPtr; clientPtr->root = treeObjPtr->root; tablePtr = Blt_Malloc(sizeof(Blt_TreeTagTable)); Blt_InitHashTable(&tablePtr->tagTable, BLT_STRING_KEYS); tablePtr->refCount = 1; clientPtr->tagTablePtr = tablePtr; } return clientPtr; } int Blt_TreeCreate( Tcl_Interp *interp, /* Interpreter to report errors back to. */ CONST char *name, /* Name of tree in namespace. Tree * must not already exist. */ TreeClient **clientPtrPtr) /* (out) Client token of newly created * tree. Releasing the token will * free the tree. If NULL, no token * is generated. */ { Tcl_DString dString; Tcl_Namespace *nsPtr; TreeInterpData *dataPtr; TreeObject *treeObjPtr; CONST char *treeName; char string[200]; dataPtr = GetTreeInterpData(interp); if (name != NULL) { /* Check if this tree already exists the current namespace. */ treeObjPtr = GetTreeObject(interp, name, NS_SEARCH_CURRENT); if (treeObjPtr != NULL) { Tcl_AppendResult(interp, "a tree object \"", name, "\" already exists", (char *)NULL); return TCL_ERROR; } } else { /* Generate a unique tree name in the current namespace. */ do { sprintf(string, "tree%d", dataPtr->nextId++); } while (GetTreeObject(interp, name, NS_SEARCH_CURRENT) != NULL); name = string; } /* * Tear apart and put back together the namespace-qualified name * of the tree. This is to ensure that naming is consistent. */ treeName = name; if (Blt_ParseQualifiedName(interp, name, &nsPtr, &treeName) != TCL_OK) { Tcl_AppendResult(interp, "can't find namespace in \"", name, "\"", (char *)NULL); return TCL_ERROR; } if (nsPtr == NULL) { /* * Note: Unlike Tcl_CreateCommand, an unqualified name * doesn't imply the global namespace, but the current one. */ nsPtr = Tcl_GetCurrentNamespace(interp); } name = Blt_GetQualifiedName(nsPtr, treeName, &dString); treeObjPtr = NewTreeObject(dataPtr, interp, name); if (treeObjPtr == NULL) { Tcl_AppendResult(interp, "can't allocate tree \"", name, "\"", (char *)NULL); Tcl_DStringFree(&dString); return TCL_ERROR; } Tcl_DStringFree(&dString); if (clientPtrPtr != NULL) { TreeClient *clientPtr; clientPtr = NewTreeClient(treeObjPtr); if (clientPtr == NULL) { Tcl_AppendResult(interp, "can't allocate tree token",(char *)NULL); return TCL_ERROR; } *clientPtrPtr = clientPtr; } return TCL_OK; } int Blt_TreeGetToken( Tcl_Interp *interp, /* Interpreter to report errors back to. */ CONST char *name, /* Name of tree in namespace. */ TreeClient **clientPtrPtr) { TreeClient *clientPtr; TreeObject *treeObjPtr; treeObjPtr = GetTreeObject(interp, name, NS_SEARCH_BOTH); if (treeObjPtr == NULL) { Tcl_AppendResult(interp, "can't find a tree object \"", name, "\"", (char *)NULL); return TCL_ERROR; } clientPtr = NewTreeClient(treeObjPtr); if (clientPtr == NULL) { Tcl_AppendResult(interp, "can't allocate token for tree \"", name, "\"", (char *)NULL); return TCL_ERROR; } *clientPtrPtr = clientPtr; return TCL_OK; } void Blt_TreeReleaseToken(TreeClient *clientPtr) { TreeObject *treeObjPtr; Blt_ChainLink *linkPtr; EventHandler *notifyPtr; TraceHandler *tracePtr; if (clientPtr->magic != TREE_MAGIC) { fprintf(stderr, "invalid tree object token 0x%lx\n", (unsigned long)clientPtr); return; } /* Remove any traces that may be set. */ for (linkPtr = Blt_ChainFirstLink(clientPtr->traces); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tracePtr = Blt_ChainGetValue(linkPtr); if (tracePtr->keyPattern != NULL) { Blt_Free(tracePtr->keyPattern); } Blt_Free(tracePtr); } Blt_ChainDestroy(clientPtr->traces); /* And any event handlers. */ for(linkPtr = Blt_ChainFirstLink(clientPtr->events); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { notifyPtr = Blt_ChainGetValue(linkPtr); if (notifyPtr->notifyPending) { Tcl_CancelIdleCall(NotifyIdleProc, notifyPtr); } Blt_Free(notifyPtr); } if (clientPtr->tagTablePtr != NULL) { ReleaseTagTable(clientPtr->tagTablePtr); } Blt_ChainDestroy(clientPtr->events); treeObjPtr = clientPtr->treeObject; if (treeObjPtr != NULL) { /* Remove the client from the server's list */ Blt_ChainDeleteLink(treeObjPtr->clients, clientPtr->linkPtr); if (Blt_ChainGetLength(treeObjPtr->clients) == 0) { DestroyTreeObject(treeObjPtr); } } clientPtr->magic = 0; Blt_Free(clientPtr); } int Blt_TreeExists(interp, name) Tcl_Interp *interp; /* Interpreter to report errors back to. */ CONST char *name; /* Name of tree in designated namespace. */ { TreeObject *treeObjPtr; treeObjPtr = GetTreeObject(interp, name, NS_SEARCH_BOTH); if (treeObjPtr == NULL) { Tcl_ResetResult(interp); return 0; } return 1; } /*ARGSUSED*/ static int SizeApplyProc( Node *nodePtr, /* Not used. */ ClientData clientData, int order) /* Not used. */ { int *sumPtr = clientData; *sumPtr = *sumPtr + 1; return TCL_OK; } int Blt_TreeSize(Node *nodePtr) { int sum; sum = 0; Blt_TreeApply(nodePtr, SizeApplyProc, &sum); return sum; } void Blt_TreeCreateEventHandler( TreeClient *clientPtr, unsigned int mask, Blt_TreeNotifyEventProc *proc, ClientData clientData) { Blt_ChainLink *linkPtr; EventHandler *notifyPtr; notifyPtr = NULL; /* Suppress compiler warning. */ /* Check if the event is already handled. */ for(linkPtr = Blt_ChainFirstLink(clientPtr->events); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { notifyPtr = Blt_ChainGetValue(linkPtr); if ((notifyPtr->proc == proc) && (notifyPtr->mask == mask) && (notifyPtr->clientData == clientData)) { break; } } if (linkPtr == NULL) { notifyPtr = Blt_Malloc(sizeof (EventHandler)); assert(notifyPtr); linkPtr = Blt_ChainAppend(clientPtr->events, notifyPtr); } if (proc == NULL) { Blt_ChainDeleteLink(clientPtr->events, linkPtr); Blt_Free(notifyPtr); } else { notifyPtr->proc = proc; notifyPtr->clientData = clientData; notifyPtr->mask = mask; notifyPtr->notifyPending = FALSE; notifyPtr->interp = clientPtr->treeObject->interp; } } void Blt_TreeDeleteEventHandler( TreeClient *clientPtr, unsigned int mask, Blt_TreeNotifyEventProc *proc, ClientData clientData) { Blt_ChainLink *linkPtr; EventHandler *notifyPtr; for(linkPtr = Blt_ChainFirstLink(clientPtr->events); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { notifyPtr = Blt_ChainGetValue(linkPtr); if ((notifyPtr->proc == proc) && (notifyPtr->mask == mask) && (notifyPtr->clientData == clientData)) { if (notifyPtr->notifyPending) { Tcl_CancelIdleCall(NotifyIdleProc, notifyPtr); } Blt_ChainDeleteLink(clientPtr->events, linkPtr); Blt_Free(notifyPtr); return; } } } /* *---------------------------------------------------------------------- * * Blt_TreeNodePath -- * *---------------------------------------------------------------------- */ char * Blt_TreeNodePath(Node *nodePtr, Tcl_DString *resultPtr) { char **nameArr; /* Used to stack the component names. */ char *staticSpace[64]; int nLevels; register int i; nLevels = nodePtr->depth; if (nLevels > 64) { nameArr = Blt_Malloc(nLevels * sizeof(char *)); assert(nameArr); } else { nameArr = staticSpace; } for (i = nLevels - 1; i >= 0; i--) { /* Save the name of each ancestor in the name array. * Note that we ignore the root. */ nameArr[i] = nodePtr->label; nodePtr = nodePtr->parent; } /* Append each the names in the array. */ Tcl_DStringInit(resultPtr); for (i = 0; i < nLevels; i++) { Tcl_DStringAppendElement(resultPtr, nameArr[i]); } if (nameArr != staticSpace) { Blt_Free(nameArr); } return Tcl_DStringValue(resultPtr); } int Blt_TreeArrayValueExists( TreeClient *clientPtr, Node *nodePtr, CONST char *arrayName, CONST char *elemName) { Blt_TreeKey key; Blt_HashEntry *hPtr; Blt_HashTable *tablePtr; register Value *valuePtr; key = Blt_TreeGetKey(arrayName); valuePtr = GetTreeValue((Tcl_Interp *)NULL, clientPtr, nodePtr, key); if (valuePtr == NULL) { return FALSE; } if (Tcl_IsShared(valuePtr->objPtr)) { Tcl_DecrRefCount(valuePtr->objPtr); valuePtr->objPtr = Tcl_DuplicateObj(valuePtr->objPtr); Tcl_IncrRefCount(valuePtr->objPtr); } if (Blt_GetArrayFromObj((Tcl_Interp *)NULL, valuePtr->objPtr, &tablePtr) != TCL_OK) { return FALSE; } hPtr = Blt_FindHashEntry(tablePtr, elemName); return (hPtr != NULL); } int Blt_TreeGetArrayValue( Tcl_Interp *interp, TreeClient *clientPtr, Node *nodePtr, CONST char *arrayName, CONST char *elemName, Tcl_Obj **valueObjPtrPtr) { Blt_TreeKey key; Blt_HashEntry *hPtr; Blt_HashTable *tablePtr; register Value *valuePtr; key = Blt_TreeGetKey(arrayName); valuePtr = GetTreeValue(interp, clientPtr, nodePtr, key); if (valuePtr == NULL) { return TCL_ERROR; } if (Tcl_IsShared(valuePtr->objPtr)) { Tcl_DecrRefCount(valuePtr->objPtr); valuePtr->objPtr = Tcl_DuplicateObj(valuePtr->objPtr); Tcl_IncrRefCount(valuePtr->objPtr); } if (Blt_GetArrayFromObj(interp, valuePtr->objPtr, &tablePtr) != TCL_OK) { return TCL_ERROR; } hPtr = Blt_FindHashEntry(tablePtr, elemName); if (hPtr == NULL) { if (interp != NULL) { Tcl_AppendResult(interp, "can't find \"", arrayName, "(", elemName, ")\"", (char *)NULL); } return TCL_ERROR; } *valueObjPtrPtr = (Tcl_Obj *)Blt_GetHashValue(hPtr); /* Reading any element of the array can cause a trace to fire. */ if (!(nodePtr->flags & TREE_TRACE_ACTIVE)) { CallTraces(interp, clientPtr, nodePtr->treeObject, nodePtr, key, TREE_TRACE_READ); } return TCL_OK; } int Blt_TreeSetArrayValue( Tcl_Interp *interp, TreeClient *clientPtr, Node *nodePtr, /* Node to be updated. */ CONST char *arrayName, CONST char *elemName, Tcl_Obj *valueObjPtr) /* New value of element. */ { Blt_TreeKey key; Blt_HashEntry *hPtr; Blt_HashTable *tablePtr; register Value *valuePtr; unsigned int flags; int isNew; assert(valueObjPtr != NULL); /* * Search for the array in the list of data fields. If one * doesn't exist, create it. */ key = Blt_TreeGetKey(arrayName); valuePtr = TreeCreateValue(nodePtr, key, &isNew); if ((valuePtr->owner != NULL) && (valuePtr->owner != clientPtr)) { if (interp != NULL) { Tcl_AppendResult(interp, "can't set private field \"", key, "\"", (char *)NULL); } return TCL_ERROR; } flags = TREE_TRACE_WRITE; if (isNew) { valuePtr->objPtr = Blt_NewArrayObj(0, (Tcl_Obj **)NULL); Tcl_IncrRefCount(valuePtr->objPtr); flags |= TREE_TRACE_CREATE; } else if (Tcl_IsShared(valuePtr->objPtr)) { Tcl_DecrRefCount(valuePtr->objPtr); valuePtr->objPtr = Tcl_DuplicateObj(valuePtr->objPtr); Tcl_IncrRefCount(valuePtr->objPtr); } if (Blt_GetArrayFromObj(interp, valuePtr->objPtr, &tablePtr) != TCL_OK) { return TCL_ERROR; } Tcl_InvalidateStringRep(valuePtr->objPtr); hPtr = Blt_CreateHashEntry(tablePtr, elemName, &isNew); assert(hPtr); Tcl_IncrRefCount(valueObjPtr); if (!isNew) { Tcl_Obj *oldValueObjPtr; /* An element by the same name already exists. Decrement the * reference count of the old value. */ oldValueObjPtr = (Tcl_Obj *)Blt_GetHashValue(hPtr); if (oldValueObjPtr != NULL) { Tcl_DecrRefCount(oldValueObjPtr); } } Blt_SetHashValue(hPtr, valueObjPtr); /* * We don't handle traces on a per array element basis. Setting * any element can fire traces for the value. */ if (!(nodePtr->flags & TREE_TRACE_ACTIVE)) { CallTraces(interp, clientPtr, nodePtr->treeObject, nodePtr, valuePtr->key, flags); } return TCL_OK; } int Blt_TreeUnsetArrayValue( Tcl_Interp *interp, TreeClient *clientPtr, Node *nodePtr, /* Node to be updated. */ CONST char *arrayName, CONST char *elemName) { Blt_TreeKey key; /* Name of field in node. */ Blt_HashEntry *hPtr; Blt_HashTable *tablePtr; Tcl_Obj *valueObjPtr; Value *valuePtr; key = Blt_TreeGetKey(arrayName); valuePtr = TreeFindValue(nodePtr, key); if (valuePtr == NULL) { return TCL_OK; } if ((valuePtr->owner != NULL) && (valuePtr->owner != clientPtr)) { if (interp != NULL) { Tcl_AppendResult(interp, "can't unset private field \"", key, "\"", (char *)NULL); } return TCL_ERROR; } if (Tcl_IsShared(valuePtr->objPtr)) { Tcl_DecrRefCount(valuePtr->objPtr); valuePtr->objPtr = Tcl_DuplicateObj(valuePtr->objPtr); Tcl_IncrRefCount(valuePtr->objPtr); } if (Blt_GetArrayFromObj(interp, valuePtr->objPtr, &tablePtr) != TCL_OK) { return TCL_ERROR; } hPtr = Blt_FindHashEntry(tablePtr, elemName); if (hPtr == NULL) { return TCL_OK; /* Element doesn't exist, Ok. */ } valueObjPtr = (Tcl_Obj *)Blt_GetHashValue(hPtr); Tcl_DecrRefCount(valueObjPtr); Blt_DeleteHashEntry(tablePtr, hPtr); /* * Un-setting any element in the array can cause the trace on the value * to fire. */ if (!(nodePtr->flags & TREE_TRACE_ACTIVE)) { CallTraces(interp, clientPtr, nodePtr->treeObject, nodePtr, valuePtr->key, TREE_TRACE_WRITE); } return TCL_OK; } int Blt_TreeArrayNames( Tcl_Interp *interp, TreeClient *clientPtr, Node *nodePtr, CONST char *arrayName, Tcl_Obj *listObjPtr) { Blt_HashEntry *hPtr; Blt_HashSearch cursor; Blt_HashTable *tablePtr; Tcl_Obj *objPtr; Value *valuePtr; char *key; key = Blt_TreeGetKey(arrayName); valuePtr = GetTreeValue(interp, clientPtr, nodePtr, key); if (valuePtr == NULL) { return TCL_ERROR; } if (Tcl_IsShared(valuePtr->objPtr)) { Tcl_DecrRefCount(valuePtr->objPtr); valuePtr->objPtr = Tcl_DuplicateObj(valuePtr->objPtr); Tcl_IncrRefCount(valuePtr->objPtr); } if (Blt_GetArrayFromObj(interp, valuePtr->objPtr, &tablePtr) != TCL_OK) { return TCL_ERROR; } tablePtr = (Blt_HashTable *)valuePtr->objPtr; for (hPtr = Blt_FirstHashEntry(tablePtr, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { objPtr = Tcl_NewStringObj(Blt_GetHashKey(tablePtr, hPtr), -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * Blt_TreeShareTagTable -- * *---------------------------------------------------------------------- */ int Blt_TreeShareTagTable( TreeClient *sourcePtr, TreeClient *targetPtr) { sourcePtr->tagTablePtr->refCount++; if (targetPtr->tagTablePtr != NULL) { ReleaseTagTable(targetPtr->tagTablePtr); } targetPtr->tagTablePtr = sourcePtr->tagTablePtr; return TCL_OK; } int Blt_TreeTagTableIsShared(TreeClient *clientPtr) { return (clientPtr->tagTablePtr->refCount > 1); } void Blt_TreeClearTags(TreeClient *clientPtr, Blt_TreeNode node) { Blt_HashEntry *hPtr, *h2Ptr; Blt_HashSearch cursor; for (hPtr = Blt_FirstHashEntry(&clientPtr->tagTablePtr->tagTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { Blt_TreeTagEntry *tPtr; tPtr = Blt_GetHashValue(hPtr); h2Ptr = Blt_FindHashEntry(&tPtr->nodeTable, (char *)node); if (h2Ptr != NULL) { Blt_DeleteHashEntry(&tPtr->nodeTable, h2Ptr); } } } int Blt_TreeHasTag( TreeClient *clientPtr, Blt_TreeNode node, CONST char *tagName) { Blt_HashEntry *hPtr; Blt_TreeTagEntry *tPtr; if (strcmp(tagName, "all") == 0) { return TRUE; } if ((strcmp(tagName, "root") == 0) && (node == Blt_TreeRootNode(clientPtr))) { return TRUE; } hPtr = Blt_FindHashEntry(&clientPtr->tagTablePtr->tagTable, tagName); if (hPtr == NULL) { return FALSE; } tPtr = Blt_GetHashValue(hPtr); hPtr = Blt_FindHashEntry(&tPtr->nodeTable, (char *)node); if (hPtr == NULL) { return FALSE; } return TRUE; } void Blt_TreeAddTag( TreeClient *clientPtr, Blt_TreeNode node, CONST char *tagName) { int isNew; Blt_HashEntry *hPtr; Blt_HashTable *tablePtr; Blt_TreeTagEntry *tPtr; if ((strcmp(tagName, "all") == 0) || (strcmp(tagName, "root") == 0)) { return; } tablePtr = &clientPtr->tagTablePtr->tagTable; hPtr = Blt_CreateHashEntry(tablePtr, tagName, &isNew); assert(hPtr); if (isNew) { tPtr = Blt_Malloc(sizeof(Blt_TreeTagEntry)); Blt_InitHashTable(&tPtr->nodeTable, BLT_ONE_WORD_KEYS); Blt_SetHashValue(hPtr, tPtr); tPtr->hashPtr = hPtr; tPtr->tagName = Blt_GetHashKey(tablePtr, hPtr); } else { tPtr = Blt_GetHashValue(hPtr); } hPtr = Blt_CreateHashEntry(&tPtr->nodeTable, (char *)node, &isNew); assert(hPtr); if (isNew) { Blt_SetHashValue(hPtr, node); } } void Blt_TreeForgetTag(TreeClient *clientPtr, CONST char *tagName) { if ((strcmp(tagName, "all") != 0) && (strcmp(tagName, "root") != 0)) { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&clientPtr->tagTablePtr->tagTable, tagName); if (hPtr != NULL) { Blt_TreeTagEntry *tPtr; Blt_DeleteHashEntry(&clientPtr->tagTablePtr->tagTable, hPtr); tPtr = Blt_GetHashValue(hPtr); Blt_DeleteHashTable(&tPtr->nodeTable); Blt_Free(tPtr); } } } /* *---------------------------------------------------------------------- * * Blt_TreeTagHashTable -- * *---------------------------------------------------------------------- */ Blt_HashTable * Blt_TreeTagHashTable(TreeClient *clientPtr, CONST char *tagName) { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&clientPtr->tagTablePtr->tagTable, tagName); if (hPtr != NULL) { Blt_TreeTagEntry *tPtr; tPtr = Blt_GetHashValue(hPtr); return &tPtr->nodeTable; } return NULL; } Blt_HashEntry * Blt_TreeFirstTag(TreeClient *clientPtr, Blt_HashSearch *cursorPtr) { return Blt_FirstHashEntry(&clientPtr->tagTablePtr->tagTable, cursorPtr); } #if (SIZEOF_VOID_P == 8) /* *---------------------------------------------------------------------- * * HashOneWord -- * * Compute a one-word hash value of a 64-bit word, which then can * be used to generate a hash index. * * From Knuth, it's a multiplicative hash. Multiplies an unsigned * 64-bit value with the golden ratio (sqrt(5) - 1) / 2. The * downshift value is 64 - n, when n is the log2 of the size of * the hash table. * * Results: * The return value is a one-word summary of the information in * 64 bit word. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Blt_Hash HashOneWord( uint64_t mask, unsigned int downshift, CONST void *key) { uint64_t a0, a1; uint64_t y0, y1; uint64_t y2, y3; uint64_t p1, p2; uint64_t result; /* Compute key * GOLDEN_RATIO in 128-bit arithmetic */ a0 = (uint64_t)key & 0x00000000FFFFFFFF; a1 = (uint64_t)key >> 32; y0 = a0 * 0x000000007f4a7c13; y1 = a0 * 0x000000009e3779b9; y2 = a1 * 0x000000007f4a7c13; y3 = a1 * 0x000000009e3779b9; y1 += y0 >> 32; /* Can't carry */ y1 += y2; /* Might carry */ if (y1 < y2) { y3 += (1LL << 32); /* Propagate */ } /* 128-bit product: p1 = loword, p2 = hiword */ p1 = ((y1 & 0x00000000FFFFFFFF) << 32) + (y0 & 0x00000000FFFFFFFF); p2 = y3 + (y1 >> 32); /* Left shift the value downward by the size of the table */ if (downshift > 0) { if (downshift < 64) { result = ((p2 << (64 - downshift)) | (p1 >> (downshift & 63))); } else { result = p2 >> (downshift & 63); } } else { result = p1; } /* Finally mask off the high bits */ return (Blt_Hash)(result & mask); } #endif /* SIZEOF_VOID_P == 8 */ /* *---------------------------------------------------------------------- * * RebuildTable -- * * This procedure is invoked when the ratio of entries to hash * buckets becomes too large. It creates a new table with a * larger bucket array and moves all of the entries into the * new table. * * Results: * None. * * Side effects: * Memory gets reallocated and entries get re-hashed to new * buckets. * *---------------------------------------------------------------------- */ static void RebuildTable(Node *nodePtr) /* Table to enlarge. */ { Value **newBucketPtr, **oldBuckets; register Value **bucketPtr, **endPtr; register Value *valuePtr, *nextPtr; unsigned int downshift; unsigned long mask; Value **buckets; size_t nBuckets; oldBuckets = (Value **)nodePtr->values; nBuckets = (1 << nodePtr->logSize); endPtr = oldBuckets + nBuckets; /* * Allocate and initialize the new bucket array, and set up * hashing constants for new array size. */ nodePtr->logSize += 2; nBuckets = (1 << nodePtr->logSize); buckets = Blt_Calloc(nBuckets, sizeof(Value *)); /* * Move all of the existing entries into the new bucket array, * based on their hash values. */ mask = nBuckets - 1; downshift = DOWNSHIFT_START - nodePtr->logSize; for (bucketPtr = oldBuckets; bucketPtr < endPtr; bucketPtr++) { for (valuePtr = *bucketPtr; valuePtr != NULL; valuePtr = nextPtr) { nextPtr = valuePtr->next; newBucketPtr = buckets + RANDOM_INDEX(valuePtr->key); valuePtr->next = *newBucketPtr; *newBucketPtr = valuePtr; } } nodePtr->values = (Value *)buckets; Blt_Free(oldBuckets); } static void ConvertValues(Node *nodePtr) { unsigned int nBuckets; Value **buckets; unsigned int mask; int downshift; Value *valuePtr, *nextPtr, **bucketPtr; /* * Convert list of values into a hash table. */ nodePtr->logSize = START_LOGSIZE; nBuckets = 1 << nodePtr->logSize; buckets = Blt_Calloc(nBuckets, sizeof(Value *)); mask = nBuckets - 1; downshift = DOWNSHIFT_START - nodePtr->logSize; for (valuePtr = nodePtr->values; valuePtr != NULL; valuePtr = nextPtr) { nextPtr = valuePtr->next; bucketPtr = buckets + RANDOM_INDEX(valuePtr->key); valuePtr->next = *bucketPtr; *bucketPtr = valuePtr; } nodePtr->values = (Value *)buckets; } /* *---------------------------------------------------------------------- * * TreeDeleteValue -- * * Remove a single entry from a hash table. * * Results: * None. * * Side effects: * The entry given by entryPtr is deleted from its table and * should never again be used by the caller. It is up to the * caller to free the clientData field of the entry, if that * is relevant. * *---------------------------------------------------------------------- */ static int TreeDeleteValue(Node *nodePtr, Blt_TreeValue value) { Value *valuePtr = value; register Value *prevPtr; if (nodePtr->logSize > 0) { Value **bucketPtr; unsigned int downshift; unsigned long mask; mask = (1 << nodePtr->logSize) - 1; downshift = DOWNSHIFT_START - nodePtr->logSize; bucketPtr = (Value **)nodePtr->values + RANDOM_INDEX(valuePtr->key); if (*bucketPtr == valuePtr) { *bucketPtr = valuePtr->next; } else { for (prevPtr = *bucketPtr; /*empty*/; prevPtr = prevPtr->next) { if (prevPtr == NULL) { return TCL_ERROR; /* Can't find value in hash bucket. */ } if (prevPtr->next == valuePtr) { prevPtr->next = valuePtr->next; break; } } } } else { prevPtr = NULL; for (valuePtr = nodePtr->values; valuePtr != NULL; valuePtr = valuePtr->next) { if (valuePtr == value) { break; } prevPtr = valuePtr; } if (valuePtr == NULL) { return TCL_ERROR; /* Can't find value in list. */ } if (prevPtr == NULL) { nodePtr->values = valuePtr->next; } else { prevPtr->next = valuePtr->next; } } nodePtr->nValues--; FreeValue(nodePtr, valuePtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeDestroyValues -- * * Free up everything associated with a hash table except for * the record for the table itself. * * Results: * None. * * Side effects: * The hash table is no longer useable. * *---------------------------------------------------------------------- */ static void TreeDestroyValues(Node *nodePtr) { register Value *valuePtr; Value *nextPtr; /* * Free up all the entries in the table. */ if (nodePtr->values != NULL) { return; } if (nodePtr->logSize > 0) { Value **buckets; int nBuckets; int i; buckets = (Value **)nodePtr->values; nBuckets = (1 << nodePtr->logSize); for (i = 0; i < nBuckets; i++) { for (valuePtr = buckets[i]; valuePtr != NULL; valuePtr = nextPtr) { nextPtr = valuePtr->next; FreeValue(nodePtr, valuePtr); } } Blt_Free(buckets); } else { for (valuePtr = nodePtr->values; valuePtr != NULL; valuePtr = nextPtr) { nextPtr = valuePtr->next; FreeValue(nodePtr, valuePtr); } } nodePtr->values = NULL; nodePtr->nValues = 0; nodePtr->logSize = 0; } /* *---------------------------------------------------------------------- * * TreeFirstValue -- * * Locate the first entry in a hash table and set up a record * that can be used to step through all the remaining entries * of the table. * * Results: * The return value is a pointer to the first value in tablePtr, * or NULL if tablePtr has no entries in it. The memory at * *searchPtr is initialized so that subsequent calls to * Blt_TreeNextValue will return all of the values in the table, * one at a time. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Value * TreeFirstValue( Node *nodePtr, Blt_TreeKeySearch *searchPtr) /* Place to store information about * progress through the table. */ { searchPtr->node = nodePtr; searchPtr->nextIndex = 0; if (nodePtr->logSize > 0) { searchPtr->nextValue = NULL; } else { searchPtr->nextValue = nodePtr->values; } return TreeNextValue(searchPtr); } /* *---------------------------------------------------------------------- * * TreeNextValue -- * * Once a hash table enumeration has been initiated by calling * Blt_TreeFirstValue, this procedure may be called to return * successive elements of the table. * * Results: * The return value is the next entry in the hash table being * enumerated, or NULL if the end of the table is reached. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Value * TreeNextValue( Blt_TreeKeySearch *searchPtr) /* Place to store information about * progress through the table. Must * have been initialized by calling * Blt_TreeFirstValue. */ { Value *valuePtr; if (searchPtr->node->logSize > 0) { size_t nBuckets; Value **buckets; nBuckets = (1 << searchPtr->node->logSize); buckets = (Value **)searchPtr->node->values; while (searchPtr->nextValue == NULL) { if (searchPtr->nextIndex >= nBuckets) { return NULL; } searchPtr->nextValue = buckets[searchPtr->nextIndex]; searchPtr->nextIndex++; } } valuePtr = searchPtr->nextValue; if (valuePtr != NULL) { searchPtr->nextValue = valuePtr->next; } return valuePtr; } /* *---------------------------------------------------------------------- * * TreeFindValue -- * * Given a hash table with one-word keys, and a one-word key, find * the entry with a matching key. * * Results: * The return value is a token for the matching entry in the * hash table, or NULL if there was no matching entry. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Value * TreeFindValue( Node *nodePtr, Blt_TreeKey key) /* Key to use to find matching entry. */ { register Value *valuePtr; Value *bucket; if (nodePtr->logSize > 0) { unsigned int downshift; unsigned long mask; mask = (1 << nodePtr->logSize) - 1; downshift = DOWNSHIFT_START - nodePtr->logSize; bucket = ((Value **)(nodePtr->values))[RANDOM_INDEX((void *)key)]; } else { bucket = nodePtr->values; /* Single chain list. */ } /* * Search all of the entries in the appropriate bucket. */ for (valuePtr = bucket; valuePtr != NULL; valuePtr = valuePtr->next) { if (valuePtr->key == key) { return valuePtr; } } return NULL; } /* *---------------------------------------------------------------------- * * Blt_TreeCreateValue -- * * Find the value with a matching key. If there is no matching * value, then create a new one. * * Results: * The return value is a pointer to the matching value. If this * is a newly-created value, then *newPtr will be set to a non-zero * value; otherwise *newPtr will be set to 0. * * Side effects: * A new value may be added to the hash table. * *---------------------------------------------------------------------- */ static Value * TreeCreateValue( Node *nodePtr, Blt_TreeKey key, /* Key to use to find or create matching * entry. */ int *newPtr) /* Store info here telling whether a new * entry was created. */ { register Value *valuePtr; /* * Check if there as so many values that storage should be * converted from a hash table instead of a list. */ if ((nodePtr->logSize == 0) && (nodePtr->nValues > MAX_LIST_VALUES)) { ConvertValues(nodePtr); } if (nodePtr->logSize > 0) { Value **bucketPtr; size_t nBuckets; unsigned int downshift; unsigned long mask; nBuckets = (1 << nodePtr->logSize); mask = nBuckets - 1; downshift = DOWNSHIFT_START - nodePtr->logSize; bucketPtr = (Value **)nodePtr->values + RANDOM_INDEX((void *)key); *newPtr = FALSE; for (valuePtr = *bucketPtr; valuePtr != NULL; valuePtr = valuePtr->next) { if (valuePtr->key == key) { return valuePtr; } } /* Value not found. Add a new value to the bucket. */ *newPtr = TRUE; valuePtr = Blt_PoolAllocItem(nodePtr->treeObject->valuePool, sizeof(Value)); valuePtr->key = key; valuePtr->owner = NULL; valuePtr->next = *bucketPtr; valuePtr->objPtr = NULL; *bucketPtr = valuePtr; nodePtr->nValues++; /* * If the table has exceeded a decent size, rebuild it with many * more buckets. */ if ((unsigned int)nodePtr->nValues >= (nBuckets * 3)) { RebuildTable(nodePtr); } } else { Value *prevPtr; prevPtr = NULL; *newPtr = FALSE; for (valuePtr = nodePtr->values; valuePtr != NULL; valuePtr = valuePtr->next) { if (valuePtr->key == key) { return valuePtr; } prevPtr = valuePtr; } /* Value not found. Add a new value to the list. */ *newPtr = TRUE; valuePtr = Blt_PoolAllocItem(nodePtr->treeObject->valuePool, sizeof(Value)); valuePtr->key = key; valuePtr->owner = NULL; valuePtr->next = NULL; valuePtr->objPtr = NULL; if (prevPtr == NULL) { nodePtr->values = valuePtr; } else { prevPtr->next = valuePtr; } nodePtr->nValues++; } return valuePtr; } #endif /* NO_TREE */ blt-2.4z.orig/src/bltTree.h0100644000175000017500000003750507534230377014331 0ustar dokodoko /* * bltTree.h -- * * Copyright 1998-1999 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 or 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. * * The "tree" data object was created by George A. Howlett. */ #ifndef _BLT_TREE_H #define _BLT_TREE_H #include #include #include typedef struct Blt_TreeNodeStruct *Blt_TreeNode; typedef struct Blt_TreeObjectStruct *Blt_TreeObject; typedef struct Blt_TreeClientStruct *Blt_Tree; typedef struct Blt_TreeTraceStruct *Blt_TreeTrace; typedef struct Blt_TreeValueStruct *Blt_TreeValue; typedef struct Blt_TreeTagEntryStruct Blt_TreeTagEntry; typedef struct Blt_TreeTagTableStruct Blt_TreeTagTable; typedef char *Blt_TreeKey; #define TREE_PREORDER (1<<0) #define TREE_POSTORDER (1<<1) #define TREE_INORDER (1<<2) #define TREE_BREADTHFIRST (1<<3) #define TREE_TRACE_UNSET (1<<3) #define TREE_TRACE_WRITE (1<<4) #define TREE_TRACE_READ (1<<5) #define TREE_TRACE_CREATE (1<<6) #define TREE_TRACE_ALL \ (TREE_TRACE_UNSET | TREE_TRACE_WRITE | TREE_TRACE_READ | TREE_TRACE_CREATE) #define TREE_TRACE_MASK (TREE_TRACE_ALL) #define TREE_TRACE_FOREIGN_ONLY (1<<8) #define TREE_TRACE_ACTIVE (1<<9) #define TREE_NOTIFY_CREATE (1<<0) #define TREE_NOTIFY_DELETE (1<<1) #define TREE_NOTIFY_MOVE (1<<2) #define TREE_NOTIFY_SORT (1<<3) #define TREE_NOTIFY_RELABEL (1<<4) #define TREE_NOTIFY_ALL \ (TREE_NOTIFY_CREATE | TREE_NOTIFY_DELETE | TREE_NOTIFY_MOVE | \ TREE_NOTIFY_SORT | TREE_NOTIFY_RELABEL) #define TREE_NOTIFY_MASK (TREE_NOTIFY_ALL) #define TREE_NOTIFY_WHENIDLE (1<<8) #define TREE_NOTIFY_FOREIGN_ONLY (1<<9) #define TREE_NOTIFY_ACTIVE (1<<10) typedef struct { int type; Blt_Tree tree; int inode; /* Node of event */ Tcl_Interp *interp; } Blt_TreeNotifyEvent; typedef struct { Blt_TreeNode node; /* Node being searched. */ unsigned long nextIndex; /* Index of next bucket to be * enumerated after present one. */ Blt_TreeValue nextValue; /* Next entry to be enumerated in the * the current bucket. */ } Blt_TreeKeySearch; /* * Blt_TreeObject -- * * Structure providing the internal representation of the tree * object. A tree is uniquely identified by a combination of * its name and originating namespace. Two trees in the same * interpreter can have the same names but reside in different * namespaces. * * The tree object represents a general-ordered tree of nodes. * Each node may contain a heterogeneous collection of data * values. Each value is identified by a field name and nodes * do not need to contain the same data fields. Data field * names are saved as reference counted strings and can be * shared among nodes. * * The tree is threaded. A node contains both a pointer to * back its parents and another to its siblings. Therefore * the tree maybe traversed non-recursively. * * A tree object can be shared by several clients. When a * client wants to use a tree object, it is given a token * that represents the tree. The tree object uses the tokens * to keep track of its clients. When all clients have * released their tokens the tree is automatically destroyed. */ struct Blt_TreeObjectStruct { Tcl_Interp *interp; /* Interpreter associated with this tree. */ char *name; Tcl_Namespace *nsPtr; Blt_HashEntry *hashPtr; /* Pointer to this tree object in tree * object hash table. */ Blt_HashTable *tablePtr; Blt_TreeNode root; /* Root of the entire tree. */ char *sortNodesCmd; /* Tcl command to invoke to sort entries */ Blt_Chain *clients; /* List of clients using this tree */ Blt_Pool nodePool; Blt_Pool valuePool; Blt_HashTable nodeTable; /* Table of node identifiers. Used to * search for a node pointer given an inode.*/ unsigned int nextInode; unsigned int nNodes; /* Always counts root node. */ unsigned int depth; /* Maximum depth of the tree. */ unsigned int flags; /* Internal flags. See definitions * below. */ unsigned int notifyFlags; /* Notification flags. See definitions * below. */ }; /* * Blt_TreeNodeStruct -- * * Structure representing a node in a general ordered tree. * Nodes are identified by their index, or inode. Nodes also * have names, but nodes names are not unique and can be * changed. Inodes are valid even if the node is moved. * * Each node can contain a list of data fields. Fields are * name-value pairs. The values are represented by Tcl_Objs. * */ struct Blt_TreeNodeStruct { Blt_TreeNode parent; /* Parent node. If NULL, then this is the root node. */ Blt_TreeNode next; /* Next sibling node. */ Blt_TreeNode prev; /* Previous sibling node. */ Blt_TreeNode first; /* First child node. */ Blt_TreeNode last; /* Last child node. */ Blt_TreeKey label; /* Node label (doesn't have to be * unique). */ Blt_TreeObject treeObject; Blt_TreeValue values; /* Depending upon the number of values * stored, this is either a chain or * hash table of Blt_TreeValue * structures. (Note: if logSize is * 0, then this is a list). Each * value contains key/value data * pair. The data is a Tcl_Obj. */ unsigned short nValues; /* # of values for this node. */ unsigned short logSize; /* Size of hash table indicated as a * power of 2 (e.g. if logSize=3, then * table size is 8). If 0, this * indicates that the node's values * are stored as a list. */ unsigned int nChildren; /* # of children for this node. */ unsigned int inode; /* Serial number of the node. */ unsigned short depth; /* The depth of this node in the tree. */ unsigned short flags; }; struct Blt_TreeTagEntryStruct { char *tagName; Blt_HashEntry *hashPtr; Blt_HashTable nodeTable; }; struct Blt_TreeTagTableStruct { Blt_HashTable tagTable; int refCount; }; /* * Blt_TreeClientStruct -- * * A tree can be shared by several clients. Each client allocates * this structure which acts as a ticket for using the tree. Clients * can designate notifier routines that are automatically invoked * by the tree object whenever the tree is changed is specific * ways by other clients. */ struct Blt_TreeClientStruct { unsigned int magic; /* Magic value indicating whether a * generic pointer is really a tree * token or not. */ Blt_ChainLink *linkPtr; /* Pointer into the server's chain of * clients. */ Blt_TreeObject treeObject; /* Pointer to the structure containing * the master information about the * tree used by the client. If NULL, * this indicates that the tree has * been destroyed (but as of yet, this * client hasn't recognized it). */ Blt_Chain *events; /* Chain of node event handlers. */ Blt_Chain *traces; /* Chain of data field callbacks. */ Blt_TreeNode root; /* Designated root for this client */ Blt_TreeTagTable *tagTablePtr; }; typedef int (Blt_TreeNotifyEventProc) _ANSI_ARGS_((ClientData clientData, Blt_TreeNotifyEvent *eventPtr)); typedef int (Blt_TreeTraceProc) _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Blt_TreeNode node, Blt_TreeKey key, unsigned int flags)); typedef int (Blt_TreeEnumProc) _ANSI_ARGS_((Blt_TreeNode node, Blt_TreeKey key, Tcl_Obj *valuePtr)); typedef int (Blt_TreeCompareNodesProc) _ANSI_ARGS_((Blt_TreeNode *n1Ptr, Blt_TreeNode *n2Ptr)); typedef int (Blt_TreeApplyProc) _ANSI_ARGS_((Blt_TreeNode node, ClientData clientData, int order)); struct Blt_TreeTraceStruct { ClientData clientData; Blt_TreeKey key; Blt_TreeNode node; unsigned int mask; Blt_TreeTraceProc *proc; }; /* * Structure definition for information used to keep track of searches * through hash tables:p */ struct Blt_TreeKeySearchStruct { Blt_TreeNode node; /* Table being searched. */ unsigned long nextIndex; /* Index of next bucket to be * enumerated after present one. */ Blt_TreeValue nextValue; /* Next entry to be enumerated in the * the current bucket. */ }; EXTERN Blt_TreeKey Blt_TreeGetKey _ANSI_ARGS_((CONST char *string)); EXTERN Blt_TreeNode Blt_TreeCreateNode _ANSI_ARGS_((Blt_Tree tree, Blt_TreeNode parent, CONST char *name, int position)); EXTERN Blt_TreeNode Blt_TreeCreateNodeWithId _ANSI_ARGS_((Blt_Tree tree, Blt_TreeNode parent, CONST char *name, int position, int inode)); EXTERN int Blt_TreeDeleteNode _ANSI_ARGS_((Blt_Tree tree, Blt_TreeNode node)); EXTERN int Blt_TreeMoveNode _ANSI_ARGS_((Blt_Tree tree, Blt_TreeNode node, Blt_TreeNode parent, Blt_TreeNode before)); EXTERN Blt_TreeNode Blt_TreeGetNode _ANSI_ARGS_((Blt_Tree tree, unsigned int inode)); EXTERN Blt_TreeNode Blt_TreeFindChild _ANSI_ARGS_((Blt_TreeNode parent, CONST char *name)); EXTERN Blt_TreeNode Blt_TreeFirstChild _ANSI_ARGS_((Blt_TreeNode parent)); EXTERN Blt_TreeNode Blt_TreeNextSibling _ANSI_ARGS_((Blt_TreeNode node)); EXTERN Blt_TreeNode Blt_TreeLastChild _ANSI_ARGS_((Blt_TreeNode parent)); EXTERN Blt_TreeNode Blt_TreePrevSibling _ANSI_ARGS_((Blt_TreeNode node)); EXTERN Blt_TreeNode Blt_TreeNextNode _ANSI_ARGS_((Blt_TreeNode root, Blt_TreeNode node)); EXTERN Blt_TreeNode Blt_TreePrevNode _ANSI_ARGS_((Blt_TreeNode root, Blt_TreeNode node)); EXTERN Blt_TreeNode Blt_TreeChangeRoot _ANSI_ARGS_((Blt_Tree tree, Blt_TreeNode node)); EXTERN Blt_TreeNode Blt_TreeEndNode _ANSI_ARGS_((Blt_TreeNode node, unsigned int nodeFlags)); EXTERN int Blt_TreeIsBefore _ANSI_ARGS_((Blt_TreeNode node1, Blt_TreeNode node2)); EXTERN int Blt_TreeIsAncestor _ANSI_ARGS_((Blt_TreeNode node1, Blt_TreeNode node2)); EXTERN int Blt_TreePrivateValue _ANSI_ARGS_((Tcl_Interp *interp, Blt_Tree tree, Blt_TreeNode node, Blt_TreeKey key)); EXTERN int Blt_TreePublicValue _ANSI_ARGS_((Tcl_Interp *interp, Blt_Tree tree, Blt_TreeNode node, Blt_TreeKey key)); EXTERN int Blt_TreeGetValue _ANSI_ARGS_((Tcl_Interp *interp, Blt_Tree tree, Blt_TreeNode node, CONST char *string, Tcl_Obj **valuePtr)); EXTERN int Blt_TreeValueExists _ANSI_ARGS_((Blt_Tree tree, Blt_TreeNode node, CONST char *string)); EXTERN int Blt_TreeSetValue _ANSI_ARGS_((Tcl_Interp *interp, Blt_Tree tree, Blt_TreeNode node, CONST char *string, Tcl_Obj *valuePtr)); EXTERN int Blt_TreeUnsetValue _ANSI_ARGS_((Tcl_Interp *interp, Blt_Tree tree, Blt_TreeNode node, CONST char *string)); EXTERN int Blt_TreeGetArrayValue _ANSI_ARGS_((Tcl_Interp *interp, Blt_Tree tree, Blt_TreeNode node, CONST char *arrayName, CONST char *elemName, Tcl_Obj **valueObjPtrPtr)); EXTERN int Blt_TreeSetArrayValue _ANSI_ARGS_((Tcl_Interp *interp, Blt_Tree tree, Blt_TreeNode node, CONST char *arrayName, CONST char *elemName, Tcl_Obj *valueObjPtr)); EXTERN int Blt_TreeUnsetArrayValue _ANSI_ARGS_((Tcl_Interp *interp, Blt_Tree tree, Blt_TreeNode node, CONST char *arrayName, CONST char *elemName)); EXTERN int Blt_TreeArrayValueExists _ANSI_ARGS_((Blt_Tree tree, Blt_TreeNode node, CONST char *arrayName, CONST char *elemName)); EXTERN int Blt_TreeArrayNames _ANSI_ARGS_((Tcl_Interp *interp, Blt_Tree tree, Blt_TreeNode node, CONST char *arrayName, Tcl_Obj *listObjPtr)); EXTERN int Blt_TreeGetValueByKey _ANSI_ARGS_((Tcl_Interp *interp, Blt_Tree tree, Blt_TreeNode node, Blt_TreeKey key, Tcl_Obj **valuePtr)); EXTERN int Blt_TreeSetValueByKey _ANSI_ARGS_((Tcl_Interp *interp, Blt_Tree tree, Blt_TreeNode node, Blt_TreeKey key, Tcl_Obj *valuePtr)); EXTERN int Blt_TreeUnsetValueByKey _ANSI_ARGS_((Tcl_Interp *interp, Blt_Tree tree, Blt_TreeNode node, Blt_TreeKey key)); EXTERN int Blt_TreeValueExistsByKey _ANSI_ARGS_((Blt_Tree tree, Blt_TreeNode node, Blt_TreeKey key)); EXTERN Blt_TreeKey Blt_TreeFirstKey _ANSI_ARGS_((Blt_Tree tree, Blt_TreeNode node, Blt_TreeKeySearch *cursorPtr)); EXTERN Blt_TreeKey Blt_TreeNextKey _ANSI_ARGS_((Blt_Tree tree, Blt_TreeKeySearch *cursorPtr)); EXTERN int Blt_TreeApply _ANSI_ARGS_((Blt_TreeNode root, Blt_TreeApplyProc *proc, ClientData clientData)); EXTERN int Blt_TreeApplyDFS _ANSI_ARGS_((Blt_TreeNode root, Blt_TreeApplyProc *proc, ClientData clientData, int order)); EXTERN int Blt_TreeApplyBFS _ANSI_ARGS_((Blt_TreeNode root, Blt_TreeApplyProc *proc, ClientData clientData)); EXTERN int Blt_TreeSortNode _ANSI_ARGS_((Blt_Tree tree, Blt_TreeNode node, Blt_TreeCompareNodesProc *proc)); EXTERN int Blt_TreeCreate _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, Blt_Tree *treePtr)); EXTERN int Blt_TreeExists _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name)); EXTERN int Blt_TreeGetToken _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, Blt_Tree *treePtr)); EXTERN void Blt_TreeReleaseToken _ANSI_ARGS_((Blt_Tree tree)); EXTERN int Blt_TreeSize _ANSI_ARGS_((Blt_TreeNode node)); EXTERN Blt_TreeTrace Blt_TreeCreateTrace _ANSI_ARGS_((Blt_Tree tree, Blt_TreeNode node, CONST char *keyPattern, CONST char *tagName, unsigned int mask, Blt_TreeTraceProc *proc, ClientData clientData)); EXTERN void Blt_TreeDeleteTrace _ANSI_ARGS_((Blt_TreeTrace token)); EXTERN void Blt_TreeCreateEventHandler _ANSI_ARGS_((Blt_Tree tree, unsigned int mask, Blt_TreeNotifyEventProc *proc, ClientData clientData)); EXTERN void Blt_TreeDeleteEventHandler _ANSI_ARGS_((Blt_Tree tree, unsigned int mask, Blt_TreeNotifyEventProc *proc, ClientData clientData)); EXTERN void Blt_TreeRelabelNode _ANSI_ARGS_((Blt_Tree tree, Blt_TreeNode node, CONST char *string)); EXTERN void Blt_TreeRelabelNode2 _ANSI_ARGS_((Blt_TreeNode node, CONST char *string)); EXTERN char *Blt_TreeNodePath _ANSI_ARGS_((Blt_TreeNode node, Tcl_DString *resultPtr)); EXTERN int Blt_TreeNodePosition _ANSI_ARGS_((Blt_TreeNode node)); EXTERN void Blt_TreeClearTags _ANSI_ARGS_((Blt_Tree tree, Blt_TreeNode node)); EXTERN int Blt_TreeHasTag _ANSI_ARGS_((Blt_Tree tree, Blt_TreeNode node, CONST char *tagName)); EXTERN void Blt_TreeAddTag _ANSI_ARGS_((Blt_Tree tree, Blt_TreeNode node, CONST char *tagName)); EXTERN void Blt_TreeForgetTag _ANSI_ARGS_((Blt_Tree tree, CONST char *tagName)); EXTERN Blt_HashTable *Blt_TreeTagHashTable _ANSI_ARGS_((Blt_Tree tree, CONST char *tagName)); EXTERN int Blt_TreeTagTableIsShared _ANSI_ARGS_((Blt_Tree tree)); EXTERN int Blt_TreeShareTagTable _ANSI_ARGS_((Blt_Tree src, Blt_Tree target)); EXTERN Blt_HashEntry *Blt_TreeFirstTag _ANSI_ARGS_((Blt_Tree tree, Blt_HashSearch *searchPtr)); #define Blt_TreeName(token) ((token)->treeObject->name) #define Blt_TreeRootNode(token) ((token)->root) #define Blt_TreeChangeRoot(token, node) ((token)->root = (node)) #define Blt_TreeNodeDepth(token, node) ((node)->depth - (token)->root->depth) #define Blt_TreeNodeLabel(node) ((node)->label) #define Blt_TreeNodeId(node) ((node)->inode) #define Blt_TreeNodeParent(node) ((node)->parent) #define Blt_TreeNodeDegree(node) ((node)->nChildren) #define Blt_TreeIsLeaf(node) ((node)->nChildren == 0) #define Blt_TreeNextNodeId(token) ((token)->treeObject->nextInode) #define Blt_TreeFirstChild(node) ((node)->first) #define Blt_TreeLastChild(node) ((node)->last) #define Blt_TreeNextSibling(node) (((node) == NULL) ? NULL : (node)->next) #define Blt_TreePrevSibling(node) (((node) == NULL) ? NULL : (node)->prev) #endif /* _BLT_TREE_H */ blt-2.4z.orig/src/bltTreeCmd.c0100644000175000017500000044422007545155105014741 0ustar dokodoko /* * * bltTreeCmd.c -- * * Copyright 1998-1999 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 or 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. * * The "tree" data object was created by George A. Howlett. */ /* tree create t0 t1 t2 tree names t0 destroy -or- tree destroy t0 tree copy tree@node tree@node -recurse -tags tree move node after|before|into t2@node $t apply -recurse $root command arg arg $t attach treename $t children $n t0 copy node1 node2 node3 node4 node5 destName $t delete $n... $t depth $n $t dump $root $t dumpfile $root fileName $t dup $t2 $t find $root -name pat -name pattern $t firstchild $n $t get $n $key $t get $n $key(abc) $t index $n $t insert $parent $switches? $t isancestor $n1 $n2 $t isbefore $n1 $n2 $t isleaf $n $t lastchild $n $t move $n1 after|before|into $n2 $t next $n $t nextsibling $n $t path $n1 $n2 $n3... $t parent $n $t previous $n $t prevsibling $n $t restore $root data -overwrite $t root ?$n? $t set $n $key $value ?$key $value? $t size $n $t slink $n $t2@$node ??? $t sort -recurse $root $t tag delete tag1 tag2 tag3... $t tag names $t tag nodes $tag $t tag set $n tag1 tag2 tag3... $t tag unset $n tag1 tag2 tag3... $t trace create $n $key how command $t trace delete id1 id2 id3... $t trace names $t trace info $id $t unset $n key1 key2 key3... $t notify create -oncreate -ondelete -onmove command $t notify create -oncreate -ondelete -onmove -onsort command arg arg arg $t notify delete id1 id2 id3 $t notify names $t notify info id for { set n [$t firstchild $node] } { $n >= 0 } { set n [$t nextsibling $n] } { } foreach n [$t children $node] { } set n [$t next $node] set n [$t previous $node] */ #include #ifndef NO_TREE #include #include #include #include "bltSwitch.h" #include #define TREE_THREAD_KEY "BLT Tree Command Data" #define TREE_MAGIC ((unsigned int) 0x46170277) enum TagTypes { TAG_TYPE_NONE, TAG_TYPE_ALL, TAG_TYPE_TAG }; typedef struct { Blt_HashTable treeTable; /* Hash table of trees keyed by address. */ Tcl_Interp *interp; } TreeCmdInterpData; typedef struct { Tcl_Interp *interp; Tcl_Command cmdToken; /* Token for tree's Tcl command. */ Blt_Tree tree; /* Token holding internal tree. */ Blt_HashEntry *hashPtr; Blt_HashTable *tablePtr; TreeCmdInterpData *dataPtr; /* */ int traceCounter; /* Used to generate trace id strings. */ Blt_HashTable traceTable; /* Table of active traces. Maps trace ids * back to their TraceInfo records. */ int notifyCounter; /* Used to generate notify id strings. */ Blt_HashTable notifyTable; /* Table of event handlers. Maps notify ids * back to their NotifyInfo records. */ } TreeCmd; typedef struct { TreeCmd *cmdPtr; Blt_TreeNode node; Blt_TreeTrace traceToken; char *withTag; /* If non-NULL, the event or trace was * specified with this tag. This * value is saved for informational * purposes. The tree's trace * matching routines do the real * checking, not the client's * callback. */ char command[1]; /* Command prefix for the trace or notify * Tcl callback. Extra arguments will be * appended to the end. Extra space will * be allocated for the length of the string */ } TraceInfo; typedef struct { TreeCmd *cmdPtr; int mask; Tcl_Obj **objv; int objc; Blt_TreeNode node; /* Node affected by event. */ Blt_TreeTrace notifyToken; } NotifyInfo; typedef struct { int mask; } NotifyData; static Blt_SwitchSpec notifySwitches[] = { {BLT_SWITCH_FLAG, "-create", Blt_Offset(NotifyData, mask), 0, 0, TREE_NOTIFY_CREATE}, {BLT_SWITCH_FLAG, "-delete", Blt_Offset(NotifyData, mask), 0, 0, TREE_NOTIFY_DELETE}, {BLT_SWITCH_FLAG, "-move", Blt_Offset(NotifyData, mask), 0, 0, TREE_NOTIFY_MOVE}, {BLT_SWITCH_FLAG, "-sort", Blt_Offset(NotifyData, mask), 0, 0, TREE_NOTIFY_SORT}, {BLT_SWITCH_FLAG, "-relabel", Blt_Offset(NotifyData, mask), 0, 0, TREE_NOTIFY_RELABEL}, {BLT_SWITCH_FLAG, "-allevents", Blt_Offset(NotifyData, mask), 0, 0, TREE_NOTIFY_ALL}, {BLT_SWITCH_FLAG, "-whenidle", Blt_Offset(NotifyData, mask), 0, 0, TREE_NOTIFY_WHENIDLE}, {BLT_SWITCH_END, NULL, 0, 0} }; static Blt_SwitchParseProc StringToChild; #define INSERT_BEFORE (ClientData)0 #define INSERT_AFTER (ClientData)1 static Blt_SwitchCustom beforeSwitch = { StringToChild, (Blt_SwitchFreeProc *)NULL, INSERT_BEFORE, }; static Blt_SwitchCustom afterSwitch = { StringToChild, (Blt_SwitchFreeProc *)NULL, INSERT_AFTER, }; typedef struct { char *label; int insertPos; int inode; char **tags; char **dataPairs; Blt_TreeNode parent; } InsertData; static Blt_SwitchSpec insertSwitches[] = { {BLT_SWITCH_CUSTOM, "-after", Blt_Offset(InsertData, insertPos), 0, &afterSwitch}, {BLT_SWITCH_INT_NONNEGATIVE, "-at", Blt_Offset(InsertData, insertPos), 0}, {BLT_SWITCH_CUSTOM, "-before", Blt_Offset(InsertData, insertPos), 0, &beforeSwitch}, {BLT_SWITCH_LIST, "-data", Blt_Offset(InsertData, dataPairs), 0}, {BLT_SWITCH_STRING, "-label", Blt_Offset(InsertData, label), 0}, {BLT_SWITCH_INT_NONNEGATIVE, "-node", Blt_Offset(InsertData, inode), 0}, {BLT_SWITCH_LIST, "-tags", Blt_Offset(InsertData, tags), 0}, {BLT_SWITCH_END, NULL, 0, 0} }; #define PATTERN_EXACT (1) #define PATTERN_GLOB (2) #define PATTERN_MASK (0x3) #define PATTERN_NONE (0) #define PATTERN_REGEXP (3) #define MATCH_INVERT (1<<8) #define MATCH_LEAFONLY (1<<4) #define MATCH_NOCASE (1<<5) #define MATCH_PATHNAME (1<<6) typedef struct { TreeCmd *cmdPtr; /* Tree to examine. */ Tcl_Obj *listObjPtr; /* List to accumulate the indices of * matching nodes. */ Tcl_Obj **objv; /* Command converted into an array of * Tcl_Obj's. */ int objc; /* Number of Tcl_Objs in above array. */ int nMatches; /* Current number of matches. */ unsigned int flags; /* See flags definitions above. */ /* Integer options. */ int maxMatches; /* If > 0, stop after this many matches. */ int maxDepth; /* If > 0, don't descend more than this * many levels. */ int order; /* Order of search: Can be either * TREE_PREORDER, TREE_POSTORDER, * TREE_INORDER, TREE_BREADTHFIRST. */ /* String options. */ Blt_List patternList; /* List of patterns to compare with labels * or values. */ char *addTag; /* If non-NULL, tag added to selected nodes. */ char **command; /* Command split into a Tcl list. */ Blt_List keyList; /* List of key name patterns. */ char *withTag; } FindData; static Blt_SwitchParseProc StringToOrder; static Blt_SwitchCustom orderSwitch = { StringToOrder, (Blt_SwitchFreeProc *)NULL, (ClientData)0, }; static Blt_SwitchParseProc StringToPattern; static Blt_SwitchFreeProc FreePatterns; static Blt_SwitchCustom regexpSwitch = { StringToPattern, FreePatterns, (ClientData)PATTERN_REGEXP, }; static Blt_SwitchCustom globSwitch = { StringToPattern, FreePatterns, (ClientData)PATTERN_GLOB, }; static Blt_SwitchCustom exactSwitch = { StringToPattern, FreePatterns, (ClientData)PATTERN_EXACT, }; static Blt_SwitchSpec findSwitches[] = { {BLT_SWITCH_STRING, "-addtag", Blt_Offset(FindData, addTag), 0}, {BLT_SWITCH_INT_NONNEGATIVE, "-count", Blt_Offset(FindData, maxMatches), 0}, {BLT_SWITCH_INT_NONNEGATIVE, "-depth", Blt_Offset(FindData, maxDepth), 0}, {BLT_SWITCH_CUSTOM, "-exact", Blt_Offset(FindData, patternList), 0, &exactSwitch}, {BLT_SWITCH_LIST, "-exec", Blt_Offset(FindData, command), 0}, {BLT_SWITCH_CUSTOM, "-glob", Blt_Offset(FindData, patternList), 0, &globSwitch}, {BLT_SWITCH_FLAG, "-invert", Blt_Offset(FindData, flags), 0, 0, MATCH_INVERT}, {BLT_SWITCH_CUSTOM, "-key", Blt_Offset(FindData, keyList), 0, &exactSwitch}, {BLT_SWITCH_CUSTOM, "-keyexact", Blt_Offset(FindData, keyList), 0, &exactSwitch}, {BLT_SWITCH_CUSTOM, "-keyglob", Blt_Offset(FindData, keyList), 0, &globSwitch}, {BLT_SWITCH_CUSTOM, "-keyregexp", Blt_Offset(FindData, keyList), 0, ®expSwitch}, {BLT_SWITCH_FLAG, "-leafonly", Blt_Offset(FindData, flags), 0, 0, MATCH_LEAFONLY}, {BLT_SWITCH_FLAG, "-nocase", Blt_Offset(FindData, flags), 0, 0, MATCH_NOCASE}, {BLT_SWITCH_CUSTOM, "-order", Blt_Offset(FindData, order), 0, &orderSwitch}, {BLT_SWITCH_FLAG, "-path", Blt_Offset(FindData, flags), 0, 0, MATCH_PATHNAME}, {BLT_SWITCH_CUSTOM, "-regexp", Blt_Offset(FindData, patternList), 0, ®expSwitch}, {BLT_SWITCH_STRING, "-tag", Blt_Offset(FindData, withTag), 0}, {BLT_SWITCH_END, NULL, 0, 0} }; static Blt_SwitchParseProc StringToNode; static Blt_SwitchCustom nodeSwitch = { StringToNode, (Blt_SwitchFreeProc *)NULL, (ClientData)0, }; typedef struct { TreeCmd *cmdPtr; /* Tree to move nodes. */ Blt_TreeNode node; int movePos; } MoveData; static Blt_SwitchSpec moveSwitches[] = { {BLT_SWITCH_CUSTOM, "-after", Blt_Offset(MoveData, node), 0, &nodeSwitch}, {BLT_SWITCH_INT_NONNEGATIVE, "-at", Blt_Offset(MoveData, movePos), 0}, {BLT_SWITCH_CUSTOM, "-before", Blt_Offset(MoveData, node), 0, &nodeSwitch}, {BLT_SWITCH_END, NULL, 0, 0} }; typedef struct { Blt_TreeNode srcNode, destNode; Blt_Tree srcTree, destTree; TreeCmd *srcPtr, *destPtr; unsigned int flags; char *label; } CopyData; #define COPY_RECURSE (1<<0) #define COPY_TAGS (1<<1) #define COPY_OVERWRITE (1<<2) static Blt_SwitchSpec copySwitches[] = { {BLT_SWITCH_STRING, "-label", Blt_Offset(CopyData, label), 0}, {BLT_SWITCH_FLAG, "-recurse", Blt_Offset(CopyData, flags), 0, 0, COPY_RECURSE}, {BLT_SWITCH_FLAG, "-tags", Blt_Offset(CopyData, flags), 0, 0, COPY_TAGS}, {BLT_SWITCH_FLAG, "-overwrite", Blt_Offset(CopyData, flags), 0, 0, COPY_OVERWRITE}, {BLT_SWITCH_END, NULL, 0, 0} }; typedef struct { TreeCmd *cmdPtr; /* Tree to examine. */ Tcl_Obj **preObjv; /* Command converted into an array of * Tcl_Obj's. */ int preObjc; /* Number of Tcl_Objs in above array. */ Tcl_Obj **postObjv; /* Command converted into an array of * Tcl_Obj's. */ int postObjc; /* Number of Tcl_Objs in above array. */ unsigned int flags; /* See flags definitions above. */ int maxDepth; /* If > 0, don't descend more than this * many levels. */ /* String options. */ Blt_List patternList; /* List of label or value patterns. */ char **preCmd; /* Pre-command split into a Tcl list. */ char **postCmd; /* Post-command split into a Tcl list. */ Blt_List keyList; /* List of key-name patterns. */ char *withTag; } ApplyData; static Blt_SwitchSpec applySwitches[] = { {BLT_SWITCH_LIST, "-precommand", Blt_Offset(ApplyData, preCmd), 0}, {BLT_SWITCH_LIST, "-postcommand", Blt_Offset(ApplyData, postCmd), 0}, {BLT_SWITCH_INT_NONNEGATIVE, "-depth", Blt_Offset(ApplyData, maxDepth), 0}, {BLT_SWITCH_CUSTOM, "-exact", Blt_Offset(ApplyData, patternList), 0, &exactSwitch}, {BLT_SWITCH_CUSTOM, "-glob", Blt_Offset(ApplyData, patternList), 0, &globSwitch}, {BLT_SWITCH_FLAG, "-invert", Blt_Offset(ApplyData, flags), 0, 0, MATCH_INVERT}, {BLT_SWITCH_CUSTOM, "-key", Blt_Offset(ApplyData, keyList), 0, &exactSwitch}, {BLT_SWITCH_CUSTOM, "-keyexact", Blt_Offset(ApplyData, keyList), 0, &exactSwitch}, {BLT_SWITCH_CUSTOM, "-keyglob", Blt_Offset(ApplyData, keyList), 0, &globSwitch}, {BLT_SWITCH_CUSTOM, "-keyregexp", Blt_Offset(ApplyData, keyList), 0, ®expSwitch}, {BLT_SWITCH_FLAG, "-leafonly", Blt_Offset(ApplyData, flags), 0, 0, MATCH_LEAFONLY}, {BLT_SWITCH_FLAG, "-nocase", Blt_Offset(ApplyData, flags), 0, 0, MATCH_NOCASE}, {BLT_SWITCH_FLAG, "-path", Blt_Offset(ApplyData, flags), 0, 0, MATCH_PATHNAME}, {BLT_SWITCH_CUSTOM, "-regexp", Blt_Offset(ApplyData, patternList), 0, ®expSwitch}, {BLT_SWITCH_STRING, "-tag", Blt_Offset(ApplyData, withTag), 0}, {BLT_SWITCH_END, NULL, 0, 0} }; typedef struct { unsigned int flags; Blt_HashTable idTable; Blt_TreeNode root; } RestoreData; #define RESTORE_NO_TAGS (1<<0) #define RESTORE_OVERWRITE (1<<1) static Blt_SwitchSpec restoreSwitches[] = { {BLT_SWITCH_FLAG, "-notags", Blt_Offset(RestoreData, flags), 0, 0, RESTORE_NO_TAGS}, {BLT_SWITCH_FLAG, "-overwrite", Blt_Offset(RestoreData, flags), 0, 0, RESTORE_OVERWRITE}, {BLT_SWITCH_END, NULL, 0, 0} }; static Blt_SwitchParseProc StringToFormat; static Blt_SwitchCustom formatSwitch = { StringToFormat, (Blt_SwitchFreeProc *)NULL, (ClientData)0, }; typedef struct { int sort; /* If non-zero, sort the nodes. */ int withParent; /* If non-zero, add the parent node id * to the output of the command.*/ int withId; /* If non-zero, echo the node id in the * output of the command. */ } PositionData; #define POSITION_SORTED (1<<0) static Blt_SwitchSpec positionSwitches[] = { {BLT_SWITCH_FLAG, "-sort", Blt_Offset(PositionData, sort), 0, 0, POSITION_SORTED}, {BLT_SWITCH_CUSTOM, "-format", 0, 0, &formatSwitch}, {BLT_SWITCH_END, NULL, 0, 0} }; static Tcl_InterpDeleteProc TreeInterpDeleteProc; static Blt_TreeApplyProc MatchNodeProc, SortApplyProc; static Blt_TreeApplyProc ApplyNodeProc; static Blt_TreeTraceProc TreeTraceProc; static Tcl_CmdDeleteProc TreeInstDeleteProc; static Blt_TreeCompareNodesProc CompareNodes; static Tcl_ObjCmdProc TreeObjCmd; static Tcl_ObjCmdProc CompareDictionaryCmd; static Tcl_ObjCmdProc ExitCmd; static Blt_TreeNotifyEventProc TreeEventProc; static int GetNode _ANSI_ARGS_((TreeCmd *cmdPtr, Tcl_Obj *objPtr, Blt_TreeNode *nodePtr)); static int nLines; /* *---------------------------------------------------------------------- * * StringToChild -- * * Convert a string represent a node number into its integer * value. * * Results: * The return value is a standard Tcl result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToChild( ClientData clientData, /* Flag indicating if the node is * considered before or after the * insertion position. */ Tcl_Interp *interp, /* Interpreter to send results back to */ char *switchName, /* Not used. */ char *string, /* String representation */ char *record, /* Structure record */ int offset) /* Offset to field in structure */ { InsertData *dataPtr = (InsertData *)record; Blt_TreeNode node; node = Blt_TreeFindChild(dataPtr->parent, string); if (node == NULL) { Tcl_AppendResult(interp, "can't find a child named \"", string, "\" in \"", Blt_TreeNodeLabel(dataPtr->parent), "\"", (char *)NULL); return TCL_ERROR; } dataPtr->insertPos = Blt_TreeNodeDegree(node); if (clientData == INSERT_AFTER) { dataPtr->insertPos++; } return TCL_OK; } /* *---------------------------------------------------------------------- * * StringToNode -- * * Convert a string represent a node number into its integer * value. * * Results: * The return value is a standard Tcl result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToNode( ClientData clientData, /* Not used. */ Tcl_Interp *interp, /* Interpreter to send results back to */ char *switchName, /* Not used. */ char *string, /* String representation */ char *record, /* Structure record */ int offset) /* Offset to field in structure */ { MoveData *dataPtr = (MoveData *)record; Blt_TreeNode node; Tcl_Obj *objPtr; TreeCmd *cmdPtr = dataPtr->cmdPtr; int result; objPtr = Tcl_NewStringObj(string, -1); result = GetNode(cmdPtr, objPtr, &node); Tcl_DecrRefCount(objPtr); if (result != TCL_OK) { return TCL_ERROR; } dataPtr->node = node; return TCL_OK; } /* *---------------------------------------------------------------------- * * StringToOrder -- * * Convert a string represent a node number into its integer * value. * * Results: * The return value is a standard Tcl result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToOrder( ClientData clientData, /* Not used. */ Tcl_Interp *interp, /* Interpreter to send results back to */ char *switchName, /* Not used. */ char *string, /* String representation */ char *record, /* Structure record */ int offset) /* Offset to field in structure */ { int *orderPtr = (int *)(record + offset); char c; c = string[0]; if ((c == 'b') && (strcmp(string, "breadthfirst") == 0)) { *orderPtr = TREE_BREADTHFIRST; } else if ((c == 'i') && (strcmp(string, "inorder") == 0)) { *orderPtr = TREE_INORDER; } else if ((c == 'p') && (strcmp(string, "preorder") == 0)) { *orderPtr = TREE_PREORDER; } else if ((c == 'p') && (strcmp(string, "postorder") == 0)) { *orderPtr = TREE_POSTORDER; } else { Tcl_AppendResult(interp, "bad order \"", string, "\": should be breadthfirst, inorder, preorder, or postorder", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * StringToPattern -- * * Convert a string represent a node number into its integer * value. * * Results: * The return value is a standard Tcl result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToPattern( ClientData clientData, /* Flag indicating type of pattern. */ Tcl_Interp *interp, /* Interpreter to send results back to */ char *switchName, /* Not used. */ char *string, /* String representation */ char *record, /* Structure record */ int offset) /* Offset to field in structure */ { Blt_List *listPtr = (Blt_List *)(record + offset); if (*listPtr == NULL) { *listPtr = Blt_ListCreate(BLT_STRING_KEYS); } Blt_ListAppend(*listPtr, string, clientData); return TCL_OK; } /* *---------------------------------------------------------------------- * * FreePatterns -- * * Convert a string represent a node number into its integer * value. * * Results: * The return value is a standard Tcl result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static void FreePatterns(char *object) { Blt_List list = (Blt_List)object; if (list != NULL) { Blt_ListDestroy(list); } } /* *---------------------------------------------------------------------- * * StringToFormat -- * * Convert a string represent a node number into its integer * value. * * Results: * The return value is a standard Tcl result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToFormat( ClientData clientData, /* Not used. */ Tcl_Interp *interp, /* Interpreter to send results back to */ char *switchName, /* Not used. */ char *string, /* String representation */ char *record, /* Structure record */ int offset) /* Offset to field in structure */ { PositionData *dataPtr = (PositionData *)record; if (strcmp(string, "position") == 0) { dataPtr->withParent = FALSE; dataPtr->withId = FALSE; } else if (strcmp(string, "id+position") == 0) { dataPtr->withParent = FALSE; dataPtr->withId = TRUE; } else if (strcmp(string, "parent-at-position") == 0) { dataPtr->withParent = TRUE; dataPtr->withId = FALSE; } else if (strcmp(string, "id+parent-at-position") == 0) { dataPtr->withParent = TRUE; dataPtr->withId = TRUE; } else { Tcl_AppendResult(interp, "bad format \"", string, "\": should be position, parent-at-position, id+position, or id+parent-at-position", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * GetTreeCmdInterpData -- * *---------------------------------------------------------------------- */ static TreeCmdInterpData * GetTreeCmdInterpData(Tcl_Interp *interp) { TreeCmdInterpData *dataPtr; Tcl_InterpDeleteProc *proc; dataPtr = (TreeCmdInterpData *) Tcl_GetAssocData(interp, TREE_THREAD_KEY, &proc); if (dataPtr == NULL) { dataPtr = Blt_Malloc(sizeof(TreeCmdInterpData)); assert(dataPtr); dataPtr->interp = interp; Tcl_SetAssocData(interp, TREE_THREAD_KEY, TreeInterpDeleteProc, dataPtr); Blt_InitHashTable(&dataPtr->treeTable, BLT_ONE_WORD_KEYS); } return dataPtr; } /* *---------------------------------------------------------------------- * * GetTreeCmd -- * * Find the tree command associated with the Tcl command "string". * * We have to do multiple lookups to get this right. * * The first step is to generate a canonical command name. If an * unqualified command name (i.e. no namespace qualifier) is * given, we should search first the current namespace and then * the global one. Most Tcl commands (like Tcl_GetCmdInfo) look * only at the global namespace. * * Next check if the string is * a) a Tcl command and * b) really is a command for a tree object. * Tcl_GetCommandInfo will get us the objClientData field that * should be a cmdPtr. We can verify that by searching our hashtable * of cmdPtr addresses. * * Results: * A pointer to the tree command. If no associated tree command * can be found, NULL is returned. It's up to the calling routines * to generate an error message. * *---------------------------------------------------------------------- */ static TreeCmd * GetTreeCmd( TreeCmdInterpData *dataPtr, Tcl_Interp *interp, CONST char *string) { CONST char *name; Tcl_Namespace *nsPtr; Tcl_CmdInfo cmdInfo; Blt_HashEntry *hPtr; Tcl_DString dString; char *treeName; int result; /* Put apart the tree name and put is back together in a standard * format. */ if (Blt_ParseQualifiedName(interp, string, &nsPtr, &name) != TCL_OK) { return NULL; /* No such parent namespace. */ } if (nsPtr == NULL) { nsPtr = Tcl_GetCurrentNamespace(interp); } /* Rebuild the fully qualified name. */ treeName = Blt_GetQualifiedName(nsPtr, name, &dString); result = Tcl_GetCommandInfo(interp, treeName, &cmdInfo); Tcl_DStringFree(&dString); if (!result) { return NULL; } hPtr = Blt_FindHashEntry(&dataPtr->treeTable, (char *)(cmdInfo.objClientData)); if (hPtr == NULL) { return NULL; } return Blt_GetHashValue(hPtr); } static Blt_TreeNode ParseModifiers( Tcl_Interp *interp, Blt_Tree tree, Blt_TreeNode node, char *modifiers) { char *p, *np; p = modifiers; do { p += 2; /* Skip the initial "->" */ np = strstr(p, "->"); if (np != NULL) { *np = '\0'; } if ((*p == 'p') && (strcmp(p, "parent") == 0)) { node = Blt_TreeNodeParent(node); } else if ((*p == 'f') && (strcmp(p, "firstchild") == 0)) { node = Blt_TreeFirstChild(node); } else if ((*p == 'l') && (strcmp(p, "lastchild") == 0)) { node = Blt_TreeLastChild(node); } else if ((*p == 'n') && (strcmp(p, "next") == 0)) { node = Blt_TreeNextNode(Blt_TreeRootNode(tree), node); } else if ((*p == 'n') && (strcmp(p, "nextsibling") == 0)) { node = Blt_TreeNextSibling(node); } else if ((*p == 'p') && (strcmp(p, "previous") == 0)) { node = Blt_TreePrevNode(Blt_TreeRootNode(tree), node); } else if ((*p == 'p') && (strcmp(p, "prevsibling") == 0)) { node = Blt_TreePrevSibling(node); } else if (isdigit(UCHAR(*p))) { int inode; if (Tcl_GetInt(interp, p, &inode) != TCL_OK) { node = NULL; } else { node = Blt_TreeGetNode(tree, inode); } } else { char *endp; if (np != NULL) { endp = np - 1; } else { endp = p + strlen(p) - 1; } if ((*p == '"') && (*endp == '"')) { *endp = '\0'; node = Blt_TreeFindChild(node, p + 1); *endp = '"'; } else { node = Blt_TreeFindChild(node, p); } } if (node == NULL) { goto error; } if (np != NULL) { *np = '-'; /* Repair the string */ } p = np; } while (np != NULL); return node; error: if (np != NULL) { *np = '-'; /* Repair the string */ } return NULL; } /* *---------------------------------------------------------------------- * * GetForeignNode -- * *---------------------------------------------------------------------- */ static int GetForeignNode( Tcl_Interp *interp, Blt_Tree tree, Tcl_Obj *objPtr, Blt_TreeNode *nodePtr) { char c; Blt_TreeNode node; char *string; char *p; string = Tcl_GetString(objPtr); c = string[0]; /* * Check if modifiers are present. */ p = strstr(string, "->"); if (isdigit(UCHAR(c))) { int inode; if (p != NULL) { char save; int result; save = *p; *p = '\0'; result = Tcl_GetInt(interp, string, &inode); *p = save; if (result != TCL_OK) { return TCL_ERROR; } } else { if (Tcl_GetIntFromObj(interp, objPtr, &inode) != TCL_OK) { return TCL_ERROR; } } node = Blt_TreeGetNode(tree, inode); if (p != NULL) { node = ParseModifiers(interp, tree, node, p); } if (node != NULL) { *nodePtr = node; return TCL_OK; } } Tcl_AppendResult(interp, "can't find tag or id \"", string, "\" in ", Blt_TreeName(tree), (char *)NULL); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * GetNode -- * *---------------------------------------------------------------------- */ static int GetNode(TreeCmd *cmdPtr, Tcl_Obj *objPtr, Blt_TreeNode *nodePtr) { Tcl_Interp *interp = cmdPtr->interp; Blt_Tree tree = cmdPtr->tree; char c; Blt_TreeNode node; char *string; char *p; string = Tcl_GetString(objPtr); c = string[0]; /* * Check if modifiers are present. */ p = strstr(string, "->"); if (isdigit(UCHAR(c))) { int inode; if (p != NULL) { char save; int result; save = *p; *p = '\0'; result = Tcl_GetInt(interp, string, &inode); *p = save; if (result != TCL_OK) { return TCL_ERROR; } } else { if (Tcl_GetIntFromObj(interp, objPtr, &inode) != TCL_OK) { return TCL_ERROR; } } node = Blt_TreeGetNode(tree, inode); } else if (cmdPtr != NULL) { char save; save = '\0'; /* Suppress compiler warning. */ if (p != NULL) { save = *p; *p = '\0'; } if (strcmp(string, "all") == 0) { if (Blt_TreeSize(Blt_TreeRootNode(tree)) > 1) { Tcl_AppendResult(interp, "more than one node tagged as \"", string, "\"", (char *)NULL); if (p != NULL) { *p = save; } return TCL_ERROR; } node = Blt_TreeRootNode(tree); } else if (strcmp(string, "root") == 0) { node = Blt_TreeRootNode(tree); } else { Blt_HashTable *tablePtr; Blt_HashSearch cursor; Blt_HashEntry *hPtr; int result; node = NULL; result = TCL_ERROR; tablePtr = Blt_TreeTagHashTable(cmdPtr->tree, string); if (tablePtr == NULL) { Tcl_AppendResult(interp, "can't find tag or id \"", string, "\" in ", Blt_TreeName(cmdPtr->tree), (char *)NULL); } else if (tablePtr->numEntries > 1) { Tcl_AppendResult(interp, "more than one node tagged as \"", string, "\"", (char *)NULL); } else if (tablePtr->numEntries > 0) { hPtr = Blt_FirstHashEntry(tablePtr, &cursor); node = Blt_GetHashValue(hPtr); result = TCL_OK; } if (result == TCL_ERROR) { if (p != NULL) { *p = save; } return TCL_ERROR; } } if (p != NULL) { *p = save; } } if (node != NULL) { if (p != NULL) { node = ParseModifiers(interp, tree, node, p); if (node == NULL) { goto error; } } *nodePtr = node; return TCL_OK; } error: Tcl_AppendResult(interp, "can't find tag or id \"", string, "\" in ", Blt_TreeName(tree), (char *)NULL); return TCL_ERROR; } typedef struct { int tagType; Blt_TreeNode root; Blt_HashSearch cursor; } TagSearch; /* *---------------------------------------------------------------------- * * FirstTaggedNode -- * * Returns the id of the first node tagged by the given tag in * objPtr. It basically hides much of the cumbersome special * case details. For example, the special tags "root" and "all" * always exist, so they don't have entries in the tag hashtable. * If it's a hashed tag (not "root" or "all"), we have to save * the place of where we are in the table for the next call to * NextTaggedNode. * *---------------------------------------------------------------------- */ static Blt_TreeNode FirstTaggedNode( Tcl_Interp *interp, TreeCmd *cmdPtr, Tcl_Obj *objPtr, TagSearch *cursorPtr) { Blt_TreeNode node, root; char *string; node = NULL; root = Blt_TreeRootNode(cmdPtr->tree); string = Tcl_GetString(objPtr); cursorPtr->tagType = TAG_TYPE_NONE; cursorPtr->root = root; /* Process strings with modifiers or digits as simple ids, not * tags. */ if ((strstr(string, "->") != NULL) || (isdigit(UCHAR(*string)))) { if (GetNode(cmdPtr, objPtr, &node) != TCL_OK) { return NULL; } return node; } if (strcmp(string, "all") == 0) { cursorPtr->tagType = TAG_TYPE_ALL; return root; } else if (strcmp(string, "root") == 0) { return root; } else { Blt_HashTable *tablePtr; tablePtr = Blt_TreeTagHashTable(cmdPtr->tree, string); if (tablePtr != NULL) { Blt_HashEntry *hPtr; cursorPtr->tagType = TAG_TYPE_TAG; hPtr = Blt_FirstHashEntry(tablePtr, &(cursorPtr->cursor)); if (hPtr == NULL) { return NULL; } node = Blt_GetHashValue(hPtr); return node; } } Tcl_AppendResult(interp, "can't find tag or id \"", string, "\" in ", Blt_TreeName(cmdPtr->tree), (char *)NULL); return NULL; } /* *---------------------------------------------------------------------- * * NextTaggedNode -- * *---------------------------------------------------------------------- */ static Blt_TreeNode NextTaggedNode(Blt_TreeNode node, TagSearch *cursorPtr) { if (cursorPtr->tagType == TAG_TYPE_ALL) { return Blt_TreeNextNode(cursorPtr->root, node); } if (cursorPtr->tagType == TAG_TYPE_TAG) { Blt_HashEntry *hPtr; hPtr = Blt_NextHashEntry(&(cursorPtr->cursor)); if (hPtr == NULL) { return NULL; } return Blt_GetHashValue(hPtr); } return NULL; } static int AddTag(TreeCmd *cmdPtr, Blt_TreeNode node, CONST char *tagName) { if (strcmp(tagName, "root") == 0) { Tcl_AppendResult(cmdPtr->interp, "can't add reserved tag \"", tagName, "\"", (char *)NULL); return TCL_ERROR; } Blt_TreeAddTag(cmdPtr->tree, node, tagName); return TCL_OK; } /* *---------------------------------------------------------------------- * * DeleteNode -- * *---------------------------------------------------------------------- */ static void DeleteNode(TreeCmd *cmdPtr, Blt_TreeNode node) { Blt_TreeNode root; if (!Blt_TreeTagTableIsShared(cmdPtr->tree)) { Blt_TreeClearTags(cmdPtr->tree, node); } root = Blt_TreeRootNode(cmdPtr->tree); if (node == root) { Blt_TreeNode next; /* Don't delete the root node. Simply clean out the tree. */ for (node = Blt_TreeFirstChild(node); node != NULL; node = next) { next = Blt_TreeNextSibling(node); Blt_TreeDeleteNode(cmdPtr->tree, node); } } else if (Blt_TreeIsAncestor(root, node)) { Blt_TreeDeleteNode(cmdPtr->tree, node); } } /* *---------------------------------------------------------------------- * * GetNodePath -- * *---------------------------------------------------------------------- */ static char * GetNodePath( TreeCmd *cmdPtr, Blt_TreeNode root, Blt_TreeNode node, int rootFlag, /* If non-zero, indicates to include * the root name in the path */ Tcl_DString *resultPtr) { char **nameArr; /* Used to stack the component names. */ char *staticSpace[64]; register int i; int nLevels; nLevels = Blt_TreeNodeDepth(cmdPtr->tree, node) - Blt_TreeNodeDepth(cmdPtr->tree, root); if (rootFlag) { nLevels++; } if (nLevels > 64) { nameArr = Blt_Malloc(nLevels * sizeof(char *)); assert(nameArr); } else { nameArr = staticSpace; } for (i = nLevels; i > 0; i--) { /* Save the name of each ancestor in the name array. * Note that we ignore the root. */ nameArr[i - 1] = Blt_TreeNodeLabel(node); node = Blt_TreeNodeParent(node); } /* Append each the names in the array. */ Tcl_DStringInit(resultPtr); for (i = 0; i < nLevels; i++) { Tcl_DStringAppendElement(resultPtr, nameArr[i]); } if (nameArr != staticSpace) { Blt_Free(nameArr); } return Tcl_DStringValue(resultPtr); } /* *---------------------------------------------------------------------- * * ParseNode5 -- * * Parses and creates a node based upon the first 3 fields of * a five field entry. This is the new restore file format. * * parentId nodeId pathList dataList tagList * * The purpose is to attempt to save and restore the node ids * embedded in the restore file information. The old format * could not distinquish between two sibling nodes with the same * label unless they were both leaves. I'm trying to avoid * dependencies upon labels. * * If you're starting from an empty tree, this obviously should * work without a hitch. We only need to map the file's root id * to 0. It's a little more complicated when adding node to an * already full tree. * * First see if the node id isn't already in use. Otherwise, map * the node id (via a hashtable) to the real node. We'll need it * later when subsequent entries refer to their parent id. * * If a parent id is unknown (the restore file may be out of * order), then follow plan B and use its path. * *---------------------------------------------------------------------- */ static Blt_TreeNode ParseNode5(TreeCmd *cmdPtr, char **argv, RestoreData *dataPtr) { Blt_HashEntry *hPtr; Blt_TreeNode node, parent; char **names; int nNames, isNew; int parentId, nodeId; if ((Tcl_GetInt(cmdPtr->interp, argv[0], &parentId) != TCL_OK) || (Tcl_GetInt(cmdPtr->interp, argv[1], &nodeId) != TCL_OK) || (Tcl_SplitList(cmdPtr->interp, argv[2], &nNames, &names) != TCL_OK)) { return NULL; } if (parentId == -1) { /* Dump marks root's parent as -1. */ node = dataPtr->root; /* Create a mapping between the old id and the new node */ hPtr = Blt_CreateHashEntry(&dataPtr->idTable, (char *)nodeId, &isNew); Blt_SetHashValue(hPtr, node); Blt_TreeRelabelNode(cmdPtr->tree, node, names[0]); } else { /* * Check if the parent has been translated to another id. * This can happen when there's a id collision with an * existing node. */ hPtr = Blt_FindHashEntry(&dataPtr->idTable, (char *)parentId); if (hPtr != NULL) { parent = Blt_GetHashValue(hPtr); } else { /* Check if the id already exists in the tree. */ parent = Blt_TreeGetNode(cmdPtr->tree, parentId); if (parent == NULL) { /* Parent id doesn't exist (partial restore?). * Plan B: Use the path to create/find the parent with * the requested parent id. */ if (nNames > 1) { int i; for (i = 1; i < (nNames - 2); i++) { node = Blt_TreeFindChild(parent, names[i]); if (node == NULL) { node = Blt_TreeCreateNode(cmdPtr->tree, parent, names[i], -1); } parent = node; } node = Blt_TreeFindChild(parent, names[nNames - 2]); if (node == NULL) { node = Blt_TreeCreateNodeWithId(cmdPtr->tree, parent, names[nNames - 2], parentId, -1); } parent = node; } else { parent = dataPtr->root; } } } /* Check if old node id already in use. */ node = NULL; if (dataPtr->flags & RESTORE_OVERWRITE) { node = Blt_TreeFindChild(parent, names[nNames - 1]); /* Create a mapping between the old id and the new node */ hPtr = Blt_CreateHashEntry(&dataPtr->idTable, (char *)nodeId, &isNew); Blt_SetHashValue(hPtr, node); } if (node == NULL) { node = Blt_TreeGetNode(cmdPtr->tree, nodeId); if (node != NULL) { node = Blt_TreeCreateNode(cmdPtr->tree, parent, names[nNames - 1], -1); /* Create a mapping between the old id and the new node */ hPtr = Blt_CreateHashEntry(&dataPtr->idTable, (char *)nodeId, &isNew); Blt_SetHashValue(hPtr, node); } else { /* Otherwise create a new node with the requested id. */ node = Blt_TreeCreateNodeWithId(cmdPtr->tree, parent, names[nNames - 1], nodeId, -1); } } } Blt_Free(names); return node; } /* *---------------------------------------------------------------------- * * ParseNode3 -- * * Parses and creates a node based upon the first field of * a three field entry. This is the old restore file format. * * pathList dataList tagList * *---------------------------------------------------------------------- */ static Blt_TreeNode ParseNode3(TreeCmd *cmdPtr, char **argv, RestoreData *dataPtr) { Blt_TreeNode node, parent; char **names; int i; int nNames; if (Tcl_SplitList(cmdPtr->interp, argv[0], &nNames, &names) != TCL_OK) { return NULL; } node = parent = dataPtr->root; /* Automatically create nodes as needed except for the last node. */ for (i = 0; i < (nNames - 1); i++) { node = Blt_TreeFindChild(parent, names[i]); if (node == NULL) { node = Blt_TreeCreateNode(cmdPtr->tree, parent, names[i], -1); } parent = node; } if (nNames > 0) { /* * By default, create duplicate nodes (two sibling nodes with * the same label), unless the -overwrite flag was set. */ node = NULL; if (dataPtr->flags & RESTORE_OVERWRITE) { node = Blt_TreeFindChild(parent, names[i]); } if (node == NULL) { node = Blt_TreeCreateNode(cmdPtr->tree, parent, names[i], -1); } } Blt_Free(names); return node; } static int RestoreNode(TreeCmd *cmdPtr, int argc, char **argv, RestoreData *dataPtr) { Blt_TreeNode node; Tcl_Obj *valueObjPtr; char **elemArr; int nElem, result; register int i; if ((argc != 3) && (argc != 5)) { Tcl_AppendResult(cmdPtr->interp, "line #", Blt_Itoa(nLines), ": wrong # elements in restore entry", (char *)NULL); return TCL_ERROR; } /* Parse the path name. */ if (argc == 3) { node = ParseNode3(cmdPtr, argv, dataPtr); argv++; } else if (argc == 5) { node = ParseNode5(cmdPtr, argv, dataPtr); argv += 3; } else { Tcl_AppendResult(cmdPtr->interp, "line #", Blt_Itoa(nLines), ": wrong # elements in restore entry", (char *)NULL); return TCL_ERROR; } if (node == NULL) { return TCL_ERROR; } /* Parse the key-value list. */ if (Tcl_SplitList(cmdPtr->interp, argv[0], &nElem, &elemArr) != TCL_OK) { return TCL_ERROR; } for (i = 0; i < nElem; i += 2) { if ((i + 1) < nElem) { valueObjPtr = Tcl_NewStringObj(elemArr[i + 1], -1); } else { valueObjPtr = bltEmptyStringObjPtr; } Tcl_IncrRefCount(valueObjPtr); result = Blt_TreeSetValue(cmdPtr->interp, cmdPtr->tree, node, elemArr[i], valueObjPtr); Tcl_DecrRefCount(valueObjPtr); if (result != TCL_OK) { Blt_Free(elemArr); return TCL_ERROR; } } Blt_Free(elemArr); if (!(dataPtr->flags & RESTORE_NO_TAGS)) { /* Parse the tag list. */ if (Tcl_SplitList(cmdPtr->interp, argv[1], &nElem, &elemArr) != TCL_OK) { return TCL_ERROR; } for (i = 0; i < nElem; i++) { if (AddTag(cmdPtr, node, elemArr[i]) != TCL_OK) { Blt_Free(elemArr); return TCL_ERROR; } } Blt_Free(elemArr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * PrintNode -- * *---------------------------------------------------------------------- */ static void PrintNode( TreeCmd *cmdPtr, Blt_TreeNode root, Blt_TreeNode node, Tcl_DString *resultPtr) { Blt_HashEntry *hPtr; Blt_HashSearch cursor; char *pathName; Tcl_DString dString; Tcl_Obj *valueObjPtr; register Blt_TreeKey key; Blt_TreeTagEntry *tPtr; Blt_TreeKeySearch keyIter; if (node == root) { Tcl_DStringAppendElement(resultPtr, "-1"); } else { Blt_TreeNode parent; parent = Blt_TreeNodeParent(node); Tcl_DStringAppendElement(resultPtr, Blt_Itoa(Blt_TreeNodeId(parent))); } Tcl_DStringAppendElement(resultPtr, Blt_Itoa(Blt_TreeNodeId(node))); pathName = GetNodePath(cmdPtr, root, node, TRUE, &dString); Tcl_DStringAppendElement(resultPtr, pathName); Tcl_DStringStartSublist(resultPtr); for (key = Blt_TreeFirstKey(cmdPtr->tree, node, &keyIter); key != NULL; key = Blt_TreeNextKey(cmdPtr->tree, &keyIter)) { if (Blt_TreeGetValueByKey((Tcl_Interp *)NULL, cmdPtr->tree, node, key, &valueObjPtr) == TCL_OK) { Tcl_DStringAppendElement(resultPtr, key); Tcl_DStringAppendElement(resultPtr, Tcl_GetString(valueObjPtr)); } } Tcl_DStringEndSublist(resultPtr); Tcl_DStringStartSublist(resultPtr); for (hPtr = Blt_TreeFirstTag(cmdPtr->tree, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tPtr = Blt_GetHashValue(hPtr); if (Blt_FindHashEntry(&tPtr->nodeTable, (char *)node) != NULL) { Tcl_DStringAppendElement(resultPtr, tPtr->tagName); } } Tcl_DStringEndSublist(resultPtr); Tcl_DStringAppend(resultPtr, "\n", -1); Tcl_DStringFree(&dString); } /* *---------------------------------------------------------------------- * * PrintTraceFlags -- * *---------------------------------------------------------------------- */ static void PrintTraceFlags(unsigned int flags, char *string) { register char *p; p = string; if (flags & TREE_TRACE_READ) { *p++ = 'r'; } if (flags & TREE_TRACE_WRITE) { *p++ = 'w'; } if (flags & TREE_TRACE_UNSET) { *p++ = 'u'; } if (flags & TREE_TRACE_CREATE) { *p++ = 'c'; } *p = '\0'; } /* *---------------------------------------------------------------------- * * GetTraceFlags -- * *---------------------------------------------------------------------- */ static int GetTraceFlags(char *string) { register char *p; unsigned int flags; flags = 0; for (p = string; *p != '\0'; p++) { switch (toupper(*p)) { case 'R': flags |= TREE_TRACE_READ; break; case 'W': flags |= TREE_TRACE_WRITE; break; case 'U': flags |= TREE_TRACE_UNSET; break; case 'C': flags |= TREE_TRACE_CREATE; break; default: return -1; } } return flags; } /* *---------------------------------------------------------------------- * * SetValues -- * *---------------------------------------------------------------------- */ static int SetValues(TreeCmd *cmdPtr, Blt_TreeNode node, int objc, Tcl_Obj *CONST *objv) { register int i; char *string; for (i = 0; i < objc; i += 2) { string = Tcl_GetString(objv[i]); if ((i + 1) == objc) { Tcl_AppendResult(cmdPtr->interp, "missing value for field \"", string, "\"", (char *)NULL); return TCL_ERROR; } if (Blt_TreeSetValue(cmdPtr->interp, cmdPtr->tree, node, string, objv[i + 1]) != TCL_OK) { return TCL_ERROR; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * UnsetValues -- * *---------------------------------------------------------------------- */ static int UnsetValues(TreeCmd *cmdPtr, Blt_TreeNode node, int objc, Tcl_Obj *CONST *objv) { if (objc == 0) { Blt_TreeKey key; Blt_TreeKeySearch cursor; for (key = Blt_TreeFirstKey(cmdPtr->tree, node, &cursor); key != NULL; key = Blt_TreeNextKey(cmdPtr->tree, &cursor)) { if (Blt_TreeUnsetValueByKey(cmdPtr->interp, cmdPtr->tree, node, key) != TCL_OK) { return TCL_ERROR; } } } else { register int i; for (i = 0; i < objc; i ++) { if (Blt_TreeUnsetValue(cmdPtr->interp, cmdPtr->tree, node, Tcl_GetString(objv[i])) != TCL_OK) { return TCL_ERROR; } } } return TCL_OK; } static int ComparePatternList(Blt_List patternList, char *string, int nocase) { Blt_ListNode node; int result, type; char *pattern; if (nocase) { string = Blt_Strdup(string); strtolower(string); } result = FALSE; for (node = Blt_ListFirstNode(patternList); node != NULL; node = Blt_ListNextNode(node)) { type = (int)Blt_ListGetValue(node); pattern = (char *)Blt_ListGetKey(node); switch (type) { case PATTERN_EXACT: result = (strcmp(string, pattern) == 0); break; case PATTERN_GLOB: result = Tcl_StringMatch(string, pattern); break; case PATTERN_REGEXP: result = Tcl_RegExpMatch((Tcl_Interp *)NULL, string, pattern); break; } } if (nocase) { Blt_Free(string); } return result; } /* *---------------------------------------------------------------------- * * MatchNodeProc -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int MatchNodeProc(Blt_TreeNode node, ClientData clientData, int order) { FindData *dataPtr = clientData; Tcl_DString dString; TreeCmd *cmdPtr = dataPtr->cmdPtr; Tcl_Interp *interp = dataPtr->cmdPtr->interp; int result, invert; if ((dataPtr->flags & MATCH_LEAFONLY) && (!Blt_TreeIsLeaf(node))) { return TCL_OK; } if ((dataPtr->maxDepth >= 0) && (dataPtr->maxDepth < Blt_TreeNodeDepth(cmdPtr->tree, node))) { return TCL_OK; } result = TRUE; Tcl_DStringInit(&dString); if (dataPtr->keyList != NULL) { Blt_TreeKey key; Blt_TreeKeySearch cursor; result = FALSE; /* It's false if no keys match. */ for (key = Blt_TreeFirstKey(cmdPtr->tree, node, &cursor); key != NULL; key = Blt_TreeNextKey(cmdPtr->tree, &cursor)) { result = ComparePatternList(dataPtr->keyList, key, 0); if (!result) { continue; } if (dataPtr->patternList != NULL) { char *string; Tcl_Obj *objPtr; Blt_TreeGetValue(interp, cmdPtr->tree, node, key, &objPtr); string = (objPtr == NULL) ? "" : Tcl_GetString(objPtr); result = ComparePatternList(dataPtr->patternList, string, dataPtr->flags & MATCH_NOCASE); if (!result) { continue; } } break; } } else if (dataPtr->patternList != NULL) { char *string; if (dataPtr->flags & MATCH_PATHNAME) { string = GetNodePath(cmdPtr, Blt_TreeRootNode(cmdPtr->tree), node, FALSE, &dString); } else { string = Blt_TreeNodeLabel(node); } result = ComparePatternList(dataPtr->patternList, string, dataPtr->flags & MATCH_NOCASE); } if ((dataPtr->withTag != NULL) && (!Blt_TreeHasTag(cmdPtr->tree, node, dataPtr->withTag))) { result = FALSE; } Tcl_DStringFree(&dString); invert = (dataPtr->flags & MATCH_INVERT) ? TRUE : FALSE; if (result != invert) { Tcl_Obj *objPtr; if (dataPtr->addTag != NULL) { if (AddTag(cmdPtr, node, dataPtr->addTag) != TCL_OK) { return TCL_ERROR; } } objPtr = Tcl_NewIntObj(Blt_TreeNodeId(node)); Tcl_ListObjAppendElement(interp, dataPtr->listObjPtr, objPtr); if (dataPtr->objv != NULL) { dataPtr->objv[dataPtr->objc - 1] = objPtr; Tcl_IncrRefCount(objPtr); result = Tcl_EvalObjv(interp, dataPtr->objc, dataPtr->objv, 0); Tcl_DecrRefCount(objPtr); dataPtr->objv[dataPtr->objc - 1] = NULL; if (result != TCL_OK) { return result; } } dataPtr->nMatches++; if ((dataPtr->maxMatches > 0) && (dataPtr->nMatches >= dataPtr->maxMatches)) { return TCL_BREAK; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * ApplyNodeProc -- * *---------------------------------------------------------------------- */ static int ApplyNodeProc(Blt_TreeNode node, ClientData clientData, int order) { ApplyData *dataPtr = clientData; TreeCmd *cmdPtr = dataPtr->cmdPtr; Tcl_Interp *interp = cmdPtr->interp; int invert, result; Tcl_DString dString; if ((dataPtr->flags & MATCH_LEAFONLY) && (!Blt_TreeIsLeaf(node))) { return TCL_OK; } if ((dataPtr->maxDepth >= 0) && (dataPtr->maxDepth < Blt_TreeNodeDepth(cmdPtr->tree, node))) { return TCL_OK; } Tcl_DStringInit(&dString); result = TRUE; if (dataPtr->keyList != NULL) { Blt_TreeKey key; Blt_TreeKeySearch cursor; result = FALSE; /* It's false if no keys match. */ for (key = Blt_TreeFirstKey(cmdPtr->tree, node, &cursor); key != NULL; key = Blt_TreeNextKey(cmdPtr->tree, &cursor)) { result = ComparePatternList(dataPtr->keyList, key, 0); if (!result) { continue; } if (dataPtr->patternList != NULL) { char *string; Tcl_Obj *objPtr; Blt_TreeGetValue(interp, cmdPtr->tree, node, key, &objPtr); string = (objPtr == NULL) ? "" : Tcl_GetString(objPtr); result = ComparePatternList(dataPtr->patternList, string, dataPtr->flags & MATCH_NOCASE); if (!result) { continue; } } break; } } else if (dataPtr->patternList != NULL) { char *string; if (dataPtr->flags & MATCH_PATHNAME) { string = GetNodePath(cmdPtr, Blt_TreeRootNode(cmdPtr->tree), node, FALSE, &dString); } else { string = Blt_TreeNodeLabel(node); } result = ComparePatternList(dataPtr->patternList, string, dataPtr->flags & MATCH_NOCASE); } Tcl_DStringFree(&dString); if ((dataPtr->withTag != NULL) && (!Blt_TreeHasTag(cmdPtr->tree, node, dataPtr->withTag))) { result = FALSE; } invert = (dataPtr->flags & MATCH_INVERT) ? 1 : 0; if (result != invert) { Tcl_Obj *objPtr; objPtr = Tcl_NewIntObj(Blt_TreeNodeId(node)); if (order == TREE_PREORDER) { dataPtr->preObjv[dataPtr->preObjc - 1] = objPtr; return Tcl_EvalObjv(interp, dataPtr->preObjc, dataPtr->preObjv, 0); } else if (order == TREE_POSTORDER) { dataPtr->postObjv[dataPtr->postObjc - 1] = objPtr; return Tcl_EvalObjv(interp, dataPtr->postObjc, dataPtr->postObjv,0); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * ReleaseTreeObject -- * *---------------------------------------------------------------------- */ static void ReleaseTreeObject(TreeCmd *cmdPtr) { Blt_HashEntry *hPtr; Blt_HashSearch cursor; TraceInfo *tracePtr; NotifyInfo *notifyPtr; int i; Blt_TreeReleaseToken(cmdPtr->tree); /* * When the tree token is released, all the traces and * notification events are automatically removed. But we still * need to clean up the bookkeeping kept for traces. Clear all * the tags and trace information. */ for (hPtr = Blt_FirstHashEntry(&(cmdPtr->traceTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tracePtr = Blt_GetHashValue(hPtr); Blt_Free(tracePtr); } for (hPtr = Blt_FirstHashEntry(&(cmdPtr->notifyTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { notifyPtr = Blt_GetHashValue(hPtr); for (i = 0; i < notifyPtr->objc - 2; i++) { Tcl_DecrRefCount(notifyPtr->objv[i]); } Blt_Free(notifyPtr->objv); Blt_Free(notifyPtr); } cmdPtr->tree = NULL; } /* *---------------------------------------------------------------------- * * TreeTraceProc -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TreeTraceProc( ClientData clientData, Tcl_Interp *interp, Blt_TreeNode node, /* Node that has just been updated. */ Blt_TreeKey key, /* Field that's updated. */ unsigned int flags) { TraceInfo *tracePtr = clientData; Tcl_DString dsCmd, dsName; char string[5]; char *qualName; int result; Tcl_DStringInit(&dsCmd); Tcl_DStringAppend(&dsCmd, tracePtr->command, -1); Tcl_DStringInit(&dsName); qualName = Blt_GetQualifiedName( Blt_GetCommandNamespace(interp, tracePtr->cmdPtr->cmdToken), Tcl_GetCommandName(interp, tracePtr->cmdPtr->cmdToken), &dsName); Tcl_DStringAppendElement(&dsCmd, qualName); Tcl_DStringFree(&dsName); if (node != NULL) { Tcl_DStringAppendElement(&dsCmd, Blt_Itoa(Blt_TreeNodeId(node))); } else { Tcl_DStringAppendElement(&dsCmd, ""); } Tcl_DStringAppendElement(&dsCmd, key); PrintTraceFlags(flags, string); Tcl_DStringAppendElement(&dsCmd, string); result = Tcl_Eval(interp, Tcl_DStringValue(&dsCmd)); Tcl_DStringFree(&dsCmd); return result; } /* *---------------------------------------------------------------------- * * TreeEventProc -- * *---------------------------------------------------------------------- */ static int TreeEventProc(ClientData clientData, Blt_TreeNotifyEvent *eventPtr) { TreeCmd *cmdPtr = clientData; Blt_HashEntry *hPtr; Blt_HashSearch cursor; NotifyInfo *notifyPtr; Blt_TreeNode node; char *string; switch (eventPtr->type) { case TREE_NOTIFY_CREATE: string = "-create"; break; case TREE_NOTIFY_DELETE: node = Blt_TreeGetNode(cmdPtr->tree, eventPtr->inode); if (node != NULL) { Blt_TreeClearTags(cmdPtr->tree, node); } string = "-delete"; break; case TREE_NOTIFY_MOVE: string = "-move"; break; case TREE_NOTIFY_SORT: string = "-sort"; break; case TREE_NOTIFY_RELABEL: string = "-relabel"; break; default: /* empty */ string = "???"; break; } for (hPtr = Blt_FirstHashEntry(&(cmdPtr->notifyTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { notifyPtr = Blt_GetHashValue(hPtr); if (notifyPtr->mask & eventPtr->type) { int result; Tcl_Obj *flagObjPtr, *nodeObjPtr; flagObjPtr = Tcl_NewStringObj(string, -1); nodeObjPtr = Tcl_NewIntObj(eventPtr->inode); Tcl_IncrRefCount(flagObjPtr); Tcl_IncrRefCount(nodeObjPtr); notifyPtr->objv[notifyPtr->objc - 2] = flagObjPtr; notifyPtr->objv[notifyPtr->objc - 1] = nodeObjPtr; result = Tcl_EvalObjv(cmdPtr->interp, notifyPtr->objc, notifyPtr->objv, 0); Tcl_DecrRefCount(nodeObjPtr); Tcl_DecrRefCount(flagObjPtr); if (result != TCL_OK) { Tcl_BackgroundError(cmdPtr->interp); return TCL_ERROR; } Tcl_ResetResult(cmdPtr->interp); } } return TCL_OK; } /* Tree command operations. */ /* *---------------------------------------------------------------------- * * ApplyOp -- * * t0 apply root -precommand {command} -postcommand {command} * *---------------------------------------------------------------------- */ static int ApplyOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { int result; Blt_TreeNode node; int i; Tcl_Obj **objArr; int count; ApplyData data; int order; if (GetNode(cmdPtr, objv[2], &node) != TCL_OK) { return TCL_ERROR; } memset(&data, 0, sizeof(data)); data.maxDepth = -1; data.cmdPtr = cmdPtr; /* Process switches */ if (Blt_ProcessObjSwitches(interp, applySwitches, objc - 3, objv + 3, (char *)&data, 0) < 0) { return TCL_ERROR; } order = 0; if (data.flags & MATCH_NOCASE) { Blt_ListNode listNode; for (listNode = Blt_ListFirstNode(data.patternList); listNode != NULL; listNode = Blt_ListNextNode(listNode)) { strtolower((char *)Blt_ListGetKey(listNode)); } } if (data.preCmd != NULL) { char **p; count = 0; for (p = data.preCmd; *p != NULL; p++) { count++; } objArr = Blt_Malloc((count + 1) * sizeof(Tcl_Obj *)); for (i = 0; i < count; i++) { objArr[i] = Tcl_NewStringObj(data.preCmd[i], -1); Tcl_IncrRefCount(objArr[i]); } data.preObjv = objArr; data.preObjc = count + 1; order |= TREE_PREORDER; } if (data.postCmd != NULL) { char **p; count = 0; for (p = data.postCmd; *p != NULL; p++) { count++; } objArr = Blt_Malloc((count + 1) * sizeof(Tcl_Obj *)); for (i = 0; i < count; i++) { objArr[i] = Tcl_NewStringObj(data.postCmd[i], -1); Tcl_IncrRefCount(objArr[i]); } data.postObjv = objArr; data.postObjc = count + 1; order |= TREE_POSTORDER; } result = Blt_TreeApplyDFS(node, ApplyNodeProc, &data, order); if (data.preObjv != NULL) { for (i = 0; i < (data.preObjc - 1); i++) { Tcl_DecrRefCount(data.preObjv[i]); } Blt_Free(data.preObjv); } if (data.postObjv != NULL) { for (i = 0; i < (data.postObjc - 1); i++) { Tcl_DecrRefCount(data.postObjv[i]); } Blt_Free(data.postObjv); } Blt_FreeSwitches(applySwitches, (char *)&data, 0); if (result == TCL_ERROR) { return TCL_ERROR; } return TCL_OK; } /*ARGSUSED*/ static int AncestorOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { int d1, d2, minDepth; register int i; Blt_TreeNode ancestor, node1, node2; if ((GetNode(cmdPtr, objv[2], &node1) != TCL_OK) || (GetNode(cmdPtr, objv[3], &node2) != TCL_OK)) { return TCL_ERROR; } if (node1 == node2) { ancestor = node1; goto done; } d1 = Blt_TreeNodeDepth(cmdPtr->tree, node1); d2 = Blt_TreeNodeDepth(cmdPtr->tree, node2); minDepth = MIN(d1, d2); if (minDepth == 0) { /* One of the nodes is root. */ ancestor = Blt_TreeRootNode(cmdPtr->tree); goto done; } /* * Traverse back from the deepest node, until the both nodes are * at the same depth. Check if the ancestor node found is the * other node. */ for (i = d1; i > minDepth; i--) { node1 = Blt_TreeNodeParent(node1); } if (node1 == node2) { ancestor = node2; goto done; } for (i = d2; i > minDepth; i--) { node2 = Blt_TreeNodeParent(node2); } if (node2 == node1) { ancestor = node1; goto done; } /* * First find the mutual ancestor of both nodes. Look at each * preceding ancestor level-by-level for both nodes. Eventually * we'll find a node that's the parent of both ancestors. Then * find the first ancestor in the parent's list of subnodes. */ for (i = minDepth; i > 0; i--) { node1 = Blt_TreeNodeParent(node1); node2 = Blt_TreeNodeParent(node2); if (node1 == node2) { ancestor = node2; goto done; } } Tcl_AppendResult(interp, "unknown ancestor", (char *)NULL); return TCL_ERROR; done: Tcl_SetIntObj(Tcl_GetObjResult(interp), Blt_TreeNodeId(ancestor)); return TCL_OK; } /* *---------------------------------------------------------------------- * * AttachOp -- * *---------------------------------------------------------------------- */ static int AttachOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { if (objc == 3) { CONST char *treeName; CONST char *name; Blt_Tree token; Tcl_Namespace *nsPtr; Tcl_DString dString; int result; treeName = Tcl_GetString(objv[2]); if (Blt_ParseQualifiedName(interp, treeName, &nsPtr, &name) != TCL_OK) { Tcl_AppendResult(interp, "can't find namespace in \"", treeName, "\"", (char *)NULL); return TCL_ERROR; } if (nsPtr == NULL) { nsPtr = Tcl_GetCurrentNamespace(interp); } treeName = Blt_GetQualifiedName(nsPtr, name, &dString); result = Blt_TreeGetToken(interp, treeName, &token); Tcl_DStringFree(&dString); if (result != TCL_OK) { return TCL_ERROR; } ReleaseTreeObject(cmdPtr); cmdPtr->tree = token; } Tcl_SetResult(interp, Blt_TreeName(cmdPtr->tree), TCL_VOLATILE); return TCL_OK; } /* *---------------------------------------------------------------------- * * ChildrenOp -- * *---------------------------------------------------------------------- */ static int ChildrenOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_TreeNode node; if (GetNode(cmdPtr, objv[2], &node) != TCL_OK) { return TCL_ERROR; } if (objc == 3) { Tcl_Obj *objPtr, *listObjPtr; listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); for (node = Blt_TreeFirstChild(node); node != NULL; node = Blt_TreeNextSibling(node)) { objPtr = Tcl_NewIntObj(Blt_TreeNodeId(node)); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } Tcl_SetObjResult(interp, listObjPtr); } else if (objc == 4) { int childPos; int inode, count; /* Get the node at */ if (Tcl_GetIntFromObj(interp, objv[3], &childPos) != TCL_OK) { return TCL_ERROR; } count = 0; inode = -1; for (node = Blt_TreeFirstChild(node); node != NULL; node = Blt_TreeNextSibling(node)) { if (count == childPos) { inode = Blt_TreeNodeId(node); break; } count++; } Tcl_SetIntObj(Tcl_GetObjResult(interp), inode); return TCL_OK; } else if (objc == 5) { int firstPos, lastPos, count; Tcl_Obj *objPtr, *listObjPtr; char *string; firstPos = lastPos = Blt_TreeNodeDegree(node) - 1; string = Tcl_GetString(objv[3]); if ((strcmp(string, "end") != 0) && (Tcl_GetIntFromObj(interp, objv[3], &firstPos) != TCL_OK)) { return TCL_ERROR; } string = Tcl_GetString(objv[4]); if ((strcmp(string, "end") != 0) && (Tcl_GetIntFromObj(interp, objv[4], &lastPos) != TCL_OK)) { return TCL_ERROR; } count = 0; listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); for (node = Blt_TreeFirstChild(node); node != NULL; node = Blt_TreeNextSibling(node)) { if ((count >= firstPos) && (count <= lastPos)) { objPtr = Tcl_NewIntObj(Blt_TreeNodeId(node)); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } count++; } Tcl_SetObjResult(interp, listObjPtr); } return TCL_OK; } static Blt_TreeNode CopyNodes( CopyData *dataPtr, Blt_TreeNode node, /* Node to be copied. */ Blt_TreeNode parent) /* New parent for the copied node. */ { Blt_TreeNode newNode; /* Newly created copy. */ char *label; newNode = NULL; label = Blt_TreeNodeLabel(node); if (dataPtr->flags & COPY_OVERWRITE) { newNode = Blt_TreeFindChild(parent, label); } if (newNode == NULL) { /* Create node in new parent. */ newNode = Blt_TreeCreateNode(dataPtr->destTree, parent, label, -1); } /* Copy the data fields. */ { Blt_TreeKey key; Tcl_Obj *objPtr; Blt_TreeKeySearch cursor; for (key = Blt_TreeFirstKey(dataPtr->srcTree, node, &cursor); key != NULL; key = Blt_TreeNextKey(dataPtr->srcTree, &cursor)) { if (Blt_TreeGetValueByKey((Tcl_Interp *)NULL, dataPtr->srcTree, node, key, &objPtr) == TCL_OK) { Blt_TreeSetValueByKey((Tcl_Interp *)NULL, dataPtr->destTree, newNode, key, objPtr); } } } /* Add tags to destination tree command. */ if ((dataPtr->destPtr != NULL) && (dataPtr->flags & COPY_TAGS)) { Blt_TreeTagEntry *tPtr; Blt_HashEntry *hPtr, *h2Ptr; Blt_HashSearch cursor; for (hPtr = Blt_TreeFirstTag(dataPtr->srcPtr->tree, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tPtr = Blt_GetHashValue(hPtr); h2Ptr = Blt_FindHashEntry(&tPtr->nodeTable, (char *)node); if (h2Ptr != NULL) { if (AddTag(dataPtr->destPtr, newNode, tPtr->tagName)!= TCL_OK) { return NULL; } } } } if (dataPtr->flags & COPY_RECURSE) { Blt_TreeNode child; for (child = Blt_TreeFirstChild(node); child != NULL; child = Blt_TreeNextSibling(child)) { if (CopyNodes(dataPtr, child, newNode) == NULL) { return NULL; } } } return newNode; } /* *---------------------------------------------------------------------- * * CopyOp -- * * t0 copy node tree node * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int CopyOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { TreeCmd *srcPtr, *destPtr; Blt_Tree srcTree, destTree; Blt_TreeNode srcNode, destNode; CopyData data; int nArgs, nSwitches; char *string; Blt_TreeNode root; register int i; if (GetNode(cmdPtr, objv[2], &srcNode) != TCL_OK) { return TCL_ERROR; } srcTree = cmdPtr->tree; srcPtr = cmdPtr; /* Find the first switch. */ for(i = 3; i < objc; i++) { string = Tcl_GetString(objv[i]); if (string[0] == '-') { break; } } nArgs = i - 2; nSwitches = objc - i; if (nArgs < 2) { string = Tcl_GetString(objv[0]); Tcl_AppendResult(interp, "must specify source and destination nodes: ", "should be \"", string, " copy srcNode ?destTree? destNode ?switches?", (char *)NULL); return TCL_ERROR; } if (nArgs == 3) { /* * The tree name is either the name of a tree command (first choice) * or an internal tree object. */ string = Tcl_GetString(objv[3]); destPtr = GetTreeCmd(cmdPtr->dataPtr, interp, string); if (destPtr != NULL) { destTree = destPtr->tree; } else { /* Try to get the tree as an internal tree data object. */ if (Blt_TreeGetToken(interp, string, &destTree) != TCL_OK) { return TCL_ERROR; } } objv++; } else { destPtr = cmdPtr; destTree = destPtr->tree; } root = NULL; if (destPtr == NULL) { if (GetForeignNode(interp, destTree, objv[3], &destNode) != TCL_OK) { goto error; } } else { if (GetNode(destPtr, objv[3], &destNode) != TCL_OK) { goto error; } } if (srcNode == destNode) { Tcl_AppendResult(interp, "source and destination nodes are the same", (char *)NULL); goto error; } memset((char *)&data, 0, sizeof(data)); /* Process switches */ if (Blt_ProcessObjSwitches(interp, copySwitches, nSwitches, objv + 4, (char *)&data, 0) < 0) { goto error; } data.destPtr = destPtr; data.destTree = destTree; data.srcPtr = srcPtr; data.srcTree = srcTree; if ((srcTree == destTree) && (data.flags & COPY_RECURSE) && (Blt_TreeIsAncestor(srcNode, destNode))) { Tcl_AppendResult(interp, "can't make cyclic copy: ", "source node is an ancestor of the destination", (char *)NULL); goto error; } /* Copy nodes to destination. */ root = CopyNodes(&data, srcNode, destNode); if (root != NULL) { Tcl_Obj *objPtr; objPtr = Tcl_NewIntObj(Blt_TreeNodeId(root)); if (data.label != NULL) { Blt_TreeRelabelNode(data.destTree, root, data.label); } Tcl_SetObjResult(interp, objPtr); } error: if (destPtr == NULL) { Blt_TreeReleaseToken(destTree); } return (root == NULL) ? TCL_ERROR : TCL_OK; } /* *---------------------------------------------------------------------- * * DepthOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int DegreeOp(cmdPtr, interp, objc, objv) TreeCmd *cmdPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { Blt_TreeNode node; int degree; if (GetNode(cmdPtr, objv[2], &node) != TCL_OK) { return TCL_ERROR; } degree = Blt_TreeNodeDegree(node); Tcl_SetIntObj(Tcl_GetObjResult(interp), degree); return TCL_OK; } /* *---------------------------------------------------------------------- * * DeleteOp -- * * Deletes one or more nodes from the tree. Nodes may be * specified by their id (a number) or a tag. * * Tags have to be handled carefully here. We can't use the * normal GetTaggedNode, NextTaggedNode, etc. routines because * they walk hashtables while we're deleting nodes. Also, * remember that deleting a node recursively deletes all its * children. If a parent and its children have the same tag, its * possible that the tag list may contain nodes than no longer * exist. So save the node indices in a list and then delete * then in a second pass. * *---------------------------------------------------------------------- */ static int DeleteOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_TreeNode node; int i; char *string; for (i = 2; i < objc; i++) { string = Tcl_GetString(objv[i]); if (isdigit(UCHAR(string[0]))) { if (GetNode(cmdPtr, objv[i], &node) != TCL_OK) { return TCL_ERROR; } DeleteNode(cmdPtr, node); } else { Blt_HashEntry *hPtr; Blt_HashTable *tablePtr; Blt_HashSearch cursor; Blt_Chain *chainPtr; Blt_ChainLink *linkPtr, *nextPtr; int inode; if ((strcmp(string, "all") == 0) || (strcmp(string, "root") == 0)) { node = Blt_TreeRootNode(cmdPtr->tree); DeleteNode(cmdPtr, node); continue; } tablePtr = Blt_TreeTagHashTable(cmdPtr->tree, string); if (tablePtr == NULL) { goto error; } /* * Generate a list of tagged nodes. Save the inode instead * of the node itself since a pruned branch may contain * more tagged nodes. */ chainPtr = Blt_ChainCreate(); for (hPtr = Blt_FirstHashEntry(tablePtr, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { node = Blt_GetHashValue(hPtr); Blt_ChainAppend(chainPtr, (ClientData)Blt_TreeNodeId(node)); } /* * Iterate through this list to delete the nodes. By * side-effect the tag table is deleted and Uids are * released. */ for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr != NULL; linkPtr = nextPtr) { nextPtr = Blt_ChainNextLink(linkPtr); inode = (int)Blt_ChainGetValue(linkPtr); node = Blt_TreeGetNode(cmdPtr->tree, inode); if (node != NULL) { DeleteNode(cmdPtr, node); } } Blt_ChainDestroy(chainPtr); } } return TCL_OK; error: Tcl_AppendResult(interp, "can't find tag or id \"", string, "\" in ", Blt_TreeName(cmdPtr->tree), (char *)NULL); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * DepthOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int DepthOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { Blt_TreeNode node; int depth; if (GetNode(cmdPtr, objv[2], &node) != TCL_OK) { return TCL_ERROR; } depth = Blt_TreeNodeDepth(cmdPtr->tree, node); Tcl_SetIntObj(Tcl_GetObjResult(interp), depth); return TCL_OK; } /* *---------------------------------------------------------------------- * * DumpOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int DumpOp(cmdPtr, interp, objc, objv) TreeCmd *cmdPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { Blt_TreeNode top; Tcl_DString dString; register Blt_TreeNode node; if (GetNode(cmdPtr, objv[2], &top) != TCL_OK) { return TCL_ERROR; } Tcl_DStringInit(&dString); for (node = top; node != NULL; node = Blt_TreeNextNode(top, node)) { PrintNode(cmdPtr, top, node, &dString); } Tcl_DStringResult(interp, &dString); return TCL_OK; } /* *---------------------------------------------------------------------- * * DumpfileOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int DumpfileOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { Blt_TreeNode top; Tcl_Channel channel; Tcl_DString dString; char *fileName; int result; register Blt_TreeNode node; if (GetNode(cmdPtr, objv[2], &top) != TCL_OK) { return TCL_ERROR; } fileName = Tcl_GetString(objv[3]); channel = Tcl_OpenFileChannel(interp, fileName, "w", 0666); if (channel == NULL) { return TCL_ERROR; } Tcl_DStringInit(&dString); for (node = top; node != NULL; node = Blt_TreeNextNode(top, node)) { PrintNode(cmdPtr, top, node, &dString); } result = Tcl_Write(channel, Tcl_DStringValue(&dString), -1); Tcl_Close(interp, channel); Tcl_DStringFree(&dString); if (result <= 0) { return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * ExistsOp -- * *---------------------------------------------------------------------- */ static int ExistsOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_TreeNode node; int bool; bool = TRUE; if (GetNode(cmdPtr, objv[2], &node) != TCL_OK) { bool = FALSE; } else if (objc == 4) { Tcl_Obj *valueObjPtr; char *string; string = Tcl_GetString(objv[3]); if (Blt_TreeGetValue((Tcl_Interp *)NULL, cmdPtr->tree, node, string, &valueObjPtr) != TCL_OK) { bool = FALSE; } } Tcl_SetObjResult(interp, Tcl_NewBooleanObj(bool)); return TCL_OK; } /* *---------------------------------------------------------------------- * * FindOp -- * *---------------------------------------------------------------------- */ static int FindOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_TreeNode node; FindData data; int result; Tcl_Obj **objArr; if (GetNode(cmdPtr, objv[2], &node) != TCL_OK) { return TCL_ERROR; } memset(&data, 0, sizeof(data)); data.maxDepth = -1; data.order = TREE_POSTORDER; objArr = NULL; /* Process switches */ if (Blt_ProcessObjSwitches(interp, findSwitches, objc - 3, objv + 3, (char *)&data, 0) < 0) { return TCL_ERROR; } if (data.maxDepth >= 0) { data.maxDepth += Blt_TreeNodeDepth(cmdPtr->tree, node); } if (data.flags & MATCH_NOCASE) { Blt_ListNode listNode; for (listNode = Blt_ListFirstNode(data.patternList); listNode != NULL; listNode = Blt_ListNextNode(listNode)) { strtolower((char *)Blt_ListGetKey(listNode)); } } if (data.command != NULL) { int count; char **p; register int i; count = 0; for (p = data.command; *p != NULL; p++) { count++; } /* Leave room for node Id argument to be appended */ objArr = Blt_Calloc(count + 2, sizeof(Tcl_Obj *)); for (i = 0; i < count; i++) { objArr[i] = Tcl_NewStringObj(data.command[i], -1); Tcl_IncrRefCount(objArr[i]); } data.objv = objArr; data.objc = count + 1; } data.listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); data.cmdPtr = cmdPtr; if (data.order == TREE_BREADTHFIRST) { result = Blt_TreeApplyBFS(node, MatchNodeProc, &data); } else { result = Blt_TreeApplyDFS(node, MatchNodeProc, &data, data.order); } if (data.command != NULL) { Tcl_Obj **objPtrPtr; for (objPtrPtr = objArr; *objPtrPtr != NULL; objPtrPtr++) { Tcl_DecrRefCount(*objPtrPtr); } Blt_Free(objArr); } Blt_FreeSwitches(findSwitches, (char *)&data, 0); if (result == TCL_ERROR) { return TCL_ERROR; } Tcl_SetObjResult(interp, data.listObjPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * FindChildOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int FindChildOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { Blt_TreeNode node, child; int inode; if (GetNode(cmdPtr, objv[2], &node) != TCL_OK) { return TCL_ERROR; } inode = -1; child = Blt_TreeFindChild(node, Tcl_GetString(objv[3])); if (child != NULL) { inode = Blt_TreeNodeId(child); } Tcl_SetIntObj(Tcl_GetObjResult(interp), inode); return TCL_OK; } /* *---------------------------------------------------------------------- * * FirstChildOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int FirstChildOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { Blt_TreeNode node; int inode; if (GetNode(cmdPtr, objv[2], &node) != TCL_OK) { return TCL_ERROR; } inode = -1; node = Blt_TreeFirstChild(node); if (node != NULL) { inode = Blt_TreeNodeId(node); } Tcl_SetIntObj(Tcl_GetObjResult(interp), inode); return TCL_OK; } /* *---------------------------------------------------------------------- * * GetOp -- * *---------------------------------------------------------------------- */ static int GetOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_TreeNode node; if (GetNode(cmdPtr, objv[2], &node) != TCL_OK) { return TCL_ERROR; } if (objc == 3) { Blt_TreeKey key; Tcl_Obj *valueObjPtr, *listObjPtr; Blt_TreeKeySearch cursor; /* Add the key-value pairs to a new Tcl_Obj */ listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); for (key = Blt_TreeFirstKey(cmdPtr->tree, node, &cursor); key != NULL; key = Blt_TreeNextKey(cmdPtr->tree, &cursor)) { if (Blt_TreeGetValue((Tcl_Interp *)NULL, cmdPtr->tree, node, key, &valueObjPtr) == TCL_OK) { Tcl_Obj *objPtr; objPtr = Tcl_NewStringObj(key, -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); Tcl_ListObjAppendElement(interp, listObjPtr, valueObjPtr); } } Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; } else { Tcl_Obj *valueObjPtr; char *string; string = Tcl_GetString(objv[3]); if (Blt_TreeGetValue((Tcl_Interp *)NULL, cmdPtr->tree, node, string, &valueObjPtr) != TCL_OK) { if (objc == 4) { Tcl_DString dString; char *path; path = GetNodePath(cmdPtr, Blt_TreeRootNode(cmdPtr->tree), node, FALSE, &dString); Tcl_AppendResult(interp, "can't find field \"", string, "\" in \"", path, "\"", (char *)NULL); Tcl_DStringFree(&dString); return TCL_ERROR; } /* Default to given value */ valueObjPtr = objv[4]; } Tcl_SetObjResult(interp, valueObjPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * IndexOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int IndexOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { Blt_TreeNode node; int inode; inode = -1; if (GetNode(cmdPtr, objv[2], &node) == TCL_OK) { inode = Blt_TreeNodeId(node); } else { register int i; int nObjs; Tcl_Obj **objArr; Blt_TreeNode parent; char *string; if (Tcl_ListObjGetElements(interp, objv[2], &nObjs, &objArr) != TCL_OK) { goto done; /* Can't split object. */ } parent = Blt_TreeRootNode(cmdPtr->tree); for (i = 0; i < nObjs; i++) { string = Tcl_GetString(objArr[i]); if (string[0] == '\0') { continue; } node = Blt_TreeFindChild(parent, string); if (node == NULL) { goto done; /* Can't find component */ } parent = node; } inode = Blt_TreeNodeId(node); } done: Tcl_SetIntObj(Tcl_GetObjResult(interp), inode); return TCL_OK; } /* *---------------------------------------------------------------------- * * InsertOp -- * *---------------------------------------------------------------------- */ static int InsertOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_TreeNode parent, child; InsertData data; child = NULL; if (GetNode(cmdPtr, objv[2], &parent) != TCL_OK) { return TCL_ERROR; } /* Initialize switch flags */ memset(&data, 0, sizeof(data)); data.insertPos = -1; /* Default to append node. */ data.parent = parent; data.inode = -1; if (Blt_ProcessObjSwitches(interp, insertSwitches, objc - 3, objv + 3, (char *)&data, 0) < 0) { goto error; } if (data.inode > 0) { Blt_TreeNode node; node = Blt_TreeGetNode(cmdPtr->tree, data.inode); if (node != NULL) { Tcl_AppendResult(interp, "can't reissue node id \"", Blt_Itoa(data.inode), "\": already exists.", (char *)NULL); goto error; } child = Blt_TreeCreateNodeWithId(cmdPtr->tree, parent, data.label, data.inode, data.insertPos); } else { child = Blt_TreeCreateNode(cmdPtr->tree, parent, data.label, data.insertPos); } if (child == NULL) { Tcl_AppendResult(interp, "can't allocate new node", (char *)NULL); goto error; } if (data.label == NULL) { char string[200]; sprintf(string, "node%d", Blt_TreeNodeId(child)); Blt_TreeRelabelNode2(child, string); } if (data.tags != NULL) { register char **p; for (p = data.tags; *p != NULL; p++) { if (AddTag(cmdPtr, child, *p) != TCL_OK) { goto error; } } } if (data.dataPairs != NULL) { register char **p; char *key; Tcl_Obj *objPtr; for (p = data.dataPairs; *p != NULL; p++) { key = *p; p++; if (*p == NULL) { Tcl_AppendResult(interp, "missing value for \"", key, "\"", (char *)NULL); goto error; } objPtr = Tcl_NewStringObj(*p, -1); if (Blt_TreeSetValue(interp, cmdPtr->tree, child, key, objPtr) != TCL_OK) { Tcl_DecrRefCount(objPtr); goto error; } } } Tcl_SetIntObj(Tcl_GetObjResult(interp), Blt_TreeNodeId(child)); Blt_FreeSwitches(insertSwitches, (char *)&data, 0); return TCL_OK; error: if (child != NULL) { Blt_TreeDeleteNode(cmdPtr->tree, child); } Blt_FreeSwitches(insertSwitches, (char *)&data, 0); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * IsAncestorOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int IsAncestorOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { Blt_TreeNode node1, node2; int bool; if ((GetNode(cmdPtr, objv[3], &node1) != TCL_OK) || (GetNode(cmdPtr, objv[4], &node2) != TCL_OK)) { return TCL_ERROR; } bool = Blt_TreeIsAncestor(node1, node2); Tcl_SetIntObj(Tcl_GetObjResult(interp), bool); return TCL_OK; } /* *---------------------------------------------------------------------- * * IsBeforeOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int IsBeforeOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { Blt_TreeNode node1, node2; int bool; if ((GetNode(cmdPtr, objv[3], &node1) != TCL_OK) || (GetNode(cmdPtr, objv[4], &node2) != TCL_OK)) { return TCL_ERROR; } bool = Blt_TreeIsBefore(node1, node2); Tcl_SetIntObj(Tcl_GetObjResult(interp), bool); return TCL_OK; } /* *---------------------------------------------------------------------- * * IsLeafOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int IsLeafOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { Blt_TreeNode node; if (GetNode(cmdPtr, objv[3], &node) != TCL_OK) { return TCL_ERROR; } Tcl_SetIntObj(Tcl_GetObjResult(interp), Blt_TreeIsLeaf(node)); return TCL_OK; } /* *---------------------------------------------------------------------- * * IsRootOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int IsRootOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { Blt_TreeNode node; int bool; if (GetNode(cmdPtr, objv[3], &node) != TCL_OK) { return TCL_ERROR; } bool = (node == Blt_TreeRootNode(cmdPtr->tree)); Tcl_SetIntObj(Tcl_GetObjResult(interp), bool); return TCL_OK; } /* *---------------------------------------------------------------------- * * IsOp -- * *---------------------------------------------------------------------- */ static Blt_OpSpec isOps[] = { {"ancestor", 1, (Blt_Op)IsAncestorOp, 5, 5, "node1 node2",}, {"before", 1, (Blt_Op)IsBeforeOp, 5, 5, "node1 node2",}, {"leaf", 1, (Blt_Op)IsLeafOp, 4, 4, "node",}, {"root", 1, (Blt_Op)IsRootOp, 4, 4, "node",}, }; static int nIsOps = sizeof(isOps) / sizeof(Blt_OpSpec); static int IsOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_Op proc; int result; proc = Blt_GetOpFromObj(interp, nIsOps, isOps, BLT_OP_ARG2, objc, objv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (cmdPtr, interp, objc, objv); return result; } /* *---------------------------------------------------------------------- * * KeysOp -- * * Returns the key names of values for a node or array value. * *---------------------------------------------------------------------- */ static int KeysOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_HashEntry *hPtr; Blt_HashSearch tagSearch; Blt_HashTable keyTable; Blt_TreeKey key; Blt_TreeKeySearch keyIter; Blt_TreeNode node; TagSearch tagIter; Tcl_Obj *listObjPtr, *objPtr; register int i; int isNew; Blt_InitHashTableWithPool(&keyTable, BLT_ONE_WORD_KEYS); for (i = 2; i < objc; i++) { node = FirstTaggedNode(interp, cmdPtr, objv[i], &tagIter); if (node == NULL) { return TCL_ERROR; } for (/* empty */; node != NULL; node = NextTaggedNode(node, &tagIter)) { for (key = Blt_TreeFirstKey(cmdPtr->tree, node, &keyIter); key != NULL; key = Blt_TreeNextKey(cmdPtr->tree, &keyIter)) { Blt_CreateHashEntry(&keyTable, key, &isNew); } } } listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); for (hPtr = Blt_FirstHashEntry(&keyTable, &tagSearch); hPtr != NULL; hPtr = Blt_NextHashEntry(&tagSearch)) { objPtr = Tcl_NewStringObj(Blt_GetHashKey(&keyTable, hPtr), -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } Tcl_SetObjResult(interp, listObjPtr); Blt_DeleteHashTable(&keyTable); return TCL_OK; } /* *---------------------------------------------------------------------- * * LabelOp -- * *---------------------------------------------------------------------- */ static int LabelOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_TreeNode node; if (GetNode(cmdPtr, objv[2], &node) != TCL_OK) { return TCL_ERROR; } if (objc == 4) { Blt_TreeRelabelNode(cmdPtr->tree, node, Tcl_GetString(objv[3])); } Tcl_SetStringObj(Tcl_GetObjResult(interp), Blt_TreeNodeLabel(node), -1); return TCL_OK; } /* *---------------------------------------------------------------------- * * LastChildOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int LastChildOp(cmdPtr, interp, objc, objv) TreeCmd *cmdPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { Blt_TreeNode node; int inode; if (GetNode(cmdPtr, objv[2], &node) != TCL_OK) { return TCL_ERROR; } inode = -1; node = Blt_TreeLastChild(node); if (node != NULL) { inode = Blt_TreeNodeId(node); } Tcl_SetIntObj(Tcl_GetObjResult(interp), inode); return TCL_OK; } /* *---------------------------------------------------------------------- * * MoveOp -- * * The big trick here is to not consider the node to be moved in * determining it's new location. Ideally, you would temporarily * pull from the tree and replace it (back in its old location if * something went wrong), but you could still pick the node by * its serial number. So here we make lots of checks for the * node to be moved. * * *---------------------------------------------------------------------- */ static int MoveOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_TreeNode root, parent, node; Blt_TreeNode before; MoveData data; if (GetNode(cmdPtr, objv[2], &node) != TCL_OK) { return TCL_ERROR; } if (GetNode(cmdPtr, objv[3], &parent) != TCL_OK) { return TCL_ERROR; } root = Blt_TreeRootNode(cmdPtr->tree); if (node == root) { Tcl_AppendResult(interp, "can't move root node", (char *)NULL); return TCL_ERROR; } if (parent == node) { Tcl_AppendResult(interp, "can't move node to self", (char *)NULL); return TCL_ERROR; } data.node = NULL; data.cmdPtr = cmdPtr; data.movePos = -1; /* Process switches */ if (Blt_ProcessObjSwitches(interp, moveSwitches, objc - 4, objv + 4, (char *)&data, 0) < 0) { return TCL_ERROR; } /* Verify they aren't ancestors. */ if (Blt_TreeIsAncestor(node, parent)) { Tcl_AppendResult(interp, "can't move node: \"", Tcl_GetString(objv[2]), (char *)NULL); Tcl_AppendResult(interp, "\" is an ancestor of \"", Tcl_GetString(objv[3]), "\"", (char *)NULL); return TCL_ERROR; } before = NULL; /* If before is NULL, this appends the * node to the parent's child list. */ if (data.node != NULL) { /* -before or -after */ if (Blt_TreeNodeParent(data.node) != parent) { Tcl_AppendResult(interp, Tcl_GetString(objv[2]), " isn't the parent of ", Blt_TreeNodeLabel(data.node), (char *)NULL); return TCL_ERROR; } if (Blt_SwitchChanged(moveSwitches, "-before", (char *)NULL)) { before = data.node; if (before == node) { Tcl_AppendResult(interp, "can't move node before itself", (char *)NULL); return TCL_ERROR; } } else { before = Blt_TreeNextSibling(data.node); if (before == node) { Tcl_AppendResult(interp, "can't move node after itself", (char *)NULL); return TCL_ERROR; } } } else if (data.movePos >= 0) { /* -at */ int count; /* Tracks the current list index. */ Blt_TreeNode child; /* * If the node is in the list, ignore it when determining the * "before" node using the -at index. An index of -1 means to * append the node to the list. */ count = 0; for(child = Blt_TreeFirstChild(parent); child != NULL; child = Blt_TreeNextSibling(child)) { if (child == node) { continue; /* Ignore the node to be moved. */ } if (count == data.movePos) { before = child; break; } count++; } } if (Blt_TreeMoveNode(cmdPtr->tree, node, parent, before) != TCL_OK) { Tcl_AppendResult(interp, "can't move node ", Tcl_GetString(objv[2]), " to ", Tcl_GetString(objv[3]), (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * NextOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int NextOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { Blt_TreeNode node; int inode; if (GetNode(cmdPtr, objv[2], &node) != TCL_OK) { return TCL_ERROR; } inode = -1; node = Blt_TreeNextNode(Blt_TreeRootNode(cmdPtr->tree), node); if (node != NULL) { inode = Blt_TreeNodeId(node); } Tcl_SetIntObj(Tcl_GetObjResult(interp), inode); return TCL_OK; } /* *---------------------------------------------------------------------- * * NextSiblingOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int NextSiblingOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { Blt_TreeNode node; int inode; if (GetNode(cmdPtr, objv[2], &node) != TCL_OK) { return TCL_ERROR; } inode = -1; node = Blt_TreeNextSibling(node); if (node != NULL) { inode = Blt_TreeNodeId(node); } Tcl_SetIntObj(Tcl_GetObjResult(interp), inode); return TCL_OK; } /* *---------------------------------------------------------------------- * * NotifyCreateOp -- * * tree0 notify create ?flags? command arg *---------------------------------------------------------------------- */ static int NotifyCreateOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { NotifyInfo *notifyPtr; NotifyData data; char *string; char idString[200]; int isNew, nArgs; Blt_HashEntry *hPtr; int count; register int i; count = 0; for (i = 3; i < objc; i++) { string = Tcl_GetString(objv[i]); if (string[0] != '-') { break; } count++; } data.mask = 0; /* Process switches */ if (Blt_ProcessObjSwitches(interp, notifySwitches, count, objv + 3, (char *)&data, 0) < 0) { return TCL_ERROR; } notifyPtr = Blt_Malloc(sizeof(NotifyInfo)); nArgs = objc - i; /* Stash away the command in structure and pass that to the notifier. */ notifyPtr->objv = Blt_Malloc((nArgs + 2) * sizeof(Tcl_Obj *)); for (count = 0; i < objc; i++, count++) { Tcl_IncrRefCount(objv[i]); notifyPtr->objv[count] = objv[i]; } notifyPtr->objc = nArgs + 2; notifyPtr->cmdPtr = cmdPtr; if (data.mask == 0) { data.mask = TREE_NOTIFY_ALL; } notifyPtr->mask = data.mask; sprintf(idString, "notify%d", cmdPtr->notifyCounter++); hPtr = Blt_CreateHashEntry(&(cmdPtr->notifyTable), idString, &isNew); Blt_SetHashValue(hPtr, notifyPtr); Tcl_SetStringObj(Tcl_GetObjResult(interp), idString, -1); return TCL_OK; } /* *---------------------------------------------------------------------- * * NotifyDeleteOp -- * *---------------------------------------------------------------------- */ static int NotifyDeleteOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { NotifyInfo *notifyPtr; Blt_HashEntry *hPtr; register int i, j; char *string; for (i = 3; i < objc; i++) { string = Tcl_GetString(objv[i]); hPtr = Blt_FindHashEntry(&(cmdPtr->notifyTable), string); if (hPtr == NULL) { Tcl_AppendResult(interp, "unknown notify name \"", string, "\"", (char *)NULL); return TCL_ERROR; } notifyPtr = Blt_GetHashValue(hPtr); Blt_DeleteHashEntry(&(cmdPtr->notifyTable), hPtr); for (j = 0; j < (notifyPtr->objc - 2); j++) { Tcl_DecrRefCount(notifyPtr->objv[j]); } Blt_Free(notifyPtr->objv); Blt_Free(notifyPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * NotifyInfoOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int NotifyInfoOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { NotifyInfo *notifyPtr; Blt_HashEntry *hPtr; Tcl_DString dString; char *string; int i; string = Tcl_GetString(objv[3]); hPtr = Blt_FindHashEntry(&(cmdPtr->notifyTable), string); if (hPtr == NULL) { Tcl_AppendResult(interp, "unknown notify name \"", string, "\"", (char *)NULL); return TCL_ERROR; } notifyPtr = Blt_GetHashValue(hPtr); Tcl_DStringInit(&dString); Tcl_DStringAppendElement(&dString, string); /* Copy notify Id */ Tcl_DStringStartSublist(&dString); if (notifyPtr->mask & TREE_NOTIFY_CREATE) { Tcl_DStringAppendElement(&dString, "-create"); } if (notifyPtr->mask & TREE_NOTIFY_DELETE) { Tcl_DStringAppendElement(&dString, "-delete"); } if (notifyPtr->mask & TREE_NOTIFY_MOVE) { Tcl_DStringAppendElement(&dString, "-move"); } if (notifyPtr->mask & TREE_NOTIFY_SORT) { Tcl_DStringAppendElement(&dString, "-sort"); } if (notifyPtr->mask & TREE_NOTIFY_RELABEL) { Tcl_DStringAppendElement(&dString, "-relabel"); } if (notifyPtr->mask & TREE_NOTIFY_WHENIDLE) { Tcl_DStringAppendElement(&dString, "-whenidle"); } Tcl_DStringEndSublist(&dString); Tcl_DStringStartSublist(&dString); for (i = 0; i < (notifyPtr->objc - 2); i++) { Tcl_DStringAppendElement(&dString, Tcl_GetString(notifyPtr->objv[i])); } Tcl_DStringEndSublist(&dString); Tcl_DStringResult(interp, &dString); return TCL_OK; } /* *---------------------------------------------------------------------- * * NotifyNamesOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int NotifyNamesOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { Blt_HashEntry *hPtr; Blt_HashSearch cursor; Tcl_Obj *objPtr, *listObjPtr; char *notifyId; listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); for (hPtr = Blt_FirstHashEntry(&(cmdPtr->notifyTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { notifyId = Blt_GetHashKey(&(cmdPtr->notifyTable), hPtr); objPtr = Tcl_NewStringObj(notifyId, -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * NotifyOp -- * *---------------------------------------------------------------------- */ static Blt_OpSpec notifyOps[] = { {"create", 1, (Blt_Op)NotifyCreateOp, 4, 0, "?flags? command",}, {"delete", 1, (Blt_Op)NotifyDeleteOp, 3, 0, "notifyId...",}, {"info", 1, (Blt_Op)NotifyInfoOp, 4, 4, "notifyId",}, {"names", 1, (Blt_Op)NotifyNamesOp, 3, 3, "",}, }; static int nNotifyOps = sizeof(notifyOps) / sizeof(Blt_OpSpec); static int NotifyOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_Op proc; int result; proc = Blt_GetOpFromObj(interp, nNotifyOps, notifyOps, BLT_OP_ARG2, objc, objv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (cmdPtr, interp, objc, objv); return result; } /*ARGSUSED*/ static int ParentOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { Blt_TreeNode node; int inode; if (GetNode(cmdPtr, objv[2], &node) != TCL_OK) { return TCL_ERROR; } inode = -1; node = Blt_TreeNodeParent(node); if (node != NULL) { inode = Blt_TreeNodeId(node); } Tcl_SetIntObj(Tcl_GetObjResult(interp), inode); return TCL_OK; } /* *---------------------------------------------------------------------- * * PathOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int PathOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { Blt_TreeNode node; Tcl_DString dString; if (GetNode(cmdPtr, objv[2], &node) != TCL_OK) { return TCL_ERROR; } GetNodePath(cmdPtr, Blt_TreeRootNode(cmdPtr->tree), node, FALSE, &dString); Tcl_DStringResult(interp, &dString); return TCL_OK; } static int ComparePositions(Blt_TreeNode *n1Ptr, Blt_TreeNode *n2Ptr) { if (*n1Ptr == *n2Ptr) { return 0; } if (Blt_TreeIsBefore(*n1Ptr, *n2Ptr)) { return -1; } return 1; } /* *---------------------------------------------------------------------- * * PositionOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int PositionOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { PositionData data; Blt_TreeNode *nodeArr, *nodePtr; Blt_TreeNode node; Blt_TreeNode parent, lastParent; Tcl_Obj *listObjPtr, *objPtr; int i; int position; Tcl_DString dString; int n; memset((char *)&data, 0, sizeof(data)); /* Process switches */ n = Blt_ProcessObjSwitches(interp, positionSwitches, objc - 2, objv + 2, (char *)&data, BLT_SWITCH_OBJV_PARTIAL); if (n < 0) { return TCL_ERROR; } objc -= n + 2, objv += n + 2; /* Collect the node ids into an array */ nodeArr = Blt_Malloc((objc + 1) * sizeof(Blt_TreeNode)); for (i = 0; i < objc; i++) { if (GetNode(cmdPtr, objv[i], &node) != TCL_OK) { Blt_Free(nodeArr); return TCL_ERROR; } nodeArr[i] = node; } nodeArr[i] = NULL; if (data.sort) { /* Sort the nodes by depth-first order * if requested. */ qsort((char *)nodeArr, objc, sizeof(Blt_TreeNode), (QSortCompareProc *)ComparePositions); } position = 0; /* Suppress compiler warning. */ lastParent = NULL; listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); Tcl_DStringInit(&dString); for (nodePtr = nodeArr; *nodePtr != NULL; nodePtr++) { parent = Blt_TreeNodeParent(*nodePtr); if ((parent != NULL) && (parent == lastParent)) { /* * Since we've sorted the nodes already, we can safely * assume that if two consecutive nodes have the same * parent, the first node came before the second. If * this is the case, use the last node as a starting * point. */ /* * Note that we start comparing from the last node, * not its successor. Some one may give us the same * node more than once. */ node = *(nodePtr - 1); /* Can't get here unless there's * more than one node. */ for(/*empty*/; node != NULL; node = Blt_TreeNextSibling(node)) { if (node == *nodePtr) { break; } position++; } } else { /* The fallback is to linearly search through the * parent's list of children, counting the number of * preceding siblings. Except for nodes with many * siblings (100+), this should be okay. */ position = Blt_TreeNodePosition(*nodePtr); } if (data.sort) { lastParent = parent; /* Update the last parent. */ } /* * Add an element in the form "parent -at position" to the * list that we're generating. */ if (data.withId) { objPtr = Tcl_NewIntObj(Blt_TreeNodeId(*nodePtr)); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } if (data.withParent) { char *string; Tcl_DStringSetLength(&dString, 0); /* Clear the string. */ string = (parent == NULL) ? "" : Blt_Itoa(Blt_TreeNodeId(parent)); Tcl_DStringAppendElement(&dString, string); Tcl_DStringAppendElement(&dString, "-at"); Tcl_DStringAppendElement(&dString, Blt_Itoa(position)); objPtr = Tcl_NewStringObj(Tcl_DStringValue(&dString), -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } else { objPtr = Tcl_NewIntObj(position); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } } Tcl_DStringFree(&dString); Blt_Free(nodeArr); Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * PreviousOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int PreviousOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { Blt_TreeNode node; int inode; if (GetNode(cmdPtr, objv[2], &node) != TCL_OK) { return TCL_ERROR; } inode = -1; node = Blt_TreePrevNode(Blt_TreeRootNode(cmdPtr->tree), node); if (node != NULL) { inode = Blt_TreeNodeId(node); } Tcl_SetIntObj(Tcl_GetObjResult(interp), inode); return TCL_OK; } /*ARGSUSED*/ static int PrevSiblingOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { Blt_TreeNode node; int inode; if (GetNode(cmdPtr, objv[2], &node) != TCL_OK) { return TCL_ERROR; } inode = -1; node = Blt_TreePrevSibling(node); if (node != NULL) { inode = Blt_TreeNodeId(node); } Tcl_SetIntObj(Tcl_GetObjResult(interp), inode); return TCL_OK; } /* *---------------------------------------------------------------------- * * RestoreOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int RestoreOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { Blt_TreeNode root; RestoreData data; Tcl_DString dString; char *entry, *eol, *next; char saved; int result; if (GetNode(cmdPtr, objv[2], &root) != TCL_OK) { return TCL_ERROR; } memset((char *)&data, 0, sizeof(data)); Blt_InitHashTable(&data.idTable, BLT_ONE_WORD_KEYS); data.root = root; /* Process switches */ if (Blt_ProcessObjSwitches(interp, restoreSwitches, objc - 4, objv + 4, (char *)&data, 0) < 0) { return TCL_ERROR; } result = TCL_OK; nLines = 0; Tcl_DStringInit(&dString); entry = eol = Tcl_GetString(objv[3]); next = entry; while (*eol != '\0') { /* Find the next end of line. */ for (eol = next; (*eol != '\n') && (*eol != '\0'); eol++) { /*empty*/ } /* * Since we don't own the string (the Tcl_Obj could be shared), * save the current end-of-line character (it's either a NUL * or NL) so we can NUL-terminate the line for the call to * Tcl_SplitList and repair it when we're done. */ saved = *eol; *eol = '\0'; next = eol + 1; nLines++; if (Tcl_CommandComplete(entry)) { char **elemArr; int nElem; if (Tcl_SplitList(interp, entry, &nElem, &elemArr) != TCL_OK) { *eol = saved; return TCL_ERROR; } if (nElem > 0) { result = RestoreNode(cmdPtr, nElem, elemArr, &data); Blt_Free(elemArr); if (result != TCL_OK) { *eol = saved; break; } } entry = next; } *eol = saved; } Blt_DeleteHashTable(&data.idTable); return result; } static int ReadEntry( Tcl_Interp *interp, Tcl_Channel channel, int *argcPtr, char ***argvPtr) { Tcl_DString dString; int result; char *entry; if (*argvPtr != NULL) { Blt_Free(*argvPtr); *argvPtr = NULL; } Tcl_DStringInit(&dString); entry = NULL; while (Tcl_Gets(channel, &dString) >= 0) { nLines++; Tcl_DStringAppend(&dString, "\n", 1); entry = Tcl_DStringValue(&dString); if (Tcl_CommandComplete(entry)) { result = Tcl_SplitList(interp, entry, argcPtr, argvPtr); Tcl_DStringFree(&dString); return result; } } Tcl_DStringFree(&dString); if (entry == NULL) { *argcPtr = 0; /* EOF */ return TCL_OK; } Tcl_AppendResult(interp, "error reading file: ", Tcl_PosixError(interp), (char *)NULL); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * RestorefileOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int RestorefileOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { Blt_TreeNode root; int nElem; char **elemArr; char *fileName; int result; Tcl_Channel channel; RestoreData data; if (GetNode(cmdPtr, objv[2], &root) != TCL_OK) { return TCL_ERROR; } fileName = Tcl_GetString(objv[3]); channel = Tcl_OpenFileChannel(interp, fileName, "r", 0); if (channel == NULL) { return TCL_ERROR; } memset((char *)&data, 0, sizeof(data)); Blt_InitHashTable(&data.idTable, BLT_ONE_WORD_KEYS); data.root = root; /* Process switches */ if (Blt_ProcessObjSwitches(interp, restoreSwitches, objc - 4, objv + 4, (char *)&data, 0) < 0) { Tcl_Close(interp, channel); return TCL_ERROR; } elemArr = NULL; nLines = 0; for (;;) { result = ReadEntry(interp, channel, &nElem, &elemArr); if ((result != TCL_OK) || (nElem == 0)) { break; } result = RestoreNode(cmdPtr, nElem, elemArr, &data); if (result != TCL_OK) { break; } } if (elemArr != NULL) { Blt_Free(elemArr); } Tcl_Close(interp, channel); return result; } /* *---------------------------------------------------------------------- * * RootOp -- * *---------------------------------------------------------------------- */ static int RootOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_TreeNode root; if (objc == 3) { Blt_TreeNode node; if (GetNode(cmdPtr, objv[2], &node) != TCL_OK) { return TCL_ERROR; } Blt_TreeChangeRoot(cmdPtr->tree, node); } root = Blt_TreeRootNode(cmdPtr->tree); Tcl_SetIntObj(Tcl_GetObjResult(interp), Blt_TreeNodeId(root)); return TCL_OK; } /* *---------------------------------------------------------------------- * * SetOp -- * *---------------------------------------------------------------------- */ static int SetOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_TreeNode node; char *string; TagSearch cursor; string = Tcl_GetString(objv[2]); if (isdigit(UCHAR(*string))) { if (GetNode(cmdPtr, objv[2], &node) != TCL_OK) { return TCL_ERROR; } if (SetValues(cmdPtr, node, objc - 3, objv + 3) != TCL_OK) { return TCL_ERROR; } } else { node = FirstTaggedNode(interp, cmdPtr, objv[2], &cursor); if (node == NULL) { return TCL_ERROR; } for (/* empty */; node != NULL; node = NextTaggedNode(node, &cursor)) { if (SetValues(cmdPtr, node, objc - 3, objv + 3) != TCL_OK) { return TCL_ERROR; } } } return TCL_OK; } /* *---------------------------------------------------------------------- * * SizeOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int SizeOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { Blt_TreeNode node; if (GetNode(cmdPtr, objv[2], &node) != TCL_OK) { return TCL_ERROR; } Tcl_SetIntObj(Tcl_GetObjResult(interp), Blt_TreeSize(node)); return TCL_OK; } /* *---------------------------------------------------------------------- * * TagForgetOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TagForgetOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { register int i; for (i = 3; i < objc; i++) { Blt_TreeForgetTag(cmdPtr->tree, Tcl_GetString(objv[i])); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TagNamesOp -- * *---------------------------------------------------------------------- */ static int TagNamesOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_HashSearch cursor; Blt_TreeTagEntry *tPtr; Tcl_Obj *listObjPtr, *objPtr; listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); objPtr = Tcl_NewStringObj("all", -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); if (objc == 3) { Blt_HashEntry *hPtr; objPtr = Tcl_NewStringObj("root", -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); for (hPtr = Blt_TreeFirstTag(cmdPtr->tree, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tPtr = Blt_GetHashValue(hPtr); objPtr = Tcl_NewStringObj(tPtr->tagName, -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } } else { register int i; Blt_TreeNode node; Blt_HashEntry *hPtr, *h2Ptr; Blt_HashTable uniqTable; int isNew; Blt_InitHashTable(&uniqTable, BLT_STRING_KEYS); for (i = 3; i < objc; i++) { if (GetNode(cmdPtr, objv[i], &node) != TCL_OK) { goto error; } if (node == Blt_TreeRootNode(cmdPtr->tree)) { Blt_CreateHashEntry(&uniqTable, "root", &isNew); } for (hPtr = Blt_TreeFirstTag(cmdPtr->tree, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tPtr = Blt_GetHashValue(hPtr); h2Ptr = Blt_FindHashEntry(&tPtr->nodeTable, (char *)node); if (h2Ptr != NULL) { Blt_CreateHashEntry(&uniqTable, tPtr->tagName, &isNew); } } } for (hPtr = Blt_FirstHashEntry(&uniqTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { objPtr = Tcl_NewStringObj(Blt_GetHashKey(&uniqTable, hPtr), -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } Blt_DeleteHashTable(&uniqTable); } Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; error: Tcl_DecrRefCount(listObjPtr); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TagNodesOp -- * *---------------------------------------------------------------------- */ static int TagNodesOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_HashEntry *hPtr; Blt_HashSearch cursor; Blt_HashTable nodeTable; Blt_TreeNode node; Tcl_Obj *listObjPtr; Tcl_Obj *objPtr; char *string; int isNew; register int i; Blt_InitHashTable(&nodeTable, BLT_ONE_WORD_KEYS); for (i = 3; i < objc; i++) { string = Tcl_GetString(objv[i]); if (strcmp(string, "all") == 0) { break; } else if (strcmp(string, "root") == 0) { Blt_CreateHashEntry(&nodeTable, (char *)Blt_TreeRootNode(cmdPtr->tree), &isNew); continue; } else { Blt_HashTable *tablePtr; tablePtr = Blt_TreeTagHashTable(cmdPtr->tree, string); if (tablePtr != NULL) { for (hPtr = Blt_FirstHashEntry(tablePtr, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { node = Blt_GetHashValue(hPtr); Blt_CreateHashEntry(&nodeTable, (char *)node, &isNew); } continue; } } Tcl_AppendResult(interp, "can't find a tag \"", string, "\"", (char *)NULL); goto error; } listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); for (hPtr = Blt_FirstHashEntry(&nodeTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { node = (Blt_TreeNode)Blt_GetHashKey(&nodeTable, hPtr); objPtr = Tcl_NewIntObj(Blt_TreeNodeId(node)); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } Tcl_SetObjResult(interp, listObjPtr); Blt_DeleteHashTable(&nodeTable); return TCL_OK; error: Blt_DeleteHashTable(&nodeTable); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TagAddOp -- * *---------------------------------------------------------------------- */ static int TagAddOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_TreeNode node; register int i; char *string; TagSearch cursor; string = Tcl_GetString(objv[3]); if (isdigit(UCHAR(string[0]))) { Tcl_AppendResult(interp, "bad tag \"", string, "\": can't start with a digit", (char *)NULL); return TCL_ERROR; } if ((strcmp(string, "all") == 0) || (strcmp(string, "root") == 0)) { Tcl_AppendResult(cmdPtr->interp, "can't add reserved tag \"", string, "\"", (char *)NULL); return TCL_ERROR; } for (i = 4; i < objc; i++) { node = FirstTaggedNode(interp, cmdPtr, objv[i], &cursor); if (node == NULL) { return TCL_ERROR; } for (/* empty */; node != NULL; node = NextTaggedNode(node, &cursor)) { if (AddTag(cmdPtr, node, string) != TCL_OK) { return TCL_ERROR; } } } return TCL_OK; } /* *---------------------------------------------------------------------- * * TagDeleteOp -- * *---------------------------------------------------------------------- */ static int TagDeleteOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { char *string; Blt_HashTable *tablePtr; string = Tcl_GetString(objv[3]); if ((strcmp(string, "all") == 0) || (strcmp(string, "root") == 0)) { Tcl_AppendResult(interp, "can't delete reserved tag \"", string, "\"", (char *)NULL); return TCL_ERROR; } tablePtr = Blt_TreeTagHashTable(cmdPtr->tree, string); if (tablePtr != NULL) { register int i; Blt_TreeNode node; TagSearch cursor; Blt_HashEntry *hPtr; for (i = 4; i < objc; i++) { node = FirstTaggedNode(interp, cmdPtr, objv[i], &cursor); if (node == NULL) { return TCL_ERROR; } for (/* empty */; node != NULL; node = NextTaggedNode(node, &cursor)) { hPtr = Blt_FindHashEntry(tablePtr, (char *)node); if (hPtr != NULL) { Blt_DeleteHashEntry(tablePtr, hPtr); } } } } return TCL_OK; } /* *---------------------------------------------------------------------- * * TagDumpOp -- * *---------------------------------------------------------------------- */ static int TagDumpOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { register Blt_TreeNode root, node; Tcl_DString dString; TagSearch cursor; register int i; Tcl_DStringInit(&dString); root = Blt_TreeRootNode(cmdPtr->tree); for (i = 3; i < objc; i++) { node = FirstTaggedNode(interp, cmdPtr, objv[i], &cursor); if (node == NULL) { Tcl_DStringFree(&dString); return TCL_ERROR; } for (/* empty */; node != NULL; node = NextTaggedNode(node, &cursor)) { PrintNode(cmdPtr, root, node, &dString); } } Tcl_DStringResult(interp, &dString); Tcl_DStringFree(&dString); return TCL_OK; } /* *---------------------------------------------------------------------- * * TagOp -- * *---------------------------------------------------------------------- */ static Blt_OpSpec tagOps[] = { {"add", 1, (Blt_Op)TagAddOp, 5, 0, "tag node...",}, {"delete", 2, (Blt_Op)TagDeleteOp, 5, 0, "tag node...",}, {"dump", 2, (Blt_Op)TagDumpOp, 4, 0, "tag...",}, {"forget", 1, (Blt_Op)TagForgetOp, 4, 0, "tag...",}, {"names", 2, (Blt_Op)TagNamesOp, 3, 0, "?node...?",}, {"nodes", 2, (Blt_Op)TagNodesOp, 4, 0, "tag ?tag...?",}, }; static int nTagOps = sizeof(tagOps) / sizeof(Blt_OpSpec); static int TagOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_Op proc; int result; proc = Blt_GetOpFromObj(interp, nTagOps, tagOps, BLT_OP_ARG2, objc, objv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (cmdPtr, interp, objc, objv); return result; } /* *---------------------------------------------------------------------- * * TraceCreateOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TraceCreateOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { Blt_HashEntry *hPtr; Blt_TreeNode node; TraceInfo *tracePtr; char *string, *key, *command; char *tagName; char idString[200]; int flags, isNew; int length; string = Tcl_GetString(objv[3]); if (isdigit(UCHAR(*string))) { if (GetNode(cmdPtr, objv[3], &node) != TCL_OK) { return TCL_ERROR; } tagName = NULL; } else { tagName = Blt_Strdup(string); node = NULL; } key = Tcl_GetString(objv[4]); string = Tcl_GetString(objv[5]); flags = GetTraceFlags(string); if (flags < 0) { Tcl_AppendResult(interp, "unknown flag in \"", string, "\"", (char *)NULL); return TCL_ERROR; } command = Tcl_GetStringFromObj(objv[6], &length); /* Stash away the command in structure and pass that to the trace. */ tracePtr = Blt_Malloc(length + sizeof(TraceInfo)); strcpy(tracePtr->command, command); tracePtr->cmdPtr = cmdPtr; tracePtr->withTag = tagName; tracePtr->node = node; tracePtr->traceToken = Blt_TreeCreateTrace(cmdPtr->tree, node, key, tagName, flags, TreeTraceProc, tracePtr); sprintf(idString, "trace%d", cmdPtr->traceCounter++); hPtr = Blt_CreateHashEntry(&(cmdPtr->traceTable), idString, &isNew); Blt_SetHashValue(hPtr, tracePtr); Tcl_SetStringObj(Tcl_GetObjResult(interp), idString, -1); return TCL_OK; } /* *---------------------------------------------------------------------- * * TraceDeleteOp -- * *---------------------------------------------------------------------- */ static int TraceDeleteOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { TraceInfo *tracePtr; Blt_HashEntry *hPtr; register int i; char *key; for (i = 3; i < objc; i++) { key = Tcl_GetString(objv[i]); hPtr = Blt_FindHashEntry(&(cmdPtr->traceTable), key); if (hPtr == NULL) { Tcl_AppendResult(interp, "unknown trace \"", key, "\"", (char *)NULL); return TCL_ERROR; } tracePtr = Blt_GetHashValue(hPtr); Blt_DeleteHashEntry(&(cmdPtr->traceTable), hPtr); Blt_TreeDeleteTrace(tracePtr->traceToken); if (tracePtr->withTag != NULL) { Blt_Free(tracePtr->withTag); } Blt_Free(tracePtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TraceNamesOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TraceNamesOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { Blt_HashEntry *hPtr; Blt_HashSearch cursor; for (hPtr = Blt_FirstHashEntry(&(cmdPtr->traceTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { Tcl_AppendElement(interp, Blt_GetHashKey(&(cmdPtr->traceTable), hPtr)); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TraceInfoOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TraceInfoOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { TraceInfo *tracePtr; struct Blt_TreeTraceStruct *tokenPtr; Blt_HashEntry *hPtr; Tcl_DString dString; char string[5]; char *key; key = Tcl_GetString(objv[3]); hPtr = Blt_FindHashEntry(&(cmdPtr->traceTable), key); if (hPtr == NULL) { Tcl_AppendResult(interp, "unknown trace \"", key, "\"", (char *)NULL); return TCL_ERROR; } Tcl_DStringInit(&dString); tracePtr = Blt_GetHashValue(hPtr); if (tracePtr->withTag != NULL) { Tcl_DStringAppendElement(&dString, tracePtr->withTag); } else { int inode; inode = Blt_TreeNodeId(tracePtr->node); Tcl_DStringAppendElement(&dString, Blt_Itoa(inode)); } tokenPtr = (struct Blt_TreeTraceStruct *)tracePtr->traceToken; Tcl_DStringAppendElement(&dString, tokenPtr->key); PrintTraceFlags(tokenPtr->mask, string); Tcl_DStringAppendElement(&dString, string); Tcl_DStringAppendElement(&dString, tracePtr->command); Tcl_DStringResult(interp, &dString); return TCL_OK; } /* *---------------------------------------------------------------------- * * TraceOp -- * *---------------------------------------------------------------------- */ static Blt_OpSpec traceOps[] = { {"create", 1, (Blt_Op)TraceCreateOp, 7, 7, "node key how command",}, {"delete", 1, (Blt_Op)TraceDeleteOp, 3, 0, "id...",}, {"info", 1, (Blt_Op)TraceInfoOp, 4, 4, "id",}, {"names", 1, (Blt_Op)TraceNamesOp, 3, 3, "",}, }; static int nTraceOps = sizeof(traceOps) / sizeof(Blt_OpSpec); static int TraceOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_Op proc; int result; proc = Blt_GetOpFromObj(interp, nTraceOps, traceOps, BLT_OP_ARG2, objc, objv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (cmdPtr, interp, objc, objv); return result; } /* *---------------------------------------------------------------------- * * GetOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TypeOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { Blt_TreeNode node; Tcl_Obj *valueObjPtr; char *string; if (GetNode(cmdPtr, objv[2], &node) != TCL_OK) { return TCL_ERROR; } string = Tcl_GetString(objv[3]); if (Blt_TreeGetValue(interp, cmdPtr->tree, node, string, &valueObjPtr) != TCL_OK) { return TCL_ERROR; } if (valueObjPtr->typePtr != NULL) { Tcl_SetResult(interp, valueObjPtr->typePtr->name, TCL_VOLATILE); } else { Tcl_SetResult(interp, "string", TCL_STATIC); } return TCL_OK; } /* *---------------------------------------------------------------------- * * UnsetOp -- * *---------------------------------------------------------------------- */ static int UnsetOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_TreeNode node; char *string; string = Tcl_GetString(objv[2]); if (isdigit(UCHAR(*string))) { if (GetNode(cmdPtr, objv[2], &node) != TCL_OK) { return TCL_ERROR; } if (UnsetValues(cmdPtr, node, objc - 3, objv + 3) != TCL_OK) { return TCL_ERROR; } } else { TagSearch cursor; node = FirstTaggedNode(interp, cmdPtr, objv[2], &cursor); if (node == NULL) { return TCL_ERROR; } for (/* empty */; node != NULL; node = NextTaggedNode(node, &cursor)) { if (UnsetValues(cmdPtr, node, objc - 3, objv + 3) != TCL_OK) { return TCL_ERROR; } } } return TCL_OK; } typedef struct { TreeCmd *cmdPtr; unsigned int flags; int type; int mode; char *key; char *command; } SortData; #define SORT_RECURSE (1<<2) #define SORT_DECREASING (1<<3) #define SORT_PATHNAME (1<<4) enum SortTypes { SORT_DICTIONARY, SORT_REAL, SORT_INTEGER, SORT_ASCII, SORT_COMMAND }; enum SortModes { SORT_FLAT, SORT_REORDER }; static Blt_SwitchSpec sortSwitches[] = { {BLT_SWITCH_VALUE, "-ascii", Blt_Offset(SortData, type), 0, 0, SORT_ASCII}, {BLT_SWITCH_STRING, "-command", Blt_Offset(SortData, command), 0}, {BLT_SWITCH_FLAG, "-decreasing", Blt_Offset(SortData, flags), 0, 0, SORT_DECREASING}, {BLT_SWITCH_VALUE, "-dictionary", Blt_Offset(SortData, type), 0, 0, SORT_DICTIONARY}, {BLT_SWITCH_VALUE, "-integer", Blt_Offset(SortData, type), 0, 0, SORT_INTEGER}, {BLT_SWITCH_STRING, "-key", Blt_Offset(SortData, key), 0}, {BLT_SWITCH_FLAG, "-path", Blt_Offset(SortData, flags), 0, 0, SORT_PATHNAME}, {BLT_SWITCH_VALUE, "-real", Blt_Offset(SortData, type), 0, 0, SORT_REAL}, {BLT_SWITCH_VALUE, "-recurse", Blt_Offset(SortData, flags), 0, 0, SORT_RECURSE}, {BLT_SWITCH_VALUE, "-reorder", Blt_Offset(SortData, mode), 0, 0, SORT_REORDER}, {BLT_SWITCH_END, NULL, 0, 0} }; static SortData sortData; static int CompareNodes(Blt_TreeNode *n1Ptr, Blt_TreeNode *n2Ptr) { TreeCmd *cmdPtr = sortData.cmdPtr; char *s1, *s2; int result; Tcl_DString dString1, dString2; s1 = s2 = ""; result = 0; if (sortData.flags & SORT_PATHNAME) { Tcl_DStringInit(&dString1); Tcl_DStringInit(&dString2); } if (sortData.key != NULL) { Tcl_Obj *valueObjPtr; if (Blt_TreeGetValue((Tcl_Interp *)NULL, cmdPtr->tree, *n1Ptr, sortData.key, &valueObjPtr) == TCL_OK) { s1 = Tcl_GetString(valueObjPtr); } if (Blt_TreeGetValue((Tcl_Interp *)NULL, cmdPtr->tree, *n2Ptr, sortData.key, &valueObjPtr) == TCL_OK) { s2 = Tcl_GetString(valueObjPtr); } } else if (sortData.flags & SORT_PATHNAME) { Blt_TreeNode root; root = Blt_TreeRootNode(cmdPtr->tree); s1 = GetNodePath(cmdPtr, root, *n1Ptr, FALSE, &dString1); s2 = GetNodePath(cmdPtr, root, *n2Ptr, FALSE, &dString2); } else { s1 = Blt_TreeNodeLabel(*n1Ptr); s2 = Blt_TreeNodeLabel(*n2Ptr); } switch (sortData.type) { case SORT_ASCII: result = strcmp(s1, s2); break; case SORT_COMMAND: if (sortData.command == NULL) { result = Blt_DictionaryCompare(s1, s2); } else { Tcl_DString dsCmd, dsName; char *qualName; result = 0; /* Hopefully this will be Ok even if the * Tcl command fails to return the correct * result. */ Tcl_DStringInit(&dsCmd); Tcl_DStringAppend(&dsCmd, sortData.command, -1); Tcl_DStringInit(&dsName); qualName = Blt_GetQualifiedName( Blt_GetCommandNamespace(cmdPtr->interp, cmdPtr->cmdToken), Tcl_GetCommandName(cmdPtr->interp, cmdPtr->cmdToken), &dsName); Tcl_DStringAppendElement(&dsCmd, qualName); Tcl_DStringFree(&dsName); Tcl_DStringAppendElement(&dsCmd, Blt_Itoa(Blt_TreeNodeId(*n1Ptr))); Tcl_DStringAppendElement(&dsCmd, Blt_Itoa(Blt_TreeNodeId(*n2Ptr))); Tcl_DStringAppendElement(&dsCmd, s1); Tcl_DStringAppendElement(&dsCmd, s2); result = Tcl_GlobalEval(cmdPtr->interp, Tcl_DStringValue(&dsCmd)); Tcl_DStringFree(&dsCmd); if ((result != TCL_OK) || (Tcl_GetInt(cmdPtr->interp, Tcl_GetStringResult(cmdPtr->interp), &result) != TCL_OK)) { Tcl_BackgroundError(cmdPtr->interp); } Tcl_ResetResult(cmdPtr->interp); } break; case SORT_DICTIONARY: result = Blt_DictionaryCompare(s1, s2); break; case SORT_INTEGER: { int i1, i2; if (Tcl_GetInt(NULL, s1, &i1) == TCL_OK) { if (Tcl_GetInt(NULL, s2, &i2) == TCL_OK) { result = i1 - i2; } else { result = -1; } } else if (Tcl_GetInt(NULL, s2, &i2) == TCL_OK) { result = 1; } else { result = Blt_DictionaryCompare(s1, s2); } } break; case SORT_REAL: { double r1, r2; if (Tcl_GetDouble(NULL, s1, &r1) == TCL_OK) { if (Tcl_GetDouble(NULL, s2, &r2) == TCL_OK) { result = (r1 < r2) ? -1 : (r1 > r2) ? 1 : 0; } else { result = -1; } } else if (Tcl_GetDouble(NULL, s2, &r2) == TCL_OK) { result = 1; } else { result = Blt_DictionaryCompare(s1, s2); } } break; } if (result == 0) { result = Blt_TreeNodeId(*n1Ptr) - Blt_TreeNodeId(*n2Ptr); } if (sortData.flags & SORT_DECREASING) { result = -result; } if (sortData.flags & SORT_PATHNAME) { Tcl_DStringFree(&dString1); Tcl_DStringFree(&dString2); } return result; } /* *---------------------------------------------------------------------- * * SortApplyProc -- * * Sorts the subnodes at a given node. * * Results: * Always returns TCL_OK. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int SortApplyProc( Blt_TreeNode node, ClientData clientData, int order) /* Not used. */ { TreeCmd *cmdPtr = clientData; if (!Blt_TreeIsLeaf(node)) { Blt_TreeSortNode(cmdPtr->tree, node, CompareNodes); } return TCL_OK; } /* *---------------------------------------------------------------------- * * SortOp -- * *---------------------------------------------------------------------- */ static int SortOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_TreeNode top; SortData data; int result; if (GetNode(cmdPtr, objv[2], &top) != TCL_OK) { return TCL_ERROR; } /* Process switches */ memset(&data, 0, sizeof(data)); data.cmdPtr = cmdPtr; if (Blt_ProcessObjSwitches(interp, sortSwitches, objc - 3, objv + 3, (char *)&data, 0) < 0) { return TCL_ERROR; } if (data.command != NULL) { data.type = SORT_COMMAND; } data.cmdPtr = cmdPtr; sortData = data; if (data.mode == SORT_FLAT) { Blt_TreeNode *p, *nodeArr, node; int nNodes; Tcl_Obj *objPtr, *listObjPtr; int i; if (data.flags & SORT_RECURSE) { nNodes = Blt_TreeSize(top); } else { nNodes = Blt_TreeNodeDegree(top); } nodeArr = Blt_Malloc(nNodes * sizeof(Blt_TreeNode)); assert(nodeArr); p = nodeArr; if (data.flags & SORT_RECURSE) { for(node = top; node != NULL; node = Blt_TreeNextNode(top, node)) { *p++ = node; } } else { for (node = Blt_TreeFirstChild(top); node != NULL; node = Blt_TreeNextSibling(node)) { *p++ = node; } } qsort((char *)nodeArr, nNodes, sizeof(Blt_TreeNode), (QSortCompareProc *)CompareNodes); listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); for (p = nodeArr, i = 0; i < nNodes; i++, p++) { objPtr = Tcl_NewIntObj(Blt_TreeNodeId(*p)); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } Tcl_SetObjResult(interp, listObjPtr); Blt_Free(nodeArr); result = TCL_OK; } else { if (data.flags & SORT_RECURSE) { result = Blt_TreeApply(top, SortApplyProc, cmdPtr); } else { result = SortApplyProc(top, cmdPtr, TREE_PREORDER); } } Blt_FreeSwitches(sortSwitches, (char *)&data, 0); return result; } /* *---------------------------------------------------------------------- * * ValuesOp -- * * Returns the names of values for a node or array value. * *---------------------------------------------------------------------- */ static int ValuesOp( TreeCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_TreeNode node; Tcl_Obj *listObjPtr; if (GetNode(cmdPtr, objv[2], &node) != TCL_OK) { return TCL_ERROR; } listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); if (objc == 4) { char *string; string = Tcl_GetString(objv[3]); if (Blt_TreeArrayNames(interp, cmdPtr->tree, node, string, listObjPtr) != TCL_OK) { return TCL_ERROR; } } else { Blt_TreeKey key; Tcl_Obj *objPtr; Blt_TreeKeySearch keyIter; for (key = Blt_TreeFirstKey(cmdPtr->tree, node, &keyIter); key != NULL; key = Blt_TreeNextKey(cmdPtr->tree, &keyIter)) { objPtr = Tcl_NewStringObj(key, -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } } Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; } /* * -------------------------------------------------------------- * * TreeInstObjCmd -- * * This procedure is invoked to process commands on behalf of * the tree object. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * * -------------------------------------------------------------- */ static Blt_OpSpec treeOps[] = { {"ancestor", 2, (Blt_Op)AncestorOp, 4, 4, "node1 node2",}, {"apply", 1, (Blt_Op)ApplyOp, 3, 0, "node ?switches?",}, {"attach", 2, (Blt_Op)AttachOp, 2, 3, "?tree?",}, {"children", 2, (Blt_Op)ChildrenOp, 3, 5, "node ?first? ?last?",}, {"copy", 2, (Blt_Op)CopyOp, 4, 0, "srcNode ?destTree? destNode ?switches?",}, {"degree", 2, (Blt_Op)DegreeOp, 3, 0, "node",}, {"delete", 2, (Blt_Op)DeleteOp, 3, 0, "node ?node...?",}, {"depth", 3, (Blt_Op)DepthOp, 3, 3, "node",}, {"dump", 4, (Blt_Op)DumpOp, 3, 3, "node",}, {"dumpfile", 5, (Blt_Op)DumpfileOp, 4, 4, "node fileName",}, {"exists", 1, (Blt_Op)ExistsOp, 3, 4, "node ?key?",}, {"find", 4, (Blt_Op)FindOp, 3, 0, "node ?switches?",}, {"findchild", 5, (Blt_Op)FindChildOp, 4, 4, "node name",}, {"firstchild", 3, (Blt_Op)FirstChildOp, 3, 3, "node",}, {"get", 1, (Blt_Op)GetOp, 3, 5, "node ?key? ?defaultValue?",}, {"index", 3, (Blt_Op)IndexOp, 3, 3, "name",}, {"insert", 3, (Blt_Op)InsertOp, 3, 0, "parent ?switches?",}, {"is", 2, (Blt_Op)IsOp, 2, 0, "oper args...",}, {"keys", 1, (Blt_Op)KeysOp, 3, 0, "node ?node...?",}, {"label", 3, (Blt_Op)LabelOp, 3, 4, "node ?newLabel?",}, {"lastchild", 3, (Blt_Op)LastChildOp, 3, 3, "node",}, {"move", 1, (Blt_Op)MoveOp, 4, 0, "node newParent ?switches?",}, {"next", 4, (Blt_Op)NextOp, 3, 3, "node",}, {"nextsibling", 5, (Blt_Op)NextSiblingOp, 3, 3, "node",}, {"notify", 2, (Blt_Op)NotifyOp, 2, 0, "args...",}, {"parent", 3, (Blt_Op)ParentOp, 3, 3, "node",}, {"path", 3, (Blt_Op)PathOp, 3, 3, "node",}, {"position", 2, (Blt_Op)PositionOp, 3, 0, "?switches? node...",}, {"previous", 5, (Blt_Op)PreviousOp, 3, 3, "node",}, {"prevsibling", 5, (Blt_Op)PrevSiblingOp, 3, 3, "node",}, {"restore", 7, (Blt_Op)RestoreOp, 4, 4, "node dataString",}, {"restorefile", 8, (Blt_Op)RestorefileOp, 4, 4, "node fileName",}, {"root", 2, (Blt_Op)RootOp, 2, 3, "?node?",}, {"set", 3, (Blt_Op)SetOp, 3, 0, "node ?key value...?",}, {"size", 2, (Blt_Op)SizeOp, 3, 3, "node",}, {"sort", 2, (Blt_Op)SortOp, 3, 0, "node ?flags...?",}, {"tag", 2, (Blt_Op)TagOp, 3, 0, "args...",}, {"trace", 2, (Blt_Op)TraceOp, 2, 0, "args...",}, {"type", 2, (Blt_Op)TypeOp, 4, 4, "node key",}, {"unset", 3, (Blt_Op)UnsetOp, 3, 0, "node ?key...?",}, {"values", 1, (Blt_Op)ValuesOp, 3, 4, "node ?key?",}, }; static int nTreeOps = sizeof(treeOps) / sizeof(Blt_OpSpec); static int TreeInstObjCmd( ClientData clientData, /* Information about the widget. */ Tcl_Interp *interp, /* Interpreter to report errors back to. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST *objv) /* Vector of argument strings. */ { Blt_Op proc; TreeCmd *cmdPtr = clientData; int result; proc = Blt_GetOpFromObj(interp, nTreeOps, treeOps, BLT_OP_ARG1, objc, objv, BLT_OP_LINEAR_SEARCH); if (proc == NULL) { return TCL_ERROR; } Tcl_Preserve(cmdPtr); result = (*proc) (cmdPtr, interp, objc, objv); Tcl_Release(cmdPtr); return result; } /* * ---------------------------------------------------------------------- * * TreeInstDeleteProc -- * * Deletes the command associated with the tree. This is * called only when the command associated with the tree is * destroyed. * * Results: * None. * * ---------------------------------------------------------------------- */ static void TreeInstDeleteProc(ClientData clientData) { TreeCmd *cmdPtr = clientData; ReleaseTreeObject(cmdPtr); if (cmdPtr->hashPtr != NULL) { Blt_DeleteHashEntry(cmdPtr->tablePtr, cmdPtr->hashPtr); } Blt_DeleteHashTable(&(cmdPtr->traceTable)); Blt_Free(cmdPtr); } /* * ---------------------------------------------------------------------- * * GenerateName -- * * Generates an unique tree command name. Tree names are in * the form "treeN", where N is a non-negative integer. Check * each name generated to see if it is already a tree. We want * to recycle names if possible. * * Results: * Returns the unique name. The string itself is stored in the * dynamic string passed into the routine. * * ---------------------------------------------------------------------- */ static CONST char * GenerateName( Tcl_Interp *interp, CONST char *prefix, CONST char *suffix, Tcl_DString *resultPtr) { int n; Tcl_Namespace *nsPtr; char string[200]; Tcl_CmdInfo cmdInfo; Tcl_DString dString; CONST char *treeName, *name; /* * Parse the command and put back so that it's in a consistent * format. * * t1 ::t1 * n1::t1 ::n1::t1 * ::t1 ::t1 * ::n1::t1 ::n1::t1 */ treeName = NULL; /* Suppress compiler warning. */ for (n = 0; n < INT_MAX; n++) { Tcl_DStringInit(&dString); Tcl_DStringAppend(&dString, prefix, -1); sprintf(string, "tree%d", n); Tcl_DStringAppend(&dString, string, -1); Tcl_DStringAppend(&dString, suffix, -1); treeName = Tcl_DStringValue(&dString); if (Blt_ParseQualifiedName(interp, treeName, &nsPtr, &name) != TCL_OK) { Tcl_AppendResult(interp, "can't find namespace in \"", treeName, "\"", (char *)NULL); return NULL; } if (nsPtr == NULL) { nsPtr = Tcl_GetCurrentNamespace(interp); } treeName = Blt_GetQualifiedName(nsPtr, name, resultPtr); /* * Check if the command already exists. */ if (Tcl_GetCommandInfo(interp, (char *)treeName, &cmdInfo)) { continue; } if (!Blt_TreeExists(interp, treeName)) { /* * We want the name of the tree command and the underlying * tree object to be the same. Check that the free command * name isn't an already a tree object name. */ break; } } return treeName; } /* *---------------------------------------------------------------------- * * TreeCreateOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TreeCreateOp( ClientData clientData, /* Interpreter-specific data. */ Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { TreeCmdInterpData *dataPtr = clientData; CONST char *treeName; Tcl_DString dString; Blt_Tree token; treeName = NULL; if (objc == 3) { treeName = Tcl_GetString(objv[2]); } Tcl_DStringInit(&dString); if (treeName == NULL) { treeName = GenerateName(interp, "", "", &dString); } else { char *p; p = strstr(treeName, "#auto"); if (p != NULL) { *p = '\0'; treeName = GenerateName(interp, treeName, p + 5, &dString); *p = '#'; } else { CONST char *name; Tcl_CmdInfo cmdInfo; Tcl_Namespace *nsPtr; nsPtr = NULL; /* * Parse the command and put back so that it's in a consistent * format. * * t1 ::t1 * n1::t1 ::n1::t1 * ::t1 ::t1 * ::n1::t1 ::n1::t1 */ if (Blt_ParseQualifiedName(interp, treeName, &nsPtr, &name) != TCL_OK) { Tcl_AppendResult(interp, "can't find namespace in \"", treeName, "\"", (char *)NULL); return TCL_ERROR; } if (nsPtr == NULL) { nsPtr = Tcl_GetCurrentNamespace(interp); } treeName = Blt_GetQualifiedName(nsPtr, name, &dString); /* * Check if the command already exists. */ if (Tcl_GetCommandInfo(interp, (char *)treeName, &cmdInfo)) { Tcl_AppendResult(interp, "a command \"", treeName, "\" already exists", (char *)NULL); goto error; } if (Blt_TreeExists(interp, treeName)) { Tcl_AppendResult(interp, "a tree \"", treeName, "\" already exists", (char *)NULL); goto error; } } } if (treeName == NULL) { goto error; } if (Blt_TreeCreate(interp, treeName, &token) == TCL_OK) { int isNew; TreeCmd *cmdPtr; cmdPtr = Blt_Calloc(1, sizeof(TreeCmd)); assert(cmdPtr); cmdPtr->dataPtr = dataPtr; cmdPtr->tree = token; cmdPtr->interp = interp; Blt_InitHashTable(&(cmdPtr->traceTable), BLT_STRING_KEYS); Blt_InitHashTable(&(cmdPtr->notifyTable), BLT_STRING_KEYS); cmdPtr->cmdToken = Tcl_CreateObjCommand(interp, (char *)treeName, (Tcl_ObjCmdProc *)TreeInstObjCmd, cmdPtr, TreeInstDeleteProc); cmdPtr->tablePtr = &dataPtr->treeTable; cmdPtr->hashPtr = Blt_CreateHashEntry(cmdPtr->tablePtr, (char *)cmdPtr, &isNew); Blt_SetHashValue(cmdPtr->hashPtr, cmdPtr); Tcl_SetResult(interp, (char *)treeName, TCL_VOLATILE); Tcl_DStringFree(&dString); Blt_TreeCreateEventHandler(cmdPtr->tree, TREE_NOTIFY_ALL, TreeEventProc, cmdPtr); return TCL_OK; } error: Tcl_DStringFree(&dString); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeDestroyOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TreeDestroyOp( ClientData clientData, /* Interpreter-specific data. */ Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { TreeCmdInterpData *dataPtr = clientData; TreeCmd *cmdPtr; char *string; register int i; for (i = 2; i < objc; i++) { string = Tcl_GetString(objv[i]); cmdPtr = GetTreeCmd(dataPtr, interp, string); if (cmdPtr == NULL) { Tcl_AppendResult(interp, "can't find a tree named \"", string, "\"", (char *)NULL); return TCL_ERROR; } Tcl_DeleteCommandFromToken(interp, cmdPtr->cmdToken); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeNamesOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TreeNamesOp( ClientData clientData, /* Interpreter-specific data. */ Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { TreeCmdInterpData *dataPtr = clientData; TreeCmd *cmdPtr; Blt_HashEntry *hPtr; Blt_HashSearch cursor; Tcl_Obj *objPtr, *listObjPtr; Tcl_DString dString; char *qualName; Tcl_DStringInit(&dString); listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); for (hPtr = Blt_FirstHashEntry(&dataPtr->treeTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { cmdPtr = Blt_GetHashValue(hPtr); qualName = Blt_GetQualifiedName( Blt_GetCommandNamespace(interp, cmdPtr->cmdToken), Tcl_GetCommandName(interp, cmdPtr->cmdToken), &dString); if (objc == 3) { if (!Tcl_StringMatch(qualName, Tcl_GetString(objv[2]))) { continue; } } objPtr = Tcl_NewStringObj(qualName, -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } Tcl_SetObjResult(interp, listObjPtr); Tcl_DStringFree(&dString); return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeObjCmd -- * *---------------------------------------------------------------------- */ static Blt_OpSpec treeCmdOps[] = { {"create", 1, (Blt_Op)TreeCreateOp, 2, 3, "?name?",}, {"destroy", 1, (Blt_Op)TreeDestroyOp, 3, 0, "name...",}, {"names", 1, (Blt_Op)TreeNamesOp, 2, 3, "?pattern?...",}, }; static int nCmdOps = sizeof(treeCmdOps) / sizeof(Blt_OpSpec); /*ARGSUSED*/ static int TreeObjCmd( ClientData clientData, /* Interpreter-specific data. */ Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_Op proc; proc = Blt_GetOpFromObj(interp, nCmdOps, treeCmdOps, BLT_OP_ARG1, objc, objv, 0); if (proc == NULL) { return TCL_ERROR; } return (*proc) (clientData, interp, objc, objv); } /* * ----------------------------------------------------------------------- * * TreeInterpDeleteProc -- * * This is called when the interpreter hosting the "tree" command * is deleted. * * Results: * None. * * Side effects: * Removes the hash table managing all tree names. * * ------------------------------------------------------------------------ */ /* ARGSUSED */ static void TreeInterpDeleteProc( ClientData clientData, /* Interpreter-specific data. */ Tcl_Interp *interp) { TreeCmdInterpData *dataPtr = clientData; /* All tree instances should already have been destroyed when * their respective Tcl commands were deleted. */ Blt_DeleteHashTable(&dataPtr->treeTable); Tcl_DeleteAssocData(interp, TREE_THREAD_KEY); Blt_Free(dataPtr); } /*ARGSUSED*/ static int CompareDictionaryCmd( ClientData clientData, /* Not used. */ Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { int result; char *s1, *s2; s1 = Tcl_GetString(objv[1]); s2 = Tcl_GetString(objv[2]); result = Blt_DictionaryCompare(s1, s2); result = (result > 0) ? -1 : (result < 0) ? 1 : 0; Tcl_SetIntObj(Tcl_GetObjResult(interp), result); return TCL_OK; } /*ARGSUSED*/ static int ExitCmd( ClientData clientData, /* Not used. */ Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { int code; if (Tcl_GetIntFromObj(interp, objv[1], &code) != TCL_OK) { return TCL_ERROR; } #ifdef TCL_THREADS Tcl_Exit(code); #else exit(code); #endif /*NOTREACHED*/ return TCL_OK; } /* * ----------------------------------------------------------------------- * * Blt_TreeInit -- * * This procedure is invoked to initialize the "tree" command. * * Results: * None. * * Side effects: * Creates the new command and adds a new entry into a global Tcl * associative array. * * ------------------------------------------------------------------------ */ int Blt_TreeInit(Tcl_Interp *interp) { TreeCmdInterpData *dataPtr; /* Interpreter-specific data. */ static Blt_ObjCmdSpec cmdSpec = { "tree", TreeObjCmd, }; static Blt_ObjCmdSpec compareSpec = { "compare", CompareDictionaryCmd, }; static Blt_ObjCmdSpec exitSpec = { "exit", ExitCmd, }; if (Blt_InitObjCmd(interp, "blt::util", &compareSpec) == NULL) { return TCL_ERROR; } if (Blt_InitObjCmd(interp, "blt::util", &exitSpec) == NULL) { return TCL_ERROR; } dataPtr = GetTreeCmdInterpData(interp); cmdSpec.clientData = dataPtr; if (Blt_InitObjCmd(interp, "blt", &cmdSpec) == NULL) { return TCL_ERROR; } return TCL_OK; } int Blt_TreeCmdGetToken( Tcl_Interp *interp, CONST char *string, Blt_Tree *treePtr) { TreeCmdInterpData *dataPtr; TreeCmd *cmdPtr; dataPtr = GetTreeCmdInterpData(interp); cmdPtr = GetTreeCmd(dataPtr, interp, string); if (cmdPtr == NULL) { Tcl_AppendResult(interp, "can't find a tree associated with \"", string, "\"", (char *)NULL); return TCL_ERROR; } *treePtr = cmdPtr->tree; return TCL_OK; } /* Dump tree to dbm */ /* Convert node data to datablock */ #endif /* NO_TREE */ blt-2.4z.orig/src/bltTreeView.c0100644000175000017500000044644707527076110015163 0ustar dokodoko /* * bltTreeView.c -- * * This module implements an hierarchy widget for the BLT toolkit. * * Copyright 1998-1999 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 or 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. * * The "treeview" widget was created by George A. Howlett. */ /* * TODO: * * BUGS: * 1. "open" operation should change scroll offset so that as many * new entries (up to half a screen) can be seen. * 2. "open" needs to adjust the scrolloffset so that the same entry * is seen at the same place. */ #include "bltInt.h" #ifndef NO_TREEVIEW #include "bltTreeView.h" #define BUTTON_PAD 2 #define BUTTON_IPAD 1 #define BUTTON_SIZE 7 #define COLUMN_PAD 2 #define FOCUS_WIDTH 1 #define ICON_PADX 2 #define ICON_PADY 1 #define INSET_PAD 0 #define LABEL_PADX 3 #define LABEL_PADY 0 #include #include #define DEF_ICON_WIDTH 16 #define DEF_ICON_HEIGHT 16 static Blt_TreeApplyProc DeleteApplyProc; static Blt_TreeApplyProc CreateApplyProc; extern Blt_CustomOption bltTreeViewDataOption; static Blt_OptionParseProc ObjToTree; static Blt_OptionPrintProc TreeToObj; static Blt_OptionFreeProc FreeTree; Blt_CustomOption bltTreeViewTreeOption = { ObjToTree, TreeToObj, FreeTree, NULL, }; static Blt_OptionParseProc ObjToIcons; static Blt_OptionPrintProc IconsToObj; static Blt_OptionFreeProc FreeIcons; Blt_CustomOption bltTreeViewIconsOption = { /* Contains a pointer to the widget that's currently being * configured. This is used in the custom configuration parse * routine for icons. */ ObjToIcons, IconsToObj, FreeIcons, NULL, }; static Blt_OptionParseProc ObjToButton; static Blt_OptionPrintProc ButtonToObj; static Blt_CustomOption buttonOption = { ObjToButton, ButtonToObj, NULL, NULL, }; static Blt_OptionParseProc ObjToUid; static Blt_OptionPrintProc UidToObj; static Blt_OptionFreeProc FreeUid; Blt_CustomOption bltTreeViewUidOption = { ObjToUid, UidToObj, FreeUid, NULL, }; static Blt_OptionParseProc ObjToScrollmode; static Blt_OptionPrintProc ScrollmodeToObj; static Blt_CustomOption scrollmodeOption = { ObjToScrollmode, ScrollmodeToObj, NULL, NULL, }; static Blt_OptionParseProc ObjToSelectmode; static Blt_OptionPrintProc SelectmodeToObj; static Blt_CustomOption selectmodeOption = { ObjToSelectmode, SelectmodeToObj, NULL, NULL, }; static Blt_OptionParseProc ObjToSeparator; static Blt_OptionPrintProc SeparatorToObj; static Blt_OptionFreeProc FreeSeparator; static Blt_CustomOption separatorOption = { ObjToSeparator, SeparatorToObj, FreeSeparator, NULL, }; static Blt_OptionParseProc ObjToLabel; static Blt_OptionPrintProc LabelToObj; static Blt_OptionFreeProc FreeLabel; static Blt_CustomOption labelOption = { ObjToLabel, LabelToObj, FreeLabel, NULL, }; #define DEF_BUTTON_ACTIVE_BACKGROUND RGB_WHITE #define DEF_BUTTON_ACTIVE_BG_MONO STD_ACTIVE_BG_MONO #define DEF_BUTTON_ACTIVE_FOREGROUND STD_ACTIVE_FOREGROUND #define DEF_BUTTON_ACTIVE_FG_MONO STD_ACTIVE_FG_MONO #define DEF_BUTTON_BORDERWIDTH "1" #if (TK_MAJOR_VERSION == 4) #define DEF_BUTTON_CLOSE_RELIEF "flat" #define DEF_BUTTON_OPEN_RELIEF "flat" #else #define DEF_BUTTON_CLOSE_RELIEF "solid" #define DEF_BUTTON_OPEN_RELIEF "solid" #endif #define DEF_BUTTON_NORMAL_BACKGROUND RGB_WHITE #define DEF_BUTTON_NORMAL_BG_MONO STD_NORMAL_BG_MONO #define DEF_BUTTON_NORMAL_FOREGROUND STD_NORMAL_FOREGROUND #define DEF_BUTTON_NORMAL_FG_MONO STD_NORMAL_FG_MONO #define DEF_BUTTON_SIZE "7" /* RGB_LIGHTBLUE1 */ #define DEF_TV_ACTIVE_FOREGROUND "black" #define DEF_TV_ACTIVE_ICONS \ "blt::tv::activeOpenFolder blt::tv::activeCloseFolder" #define DEF_TV_ACTIVE_RELIEF "flat" #define DEF_TV_ACTIVE_STIPPLE "gray25" #define DEF_TV_ALLOW_DUPLICATES "yes" #define DEF_TV_BACKGROUND "white" #define DEF_TV_BORDERWIDTH STD_BORDERWIDTH #define DEF_TV_BUTTON "auto" #define DEF_TV_DASHES "dot" #define DEF_TV_EXPORT_SELECTION "no" #define DEF_TV_FOREGROUND STD_NORMAL_FOREGROUND #define DEF_TV_FG_MONO STD_NORMAL_FG_MONO #define DEF_TV_FLAT "no" #define DEF_TV_FOCUS_DASHES "dot" #define DEF_TV_FOCUS_EDIT "no" #define DEF_TV_FOCUS_FOREGROUND STD_ACTIVE_FOREGROUND #define DEF_TV_FOCUS_FG_MONO STD_ACTIVE_FG_MONO #define DEF_TV_FONT "Courier 12" #define DEF_TV_HEIGHT "400" #define DEF_TV_HIDE_LEAVES "no" #define DEF_TV_HIDE_ROOT "yes" #define DEF_TV_FOCUS_HIGHLIGHT_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_TV_FOCUS_HIGHLIGHT_COLOR "black" #define DEF_TV_FOCUS_HIGHLIGHT_WIDTH "2" #define DEF_TV_ICONS "blt::tv::normalOpenFolder blt::tv::normalCloseFolder" #define DEF_TV_VLINE_COLOR RGB_GREY50 #define DEF_TV_VLINE_MONO STD_NORMAL_FG_MONO #define DEF_TV_LINESPACING "0" #define DEF_TV_LINEWIDTH "1" #define DEF_TV_MAKE_PATH "no" #define DEF_TV_NEW_TAGS "no" #define DEF_TV_NORMAL_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_TV_NORMAL_FG_MONO STD_ACTIVE_FG_MONO #define DEF_TV_RELIEF "sunken" #define DEF_TV_RESIZE_CURSOR "arrow" #define DEF_TV_SCROLL_INCREMENT "20" #define DEF_TV_SCROLL_MODE "hierbox" #define DEF_TV_SELECT_BACKGROUND STD_SELECT_BACKGROUND /* RGB_LIGHTBLUE1 */ #define DEF_TV_SELECT_BG_MONO STD_SELECT_BG_MONO #define DEF_TV_SELECT_BORDERWIDTH "1" #define DEF_TV_SELECT_FOREGROUND STD_SELECT_FOREGROUND #define DEF_TV_SELECT_FG_MONO STD_SELECT_FG_MONO #define DEF_TV_SELECT_MODE "single" #define DEF_TV_SELECT_RELIEF "flat" #define DEF_TV_SHOW_ROOT "yes" #define DEF_TV_SHOW_TITLES "yes" #define DEF_TV_SORT_SELECTION "no" #define DEF_TV_TAKE_FOCUS "1" #define DEF_TV_TEXT_COLOR STD_NORMAL_FOREGROUND #define DEF_TV_TEXT_MONO STD_NORMAL_FG_MONO #define DEF_TV_TRIMLEFT "" #define DEF_TV_WIDTH "200" Blt_ConfigSpec bltTreeViewButtonSpecs[] = { {BLT_CONFIG_BORDER, "-activebackground", "activeBackground", "Background", DEF_BUTTON_ACTIVE_BACKGROUND, Blt_Offset(TreeView, button.activeBorder), 0}, {BLT_CONFIG_SYNONYM, "-activebg", "activeBackground", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_SYNONYM, "-activefg", "activeForeground", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_COLOR, "-activeforeground", "activeForeground", "Foreground", DEF_BUTTON_ACTIVE_FOREGROUND, Blt_Offset(TreeView, button.activeFgColor), 0}, {BLT_CONFIG_BORDER, "-background", "background", "Background", DEF_BUTTON_NORMAL_BACKGROUND, Blt_Offset(TreeView, button.border), 0}, {BLT_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_DISTANCE, "-borderwidth", "borderWidth", "BorderWidth", DEF_BUTTON_BORDERWIDTH, Blt_Offset(TreeView, button.borderWidth), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_RELIEF, "-closerelief", "closeRelief", "Relief", DEF_BUTTON_CLOSE_RELIEF, Blt_Offset(TreeView, button.closeRelief), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_SYNONYM, "-fg", "foreground", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_BUTTON_NORMAL_FOREGROUND, Blt_Offset(TreeView, button.fgColor), 0}, {BLT_CONFIG_CUSTOM, "-images", "images", "Icons", (char *)NULL, Blt_Offset(TreeView, button.icons), BLT_CONFIG_NULL_OK, &bltTreeViewIconsOption}, {BLT_CONFIG_RELIEF, "-openrelief", "openRelief", "Relief", DEF_BUTTON_OPEN_RELIEF, Blt_Offset(TreeView, button.openRelief), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_DISTANCE, "-size", "size", "Size", DEF_BUTTON_SIZE, Blt_Offset(TreeView, button.reqSize), 0}, {BLT_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; Blt_ConfigSpec bltTreeViewEntrySpecs[] = { {BLT_CONFIG_CUSTOM, "-activeicons", (char *)NULL, (char *)NULL, (char *)NULL, Blt_Offset(TreeViewEntry, activeIcons), BLT_CONFIG_NULL_OK, &bltTreeViewIconsOption}, {BLT_CONFIG_CUSTOM, "-bindtags", (char *)NULL, (char *)NULL, (char *)NULL, Blt_Offset(TreeViewEntry, tagsUid), BLT_CONFIG_NULL_OK, &bltTreeViewUidOption}, {BLT_CONFIG_CUSTOM, "-button", (char *)NULL, (char *)NULL, DEF_TV_BUTTON, Blt_Offset(TreeViewEntry, flags), BLT_CONFIG_DONT_SET_DEFAULT, &buttonOption}, {BLT_CONFIG_CUSTOM, "-closecommand", (char *)NULL, (char *)NULL, (char *)NULL, Blt_Offset(TreeViewEntry, closeCmd), BLT_CONFIG_NULL_OK, &bltTreeViewUidOption}, {BLT_CONFIG_CUSTOM, "-data", (char *)NULL, (char *)NULL, (char *)NULL, 0, BLT_CONFIG_NULL_OK, &bltTreeViewDataOption}, {BLT_CONFIG_SYNONYM, "-fg", "foreground", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_FONT, "-font", (char *)NULL, (char *)NULL, (char *)NULL, Blt_Offset(TreeViewEntry, font), 0}, {BLT_CONFIG_COLOR, "-foreground", "foreground", (char *)NULL, (char *)NULL, Blt_Offset(TreeViewEntry, color), BLT_CONFIG_NULL_OK}, {BLT_CONFIG_DISTANCE, "-height", (char *)NULL, (char *)NULL, (char *)NULL, Blt_Offset(TreeViewEntry, reqHeight), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_CUSTOM, "-icons", (char *)NULL, (char *)NULL, (char *)NULL, Blt_Offset(TreeViewEntry, icons), BLT_CONFIG_NULL_OK, &bltTreeViewIconsOption}, {BLT_CONFIG_CUSTOM, "-label", (char *)NULL, (char *)NULL, (char *)NULL, Blt_Offset(TreeViewEntry, labelUid), 0, &labelOption}, {BLT_CONFIG_CUSTOM, "-opencommand", (char *)NULL, (char *)NULL, (char *)NULL, Blt_Offset(TreeViewEntry, openCmd), BLT_CONFIG_NULL_OK, &bltTreeViewUidOption}, {BLT_CONFIG_SHADOW, "-shadow", (char *)NULL, (char *)NULL, (char *)NULL, Blt_Offset(TreeViewEntry, shadow), BLT_CONFIG_NULL_OK | BLT_CONFIG_COLOR_ONLY}, {BLT_CONFIG_SHADOW, "-shadow", (char *)NULL, (char *)NULL, (char *)NULL, Blt_Offset(TreeViewEntry, shadow), BLT_CONFIG_NULL_OK | BLT_CONFIG_MONO_ONLY}, {BLT_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; Blt_ConfigSpec bltTreeViewSpecs[] = { {BLT_CONFIG_CUSTOM, "-activeicons", "activeIcons", "Icons", DEF_TV_ACTIVE_ICONS, Blt_Offset(TreeView, activeIcons), BLT_CONFIG_NULL_OK, &bltTreeViewIconsOption}, {BLT_CONFIG_BITFLAG, "-allowduplicates", "allowDuplicates", "AllowDuplicates", DEF_TV_ALLOW_DUPLICATES, Blt_Offset(TreeView, flags), BLT_CONFIG_DONT_SET_DEFAULT, (Blt_CustomOption *)TV_ALLOW_DUPLICATES}, {BLT_CONFIG_BITFLAG, "-autocreate", "autoCreate", "AutoCreate", DEF_TV_MAKE_PATH, Blt_Offset(TreeView, flags), BLT_CONFIG_DONT_SET_DEFAULT, (Blt_CustomOption *)TV_FILL_ANCESTORS}, {BLT_CONFIG_BORDER, "-background", "background", "Background", DEF_TV_BACKGROUND, Blt_Offset(TreeView, border), 0}, {BLT_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_DISTANCE, "-borderwidth", "borderWidth", "BorderWidth", DEF_TV_BORDERWIDTH, Blt_Offset(TreeView, borderWidth), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_CUSTOM, "-button", "button", "Button", DEF_TV_BUTTON, Blt_Offset(TreeView, buttonFlags), BLT_CONFIG_DONT_SET_DEFAULT, &buttonOption}, {BLT_CONFIG_STRING, "-closecommand", "closeCommand", "CloseCommand", (char *)NULL, Blt_Offset(TreeView, closeCmd), BLT_CONFIG_NULL_OK}, {BLT_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", (char *)NULL, Blt_Offset(TreeView, cursor), BLT_CONFIG_NULL_OK}, {BLT_CONFIG_DASHES, "-dashes", "dashes", "Dashes", DEF_TV_DASHES, Blt_Offset(TreeView, dashes), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_BITFLAG, "-exportselection", "exportSelection", "ExportSelection", DEF_TV_EXPORT_SELECTION, Blt_Offset(TreeView, flags), BLT_CONFIG_DONT_SET_DEFAULT, (Blt_CustomOption *)TV_SELECT_EXPORT}, {BLT_CONFIG_SYNONYM, "-fg", "foreground", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_BOOLEAN, "-flat", "flat", "Flat", DEF_TV_FLAT, Blt_Offset(TreeView, flatView), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_DASHES, "-focusdashes", "focusDashes", "FocusDashes", DEF_TV_FOCUS_DASHES, Blt_Offset(TreeView, focusDashes), BLT_CONFIG_NULL_OK}, {BLT_CONFIG_COLOR, "-focusforeground", "focusForeground", "FocusForeground", DEF_TV_FOCUS_FOREGROUND, Blt_Offset(TreeView, focusColor), BLT_CONFIG_COLOR_ONLY}, {BLT_CONFIG_COLOR, "-focusforeground", "focusForeground", "FocusForeground", DEF_TV_FOCUS_FG_MONO, Blt_Offset(TreeView, focusColor), BLT_CONFIG_MONO_ONLY}, {BLT_CONFIG_FONT, "-font", "font", "Font", DEF_TV_FONT, Blt_Offset(TreeView, font), 0}, {BLT_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_TV_TEXT_COLOR, Blt_Offset(TreeView, fgColor), BLT_CONFIG_COLOR_ONLY}, {BLT_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_TV_TEXT_MONO, Blt_Offset(TreeView, fgColor), BLT_CONFIG_MONO_ONLY}, {BLT_CONFIG_DISTANCE, "-height", "height", "Height", DEF_TV_HEIGHT, Blt_Offset(TreeView, reqHeight), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_BITFLAG, "-hideleaves", "hideLeaves", "HideLeaves", DEF_TV_HIDE_LEAVES, Blt_Offset(TreeView, flags), BLT_CONFIG_DONT_SET_DEFAULT, (Blt_CustomOption *)TV_HIDE_LEAVES}, {BLT_CONFIG_BITFLAG, "-hideroot", "hideRoot", "HideRoot", DEF_TV_HIDE_ROOT, Blt_Offset(TreeView, flags), BLT_CONFIG_DONT_SET_DEFAULT, (Blt_CustomOption *)TV_HIDE_ROOT}, {BLT_CONFIG_COLOR, "-highlightbackground", "highlightBackground", "HighlightBackground", DEF_TV_FOCUS_HIGHLIGHT_BACKGROUND, Blt_Offset(TreeView, highlightBgColor), 0}, {BLT_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", DEF_TV_FOCUS_HIGHLIGHT_COLOR, Blt_Offset(TreeView, highlightColor), 0}, {BLT_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", "HighlightThickness", DEF_TV_FOCUS_HIGHLIGHT_WIDTH, Blt_Offset(TreeView, highlightWidth), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_CUSTOM, "-icons", "icons", "Icons", DEF_TV_ICONS, Blt_Offset(TreeView, icons), BLT_CONFIG_NULL_OK, &bltTreeViewIconsOption}, {BLT_CONFIG_BORDER, "-nofocusselectbackground", "noFocusSelectBackground", "NoFocusSelectBackground", DEF_TV_SELECT_BACKGROUND, Blt_Offset(TreeView, selOutFocusBorder), TK_CONFIG_NULL_OK}, {BLT_CONFIG_COLOR, "-nofocusselectforeground", "noFocusSelectForeground", "NoFocusSelectForeground", DEF_TV_SELECT_FOREGROUND, Blt_Offset(TreeView, selOutFocusFgColor), TK_CONFIG_NULL_OK}, {BLT_CONFIG_COLOR, "-linecolor", "lineColor", "LineColor", DEF_TV_VLINE_COLOR, Blt_Offset(TreeView, lineColor), BLT_CONFIG_COLOR_ONLY}, {BLT_CONFIG_COLOR, "-linecolor", "lineColor", "LineColor", DEF_TV_VLINE_MONO, Blt_Offset(TreeView, lineColor), BLT_CONFIG_MONO_ONLY}, {BLT_CONFIG_DISTANCE, "-linespacing", "lineSpacing", "LineSpacing", DEF_TV_LINESPACING, Blt_Offset(TreeView, leader), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_DISTANCE, "-linewidth", "lineWidth", "LineWidth", DEF_TV_LINEWIDTH, Blt_Offset(TreeView, lineWidth), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_BITFLAG, "-newtags", "newTags", "NewTags", DEF_TV_NEW_TAGS, Blt_Offset(TreeView, flags), BLT_CONFIG_DONT_SET_DEFAULT, (Blt_CustomOption *)TV_NEW_TAGS}, {BLT_CONFIG_STRING, "-opencommand", "openCommand", "OpenCommand", (char *)NULL, Blt_Offset(TreeView, openCmd), BLT_CONFIG_NULL_OK}, {BLT_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_TV_RELIEF, Blt_Offset(TreeView, relief), 0}, {BLT_CONFIG_CURSOR, "-resizecursor", "resizeCursor", "ResizeCursor", DEF_TV_RESIZE_CURSOR, Blt_Offset(TreeView, resizeCursor), 0}, {BLT_CONFIG_CUSTOM, "-scrollmode", "scrollMode", "ScrollMode", DEF_TV_SCROLL_MODE, Blt_Offset(TreeView, scrollMode), BLT_CONFIG_DONT_SET_DEFAULT, &scrollmodeOption}, {BLT_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground", DEF_TV_SELECT_BACKGROUND, Blt_Offset(TreeView, selInFocusBorder), 0}, {BLT_CONFIG_DISTANCE, "-selectborderwidth", "selectBorderWidth", "BorderWidth", DEF_TV_SELECT_BORDERWIDTH, Blt_Offset(TreeView, selBorderWidth), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_STRING, "-selectcommand", "selectCommand", "SelectCommand", (char *)NULL, Blt_Offset(TreeView, selectCmd), BLT_CONFIG_NULL_OK}, {BLT_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background", DEF_TV_SELECT_FOREGROUND, Blt_Offset(TreeView, selInFocusFgColor), 0}, {BLT_CONFIG_CUSTOM, "-selectmode", "selectMode", "SelectMode", DEF_TV_SELECT_MODE, Blt_Offset(TreeView, selectMode), BLT_CONFIG_DONT_SET_DEFAULT, &selectmodeOption}, {BLT_CONFIG_RELIEF, "-selectrelief", "selectRelief", "Relief", DEF_TV_SELECT_RELIEF, Blt_Offset(TreeView, selRelief), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_CUSTOM, "-separator", "separator", "Separator", (char *)NULL, Blt_Offset(TreeView, pathSep), BLT_CONFIG_NULL_OK, &separatorOption}, {BLT_CONFIG_BITFLAG, "-showtitles", "showTitles", "ShowTitles", DEF_TV_SHOW_TITLES, Blt_Offset(TreeView, flags), 0, (Blt_CustomOption *)TV_SHOW_COLUMN_TITLES}, {BLT_CONFIG_BITFLAG, "-sortselection", "sortSelection", "SortSelection", DEF_TV_SORT_SELECTION, Blt_Offset(TreeView, flags), BLT_CONFIG_DONT_SET_DEFAULT, (Blt_CustomOption *)TV_SELECT_SORTED}, {BLT_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", DEF_TV_TAKE_FOCUS, Blt_Offset(TreeView, takeFocus), BLT_CONFIG_NULL_OK}, {BLT_CONFIG_CUSTOM, "-tree", "tree", "Tree", (char *)NULL, Blt_Offset(TreeView, tree), BLT_CONFIG_NULL_OK, &bltTreeViewTreeOption}, {BLT_CONFIG_STRING, "-trim", "trim", "Trim", DEF_TV_TRIMLEFT, Blt_Offset(TreeView, trimLeft), BLT_CONFIG_NULL_OK}, {BLT_CONFIG_DISTANCE, "-width", "width", "Width", DEF_TV_WIDTH, Blt_Offset(TreeView, reqWidth), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand", (char *)NULL, Blt_Offset(TreeView, xScrollCmdPrefix), BLT_CONFIG_NULL_OK}, {BLT_CONFIG_DISTANCE, "-xscrollincrement", "xScrollIncrement", "ScrollIncrement", DEF_TV_SCROLL_INCREMENT, Blt_Offset(TreeView, xScrollUnits), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand", (char *)NULL, Blt_Offset(TreeView, yScrollCmdPrefix), BLT_CONFIG_NULL_OK}, {BLT_CONFIG_DISTANCE, "-yscrollincrement", "yScrollIncrement", "ScrollIncrement", DEF_TV_SCROLL_INCREMENT, Blt_Offset(TreeView, yScrollUnits), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; /* Forward Declarations */ static Blt_TreeNotifyEventProc TreeEventProc; static Blt_TreeTraceProc TreeTraceProc; static Tcl_CmdDeleteProc WidgetInstCmdDeleteProc; static Tcl_FreeProc DestroyTreeView; static Tcl_IdleProc DisplayTreeView; static Tk_EventProc TreeViewEventProc; static int ComputeVisibleEntries _ANSI_ARGS_((TreeView *tvPtr)); EXTERN int Blt_TreeCmdGetToken _ANSI_ARGS_((Tcl_Interp *interp, CONST char *treeName, Blt_Tree *treePtr)); extern Blt_TreeApplyProc Blt_TreeViewSortApplyProc; static Blt_BindPickProc PickItem; static Blt_BindTagProc GetTags; static Tcl_FreeProc DestroyEntry; static Tcl_ObjCmdProc TreeViewObjCmd; static Tk_ImageChangedProc IconChangedProc; static Tk_SelectionProc SelectionProc; /* *---------------------------------------------------------------------- * * Blt_TreeViewEventuallyRedraw -- * * Queues a request to redraw the widget at the next idle point. * * Results: * None. * * Side effects: * Information gets redisplayed. Right now we don't do selective * redisplays: the whole window will be redrawn. * *---------------------------------------------------------------------- */ void Blt_TreeViewEventuallyRedraw(TreeView *tvPtr) { if ((tvPtr->tkwin != NULL) && ((tvPtr->flags & TV_REDRAW) == 0)) { tvPtr->flags |= TV_REDRAW; Tcl_DoWhenIdle(DisplayTreeView, tvPtr); } } void Blt_TreeViewTraceColumn(TreeView *tvPtr, TreeViewColumn *columnPtr) { Blt_TreeCreateTrace(tvPtr->tree, NULL /* Node */, columnPtr->key, NULL, TREE_TRACE_FOREIGN_ONLY | TREE_TRACE_WRITE | TREE_TRACE_UNSET, TreeTraceProc, tvPtr); } static void TraceColumns(TreeView *tvPtr) { Blt_ChainLink *linkPtr; TreeViewColumn *columnPtr; for(linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { columnPtr = Blt_ChainGetValue(linkPtr); Blt_TreeCreateTrace( tvPtr->tree, NULL /* Node */, columnPtr->key /* Key pattern */, NULL /* Tag */, TREE_TRACE_FOREIGN_ONLY | TREE_TRACE_WRITE | TREE_TRACE_UNSET, TreeTraceProc /* Callback routine */, tvPtr /* Client data */); } } /* *---------------------------------------------------------------------- * * ObjToTree -- * * Convert the string representing the name of a tree object * into a tree token. * * Results: * If the string is successfully converted, TCL_OK is returned. * Otherwise, TCL_ERROR is returned and an error message is left * in interpreter's result field. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ObjToTree( ClientData clientData, /* Not used. */ Tcl_Interp *interp, /* Interpreter to send results back to */ Tk_Window tkwin, /* Not used. */ Tcl_Obj *objPtr, /* Tcl_Obj representing the new value. */ char *widgRec, int offset) { Blt_Tree *treePtr = (Blt_Tree *)(widgRec + offset); Blt_Tree tree; char *string; tree = NULL; string = Tcl_GetString(objPtr); if ((string[0] != '\0') && (Blt_TreeGetToken(interp, string, &tree) != TCL_OK)) { return TCL_ERROR; } *treePtr = tree; return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeToObj -- * * Results: * The string representation of the button boolean is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static Tcl_Obj * TreeToObj( ClientData clientData, /* Not used. */ Tcl_Interp *interp, Tk_Window tkwin, /* Not used. */ char *widgRec, int offset) { Blt_Tree tree = *(Blt_Tree *)(widgRec + offset); if (tree == NULL) { return bltEmptyStringObjPtr; } else { return Tcl_NewStringObj(Blt_TreeName(tree), -1); } } /*ARGSUSED*/ static void FreeTree( ClientData clientData, Display *display, /* Not used. */ char *widgRec, int offset) { Blt_Tree *treePtr = (Blt_Tree *)(widgRec + offset); if (*treePtr != NULL) { Blt_TreeNode root; TreeView *tvPtr = clientData; /* * Release the current tree, removing any entry fields. */ root = Blt_TreeRootNode(*treePtr); Blt_TreeApply(root, DeleteApplyProc, tvPtr); Blt_TreeViewClearSelection(tvPtr); Blt_TreeReleaseToken(*treePtr); } } /* *---------------------------------------------------------------------- * * ObjToScrollmode -- * * Convert the string reprsenting a scroll mode, to its numeric * form. * * Results: * If the string is successfully converted, TCL_OK is returned. * Otherwise, TCL_ERROR is returned and an error message is left * in interpreter's result field. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ObjToScrollmode( ClientData clientData, /* Not used. */ Tcl_Interp *interp, /* Interpreter to send results back to */ Tk_Window tkwin, /* Not used. */ Tcl_Obj *objPtr, /* New legend position string */ char *widgRec, int offset) { char *string; char c; int *modePtr = (int *)(widgRec + offset); string = Tcl_GetString(objPtr); c = string[0]; if ((c == 'l') && (strcmp(string, "listbox") == 0)) { *modePtr = BLT_SCROLL_MODE_LISTBOX; } else if ((c == 't') && (strcmp(string, "treeview") == 0)) { *modePtr = BLT_SCROLL_MODE_HIERBOX; } else if ((c == 'h') && (strcmp(string, "hiertable") == 0)) { *modePtr = BLT_SCROLL_MODE_HIERBOX; } else if ((c == 'c') && (strcmp(string, "canvas") == 0)) { *modePtr = BLT_SCROLL_MODE_CANVAS; } else { Tcl_AppendResult(interp, "bad scroll mode \"", string, "\": should be \"treeview\", \"listbox\", or \"canvas\"", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * ScrollmodeToObj -- * * Results: * The string representation of the button boolean is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static Tcl_Obj * ScrollmodeToObj( ClientData clientData, /* Not used. */ Tcl_Interp *interp, Tk_Window tkwin, /* Not used. */ char *widgRec, int offset) { int mode = *(int *)(widgRec + offset); switch (mode) { case BLT_SCROLL_MODE_LISTBOX: return Tcl_NewStringObj("listbox", -1); case BLT_SCROLL_MODE_HIERBOX: return Tcl_NewStringObj("hierbox", -1); case BLT_SCROLL_MODE_CANVAS: return Tcl_NewStringObj("canvas", -1); default: return Tcl_NewStringObj("unknown scroll mode", -1); } } /* *---------------------------------------------------------------------- * * ObjToSelectmode -- * * Convert the string reprsenting a scroll mode, to its numeric * form. * * Results: * If the string is successfully converted, TCL_OK is returned. * Otherwise, TCL_ERROR is returned and an error message is left * in interpreter's result field. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ObjToSelectmode( ClientData clientData, /* Not used. */ Tcl_Interp *interp, /* Interpreter to send results back to */ Tk_Window tkwin, /* Not used. */ Tcl_Obj *objPtr, /* Tcl_Obj representing the new value. */ char *widgRec, int offset) { char *string; char c; int *modePtr = (int *)(widgRec + offset); string = Tcl_GetString(objPtr); c = string[0]; if ((c == 's') && (strcmp(string, "single") == 0)) { *modePtr = SELECT_MODE_SINGLE; } else if ((c == 'm') && (strcmp(string, "multiple") == 0)) { *modePtr = SELECT_MODE_MULTIPLE; } else if ((c == 'a') && (strcmp(string, "active") == 0)) { *modePtr = SELECT_MODE_SINGLE; } else { Tcl_AppendResult(interp, "bad select mode \"", string, "\": should be \"single\" or \"multiple\"", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * SelectmodeToObj -- * * Results: * The string representation of the button boolean is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static Tcl_Obj * SelectmodeToObj( ClientData clientData, /* Not used. */ Tcl_Interp *interp, Tk_Window tkwin, /* Not used. */ char *widgRec, int offset) { int mode = *(int *)(widgRec + offset); switch (mode) { case SELECT_MODE_SINGLE: return Tcl_NewStringObj("single", -1); case SELECT_MODE_MULTIPLE: return Tcl_NewStringObj("multiple", -1); default: return Tcl_NewStringObj("unknown scroll mode", -1); } } /* *---------------------------------------------------------------------- * * ObjToButton -- * * Convert a string to one of three values. * 0 - false, no, off * 1 - true, yes, on * 2 - auto * Results: * If the string is successfully converted, TCL_OK is returned. * Otherwise, TCL_ERROR is returned and an error message is left in * interpreter's result field. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ObjToButton( ClientData clientData, /* Not used. */ Tcl_Interp *interp, /* Interpreter to send results back to */ Tk_Window tkwin, /* Not used. */ Tcl_Obj *objPtr, /* Tcl_Obj representing the new value. */ char *widgRec, int offset) { char *string; int *flagsPtr = (int *)(widgRec + offset); string = Tcl_GetString(objPtr); if ((string[0] == 'a') && (strcmp(string, "auto") == 0)) { *flagsPtr &= ~BUTTON_MASK; *flagsPtr |= BUTTON_AUTO; } else { int bool; if (Tcl_GetBooleanFromObj(interp, objPtr, &bool) != TCL_OK) { return TCL_ERROR; } *flagsPtr &= ~BUTTON_MASK; if (bool) { *flagsPtr |= BUTTON_SHOW; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * ButtonToObj -- * * Results: * The string representation of the button boolean is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static Tcl_Obj * ButtonToObj( ClientData clientData, /* Not used. */ Tcl_Interp *interp, Tk_Window tkwin, /* Not used. */ char *widgRec, int offset) { int bool; unsigned int flags = *(int *)(widgRec + offset); bool = (flags & BUTTON_MASK); if (bool == BUTTON_AUTO) { return Tcl_NewStringObj("auto", 4); } else { return Tcl_NewBooleanObj(bool); } } /* *---------------------------------------------------------------------- * * ObjToScrollmode -- * * Convert the string reprsenting a scroll mode, to its numeric * form. * * Results: * If the string is successfully converted, TCL_OK is returned. * Otherwise, TCL_ERROR is returned and an error message is left * in interpreter's result field. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ObjToSeparator(clientData, interp, tkwin, objPtr, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ Tcl_Obj *objPtr; /* Tcl_Obj representing the new value. */ char *widgRec; int offset; { char **sepPtr = (char **)(widgRec + offset); char *string; string = Tcl_GetString(objPtr); if (*string == '\0') { *sepPtr = SEPARATOR_LIST; } else if (strcmp(string, "none") == 0) { *sepPtr = SEPARATOR_NONE; } else { *sepPtr = Blt_Strdup(string); } return TCL_OK; } /* *---------------------------------------------------------------------- * * SeparatorToObj -- * * Results: * The string representation of the separator is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static Tcl_Obj * SeparatorToObj( ClientData clientData, /* Not used. */ Tcl_Interp *interp, Tk_Window tkwin, /* Not used. */ char *widgRec, int offset) { char *separator = *(char **)(widgRec + offset); if (separator == SEPARATOR_NONE) { return bltEmptyStringObjPtr; } else if (separator == SEPARATOR_LIST) { return Tcl_NewStringObj("list", -1); } else { return Tcl_NewStringObj(separator, -1); } } /* *---------------------------------------------------------------------- * * FreeSeparator -- * * Free the UID from the widget record, setting it to NULL. * * Results: * The UID in the widget record is set to NULL. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static void FreeSeparator( ClientData clientData, Display *display, /* Not used. */ char *widgRec, int offset) { char *separator = *(char **)(widgRec + offset); if ((separator != SEPARATOR_LIST) && (separator != SEPARATOR_NONE)) { Blt_Free(separator); } } /* *---------------------------------------------------------------------- * * ObjToLabel -- * * Convert the string representing the label. * * Results: * If the string is successfully converted, TCL_OK is returned. * Otherwise, TCL_ERROR is returned and an error message is left * in interpreter's result field. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ObjToLabel( ClientData clientData, /* Not used. */ Tcl_Interp *interp, /* Interpreter to send results back to */ Tk_Window tkwin, /* Not used. */ Tcl_Obj *objPtr, /* Tcl_Obj representing the new value. */ char *widgRec, int offset) { UID *labelPtr = (UID *)(widgRec + offset); char *string; string = Tcl_GetString(objPtr); if (string[0] != '\0') { TreeView *tvPtr = clientData; *labelPtr = Blt_TreeViewGetUid(tvPtr, string); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeToObj -- * * Results: * The string of the entry's label is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static Tcl_Obj * LabelToObj( ClientData clientData, /* Not used. */ Tcl_Interp *interp, Tk_Window tkwin, /* Not used. */ char *widgRec, int offset) { UID labelUid = *(UID *)(widgRec + offset); char *string; if (labelUid == NULL) { TreeViewEntry *entryPtr = (TreeViewEntry *)widgRec; string = Blt_TreeNodeLabel(entryPtr->node); } else { string = labelUid; } return Tcl_NewStringObj(string, -1); } /*ARGSUSED*/ static void FreeLabel( ClientData clientData, Display *display, /* Not used. */ char *widgRec, int offset) { UID *labelPtr = (UID *)(widgRec + offset); if (*labelPtr != NULL) { TreeView *tvPtr = clientData; Blt_TreeViewFreeUid(tvPtr, *labelPtr); } } /* *---------------------------------------------------------------------- * * Blt_TreeViewGetUid -- * * Gets or creates a unique string identifier. Strings are * reference counted. The string is placed into a hashed table * local to the treeview. * * Results: * Returns the pointer to the hashed string. * *---------------------------------------------------------------------- */ UID Blt_TreeViewGetUid(TreeView *tvPtr, CONST char *string) { Blt_HashEntry *hPtr; int isNew; int refCount; hPtr = Blt_CreateHashEntry(&tvPtr->uidTable, string, &isNew); if (isNew) { refCount = 1; } else { refCount = (int)Blt_GetHashValue(hPtr); refCount++; } Blt_SetHashValue(hPtr, (ClientData)refCount); return Blt_GetHashKey(&tvPtr->uidTable, hPtr); } /* *---------------------------------------------------------------------- * * Blt_TreeViewFreeUid -- * * Releases the uid. Uids are reference counted, so only when * the reference count is zero (i.e. no one else is using the * string) is the entry removed from the hash table. * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_TreeViewFreeUid(TreeView *tvPtr, UID uid) { Blt_HashEntry *hPtr; int refCount; hPtr = Blt_FindHashEntry(&tvPtr->uidTable, uid); assert(hPtr != NULL); refCount = (int)Blt_GetHashValue(hPtr); refCount--; if (refCount > 0) { Blt_SetHashValue(hPtr, (ClientData)refCount); } else { Blt_DeleteHashEntry(&tvPtr->uidTable, hPtr); } } /* *---------------------------------------------------------------------- * * ObjToUid -- * * Converts the string to a Uid. Uid's are hashed, reference * counted strings. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ObjToUid( ClientData clientData, /* Not used. */ Tcl_Interp *interp, /* Interpreter to send results back to */ Tk_Window tkwin, /* Not used. */ Tcl_Obj *objPtr, /* Tcl_Obj representing the new value. */ char *widgRec, int offset) { TreeView *tvPtr = clientData; UID *uidPtr = (UID *)(widgRec + offset); UID newId; char *string; newId = NULL; string = Tcl_GetString(objPtr); if (*string != '\0') { newId = Blt_TreeViewGetUid(tvPtr, string); } *uidPtr = newId; return TCL_OK; } /* *---------------------------------------------------------------------- * * UidToObj -- * * Returns the uid as a string. * * Results: * The fill style string is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static Tcl_Obj * UidToObj( ClientData clientData, /* Not used. */ Tcl_Interp *interp, Tk_Window tkwin, /* Not used. */ char *widgRec, int offset) { UID uid = *(UID *)(widgRec + offset); if (uid == NULL) { return bltEmptyStringObjPtr; } return Tcl_NewStringObj(uid, -1); } /* *---------------------------------------------------------------------- * * FreeUid -- * * Free the UID from the widget record, setting it to NULL. * * Results: * The UID in the widget record is set to NULL. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static void FreeUid( ClientData clientData, Display *display, /* Not used. */ char *widgRec, int offset) { UID *uidPtr = (UID *)(widgRec + offset); if (*uidPtr != NULL) { TreeView *tvPtr = clientData; Blt_TreeViewFreeUid(tvPtr, *uidPtr); } } /* *---------------------------------------------------------------------- * * IconChangedProc * * * Results: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static void IconChangedProc( ClientData clientData, int x, /* Not used. */ int y, /* Not used. */ int width, /* Not used. */ int height, /* Not used. */ int imageWidth, /* Not used. */ int imageHeight) /* Not used. */ { TreeView *tvPtr = clientData; tvPtr->flags |= (TV_DIRTY | TV_LAYOUT | TV_SCROLL); Blt_TreeViewEventuallyRedraw(tvPtr); } TreeViewIcon Blt_TreeViewGetIcon(TreeView *tvPtr, CONST char *iconName) { Blt_HashEntry *hPtr; int isNew; struct TreeViewIconStruct *iconPtr; hPtr = Blt_CreateHashEntry(&tvPtr->iconTable, iconName, &isNew); if (isNew) { Tk_Image tkImage; int width, height; tkImage = Tk_GetImage(tvPtr->interp, tvPtr->tkwin, (char *)iconName, IconChangedProc, tvPtr); if (tkImage == NULL) { Blt_DeleteHashEntry(&tvPtr->iconTable, hPtr); return NULL; } Tk_SizeOfImage(tkImage, &width, &height); iconPtr = Blt_Malloc(sizeof(struct TreeViewIconStruct)); iconPtr->tkImage = tkImage; iconPtr->hashPtr = hPtr; iconPtr->refCount = 1; iconPtr->width = width; iconPtr->height = height; Blt_SetHashValue(hPtr, iconPtr); } else { iconPtr = Blt_GetHashValue(hPtr); iconPtr->refCount++; } return iconPtr; } void Blt_TreeViewFreeIcon( TreeView *tvPtr, struct TreeViewIconStruct *iconPtr) { iconPtr->refCount--; if (iconPtr->refCount == 0) { Blt_DeleteHashEntry(&tvPtr->iconTable, iconPtr->hashPtr); Tk_FreeImage(iconPtr->tkImage); Blt_Free(iconPtr); } } static void DumpIconTable(TreeView *tvPtr) { Blt_HashEntry *hPtr; Blt_HashSearch cursor; struct TreeViewIconStruct *iconPtr; for (hPtr = Blt_FirstHashEntry(&tvPtr->iconTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { iconPtr = Blt_GetHashValue(hPtr); Tk_FreeImage(iconPtr->tkImage); Blt_Free(iconPtr); } Blt_DeleteHashTable(&tvPtr->iconTable); } /* *---------------------------------------------------------------------- * * ObjToIcons -- * * Convert a list of image names into Tk images. * * Results: * If the string is successfully converted, TCL_OK is returned. * Otherwise, TCL_ERROR is returned and an error message is left in * interpreter's result field. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ObjToIcons( ClientData clientData, /* Not used. */ Tcl_Interp *interp, /* Interpreter to send results back to */ Tk_Window tkwin, /* Not used. */ Tcl_Obj *objPtr, /* Tcl_Obj representing the new value. */ char *widgRec, int offset) { Tcl_Obj **objv; TreeView *tvPtr = clientData; TreeViewIcon **iconPtrPtr = (TreeViewIcon **)(widgRec + offset); TreeViewIcon *icons; int objc; int result; result = TCL_OK; icons = NULL; if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { return TCL_ERROR; } if (objc > 0) { register int i; icons = Blt_Malloc(sizeof(TreeViewIcon *) * (objc + 1)); assert(icons); for (i = 0; i < objc; i++) { icons[i] = Blt_TreeViewGetIcon(tvPtr, Tcl_GetString(objv[i])); if (icons[i] == NULL) { result = TCL_ERROR; break; } } icons[i] = NULL; } *iconPtrPtr = icons; return result; } /* *---------------------------------------------------------------------- * * IconsToObj -- * * Converts the icon into its string representation (its name). * * Results: * The name of the icon is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static Tcl_Obj * IconsToObj( ClientData clientData, /* Not used. */ Tcl_Interp *interp, Tk_Window tkwin, /* Not used. */ char *widgRec, int offset) { TreeViewIcon *icons = *(TreeViewIcon **)(widgRec + offset); Tcl_Obj *listObjPtr; listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); if (icons != NULL) { register TreeViewIcon *iconPtr; Tcl_Obj *objPtr; for (iconPtr = icons; *iconPtr != NULL; iconPtr++) { objPtr = Tcl_NewStringObj(Blt_NameOfImage((*iconPtr)->tkImage), -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } } return listObjPtr; } /*ARGSUSED*/ static void FreeIcons( ClientData clientData, Display *display, /* Not used. */ char *widgRec, int offset) { TreeViewIcon *icons = *(TreeViewIcon **)(widgRec + offset); if (icons != NULL) { register TreeViewIcon *iconPtr; TreeView *tvPtr = clientData; for (iconPtr = icons; *iconPtr != NULL; iconPtr++) { Blt_TreeViewFreeIcon(tvPtr, *iconPtr); } Blt_Free(icons); } } TreeViewEntry * Blt_NodeToEntry(TreeView *tvPtr, Blt_TreeNode node) { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&tvPtr->entryTable, (char *)node); if (hPtr == NULL) { abort(); return NULL; } return Blt_GetHashValue(hPtr); } int Blt_TreeViewApply( TreeView *tvPtr, TreeViewEntry *entryPtr, /* Root entry of subtree. */ TreeViewApplyProc *proc, /* Procedure to call for each entry. */ unsigned int flags) { if ((flags & ENTRY_HIDDEN) && (Blt_TreeViewEntryIsHidden(entryPtr))) { return TCL_OK; /* Hidden node. */ } if ((flags & ENTRY_HIDDEN) && (entryPtr->flags & ENTRY_HIDDEN)) { return TCL_OK; /* Hidden node. */ } if (((flags & ENTRY_CLOSED) == 0) || ((entryPtr->flags & ENTRY_CLOSED) == 0)) { TreeViewEntry *childPtr; Blt_TreeNode node, next; for (node = Blt_TreeFirstChild(entryPtr->node); node != NULL; node = next) { next = Blt_TreeNextSibling(node); /* * Get the next child before calling Blt_TreeViewApply * recursively. This is because the apply callback may * delete the node and its link. */ childPtr = Blt_NodeToEntry(tvPtr, node); if (Blt_TreeViewApply(tvPtr, childPtr, proc, flags) != TCL_OK) { return TCL_ERROR; } } } if ((*proc) (tvPtr, entryPtr) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } int Blt_TreeViewEntryIsHidden(TreeViewEntry *entryPtr) { TreeView *tvPtr = entryPtr->tvPtr; if ((tvPtr->flags & TV_HIDE_LEAVES) && (Blt_TreeIsLeaf(entryPtr->node))) { return TRUE; } return (entryPtr->flags & ENTRY_HIDDEN) ? TRUE : FALSE; } #ifdef notdef int Blt_TreeViewEntryIsMapped(TreeViewEntry *entryPtr) { TreeView *tvPtr = entryPtr->tvPtr; /* Don't check if the entry itself is open, only that its * ancestors are. */ if (Blt_TreeViewEntryIsHidden(entryPtr)) { return FALSE; } if (entryPtr == tvPtr->rootPtr) { return TRUE; } entryPtr = Blt_TreeViewParentEntry(entryPtr); while (entryPtr != tvPtr->rootPtr) { if (entryPtr->flags & (ENTRY_CLOSED | ENTRY_HIDDEN)) { return FALSE; } entryPtr = Blt_TreeViewParentEntry(entryPtr); } return TRUE; } #endif TreeViewEntry * Blt_TreeViewFirstChild(TreeViewEntry *entryPtr, unsigned int mask) { Blt_TreeNode node; TreeView *tvPtr = entryPtr->tvPtr; for (node = Blt_TreeFirstChild(entryPtr->node); node != NULL; node = Blt_TreeNextSibling(node)) { entryPtr = Blt_NodeToEntry(tvPtr, node); if (((mask & ENTRY_HIDDEN) == 0) || (!Blt_TreeViewEntryIsHidden(entryPtr))) { return entryPtr; } } return NULL; } TreeViewEntry * Blt_TreeViewLastChild(TreeViewEntry *entryPtr, unsigned int mask) { Blt_TreeNode node; TreeView *tvPtr = entryPtr->tvPtr; for (node = Blt_TreeLastChild(entryPtr->node); node != NULL; node = Blt_TreePrevSibling(node)) { entryPtr = Blt_NodeToEntry(tvPtr, node); if (((mask & ENTRY_HIDDEN) == 0) || (!Blt_TreeViewEntryIsHidden(entryPtr))) { return entryPtr; } } return NULL; } TreeViewEntry * Blt_TreeViewNextSibling(TreeViewEntry *entryPtr, unsigned int mask) { Blt_TreeNode node; TreeView *tvPtr = entryPtr->tvPtr; for (node = Blt_TreeNextSibling(entryPtr->node); node != NULL; node = Blt_TreeNextSibling(node)) { entryPtr = Blt_NodeToEntry(tvPtr, node); if (((mask & ENTRY_HIDDEN) == 0) || (!Blt_TreeViewEntryIsHidden(entryPtr))) { return entryPtr; } } return NULL; } TreeViewEntry * Blt_TreeViewPrevSibling(TreeViewEntry *entryPtr, unsigned int mask) { Blt_TreeNode node; TreeView *tvPtr = entryPtr->tvPtr; for (node = Blt_TreePrevSibling(entryPtr->node); node != NULL; node = Blt_TreePrevSibling(node)) { entryPtr = Blt_NodeToEntry(tvPtr, node); if (((mask & ENTRY_HIDDEN) == 0) || (!Blt_TreeViewEntryIsHidden(entryPtr))) { return entryPtr; } } return NULL; } /* *---------------------------------------------------------------------- * * Blt_TreeViewPrevEntry -- * * Returns the "previous" node in the tree. This node (in * depth-first order) is its parent if the node has no siblings * that are previous to it. Otherwise it is the last descendant * of the last sibling. In this case, descend the sibling's * hierarchy, using the last child at any ancestor, until we * we find a leaf. * *---------------------------------------------------------------------- */ TreeViewEntry * Blt_TreeViewPrevEntry(TreeViewEntry *entryPtr, unsigned int mask) { TreeView *tvPtr = entryPtr->tvPtr; TreeViewEntry *prevPtr; if (entryPtr->node == Blt_TreeRootNode(tvPtr->tree)) { return NULL; /* The root is the first node. */ } prevPtr = Blt_TreeViewPrevSibling(entryPtr, mask); if (prevPtr == NULL) { /* There are no siblings previous to this one, so pick the parent. */ prevPtr = Blt_TreeViewParentEntry(entryPtr); } else { /* * Traverse down the right-most thread in order to select the * last entry. Stop if we find a "closed" entry or reach a leaf. */ entryPtr = prevPtr; while ((entryPtr->flags & mask) == 0) { entryPtr = Blt_TreeViewLastChild(entryPtr, mask); if (entryPtr == NULL) { break; /* Found a leaf. */ } prevPtr = entryPtr; } } if (prevPtr == NULL) { return NULL; } return prevPtr; } /* *---------------------------------------------------------------------- * * Blt_TreeViewNextNode -- * * Returns the "next" node in relation to the given node. * The next node (in depth-first order) is either the first * child of the given node the next sibling if the node has * no children (the node is a leaf). If the given node is the * last sibling, then try it's parent next sibling. Continue * until we either find a next sibling for some ancestor or * we reach the root node. In this case the current node is * the last node in the tree. * *---------------------------------------------------------------------- */ TreeViewEntry * Blt_TreeViewNextEntry(TreeViewEntry *entryPtr, unsigned int mask) { TreeView *tvPtr = entryPtr->tvPtr; TreeViewEntry *nextPtr; int ignoreLeaf; ignoreLeaf = ((tvPtr->flags & TV_HIDE_LEAVES) && (Blt_TreeIsLeaf(entryPtr->node))); if ((!ignoreLeaf) && ((entryPtr->flags & mask) == 0)) { nextPtr = Blt_TreeViewFirstChild(entryPtr, mask); if (nextPtr != NULL) { return nextPtr; /* Pick the first sub-node. */ } } /* * Back up until to a level where we can pick a "next sibling". * For the last entry we'll thread our way back to the root. */ while (entryPtr != tvPtr->rootPtr) { nextPtr = Blt_TreeViewNextSibling(entryPtr, mask); if (nextPtr != NULL) { return nextPtr; } entryPtr = Blt_TreeViewParentEntry(entryPtr); } return NULL; /* At root, no next node. */ } void Blt_TreeViewConfigureButtons(TreeView *tvPtr) { GC newGC; TreeViewButton *buttonPtr = &tvPtr->button; XGCValues gcValues; unsigned long gcMask; gcMask = GCForeground; gcValues.foreground = buttonPtr->fgColor->pixel; newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues); if (buttonPtr->normalGC != NULL) { Tk_FreeGC(tvPtr->display, buttonPtr->normalGC); } buttonPtr->normalGC = newGC; gcMask = GCForeground; gcValues.foreground = buttonPtr->activeFgColor->pixel; newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues); if (buttonPtr->activeGC != NULL) { Tk_FreeGC(tvPtr->display, buttonPtr->activeGC); } buttonPtr->activeGC = newGC; buttonPtr->width = buttonPtr->height = ODD(buttonPtr->reqSize); if (buttonPtr->icons != NULL) { register int i; int width, height; for (i = 0; i < 2; i++) { if (buttonPtr->icons[i] == NULL) { break; } width = TreeViewIconWidth(buttonPtr->icons[i]); height = TreeViewIconWidth(buttonPtr->icons[i]); if (buttonPtr->width < width) { buttonPtr->width = width; } if (buttonPtr->height < height) { buttonPtr->height = height; } } } buttonPtr->width += 2 * buttonPtr->borderWidth; buttonPtr->height += 2 * buttonPtr->borderWidth; } int Blt_TreeViewConfigureEntry( TreeView *tvPtr, TreeViewEntry *entryPtr, int objc, Tcl_Obj *CONST *objv, int flags) { GC newGC; Blt_ChainLink *linkPtr; TreeViewColumn *columnPtr; bltTreeViewIconsOption.clientData = tvPtr; bltTreeViewUidOption.clientData = tvPtr; labelOption.clientData = tvPtr; if (Blt_ConfigureWidgetFromObj(tvPtr->interp, tvPtr->tkwin, bltTreeViewEntrySpecs, objc, objv, (char *)entryPtr, flags) != TCL_OK) { return TCL_ERROR; } /* * Check if there are values that need to be added */ for(linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { columnPtr = Blt_ChainGetValue(linkPtr); Blt_TreeViewAddValue(entryPtr, columnPtr); } newGC = NULL; if ((entryPtr->font != NULL) || (entryPtr->color != NULL)) { Tk_Font font; XColor *colorPtr; XGCValues gcValues; unsigned long gcMask; font = entryPtr->font; if (font == NULL) { font = Blt_TreeViewGetStyleFont(tvPtr, tvPtr->treeColumn.stylePtr); } colorPtr = CHOOSE(tvPtr->fgColor, entryPtr->color); gcMask = GCForeground | GCFont; gcValues.foreground = colorPtr->pixel; gcValues.font = Tk_FontId(font); newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues); } if (entryPtr->gc != NULL) { Tk_FreeGC(tvPtr->display, entryPtr->gc); } /* Assume all changes require a new layout. */ entryPtr->gc = newGC; entryPtr->flags |= ENTRY_LAYOUT_PENDING; if (Blt_ObjConfigModified(bltTreeViewEntrySpecs, "-font", (char *)NULL)) { tvPtr->flags |= TV_UPDATE; } tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT); return TCL_OK; } void Blt_TreeViewDestroyValue(TreeView *tvPtr, TreeViewValue *valuePtr) { if (valuePtr->stylePtr != NULL) { Blt_TreeViewFreeStyle(tvPtr, valuePtr->stylePtr); } if (valuePtr->textPtr != NULL) { Blt_Free(valuePtr->textPtr); } } static void DestroyEntry(DestroyData data) { TreeViewEntry *entryPtr = (TreeViewEntry *)data; TreeView *tvPtr; tvPtr = entryPtr->tvPtr; bltTreeViewIconsOption.clientData = tvPtr; bltTreeViewUidOption.clientData = tvPtr; labelOption.clientData = tvPtr; Blt_FreeObjOptions(bltTreeViewEntrySpecs, (char *)entryPtr, tvPtr->display, 0); if (!Blt_TreeTagTableIsShared(tvPtr->tree)) { /* Don't clear tags unless this client is the only one using * the tag table.*/ Blt_TreeClearTags(tvPtr->tree, entryPtr->node); } if (entryPtr->gc != NULL) { Tk_FreeGC(tvPtr->display, entryPtr->gc); } if (entryPtr->shadow.color != NULL) { Tk_FreeColor(entryPtr->shadow.color); } /* Delete the chain of data values from the entry. */ if (entryPtr->values != NULL) { TreeViewValue *valuePtr, *nextPtr; for (valuePtr = entryPtr->values; valuePtr != NULL; valuePtr = nextPtr) { nextPtr = valuePtr->nextPtr; Blt_TreeViewDestroyValue(tvPtr, valuePtr); } entryPtr->values = NULL; } if (entryPtr->fullName != NULL) { Blt_Free(entryPtr->fullName); } if (entryPtr->textPtr != NULL) { Blt_Free(entryPtr->textPtr); } Blt_PoolFreeItem(tvPtr->entryPool, entryPtr); } TreeViewEntry * Blt_TreeViewParentEntry(TreeViewEntry *entryPtr) { TreeView *tvPtr = entryPtr->tvPtr; Blt_TreeNode node; if (entryPtr->node == Blt_TreeRootNode(tvPtr->tree)) { return NULL; } node = Blt_TreeNodeParent(entryPtr->node); if (node == NULL) { return NULL; } return Blt_NodeToEntry(tvPtr, node); } static void FreeEntry(TreeView *tvPtr, TreeViewEntry *entryPtr) { Blt_HashEntry *hPtr; if (entryPtr == tvPtr->activePtr) { tvPtr->activePtr = Blt_TreeViewParentEntry(entryPtr); } if (entryPtr == tvPtr->activeButtonPtr) { tvPtr->activeButtonPtr = NULL; } if (entryPtr == tvPtr->focusPtr) { tvPtr->focusPtr = Blt_TreeViewParentEntry(entryPtr); Blt_SetFocusItem(tvPtr->bindTable, tvPtr->focusPtr, ITEM_ENTRY); } if (entryPtr == tvPtr->selAnchorPtr) { tvPtr->selMarkPtr = tvPtr->selAnchorPtr = NULL; } Blt_TreeViewDeselectEntry(tvPtr, entryPtr); Blt_TreeViewPruneSelection(tvPtr, entryPtr); Blt_DeleteBindings(tvPtr->bindTable, entryPtr); hPtr = Blt_FindHashEntry(&tvPtr->entryTable, entryPtr->node); if (hPtr != NULL) { Blt_DeleteHashEntry(&tvPtr->entryTable, hPtr); } entryPtr->node = NULL; Tcl_EventuallyFree(entryPtr, DestroyEntry); /* * Indicate that the screen layout of the hierarchy may have changed * because this node was deleted. The screen positions of the nodes * in tvPtr->visibleArr are invalidated. */ tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT); Blt_TreeViewEventuallyRedraw(tvPtr); } int Blt_TreeViewEntryIsSelected(TreeView *tvPtr, TreeViewEntry *entryPtr) { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&tvPtr->selectTable, (char *)entryPtr); return (hPtr != NULL); } void Blt_TreeViewSelectEntry(TreeView *tvPtr, TreeViewEntry *entryPtr) { int isNew; Blt_HashEntry *hPtr; hPtr = Blt_CreateHashEntry(&tvPtr->selectTable, (char *)entryPtr, &isNew); if (isNew) { Blt_ChainLink *linkPtr; linkPtr = Blt_ChainAppend(tvPtr->selChainPtr, entryPtr); Blt_SetHashValue(hPtr, linkPtr); } } void Blt_TreeViewDeselectEntry(TreeView *tvPtr, TreeViewEntry *entryPtr) { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&tvPtr->selectTable, (char *)entryPtr); if (hPtr != NULL) { Blt_ChainLink *linkPtr; linkPtr = Blt_GetHashValue(hPtr); Blt_ChainDeleteLink(tvPtr->selChainPtr, linkPtr); Blt_DeleteHashEntry(&tvPtr->selectTable, hPtr); } } char * Blt_TreeViewGetFullName( TreeView *tvPtr, TreeViewEntry *entryPtr, int checkEntryLabel, Tcl_DString *resultPtr) { Blt_TreeNode node; char **names; /* Used the stack the component names. */ char *staticSpace[64]; int level; register int i; level = Blt_TreeNodeDepth(tvPtr->tree, entryPtr->node); if (tvPtr->rootPtr->labelUid == NULL) { level--; } if (level > 64) { names = Blt_Malloc((level + 2) * sizeof(char *)); assert(names); } else { names = staticSpace; } for (i = level; i >= 0; i--) { /* Save the name of each ancestor in the name array. */ if (checkEntryLabel) { names[i] = GETLABEL(entryPtr); } else { names[i] = Blt_TreeNodeLabel(entryPtr->node); } node = Blt_TreeNodeParent(entryPtr->node); if (node != NULL) { entryPtr = Blt_NodeToEntry(tvPtr, node); } } Tcl_DStringInit(resultPtr); if (level >= 0) { if ((tvPtr->pathSep == SEPARATOR_LIST) || (tvPtr->pathSep == SEPARATOR_NONE)) { for (i = 0; i <= level; i++) { Tcl_DStringAppendElement(resultPtr, names[i]); } } else { Tcl_DStringAppend(resultPtr, names[0], -1); for (i = 1; i <= level; i++) { Tcl_DStringAppend(resultPtr, tvPtr->pathSep, -1); Tcl_DStringAppend(resultPtr, names[i], -1); } } } else { if ((tvPtr->pathSep != SEPARATOR_LIST) && (tvPtr->pathSep != SEPARATOR_NONE)) { Tcl_DStringAppend(resultPtr, tvPtr->pathSep, -1); } } if (names != staticSpace) { Blt_Free(names); } return Tcl_DStringValue(resultPtr); } int Blt_TreeViewCloseEntry(TreeView *tvPtr, TreeViewEntry *entryPtr) { char *cmd; if (entryPtr->flags & ENTRY_CLOSED) { return TCL_OK; /* Entry is already closed. */ } entryPtr->flags |= ENTRY_CLOSED; /* * Invoke the entry's "close" command, if there is one. Otherwise * try the treeview's global "close" command. */ cmd = CHOOSE(tvPtr->closeCmd, entryPtr->closeCmd); if (cmd != NULL) { Tcl_DString dString; int result; Blt_TreeViewPercentSubst(tvPtr, entryPtr, cmd, &dString); Tcl_Preserve(entryPtr); result = Tcl_GlobalEval(tvPtr->interp, Tcl_DStringValue(&dString)); Tcl_Release(entryPtr); Tcl_DStringFree(&dString); if (result != TCL_OK) { return TCL_ERROR; } } tvPtr->flags |= TV_LAYOUT; return TCL_OK; } int Blt_TreeViewOpenEntry(TreeView *tvPtr, TreeViewEntry *entryPtr) { char *cmd; if ((entryPtr->flags & ENTRY_CLOSED) == 0) { return TCL_OK; /* Entry is already open. */ } entryPtr->flags &= ~ENTRY_CLOSED; /* * If there's a "open" command proc specified for the entry, use * that instead of the more general "open" proc for the entire * treeview. */ cmd = CHOOSE(tvPtr->openCmd, entryPtr->openCmd); if (cmd != NULL) { Tcl_DString dString; int result; Blt_TreeViewPercentSubst(tvPtr, entryPtr, cmd, &dString); Tcl_Preserve(entryPtr); result = Tcl_GlobalEval(tvPtr->interp, Tcl_DStringValue(&dString)); Tcl_Release(entryPtr); Tcl_DStringFree(&dString); if (result != TCL_OK) { return TCL_ERROR; } } tvPtr->flags |= TV_LAYOUT; return TCL_OK; } /* *---------------------------------------------------------------------- * * Blt_TreeViewCreateEntry -- * * This procedure is called by the Tree object when a node is * created and inserted into the tree. It adds a new treeview * entry field to the node. * * Results: * Returns the entry. * *---------------------------------------------------------------------- */ int Blt_TreeViewCreateEntry( TreeView *tvPtr, Blt_TreeNode node, /* Node that has just been created. */ int objc, Tcl_Obj *CONST *objv, int flags) { TreeViewEntry *entryPtr; int isNew; Blt_HashEntry *hPtr; hPtr = Blt_CreateHashEntry(&tvPtr->entryTable, (char *)node, &isNew); if (isNew) { /* Create the entry structure */ entryPtr = Blt_PoolAllocItem(tvPtr->entryPool, sizeof(TreeViewEntry)); memset(entryPtr, 0, sizeof(TreeViewEntry)); entryPtr->flags = tvPtr->buttonFlags | ENTRY_CLOSED; entryPtr->tvPtr = tvPtr; entryPtr->labelUid = NULL; entryPtr->node = node; Blt_SetHashValue(hPtr, entryPtr); } else { entryPtr = Blt_GetHashValue(hPtr); } if (Blt_TreeViewConfigureEntry(tvPtr, entryPtr, objc, objv, flags) != TCL_OK) { FreeEntry(tvPtr, entryPtr); return TCL_ERROR; /* Error configuring the entry. */ } tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT); Blt_TreeViewEventuallyRedraw(tvPtr); return TCL_OK; } /*ARGSUSED*/ static int CreateApplyProc( Blt_TreeNode node, /* Node that has just been created. */ ClientData clientData, int order) /* Not used. */ { TreeView *tvPtr = clientData; return Blt_TreeViewCreateEntry(tvPtr, node, 0, NULL, 0); } /*ARGSUSED*/ static int DeleteApplyProc( Blt_TreeNode node, ClientData clientData, int order) /* Not used. */ { TreeView *tvPtr = clientData; /* * Unsetting the tree value triggers a call back to destroy the entry * and also releases the Tcl_Obj that contains it. */ return Blt_TreeUnsetValueByKey(tvPtr->interp, tvPtr->tree, node, tvPtr->treeColumn.key); } static int TreeEventProc(ClientData clientData, Blt_TreeNotifyEvent *eventPtr) { Blt_TreeNode node; TreeView *tvPtr = clientData; node = Blt_TreeGetNode(eventPtr->tree, eventPtr->inode); switch (eventPtr->type) { case TREE_NOTIFY_CREATE: return Blt_TreeViewCreateEntry(tvPtr, node, 0, NULL, 0); case TREE_NOTIFY_DELETE: /* * Deleting the tree node triggers a call back to free the * treeview entry that is associated with it. */ if (node != NULL) { FreeEntry(tvPtr, Blt_NodeToEntry(tvPtr, node)); } break; case TREE_NOTIFY_RELABEL: if (node != NULL) { TreeViewEntry *entryPtr; entryPtr = Blt_NodeToEntry(tvPtr, node); entryPtr->flags |= ENTRY_DIRTY; } /*FALLTHRU*/ case TREE_NOTIFY_MOVE: case TREE_NOTIFY_SORT: Blt_TreeViewEventuallyRedraw(tvPtr); tvPtr->flags |= (TV_LAYOUT | TV_DIRTY); break; default: /* empty */ break; } return TCL_OK; } TreeViewValue * Blt_TreeViewFindValue(TreeViewEntry *entryPtr, TreeViewColumn *columnPtr) { register TreeViewValue *valuePtr; for (valuePtr = entryPtr->values; valuePtr != NULL; valuePtr = valuePtr->nextPtr) { if (valuePtr->columnPtr == columnPtr) { return valuePtr; } } return NULL; } void Blt_TreeViewAddValue(TreeViewEntry *entryPtr, TreeViewColumn *columnPtr) { if (Blt_TreeViewFindValue(entryPtr, columnPtr) == NULL) { Tcl_Obj *objPtr; if (Blt_TreeViewGetData(entryPtr, columnPtr->key, &objPtr) == TCL_OK) { TreeViewValue *valuePtr; /* Add a new value only if a data entry exists. */ valuePtr = Blt_PoolAllocItem(entryPtr->tvPtr->valuePool, sizeof(TreeViewValue)); valuePtr->columnPtr = columnPtr; valuePtr->nextPtr = entryPtr->values; valuePtr->textPtr = NULL; valuePtr->width = valuePtr->height = 0; valuePtr->stylePtr = NULL; valuePtr->string = NULL; entryPtr->values = valuePtr; } } entryPtr->tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT); entryPtr->flags |= ENTRY_DIRTY; } /* *---------------------------------------------------------------------- * * TreeTraceProc -- * * Mirrors the individual values of the tree object (they must * also be listed in the widget's columns chain). This is because * it must track and save the sizes of each individual data * entry, rather than re-computing all the sizes each time the * widget is redrawn. * * This procedure is called by the Tree object when a node data * value is set unset. * * Results: * Returns TCL_OK. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TreeTraceProc( ClientData clientData, Tcl_Interp *interp, Blt_TreeNode node, /* Node that has just been updated. */ Blt_TreeKey key, /* Key of value that's been updated. */ unsigned int flags) { Blt_HashEntry *hPtr; TreeView *tvPtr = clientData; TreeViewColumn *columnPtr; TreeViewEntry *entryPtr; TreeViewValue *valuePtr, *nextPtr, *lastPtr; hPtr = Blt_FindHashEntry(&tvPtr->entryTable, (char *)node); if (hPtr == NULL) { return TCL_OK; /* Not a node that we're interested in. */ } entryPtr = Blt_GetHashValue(hPtr); flags &= TREE_TRACE_WRITE | TREE_TRACE_READ | TREE_TRACE_UNSET; switch (flags) { case TREE_TRACE_WRITE: hPtr = Blt_FindHashEntry(&tvPtr->columnTable, key); if (hPtr == NULL) { return TCL_OK; /* Data value isn't used by widget. */ } columnPtr = Blt_GetHashValue(hPtr); if (columnPtr != &tvPtr->treeColumn) { Blt_TreeViewAddValue(entryPtr, columnPtr); } entryPtr->flags |= ENTRY_DIRTY; Blt_TreeViewEventuallyRedraw(tvPtr); tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT); break; case TREE_TRACE_UNSET: lastPtr = NULL; for(valuePtr = entryPtr->values; valuePtr != NULL; valuePtr = nextPtr) { nextPtr = valuePtr->nextPtr; if (valuePtr->columnPtr->key == key) { Blt_TreeViewDestroyValue(tvPtr, valuePtr); if (lastPtr == NULL) { entryPtr->values = nextPtr; } else { lastPtr->nextPtr = nextPtr; } entryPtr->flags |= ENTRY_DIRTY; Blt_TreeViewEventuallyRedraw(tvPtr); tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT); break; } lastPtr = valuePtr; } break; default: break; } return TCL_OK; } static void GetValueSize( TreeView *tvPtr, TreeViewEntry *entryPtr, TreeViewValue *valuePtr, TreeViewStyle *stylePtr) { TreeViewColumn *columnPtr; columnPtr = valuePtr->columnPtr; valuePtr->width = valuePtr->height = 0; if (entryPtr->flags & ENTRY_DIRTY) { /* Reparse the data. */ char *string; TreeViewIcon icon; Tcl_Obj *valueObjPtr; TreeViewStyle *newStylePtr; icon = NULL; newStylePtr = NULL; if (Blt_TreeViewGetData(entryPtr, valuePtr->columnPtr->key, &valueObjPtr) != TCL_OK) { return; /* No data ??? */ } string = Tcl_GetString(valueObjPtr); valuePtr->string = string; if (string[0] == '@') { /* Name of style or Tk image. */ int objc; Tcl_Obj **objv; if ((Tcl_ListObjGetElements(tvPtr->interp, valueObjPtr, &objc, &objv) != TCL_OK) || (objc < 1) || (objc > 2)) { goto handleString; } if (objc > 0) { char *name; name = Tcl_GetString(objv[0]) + 1; if (Blt_TreeViewGetStyle((Tcl_Interp *)NULL, tvPtr, name, &newStylePtr) != TCL_OK) { icon = Blt_TreeViewGetIcon(tvPtr, name); if (icon == NULL) { goto handleString; } /* Create a new style by the name of the image. */ newStylePtr = Blt_TreeViewCreateStyle((Tcl_Interp *)NULL, tvPtr, STYLE_TEXTBOX, name); assert(newStylePtr); Blt_TreeViewUpdateStyleGCs(tvPtr, newStylePtr); } } if (valuePtr->stylePtr != NULL) { Blt_TreeViewFreeStyle(tvPtr, valuePtr->stylePtr); } if (icon != NULL) { Blt_TreeViewSetStyleIcon(tvPtr, newStylePtr, icon); } valuePtr->stylePtr = newStylePtr; valuePtr->string = (objc > 1) ? Tcl_GetString(objv[1]) : NULL; } } handleString: stylePtr = CHOOSE(columnPtr->stylePtr, valuePtr->stylePtr); /* Measure the text string. */ (*stylePtr->classPtr->measProc)(tvPtr, stylePtr, valuePtr); } static void GetRowExtents( TreeView *tvPtr, TreeViewEntry *entryPtr, int *widthPtr, int *heightPtr) { TreeViewValue *valuePtr; int valueWidth; /* Width of individual value. */ int width, height; /* Compute dimensions of row. */ TreeViewStyle *stylePtr; width = height = 0; for (valuePtr = entryPtr->values; valuePtr != NULL; valuePtr = valuePtr->nextPtr) { stylePtr = valuePtr->stylePtr; if (stylePtr == NULL) { stylePtr = valuePtr->columnPtr->stylePtr; } if ((entryPtr->flags & ENTRY_DIRTY) || (stylePtr->flags & STYLE_DIRTY)) { GetValueSize(tvPtr, entryPtr, valuePtr, stylePtr); } if (valuePtr->height > height) { height = valuePtr->height; } valueWidth = valuePtr->width; width += valueWidth; } *widthPtr = width; *heightPtr = height; } /* *---------------------------------------------------------------------- * * Blt_TreeViewNearestEntry -- * * Finds the entry closest to the given screen X-Y coordinates * in the viewport. * * Results: * Returns the pointer to the closest node. If no node is * visible (nodes may be hidden), NULL is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ TreeViewEntry * Blt_TreeViewNearestEntry(TreeView *tvPtr, int x, int y, int selectOne) { TreeViewEntry *lastPtr, *entryPtr; register TreeViewEntry **p; /* * We implicitly can pick only visible entries. So make sure that * the tree exists. */ if (tvPtr->nVisible == 0) { return NULL; } if (y < tvPtr->titleHeight) { return (selectOne) ? tvPtr->visibleArr[0] : NULL; } /* * Since the entry positions were previously computed in world * coordinates, convert Y-coordinate from screen to world * coordinates too. */ y = WORLDY(tvPtr, y); lastPtr = tvPtr->visibleArr[0]; for (p = tvPtr->visibleArr; *p != NULL; p++) { entryPtr = *p; /* * If the start of the next entry starts beyond the point, * use the last entry. */ if (entryPtr->worldY > y) { return (selectOne) ? entryPtr : NULL; } if (y < (entryPtr->worldY + entryPtr->height)) { return entryPtr; /* Found it. */ } lastPtr = entryPtr; } return (selectOne) ? lastPtr : NULL; } ClientData Blt_TreeViewEntryTag(TreeView *tvPtr, CONST char *string) { Blt_HashEntry *hPtr; int isNew; /* Not used. */ hPtr = Blt_CreateHashEntry(&tvPtr->entryTagTable, string, &isNew); return Blt_GetHashKey(&tvPtr->entryTagTable, hPtr); } ClientData Blt_TreeViewButtonTag(TreeView *tvPtr, CONST char *string) { Blt_HashEntry *hPtr; int isNew; /* Not used. */ hPtr = Blt_CreateHashEntry(&tvPtr->buttonTagTable, string, &isNew); return Blt_GetHashKey(&tvPtr->buttonTagTable, hPtr); } ClientData Blt_TreeViewColumnTag(TreeView *tvPtr, CONST char *string) { Blt_HashEntry *hPtr; int isNew; /* Not used. */ hPtr = Blt_CreateHashEntry(&tvPtr->columnTagTable, string, &isNew); return Blt_GetHashKey(&tvPtr->columnTagTable, hPtr); } ClientData Blt_TreeViewStyleTag(TreeView *tvPtr, CONST char *string) { Blt_HashEntry *hPtr; int isNew; /* Not used. */ hPtr = Blt_CreateHashEntry(&tvPtr->styleTagTable, string, &isNew); return Blt_GetHashKey(&tvPtr->styleTagTable, hPtr); } static void GetTags( Blt_BindTable table, ClientData object, /* Object picked. */ ClientData context, /* Context of object. */ Blt_List ids) /* (out) List of binding ids to be * applied for this object. */ { TreeView *tvPtr; int nNames; char **names; register char **p; tvPtr = Blt_GetBindingData(table); if (context == (ClientData)ITEM_ENTRY_BUTTON) { TreeViewEntry *entryPtr = object; Blt_ListAppend(ids, Blt_TreeViewButtonTag(tvPtr, "Button"), 0); if (entryPtr->tagsUid != NULL) { if (Tcl_SplitList((Tcl_Interp *)NULL, entryPtr->tagsUid, &nNames, &names) == TCL_OK) { for (p = names; *p != NULL; p++) { Blt_ListAppend(ids, Blt_TreeViewButtonTag(tvPtr, *p), 0); } Blt_Free(names); } } else { Blt_ListAppend(ids, Blt_TreeViewButtonTag(tvPtr, "Entry"), 0); Blt_ListAppend(ids, Blt_TreeViewButtonTag(tvPtr, "all"), 0); } } else if (context == (ClientData)ITEM_COLUMN_TITLE) { TreeViewColumn *columnPtr = object; Blt_ListAppend(ids, (char *)columnPtr, 0); if (columnPtr->tagsUid != NULL) { if (Tcl_SplitList((Tcl_Interp *)NULL, columnPtr->tagsUid, &nNames, &names) == TCL_OK) { for (p = names; *p != NULL; p++) { Blt_ListAppend(ids, Blt_TreeViewColumnTag(tvPtr, *p), 0); } Blt_Free(names); } } } else if (context == ITEM_COLUMN_RULE) { Blt_ListAppend(ids, Blt_TreeViewColumnTag(tvPtr, "Rule"), 0); } else { TreeViewEntry *entryPtr = object; Blt_ListAppend(ids, (char *)entryPtr, 0); if (entryPtr->tagsUid != NULL) { if (Tcl_SplitList((Tcl_Interp *)NULL, entryPtr->tagsUid, &nNames, &names) == TCL_OK) { for (p = names; *p != NULL; p++) { Blt_ListAppend(ids, Blt_TreeViewEntryTag(tvPtr, *p), 0); } Blt_Free(names); } } else if (context == ITEM_ENTRY){ Blt_ListAppend(ids, Blt_TreeViewEntryTag(tvPtr, "Entry"), 0); Blt_ListAppend(ids, Blt_TreeViewEntryTag(tvPtr, "all"), 0); } else { TreeViewValue *valuePtr = context; if (valuePtr != NULL) { TreeViewStyle *stylePtr = valuePtr->stylePtr; if (stylePtr == NULL) { stylePtr = valuePtr->columnPtr->stylePtr; } Blt_ListAppend(ids, Blt_TreeViewEntryTag(tvPtr, stylePtr->name), 0); Blt_ListAppend(ids, Blt_TreeViewEntryTag(tvPtr, valuePtr->columnPtr->key), 0); Blt_ListAppend(ids, Blt_TreeViewEntryTag(tvPtr, stylePtr->classPtr->className), 0); #ifndef notdef Blt_ListAppend(ids, Blt_TreeViewEntryTag(tvPtr, "Entry"), 0); Blt_ListAppend(ids, Blt_TreeViewEntryTag(tvPtr, "all"), 0); #endif } } } } /*ARGSUSED*/ static ClientData PickItem( ClientData clientData, int x, int y, /* Screen coordinates of the test point. */ ClientData *contextPtr) /* (out) Context of item selected: should * be ITEM_ENTRY, ITEM_ENTRY_BUTTON, * ITEM_COLUMN_TITLE, * ITEM_COLUMN_RULE, or * ITEM_STYLE. */ { TreeView *tvPtr = clientData; TreeViewEntry *entryPtr; TreeViewColumn *columnPtr; if (contextPtr != NULL) { *contextPtr = NULL; } if (tvPtr->flags & TV_DIRTY) { /* Can't trust the selected entry if nodes have been added or * deleted. So recompute the layout. */ if (tvPtr->flags & TV_LAYOUT) { Blt_TreeViewComputeLayout(tvPtr); } ComputeVisibleEntries(tvPtr); } columnPtr = Blt_TreeViewNearestColumn(tvPtr, x, y, contextPtr); if ((*contextPtr != NULL) && (tvPtr->flags & TV_SHOW_COLUMN_TITLES)) { return columnPtr; } if (tvPtr->nVisible == 0) { return NULL; } entryPtr = Blt_TreeViewNearestEntry(tvPtr, x, y, FALSE); if (entryPtr == NULL) { return NULL; } x = WORLDX(tvPtr, x); y = WORLDY(tvPtr, y); if (contextPtr != NULL) { *contextPtr = ITEM_ENTRY; if (columnPtr != NULL) { TreeViewValue *valuePtr; valuePtr = Blt_TreeViewFindValue(entryPtr, columnPtr); if (valuePtr != NULL) { TreeViewStyle *stylePtr; stylePtr = valuePtr->stylePtr; if (stylePtr == NULL) { stylePtr = valuePtr->columnPtr->stylePtr; } if ((stylePtr->classPtr->pickProc == NULL) || ((*stylePtr->classPtr->pickProc)(entryPtr, valuePtr, stylePtr, x, y))) { *contextPtr = valuePtr; } } } if (entryPtr->flags & ENTRY_HAS_BUTTON) { TreeViewButton *buttonPtr = &tvPtr->button; int left, right, top, bottom; left = entryPtr->worldX + entryPtr->buttonX - BUTTON_PAD; right = left + buttonPtr->width + 2 * BUTTON_PAD; top = entryPtr->worldY + entryPtr->buttonY - BUTTON_PAD; bottom = top + buttonPtr->height + 2 * BUTTON_PAD; if ((x >= left) && (x < right) && (y >= top) && (y < bottom)) { *contextPtr = (ClientData)ITEM_ENTRY_BUTTON; } } } return entryPtr; } static void GetEntryExtents(TreeView *tvPtr, TreeViewEntry *entryPtr) { Tk_Font font; TreeViewIcon *icons; char *label; int entryWidth, entryHeight; int width, height; /* * FIXME: Use of DIRTY flag inconsistent. When does it * mean "dirty entry"? When does it mean "dirty column"? * Does it matter? probably */ if ((entryPtr->flags & ENTRY_DIRTY) || (tvPtr->flags & TV_UPDATE)) { Tk_FontMetrics fontMetrics; entryPtr->iconWidth = entryPtr->iconHeight = 0; icons = CHOOSE(tvPtr->icons, entryPtr->icons); if (icons != NULL) { register int i; for (i = 0; i < 2; i++) { if (icons[i] == NULL) { break; } if (entryPtr->iconWidth < TreeViewIconWidth(icons[i])) { entryPtr->iconWidth = TreeViewIconWidth(icons[i]); } if (entryPtr->iconHeight < TreeViewIconHeight(icons[i])) { entryPtr->iconHeight = TreeViewIconHeight(icons[i]); } } } if ((icons == NULL) || (icons[0] == NULL)) { entryPtr->iconWidth = DEF_ICON_WIDTH; entryPtr->iconHeight = DEF_ICON_HEIGHT; } entryPtr->iconWidth += 2 * ICON_PADX; entryPtr->iconHeight += 2 * ICON_PADY; entryHeight = MAX(entryPtr->iconHeight, tvPtr->button.height); font = entryPtr->font; if (font == NULL) { font = Blt_TreeViewGetStyleFont(tvPtr, tvPtr->treeColumn.stylePtr); } if (entryPtr->fullName != NULL) { Blt_Free(entryPtr->fullName); entryPtr->fullName = NULL; } if (entryPtr->textPtr != NULL) { Blt_Free(entryPtr->textPtr); entryPtr->textPtr = NULL; } Tk_GetFontMetrics(font, &fontMetrics); entryPtr->lineHeight = fontMetrics.linespace; entryPtr->lineHeight += 2 * (FOCUS_WIDTH + LABEL_PADY + tvPtr->selBorderWidth) + tvPtr->leader; label = GETLABEL(entryPtr); if (label[0] == '\0') { width = height = entryPtr->lineHeight; } else { TextStyle ts; Blt_InitTextStyle(&ts); ts.shadow.offset = entryPtr->shadow.offset; ts.font = font; if (tvPtr->flatView) { Tcl_DString dString; Blt_TreeViewGetFullName(tvPtr, entryPtr, TRUE, &dString); entryPtr->fullName = Blt_Strdup(Tcl_DStringValue(&dString)); Tcl_DStringFree(&dString); entryPtr->textPtr = Blt_GetTextLayout(entryPtr->fullName, &ts); } else { entryPtr->textPtr = Blt_GetTextLayout(label, &ts); } width = entryPtr->textPtr->width; height = entryPtr->textPtr->height; } width += 2 * (FOCUS_WIDTH + LABEL_PADX + tvPtr->selBorderWidth); height += 2 * (FOCUS_WIDTH + LABEL_PADY + tvPtr->selBorderWidth); width = ODD(width); if (entryPtr->reqHeight > height) { height = entryPtr->reqHeight; } height = ODD(height); entryWidth = width; if (entryHeight < height) { entryHeight = height; } entryPtr->labelWidth = width; entryPtr->labelHeight = height; } else { entryHeight = entryPtr->labelHeight; entryWidth = entryPtr->labelWidth; } /* * Find the maximum height of the data value entries. This also has * the side effect of contributing the maximum width of the column. */ GetRowExtents(tvPtr, entryPtr, &width, &height); if (entryHeight < height) { entryHeight = height; } entryPtr->width = entryWidth + COLUMN_PAD; entryPtr->height = entryHeight + tvPtr->leader; /* * Force the height of the entry to an even number. This is to * make the dots or the vertical line segments coincide with the * start of the horizontal lines. */ if (entryPtr->height & 0x01) { entryPtr->height++; } entryPtr->flags &= ~ENTRY_DIRTY; } /* * TreeView Procedures */ /* * ---------------------------------------------------------------------- * * CreateTreeView -- * * ---------------------------------------------------------------------- */ static TreeView * CreateTreeView( Tcl_Interp *interp, Tcl_Obj *objPtr, /* Name of the new widget. */ CONST char *className) { Tk_Window tkwin; TreeView *tvPtr; char *name; Tcl_DString dString; int result; name = Tcl_GetString(objPtr); tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp), name, (char *)NULL); if (tkwin == NULL) { return NULL; } Tk_SetClass(tkwin, (char *)className); tvPtr = Blt_Calloc(1, sizeof(TreeView)); assert(tvPtr); tvPtr->tkwin = tkwin; tvPtr->display = Tk_Display(tkwin); tvPtr->interp = interp; tvPtr->flags = (TV_HIDE_ROOT | TV_SHOW_COLUMN_TITLES | TV_DIRTY | TV_LAYOUT | TV_RESORT); tvPtr->leader = 0; tvPtr->dashes = 1; tvPtr->highlightWidth = 2; tvPtr->selBorderWidth = 1; tvPtr->borderWidth = 2; tvPtr->relief = TK_RELIEF_SUNKEN; tvPtr->selRelief = TK_RELIEF_FLAT; tvPtr->scrollMode = BLT_SCROLL_MODE_HIERBOX; tvPtr->selectMode = SELECT_MODE_SINGLE; tvPtr->button.closeRelief = tvPtr->button.openRelief = TK_RELIEF_SOLID; tvPtr->reqWidth = 200; tvPtr->reqHeight = 400; tvPtr->xScrollUnits = tvPtr->yScrollUnits = 20; tvPtr->lineWidth = 1; tvPtr->button.borderWidth = 1; tvPtr->colChainPtr = Blt_ChainCreate(); tvPtr->buttonFlags = BUTTON_AUTO; tvPtr->selChainPtr = Blt_ChainCreate(); Blt_InitHashTableWithPool(&tvPtr->entryTable, BLT_ONE_WORD_KEYS); Blt_InitHashTable(&tvPtr->columnTable, BLT_ONE_WORD_KEYS); Blt_InitHashTable(&tvPtr->iconTable, BLT_STRING_KEYS); Blt_InitHashTable(&tvPtr->selectTable, BLT_ONE_WORD_KEYS); Blt_InitHashTable(&tvPtr->uidTable, BLT_STRING_KEYS); Blt_InitHashTable(&tvPtr->styleTable, BLT_STRING_KEYS); tvPtr->bindTable = Blt_CreateBindingTable(interp, tkwin, tvPtr, PickItem, GetTags); Blt_InitHashTable(&tvPtr->entryTagTable, BLT_STRING_KEYS); Blt_InitHashTable(&tvPtr->columnTagTable, BLT_STRING_KEYS); Blt_InitHashTable(&tvPtr->buttonTagTable, BLT_STRING_KEYS); Blt_InitHashTable(&tvPtr->styleTagTable, BLT_STRING_KEYS); tvPtr->entryPool = Blt_PoolCreate(BLT_FIXED_SIZE_ITEMS); tvPtr->valuePool = Blt_PoolCreate(BLT_FIXED_SIZE_ITEMS); #if (TK_MAJOR_VERSION > 4) Blt_SetWindowInstanceData(tkwin, tvPtr); #endif tvPtr->cmdToken = Tcl_CreateObjCommand(interp, Tk_PathName(tvPtr->tkwin), Blt_TreeViewWidgetInstCmd, tvPtr, WidgetInstCmdDeleteProc); #ifdef ITCL_NAMESPACES Itk_SetWidgetCommand(tvPtr->tkwin, tvPtr->cmdToken); #endif Tk_CreateSelHandler(tvPtr->tkwin, XA_PRIMARY, XA_STRING, SelectionProc, tvPtr, XA_STRING); Tk_CreateEventHandler(tvPtr->tkwin, ExposureMask | StructureNotifyMask | FocusChangeMask, TreeViewEventProc, tvPtr); /* * Create a default style. This must exist before we can create * the treeview column. */ tvPtr->stylePtr = Blt_TreeViewCreateStyle(interp, tvPtr, STYLE_TEXTBOX, "text"); if (tvPtr->stylePtr == NULL) { return NULL; } /* Create a default column to display the view of the tree. */ Tcl_DStringInit(&dString); Tcl_DStringAppend(&dString, "BLT TreeView ", -1); Tcl_DStringAppend(&dString, Tk_PathName(tvPtr->tkwin), -1); result = Blt_TreeViewCreateColumn(tvPtr, &tvPtr->treeColumn, Tcl_DStringValue(&dString), ""); Tcl_DStringFree(&dString); if (result != TCL_OK) { return NULL; } Blt_ChainAppend(tvPtr->colChainPtr, &tvPtr->treeColumn); return tvPtr; } /* * ---------------------------------------------------------------------- * * DestroyTreeView -- * * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release * to clean up the internal structure of a TreeView at a safe time * (when no-one is using it anymore). * * Results: * None. * * Side effects: * Everything associated with the widget is freed up. * * ---------------------------------------------------------------------- */ static void DestroyTreeView(DestroyData dataPtr) /* Pointer to the widget record. */ { Blt_HashEntry *hPtr; Blt_HashSearch cursor; TreeView *tvPtr = (TreeView *)dataPtr; TreeViewButton *buttonPtr; TreeViewEntry *entryPtr; TreeViewStyle *stylePtr; Blt_TreeDeleteEventHandler(tvPtr->tree, TREE_NOTIFY_ALL, TreeEventProc, tvPtr); for (hPtr = Blt_FirstHashEntry(&tvPtr->entryTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { entryPtr = Blt_GetHashValue(hPtr); DestroyEntry((ClientData)entryPtr); } bltTreeViewTreeOption.clientData = tvPtr; bltTreeViewIconsOption.clientData = tvPtr; Blt_FreeObjOptions(bltTreeViewSpecs, (char *)tvPtr, tvPtr->display, 0); if (tvPtr->tkwin != NULL) { Tk_DeleteSelHandler(tvPtr->tkwin, XA_PRIMARY, XA_STRING); } if (tvPtr->lineGC != NULL) { Tk_FreeGC(tvPtr->display, tvPtr->lineGC); } if (tvPtr->focusGC != NULL) { Blt_FreePrivateGC(tvPtr->display, tvPtr->focusGC); } if (tvPtr->visibleArr != NULL) { Blt_Free(tvPtr->visibleArr); } if (tvPtr->flatArr != NULL) { Blt_Free(tvPtr->flatArr); } if (tvPtr->levelInfo != NULL) { Blt_Free(tvPtr->levelInfo); } buttonPtr = &tvPtr->button; if (buttonPtr->activeGC != NULL) { Tk_FreeGC(tvPtr->display, buttonPtr->activeGC); } if (buttonPtr->normalGC != NULL) { Tk_FreeGC(tvPtr->display, buttonPtr->normalGC); } if (tvPtr->stylePtr != NULL) { Blt_TreeViewFreeStyle(tvPtr, tvPtr->stylePtr); } Blt_TreeViewDestroyColumns(tvPtr); Blt_DestroyBindingTable(tvPtr->bindTable); Blt_ChainDestroy(tvPtr->selChainPtr); Blt_DeleteHashTable(&tvPtr->entryTagTable); Blt_DeleteHashTable(&tvPtr->columnTagTable); Blt_DeleteHashTable(&tvPtr->buttonTagTable); Blt_DeleteHashTable(&tvPtr->styleTagTable); for (hPtr = Blt_FirstHashEntry(&tvPtr->styleTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { stylePtr = Blt_GetHashValue(hPtr); /* stylePtr->refCount = 0; */ stylePtr->flags &= ~STYLE_USER; Blt_TreeViewFreeStyle(tvPtr, stylePtr); } if (tvPtr->comboWin != NULL) { Tk_DestroyWindow(tvPtr->comboWin); } Blt_DeleteHashTable(&tvPtr->styleTable); Blt_DeleteHashTable(&tvPtr->selectTable); Blt_DeleteHashTable(&tvPtr->uidTable); Blt_DeleteHashTable(&tvPtr->entryTable); Blt_PoolDestroy(tvPtr->entryPool); Blt_PoolDestroy(tvPtr->valuePool); DumpIconTable(tvPtr); Blt_Free(tvPtr); } /* * -------------------------------------------------------------- * * TreeViewEventProc -- * * This procedure is invoked by the Tk dispatcher for various * events on treeview widgets. * * Results: * None. * * Side effects: * When the window gets deleted, internal structures get * cleaned up. When it gets exposed, it is redisplayed. * * -------------------------------------------------------------- */ static void TreeViewEventProc( ClientData clientData, /* Information about window. */ XEvent *eventPtr) /* Information about event. */ { TreeView *tvPtr = clientData; if (eventPtr->type == Expose) { if (eventPtr->xexpose.count == 0) { Blt_TreeViewEventuallyRedraw(tvPtr); Blt_PickCurrentItem(tvPtr->bindTable); } } else if (eventPtr->type == ConfigureNotify) { tvPtr->flags |= (TV_LAYOUT | TV_SCROLL); Blt_TreeViewEventuallyRedraw(tvPtr); } else if ((eventPtr->type == FocusIn) || (eventPtr->type == FocusOut)) { if (eventPtr->xfocus.detail != NotifyInferior) { if (eventPtr->type == FocusIn) { tvPtr->flags |= TV_FOCUS; } else { tvPtr->flags &= ~TV_FOCUS; } Blt_TreeViewEventuallyRedraw(tvPtr); } } else if (eventPtr->type == DestroyNotify) { if (tvPtr->tkwin != NULL) { tvPtr->tkwin = NULL; Tcl_DeleteCommandFromToken(tvPtr->interp, tvPtr->cmdToken); } if (tvPtr->flags & TV_REDRAW) { Tcl_CancelIdleCall(DisplayTreeView, tvPtr); } if (tvPtr->flags & TV_SELECT_PENDING) { Tcl_CancelIdleCall(Blt_TreeViewSelectCmdProc, tvPtr); } Tcl_EventuallyFree(tvPtr, DestroyTreeView); } } /* Selection Procedures */ /* *---------------------------------------------------------------------- * * SelectionProc -- * * This procedure is called back by Tk when the selection is * requested by someone. It returns part or all of the selection * in a buffer provided by the caller. * * Results: * The return value is the number of non-NULL bytes stored at * buffer. Buffer is filled (or partially filled) with a * NUL-terminated string containing part or all of the * selection, as given by offset and maxBytes. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int SelectionProc( ClientData clientData, /* Information about the widget. */ int offset, /* Offset within selection of first * character to be returned. */ char *buffer, /* Location in which to place * selection. */ int maxBytes) /* Maximum number of bytes to place * at buffer, not including terminating * NULL character. */ { Tcl_DString dString; TreeView *tvPtr = clientData; TreeViewEntry *entryPtr; int size; if ((tvPtr->flags & TV_SELECT_EXPORT) == 0) { return -1; } /* * Retrieve the names of the selected entries. */ Tcl_DStringInit(&dString); if (tvPtr->flags & TV_SELECT_SORTED) { Blt_ChainLink *linkPtr; for (linkPtr = Blt_ChainFirstLink(tvPtr->selChainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { entryPtr = Blt_ChainGetValue(linkPtr); Tcl_DStringAppend(&dString, GETLABEL(entryPtr), -1); Tcl_DStringAppend(&dString, "\n", -1); } } else { for (entryPtr = tvPtr->rootPtr; entryPtr != NULL; entryPtr = Blt_TreeViewNextEntry(entryPtr, ENTRY_MASK)) { if (Blt_TreeViewEntryIsSelected(tvPtr, entryPtr)) { Tcl_DStringAppend(&dString, GETLABEL(entryPtr), -1); Tcl_DStringAppend(&dString, "\n", -1); } } } size = Tcl_DStringLength(&dString) - offset; strncpy(buffer, Tcl_DStringValue(&dString) + offset, maxBytes); Tcl_DStringFree(&dString); buffer[maxBytes] = '\0'; return (size > maxBytes) ? maxBytes : size; } /* *---------------------------------------------------------------------- * * WidgetInstCmdDeleteProc -- * * This procedure is invoked when a widget command is deleted. If * the widget isn't already in the process of being destroyed, * this command destroys it. * * Results: * None. * * Side effects: * The widget is destroyed. * *---------------------------------------------------------------------- */ static void WidgetInstCmdDeleteProc(ClientData clientData) { TreeView *tvPtr = clientData; /* * This procedure could be invoked either because the window was * destroyed and the command was then deleted (in which case tkwin * is NULL) or because the command was deleted, and then this * procedure destroys the widget. */ if (tvPtr->tkwin != NULL) { Tk_Window tkwin; tkwin = tvPtr->tkwin; tvPtr->tkwin = NULL; Tk_DestroyWindow(tkwin); #ifdef ITCL_NAMESPACES Itk_SetWidgetCommand(tkwin, (Tcl_Command) NULL); #endif /* ITCL_NAMESPACES */ } } /* * ---------------------------------------------------------------------- * * Blt_TreeViewUpdateWidget -- * * Updates the GCs and other information associated with the * treeview widget. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then interp->result contains an error message. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for tvPtr; old resources get freed, if there * were any. The widget is redisplayed. * * ---------------------------------------------------------------------- */ int Blt_TreeViewUpdateWidget(Tcl_Interp *interp, TreeView *tvPtr) { GC newGC; XGCValues gcValues; int setupTree; unsigned long gcMask; /* * GC for dotted vertical line. */ gcMask = (GCForeground | GCLineWidth); gcValues.foreground = tvPtr->lineColor->pixel; gcValues.line_width = tvPtr->lineWidth; if (tvPtr->dashes > 0) { gcMask |= (GCLineStyle | GCDashList); gcValues.line_style = LineOnOffDash; gcValues.dashes = tvPtr->dashes; } newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues); if (tvPtr->lineGC != NULL) { Tk_FreeGC(tvPtr->display, tvPtr->lineGC); } tvPtr->lineGC = newGC; /* * GC for active label. Dashed outline. */ gcMask = GCForeground | GCLineStyle; gcValues.foreground = tvPtr->focusColor->pixel; gcValues.line_style = (LineIsDashed(tvPtr->focusDashes)) ? LineOnOffDash : LineSolid; newGC = Blt_GetPrivateGC(tvPtr->tkwin, gcMask, &gcValues); if (LineIsDashed(tvPtr->focusDashes)) { tvPtr->focusDashes.offset = 2; Blt_SetDashes(tvPtr->display, newGC, &tvPtr->focusDashes); } if (tvPtr->focusGC != NULL) { Blt_FreePrivateGC(tvPtr->display, tvPtr->focusGC); } tvPtr->focusGC = newGC; Blt_TreeViewConfigureButtons(tvPtr); tvPtr->inset = tvPtr->highlightWidth + tvPtr->borderWidth + INSET_PAD; setupTree = FALSE; /* * If no tree object was named, allocate a new one. The name will * be the same as the widget pathname. */ if (tvPtr->tree == NULL) { Blt_Tree token; char *string; string = Tk_PathName(tvPtr->tkwin); if (Blt_TreeCreate(interp, string, &token) != TCL_OK) { return TCL_ERROR; } tvPtr->tree = token; setupTree = TRUE; } /* * If the tree object was changed, we need to setup the new one. */ if (Blt_ObjConfigModified(bltTreeViewSpecs, "-tree", (char *)NULL)) { setupTree = TRUE; } /* * These options change the layout of the box. Mark the widget for update. */ if (Blt_ObjConfigModified(bltTreeViewSpecs, "-font", "-linespacing", "-*width", "-height", "-hide*", "-tree", "-flat", (char *)NULL)) { tvPtr->flags |= (TV_LAYOUT | TV_SCROLL); } /* * If the tree view was changed, mark all the nodes dirty (we'll * be switching back to either the full path name or the label) * and free the array representing the flattened view of the tree. */ if (Blt_ObjConfigModified(bltTreeViewSpecs, "-hideleaves", "-flat", (char *)NULL)) { TreeViewEntry *entryPtr; tvPtr->flags |= (TV_DIRTY | TV_RESORT); /* Mark all entries dirty. */ for (entryPtr = tvPtr->rootPtr; entryPtr != NULL; entryPtr = Blt_TreeViewNextEntry(entryPtr, 0)) { entryPtr->flags |= ENTRY_DIRTY; } if ((!tvPtr->flatView) && (tvPtr->flatArr != NULL)) { Blt_Free(tvPtr->flatArr); tvPtr->flatArr = NULL; } } if ((tvPtr->reqHeight != Tk_ReqHeight(tvPtr->tkwin)) || (tvPtr->reqWidth != Tk_ReqWidth(tvPtr->tkwin))) { Tk_GeometryRequest(tvPtr->tkwin, tvPtr->reqWidth, tvPtr->reqHeight); } if (setupTree) { Blt_TreeNode root; Blt_TreeCreateEventHandler(tvPtr->tree, TREE_NOTIFY_ALL, TreeEventProc, tvPtr); TraceColumns(tvPtr); root = Blt_TreeRootNode(tvPtr->tree); /* Automatically add view-entry values to the new tree. */ Blt_TreeApply(root, CreateApplyProc, tvPtr); tvPtr->focusPtr = tvPtr->rootPtr = Blt_NodeToEntry(tvPtr, root); tvPtr->selMarkPtr = tvPtr->selAnchorPtr = NULL; Blt_SetFocusItem(tvPtr->bindTable, tvPtr->rootPtr, ITEM_ENTRY); /* Automatically open the root node. */ if (Blt_TreeViewOpenEntry(tvPtr, tvPtr->rootPtr) != TCL_OK) { return TCL_ERROR; } if (!(tvPtr->flags & TV_NEW_TAGS)) { Blt_Tree tree; if (Blt_TreeCmdGetToken(interp, Blt_TreeName(tvPtr->tree), &tree) == TCL_OK) { Blt_TreeShareTagTable(tree, tvPtr->tree); } } } if (Blt_ObjConfigModified(bltTreeViewSpecs, "-font", "-color", (char *)NULL)) { Blt_TreeViewUpdateColumnGCs(tvPtr, &tvPtr->treeColumn); } Blt_TreeViewEventuallyRedraw(tvPtr); return TCL_OK; } /* * ---------------------------------------------------------------------- * * ResetCoordinates -- * * Determines the maximum height of all visible entries. * * 1. Sets the worldY coordinate for all mapped/open entries. * 2. Determines if entry needs a button. * 3. Collects the minimum height of open/mapped entries. (Do for all * entries upon insert). * 4. Figures out horizontal extent of each entry (will be width of * tree view column). * 5. Collects maximum icon size for each level. * 6. The height of its vertical line * * Results: * Returns 1 if beyond the last visible entry, 0 otherwise. * * Side effects: * The array of visible nodes is filled. * * ---------------------------------------------------------------------- */ static void ResetCoordinates( TreeView *tvPtr, TreeViewEntry *entryPtr, int *yPtr) { int depth; entryPtr->worldY = -1; entryPtr->vertLineLength = -1; if ((entryPtr != tvPtr->rootPtr) && (Blt_TreeViewEntryIsHidden(entryPtr))) { return; /* If the entry is hidden, then do nothing. */ } entryPtr->worldY = *yPtr; entryPtr->vertLineLength = -(*yPtr); *yPtr += entryPtr->height; depth = DEPTH(tvPtr, entryPtr->node) + 1; if (tvPtr->levelInfo[depth].labelWidth < entryPtr->labelWidth) { tvPtr->levelInfo[depth].labelWidth = entryPtr->labelWidth; } if (tvPtr->levelInfo[depth].iconWidth < entryPtr->iconWidth) { tvPtr->levelInfo[depth].iconWidth = entryPtr->iconWidth; } tvPtr->levelInfo[depth].iconWidth |= 0x01; if ((entryPtr->flags & ENTRY_CLOSED) == 0) { TreeViewEntry *bottomPtr, *childPtr; bottomPtr = entryPtr; for (childPtr = Blt_TreeViewFirstChild(entryPtr, ENTRY_HIDDEN); childPtr != NULL; childPtr = Blt_TreeViewNextSibling(childPtr, ENTRY_HIDDEN)){ ResetCoordinates(tvPtr, childPtr, yPtr); bottomPtr = childPtr; } entryPtr->vertLineLength += bottomPtr->worldY; } } static void AdjustColumns(TreeView *tvPtr) { Blt_ChainLink *linkPtr; TreeViewColumn *columnPtr; double weight; int nOpen; int size, avail, ration, growth; growth = VPORTWIDTH(tvPtr) - tvPtr->worldWidth; nOpen = 0; weight = 0.0; /* Find out how many columns still have space available */ for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { columnPtr = Blt_ChainGetValue(linkPtr); if ((columnPtr->hidden) || (columnPtr->weight == 0.0) || (columnPtr->width >= columnPtr->max) || (columnPtr->reqWidth > 0)) { continue; } nOpen++; weight += columnPtr->weight; } while ((nOpen > 0) && (weight > 0.0) && (growth > 0)) { ration = (int)(growth / weight); if (ration == 0) { ration = 1; } for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { columnPtr = Blt_ChainGetValue(linkPtr); if ((columnPtr->hidden) || (columnPtr->weight == 0.0) || (columnPtr->width >= columnPtr->max) || (columnPtr->reqWidth > 0)) { continue; } size = (int)(ration * columnPtr->weight); if (size > growth) { size = growth; } avail = columnPtr->max - columnPtr->width; if (size > avail) { size = avail; nOpen--; weight -= columnPtr->weight; } growth -= size; columnPtr->width += size; } } } /* * ---------------------------------------------------------------------- * * ComputeFlatLayout -- * * Recompute the layout when entries are opened/closed, * inserted/deleted, or when text attributes change (such as * font, linespacing). * * Results: * None. * * Side effects: * The world coordinates are set for all the opened entries. * * ---------------------------------------------------------------------- */ static void ComputeFlatLayout(TreeView *tvPtr) { Blt_ChainLink *linkPtr; TreeViewColumn *columnPtr; TreeViewEntry **p; TreeViewEntry *entryPtr; int count; int maxX; int y; /* * Pass 1: Reinitialize column sizes and loop through all nodes. * * 1. Recalculate the size of each entry as needed. * 2. The maximum depth of the tree. * 3. Minimum height of an entry. Dividing this by the * height of the widget gives a rough estimate of the * maximum number of visible entries. * 4. Build an array to hold level information to be filled * in on pass 2. */ if (tvPtr->flags & (TV_DIRTY | TV_UPDATE)) { int position; /* Reset the positions of all the columns and initialize the * column used to track the widest value. */ position = 1; for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { columnPtr = Blt_ChainGetValue(linkPtr); columnPtr->maxWidth = 0; columnPtr->max = SHRT_MAX; if (columnPtr->reqMax > 0) { columnPtr->max = columnPtr->reqMax; } columnPtr->position = position; position++; } /* If the view needs to be resorted, free the old view. */ if ((tvPtr->flags & TV_RESORT) && (tvPtr->flatArr != NULL)) { Blt_Free(tvPtr->flatArr); tvPtr->flatArr = NULL; } /* Recreate the flat view of all the open and not-hidden entries. */ if (tvPtr->flatArr == NULL) { count = 0; /* Count the number of open entries to allocate for the array. */ for (entryPtr = tvPtr->rootPtr; entryPtr != NULL; entryPtr = Blt_TreeViewNextEntry(entryPtr, ENTRY_MASK)) { if ((tvPtr->flags & TV_HIDE_ROOT) && (entryPtr == tvPtr->rootPtr)) { continue; } count++; } tvPtr->nEntries = count; /* Allocate an array for the flat view. */ tvPtr->flatArr = Blt_Calloc((count + 1), sizeof(TreeViewEntry *)); assert(tvPtr->flatArr); /* Fill the array with open and not-hidden entries */ p = tvPtr->flatArr; for (entryPtr = tvPtr->rootPtr; entryPtr != NULL; entryPtr = Blt_TreeViewNextEntry(entryPtr, ENTRY_MASK)) { if ((tvPtr->flags & TV_HIDE_ROOT) && (entryPtr == tvPtr->rootPtr)) { continue; } *p++ = entryPtr; } *p = NULL; tvPtr->flags &= ~TV_SORTED; /* Indicate the view isn't sorted. */ } /* Collect the extents of the entries in the flat view. */ tvPtr->depth = 0; tvPtr->minHeight = SHRT_MAX; for (p = tvPtr->flatArr; *p != NULL; p++) { entryPtr = *p; GetEntryExtents(tvPtr, entryPtr); if (tvPtr->minHeight > entryPtr->height) { tvPtr->minHeight = entryPtr->height; } entryPtr->flags &= ~ENTRY_HAS_BUTTON; } if (tvPtr->levelInfo != NULL) { Blt_Free(tvPtr->levelInfo); } tvPtr->levelInfo = Blt_Calloc(tvPtr->depth + 2, sizeof(LevelInfo)); assert(tvPtr->levelInfo); tvPtr->flags &= ~(TV_DIRTY | TV_UPDATE | TV_RESORT); if (tvPtr->flags & TV_SORT_AUTO) { /* If we're auto-sorting, schedule the view to be resorted. */ tvPtr->flags |= TV_SORT_PENDING; } } if (tvPtr->flags & TV_SORT_PENDING) { Blt_TreeViewSortFlatView(tvPtr); } tvPtr->levelInfo[0].labelWidth = tvPtr->levelInfo[0].x = tvPtr->levelInfo[0].iconWidth = 0; /* * Pass 2: Loop through all open/mapped nodes. * * 1. Set world y-coordinates for entries. We must defer * setting the x-coordinates until we know the maximum * icon sizes at each level. * 2. Compute the maximum depth of the tree. * 3. Build an array to hold level information. */ y = 0; count = 0; for(p = tvPtr->flatArr; *p != NULL; p++) { entryPtr = *p; entryPtr->flatIndex = count++; entryPtr->worldY = y; entryPtr->vertLineLength = 0; y += entryPtr->height; if (tvPtr->levelInfo[0].labelWidth < entryPtr->labelWidth) { tvPtr->levelInfo[0].labelWidth = entryPtr->labelWidth; } if (tvPtr->levelInfo[0].iconWidth < entryPtr->iconWidth) { tvPtr->levelInfo[0].iconWidth = entryPtr->iconWidth; } } tvPtr->levelInfo[0].iconWidth |= 0x01; tvPtr->worldHeight = y; /* Set the scroll height of the hierarchy. */ if (tvPtr->worldHeight < 1) { tvPtr->worldHeight = 1; } maxX = tvPtr->levelInfo[0].iconWidth + tvPtr->levelInfo[0].labelWidth; tvPtr->treeColumn.maxWidth = maxX; tvPtr->treeWidth = maxX; tvPtr->flags |= TV_VIEWPORT; } /* * ---------------------------------------------------------------------- * * ComputeTreeLayout -- * * Recompute the layout when entries are opened/closed, * inserted/deleted, or when text attributes change (such as * font, linespacing). * * Results: * None. * * Side effects: * The world coordinates are set for all the opened entries. * * ---------------------------------------------------------------------- */ static void ComputeTreeLayout(TreeView *tvPtr) { Blt_ChainLink *linkPtr; TreeViewColumn *columnPtr; TreeViewEntry *entryPtr; int maxX, x, y; int sum; register int i; /* * Pass 1: Reinitialize column sizes and loop through all nodes. * * 1. Recalculate the size of each entry as needed. * 2. The maximum depth of the tree. * 3. Minimum height of an entry. Dividing this by the * height of the widget gives a rough estimate of the * maximum number of visible entries. * 4. Build an array to hold level information to be filled * in on pass 2. */ if (tvPtr->flags & TV_DIRTY) { int position; position = 1; for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { columnPtr = Blt_ChainGetValue(linkPtr); columnPtr->maxWidth = 0; columnPtr->max = SHRT_MAX; if (columnPtr->reqMax > 0) { columnPtr->max = columnPtr->reqMax; } columnPtr->position = position; position++; } tvPtr->minHeight = SHRT_MAX; tvPtr->depth = 0; for (entryPtr = tvPtr->rootPtr; entryPtr != NULL; entryPtr = Blt_TreeViewNextEntry(entryPtr, 0)) { GetEntryExtents(tvPtr, entryPtr); if (tvPtr->minHeight > entryPtr->height) { tvPtr->minHeight = entryPtr->height; } /* * Determine if the entry should display a button * (indicating that it has children) and mark the * entry accordingly. */ entryPtr->flags &= ~ENTRY_HAS_BUTTON; if (entryPtr->flags & BUTTON_SHOW) { entryPtr->flags |= ENTRY_HAS_BUTTON; } else if (entryPtr->flags & BUTTON_AUTO) { if (tvPtr->flags & TV_HIDE_LEAVES) { /* Check that a non-leaf child exists */ if (Blt_TreeViewFirstChild(entryPtr, ENTRY_HIDDEN) != NULL) { entryPtr->flags |= ENTRY_HAS_BUTTON; } } else if (!Blt_TreeIsLeaf(entryPtr->node)) { entryPtr->flags |= ENTRY_HAS_BUTTON; } } /* Determine the depth of the tree. */ if (tvPtr->depth < DEPTH(tvPtr, entryPtr->node)) { tvPtr->depth = DEPTH(tvPtr, entryPtr->node); } } if (tvPtr->flags & TV_SORT_PENDING) { Blt_TreeViewSortTreeView(tvPtr); } if (tvPtr->levelInfo != NULL) { Blt_Free(tvPtr->levelInfo); } tvPtr->levelInfo = Blt_Calloc(tvPtr->depth + 2, sizeof(LevelInfo)); assert(tvPtr->levelInfo); tvPtr->flags &= ~(TV_DIRTY | TV_RESORT); } for (i = 0; i <= (tvPtr->depth + 1); i++) { tvPtr->levelInfo[i].labelWidth = tvPtr->levelInfo[i].x = tvPtr->levelInfo[i].iconWidth = 0; } /* * Pass 2: Loop through all open/mapped nodes. * * 1. Set world y-coordinates for entries. We must defer * setting the x-coordinates until we know the maximum * icon sizes at each level. * 2. Compute the maximum depth of the tree. * 3. Build an array to hold level information. */ y = 0; if (tvPtr->flags & TV_HIDE_ROOT) { /* If the root entry is to be hidden, cheat by offsetting * the y-coordinates by the height of the entry. */ y = -(tvPtr->rootPtr->height); } ResetCoordinates(tvPtr, tvPtr->rootPtr, &y); tvPtr->worldHeight = y; /* Set the scroll height of the hierarchy. */ if (tvPtr->worldHeight < 1) { tvPtr->worldHeight = 1; } sum = maxX = 0; for (i = 0; i <= (tvPtr->depth + 1); i++) { sum += tvPtr->levelInfo[i].iconWidth; if (i <= tvPtr->depth) { tvPtr->levelInfo[i + 1].x = sum; } x = sum + tvPtr->levelInfo[i].labelWidth; if (x > maxX) { maxX = x; } } tvPtr->treeColumn.maxWidth = maxX; tvPtr->treeWidth = maxX; } static void LayoutColumns(TreeView *tvPtr) { Blt_ChainLink *linkPtr; TreeViewColumn *columnPtr; int sum; /* The width of the widget (in world coordinates) is the sum * of the column widths. */ tvPtr->worldWidth = tvPtr->titleHeight = 0; sum = 0; for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { columnPtr = Blt_ChainGetValue(linkPtr); columnPtr->width = 0; if (!columnPtr->hidden) { if ((tvPtr->flags & TV_SHOW_COLUMN_TITLES) && (tvPtr->titleHeight < columnPtr->titleHeight)) { tvPtr->titleHeight = columnPtr->titleHeight; } if (columnPtr->reqWidth > 0) { columnPtr->width = columnPtr->reqWidth; } else { /* The computed width of a column is the maximum of * the title width and the widest entry. */ columnPtr->width = MAX(columnPtr->titleWidth, columnPtr->maxWidth); /* Check that the width stays within any constraints that * have been set. */ if ((columnPtr->reqMin > 0) && (columnPtr->reqMin > columnPtr->width)) { columnPtr->width = columnPtr->reqMin; } if ((columnPtr->reqMax > 0) && (columnPtr->reqMax < columnPtr->width)) { columnPtr->width = columnPtr->reqMax; } } columnPtr->width += PADDING(columnPtr->pad) + 2 * columnPtr->borderWidth; } columnPtr->worldX = sum; sum += columnPtr->width; } tvPtr->worldWidth = sum; if (VPORTWIDTH(tvPtr) > sum) { AdjustColumns(tvPtr); } sum = 0; for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { columnPtr = Blt_ChainGetValue(linkPtr); columnPtr->worldX = sum; sum += columnPtr->width; } if (tvPtr->titleHeight > 0) { /* If any headings are displayed, add some extra padding to * the height. */ tvPtr->titleHeight += 4; } /* tvPtr->worldWidth += 10; */ if (tvPtr->yScrollUnits < 1) { tvPtr->yScrollUnits = 1; } if (tvPtr->xScrollUnits < 1) { tvPtr->xScrollUnits = 1; } if (tvPtr->worldWidth < 1) { tvPtr->worldWidth = 1; } tvPtr->flags &= ~TV_LAYOUT; tvPtr->flags |= TV_SCROLL; } /* * ---------------------------------------------------------------------- * * Blt_TreeViewComputeLayout -- * * Recompute the layout when entries are opened/closed, * inserted/deleted, or when text attributes change (such as * font, linespacing). * * Results: * None. * * Side effects: * The world coordinates are set for all the opened entries. * * ---------------------------------------------------------------------- */ void Blt_TreeViewComputeLayout(TreeView *tvPtr) { Blt_ChainLink *linkPtr; TreeViewColumn *columnPtr; TreeViewEntry *entryPtr; TreeViewValue *valuePtr; if (tvPtr->flatView) { ComputeFlatLayout(tvPtr); } else { ComputeTreeLayout(tvPtr); } /* * Determine the width of each column based upon the entries * that as open (not hidden). The widest entry in a column * determines the width of that column. */ /* Initialize the columns. */ for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { columnPtr = Blt_ChainGetValue(linkPtr); columnPtr->maxWidth = 0; columnPtr->max = SHRT_MAX; if (columnPtr->reqMax > 0) { columnPtr->max = columnPtr->reqMax; } } /* The treeview column width was computed earlier. */ tvPtr->treeColumn.maxWidth = tvPtr->treeWidth; /* * Look at all open entries and their values. Determine the column * widths by tracking the maximum width value in each column. */ for (entryPtr = tvPtr->rootPtr; entryPtr != NULL; entryPtr = Blt_TreeViewNextEntry(entryPtr, ENTRY_MASK)) { for (valuePtr = entryPtr->values; valuePtr != NULL; valuePtr = valuePtr->nextPtr) { if (valuePtr->columnPtr->maxWidth < valuePtr->width) { valuePtr->columnPtr->maxWidth = valuePtr->width; } } } /* Now layout the columns with the proper sizes. */ LayoutColumns(tvPtr); } /* * ---------------------------------------------------------------------- * * ComputeVisibleEntries -- * * The entries visible in the viewport (the widget's window) are * inserted into the array of visible nodes. * * Results: * Returns 1 if beyond the last visible entry, 0 otherwise. * * Side effects: * The array of visible nodes is filled. * * ---------------------------------------------------------------------- */ static int ComputeVisibleEntries(TreeView *tvPtr) { int height; int level; int nSlots; int x, maxX; int xOffset, yOffset; xOffset = Blt_AdjustViewport(tvPtr->xOffset, tvPtr->worldWidth, VPORTWIDTH(tvPtr), tvPtr->xScrollUnits, tvPtr->scrollMode); yOffset = Blt_AdjustViewport(tvPtr->yOffset, tvPtr->worldHeight, VPORTHEIGHT(tvPtr), tvPtr->yScrollUnits, tvPtr->scrollMode); if ((xOffset != tvPtr->xOffset) || (yOffset != tvPtr->yOffset)) { tvPtr->yOffset = yOffset; tvPtr->xOffset = xOffset; tvPtr->flags |= TV_VIEWPORT; } height = VPORTHEIGHT(tvPtr); /* Allocate worst case number of slots for entry array. */ nSlots = (height / tvPtr->minHeight) + 3; if (nSlots != tvPtr->nVisible) { if (tvPtr->visibleArr != NULL) { Blt_Free(tvPtr->visibleArr); } tvPtr->visibleArr = Blt_Calloc(nSlots, sizeof(TreeViewEntry *)); assert(tvPtr->visibleArr); } tvPtr->nVisible = 0; if (tvPtr->rootPtr->flags & ENTRY_HIDDEN) { return TCL_OK; /* Root node is hidden. */ } /* Find the node where the view port starts. */ if (tvPtr->flatView) { register TreeViewEntry **p, *entryPtr; /* Find the starting entry visible in the viewport. It can't * be hidden or any of it's ancestors closed. */ again: for (p = tvPtr->flatArr; *p != NULL; p++) { entryPtr = *p; if ((entryPtr->worldY + entryPtr->height) > tvPtr->yOffset) { break; } } /* * If we can't find the starting node, then the view must be * scrolled down, but some nodes were deleted. Reset the view * back to the top and try again. */ if (*p == NULL) { if (tvPtr->yOffset == 0) { return TCL_OK; /* All entries are hidden. */ } tvPtr->yOffset = 0; goto again; } maxX = 0; height += tvPtr->yOffset; for (/* empty */; *p != NULL; p++) { entryPtr = *p; entryPtr->worldX = LEVELX(0) + tvPtr->treeColumn.worldX; x = entryPtr->worldX + ICONWIDTH(0) + entryPtr->width; if (x > maxX) { maxX = x; } if (entryPtr->worldY >= height) { break; } tvPtr->visibleArr[tvPtr->nVisible] = *p; tvPtr->nVisible++; } tvPtr->visibleArr[tvPtr->nVisible] = NULL; } else { TreeViewEntry *entryPtr; entryPtr = tvPtr->rootPtr; while ((entryPtr->worldY + entryPtr->height) <= tvPtr->yOffset) { for (entryPtr = Blt_TreeViewLastChild(entryPtr, ENTRY_HIDDEN); entryPtr != NULL; entryPtr = Blt_TreeViewPrevSibling(entryPtr, ENTRY_HIDDEN)) { if (entryPtr->worldY <= tvPtr->yOffset) { break; } } /* * If we can't find the starting node, then the view must be * scrolled down, but some nodes were deleted. Reset the view * back to the top and try again. */ if (entryPtr == NULL) { if (tvPtr->yOffset == 0) { return TCL_OK; /* All entries are hidden. */ } tvPtr->yOffset = 0; continue; } } height += tvPtr->yOffset; maxX = 0; tvPtr->treeColumn.maxWidth = tvPtr->treeWidth; for (/* empty */; entryPtr != NULL; entryPtr = Blt_TreeViewNextEntry(entryPtr, ENTRY_MASK)) { /* * Compute and save the entry's X-coordinate now that we know * the maximum level offset for the entire widget. */ level = DEPTH(tvPtr, entryPtr->node); entryPtr->worldX = LEVELX(level) + tvPtr->treeColumn.worldX; x = entryPtr->worldX + ICONWIDTH(level) + ICONWIDTH(level + 1) + entryPtr->width; if (x > maxX) { maxX = x; } if (entryPtr->worldY >= height) { break; } tvPtr->visibleArr[tvPtr->nVisible] = entryPtr; tvPtr->nVisible++; } tvPtr->visibleArr[tvPtr->nVisible] = NULL; } /* * ------------------------------------------------------------------- * * Note: It's assumed that the view port always starts at or * over an entry. Check that a change in the hierarchy * (e.g. closing a node) hasn't left the viewport beyond * the last entry. If so, adjust the viewport to start * on the last entry. * * ------------------------------------------------------------------- */ if (tvPtr->xOffset > (tvPtr->worldWidth - tvPtr->xScrollUnits)) { tvPtr->xOffset = tvPtr->worldWidth - tvPtr->xScrollUnits; } if (tvPtr->yOffset > (tvPtr->worldHeight - tvPtr->yScrollUnits)) { tvPtr->yOffset = tvPtr->worldHeight - tvPtr->yScrollUnits; } tvPtr->xOffset = Blt_AdjustViewport(tvPtr->xOffset, tvPtr->worldWidth, VPORTWIDTH(tvPtr), tvPtr->xScrollUnits, tvPtr->scrollMode); tvPtr->yOffset = Blt_AdjustViewport(tvPtr->yOffset, tvPtr->worldHeight, VPORTHEIGHT(tvPtr), tvPtr->yScrollUnits, tvPtr->scrollMode); Blt_PickCurrentItem(tvPtr->bindTable); tvPtr->flags &= ~TV_DIRTY; return TCL_OK; } /* * --------------------------------------------------------------------------- * * DrawVerticals -- * * Draws vertical lines for the ancestor nodes. While the entry * of the ancestor may not be visible, its vertical line segment * does extent into the viewport. So walk back up the hierarchy * drawing lines until we get to the root. * * Results: * None. * * Side Effects: * Vertical lines are drawn for the ancestor nodes. * * --------------------------------------------------------------------------- */ static void DrawVerticals( TreeView *tvPtr, /* Widget record containing the attribute * information for buttons. */ TreeViewEntry *entryPtr, /* Entry to be drawn. */ Drawable drawable) /* Pixmap or window to draw into. */ { int height, level; int x, y; int x1, y1, x2, y2; while (entryPtr != tvPtr->rootPtr) { entryPtr = Blt_TreeViewParentEntry(entryPtr); if (entryPtr == NULL) { break; } level = DEPTH(tvPtr, entryPtr->node); /* * World X-coordinates aren't computed only for entries that are * outside the view port. So for each off-screen ancestor node * compute it here too. */ entryPtr->worldX = LEVELX(level) + tvPtr->treeColumn.worldX; x = SCREENX(tvPtr, entryPtr->worldX); y = SCREENY(tvPtr, entryPtr->worldY); height = MAX3(entryPtr->lineHeight, entryPtr->iconHeight, tvPtr->button.height); y += (height - tvPtr->button.height) / 2; x1 = x2 = x + ICONWIDTH(level) + ICONWIDTH(level + 1) / 2; y1 = y + tvPtr->button.height / 2; y2 = y1 + entryPtr->vertLineLength; if ((entryPtr == tvPtr->rootPtr) && (tvPtr->flags & TV_HIDE_ROOT)) { y1 += entryPtr->height; } /* * Clip the line's Y-coordinates at the viewport borders. */ if (y1 < 0) { y1 = (y1 & 0x1); /* Make sure the dotted line starts on * the same even/odd pixel. */ } if (y2 > Tk_Height(tvPtr->tkwin)) { y2 = Tk_Height(tvPtr->tkwin); } if ((y1 < Tk_Height(tvPtr->tkwin)) && (y2 > 0)) { XDrawLine(tvPtr->display, drawable, tvPtr->lineGC, x1, y1, x2, y2); } } } void Blt_TreeViewDrawRule( TreeView *tvPtr, /* Widget record containing the * attribute information for rules. */ TreeViewColumn *columnPtr, Drawable drawable) /* Pixmap or window to draw into. */ { int x, y1, y2; x = SCREENX(tvPtr, columnPtr->worldX) + columnPtr->width + tvPtr->ruleMark - tvPtr->ruleAnchor - 1; y1 = tvPtr->titleHeight + tvPtr->inset; y2 = Tk_Height(tvPtr->tkwin) - tvPtr->inset; XDrawLine(tvPtr->display, drawable, columnPtr->ruleGC, x, y1, x, y2); tvPtr->flags = TOGGLE(tvPtr->flags, TV_RULE_ACTIVE); } /* * --------------------------------------------------------------------------- * * Blt_TreeViewDrawButton -- * * Draws a button for the given entry. The button is drawn * centered in the region immediately to the left of the origin * of the entry (computed in the layout routines). The height * and width of the button were previously calculated from the * average row height. * * button height = entry height - (2 * some arbitrary padding). * button width = button height. * * The button may have a border. The symbol (either a plus or * minus) is slight smaller than the width or height minus the * border. * * x,y origin of entry * * +---+ * | + | icon label * +---+ * closed * * |----|----| horizontal offset * * +---+ * | - | icon label * +---+ * open * * Results: * None. * * Side Effects: * A button is drawn for the entry. * * --------------------------------------------------------------------------- */ void Blt_TreeViewDrawButton( TreeView *tvPtr, /* Widget record containing the * attribute information for * buttons. */ TreeViewEntry *entryPtr, /* Entry. */ Drawable drawable, /* Pixmap or window to draw into. */ int x, int y) { Tk_3DBorder border; TreeViewButton *buttonPtr = &tvPtr->button; TreeViewIcon icon; int relief; int width, height; if (entryPtr == tvPtr->activeButtonPtr) { border = buttonPtr->activeBorder; } else { border = buttonPtr->border; } if (entryPtr->flags & ENTRY_CLOSED) { relief = buttonPtr->closeRelief; } else { relief = buttonPtr->openRelief; } if (relief == TK_RELIEF_SOLID) { relief = TK_RELIEF_FLAT; } Blt_Fill3DRectangle(tvPtr->tkwin, drawable, border, x, y, buttonPtr->width, buttonPtr->height, buttonPtr->borderWidth, relief); x += buttonPtr->borderWidth; y += buttonPtr->borderWidth; width = buttonPtr->width - (2 * buttonPtr->borderWidth); height = buttonPtr->height - (2 * buttonPtr->borderWidth); icon = NULL; if (buttonPtr->icons != NULL) { /* Open or close button icon? */ icon = buttonPtr->icons[0]; if (((entryPtr->flags & ENTRY_CLOSED) == 0) && (buttonPtr->icons[1] != NULL)) { icon = buttonPtr->icons[1]; } } if (icon != NULL) { /* Icon or rectangle? */ Tk_RedrawImage(TreeViewIconBits(icon), 0, 0, width, height, drawable, x, y); } else { int top, bottom, left, right; XSegment segments[6]; int count; GC gc; gc = (entryPtr == tvPtr->activeButtonPtr) ? buttonPtr->activeGC : buttonPtr->normalGC; if (relief == TK_RELIEF_FLAT) { /* Draw the box outline */ left = x - buttonPtr->borderWidth; top = y - buttonPtr->borderWidth; right = left + buttonPtr->width - 1; bottom = top + buttonPtr->height - 1; segments[0].x1 = left; segments[0].x2 = right; segments[0].y2 = segments[0].y1 = top; segments[1].x2 = segments[1].x1 = right; segments[1].y1 = top; segments[1].y2 = bottom; segments[2].x2 = segments[2].x1 = left; segments[2].y1 = top; segments[2].y2 = bottom; #ifdef WIN32 segments[2].y2++; #endif segments[3].x1 = left; segments[3].x2 = right; segments[3].y2 = segments[3].y1 = bottom; #ifdef WIN32 segments[3].x2++; #endif } top = y + height / 2; left = x + BUTTON_IPAD; right = x + width - BUTTON_IPAD; segments[4].y1 = segments[4].y2 = top; segments[4].x1 = left; segments[4].x2 = right - 1; #ifdef WIN32 segments[4].x2++; #endif count = 5; if (entryPtr->flags & ENTRY_CLOSED) { /* Draw the vertical * line for the plus. */ top = y + BUTTON_IPAD; bottom = y + height - BUTTON_IPAD; segments[5].y1 = top; segments[5].y2 = bottom - 1; segments[5].x1 = segments[5].x2 = x + width / 2; #ifdef WIN32 segments[5].y2++; #endif count = 6; } XDrawSegments(tvPtr->display, drawable, gc, segments, count); } } /* * --------------------------------------------------------------------------- * * Blt_TreeViewGetEntryIcon -- * * Selects the correct image for the entry's icon depending upon * the current state of the entry: active/inactive normal/selected. * * active - normal * active - selected * inactive - normal * inactive - selected * * Results: * Returns the image for the icon. * * --------------------------------------------------------------------------- */ TreeViewIcon Blt_TreeViewGetEntryIcon(TreeView *tvPtr, TreeViewEntry *entryPtr) { TreeViewIcon *icons; TreeViewIcon icon; int isActive, hasFocus; isActive = (entryPtr == tvPtr->activePtr); hasFocus = (entryPtr == tvPtr->focusPtr); icons = NULL; if (isActive) { icons = CHOOSE(tvPtr->activeIcons, entryPtr->activeIcons); } if (icons == NULL) { icons = CHOOSE(tvPtr->icons, entryPtr->icons); } icon = NULL; if (icons != NULL) { /* Selected or normal icon? */ icon = icons[0]; if ((hasFocus) && (icons[1] != NULL)) { icon = icons[1]; } } return icon; } int Blt_TreeViewDrawIcon( TreeView *tvPtr, /* Widget record containing the attribute * information for buttons. */ TreeViewEntry *entryPtr, /* Entry to display. */ Drawable drawable, /* Pixmap or window to draw into. */ int x, int y) { TreeViewIcon icon; icon = Blt_TreeViewGetEntryIcon(tvPtr, entryPtr); if (icon != NULL) { /* Icon or default icon bitmap? */ int entryHeight; int level; int maxY; int top, bottom; int topInset, botInset; int width, height; level = DEPTH(tvPtr, entryPtr->node); entryHeight = MAX3(entryPtr->lineHeight, entryPtr->iconHeight, tvPtr->button.height); height = TreeViewIconHeight(icon); width = TreeViewIconWidth(icon); if (tvPtr->flatView) { x += (ICONWIDTH(0) - width) / 2; } else { x += (ICONWIDTH(level + 1) - width) / 2; } y += (entryHeight - height) / 2; botInset = tvPtr->inset - INSET_PAD; topInset = tvPtr->titleHeight + tvPtr->inset; maxY = Tk_Height(tvPtr->tkwin) - botInset; top = 0; bottom = y + height; if (y < topInset) { height += y - topInset; top = -y + topInset; y = topInset; } else if (bottom >= maxY) { height = maxY - y; } Tk_RedrawImage(TreeViewIconBits(icon), 0, top, width, height, drawable, x, y); } return (icon != NULL); } static int DrawLabel( TreeView *tvPtr, /* Widget record. */ TreeViewEntry *entryPtr, /* Entry attribute information. */ Drawable drawable, /* Pixmap or window to draw into. */ int x, int y) { char *label; int entryHeight; int isFocused; int width, height; /* Width and height of label. */ int selected; entryHeight = MAX3(entryPtr->lineHeight, entryPtr->iconHeight, tvPtr->button.height); isFocused = ((entryPtr == tvPtr->focusPtr) && (tvPtr->flags & TV_FOCUS)); selected = Blt_TreeViewEntryIsSelected(tvPtr, entryPtr); /* Includes padding, selection 3-D border, and focus outline. */ width = entryPtr->labelWidth; height = entryPtr->labelHeight; /* Center the label, if necessary, vertically along the entry row. */ if (height < entryHeight) { y += (entryHeight - height) / 2; } if (isFocused) { /* Focus outline */ if (selected) { XColor *color; color = SELECT_FG(tvPtr); XSetForeground(tvPtr->display, tvPtr->focusGC, color->pixel); } XDrawRectangle(tvPtr->display, drawable, tvPtr->focusGC, x, y, width - 1, height - 1); if (selected) { XSetForeground(tvPtr->display, tvPtr->focusGC, tvPtr->focusColor->pixel); } } x += FOCUS_WIDTH + LABEL_PADX + tvPtr->selBorderWidth; y += FOCUS_WIDTH + LABEL_PADY + tvPtr->selBorderWidth; label = GETLABEL(entryPtr); if (label[0] != '\0') { GC gc; TreeViewStyle *stylePtr; TextStyle ts; Tk_Font font; XColor *normalColor, *activeColor; stylePtr = tvPtr->treeColumn.stylePtr; font = entryPtr->font; if (font == NULL) { font = Blt_TreeViewGetStyleFont(tvPtr, stylePtr); } normalColor = entryPtr->color; if (normalColor == NULL) { normalColor = Blt_TreeViewGetStyleFg(tvPtr, stylePtr); } activeColor = (selected) ? SELECT_FG(tvPtr) : normalColor; gc = entryPtr->gc; if (gc == NULL) { gc = Blt_TreeViewGetStyleGC(stylePtr); } Blt_SetDrawTextStyle(&ts, font, gc, normalColor, activeColor, entryPtr->shadow.color, 0.0, TK_ANCHOR_NW, TK_JUSTIFY_LEFT, 0, entryPtr->shadow.offset); ts.state = (selected || (entryPtr->gc == NULL)) ? STATE_ACTIVE : 0; Blt_DrawTextLayout(tvPtr->tkwin, drawable, entryPtr->textPtr, &ts, x, y); } return entryHeight; } /* * --------------------------------------------------------------------------- * * DrawFlatEntry -- * * Draws a button for the given entry. Note that buttons should only * be drawn if the entry has sub-entries to be opened or closed. It's * the responsibility of the calling routine to ensure this. * * The button is drawn centered in the region immediately to the left * of the origin of the entry (computed in the layout routines). The * height and width of the button were previously calculated from the * average row height. * * button height = entry height - (2 * some arbitrary padding). * button width = button height. * * The button has a border. The symbol (either a plus or minus) is * slight smaller than the width or height minus the border. * * x,y origin of entry * * +---+ * | + | icon label * +---+ * closed * * |----|----| horizontal offset * * +---+ * | - | icon label * +---+ * open * * Results: * None. * * Side Effects: * A button is drawn for the entry. * * --------------------------------------------------------------------------- */ static void DrawFlatEntry( TreeView *tvPtr, /* Widget record containing the attribute * information for buttons. */ TreeViewEntry *entryPtr, /* Entry to be drawn. */ Drawable drawable) /* Pixmap or window to draw into. */ { int level; int x, y; entryPtr->flags &= ~ENTRY_REDRAW; x = SCREENX(tvPtr, entryPtr->worldX); y = SCREENY(tvPtr, entryPtr->worldY); if (!Blt_TreeViewDrawIcon(tvPtr, entryPtr, drawable, x, y)) { x -= (DEF_ICON_WIDTH * 2) / 3; } level = 0; x += ICONWIDTH(level); /* Entry label. */ DrawLabel(tvPtr, entryPtr, drawable, x, y); } /* * --------------------------------------------------------------------------- * * DrawTreeEntry -- * * Draws a button for the given entry. Note that buttons should only * be drawn if the entry has sub-entries to be opened or closed. It's * the responsibility of the calling routine to ensure this. * * The button is drawn centered in the region immediately to the left * of the origin of the entry (computed in the layout routines). The * height and width of the button were previously calculated from the * average row height. * * button height = entry height - (2 * some arbitrary padding). * button width = button height. * * The button has a border. The symbol (either a plus or minus) is * slight smaller than the width or height minus the border. * * x,y origin of entry * * +---+ * | + | icon label * +---+ * closed * * |----|----| horizontal offset * * +---+ * | - | icon label * +---+ * open * * Results: * None. * * Side Effects: * A button is drawn for the entry. * * --------------------------------------------------------------------------- */ static void DrawTreeEntry( TreeView *tvPtr, /* Widget record. */ TreeViewEntry *entryPtr, /* Entry to be drawn. */ Drawable drawable) /* Pixmap or window to draw into. */ { TreeViewButton *buttonPtr = &tvPtr->button; int buttonY; int level; int width, height; int x, y; int x1, y1, x2, y2; entryPtr->flags &= ~ENTRY_REDRAW; x = SCREENX(tvPtr, entryPtr->worldX); y = SCREENY(tvPtr, entryPtr->worldY); level = DEPTH(tvPtr, entryPtr->node); width = ICONWIDTH(level); height = MAX3(entryPtr->lineHeight, entryPtr->iconHeight, buttonPtr->height); entryPtr->buttonX = (width - buttonPtr->width) / 2; entryPtr->buttonY = (height - buttonPtr->height) / 2; buttonY = y + entryPtr->buttonY; x1 = x + (width / 2); y1 = y2 = buttonY + (buttonPtr->height / 2); x2 = x1 + (ICONWIDTH(level) + ICONWIDTH(level + 1)) / 2; if ((Blt_TreeNodeParent(entryPtr->node) != NULL) && (tvPtr->lineWidth > 0)) { /* * For every node except root, draw a horizontal line from * the vertical bar to the middle of the icon. */ XDrawLine(tvPtr->display, drawable, tvPtr->lineGC, x1, y1, x2, y2); } if (((entryPtr->flags & ENTRY_CLOSED) == 0) && (tvPtr->lineWidth > 0)) { /* * Entry is open, draw vertical line. */ y2 = y1 + entryPtr->vertLineLength; if (y2 > Tk_Height(tvPtr->tkwin)) { y2 = Tk_Height(tvPtr->tkwin); /* Clip line at window border. */ } XDrawLine(tvPtr->display, drawable, tvPtr->lineGC, x2, y1, x2, y2); } if ((entryPtr->flags & ENTRY_HAS_BUTTON) && (entryPtr != tvPtr->rootPtr)) { /* * Except for the root, draw a button for every entry that * needs one. The displayed button can be either an icon (Tk * image) or a line drawing (rectangle with plus or minus * sign). */ Blt_TreeViewDrawButton(tvPtr, entryPtr, drawable, x + entryPtr->buttonX, y + entryPtr->buttonY); } x += ICONWIDTH(level); if (!Blt_TreeViewDrawIcon(tvPtr, entryPtr, drawable, x, y)) { x -= (DEF_ICON_WIDTH * 2) / 3; } x += ICONWIDTH(level + 1) + 4; /* Entry label. */ DrawLabel(tvPtr, entryPtr, drawable, x, y); } /* * --------------------------------------------------------------------------- * * Blt_TreeViewDrawValue -- * * Draws a column value for the given entry. * * Results: * None. * * Side Effects: * A button is drawn for the entry. * * --------------------------------------------------------------------------- */ void Blt_TreeViewDrawValue( TreeView *tvPtr, /* Widget record. */ TreeViewEntry *entryPtr, /* Node of entry to be drawn. */ TreeViewValue *valuePtr, Drawable drawable, /* Pixmap or window to draw into. */ int x, int y) { TreeViewStyle *stylePtr; stylePtr = CHOOSE(valuePtr->columnPtr->stylePtr, valuePtr->stylePtr); (*stylePtr->classPtr->drawProc)(tvPtr, drawable, entryPtr, valuePtr, stylePtr, x, y); } static void DrawTitle( TreeView *tvPtr, TreeViewColumn *columnPtr, Drawable drawable, int x) { GC gc; Tk_3DBorder border; XColor *fgColor; int columnWidth; int width; int x0, cx, xOffset; columnWidth = columnPtr->width; cx = x; if (columnPtr->position == Blt_ChainGetLength(tvPtr->colChainPtr)) { /* If there's any room left over, let the last column take it. */ columnWidth = Tk_Width(tvPtr->tkwin) - x; } else if (columnPtr->position == 1) { columnWidth += x; cx = 0; } x0 = x + columnPtr->borderWidth; if (columnPtr == tvPtr->activeTitleColumnPtr) { border = columnPtr->activeTitleBorder; gc = columnPtr->activeTitleGC; fgColor = columnPtr->activeTitleFgColor; } else { border = columnPtr->titleBorder; gc = columnPtr->titleGC; fgColor = columnPtr->titleFgColor; } Blt_Fill3DRectangle(tvPtr->tkwin, drawable, border, cx + 1, tvPtr->inset + 1, columnWidth - 2, tvPtr->titleHeight - 2, 0, TK_RELIEF_FLAT); width = columnPtr->width; xOffset = x0 + columnPtr->pad.side1 + 1; if (width > columnPtr->titleWidth) { x += (width - columnPtr->titleWidth) / 2; } if (columnPtr == tvPtr->sortColumnPtr) { /* Make sure there's room for the sorting-direction triangle. */ if ((x - xOffset) <= (STD_ARROW_WIDTH + 4)) { x = xOffset + STD_ARROW_WIDTH + 4; } } if (columnPtr->titleIcon != NULL) { int iconX, iconY, iconWidth, iconHeight; iconHeight = TreeViewIconHeight(columnPtr->titleIcon); iconWidth = TreeViewIconWidth(columnPtr->titleIcon); iconX = x; if (columnPtr->titleTextPtr != NULL) { iconX += 2; } iconY = tvPtr->inset + (tvPtr->titleHeight - iconHeight) / 2; Tk_RedrawImage(TreeViewIconBits(columnPtr->titleIcon), 0, 0, iconWidth, iconHeight, drawable, iconX, iconY); x += iconWidth + 6; } if (columnPtr->titleTextPtr != NULL) { TextStyle ts; Blt_SetDrawTextStyle(&ts, columnPtr->titleFont, gc, fgColor, SELECT_FG(tvPtr), columnPtr->titleShadow.color, 0.0, TK_ANCHOR_NW, TK_JUSTIFY_LEFT, 0, columnPtr->titleShadow.offset); Blt_DrawTextLayout(tvPtr->tkwin, drawable, columnPtr->titleTextPtr, &ts, x, tvPtr->inset + 1); } if ((columnPtr == tvPtr->sortColumnPtr) && (tvPtr->flatView)) { Blt_DrawArrow(tvPtr->display, drawable, gc, xOffset + ARROW_OFFSET, tvPtr->inset + tvPtr->titleHeight / 2, STD_ARROW_HEIGHT, (tvPtr->sortDecreasing) ? ARROW_UP : ARROW_DOWN); } Blt_Draw3DRectangle(tvPtr->tkwin, drawable, border, cx, tvPtr->inset, columnWidth, tvPtr->titleHeight, columnPtr->titleBorderWidth, columnPtr->titleRelief); } void Blt_TreeViewDrawHeadings(tvPtr, drawable) TreeView *tvPtr; Drawable drawable; { Blt_ChainLink *linkPtr; TreeViewColumn *columnPtr; int x; for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { columnPtr = Blt_ChainGetValue(linkPtr); if (columnPtr->hidden) { continue; } x = SCREENX(tvPtr, columnPtr->worldX); if ((x + columnPtr->width) < 0) { continue; /* Don't draw columns before the left edge. */ } if (x > Tk_Width(tvPtr->tkwin)) { break; /* Discontinue when a column starts beyond * the right edge. */ } DrawTitle(tvPtr, columnPtr, drawable, x); } } static void DrawTreeView(tvPtr, drawable, x) TreeView *tvPtr; Drawable drawable; int x; { register TreeViewEntry **p; Tk_3DBorder selBorder; /* * Draw the backgrounds of selected entries first. The vertical * lines connecting child entries will be draw on top. */ selBorder = SELECT_BORDER(tvPtr); for (p = tvPtr->visibleArr; *p != NULL; p++) { if (Blt_TreeViewEntryIsSelected(tvPtr, *p)) { int y; y = SCREENY(tvPtr, (*p)->worldY) - 1; Blt_Fill3DRectangle(tvPtr->tkwin, drawable, selBorder, x, y, tvPtr->treeColumn.width, (*p)->height + 1, tvPtr->selBorderWidth, tvPtr->selRelief); } } if ((tvPtr->lineWidth > 0) && (tvPtr->nVisible > 0)) { /* Draw all the vertical lines from topmost node. */ DrawVerticals(tvPtr, tvPtr->visibleArr[0], drawable); } for (p = tvPtr->visibleArr; *p != NULL; p++) { DrawTreeEntry(tvPtr, *p, drawable); } } static void DrawFlatView( TreeView *tvPtr, Drawable drawable, int x) { register TreeViewEntry **p; Tk_3DBorder selBorder; /* * Draw the backgrounds of selected entries first. The vertical * lines connecting child entries will be draw on top. */ selBorder = SELECT_BORDER(tvPtr); for (p = tvPtr->visibleArr; *p != NULL; p++) { if (Blt_TreeViewEntryIsSelected(tvPtr, *p)) { int y; y = SCREENY(tvPtr, (*p)->worldY) - 1; Blt_Fill3DRectangle(tvPtr->tkwin, drawable, selBorder, x, y, tvPtr->treeColumn.width, (*p)->height + 1, tvPtr->selBorderWidth, tvPtr->selRelief); } } for (p = tvPtr->visibleArr; *p != NULL; p++) { DrawFlatEntry(tvPtr, *p, drawable); } } void Blt_TreeViewDrawOuterBorders(tvPtr, drawable) TreeView *tvPtr; Drawable drawable; { /* Draw 3D border just inside of the focus highlight ring. */ if ((tvPtr->borderWidth > 0) && (tvPtr->relief != TK_RELIEF_FLAT)) { Blt_Draw3DRectangle(tvPtr->tkwin, drawable, tvPtr->border, tvPtr->highlightWidth, tvPtr->highlightWidth, Tk_Width(tvPtr->tkwin) - 2 * tvPtr->highlightWidth, Tk_Height(tvPtr->tkwin) - 2 * tvPtr->highlightWidth, tvPtr->borderWidth, tvPtr->relief); } /* Draw focus highlight ring. */ if (tvPtr->highlightWidth > 0) { XColor *color; GC gc; color = (tvPtr->flags & TV_FOCUS) ? tvPtr->highlightColor : tvPtr->highlightBgColor; gc = Tk_GCForColor(color, drawable); Tk_DrawFocusHighlight(tvPtr->tkwin, gc, tvPtr->highlightWidth, drawable); } tvPtr->flags &= ~TV_BORDERS; } /* * ---------------------------------------------------------------------- * * DisplayTreeView -- * * This procedure is invoked to display the widget. * * Recompute the layout of the text if necessary. This is * necessary if the world coordinate system has changed. * Specifically, the following may have occurred: * * 1. a text attribute has changed (font, linespacing, etc.). * 2. an entry's option changed, possibly resizing the entry. * * This is deferred to the display routine since potentially * many of these may occur. * * Set the vertical and horizontal scrollbars. This is done * here since the window width and height are needed for the * scrollbar calculations. * * Results: * None. * * Side effects: * The widget is redisplayed. * * ---------------------------------------------------------------------- */ static void DisplayTreeView(ClientData clientData) /* Information about widget. */ { Blt_ChainLink *linkPtr; TreeView *tvPtr = clientData; TreeViewColumn *columnPtr; Pixmap drawable; int width, height; int x; tvPtr->flags &= ~TV_REDRAW; if (tvPtr->tkwin == NULL) { return; /* Window has been destroyed. */ } if (tvPtr->flags & TV_LAYOUT) { /* * Recompute the layout when entries are opened/closed, * inserted/deleted, or when text attributes change (such as * font, linespacing). */ Blt_TreeViewComputeLayout(tvPtr); } if (tvPtr->flags & TV_SCROLL) { /* * Scrolling means that the view port has changed and that the * visible entries need to be recomputed. */ ComputeVisibleEntries(tvPtr); width = VPORTWIDTH(tvPtr); height = VPORTHEIGHT(tvPtr); if (tvPtr->flags & TV_XSCROLL) { if (tvPtr->xScrollCmdPrefix != NULL) { Blt_UpdateScrollbar(tvPtr->interp, tvPtr->xScrollCmdPrefix, (double)tvPtr->xOffset / tvPtr->worldWidth, (double)(tvPtr->xOffset + width) / tvPtr->worldWidth); } } if (tvPtr->flags & TV_YSCROLL) { if (tvPtr->yScrollCmdPrefix != NULL) { Blt_UpdateScrollbar(tvPtr->interp, tvPtr->yScrollCmdPrefix, (double)tvPtr->yOffset / tvPtr->worldHeight, (double)(tvPtr->yOffset + height) / tvPtr->worldHeight); } } tvPtr->flags &= ~TV_SCROLL; } if (tvPtr->reqWidth == 0) { /* * The first time through this routine, set the requested * width to the computed width. All we want is to * automatically set the width of the widget, not dynamically * grow/shrink it as attributes change. */ tvPtr->reqWidth = tvPtr->worldWidth + 2 * tvPtr->inset; Tk_GeometryRequest(tvPtr->tkwin, tvPtr->reqWidth, tvPtr->reqHeight); } if (!Tk_IsMapped(tvPtr->tkwin)) { return; } drawable = Tk_GetPixmap(tvPtr->display, Tk_WindowId(tvPtr->tkwin), Tk_Width(tvPtr->tkwin), Tk_Height(tvPtr->tkwin), Tk_Depth(tvPtr->tkwin)); tvPtr->flags |= TV_VIEWPORT; if ((tvPtr->flags & TV_RULE_ACTIVE) && (tvPtr->resizeColumnPtr != NULL)) { Blt_TreeViewDrawRule(tvPtr, tvPtr->resizeColumnPtr, drawable); } { register TreeViewEntry **p; Tk_3DBorder border, selBorder; int y; selBorder = SELECT_BORDER(tvPtr); for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { columnPtr = Blt_ChainGetValue(linkPtr); columnPtr->flags &= ~COLUMN_DIRTY; if (columnPtr->hidden) { continue; } x = SCREENX(tvPtr, columnPtr->worldX); if ((x + columnPtr->width) < 0) { continue; /* Don't draw columns before the left edge. */ } if (x > Tk_Width(tvPtr->tkwin)) { break; /* Discontinue when a column starts beyond * the right edge. */ } /* Clear the column background. */ border = Blt_TreeViewGetStyleBorder(tvPtr, tvPtr->stylePtr); Blt_Fill3DRectangle(tvPtr->tkwin, drawable, border, x, 0, columnPtr->width, Tk_Height(tvPtr->tkwin), 0, TK_RELIEF_FLAT); if (columnPtr != &tvPtr->treeColumn) { TreeViewValue *valuePtr; TreeViewEntry *entryPtr; for (p = tvPtr->visibleArr; *p != NULL; p++) { entryPtr = *p; y = SCREENY(tvPtr, entryPtr->worldY); /* Draw the background of the value. */ if (Blt_TreeViewEntryIsSelected(tvPtr, entryPtr)) { Blt_Fill3DRectangle(tvPtr->tkwin, drawable, selBorder, x, y - 1, columnPtr->width, entryPtr->height + 1, tvPtr->selBorderWidth, tvPtr->selRelief); } /* Check if there's a corresponding value in the entry. */ valuePtr = Blt_TreeViewFindValue(entryPtr, columnPtr); if (valuePtr != NULL) { Blt_TreeViewDrawValue(tvPtr, entryPtr, valuePtr, drawable, x + columnPtr->pad.side1, y); } } } else { if (tvPtr->flatView) { DrawFlatView(tvPtr, drawable, x); } else { DrawTreeView(tvPtr, drawable, x); } } if (columnPtr->relief != TK_RELIEF_FLAT) { Blt_Draw3DRectangle(tvPtr->tkwin, drawable, border, x, 0, columnPtr->width, Tk_Height(tvPtr->tkwin), columnPtr->borderWidth, columnPtr->relief); } } } if (tvPtr->flags & TV_SHOW_COLUMN_TITLES) { Blt_TreeViewDrawHeadings(tvPtr, drawable); } Blt_TreeViewDrawOuterBorders(tvPtr, drawable); if ((tvPtr->flags & TV_RULE_NEEDED) && (tvPtr->resizeColumnPtr != NULL)) { Blt_TreeViewDrawRule(tvPtr, tvPtr->resizeColumnPtr, drawable); } /* Now copy the new view to the window. */ XCopyArea(tvPtr->display, drawable, Tk_WindowId(tvPtr->tkwin), tvPtr->lineGC, 0, 0, Tk_Width(tvPtr->tkwin), Tk_Height(tvPtr->tkwin), 0, 0); Tk_FreePixmap(tvPtr->display, drawable); tvPtr->flags &= ~TV_VIEWPORT; } /* *---------------------------------------------------------------------- * * Blt_TreeViewSelectCmdProc -- * * Invoked at the next idle point whenever the current * selection changes. Executes some application-specific code * in the -selectcommand option. This provides a way for * applications to handle selection changes. * * Results: * None. * * Side effects: * Tcl code gets executed for some application-specific task. * *---------------------------------------------------------------------- */ void Blt_TreeViewSelectCmdProc(ClientData clientData) { TreeView *tvPtr = clientData; Tcl_Preserve(tvPtr); if (tvPtr->selectCmd != NULL) { tvPtr->flags &= ~TV_SELECT_PENDING; if (Tcl_GlobalEval(tvPtr->interp, tvPtr->selectCmd) != TCL_OK) { Tcl_BackgroundError(tvPtr->interp); } } Tcl_Release(tvPtr); } /* * -------------------------------------------------------------- * * TreeViewObjCmd -- * * This procedure is invoked to process the Tcl command that * corresponds to a widget managed by this module. See the user * documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * * -------------------------------------------------------------- */ /* ARGSUSED */ static int TreeViewObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Main window associated with interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST *objv; /* Argument strings. */ { Tcl_CmdInfo cmdInfo; Tcl_Obj *initObjv[2]; TreeView *tvPtr; char *className; char *string; string = Tcl_GetString(objv[0]); if (objc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", string, " pathName ?option value?...\"", (char *)NULL); return TCL_ERROR; } className = (string[0] == 'h') ? "Hiertable" : "TreeView"; tvPtr = CreateTreeView(interp, objv[1], className); if (tvPtr == NULL) { goto error; } /* * Invoke a procedure to initialize various bindings on treeview * entries. If the procedure doesn't already exist, source it * from "$blt_library/treeview.tcl". We deferred sourcing the * file until now so that the variable $blt_library could be set * within a script. */ if (!Tcl_GetCommandInfo(interp, "blt::tv::Initialize", &cmdInfo)) { char cmd[200]; sprintf(cmd, "set className %s\n\ source [file join $blt_library treeview.tcl]\n\ unset className\n", className); if (Tcl_GlobalEval(interp, cmd) != TCL_OK) { char info[200]; sprintf(info, "\n (while loading bindings for %.50s)", Tcl_GetString(objv[0])); Tcl_AddErrorInfo(interp, info); goto error; } } /* * Initialize the widget's configuration options here. The options * need to be set first, so that entry, column, and style * components can use them for their own GCs. */ bltTreeViewIconsOption.clientData = tvPtr; bltTreeViewTreeOption.clientData = tvPtr; if (Blt_ConfigureWidgetFromObj(interp, tvPtr->tkwin, bltTreeViewSpecs, objc - 2, objv + 2, (char *)tvPtr, 0) != TCL_OK) { return TCL_ERROR; } if (Blt_ConfigureComponentFromObj(interp, tvPtr->tkwin, "button", "Button", bltTreeViewButtonSpecs, 0, (Tcl_Obj **)NULL, (char *)tvPtr, 0) != TCL_OK) { goto error; } /* * Rebuild the widget's GC and other resources that are predicated * by the widget's configuration options. Do the same for the * default column. */ if (Blt_TreeViewUpdateWidget(interp, tvPtr) != TCL_OK) { goto error; } Blt_TreeViewUpdateColumnGCs(tvPtr, &tvPtr->treeColumn); Blt_TreeViewUpdateStyleGCs(tvPtr, tvPtr->stylePtr); /* * Invoke a procedure to initialize various bindings on treeview * entries. If the procedure doesn't already exist, source it * from "$blt_library/treeview.tcl". We deferred sourcing the * file until now so that the variable $blt_library could be set * within a script. */ initObjv[0] = Tcl_NewStringObj("blt::tv::Initialize", -1); initObjv[1] = objv[1]; if (Tcl_EvalObjv(interp, 2, initObjv, TCL_EVAL_GLOBAL) != TCL_OK) { goto error; } Tcl_DecrRefCount(initObjv[0]); Tcl_SetObjResult(interp, Tcl_NewStringObj(Tk_PathName(tvPtr->tkwin), -1)); return TCL_OK; error: Tk_DestroyWindow(tvPtr->tkwin); return TCL_ERROR; } int Blt_TreeViewInit(Tcl_Interp *interp) { static Blt_ObjCmdSpec cmdSpec[] = { { "treeview", TreeViewObjCmd, }, { "hiertable", TreeViewObjCmd, } }; if (Blt_InitObjCmd(interp, "blt", cmdSpec) == NULL) { return TCL_ERROR; } if (Blt_InitObjCmd(interp, "blt", cmdSpec + 1) == NULL) { return TCL_ERROR; } return TCL_OK; } #endif /* NO_TREEVIEW */ blt-2.4z.orig/src/bltTreeView.h0100644000175000017500000011077507527024466015167 0ustar dokodoko /* * bltTreeView.h -- * * This module implements an hierarchy widget for the BLT toolkit. * * Copyright 1998-1999 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 or 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. * * The "treeview" widget was created by George A. Howlett. */ /* * TODO: * * BUGS: * 1. "open" operation should change scroll offset so that as many * new entries (up to half a screen) can be seen. * 2. "open" needs to adjust the scrolloffset so that the same entry * is seen at the same place. */ #ifndef BLT_TREEVIEW_H #define BLT_TREEVIEW_H #include "bltImage.h" #include "bltHash.h" #include "bltChain.h" #include "bltTree.h" #include "bltTile.h" #include "bltBind.h" #include "bltObjConfig.h" #define ITEM_ENTRY (ClientData)0 #define ITEM_ENTRY_BUTTON (ClientData)1 #define ITEM_COLUMN_TITLE (ClientData)2 #define ITEM_COLUMN_RULE (ClientData)3 #define ITEM_STYLE (ClientData)0x10004 #if HAVE_UTF #else #define Tcl_NumUtfChars(s,n) (((n) == -1) ? strlen((s)) : (n)) #define Tcl_UtfAtIndex(s,i) ((s) + (i)) #endif #define ODD(x) ((x) | 0x01) #define END (-1) #define SEPARATOR_LIST ((char *)NULL) #define SEPARATOR_NONE ((char *)-1) #define SEARCH_Y 1 typedef char *UID; /* * The macro below is used to modify a "char" value (e.g. by casting * it to an unsigned character) so that it can be used safely with * macros such as isspace. */ #define UCHAR(c) ((unsigned char) (c)) #define TOGGLE(x, mask) (((x) & (mask)) ? ((x) & ~(mask)) : ((x) | (mask))) #define SCREENX(h, wx) ((wx) - (h)->xOffset + (h)->inset) #define SCREENY(h, wy) ((wy) - (h)->yOffset + (h)->inset + (h)->titleHeight) #define WORLDX(h, sx) ((sx) - (h)->inset + (h)->xOffset) #define WORLDY(h, sy) ((sy) - ((h)->inset + (h)->titleHeight) + (h)->yOffset) #define VPORTWIDTH(h) (Tk_Width((h)->tkwin) - 2 * (h)->inset) #define VPORTHEIGHT(h) \ (Tk_Height((h)->tkwin) - (h)->titleHeight - 2 * (h)->inset) #define ICONWIDTH(d) (tvPtr->levelInfo[(d)].iconWidth) #define LEVELX(d) (tvPtr->levelInfo[(d)].x) #define DEPTH(h, n) \ (((h)->flatView) ? 0 : Blt_TreeNodeDepth((h)->tree, (n))) #define SELECT_FG(t) \ (((((t)->flags & TV_FOCUS)) || ((t)->selOutFocusFgColor == NULL)) \ ? (t)->selInFocusFgColor : (t)->selOutFocusFgColor) #define SELECT_BORDER(t) \ (((((t)->flags & TV_FOCUS)) || ((t)->selOutFocusBorder == NULL)) \ ? (t)->selInFocusBorder : (t)->selOutFocusBorder) #define SELECT_MODE_SINGLE (1<<0) #define SELECT_MODE_MULTIPLE (1<<1) /* * ---------------------------------------------------------------------------- * * Internal treeview widget flags: * * TV_LAYOUT The layout of the hierarchy needs to be recomputed. * * TV_REDRAW A redraw request is pending for the widget. * * TV_XSCROLL X-scroll request is pending. * * TV_YSCROLL Y-scroll request is pending. * * TV_SCROLL Both X-scroll and Y-scroll requests are pending. * * TV_FOCUS The widget is receiving keyboard events. * Draw the focus highlight border around the widget. * * TV_DIRTY The hierarchy has changed. It may invalidate * the locations and pointers to entries. The widget * will need to recompute its layout. * * TV_RESORT The tree has changed such that the view needs to * be resorted. This can happen when an entry is * open or closed, it's label changes, a column value * changes, etc. * * TV_BORDERS The borders of the widget (highlight ring and * 3-D border) need to be redrawn. * * TV_VIEWPORT Indicates that the viewport has changed in some * way: the size of the viewport, the location of * the viewport, or the contents of the viewport. * */ #define TV_LAYOUT (1<<0) #define TV_REDRAW (1<<1) #define TV_XSCROLL (1<<2) #define TV_YSCROLL (1<<3) #define TV_SCROLL (TV_XSCROLL | TV_YSCROLL) #define TV_FOCUS (1<<4) #define TV_DIRTY (1<<5) #define TV_UPDATE (1<<6) #define TV_RESORT (1<<7) #define TV_SORTED (1<<8) #define TV_SORT_PENDING (1<<9) #define TV_BORDERS (1<<10) #define TV_VIEWPORT (1<<11) /* * Rule related flags: Rules are XOR-ed lines. We need to track whether * they have been drawn or not. * * TV_RULE_ACTIVE Indicates that a rule is currently being drawn * for a column. * * * TV_RULE_NEEDED Indicates that a rule is needed (but not yet * drawn) for a column. */ #define TV_RULE_ACTIVE (1<<15) #define TV_RULE_NEEDED (1<<16) /* * Selection related flags: * * TV_SELECT_EXPORT Export the selection to X11. * * TV_SELECT_PENDING A "selection" command idle task is pending. * * TV_SELECT_CLEAR Clear selection flag of entry. * * TV_SELECT_SET Set selection flag of entry. * * TV_SELECT_TOGGLE Toggle selection flag of entry. * * TV_SELECT_MASK Mask of selection set/clear/toggle flags. * * TV_SELECT_SORTED Indicates if the entries in the selection * should be sorted or displayed in the order * they were selected. * */ #define TV_SELECT_CLEAR (1<<16) #define TV_SELECT_EXPORT (1<<17) #define TV_SELECT_PENDING (1<<18) #define TV_SELECT_SET (1<<19) #define TV_SELECT_TOGGLE (TV_SELECT_SET | TV_SELECT_CLEAR) #define TV_SELECT_MASK (TV_SELECT_SET | TV_SELECT_CLEAR) #define TV_SELECT_SORTED (1<<20) /* * Miscellaneous flags: * * TV_ALLOW_DUPLICATES When inserting new entries, create * duplicate entries. * * TV_FILL_ANCESTORS Automatically create ancestor entries * as needed when inserting a new entry. * * TV_HIDE_ROOT Don't display the root entry. * * TV_HIDE_LEAVES Don't display entries that are leaves. * * TV_SHOW_COLUMN_TITLES Indicates whether to draw titles over each * column. * */ #define TV_ALLOW_DUPLICATES (1<<21) #define TV_FILL_ANCESTORS (1<<22) #define TV_HIDE_ROOT (1<<23) #define TV_HIDE_LEAVES (1<<24) #define TV_SHOW_COLUMN_TITLES (1<<25) #define TV_SORT_AUTO (1<<26) #define TV_NEW_TAGS (1<<27) #define TV_HIGHLIGHT_CELLS (1<<28) #define TV_ITEM_COLUMN 1 #define TV_ITEM_RULE 2 /* * ------------------------------------------------------------------------- * * Internal entry flags: * * ENTRY_HAS_BUTTON Indicates that a button needs to be * drawn for this entry. * * ENTRY_CLOSED Indicates that the entry is closed and * its subentries are not displayed. * * ENTRY_HIDDEN Indicates that the entry is hidden (i.e. * can not be viewed by opening or scrolling). * * BUTTON_AUTO * BUTTON_SHOW * BUTTON_MASK * * ------------------------------------------------------------------------- */ #define ENTRY_CLOSED (1<<0) #define ENTRY_HIDDEN (1<<1) #define ENTRY_NOT_LEAF (1<<2) #define ENTRY_MASK (ENTRY_CLOSED | ENTRY_HIDDEN) #define ENTRY_HAS_BUTTON (1<<3) #define ENTRY_ICON (1<<4) #define ENTRY_REDRAW (1<<5) #define ENTRY_LAYOUT_PENDING (1<<6) #define ENTRY_DATA_CHANGED (1<<7) #define ENTRY_DIRTY (ENTRY_DATA_CHANGED | ENTRY_LAYOUT_PENDING) #define BUTTON_AUTO (1<<8) #define BUTTON_SHOW (1<<9) #define BUTTON_MASK (BUTTON_AUTO | BUTTON_SHOW) #define COLUMN_RULE_PICKED (1<<1) #define COLUMN_DIRTY (1<<2) #define STYLE_TEXTBOX (0) #define STYLE_COMBOBOX (1) #define STYLE_CHECKBOX (2) #define STYLE_TYPE 0x3 #define STYLE_LAYOUT (1<<3) #define STYLE_DIRTY (1<<4) #define STYLE_HIGHLIGHT (1<<5) #define STYLE_USER (1<<6) typedef struct TreeViewColumnStruct TreeViewColumn; typedef struct TreeViewComboboxStruct TreeViewCombobox; typedef struct TreeViewEntryStruct TreeViewEntry; typedef struct TreeViewStruct TreeView; typedef struct TreeViewStyleClassStruct TreeViewStyleClass; typedef struct TreeViewStyleStruct TreeViewStyle; typedef int (TreeViewCompareProc) _ANSI_ARGS_((Tcl_Interp *interp, char *name, char *pattern)); typedef TreeViewEntry *(TreeViewIterProc) _ANSI_ARGS_((TreeViewEntry *entryPtr, unsigned int mask)); typedef struct { int tagType; TreeView *tvPtr; Blt_HashSearch cursor; TreeViewEntry *entryPtr; } TreeViewTagInfo; /* * TreeViewIcon -- * * Since instances of the same Tk image can be displayed in * different windows with possibly different color palettes, Tk * internally stores each instance in a linked list. But if * the instances are used in the same widget and therefore use * the same color palette, this adds a lot of overhead, * especially when deleting instances from the linked list. * * For the treeview widget, we never need more than a single * instance of an image, regardless of how many times it's used. * Cache the image, maintaining a reference count for each * image used in the widget. It's likely that the treeview * widget will use many instances of the same image (for example * the open/close icons). */ typedef struct TreeViewIconStruct { Tk_Image tkImage; /* The Tk image being cached. */ int refCount; /* Reference count for this image. */ short int width, height; /* Dimensions of the cached image. */ Blt_HashEntry *hashPtr; /* Hash table pointer to the image. */ } *TreeViewIcon; #define TreeViewIconHeight(icon) ((icon)->height) #define TreeViewIconWidth(icon) ((icon)->width) #define TreeViewIconBits(icon) ((icon)->tkImage) /* * TreeViewColumn -- * * A column describes how to display a field of data in the tree. * It may display a title that you can bind to. It may display a * rule for resizing the column. Columns may be hidden, and have * attributes (foreground color, background color, font, etc) * that override those designated globally for the treeview * widget. */ struct TreeViewColumnStruct { int type; /* Always TV_COLUMN */ Blt_TreeKey key; /* Data cell identifier for current tree. */ int position; /* Position of column in list. Used * to indicate the first and last * columns. */ UID tagsUid; /* List of binding tags for this * entry. UID, not a string, because * in the typical case most columns * will have the same bindtags. */ TreeView *tvPtr; unsigned int flags; /* Title-related information */ char *title; /* Text displayed in column heading as its * title. By default, this is the same as * the data cell name. */ Tk_Font titleFont; /* Font to draw title in. */ Shadow titleShadow; XColor *titleFgColor; /* Foreground color of text displayed in * the heading */ Tk_3DBorder titleBorder; /* Background color of the column's heading. */ GC titleGC; XColor *activeTitleFgColor; /* Foreground color of text heading when * the column is activated.*/ Tk_3DBorder activeTitleBorder; int titleBorderWidth; int titleRelief; GC activeTitleGC; TextLayout *titleTextPtr; short int titleWidth, titleHeight; TreeViewIcon titleIcon; /* Icon displayed in column heading */ char *titleCmd; /* Tcl script to be executed by the * column's "invoke" operation. */ char *sortCmd; /* Tcl script used to compare two * columns. */ /* General information. */ int hidden; /* Indicates if the column is * displayed */ int state; /* Indicates if column title can * invoked. */ int editable; /* Indicates if column can be * edited. */ int max; /* Maximum space allowed for column. */ int reqMin, reqMax; /* Requested bounds on the width of * column. Does not include any * padding or the borderwidth of * column. If non-zero, overrides the * computed width of the column. */ int reqWidth; /* User-requested width of * column. Does not include any * padding or the borderwidth of * column. If non-zero, overrides the * computed column width. */ int maxWidth; /* Width of the widest entry in the * column. */ int worldX; /* Starting world x-coordinate of the * column. */ double weight; /* Growth factor for column. Zero * indicates that the column can not * be resized. */ int width; /* Computed width of column. */ TreeViewStyle *stylePtr; /* Default style for column. */ Tk_3DBorder border; /* Background color of column. */ int borderWidth; /* Border width of the column. */ int relief; /* Relief of the column. */ Blt_Pad pad; /* Horizontal padding on either side * of the column. */ Tk_Justify justify; /* Indicates how the text or icon is * justified within the column. */ Blt_ChainLink *linkPtr; int ruleLineWidth; Blt_Dashes ruleDashes; GC ruleGC; }; struct TreeViewStyleStruct { int refCount; /* Usage reference count. A reference * count of zero indicates that the * style may be freed. */ unsigned int flags; /* Bit field containing both the style * type and various flags. */ char *name; /* Instance name. */ TreeViewStyleClass *classPtr; /* Contains class-specific information such * as configuration specifications and * configure, draw, etc. routines. */ Blt_HashEntry *hashPtr; /* If non-NULL, points to the hash * table entry for the style. A style * that's been deleted, but still in * use (non-zero reference count) will * have no hash table entry. */ /* General style fields. */ Tk_Cursor cursor; /* X Cursor */ TreeViewIcon icon; /* If non-NULL, is a Tk_Image to be drawn * in the cell. */ int gap; /* # pixels gap between icon and text. */ Tk_Font font; XColor *fgColor; /* Normal foreground color of cell. */ Tk_3DBorder border; /* Normal background color of cell. */ XColor *highlightFgColor; /* Foreground color of cell when * highlighted. */ Tk_3DBorder highlightBorder;/* Background color of cell when * highlighted. */ XColor *activeFgColor; /* Foreground color of cell when active. */ Tk_3DBorder activeBorder; /* Background color of cell when active. */ }; typedef struct TreeViewValueStruct { TreeViewColumn *columnPtr; /* Column in which the value is located. */ short int width, height; /* Dimensions of value. */ TreeViewStyle *stylePtr; /* Style information for cell * displaying value. */ char *string; /* Raw text string. */ TextLayout *textPtr; /* Processes string to be displayed .*/ struct TreeViewValueStruct *nextPtr; } TreeViewValue; typedef void (StyleConfigProc) _ANSI_ARGS_((TreeView *tvPtr, TreeViewStyle *stylePtr)); typedef void (StyleDrawProc) _ANSI_ARGS_((TreeView *tvPtr, Drawable drawable, TreeViewEntry *entryPtr, TreeViewValue *valuePtr, TreeViewStyle *stylePtr, int x, int y)); typedef int (StyleEditProc) _ANSI_ARGS_((TreeView *tvPtr, TreeViewEntry *entryPtr, TreeViewValue *valuePtr, TreeViewStyle *stylePtr)); typedef void (StyleFreeProc) _ANSI_ARGS_((TreeView *tvPtr, TreeViewStyle *stylePtr)); typedef void (StyleMeasureProc) _ANSI_ARGS_((TreeView *tvPtr, TreeViewStyle *stylePtr, TreeViewValue *valuePtr)); typedef int (StylePickProc) _ANSI_ARGS_((TreeViewEntry *entryPtr, TreeViewValue *valuePtr, TreeViewStyle *stylePtr, int worldX, int worldY)); struct TreeViewStyleClassStruct { char *className; /* Class name of the style */ Blt_ConfigSpec *specsPtr; /* Style configuration specifications */ StyleConfigProc *configProc;/* Sets the GCs for style. */ StyleMeasureProc *measProc; /* Measures the area needed for the value * with this style. */ StyleDrawProc *drawProc; /* Draw the value in it's style. */ StylePickProc *pickProc; /* Routine to pick the style's button. * Indicates if the mouse pointer is over * the style's button (if it has one). */ StyleEditProc *editProc; /* Routine to edit the style's value. */ StyleFreeProc *freeProc; /* Routine to free the style's resources. */ }; /* * TreeViewEntry -- * * Contains data-specific information how to represent the data * of a node of the hierarchy. * */ struct TreeViewEntryStruct { Blt_TreeNode node; /* Node containing entry */ int worldX, worldY; /* X-Y position in world coordinates * where the entry is positioned. */ short int width, height; /* Dimensions of the entry. This * includes the size of its * columns. */ int reqHeight; /* Requested height of the entry. * Overrides computed height. */ int vertLineLength; /* Length of the vertical line * segment. */ int lineHeight; /* Height of first line of text. */ unsigned int flags; /* Flags for this entry. For the * definitions of the various bit * fields see below. */ UID tagsUid; /* List of binding tags for this * entry. UID, not a string, because * in the typical case most entries * will have the same bindtags. */ TreeView *tvPtr; UID openCmd, closeCmd; /* Tcl commands to invoke when entries * are opened or closed. They override * those specified globally. */ /* * Button information: */ short int buttonX, buttonY; /* X-Y coordinate offsets from to * upper left corner of the entry to * the upper-left corner of the * button. Used to pick the * button quickly */ TreeViewIcon *icons; /* Tk images displayed for the entry. * The first image is the icon * displayed to the left of the * entry's label. The second is icon * displayed when entry is "open". */ TreeViewIcon *activeIcons; /* Tk images displayed for the entry. * The first image is the icon * displayed to the left of the * entry's label. The second is icon * displayed when entry is "open". */ short int iconWidth; short int iconHeight; /* Maximum dimensions for icons and * buttons for this entry. This is * used to align the button, icon, and * text. */ /* * Label information: */ TextLayout *textPtr; short int labelWidth; short int labelHeight; UID labelUid; /* Text displayed right of the icon. */ Tk_Font font; /* Font of label. Overrides global * font specification. */ char *fullName; int flatIndex; Tcl_Obj *dataObjPtr; /* pre-fetched data for sorting */ XColor *color; /* Color of label. Overrides default * text color specification. */ GC gc; Shadow shadow; TreeViewValue *values; /* List of column-related information * for each data value in the node. * Non-NULL only if there are value * entries. */ }; /* * TreeViewButton -- * * A button is the open/close indicator at the far left of the * entry. It is displayed as a plus or minus in a solid * colored box with optionally an border. It has both "active" * and "normal" colors. */ typedef struct { XColor *fgColor; /* Foreground color. */ Tk_3DBorder border; /* Background color. */ XColor *activeFgColor; /* Active foreground color. */ Tk_3DBorder activeBorder; /* Active background color. */ GC normalGC; GC activeGC; int reqSize; int borderWidth; int openRelief, closeRelief; int width, height; TreeViewIcon *icons; } TreeViewButton; /* * LevelInfo -- * */ typedef struct { int x; int iconWidth; int labelWidth; } LevelInfo; /* * TreeView -- * * A TreeView is a widget that displays an hierarchical table * of one or more entries. * * Entries are positioned in "world" coordinates, referring to * the virtual treeview. Coordinate 0,0 is the upper-left corner * of the root entry and the bottom is the end of the last entry. * The widget's Tk window acts as view port into this virtual * space. The treeview's xOffset and yOffset fields specify the * location of the view port in the virtual world. Scrolling the * viewport is therefore simply changing the xOffset and/or * yOffset fields and redrawing. * * Note that world coordinates are integers, not signed short * integers like X11 screen coordinates. It's very easy to * create a hierarchy taller than 0x7FFF pixels. */ struct TreeViewStruct { Tcl_Interp *interp; Tcl_Command cmdToken; /* Token for widget's Tcl command. */ Blt_Tree tree; /* Token holding internal tree. */ Blt_HashEntry *hashPtr; /* TreeView specific fields. */ Tk_Window tkwin; /* Window that embodies the widget. * NULL means that the window has been * destroyed but the data structures * haven't yet been cleaned up.*/ Display *display; /* Display containing widget; needed, * among other things, to release * resources after tkwin has already * gone away. */ Blt_HashTable entryTable; /* Table of entry information, keyed by * the node pointer. */ Blt_HashTable columnTable; /* Table of column information. */ Blt_Chain *colChainPtr; /* Chain of columns. Same as the hash * table above but maintains the order * in which columns are displayed. */ unsigned int flags; /* For bitfield definitions, see below */ int inset; /* Total width of all borders, * including traversal highlight and * 3-D border. Indicates how much * interior stuff must be offset from * outside edges to leave room for * borders. */ Tk_Font font; XColor *fgColor; Tk_3DBorder border; /* 3D border surrounding the window * (viewport). */ int borderWidth; /* Width of 3D border. */ int relief; /* 3D border relief. */ int highlightWidth; /* Width in pixels of highlight to * draw around widget when it has the * focus. <= 0 means don't draw a * highlight. */ XColor *highlightBgColor; /* Color for drawing traversal * highlight area when highlight is * off. */ XColor *highlightColor; /* Color for drawing traversal highlight. */ char *pathSep; /* Pathname separators */ char *trimLeft; /* Leading characters to trim from * pathnames */ /* * Entries are connected by horizontal and vertical lines. They * may be drawn dashed or solid. */ int lineWidth; /* Width of lines connecting entries */ int dashes; /* Dash on-off value. */ XColor *lineColor; /* Color of connecting lines. */ /* * Button Information: * * The button is the open/close indicator at the far left of the * entry. It is usually displayed as a plus or minus in a solid * colored box with optionally an border. It has both "active" and * "normal" colors. */ TreeViewButton button; /* * Selection Information: * * The selection is the rectangle that contains a selected entry. * There may be many selected entries. It is displayed as a solid * colored box with optionally a 3D border. */ int selRelief; /* Relief of selected items. Currently * is always raised. */ int selBorderWidth; /* Border width of a selected entry.*/ XColor *selInFocusFgColor; /* Text color of a selected entry. */ XColor *selOutFocusFgColor; Tk_3DBorder selInFocusBorder; Tk_3DBorder selOutFocusBorder; TreeViewEntry *selAnchorPtr; /* Fixed end of selection (i.e. entry * at which selection was started.) */ TreeViewEntry *selMarkPtr; int selectMode; /* Selection style: "single" or * "multiple". */ char *selectCmd; /* Tcl script that's invoked whenever * the selection changes. */ Blt_HashTable selectTable; /* Hash table of currently selected * entries. */ Blt_Chain *selChainPtr; /* Chain of currently selected * entries. Contains the same * information as the above hash * table, but maintains the order in * which entries are selected. */ int leader; /* Number of pixels padding between * entries. */ Tk_Cursor cursor; /* X Cursor */ Tk_Cursor resizeCursor; /* Resize Cursor */ int reqWidth, reqHeight; /* Requested dimensions of the * treeview widget's window. */ GC lineGC; /* GC for drawing dotted line between * entries. */ XColor *focusColor; Blt_Dashes focusDashes; /* Dash on-off value. */ GC focusGC; /* Graphics context for the active * label. */ Tk_Window comboWin; TreeViewEntry *activePtr; /* Last active entry. */ TreeViewEntry *focusPtr; /* Entry that currently has focus. */ TreeViewEntry *activeButtonPtr; /* Pointer to last active button */ TreeViewEntry *fromPtr; TreeViewValue *activeValuePtr;/* Last active value. */ int xScrollUnits, yScrollUnits; /* # of pixels per scroll unit. */ /* Command strings to control horizontal and vertical * scrollbars. */ char *xScrollCmdPrefix, *yScrollCmdPrefix; int scrollMode; /* Selects mode of scrolling: either * BLT_SCROLL_MODE_HIERBOX, * BLT_SCROLL_MODE_LISTBOX, * or BLT_SCROLL_MODE_CANVAS. */ /* * Total size of all "open" entries. This represents the range of * world coordinates. */ int worldWidth, worldHeight; int xOffset, yOffset; /* Translation between view port and * world origin. */ short int minHeight; /* Minimum entry height. Used to to * compute what the y-scroll unit * should be. */ short int titleHeight; /* Height of column titles. */ LevelInfo *levelInfo; /* * Scanning information: */ int scanAnchorX, scanAnchorY; /* Scan anchor in screen coordinates. */ int scanX, scanY; /* X-Y world coordinate where the scan * started. */ Blt_HashTable iconTable; /* Table of Tk images */ Blt_HashTable uidTable; /* Table of strings. */ Blt_HashTable styleTable; /* Table of cell styles. */ TreeViewEntry *rootPtr; /* Root entry of tree. */ TreeViewEntry **visibleArr; /* Array of visible entries */ int nVisible; /* Number of entries in the above array */ int nEntries; /* Number of entries in tree. */ int treeWidth; /* Computed width of the tree. */ int buttonFlags; /* Global button indicator for all * entries. This may be overridden by * the entry's -button option. */ char *openCmd, *closeCmd; /* Tcl commands to invoke when entries * are opened or closed. */ TreeViewIcon *icons; /* Tk images displayed for the entry. * The first image is the icon * displayed to the left of the * entry's label. The second is icon * displayed when entry is "open". */ TreeViewIcon *activeIcons; /* Tk images displayed for the entry. * The first image is the icon * displayed to the left of the * entry's label. The second is icon * displayed when entry is "open". */ char *takeFocus; ClientData clientData; Blt_BindTable bindTable; /* Binding information for entries. */ Blt_HashTable entryTagTable; Blt_HashTable buttonTagTable; Blt_HashTable columnTagTable; Blt_HashTable styleTagTable; TreeViewStyle *stylePtr; /* Default style for text cells */ TreeViewColumn treeColumn; TreeViewColumn *activeColumnPtr; TreeViewColumn *activeTitleColumnPtr; /* Column title currently active. */ TreeViewColumn *resizeColumnPtr; /* Column that is being resized. */ int depth; int flatView; /* Indicates if the view of the tree * has been flattened. */ TreeViewEntry **flatArr; /* Flattened array of entries. */ char *sortField; /* Field to be sorted. */ int sortType; /* Type of sorting to be performed. See * below for valid values. */ char *sortCmd; /* Sort command. */ int sortDecreasing; /* Indicates entries should be sorted * in decreasing order. */ int viewIsDecreasing; /* Current sorting direction */ TreeViewColumn *sortColumnPtr;/* Column to use for sorting criteria. */ #ifdef notdef Pixmap drawable; /* Pixmap used to cache the entries * displayed. The pixmap is saved so * that only selected elements can be * drawn quicky. */ short int drawWidth, drawHeight; #endif short int ruleAnchor, ruleMark; Blt_Pool entryPool; Blt_Pool valuePool; }; extern UID Blt_TreeViewGetUid _ANSI_ARGS_((TreeView *tvPtr, CONST char *string)); extern void Blt_TreeViewFreeUid _ANSI_ARGS_((TreeView *tvPtr, UID uid)); extern void Blt_TreeViewEventuallyRedraw _ANSI_ARGS_((TreeView *tvPtr)); extern Tcl_ObjCmdProc Blt_TreeViewWidgetInstCmd; extern TreeViewEntry *Blt_TreeViewNearestEntry _ANSI_ARGS_((TreeView *tvPtr, int x, int y, int flags)); extern char *Blt_TreeViewGetFullName _ANSI_ARGS_((TreeView *tvPtr, TreeViewEntry *entryPtr, int checkEntryLabel, Tcl_DString *dsPtr)); extern void Blt_TreeViewSelectCmdProc _ANSI_ARGS_((ClientData clientData)); extern void Blt_TreeViewInsertText _ANSI_ARGS_((TreeView *tvPtr, TreeViewEntry *entryPtr, char *string, int extra, int insertPos)); extern void Blt_TreeViewComputeLayout _ANSI_ARGS_((TreeView *tvPtr)); extern void Blt_TreeViewPercentSubst _ANSI_ARGS_((TreeView *tvPtr, TreeViewEntry *entryPtr, char *command, Tcl_DString *resultPtr)); extern void Blt_TreeViewDrawButton _ANSI_ARGS_((TreeView *tvPtr, TreeViewEntry *entryPtr, Drawable drawable, int x, int y)); extern void Blt_TreeViewDrawValue _ANSI_ARGS_((TreeView *tvPtr, TreeViewEntry *entryPtr, TreeViewValue *valuePtr, Drawable drawable, int x, int y)); extern void Blt_TreeViewDrawOuterBorders _ANSI_ARGS_((TreeView *tvPtr, Drawable drawable)); extern int Blt_TreeViewDrawIcon _ANSI_ARGS_((TreeView *tvPtr, TreeViewEntry *entryPtr, Drawable drawable, int x, int y)); extern void Blt_TreeViewDrawHeadings _ANSI_ARGS_((TreeView *tvPtr, Drawable drawable)); extern void Blt_TreeViewDrawRule _ANSI_ARGS_((TreeView *tvPtr, TreeViewColumn *columnPtr, Drawable drawable)); extern void Blt_TreeViewConfigureButtons _ANSI_ARGS_((TreeView *tvPtr)); extern int Blt_TreeViewUpdateWidget _ANSI_ARGS_((Tcl_Interp *interp, TreeView *tvPtr)); extern int Blt_TreeViewScreenToIndex _ANSI_ARGS_((TreeView *tvPtr, int x, int y)); extern void Blt_TreeViewFreeIcon _ANSI_ARGS_((TreeView *tvPtr, TreeViewIcon icon)); extern TreeViewIcon Blt_TreeViewGetIcon _ANSI_ARGS_((TreeView *tvPtr, CONST char *iconName)); extern void Blt_TreeViewAddValue _ANSI_ARGS_((TreeViewEntry *entryPtr, TreeViewColumn *columnPtr)); extern int Blt_TreeViewCreateColumn _ANSI_ARGS_((TreeView *tvPtr, TreeViewColumn *columnPtr, char *name, char *defaultLabel)); extern void Blt_TreeViewDestroyValue _ANSI_ARGS_((TreeView *tvPtr, TreeViewValue *valuePtr)); extern TreeViewValue *Blt_TreeViewFindValue _ANSI_ARGS_(( TreeViewEntry *entryPtr, TreeViewColumn *columnPtr)); extern void Blt_TreeViewDestroyColumns _ANSI_ARGS_((TreeView *tvPtr)); extern void Blt_TreeViewAllocateColumnUids _ANSI_ARGS_((TreeView *tvPtr)); extern void Blt_TreeViewFreeColumnUids _ANSI_ARGS_((TreeView *tvPtr)); extern void Blt_TreeViewUpdateColumnGCs _ANSI_ARGS_((TreeView *tvPtr, TreeViewColumn *columnPtr)); extern TreeViewColumn *Blt_TreeViewNearestColumn _ANSI_ARGS_((TreeView *tvPtr, int x, int y, ClientData *contextPtr)); extern void Blt_TreeViewDrawRule _ANSI_ARGS_((TreeView *tvPtr, TreeViewColumn *columnPtr, Drawable drawable)); extern int Blt_TreeViewTextOp _ANSI_ARGS_((TreeView *tvPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv)); extern int Blt_TreeViewCombobox _ANSI_ARGS_((TreeView *tvPtr, TreeViewEntry *entryPtr, TreeViewColumn *columnPtr)); extern int Blt_TreeViewCreateEntry _ANSI_ARGS_((TreeView *tvPtr, Blt_TreeNode node, int objc, Tcl_Obj *CONST *objv, int flags)); extern int Blt_TreeViewConfigureEntry _ANSI_ARGS_((TreeView *tvPtr, TreeViewEntry *entryPtr, int objc, Tcl_Obj *CONST *objv, int flags)); extern int Blt_TreeViewOpenEntry _ANSI_ARGS_((TreeView *tvPtr, TreeViewEntry *entryPtr)); extern int Blt_TreeViewCloseEntry _ANSI_ARGS_((TreeView *tvPtr, TreeViewEntry *entryPtr)); extern TreeViewEntry *Blt_TreeViewNextEntry _ANSI_ARGS_(( TreeViewEntry *entryPtr, unsigned int mask)); extern TreeViewEntry *Blt_TreeViewPrevEntry _ANSI_ARGS_(( TreeViewEntry *entryPtr, unsigned int mask)); extern int Blt_TreeViewGetEntry _ANSI_ARGS_((TreeView *tvPtr, Tcl_Obj *objPtr, TreeViewEntry **entryPtrPtr)); extern int Blt_TreeViewEntryIsHidden _ANSI_ARGS_((TreeViewEntry *entryPtr)); extern TreeViewEntry *Blt_TreeViewNextSibling _ANSI_ARGS_(( TreeViewEntry *entryPtr, unsigned int mask)); extern TreeViewEntry *Blt_TreeViewPrevSibling _ANSI_ARGS_(( TreeViewEntry *entryPtr, unsigned int mask)); extern TreeViewEntry *Blt_TreeViewFirstChild _ANSI_ARGS_(( TreeViewEntry *parentPtr, unsigned int mask)); extern TreeViewEntry *Blt_TreeViewLastChild _ANSI_ARGS_(( TreeViewEntry *entryPtr, unsigned int mask)); extern TreeViewEntry *Blt_TreeViewParentEntry _ANSI_ARGS_(( TreeViewEntry *entryPtr)); typedef int (TreeViewApplyProc) _ANSI_ARGS_((TreeView *tvPtr, TreeViewEntry *entryPtr)); extern int Blt_TreeViewApply _ANSI_ARGS_((TreeView *tvPtr, TreeViewEntry *entryPtr, TreeViewApplyProc *proc, unsigned int mask)); extern int Blt_TreeViewColumnOp _ANSI_ARGS_((TreeView *tvPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv)); extern int Blt_TreeViewSortOp _ANSI_ARGS_((TreeView *tvPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv)); extern int Blt_TreeViewGetColumn _ANSI_ARGS_((Tcl_Interp *interp, TreeView *tvPtr, Tcl_Obj *objPtr, TreeViewColumn **columnPtrPtr)); extern void Blt_TreeViewSortFlatView _ANSI_ARGS_((TreeView *tvPtr)); extern void Blt_TreeViewSortTreeView _ANSI_ARGS_((TreeView *tvPtr)); extern int Blt_TreeViewEntryIsSelected _ANSI_ARGS_((TreeView *tvPtr, TreeViewEntry *entryPtr)); extern void Blt_TreeViewSelectEntry _ANSI_ARGS_((TreeView *tvPtr, TreeViewEntry *entryPtr)); extern void Blt_TreeViewDeselectEntry _ANSI_ARGS_((TreeView *tvPtr, TreeViewEntry *entryPtr)); extern void Blt_TreeViewPruneSelection _ANSI_ARGS_((TreeView *tvPtr, TreeViewEntry *entryPtr)); extern void Blt_TreeViewClearSelection _ANSI_ARGS_((TreeView *tvPtr)); extern void Blt_TreeViewClearTags _ANSI_ARGS_((TreeView *tvPtr, TreeViewEntry *entryPtr)); extern int Blt_TreeViewFindTaggedEntries _ANSI_ARGS_((TreeView *tvPtr, Tcl_Obj *objPtr, TreeViewTagInfo *infoPtr)); extern TreeViewEntry *Blt_TreeViewFirstTaggedEntry _ANSI_ARGS_(( TreeViewTagInfo *infoPtr)); extern TreeViewEntry *Blt_TreeViewNextTaggedEntry _ANSI_ARGS_(( TreeViewTagInfo *infoPtr)); extern ClientData Blt_TreeViewButtonTag _ANSI_ARGS_((TreeView *tvPtr, CONST char *string)); extern ClientData Blt_TreeViewEntryTag _ANSI_ARGS_((TreeView *tvPtr, CONST char *string)); extern ClientData Blt_TreeViewColumnTag _ANSI_ARGS_((TreeView *tvPtr, CONST char *string)); extern void Blt_TreeViewGetTags _ANSI_ARGS_((Tcl_Interp *interp, TreeView *tvPtr, TreeViewEntry *entryPtr, Blt_List list)); extern void Blt_TreeViewTraceColumn _ANSI_ARGS_((TreeView *tvPtr, TreeViewColumn *columnPtr)); extern TreeViewIcon Blt_TreeViewGetEntryIcon _ANSI_ARGS_((TreeView *tvPtr, TreeViewEntry *entryPtr)); extern void Blt_TreeViewSetStyleIcon _ANSI_ARGS_((TreeView *tvPtr, TreeViewStyle *stylePtr, TreeViewIcon icon)); extern int Blt_TreeViewGetStyle _ANSI_ARGS_((Tcl_Interp *interp, TreeView *tvPtr, char *styleName, TreeViewStyle **stylePtrPtr)); extern void Blt_TreeViewFreeStyle _ANSI_ARGS_((TreeView *tvPtr, TreeViewStyle *stylePtr)); extern TreeViewStyle *Blt_TreeViewCreateStyle _ANSI_ARGS_((Tcl_Interp *interp, TreeView *tvPtr, int type, char *styleName)); extern void Blt_TreeViewUpdateStyleGCs _ANSI_ARGS_((TreeView *tvPtr, TreeViewStyle *stylePtr)); extern Tk_3DBorder Blt_TreeViewGetStyleBorder _ANSI_ARGS_((TreeView *tvPtr, TreeViewStyle *stylePtr)); extern GC Blt_TreeViewGetStyleGC _ANSI_ARGS_((TreeViewStyle *stylePtr)); extern Tk_Font Blt_TreeViewGetStyleFont _ANSI_ARGS_((TreeView *tvPtr, TreeViewStyle *stylePtr)); extern XColor *Blt_TreeViewGetStyleFg _ANSI_ARGS_((TreeView *tvPtr, TreeViewStyle *stylePtr)); extern TreeViewEntry *Blt_NodeToEntry _ANSI_ARGS_((TreeView *tvPtr, Blt_TreeNode node)); extern int Blt_TreeViewStyleOp _ANSI_ARGS_((TreeView *tvPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv)); #define CHOOSE(default, override) \ (((override) == NULL) ? (default) : (override)) #define GETLABEL(e) \ (((e)->labelUid != NULL) ? (e)->labelUid : Blt_TreeNodeLabel((e)->node)) #define Blt_TreeViewGetData(entryPtr, key, objPtrPtr) \ Blt_TreeGetValueByKey((Tcl_Interp *)NULL, (entryPtr)->tvPtr->tree, \ (entryPtr)->node, key, objPtrPtr) #endif /* BLT_TREEVIEW_H */ blt-2.4z.orig/src/bltTreeViewCmd.c0100644000175000017500000040475507542177233015610 0ustar dokodoko /* * bltTreeViewCmd.c -- * * This module implements an hierarchy widget for the BLT toolkit. * * Copyright 1998-1999 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 or 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. * * The "treeview" widget was created by George A. Howlett. */ /* * TODO: * * BUGS: * 1. "open" operation should change scroll offset so that as many * new entries (up to half a screen) can be seen. * 2. "open" needs to adjust the scrolloffset so that the same entry * is seen at the same place. */ #include "bltInt.h" #ifndef NO_TREEVIEW #include "bltTreeView.h" #include "bltList.h" #include #include #define CLAMP(val,low,hi) \ (((val) < (low)) ? (low) : ((val) > (hi)) ? (hi) : (val)) static TreeViewCompareProc ExactCompare, GlobCompare, RegexpCompare; static TreeViewApplyProc ShowEntryApplyProc, HideEntryApplyProc, MapAncestorsApplyProc, FixSelectionsApplyProc; static Tk_LostSelProc LostSelection; static TreeViewApplyProc SelectEntryApplyProc; extern Blt_CustomOption bltTreeViewIconsOption; extern Blt_CustomOption bltTreeViewUidOption; extern Blt_CustomOption bltTreeViewTreeOption; extern Blt_ConfigSpec bltTreeViewButtonSpecs[]; extern Blt_ConfigSpec bltTreeViewSpecs[]; extern Blt_ConfigSpec bltTreeViewEntrySpecs[]; #define TAG_UNKNOWN (1<<0) #define TAG_RESERVED (1<<1) #define TAG_USER_DEFINED (1<<2) #define TAG_SINGLE (1<<3) #define TAG_MULTIPLE (1<<4) #define TAG_ALL (1<<5) /* *---------------------------------------------------------------------- * * SkipSeparators -- * * Moves the character pointer past one of more separators. * * Results: * Returns the updates character pointer. * *---------------------------------------------------------------------- */ static char * SkipSeparators(path, separator, length) char *path, *separator; int length; { while ((path[0] == separator[0]) && (strncmp(path, separator, length) == 0)) { path += length; } return path; } /* *---------------------------------------------------------------------- * * DeleteNode -- * * Delete the node and its descendants. Don't remove the root * node, though. If the root node is specified, simply remove * all its children. * *---------------------------------------------------------------------- */ static void DeleteNode(tvPtr, node) TreeView *tvPtr; Blt_TreeNode node; { Blt_TreeNode root; if (!Blt_TreeTagTableIsShared(tvPtr->tree)) { Blt_TreeClearTags(tvPtr->tree, node); } root = Blt_TreeRootNode(tvPtr->tree); if (node == root) { Blt_TreeNode next; /* Don't delete the root node. Simply clean out the tree. */ for (node = Blt_TreeFirstChild(node); node != NULL; node = next) { next = Blt_TreeNextSibling(node); Blt_TreeDeleteNode(tvPtr->tree, node); } } else if (Blt_TreeIsAncestor(root, node)) { Blt_TreeDeleteNode(tvPtr->tree, node); } } /* *---------------------------------------------------------------------- * * SplitPath -- * * Returns the trailing component of the given path. Trailing * separators are ignored. * * Results: * Returns the string of the tail component. * *---------------------------------------------------------------------- */ static int SplitPath(tvPtr, path, depthPtr, compPtrPtr) TreeView *tvPtr; char *path; int *depthPtr; char ***compPtrPtr; { int skipLen, pathLen; int depth, listSize; char **components; register char *p; char *sep; if (tvPtr->pathSep == SEPARATOR_LIST) { if (Tcl_SplitList(tvPtr->interp, path, depthPtr, compPtrPtr) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } pathLen = strlen(path); skipLen = strlen(tvPtr->pathSep); path = SkipSeparators(path, tvPtr->pathSep, skipLen); depth = pathLen / skipLen; listSize = (depth + 1) * sizeof(char *); components = Blt_Malloc(listSize + (pathLen + 1)); assert(components); p = (char *)components + listSize; strcpy(p, path); sep = strstr(p, tvPtr->pathSep); depth = 0; while ((*p != '\0') && (sep != NULL)) { *sep = '\0'; components[depth++] = p; p = SkipSeparators(sep + skipLen, tvPtr->pathSep, skipLen); sep = strstr(p, tvPtr->pathSep); } if (*p != '\0') { components[depth++] = p; } components[depth] = NULL; *depthPtr = depth; *compPtrPtr = components; return TCL_OK; } static TreeViewEntry * LastEntry(tvPtr, entryPtr, mask) TreeView *tvPtr; TreeViewEntry *entryPtr; unsigned int mask; { Blt_TreeNode next; TreeViewEntry *nextPtr; next = Blt_TreeLastChild(entryPtr->node); while (next != NULL) { nextPtr = Blt_NodeToEntry(tvPtr, next); if ((nextPtr->flags & mask) != mask) { break; } entryPtr = nextPtr; next = Blt_TreeLastChild(next); } return entryPtr; } /* *---------------------------------------------------------------------- * * ShowEntryApplyProc -- * * Results: * Always returns TCL_OK. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ShowEntryApplyProc(tvPtr, entryPtr) TreeView *tvPtr; /* Not used. */ TreeViewEntry *entryPtr; { entryPtr->flags &= ~ENTRY_HIDDEN; return TCL_OK; } /* *---------------------------------------------------------------------- * * HideEntryApplyProc -- * * Results: * Always returns TCL_OK. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int HideEntryApplyProc(tvPtr, entryPtr) TreeView *tvPtr; /* Not used. */ TreeViewEntry *entryPtr; { entryPtr->flags |= ENTRY_HIDDEN; return TCL_OK; } static void MapAncestors(tvPtr, entryPtr) TreeView *tvPtr; TreeViewEntry *entryPtr; { while (entryPtr != tvPtr->rootPtr) { entryPtr = Blt_TreeViewParentEntry(entryPtr); if (entryPtr->flags & (ENTRY_CLOSED | ENTRY_HIDDEN)) { tvPtr->flags |= TV_LAYOUT; entryPtr->flags &= ~(ENTRY_CLOSED | ENTRY_HIDDEN); } } } /* *---------------------------------------------------------------------- * * MapAncestorsApplyProc -- * * If a node in mapped, then all its ancestors must be mapped also. * This routine traverses upwards and maps each unmapped ancestor. * It's assumed that for any mapped ancestor, all it's ancestors * will already be mapped too. * * Results: * Always returns TCL_OK. * *---------------------------------------------------------------------- */ static int MapAncestorsApplyProc(tvPtr, entryPtr) TreeView *tvPtr; TreeViewEntry *entryPtr; { /* * Make sure that all the ancestors of this entry are mapped too. */ while (entryPtr != tvPtr->rootPtr) { entryPtr = Blt_TreeViewParentEntry(entryPtr); if ((entryPtr->flags & (ENTRY_HIDDEN | ENTRY_CLOSED)) == 0) { break; /* Assume ancestors are also mapped. */ } entryPtr->flags &= ~(ENTRY_HIDDEN | ENTRY_CLOSED); } return TCL_OK; } /* *---------------------------------------------------------------------- * * FindPath -- * * Finds the node designated by the given path. Each path * component is searched for as the tree is traversed. * * A leading character string is trimmed off the path if it * matches the one designated (see the -trimleft option). * * If no separator is designated (see the -separator * configuration option), the path is considered a Tcl list. * Otherwise the each component of the path is separated by a * character string. Leading and trailing separators are * ignored. Multiple separators are treated as one. * * Results: * Returns the pointer to the designated node. If any component * can't be found, NULL is returned. * *---------------------------------------------------------------------- */ static TreeViewEntry * FindPath(tvPtr, rootPtr, path) TreeView *tvPtr; TreeViewEntry *rootPtr; char *path; { Blt_TreeNode child; char **compArr; char *name; int nComp; register char **p; TreeViewEntry *entryPtr; /* Trim off characters that we don't want */ if (tvPtr->trimLeft != NULL) { register char *s1, *s2; /* Trim off leading character string if one exists. */ for (s1 = path, s2 = tvPtr->trimLeft; *s2 != '\0'; s2++, s1++) { if (*s1 != *s2) { break; } } if (*s2 == '\0') { path = s1; } } if (*path == '\0') { return rootPtr; } name = path; entryPtr = rootPtr; if (tvPtr->pathSep == SEPARATOR_NONE) { child = Blt_TreeFindChild(entryPtr->node, name); if (child == NULL) { goto error; } return Blt_NodeToEntry(tvPtr, child); } if (SplitPath(tvPtr, path, &nComp, &compArr) != TCL_OK) { return NULL; } for (p = compArr; *p != NULL; p++) { name = *p; child = Blt_TreeFindChild(entryPtr->node, name); if (child == NULL) { Blt_Free(compArr); goto error; } entryPtr = Blt_NodeToEntry(tvPtr, child); } Blt_Free(compArr); return entryPtr; error: { Tcl_DString dString; Blt_TreeViewGetFullName(tvPtr, entryPtr, FALSE, &dString); Tcl_AppendResult(tvPtr->interp, "can't find node \"", name, "\" in parent node \"", Tcl_DStringValue(&dString), "\"", (char *)NULL); Tcl_DStringFree(&dString); } return NULL; } /* *---------------------------------------------------------------------- * * NodeToObj -- * * Converts a node pointer to a string representation. * The string contains the node's index which is unique. * * Results: * The string representation of the node is returned. Note that * the string is stored statically, so that callers must save the * string before the next call to this routine overwrites the * static array again. * *---------------------------------------------------------------------- */ static Tcl_Obj * NodeToObj(node) Blt_TreeNode node; { char string[200]; sprintf(string, "%d", Blt_TreeNodeId(node)); return Tcl_NewStringObj(string, -1); } static int GetEntryFromSpecialId(tvPtr, string, entryPtrPtr) TreeView *tvPtr; char *string; TreeViewEntry **entryPtrPtr; { Blt_TreeNode node; TreeViewEntry *fromPtr, *entryPtr; char c; entryPtr = NULL; fromPtr = tvPtr->fromPtr; if (fromPtr == NULL) { fromPtr = tvPtr->focusPtr; } if (fromPtr == NULL) { fromPtr = tvPtr->rootPtr; } c = string[0]; if (c == '@') { int x, y; if (Blt_GetXY(tvPtr->interp, tvPtr->tkwin, string, &x, &y) == TCL_OK) { *entryPtrPtr = Blt_TreeViewNearestEntry(tvPtr, x, y, TRUE); } } else if ((c == 'b') && (strcmp(string, "bottom") == 0)) { if (tvPtr->flatView) { entryPtr = tvPtr->flatArr[tvPtr->nEntries - 1]; } else { entryPtr = LastEntry(tvPtr, tvPtr->rootPtr, ENTRY_MASK); } } else if ((c == 't') && (strcmp(string, "top") == 0)) { if (tvPtr->flatView) { entryPtr = tvPtr->flatArr[0]; } else { entryPtr = tvPtr->rootPtr; if (tvPtr->flags & TV_HIDE_ROOT) { entryPtr = Blt_TreeViewNextEntry(entryPtr, ENTRY_MASK); } } } else if ((c == 'e') && (strcmp(string, "end") == 0)) { entryPtr = LastEntry(tvPtr, tvPtr->rootPtr, ENTRY_MASK); } else if ((c == 'a') && (strcmp(string, "anchor") == 0)) { entryPtr = tvPtr->selAnchorPtr; } else if ((c == 'f') && (strcmp(string, "focus") == 0)) { entryPtr = tvPtr->focusPtr; if ((entryPtr == tvPtr->rootPtr) && (tvPtr->flags & TV_HIDE_ROOT)) { entryPtr = Blt_TreeViewNextEntry(tvPtr->rootPtr, ENTRY_MASK); } } else if ((c == 'r') && (strcmp(string, "root") == 0)) { entryPtr = tvPtr->rootPtr; } else if ((c == 'p') && (strcmp(string, "parent") == 0)) { if (fromPtr != tvPtr->rootPtr) { entryPtr = Blt_TreeViewParentEntry(fromPtr); } } else if ((c == 'c') && (strcmp(string, "current") == 0)) { /* Can't trust picked item, if entries have been * added or deleted. */ if (!(tvPtr->flags & TV_DIRTY)) { ClientData context; context = Blt_GetCurrentContext(tvPtr->bindTable); if ((context == ITEM_ENTRY) || (context == ITEM_ENTRY_BUTTON) || (context >= ITEM_STYLE)) { entryPtr = Blt_GetCurrentItem(tvPtr->bindTable); } } } else if ((c == 'u') && (strcmp(string, "up") == 0)) { entryPtr = fromPtr; if (tvPtr->flatView) { int i; i = entryPtr->flatIndex - 1; if (i >= 0) { entryPtr = tvPtr->flatArr[i]; } } else { entryPtr = Blt_TreeViewPrevEntry(fromPtr, ENTRY_MASK); if (entryPtr == NULL) { entryPtr = fromPtr; } if ((entryPtr == tvPtr->rootPtr) && (tvPtr->flags & TV_HIDE_ROOT)) { entryPtr = Blt_TreeViewNextEntry(entryPtr, ENTRY_MASK); } } } else if ((c == 'd') && (strcmp(string, "down") == 0)) { entryPtr = fromPtr; if (tvPtr->flatView) { int i; i = entryPtr->flatIndex + 1; if (i < tvPtr->nEntries) { entryPtr = tvPtr->flatArr[i]; } } else { entryPtr = Blt_TreeViewNextEntry(fromPtr, ENTRY_MASK); if (entryPtr == NULL) { entryPtr = fromPtr; } if ((entryPtr == tvPtr->rootPtr) && (tvPtr->flags & TV_HIDE_ROOT)) { entryPtr = Blt_TreeViewNextEntry(entryPtr, ENTRY_MASK); } } } else if (((c == 'l') && (strcmp(string, "last") == 0)) || ((c == 'p') && (strcmp(string, "prev") == 0))) { entryPtr = fromPtr; if (tvPtr->flatView) { int i; i = entryPtr->flatIndex - 1; if (i < 0) { i = tvPtr->nEntries - 1; } entryPtr = tvPtr->flatArr[i]; } else { entryPtr = Blt_TreeViewPrevEntry(fromPtr, ENTRY_MASK); if (entryPtr == NULL) { entryPtr = LastEntry(tvPtr, tvPtr->rootPtr, ENTRY_MASK); } if ((entryPtr == tvPtr->rootPtr) && (tvPtr->flags & TV_HIDE_ROOT)) { entryPtr = Blt_TreeViewNextEntry(entryPtr, ENTRY_MASK); } } } else if ((c == 'n') && (strcmp(string, "next") == 0)) { entryPtr = fromPtr; if (tvPtr->flatView) { int i; i = entryPtr->flatIndex + 1; if (i >= tvPtr->nEntries) { i = 0; } entryPtr = tvPtr->flatArr[i]; } else { entryPtr = Blt_TreeViewNextEntry(fromPtr, ENTRY_MASK); if (entryPtr == NULL) { if (tvPtr->flags & TV_HIDE_ROOT) { entryPtr = Blt_TreeViewNextEntry(tvPtr->rootPtr,ENTRY_MASK); } else { entryPtr = tvPtr->rootPtr; } } } } else if ((c == 'n') && (strcmp(string, "nextsibling") == 0)) { node = Blt_TreeNextSibling(fromPtr->node); if (node != NULL) { entryPtr = Blt_NodeToEntry(tvPtr, node); } } else if ((c == 'p') && (strcmp(string, "prevsibling") == 0)) { node = Blt_TreePrevSibling(fromPtr->node); if (node != NULL) { entryPtr = Blt_NodeToEntry(tvPtr, node); } } else if ((c == 'v') && (strcmp(string, "view.top") == 0)) { if (tvPtr->nVisible > 0) { entryPtr = tvPtr->visibleArr[0]; } } else if ((c == 'v') && (strcmp(string, "view.bottom") == 0)) { if (tvPtr->nVisible > 0) { entryPtr = tvPtr->visibleArr[tvPtr->nVisible - 1]; } } else { return TCL_ERROR; } *entryPtrPtr = entryPtr; return TCL_OK; } static int GetTagInfo(tvPtr, tagName, infoPtr) TreeView *tvPtr; char *tagName; TreeViewTagInfo *infoPtr; { infoPtr->tagType = TAG_RESERVED | TAG_SINGLE; infoPtr->entryPtr = NULL; if (strcmp(tagName, "all") == 0) { infoPtr->entryPtr = tvPtr->rootPtr; infoPtr->tagType |= TAG_ALL; } else { Blt_HashTable *tablePtr; tablePtr = Blt_TreeTagHashTable(tvPtr->tree, tagName); if (tablePtr != NULL) { Blt_HashEntry *hPtr; infoPtr->tagType = TAG_USER_DEFINED; /* Empty tags are not * an error. */ hPtr = Blt_FirstHashEntry(tablePtr, &infoPtr->cursor); if (hPtr != NULL) { Blt_TreeNode node; node = Blt_GetHashValue(hPtr); infoPtr->entryPtr = Blt_NodeToEntry(tvPtr, node); if (tablePtr->numEntries > 1) { infoPtr->tagType |= TAG_MULTIPLE; } } } else { infoPtr->tagType = TAG_UNKNOWN; Tcl_AppendResult(tvPtr->interp, "can't find tag or id \"", tagName, "\" in \"", Tk_PathName(tvPtr->tkwin), "\"", (char *)NULL); return TCL_ERROR; } } return TCL_OK; } /*ARGSUSED*/ void Blt_TreeViewGetTags(interp, tvPtr, entryPtr, list) Tcl_Interp *interp; /* Not used. */ TreeView *tvPtr; TreeViewEntry *entryPtr; Blt_List list; { Blt_HashEntry *hPtr; Blt_HashSearch cursor; Blt_TreeTagEntry *tPtr; for (hPtr = Blt_TreeFirstTag(tvPtr->tree, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tPtr = Blt_GetHashValue(hPtr); hPtr = Blt_FindHashEntry(&tPtr->nodeTable, (char *)entryPtr->node); if (hPtr != NULL) { Blt_ListAppend(list, Blt_TreeViewGetUid(tvPtr, tPtr->tagName),0); } } } /* *---------------------------------------------------------------------- * * AddTag -- * *---------------------------------------------------------------------- */ static int AddTag(tvPtr, node, tagName) TreeView *tvPtr; Blt_TreeNode node; char *tagName; { TreeViewEntry *entryPtr; if (strcmp(tagName, "root") == 0) { Tcl_AppendResult(tvPtr->interp, "can't add reserved tag \"", tagName, "\"", (char *)NULL); return TCL_ERROR; } if (isdigit(UCHAR(tagName[0]))) { Tcl_AppendResult(tvPtr->interp, "invalid tag \"", tagName, "\": can't start with digit", (char *)NULL); return TCL_ERROR; } if (isdigit(UCHAR(tagName[0]))) { Tcl_AppendResult(tvPtr->interp, "invalid tag \"", tagName, "\": can't start with digit", (char *)NULL); return TCL_ERROR; } if (tagName[0] == '@') { Tcl_AppendResult(tvPtr->interp, "invalid tag \"", tagName, "\": can't start with \"@\"", (char *)NULL); return TCL_ERROR; } tvPtr->fromPtr = NULL; if (GetEntryFromSpecialId(tvPtr, tagName, &entryPtr) == TCL_OK) { Tcl_AppendResult(tvPtr->interp, "invalid tag \"", tagName, "\": is a special id", (char *)NULL); return TCL_ERROR; } /* Add the tag to the node. */ Blt_TreeAddTag(tvPtr->tree, node, tagName); return TCL_OK; } TreeViewEntry * Blt_TreeViewFirstTaggedEntry(infoPtr) TreeViewTagInfo *infoPtr; { return infoPtr->entryPtr; } int Blt_TreeViewFindTaggedEntries(tvPtr, objPtr, infoPtr) TreeView *tvPtr; Tcl_Obj *objPtr; TreeViewTagInfo *infoPtr; { char *tagName; TreeViewEntry *entryPtr; tagName = Tcl_GetString(objPtr); tvPtr->fromPtr = NULL; if (isdigit(UCHAR(tagName[0]))) { int inode; Blt_TreeNode node; if (Tcl_GetIntFromObj(tvPtr->interp, objPtr, &inode) != TCL_OK) { return TCL_ERROR; } node = Blt_TreeGetNode(tvPtr->tree, inode); infoPtr->entryPtr = Blt_NodeToEntry(tvPtr, node); infoPtr->tagType = (TAG_RESERVED | TAG_SINGLE); } else if (GetEntryFromSpecialId(tvPtr, tagName, &entryPtr) == TCL_OK) { infoPtr->entryPtr = entryPtr; infoPtr->tagType = (TAG_RESERVED | TAG_SINGLE); } else { if (GetTagInfo(tvPtr, tagName, infoPtr) != TCL_OK) { return TCL_ERROR; } } return TCL_OK; } TreeViewEntry * Blt_TreeViewNextTaggedEntry(infoPtr) TreeViewTagInfo *infoPtr; { TreeViewEntry *entryPtr; entryPtr = NULL; if (infoPtr->entryPtr != NULL) { TreeView *tvPtr = infoPtr->entryPtr->tvPtr; if (infoPtr->tagType & TAG_ALL) { entryPtr = Blt_TreeViewNextEntry(infoPtr->entryPtr, 0); } else if (infoPtr->tagType & TAG_MULTIPLE) { Blt_HashEntry *hPtr; hPtr = Blt_NextHashEntry(&infoPtr->cursor); if (hPtr != NULL) { Blt_TreeNode node; node = Blt_GetHashValue(hPtr); entryPtr = Blt_NodeToEntry(tvPtr, node); } } infoPtr->entryPtr = entryPtr; } return entryPtr; } /* *---------------------------------------------------------------------- * * GetEntryFromObj2 -- * * Converts a string into node pointer. The string may be in one * of the following forms: * * NNN - inode. * "active" - Currently active node. * "anchor" - anchor of selected region. * "current" - Currently picked node in bindtable. * "focus" - The node currently with focus. * "root" - Root node. * "end" - Last open node in the entire hierarchy. * "next" - Next open node from the currently active * node. Wraps around back to top. * "last" - Previous open node from the currently active * node. Wraps around back to bottom. * "up" - Next open node from the currently active * node. Does not wrap around. * "down" - Previous open node from the currently active * node. Does not wrap around. * "nextsibling" - Next sibling of the current node. * "prevsibling" - Previous sibling of the current node. * "parent" - Parent of the current node. * "view.top" - Top of viewport. * "view.bottom" - Bottom of viewport. * @x,y - Closest node to the specified X-Y position. * * Results: * If the string is successfully converted, TCL_OK is returned. * The pointer to the node is returned via nodePtr. * Otherwise, TCL_ERROR is returned and an error message is left * in interpreter's result field. * *---------------------------------------------------------------------- */ static int GetEntryFromObj2(tvPtr, objPtr, entryPtrPtr) TreeView *tvPtr; Tcl_Obj *objPtr; TreeViewEntry **entryPtrPtr; { Tcl_Interp *interp; char *string; TreeViewTagInfo info; interp = tvPtr->interp; string = Tcl_GetString(objPtr); *entryPtrPtr = NULL; if (isdigit(UCHAR(string[0]))) { Blt_TreeNode node; int inode; if (Tcl_GetIntFromObj(interp, objPtr, &inode) != TCL_OK) { return TCL_ERROR; } node = Blt_TreeGetNode(tvPtr->tree, inode); if (node != NULL) { *entryPtrPtr = Blt_NodeToEntry(tvPtr, node); } return TCL_OK; /* Node Id. */ } if (GetEntryFromSpecialId(tvPtr, string, entryPtrPtr) == TCL_OK) { return TCL_OK; /* Special Id. */ } if (GetTagInfo(tvPtr, string, &info) != TCL_OK) { return TCL_ERROR; } if (info.tagType & TAG_MULTIPLE) { Tcl_AppendResult(interp, "more than one entry tagged as \"", string, "\"", (char *)NULL); return TCL_ERROR; } *entryPtrPtr = info.entryPtr; return TCL_OK; /* Singleton tag. */ } static int GetEntryFromObj(tvPtr, objPtr, entryPtrPtr) TreeView *tvPtr; Tcl_Obj *objPtr; TreeViewEntry **entryPtrPtr; { tvPtr->fromPtr = NULL; return GetEntryFromObj2(tvPtr, objPtr, entryPtrPtr); } /* *---------------------------------------------------------------------- * * Blt_TreeViewGetEntry -- * * Returns an entry based upon its index. * * Results: * If the string is successfully converted, TCL_OK is returned. * The pointer to the node is returned via nodePtr. * Otherwise, TCL_ERROR is returned and an error message is left * in interpreter's result field. * *---------------------------------------------------------------------- */ int Blt_TreeViewGetEntry(tvPtr, objPtr, entryPtrPtr) TreeView *tvPtr; Tcl_Obj *objPtr; TreeViewEntry **entryPtrPtr; { TreeViewEntry *entryPtr; if (GetEntryFromObj(tvPtr, objPtr, &entryPtr) != TCL_OK) { return TCL_ERROR; } if (entryPtr == NULL) { Tcl_ResetResult(tvPtr->interp); Tcl_AppendResult(tvPtr->interp, "can't find entry \"", Tcl_GetString(objPtr), "\" in \"", Tk_PathName(tvPtr->tkwin), "\"", (char *)NULL); return TCL_ERROR; } *entryPtrPtr = entryPtr; return TCL_OK; } static Blt_TreeNode GetNthNode(parent, position) Blt_TreeNode parent; int position; { Blt_TreeNode node; int count; count = 0; for(node = Blt_TreeFirstChild(parent); node != NULL; node = Blt_TreeNextSibling(node)) { if (count == position) { return node; } } return Blt_TreeLastChild(parent); } static TreeViewEntry * GetNthEntry( TreeViewEntry *parentPtr, int position, unsigned int mask) { TreeViewEntry *entryPtr; int count; count = 0; for(entryPtr = Blt_TreeViewFirstChild(parentPtr, mask); entryPtr != NULL; entryPtr = Blt_TreeViewNextSibling(entryPtr, mask)) { if (count == position) { return entryPtr; } } return Blt_TreeViewLastChild(parentPtr, mask); } /* * Preprocess the command string for percent substitution. */ void Blt_TreeViewPercentSubst(tvPtr, entryPtr, command, resultPtr) TreeView *tvPtr; TreeViewEntry *entryPtr; char *command; Tcl_DString *resultPtr; { register char *last, *p; char *fullName; Tcl_DString dString; /* * Get the full path name of the node, in case we need to * substitute for it. */ fullName = Blt_TreeViewGetFullName(tvPtr, entryPtr, TRUE, &dString); Tcl_DStringInit(resultPtr); /* Append the widget name and the node .t 0 */ for (last = p = command; *p != '\0'; p++) { if (*p == '%') { char *string; char buf[3]; if (p > last) { *p = '\0'; Tcl_DStringAppend(resultPtr, last, -1); *p = '%'; } switch (*(p + 1)) { case '%': /* Percent sign */ string = "%"; break; case 'W': /* Widget name */ string = Tk_PathName(tvPtr->tkwin); break; case 'P': /* Full pathname */ string = fullName; break; case 'p': /* Name of the node */ string = GETLABEL(entryPtr); break; case '#': /* Node identifier */ string = Blt_Itoa(Blt_TreeNodeId(entryPtr->node)); break; default: if (*(p + 1) == '\0') { p--; } buf[0] = *p, buf[1] = *(p + 1), buf[2] = '\0'; string = buf; break; } Tcl_DStringAppend(resultPtr, string, -1); p++; last = p + 1; } } if (p > last) { *p = '\0'; Tcl_DStringAppend(resultPtr, last, -1); } Tcl_DStringFree(&dString); } /* *---------------------------------------------------------------------- * * SelectEntryApplyProc -- * * Sets the selection flag for a node. The selection flag is * set/cleared/toggled based upon the flag set in the treeview * widget. * * Results: * Always returns TCL_OK. * *---------------------------------------------------------------------- */ static int SelectEntryApplyProc(tvPtr, entryPtr) TreeView *tvPtr; TreeViewEntry *entryPtr; { Blt_HashEntry *hPtr; switch (tvPtr->flags & TV_SELECT_MASK) { case TV_SELECT_CLEAR: Blt_TreeViewDeselectEntry(tvPtr, entryPtr); break; case TV_SELECT_SET: Blt_TreeViewSelectEntry(tvPtr, entryPtr); break; case TV_SELECT_TOGGLE: hPtr = Blt_FindHashEntry(&tvPtr->selectTable, (char *)entryPtr); if (hPtr != NULL) { Blt_TreeViewDeselectEntry(tvPtr, entryPtr); } else { Blt_TreeViewSelectEntry(tvPtr, entryPtr); } break; } return TCL_OK; } /* *---------------------------------------------------------------------- * * EventuallyInvokeSelectCmd -- * * Queues a request to execute the -selectcommand code associated * with the widget at the next idle point. Invoked whenever the * selection changes. * * Results: * None. * * Side effects: * Tcl code gets executed for some application-specific task. * *---------------------------------------------------------------------- */ static void EventuallyInvokeSelectCmd(tvPtr) TreeView *tvPtr; { if (!(tvPtr->flags & TV_SELECT_PENDING)) { tvPtr->flags |= TV_SELECT_PENDING; Tcl_DoWhenIdle(Blt_TreeViewSelectCmdProc, tvPtr); } } /* *---------------------------------------------------------------------- * * Blt_TreeViewPruneSelection -- * * The root entry being deleted or closed. Deselect any of its * descendants that are currently selected. * * Results: * None. * * Side effects: * If any of the entry's descendants are deselected the widget * is redrawn and the a selection command callback is invoked * (if there's one configured). * *---------------------------------------------------------------------- */ void Blt_TreeViewPruneSelection(tvPtr, rootPtr) TreeView *tvPtr; TreeViewEntry *rootPtr; { Blt_ChainLink *linkPtr, *nextPtr; TreeViewEntry *entryPtr; int selectionChanged; /* * Check if any of the currently selected entries are a descendant * of of the current root entry. Deselect the entry and indicate * that the treeview widget needs to be redrawn. */ selectionChanged = FALSE; for (linkPtr = Blt_ChainFirstLink(tvPtr->selChainPtr); linkPtr != NULL; linkPtr = nextPtr) { nextPtr = Blt_ChainNextLink(linkPtr); entryPtr = Blt_ChainGetValue(linkPtr); if (Blt_TreeIsAncestor(rootPtr->node, entryPtr->node)) { Blt_TreeViewDeselectEntry(tvPtr, entryPtr); selectionChanged = TRUE; } } if (selectionChanged) { Blt_TreeViewEventuallyRedraw(tvPtr); if (tvPtr->selectCmd != NULL) { EventuallyInvokeSelectCmd(tvPtr); } } } /* * -------------------------------------------------------------- * * TreeView operations * * -------------------------------------------------------------- */ /*ARGSUSED*/ static int FocusOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { if (objc == 3) { TreeViewEntry *entryPtr; if (GetEntryFromObj(tvPtr, objv[2], &entryPtr) != TCL_OK) { return TCL_ERROR; } if ((entryPtr != NULL) && (entryPtr != tvPtr->focusPtr)) { if (entryPtr->flags & ENTRY_HIDDEN) { /* Doesn't make sense to set focus to a node you can't see. */ MapAncestors(tvPtr, entryPtr); } /* Changing focus can only affect the visible entries. The * entry layout stays the same. */ if (tvPtr->focusPtr != NULL) { tvPtr->focusPtr->flags |= ENTRY_REDRAW; } entryPtr->flags |= ENTRY_REDRAW; tvPtr->flags |= TV_SCROLL; tvPtr->focusPtr = entryPtr; } Blt_TreeViewEventuallyRedraw(tvPtr); } Blt_SetFocusItem(tvPtr->bindTable, tvPtr->focusPtr, ITEM_ENTRY); if (tvPtr->focusPtr != NULL) { Tcl_SetObjResult(interp, NodeToObj(tvPtr->focusPtr->node)); } return TCL_OK; } /* *---------------------------------------------------------------------- * * BboxOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int BboxOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { register int i; TreeViewEntry *entryPtr; int width, height, yBot; int left, top, right, bottom; int screen; int lWidth; char *string; if (tvPtr->flags & TV_LAYOUT) { /* * The layout is dirty. Recompute it now, before we use the * world dimensions. But remember, the "bbox" operation isn't * valid for hidden entries (since they're not visible, they * don't have world coordinates). */ Blt_TreeViewComputeLayout(tvPtr); } left = tvPtr->worldWidth; top = tvPtr->worldHeight; right = bottom = 0; screen = FALSE; string = Tcl_GetString(objv[2]); if ((string[0] == '-') && (strcmp(string, "-screen") == 0)) { screen = TRUE; objc--, objv++; } for (i = 2; i < objc; i++) { string = Tcl_GetString(objv[i]); if ((string[0] == 'a') && (strcmp(string, "all") == 0)) { left = top = 0; right = tvPtr->worldWidth; bottom = tvPtr->worldHeight; break; } if (GetEntryFromObj(tvPtr, objv[i], &entryPtr) != TCL_OK) { return TCL_ERROR; } if (entryPtr == NULL) { continue; } if (entryPtr->flags & ENTRY_HIDDEN) { continue; } yBot = entryPtr->worldY + entryPtr->height; height = VPORTHEIGHT(tvPtr); if ((yBot <= tvPtr->yOffset) && (entryPtr->worldY >= (tvPtr->yOffset + height))) { continue; } if (bottom < yBot) { bottom = yBot; } if (top > entryPtr->worldY) { top = entryPtr->worldY; } lWidth = ICONWIDTH(DEPTH(tvPtr, entryPtr->node)); if (right < (entryPtr->worldX + entryPtr->width + lWidth)) { right = (entryPtr->worldX + entryPtr->width + lWidth); } if (left > entryPtr->worldX) { left = entryPtr->worldX; } } if (screen) { width = VPORTWIDTH(tvPtr); height = VPORTHEIGHT(tvPtr); /* * Do a min-max text for the intersection of the viewport and * the computed bounding box. If there is no intersection, return * the empty string. */ if ((right < tvPtr->xOffset) || (bottom < tvPtr->yOffset) || (left >= (tvPtr->xOffset + width)) || (top >= (tvPtr->yOffset + height))) { return TCL_OK; } /* Otherwise clip the coordinates at the view port boundaries. */ if (left < tvPtr->xOffset) { left = tvPtr->xOffset; } else if (right > (tvPtr->xOffset + width)) { right = tvPtr->xOffset + width; } if (top < tvPtr->yOffset) { top = tvPtr->yOffset; } else if (bottom > (tvPtr->yOffset + height)) { bottom = tvPtr->yOffset + height; } left = SCREENX(tvPtr, left), top = SCREENY(tvPtr, top); right = SCREENX(tvPtr, right), bottom = SCREENY(tvPtr, bottom); } if ((left < right) && (top < bottom)) { Tcl_Obj *listObjPtr; listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewIntObj(left)); Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewIntObj(top)); Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewIntObj(right - left)); Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewIntObj(bottom - top)); Tcl_SetObjResult(interp, listObjPtr); } return TCL_OK; } static void DrawButton(tvPtr, entryPtr) TreeView *tvPtr; TreeViewEntry *entryPtr; { Drawable drawable; int sx, sy, dx, dy; int width, height; int left, right, top, bottom; dx = SCREENX(tvPtr, entryPtr->worldX) + entryPtr->buttonX; dy = SCREENY(tvPtr, entryPtr->worldY) + entryPtr->buttonY; width = tvPtr->button.width; height = tvPtr->button.height; top = tvPtr->titleHeight + tvPtr->inset; bottom = Tk_Height(tvPtr->tkwin) - tvPtr->inset; left = tvPtr->inset; right = Tk_Width(tvPtr->tkwin) - tvPtr->inset; if (((dx + width) < left) || (dx > right) || ((dy + height) < top) || (dy > bottom)) { return; /* Value is clipped. */ } drawable = Tk_GetPixmap(tvPtr->display, Tk_WindowId(tvPtr->tkwin), width, height, Tk_Depth(tvPtr->tkwin)); /* Draw the background of the value. */ Blt_TreeViewDrawButton(tvPtr, entryPtr, drawable, 0, 0); /* Clip the drawable if necessary */ sx = sy = 0; if (dx < left) { width -= left - dx; sx += left - dx; dx = left; } if ((dx + width) >= right) { width -= (dx + width) - right; } if (dy < top) { height -= top - dy; sy += top - dy; dy = top; } if ((dy + height) >= bottom) { height -= (dy + height) - bottom; } XCopyArea(tvPtr->display, drawable, Tk_WindowId(tvPtr->tkwin), tvPtr->lineGC, sx, sy, width, height, dx, dy); Tk_FreePixmap(tvPtr->display, drawable); } /* *---------------------------------------------------------------------- * * ButtonActivateOp -- * * Selects the button to appear active. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ButtonActivateOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { TreeViewEntry *oldPtr, *newPtr; char *string; string = Tcl_GetString(objv[3]); if (string[0] == '\0') { newPtr = NULL; } else if (GetEntryFromObj(tvPtr, objv[3], &newPtr) != TCL_OK) { return TCL_ERROR; } if (tvPtr->treeColumn.hidden) { return TCL_OK; } if ((newPtr != NULL) && !(newPtr->flags & ENTRY_HAS_BUTTON)) { newPtr = NULL; } oldPtr = tvPtr->activeButtonPtr; tvPtr->activeButtonPtr = newPtr; if (!(tvPtr->flags & TV_REDRAW) && (newPtr != oldPtr)) { if ((oldPtr != NULL) && (oldPtr != tvPtr->rootPtr)) { DrawButton(tvPtr, oldPtr); } if ((newPtr != NULL) && (newPtr != tvPtr->rootPtr)) { DrawButton(tvPtr, newPtr); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * ButtonBindOp -- * * .t bind tag sequence command * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ButtonBindOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { ClientData object; char *string; string = Tcl_GetString(objv[3]); /* Assume that this is a binding tag. */ object = Blt_TreeViewButtonTag(tvPtr, string); return Blt_ConfigureBindingsFromObj(interp, tvPtr->bindTable, object, objc - 4, objv + 4); } /* *---------------------------------------------------------------------- * * ButtonCgetOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ButtonCgetOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { return Blt_ConfigureValueFromObj(interp, tvPtr->tkwin, bltTreeViewButtonSpecs, (char *)tvPtr, objv[3], 0); } /* *---------------------------------------------------------------------- * * ButtonConfigureOp -- * * This procedure is called to process a list of configuration * options database, in order to reconfigure the one of more * entries in the widget. * * .h button configure option value * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for tvPtr; old resources get freed, if there * were any. The hypertext is redisplayed. * *---------------------------------------------------------------------- */ static int ButtonConfigureOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { if (objc == 3) { return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin, bltTreeViewButtonSpecs, (char *)tvPtr, (Tcl_Obj *)NULL, 0); } else if (objc == 4) { return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin, bltTreeViewButtonSpecs, (char *)tvPtr, objv[3], 0); } bltTreeViewIconsOption.clientData = tvPtr; if (Blt_ConfigureWidgetFromObj(tvPtr->interp, tvPtr->tkwin, bltTreeViewButtonSpecs, objc - 3, objv + 3, (char *)tvPtr, BLT_CONFIG_OBJV_ONLY) != TCL_OK) { return TCL_ERROR; } Blt_TreeViewConfigureButtons(tvPtr); Blt_TreeViewEventuallyRedraw(tvPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * ButtonOp -- * * This procedure handles button operations. * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ static Blt_OpSpec buttonOps[] = { {"activate", 1, (Blt_Op)ButtonActivateOp, 4, 4, "tagOrId",}, {"bind", 1, (Blt_Op)ButtonBindOp, 4, 6, "tagName ?sequence command?",}, {"cget", 2, (Blt_Op)ButtonCgetOp, 4, 4, "option",}, {"configure", 2, (Blt_Op)ButtonConfigureOp, 3, 0, "?option value?...",}, {"highlight", 1, (Blt_Op)ButtonActivateOp, 4, 4, "tagOrId",}, }; static int nButtonOps = sizeof(buttonOps) / sizeof(Blt_OpSpec); static int ButtonOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { Blt_Op proc; int result; proc = Blt_GetOpFromObj(interp, nButtonOps, buttonOps, BLT_OP_ARG2, objc, objv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (tvPtr, interp, objc, objv); return result; } /* *---------------------------------------------------------------------- * * CgetOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int CgetOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { return Blt_ConfigureValueFromObj(interp, tvPtr->tkwin, bltTreeViewSpecs, (char *)tvPtr, objv[2], 0); } /*ARGSUSED*/ static int CloseOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; /* Not used. */ int objc; Tcl_Obj *CONST *objv; { TreeViewEntry *entryPtr; TreeViewTagInfo info; int recurse, result; register int i; recurse = FALSE; if (objc > 2) { char *string; int length; string = Tcl_GetStringFromObj(objv[2], &length); if ((string[0] == '-') && (length > 1) && (strncmp(string, "-recurse", length) == 0)) { objv++, objc--; recurse = TRUE; } } for (i = 2; i < objc; i++) { if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[i], &info) != TCL_OK) { return TCL_ERROR; } for (entryPtr = Blt_TreeViewFirstTaggedEntry(&info); entryPtr != NULL; entryPtr = Blt_TreeViewNextTaggedEntry(&info)) { /* * Clear the selections for any entries that may have become * hidden by closing the node. */ Blt_TreeViewPruneSelection(tvPtr, entryPtr); /* * ----------------------------------------------------------- * * Check if either the "focus" entry or selection anchor * is in this hierarchy. Must move it or disable it before * we close the node. Otherwise it may be deleted by a Tcl * "close" script, and we'll be left pointing to a bogus * memory location. * * ----------------------------------------------------------- */ if ((tvPtr->focusPtr != NULL) && (Blt_TreeIsAncestor(entryPtr->node, tvPtr->focusPtr->node))) { tvPtr->focusPtr = entryPtr; Blt_SetFocusItem(tvPtr->bindTable, tvPtr->focusPtr, ITEM_ENTRY); } if ((tvPtr->selAnchorPtr != NULL) && (Blt_TreeIsAncestor(entryPtr->node, tvPtr->selAnchorPtr->node))) { tvPtr->selMarkPtr = tvPtr->selAnchorPtr = NULL; } if ((tvPtr->activePtr != NULL) && (Blt_TreeIsAncestor(entryPtr->node, tvPtr->activePtr->node))) { tvPtr->activePtr = entryPtr; } if (recurse) { result = Blt_TreeViewApply(tvPtr, entryPtr, Blt_TreeViewCloseEntry, 0); } else { result = Blt_TreeViewCloseEntry(tvPtr, entryPtr); } if (result != TCL_OK) { return TCL_ERROR; } } } /* Closing a node may affect the visible entries and the * the world layout of the entries. */ tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT); Blt_TreeViewEventuallyRedraw(tvPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * ConfigureOp -- * * This procedure is called to process an objv/objc list, plus * the Tk option database, in order to configure (or reconfigure) * the widget. * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for tvPtr; old resources get freed, if there * were any. The widget is redisplayed. * *---------------------------------------------------------------------- */ static int ConfigureOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { if (objc == 2) { return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin, bltTreeViewSpecs, (char *)tvPtr, (Tcl_Obj *)NULL, 0); } else if (objc == 3) { return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin, bltTreeViewSpecs, (char *)tvPtr, objv[2], 0); } bltTreeViewIconsOption.clientData = tvPtr; bltTreeViewTreeOption.clientData = tvPtr; if (Blt_ConfigureWidgetFromObj(interp, tvPtr->tkwin, bltTreeViewSpecs, objc - 2, objv + 2, (char *)tvPtr, BLT_CONFIG_OBJV_ONLY) != TCL_OK) { return TCL_ERROR; } if (Blt_TreeViewUpdateWidget(interp, tvPtr) != TCL_OK) { return TCL_ERROR; } Blt_TreeViewEventuallyRedraw(tvPtr); return TCL_OK; } /*ARGSUSED*/ static int CurselectionOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; /* Not used. */ int objc; /* Not used. */ Tcl_Obj *CONST *objv; /* Not used. */ { TreeViewEntry *entryPtr; Tcl_Obj *listObjPtr, *objPtr; listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); if (tvPtr->flags & TV_SELECT_SORTED) { Blt_ChainLink *linkPtr; for (linkPtr = Blt_ChainFirstLink(tvPtr->selChainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { entryPtr = Blt_ChainGetValue(linkPtr); objPtr = NodeToObj(entryPtr->node); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } } else { for (entryPtr = tvPtr->rootPtr; entryPtr != NULL; entryPtr = Blt_TreeViewNextEntry(entryPtr, ENTRY_MASK)) { if (Blt_TreeViewEntryIsSelected(tvPtr, entryPtr)) { objPtr = NodeToObj(entryPtr->node); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } } } Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * BindOp -- * * .t bind tagOrId sequence command * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int BindOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { ClientData object; TreeViewEntry *entryPtr; char *string; /* * Entries are selected by id only. All other strings are * interpreted as a binding tag. */ string = Tcl_GetString(objv[2]); if (isdigit(UCHAR(string[0]))) { Blt_TreeNode node; int inode; if (Tcl_GetIntFromObj(tvPtr->interp, objv[2], &inode) != TCL_OK) { return TCL_ERROR; } node = Blt_TreeGetNode(tvPtr->tree, inode); object = Blt_NodeToEntry(tvPtr, node); } else if (GetEntryFromSpecialId(tvPtr, string, &entryPtr) == TCL_OK) { if (entryPtr != NULL) { return TCL_OK; /* Special id doesn't currently exist. */ } object = entryPtr; } else { /* Assume that this is a binding tag. */ object = Blt_TreeViewEntryTag(tvPtr, string); } return Blt_ConfigureBindingsFromObj(interp, tvPtr->bindTable, object, objc - 3, objv + 3); } /*ARGSUSED*/ static int EditOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; /* Not used. */ int objc; Tcl_Obj *CONST *objv; { TreeViewEntry *entryPtr; char *string; int isRoot, isTest; int x, y; isRoot = isTest = FALSE; string = Tcl_GetString(objv[2]); if (strcmp("-root", string) == 0) { isRoot = TRUE; objv++, objc--; } string = Tcl_GetString(objv[2]); if (strcmp("-test", string) == 0) { isTest = TRUE; objv++, objc--; } if (objc != 4) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " ", Tcl_GetString(objv[1]), " ?-root? x y\"", (char *)NULL); return TCL_ERROR; } if ((Tcl_GetIntFromObj(interp, objv[2], &x) != TCL_OK) || (Tcl_GetIntFromObj(interp, objv[3], &y) != TCL_OK)) { return TCL_ERROR; } if (isRoot) { int rootX, rootY; Tk_GetRootCoords(tvPtr->tkwin, &rootX, &rootY); x -= rootX; y -= rootY; } entryPtr = Blt_TreeViewNearestEntry(tvPtr, x, y, FALSE); if (entryPtr != NULL) { Blt_ChainLink *linkPtr; TreeViewColumn *columnPtr; int worldX; worldX = WORLDX(tvPtr, x); for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { columnPtr = Blt_ChainGetValue(linkPtr); if (!columnPtr->editable) { continue; /* Column isn't editable. */ } if ((worldX >= columnPtr->worldX) && (worldX < (columnPtr->worldX + columnPtr->width))) { TreeViewValue *valuePtr; valuePtr = Blt_TreeViewFindValue(entryPtr, columnPtr); if (valuePtr != NULL) { TreeViewStyle *stylePtr; stylePtr = valuePtr->stylePtr; if (stylePtr == NULL) { stylePtr = columnPtr->stylePtr; } if ((stylePtr->classPtr->editProc != NULL) && (!isTest)) { if ((*stylePtr->classPtr->editProc)(tvPtr, entryPtr, valuePtr, stylePtr) != TCL_OK) { return TCL_ERROR; } Blt_TreeViewEventuallyRedraw(tvPtr); } Tcl_SetObjResult(interp, Tcl_NewIntObj(1)); return TCL_OK; } } } } Tcl_SetObjResult(interp, Tcl_NewIntObj(0)); return TCL_OK; } /* *---------------------------------------------------------------------- * * EntryActivateOp -- * * Selects the entry to appear active. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int EntryActivateOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { TreeViewEntry *newPtr, *oldPtr; char *string; string = Tcl_GetString(objv[3]); if (string[0] == '\0') { newPtr = NULL; } else if (GetEntryFromObj(tvPtr, objv[3], &newPtr) != TCL_OK) { return TCL_ERROR; } if (tvPtr->treeColumn.hidden) { return TCL_OK; } oldPtr = tvPtr->activePtr; tvPtr->activePtr = newPtr; if (!(tvPtr->flags & TV_REDRAW) && (newPtr != oldPtr)) { Drawable drawable; int x, y; drawable = Tk_WindowId(tvPtr->tkwin); if (oldPtr != NULL) { x = SCREENX(tvPtr, oldPtr->worldX); if (!tvPtr->flatView) { x += ICONWIDTH(DEPTH(tvPtr, oldPtr->node)); } y = SCREENY(tvPtr, oldPtr->worldY); oldPtr->flags |= ENTRY_ICON; Blt_TreeViewDrawIcon(tvPtr, oldPtr, drawable, x, y); } if (newPtr != NULL) { x = SCREENX(tvPtr, newPtr->worldX); if (!tvPtr->flatView) { x += ICONWIDTH(DEPTH(tvPtr, newPtr->node)); } y = SCREENY(tvPtr, newPtr->worldY); newPtr->flags |= ENTRY_ICON; Blt_TreeViewDrawIcon(tvPtr, newPtr, drawable, x, y); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * EntryCgetOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int EntryCgetOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { TreeViewEntry *entryPtr; if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK) { return TCL_ERROR; } return Blt_ConfigureValueFromObj(interp, tvPtr->tkwin, bltTreeViewEntrySpecs, (char *)entryPtr, objv[4], 0); } /* *---------------------------------------------------------------------- * * EntryConfigureOp -- * * This procedure is called to process a list of configuration * options database, in order to reconfigure the one of more * entries in the widget. * * .h entryconfigure node node node node option value * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for tvPtr; old resources get freed, if there * were any. The hypertext is redisplayed. * *---------------------------------------------------------------------- */ static int EntryConfigureOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { int nIds, configObjc; Tcl_Obj *CONST *configObjv; register int i; TreeViewEntry *entryPtr; TreeViewTagInfo info; char *string; /* Figure out where the option value pairs begin */ objc -= 3, objv += 3; for (i = 0; i < objc; i++) { string = Tcl_GetString(objv[i]); if (string[0] == '-') { break; } } nIds = i; /* # of tags or ids specified */ configObjc = objc - i; /* # of options specified */ configObjv = objv + i; /* Start of options in objv */ bltTreeViewIconsOption.clientData = tvPtr; bltTreeViewUidOption.clientData = tvPtr; for (i = 0; i < nIds; i++) { if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[i], &info) != TCL_OK) { return TCL_ERROR; } for (entryPtr = Blt_TreeViewFirstTaggedEntry(&info); entryPtr != NULL; entryPtr = Blt_TreeViewNextTaggedEntry(&info)) { if (configObjc == 0) { return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin, bltTreeViewEntrySpecs, (char *)entryPtr, (Tcl_Obj *)NULL, 0); } else if (configObjc == 1) { return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin, bltTreeViewEntrySpecs, (char *)entryPtr, configObjv[0], 0); } if (Blt_TreeViewConfigureEntry(tvPtr, entryPtr, configObjc, configObjv, BLT_CONFIG_OBJV_ONLY) != TCL_OK) { return TCL_ERROR; } } } tvPtr->flags |= (TV_DIRTY | TV_LAYOUT | TV_SCROLL | TV_RESORT); Blt_TreeViewEventuallyRedraw(tvPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * EntryIsOpenOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int EntryIsBeforeOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { TreeViewEntry *e1Ptr, *e2Ptr; int bool; if ((Blt_TreeViewGetEntry(tvPtr, objv[3], &e1Ptr) != TCL_OK) || (Blt_TreeViewGetEntry(tvPtr, objv[4], &e2Ptr) != TCL_OK)) { return TCL_ERROR; } bool = Blt_TreeIsBefore(e1Ptr->node, e2Ptr->node); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(bool)); return TCL_OK; } /* *---------------------------------------------------------------------- * * EntryIsHiddenOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int EntryIsHiddenOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { TreeViewEntry *entryPtr; int bool; if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK) { return TCL_ERROR; } bool = (entryPtr->flags & ENTRY_HIDDEN); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(bool)); return TCL_OK; } /* *---------------------------------------------------------------------- * * EntryIsOpenOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int EntryIsOpenOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { TreeViewEntry *entryPtr; int bool; if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK) { return TCL_ERROR; } bool = ((entryPtr->flags & ENTRY_CLOSED) == 0); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(bool)); return TCL_OK; } /*ARGSUSED*/ static int EntryChildrenOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { TreeViewEntry *parentPtr; Tcl_Obj *listObjPtr, *objPtr; unsigned int mask; mask = 0; if (Blt_TreeViewGetEntry(tvPtr, objv[3], &parentPtr) != TCL_OK) { return TCL_ERROR; } listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); if (objc == 4) { TreeViewEntry *entryPtr; for (entryPtr = Blt_TreeViewFirstChild(parentPtr, mask); entryPtr != NULL; entryPtr = Blt_TreeViewNextSibling(entryPtr, mask)) { objPtr = NodeToObj(entryPtr->node); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } } else if (objc == 6) { TreeViewEntry *entryPtr, *lastPtr, *firstPtr; int firstPos, lastPos; int nNodes; if ((Blt_GetPositionFromObj(interp, objv[4], &firstPos) != TCL_OK) || (Blt_GetPositionFromObj(interp, objv[5], &lastPos) != TCL_OK)) { return TCL_ERROR; } nNodes = Blt_TreeNodeDegree(parentPtr->node); if (nNodes == 0) { return TCL_OK; } if ((lastPos == END) || (lastPos >= nNodes)) { lastPtr = Blt_TreeViewLastChild(parentPtr, mask); } else { lastPtr = GetNthEntry(parentPtr, lastPos, mask); } if ((firstPos == END) || (firstPos >= nNodes)) { firstPtr = Blt_TreeViewLastChild(parentPtr, mask); } else { firstPtr = GetNthEntry(parentPtr, firstPos, mask); } if ((lastPos != END) && (firstPos > lastPos)) { for (entryPtr = lastPtr; entryPtr != NULL; entryPtr = Blt_TreeViewPrevEntry(entryPtr, mask)) { objPtr = NodeToObj(entryPtr->node); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); if (entryPtr == firstPtr) { break; } } } else { for (entryPtr = firstPtr; entryPtr != NULL; entryPtr = Blt_TreeViewNextEntry(entryPtr, mask)) { objPtr = NodeToObj(entryPtr->node); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); if (entryPtr == lastPtr) { break; } } } } else { Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " ", Tcl_GetString(objv[1]), " ", Tcl_GetString(objv[2]), " tagOrId ?first last?", (char *)NULL); return TCL_ERROR; } Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * EntryDeleteOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int EntryDeleteOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { TreeViewEntry *entryPtr; if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK) { return TCL_ERROR; } if (objc == 5) { int entryPos; Blt_TreeNode node; /* * Delete a single child node from a hierarchy specified * by its numeric position. */ if (Blt_GetPositionFromObj(interp, objv[3], &entryPos) != TCL_OK) { return TCL_ERROR; } if (entryPos >= (int)Blt_TreeNodeDegree(entryPtr->node)) { return TCL_OK; /* Bad first index */ } if (entryPos == END) { node = Blt_TreeLastChild(entryPtr->node); } else { node = GetNthNode(entryPtr->node, entryPos); } DeleteNode(tvPtr, node); } else { int firstPos, lastPos; Blt_TreeNode node, first, last, next; int nEntries; /* * Delete range of nodes in hierarchy specified by first/last * positions. */ if ((Blt_GetPositionFromObj(interp, objv[4], &firstPos) != TCL_OK) || (Blt_GetPositionFromObj(interp, objv[5], &lastPos) != TCL_OK)) { return TCL_ERROR; } nEntries = Blt_TreeNodeDegree(entryPtr->node); if (nEntries == 0) { return TCL_OK; } if (firstPos == END) { firstPos = nEntries - 1; } if (firstPos >= nEntries) { Tcl_AppendResult(interp, "first position \"", Tcl_GetString(objv[4]), " is out of range", (char *)NULL); return TCL_ERROR; } if ((lastPos == END) || (lastPos >= nEntries)) { lastPos = nEntries - 1; } if (firstPos > lastPos) { Tcl_AppendResult(interp, "bad range: \"", Tcl_GetString(objv[4]), " > ", Tcl_GetString(objv[5]), "\"", (char *)NULL); return TCL_ERROR; } first = GetNthNode(entryPtr->node, firstPos); last = GetNthNode(entryPtr->node, lastPos); for (node = first; node != NULL; node = next) { next = Blt_TreeNextSibling(node); DeleteNode(tvPtr, node); if (node == last) { break; } } } tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT); Blt_TreeViewEventuallyRedraw(tvPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * EntrySizeOp -- * * Counts the number of entries at this node. * * Results: * A standard Tcl result. If an error occurred TCL_ERROR is * returned and interp->result will contain an error message. * Otherwise, TCL_OK is returned and interp->result contains * the number of entries. * *---------------------------------------------------------------------- */ static int EntrySizeOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { TreeViewEntry *entryPtr; int length, sum, recurse; char *string; recurse = FALSE; string = Tcl_GetStringFromObj(objv[3], &length); if ((string[0] == '-') && (length > 1) && (strncmp(string, "-recurse", length) == 0)) { objv++, objc--; recurse = TRUE; } if (objc == 3) { Tcl_AppendResult(interp, "missing node argument: should be \"", Tcl_GetString(objv[0]), " entry open node\"", (char *)NULL); return TCL_ERROR; } if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK) { return TCL_ERROR; } if (recurse) { sum = Blt_TreeSize(entryPtr->node); } else { sum = Blt_TreeNodeDegree(entryPtr->node); } Tcl_SetObjResult(interp, Tcl_NewIntObj(sum)); return TCL_OK; } /* *---------------------------------------------------------------------- * * EntryOp -- * * This procedure handles entry operations. * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ static Blt_OpSpec entryOps[] = { {"activate", 1, (Blt_Op)EntryActivateOp, 4, 4, "tagOrId",}, /*bbox*/ /*bind*/ {"cget", 2, (Blt_Op)EntryCgetOp, 5, 5, "tagOrId option",}, {"children", 2, (Blt_Op)EntryChildrenOp, 4, 6, "tagOrId firstPos lastPos",}, /*close*/ {"configure", 2, (Blt_Op)EntryConfigureOp, 4, 0, "tagOrId ?tagOrId...? ?option value?...",}, {"delete", 2, (Blt_Op)EntryDeleteOp, 5, 6, "tagOrId firstPos ?lastPos?",}, /*focus*/ /*hide*/ {"highlight", 1, (Blt_Op)EntryActivateOp, 4, 4, "tagOrId",}, /*index*/ {"isbefore", 3, (Blt_Op)EntryIsBeforeOp, 5, 5, "tagOrId tagOrId",}, {"ishidden", 3, (Blt_Op)EntryIsHiddenOp, 4, 4, "tagOrId",}, {"isopen", 3, (Blt_Op)EntryIsOpenOp, 4, 4, "tagOrId",}, /*move*/ /*nearest*/ /*open*/ /*see*/ /*show*/ {"size", 1, (Blt_Op)EntrySizeOp, 4, 5, "?-recurse? tagOrId",}, /*toggle*/ }; static int nEntryOps = sizeof(entryOps) / sizeof(Blt_OpSpec); static int EntryOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { Blt_Op proc; int result; proc = Blt_GetOpFromObj(interp, nEntryOps, entryOps, BLT_OP_ARG2, objc, objv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (tvPtr, interp, objc, objv); return result; } /*ARGSUSED*/ static int ExactCompare(interp, name, pattern) Tcl_Interp *interp; /* Not used. */ char *name; char *pattern; { return (strcmp(name, pattern) == 0); } /*ARGSUSED*/ static int GlobCompare(interp, name, pattern) Tcl_Interp *interp; /* Not used. */ char *name; char *pattern; { return Tcl_StringMatch(name, pattern); } static int RegexpCompare(interp, name, pattern) Tcl_Interp *interp; char *name; char *pattern; { return Tcl_RegExpMatch(interp, name, pattern); } /* *---------------------------------------------------------------------- * * FindOp -- * * Find one or more nodes based upon the pattern provided. * * Results: * A standard Tcl result. The interpreter result will contain a * list of the node serial identifiers. * *---------------------------------------------------------------------- */ static int FindOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { TreeViewEntry *firstPtr, *lastPtr; int nMatches, maxMatches; char c; int length; TreeViewCompareProc *compareProc; TreeViewIterProc *nextProc; int invertMatch; /* normal search mode (matching entries) */ char *namePattern, *fullPattern; char *execCmd; register int i; int result; char *pattern, *option; Tcl_DString dString; Blt_List options; Blt_ListNode node; char *addTag, *withTag; register TreeViewEntry *entryPtr; char *string; Tcl_Obj *listObjPtr, *objPtr; invertMatch = FALSE; maxMatches = 0; execCmd = namePattern = fullPattern = NULL; compareProc = ExactCompare; nextProc = Blt_TreeViewNextEntry; options = Blt_ListCreate(BLT_ONE_WORD_KEYS); withTag = addTag = NULL; entryPtr = tvPtr->rootPtr; /* * Step 1: Process flags for find operation. */ for (i = 2; i < objc; i++) { string = Tcl_GetStringFromObj(objv[i], &length); if (string[0] != '-') { break; } option = string + 1; length--; c = option[0]; if ((c == 'e') && (length > 2) && (strncmp(option, "exact", length) == 0)) { compareProc = ExactCompare; } else if ((c == 'g') && (strncmp(option, "glob", length) == 0)) { compareProc = GlobCompare; } else if ((c == 'r') && (strncmp(option, "regexp", length) == 0)) { compareProc = RegexpCompare; } else if ((c == 'n') && (length > 1) && (strncmp(option, "nonmatching", length) == 0)) { invertMatch = TRUE; } else if ((c == 'n') && (length > 1) && (strncmp(option, "name", length) == 0)) { if ((i + 1) == objc) { goto missingArg; } i++; namePattern = Tcl_GetString(objv[i]); } else if ((c == 'f') && (strncmp(option, "full", length) == 0)) { if ((i + 1) == objc) { goto missingArg; } i++; fullPattern = Tcl_GetString(objv[i]); } else if ((c == 'e') && (length > 2) && (strncmp(option, "exec", length) == 0)) { if ((i + 1) == objc) { goto missingArg; } i++; execCmd = Tcl_GetString(objv[i]); } else if ((c == 'a') && (length > 1) && (strncmp(option, "addtag", length) == 0)) { if ((i + 1) == objc) { goto missingArg; } i++; addTag = Tcl_GetString(objv[i]); } else if ((c == 't') && (length > 1) && (strncmp(option, "tag", length) == 0)) { if ((i + 1) == objc) { goto missingArg; } i++; withTag = Tcl_GetString(objv[i]); } else if ((c == 'c') && (strncmp(option, "count", length) == 0)) { if ((i + 1) == objc) { goto missingArg; } i++; if (Tcl_GetIntFromObj(interp, objv[i], &maxMatches) != TCL_OK) { return TCL_ERROR; } if (maxMatches < 0) { Tcl_AppendResult(interp, "bad match count \"", objv[i], "\": should be a positive number", (char *)NULL); Blt_ListDestroy(options); return TCL_ERROR; } } else if ((option[0] == '-') && (option[1] == '\0')) { break; } else { /* * Verify that the switch is actually an entry configuration * option. */ if (Blt_ConfigureValueFromObj(interp, tvPtr->tkwin, bltTreeViewEntrySpecs, (char *)entryPtr, objv[i], 0) != TCL_OK) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, "bad find switch \"", string, "\"", (char *)NULL); Blt_ListDestroy(options); return TCL_ERROR; } if ((i + 1) == objc) { goto missingArg; } /* Save the option in the list of configuration options */ node = Blt_ListGetNode(options, (char *)objv[i]); if (node == NULL) { node = Blt_ListCreateNode(options, (char *)objv[i]); Blt_ListAppendNode(options, node); } i++; Blt_ListSetValue(node, Tcl_GetString(objv[i])); } } if ((objc - i) > 2) { Blt_ListDestroy(options); Tcl_AppendResult(interp, "too many args", (char *)NULL); return TCL_ERROR; } /* * Step 2: Find the range of the search. Check the order of two * nodes and arrange the search accordingly. * * Note: Be careful to treat "end" as the end of all nodes, instead * of the end of visible nodes. That way, we can search the * entire tree, even if the last folder is closed. */ firstPtr = tvPtr->rootPtr; /* Default to root node */ lastPtr = LastEntry(tvPtr, firstPtr, 0); if (i < objc) { string = Tcl_GetString(objv[i]); if ((string[0] == 'e') && (strcmp(string, "end") == 0)) { firstPtr = LastEntry(tvPtr, tvPtr->rootPtr, 0); } else if (Blt_TreeViewGetEntry(tvPtr, objv[i], &firstPtr) != TCL_OK) { return TCL_ERROR; } i++; } if (i < objc) { string = Tcl_GetString(objv[i]); if ((string[0] == 'e') && (strcmp(string, "end") == 0)) { lastPtr = LastEntry(tvPtr, tvPtr->rootPtr, 0); } else if (Blt_TreeViewGetEntry(tvPtr, objv[i], &lastPtr) != TCL_OK) { return TCL_ERROR; } } if (Blt_TreeIsBefore(lastPtr->node, firstPtr->node)) { nextProc = Blt_TreeViewPrevEntry; } nMatches = 0; /* * Step 3: Search through the tree and look for nodes that match the * current pattern specifications. Save the name of each of * the matching nodes. */ listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); for (entryPtr = firstPtr; entryPtr != NULL; entryPtr = (*nextProc) (entryPtr, 0)) { if (namePattern != NULL) { result = (*compareProc)(interp, Blt_TreeNodeLabel(entryPtr->node), namePattern); if (result == invertMatch) { goto nextEntry; /* Failed to match */ } } if (fullPattern != NULL) { Tcl_DString fullName; Blt_TreeViewGetFullName(tvPtr, entryPtr, FALSE, &fullName); result = (*compareProc) (interp, Tcl_DStringValue(&fullName), fullPattern); Tcl_DStringFree(&fullName); if (result == invertMatch) { goto nextEntry; /* Failed to match */ } } if (withTag != NULL) { result = Blt_TreeHasTag(tvPtr->tree, entryPtr->node, withTag); if (result == invertMatch) { goto nextEntry; /* Failed to match */ } } for (node = Blt_ListFirstNode(options); node != NULL; node = Blt_ListNextNode(node)) { objPtr = (Tcl_Obj *)Blt_ListGetKey(node); Tcl_ResetResult(interp); Blt_ConfigureValueFromObj(interp, tvPtr->tkwin, bltTreeViewEntrySpecs, (char *)entryPtr, objPtr, 0); pattern = Blt_ListGetValue(node); objPtr = Tcl_GetObjResult(interp); result = (*compareProc) (interp, Tcl_GetString(objPtr), pattern); if (result == invertMatch) { goto nextEntry; /* Failed to match */ } } /* * Someone may actually delete the current node in the "exec" * callback. Preserve the entry. */ Tcl_Preserve(entryPtr); if (execCmd != NULL) { Tcl_DString cmdString; Blt_TreeViewPercentSubst(tvPtr, entryPtr, execCmd, &cmdString); result = Tcl_GlobalEval(interp, Tcl_DStringValue(&cmdString)); Tcl_DStringFree(&cmdString); if (result != TCL_OK) { Tcl_Release(entryPtr); goto error; } } /* A NULL node reference in an entry indicates that the entry * was deleted, but its memory not released yet. */ if (entryPtr->node != NULL) { /* Finally, save the matching node name. */ objPtr = NodeToObj(entryPtr->node); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); if (addTag != NULL) { if (AddTag(tvPtr, entryPtr->node, addTag) != TCL_OK) { goto error; } } } Tcl_Release(entryPtr); nMatches++; if ((nMatches == maxMatches) && (maxMatches > 0)) { break; } nextEntry: if (entryPtr == lastPtr) { break; } } Tcl_ResetResult(interp); Blt_ListDestroy(options); Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; missingArg: Tcl_AppendResult(interp, "missing argument for find option \"", objv[i], "\"", (char *)NULL); error: Tcl_DStringFree(&dString); Blt_ListDestroy(options); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * GetOp -- * * Converts one or more node identifiers to its path component. * The path may be either the single entry name or the full path * of the entry. * * Results: * A standard Tcl result. The interpreter result will contain a * list of the convert names. * *---------------------------------------------------------------------- */ static int GetOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { TreeViewTagInfo info; TreeViewEntry *entryPtr; int useFullName; register int i; Tcl_DString dString1, dString2; int count; useFullName = FALSE; if (objc > 2) { char *string; string = Tcl_GetString(objv[2]); if ((string[0] == '-') && (strcmp(string, "-full") == 0)) { useFullName = TRUE; objv++, objc--; } } Tcl_DStringInit(&dString1); Tcl_DStringInit(&dString2); count = 0; for (i = 2; i < objc; i++) { if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[i], &info) != TCL_OK) { return TCL_ERROR; } for (entryPtr = Blt_TreeViewFirstTaggedEntry(&info); entryPtr != NULL; entryPtr = Blt_TreeViewNextTaggedEntry(&info)) { Tcl_DStringSetLength(&dString2, 0); count++; if (entryPtr->node == NULL) { Tcl_DStringAppendElement(&dString1, ""); continue; } if (useFullName) { Blt_TreeViewGetFullName(tvPtr, entryPtr, FALSE, &dString2); Tcl_DStringAppendElement(&dString1, Tcl_DStringValue(&dString2)); } else { Tcl_DStringAppendElement(&dString1, Blt_TreeNodeLabel(entryPtr->node)); } } } /* This handles the single element list problem. */ if (count == 1) { Tcl_DStringResult(interp, &dString2); Tcl_DStringFree(&dString1); } else { Tcl_DStringResult(interp, &dString1); Tcl_DStringFree(&dString2); } return TCL_OK; } /* *---------------------------------------------------------------------- * * SearchAndApplyToTree -- * * Searches through the current tree and applies a procedure * to matching nodes. The search specification is taken from * the following command-line arguments: * * ?-exact? ?-glob? ?-regexp? ?-nonmatching? * ?-data string? * ?-name string? * ?-full string? * ?--? * ?inode...? * * Results: * A standard Tcl result. If the result is valid, and if the * nonmatchPtr is specified, it returns a boolean value * indicating whether or not the search was inverted. This * is needed to fix things properly for the "hide nonmatching" * case. * *---------------------------------------------------------------------- */ static int SearchAndApplyToTree(tvPtr, interp, objc, objv, proc, nonMatchPtr) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; TreeViewApplyProc *proc; int *nonMatchPtr; /* returns: inverted search indicator */ { TreeViewCompareProc *compareProc; int invertMatch; /* normal search mode (matching entries) */ char *namePattern, *fullPattern; register int i; int length; int result; char *option, *pattern; char c; Blt_List options; TreeViewEntry *entryPtr; register Blt_ListNode node; char *string; char *withTag; Tcl_Obj *objPtr; TreeViewTagInfo info; options = Blt_ListCreate(BLT_ONE_WORD_KEYS); invertMatch = FALSE; namePattern = fullPattern = NULL; compareProc = ExactCompare; withTag = NULL; entryPtr = tvPtr->rootPtr; for (i = 2; i < objc; i++) { string = Tcl_GetStringFromObj(objv[i], &length); if (string[0] != '-') { break; } option = string + 1; length--; c = option[0]; if ((c == 'e') && (strncmp(option, "exact", length) == 0)) { compareProc = ExactCompare; } else if ((c == 'g') && (strncmp(option, "glob", length) == 0)) { compareProc = GlobCompare; } else if ((c == 'r') && (strncmp(option, "regexp", length) == 0)) { compareProc = RegexpCompare; } else if ((c == 'n') && (length > 1) && (strncmp(option, "nonmatching", length) == 0)) { invertMatch = TRUE; } else if ((c == 'f') && (strncmp(option, "full", length) == 0)) { if ((i + 1) == objc) { goto missingArg; } i++; fullPattern = Tcl_GetString(objv[i]); } else if ((c == 'n') && (length > 1) && (strncmp(option, "name", length) == 0)) { if ((i + 1) == objc) { goto missingArg; } i++; namePattern = Tcl_GetString(objv[i]); } else if ((c == 't') && (length > 1) && (strncmp(option, "tag", length) == 0)) { if ((i + 1) == objc) { goto missingArg; } i++; withTag = Tcl_GetString(objv[i]); } else if ((option[0] == '-') && (option[1] == '\0')) { break; } else { /* * Verify that the switch is actually an entry configuration option. */ if (Blt_ConfigureValueFromObj(interp, tvPtr->tkwin, bltTreeViewEntrySpecs, (char *)entryPtr, objv[i], 0) != TCL_OK) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, "bad switch \"", string, "\": must be -exact, -glob, -regexp, -name, -full, or -nonmatching", (char *)NULL); return TCL_ERROR; } if ((i + 1) == objc) { goto missingArg; } /* Save the option in the list of configuration options */ node = Blt_ListGetNode(options, (char *)objv[i]); if (node == NULL) { node = Blt_ListCreateNode(options, (char *)objv[i]); Blt_ListAppendNode(options, node); } i++; Blt_ListSetValue(node, Tcl_GetString(objv[i])); } } if ((namePattern != NULL) || (fullPattern != NULL) || (Blt_ListGetLength(options) > 0)) { /* * Search through the tree and look for nodes that match the * current spec. Apply the input procedure to each of the * matching nodes. */ for (entryPtr = tvPtr->rootPtr; entryPtr != NULL; entryPtr = Blt_TreeViewNextEntry(entryPtr, 0)) { if (namePattern != NULL) { result = (*compareProc) (interp, Blt_TreeNodeLabel(entryPtr->node), namePattern); if (result == invertMatch) { continue; /* Failed to match */ } } if (fullPattern != NULL) { Tcl_DString dString; Blt_TreeViewGetFullName(tvPtr, entryPtr, FALSE, &dString); result = (*compareProc) (interp, Tcl_DStringValue(&dString), fullPattern); Tcl_DStringFree(&dString); if (result == invertMatch) { continue; /* Failed to match */ } } if (withTag != NULL) { result = Blt_TreeHasTag(tvPtr->tree, entryPtr->node, withTag); if (result == invertMatch) { continue; /* Failed to match */ } } for (node = Blt_ListFirstNode(options); node != NULL; node = Blt_ListNextNode(node)) { objPtr = (Tcl_Obj *)Blt_ListGetKey(node); Tcl_ResetResult(interp); if (Blt_ConfigureValueFromObj(interp, tvPtr->tkwin, bltTreeViewEntrySpecs, (char *)entryPtr, objPtr, 0) != TCL_OK) { return TCL_ERROR; /* This shouldn't happen. */ } pattern = Blt_ListGetValue(node); objPtr = Tcl_GetObjResult(interp); result = (*compareProc)(interp, Tcl_GetString(objPtr), pattern); if (result == invertMatch) { continue; /* Failed to match */ } } /* Finally, apply the procedure to the node */ (*proc) (tvPtr, entryPtr); } Tcl_ResetResult(interp); Blt_ListDestroy(options); } /* * Apply the procedure to nodes that have been specified * individually. */ for ( /*empty*/ ; i < objc; i++) { if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[i], &info) != TCL_OK) { return TCL_ERROR; } for (entryPtr = Blt_TreeViewFirstTaggedEntry(&info); entryPtr != NULL; entryPtr = Blt_TreeViewNextTaggedEntry(&info)) { if ((*proc) (tvPtr, entryPtr) != TCL_OK) { return TCL_ERROR; } } } if (nonMatchPtr != NULL) { *nonMatchPtr = invertMatch; /* return "inverted search" status */ } return TCL_OK; missingArg: Blt_ListDestroy(options); Tcl_AppendResult(interp, "missing pattern for search option \"", objv[i], "\"", (char *)NULL); return TCL_ERROR; } static int FixSelectionsApplyProc(tvPtr, entryPtr) TreeView *tvPtr; TreeViewEntry *entryPtr; { if (entryPtr->flags & ENTRY_HIDDEN) { Blt_TreeViewDeselectEntry(tvPtr, entryPtr); if ((tvPtr->focusPtr != NULL) && (Blt_TreeIsAncestor(entryPtr->node, tvPtr->focusPtr->node))) { if (entryPtr != tvPtr->rootPtr) { entryPtr = Blt_TreeViewParentEntry(entryPtr); tvPtr->focusPtr = (entryPtr == NULL) ? tvPtr->focusPtr : entryPtr; Blt_SetFocusItem(tvPtr->bindTable, tvPtr->focusPtr, ITEM_ENTRY); } } if ((tvPtr->selAnchorPtr != NULL) && (Blt_TreeIsAncestor(entryPtr->node, tvPtr->selAnchorPtr->node))) { tvPtr->selMarkPtr = tvPtr->selAnchorPtr = NULL; } if ((tvPtr->activePtr != NULL) && (Blt_TreeIsAncestor(entryPtr->node, tvPtr->activePtr->node))) { tvPtr->activePtr = NULL; } Blt_TreeViewPruneSelection(tvPtr, entryPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * HideOp -- * * Hides one or more nodes. Nodes can be specified by their * inode, or by matching a name or data value pattern. By * default, the patterns are matched exactly. They can also * be matched using glob-style and regular expression rules. * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ static int HideOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { int status, nonmatching; status = SearchAndApplyToTree(tvPtr, interp, objc, objv, HideEntryApplyProc, &nonmatching); if (status != TCL_OK) { return TCL_ERROR; } /* * If this was an inverted search, scan back through the * tree and make sure that the parents for all visible * nodes are also visible. After all, if a node is supposed * to be visible, its parent can't be hidden. */ if (nonmatching) { Blt_TreeViewApply(tvPtr, tvPtr->rootPtr, MapAncestorsApplyProc, 0); } /* * Make sure that selections are cleared from any hidden * nodes. This wasn't done earlier--we had to delay it until * we fixed the visibility status for the parents. */ Blt_TreeViewApply(tvPtr, tvPtr->rootPtr, FixSelectionsApplyProc, 0); /* Hiding an entry only effects the visible nodes. */ tvPtr->flags |= (TV_LAYOUT | TV_SCROLL); Blt_TreeViewEventuallyRedraw(tvPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * ShowOp -- * * Mark one or more nodes to be exposed. Nodes can be specified * by their inode, or by matching a name or data value pattern. By * default, the patterns are matched exactly. They can also * be matched using glob-style and regular expression rules. * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ static int ShowOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { if (SearchAndApplyToTree(tvPtr, interp, objc, objv, ShowEntryApplyProc, (int *)NULL) != TCL_OK) { return TCL_ERROR; } tvPtr->flags |= (TV_LAYOUT | TV_SCROLL); Blt_TreeViewEventuallyRedraw(tvPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * IndexOp -- * * Converts one of more words representing indices of the entries * in the treeview widget to their respective serial identifiers. * * Results: * A standard Tcl result. Interp->result will contain the * identifier of each inode found. If an inode could not be found, * then the serial identifier will be the empty string. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int IndexOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { TreeViewEntry *entryPtr; char *string; TreeViewEntry *fromPtr; int usePath; usePath = FALSE; fromPtr = NULL; string = Tcl_GetString(objv[2]); if ((string[0] == '-') && (strcmp(string, "-path") == 0)) { usePath = TRUE; objv++, objc--; } if ((string[0] == '-') && (strcmp(string, "-at") == 0)) { if (Blt_TreeViewGetEntry(tvPtr, objv[3], &fromPtr) != TCL_OK) { return TCL_ERROR; } objv += 2, objc -= 2; } if (objc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " index ?-at tagOrId? ?-path? tagOrId\"", (char *)NULL); return TCL_ERROR; } tvPtr->fromPtr = fromPtr; if (tvPtr->fromPtr == NULL) { tvPtr->fromPtr = tvPtr->focusPtr; } if (tvPtr->fromPtr == NULL) { tvPtr->fromPtr = tvPtr->rootPtr; } if (usePath) { if (fromPtr == NULL) { fromPtr = tvPtr->rootPtr; } string = Tcl_GetString(objv[2]); entryPtr = FindPath(tvPtr, fromPtr, string); if (entryPtr != NULL) { Tcl_SetObjResult(interp, NodeToObj(entryPtr->node)); } } else { if ((GetEntryFromObj2(tvPtr, objv[2], &entryPtr) == TCL_OK) && (entryPtr != NULL)) { Tcl_SetObjResult(interp, NodeToObj(entryPtr->node)); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * InsertOp -- * * Add new entries into a hierarchy. If no node is specified, * new entries will be added to the root of the hierarchy. * *---------------------------------------------------------------------- */ static int InsertOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { Blt_TreeNode node, parent; int insertPos; int depth, count; char *path; Tcl_Obj *CONST *options; Tcl_Obj *listObjPtr; char **compArr; register char **p; register int n; TreeViewEntry *rootPtr; char *string; rootPtr = tvPtr->rootPtr; string = Tcl_GetString(objv[2]); if ((string[0] == '-') && (strcmp(string, "-at") == 0)) { if (objc > 2) { if (Blt_TreeViewGetEntry(tvPtr, objv[3], &rootPtr) != TCL_OK) { return TCL_ERROR; } objv += 2, objc -= 2; } else { Tcl_AppendResult(interp, "missing argument for \"-at\" flag", (char *)NULL); return TCL_ERROR; } } if (objc == 2) { Tcl_AppendResult(interp, "missing position argument", (char *)NULL); return TCL_ERROR; } if (Blt_GetPositionFromObj(interp, objv[2], &insertPos) != TCL_OK) { return TCL_ERROR; } node = NULL; objc -= 3, objv += 3; listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); while (objc > 0) { path = Tcl_GetString(objv[0]); objv++, objc--; /* * Count the option-value pairs that follow. Count until we * spot one that looks like an entry name (i.e. doesn't start * with a minus "-"). */ for (count = 0; count < objc; count += 2) { string = Tcl_GetString(objv[count]); if (string[0] != '-') { break; } } if (count > objc) { count = objc; } options = objv; objc -= count, objv += count; if (tvPtr->trimLeft != NULL) { register char *s1, *s2; /* Trim off leading character string if one exists. */ for (s1 = path, s2 = tvPtr->trimLeft; *s2 != '\0'; s2++, s1++) { if (*s1 != *s2) { break; } } if (*s2 == '\0') { path = s1; } } /* * Split the path and find the parent node of the path. */ compArr = &path; depth = 1; if (tvPtr->pathSep != SEPARATOR_NONE) { if (SplitPath(tvPtr, path, &depth, &compArr) != TCL_OK) { goto error; } if (depth == 0) { Blt_Free(compArr); continue; /* Root already exists. */ } } parent = rootPtr->node; depth--; /* Verify each component in the path preceding the tail. */ for (n = 0, p = compArr; n < depth; n++, p++) { node = Blt_TreeFindChild(parent, *p); if (node == NULL) { if ((tvPtr->flags & TV_FILL_ANCESTORS) == 0) { Tcl_AppendResult(interp, "can't find path component \"", *p, "\" in \"", path, "\"", (char *)NULL); goto error; } node = Blt_TreeCreateNode(tvPtr->tree, parent, *p, END); if (node == NULL) { goto error; } } parent = node; } node = NULL; if (((tvPtr->flags & TV_ALLOW_DUPLICATES) == 0) && (Blt_TreeFindChild(parent, *p) != NULL)) { Tcl_AppendResult(interp, "entry \"", *p, "\" already exists in \"", path, "\"", (char *)NULL); goto error; } node = Blt_TreeCreateNode(tvPtr->tree, parent, *p, insertPos); if (node == NULL) { goto error; } if (Blt_TreeViewCreateEntry(tvPtr, node, count, options, 0) != TCL_OK) { goto error; } if (compArr != &path) { Blt_Free(compArr); } Tcl_ListObjAppendElement(interp, listObjPtr, NodeToObj(node)); } tvPtr->flags |= (TV_LAYOUT | TV_SCROLL | TV_DIRTY | TV_RESORT); Blt_TreeViewEventuallyRedraw(tvPtr); Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; error: if (compArr != &path) { Blt_Free(compArr); } Tcl_DecrRefCount(listObjPtr); if (node != NULL) { DeleteNode(tvPtr, node); } return TCL_ERROR; } #ifdef notdef /* *---------------------------------------------------------------------- * * AddOp -- * * Add new entries into a hierarchy. If no node is specified, * new entries will be added to the root of the hierarchy. * *---------------------------------------------------------------------- */ static Blt_SwitchParseProc StringToChild; #define INSERT_BEFORE (ClientData)0 #define INSERT_AFTER (ClientData)1 static Blt_SwitchCustom beforeSwitch = { StringToChild, (Blt_SwitchFreeProc *)NULL, INSERT_BEFORE, }; static Blt_SwitchCustom afterSwitch = { StringToChild, (Blt_SwitchFreeProc *)NULL, INSERT_AFTER, }; typedef struct { int insertPos; Blt_TreeNode parent; } InsertData; static Blt_SwitchSpec insertSwitches[] = { {BLT_SWITCH_CUSTOM, "-after", Blt_Offset(InsertData, insertPos), 0, &afterSwitch}, {BLT_SWITCH_INT_NONNEGATIVE, "-at", Blt_Offset(InsertData, insertPos), 0}, {BLT_SWITCH_CUSTOM, "-before", Blt_Offset(InsertData, insertPos), 0, &beforeSwitch}, {BLT_SWITCH_END, NULL, 0, 0} }; static int AddOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { Blt_TreeNode node, parent; int insertPos; int depth, count; char *path; Tcl_Obj *CONST *options; Tcl_Obj *listObjPtr; char **compArr; register char **p; register int n; TreeViewEntry *rootPtr; char *string; memset(&data, 0, sizeof(data)); data.maxDepth = -1; data.cmdPtr = cmdPtr; /* Process any leading switches */ i = Blt_ProcessObjSwitches(interp, addSwitches, objc - 2, objv + 2, (char *)&data, BLT_CONFIG_OBJV_PARTIAL); if (i < 0) { return TCL_ERROR; } i += 2; /* Should have at the starting node */ if (i >= objc) { Tcl_AppendResult(interp, "starting node argument is missing", (char *)NULL); return TCL_ERROR; } if (Blt_TreeViewGetEntry(tvPtr, objv[i], &rootPtr) != TCL_OK) { return TCL_ERROR; } objv += i, objc -= i; node = NULL; /* Process sections of path ?options? */ listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); while (objc > 0) { path = Tcl_GetString(objv[0]); objv++, objc--; /* * Count the option-value pairs that follow. Count until we * spot one that looks like an entry name (i.e. doesn't start * with a minus "-"). */ for (count = 0; count < objc; count += 2) { if (!Blt_ObjIsOption(bltTreeViewEntrySpecs, objv[count], 0)) { break; } } if (count > objc) { count = objc; } options = objv; objc -= count, objv += count; if (tvPtr->trimLeft != NULL) { register char *s1, *s2; /* Trim off leading character string if one exists. */ for (s1 = path, s2 = tvPtr->trimLeft; *s2 != '\0'; s2++, s1++) { if (*s1 != *s2) { break; } } if (*s2 == '\0') { path = s1; } } /* * Split the path and find the parent node of the path. */ compArr = &path; depth = 1; if (tvPtr->pathSep != SEPARATOR_NONE) { if (SplitPath(tvPtr, path, &depth, &compArr) != TCL_OK) { goto error; } if (depth == 0) { Blt_Free(compArr); continue; /* Root already exists. */ } } parent = rootPtr->node; depth--; /* Verify each component in the path preceding the tail. */ for (n = 0, p = compArr; n < depth; n++, p++) { node = Blt_TreeFindChild(parent, *p); if (node == NULL) { if ((tvPtr->flags & TV_FILL_ANCESTORS) == 0) { Tcl_AppendResult(interp, "can't find path component \"", *p, "\" in \"", path, "\"", (char *)NULL); goto error; } node = Blt_TreeCreateNode(tvPtr->tree, parent, *p, END); if (node == NULL) { goto error; } } parent = node; } node = NULL; if (((tvPtr->flags & TV_ALLOW_DUPLICATES) == 0) && (Blt_TreeFindChild(parent, *p) != NULL)) { Tcl_AppendResult(interp, "entry \"", *p, "\" already exists in \"", path, "\"", (char *)NULL); goto error; } node = Blt_TreeCreateNode(tvPtr->tree, parent, *p, insertPos); if (node == NULL) { goto error; } if (Blt_TreeViewCreateEntry(tvPtr, node, count, options, 0) != TCL_OK) { goto error; } if (compArr != &path) { Blt_Free(compArr); } Tcl_ListObjAppendElement(interp, listObjPtr, NodeToObj(node)); } tvPtr->flags |= (TV_LAYOUT | TV_SCROLL | TV_DIRTY | TV_RESORT); Blt_TreeViewEventuallyRedraw(tvPtr); Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; error: if (compArr != &path) { Blt_Free(compArr); } Tcl_DecrRefCount(listObjPtr); if (node != NULL) { DeleteNode(tvPtr, node); } return TCL_ERROR; } #endif /* *---------------------------------------------------------------------- * * DeleteOp -- * * Deletes nodes from the hierarchy. Deletes one or more entries * (except root). In all cases, nodes are removed recursively. * * Note: There's no need to explicitly clean up Entry structures * or request a redraw of the widget. When a node is * deleted in the tree, all of the Tcl_Objs representing * the various data fields are also removed. The treeview * widget store the Entry structure in a data field. So it's * automatically cleaned up when FreeEntryInternalRep is * called. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int DeleteOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { TreeViewTagInfo info; TreeViewEntry *entryPtr; register int i; for (i = 2; i < objc; i++) { if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[i], &info) != TCL_OK) { return TCL_ERROR; } for (entryPtr = Blt_TreeViewFirstTaggedEntry(&info); entryPtr != NULL; entryPtr = Blt_TreeViewNextTaggedEntry(&info)) { if (entryPtr == tvPtr->rootPtr) { Blt_TreeNode next, node; /* * Don't delete the root node. We implicitly assume * that even an empty tree has at a root. Instead * delete all the children regardless if they're closed * or hidden. */ for (node = Blt_TreeFirstChild(entryPtr->node); node != NULL; node = next) { next = Blt_TreeNextSibling(node); DeleteNode(tvPtr, node); } } else { DeleteNode(tvPtr, entryPtr->node); } } } return TCL_OK; } /* *---------------------------------------------------------------------- * * MoveOp -- * * Move an entry into a new location in the hierarchy. * * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int MoveOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { Blt_TreeNode parent; TreeViewEntry *srcPtr, *destPtr; char c; int action; char *string; TreeViewTagInfo info; #define MOVE_INTO (1<<0) #define MOVE_BEFORE (1<<1) #define MOVE_AFTER (1<<2) if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[2], &info) != TCL_OK) { return TCL_ERROR; } string = Tcl_GetString(objv[3]); c = string[0]; if ((c == 'i') && (strcmp(string, "into") == 0)) { action = MOVE_INTO; } else if ((c == 'b') && (strcmp(string, "before") == 0)) { action = MOVE_BEFORE; } else if ((c == 'a') && (strcmp(string, "after") == 0)) { action = MOVE_AFTER; } else { Tcl_AppendResult(interp, "bad position \"", string, "\": should be into, before, or after", (char *)NULL); return TCL_ERROR; } if (Blt_TreeViewGetEntry(tvPtr, objv[4], &destPtr) != TCL_OK) { return TCL_ERROR; } for (srcPtr = Blt_TreeViewFirstTaggedEntry(&info); srcPtr != NULL; srcPtr = Blt_TreeViewNextTaggedEntry(&info)) { /* Verify they aren't ancestors. */ if (Blt_TreeIsAncestor(srcPtr->node, destPtr->node)) { Tcl_DString dString; char *path; path = Blt_TreeViewGetFullName(tvPtr, srcPtr, 1, &dString); Tcl_AppendResult(interp, "can't move node: \"", path, "\" is an ancestor of \"", Tcl_GetString(objv[4]), "\"", (char *)NULL); Tcl_DStringFree(&dString); return TCL_ERROR; } parent = Blt_TreeNodeParent(destPtr->node); if (parent == NULL) { action = MOVE_INTO; } switch (action) { case MOVE_INTO: Blt_TreeMoveNode(tvPtr->tree, srcPtr->node, destPtr->node, (Blt_TreeNode)NULL); break; case MOVE_BEFORE: Blt_TreeMoveNode(tvPtr->tree, srcPtr->node, parent, destPtr->node); break; case MOVE_AFTER: Blt_TreeMoveNode(tvPtr->tree, srcPtr->node, parent, Blt_TreeNextSibling(destPtr->node)); break; } } tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT); Blt_TreeViewEventuallyRedraw(tvPtr); return TCL_OK; } /*ARGSUSED*/ static int NearestOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { TreeViewButton *buttonPtr = &tvPtr->button; int x, y; /* Screen coordinates of the test point. */ register TreeViewEntry *entryPtr; int isRoot; char *string; isRoot = FALSE; string = Tcl_GetString(objv[2]); if (strcmp("-root", string) == 0) { isRoot = TRUE; objv++, objc--; } if (objc < 4) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " ", Tcl_GetString(objv[1]), " ?-root? x y\"", (char *)NULL); return TCL_ERROR; } if ((Tk_GetPixelsFromObj(interp, tvPtr->tkwin, objv[2], &x) != TCL_OK) || (Tk_GetPixelsFromObj(interp, tvPtr->tkwin, objv[3], &y) != TCL_OK)) { return TCL_ERROR; } if (tvPtr->nVisible == 0) { return TCL_OK; } if (isRoot) { int rootX, rootY; Tk_GetRootCoords(tvPtr->tkwin, &rootX, &rootY); x -= rootX; y -= rootY; } entryPtr = Blt_TreeViewNearestEntry(tvPtr, x, y, TRUE); if (entryPtr == NULL) { return TCL_OK; } x = WORLDX(tvPtr, x); y = WORLDY(tvPtr, y); if (objc > 4) { char *where; int labelX, labelY, depth; TreeViewIcon icon; where = ""; if (entryPtr->flags & ENTRY_HAS_BUTTON) { int buttonX, buttonY; buttonX = entryPtr->worldX + entryPtr->buttonX; buttonY = entryPtr->worldY + entryPtr->buttonY; if ((x >= buttonX) && (x < (buttonX + buttonPtr->width)) && (y >= buttonY) && (y < (buttonY + buttonPtr->height))) { where = "button"; goto done; } } depth = DEPTH(tvPtr, entryPtr->node); icon = Blt_TreeViewGetEntryIcon(tvPtr, entryPtr); if (icon != NULL) { int iconWidth, iconHeight, entryHeight; int iconX, iconY; entryHeight = MAX(entryPtr->iconHeight, tvPtr->button.height); iconHeight = TreeViewIconHeight(icon); iconWidth = TreeViewIconWidth(icon); iconX = entryPtr->worldX + ICONWIDTH(depth); iconY = entryPtr->worldY; if (tvPtr->flatView) { iconX += (ICONWIDTH(0) - iconWidth) / 2; } else { iconX += (ICONWIDTH(depth + 1) - iconWidth) / 2; } iconY += (entryHeight - iconHeight) / 2; if ((x >= iconX) && (x <= (iconX + iconWidth)) && (y >= iconY) && (y < (iconY + iconHeight))) { where = "icon"; goto done; } } labelX = entryPtr->worldX + ICONWIDTH(depth); labelY = entryPtr->worldY; if (!tvPtr->flatView) { labelX += ICONWIDTH(depth + 1) + 4; } if ((x >= labelX) && (x < (labelX + entryPtr->labelWidth)) && (y >= labelY) && (y < (labelY + entryPtr->labelHeight))) { where = "label"; } done: if (Tcl_SetVar(interp, Tcl_GetString(objv[4]), where, TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } } Tcl_SetObjResult(interp, NodeToObj(entryPtr->node)); return TCL_OK; } /*ARGSUSED*/ static int OpenOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; /* Not used. */ int objc; Tcl_Obj *CONST *objv; { TreeViewEntry *entryPtr; TreeViewTagInfo info; int recurse, result; register int i; recurse = FALSE; if (objc > 2) { int length; char *string; string = Tcl_GetStringFromObj(objv[2], &length); if ((string[0] == '-') && (length > 1) && (strncmp(string, "-recurse", length) == 0)) { objv++, objc--; recurse = TRUE; } } for (i = 2; i < objc; i++) { if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[i], &info) != TCL_OK) { return TCL_ERROR; } for (entryPtr = Blt_TreeViewFirstTaggedEntry(&info); entryPtr != NULL; entryPtr = Blt_TreeViewNextTaggedEntry(&info)) { if (recurse) { result = Blt_TreeViewApply(tvPtr, entryPtr, Blt_TreeViewOpenEntry, 0); } else { result = Blt_TreeViewOpenEntry(tvPtr, entryPtr); } if (result != TCL_OK) { return TCL_ERROR; } /* Make sure ancestors of this node aren't hidden. */ MapAncestors(tvPtr, entryPtr); } } /*FIXME: This is only for flattened entries. */ tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT); Blt_TreeViewEventuallyRedraw(tvPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * RangeOp -- * * Returns the node identifiers in a given range. * *---------------------------------------------------------------------- */ static int RangeOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { TreeViewEntry *entryPtr, *firstPtr, *lastPtr; unsigned int mask; int length; Tcl_Obj *listObjPtr, *objPtr; char *string; mask = 0; string = Tcl_GetStringFromObj(objv[2], &length); if ((string[0] == '-') && (length > 1) && (strncmp(string, "-open", length) == 0)) { objv++, objc--; mask |= ENTRY_CLOSED; } if (Blt_TreeViewGetEntry(tvPtr, objv[2], &firstPtr) != TCL_OK) { return TCL_ERROR; } if (objc > 3) { if (Blt_TreeViewGetEntry(tvPtr, objv[3], &lastPtr) != TCL_OK) { return TCL_ERROR; } } else { lastPtr = LastEntry(tvPtr, firstPtr, mask); } if (mask & ENTRY_CLOSED) { if (firstPtr->flags & ENTRY_HIDDEN) { Tcl_AppendResult(interp, "first node \"", Tcl_GetString(objv[2]), "\" is hidden.", (char *)NULL); return TCL_ERROR; } if (lastPtr->flags & ENTRY_HIDDEN) { Tcl_AppendResult(interp, "last node \"", Tcl_GetString(objv[3]), "\" is hidden.", (char *)NULL); return TCL_ERROR; } } /* * The relative order of the first/last markers determines the * direction. */ listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); if (Blt_TreeIsBefore(lastPtr->node, firstPtr->node)) { for (entryPtr = lastPtr; entryPtr != NULL; entryPtr = Blt_TreeViewPrevEntry(entryPtr, mask)) { objPtr = NodeToObj(entryPtr->node); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); if (entryPtr == firstPtr) { break; } } } else { for (entryPtr = firstPtr; entryPtr != NULL; entryPtr = Blt_TreeViewNextEntry(entryPtr, mask)) { objPtr = NodeToObj(entryPtr->node); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); if (entryPtr == lastPtr) { break; } } } Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * ScanOp -- * * Implements the quick scan. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ScanOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { int x, y; char c; int length; int oper; char *string; Tk_Window tkwin; #define SCAN_MARK 1 #define SCAN_DRAGTO 2 string = Tcl_GetStringFromObj(objv[2], &length); c = string[0]; tkwin = tvPtr->tkwin; if ((c == 'm') && (strncmp(string, "mark", length) == 0)) { oper = SCAN_MARK; } else if ((c == 'd') && (strncmp(string, "dragto", length) == 0)) { oper = SCAN_DRAGTO; } else { Tcl_AppendResult(interp, "bad scan operation \"", string, "\": should be either \"mark\" or \"dragto\"", (char *)NULL); return TCL_ERROR; } if ((Blt_GetPixelsFromObj(interp, tkwin, objv[3], 0, &x) != TCL_OK) || (Blt_GetPixelsFromObj(interp, tkwin, objv[4], 0, &y) != TCL_OK)) { return TCL_ERROR; } if (oper == SCAN_MARK) { tvPtr->scanAnchorX = x; tvPtr->scanAnchorY = y; tvPtr->scanX = tvPtr->xOffset; tvPtr->scanY = tvPtr->yOffset; } else { int worldX, worldY; int dx, dy; dx = tvPtr->scanAnchorX - x; dy = tvPtr->scanAnchorY - y; worldX = tvPtr->scanX + (10 * dx); worldY = tvPtr->scanY + (10 * dy); if (worldX < 0) { worldX = 0; } else if (worldX >= tvPtr->worldWidth) { worldX = tvPtr->worldWidth - tvPtr->xScrollUnits; } if (worldY < 0) { worldY = 0; } else if (worldY >= tvPtr->worldHeight) { worldY = tvPtr->worldHeight - tvPtr->yScrollUnits; } tvPtr->xOffset = worldX; tvPtr->yOffset = worldY; tvPtr->flags |= TV_SCROLL; Blt_TreeViewEventuallyRedraw(tvPtr); } return TCL_OK; } /*ARGSUSED*/ static int SeeOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; /* Not used. */ int objc; Tcl_Obj *CONST *objv; { TreeViewEntry *entryPtr; int width, height; int x, y; Tk_Anchor anchor; int left, right, top, bottom; char *string; string = Tcl_GetString(objv[2]); anchor = TK_ANCHOR_W; /* Default anchor is West */ if ((string[0] == '-') && (strcmp(string, "-anchor") == 0)) { if (objc == 3) { Tcl_AppendResult(interp, "missing \"-anchor\" argument", (char *)NULL); return TCL_ERROR; } if (Tk_GetAnchorFromObj(interp, objv[3], &anchor) != TCL_OK) { return TCL_ERROR; } objc -= 2, objv += 2; } if (objc == 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", objv[0], "see ?-anchor anchor? tagOrId\"", (char *)NULL); return TCL_ERROR; } if (GetEntryFromObj(tvPtr, objv[2], &entryPtr) != TCL_OK) { return TCL_ERROR; } if (entryPtr == NULL) { return TCL_OK; } if (entryPtr->flags & ENTRY_HIDDEN) { MapAncestors(tvPtr, entryPtr); tvPtr->flags |= TV_SCROLL; /* * If the entry wasn't previously exposed, its world coordinates * aren't likely to be valid. So re-compute the layout before * we try to see the viewport to the entry's location. */ Blt_TreeViewComputeLayout(tvPtr); } width = VPORTWIDTH(tvPtr); height = VPORTHEIGHT(tvPtr); /* * XVIEW: If the entry is left or right of the current view, adjust * the offset. If the entry is nearby, adjust the view just * a bit. Otherwise, center the entry. */ left = tvPtr->xOffset; right = tvPtr->xOffset + width; switch (anchor) { case TK_ANCHOR_W: case TK_ANCHOR_NW: case TK_ANCHOR_SW: x = 0; break; case TK_ANCHOR_E: case TK_ANCHOR_NE: case TK_ANCHOR_SE: x = entryPtr->worldX + entryPtr->width + ICONWIDTH(DEPTH(tvPtr, entryPtr->node)) - width; break; default: if (entryPtr->worldX < left) { x = entryPtr->worldX; } else if ((entryPtr->worldX + entryPtr->width) > right) { x = entryPtr->worldX + entryPtr->width - width; } else { x = tvPtr->xOffset; } break; } /* * YVIEW: If the entry is above or below the current view, adjust * the offset. If the entry is nearby, adjust the view just * a bit. Otherwise, center the entry. */ top = tvPtr->yOffset; bottom = tvPtr->yOffset + height; switch (anchor) { case TK_ANCHOR_N: y = tvPtr->yOffset; break; case TK_ANCHOR_NE: case TK_ANCHOR_NW: y = entryPtr->worldY - (height / 2); break; case TK_ANCHOR_S: case TK_ANCHOR_SE: case TK_ANCHOR_SW: y = entryPtr->worldY + entryPtr->height - height; break; default: if (entryPtr->worldY < top) { y = entryPtr->worldY; } else if ((entryPtr->worldY + entryPtr->height) > bottom) { y = entryPtr->worldY + entryPtr->height - height; } else { y = tvPtr->yOffset; } break; } if ((y != tvPtr->yOffset) || (x != tvPtr->xOffset)) { /* tvPtr->xOffset = x; */ tvPtr->yOffset = y; tvPtr->flags |= TV_SCROLL; } Blt_TreeViewEventuallyRedraw(tvPtr); return TCL_OK; } void Blt_TreeViewClearSelection(tvPtr) TreeView *tvPtr; { Blt_DeleteHashTable(&tvPtr->selectTable); Blt_InitHashTable(&tvPtr->selectTable, BLT_ONE_WORD_KEYS); Blt_ChainReset(tvPtr->selChainPtr); Blt_TreeViewEventuallyRedraw(tvPtr); if (tvPtr->selectCmd != NULL) { EventuallyInvokeSelectCmd(tvPtr); } } /* *---------------------------------------------------------------------- * * LostSelection -- * * This procedure is called back by Tk when the selection is grabbed * away. * * Results: * None. * * Side effects: * The existing selection is unhighlighted, and the window is * marked as not containing a selection. * *---------------------------------------------------------------------- */ static void LostSelection(clientData) ClientData clientData; /* Information about the widget. */ { TreeView *tvPtr = clientData; if ((tvPtr->flags & TV_SELECT_EXPORT) == 0) { return; } Blt_TreeViewClearSelection(tvPtr); } /* *---------------------------------------------------------------------- * * SelectRange -- * * Sets the selection flag for a range of nodes. The range is * determined by two pointers which designate the first/last * nodes of the range. * * Results: * Always returns TCL_OK. * *---------------------------------------------------------------------- */ static int SelectRange(tvPtr, fromPtr, toPtr) TreeView *tvPtr; TreeViewEntry *fromPtr, *toPtr; { if (tvPtr->flatView) { register int i; if (fromPtr->flatIndex > toPtr->flatIndex) { for (i = fromPtr->flatIndex; i >= toPtr->flatIndex; i--) { SelectEntryApplyProc(tvPtr, tvPtr->flatArr[i]); } } else { for (i = fromPtr->flatIndex; i <= toPtr->flatIndex; i++) { SelectEntryApplyProc(tvPtr, tvPtr->flatArr[i]); } } } else { TreeViewEntry *entryPtr; TreeViewIterProc *proc; /* From the range determine the direction to select entries. */ proc = (Blt_TreeIsBefore(toPtr->node, fromPtr->node)) ? Blt_TreeViewPrevEntry : Blt_TreeViewNextEntry; for (entryPtr = fromPtr; entryPtr != NULL; entryPtr = (*proc)(entryPtr, ENTRY_MASK)) { SelectEntryApplyProc(tvPtr, entryPtr); if (entryPtr == toPtr) { break; } } } return TCL_OK; } /* *---------------------------------------------------------------------- * * SelectionAnchorOp -- * * Sets the selection anchor to the element given by a index. * The selection anchor is the end of the selection that is fixed * while dragging out a selection with the mouse. The index * "anchor" may be used to refer to the anchor element. * * Results: * None. * * Side effects: * The selection changes. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int SelectionAnchorOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; /* Not used. */ int objc; /* Not used. */ Tcl_Obj *CONST *objv; { TreeViewEntry *entryPtr; if (GetEntryFromObj(tvPtr, objv[3], &entryPtr) != TCL_OK) { return TCL_ERROR; } /* Set both the anchor and the mark. Indicates that a single entry * is selected. */ tvPtr->selAnchorPtr = entryPtr; tvPtr->selMarkPtr = NULL; if (entryPtr != NULL) { Tcl_SetObjResult(interp, NodeToObj(entryPtr->node)); } Blt_TreeViewEventuallyRedraw(tvPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * SelectionClearallOp * * Clears the entire selection. * * Results: * None. * * Side effects: * The selection changes. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int SelectionClearallOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; /* Not used. */ int objc; /* Not used. */ Tcl_Obj *CONST *objv; /* Not used. */ { Blt_TreeViewClearSelection(tvPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * SelectionIncludesOp * * Returns 1 if the element indicated by index is currently * selected, 0 if it isn't. * * Results: * None. * * Side effects: * The selection changes. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int SelectionIncludesOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { TreeViewEntry *entryPtr; int bool; if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK) { return TCL_ERROR; } bool = Blt_TreeViewEntryIsSelected(tvPtr, entryPtr); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(bool)); return TCL_OK; } /* *---------------------------------------------------------------------- * * SelectionMarkOp -- * * Sets the selection mark to the element given by a index. * The selection anchor is the end of the selection that is movable * while dragging out a selection with the mouse. The index * "mark" may be used to refer to the anchor element. * * Results: * None. * * Side effects: * The selection changes. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int SelectionMarkOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; /* Not used. */ int objc; /* Not used. */ Tcl_Obj *CONST *objv; { TreeViewEntry *entryPtr; if (GetEntryFromObj(tvPtr, objv[3], &entryPtr) != TCL_OK) { return TCL_ERROR; } if (tvPtr->selAnchorPtr == NULL) { Tcl_AppendResult(interp, "selection anchor must be set first", (char *)NULL); return TCL_ERROR; } if (tvPtr->selMarkPtr != entryPtr) { Blt_ChainLink *linkPtr, *nextPtr; TreeViewEntry *selectPtr; /* Deselect entry from the list all the way back to the anchor. */ for (linkPtr = Blt_ChainLastLink(tvPtr->selChainPtr); linkPtr != NULL; linkPtr = nextPtr) { nextPtr = Blt_ChainPrevLink(linkPtr); selectPtr = Blt_ChainGetValue(linkPtr); if (selectPtr == tvPtr->selAnchorPtr) { break; } Blt_TreeViewDeselectEntry(tvPtr, selectPtr); } tvPtr->flags &= ~TV_SELECT_MASK; tvPtr->flags |= TV_SELECT_SET; SelectRange(tvPtr, tvPtr->selAnchorPtr, entryPtr); Tcl_SetObjResult(interp, NodeToObj(entryPtr->node)); tvPtr->selMarkPtr = entryPtr; Blt_TreeViewEventuallyRedraw(tvPtr); if (tvPtr->selectCmd != NULL) { EventuallyInvokeSelectCmd(tvPtr); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * SelectionPresentOp * * Returns 1 if there is a selection and 0 if it isn't. * * Results: * A standard Tcl result. interp->result will contain a * boolean string indicating if there is a selection. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int SelectionPresentOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { int bool; bool = (Blt_ChainGetLength(tvPtr->selChainPtr) > 0); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(bool)); return TCL_OK; } /* *---------------------------------------------------------------------- * * SelectionSetOp * * Selects, deselects, or toggles all of the elements in the * range between first and last, inclusive, without affecting the * selection state of elements outside that range. * * Results: * None. * * Side effects: * The selection changes. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int SelectionSetOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { TreeViewEntry *firstPtr, *lastPtr; char *string; tvPtr->flags &= ~TV_SELECT_MASK; string = Tcl_GetString(objv[2]); switch (string[0]) { case 's': tvPtr->flags |= TV_SELECT_SET; break; case 'c': tvPtr->flags |= TV_SELECT_CLEAR; break; case 't': tvPtr->flags |= TV_SELECT_TOGGLE; break; } if (Blt_TreeViewGetEntry(tvPtr, objv[3], &firstPtr) != TCL_OK) { return TCL_ERROR; } if ((firstPtr->flags & ENTRY_HIDDEN) && (!(tvPtr->flags & TV_SELECT_CLEAR))) { Tcl_AppendResult(interp, "can't select hidden node \"", Tcl_GetString(objv[3]), "\"", (char *)NULL); return TCL_ERROR; } lastPtr = firstPtr; if (objc > 4) { if (Blt_TreeViewGetEntry(tvPtr, objv[4], &lastPtr) != TCL_OK) { return TCL_ERROR; } if ((lastPtr->flags & ENTRY_HIDDEN) && (!(tvPtr->flags & TV_SELECT_CLEAR))) { Tcl_AppendResult(interp, "can't select hidden node \"", Tcl_GetString(objv[4]), "\"", (char *)NULL); return TCL_ERROR; } } if (firstPtr == lastPtr) { SelectEntryApplyProc(tvPtr, firstPtr); } else { SelectRange(tvPtr, firstPtr, lastPtr); } /* Set both the anchor and the mark. Indicates that a single entry * is selected. */ if (tvPtr->selAnchorPtr == NULL) { tvPtr->selAnchorPtr = firstPtr; } if (tvPtr->flags & TV_SELECT_EXPORT) { Tk_OwnSelection(tvPtr->tkwin, XA_PRIMARY, LostSelection, tvPtr); } Blt_TreeViewEventuallyRedraw(tvPtr); if (tvPtr->selectCmd != NULL) { EventuallyInvokeSelectCmd(tvPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * SelectionOp -- * * This procedure handles the individual options for text * selections. The selected text is designated by start and end * indices into the text pool. The selected segment has both a * anchored and unanchored ends. * * Results: * None. * * Side effects: * The selection changes. * *---------------------------------------------------------------------- */ static Blt_OpSpec selectionOps[] = { {"anchor", 1, (Blt_Op)SelectionAnchorOp, 4, 4, "tagOrId",}, {"clear", 5, (Blt_Op)SelectionSetOp, 4, 5, "first ?last?",}, {"clearall", 6, (Blt_Op)SelectionClearallOp, 3, 3, "",}, {"includes", 1, (Blt_Op)SelectionIncludesOp, 4, 4, "tagOrId",}, {"mark", 1, (Blt_Op)SelectionMarkOp, 4, 4, "tagOrId",}, {"present", 1, (Blt_Op)SelectionPresentOp, 3, 3, "",}, {"set", 1, (Blt_Op)SelectionSetOp, 4, 5, "first ?last?",}, {"toggle", 1, (Blt_Op)SelectionSetOp, 4, 5, "first ?last?",}, }; static int nSelectionOps = sizeof(selectionOps) / sizeof(Blt_OpSpec); static int SelectionOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { Blt_Op proc; int result; proc = Blt_GetOpFromObj(interp, nSelectionOps, selectionOps, BLT_OP_ARG2, objc, objv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (tvPtr, interp, objc, objv); return result; } /* *---------------------------------------------------------------------- * * TagForgetOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TagForgetOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { register int i; for (i = 3; i < objc; i++) { Blt_TreeForgetTag(tvPtr->tree, Tcl_GetString(objv[i])); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TagNamesOp -- * *---------------------------------------------------------------------- */ static int TagNamesOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { Tcl_Obj *listObjPtr, *objPtr; listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); objPtr = Tcl_NewStringObj("all", -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); if (objc == 3) { Blt_HashEntry *hPtr; Blt_HashSearch cursor; Blt_TreeTagEntry *tPtr; objPtr = Tcl_NewStringObj("root", -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); for (hPtr = Blt_TreeFirstTag(tvPtr->tree, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tPtr = Blt_GetHashValue(hPtr); objPtr = Tcl_NewStringObj(tPtr->tagName, -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } } else { register int i; TreeViewEntry *entryPtr; Blt_List list; Blt_ListNode listNode; for (i = 3; i < objc; i++) { if (Blt_TreeViewGetEntry(tvPtr, objv[i], &entryPtr) != TCL_OK) { return TCL_ERROR; } list = Blt_ListCreate(BLT_ONE_WORD_KEYS); Blt_TreeViewGetTags(interp, tvPtr, entryPtr, list); for (listNode = Blt_ListFirstNode(list); listNode != NULL; listNode = Blt_ListNextNode(listNode)) { objPtr = Tcl_NewStringObj(Blt_ListGetKey(listNode), -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } Blt_ListDestroy(list); } } Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * TagNodesOp -- * *---------------------------------------------------------------------- */ static int TagNodesOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { Blt_HashEntry *hPtr; Blt_HashSearch cursor; Blt_HashTable nodeTable; Blt_TreeNode node; TreeViewTagInfo info; Tcl_Obj *listObjPtr; Tcl_Obj *objPtr; TreeViewEntry *entryPtr; int isNew; register int i; Blt_InitHashTable(&nodeTable, BLT_ONE_WORD_KEYS); for (i = 3; i < objc; i++) { if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[i], &info) != TCL_OK) { return TCL_ERROR; } for (entryPtr = Blt_TreeViewFirstTaggedEntry(&info); entryPtr != NULL; entryPtr = Blt_TreeViewNextTaggedEntry(&info)) { Blt_CreateHashEntry(&nodeTable, (char *)entryPtr->node, &isNew); } } listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); for (hPtr = Blt_FirstHashEntry(&nodeTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { node = (Blt_TreeNode)Blt_GetHashKey(&nodeTable, hPtr); objPtr = Tcl_NewIntObj(Blt_TreeNodeId(node)); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } Tcl_SetObjResult(interp, listObjPtr); Blt_DeleteHashTable(&nodeTable); return TCL_OK; } /* *---------------------------------------------------------------------- * * TagAddOp -- * *---------------------------------------------------------------------- */ static int TagAddOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { TreeViewEntry *entryPtr; register int i; char *tagName; TreeViewTagInfo info; tagName = Tcl_GetString(objv[3]); tvPtr->fromPtr = NULL; if (strcmp(tagName, "root") == 0) { Tcl_AppendResult(interp, "can't add reserved tag \"", tagName, "\"", (char *)NULL); return TCL_ERROR; } if (isdigit(UCHAR(tagName[0]))) { Tcl_AppendResult(interp, "invalid tag \"", tagName, "\": can't start with digit", (char *)NULL); return TCL_ERROR; } if (tagName[0] == '@') { Tcl_AppendResult(tvPtr->interp, "invalid tag \"", tagName, "\": can't start with \"@\"", (char *)NULL); return TCL_ERROR; } if (GetEntryFromSpecialId(tvPtr, tagName, &entryPtr) == TCL_OK) { Tcl_AppendResult(interp, "invalid tag \"", tagName, "\": is a special id", (char *)NULL); return TCL_ERROR; } for (i = 4; i < objc; i++) { if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[i], &info) != TCL_OK) { return TCL_ERROR; } for (entryPtr = Blt_TreeViewFirstTaggedEntry(&info); entryPtr != NULL; entryPtr = Blt_TreeViewNextTaggedEntry(&info)) { if (AddTag(tvPtr, entryPtr->node, tagName) != TCL_OK) { return TCL_ERROR; } } } return TCL_OK; } /* *---------------------------------------------------------------------- * * TagDeleteOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TagDeleteOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; /* Not used. */ int objc; Tcl_Obj *CONST *objv; { char *tagName; Blt_HashTable *tablePtr; TreeViewTagInfo info; tagName = Tcl_GetString(objv[3]); tablePtr = Blt_TreeTagHashTable(tvPtr->tree, tagName); if (tablePtr != NULL) { register int i; Blt_HashEntry *hPtr; TreeViewEntry *entryPtr; for (i = 4; i < objc; i++) { if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[i], &info)!= TCL_OK) { return TCL_ERROR; } for (entryPtr = Blt_TreeViewFirstTaggedEntry(&info); entryPtr != NULL; entryPtr = Blt_TreeViewNextTaggedEntry(&info)) { hPtr = Blt_FindHashEntry(tablePtr, (char *)entryPtr->node); if (hPtr != NULL) { Blt_DeleteHashEntry(tablePtr, hPtr); } } } } return TCL_OK; } /* *---------------------------------------------------------------------- * * TagOp -- * *---------------------------------------------------------------------- */ static Blt_OpSpec tagOps[] = { {"add", 1, (Blt_Op)TagAddOp, 5, 0, "tag id...",}, {"delete", 2, (Blt_Op)TagDeleteOp, 5, 0, "tag id...",}, {"forget", 1, (Blt_Op)TagForgetOp, 4, 0, "tag...",}, {"names", 2, (Blt_Op)TagNamesOp, 3, 0, "?id...?",}, {"nodes", 2, (Blt_Op)TagNodesOp, 4, 0, "tag ?tag...?",}, }; static int nTagOps = sizeof(tagOps) / sizeof(Blt_OpSpec); static int TagOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { Blt_Op proc; int result; proc = Blt_GetOpFromObj(interp, nTagOps, tagOps, BLT_OP_ARG2, objc, objv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc)(tvPtr, interp, objc, objv); return result; } /*ARGSUSED*/ static int ToggleOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; /* Not used. */ int objc; Tcl_Obj *CONST *objv; { TreeViewEntry *entryPtr; TreeViewTagInfo info; if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[2], &info) != TCL_OK) { return TCL_ERROR; } for (entryPtr = Blt_TreeViewFirstTaggedEntry(&info); entryPtr != NULL; entryPtr = Blt_TreeViewNextTaggedEntry(&info)) { if (entryPtr == NULL) { return TCL_OK; } if (entryPtr->flags & ENTRY_CLOSED) { Blt_TreeViewOpenEntry(tvPtr, entryPtr); } else { Blt_TreeViewPruneSelection(tvPtr, entryPtr); if ((tvPtr->focusPtr != NULL) && (Blt_TreeIsAncestor(entryPtr->node, tvPtr->focusPtr->node))) { tvPtr->focusPtr = entryPtr; Blt_SetFocusItem(tvPtr->bindTable, tvPtr->focusPtr, ITEM_ENTRY); } if ((tvPtr->selAnchorPtr != NULL) && (Blt_TreeIsAncestor(entryPtr->node, tvPtr->selAnchorPtr->node))) { tvPtr->selAnchorPtr = NULL; } Blt_TreeViewCloseEntry(tvPtr, entryPtr); } } tvPtr->flags |= TV_SCROLL; Blt_TreeViewEventuallyRedraw(tvPtr); return TCL_OK; } static int XViewOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { int width, worldWidth; width = VPORTWIDTH(tvPtr); worldWidth = tvPtr->worldWidth; if (objc == 2) { double fract; Tcl_Obj *listObjPtr; /* * Note that we are bounding the fractions between 0.0 and 1.0 * to support the "canvas"-style of scrolling. */ listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); fract = (double)tvPtr->xOffset / worldWidth; fract = CLAMP(fract, 0.0, 1.0); Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(fract)); fract = (double)(tvPtr->xOffset + width) / worldWidth; fract = CLAMP(fract, 0.0, 1.0); Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(fract)); Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; } if (Blt_GetScrollInfoFromObj(interp, objc - 2, objv + 2, &tvPtr->xOffset, worldWidth, width, tvPtr->xScrollUnits, tvPtr->scrollMode) != TCL_OK) { return TCL_ERROR; } tvPtr->flags |= TV_XSCROLL; Blt_TreeViewEventuallyRedraw(tvPtr); return TCL_OK; } static int YViewOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { int height, worldHeight; height = VPORTHEIGHT(tvPtr); worldHeight = tvPtr->worldHeight; if (objc == 2) { double fract; Tcl_Obj *listObjPtr; listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); /* Report first and last fractions */ fract = (double)tvPtr->yOffset / worldHeight; fract = CLAMP(fract, 0.0, 1.0); Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(fract)); fract = (double)(tvPtr->yOffset + height) / worldHeight; fract = CLAMP(fract, 0.0, 1.0); Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(fract)); Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; } if (Blt_GetScrollInfoFromObj(interp, objc - 2, objv + 2, &tvPtr->yOffset, worldHeight, height, tvPtr->yScrollUnits, tvPtr->scrollMode) != TCL_OK) { return TCL_ERROR; } tvPtr->flags |= TV_SCROLL; Blt_TreeViewEventuallyRedraw(tvPtr); return TCL_OK; } /* * -------------------------------------------------------------- * * Blt_TreeViewWidgetInstCmd -- * * This procedure is invoked to process commands on behalf of * the treeview widget. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * * -------------------------------------------------------------- */ static Blt_OpSpec treeViewOps[] = { {"bbox", 2, (Blt_Op)BboxOp, 3, 0, "tagOrId...",}, {"bind", 2, (Blt_Op)BindOp, 3, 5, "tagName ?sequence command?",}, {"button", 2, (Blt_Op)ButtonOp, 2, 0, "args",}, {"cget", 2, (Blt_Op)CgetOp, 3, 3, "option",}, {"close", 2, (Blt_Op)CloseOp, 2, 0, "?-recurse? tagOrId...",}, {"column", 3, (Blt_Op)Blt_TreeViewColumnOp, 2, 0, "oper args",}, {"configure", 3, (Blt_Op)ConfigureOp, 2, 0, "?option value?...",}, {"curselection", 2, (Blt_Op)CurselectionOp, 2, 2, "",}, {"delete", 1, (Blt_Op)DeleteOp, 2, 0, "tagOrId ?tagOrId...?",}, {"edit", 2, (Blt_Op)EditOp, 4, 6, "?-root|-test? x y",}, {"entry", 2, (Blt_Op)EntryOp, 2, 0, "oper args",}, {"find", 2, (Blt_Op)FindOp, 2, 0, "?flags...? ?first last?",}, {"focus", 2, (Blt_Op)FocusOp, 3, 3, "tagOrId",}, {"get", 1, (Blt_Op)GetOp, 2, 0, "?-full? tagOrId ?tagOrId...?",}, {"hide", 1, (Blt_Op)HideOp, 2, 0, "?-exact? ?-glob? ?-regexp? ?-nonmatching? ?-name string? ?-full string? ?-data string? ?--? ?tagOrId...?",}, {"index", 3, (Blt_Op)IndexOp, 3, 6, "?-at tagOrId? ?-path? string",}, {"insert", 3, (Blt_Op)InsertOp, 3, 0, "?-at tagOrId? position label ?label...? ?option value?",}, {"move", 1, (Blt_Op)MoveOp, 5, 5, "tagOrId into|before|after tagOrId",}, {"nearest", 1, (Blt_Op)NearestOp, 4, 5, "x y ?varName?",}, {"open", 1, (Blt_Op)OpenOp, 2, 0, "?-recurse? tagOrId...",}, {"range", 1, (Blt_Op)RangeOp, 4, 5, "?-open? tagOrId tagOrId",}, {"scan", 2, (Blt_Op)ScanOp, 5, 5, "dragto|mark x y",}, {"see", 3, (Blt_Op)SeeOp, 3, 0, "?-anchor anchor? tagOrId",}, {"selection", 3, (Blt_Op)SelectionOp, 2, 0, "oper args",}, {"show", 2, (Blt_Op)ShowOp, 2, 0, "?-exact? ?-glob? ?-regexp? ?-nonmatching? ?-name string? ?-full string? ?-data string? ?--? ?tagOrId...?",}, {"sort", 2, (Blt_Op)Blt_TreeViewSortOp, 2, 0, "args",}, {"style", 2, (Blt_Op)Blt_TreeViewStyleOp, 2, 0, "args",}, {"tag", 2, (Blt_Op)TagOp, 2, 0, "oper args",}, {"toggle", 2, (Blt_Op)ToggleOp, 3, 3, "tagOrId",}, {"xview", 1, (Blt_Op)XViewOp, 2, 5, "?moveto fract? ?scroll number what?",}, {"yview", 1, (Blt_Op)YViewOp, 2, 5, "?moveto fract? ?scroll number what?",}, }; static int nTreeViewOps = sizeof(treeViewOps) / sizeof(Blt_OpSpec); int Blt_TreeViewWidgetInstCmd(clientData, interp, objc, objv) ClientData clientData; /* Information about the widget. */ Tcl_Interp *interp; /* Interpreter to report errors back to. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST *objv; /* Vector of argument strings. */ { Blt_Op proc; TreeView *tvPtr = clientData; int result; proc = Blt_GetOpFromObj(interp, nTreeViewOps, treeViewOps, BLT_OP_ARG1, objc, objv, 0); if (proc == NULL) { return TCL_ERROR; } Tcl_Preserve(tvPtr); result = (*proc) (tvPtr, interp, objc, objv); Tcl_Release(tvPtr); return result; } #endif /* NO_TREEVIEW */ blt-2.4z.orig/src/bltTreeViewColumn.c0100644000175000017500000016000507540713417016323 0ustar dokodoko /* * bltTreeViewColumn.c -- * * This module implements an hierarchy widget for the BLT toolkit. * * Copyright 1998-1999 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 or 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. * * The "treeview" widget was created by George A. Howlett. */ /* * TODO: * * BUGS: * 1. "open" operation should change scroll offset so that as many * new entries (up to half a screen) can be seen. * 2. "open" needs to adjust the scrolloffset so that the same entry * is seen at the same place. */ #include "bltInt.h" #ifndef NO_TREEVIEW #include "bltTreeView.h" #include #define RULE_AREA (8) static Blt_OptionParseProc ObjToColumn; static Blt_OptionPrintProc ColumnToObj; static Blt_OptionParseProc ObjToData; static Blt_OptionPrintProc DataToObj; static char *sortTypeStrings[] = { "dictionary", "ascii", "integer", "real", "command", "none", NULL }; enum SortTypeValues { SORT_TYPE_DICTIONARY, SORT_TYPE_ASCII, SORT_TYPE_INTEGER, SORT_TYPE_REAL, SORT_TYPE_COMMAND, SORT_TYPE_NONE }; #define DEF_SORT_COLUMN (char *)NULL #define DEF_SORT_COMMAND (char *)NULL #define DEF_SORT_DECREASING "no" #define DEF_SORT_TYPE "dictionary" #ifdef WIN32 #define DEF_COLUMN_ACTIVE_TITLE_BG RGB_GREY85 #else #define DEF_COLUMN_ACTIVE_TITLE_BG RGB_GREY90 #endif #define DEF_COLUMN_ACTIVE_TITLE_FG STD_ACTIVE_FOREGROUND #define DEF_COLUMN_BACKGROUND (char *)NULL #define DEF_COLUMN_BIND_TAGS "all" #define DEF_COLUMN_BORDERWIDTH STD_BORDERWIDTH #define DEF_COLUMN_COLOR RGB_BLACK #define DEF_COLUMN_EDIT "yes" #define DEF_COLUMN_FONT STD_FONT #define DEF_COLUMN_COMMAND (char *)NULL #define DEF_COLUMN_FORMAT_COMMAND (char *)NULL #define DEF_COLUMN_HIDE "no" #define DEF_COLUMN_JUSTIFY "center" #define DEF_COLUMN_MAX "0" #define DEF_COLUMN_MIN "0" #define DEF_COLUMN_PAD "2" #define DEF_COLUMN_RELIEF "flat" #define DEF_COLUMN_STATE "normal" #define DEF_COLUMN_STYLE "text" #define DEF_COLUMN_TITLE_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_COLUMN_TITLE_BORDERWIDTH STD_BORDERWIDTH #define DEF_COLUMN_TITLE_FONT STD_FONT #define DEF_COLUMN_TITLE_FOREGROUND STD_NORMAL_FOREGROUND #define DEF_COLUMN_TITLE_RELIEF "raised" #define DEF_COLUMN_WEIGHT "1.0" #define DEF_COLUMN_WIDTH "0" #define DEF_COLUMN_RULE_DASHES "dot" extern Blt_OptionParseProc Blt_ObjToEnum; extern Blt_OptionPrintProc Blt_EnumToObj; static Blt_CustomOption typeOption = { Blt_ObjToEnum, Blt_EnumToObj, NULL, (ClientData)sortTypeStrings }; static Blt_CustomOption columnOption = { ObjToColumn, ColumnToObj, NULL, (ClientData)0 }; Blt_CustomOption bltTreeViewDataOption = { ObjToData, DataToObj, NULL, (ClientData)0, }; static Blt_OptionParseProc ObjToStyle; static Blt_OptionPrintProc StyleToObj; static Blt_OptionFreeProc FreeStyle; static Blt_CustomOption styleOption = { /* Contains a pointer to the widget that's currently being * configured. This is used in the custom configuration parse * routine for icons. */ ObjToStyle, StyleToObj, FreeStyle, NULL, }; extern Blt_CustomOption bltTreeViewUidOption; extern Blt_CustomOption bltTreeViewIconOption; static Blt_TreeApplyProc SortApplyProc; static Blt_ConfigSpec columnSpecs[] = { {BLT_CONFIG_BORDER, "-activetitlebackground", "activeTitleBackground", "Background", DEF_COLUMN_ACTIVE_TITLE_BG, Blt_Offset(TreeViewColumn, activeTitleBorder), 0}, {BLT_CONFIG_COLOR, "-activetitleforeground", "activeTitleForeground", "Foreground", DEF_COLUMN_ACTIVE_TITLE_FG, Blt_Offset(TreeViewColumn, activeTitleFgColor), 0}, {BLT_CONFIG_BORDER, "-background", "background", "Background", DEF_COLUMN_BACKGROUND, Blt_Offset(TreeViewColumn, border), BLT_CONFIG_NULL_OK}, {BLT_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags", DEF_COLUMN_BIND_TAGS, Blt_Offset(TreeViewColumn, tagsUid), BLT_CONFIG_NULL_OK, &bltTreeViewUidOption}, {BLT_CONFIG_DISTANCE, "-borderwidth", "borderWidth", "BorderWidth", DEF_COLUMN_BORDERWIDTH, Blt_Offset(TreeViewColumn, borderWidth), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_STRING, "-command", "command", "Command", DEF_COLUMN_COMMAND, Blt_Offset(TreeViewColumn, titleCmd), BLT_CONFIG_DONT_SET_DEFAULT | BLT_CONFIG_NULL_OK}, {BLT_CONFIG_BOOLEAN, "-edit", "edit", "Edit", DEF_COLUMN_STATE, Blt_Offset(TreeViewColumn, editable), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_BOOLEAN, "-hide", "hide", "Hide", DEF_COLUMN_HIDE, Blt_Offset(TreeViewColumn, hidden), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_CUSTOM, "-icon", "icon", "icon", (char *)NULL, Blt_Offset(TreeViewColumn, titleIcon), BLT_CONFIG_DONT_SET_DEFAULT, &bltTreeViewIconOption}, {BLT_CONFIG_JUSTIFY, "-justify", "justify", "Justify", DEF_COLUMN_JUSTIFY, Blt_Offset(TreeViewColumn, justify), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_DISTANCE, "-max", "max", "Max", DEF_COLUMN_MAX, Blt_Offset(TreeViewColumn, reqMax), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_DISTANCE, "-min", "min", "Min", DEF_COLUMN_MIN, Blt_Offset(TreeViewColumn, reqMin), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_PAD, "-pad", "pad", "Pad", DEF_COLUMN_PAD, Blt_Offset(TreeViewColumn, pad), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_COLUMN_RELIEF, Blt_Offset(TreeViewColumn, relief), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_DASHES, "-ruledashes", "ruleDashes", "RuleDashes", DEF_COLUMN_RULE_DASHES, Blt_Offset(TreeViewColumn, ruleDashes), BLT_CONFIG_NULL_OK}, {BLT_CONFIG_STRING, "-sortcommand", "sortCommand", "SortCommand", DEF_SORT_COMMAND, Blt_Offset(TreeViewColumn, sortCmd), BLT_CONFIG_NULL_OK}, {BLT_CONFIG_STATE, "-state", "state", "State", DEF_COLUMN_STATE, Blt_Offset(TreeViewColumn, state), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_CUSTOM, "-style", "style", "Style", DEF_COLUMN_STYLE, Blt_Offset(TreeViewColumn, stylePtr), 0, &styleOption}, {BLT_CONFIG_STRING, "-text", "text", "Text", (char *)NULL, Blt_Offset(TreeViewColumn, title), 0}, {BLT_CONFIG_STRING, "-title", "title", "Title", (char *)NULL, Blt_Offset(TreeViewColumn, title), 0}, {BLT_CONFIG_BORDER, "-titlebackground", "titleBackground", "TitleBackground", DEF_COLUMN_TITLE_BACKGROUND, Blt_Offset(TreeViewColumn, titleBorder),0}, {BLT_CONFIG_DISTANCE, "-titleborderwidth", "BorderWidth", "TitleBorderWidth", DEF_COLUMN_TITLE_BORDERWIDTH, Blt_Offset(TreeViewColumn, titleBorderWidth), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_FONT, "-titlefont", "titleFont", "Font", DEF_COLUMN_TITLE_FONT, Blt_Offset(TreeViewColumn, titleFont), 0}, {BLT_CONFIG_COLOR, "-titleforeground", "titleForeground", "TitleForeground", DEF_COLUMN_TITLE_FOREGROUND, Blt_Offset(TreeViewColumn, titleFgColor), 0}, {BLT_CONFIG_RELIEF, "-titlerelief", "titleRelief", "TitleRelief", DEF_COLUMN_TITLE_RELIEF, Blt_Offset(TreeViewColumn, titleRelief), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_SHADOW, "-titleshadow", "titleShadow", "TitleShadow", (char *)NULL, Blt_Offset(TreeViewColumn, titleShadow), 0}, {BLT_CONFIG_DOUBLE, "-weight", (char *)NULL, (char *)NULL, DEF_COLUMN_WEIGHT, Blt_Offset(TreeViewColumn, weight), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_DISTANCE, "-width", "width", "Width", DEF_COLUMN_WIDTH, Blt_Offset(TreeViewColumn, reqWidth), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; static Blt_ConfigSpec sortSpecs[] = { {BLT_CONFIG_STRING, "-command", "command", "Command", DEF_SORT_COMMAND, Blt_Offset(TreeView, sortCmd), BLT_CONFIG_DONT_SET_DEFAULT | BLT_CONFIG_NULL_OK}, {BLT_CONFIG_CUSTOM, "-column", "column", "Column", DEF_SORT_COLUMN, Blt_Offset(TreeView, sortColumnPtr), BLT_CONFIG_DONT_SET_DEFAULT, &columnOption}, {BLT_CONFIG_BOOLEAN, "-decreasing", "decreasing", "Decreasing", DEF_SORT_DECREASING, Blt_Offset(TreeView, sortDecreasing), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_CUSTOM, "-mode", "mode", "Mode", DEF_SORT_TYPE, Blt_Offset(TreeView, sortType), 0, &typeOption}, {BLT_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; static Blt_TreeCompareNodesProc CompareNodes; static Blt_TreeApplyProc SortApplyProc; /* *---------------------------------------------------------------------- * * ObjToColumn -- * * Convert the string reprsenting a scroll mode, to its numeric * form. * * Results: * If the string is successfully converted, TCL_OK is returned. * Otherwise, TCL_ERROR is returned and an error message is left * in interpreter's result field. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ObjToColumn(clientData, interp, tkwin, objPtr, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ Tcl_Obj *objPtr; /* New legend position string */ char *widgRec; int offset; { TreeViewColumn **columnPtrPtr = (TreeViewColumn **)(widgRec + offset); char *string; string = Tcl_GetString(objPtr); if (*string == '\0') { *columnPtrPtr = NULL; } else { TreeView *tvPtr = (TreeView *)widgRec; if (Blt_TreeViewGetColumn(interp, tvPtr, objPtr, columnPtrPtr) != TCL_OK) { return TCL_ERROR; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * ColumnToString -- * * Results: * The string representation of the button boolean is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static Tcl_Obj * ColumnToObj(clientData, interp, tkwin, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; Tk_Window tkwin; /* Not used. */ char *widgRec; int offset; { TreeViewColumn *columnPtr = *(TreeViewColumn **)(widgRec + offset); if (columnPtr == NULL) { return bltEmptyStringObjPtr; } return Tcl_NewStringObj(columnPtr->key, -1); } /* *---------------------------------------------------------------------- * * ObjToData -- * * Convert the string reprsenting a scroll mode, to its numeric * form. * * Results: * If the string is successfully converted, TCL_OK is returned. * Otherwise, TCL_ERROR is returned and an error message is left * in interpreter's result field. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ObjToData(clientData, interp, tkwin, objPtr, widgRec, offset) ClientData clientData; /* Node of entry. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ Tcl_Obj *objPtr; /* Tcl_Obj representing new data. */ char *widgRec; int offset; { Tcl_Obj **objv; TreeViewColumn *columnPtr; TreeViewEntry *entryPtr = (TreeViewEntry *)widgRec; char *string; int objc; register int i; string = Tcl_GetString(objPtr); if (*string == '\0') { return TCL_OK; } if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { return TCL_ERROR; } if (objc == 0) { return TCL_OK; } if (objc & 0x1) { Tcl_AppendResult(interp, "data \"", string, "\" must be in even name-value pairs", (char *)NULL); return TCL_ERROR; } for (i = 0; i < objc; i += 2) { TreeView *tvPtr = entryPtr->tvPtr; if (Blt_TreeViewGetColumn(interp, tvPtr, objv[i], &columnPtr) != TCL_OK) { return TCL_ERROR; } if (Blt_TreeSetValueByKey(tvPtr->interp, tvPtr->tree, entryPtr->node, columnPtr->key, objv[i + 1]) != TCL_OK) { return TCL_ERROR; } Blt_TreeViewAddValue(entryPtr, columnPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * DataToObj -- * * Results: * The string representation of the data is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static Tcl_Obj * DataToObj(clientData, interp, tkwin, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; Tk_Window tkwin; /* Not used. */ char *widgRec; int offset; { Tcl_Obj *listObjPtr, *objPtr; TreeViewEntry *entryPtr = (TreeViewEntry *)widgRec; TreeViewValue *valuePtr; /* Add the key-value pairs to a new Tcl_Obj */ listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); for (valuePtr = entryPtr->values; valuePtr != NULL; valuePtr = valuePtr->nextPtr) { objPtr = Tcl_NewStringObj(valuePtr->columnPtr->key, -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); if (Blt_TreeViewGetData(entryPtr, valuePtr->columnPtr->key, &objPtr) != TCL_OK) { objPtr = bltEmptyStringObjPtr; } Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } return listObjPtr; } int Blt_TreeViewGetColumn(interp, tvPtr, objPtr, columnPtrPtr) Tcl_Interp *interp; TreeView *tvPtr; Tcl_Obj *objPtr; TreeViewColumn **columnPtrPtr; { char *string; string = Tcl_GetString(objPtr); if (strcmp(string, "treeView") == 0) { *columnPtrPtr = &tvPtr->treeColumn; } else { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&tvPtr->columnTable, Blt_TreeGetKey(string)); if (hPtr == NULL) { if (interp != NULL) { Tcl_AppendResult(interp, "can't find column \"", string, "\" in \"", Tk_PathName(tvPtr->tkwin), "\"", (char *)NULL); } return TCL_ERROR; } *columnPtrPtr = Blt_GetHashValue(hPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * ObjToStyle -- * * Convert the name of an icon into a treeview style. * * Results: * If the string is successfully converted, TCL_OK is returned. * Otherwise, TCL_ERROR is returned and an error message is left in * interpreter's result field. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ObjToStyle(clientData, interp, tkwin, objPtr, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ Tcl_Obj *objPtr; /* Tcl_Obj representing the new value. */ char *widgRec; int offset; { TreeView *tvPtr = clientData; TreeViewStyle **stylePtrPtr = (TreeViewStyle **)(widgRec + offset); TreeViewStyle *stylePtr; if (Blt_TreeViewGetStyle(interp, tvPtr, Tcl_GetString(objPtr), &stylePtr) != TCL_OK) { return TCL_ERROR; } stylePtr->flags |= STYLE_DIRTY; tvPtr->flags |= (TV_LAYOUT | TV_DIRTY); *stylePtrPtr = stylePtr; return TCL_OK; } /* *---------------------------------------------------------------------- * * IconToObj -- * * Converts the icon into its string representation (its name). * * Results: * The name of the icon is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static Tcl_Obj * StyleToObj(clientData, interp, tkwin, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; Tk_Window tkwin; /* Not used. */ char *widgRec; int offset; { TreeViewStyle *stylePtr = *(TreeViewStyle **)(widgRec + offset); if (stylePtr == NULL) { return bltEmptyStringObjPtr; } return Tcl_NewStringObj(stylePtr->name, -1); } /*ARGSUSED*/ static void FreeStyle(clientData, display, widgRec, offset) ClientData clientData; Display *display; /* Not used. */ char *widgRec; int offset; { TreeView *tvPtr = clientData; TreeViewStyle *stylePtr = *(TreeViewStyle **)(widgRec + offset); Blt_TreeViewFreeStyle(tvPtr, stylePtr); } void Blt_TreeViewUpdateColumnGCs(tvPtr, columnPtr) TreeView *tvPtr; TreeViewColumn *columnPtr; { Drawable drawable; GC newGC; Tk_3DBorder border; XGCValues gcValues; int ruleDrawn; unsigned long gcMask; int iconWidth, iconHeight; int textWidth, textHeight; gcMask = GCForeground | GCFont; gcValues.font = Tk_FontId(columnPtr->titleFont); /* Normal title text */ gcValues.foreground = columnPtr->titleFgColor->pixel; newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues); if (columnPtr->titleGC != NULL) { Tk_FreeGC(tvPtr->display, columnPtr->titleGC); } columnPtr->titleGC = newGC; /* Active title text */ gcValues.foreground = columnPtr->activeTitleFgColor->pixel; newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues); if (columnPtr->activeTitleGC != NULL) { Tk_FreeGC(tvPtr->display, columnPtr->activeTitleGC); } columnPtr->activeTitleGC = newGC; columnPtr->titleWidth = 0; iconWidth = iconHeight = 0; if (columnPtr->titleIcon != NULL) { iconWidth = TreeViewIconWidth(columnPtr->titleIcon); iconHeight = TreeViewIconHeight(columnPtr->titleIcon); columnPtr->titleWidth += iconWidth; } if (columnPtr->titleTextPtr != NULL) { Blt_Free(columnPtr->titleTextPtr); columnPtr->titleTextPtr = NULL; } textWidth = textHeight = 0; if (columnPtr->title != NULL) { TextStyle ts; memset(&ts, 0, sizeof(TextStyle)); ts.font = columnPtr->titleFont; ts.justify = TK_JUSTIFY_LEFT; ts.shadow.offset = columnPtr->titleShadow.offset; columnPtr->titleTextPtr = Blt_GetTextLayout(columnPtr->title, &ts); textHeight = columnPtr->titleTextPtr->height; textWidth = columnPtr->titleTextPtr->width; columnPtr->titleWidth += textWidth; } if ((iconWidth > 0) && (textWidth > 0)) { columnPtr->titleWidth += 8; } columnPtr->titleWidth += STD_ARROW_HEIGHT; columnPtr->titleHeight = MAX(iconHeight, textHeight); gcMask = (GCFunction | GCLineWidth | GCLineStyle | GCForeground); /* * If the rule is active, turn it off (i.e. draw again to erase * it) before changing the GC. If the color changes, we won't be * able to erase the old line, since it will no longer be * correctly XOR-ed with the background. */ drawable = Tk_WindowId(tvPtr->tkwin); ruleDrawn = ((tvPtr->flags & TV_RULE_ACTIVE) && (tvPtr->activeTitleColumnPtr == columnPtr) && (drawable != None)); if (ruleDrawn) { Blt_TreeViewDrawRule(tvPtr, columnPtr, drawable); } /* XOR-ed rule column divider */ gcValues.line_width = LineWidth(columnPtr->ruleLineWidth); gcValues.foreground = Blt_TreeViewGetStyleFg(tvPtr, columnPtr->stylePtr)->pixel; if (LineIsDashed(columnPtr->ruleDashes)) { gcValues.line_style = LineOnOffDash; } else { gcValues.line_style = LineSolid; } gcValues.function = GXxor; border = CHOOSE(tvPtr->border, columnPtr->border); gcValues.foreground ^= Tk_3DBorderColor(border)->pixel; newGC = Blt_GetPrivateGC(tvPtr->tkwin, gcMask, &gcValues); if (columnPtr->ruleGC != NULL) { Blt_FreePrivateGC(tvPtr->display, columnPtr->ruleGC); } if (LineIsDashed(columnPtr->ruleDashes)) { Blt_SetDashes(tvPtr->display, newGC, &columnPtr->ruleDashes); } columnPtr->ruleGC = newGC; if (ruleDrawn) { Blt_TreeViewDrawRule(tvPtr, columnPtr, drawable); } columnPtr->flags |= COLUMN_DIRTY; tvPtr->flags |= TV_UPDATE; } static void DestroyColumn(tvPtr, columnPtr) TreeView *tvPtr; TreeViewColumn *columnPtr; { Blt_HashEntry *hPtr; bltTreeViewUidOption.clientData = tvPtr; bltTreeViewIconOption.clientData = tvPtr; styleOption.clientData = tvPtr; Blt_FreeObjOptions(columnSpecs, (char *)columnPtr, tvPtr->display, 0); if (columnPtr->titleGC != NULL) { Tk_FreeGC(tvPtr->display, columnPtr->titleGC); } if (columnPtr->ruleGC != NULL) { Blt_FreePrivateGC(tvPtr->display, columnPtr->ruleGC); } hPtr = Blt_FindHashEntry(&tvPtr->columnTable, columnPtr->key); if (hPtr != NULL) { Blt_DeleteHashEntry(&tvPtr->columnTable, hPtr); } if (columnPtr->linkPtr != NULL) { Blt_ChainDeleteLink(tvPtr->colChainPtr, columnPtr->linkPtr); } if (columnPtr->title != NULL) { Blt_Free(columnPtr->title); } if (columnPtr->titleTextPtr != NULL) { Blt_Free(columnPtr->titleTextPtr); } if (columnPtr->stylePtr != NULL) { Blt_TreeViewFreeStyle(tvPtr, columnPtr->stylePtr); } if (columnPtr != &tvPtr->treeColumn) { Blt_Free(columnPtr); } } void Blt_TreeViewDestroyColumns(tvPtr) TreeView *tvPtr; { if (tvPtr->colChainPtr != NULL) { Blt_ChainLink *linkPtr; TreeViewColumn *columnPtr; for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { columnPtr = Blt_ChainGetValue(linkPtr); columnPtr->linkPtr = NULL; DestroyColumn(tvPtr, columnPtr); } Blt_ChainDestroy(tvPtr->colChainPtr); tvPtr->colChainPtr = NULL; } Blt_DeleteHashTable(&tvPtr->columnTable); } int Blt_TreeViewCreateColumn(tvPtr, columnPtr, name, defTitle) TreeView *tvPtr; TreeViewColumn *columnPtr; char *name, *defTitle; { Blt_HashEntry *hPtr; int isNew; columnPtr->key = Blt_TreeGetKey(name); columnPtr->title = Blt_Strdup(defTitle); columnPtr->justify = TK_JUSTIFY_CENTER; columnPtr->relief = TK_RELIEF_FLAT; columnPtr->borderWidth = 1; columnPtr->pad.side1 = columnPtr->pad.side2 = 2; columnPtr->state = STATE_NORMAL; columnPtr->weight = 1.0; columnPtr->editable = FALSE; columnPtr->ruleLineWidth = 1; columnPtr->titleBorderWidth = 2; columnPtr->titleRelief = TK_RELIEF_RAISED; columnPtr->titleIcon = NULL; hPtr = Blt_CreateHashEntry(&tvPtr->columnTable, columnPtr->key, &isNew); Blt_SetHashValue(hPtr, columnPtr); bltTreeViewUidOption.clientData = tvPtr; bltTreeViewIconOption.clientData = tvPtr; styleOption.clientData = tvPtr; if (Blt_ConfigureComponentFromObj(tvPtr->interp, tvPtr->tkwin, name, "Column", columnSpecs, 0, (Tcl_Obj **)NULL, (char *)columnPtr, 0) != TCL_OK) { DestroyColumn(tvPtr, columnPtr); return TCL_ERROR; } return TCL_OK; } static TreeViewColumn * CreateColumn(tvPtr, nameObjPtr, objc, objv) TreeView *tvPtr; Tcl_Obj *nameObjPtr; int objc; Tcl_Obj *CONST *objv; { TreeViewColumn *columnPtr; columnPtr = Blt_Calloc(1, sizeof(TreeViewColumn)); assert(columnPtr); if (Blt_TreeViewCreateColumn(tvPtr, columnPtr, Tcl_GetString(nameObjPtr), Tcl_GetString(nameObjPtr)) != TCL_OK) { return NULL; } bltTreeViewUidOption.clientData = tvPtr; bltTreeViewIconOption.clientData = tvPtr; styleOption.clientData = tvPtr; if (Blt_ConfigureComponentFromObj(tvPtr->interp, tvPtr->tkwin, columnPtr->key, "Column", columnSpecs, objc, objv, (char *)columnPtr, BLT_CONFIG_OBJV_ONLY) != TCL_OK) { DestroyColumn(tvPtr, columnPtr); return NULL; } Blt_TreeViewUpdateColumnGCs(tvPtr, columnPtr); return columnPtr; } TreeViewColumn * Blt_TreeViewNearestColumn(tvPtr, x, y, contextPtr) TreeView *tvPtr; int x, y; ClientData *contextPtr; { if (tvPtr->nVisible > 0) { Blt_ChainLink *linkPtr; TreeViewColumn *columnPtr; int right; /* * Determine if the pointer is over the rightmost portion of the * column. This activates the rule. */ x = WORLDX(tvPtr, x); for(linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { columnPtr = Blt_ChainGetValue(linkPtr); right = columnPtr->worldX + columnPtr->width; if ((x >= columnPtr->worldX) && (x <= right)) { if (contextPtr != NULL) { *contextPtr = NULL; if ((tvPtr->flags & TV_SHOW_COLUMN_TITLES) && (y >= tvPtr->inset) && (y < (tvPtr->titleHeight + tvPtr->inset))) { *contextPtr = (x >= (right - RULE_AREA)) ? ITEM_COLUMN_RULE : ITEM_COLUMN_TITLE; } } return columnPtr; } } } return NULL; } /* *---------------------------------------------------------------------- * * ColumnActivateOp -- * * Selects the button to appear active. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ColumnActivateOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { if (objc == 4) { Drawable drawable; TreeViewColumn *columnPtr; char *string; string = Tcl_GetString(objv[3]); if (string[0] == '\0') { columnPtr = NULL; } else { if (Blt_TreeViewGetColumn(interp, tvPtr, objv[3], &columnPtr) != TCL_OK) { return TCL_ERROR; } if (((tvPtr->flags & TV_SHOW_COLUMN_TITLES) == 0) || (columnPtr->hidden) || (columnPtr->state == STATE_DISABLED)) { columnPtr = NULL; } } tvPtr->activeTitleColumnPtr = tvPtr->activeColumnPtr = columnPtr; drawable = Tk_WindowId(tvPtr->tkwin); if (drawable != None) { Blt_TreeViewDrawHeadings(tvPtr, drawable); Blt_TreeViewDrawOuterBorders(tvPtr, drawable); } } if (tvPtr->activeTitleColumnPtr != NULL) { Tcl_SetResult(interp, tvPtr->activeTitleColumnPtr->key, TCL_VOLATILE); } return TCL_OK; } /* *---------------------------------------------------------------------- * * ColumnBindOp -- * * .t bind tag sequence command * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ColumnBindOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { ClientData object; TreeViewColumn *columnPtr; if (Blt_TreeViewGetColumn(NULL, tvPtr, objv[3], &columnPtr) == TCL_OK) { object = Blt_TreeViewColumnTag(tvPtr, columnPtr->key); } else { object = Blt_TreeViewColumnTag(tvPtr, Tcl_GetString(objv[3])); } return Blt_ConfigureBindingsFromObj(interp, tvPtr->bindTable, object, objc - 4, objv + 4); } /* *---------------------------------------------------------------------- * * ColumnCgetOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ColumnCgetOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { TreeViewColumn *columnPtr; if (Blt_TreeViewGetColumn(interp, tvPtr, objv[3], &columnPtr) != TCL_OK) { return TCL_ERROR; } return Blt_ConfigureValueFromObj(interp, tvPtr->tkwin, columnSpecs, (char *)columnPtr, objv[4], 0); } /* *---------------------------------------------------------------------- * * ColumnConfigureOp -- * * This procedure is called to process a list of configuration * options database, in order to reconfigure the one of more * entries in the widget. * * .h entryconfigure node node node node option value * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for tvPtr; old resources get freed, if there * were any. The hypertext is redisplayed. * *---------------------------------------------------------------------- */ static int ColumnConfigureOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { TreeViewColumn *columnPtr; int nOptions, start; register int i; /* Figure out where the option value pairs begin */ for(i = 3; i < objc; i++) { if (Blt_ObjIsOption(columnSpecs, objv[i], 0)) { break; } if (Blt_TreeViewGetColumn(interp, tvPtr, objv[i], &columnPtr) != TCL_OK) { return TCL_ERROR; } } start = i; nOptions = objc - start; bltTreeViewUidOption.clientData = tvPtr; bltTreeViewIconOption.clientData = tvPtr; styleOption.clientData = tvPtr; for (i = 3; i < start; i++) { if (Blt_TreeViewGetColumn(interp, tvPtr, objv[i], &columnPtr) != TCL_OK) { return TCL_ERROR; } if (nOptions == 0) { return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin, columnSpecs, (char *)columnPtr, (Tcl_Obj *)NULL, 0); } else if (nOptions == 1) { return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin, columnSpecs, (char *)columnPtr, objv[start], 0); } if (Blt_ConfigureWidgetFromObj(tvPtr->interp, tvPtr->tkwin, columnSpecs, nOptions, objv + start, (char *)columnPtr, BLT_CONFIG_OBJV_ONLY) != TCL_OK) { return TCL_ERROR; } Blt_TreeViewUpdateColumnGCs(tvPtr, columnPtr); } /*FIXME: Makes every change redo everything. */ tvPtr->flags |= (TV_LAYOUT | TV_DIRTY); Blt_TreeViewEventuallyRedraw(tvPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * ColumnDeleteOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ColumnDeleteOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; /* Not used. */ int objc; Tcl_Obj *CONST *objv; { TreeViewColumn *columnPtr; TreeViewEntry *entryPtr; register int i; for(i = 3; i < objc; i++) { if (Blt_TreeViewGetColumn(interp, tvPtr, objv[i], &columnPtr) != TCL_OK) { return TCL_ERROR; } /* Traverse the tree deleting values associated with the column. */ for(entryPtr = tvPtr->rootPtr; entryPtr != NULL; entryPtr = Blt_TreeViewNextEntry(entryPtr, 0)) { if (entryPtr != NULL) { TreeViewValue *valuePtr, *lastPtr, *nextPtr; lastPtr = NULL; for (valuePtr = entryPtr->values; valuePtr != NULL; valuePtr = nextPtr) { nextPtr = valuePtr->nextPtr; if (valuePtr->columnPtr == columnPtr) { Blt_TreeViewDestroyValue(tvPtr, valuePtr); if (lastPtr == NULL) { entryPtr->values = nextPtr; } else { lastPtr->nextPtr = nextPtr; } break; } lastPtr = valuePtr; } } } DestroyColumn(tvPtr, columnPtr); } /* Deleting a column may affect the height of an entry. */ tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT); Blt_TreeViewEventuallyRedraw(tvPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * ColumnInsertOp -- * * Add new columns to the tree. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ColumnInsertOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { Blt_ChainLink *beforePtr; Tcl_Obj *CONST *options; TreeViewColumn *columnPtr; TreeViewEntry *entryPtr; int insertPos; int nOptions; int start; register int i; if (Blt_GetPositionFromObj(tvPtr->interp, objv[3], &insertPos) != TCL_OK) { return TCL_ERROR; } if ((insertPos == -1) || (insertPos >= Blt_ChainGetLength(tvPtr->colChainPtr))) { beforePtr = NULL; } else { beforePtr = Blt_ChainGetNthLink(tvPtr->colChainPtr, insertPos); } /* * Count the column names that follow. Count the arguments until we * spot one that looks like a configuration option (i.e. starts * with a minus ("-")). */ for (i = 4; i < objc; i++) { if (Blt_ObjIsOption(columnSpecs, objv[i], 0)) { break; } } start = i; nOptions = objc - i; options = objv + start; for (i = 4; i < start; i++) { if (Blt_TreeViewGetColumn(NULL, tvPtr, objv[i], &columnPtr) == TCL_OK) { Tcl_AppendResult(interp, "column \"", Tcl_GetString(objv[i]), "\" already exists", (char *)NULL); return TCL_ERROR; } columnPtr = CreateColumn(tvPtr, objv[i], nOptions, options); if (columnPtr == NULL) { return TCL_ERROR; } if (beforePtr == NULL) { columnPtr->linkPtr = Blt_ChainAppend(tvPtr->colChainPtr, columnPtr); } else { columnPtr->linkPtr = Blt_ChainNewLink(); Blt_ChainSetValue(columnPtr->linkPtr, columnPtr); Blt_ChainLinkBefore(tvPtr->colChainPtr, columnPtr->linkPtr, beforePtr); } /* * Traverse the tree adding column entries where needed. */ for(entryPtr = tvPtr->rootPtr; entryPtr != NULL; entryPtr = Blt_TreeViewNextEntry(entryPtr, 0)) { Blt_TreeViewAddValue(entryPtr, columnPtr); } Blt_TreeViewTraceColumn(tvPtr, columnPtr); } Blt_TreeViewEventuallyRedraw(tvPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * ColumnCurrentOp -- * * Make the rule to appear active. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ColumnCurrentOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; /* Not used. */ { ClientData context; TreeViewColumn *columnPtr; columnPtr = NULL; context = Blt_GetCurrentContext(tvPtr->bindTable); if ((context == ITEM_COLUMN_TITLE) || (context == ITEM_COLUMN_RULE)) { columnPtr = Blt_GetCurrentItem(tvPtr->bindTable); } if (context >= ITEM_STYLE) { TreeViewValue *valuePtr = context; columnPtr = valuePtr->columnPtr; } if (columnPtr != NULL) { Tcl_SetResult(interp, columnPtr->key, TCL_VOLATILE); } return TCL_OK; } /* *---------------------------------------------------------------------- * * ColumnInvokeOp -- * * This procedure is called to invoke a column command. * * .h column invoke columnName * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ColumnInvokeOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; /* Not used. */ int objc; Tcl_Obj *CONST *objv; { TreeViewColumn *columnPtr; char *string; string = Tcl_GetString(objv[3]); if (string[0] == '\0') { return TCL_OK; } if (Blt_TreeViewGetColumn(interp, tvPtr, objv[3], &columnPtr) != TCL_OK) { return TCL_ERROR; } if ((columnPtr->state == STATE_NORMAL) && (columnPtr->titleCmd != NULL)) { int result; Tcl_Preserve(tvPtr); Tcl_Preserve(columnPtr); result = Tcl_GlobalEval(interp, columnPtr->titleCmd); Tcl_Release(columnPtr); Tcl_Release(tvPtr); return result; } return TCL_OK; } /* *---------------------------------------------------------------------- * * ColumnMoveOp -- * * Move a column. * * .h column move field1 position *---------------------------------------------------------------------- */ /* *---------------------------------------------------------------------- * * ColumnNamesOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ColumnNamesOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; /* Not used. */ { Blt_ChainLink *linkPtr; Tcl_Obj *listObjPtr, *objPtr; TreeViewColumn *columnPtr; listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); for(linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { columnPtr = Blt_ChainGetValue(linkPtr); objPtr = Tcl_NewStringObj(columnPtr->key, -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; } /*ARGSUSED*/ static int ColumnNearestOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { int x, y; /* Screen coordinates of the test point. */ TreeViewColumn *columnPtr; ClientData context; int checkTitle; #ifdef notdef int isRoot; isRoot = FALSE; string = Tcl_GetString(objv[3]); if (strcmp("-root", string) == 0) { isRoot = TRUE; objv++, objc--; } if (objc != 5) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " ", Tcl_GetString(objv[1]), Tcl_GetString(objv[2]), " ?-root? x y\"", (char *)NULL); return TCL_ERROR; } #endif if (Tk_GetPixelsFromObj(interp, tvPtr->tkwin, objv[3], &x) != TCL_OK) { return TCL_ERROR; } y = 0; checkTitle = FALSE; if (objc == 5) { if (Tk_GetPixelsFromObj(interp, tvPtr->tkwin, objv[4], &y) != TCL_OK) { return TCL_ERROR; } checkTitle = TRUE; } columnPtr = Blt_TreeViewNearestColumn(tvPtr, x, y, &context); if ((checkTitle) && (context == NULL)) { columnPtr = NULL; } if (columnPtr != NULL) { Tcl_SetResult(interp, columnPtr->key, TCL_VOLATILE); } return TCL_OK; } static void UpdateMark(tvPtr, newMark) TreeView *tvPtr; int newMark; { Drawable drawable; TreeViewColumn *columnPtr; int dx; int width; columnPtr = tvPtr->resizeColumnPtr; if (columnPtr == NULL) { return; } drawable = Tk_WindowId(tvPtr->tkwin); if (drawable == None) { return; } /* Erase any existing rule. */ if (tvPtr->flags & TV_RULE_ACTIVE) { Blt_TreeViewDrawRule(tvPtr, columnPtr, drawable); } dx = newMark - tvPtr->ruleAnchor; width = columnPtr->width - (PADDING(columnPtr->pad) + 2 * columnPtr->borderWidth); if ((columnPtr->reqMin > 0) && ((width + dx) < columnPtr->reqMin)) { dx = columnPtr->reqMin - width; } if ((columnPtr->reqMax > 0) && ((width + dx) > columnPtr->reqMax)) { dx = columnPtr->reqMax - width; } if ((width + dx) < 4) { dx = 4 - width; } tvPtr->ruleMark = tvPtr->ruleAnchor + dx; /* Redraw the rule if required. */ if (tvPtr->flags & TV_RULE_NEEDED) { Blt_TreeViewDrawRule(tvPtr, columnPtr, drawable); } } /* *---------------------------------------------------------------------- * * ResizeActivateOp -- * * Turns on/off the resize cursor. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ResizeActivateOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { TreeViewColumn *columnPtr; char *string; string = Tcl_GetString(objv[4]); if (string[0] == '\0') { if (tvPtr->cursor != None) { Tk_DefineCursor(tvPtr->tkwin, tvPtr->cursor); } else { Tk_UndefineCursor(tvPtr->tkwin); } tvPtr->resizeColumnPtr = NULL; } else if (Blt_TreeViewGetColumn(interp, tvPtr, objv[4], &columnPtr) == TCL_OK) { if (tvPtr->resizeCursor != None) { Tk_DefineCursor(tvPtr->tkwin, tvPtr->resizeCursor); } tvPtr->resizeColumnPtr = columnPtr; } else { return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * ResizeAnchorOp -- * * Set the anchor for the resize. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ResizeAnchorOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { int x; if (Tcl_GetIntFromObj(NULL, objv[4], &x) != TCL_OK) { return TCL_ERROR; } tvPtr->ruleAnchor = x; tvPtr->flags |= TV_RULE_NEEDED; UpdateMark(tvPtr, x); return TCL_OK; } /* *---------------------------------------------------------------------- * * ResizeMarkOp -- * * Sets the resize mark. The distance between the mark and the anchor * is the delta to change the width of the active column. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ResizeMarkOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { int x; if (Tcl_GetIntFromObj(NULL, objv[4], &x) != TCL_OK) { return TCL_ERROR; } tvPtr->flags |= TV_RULE_NEEDED; UpdateMark(tvPtr, x); return TCL_OK; } /* *---------------------------------------------------------------------- * * ResizeSetOp -- * * Returns the new width of the column including the resize delta. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ResizeSetOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; /* Not used. */ { tvPtr->flags &= ~TV_RULE_NEEDED; UpdateMark(tvPtr, tvPtr->ruleMark); if (tvPtr->resizeColumnPtr != NULL) { int width, delta; TreeViewColumn *columnPtr; columnPtr = tvPtr->resizeColumnPtr; delta = (tvPtr->ruleMark - tvPtr->ruleAnchor); width = tvPtr->resizeColumnPtr->width + delta - (PADDING(columnPtr->pad) + 2 * columnPtr->borderWidth) - 1; Tcl_SetObjResult(interp, Tcl_NewIntObj(width)); } return TCL_OK; } static Blt_OpSpec resizeOps[] = { {"activate", 2, (Blt_Op)ResizeActivateOp, 5, 5, "column"}, {"anchor", 2, (Blt_Op)ResizeAnchorOp, 5, 5, "x"}, {"mark", 1, (Blt_Op)ResizeMarkOp, 5, 5, "x"}, {"set", 1, (Blt_Op)ResizeSetOp, 4, 4, "",}, }; static int nResizeOps = sizeof(resizeOps) / sizeof(Blt_OpSpec); /* *---------------------------------------------------------------------- * * ColumnResizeOp -- * *---------------------------------------------------------------------- */ static int ColumnResizeOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { Blt_Op proc; int result; proc = Blt_GetOpFromObj(interp, nResizeOps, resizeOps, BLT_OP_ARG3, objc, objv,0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (tvPtr, interp, objc, objv); return result; } static Blt_OpSpec columnOps[] = { {"activate", 1, (Blt_Op)ColumnActivateOp, 3, 4, "?field?",}, {"bind", 1, (Blt_Op)ColumnBindOp, 4, 6, "tagName ?sequence command?",}, {"cget", 2, (Blt_Op)ColumnCgetOp, 5, 5, "field option",}, {"configure", 2, (Blt_Op)ColumnConfigureOp, 4, 0, "field ?option value?...",}, {"current", 2, (Blt_Op)ColumnCurrentOp, 3, 3, "",}, {"delete", 1, (Blt_Op)ColumnDeleteOp, 3, 0, "?field...?",}, {"highlight", 1, (Blt_Op)ColumnActivateOp, 3, 4, "?field?",}, {"insert", 3, (Blt_Op)ColumnInsertOp, 5, 0, "position field ?field...? ?option value?...",}, {"invoke", 3, (Blt_Op)ColumnInvokeOp, 4, 4, "field",}, {"names", 2, (Blt_Op)ColumnNamesOp, 3, 3, "",}, {"nearest", 2, (Blt_Op)ColumnNearestOp, 4, 5, "x ?y?",}, {"resize", 1, (Blt_Op)ColumnResizeOp, 3, 0, "arg",}, }; static int nColumnOps = sizeof(columnOps) / sizeof(Blt_OpSpec); /* *---------------------------------------------------------------------- * * Blt_TreeViewColumnOp -- * *---------------------------------------------------------------------- */ int Blt_TreeViewColumnOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { Blt_Op proc; int result; proc = Blt_GetOpFromObj(interp, nColumnOps, columnOps, BLT_OP_ARG2, objc, objv,0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (tvPtr, interp, objc, objv); return result; } static int InvokeCompare(tvPtr, e1Ptr, e2Ptr, command) TreeView *tvPtr; TreeViewEntry *e1Ptr, *e2Ptr; char *command; { int result; Tcl_Obj *objv[8]; int i; objv[0] = Tcl_NewStringObj(command, -1); objv[1] = Tcl_NewStringObj(Tk_PathName(tvPtr->tkwin), -1); objv[2] = Tcl_NewIntObj(Blt_TreeNodeId(e1Ptr->node)); objv[3] = Tcl_NewIntObj(Blt_TreeNodeId(e2Ptr->node)); objv[4] = Tcl_NewStringObj(tvPtr->sortColumnPtr->key, -1); if (tvPtr->flatView) { objv[5] = Tcl_NewStringObj(e1Ptr->fullName, -1); objv[6] = Tcl_NewStringObj(e2Ptr->fullName, -1); } else { objv[5] = Tcl_NewStringObj(GETLABEL(e1Ptr), -1); objv[6] = Tcl_NewStringObj(GETLABEL(e2Ptr), -1); } for(i = 0; i < 7; i++) { Tcl_IncrRefCount(objv[i]); } objv[7] = NULL; result = Tcl_EvalObjv(tvPtr->interp, 7, objv, TCL_EVAL_GLOBAL); if ((result != TCL_OK) || (Tcl_GetIntFromObj(tvPtr->interp, Tcl_GetObjResult(tvPtr->interp), &result) != TCL_OK)) { Tcl_BackgroundError(tvPtr->interp); } for(i = 0; i < 7; i++) { Tcl_DecrRefCount(objv[i]); } Tcl_ResetResult(tvPtr->interp); return result; } static TreeView *treeViewInstance; static int CompareEntries(a, b) CONST void *a, *b; { TreeView *tvPtr; TreeViewEntry **e1PtrPtr = (TreeViewEntry **)a; TreeViewEntry **e2PtrPtr = (TreeViewEntry **)b; Tcl_Obj *obj1, *obj2; char *s1, *s2; int result; tvPtr = (*e1PtrPtr)->tvPtr; obj1 = (*e1PtrPtr)->dataObjPtr; obj2 = (*e2PtrPtr)->dataObjPtr; s1 = Tcl_GetString(obj1); s2 = Tcl_GetString(obj2); result = 0; switch (tvPtr->sortType) { case SORT_TYPE_ASCII: result = strcmp(s1, s2); break; case SORT_TYPE_COMMAND: { char *cmd; cmd = tvPtr->sortColumnPtr->sortCmd; if (cmd == NULL) { cmd = tvPtr->sortCmd; } if (cmd == NULL) { result = Blt_DictionaryCompare(s1, s2); } else { result = InvokeCompare(tvPtr, *e1PtrPtr, *e2PtrPtr, cmd); } } break; case SORT_TYPE_DICTIONARY: result = Blt_DictionaryCompare(s1, s2); break; case SORT_TYPE_INTEGER: { int i1, i2; if (Tcl_GetIntFromObj(NULL, obj1, &i1)==TCL_OK) { if (Tcl_GetIntFromObj(NULL, obj2, &i2) == TCL_OK) { result = i1 - i2; } else { result = -1; } } else if (Tcl_GetIntFromObj(NULL, obj2, &i2) == TCL_OK) { result = 1; } else { result = Blt_DictionaryCompare(s1, s2); } } break; case SORT_TYPE_REAL: { double r1, r2; if (Tcl_GetDoubleFromObj(NULL, obj1, &r1) == TCL_OK) { if (Tcl_GetDoubleFromObj(NULL, obj2, &r2) == TCL_OK) { result = (r1 < r2) ? -1 : (r1 > r2) ? 1 : 0; } else { result = -1; } } else if (Tcl_GetDoubleFromObj(NULL, obj2, &r2) == TCL_OK) { result = 1; } else { result = Blt_DictionaryCompare(s1, s2); } } break; } if (tvPtr->sortDecreasing) { return -result; } return result; } /* *---------------------------------------------------------------------- * * CompareNodes -- * * Comparison routine (used by qsort) to sort a chain of subnodes. * * Results: * 1 is the first is greater, -1 is the second is greater, 0 * if equal. * *---------------------------------------------------------------------- */ static int CompareNodes(n1Ptr, n2Ptr) Blt_TreeNode *n1Ptr, *n2Ptr; { TreeView *tvPtr = treeViewInstance; TreeViewEntry *e1Ptr, *e2Ptr; e1Ptr = Blt_NodeToEntry(tvPtr, *n1Ptr); e2Ptr = Blt_NodeToEntry(tvPtr, *n2Ptr); /* Fetch the data for sorting. */ if (tvPtr->sortType == SORT_TYPE_COMMAND) { e1Ptr->dataObjPtr = Tcl_NewIntObj(Blt_TreeNodeId(*n1Ptr)); e2Ptr->dataObjPtr = Tcl_NewIntObj(Blt_TreeNodeId(*n2Ptr)); } else if (tvPtr->sortColumnPtr == &tvPtr->treeColumn) { Tcl_DString dString; Tcl_DStringInit(&dString); if (e1Ptr->fullName == NULL) { Blt_TreeViewGetFullName(tvPtr, e1Ptr, TRUE, &dString); e1Ptr->fullName = Blt_Strdup(Tcl_DStringValue(&dString)); } e1Ptr->dataObjPtr = Tcl_NewStringObj(e1Ptr->fullName, -1); if (e2Ptr->fullName == NULL) { Blt_TreeViewGetFullName(tvPtr, e2Ptr, TRUE, &dString); e2Ptr->fullName = Blt_Strdup(Tcl_DStringValue(&dString)); } e2Ptr->dataObjPtr = Tcl_NewStringObj(e2Ptr->fullName, -1); Tcl_DStringFree(&dString); } else { Blt_TreeKey key; Tcl_Obj *objPtr; key = tvPtr->sortColumnPtr->key; if (Blt_TreeViewGetData(e1Ptr, key, &objPtr) != TCL_OK) { e1Ptr->dataObjPtr = bltEmptyStringObjPtr; } else { e1Ptr->dataObjPtr = objPtr; } if (Blt_TreeViewGetData(e2Ptr, key, &objPtr) != TCL_OK) { e2Ptr->dataObjPtr = bltEmptyStringObjPtr; } else { e2Ptr->dataObjPtr = objPtr; } } return CompareEntries(&e1Ptr, &e2Ptr); } static int SortAutoOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; /* Not used. */ int objc; Tcl_Obj *CONST *objv; { if (objc == 4) { int bool; int isAuto; isAuto = ((tvPtr->flags & TV_SORT_AUTO) != 0); if (Tcl_GetBooleanFromObj(interp, objv[3], &bool) != TCL_OK) { return TCL_ERROR; } if (isAuto != bool) { tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT); Blt_TreeViewEventuallyRedraw(tvPtr); } if (bool) { tvPtr->flags |= TV_SORT_AUTO; } else { tvPtr->flags &= ~TV_SORT_AUTO; } } Tcl_SetObjResult(interp, Tcl_NewBooleanObj(tvPtr->flags & TV_SORT_AUTO)); return TCL_OK; } /* *---------------------------------------------------------------------- * * SortCgetOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int SortCgetOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { return Blt_ConfigureValueFromObj(interp, tvPtr->tkwin, sortSpecs, (char *)tvPtr, objv[3], 0); } /* *---------------------------------------------------------------------- * * SortConfigureOp -- * * This procedure is called to process a list of configuration * options database, in order to reconfigure the one of more * entries in the widget. * * .h sort configure option value * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for tvPtr; old resources get freed, if there * were any. The hypertext is redisplayed. * *---------------------------------------------------------------------- */ static int SortConfigureOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { int oldType; char *oldCommand; TreeViewColumn *oldColumn; if (objc == 3) { return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin, sortSpecs, (char *)tvPtr, (Tcl_Obj *)NULL, 0); } else if (objc == 4) { return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin, sortSpecs, (char *)tvPtr, objv[3], 0); } oldColumn = tvPtr->sortColumnPtr; oldType = tvPtr->sortType; oldCommand = tvPtr->sortCmd; if (Blt_ConfigureWidgetFromObj(interp, tvPtr->tkwin, sortSpecs, objc - 3, objv + 3, (char *)tvPtr, BLT_CONFIG_OBJV_ONLY) != TCL_OK) { return TCL_ERROR; } if ((oldColumn != tvPtr->sortColumnPtr) || (oldType != tvPtr->sortType) || (oldCommand != tvPtr->sortCmd)) { tvPtr->flags &= ~TV_SORTED; tvPtr->flags |= (TV_DIRTY | TV_RESORT); } if (tvPtr->flags & TV_SORT_AUTO) { tvPtr->flags |= TV_SORT_PENDING; } Blt_TreeViewEventuallyRedraw(tvPtr); return TCL_OK; } /*ARGSUSED*/ static int SortOnceOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; /* Not used. */ int objc; Tcl_Obj *CONST *objv; { TreeViewEntry *entryPtr; int recurse, result; register int i; recurse = FALSE; if (objc > 3) { char *string; int length; string = Tcl_GetStringFromObj(objv[3], &length); if ((string[0] == '-') && (length > 1) && (strncmp(string, "-recurse", length) == 0)) { objv++, objc--; recurse = TRUE; } } for (i = 3; i < objc; i++) { if (Blt_TreeViewGetEntry(tvPtr, objv[i], &entryPtr) != TCL_OK) { return TCL_ERROR; } if (recurse) { result = Blt_TreeApply(entryPtr->node, SortApplyProc, tvPtr); } else { result = SortApplyProc(entryPtr->node, tvPtr, TREE_PREORDER); } if (result != TCL_OK) { return TCL_ERROR; } } tvPtr->flags |= TV_LAYOUT; Blt_TreeViewEventuallyRedraw(tvPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * Blt_TreeViewSortOp -- * * Comparison routine (used by qsort) to sort a chain of subnodes. * A simple string comparison is performed on each node name. * * .h sort auto * .h sort once -recurse root * * Results: * 1 is the first is greater, -1 is the second is greater, 0 * if equal. * *---------------------------------------------------------------------- */ static Blt_OpSpec sortOps[] = { {"auto", 1, (Blt_Op)SortAutoOp, 3, 4, "?boolean?",}, {"cget", 2, (Blt_Op)SortCgetOp, 4, 4, "option",}, {"configure", 2, (Blt_Op)SortConfigureOp, 3, 0, "?option value?...",}, {"once", 1, (Blt_Op)SortOnceOp, 3, 0, "?-recurse? node...",}, }; static int nSortOps = sizeof(sortOps) / sizeof(Blt_OpSpec); /*ARGSUSED*/ int Blt_TreeViewSortOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; /* Not used. */ int objc; Tcl_Obj *CONST *objv; { Blt_Op proc; int result; proc = Blt_GetOpFromObj(interp, nSortOps, sortOps, BLT_OP_ARG2, objc, objv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (tvPtr, interp, objc, objv); return result; } /* *---------------------------------------------------------------------- * * SortApplyProc -- * * Sorts the subnodes at a given node. * * Results: * Always returns TCL_OK. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int SortApplyProc(node, clientData, order) Blt_TreeNode node; ClientData clientData; int order; /* Not used. */ { TreeView *tvPtr = clientData; if (!Blt_TreeIsLeaf(node)) { Blt_TreeSortNode(tvPtr->tree, node, CompareNodes); } return TCL_OK; } /* *---------------------------------------------------------------------- * * Blt_TreeViewSortFlatView -- * * Sorts the flatten array of entries. * *---------------------------------------------------------------------- */ void Blt_TreeViewSortFlatView(tvPtr) TreeView *tvPtr; { TreeViewEntry *entryPtr, **p; tvPtr->flags &= ~TV_SORT_PENDING; if ((tvPtr->sortType == SORT_TYPE_NONE) || (tvPtr->sortColumnPtr == NULL) || (tvPtr->nEntries == 1)) { return; } if (tvPtr->flags & TV_SORTED) { int first, last; TreeViewEntry *hold; if (tvPtr->sortDecreasing == tvPtr->viewIsDecreasing) { return; } /* * The view is already sorted but in the wrong direction. * Reverse the entries in the array. */ for (first = 0, last = tvPtr->nEntries - 1; last > first; first++, last--) { hold = tvPtr->flatArr[first]; tvPtr->flatArr[first] = tvPtr->flatArr[last]; tvPtr->flatArr[last] = hold; } tvPtr->viewIsDecreasing = tvPtr->sortDecreasing; tvPtr->flags |= TV_SORTED | TV_LAYOUT; return; } /* Fetch each entry's data as Tcl_Objs for sorting. */ if (tvPtr->sortColumnPtr == &tvPtr->treeColumn) { for(p = tvPtr->flatArr; *p != NULL; p++) { entryPtr = *p; if (entryPtr->fullName == NULL) { Tcl_DString dString; Blt_TreeViewGetFullName(tvPtr, entryPtr, TRUE, &dString); entryPtr->fullName = Blt_Strdup(Tcl_DStringValue(&dString)); Tcl_DStringFree(&dString); } entryPtr->dataObjPtr = Tcl_NewStringObj(entryPtr->fullName, -1); Tcl_IncrRefCount(entryPtr->dataObjPtr); } } else { Blt_TreeKey key; Tcl_Obj *objPtr; key = tvPtr->sortColumnPtr->key; for(p = tvPtr->flatArr; *p != NULL; p++) { entryPtr = *p; if (Blt_TreeViewGetData(entryPtr, key, &objPtr) != TCL_OK) { objPtr = bltEmptyStringObjPtr; } entryPtr->dataObjPtr = objPtr; Tcl_IncrRefCount(entryPtr->dataObjPtr); } } qsort((char *)tvPtr->flatArr, tvPtr->nEntries, sizeof(TreeViewEntry *), (QSortCompareProc *)CompareEntries); /* Free all the Tcl_Objs used for comparison data. */ for(p = tvPtr->flatArr; *p != NULL; p++) { Tcl_DecrRefCount((*p)->dataObjPtr); } tvPtr->viewIsDecreasing = tvPtr->sortDecreasing; tvPtr->flags |= TV_SORTED; } /* *---------------------------------------------------------------------- * * Blt_TreeViewSortTreeView -- * * Sorts the tree array of entries. * *---------------------------------------------------------------------- */ void Blt_TreeViewSortTreeView(tvPtr) TreeView *tvPtr; { tvPtr->flags &= ~TV_SORT_PENDING; if ((tvPtr->sortType != SORT_TYPE_NONE) && (tvPtr->sortColumnPtr != NULL)) { treeViewInstance = tvPtr; Blt_TreeApply(tvPtr->rootPtr->node, SortApplyProc, tvPtr); } tvPtr->viewIsDecreasing = tvPtr->sortDecreasing; } #endif /* NO_TREEVIEW */ blt-2.4z.orig/src/bltTreeViewEdit.c0100644000175000017500000014177207540713417015765 0ustar dokodoko/* Remember row,column where string was acquired. postcombobox x y icon?, text, row, column position, fg, bg button? based upon style. grab set SetIcon SetText SetBg SetFg SetFont SetButton */ /* * bltTreeViewEdit.c -- * * This module implements an hierarchy widget for the BLT toolkit. * * Copyright 1998-1999 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 or 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. * * The "treeview" widget was created by George A. Howlett. */ #include "bltInt.h" #ifndef NO_TREEVIEW #include "bltTreeView.h" #include #include #define TEXTBOX_FOCUS (1<<0) #define TEXTBOX_REDRAW (1<<1) static Tcl_IdleProc DisplayTextbox; static Tcl_FreeProc DestroyTextbox; static Tcl_TimerProc BlinkCursorProc; static Tcl_ObjCmdProc TextboxCmd; /* * Textbox -- * * This structure is shared by entries when their labels are * edited via the keyboard. It maintains the location of the * insertion cursor and the text selection for the editted entry. * The structure is shared since we need only one. The "focus" * entry should be the only entry receiving KeyPress/KeyRelease * events at any time. Information from the previously editted * entry is overwritten. * * Note that all the indices internally are in terms of bytes, * not characters. This is because UTF-8 strings may encode a * single character into a multi-byte sequence. To find the * respective character position * * n = Tcl_NumUtfChars(string, index); * * where n is the resulting character number. */ typedef struct { /* * This is a SNAFU in the Tk API. It assumes that only an official * Tk "toplevel" widget will ever become a toplevel window (i.e. a * window whose parent is the root window). Because under Win32, * Tk tries to use the widget record associated with the TopLevel * as a Tk frame widget, to read its menu name. What this means * is that any widget that's going to be a toplevel, must also look * like a frame. Therefore we've copied the frame widget structure * fields into the token. */ Tk_Window tkwin; /* Window that embodies the frame. NULL * means that the window has been destroyed * but the data structures haven't yet been * cleaned up. */ Display *display; /* Display containing widget. Used, among * other things, so that resources can be * freed even after tkwin has gone away. */ Tcl_Interp *interp; /* Interpreter associated with widget. Used * to delete widget command. */ Tcl_Command widgetCmd; /* Token for frame's widget command. */ char *className; /* Class name for widget (from configuration * option). Malloc-ed. */ int mask; /* Either FRAME or TOPLEVEL; used to select * which configuration options are valid for * widget. */ char *screenName; /* Screen on which widget is created. Non-null * only for top-levels. Malloc-ed, may be * NULL. */ char *visualName; /* Textual description of visual for window, * from -visual option. Malloc-ed, may be * NULL. */ char *colormapName; /* Textual description of colormap for window, * from -colormap option. Malloc-ed, may be * NULL. */ char *menuName; /* Textual description of menu to use for * menubar. Malloc-ed, may be NULL. */ Colormap colormap; /* If not None, identifies a colormap * allocated for this window, which must be * freed when the window is deleted. */ Tk_3DBorder border; /* Structure used to draw 3-D border and * background. NULL means no background * or border. */ int borderWidth; /* Width of 3-D border (if any). */ int relief; /* 3-d effect: TK_RELIEF_RAISED etc. */ int highlightWidth; /* Width in pixels of highlight to draw * around widget when it has the focus. * 0 means don't draw a highlight. */ XColor *highlightBgColorPtr; /* Color for drawing traversal highlight * area when highlight is off. */ XColor *highlightColorPtr; /* Color for drawing traversal highlight. */ int width; /* Width to request for window. <= 0 means * don't request any size. */ int height; /* Height to request for window. <= 0 means * don't request any size. */ Tk_Cursor cursor; /* Current cursor for window, or None. */ char *takeFocus; /* Value of -takefocus option; not used in * the C code, but used by keyboard traversal * scripts. Malloc'ed, but may be NULL. */ int isContainer; /* 1 means this window is a container, 0 means * that it isn't. */ char *useThis; /* If the window is embedded, this points to * the name of the window in which it is * embedded (malloc'ed). For non-embedded * windows this is NULL. */ int flags; /* Various flags; see below for * definitions. */ /* Textbox-specific fields */ TreeView *tvPtr; int x, y; /* Position of window. */ int active; /* Indicates that the frame is active. */ int exportSelection; int insertPos; /* Position of the cursor within the * array of bytes of the entry's label. */ int cursorX, cursorY; /* Position of the insertion cursor in the * textbox window. */ short int cursorWidth; /* Size of the insertion cursor symbol. */ short int cursorHeight; int selAnchor; /* Fixed end of selection. Used to extend * the selection while maintaining the * other end of the selection. */ int selFirst; /* Position of the first character in the * selection. */ int selLast; /* Position of the last character in the * selection. */ int cursorOn; /* Indicates if the cursor is displayed. */ int onTime, offTime; /* Time in milliseconds to wait before * changing the cursor from off-to-on * and on-to-off. Setting offTime to 0 makes * the cursor steady. */ Tcl_TimerToken timerToken; /* Handle for a timer event called periodically * to blink the cursor. */ /* Data-specific fields. */ TreeViewEntry *entryPtr; /* Selected entry */ TreeViewColumn *columnPtr; /* Column of entry to be edited */ TreeViewStyle *stylePtr; TreeViewIcon icon; int gap; char *string; TextLayout *textPtr; Tk_Font font; GC gc; Tk_3DBorder selBorder; int selRelief; int selBorderWidth; XColor *selFgColor; /* Text color of a selected entry. */ int buttonBorderWidth; Tk_3DBorder buttonBorder; int buttonRelief; } Textbox; #define DEF_TEXTBOX_BACKGROUND RGB_WHITE #define DEF_TEXTBOX_BORDERWIDTH STD_BORDERWIDTH #ifdef WIN32 #define DEF_TEXTBOX_BUTTON_BACKGROUND RGB_GREY85 #else #define DEF_TEXTBOX_BUTTON_BACKGROUND RGB_GREY90 #endif #define DEF_TEXTBOX_BUTTON_BORDERWIDTH "2" #define DEF_TEXTBOX_BUTTON_RELIEF "raised" #define DEF_TEXTBOX_CURSOR (char *)NULL #define DEF_TEXTBOX_EXPORT_SELECTION "no" #define DEF_TEXTBOX_NORMAL_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_TEXTBOX_NORMAL_FG_MONO STD_ACTIVE_FG_MONO #define DEF_TEXTBOX_RELIEF "sunken" #define DEF_TEXTBOX_SELECT_BACKGROUND RGB_LIGHTBLUE0 #define DEF_TEXTBOX_SELECT_BG_MONO STD_SELECT_BG_MONO #define DEF_TEXTBOX_SELECT_BORDERWIDTH "1" #define DEF_TEXTBOX_SELECT_FOREGROUND STD_SELECT_FOREGROUND #define DEF_TEXTBOX_SELECT_FG_MONO STD_SELECT_FG_MONO #define DEF_TEXTBOX_SELECT_RELIEF "flat" /* Textbox Procedures */ static Blt_ConfigSpec textboxConfigSpecs[] = { {BLT_CONFIG_BORDER, "-background", "background", "Background", DEF_TEXTBOX_BACKGROUND, Blt_Offset(Textbox, border), 0}, {BLT_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0,0}, {BLT_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0,0}, {BLT_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", DEF_TEXTBOX_CURSOR, Blt_Offset(Textbox, cursor), BLT_CONFIG_NULL_OK}, {BLT_CONFIG_DISTANCE, "-borderwidth", "borderWidth", "BorderWidth", DEF_TEXTBOX_BORDERWIDTH, Blt_Offset(Textbox, borderWidth), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_BORDER, "-buttonbackground", "buttonBackground", "ButtonBackground", DEF_TEXTBOX_BUTTON_BACKGROUND, Blt_Offset(Textbox, buttonBorder), 0}, {BLT_CONFIG_RELIEF, "-buttonrelief", "buttonRelief", "ButtonRelief", DEF_TEXTBOX_BUTTON_RELIEF, Blt_Offset(Textbox, buttonRelief), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_DISTANCE, "-buttonborderwidth", "buttonBorderWidth", "ButtonBorderWidth", DEF_TEXTBOX_BUTTON_BORDERWIDTH, Blt_Offset(Textbox, buttonBorderWidth), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_BOOLEAN, "-exportselection", "exportSelection", "ExportSelection", DEF_TEXTBOX_EXPORT_SELECTION, Blt_Offset(Textbox, exportSelection), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_TEXTBOX_RELIEF, Blt_Offset(Textbox, relief), 0}, {BLT_CONFIG_BORDER, "-selectbackground", "selectBackground", "Background", DEF_TEXTBOX_SELECT_BG_MONO, Blt_Offset(Textbox, selBorder), BLT_CONFIG_MONO_ONLY}, {BLT_CONFIG_BORDER, "-selectbackground", "selectBackground", "Background", DEF_TEXTBOX_SELECT_BACKGROUND, Blt_Offset(Textbox, selBorder), BLT_CONFIG_COLOR_ONLY}, {BLT_CONFIG_DISTANCE, "-selectborderwidth", "selectBorderWidth", "BorderWidth", DEF_TEXTBOX_SELECT_BORDERWIDTH, Blt_Offset(Textbox, selBorderWidth), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_COLOR, "-selectforeground", "selectForeground", "Foreground", DEF_TEXTBOX_SELECT_FG_MONO, Blt_Offset(Textbox, selFgColor), BLT_CONFIG_MONO_ONLY}, {BLT_CONFIG_COLOR, "-selectforeground", "selectForeground", "Foreground", DEF_TEXTBOX_SELECT_FOREGROUND, Blt_Offset(Textbox, selFgColor), BLT_CONFIG_COLOR_ONLY}, {BLT_CONFIG_RELIEF, "-selectrelief", "selectRelief", "Relief", DEF_TEXTBOX_SELECT_RELIEF, Blt_Offset(Textbox, selRelief), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; static Tk_LostSelProc TextboxLostSelectionProc; static Tk_SelectionProc TextboxSelectionProc; static Tk_EventProc TextboxEventProc; /* *---------------------------------------------------------------------- * * EventuallyRedraw -- * * Queues a request to redraw the widget at the next idle point. * * Results: * None. * * Side effects: * Information gets redisplayed. Right now we don't do selective * redisplays: the whole window will be redrawn. * *---------------------------------------------------------------------- */ static void EventuallyRedraw(tbPtr) Textbox *tbPtr; { if ((tbPtr->tkwin != NULL) && ((tbPtr->flags & TEXTBOX_REDRAW) == 0)) { tbPtr->flags |= TEXTBOX_REDRAW; Tcl_DoWhenIdle(DisplayTextbox, tbPtr); } } /* *---------------------------------------------------------------------- * * BlinkCursorProc -- * * This procedure is called as a timer handler to blink the * insertion cursor off and on. * * Results: * None. * * Side effects: * The cursor gets turned on or off, redisplay gets invoked, * and this procedure reschedules itself. * *---------------------------------------------------------------------- */ static void BlinkCursorProc(clientData) ClientData clientData; /* Pointer to record describing entry. */ { Textbox *tbPtr = clientData; int interval; if (!(tbPtr->flags & TEXTBOX_FOCUS) || (tbPtr->offTime == 0)) { return; } if (tbPtr->active) { tbPtr->cursorOn ^= 1; interval = (tbPtr->cursorOn) ? tbPtr->onTime : tbPtr->offTime; tbPtr->timerToken = Tcl_CreateTimerHandler(interval, BlinkCursorProc, tbPtr); EventuallyRedraw(tbPtr); } } /* * -------------------------------------------------------------- * * TextboxEventProc -- * * This procedure is invoked by the Tk dispatcher for various * events on treeview widgets. * * Results: * None. * * Side effects: * When the window gets deleted, internal structures get * cleaned up. When it gets exposed, it is redisplayed. * * -------------------------------------------------------------- */ static void TextboxEventProc(clientData, eventPtr) ClientData clientData; /* Information about window. */ XEvent *eventPtr; /* Information about event. */ { Textbox *tbPtr = clientData; if (eventPtr->type == Expose) { if (eventPtr->xexpose.count == 0) { EventuallyRedraw(tbPtr); } } else if (eventPtr->type == ConfigureNotify) { EventuallyRedraw(tbPtr); } else if ((eventPtr->type == FocusIn) || (eventPtr->type == FocusOut)) { if (eventPtr->xfocus.detail == NotifyInferior) { return; } if (eventPtr->type == FocusIn) { tbPtr->flags |= TEXTBOX_FOCUS; } else { tbPtr->flags &= ~TEXTBOX_FOCUS; } Tcl_DeleteTimerHandler(tbPtr->timerToken); if ((tbPtr->active) && (tbPtr->flags & TEXTBOX_FOCUS)) { tbPtr->cursorOn = TRUE; if (tbPtr->offTime != 0) { tbPtr->timerToken = Tcl_CreateTimerHandler(tbPtr->onTime, BlinkCursorProc, tbPtr); } } else { tbPtr->cursorOn = FALSE; tbPtr->timerToken = (Tcl_TimerToken) NULL; } EventuallyRedraw(tbPtr); } else if (eventPtr->type == DestroyNotify) { if (tbPtr->tkwin != NULL) { tbPtr->tkwin = NULL; } if (tbPtr->flags & TEXTBOX_REDRAW) { Tcl_CancelIdleCall(DisplayTextbox, tbPtr); } if (tbPtr->timerToken != NULL) { Tcl_DeleteTimerHandler(tbPtr->timerToken); } tbPtr->tvPtr->comboWin = NULL; Tcl_EventuallyFree(tbPtr, DestroyTextbox); } } /* *---------------------------------------------------------------------- * * TextboxLostSelectionProc -- * * This procedure is called back by Tk when the selection is * grabbed away from a Text widget. * * Results: * None. * * Side effects: * The existing selection is unhighlighted, and the window is * marked as not containing a selection. * *---------------------------------------------------------------------- */ static void TextboxLostSelectionProc(clientData) ClientData clientData; /* Information about Text widget. */ { Textbox *tbPtr = clientData; if ((tbPtr->selFirst >= 0) && (tbPtr->exportSelection)) { tbPtr->selFirst = tbPtr->selLast = -1; EventuallyRedraw(tbPtr); } } static int PointerToIndex(tbPtr, x, y) Textbox *tbPtr; int x, y; { TextLayout *textPtr; Tk_FontMetrics fontMetrics; TextFragment *fragPtr; int nBytes; register int i; int total; if ((tbPtr->string == NULL) || (tbPtr->string[0] == '\0')) { return 0; } x -= tbPtr->selBorderWidth; y -= tbPtr->selBorderWidth; textPtr = tbPtr->textPtr; /* Bound the y-coordinate within the window. */ if (y < 0) { y = 0; } else if (y >= textPtr->height) { y = textPtr->height - 1; } /* * Compute the line that contains the y-coordinate. * * FIXME: This assumes that segments are distributed * line-by-line. This may change in the future. */ Tk_GetFontMetrics(tbPtr->font, &fontMetrics); fragPtr = textPtr->fragArr; total = 0; for (i = (y / fontMetrics.linespace); i > 0; i--) { total += fragPtr->count; fragPtr++; } if (x < 0) { nBytes = 0; } else if (x >= textPtr->width) { nBytes = fragPtr->count; } else { int newX; /* Find the character underneath the pointer. */ nBytes = Tk_MeasureChars(tbPtr->font, fragPtr->text, fragPtr->count, x, 0, &newX); if ((newX < x) && (nBytes < fragPtr->count)) { double fract; int length, charSize; char *next; next = fragPtr->text + nBytes; #if HAVE_UTF { Tcl_UniChar dummy; length = Tcl_UtfToUniChar(next, &dummy); } #else length = 1; #endif charSize = Tk_TextWidth(tbPtr->font, next, length); fract = ((double)(x - newX) / (double)charSize); if (ROUND(fract)) { nBytes += length; } } } return nBytes + total; } static int IndexToPointer(tbPtr) Textbox *tbPtr; { int x, y; int maxLines; TextLayout *textPtr; Tk_FontMetrics fontMetrics; int nBytes; int sum; TextFragment *fragPtr; register int i; textPtr = tbPtr->textPtr; Tk_GetFontMetrics(tbPtr->font, &fontMetrics); maxLines = (textPtr->height / fontMetrics.linespace) - 1; sum = 0; x = y = tbPtr->borderWidth; if (tbPtr->icon != NULL) { x += TreeViewIconWidth(tbPtr->icon) + 2 * tbPtr->gap; } fragPtr = textPtr->fragArr; for (i = 0; i <= maxLines; i++) { /* Total the number of bytes on each line. Include newlines. */ nBytes = fragPtr->count + 1; if ((sum + nBytes) > tbPtr->insertPos) { x += Tk_TextWidth(tbPtr->font, fragPtr->text, tbPtr->insertPos - sum); break; } y += fontMetrics.linespace; sum += nBytes; fragPtr++; } tbPtr->cursorX = x; tbPtr->cursorY = y; tbPtr->cursorHeight = fontMetrics.linespace; tbPtr->cursorWidth = 3; return TCL_OK; } static void UpdateLayout(tbPtr) Textbox *tbPtr; { TextStyle ts; int width, height; TextLayout *textPtr; int gap; int iconWidth, iconHeight; gap = iconWidth = iconHeight = 0; if (tbPtr->icon != NULL) { iconWidth = TreeViewIconWidth(tbPtr->icon) + 4; iconHeight = TreeViewIconHeight(tbPtr->icon); gap = tbPtr->gap; } /* The layout is based upon the current font. */ Blt_InitTextStyle(&ts); ts.anchor = TK_ANCHOR_NW; ts.justify = TK_JUSTIFY_LEFT; ts.font = tbPtr->font; textPtr = Blt_GetTextLayout(tbPtr->string, &ts); if (tbPtr->textPtr != NULL) { Blt_Free(tbPtr->textPtr); } tbPtr->textPtr = textPtr; width = iconWidth + textPtr->width + gap * 2; height = MAX(iconHeight, textPtr->height); if (width <= tbPtr->columnPtr->width) { width = tbPtr->columnPtr->width; } if (height < tbPtr->entryPtr->height) { height = tbPtr->entryPtr->height; } tbPtr->width = width + (2 * tbPtr->borderWidth); tbPtr->height = height + (2 * tbPtr->borderWidth); IndexToPointer(tbPtr); Tk_MoveResizeWindow(tbPtr->tkwin, tbPtr->x, tbPtr->y, tbPtr->width, tbPtr->height); Tk_MapWindow(tbPtr->tkwin); XRaiseWindow(tbPtr->display, Tk_WindowId(tbPtr->tkwin)); } static void InsertText(tbPtr, insertText, insertPos, nBytes) Textbox *tbPtr; char *insertText; int insertPos; int nBytes; { int oldSize, newSize; char *oldText, *newText; oldText = tbPtr->string; oldSize = strlen(oldText); newSize = oldSize + nBytes; newText = Blt_Malloc(sizeof(char) * (newSize + 1)); if (insertPos == oldSize) { /* Append */ strcpy(newText, oldText); strcat(newText, insertText); } else if (insertPos == 0) {/* Prepend */ strcpy(newText, insertText); strcat(newText, oldText); } else { /* Insert into existing. */ char *p; p = newText; strncpy(p, oldText, insertPos); p += insertPos; strcpy(p, insertText); p += nBytes; strcpy(p, oldText + insertPos); } /* * All indices from the start of the insertion to the end of the * string need to be updated. Simply move the indices down by the * number of characters added. */ if (tbPtr->selFirst >= insertPos) { tbPtr->selFirst += nBytes; } if (tbPtr->selLast > insertPos) { tbPtr->selLast += nBytes; } if ((tbPtr->selAnchor > insertPos) || (tbPtr->selFirst >= insertPos)) { tbPtr->selAnchor += nBytes; } if (tbPtr->string != NULL) { Blt_Free(tbPtr->string); } tbPtr->string = newText; tbPtr->insertPos = insertPos + nBytes; UpdateLayout(tbPtr); } static int DeleteText(tbPtr, firstPos, lastPos) Textbox *tbPtr; int firstPos, lastPos; { char *oldText, *newText; int oldSize, newSize; int nBytes; char *p; oldText = tbPtr->string; if (firstPos > lastPos) { return TCL_OK; } lastPos++; /* Now is the position after the last * character. */ nBytes = lastPos - firstPos; oldSize = strlen(oldText) + 1; newSize = oldSize - nBytes + 1; newText = Blt_Malloc(sizeof(char) * newSize); p = newText; if (firstPos > 0) { strncpy(p, oldText, firstPos); p += firstPos; } *p = '\0'; if (lastPos < oldSize) { strcpy(p, oldText + lastPos); } Blt_Free(oldText); /* * Since deleting characters compacts the character array, we need to * update the various character indices according. It depends where * the index occurs in relation to range of deleted characters: * * before Ignore. * within Move the index back to the start of the deletion. * after Subtract off the deleted number of characters, * since the array has been compressed by that * many characters. * */ if (tbPtr->selFirst >= firstPos) { if (tbPtr->selFirst >= lastPos) { tbPtr->selFirst -= nBytes; } else { tbPtr->selFirst = firstPos; } } if (tbPtr->selLast >= firstPos) { if (tbPtr->selLast >= lastPos) { tbPtr->selLast -= nBytes; } else { tbPtr->selLast = firstPos; } } if (tbPtr->selLast <= tbPtr->selFirst) { tbPtr->selFirst = tbPtr->selLast = -1; /* Cut away the entire * selection. */ } if (tbPtr->selAnchor >= firstPos) { if (tbPtr->selAnchor >= lastPos) { tbPtr->selAnchor -= nBytes; } else { tbPtr->selAnchor = firstPos; } } if (tbPtr->insertPos >= firstPos) { if (tbPtr->insertPos >= lastPos) { tbPtr->insertPos -= nBytes; } else { tbPtr->insertPos = firstPos; } } tbPtr->string = newText; UpdateLayout(tbPtr); EventuallyRedraw(tbPtr); return TCL_OK; } static int AcquireText(tvPtr, tbPtr, entryPtr, columnPtr) TreeView *tvPtr; Textbox *tbPtr; TreeViewEntry *entryPtr; TreeViewColumn *columnPtr; { TreeViewStyle *stylePtr; int x, y; char *string; TreeViewIcon icon; if (columnPtr == &tvPtr->treeColumn) { int level; level = DEPTH(tvPtr, entryPtr->node); x = SCREENX(tvPtr, entryPtr->worldX); y = SCREENY(tvPtr, entryPtr->worldY); x += ICONWIDTH(level) + ICONWIDTH(level + 1) + 4; string = GETLABEL(entryPtr); stylePtr = columnPtr->stylePtr; icon = Blt_TreeViewGetEntryIcon(tvPtr, entryPtr); } else { TreeViewValue *valuePtr; x = SCREENX(tvPtr, columnPtr->worldX); y = SCREENY(tvPtr, entryPtr->worldY); stylePtr = columnPtr->stylePtr; valuePtr = Blt_TreeViewFindValue(entryPtr, columnPtr); string = valuePtr->string; if (valuePtr->stylePtr != NULL) { stylePtr = valuePtr->stylePtr; } icon = stylePtr->icon; } if (tbPtr->textPtr != NULL) { Blt_Free(tbPtr->textPtr); tbPtr->textPtr = NULL; } if (tbPtr->string != NULL) { Blt_Free(tbPtr->string); } if (string == NULL) { string = ""; } tbPtr->icon = icon; tbPtr->entryPtr = entryPtr; tbPtr->columnPtr = columnPtr; tbPtr->x = x - tbPtr->borderWidth; tbPtr->y = y - tbPtr->borderWidth; tbPtr->gap = stylePtr->gap; tbPtr->string = Blt_Strdup(string); tbPtr->gc = Blt_TreeViewGetStyleGC(stylePtr); tbPtr->font = Blt_TreeViewGetStyleFont(tvPtr, stylePtr); tbPtr->selFirst = tbPtr->selLast = -1; UpdateLayout(tbPtr); Tk_MapWindow(tbPtr->tkwin); EventuallyRedraw(tbPtr); return TCL_OK; } /* *--------------------------------------------------------------------------- * * GetIndexFromObj -- * * Parse an index into an entry and return either its value * or an error. * * Results: * A standard Tcl result. If all went well, then *indexPtr is * filled in with the character index (into entryPtr) corresponding to * string. The index value is guaranteed to lie between 0 and * the number of characters in the string, inclusive. If an * error occurs then an error message is left in the interp's result. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int GetIndexFromObj(interp, tbPtr, objPtr, indexPtr) Tcl_Interp *interp; Textbox *tbPtr; Tcl_Obj *objPtr; int *indexPtr; { int textPos; char c; char *string; string = Tcl_GetString(objPtr); if ((tbPtr->string == NULL) || (tbPtr->string[0] == '\0')) { *indexPtr = 0; return TCL_OK; } c = string[0]; if ((c == 'a') && (strcmp(string, "anchor") == 0)) { textPos = tbPtr->selAnchor; } else if ((c == 'e') && (strcmp(string, "end") == 0)) { textPos = strlen(tbPtr->string); } else if ((c == 'i') && (strcmp(string, "insert") == 0)) { textPos = tbPtr->insertPos; } else if ((c == 'n') && (strcmp(string, "next") == 0)) { textPos = tbPtr->insertPos; if (textPos < (int)strlen(tbPtr->string)) { textPos++; } } else if ((c == 'l') && (strcmp(string, "last") == 0)) { textPos = tbPtr->insertPos; if (textPos > 0) { textPos--; } } else if ((c == 's') && (strcmp(string, "sel.first") == 0)) { if (tbPtr->selFirst < 0) { textPos = -1; } else { textPos = tbPtr->selFirst; } } else if ((c == 's') && (strcmp(string, "sel.last") == 0)) { if (tbPtr->selLast < 0) { textPos = -1; } else { textPos = tbPtr->selLast; } } else if (c == '@') { int x, y; if (Blt_GetXY(interp, tbPtr->tkwin, string, &x, &y) != TCL_OK) { return TCL_ERROR; } textPos = PointerToIndex(tbPtr, x, y); } else if (isdigit((int)c)) { int number; int maxChars; if (Tcl_GetIntFromObj(interp, objPtr, &number) != TCL_OK) { return TCL_ERROR; } /* Don't allow the index to point outside the label. */ maxChars = Tcl_NumUtfChars(tbPtr->string, -1); if (number < 0) { textPos = 0; } else if (number > maxChars) { textPos = strlen(tbPtr->string); } else { textPos = Tcl_UtfAtIndex(tbPtr->string, number) - tbPtr->string; } } else { if (interp != NULL) { Tcl_AppendResult(interp, "bad label index \"", string, "\"", (char *)NULL); } return TCL_ERROR; } *indexPtr = textPos; return TCL_OK; } /* *---------------------------------------------------------------------- * * SelectText -- * * Modify the selection by moving its un-anchored end. This * could make the selection either larger or smaller. * * Results: * None. * * Side effects: * The selection changes. * *---------------------------------------------------------------------- */ static int SelectText(tbPtr, textPos) Textbox *tbPtr; /* Information about textbox. */ int textPos; /* Index of element that is to * become the "other" end of the * selection. */ { int selFirst, selLast; /* * Grab the selection if we don't own it already. */ if ((tbPtr->exportSelection) && (tbPtr->selFirst == -1)) { Tk_OwnSelection(tbPtr->tkwin, XA_PRIMARY, TextboxLostSelectionProc, tbPtr); } /* If the anchor hasn't been set yet, assume the beginning of the text*/ if (tbPtr->selAnchor < 0) { tbPtr->selAnchor = 0; } if (tbPtr->selAnchor <= textPos) { selFirst = tbPtr->selAnchor; selLast = textPos; } else { selFirst = textPos; selLast = tbPtr->selAnchor; } if ((tbPtr->selFirst != selFirst) || (tbPtr->selLast != selLast)) { tbPtr->selFirst = selFirst; tbPtr->selLast = selLast; EventuallyRedraw(tbPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TextboxSelectionProc -- * * This procedure is called back by Tk when the selection is * requested by someone. It returns part or all of the selection * in a buffer provided by the caller. * * Results: * The return value is the number of non-NULL bytes stored at * buffer. Buffer is filled (or partially filled) with a * NUL-terminated string containing part or all of the * selection, as given by offset and maxBytes. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TextboxSelectionProc(clientData, offset, buffer, maxBytes) ClientData clientData; /* Information about the widget. */ int offset; /* Offset within selection of first * character to be returned. */ char *buffer; /* Location in which to place * selection. */ int maxBytes; /* Maximum number of bytes to place * at buffer, not including terminating * NULL character. */ { Textbox *tbPtr = clientData; int size; size = strlen(tbPtr->string + offset); /* * Return the string currently in the textbox. */ strncpy(buffer, tbPtr->string + offset, maxBytes); buffer[maxBytes] = '\0'; return (size > maxBytes) ? maxBytes : size; } static void DestroyTextbox(data) DestroyData data; { Textbox *tbPtr = (Textbox *)data; Blt_FreeObjOptions(textboxConfigSpecs, (char *)tbPtr, tbPtr->display, 0); if (tbPtr->string != NULL) { Blt_Free(tbPtr->string); } if (tbPtr->textPtr != NULL) { Blt_Free(tbPtr->textPtr); } if (tbPtr->timerToken != NULL) { Tcl_DeleteTimerHandler(tbPtr->timerToken); } if (tbPtr->tkwin != NULL) { Tk_DeleteSelHandler(tbPtr->tkwin, XA_PRIMARY, XA_STRING); } Blt_Free(tbPtr); } static void ConfigureTextbox(tbPtr) Textbox *tbPtr; { #ifdef notdef GC newGC; Textbox *tbPtr = tvPtr->tbPtr; XGCValues gcValues; unsigned long gcMask; /* * GC for edit window. */ gcMask = 0; newGC = Tk_GetGC(tbPtr->tkwin, gcMask, &gcValues); if (tbPtr->gc != NULL) { Tk_FreeGC(tbPtr->display, tbPtr->gc); } tbPtr->gc = newGC; tbPtr->width = tbPtr->textPtr->width + 2 * (tbPtr->borderWidth + tbPtr->highlightWidth); tbPtr->height = tbPtr->textPtr->height + 2 * (tbPtr->borderWidth + tbPtr->highlightWidth); if (Tk_IsMapped(tbPtr->tkwin)) { if ((tbPtr->height != Tk_Height(tbPtr->tkwin)) || (tbPtr->width != Tk_Width(tbPtr->tkwin))) { Tk_ResizeWindow(tbPtr->tkwin, tbPtr->width, tbPtr->height); } } #endif } int Blt_TreeViewTextbox(tvPtr, entryPtr, columnPtr) TreeView *tvPtr; TreeViewEntry *entryPtr; TreeViewColumn *columnPtr; { Tk_Window tkwin; Textbox *tbPtr; char editClass[20]; if (tvPtr->comboWin != NULL) { Tk_DestroyWindow(tvPtr->comboWin); } tkwin = Tk_CreateWindow(tvPtr->interp, tvPtr->tkwin, "edit", (char *)NULL); if (tkwin == NULL) { return TCL_ERROR; } Tk_MakeWindowExist(tkwin); sprintf(editClass, "%sEditor", Tk_Class(tvPtr->tkwin)); Tk_SetClass(tkwin, editClass); tbPtr = Blt_Calloc(1, sizeof(Textbox)); assert(tbPtr); tbPtr->interp = tvPtr->interp; tbPtr->display = Tk_Display(tkwin); tbPtr->tkwin = tkwin; tbPtr->borderWidth = 1; tbPtr->relief = TK_RELIEF_SOLID; tbPtr->selRelief = TK_RELIEF_FLAT; tbPtr->selBorderWidth = 1; tbPtr->selAnchor = -1; tbPtr->selFirst = tbPtr->selLast = -1; tbPtr->onTime = 600; tbPtr->active = TRUE; tbPtr->offTime = 300; tbPtr->tvPtr = tvPtr; tbPtr->buttonRelief = TK_RELIEF_SUNKEN; tbPtr->buttonBorderWidth = 1; tvPtr->comboWin = tkwin; #if (TK_MAJOR_VERSION > 4) Blt_SetWindowInstanceData(tkwin, tbPtr); #endif Tk_CreateSelHandler(tkwin, XA_PRIMARY, XA_STRING, TextboxSelectionProc, tbPtr, XA_STRING); Tk_CreateEventHandler(tkwin, ExposureMask | StructureNotifyMask | FocusChangeMask, TextboxEventProc, tbPtr); Tcl_CreateObjCommand(tvPtr->interp, Tk_PathName(tkwin), TextboxCmd, tbPtr, NULL); if (Blt_ConfigureWidgetFromObj(tvPtr->interp, tkwin, textboxConfigSpecs, 0, (Tcl_Obj **)NULL, (char *)tbPtr, 0) != TCL_OK) { Tk_DestroyWindow(tkwin); return TCL_ERROR; } AcquireText(tvPtr, tbPtr, entryPtr, columnPtr); tbPtr->insertPos = strlen(tbPtr->string); Tk_MoveResizeWindow(tkwin, tbPtr->x, tbPtr->y, tbPtr->width, tbPtr->height); Tk_MapWindow(tkwin); Tk_MakeWindowExist(tkwin); XRaiseWindow(tbPtr->display, Tk_WindowId(tkwin)); EventuallyRedraw(tbPtr); return TCL_OK; } static void DisplayTextbox(clientData) ClientData clientData; { Textbox *tbPtr = clientData; Pixmap drawable; register int i; int x1, x2; int count, nChars; int leftPos, rightPos; int selStart, selEnd, selLength; int x, y; TextFragment *fragPtr; Tk_FontMetrics fontMetrics; #ifdef notdef int buttonX, buttonY, buttonWidth, buttonHeight; #endif tbPtr->flags &= ~TEXTBOX_REDRAW; if (!Tk_IsMapped(tbPtr->tkwin)) { return; } if (tbPtr->columnPtr == NULL) { return; } drawable = Tk_GetPixmap(tbPtr->display, Tk_WindowId(tbPtr->tkwin), Tk_Width(tbPtr->tkwin), Tk_Height(tbPtr->tkwin), Tk_Depth(tbPtr->tkwin)); Blt_Fill3DRectangle(tbPtr->tkwin, drawable, tbPtr->border, 0, 0, Tk_Width(tbPtr->tkwin), Tk_Height(tbPtr->tkwin), tbPtr->borderWidth, tbPtr->relief); x = tbPtr->borderWidth + tbPtr->gap; y = tbPtr->borderWidth; #ifdef notdef buttonX = Tk_Width(tbPtr->tkwin) - (tbPtr->borderWidth + tbPtr->gap + 1); buttonY = tbPtr->borderWidth + 1; #endif if (tbPtr->icon != NULL) { y += (tbPtr->height - TreeViewIconHeight(tbPtr->icon)) / 2; Tk_RedrawImage(TreeViewIconBits(tbPtr->icon), 0, 0, TreeViewIconWidth(tbPtr->icon), TreeViewIconHeight(tbPtr->icon), drawable, x, y); x += TreeViewIconWidth(tbPtr->icon) + tbPtr->gap; } Tk_GetFontMetrics(tbPtr->font, &fontMetrics); fragPtr = tbPtr->textPtr->fragArr; count = 0; y = tbPtr->borderWidth; if (tbPtr->height > fontMetrics.linespace) { y += (tbPtr->height - fontMetrics.linespace) / 2; } for (i = 0; i < tbPtr->textPtr->nFrags; i++, fragPtr++) { leftPos = count; count += fragPtr->count; rightPos = count; if ((rightPos < tbPtr->selFirst) || (leftPos > tbPtr->selLast)) { /* No part of the text fragment is selected. */ Tk_DrawChars(tbPtr->display, drawable, tbPtr->gc, tbPtr->font, fragPtr->text, fragPtr->count, x + fragPtr->x, y + fragPtr->y); continue; } /* * A text fragment can have up to 3 regions: * * 1. Text before the start the selection * 2. Selected text itself (drawn in a raised border) * 3. Text following the selection. */ selStart = leftPos; selEnd = rightPos; /* First adjust selected region for current line. */ if (tbPtr->selFirst > leftPos) { selStart = tbPtr->selFirst; } if (tbPtr->selLast < rightPos) { selEnd = tbPtr->selLast; } selLength = (selEnd - selStart); x1 = x; if (selStart > leftPos) { /* Normal text preceding the selection */ nChars = (selStart - leftPos); Tk_MeasureChars(tbPtr->font, tbPtr->string + leftPos, nChars, 10000, DEF_TEXT_FLAGS, &x1); x1 += x; } if (selLength > 0) { /* The selection itself */ int width; Tk_MeasureChars(tbPtr->font, fragPtr->text + selStart, selLength, 10000, DEF_TEXT_FLAGS, &x2); x2 += x; width = (x2 - x1) + 1; Blt_Fill3DRectangle(tbPtr->tkwin, drawable, tbPtr->selBorder, x1, y + fragPtr->y - fontMetrics.ascent, width, fontMetrics.linespace, tbPtr->selBorderWidth, tbPtr->selRelief); } Tk_DrawChars(Tk_Display(tbPtr->tkwin), drawable, tbPtr->gc, tbPtr->font, fragPtr->text, fragPtr->count, fragPtr->x + x, fragPtr->y + y); } if ((tbPtr->flags & TEXTBOX_FOCUS) && (tbPtr->cursorOn)) { int left, top, right, bottom; IndexToPointer(tbPtr); left = tbPtr->cursorX + 1; right = left + 1; top = tbPtr->cursorY; if (tbPtr->height > fontMetrics.linespace) { top += (tbPtr->height - fontMetrics.linespace) / 2; } bottom = top + tbPtr->cursorHeight - 1; XDrawLine(tbPtr->display, drawable, tbPtr->gc, left, top, left, bottom); XDrawLine(tbPtr->display, drawable, tbPtr->gc, left - 1, top, right, top); XDrawLine(tbPtr->display, drawable, tbPtr->gc, left - 1, bottom, right, bottom); } #ifdef notdef buttonWidth = STD_ARROW_WIDTH + 6 + 2 * tbPtr->buttonBorderWidth; buttonX -= buttonWidth; buttonHeight = Tk_Height(tbPtr->tkwin) - 4; Blt_Fill3DRectangle(tbPtr->tkwin, drawable, tbPtr->buttonBorder, buttonX, buttonY, buttonWidth, buttonHeight, tbPtr->buttonBorderWidth, tbPtr->buttonRelief); buttonX += buttonWidth / 2; buttonY = tbPtr->height / 2; Blt_DrawArrow(tbPtr->display, drawable, tbPtr->gc, buttonX, buttonY, STD_ARROW_HEIGHT, ARROW_DOWN); #endif Blt_Draw3DRectangle(tbPtr->tkwin, drawable, tbPtr->border, 0, 0, Tk_Width(tbPtr->tkwin), Tk_Height(tbPtr->tkwin), tbPtr->borderWidth, tbPtr->relief); XCopyArea(tbPtr->display, drawable, Tk_WindowId(tbPtr->tkwin), tbPtr->gc, 0, 0, Tk_Width(tbPtr->tkwin), Tk_Height(tbPtr->tkwin), 0, 0); Tk_FreePixmap(tbPtr->display, drawable); } /*ARGSUSED*/ static int ApplyOp(tbPtr, interp, objc, objv) Textbox *tbPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; /* Not used. */ { TreeViewEntry *entryPtr; TreeView *tvPtr = tbPtr->tvPtr; entryPtr = tbPtr->entryPtr; if (tbPtr->columnPtr == &tvPtr->treeColumn) { if (entryPtr->labelUid != NULL) { Blt_TreeViewFreeUid(tvPtr, entryPtr->labelUid); } if (tbPtr->string == NULL) { entryPtr->labelUid = Blt_TreeViewGetUid(tvPtr, ""); } else { entryPtr->labelUid = Blt_TreeViewGetUid(tvPtr, tbPtr->string); } } else { TreeViewColumn *columnPtr; Tcl_Obj *objPtr; columnPtr = tbPtr->columnPtr; objPtr = Tcl_NewStringObj(tbPtr->string, -1); if (Blt_TreeSetValueByKey(interp, tvPtr->tree, entryPtr->node, columnPtr->key, objPtr) != TCL_OK) { Tcl_DecrRefCount(objPtr); return TCL_ERROR; } entryPtr->flags |= ENTRY_DIRTY; } if (tvPtr != NULL) { Blt_TreeViewConfigureEntry(tvPtr, entryPtr, 0, NULL, BLT_CONFIG_OBJV_ONLY); tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT); Blt_TreeViewEventuallyRedraw(tvPtr); } Tk_DestroyWindow(tbPtr->tkwin); return TCL_OK; } /*ARGSUSED*/ static int CancelOp(tbPtr, interp, objc, objv) Textbox *tbPtr; Tcl_Interp *interp; /* Not used. */ int objc; /* Not used. */ Tcl_Obj *CONST *objv; /* Not used. */ { Tk_DestroyWindow(tbPtr->tkwin); return TCL_OK; } /* *---------------------------------------------------------------------- * * CgetOp -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int CgetOp(tbPtr, interp, objc, objv) Textbox *tbPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { return Blt_ConfigureValueFromObj(interp, tbPtr->tkwin, textboxConfigSpecs, (char *)tbPtr, objv[2], 0); } /* *---------------------------------------------------------------------- * * ConfigureOp -- * * This procedure is called to process a list of configuration * options database, in order to reconfigure the one of more * entries in the widget. * * .c configure option value * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for tvPtr; old resources get freed, if there * were any. The hypertext is redisplayed. * *---------------------------------------------------------------------- */ static int ConfigureOp(tbPtr, interp, objc, objv) Textbox *tbPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { if (objc == 2) { return Blt_ConfigureInfoFromObj(interp, tbPtr->tkwin, textboxConfigSpecs, (char *)tbPtr, (Tcl_Obj *)NULL, 0); } else if (objc == 3) { return Blt_ConfigureInfoFromObj(interp, tbPtr->tkwin, textboxConfigSpecs, (char *)tbPtr, objv[3], 0); } if (Blt_ConfigureWidgetFromObj(interp, tbPtr->tkwin, textboxConfigSpecs, objc - 2, objv + 2, (char *)tbPtr, BLT_CONFIG_OBJV_ONLY) != TCL_OK) { return TCL_ERROR; } ConfigureTextbox(tbPtr); EventuallyRedraw(tbPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * DeleteOp -- * * Remove one or more characters from the label of an entry. * * Results: * None. * * Side effects: * Memory gets freed, the entry gets modified and (eventually) * redisplayed. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int DeleteOp(tbPtr, interp, objc, objv) Textbox *tbPtr; Tcl_Interp *interp; /* Not used. */ int objc; Tcl_Obj *CONST *objv; { int firstPos, lastPos; if (tbPtr->entryPtr == NULL) { return TCL_OK; } if (GetIndexFromObj(interp, tbPtr, objv[2], &firstPos) != TCL_OK) { return TCL_ERROR; } lastPos = firstPos; if ((objc == 4) && (GetIndexFromObj(interp, tbPtr, objv[3], &lastPos) != TCL_OK)) { return TCL_ERROR; } if (firstPos > lastPos) { return TCL_OK; } return DeleteText(tbPtr, firstPos, lastPos); } /* *---------------------------------------------------------------------- * * IcursorOp -- * * Returns the numeric index of the given string. Indices can be * one of the following: * * "anchor" Selection anchor. * "end" End of the label. * "insert" Insertion cursor. * "sel.first" First character selected. * "sel.last" Last character selected. * @x,y Index at X-Y screen coordinate. * number Returns the same number. * * Results: * A standard Tcl result. If the argument does not represent a * valid label index, then TCL_ERROR is returned and the interpreter * result will contain an error message. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int IcursorOp(tbPtr, interp, objc, objv) Textbox *tbPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { int textPos; if (GetIndexFromObj(interp, tbPtr, objv[2], &textPos) != TCL_OK) { return TCL_ERROR; } if (tbPtr->columnPtr != NULL) { tbPtr->insertPos = textPos; IndexToPointer(tbPtr); EventuallyRedraw(tbPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * IndexOp -- * * Returns the numeric index of the given string. Indices can be * one of the following: * * "anchor" Selection anchor. * "end" End of the label. * "insert" Insertion cursor. * "sel.first" First character selected. * "sel.last" Last character selected. * @x,y Index at X-Y screen coordinate. * number Returns the same number. * * Results: * A standard Tcl result. If the argument does not represent a * valid label index, then TCL_ERROR is returned and the interpreter * result will contain an error message. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int IndexOp(tbPtr, interp, objc, objv) Textbox *tbPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { int textPos; if (GetIndexFromObj(interp, tbPtr, objv[2], &textPos) != TCL_OK) { return TCL_ERROR; } if ((tbPtr->columnPtr != NULL) && (tbPtr->string != NULL)) { int nChars; nChars = Tcl_NumUtfChars(tbPtr->string, textPos); Tcl_SetObjResult(interp, Tcl_NewIntObj(nChars)); } return TCL_OK; } /* *---------------------------------------------------------------------- * * InsertOp -- * * Add new characters to the label of an entry. * * Results: * None. * * Side effects: * New information gets added to tbPtr; it will be redisplayed * soon, but not necessarily immediately. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int InsertOp(tbPtr, interp, objc, objv) Textbox *tbPtr; Tcl_Interp *interp; /* Not used. */ int objc; Tcl_Obj *CONST *objv; { int extra; int insertPos; char *string; if (tbPtr->entryPtr == NULL) { return TCL_ERROR; } if (GetIndexFromObj(interp, tbPtr, objv[2], &insertPos) != TCL_OK) { return TCL_ERROR; } string = Tcl_GetStringFromObj(objv[3], &extra); if (extra == 0) { /* Nothing to insert. Move the cursor anyways. */ tbPtr->insertPos = insertPos; } else { InsertText(tbPtr, string, insertPos, extra); } return TCL_OK; } /*ARGSUSED*/ static int SelectionAdjustOp(tbPtr, interp, objc, objv) Textbox *tbPtr; Tcl_Interp *interp; /* Not used. */ int objc; Tcl_Obj *CONST *objv; { int textPos; int half1, half2; if (GetIndexFromObj(interp, tbPtr, objv[3], &textPos) != TCL_OK) { return TCL_ERROR; } half1 = (tbPtr->selFirst + tbPtr->selLast) / 2; half2 = (tbPtr->selFirst + tbPtr->selLast + 1) / 2; if (textPos < half1) { tbPtr->selAnchor = tbPtr->selLast; } else if (textPos > half2) { tbPtr->selAnchor = tbPtr->selFirst; } return SelectText(tbPtr, textPos); } /*ARGSUSED*/ static int SelectionClearOp(tbPtr, interp, objc, objv) Textbox *tbPtr; Tcl_Interp *interp; /* Not used. */ int objc; /* Not used. */ Tcl_Obj *CONST *objv; /* Not used. */ { if (tbPtr->selFirst != -1) { tbPtr->selFirst = tbPtr->selLast = -1; EventuallyRedraw(tbPtr); } return TCL_OK; } /*ARGSUSED*/ static int SelectionFromOp(tbPtr, interp, objc, objv) Textbox *tbPtr; Tcl_Interp *interp; /* Not used. */ int objc; Tcl_Obj *CONST *objv; { int textPos; if (GetIndexFromObj(interp, tbPtr, objv[3], &textPos) != TCL_OK) { return TCL_ERROR; } tbPtr->selAnchor = textPos; return TCL_OK; } /*ARGSUSED*/ static int SelectionPresentOp(tbPtr, interp, objc, objv) Textbox *tbPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; /* Not used. */ { int bool; bool = (tbPtr->selFirst != -1); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(bool)); return TCL_OK; } /*ARGSUSED*/ static int SelectionRangeOp(tbPtr, interp, objc, objv) Textbox *tbPtr; Tcl_Interp *interp; /* Not used. */ int objc; Tcl_Obj *CONST *objv; { int selFirst, selLast; if (GetIndexFromObj(interp, tbPtr, objv[3], &selFirst) != TCL_OK) { return TCL_ERROR; } if (GetIndexFromObj(interp, tbPtr, objv[4], &selLast) != TCL_OK) { return TCL_ERROR; } tbPtr->selAnchor = selFirst; return SelectText(tbPtr, selLast); } /*ARGSUSED*/ static int SelectionToOp(tbPtr, interp, objc, objv) Textbox *tbPtr; Tcl_Interp *interp; /* Not used. */ int objc; Tcl_Obj *CONST *objv; { int textPos; if (GetIndexFromObj(interp, tbPtr, objv[3], &textPos) != TCL_OK) { return TCL_ERROR; } return SelectText(tbPtr, textPos); } static Blt_OpSpec selectionOps[] = { {"adjust", 1, (Blt_Op)SelectionAdjustOp, 4, 4, "index",}, {"clear", 1, (Blt_Op)SelectionClearOp, 3, 3, "",}, {"from", 1, (Blt_Op)SelectionFromOp, 4, 4, "index"}, {"present", 1, (Blt_Op)SelectionPresentOp, 3, 3, ""}, {"range", 1, (Blt_Op)SelectionRangeOp, 5, 5, "start end",}, {"to", 1, (Blt_Op)SelectionToOp, 4, 4, "index"}, }; static int nSelectionOps = sizeof(selectionOps) / sizeof(Blt_OpSpec); /* * This procedure handles the individual options for text * selections. The selected text is designated by start and end * indices into the text pool. The selected segment has both a * anchored and unanchored ends. The following selection * operations are implemented: * * "adjust" - resets either the first or last index * of the selection. * "clear" - clears the selection. Sets first/last * indices to -1. * "from" - sets the index of the selection anchor. * "present" - return "1" if a selection is available, * "0" otherwise. * "range" - sets the first and last indices. * "to" - sets the index of the un-anchored end. */ static int SelectionOp(tbPtr, interp, objc, objv) Textbox *tbPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { Blt_Op proc; int result; proc = Blt_GetOpFromObj(interp, nSelectionOps, selectionOps, BLT_OP_ARG2, objc, objv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (tbPtr, interp, objc, objv); return result; } /* *---------------------------------------------------------------------- * * TextboxCmd -- * * This procedure handles entry operations. * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ static Blt_OpSpec comboOps[] = { {"apply", 1, (Blt_Op)ApplyOp, 2, 2, "",}, {"cancel", 2, (Blt_Op)CancelOp, 2, 2, "",}, {"cget", 2, (Blt_Op)CgetOp, 3, 3, "value",}, {"configure", 2, (Blt_Op)ConfigureOp, 2, 0, "?option value...?",}, {"delete", 1, (Blt_Op)DeleteOp, 3, 4, "first ?last?"}, {"icursor", 2, (Blt_Op)IcursorOp, 3, 3, "index"}, {"index", 3, (Blt_Op)IndexOp, 3, 3, "index"}, {"insert", 3, (Blt_Op)InsertOp, 4, 4, "index string"}, {"selection", 1, (Blt_Op)SelectionOp, 2, 0, "args"}, }; static int nComboOps = sizeof(comboOps) / sizeof(Blt_OpSpec); static int TextboxCmd(clientData, interp, objc, objv) ClientData clientData; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { Textbox *tbPtr = clientData; Blt_Op proc; int result; proc = Blt_GetOpFromObj(interp, nComboOps, comboOps, BLT_OP_ARG1, objc, objv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (tbPtr, interp, objc, objv); return result; } #endif blt-2.4z.orig/src/bltTreeViewStyle.c0100644000175000017500000023114507517102300016155 0ustar dokodoko /* * bltTreeViewStyle.c -- * * This module implements styles for treeview widget cells. * * Copyright 1998-1999 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 or 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. * * The "treeview" widget was created by George A. Howlett. */ #include "bltInt.h" #ifndef NO_TREEVIEW #include "bltTreeView.h" #include "bltList.h" #include #include #define STYLE_GAP 2 static Blt_OptionParseProc ObjToIcon; static Blt_OptionPrintProc IconToObj; static Blt_OptionFreeProc FreeIcon; Blt_CustomOption bltTreeViewIconOption = { /* Contains a pointer to the widget that's currently being * configured. This is used in the custom configuration parse * routine for icons. */ ObjToIcon, IconToObj, FreeIcon, NULL, }; #define DEF_STYLE_HIGHLIGHT_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_STYLE_HIGHLIGHT_FOREGROUND STD_NORMAL_FOREGROUND #ifdef WIN32 #define DEF_STYLE_ACTIVE_BACKGROUND RGB_GREY85 #else #define DEF_STYLE_ACTIVE_BACKGROUND RGB_GREY95 #endif #define DEF_STYLE_ACTIVE_FOREGROUND STD_ACTIVE_FOREGROUND #define DEF_STYLE_GAP "2" typedef struct { int refCount; /* Usage reference count. */ unsigned int flags; char *name; TreeViewStyleClass *classPtr; /* Class-specific routines to manage style. */ Blt_HashEntry *hashPtr; /* General style fields. */ Tk_Cursor cursor; /* X Cursor */ TreeViewIcon icon; /* If non-NULL, is a Tk_Image to be drawn * in the cell. */ int gap; /* # pixels gap between icon and text. */ Tk_Font font; XColor *fgColor; /* Normal foreground color of cell. */ Tk_3DBorder border; /* Normal background color of cell. */ XColor *highlightFgColor; /* Foreground color of cell when * highlighted. */ Tk_3DBorder highlightBorder;/* Background color of cell when * highlighted. */ XColor *activeFgColor; /* Foreground color of cell when active. */ Tk_3DBorder activeBorder; /* Background color of cell when active. */ /* TextBox-specific fields */ GC gc; GC highlightGC; GC activeGC; int side; /* Position of the text in relation to * the icon. */ Blt_TreeKey key; /* Actual data resides in this tree value. */ } TreeViewTextBox; #ifdef WIN32 #define DEF_TEXTBOX_CURSOR "arrow" #else #define DEF_TEXTBOX_CURSOR "hand2" #endif /*WIN32*/ #define DEF_TEXTBOX_SIDE "left" static Blt_ConfigSpec textBoxSpecs[] = { {BLT_CONFIG_BORDER, "-activebackground", "activeBackground", "ActiveBackground", DEF_STYLE_ACTIVE_BACKGROUND, Blt_Offset(TreeViewTextBox, activeBorder), 0}, {BLT_CONFIG_SYNONYM, "-activebg", "activeBackground", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_SYNONYM, "-activefg", "activeFackground", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_COLOR, "-activeforeground", "activeForeground", "ActiveForeground", DEF_STYLE_ACTIVE_FOREGROUND, Blt_Offset(TreeViewTextBox, activeFgColor), 0}, {BLT_CONFIG_BORDER, "-background", "background", "Background", (char *)NULL, Blt_Offset(TreeViewTextBox, border), BLT_CONFIG_NULL_OK}, {BLT_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_CURSOR, "-cursor", "cursor", "Cursor", DEF_TEXTBOX_CURSOR, Blt_Offset(TreeViewTextBox, cursor), 0}, {BLT_CONFIG_SYNONYM, "-fg", "foreground", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_FONT, "-font", "font", "Font", (char *)NULL, Blt_Offset(TreeViewTextBox, font), BLT_CONFIG_NULL_OK}, {BLT_CONFIG_COLOR, "-foreground", "foreground", "Foreground", (char *)NULL, Blt_Offset(TreeViewTextBox, fgColor),BLT_CONFIG_NULL_OK }, {BLT_CONFIG_DISTANCE, "-gap", "gap", "Gap", DEF_STYLE_GAP, Blt_Offset(TreeViewTextBox, gap), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_BORDER, "-highlightbackground", "highlightBackground", "HighlightBackground", DEF_STYLE_HIGHLIGHT_BACKGROUND, Blt_Offset(TreeViewTextBox, highlightBorder), BLT_CONFIG_COLOR_ONLY}, {BLT_CONFIG_COLOR, "-highlightforeground", "highlightForeground", "HighlightForeground", DEF_STYLE_HIGHLIGHT_FOREGROUND, Blt_Offset(TreeViewTextBox, highlightFgColor), 0}, {BLT_CONFIG_SYNONYM, "-highlightbg", "highlightBackground", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_SYNONYM, "-highlightfg", "highlightForeground", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_CUSTOM, "-icon", "icon", "Icon", (char *)NULL, Blt_Offset(TreeViewTextBox, icon), BLT_CONFIG_NULL_OK, &bltTreeViewIconOption}, {BLT_CONFIG_STRING, "-key", "key", "key", (char *)NULL, Blt_Offset(TreeViewTextBox, key), BLT_CONFIG_NULL_OK, 0}, {BLT_CONFIG_SIDE, "-side", "side", "side", DEF_TEXTBOX_SIDE, Tk_Offset(TreeViewTextBox, side), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; typedef struct { int refCount; /* Usage reference count. */ unsigned int flags; /* Contains style type and update flags. */ char *name; /* Instance name. */ TreeViewStyleClass *classPtr; /* Class-specific routines to manage style. */ Blt_HashEntry *hashPtr; /* General style fields. */ Tk_Cursor cursor; /* X Cursor */ TreeViewIcon icon; /* If non-NULL, is a Tk_Image to be drawn * in the cell. */ int gap; /* # pixels gap between icon and text. */ Tk_Font font; XColor *fgColor; /* Normal foreground color of cell. */ Tk_3DBorder border; /* Normal background color of cell. */ XColor *highlightFgColor; /* Foreground color of cell when * highlighted. */ Tk_3DBorder highlightBorder;/* Background color of cell when * highlighted. */ XColor *activeFgColor; /* Foreground color of cell when active. */ Tk_3DBorder activeBorder; /* Background color of cell when active. */ /* Checkbox specific fields. */ GC gc; GC highlightGC; GC activeGC; Blt_TreeKey key; /* Actual data resides in this tree value. */ int size; /* Size of the checkbox. */ int showValue; /* If non-zero, display the on/off value. */ char *onValue; char *offValue; int lineWidth; /* Linewidth of the surrounding box. */ XColor *boxColor; /* Rectangle (box) color (grey). */ XColor *fillColor; /* Fill color (white) */ XColor *checkColor; /* Check color (red). */ GC boxGC; GC fillGC; /* Box fill GC */ GC checkGC; TextLayout *onPtr, *offPtr; } TreeViewCheckBox; #define DEF_CHECKBOX_BOX_COLOR "black" #define DEF_CHECKBOX_CHECK_COLOR "red" #define DEF_CHECKBOX_FILL_COLOR "white" #define DEF_CHECKBOX_OFFVALUE "0" #define DEF_CHECKBOX_ONVALUE "1" #define DEF_CHECKBOX_SHOWVALUE "yes" #define DEF_CHECKBOX_SIZE "11" #define DEF_CHECKBOX_LINEWIDTH "2" #define DEF_CHECKBOX_GAP "4" #ifdef WIN32 #define DEF_CHECKBOX_CURSOR "arrow" #else #define DEF_CHECKBOX_CURSOR "hand2" #endif /*WIN32*/ static Blt_ConfigSpec checkBoxSpecs[] = { {BLT_CONFIG_BORDER, "-activebackground", "activeBackground", "ActiveBackground", DEF_STYLE_ACTIVE_BACKGROUND, Blt_Offset(TreeViewCheckBox, activeBorder), 0}, {BLT_CONFIG_SYNONYM, "-activebg", "activeBackground", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_SYNONYM, "-activefg", "activeFackground", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_COLOR, "-activeforeground", "activeForeground", "ActiveForeground", DEF_STYLE_ACTIVE_FOREGROUND, Blt_Offset(TreeViewCheckBox, activeFgColor), 0}, {BLT_CONFIG_BORDER, "-background", "background", "Background", (char *)NULL, Blt_Offset(TreeViewCheckBox, border), BLT_CONFIG_NULL_OK}, {BLT_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_POS_DISTANCE, "-boxsize", "boxSize", "BoxSize", DEF_CHECKBOX_SIZE, Blt_Offset(TreeViewCheckBox, size), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_CURSOR, "-cursor", "cursor", "Cursor", DEF_CHECKBOX_CURSOR, Blt_Offset(TreeViewTextBox, cursor), 0}, {BLT_CONFIG_SYNONYM, "-fg", "foreground", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_FONT, "-font", "font", "Font", (char *)NULL, Blt_Offset(TreeViewCheckBox, font), BLT_CONFIG_NULL_OK}, {BLT_CONFIG_COLOR, "-foreground", "foreground", "Foreground", (char *)NULL, Blt_Offset(TreeViewCheckBox, fgColor), BLT_CONFIG_NULL_OK }, {BLT_CONFIG_DISTANCE, "-gap", "gap", "Gap", DEF_CHECKBOX_GAP, Blt_Offset(TreeViewCheckBox, gap), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_BORDER, "-highlightbackground", "highlightBackground", "HighlightBackground", DEF_STYLE_HIGHLIGHT_BACKGROUND, Blt_Offset(TreeViewCheckBox, highlightBorder), BLT_CONFIG_COLOR_ONLY}, {BLT_CONFIG_COLOR, "-highlightforeground", "highlightForeground", "HighlightForeground", DEF_STYLE_HIGHLIGHT_FOREGROUND, Blt_Offset(TreeViewCheckBox, highlightFgColor), 0}, {BLT_CONFIG_SYNONYM, "-highlightbg", "highlightBackground", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_SYNONYM, "-highlightfg", "highlightForeground", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_CUSTOM, "-icon", "icon", "Icon", (char *)NULL, Blt_Offset(TreeViewCheckBox, icon), BLT_CONFIG_NULL_OK, &bltTreeViewIconOption}, {BLT_CONFIG_STRING, "-key", "key", "key", (char *)NULL, Blt_Offset(TreeViewCheckBox, key), BLT_CONFIG_NULL_OK, 0}, {BLT_CONFIG_DISTANCE, "-linewidth", "lineWidth", "LineWidth", DEF_CHECKBOX_LINEWIDTH, Blt_Offset(TreeViewCheckBox, lineWidth), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_COLOR, "-checkcolor", "checkColor", "CheckColor", DEF_CHECKBOX_CHECK_COLOR, Blt_Offset(TreeViewCheckBox, checkColor), 0}, {BLT_CONFIG_COLOR, "-boxcolor", "boxColor", "BoxColor", DEF_CHECKBOX_BOX_COLOR, Blt_Offset(TreeViewCheckBox, boxColor), 0}, {BLT_CONFIG_COLOR, "-fillcolor", "fillColor", "FillColor", DEF_CHECKBOX_FILL_COLOR, Blt_Offset(TreeViewCheckBox, fillColor), 0}, {BLT_CONFIG_STRING, "-offvalue", "offValue", "OffValue", DEF_CHECKBOX_OFFVALUE, Blt_Offset(TreeViewCheckBox, offValue), BLT_CONFIG_NULL_OK}, {BLT_CONFIG_STRING, "-onvalue", "onValue", "OnValue", DEF_CHECKBOX_ONVALUE, Blt_Offset(TreeViewCheckBox, onValue), BLT_CONFIG_NULL_OK}, {BLT_CONFIG_STRING, "-key", "key", "key", (char *)NULL, Blt_Offset(TreeViewCheckBox, key), BLT_CONFIG_NULL_OK, 0}, {BLT_CONFIG_BOOLEAN, "-showvalue", "showValue", "ShowValue", DEF_CHECKBOX_SHOWVALUE, Blt_Offset(TreeViewCheckBox, showValue), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; typedef struct { int refCount; /* Usage reference count. */ unsigned int flags; char *name; TreeViewStyleClass *classPtr;/* Class-specific style routines. */ Blt_HashEntry *hashPtr; /* General style fields. */ Tk_Cursor cursor; /* X Cursor */ TreeViewIcon icon; /* If non-NULL, is a Tk_Image to be drawn * in the cell. */ int gap; /* # pixels gap between icon and text. */ Tk_Font font; XColor *fgColor; /* Normal foreground color of cell. */ Tk_3DBorder border; /* Normal background color of cell. */ XColor *highlightFgColor; /* Foreground color of cell when * highlighted. */ Tk_3DBorder highlightBorder;/* Background color of cell when * highlighted. */ XColor *activeFgColor; /* Foreground color of cell when active. */ Tk_3DBorder activeBorder; /* Background color of cell when active. */ /* ComboBox-specific fields */ GC gc; GC highlightGC; GC activeGC; int borderWidth; /* Width of outer border surrounding * the entire box. */ int relief; /* Relief of outer border. */ Blt_TreeKey key; /* Actual data resides in this tree value. */ char *choices; /* List of available choices. */ char *choiceIcons; /* List of icons associated with choices. */ int scrollWidth; int button; int buttonWidth; int buttonBorderWidth; /* Border width of button. */ int buttonRelief; /* Normal relief of button. */ } TreeViewComboBox; #define DEF_COMBOBOX_BORDERWIDTH "1" #define DEF_COMBOBOX_BUTTON_BORDERWIDTH "1" #define DEF_COMBOBOX_BUTTON_RELIEF "raised" #define DEF_COMBOBOX_RELIEF "flat" #ifdef WIN32 #define DEF_COMBOBOX_CURSOR "arrow" #else #define DEF_COMBOBOX_CURSOR "hand2" #endif /*WIN32*/ static Blt_ConfigSpec comboBoxSpecs[] = { {BLT_CONFIG_BORDER, "-activebackground", "activeBackground", "ActiveBackground", DEF_STYLE_ACTIVE_BACKGROUND, Blt_Offset(TreeViewComboBox, activeBorder), 0}, {BLT_CONFIG_SYNONYM, "-activebg", "activeBackground", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_SYNONYM, "-activefg", "activeFackground", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_COLOR, "-activeforeground", "activeForeground", "ActiveForeground", DEF_STYLE_ACTIVE_FOREGROUND, Blt_Offset(TreeViewComboBox, activeFgColor), 0}, {BLT_CONFIG_BORDER, "-background", "background", "Background", (char *)NULL, Blt_Offset(TreeViewComboBox, border), BLT_CONFIG_NULL_OK}, {BLT_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_DISTANCE, "-borderwidth", "borderWidth", "BorderWidth", DEF_COMBOBOX_BORDERWIDTH, Blt_Offset(TreeViewComboBox, borderWidth), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_RELIEF, "-buttonrelief", "buttonRelief", "ButtonRelief", DEF_COMBOBOX_BUTTON_RELIEF, Blt_Offset(TreeViewComboBox, buttonRelief), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_DISTANCE, "-buttonborderwidth", "buttonBorderWidth", "ButtonBorderWidth", DEF_COMBOBOX_BUTTON_BORDERWIDTH, Blt_Offset(TreeViewComboBox, buttonBorderWidth), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_CURSOR, "-cursor", "cursor", "Cursor", DEF_COMBOBOX_CURSOR, Blt_Offset(TreeViewTextBox, cursor), 0}, {BLT_CONFIG_SYNONYM, "-fg", "foreground", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_FONT, "-font", "font", "Font", (char *)NULL, Blt_Offset(TreeViewComboBox, font), BLT_CONFIG_NULL_OK}, {BLT_CONFIG_COLOR, "-foreground", "foreground", "Foreground", (char *)NULL, Blt_Offset(TreeViewComboBox, fgColor), BLT_CONFIG_NULL_OK }, {BLT_CONFIG_DISTANCE, "-gap", "gap", "Gap", DEF_STYLE_GAP, Blt_Offset(TreeViewComboBox, gap), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_BORDER, "-highlightbackground", "highlightBackground", "HighlightBackground", DEF_STYLE_HIGHLIGHT_BACKGROUND, Blt_Offset(TreeViewComboBox, highlightBorder), BLT_CONFIG_COLOR_ONLY}, {BLT_CONFIG_COLOR, "-highlightforeground", "highlightForeground", "HighlightForeground", DEF_STYLE_HIGHLIGHT_FOREGROUND, Blt_Offset(TreeViewComboBox, highlightFgColor), 0}, {BLT_CONFIG_SYNONYM, "-highlightbg", "highlightBackground", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_SYNONYM, "-highlightfg", "highlightForeground", (char *)NULL, (char *)NULL, 0, 0}, {BLT_CONFIG_CUSTOM, "-icon", "icon", "Icon", (char *)NULL, Blt_Offset(TreeViewComboBox, icon), BLT_CONFIG_NULL_OK, &bltTreeViewIconOption}, {BLT_CONFIG_STRING, "-key", "key", "key", (char *)NULL, Blt_Offset(TreeViewComboBox, key), BLT_CONFIG_NULL_OK, 0}, {BLT_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_COMBOBOX_RELIEF, Blt_Offset(TreeViewComboBox, relief), BLT_CONFIG_DONT_SET_DEFAULT}, {BLT_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; typedef TreeViewStyle *(StyleCreateProc) _ANSI_ARGS_((TreeView *tvPtr, Blt_HashEntry *hPtr)); static StyleConfigProc ConfigureTextBox, ConfigureCheckBox, ConfigureComboBox; static StyleCreateProc CreateTextBox, CreateCheckBox, CreateComboBox; static StyleDrawProc DrawTextBox, DrawCheckBox, DrawComboBox; static StyleEditProc EditTextBox, EditCheckBox, EditComboBox; static StyleFreeProc FreeTextBox, FreeCheckBox, FreeComboBox; static StyleMeasureProc MeasureTextBox, MeasureCheckBox, MeasureComboBox; static StylePickProc PickCheckBox, PickComboBox; /* *---------------------------------------------------------------------- * * ObjToIcon -- * * Convert the name of an icon into a Tk image. * * Results: * If the string is successfully converted, TCL_OK is returned. * Otherwise, TCL_ERROR is returned and an error message is left in * interpreter's result field. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ObjToIcon(clientData, interp, tkwin, objPtr, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ Tcl_Obj *objPtr; /* Tcl_Obj representing the new value. */ char *widgRec; int offset; { TreeView *tvPtr = clientData; TreeViewIcon *iconPtr = (TreeViewIcon *)(widgRec + offset); TreeViewIcon icon; icon = Blt_TreeViewGetIcon(tvPtr, Tcl_GetString(objPtr)); if (icon == NULL) { return TCL_ERROR; } *iconPtr = icon; return TCL_OK; } /* *---------------------------------------------------------------------- * * IconToObj -- * * Converts the icon into its string representation (its name). * * Results: * The name of the icon is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static Tcl_Obj * IconToObj(clientData, interp, tkwin, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; Tk_Window tkwin; /* Not used. */ char *widgRec; int offset; { TreeViewIcon icon = *(TreeViewIcon *)(widgRec + offset); if (icon == NULL) { return bltEmptyStringObjPtr; } return Tcl_NewStringObj(Blt_NameOfImage((icon)->tkImage), -1); } /*ARGSUSED*/ static void FreeIcon(clientData, display, widgRec, offset) ClientData clientData; Display *display; /* Not used. */ char *widgRec; int offset; { TreeViewIcon icon = *(TreeViewIcon *)(widgRec + offset); TreeView *tvPtr = clientData; Blt_TreeViewFreeIcon(tvPtr, icon); } static TreeViewStyleClass textBoxClass = { "TextBoxStyle", textBoxSpecs, ConfigureTextBox, MeasureTextBox, DrawTextBox, NULL, EditTextBox, FreeTextBox, }; static TreeViewStyleClass checkBoxClass = { "CheckBoxStyle", checkBoxSpecs, ConfigureCheckBox, MeasureCheckBox, DrawCheckBox, NULL, EditCheckBox, FreeCheckBox, }; static TreeViewStyleClass comboBoxClass = { "ComboBoxStyle", comboBoxSpecs, ConfigureComboBox, MeasureComboBox, DrawComboBox, PickComboBox, EditComboBox, FreeComboBox, }; /* *---------------------------------------------------------------------- * * CreateTextBox -- * * Creates a "textbox" style. * * Results: * A pointer to the new style structure. * *---------------------------------------------------------------------- */ static TreeViewStyle * CreateTextBox(tvPtr, hPtr) TreeView *tvPtr; Blt_HashEntry *hPtr; { TreeViewTextBox *tbPtr; tbPtr = Blt_Calloc(1, sizeof(TreeViewTextBox)); assert(tbPtr); tbPtr->classPtr = &textBoxClass; tbPtr->side = SIDE_LEFT; tbPtr->gap = STYLE_GAP; tbPtr->name = Blt_Strdup(Blt_GetHashKey(&tvPtr->styleTable, hPtr)); tbPtr->hashPtr = hPtr; tbPtr->flags = STYLE_TEXTBOX; tbPtr->refCount = 1; Blt_SetHashValue(hPtr, tbPtr); return (TreeViewStyle *)tbPtr; } /* *---------------------------------------------------------------------- * * ConfigureTextBox -- * * Configures a "textbox" style. This routine performs * generates the GCs required for a textbox style. * * Results: * None. * * Side Effects: * GCs are created for the style. * *---------------------------------------------------------------------- */ static void ConfigureTextBox(tvPtr, stylePtr) TreeView *tvPtr; TreeViewStyle *stylePtr; { GC newGC; TreeViewTextBox *tbPtr = (TreeViewTextBox *)stylePtr; XColor *bgColor; XGCValues gcValues; unsigned long gcMask; gcMask = GCForeground | GCBackground | GCFont; gcValues.font = Tk_FontId(CHOOSE(tvPtr->font, tbPtr->font)); bgColor = Tk_3DBorderColor(CHOOSE(tvPtr->border, tbPtr->border)); gcValues.background = bgColor->pixel; gcValues.foreground = CHOOSE(tvPtr->fgColor, tbPtr->fgColor)->pixel; newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues); if (tbPtr->gc != NULL) { Tk_FreeGC(tvPtr->display, tbPtr->gc); } tbPtr->gc = newGC; gcValues.background = Tk_3DBorderColor(tbPtr->highlightBorder)->pixel; gcValues.foreground = tbPtr->highlightFgColor->pixel; newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues); if (tbPtr->highlightGC != NULL) { Tk_FreeGC(tvPtr->display, tbPtr->highlightGC); } tbPtr->highlightGC = newGC; gcValues.background = Tk_3DBorderColor(tbPtr->activeBorder)->pixel; gcValues.foreground = tbPtr->activeFgColor->pixel; newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues); if (tbPtr->activeGC != NULL) { Tk_FreeGC(tvPtr->display, tbPtr->activeGC); } tbPtr->activeGC = newGC; tbPtr->flags |= STYLE_DIRTY; } /* *---------------------------------------------------------------------- * * MeasureTextBox -- * * Determines the space requirements for the "textbox" given * the value to be displayed. Depending upon whether an icon * or text is displayed and their relative placements, this * routine computes the space needed for the text entry. * * Results: * None. * * Side Effects: * The width and height fields of *valuePtr* are set with the * computed dimensions. * *---------------------------------------------------------------------- */ static void MeasureTextBox(tvPtr, stylePtr, valuePtr) TreeView *tvPtr; TreeViewStyle *stylePtr; TreeViewValue *valuePtr; { TreeViewTextBox *tbPtr = (TreeViewTextBox *)stylePtr; int iconWidth, iconHeight; int textWidth, textHeight; int gap; textWidth = textHeight = 0; iconWidth = iconHeight = 0; valuePtr->width = valuePtr->height = 0; if (tbPtr->icon != NULL) { iconWidth = TreeViewIconWidth(tbPtr->icon); iconHeight = TreeViewIconHeight(tbPtr->icon); } if (valuePtr->textPtr != NULL) { Blt_Free(valuePtr->textPtr); valuePtr->textPtr = NULL; } if (valuePtr->string != NULL) { /* New string defined. */ TextStyle ts; Blt_InitTextStyle(&ts); ts.font = CHOOSE(tvPtr->font, tbPtr->font); ts.anchor = TK_ANCHOR_NW; ts.justify = TK_JUSTIFY_LEFT; valuePtr->textPtr = Blt_GetTextLayout(valuePtr->string, &ts); } gap = 0; if (valuePtr->textPtr != NULL) { textWidth = valuePtr->textPtr->width; textHeight = valuePtr->textPtr->height; if (tbPtr->icon != NULL) { gap = tbPtr->gap; } } if (SIDE_VERTICAL(tbPtr->side)) { valuePtr->height = iconHeight + gap + textHeight; valuePtr->width = MAX(textWidth, iconWidth); } else { valuePtr->width = iconWidth + gap + textWidth; valuePtr->height = MAX(textHeight, iconHeight); } } /* *---------------------------------------------------------------------- * * DrawTextBox -- * * Draws the "textbox" given the screen coordinates and the * value to be displayed. * * Results: * None. * * Side Effects: * The textbox value is drawn. * *---------------------------------------------------------------------- */ static void DrawTextBox(tvPtr, drawable, entryPtr, valuePtr, stylePtr, x, y) TreeView *tvPtr; Drawable drawable; TreeViewEntry *entryPtr; TreeViewValue *valuePtr; TreeViewStyle *stylePtr; int x, y; { GC gc; TreeViewColumn *columnPtr; TreeViewTextBox *tbPtr = (TreeViewTextBox *)stylePtr; int iconX, iconY, iconWidth, iconHeight; int textX, textY, textWidth, textHeight; int gap, columnWidth; Tk_3DBorder border; XColor *fgColor; columnPtr = valuePtr->columnPtr; if (stylePtr->flags & STYLE_HIGHLIGHT) { gc = tbPtr->highlightGC; border = tbPtr->highlightBorder; fgColor = tbPtr->highlightFgColor; } else { gc = tbPtr->gc; border = CHOOSE(tvPtr->border, tbPtr->border); fgColor = CHOOSE(tvPtr->fgColor, tbPtr->fgColor); } if (!Blt_TreeViewEntryIsSelected(tvPtr, entryPtr)) { /* * Draw the active or normal background color over the entire * label area. This includes both the tab's text and image. * The rectangle should be 2 pixels wider/taller than this * area. So if the label consists of just an image, we get an * halo around the image when the tab is active. */ if (border != NULL) { Blt_Fill3DRectangle(tvPtr->tkwin, drawable, border, x, y, columnPtr->width, entryPtr->height, 0, TK_RELIEF_FLAT); } } columnWidth = columnPtr->width - (2 * columnPtr->borderWidth + PADDING(columnPtr->pad)); if (columnWidth > valuePtr->width) { switch(columnPtr->justify) { case TK_JUSTIFY_RIGHT: x += (columnWidth - valuePtr->width); break; case TK_JUSTIFY_CENTER: x += (columnWidth - valuePtr->width) / 2; break; case TK_JUSTIFY_LEFT: break; } } textX = textY = iconX = iconY = 0; /* Suppress compiler warning. */ iconWidth = iconHeight = 0; if (tbPtr->icon != NULL) { iconWidth = TreeViewIconWidth(tbPtr->icon); iconHeight = TreeViewIconHeight(tbPtr->icon); } textWidth = textHeight = 0; if (valuePtr->textPtr != NULL) { textWidth = valuePtr->textPtr->width; textHeight = valuePtr->textPtr->height; } gap = 0; if ((tbPtr->icon != NULL) && (valuePtr->textPtr != NULL)) { gap = tbPtr->gap; } switch (tbPtr->side) { case SIDE_RIGHT: textX = x; textY = y + (entryPtr->height - textHeight) / 2; iconX = textX + textWidth + gap; iconY = y + (entryPtr->height - iconHeight) / 2; break; case SIDE_LEFT: iconX = x; iconY = y + (entryPtr->height - iconHeight) / 2; textX = iconX + iconWidth + gap; textY = y + (entryPtr->height - textHeight) / 2; break; case SIDE_TOP: iconY = y; iconX = x + (columnWidth - iconWidth) / 2; textY = iconY + iconHeight + gap; textX = x + (columnWidth - textWidth) / 2; break; case SIDE_BOTTOM: textY = y; textX = x + (columnWidth - textWidth) / 2; iconY = textY + textHeight + gap; iconX = x + (columnWidth - iconWidth) / 2; break; } if (tbPtr->icon != NULL) { Tk_RedrawImage(TreeViewIconBits(tbPtr->icon), 0, 0, iconWidth, iconHeight, drawable, iconX, iconY); } if (valuePtr->textPtr != NULL) { TextStyle ts; XColor *color; Tk_Font font; font = CHOOSE(tvPtr->font, tbPtr->font); if (Blt_TreeViewEntryIsSelected(tvPtr, entryPtr)) { color = SELECT_FG(tvPtr); XSetForeground(tvPtr->display, gc, color->pixel); } else if (entryPtr->color != NULL) { color = entryPtr->color; XSetForeground(tvPtr->display, gc, color->pixel); } else { color = fgColor; } Blt_SetDrawTextStyle(&ts, font, gc, color, fgColor, NULL, 0.0, TK_ANCHOR_NW, TK_JUSTIFY_LEFT, 0, 0); Blt_DrawTextLayout(tvPtr->tkwin, drawable, valuePtr->textPtr, &ts, textX, textY); if (color != fgColor) { XSetForeground(tvPtr->display, gc, fgColor->pixel); } } stylePtr->flags &= ~STYLE_DIRTY; } /* *---------------------------------------------------------------------- * * EditCombobox -- * * Edits the "combobox". * * Results: * None. * * Side Effects: * The checkbox value is drawn. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int EditTextBox(tvPtr, entryPtr, valuePtr, stylePtr) TreeView *tvPtr; TreeViewEntry *entryPtr; TreeViewValue *valuePtr; TreeViewStyle *stylePtr; /* Not used. */ { return Blt_TreeViewTextbox(tvPtr, entryPtr, valuePtr->columnPtr); } /* *---------------------------------------------------------------------- * * FreeTextBox -- * * Releases resources allocated for the textbox. The resources * freed by this routine are specific only to the "textbox". * Other resources (common to all styles) are freed in the * Blt_TreeViewFreeStyle routine. * * Results: * None. * * Side Effects: * GCs allocated for the textbox are freed. * *---------------------------------------------------------------------- */ static void FreeTextBox(tvPtr, stylePtr) TreeView *tvPtr; TreeViewStyle *stylePtr; { TreeViewTextBox *tbPtr = (TreeViewTextBox *)stylePtr; if (tbPtr->highlightGC != NULL) { Tk_FreeGC(tvPtr->display, tbPtr->highlightGC); } if (tbPtr->activeGC != NULL) { Tk_FreeGC(tvPtr->display, tbPtr->activeGC); } if (tbPtr->gc != NULL) { Tk_FreeGC(tvPtr->display, tbPtr->gc); } if (tbPtr->icon != NULL) { Blt_TreeViewFreeIcon(tvPtr, tbPtr->icon); } } /* *---------------------------------------------------------------------- * * CreateCheckbox -- * * Creates a "checkbox" style. * * Results: * A pointer to the new style structure. * *---------------------------------------------------------------------- */ static TreeViewStyle * CreateCheckBox(tvPtr, hPtr) TreeView *tvPtr; Blt_HashEntry *hPtr; { TreeViewCheckBox *cbPtr; cbPtr = Blt_Calloc(1, sizeof(TreeViewCheckBox)); assert(cbPtr); cbPtr->classPtr = &checkBoxClass; cbPtr->gap = 4; cbPtr->size = 11; cbPtr->lineWidth = 2; cbPtr->showValue = TRUE; cbPtr->name = Blt_Strdup(Blt_GetHashKey(&tvPtr->styleTable, hPtr)); cbPtr->hashPtr = hPtr; cbPtr->flags = STYLE_CHECKBOX; cbPtr->refCount = 1; Blt_SetHashValue(hPtr, cbPtr); return (TreeViewStyle *)cbPtr; } /* *---------------------------------------------------------------------- * * ConfigureCheckbox -- * * Configures a "checkbox" style. This routine performs * generates the GCs required for a checkbox style. * * Results: * None. * * Side Effects: * GCs are created for the style. * *---------------------------------------------------------------------- */ static void ConfigureCheckBox(tvPtr, stylePtr) TreeView *tvPtr; TreeViewStyle *stylePtr; { GC newGC; TreeViewCheckBox *cbPtr = (TreeViewCheckBox *)stylePtr; XColor *bgColor; XGCValues gcValues; unsigned long gcMask; gcMask = GCForeground | GCBackground | GCFont; gcValues.font = Tk_FontId(CHOOSE(tvPtr->font, cbPtr->font)); bgColor = Tk_3DBorderColor(CHOOSE(tvPtr->border, cbPtr->border)); gcValues.background = bgColor->pixel; gcValues.foreground = CHOOSE(tvPtr->fgColor, cbPtr->fgColor)->pixel; newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues); if (cbPtr->gc != NULL) { Tk_FreeGC(tvPtr->display, cbPtr->gc); } cbPtr->gc = newGC; gcValues.background = Tk_3DBorderColor(cbPtr->highlightBorder)->pixel; gcValues.foreground = cbPtr->highlightFgColor->pixel; newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues); if (cbPtr->highlightGC != NULL) { Tk_FreeGC(tvPtr->display, cbPtr->highlightGC); } cbPtr->highlightGC = newGC; gcValues.background = Tk_3DBorderColor(cbPtr->activeBorder)->pixel; gcValues.foreground = cbPtr->activeFgColor->pixel; newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues); if (cbPtr->activeGC != NULL) { Tk_FreeGC(tvPtr->display, cbPtr->activeGC); } cbPtr->activeGC = newGC; gcMask = GCForeground; gcValues.foreground = cbPtr->fillColor->pixel; newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues); if (cbPtr->fillGC != NULL) { Tk_FreeGC(tvPtr->display, cbPtr->fillGC); } cbPtr->fillGC = newGC; gcMask = GCForeground | GCLineWidth; gcValues.line_width = cbPtr->lineWidth; gcValues.foreground = cbPtr->boxColor->pixel; newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues); if (cbPtr->boxGC != NULL) { Tk_FreeGC(tvPtr->display, cbPtr->boxGC); } cbPtr->boxGC = newGC; gcMask = GCForeground | GCLineWidth; gcValues.line_width = 1; gcValues.foreground = cbPtr->checkColor->pixel; newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues); if (cbPtr->checkGC != NULL) { Tk_FreeGC(tvPtr->display, cbPtr->checkGC); } cbPtr->checkGC = newGC; cbPtr->flags |= STYLE_DIRTY; } /* *---------------------------------------------------------------------- * * MeasureCheckbox -- * * Determines the space requirements for the "checkbox" given * the value to be displayed. Depending upon whether an icon * or text is displayed and their relative placements, this * routine computes the space needed for the text entry. * * Results: * None. * * Side Effects: * The width and height fields of *valuePtr* are set with the * computed dimensions. * *---------------------------------------------------------------------- */ static void MeasureCheckBox(tvPtr, stylePtr, valuePtr) TreeView *tvPtr; TreeViewStyle *stylePtr; TreeViewValue *valuePtr; { TreeViewCheckBox *cbPtr = (TreeViewCheckBox *)stylePtr; int iconWidth, iconHeight; int textWidth, textHeight; int gap; int boxWidth, boxHeight; boxWidth = boxHeight = ODD(cbPtr->size); textWidth = textHeight = iconWidth = iconHeight = 0; valuePtr->width = valuePtr->height = 0; if (cbPtr->icon != NULL) { iconWidth = TreeViewIconWidth(cbPtr->icon); iconHeight = TreeViewIconHeight(cbPtr->icon); } if (cbPtr->onPtr != NULL) { Blt_Free(cbPtr->onPtr); cbPtr->onPtr = NULL; } if (cbPtr->offPtr != NULL) { Blt_Free(cbPtr->offPtr); cbPtr->offPtr = NULL; } gap = 0; if (cbPtr->showValue) { TextStyle ts; char *string; Blt_InitTextStyle(&ts); ts.font = CHOOSE(tvPtr->font, cbPtr->font); ts.anchor = TK_ANCHOR_NW; ts.justify = TK_JUSTIFY_LEFT; string = (cbPtr->onValue != NULL) ? cbPtr->onValue : valuePtr->string; cbPtr->onPtr = Blt_GetTextLayout(string, &ts); string = (cbPtr->offValue != NULL) ? cbPtr->offValue : valuePtr->string; cbPtr->offPtr = Blt_GetTextLayout(string, &ts); textWidth = MAX(cbPtr->offPtr->width, cbPtr->onPtr->width); textHeight = MAX(cbPtr->offPtr->height, cbPtr->onPtr->height); if (cbPtr->icon != NULL) { gap = cbPtr->gap; } } valuePtr->width = cbPtr->gap * 2 + boxWidth + iconWidth + gap + textWidth; valuePtr->height = MAX3(boxHeight, textHeight, iconHeight); } /* *---------------------------------------------------------------------- * * DrawCheckbox -- * * Draws the "checkbox" given the screen coordinates and the * value to be displayed. * * Results: * None. * * Side Effects: * The checkbox value is drawn. * *---------------------------------------------------------------------- */ static void DrawCheckBox(tvPtr, drawable, entryPtr, valuePtr, stylePtr, x, y) TreeView *tvPtr; Drawable drawable; TreeViewEntry *entryPtr; TreeViewValue *valuePtr; TreeViewStyle *stylePtr; int x, y; { GC gc; TreeViewColumn *columnPtr; TreeViewCheckBox *cbPtr = (TreeViewCheckBox *)stylePtr; int iconX, iconY, iconWidth, iconHeight; int textX, textY, textHeight; int gap, columnWidth; Tk_3DBorder border; XColor *fgColor; Tk_Font font; int bool; int borderWidth, relief; TextLayout *textPtr; int boxX, boxY, boxWidth, boxHeight; font = CHOOSE(tvPtr->font, cbPtr->font); columnPtr = valuePtr->columnPtr; borderWidth = 0; relief = TK_RELIEF_FLAT; if (valuePtr == tvPtr->activeValuePtr) { gc = cbPtr->activeGC; border = cbPtr->activeBorder; fgColor = cbPtr->activeFgColor; borderWidth = 1; relief = TK_RELIEF_RAISED; } else if (stylePtr->flags & STYLE_HIGHLIGHT) { gc = cbPtr->highlightGC; border = cbPtr->highlightBorder; fgColor = cbPtr->highlightFgColor; } else { gc = cbPtr->gc; border = CHOOSE(tvPtr->border, cbPtr->border); fgColor = CHOOSE(tvPtr->fgColor, cbPtr->fgColor); } columnWidth = columnPtr->width - PADDING(columnPtr->pad); if (valuePtr == tvPtr->activeValuePtr) { /* * Draw the active or normal background color over the entire * label area. This includes both the tab's text and image. * The rectangle should be 2 pixels wider/taller than this * area. So if the label consists of just an image, we get an * halo around the image when the tab is active. */ if (Blt_TreeViewEntryIsSelected(tvPtr, entryPtr)) { Blt_Fill3DRectangle(tvPtr->tkwin, drawable, SELECT_BORDER(tvPtr), x, y, columnWidth, entryPtr->height - 1, borderWidth, relief); } else { Blt_Fill3DRectangle(tvPtr->tkwin, drawable, border, x, y, columnWidth, entryPtr->height - 1, borderWidth, relief); } } if (columnWidth > valuePtr->width) { switch(columnPtr->justify) { case TK_JUSTIFY_RIGHT: x += (columnWidth - valuePtr->width); break; case TK_JUSTIFY_CENTER: x += (columnWidth - valuePtr->width) / 2; break; case TK_JUSTIFY_LEFT: break; } } bool = (strcmp(valuePtr->string, cbPtr->onValue) == 0); textPtr = (bool) ? cbPtr->onPtr : cbPtr->offPtr; /* * Draw the box and check. * * +-----------+ * | | * | * | * | * | * | * * | * | * * | * | * * | * | * | * +-----------+ */ boxWidth = boxHeight = ODD(cbPtr->size); boxX = x + cbPtr->gap; boxY = y + (entryPtr->height - boxHeight) / 2; XFillRectangle(tvPtr->display, drawable, cbPtr->fillGC, boxX, boxY, boxWidth, boxHeight); XDrawRectangle(tvPtr->display, drawable, cbPtr->boxGC, boxX, boxY, boxWidth, boxHeight); if (bool) { int midX, midY; int i; for (i = 0; i < 3; i++) { midX = boxX + 2 * boxWidth / 5; midY = boxY + boxHeight - 5 + i; XDrawLine(tvPtr->display, drawable, cbPtr->checkGC, boxX + 2, boxY + boxHeight / 3 + 1 + i, midX, midY); XDrawLine(tvPtr->display, drawable, cbPtr->checkGC, midX, midY, boxX + boxWidth - 2, boxY + i + 1); } } #ifdef notdef textX = textY = iconX = iconY = 0; /* Suppress compiler warning. */ #endif iconWidth = iconHeight = 0; if (cbPtr->icon != NULL) { iconWidth = TreeViewIconWidth(cbPtr->icon); iconHeight = TreeViewIconHeight(cbPtr->icon); } textHeight = 0; gap = 0; if (cbPtr->showValue) { textHeight = textPtr->height; if (cbPtr->icon != NULL) { gap = cbPtr->gap; } } x = boxX + boxWidth + cbPtr->gap; /* The icon sits to the left of the text. */ iconX = x; iconY = y + (entryPtr->height - iconHeight) / 2; textX = iconX + iconWidth + gap; textY = y + (entryPtr->height - textHeight) / 2; if (cbPtr->icon != NULL) { Tk_RedrawImage(TreeViewIconBits(cbPtr->icon), 0, 0, iconWidth, iconHeight, drawable, iconX, iconY); } if ((cbPtr->showValue) && (textPtr != NULL)) { TextStyle ts; XColor *color; if (Blt_TreeViewEntryIsSelected(tvPtr, entryPtr)) { color = SELECT_FG(tvPtr); XSetForeground(tvPtr->display, gc, color->pixel); } else if (entryPtr->color != NULL) { color = entryPtr->color; XSetForeground(tvPtr->display, gc, color->pixel); } else { color = fgColor; } Blt_SetDrawTextStyle(&ts, font, gc, color, fgColor, NULL, 0.0, TK_ANCHOR_NW, TK_JUSTIFY_LEFT, 0, 0); Blt_DrawTextLayout(tvPtr->tkwin, drawable, textPtr, &ts, textX, textY); if (color != fgColor) { XSetForeground(tvPtr->display, gc, fgColor->pixel); } } stylePtr->flags &= ~STYLE_DIRTY; } /* *---------------------------------------------------------------------- * * PickCheckbox -- * * Draws the "checkbox" given the screen coordinates and the * value to be displayed. * * Results: * None. * * Side Effects: * The checkbox value is drawn. * *---------------------------------------------------------------------- */ static int PickCheckBox(entryPtr, valuePtr, stylePtr, worldX, worldY) TreeViewEntry *entryPtr; TreeViewValue *valuePtr; TreeViewStyle *stylePtr; int worldX, worldY; { TreeViewColumn *columnPtr; TreeViewCheckBox *cbPtr = (TreeViewCheckBox *)stylePtr; int columnWidth; int x, y, width, height; columnPtr = valuePtr->columnPtr; columnWidth = columnPtr->width - (2 * columnPtr->borderWidth + PADDING(columnPtr->pad)); if (columnWidth > valuePtr->width) { switch(columnPtr->justify) { case TK_JUSTIFY_RIGHT: worldX += (columnWidth - valuePtr->width); break; case TK_JUSTIFY_CENTER: worldX += (columnWidth - valuePtr->width) / 2; break; case TK_JUSTIFY_LEFT: break; } } width = height = ODD(cbPtr->size) + 2 * cbPtr->lineWidth; x = columnPtr->worldX + columnPtr->pad.side1 + cbPtr->gap - cbPtr->lineWidth; y = entryPtr->worldY + (entryPtr->height - height) / 2; if ((worldX >= x) && (worldX < (x + width)) && (worldY >= y) && (worldY < (y + height))) { return TRUE; } return FALSE; } /* *---------------------------------------------------------------------- * * EditCheckbox -- * * Edits the "checkbox". * * Results: * None. * * Side Effects: * The checkbox value is drawn. * *---------------------------------------------------------------------- */ static int EditCheckBox(tvPtr, entryPtr, valuePtr, stylePtr) TreeView *tvPtr; TreeViewEntry *entryPtr; TreeViewValue *valuePtr; TreeViewStyle *stylePtr; { TreeViewColumn *columnPtr; TreeViewCheckBox *cbPtr = (TreeViewCheckBox *)stylePtr; Tcl_Obj *objPtr; columnPtr = valuePtr->columnPtr; if (Blt_TreeGetValueByKey(tvPtr->interp, tvPtr->tree, entryPtr->node, columnPtr->key, &objPtr) != TCL_OK) { return TCL_ERROR; } if (strcmp(Tcl_GetString(objPtr), cbPtr->onValue) == 0) { objPtr = Tcl_NewStringObj(cbPtr->offValue, -1); } else { objPtr = Tcl_NewStringObj(cbPtr->onValue, -1); } entryPtr->flags |= ENTRY_DIRTY; tvPtr->flags |= (TV_DIRTY | TV_LAYOUT | TV_SCROLL | TV_RESORT); if (Blt_TreeSetValueByKey(tvPtr->interp, tvPtr->tree, entryPtr->node, columnPtr->key, objPtr) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * FreeCheckbox -- * * Releases resources allocated for the checkbox. The resources * freed by this routine are specific only to the "checkbox". * Other resources (common to all styles) are freed in the * Blt_TreeViewFreeStyle routine. * * Results: * None. * * Side Effects: * GCs allocated for the checkbox are freed. * *---------------------------------------------------------------------- */ static void FreeCheckBox(tvPtr, stylePtr) TreeView *tvPtr; TreeViewStyle *stylePtr; { TreeViewCheckBox *cbPtr = (TreeViewCheckBox *)stylePtr; if (cbPtr->highlightGC != NULL) { Tk_FreeGC(tvPtr->display, cbPtr->highlightGC); } if (cbPtr->activeGC != NULL) { Tk_FreeGC(tvPtr->display, cbPtr->activeGC); } if (cbPtr->gc != NULL) { Tk_FreeGC(tvPtr->display, cbPtr->gc); } if (cbPtr->fillGC != NULL) { Tk_FreeGC(tvPtr->display, cbPtr->fillGC); } if (cbPtr->boxGC != NULL) { Tk_FreeGC(tvPtr->display, cbPtr->boxGC); } if (cbPtr->checkGC != NULL) { Tk_FreeGC(tvPtr->display, cbPtr->checkGC); } if (cbPtr->icon != NULL) { Blt_TreeViewFreeIcon(tvPtr, cbPtr->icon); } if (cbPtr->offPtr != NULL) { Blt_Free(cbPtr->offPtr); } if (cbPtr->onPtr != NULL) { Blt_Free(cbPtr->onPtr); } } /* *---------------------------------------------------------------------- * * CreateComboBox -- * * Creates a "combobox" style. * * Results: * A pointer to the new style structure. * *---------------------------------------------------------------------- */ static TreeViewStyle * CreateComboBox(tvPtr, hPtr) TreeView *tvPtr; Blt_HashEntry *hPtr; { TreeViewComboBox *cbPtr; cbPtr = Blt_Calloc(1, sizeof(TreeViewComboBox)); assert(cbPtr); cbPtr->classPtr = &comboBoxClass; cbPtr->gap = STYLE_GAP; cbPtr->buttonRelief = TK_RELIEF_RAISED; cbPtr->buttonBorderWidth = 1; cbPtr->borderWidth = 1; cbPtr->relief = TK_RELIEF_FLAT; cbPtr->name = Blt_Strdup(Blt_GetHashKey(&tvPtr->styleTable, hPtr)); cbPtr->hashPtr = hPtr; cbPtr->flags = STYLE_COMBOBOX; cbPtr->refCount = 1; Blt_SetHashValue(hPtr, cbPtr); return (TreeViewStyle *)cbPtr; } /* *---------------------------------------------------------------------- * * ConfigureComboBox -- * * Configures a "combobox" style. This routine performs * generates the GCs required for a combobox style. * * Results: * None. * * Side Effects: * GCs are created for the style. * *---------------------------------------------------------------------- */ static void ConfigureComboBox(tvPtr, stylePtr) TreeView *tvPtr; TreeViewStyle *stylePtr; { GC newGC; TreeViewComboBox *cbPtr = (TreeViewComboBox *)stylePtr; XColor *bgColor; XGCValues gcValues; unsigned long gcMask; gcValues.font = Tk_FontId(CHOOSE(tvPtr->font, cbPtr->font)); bgColor = Tk_3DBorderColor(CHOOSE(tvPtr->border, cbPtr->border)); gcMask = GCForeground | GCBackground | GCFont; /* Normal foreground */ gcValues.background = bgColor->pixel; gcValues.foreground = CHOOSE(tvPtr->fgColor, cbPtr->fgColor)->pixel; newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues); if (cbPtr->gc != NULL) { Tk_FreeGC(tvPtr->display, cbPtr->gc); } cbPtr->gc = newGC; /* Highlight foreground */ gcValues.background = Tk_3DBorderColor(cbPtr->highlightBorder)->pixel; gcValues.foreground = cbPtr->highlightFgColor->pixel; newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues); if (cbPtr->highlightGC != NULL) { Tk_FreeGC(tvPtr->display, cbPtr->highlightGC); } cbPtr->highlightGC = newGC; /* Active foreground */ gcValues.background = Tk_3DBorderColor(cbPtr->activeBorder)->pixel; gcValues.foreground = cbPtr->activeFgColor->pixel; newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues); if (cbPtr->activeGC != NULL) { Tk_FreeGC(tvPtr->display, cbPtr->activeGC); } cbPtr->activeGC = newGC; cbPtr->flags |= STYLE_DIRTY; } /* *---------------------------------------------------------------------- * * MeasureComboBox -- * * Determines the space requirements for the "combobox" given * the value to be displayed. Depending upon whether an icon * or text is displayed and their relative placements, this * routine computes the space needed for the text entry. * * Results: * None. * * Side Effects: * The width and height fields of *valuePtr* are set with the * computed dimensions. * *---------------------------------------------------------------------- */ static void MeasureComboBox(tvPtr, stylePtr, valuePtr) TreeView *tvPtr; TreeViewStyle *stylePtr; TreeViewValue *valuePtr; { TreeViewComboBox *cbPtr = (TreeViewComboBox *)stylePtr; int iconWidth, iconHeight; int textWidth, textHeight; int gap; Tk_Font font; textWidth = textHeight = 0; iconWidth = iconHeight = 0; valuePtr->width = valuePtr->height = 0; if (cbPtr->icon != NULL) { iconWidth = TreeViewIconWidth(cbPtr->icon); iconHeight = TreeViewIconHeight(cbPtr->icon); } if (valuePtr->textPtr != NULL) { Blt_Free(valuePtr->textPtr); valuePtr->textPtr = NULL; } font = CHOOSE(tvPtr->font, cbPtr->font); if (valuePtr->string != NULL) { /* New string defined. */ TextStyle ts; Blt_InitTextStyle(&ts); ts.font = font; ts.anchor = TK_ANCHOR_NW; ts.justify = TK_JUSTIFY_LEFT; valuePtr->textPtr = Blt_GetTextLayout(valuePtr->string, &ts); } gap = 0; if (valuePtr->textPtr != NULL) { textWidth = valuePtr->textPtr->width; textHeight = valuePtr->textPtr->height; if (cbPtr->icon != NULL) { gap = cbPtr->gap; } } cbPtr->buttonWidth = STD_ARROW_WIDTH + 6 + 2 * cbPtr->buttonBorderWidth; valuePtr->width = 2 * cbPtr->borderWidth + iconWidth + 4 * gap + cbPtr->buttonWidth + textWidth; valuePtr->height = MAX(textHeight, iconHeight) + 2 * cbPtr->borderWidth; } /* *---------------------------------------------------------------------- * * DrawComboBox -- * * Draws the "combobox" given the screen coordinates and the * value to be displayed. * * Results: * None. * * Side Effects: * The combobox value is drawn. * *---------------------------------------------------------------------- */ static void DrawComboBox(tvPtr, drawable, entryPtr, valuePtr, stylePtr, x, y) TreeView *tvPtr; Drawable drawable; TreeViewEntry *entryPtr; TreeViewValue *valuePtr; TreeViewStyle *stylePtr; int x, y; { GC gc; TreeViewColumn *columnPtr; TreeViewComboBox *cbPtr = (TreeViewComboBox *)stylePtr; int iconX, iconY, iconWidth, iconHeight; int textX, textY, textHeight; int buttonX, buttonY; int gap, columnWidth; Tk_3DBorder border; XColor *fgColor; columnPtr = valuePtr->columnPtr; if (stylePtr->flags & STYLE_HIGHLIGHT) { gc = cbPtr->highlightGC; border = cbPtr->highlightBorder; fgColor = cbPtr->highlightFgColor; } else { gc = cbPtr->gc; border = CHOOSE(tvPtr->border, cbPtr->border); fgColor = CHOOSE(tvPtr->fgColor, cbPtr->fgColor); } if (!Blt_TreeViewEntryIsSelected(tvPtr, entryPtr)) { /* * Draw the active or normal background color over the entire * label area. This includes both the tab's text and image. * The rectangle should be 2 pixels wider/taller than this * area. So if the label consists of just an image, we get an * halo around the image when the tab is active. */ if (border != NULL) { Blt_Fill3DRectangle(tvPtr->tkwin, drawable, border, x, y, columnPtr->width, entryPtr->height, cbPtr->borderWidth, cbPtr->relief); } } buttonX = x + columnPtr->width; buttonX -= columnPtr->pad.side2 + cbPtr->borderWidth + cbPtr->buttonWidth + cbPtr->gap; buttonY = y; columnWidth = columnPtr->width - (2 * columnPtr->borderWidth + PADDING(columnPtr->pad)); if (columnWidth > valuePtr->width) { switch(columnPtr->justify) { case TK_JUSTIFY_RIGHT: x += (columnWidth - valuePtr->width); break; case TK_JUSTIFY_CENTER: x += (columnWidth - valuePtr->width) / 2; break; case TK_JUSTIFY_LEFT: break; } } #ifdef notdef textX = textY = iconX = iconY = 0; /* Suppress compiler warning. */ #endif iconWidth = iconHeight = 0; if (cbPtr->icon != NULL) { iconWidth = TreeViewIconWidth(cbPtr->icon); iconHeight = TreeViewIconHeight(cbPtr->icon); } textHeight = 0; if (valuePtr->textPtr != NULL) { textHeight = valuePtr->textPtr->height; } gap = 0; if ((cbPtr->icon != NULL) && (valuePtr->textPtr != NULL)) { gap = cbPtr->gap; } iconX = x + gap; iconY = y + (entryPtr->height - iconHeight) / 2; textX = iconX + iconWidth + gap; textY = y + (entryPtr->height - textHeight) / 2; if (cbPtr->icon != NULL) { Tk_RedrawImage(TreeViewIconBits(cbPtr->icon), 0, 0, iconWidth, iconHeight, drawable, iconX, iconY); } if (valuePtr->textPtr != NULL) { TextStyle ts; XColor *color; Tk_Font font; font = CHOOSE(tvPtr->font, cbPtr->font); if (Blt_TreeViewEntryIsSelected(tvPtr, entryPtr)) { color = SELECT_FG(tvPtr); XSetForeground(tvPtr->display, gc, color->pixel); } else if (entryPtr->color != NULL) { color = entryPtr->color; XSetForeground(tvPtr->display, gc, color->pixel); } else { color = fgColor; } Blt_SetDrawTextStyle(&ts, font, gc, color, fgColor, NULL, 0.0, TK_ANCHOR_NW, TK_JUSTIFY_LEFT, 0, 0); Blt_DrawTextLayout(tvPtr->tkwin, drawable, valuePtr->textPtr, &ts, textX, textY); if (color != fgColor) { XSetForeground(tvPtr->display, gc, fgColor->pixel); } } if (valuePtr == tvPtr->activeValuePtr) { Blt_Fill3DRectangle(tvPtr->tkwin, drawable, stylePtr->activeBorder, buttonX, buttonY + cbPtr->borderWidth, cbPtr->buttonWidth, entryPtr->height - 2 * cbPtr->borderWidth, cbPtr->buttonBorderWidth, cbPtr->buttonRelief); } else { Blt_Fill3DRectangle(tvPtr->tkwin, drawable, columnPtr->titleBorder, buttonX, buttonY + cbPtr->borderWidth, cbPtr->buttonWidth, entryPtr->height - 2 * cbPtr->borderWidth, cbPtr->buttonBorderWidth, cbPtr->buttonRelief); } buttonX += cbPtr->buttonWidth / 2; buttonY += entryPtr->height / 2; Blt_DrawArrow(tvPtr->display, drawable, gc, buttonX, buttonY, STD_ARROW_HEIGHT, ARROW_DOWN); stylePtr->flags &= ~STYLE_DIRTY; } /* *---------------------------------------------------------------------- * * PickCombobox -- * * Draws the "checkbox" given the screen coordinates and the * value to be displayed. * * Results: * None. * * Side Effects: * The checkbox value is drawn. * *---------------------------------------------------------------------- */ static int PickComboBox(entryPtr, valuePtr, stylePtr, worldX, worldY) TreeViewEntry *entryPtr; TreeViewValue *valuePtr; TreeViewStyle *stylePtr; int worldX, worldY; { TreeViewColumn *columnPtr; TreeViewComboBox *cbPtr = (TreeViewComboBox *)stylePtr; int x, y, width, height; columnPtr = valuePtr->columnPtr; width = cbPtr->buttonWidth; height = entryPtr->height - 4; x = columnPtr->worldX + columnPtr->width - columnPtr->pad.side2 - cbPtr->borderWidth - columnPtr->borderWidth - width; y = entryPtr->worldY + cbPtr->borderWidth; if ((worldX >= x) && (worldX < (x + width)) && (worldY >= y) && (worldY < (y + height))) { return TRUE; } return FALSE; } /* *---------------------------------------------------------------------- * * EditCombobox -- * * Edits the "combobox". * * Results: * None. * * Side Effects: * The checkbox value is drawn. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int EditComboBox(tvPtr, entryPtr, valuePtr, stylePtr) TreeView *tvPtr; TreeViewEntry *entryPtr; TreeViewValue *valuePtr; TreeViewStyle *stylePtr; /* Not used. */ { return Blt_TreeViewTextbox(tvPtr, entryPtr, valuePtr->columnPtr); } /* *---------------------------------------------------------------------- * * FreeComboBox -- * * Releases resources allocated for the combobox. The resources * freed by this routine are specific only to the "combobox". * Other resources (common to all styles) are freed in the * Blt_TreeViewFreeStyle routine. * * Results: * None. * * Side Effects: * GCs allocated for the combobox are freed. * *---------------------------------------------------------------------- */ static void FreeComboBox(tvPtr, stylePtr) TreeView *tvPtr; TreeViewStyle *stylePtr; { TreeViewComboBox *cbPtr = (TreeViewComboBox *)stylePtr; if (cbPtr->highlightGC != NULL) { Tk_FreeGC(tvPtr->display, cbPtr->highlightGC); } if (cbPtr->activeGC != NULL) { Tk_FreeGC(tvPtr->display, cbPtr->activeGC); } if (cbPtr->gc != NULL) { Tk_FreeGC(tvPtr->display, cbPtr->gc); } if (cbPtr->icon != NULL) { Blt_TreeViewFreeIcon(tvPtr, cbPtr->icon); } } static TreeViewStyle * GetStyle(interp, tvPtr, styleName) Tcl_Interp *interp; TreeView *tvPtr; char *styleName; { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&tvPtr->styleTable, styleName); if (hPtr == NULL) { if (interp != NULL) { Tcl_AppendResult(interp, "can't find cell style \"", styleName, "\"", (char *)NULL); } return NULL; } return Blt_GetHashValue(hPtr); } int Blt_TreeViewGetStyle(interp, tvPtr, styleName, stylePtrPtr) Tcl_Interp *interp; TreeView *tvPtr; char *styleName; TreeViewStyle **stylePtrPtr; { TreeViewStyle *stylePtr; stylePtr = GetStyle(interp, tvPtr, styleName); if (stylePtr == NULL) { return TCL_ERROR; } stylePtr->refCount++; *stylePtrPtr = stylePtr; return TCL_OK; } static TreeViewStyle * CreateStyle(interp, tvPtr, type, styleName, objc, objv) Tcl_Interp *interp; TreeView *tvPtr; /* TreeView widget. */ int type; /* Type of style: either * STYLE_TEXTBOX, * STYLE_COMBOBOX, or * STYLE_CHECKBOX */ char *styleName; /* Name of the new style. */ int objc; Tcl_Obj *CONST *objv; { Blt_HashEntry *hPtr; int isNew; TreeViewStyle *stylePtr; hPtr = Blt_CreateHashEntry(&tvPtr->styleTable, styleName, &isNew); if (!isNew) { if (interp != NULL) { Tcl_AppendResult(interp, "cell style \"", styleName, "\" already exists", (char *)NULL); } return NULL; } /* Create the new marker based upon the given type */ switch (type) { case STYLE_TEXTBOX: stylePtr = CreateTextBox(tvPtr, hPtr); break; case STYLE_COMBOBOX: stylePtr = CreateComboBox(tvPtr, hPtr); break; case STYLE_CHECKBOX: stylePtr = CreateCheckBox(tvPtr, hPtr); break; default: return NULL; } bltTreeViewIconOption.clientData = tvPtr; if (Blt_ConfigureComponentFromObj(interp, tvPtr->tkwin, styleName, stylePtr->classPtr->className, stylePtr->classPtr->specsPtr, objc, objv, (char *)stylePtr, 0) != TCL_OK) { Blt_TreeViewFreeStyle(tvPtr, stylePtr); return NULL; } return stylePtr; } void Blt_TreeViewUpdateStyleGCs(tvPtr, stylePtr) TreeView *tvPtr; TreeViewStyle *stylePtr; { (*stylePtr->classPtr->configProc)(tvPtr, stylePtr); stylePtr->flags |= STYLE_DIRTY; Blt_TreeViewEventuallyRedraw(tvPtr); } TreeViewStyle * Blt_TreeViewCreateStyle(interp, tvPtr, type, styleName) Tcl_Interp *interp; TreeView *tvPtr; /* TreeView widget. */ int type; /* Type of style: either * STYLE_TEXTBOX, * STYLE_COMBOBOX, or * STYLE_CHECKBOX */ char *styleName; /* Name of the new style. */ { return CreateStyle(interp, tvPtr, type, styleName, 0, (Tcl_Obj **)NULL); } void Blt_TreeViewFreeStyle(tvPtr, stylePtr) TreeView *tvPtr; TreeViewStyle *stylePtr; { stylePtr->refCount--; #ifdef notdef fprint(f(stderr, "Blt_TreeViewFreeStyle %s count=%d\n", stylePtr->name, stylePtr->refCount); #endif /* Remove the style from the hash table so that it's name can be used.*/ /* If no cell is using the style, remove it.*/ if ((stylePtr->refCount <= 0) && !(stylePtr->flags & STYLE_USER)){ #ifdef notdef fprintf(stderr, "freeing %s\n", stylePtr->name); #endif bltTreeViewIconOption.clientData = tvPtr; Blt_FreeObjOptions(stylePtr->classPtr->specsPtr, (char *)stylePtr, tvPtr->display, 0); (*stylePtr->classPtr->freeProc)(tvPtr, stylePtr); if (stylePtr->hashPtr != NULL) { Blt_DeleteHashEntry(&tvPtr->styleTable, stylePtr->hashPtr); } if (stylePtr->name != NULL) { Blt_Free(stylePtr->name); } Blt_Free(stylePtr); } } void Blt_TreeViewSetStyleIcon(tvPtr, stylePtr, icon) TreeView *tvPtr; TreeViewStyle *stylePtr; TreeViewIcon icon; { TreeViewTextBox *tbPtr = (TreeViewTextBox *)stylePtr; if (tbPtr->icon != NULL) { Blt_TreeViewFreeIcon(tvPtr, tbPtr->icon); } tbPtr->icon = icon; } GC Blt_TreeViewGetStyleGC(stylePtr) TreeViewStyle *stylePtr; { TreeViewTextBox *tbPtr = (TreeViewTextBox *)stylePtr; return tbPtr->gc; } Tk_3DBorder Blt_TreeViewGetStyleBorder(tvPtr, stylePtr) TreeView *tvPtr; TreeViewStyle *stylePtr; { TreeViewTextBox *tbPtr = (TreeViewTextBox *)stylePtr; Tk_3DBorder border; border = (tbPtr->flags & STYLE_HIGHLIGHT) ? tbPtr->highlightBorder : tbPtr->border; return (border != NULL) ? border : tvPtr->border; } Tk_Font Blt_TreeViewGetStyleFont(tvPtr, stylePtr) TreeView *tvPtr; TreeViewStyle *stylePtr; { TreeViewTextBox *tbPtr = (TreeViewTextBox *)stylePtr; if (tbPtr->font != NULL) { return tbPtr->font; } return tvPtr->font; } XColor * Blt_TreeViewGetStyleFg(tvPtr, stylePtr) TreeView *tvPtr; TreeViewStyle *stylePtr; { TreeViewTextBox *tbPtr = (TreeViewTextBox *)stylePtr; if (tbPtr->fgColor != NULL) { return tbPtr->fgColor; } return tvPtr->fgColor; } static void DrawValue(tvPtr, entryPtr, valuePtr) TreeView *tvPtr; TreeViewEntry *entryPtr; TreeViewValue *valuePtr; { Drawable drawable; int sx, sy, dx, dy; int width, height; int left, right, top, bottom; TreeViewColumn *columnPtr; TreeViewStyle *stylePtr; stylePtr = valuePtr->stylePtr; if (stylePtr == NULL) { stylePtr = valuePtr->columnPtr->stylePtr; } if (stylePtr->cursor != None) { if (valuePtr == tvPtr->activeValuePtr) { Tk_DefineCursor(tvPtr->tkwin, stylePtr->cursor); } else { if (tvPtr->cursor != None) { Tk_DefineCursor(tvPtr->tkwin, tvPtr->cursor); } else { Tk_UndefineCursor(tvPtr->tkwin); } } } columnPtr = valuePtr->columnPtr; dx = SCREENX(tvPtr, columnPtr->worldX) + columnPtr->pad.side1; dy = SCREENY(tvPtr, entryPtr->worldY); height = entryPtr->height - 1; width = valuePtr->columnPtr->width - PADDING(columnPtr->pad); top = tvPtr->titleHeight + tvPtr->inset; bottom = Tk_Height(tvPtr->tkwin) - tvPtr->inset; left = tvPtr->inset; right = Tk_Width(tvPtr->tkwin) - tvPtr->inset; if (((dx + width) < left) || (dx > right) || ((dy + height) < top) || (dy > bottom)) { return; /* Value is clipped. */ } drawable = Tk_GetPixmap(tvPtr->display, Tk_WindowId(tvPtr->tkwin), width, height, Tk_Depth(tvPtr->tkwin)); /* Draw the background of the value. */ if ((valuePtr == tvPtr->activeValuePtr) || (!Blt_TreeViewEntryIsSelected(tvPtr, entryPtr))) { Tk_3DBorder border; border = Blt_TreeViewGetStyleBorder(tvPtr, tvPtr->stylePtr); Blt_Fill3DRectangle(tvPtr->tkwin, drawable, border, 0, 0, width, height, 0, TK_RELIEF_FLAT); } else { Blt_Fill3DRectangle(tvPtr->tkwin, drawable, SELECT_BORDER(tvPtr), 0, 0, width, height, tvPtr->selBorderWidth, tvPtr->selRelief); } Blt_TreeViewDrawValue(tvPtr, entryPtr, valuePtr, drawable, 0, 0); /* Clip the drawable if necessary */ sx = sy = 0; if (dx < left) { width -= left - dx; sx += left - dx; dx = left; } if ((dx + width) >= right) { width -= (dx + width) - right; } if (dy < top) { height -= top - dy; sy += top - dy; dy = top; } if ((dy + height) >= bottom) { height -= (dy + height) - bottom; } XCopyArea(tvPtr->display, drawable, Tk_WindowId(tvPtr->tkwin), tvPtr->lineGC, sx, sy, width, height, dx, dy); Tk_FreePixmap(tvPtr->display, drawable); } /* *---------------------------------------------------------------------- * * StyleActivateOp -- * * Turns on/off highlighting for a particular style. * * .t style activate entry column * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StyleActivateOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { TreeViewEntry *entryPtr; TreeViewValue *valuePtr, *oldPtr; oldPtr = tvPtr->activeValuePtr; if (objc == 3) { Tcl_Obj *listObjPtr; valuePtr = tvPtr->activeValuePtr; entryPtr = tvPtr->activePtr; listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); if ((entryPtr != NULL) && (valuePtr != NULL)) { Tcl_Obj *objPtr; objPtr = Tcl_NewIntObj(Blt_TreeNodeId(entryPtr->node)); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); objPtr = Tcl_NewStringObj(valuePtr->columnPtr->key, -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; } else if (objc == 4) { tvPtr->activeValuePtr = NULL; if ((oldPtr != NULL) && (tvPtr->activePtr != NULL)) { DrawValue(tvPtr, tvPtr->activePtr, oldPtr); } } else { TreeViewColumn *columnPtr; if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK) { return TCL_ERROR; } if (Blt_TreeViewGetColumn(interp, tvPtr, objv[4], &columnPtr) != TCL_OK) { return TCL_ERROR; } valuePtr = Blt_TreeViewFindValue(entryPtr, columnPtr); if (valuePtr == NULL) { return TCL_OK; } tvPtr->activePtr = entryPtr; tvPtr->activeColumnPtr = columnPtr; oldPtr = tvPtr->activeValuePtr; tvPtr->activeValuePtr = valuePtr; if (valuePtr != oldPtr) { if (oldPtr != NULL) { DrawValue(tvPtr, entryPtr, oldPtr); } if (valuePtr != NULL) { DrawValue(tvPtr, entryPtr, valuePtr); } } } return TCL_OK; } /* *---------------------------------------------------------------------- * * StyleCgetOp -- * * .t style cget "styleName" -background * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StyleCgetOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { TreeViewStyle *stylePtr; stylePtr = GetStyle(interp, tvPtr, Tcl_GetString(objv[3])); if (stylePtr == NULL) { return TCL_ERROR; } return Blt_ConfigureValueFromObj(interp, tvPtr->tkwin, stylePtr->classPtr->specsPtr, (char *)tvPtr, objv[4], 0); } /* *---------------------------------------------------------------------- * * StyleCheckBoxOp -- * * .t style checkbox "styleName" -background blue * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StyleCheckBoxOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { TreeViewStyle *stylePtr; stylePtr = CreateStyle(interp, tvPtr, STYLE_CHECKBOX, Tcl_GetString(objv[3]), objc - 4, objv + 4); if (stylePtr == NULL) { return TCL_ERROR; } stylePtr->refCount = 0; stylePtr->flags |= STYLE_USER; Blt_TreeViewUpdateStyleGCs(tvPtr, stylePtr); Tcl_SetObjResult(interp, objv[3]); return TCL_OK; } /* *---------------------------------------------------------------------- * * StyleComboBoxOp -- * * .t style combobox "styleName" -background blue * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StyleComboBoxOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { TreeViewStyle *stylePtr; stylePtr = CreateStyle(interp, tvPtr, STYLE_COMBOBOX, Tcl_GetString(objv[3]), objc - 4, objv + 4); if (stylePtr == NULL) { return TCL_ERROR; } stylePtr->refCount = 0; stylePtr->flags |= STYLE_USER; Blt_TreeViewUpdateStyleGCs(tvPtr, stylePtr); Tcl_SetObjResult(interp, objv[3]); return TCL_OK; } /* *---------------------------------------------------------------------- * * StyleConfigureOp -- * * This procedure is called to process a list of configuration * options database, in order to reconfigure a style. * * .t style configure "styleName" option value * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for stylePtr; old resources get freed, if there * were any. * *---------------------------------------------------------------------- */ static int StyleConfigureOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { TreeViewStyle *stylePtr; stylePtr = GetStyle(interp, tvPtr, Tcl_GetString(objv[3])); if (stylePtr == NULL) { return TCL_ERROR; } if (objc == 4) { return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin, stylePtr->classPtr->specsPtr, (char *)stylePtr, (Tcl_Obj *)NULL, 0); } else if (objc == 5) { return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin, stylePtr->classPtr->specsPtr, (char *)stylePtr, objv[5], 0); } bltTreeViewIconOption.clientData = tvPtr; if (Blt_ConfigureWidgetFromObj(interp, tvPtr->tkwin, stylePtr->classPtr->specsPtr, objc - 4, objv + 4, (char *)stylePtr, BLT_CONFIG_OBJV_ONLY) != TCL_OK) { return TCL_ERROR; } (*stylePtr->classPtr->configProc)(tvPtr, stylePtr); stylePtr->flags |= STYLE_DIRTY; tvPtr->flags |= (TV_LAYOUT | TV_DIRTY); Blt_TreeViewEventuallyRedraw(tvPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * StyleForgetOp -- * * Eliminates one or more style names. A style still may be in * use after its name has been officially removed. Only its hash * table entry is removed. The style itself remains until its * reference count returns to zero (i.e. no one else is using it). * * .t style forget "styleName"... * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * *---------------------------------------------------------------------- */ static int StyleForgetOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { TreeViewStyle *stylePtr; int i; for (i = 3; i < objc; i++) { stylePtr = GetStyle(interp, tvPtr, Tcl_GetString(objv[i])); if (stylePtr == NULL) { return TCL_ERROR; } if (stylePtr->hashPtr != NULL) { Blt_DeleteHashEntry(&tvPtr->styleTable, stylePtr->hashPtr); stylePtr->hashPtr = NULL; } stylePtr->flags &= ~STYLE_USER; if (stylePtr->refCount <= 0) { Blt_TreeViewFreeStyle(tvPtr, stylePtr); } } Blt_TreeViewEventuallyRedraw(tvPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * StyleHighlightOp -- * * Turns on/off highlighting for a particular style. * * .t style highlight styleName on|off * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StyleHighlightOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { TreeViewStyle *stylePtr; int bool, oldBool; stylePtr = GetStyle(interp, tvPtr, Tcl_GetString(objv[3])); if (stylePtr == NULL) { return TCL_ERROR; } if (Tcl_GetBooleanFromObj(interp, objv[4], &bool) != TCL_OK) { return TCL_ERROR; } oldBool = ((stylePtr->flags & STYLE_HIGHLIGHT) != 0); if (oldBool != bool) { if (bool) { stylePtr->flags |= STYLE_HIGHLIGHT; } else { stylePtr->flags &= ~STYLE_HIGHLIGHT; } Blt_TreeViewEventuallyRedraw(tvPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * StyleNamesOp -- * * Lists the names of all the current styles in the treeview widget. * * .t style names * * Results: * Always TCL_OK. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StyleNamesOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; /* Not used. */ { Blt_HashEntry *hPtr; Blt_HashSearch cursor; Tcl_Obj *listObjPtr, *objPtr; TreeViewStyle *stylePtr; listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); for (hPtr = Blt_FirstHashEntry(&tvPtr->styleTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { stylePtr = Blt_GetHashValue(hPtr); objPtr = Tcl_NewStringObj(stylePtr->name, -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * StyleSetOp -- * * Sets a style for a given key for all the ids given. * * .t style set styleName key node... * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * *---------------------------------------------------------------------- */ static int StyleSetOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { Blt_TreeKey key; TreeViewEntry *entryPtr; TreeViewStyle *stylePtr, *oldStylePtr; TreeViewTagInfo info; int i; stylePtr = GetStyle(interp, tvPtr, Tcl_GetString(objv[3])); if (stylePtr == NULL) { return TCL_ERROR; } key = Blt_TreeGetKey(Tcl_GetString(objv[4])); stylePtr->flags |= STYLE_LAYOUT; for (i = 5; i < objc; i++) { if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[i], &info) != TCL_OK) { return TCL_ERROR; } for (entryPtr = Blt_TreeViewFirstTaggedEntry(&info); entryPtr != NULL; entryPtr = Blt_TreeViewNextTaggedEntry(&info)) { register TreeViewValue *valuePtr; for (valuePtr = entryPtr->values; valuePtr != NULL; valuePtr = valuePtr->nextPtr) { if (valuePtr->columnPtr->key == key) { stylePtr->refCount++; oldStylePtr = valuePtr->stylePtr; valuePtr->stylePtr = stylePtr; if (oldStylePtr != NULL) { Blt_TreeViewFreeStyle(tvPtr, oldStylePtr); } break; } } } } Blt_TreeViewEventuallyRedraw(tvPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * StyleTextBoxOp -- * * .t style text "styleName" -background blue * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int StyleTextBoxOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { TreeViewStyle *stylePtr; stylePtr = CreateStyle(interp, tvPtr, STYLE_TEXTBOX, Tcl_GetString(objv[3]), objc - 4, objv + 4); if (stylePtr == NULL) { return TCL_ERROR; } stylePtr->refCount = 0; stylePtr->flags |= STYLE_USER; Blt_TreeViewUpdateStyleGCs(tvPtr, stylePtr); Tcl_SetObjResult(interp, objv[3]); return TCL_OK; } /* *---------------------------------------------------------------------- * * StyleUnsetOp -- * * Removes a style for a given key for all the ids given. * The cell's style is returned to its default state. * * .t style unset styleName key node... * * Results: * A standard Tcl result. If TCL_ERROR is returned, then * interp->result contains an error message. * *---------------------------------------------------------------------- */ static int StyleUnsetOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { Blt_TreeKey key; TreeViewEntry *entryPtr; TreeViewStyle *stylePtr; TreeViewTagInfo info; int i; stylePtr = GetStyle(interp, tvPtr, Tcl_GetString(objv[3])); if (stylePtr == NULL) { return TCL_ERROR; } key = Blt_TreeGetKey(Tcl_GetString(objv[4])); stylePtr->flags |= STYLE_LAYOUT; for (i = 5; i < objc; i++) { if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[i], &info) != TCL_OK) { return TCL_ERROR; } for (entryPtr = Blt_TreeViewFirstTaggedEntry(&info); entryPtr != NULL; entryPtr = Blt_TreeViewNextTaggedEntry(&info)) { register TreeViewValue *valuePtr; for (valuePtr = entryPtr->values; valuePtr != NULL; valuePtr = valuePtr->nextPtr) { if (valuePtr->columnPtr->key == key) { if (valuePtr->stylePtr != NULL) { Blt_TreeViewFreeStyle(tvPtr, valuePtr->stylePtr); valuePtr->stylePtr = NULL; } break; } } } } Blt_TreeViewEventuallyRedraw(tvPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * StyleOp -- * * .t style activate $node $column * .t style activate * .t style cget "highlight" -foreground * .t style configure "highlight" -fg blue -bg green * .t style checkbox "highlight" * .t style highlight "highlight" on|off * .t style combobox "highlight" * .t style text "highlight" * .t style forget "highlight" * .t style get "mtime" $node * .t style names * .t style set "mtime" "highlight" all * .t style unset "mtime" all * *---------------------------------------------------------------------- */ static Blt_OpSpec styleOps[] = { {"activate", 1, (Blt_Op)StyleActivateOp, 3, 5,"entry column",}, {"cget", 2, (Blt_Op)StyleCgetOp, 5, 5, "styleName option",}, {"checkbox", 2, (Blt_Op)StyleCheckBoxOp, 4, 0, "styleName options...",}, {"combobox", 3, (Blt_Op)StyleComboBoxOp, 4, 0, "styleName options...",}, {"configure", 3, (Blt_Op)StyleConfigureOp, 4, 0, "styleName options...",}, {"forget", 1, (Blt_Op)StyleForgetOp, 3, 0, "styleName...",}, {"highlight", 1, (Blt_Op)StyleHighlightOp, 5, 5, "styleName boolean",}, {"names", 1, (Blt_Op)StyleNamesOp, 3, 3, "",}, {"set", 1, (Blt_Op)StyleSetOp, 6, 6, "key styleName tagOrId...",}, {"textbox", 1, (Blt_Op)StyleTextBoxOp, 4, 0, "styleName options...",}, {"unset", 1, (Blt_Op)StyleUnsetOp, 5, 5, "key tagOrId",}, }; static int nStyleOps = sizeof(styleOps) / sizeof(Blt_OpSpec); int Blt_TreeViewStyleOp(tvPtr, interp, objc, objv) TreeView *tvPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { Blt_Op proc; int result; proc = Blt_GetOpFromObj(interp, nStyleOps, styleOps, BLT_OP_ARG2, objc, objv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc)(tvPtr, interp, objc, objv); return result; } #endif /* NO_TREEVIEW */ blt-2.4z.orig/src/bltTuple.c0100644000175000017500000022370607541720676014522 0ustar dokodoko#include #include /* * array or row pointers * _ * |_---> [row index * |_ [#columns array of Tcl_Objs * |_ [tuple pointer ---> [ . . . . . ] * |_ * |_ * |_ * |_ * |_ * |_ * |_ * |_ * |_ * |_ * |_ * |_ * |_ * |_ * |_ * |_ * |_ * |_ * */ enum TagTypes { TAG_TYPE_NONE, TAG_TYPE_ALL, TAG_TYPE_TAG }; #define TUPLE_THREAD_KEY "BLT Tuple Data" #define TUPLE_MAGIC ((unsigned int) 0x46170277) #define TUPLE_DESTROYED (1<<0) #define TRACE_IGNORE (0) #define TRACE_OK (1) #define VALUE(r,c) \ ((((c)->index < (r)->nColumns) && ((r)->data != NULL)) \ ? (r)->data[(c)->index] : NULL) typedef struct Blt_TupleColumnStruct Column; typedef struct Blt_TupleRowStruct Row; typedef struct Blt_TupleTagTableStruct TagTable; typedef struct Blt_TupleTraceStruct Trace; typedef struct Blt_TupleClientStruct TupleClient; typedef struct Blt_TupleNotifierStruct Notifier; struct Blt_TupleRowStruct { Tcl_Obj **data; /* Array of Tcl_Objs represents the tuple's * data. */ unsigned short nColumns; /* # columns allocated for this tuple. */ unsigned short flags; /* Special flags for this tuple. */ unsigned int index; /* Index of the tuple in the array. */ }; struct Blt_TupleColumnStruct { char *key; /* Name of column. */ int type; /* Type of column: * TYPE_INTEGER * TYPE_NUMBER * TYPE_FLOAT * TYPE_STRING * TYPE_BOOLEAN * TYPE_LIST * TYPE_ARRAY */ int nz; /* Number of (non-NULL) defined values * in the column. */ unsigned int index; /* Location of column in tuple. */ unsigned int flags; /* Special flags for this column. */ Blt_HashEntry *hashPtr; /* Vector linkage */ }; struct Blt_TupleTagTableStruct { Blt_HashTable tagTable; int refCount; }; typedef struct { Blt_HashTable instTable; /* Table of tuple objects. */ unsigned int nextId; Tcl_Interp *interp; } TupleInterpData; typedef struct { Row *rowPtr; Column *columnPtr; } BusyKey; /* Blt_TupleRemoveColumn(table, key); Blt_TupleAddColumn(table, key); Blt_TupleRenameColumn(table, key, newKey); Blt_TupleSetColumnType(table, key, type); Blt_TupleGetColumnType(table, key, typePtr); unsigned int Blt_TupleColumnLength(table, key, flags); Tcl_Obj **Blt_TupleGetColumnVector(tuple, key); unsigned int Blt_TupleLength(table); unsigned int Blt_TupleSize(table); Blt_TupleTuple Blt_TableGetTuple(table, index); Blt_TupleSetTuple(table, index, tuple); Blt_TupleTuple Blt_TableAppendTuple(tuple); Blt_TableTuple Blt_TupleInsertTuple(table, newPosition); Blt_TupleDeleteTuple(table, tuple); Blt_TupleMoveTuple(table, tuple, newPosition); */ /* * Blt_TupleObject -- * * Structure representing a tuple object. * * Tuple objects are uniquely identified by a combination of * their name and the originating namespace. Two objects in the * same interpreter can have similar names but must reside in * different namespaces. * * The tuple object is an array of tuples. A tuple itself is an * array of Tcl_Objs representing data for each column (or key). * Value are identified by their column name. A tuple does not * need to contain values for all columns. Undefined values * (Tcl_Objs) are NULL. * * A tuple object can be shared by several clients. When a * client wants to use a tuple object, it is given a token that * represents the table. The object tracks its clients by its * token. When all clients have released their tokens, the tuple * object is automatically destroyed. * */ typedef struct { Tcl_Interp *interp; /* Interpreter associated with this * object. */ char *name; /* Name of tuple object. */ Tcl_Namespace *nsPtr; Blt_HashEntry *hashPtr; /* Pointer to this object in object * hash table. */ Blt_HashTable *tablePtr; unsigned int columnsAllocated; unsigned int rowsAllocated; unsigned int nColumns; /* Number columns in each tuple. */ unsigned int nRows; /* Number of rows (tuples). */ Row **rows; Column **columns; /* Array of column pointers. Supports * mappings of numeric indices back to * columns. */ Blt_HashTable columnTable; /* Hash table of columns. Supports * mappings of string names back to * columns. */ Blt_Pool rowPool; /* Pool that allocates row containers. */ char *sortCmd; /* Tcl command to invoke to sort * entries. */ Blt_Chain *clients; /* List of clients using this table */ unsigned int flags; /* Internal flags. See definitions * below. */ unsigned int notifyFlags; /* Notification flags. See definitions * below. */ Blt_Chain *notifiers; /* Chain of node event handlers. */ Blt_Chain *traces; /* Chain of callbacks for value changes. */ Blt_HashTable busyTable; /* Hash table tracking the cells that * have traces currently active. */ int notifyHold; } TupleObject; /* * Blt_TupleClientStruct -- * * A tuple object can be shared by several clients. Each client * allocates this structure which acts as a ticket for using the * table. Clients can designate notifier routines that are * automatically invoked by the tuple object whenever the object * is changed is specific ways by other clients. */ struct Blt_TupleClientStruct { unsigned int magic; /* Magic value indicating whether a * generic pointer is really a tuple * token or not. */ Blt_ChainLink *linkPtr; /* Pointer into the server's chain of * clients. */ Tcl_Interp *interp; TupleObject *tupleObjPtr; /* Pointer to the structure containing * the master information about the * table used by the client. If NULL, * this indicates that the table has * been destroyed (but as of yet, this * client hasn't recognized it). */ TagTable *tagTablePtr; }; #define Blt_TupleTableLength(table) ((table)->nRows) #define Blt_TupleTableWidth(table) ((table)->nColumns) static Tcl_InterpDeleteProc TupleInterpDeleteProc; static Row * NewRow(TupleObject *tupleObjPtr, unsigned int rowIndex) { Row *rowPtr; rowPtr = Blt_PoolAllocItem(tupleObjPtr->rowPool, sizeof(Row)); rowPtr->data = NULL; rowPtr->nColumns = 0; rowPtr->index = rowIndex; return rowPtr; } static void DeleteRow(TupleObject *tupleObjPtr, Row *rowPtr) { if (rowPtr->data != NULL) { int i; Tcl_Obj *objPtr; for(i = 0; i < rowPtr->nColumns; i++) { objPtr = rowPtr->data[i]; if (objPtr != NULL) { Tcl_DecrRefCount(objPtr); } } Blt_Free(rowPtr->data); } Blt_PoolFreeItem(tupleObjPtr->rowPool, (char *)rowPtr); } /* * -------------------------------------------------------------- * * NewTupleObject -- * * Creates and initializes a new tuple object. * * Results: * Returns a pointer to the new object is successful, NULL * otherwise. If a tuple object can't be generated, * interp->result will contain an error message. * * -------------------------------------------------------------- */ static TupleObject * NewTupleObject( TupleInterpData *dataPtr, Tcl_Interp *interp, CONST char *name) { TupleObject *tupleObjPtr; int isNew; Blt_HashEntry *hPtr; tupleObjPtr = Blt_Calloc(1, sizeof(TupleObject)); if (tupleObjPtr == NULL) { Tcl_AppendResult(interp, "can't allocate tuple object", (char *)NULL); return NULL; } tupleObjPtr->interp = interp; tupleObjPtr->clients = Blt_ChainCreate(); tupleObjPtr->traces = Blt_ChainCreate(); tupleObjPtr->notifiers = Blt_ChainCreate(); tupleObjPtr->notifyFlags = 0; Blt_InitHashTableWithPool(&tupleObjPtr->busyTable, BLT_ONE_WORD_KEYS); Blt_InitHashTable(&tupleObjPtr->columnTable, BLT_STRING_KEYS); tupleObjPtr->tablePtr = &dataPtr->instTable; hPtr = Blt_CreateHashEntry(tupleObjPtr->tablePtr, name, &isNew); tupleObjPtr->hashPtr = hPtr; tupleObjPtr->name = Blt_GetHashKey(tupleObjPtr->tablePtr, hPtr); Blt_SetHashValue(hPtr, tupleObjPtr); return tupleObjPtr; } /* * ---------------------------------------------------------------------- * * DestroyTupleObject -- * * Destroys the tuple object. This is the final clean up of the * object. The object's entry is removed from the hash table of * tuples. * * Results: * None. * * ---------------------------------------------------------------------- */ static void DestroyTupleObject(TupleObject *tupleObjPtr) { Blt_ChainLink *linkPtr; Trace *tracePtr; struct Blt_TupleNotifierStruct *notifyPtr; tupleObjPtr->flags |= TUPLE_DESTROYED; for (linkPtr = Blt_ChainFirstLink(tupleObjPtr->traces); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tracePtr = Blt_ChainGetValue(linkPtr); tracePtr->linkPtr = NULL; Blt_TupleDeleteTrace(tracePtr); } for (linkPtr = Blt_ChainFirstLink(tupleObjPtr->notifiers); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { notifyPtr = Blt_ChainGetValue(linkPtr); notifyPtr->linkPtr = NULL; Blt_TupleDeleteNotifier(notifyPtr); } Blt_ChainDestroy(tupleObjPtr->traces); Blt_ChainDestroy(tupleObjPtr->notifiers); Blt_ChainDestroy(tupleObjPtr->clients); if (tupleObjPtr->rows != NULL) { int i; for (i = 0; i < tupleObjPtr->nRows; i++) { DeleteRow(tupleObjPtr, tupleObjPtr->rows[i]); } Blt_Free(tupleObjPtr->rows); } tupleObjPtr->nRows = 0; Blt_PoolDestroy(tupleObjPtr->rowPool); Blt_DeleteHashTable(&tupleObjPtr->columnTable); Blt_DeleteHashTable(&tupleObjPtr->busyTable); if (tupleObjPtr->hashPtr != NULL) { Blt_DeleteHashEntry(tupleObjPtr->tablePtr, tupleObjPtr->hashPtr); } Blt_Free(tupleObjPtr); } /* * ----------------------------------------------------------------------- * * TupleInterpDeleteProc -- * * This is called when the interpreter hosting the tree object * is deleted from the interpreter. * * Results: * None. * * Side effects: * Destroys all remaining trees and removes the hash table * used to register tree names. * * ------------------------------------------------------------------------ */ /* ARGSUSED */ static void TupleInterpDeleteProc( ClientData clientData, /* Interpreter-specific data. */ Tcl_Interp *interp) { TupleInterpData *dataPtr = clientData; Blt_HashEntry *hPtr; Blt_HashSearch cursor; TupleObject *tupleObjPtr; for (hPtr = Blt_FirstHashEntry(&dataPtr->instTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tupleObjPtr = (TupleObject *)Blt_GetHashValue(hPtr); tupleObjPtr->hashPtr = NULL; DestroyTupleObject(tupleObjPtr); } Blt_DeleteHashTable(&dataPtr->instTable); Tcl_DeleteAssocData(interp, TUPLE_THREAD_KEY); Blt_Free(dataPtr); } /* * -------------------------------------------------------------- * * GetTupleInterpData -- * * Creates or retrieves data associated with tuple data objects * for a particular thread. We're using Tcl_GetAssocData rather * than the Tcl thread routines so BLT can work with pre-8.0 * Tcl versions that don't have thread support. * * Results: * Returns a pointer to the tuple interpreter data. * * -------------------------------------------------------------- */ static TupleInterpData * GetTupleInterpData(Tcl_Interp *interp) { Tcl_InterpDeleteProc *proc; TupleInterpData *dataPtr; dataPtr = (TupleInterpData *) Tcl_GetAssocData(interp, TUPLE_THREAD_KEY, &proc); if (dataPtr == NULL) { dataPtr = Blt_Malloc(sizeof(TupleInterpData)); assert(dataPtr); dataPtr->interp = interp; Tcl_SetAssocData(interp, TUPLE_THREAD_KEY, TupleInterpDeleteProc, dataPtr); Blt_InitHashTable(&dataPtr->instTable, BLT_STRING_KEYS); } return dataPtr; } /* *---------------------------------------------------------------------- * * NewTagTable -- * *---------------------------------------------------------------------- */ static TagTable * NewTagTable(void) { TagTable *tablePtr; tablePtr = Blt_Malloc(sizeof(TagTable)); Blt_InitHashTable(&tablePtr->tagTable, BLT_STRING_KEYS); tablePtr->refCount = 1; return tablePtr; } static void ReleaseTagTable(TagTable *tablePtr) { tablePtr->refCount--; if (tablePtr->refCount <= 0) { Blt_HashEntry *hPtr; Blt_HashSearch cursor; Blt_TupleTagEntry *tPtr; for(hPtr = Blt_FirstHashEntry(&tablePtr->tagTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tPtr = Blt_GetHashValue(hPtr); Blt_DeleteHashTable(&tPtr->rowTable); Blt_Free(tPtr); } Blt_DeleteHashTable(&tablePtr->tagTable); Blt_Free(tablePtr); } } static int ParseParentheses( Tcl_Interp *interp, CONST char *string, char **leftPtr, char **rightPtr) { register char *p; char *left, *right; left = right = NULL; for (p = (char *)string; *p != '\0'; p++) { if (*p == '(') { left = p; } else if (*p == ')') { right = p; } } if (left != right) { if (((left != NULL) && (right == NULL)) || ((left == NULL) && (right != NULL)) || (left > right) || (right != (p - 1))) { if (interp != NULL) { Tcl_AppendResult(interp, "bad array specification \"", string, "\"", (char *)NULL); } return TCL_ERROR; } } *leftPtr = left; *rightPtr = right; return TCL_OK; } /* *---------------------------------------------------------------------- * * Blt_TupleGetColumnIndex-- * * Returns the index of the column by the name given. Translates * between column names and indices. Column indices are a direct * lookup while names must be hashed. * * Results: * A standard Tcl result. Returns the index of via *indexPtr. * If no column can be found, then TCL_ERROR is returned and * an error message is left in the interpreter result. * *---------------------------------------------------------------------- */ int Blt_TupleGetColumnIndex( Tcl_Interp *interp, TupleObject *tupleObjPtr, CONST char *key, unsigned int *indexPtr) { char *left, *right; Column *columnPtr; Blt_HashEntry *hPtr; if (ParseParentheses(interp, key, &left, &right) != TCL_OK) { return TCL_ERROR; } if (left != NULL) { *left = '\0'; hPtr = Blt_FindHashEntry(&tupleObjPtr->columnTable, key); *left = '('; } else { hPtr = Blt_FindHashEntry(&tupleObjPtr->columnTable, key); } if (hPtr == NULL) { if (interp != NULL) { Tcl_AppendResult(interp, "can't find column \"", key, "\" in \"", tupleObjPtr->name, "\"", (char *)NULL); } return TCL_ERROR; } columnPtr = Blt_GetHashValue(hPtr); *indexPtr = columnPtr->index; return TCL_OK; } /* *---------------------------------------------------------------------- * * CallTraces -- * * Examines the traces set for each client of the tuple object * and fires any matching trace. * * Traces can match on * row if the trace was specified by index. * tag if the trace was specified by tag. * key if the trace was specified with a list of * one or more keys. * flag type of trace (read, write, unset, create) * * If no matching criteria is specified (no tag, key, or tuple * address) then only the bit flag has to match. * * If the TUPLE_TRACE_FOREIGN_ONLY is set in the handler, it * means to ignore actions that are initiated by that client of * the object. Only actions by other clients are handled. * * Results: * Always returns TCL_OK. * * Side Effects: * Traces on the tuple table location may be fired. * *---------------------------------------------------------------------- */ static void CallTraces( Tcl_Interp *interp, TupleClient *clientPtr, /* Client holding a reference to the * tuple object. */ Row *rowPtr, /* Tuple being modified. */ Column *columnPtr, unsigned int flags) { Blt_ChainLink *linkPtr; Trace *tracePtr; TupleObject *tupleObjPtr; /* Tuple that was changed. */ tupleObjPtr = clientPtr->tupleObjPtr; /* For each client, examine its trace handlers. */ for(linkPtr = Blt_ChainFirstLink(tupleObjPtr->traces); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tracePtr = Blt_ChainGetValue(linkPtr); if ((tracePtr->tuple != NULL) && (tracePtr->tuple != rowPtr)) { continue; /* Row doesn't match. */ } if ((tracePtr->mask & flags) == 0) { continue; /* Missing the required trace flags. */ } if ((tracePtr->table == clientPtr) && (tracePtr->mask & TUPLE_TRACE_FOREIGN_ONLY)) { continue; /* This client initiated the action. */ } if ((tracePtr->withTag != NULL) && (!Blt_TupleHasTag(tracePtr->table, rowPtr, tracePtr->withTag))){ continue; /* Tag doesn't match. */ } if (tracePtr->keys != NULL) { register CONST char **p; for (p = tracePtr->keys; *p != NULL; p++) { if (strcmp(*p, columnPtr->key) == 0) { break; } } if (*p == NULL) { continue; /* No keys match. */ } } if ((*tracePtr->proc) (tracePtr->clientData, tupleObjPtr->interp, rowPtr->index, columnPtr->index, flags) != TCL_OK) { if (interp != NULL) { Tcl_BackgroundError(interp); } } } } /* * -------------------------------------------------------------- * * GetValue -- * * Gets a scalar Tcl_Obj value from the table at the designated * row and column. Create and read traces may be fired. * * Results: * Always returns TCL_OK. * * -------------------------------------------------------------- */ static int GetValue( Tcl_Interp *interp, /* Interpreter to reports result to. */ TupleClient *clientPtr, /* Table. */ Row *rowPtr, /* Row. */ Column *columnPtr, /* Column. */ Tcl_Obj **objPtrPtr) /* (out) Value from table. */ { Blt_HashEntry *hPtr; BusyKey busy; TupleObject *tupleObjPtr = clientPtr->tupleObjPtr; int isNew; busy.rowPtr = rowPtr; busy.columnPtr = columnPtr; hPtr = Blt_CreateHashEntry(&tupleObjPtr->busyTable, &busy, &isNew); if (isNew) { CallTraces(interp, clientPtr, rowPtr, columnPtr, TUPLE_TRACE_READ); } Blt_DeleteHashEntry(&tupleObjPtr->busyTable, hPtr); /* Access the data value after traces have been called. */ *objPtrPtr = VALUE(rowPtr, columnPtr); return TCL_OK; } /* * -------------------------------------------------------------- * * SetValue -- * * Sets a scalar Tcl_Obj value in the table at the designated row * and column. Write traces may be fired. * * Results: * Always returns TCL_OK. * * -------------------------------------------------------------- */ static int SetValue( Tcl_Interp *interp, TupleClient *clientPtr, Row *rowPtr, Column *columnPtr, Tcl_Obj *objPtr) { Tcl_Obj *oldObjPtr; unsigned int flags; Blt_HashEntry *hPtr; int isNew; BusyKey busy; TupleObject *tupleObjPtr = clientPtr->tupleObjPtr; if ((rowPtr->nColumns < columnPtr->index) && (rowPtr->data != NULL)) { oldObjPtr = rowPtr->data[columnPtr->index]; } else { AllocateRows(tupleObjPtr, rowPtr); objObjPtr = NULL; } if (objPtr != NULL) { Tcl_IncrRefCount(objPtr); } if (oldObjPtr != NULL) { Tcl_DecrRefCount(oldObjPtr); } rowPtr->data[columnPtr->index] = objPtr; flags = TUPLE_TRACE_WRITE; if (oldObjPtr == NULL) { flags |= TUPLE_TRACE_CREATE; } busy.rowPtr = rowPtr; busy.columnPtr = columnPtr; hPtr = Blt_CreateHashEntry(&tupleObjPtr->busyTable, &busy, &isNew); if (isNew) { CallTraces(interp, clientPtr, rowPtr, columnPtr, flags); } Blt_DeleteHashEntry(&tupleObjPtr->busyTable, hPtr); return TCL_OK; } /* * -------------------------------------------------------------- * * UnsetValue -- * * Unsets a scalar Tcl_Obj value in the table at the designated * row and column. Unset traces may be fired. * * Results: * Always returns TCL_OK. * * -------------------------------------------------------------- */ static int UnsetValue( Tcl_Interp *interp, TupleClient *clientPtr, Row *rowPtr, Column *columnPtr) { Tcl_Obj *objPtr; objPtr = VALUE(rowPtr, columnPtr); if (objPtr != NULL) { TupleObject *tupleObjPtr = clientPtr->tupleObjPtr; Blt_HashEntry *hPtr; BusyKey busy; int isNew; Tcl_DecrRefCount(objPtr); rowPtr->data[columnPtr->index] = NULL; busy.rowPtr = rowPtr; busy.columnPtr = columnPtr; hPtr = Blt_CreateHashEntry(&tupleObjPtr->busyTable, &busy, &isNew); if (isNew) { CallTraces(interp, clientPtr, rowPtr, columnPtr, TUPLE_TRACE_UNSET); } Blt_DeleteHashEntry(&tupleObjPtr->busyTable, hPtr); } return TCL_OK; } static int GetArrayValue( Tcl_Interp *interp, TupleClient *clientPtr, Row *rowPtr, Column *columnPtr, CONST char *elemName, Tcl_Obj **objPtrPtr, int doTrace) { TupleObject *tupleObjPtr = clientPtr->tupleObjPtr; Tcl_Obj *objPtr; Blt_HashTable *tablePtr; Blt_HashEntry *hPtr; if (doTrace) { BusyKey busy; int isNew; busy.rowPtr = rowPtr; busy.columnPtr = columnPtr; hPtr = Blt_CreateHashEntry(&tupleObjPtr->busyTable, &busy, &isNew); if (isNew) { CallTraces(interp, clientPtr, rowPtr, columnPtr, TUPLE_TRACE_READ); } Blt_DeleteHashEntry(&tupleObjPtr->busyTable, hPtr); } /* Access the data value after traces have been called. */ objPtr = VALUE(rowPtr, columnPtr); if (objPtr != NULL) { if (Tcl_IsShared(objPtr)) { Tcl_DecrRefCount(objPtr); objPtr = Tcl_DuplicateObj(objPtr); Tcl_IncrRefCount(objPtr); rowPtr->data[columnPtr->index] = objPtr; } if (Blt_GetArrayFromObj(interp, objPtr, &tablePtr) != TCL_OK) { return TCL_ERROR; } hPtr = Blt_FindHashEntry(tablePtr, elemName); if (hPtr == NULL) { if (interp != NULL) { Tcl_AppendResult(interp, "can't find \"", columnPtr->key, "(", elemName, ")\"", (char *)NULL); } return TCL_ERROR; } objPtr = Blt_GetHashValue(hPtr); } *objPtrPtr = objPtr; return TCL_OK; } static int SetArrayValue( Tcl_Interp *interp, TupleClient *clientPtr, Row *rowPtr, Column *columnPtr, CONST char *elemName, Tcl_Obj *valueObjPtr) { Blt_HashTable *tablePtr; Tcl_Obj *arrayObjPtr; unsigned int flags; Blt_HashEntry *hPtr; int isNew; BusyKey busy; TupleObject *tupleObjPtr = clientPtr->tupleObjPtr; flags = TUPLE_TRACE_WRITE; arrayObjPtr = VALUE(rowPtr, columnPtr); if (arrayObjPtr == NULL) { arrayObjPtr = Blt_NewArrayObj(0, (Tcl_Obj **)NULL); Tcl_IncrRefCount(arrayObjPtr); flags |= TUPLE_TRACE_CREATE; AllocateRows(tupleObjPtr, rowPtr); } else if (Tcl_IsShared(arrayObjPtr)) { Tcl_DecrRefCount(arrayObjPtr); arrayObjPtr = Tcl_DuplicateObj(arrayObjPtr); Tcl_IncrRefCount(arrayObjPtr); } rowPtr->data[columnPtr->index] = arrayObjPtr; if (Blt_GetArrayFromObj(interp, arrayObjPtr, &tablePtr) != TCL_OK) { return TCL_ERROR; } Tcl_InvalidateStringRep(arrayObjPtr); hPtr = Blt_CreateHashEntry(tablePtr, elemName, &isNew); assert(hPtr); Tcl_IncrRefCount(valueObjPtr); if (!isNew) { Tcl_Obj *oldValueObjPtr; /* An element by the same name already exists. Decrement the * reference count of the old value. */ oldValueObjPtr = Blt_GetHashValue(hPtr); if (oldValueObjPtr != NULL) { Tcl_DecrRefCount(oldValueObjPtr); } } Blt_SetHashValue(hPtr, valueObjPtr); /* * We don't handle traces on a per array element basis. Setting * any element can fire traces for the value. */ busy.rowPtr = rowPtr; busy.columnPtr = columnPtr; hPtr = Blt_CreateHashEntry(&tupleObjPtr->busyTable, &busy, &isNew); if (isNew) { CallTraces(interp, clientPtr, rowPtr, columnPtr, flags); } Blt_DeleteHashEntry(&tupleObjPtr->busyTable, hPtr); return TCL_OK; } static int UnsetArrayValue( Tcl_Interp *interp, TupleClient *clientPtr, Row *rowPtr, Column *columnPtr, CONST char *elemName) { Blt_HashEntry *hPtr; Blt_HashTable *tablePtr; BusyKey busy; Tcl_Obj *arrayObjPtr, *valueObjPtr; TupleObject *tupleObjPtr = clientPtr->tupleObjPtr; int isNew; arrayObjPtr = VALUE(rowPtr, columnPtr); if (arrayObjPtr == NULL) { return TCL_OK; } if (Tcl_IsShared(arrayObjPtr)) { Tcl_DecrRefCount(arrayObjPtr); arrayObjPtr = Tcl_DuplicateObj(arrayObjPtr); Tcl_IncrRefCount(arrayObjPtr); } if (Blt_GetArrayFromObj(interp, arrayObjPtr, &tablePtr) != TCL_OK) { return TCL_ERROR; } hPtr = Blt_FindHashEntry(tablePtr, elemName); if (hPtr == NULL) { return TCL_OK; /* Element doesn't exist, Ok. */ } valueObjPtr = Blt_GetHashValue(hPtr); Tcl_DecrRefCount(valueObjPtr); Blt_DeleteHashEntry(tablePtr, hPtr); rowPtr->data[columnPtr->index] = NULL; /* * Un-setting any element in the array can cause the trace on the value * to fire. */ busy.rowPtr = rowPtr; busy.columnPtr = columnPtr; hPtr = Blt_CreateHashEntry(&tupleObjPtr->busyTable, &busy, &isNew); if (isNew) { CallTraces(interp, clientPtr, rowPtr, columnPtr, TUPLE_TRACE_UNSET); } Blt_DeleteHashEntry(&tupleObjPtr->busyTable, hPtr); return TCL_OK; } static int ExtendRows(TupleObject *tupleObjPtr, int extra) { int nRows; int i; nRows = tupleObjPtr->nRows + extra; if (tupleObjPtr->rowsAllocated < nRows) { Row **rows; if (tupleObjPtr->rowsAllocated == 0) { tupleObjPtr->rowsAllocated = 32; } while (tupleObjPtr->rowsAllocated < nRows) { tupleObjPtr->rowsAllocated += tupleObjPtr->rowsAllocated; } rows = Blt_Realloc(tupleObjPtr->rows, tupleObjPtr->rowsAllocated * sizeof(Row *)); if (rows == NULL) { return -1; } tupleObjPtr->rows = rows; } for (i = tupleObjPtr->nRows; i < nRows; i++) { tupleObjPtr->rows[i] = NewRow(tupleObjPtr, i); } tupleObjPtr->nRows = nRows; return 0; } static int ExtendColumns(TupleObject *tupleObjPtr, Row *rowPtr) { if (tupleObjPtr->columnsAllocated < rowPtr->nColumns) { Tcl_Obj **data; int i; data = Blt_Realloc(rowPtr->data, tupleObjPtr->columnsAllocated * sizeof(Tcl_Obj *)); if (data == NULL) { return TCL_ERROR; } for(i = rowPtr->nColumns; i < tupleObjPtr->columnsAllocated; i++) { data[i] = NULL; } rowPtr->data = data; rowPtr->nColumns = tupleObjPtr->columnsAllocated; } return TCL_OK; } /* * ---------------------------------------------------------------------- * * FindTupleObjectInNamespace -- * * Searches for the tuple object in a given namespace. * * Results: * Returns a pointer to the tuple object if found, otherwise NULL. * * ---------------------------------------------------------------------- */ static TupleObject * FindTupleObjectInNamespace( TupleInterpData *dataPtr, /* Interpreter-specific data. */ Tcl_Namespace *nsPtr, CONST char *objName) { Tcl_DString dString; char *name; Blt_HashEntry *hPtr; name = Blt_GetQualifiedName(nsPtr, objName, &dString); hPtr = Blt_FindHashEntry(&dataPtr->instTable, name); Tcl_DStringFree(&dString); if (hPtr != NULL) { return Blt_GetHashValue(hPtr); } return NULL; } /* * ---------------------------------------------------------------------- * * GetTupleObject -- * * Searches for the tuple object associated by the name given. * * Results: * Returns a pointer to the tuple object if found, otherwise NULL. * * ---------------------------------------------------------------------- */ static TupleObject * GetTupleObject(Tcl_Interp *interp, CONST char *name, unsigned int flags) { CONST char *tupleName; Tcl_Namespace *nsPtr; /* Namespace associated with the tuple object. * If NULL, indicates to look in first the * current namespace and then the global * for the object. */ TupleInterpData *dataPtr; /* Interpreter-specific data. */ TupleObject *tupleObjPtr; tupleObjPtr = NULL; if (Blt_ParseQualifiedName(interp, name, &nsPtr, &tupleName) != TCL_OK) { Tcl_AppendResult(interp, "can't find namespace in \"", name, "\"", (char *)NULL); return NULL; } dataPtr = GetTupleInterpData(interp); if (nsPtr != NULL) { tupleObjPtr = FindTupleObjectInNamespace(dataPtr, nsPtr, tupleName); } else { if (flags & NS_SEARCH_CURRENT) { /* Look first in the current namespace. */ nsPtr = Tcl_GetCurrentNamespace(interp); tupleObjPtr = FindTupleObjectInNamespace(dataPtr, nsPtr, tupleName); } if ((tupleObjPtr == NULL) && (flags & NS_SEARCH_GLOBAL)) { nsPtr = Tcl_GetGlobalNamespace(interp); tupleObjPtr = FindTupleObjectInNamespace(dataPtr, nsPtr, tupleName); } } return tupleObjPtr; } /* *---------------------------------------------------------------------- * * NewTupleClient -- * * Creates a new tuple client. Clients shared a tuple data * object. They individually manage traces and events on tuple * objects. Returns a pointer to the malloc'ed structure. This * is passed to the client as a tuple token. * * Results: * A pointer to a TupleClient is returned. If one can't * be allocated, NULL is returned. * *---------------------------------------------------------------------- */ static TupleClient * NewTupleClient(TupleObject *tupleObjPtr) { TupleClient *clientPtr; clientPtr = Blt_Calloc(1, sizeof(TupleClient)); if (clientPtr != NULL) { clientPtr->magic = TUPLE_MAGIC; clientPtr->linkPtr = Blt_ChainAppend(tupleObjPtr->clients, clientPtr); clientPtr->tupleObjPtr = tupleObjPtr; clientPtr->tagTablePtr = NewTagTable(); } return clientPtr; } /* *---------------------------------------------------------------------- * * NotifyIdleProc -- * * Used to invoke event handler routines at some idle point. * This routine is called from the Tcl event loop. Errors * generated by the event handler routines are backgrounded. * * Results: * None. * *---------------------------------------------------------------------- */ static void NotifyIdleProc(ClientData clientData) { Notifier *notifyPtr = clientData; int result; notifyPtr->notifyPending = FALSE; notifyPtr->mask |= TUPLE_NOTIFY_ACTIVE; result = (*notifyPtr->proc)(notifyPtr->clientData, ¬ifyPtr->event); notifyPtr->mask &= ~TUPLE_NOTIFY_ACTIVE; if (result != TCL_OK) { Tcl_BackgroundError(notifyPtr->interp); } } /* *---------------------------------------------------------------------- * * NotifyClients -- * * Traverses the list of event callbacks and checks if one * matches the given event. A client may trigger an action that * causes the tuple object to notify it. This can be prevented * by setting the TUPLE_NOTIFY_FOREIGN_ONLY bit in the event * handler. * * If a matching handler is found, a callback may be called either * immediately or at the next idle time depending upon the * TUPLE_NOTIFY_WHENIDLE bit. * * Since a handler routine may trigger yet another call to * itself, callbacks are ignored while the event handler is * executing. * *---------------------------------------------------------------------- */ static void NotifyClients( TupleClient *sourcePtr, TupleObject *tupleObjPtr, unsigned int eventFlag) { Blt_ChainLink *linkPtr; Blt_TupleNotifyEvent event; Notifier *notifyPtr; event.type = eventFlag; /* Issue callbacks indicating that the structure of the tuple * table has changed. */ for (linkPtr = Blt_ChainFirstLink(tupleObjPtr->notifiers); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { notifyPtr = Blt_ChainGetValue(linkPtr); if ((notifyPtr->mask & TUPLE_NOTIFY_ACTIVE) || (notifyPtr->mask & eventFlag) == 0) { continue; /* Ignore callbacks that are generated * inside of a notify handler routine. */ } if ((notifyPtr->table == sourcePtr) && (notifyPtr->mask & TUPLE_NOTIFY_FOREIGN_ONLY)) { continue; /* Don't notify yourself. */ } event.table = notifyPtr->table; if (notifyPtr->mask & TUPLE_NOTIFY_WHENIDLE) { if (!notifyPtr->notifyPending) { notifyPtr->notifyPending = TRUE; notifyPtr->event = event; Tcl_DoWhenIdle(NotifyIdleProc, notifyPtr); } } else { int result; notifyPtr->mask |= TUPLE_NOTIFY_ACTIVE; result = (*notifyPtr->proc) (notifyPtr->clientData, &event); notifyPtr->mask &= ~TUPLE_NOTIFY_ACTIVE; if (result != TCL_OK) { Tcl_BackgroundError(notifyPtr->interp); } } } } /* *---------------------------------------------------------------------- * * Blt_TupleCreateObject -- * * Creates a tuple object by the designated name. It's an error * if a tuple object already exists by that name. After * successfully creating the object, the caller must then call * Blt_TupleGetToken to allocate a token to share and manipulate * the object. * * Results: * A standard Tcl result. If successful, a new tuple object is * created and TCL_OK is returned. If an object already exists * or the tuple object can't be allocated, then TCL_ERROR is * returned and an error message is left in the interpreter. * * Side Effects: * A new tuple object is created. * *---------------------------------------------------------------------- */ int Blt_TupleCreateTable( Tcl_Interp *interp, /* Interpreter to report errors back to. */ CONST char *name, /* Name of tuple in namespace. Object * must not already exist. */ TupleClient **clientPtrPtr) /* (out) Client token of newly created * tuple object. Releasing the token * will free the tuple. If NULL, no * token is generated. */ { Tcl_DString dString; Tcl_Namespace *nsPtr; TupleInterpData *dataPtr; TupleObject *tupleObjPtr; CONST char *tupleName; char string[200]; dataPtr = GetTupleInterpData(interp); if (name != NULL) { /* Does an object by this name already exist in the current * namespace? */ tupleObjPtr = GetTupleObject(interp, name, NS_SEARCH_CURRENT); if (tupleObjPtr != NULL) { Tcl_AppendResult(interp, "a tuple object \"", name, "\" already exists", (char *)NULL); return TCL_ERROR; } } else { /* Generate a unique name in the current namespace. */ do { sprintf(string, "tuple%d", dataPtr->nextId++); } while (GetTupleObject(interp, name, NS_SEARCH_CURRENT) != NULL); name = string; } /* * Tear apart and put back together the namespace-qualified name * of the object. This is to ensure that naming is consistent. */ tupleName = name; if (Blt_ParseQualifiedName(interp, name, &nsPtr, &tupleName) != TCL_OK) { Tcl_AppendResult(interp, "can't find namespace in \"", name, "\"", (char *)NULL); return TCL_ERROR; } if (nsPtr == NULL) { /* * Note that unlike Tcl_CreateCommand, an unqualified name * doesn't imply the global namespace, but the current one. */ nsPtr = Tcl_GetCurrentNamespace(interp); } name = Blt_GetQualifiedName(nsPtr, tupleName, &dString); tupleObjPtr = NewTupleObject(dataPtr, interp, name); if (tupleObjPtr == NULL) { Tcl_AppendResult(interp, "can't allocate tuple object \"", name, "\"", (char *)NULL); Tcl_DStringFree(&dString); return TCL_ERROR; } Tcl_DStringFree(&dString); if (clientPtrPtr != NULL) { TupleClient *clientPtr; clientPtr = NewTupleClient(tupleObjPtr); if (clientPtr == NULL) { Tcl_AppendResult(interp, "can't allocate tuple token", (char *)NULL); return TCL_ERROR; } *clientPtrPtr = clientPtr; } return TCL_OK; } /* *---------------------------------------------------------------------- * * Blt_TupleGetToken -- * * Allocates a token for the tuple object designated by name. * It's an error if no tuple object exists by that name. The * token returned is passed to various routines to manipulate the * object. Traces and event notifications are also made through * the token. * * Results: * A new token is returned representing the tuple object. * * Side Effects: * If this is the remaining client, then the tuple object itself * is freed. * *---------------------------------------------------------------------- */ int Blt_TupleGetTable( Tcl_Interp *interp, /* Interpreter to report errors back to. */ CONST char *name, /* Name of tuple object in namespace. */ TupleClient **clientPtrPtr) { TupleClient *clientPtr; TupleObject *tupleObjPtr; tupleObjPtr = GetTupleObject(interp, name, NS_SEARCH_BOTH); if (tupleObjPtr == NULL) { Tcl_AppendResult(interp, "can't find a tuple object \"", name, "\"", (char *)NULL); return TCL_ERROR; } clientPtr = NewTupleClient(tupleObjPtr); if (clientPtr == NULL) { Tcl_AppendResult(interp, "can't allocate token for tuple \"", name, "\"", (char *)NULL); return TCL_ERROR; } *clientPtrPtr = clientPtr; return TCL_OK; } /* *---------------------------------------------------------------------- * * Blt_TupleReleaseToken -- * * Releases the tuple token, indicating this the client is no * longer using the object. The client is removed from the tuple * object's client list. If this is the last client, then the * object itself is destroyed and memory is freed. * * Results: * None. * * Side Effects: * If this is the remaining client, then the tuple object itself * is freed. * *---------------------------------------------------------------------- */ void Blt_TupleReleaseTable(TupleClient *clientPtr) { TupleObject *tupleObjPtr; Blt_ChainLink *linkPtr; Notifier *notifyPtr; Trace *tracePtr; if (clientPtr->magic != TUPLE_MAGIC) { fprintf(stderr, "invalid tuple object token 0x%lx\n", (unsigned long)clientPtr); return; } /* Remove any traces that were set by this client. */ for (linkPtr = Blt_ChainFirstLink(tupleObjPtr->traces); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { tracePtr = Blt_ChainGetValue(linkPtr); if (tracePtr->table == clientPtr) { Blt_TupleDeleteTrace(tracePtr); } } /* Also remove all event handlers created by this client. */ for(linkPtr = Blt_ChainFirstLink(tupleObjPtr->notifiers); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { notifyPtr = Blt_ChainGetValue(linkPtr); if (notifyPtr->table == clientPtr) { Blt_TupleDeleteNotifier(notifyPtr); } } if (clientPtr->tagTablePtr != NULL) { ReleaseTagTable(clientPtr->tagTablePtr); } tupleObjPtr = clientPtr->tupleObjPtr; if (tupleObjPtr != NULL) { /* Remove the client from the server's list */ Blt_ChainDeleteLink(tupleObjPtr->clients, clientPtr->linkPtr); if (Blt_ChainGetLength(tupleObjPtr->clients) == 0) { DestroyTupleObject(tupleObjPtr); } } clientPtr->magic = 0; Blt_Free(clientPtr); } /* *---------------------------------------------------------------------- * * Blt_TupleTableExists -- * * Indicates if a tuple object by the given name exists in either * the current or global namespace. * * Results: * Returns 1 if a tuple object exists and 0 otherwise. * *---------------------------------------------------------------------- */ int Blt_TupleTableExists( Tcl_Interp *interp, /* Interpreter to report errors back to. */ CONST char *name) /* Name of tuple object in the * designated namespace. */ { TupleObject *tupleObjPtr; tupleObjPtr = GetTupleObject(interp, name, NS_SEARCH_BOTH); if (tupleObjPtr == NULL) { Tcl_ResetResult(interp); return 0; } return 1; } /* *---------------------------------------------------------------------- * * Blt_TupleCreateNotifier -- * * Creates an notifier using the following three pieces of * information: * 1. C function pointer, * 2. one-word of data passed on each call, and * 3. event mask indicating which events are of interest. * If an event already exists matching all of the above criteria, * it is repositioned on the end of the event handler list. This * means that it will be the last to fire. * * Results: * Returns a pointer to the event handler. * * Side Effects: * Memory for the event handler is possibly allocated. * *---------------------------------------------------------------------- */ Blt_TupleNotifier Blt_TupleCreateNotifier( TupleClient *clientPtr, unsigned int mask, Blt_TupleNotifyEventProc *proc, ClientData clientData) { Notifier *notifyPtr; notifyPtr = Blt_Malloc(sizeof (Notifier)); assert(notifyPtr); notifyPtr->proc = proc; notifyPtr->clientData = clientData; notifyPtr->mask = mask; notifyPtr->notifyPending = FALSE; notifyPtr->interp = clientPtr->tupleObjPtr->interp; notifyPtr->linkPtr = Blt_ChainAppend(clientPtr->tupleObjPtr->notifiers, notifyPtr); return notifyPtr; } /* *---------------------------------------------------------------------- * * Blt_TupleDeleteNotifier -- * * Removes the event handler designated by following three pieces * of information: 1. C function pointer, 2. one-word of data * passed on each call, and 3. event mask indicating which events * are of interest. * * Results: * Nothing. * * Side Effects: * Memory for the event handler is freed. * *---------------------------------------------------------------------- */ void Blt_TupleDeleteNotifier(Notifier *notifyPtr) { if (notifyPtr->notifyPending) { Tcl_CancelIdleCall(NotifyIdleProc, notifyPtr); } if (notifyPtr->linkPtr != NULL){ Blt_ChainDeleteLink(notifyPtr->table->tupleObjPtr->notifiers, notifyPtr->linkPtr); Blt_Free(notifyPtr); } } /* *---------------------------------------------------------------------- * * Blt_TupleRowIndex -- * * Returns the index of the tuple. * * Results: * Returns the row index of the tuple. * *---------------------------------------------------------------------- */ unsigned int Blt_TupleRowIndex(Row *rowPtr) { return rowPtr->index; } /* *---------------------------------------------------------------------- * * Blt_TupleGetTupleByIndex -- * * Returns the tuple at the row designated int the tuple table. * * Results: * Returns the tuple at the row. If the index is out of range * then NULL is returned. * *---------------------------------------------------------------------- */ Blt_Tuple Blt_TupleGetTupleByIndex(TupleClient *clientPtr, unsigned int row) { if (row >= clientPtr->tupleObjPtr->nRows) { return NULL; } return clientPtr->tupleObjPtr->rows[row]; } Blt_Tuple Blt_TupleNextTuple(TupleClient *clientPtr, Row *rowPtr) { return Blt_TupleGetTupleByIndex(clientPtr, rowPtr->index + 1); } /* *---------------------------------------------------------------------- * * Blt_TupleGetColumnKey -- * * Returns the key of the column with the given index. This is a * helper routine to translate between column indices and keys. * * Results: * Returns the key of the column with the given index. If the * index is invalid, NULL is returned. * *---------------------------------------------------------------------- */ CONST char * Blt_TupleGetColumnKey(TupleClient *clientPtr, int columnIndex) { TupleObject *tupleObjPtr = clientPtr->tupleObjPtr; Column *columnPtr; if ((columnIndex < 0) || (columnIndex >= tupleObjPtr->nColumns)) { return NULL; } columnPtr = tupleObjPtr->columns[columnIndex]; return columnPtr->key; } /* *---------------------------------------------------------------------- * * Blt_TupleAddColumn -- * * Add a new column to the tuple object. Rows are slots in an * array of tuples. The array grows by doubling its size, so * there may be more slots than needed (# rows). * * Results: * Returns TCL_OK is the table is resized and TCL_ERROR if an * not enough memory was available. * * Side Effects: * If more rows are needed, the array which holds the tuples is * reallocated by doubling its size. Storage for the tuples * isn't allocated until the tuple is needed. * *---------------------------------------------------------------------- */ unsigned int Blt_TupleAddColumn( TupleClient *clientPtr, CONST char *key, int *isNewPtr) { TupleObject *tupleObjPtr = clientPtr->tupleObjPtr; Blt_HashEntry *hPtr; Column *columnPtr; hPtr = Blt_CreateHashEntry(&tupleObjPtr->columnTable, key, isNewPtr); if (!*isNewPtr) { columnPtr = Blt_GetHashValue(hPtr); } else { columnPtr = Blt_Calloc(1, sizeof(Column)); columnPtr->key = Blt_GetHashKey(&tupleObjPtr->columnTable, hPtr); columnPtr->type = 0; columnPtr->hashPtr = hPtr; columnPtr->index = tupleObjPtr->nColumns; tupleObjPtr->columns[columnPtr->index] = columnPtr; tupleObjPtr->nColumns++; NotifyClients(clientPtr, tupleObjPtr, TUPLE_NOTIFY_CREATE_COLUMN); } return columnPtr->index; } /* *---------------------------------------------------------------------- * * Blt_TupleAddColumns -- * * Adds one or more columns to the tuple table. This creates a * new column. The tuples are individually resized when new data * is added to them. * * Results: * Returns TCL_OK is the tuple is resized and TCL_ERROR if an * not enough memory was available. * * Side Effects: * If more rows are needed, the array which holds the tuples is * reallocated by doubling its size. Storage for the tuples * isn't allocated until the tuple is needed. * *---------------------------------------------------------------------- */ int Blt_TupleAddColumns( Tcl_Interp *interp, TupleClient *clientPtr, char **keys) { TupleObject *tupleObjPtr = clientPtr->tupleObjPtr; int i; int nColumns, extra; char **p; Blt_HashEntry *hPtr; int isNew; extra = 0; for (p = keys; *p != NULL; p++) { hPtr = Blt_FindHashEntry(&tupleObjPtr->columnTable, *p); if (hPtr != NULL) { Tcl_AppendResult(interp, "a column \"", *p, "\" already exists in \"", tupleObjPtr->name, "\"", (char *)NULL); return TCL_ERROR; } extra++; /* Count the number of new columns. */ } nColumns = tupleObjPtr->nColumns + extra; if (nColumns >= tupleObjPtr->columnsAllocated) { Column **columns; int columnsAllocated; columnsAllocated = tupleObjPtr->columnsAllocated; while (nColumns >= columnsAllocated) { columnsAllocated += columnsAllocated; } columns = Blt_Realloc(tupleObjPtr->columns, sizeof(Column *) * columnsAllocated); if (columns == NULL) { return TCL_ERROR; } tupleObjPtr->columns = columns; tupleObjPtr->columnsAllocated = columnsAllocated; } for (p = keys; *p != NULL; p++) { Column *columnPtr; hPtr = Blt_CreateHashEntry(&tupleObjPtr->columnTable, *p, &isNew); columnPtr = Blt_Calloc(1, sizeof(Column)); columnPtr->key = Blt_GetHashKey(&tupleObjPtr->columnTable, hPtr); columnPtr->index = 0; columnPtr->type = 0; columnPtr->hashPtr = hPtr; columnPtr->index = tupleObjPtr->nColumns; tupleObjPtr->columns[columnPtr->index] = columnPtr; tupleObjPtr->nColumns++; } for(i = tupleObjPtr->nColumns; i < tupleObjPtr->columnsAllocated; i++) { tupleObjPtr->columns[i] = NULL; } NotifyClients(clientPtr, tupleObjPtr, TUPLE_NOTIFY_CREATE_COLUMN); return TCL_OK; } int Blt_TupleDeleteColumnByIndex( Tcl_Interp *interp, TupleClient *clientPtr, unsigned int column) { TupleObject *tupleObjPtr = clientPtr->tupleObjPtr; Column *columnPtr; columnPtr = tupleObjPtr->columns[column]; if (columnPtr != NULL) { Row *rowPtr; int i; int j, k; if (columnPtr->hashPtr != NULL) { Blt_DeleteHashEntry(&tupleObjPtr->columnTable, columnPtr->hashPtr); } for (i = 0; i < tupleObjPtr->nRows; i++) { rowPtr = tupleObjPtr->rows[i]; if ((column < rowPtr->nColumns) && (rowPtr->data != NULL)) { Tcl_Obj *objPtr; /* Release the Tcl_Obj associated with this column and * compress the tuple. */ objPtr = rowPtr->data[column]; if (objPtr != NULL) { Tcl_DecrRefCount(objPtr); rowPtr->data[column] = NULL; } for (j = column, k = column + 1; j < rowPtr->nColumns; j++, k++) { rowPtr->data[k] = rowPtr->data[j]; } rowPtr->nColumns--; } } for (j = column, k = column + 1; j < tupleObjPtr->nColumns; j++, k++) { tupleObjPtr->columns[k] = tupleObjPtr->columns[j]; } tupleObjPtr->columns[k] = NULL; tupleObjPtr->nColumns--; Blt_Free(columnPtr); NotifyClients(clientPtr, tupleObjPtr, TUPLE_NOTIFY_DELETE_COLUMN); } return TCL_OK; } int Blt_TupleDeleteColumn( Tcl_Interp *interp, TupleClient *clientPtr, CONST char *key) { unsigned int column; if (Blt_TupleGetColumnIndex(interp, clientPtr->tupleObjPtr, key, &column) != TCL_OK) { return TCL_ERROR; } return Blt_TupleDeleteColumnByIndex(interp, clientPtr, column); } /* *---------------------------------------------------------------------- * * Blt_TupleValueExists -- * * Indicates if a value exists for a given row,column index in * the tuple. Note that this routine does not fire read traces. * * Results: * Returns 1 is a value exists, 0 otherwise. * *---------------------------------------------------------------------- */ int Blt_TupleValueExists( TupleClient *clientPtr, Row *rowPtr, CONST char *key) { Blt_HashEntry *hPtr; TupleObject *tupleObjPtr = clientPtr->tupleObjPtr; char *left, *right; int result; if (rowPtr->index < tupleObjPtr->nRows) { return FALSE; } if (ParseParentheses((Tcl_Interp *)NULL, key, &left, &right) != TCL_OK) { return TCL_ERROR; } result = FALSE; if (left != NULL) { *left = *right = '\0'; hPtr = Blt_FindHashEntry(&tupleObjPtr->columnTable, key); if (hPtr != NULL) { Tcl_Obj *objPtr; Column *columnPtr; columnPtr = Blt_GetHashValue(hPtr); if (GetArrayValue((Tcl_Interp *)NULL, clientPtr, rowPtr, columnPtr, left + 1, &objPtr, TRACE_IGNORE) == TCL_OK) { result = (objPtr != NULL); } } *left = '(', *right = ')'; } else { hPtr = Blt_FindHashEntry(&tupleObjPtr->columnTable, key); if (hPtr != NULL) { Tcl_Obj *objPtr; Column *columnPtr; columnPtr = Blt_GetHashValue(hPtr); objPtr = VALUE(rowPtr, columnPtr); result = (objPtr != NULL); } } return result; } /* *---------------------------------------------------------------------- * * Blt_TupleGetValue -- * * Returns the value at the given row, column index, if one * exists. If no traces are currently active on the the slot, * then a call to check if any trace should fire is called. * * Results: * A standard Tcl result. If the column key isn't valid TCL_ERROR * is returned and an error message is left as the interpreter * result. * * Side Effects: * Traces on the table location may be fired. * *---------------------------------------------------------------------- */ int Blt_TupleGetValue( Tcl_Interp *interp, TupleClient *clientPtr, Row *rowPtr, CONST char *key, Tcl_Obj **objPtrPtr) { Blt_HashEntry *hPtr; Column *columnPtr; TupleObject *tupleObjPtr = clientPtr->tupleObjPtr; char *left, *right; int result; if (ParseParentheses(interp, key, &left, &right) != TCL_OK) { return TCL_ERROR; } if (left != NULL) { *left = *right = '\0'; hPtr = Blt_FindHashEntry(&tupleObjPtr->columnTable, key); if (hPtr != NULL) { columnPtr = Blt_GetHashValue(hPtr); result = GetArrayValue(interp, clientPtr, rowPtr, columnPtr, left + 1, objPtrPtr, TRACE_OK); } else if (interp != NULL) { Tcl_AppendResult(interp, "can't find column \"", key, "\" in \"", tupleObjPtr->name, "\"", (char *)NULL); } *left = '(', *right = ')'; if (hPtr == NULL) { return TCL_ERROR; } } else { hPtr = Blt_FindHashEntry(&tupleObjPtr->columnTable, key); if (hPtr == NULL) { if (interp != NULL) { Tcl_AppendResult(interp, "can't find column \"", key, "\" in \"", tupleObjPtr->name, "\"", (char *)NULL); } return TCL_ERROR; } columnPtr = Blt_GetHashValue(hPtr); result = GetValue(interp, clientPtr, rowPtr, columnPtr, objPtrPtr); } return result; } /* *---------------------------------------------------------------------- * * Blt_TupleSetValue -- * * Sets the value at the given row, column index. If the slot * is currently filled, the old Tcl_Obj is decremented. The * new Tcl_Obj is incremented. If no traces are currently active * on the the slot, then a call to check if any trace should * fire is called. There are two type of traces that may fire: * * TUPLE_TRACE_WRITE indicates that the slot was * written to. * TUPLE_TRACE_CREATE indicates there was no former * value set. * * Results: * Always returns TCL_OK. * * Side Effects: * Traces on the table location may be fired. * *---------------------------------------------------------------------- */ int Blt_TupleSetValue( Tcl_Interp *interp, TupleClient *clientPtr, Row *rowPtr, CONST char *key, Tcl_Obj *objPtr) { Blt_HashEntry *hPtr; Column *columnPtr; TupleObject *tupleObjPtr = clientPtr->tupleObjPtr; char *left, *right; int result; if (ParseParentheses(interp, key, &left, &right) != TCL_OK) { return TCL_ERROR; } if (left != NULL) { *left = *right = '\0'; hPtr = Blt_FindHashEntry(&tupleObjPtr->columnTable, key); if (hPtr != NULL) { columnPtr = Blt_GetHashValue(hPtr); result = SetArrayValue(interp, clientPtr, rowPtr, columnPtr, left + 1, objPtr); } else if (interp != NULL) { Tcl_AppendResult(interp, "can't find column \"", key, "\" in \"", tupleObjPtr->name, "\"", (char *)NULL); } *left = '(', *right = ')'; if (hPtr == NULL) { return TCL_ERROR; } } else { hPtr = Blt_FindHashEntry(&tupleObjPtr->columnTable, key); if (hPtr == NULL) { if (interp != NULL) { Tcl_AppendResult(interp, "can't find column \"", key, "\" in \"", tupleObjPtr->name, "\"", (char *)NULL); } return TCL_ERROR; } columnPtr = Blt_GetHashValue(hPtr); result = SetValue(interp, clientPtr, rowPtr, columnPtr, objPtr); } return result; } /* *---------------------------------------------------------------------- * * Blt_TupleUnsetValue -- * * Removes the value at the given tuple and column key, if one * exists. The Tcl_Obj is decremented and the slot is set to * NULL. If no traces are currently active on the the slot, then * a call to check if any trace should fire is called. * * The row, column indices are assumed to be valid. * * Results: * Always returns TCL_OK. * * Side Effects: * Traces on the table location may be fired. * *---------------------------------------------------------------------- */ int Blt_TupleUnsetValue( Tcl_Interp *interp, TupleClient *clientPtr, Row *rowPtr, CONST char *key) { Blt_HashEntry *hPtr; Column *columnPtr; TupleObject *tupleObjPtr = clientPtr->tupleObjPtr; char *left, *right; int result; if (ParseParentheses(interp, key, &left, &right) != TCL_OK) { return TCL_ERROR; } if (left != NULL) { *left = *right = '\0'; hPtr = Blt_FindHashEntry(&tupleObjPtr->columnTable, key); if (hPtr != NULL) { columnPtr = Blt_GetHashValue(hPtr); result = UnsetArrayValue(interp, clientPtr, rowPtr, columnPtr, left + 1); } else if (interp != NULL) { Tcl_AppendResult(interp, "can't find column \"", key, "\" in \"", tupleObjPtr->name, "\"", (char *)NULL); } *left = '(', *right = ')'; if (hPtr == NULL) { return TCL_ERROR; } } else { hPtr = Blt_FindHashEntry(&tupleObjPtr->columnTable, key); if (hPtr == NULL) { if (interp != NULL) { Tcl_AppendResult(interp, "can't find column \"", key, "\" in \"", tupleObjPtr->name, "\"", (char *)NULL); } return TCL_ERROR; } columnPtr = Blt_GetHashValue(hPtr); result = UnsetValue(interp, clientPtr, rowPtr, columnPtr); } return result; } /* *---------------------------------------------------------------------- * * Blt_TupleGetValueByIndex -- * * Returns the value at the given row, column index, if one * exists. If no traces are currently active on the the slot, * then a call to check if any trace should fire is called. * * The row, column indices are assumed to be valid. * * Results: * Always returns TCL_OK. * * Side Effects: * Traces on the table location may be fired. * *---------------------------------------------------------------------- */ int Blt_TupleGetValueByIndex( Tcl_Interp *interp, TupleClient *clientPtr, unsigned int row, unsigned int column, Tcl_Obj **objPtrPtr) { TupleObject *tupleObjPtr = clientPtr->tupleObjPtr; Row *rowPtr; Column *columnPtr; assert((row >= 0) && (row < tupleObjPtr->nRows)); assert((column >= 0) && (column < tupleObjPtr->nColumns)); rowPtr = tupleObjPtr->rows[row]; columnPtr = tupleObjPtr->columns[column]; return GetValue(interp, clientPtr, rowPtr, columnPtr, objPtrPtr); } /* *---------------------------------------------------------------------- * * Blt_TupleSetValueByIndex -- * * Sets the value at the given row, column index. If the slot * is currently filled, the old Tcl_Obj is decremented. The * new Tcl_Obj is incremented. If no traces are currently active * on the the slot, then a call to check if any trace should * fire is called. There are two type of traces that may fire: * * TUPLE_TRACE_WRITE indicates that the slot was * written to. * TUPLE_TRACE_CREATE indicates there was no former * value set. * * The row, column indices are assumed to be valid. * * Results: * Always returns TCL_OK. * * Side Effects: * Traces on the table location may be fired. * *---------------------------------------------------------------------- */ int Blt_TupleSetValueByIndex( Tcl_Interp *interp, TupleClient *clientPtr, unsigned int row, unsigned int column, Tcl_Obj *objPtr) { TupleObject *tupleObjPtr = clientPtr->tupleObjPtr; Row *rowPtr; Column *columnPtr; assert(row < tupleObjPtr->nRows); assert(column < tupleObjPtr->nColumns); rowPtr = tupleObjPtr->rows[row]; columnPtr = tupleObjPtr->columns[column]; return SetValue(interp, clientPtr, rowPtr, columnPtr, objPtr); } /* *---------------------------------------------------------------------- * * Blt_TupleUnsetValueByIndex -- * * Removes the value at the given row, column index, if one * exists. The Tcl_Obj is decremented and the slot is set * to NULL. If no traces are currently active on the the slot, * then a call to check if any trace should fire is called. * * It's not an error to "unset" nonexistent table locations. * * Results: * Always returns TCL_OK. * * Side Effects: * Traces on the table location may be fired. * *---------------------------------------------------------------------- */ int Blt_TupleUnsetValueByIndex( Tcl_Interp *interp, TupleClient *clientPtr, unsigned int row, unsigned int column) { TupleObject *tupleObjPtr = clientPtr->tupleObjPtr; Row *rowPtr; Column *columnPtr; assert(row < tupleObjPtr->nRows); assert(column < tupleObjPtr->nColumns); rowPtr = tupleObjPtr->rows[row]; columnPtr = tupleObjPtr->columns[column]; return UnsetValue(interp, clientPtr, rowPtr, columnPtr); } /* *---------------------------------------------------------------------- * * Blt_TupleInsertRows -- * * Creates a new rows in the table. The name and position in * the parent are also provided. * *---------------------------------------------------------------------- */ int Blt_TupleInsertRows( TupleClient *clientPtr, /* The tuple client that is creating * this node. If NULL, indicates to * trigger notify events on behalf of * the initiating client also. */ unsigned int insertRow, /* Position in the parent's list of children * where to insert the new node. */ unsigned int nRows) /* Number of rows tuples to insert. */ { TupleObject *tupleObjPtr; int oldRows; tupleObjPtr = clientPtr->tupleObjPtr; if (insertRow >= tupleObjPtr->nRows) { insertRow = tupleObjPtr->nRows; } oldRows = tupleObjPtr->nRows; if (!ExtendRows(tupleObjPtr, nRows)) { return TCL_ERROR; } if (insertRow < oldRows) { int i, j; /* Slide the rows down, creating new tuples in its place. */ for (i = insertRow, j = insertRow + nRows; i < oldRows; i++, j++) { tupleObjPtr->rows[j] = tupleObjPtr->rows[i]; tupleObjPtr->rows[j]->index = j; tupleObjPtr->rows[i] = NewRow(tupleObjPtr, i); } } else { int i; for (i = oldRows; i < tupleObjPtr->nRows; i++) { tupleObjPtr->rows[i] = NewRow(tupleObjPtr, i); } } /* * Issue callbacks to each client indicating that a new node has * been created. */ NotifyClients(clientPtr, tupleObjPtr, TUPLE_NOTIFY_CREATE); return insertRow; } /* *---------------------------------------------------------------------- * * Blt_TupleMoveRows -- * * Move one of more rows to a new location in the tuple. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ int Blt_TupleMoveRows( TupleClient *clientPtr, int fromRow, int toRow, int nRows) { TupleObject *tupleObjPtr = clientPtr->tupleObjPtr; Row *fromPtr; int i; /* [ | |a| | | | | | | | |b| | | ] */ fromPtr = tupleObjPtr->rows[fromRow]; for (i = fromRow; i < tupleObjPtr->nRows; i++) { /* Compress the array. */ } /* * Issue callbacks to each client indicating that a node has * been moved. */ NotifyClients(clientPtr, tupleObjPtr, TUPLE_NOTIFY_MOVE); return TCL_OK; } /* *---------------------------------------------------------------------- * * Blt_TupleDeleteTuple -- * * Deletes one or more rows starting at the given index. * This will cause a single delete event. * * Results: * Returns the row at the given index. If the index is out * of range, then NULL is returned. * *---------------------------------------------------------------------- */ void Blt_TupleDeleteTuple( TupleClient *clientPtr, Row *rowPtr) { TupleObject *tupleObjPtr = clientPtr->tupleObjPtr; int i, j; if (!tupleObjPtr->notifyHold) { /* * Issue callbacks to each client indicating that a tuple will be * removed. */ NotifyClients(clientPtr, tupleObjPtr, TUPLE_NOTIFY_DELETE_ROW); for (j = tupleObjPtr->nRows - 1, i = j - 1; i >= rowPtr->index; i--, j--) { tupleObjPtr->rows[i] = tupleObjPtr->rows[j]; tupleObjPtr->rows[i]->index = i; } tupleObjPtr->nRows--; } if (Blt_ChainGetLength(tupleObjPtr->clients) < 2) { Blt_TupleClearTags(clientPtr, rowPtr); } DeleteRow(tupleObjPtr, rowPtr); } /* *---------------------------------------------------------------------- * * Blt_TupleStartDeleteRows -- * * Deletes one or more rows starting at the given index. * This will cause a single delete event. * * Results: * Returns the row at the given index. If the index is out * of range, then NULL is returned. * *---------------------------------------------------------------------- */ void Blt_TupleStartDeleteRows(TupleClient *clientPtr) { TupleObject *tupleObjPtr = clientPtr->tupleObjPtr; tupleObjPtr->notifyHold = TRUE; } /* *---------------------------------------------------------------------- * * Blt_TupleEndDeleteRows -- * * Deletes one or more rows starting at the given index. * This will cause a single delete event. * * Results: * Returns the row at the given index. If the index is out * of range, then NULL is returned. * *---------------------------------------------------------------------- */ void Blt_TupleEndDeleteRows(TupleClient *clientPtr) { TupleObject *tupleObjPtr = clientPtr->tupleObjPtr; int first; int count; int i; /* * Issue callbacks to each client indicating that a tuple will be * removed. */ tupleObjPtr->notifyHold = FALSE; count = 0; for (i = 0; i < tupleObjPtr->nRows; i++) { if (tupleObjPtr->rows[i] == NULL) { if (first == -1) { first = i; } continue; } if (count < i) { tupleObjPtr->rows[count] = tupleObjPtr->rows[i]; tupleObjPtr->rows[count]->index = count; } count++; } tupleObjPtr->nRows = count++; NotifyClients(clientPtr, tupleObjPtr, TUPLE_NOTIFY_DELETE_ROW); } /* *---------------------------------------------------------------------- * * Blt_TupleCreateTrace -- * * Creates a trace for one or more tuples with one or more column * keys. Whenever a matching action occurs in the tuple object, * the specified procedure is executed. * * Results: * Returns a token for the trace. * * Side Effects: * Memory is allocated for the trace. * *---------------------------------------------------------------------- */ Blt_TupleTrace Blt_TupleCreateTrace( TupleClient *clientPtr, Row *rowPtr, /* Tuple to be traced. May be NULL, * indicating no row. */ CONST char *tagName, /* Tag of tuple(s) to be traced. May * be NULL. */ CONST char *keyList, /* Tcl list of keys. Split and freed * by Blt_TupleDeleteTrace. May be * NULL indicating all keys match. */ unsigned int mask, /* Bit mask indicating what actions to trace. */ Blt_TupleTraceProc *proc, /* Callback procedure for the trace. */ ClientData clientData) /* One-word of data passed along when * the callback is executed. */ { Trace *tracePtr; TupleObject *tupleObjPtr = clientPtr->tupleObjPtr; tracePtr = Blt_Calloc(1, sizeof (Trace)); assert(tracePtr); if (keyList != NULL) { CONST char **keys; int nKeys; if (Tcl_SplitList(clientPtr->interp, keyList, &nKeys, (char ***)&keys) != TCL_OK) { Blt_Free(tracePtr); return NULL; } if (nKeys == 0) { Blt_Free(keys); } else { tracePtr->keys = keys; } } if (tagName != NULL) { tracePtr->withTag = Blt_Strdup(tagName); } tracePtr->table = clientPtr; tracePtr->proc = proc; tracePtr->clientData = clientData; tracePtr->mask = mask; tracePtr->tuple = rowPtr; tracePtr->withTag = NULL; tracePtr->linkPtr = Blt_ChainAppend(tupleObjPtr->traces, tracePtr); return tracePtr; } /* *---------------------------------------------------------------------- * * Blt_TupleDeleteTrace -- * * Deletes a trace. * * Results: * None. * * Side Effects: * Memory is de-allocated for the trace. * *---------------------------------------------------------------------- */ void Blt_TupleDeleteTrace(Trace *tracePtr) { Blt_ChainDeleteLink(tracePtr->table->tupleObjPtr->traces, tracePtr->linkPtr); if (tracePtr->keys != NULL) { Blt_Free(tracePtr->keys); } if (tracePtr->withTag != NULL) { Blt_Free(tracePtr->withTag); } Blt_Free(tracePtr); } /* *---------------------------------------------------------------------- * * Blt_TupleExtendRows -- * * Adds new rows to the table. Rows are slots in an array * of Rows. The array grows by doubling its size, so there * may be more slots than needed (# rows). * * Results: * Returns TCL_OK is the tuple is resized and TCL_ERROR if an * not enough memory was available. * * Side Effects: * If more rows are needed, the array which holds the tuples is * reallocated by doubling its size. * *---------------------------------------------------------------------- */ int Blt_TupleExtendRows(TupleClient *clientPtr, unsigned int nRows) { TupleObject *tupleObjPtr = clientPtr->tupleObjPtr; int oldSize; int i; oldSize = tupleObjPtr->nRows; if (!ExtendRows(tupleObjPtr, nRows)) { return TCL_ERROR; } for (i = oldSize; i < tupleObjPtr->nRows; i++) { tupleObjPtr->rows[i] = NewRow(tupleObjPtr, i); } tupleObjPtr->nRows = nRows; NotifyClients(clientPtr, tupleObjPtr, TUPLE_NOTIFY_CREATE); return TCL_OK; } int Blt_TupleReduceRows(TupleClient *clientPtr, int nRows) { TupleObject *tupleObjPtr = clientPtr->tupleObjPtr; if (nRows < tupleObjPtr->nRows) { if (tupleObjPtr->rowsAllocated < nRows) { Row **rows; while (tupleObjPtr->rowsAllocated < nRows) { tupleObjPtr->rowsAllocated += tupleObjPtr->rowsAllocated; } rows = Blt_Realloc(tupleObjPtr->rows, tupleObjPtr->rowsAllocated * sizeof(Row *)); if (rows == NULL) { return TCL_ERROR; } tupleObjPtr->rows = rows; } tupleObjPtr->nRows = nRows; } return TCL_OK; } /* *---------------------------------------------------------------------- * * Blt_TupleAddTag -- * *---------------------------------------------------------------------- */ void Blt_TupleAddTag( TupleClient *clientPtr, Row *rowPtr, CONST char *tagName) { if (strcmp(tagName, "all") != 0) { Blt_HashEntry *hPtr; Blt_HashTable *tablePtr; Blt_TupleTagEntry *tPtr; int isNew; tablePtr = &clientPtr->tagTablePtr->tagTable; hPtr = Blt_CreateHashEntry(tablePtr, tagName, &isNew); assert(hPtr); if (isNew) { tPtr = Blt_Malloc(sizeof(Blt_TupleTagEntry)); Blt_InitHashTable(&tPtr->rowTable, BLT_ONE_WORD_KEYS); Blt_SetHashValue(hPtr, tPtr); tPtr->hashPtr = hPtr; tPtr->tagName = Blt_GetHashKey(tablePtr, hPtr); } else { tPtr = Blt_GetHashValue(hPtr); } hPtr = Blt_CreateHashEntry(&tPtr->rowTable, (char *)rowPtr, &isNew); assert(hPtr); if (isNew) { Blt_SetHashValue(hPtr, rowPtr); } } } /* *---------------------------------------------------------------------- * * Blt_TupleClearTags -- * *---------------------------------------------------------------------- */ void Blt_TupleClearTags(TupleClient *clientPtr, Row *rowPtr) { Blt_HashEntry *hPtr, *h2Ptr; Blt_HashSearch cursor; Blt_TupleTagEntry *tPtr; for (hPtr = Blt_FirstHashEntry(&clientPtr->tagTablePtr->tagTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tPtr = Blt_GetHashValue(hPtr); h2Ptr = Blt_FindHashEntry(&tPtr->rowTable, (char *)rowPtr); if (h2Ptr != NULL) { Blt_DeleteHashEntry(&tPtr->rowTable, h2Ptr); } } } /* *---------------------------------------------------------------------- * * Blt_TupleFirstTag -- * *---------------------------------------------------------------------- */ Blt_HashEntry * Blt_TupleFirstTag( TupleClient *clientPtr, Blt_HashSearch *cursorPtr) { return Blt_FirstHashEntry(&clientPtr->tagTablePtr->tagTable, cursorPtr); } /* *---------------------------------------------------------------------- * * Blt_TupleForgetTag -- * *---------------------------------------------------------------------- */ void Blt_TupleForgetTag( TupleClient *clientPtr, CONST char *tagName) { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&clientPtr->tagTablePtr->tagTable, tagName); if (hPtr != NULL) { Blt_TupleTagEntry *tPtr; tPtr = Blt_GetHashValue(hPtr); Blt_DeleteHashEntry(&clientPtr->tagTablePtr->tagTable, hPtr); Blt_DeleteHashTable(&tPtr->rowTable); Blt_Free(tPtr); } } /* *---------------------------------------------------------------------- * * Blt_TupleHasTag -- * *---------------------------------------------------------------------- */ int Blt_TupleHasTag( TupleClient *clientPtr, Row *rowPtr, CONST char *tagName) { Blt_HashEntry *hPtr; if (strcmp(tagName, "all") == 0) { return TRUE; } hPtr = Blt_FindHashEntry(&clientPtr->tagTablePtr->tagTable, tagName); if (hPtr != NULL) { Blt_TupleTagEntry *tPtr; tPtr = Blt_GetHashValue(hPtr); hPtr = Blt_FindHashEntry(&tPtr->rowTable, (char *)rowPtr); if (hPtr != NULL) { return TRUE; } } return FALSE; } /* *---------------------------------------------------------------------- * * Blt_TupleRemoveTag -- * *---------------------------------------------------------------------- */ void Blt_TupleRemoveTag( TupleClient *clientPtr, Row *rowPtr, CONST char *tagName) { if (strcmp(tagName, "all") != 0) { Blt_HashEntry *hPtr; Blt_HashTable *tablePtr; tablePtr = &clientPtr->tagTablePtr->tagTable; hPtr = Blt_FindHashEntry(tablePtr, tagName); if (hPtr != NULL) { Blt_TupleTagEntry *tPtr; tPtr = Blt_GetHashValue(hPtr); hPtr = Blt_FindHashEntry(&tPtr->rowTable, (char *)rowPtr); if (hPtr != NULL) { Blt_DeleteHashEntry(&tPtr->rowTable, hPtr); } } } } /* *---------------------------------------------------------------------- * * Blt_TupleTagSetHashTable -- * *---------------------------------------------------------------------- */ Blt_HashTable * Blt_TupleTagTableHashTable( TupleClient *clientPtr, CONST char *tagName) { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&clientPtr->tagTablePtr->tagTable, tagName); if (hPtr != NULL) { Blt_TupleTagEntry *tPtr; tPtr = Blt_GetHashValue(hPtr); return &tPtr->rowTable; } return NULL; } int Blt_TupleTagTableIsShared(TupleClient *clientPtr) { return (clientPtr->tagTablePtr->refCount > 1); } /* *---------------------------------------------------------------------- * * Blt_TupleFirstTagged -- * * Returns the id of the first tuple tagged by the given tag in * objPtr. * *---------------------------------------------------------------------- */ Blt_Tuple Blt_TupleFirstTagged( Tcl_Interp *interp, TupleClient *clientPtr, Tcl_Obj *objPtr, Blt_TupleTagSearch *cursorPtr) { char *tagName; cursorPtr->tagType = TAG_TYPE_NONE; tagName = Tcl_GetString(objPtr); /* Process strings that start with digits as indices, not tags. */ if (isdigit(UCHAR(*tagName))) { int row; if (Tcl_GetIntFromObj(interp, objPtr, &row) != TCL_OK) { return NULL; } if ((row < 0) || (row >= clientPtr->tupleObjPtr->nRows)) { Tcl_AppendResult(interp, "row index \"", tagName, "\" is out of range", (char *)NULL); return NULL; } return clientPtr->tupleObjPtr->rows[row]; } cursorPtr->nRows = clientPtr->tupleObjPtr->nRows; if (strcmp(tagName, "all") == 0) { cursorPtr->tagType = TAG_TYPE_ALL; cursorPtr->row = 0; return clientPtr->tupleObjPtr->rows[0]; } else { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&clientPtr->tagTablePtr->tagTable, tagName); if (hPtr != NULL) { Blt_TupleTagEntry *tPtr; Row *rowPtr; tPtr = Blt_GetHashValue(hPtr); cursorPtr->rowTablePtr = &tPtr->rowTable; cursorPtr->tagType = TAG_TYPE_TAG; hPtr = Blt_FirstHashEntry(cursorPtr->rowTablePtr, &cursorPtr->cursor); if (hPtr == NULL) { return NULL; } rowPtr = Blt_GetHashValue(hPtr); return rowPtr; } } Tcl_AppendResult(interp, "can't find tag or id \"", tagName, "\" in ", clientPtr->tupleObjPtr->name, (char *)NULL); return NULL; } /* *---------------------------------------------------------------------- * * Blt_TupleNextTagged -- * *---------------------------------------------------------------------- */ Blt_Tuple Blt_TupleNextTagged(Blt_TupleTagSearch *cursorPtr) { if (cursorPtr->tagType == TAG_TYPE_ALL) { TupleClient *clientPtr = cursorPtr->table; cursorPtr->row++; if (cursorPtr->row >= clientPtr->tupleObjPtr->nRows) { return NULL; } return clientPtr->tupleObjPtr->rows[cursorPtr->row]; } if (cursorPtr->tagType == TAG_TYPE_TAG) { Blt_HashEntry *hPtr; Row *rowPtr; hPtr = Blt_NextHashEntry(&cursorPtr->cursor); if (hPtr == NULL) { return NULL; } rowPtr = Blt_GetHashValue(hPtr); return rowPtr; } return NULL; } blt-2.4z.orig/src/bltTuple.h0100644000175000017500000002002107534251621014477 0ustar dokodoko /* * bltTuple.h -- * * Copyright 1998-1999 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 or 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. * * The tuple data object was created by George A. Howlett. */ #ifndef _BLT_TUPLE_H #define _BLT_TUPLE_H #include #include #include /* * array or row pointers * _ * |_---> [row index * |_ [#columns array of Tcl_Objs * |_ [tuple pointer ---> [ . . . . . ] * |_ * |_ * |_ * |_ * |_ * |_ * |_ * |_ * |_ * |_ * |_ * |_ * |_ * |_ * |_ * |_ * |_ * |_ * */ typedef struct Blt_TupleRowStruct *Blt_Tuple; typedef struct Blt_TupleTraceStruct *Blt_TupleTrace; typedef struct Blt_TupleNotifierStruct *Blt_TupleNotifier; typedef struct Blt_TupleClientStruct *Blt_TupleTable; typedef struct Blt_TupleColumnStruct Blt_TupleColumn; typedef struct Blt_TupleRowStruct Blt_TupleRow; typedef struct Blt_TupleTagTableStruct Blt_TupleTagTable; #define TUPLE_NOTIFY_CREATE_COLUMN (1<<0) #define TUPLE_NOTIFY_CREATE_ROW (1<<1) #define TUPLE_NOTIFY_CREATE \ (TUPLE_NOTIFY_CREATE_COLUMN|TUPLE_NOTIFY_CREATE_ROW) #define TUPLE_NOTIFY_DELETE_ROW (1<<2) #define TUPLE_NOTIFY_DELETE_COLUMN (1<<3) #define TUPLE_NOTIFY_DELETE \ (TUPLE_NOTIFY_DELETE_COLUMN|TUPLE_NOTIFY_DELETE_ROW) #define TUPLE_NOTIFY_MOVE (1<<4) #define TUPLE_NOTIFY_SORT (1<<5) #define TUPLE_NOTIFY_RELABEL (1<<6) #define TUPLE_NOTIFY_ALL \ (TUPLE_NOTIFY_CREATE | TUPLE_NOTIFY_DELETE | TUPLE_NOTIFY_MOVE | \ TUPLE_NOTIFY_SORT | TUPLE_NOTIFY_RELABEL) #define TUPLE_NOTIFY_MASK (TUPLE_NOTIFY_ALL) #define TUPLE_NOTIFY_WHENIDLE (1<<8) #define TUPLE_NOTIFY_FOREIGN_ONLY (1<<9) #define TUPLE_NOTIFY_ACTIVE (1<<10) typedef struct { int type; /* Indicates type of event received. */ int row; /* Index of tuple receiving the event. */ Tcl_Interp *interp; /* Interpreter to report to */ Blt_TupleTable table; /* Tuple object client that received * the event. */ } Blt_TupleNotifyEvent; typedef int (Blt_TupleNotifyEventProc)(ClientData clientData, Blt_TupleNotifyEvent *eventPtr); struct Blt_TupleNotifierStruct { Blt_TupleTable table; Blt_ChainLink *linkPtr; Blt_TupleNotifyEvent event; Blt_TupleNotifyEventProc *proc; ClientData clientData; Tcl_Interp *interp; char *key; int notifyPending; unsigned int mask; }; EXTERN Blt_TupleNotifier Blt_TupleCreateNotifier(Blt_TupleTable table, unsigned int mask, Blt_TupleNotifyEventProc *proc, ClientData clientData); EXTERN void Blt_TupleDeleteNotifier(Blt_TupleNotifier notifier); typedef struct { char *tagName; Blt_HashEntry *hashPtr; Blt_HashTable rowTable; /* Hash table of row pointers. This * represents all the rows tagged by * this tag. */ } Blt_TupleTagEntry; typedef struct { Blt_TupleTable table; int tagType; unsigned int row, nRows; Blt_HashSearch cursor; Blt_HashTable *rowTablePtr; } Blt_TupleTagSearch; EXTERN Blt_Tuple Blt_TupleFirstTagged(Tcl_Interp *interp, Blt_TupleTable table, Tcl_Obj *objPtr, Blt_TupleTagSearch *cursorPtr); EXTERN Blt_Tuple Blt_TupleNextTagged(Blt_TupleTagSearch *cursorPtr); EXTERN void Blt_TupleClearTags(Blt_TupleTable table, Blt_Tuple tuple); EXTERN void Blt_TupleRemoveTag(Blt_TupleTable table, Blt_Tuple tuple, CONST char *tagName); EXTERN int Blt_TupleHasTag(Blt_TupleTable table, Blt_Tuple tuple, CONST char *tagName); EXTERN void Blt_TupleAddTag(Blt_TupleTable table, Blt_Tuple tuple, CONST char *tagName); EXTERN void Blt_TupleForgetTag(Blt_TupleTable table, CONST char *tagName); EXTERN Blt_HashTable *Blt_TupleTagHashTable(Blt_TupleTable table, CONST char *tagName); EXTERN int Blt_TupleTagTableIsShared(Blt_TupleTable table); #define TUPLE_TRACE_UNSET (1<<3) #define TUPLE_TRACE_WRITE (1<<4) #define TUPLE_TRACE_READ (1<<5) #define TUPLE_TRACE_CREATE (1<<6) #define TUPLE_TRACE_ALL \ (TUPLE_TRACE_UNSET | TUPLE_TRACE_WRITE | TUPLE_TRACE_READ | \ TUPLE_TRACE_CREATE) #define TUPLE_TRACE_MASK (TUPLE_TRACE_ALL) #define TUPLE_TRACE_FOREIGN_ONLY (1<<8) #define TUPLE_TRACE_ACTIVE (1<<9) typedef int (Blt_TupleTraceProc)(ClientData clientData, Tcl_Interp *interp, unsigned int row, unsigned int column, unsigned int flags); struct Blt_TupleTraceStruct { Tcl_Interp *interp; Blt_ChainLink *linkPtr; Blt_TupleTable table; Blt_Tuple tuple; CONST char **keys; char *withTag; unsigned int mask; Blt_TupleTraceProc *proc; ClientData clientData; }; EXTERN Blt_TupleTrace Blt_TupleCreateTrace(Blt_TupleTable table, Blt_Tuple tuple, CONST char *tagName, CONST char *keyList, unsigned int mask, Blt_TupleTraceProc *proc, ClientData clientData); EXTERN void Blt_TupleDeleteTrace(Blt_TupleTrace trace); EXTERN int Blt_TupleGetValueByIndex(Tcl_Interp *interp, Blt_TupleTable table, unsigned int row, unsigned int column, Tcl_Obj **objPtrPtr); EXTERN int Blt_TupleSetValueByIndex(Tcl_Interp *interp, Blt_TupleTable table, unsigned int row, unsigned int column, Tcl_Obj *objPtr); EXTERN int Blt_TupleUnsetValueByIndex(Tcl_Interp *interp, Blt_TupleTable table, unsigned int row, unsigned int column); EXTERN int Blt_TupleGetValue(Tcl_Interp *interp, Blt_TupleTable table, Blt_Tuple tuple, CONST char *key, Tcl_Obj **objPtrPtr); EXTERN int Blt_TupleSetValue(Tcl_Interp *interp, Blt_TupleTable table, Blt_Tuple tuple, CONST char *key, Tcl_Obj *objPtr); EXTERN int Blt_TupleUnsetValue(Tcl_Interp *interp, Blt_TupleTable table, Blt_Tuple tuple, CONST char *key); EXTERN int Blt_TupleGetArrayValue(Tcl_Interp *interp, Blt_TupleTable table, Blt_Tuple tuple, CONST char *key, CONST char *elemName, Tcl_Obj **objPtrPtr); EXTERN int Blt_TupleSetArrayValue(Tcl_Interp *interp, Blt_TupleTable table, Blt_Tuple tuple, CONST char *key, CONST char *elemName, Tcl_Obj *objPtr); EXTERN int Blt_TupleUnsetArrayValue(Tcl_Interp *interp, Blt_TupleTable table, Blt_Tuple tuple, CONST char *key, CONST char *elemName); EXTERN unsigned int Blt_TupleAddColumn(Blt_TupleTable table, CONST char *key, int *isNewPtr); EXTERN unsigned int Blt_TupleRowIndex(Blt_Tuple tuple); EXTERN CONST char *Blt_TupleGetColumnKey(Blt_TupleTable table, int column); EXTERN Blt_HashEntry *Blt_TupleFirstTag(Blt_TupleTable table, Blt_HashSearch *cursorPtr); EXTERN Blt_Tuple Blt_TupleGetTupleByIndex(Blt_TupleTable table, unsigned int row); EXTERN int Blt_TupleExtendRows(Blt_TupleTable table, unsigned int extra); EXTERN Blt_Tuple Blt_TupleNextTuple(Blt_TupleTable table, Blt_Tuple tuple); EXTERN void Blt_TupleStartDeleteRows(Blt_TupleTable table); EXTERN void Blt_TupleDeleteTuple(Blt_TupleTable table, Blt_Tuple tuple); EXTERN void Blt_TupleEndDeleteRows(Blt_TupleTable table); EXTERN int Blt_TupleTableExists(Tcl_Interp *interp, CONST char *objName); EXTERN int Blt_TupleCreateTable(Tcl_Interp *interp, CONST char *name, Blt_TupleTable *tablePtr); EXTERN int Blt_TupleGetTable(Tcl_Interp *interp, CONST char *name, Blt_TupleTable *tablePtr); EXTERN void Blt_TupleReleaseTable(Blt_TupleTable table); EXTERN CONST char *Blt_TupleTableName(Blt_TupleTable table); EXTERN unsigned int Blt_TupleTableLength(Blt_TupleTable table); EXTERN unsigned int Blt_TupleTableWidth(Blt_TupleTable table); #endif /* BLT_TUPLE_H */ blt-2.4z.orig/src/bltTupleCmd.c0100644000175000017500000024457007541720676015150 0ustar dokodoko /* * * bltTupleCmd.c -- * * Copyright 1998-1999 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 or 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. * * The "tuple" data object was created by George A. Howlett. */ /* tuple create t0 t1 t2 tuple names t0 destroy -or- tuple destroy t0 tuple copy tuple@node tuple@node -recurse -tags tuple move node after|before|into t2@node $t apply -recurse $root command arg arg $t attach tuplename $t children $n t0 copy node1 node2 node3 node4 node5 destName $t delete $n... $t delete 0 $t delete 0 10 $t delete all $t depth $n $t dump $root $t dumpfile $root fileName $t dup $t2 $t find $root -name pat -name pattern $t firstchild $n $t get $n $key $t get $n $key(abc) $t index $n $t insert $parent $switches? $t isancestor $n1 $n2 $t isbefore $n1 $n2 $t isleaf $n $t lastchild $n $t move $n1 after|before|into $n2 $t next $n $t nextsibling $n $t path $n1 $n2 $n3... $t parent $n $t previous $n $t prevsibling $n $t restore $root data -overwrite $t root ?$n? $t set $n $key $value ?$key $value? $t size $n $t slink $n $t2@$node ??? $t sort -recurse $root $t tag delete tag1 tag2 tag3... $t tag names $t tag nodes $tag $t tag set $n tag1 tag2 tag3... $t tag unset $n tag1 tag2 tag3... $t trace create $n $key how command $t trace delete id1 id2 id3... $t trace names $t trace info $id $t unset $n key1 key2 key3... $t notify create -oncreate -ondelete -onmove command $t notify create -oncreate -ondelete -onmove -onsort command arg arg arg $t notify delete id1 id2 id3 $t notify names $t notify info id for { set n [$t firstchild $node] } { $n >= 0 } { set n [$t nextsibling $n] } { } foreach n [$t children $node] { } set n [$t next $node] set n [$t previous $node] */ /* * Rows as tokens. * */ #include #ifndef NO_TUPLE #include #include #include #include "bltSwitch.h" #include #define TUPLE_THREAD_KEY "BLT Tuple Command Data" #define TUPLE_MAGIC ((unsigned int) 0x46170277) enum TagTypes { TAG_TYPE_NONE, TAG_TYPE_ALL, TAG_TYPE_TAG }; typedef struct { Blt_HashTable instTable; /* Hash table of tuples keyed by address. */ Tcl_Interp *interp; } TupleCmdInterpData; typedef struct { Tcl_Interp *interp; Blt_TupleTable table; /* Token representing the tuple * table. */ Tcl_Command cmdToken; /* Token for tuple object's Tcl * command. */ Tcl_Obj *emptyObjPtr; /* String representing an empty table * value. */ Blt_HashEntry *hashPtr; Blt_HashTable *instTablePtr; int traceCounter; /* Used to generate trace id strings. */ Blt_HashTable traceTable; /* Table of active traces. Maps trace ids * back to their TraceInfo records. */ int notifyCounter; /* Used to generate notify id strings. */ Blt_HashTable notifyTable; /* Table of event handlers. Maps notify ids * back to their NotifyInfo records. */ } TupleCmd; typedef struct { Blt_TupleTrace trace; TupleCmd *cmdPtr; Tcl_Obj **objv; int objc; Blt_HashEntry *hashPtr; } TraceInfo; typedef struct { Blt_TupleNotifier notifier; TupleCmd *cmdPtr; Tcl_Obj **objv; int objc; Blt_HashEntry *hashPtr; } NotifyInfo; typedef struct { unsigned int column; Tcl_Obj *objPtr; } KeyValue; typedef struct { int mask; } NotifyData; static Blt_SwitchSpec notifySwitches[] = { {BLT_SWITCH_FLAG, "-create", Blt_Offset(NotifyData, mask), 0, 0, TUPLE_NOTIFY_CREATE}, {BLT_SWITCH_FLAG, "-createrow", Blt_Offset(NotifyData, mask), 0, 0, TUPLE_NOTIFY_CREATE_ROW}, {BLT_SWITCH_FLAG, "-createcolumn", Blt_Offset(NotifyData, mask), 0, 0, TUPLE_NOTIFY_CREATE_COLUMN}, {BLT_SWITCH_FLAG, "-delete", Blt_Offset(NotifyData, mask), 0, 0, TUPLE_NOTIFY_DELETE}, {BLT_SWITCH_FLAG, "-deleterow", Blt_Offset(NotifyData, mask), 0, 0, TUPLE_NOTIFY_DELETE_ROW}, {BLT_SWITCH_FLAG, "-deletecolumn", Blt_Offset(NotifyData, mask), 0, 0, TUPLE_NOTIFY_DELETE_COLUMN}, {BLT_SWITCH_FLAG, "-move", Blt_Offset(NotifyData, mask), 0, 0, TUPLE_NOTIFY_MOVE}, {BLT_SWITCH_FLAG, "-sort", Blt_Offset(NotifyData, mask), 0, 0, TUPLE_NOTIFY_SORT}, {BLT_SWITCH_FLAG, "-relabel", Blt_Offset(NotifyData, mask), 0, 0, TUPLE_NOTIFY_RELABEL}, {BLT_SWITCH_FLAG, "-allevents", Blt_Offset(NotifyData, mask), 0, 0, TUPLE_NOTIFY_ALL}, {BLT_SWITCH_FLAG, "-whenidle", Blt_Offset(NotifyData, mask), 0, 0, TUPLE_NOTIFY_WHENIDLE}, {BLT_SWITCH_END, NULL, 0, 0} }; #ifdef notdef static Blt_SwitchParseProc StringToChild; #define INSERT_BEFORE (ClientData)0 #define INSERT_AFTER (ClientData)1 static Blt_SwitchCustom beforeSwitch = { StringToChild, (Blt_SwitchFreeProc *)NULL, INSERT_BEFORE, }; static Blt_SwitchCustom afterSwitch = { StringToChild, (Blt_SwitchFreeProc *)NULL, INSERT_AFTER, }; typedef struct { char *label; int insertPos; int inode; char **tags; char **dataPairs; Blt_TupleNode parent; } InsertData; static Blt_SwitchSpec insertSwitches[] = { {BLT_SWITCH_CUSTOM, "-after", Blt_Offset(InsertData, insertPos), 0, &afterSwitch}, {BLT_SWITCH_INT_NONNEGATIVE, "-at", Blt_Offset(InsertData, insertPos), 0}, {BLT_SWITCH_CUSTOM, "-before", Blt_Offset(InsertData, insertPos), 0, &beforeSwitch}, {BLT_SWITCH_LIST, "-data", Blt_Offset(InsertData, dataPairs), 0}, {BLT_SWITCH_STRING, "-label", Blt_Offset(InsertData, label), 0}, {BLT_SWITCH_INT_NONNEGATIVE, "-node", Blt_Offset(InsertData, inode), 0}, {BLT_SWITCH_LIST, "-tags", Blt_Offset(InsertData, tags), 0}, {BLT_SWITCH_END, NULL, 0, 0} }; #define PATTERN_EXACT (1) #define PATTERN_GLOB (2) #define PATTERN_MASK (0x3) #define PATTERN_NONE (0) #define PATTERN_REGEXP (3) #define MATCH_INVERT (1<<8) #define MATCH_LEAFONLY (1<<4) #define MATCH_NOCASE (1<<5) #define MATCH_PATHNAME (1<<6) typedef struct { TupleCmd *cmdPtr; /* Tuple to examine. */ Tcl_Obj *listObjPtr; /* List to accumulate the indices of * matching nodes. */ Tcl_Obj **objv; /* Command converted into an array of * Tcl_Obj's. */ int objc; /* Number of Tcl_Objs in above array. */ int nMatches; /* Current number of matches. */ unsigned int flags; /* See flags definitions above. */ /* Integer options. */ int maxMatches; /* If > 0, stop after this many matches. */ int maxDepth; /* If > 0, don't descend more than this * many levels. */ int order; /* Order of search: Can be either * TUPLE_PREORDER, TUPLE_POSTORDER, * TUPLE_INORDER, TUPLE_BREADTHFIRST. */ /* String options. */ Blt_List patternList; /* List of patterns to compare with labels * or values. */ char *addTag; /* If non-NULL, tag added to selected nodes. */ char **command; /* Command split into a Tcl list. */ Blt_List keyList; /* List of key name patterns. */ char *withTag; } FindData; static Blt_SwitchParseProc StringToOrder; static Blt_SwitchCustom orderSwitch = { StringToOrder, (Blt_SwitchFreeProc *)NULL, (ClientData)0, }; static Blt_SwitchParseProc StringToPattern; static Blt_SwitchFreeProc FreePatterns; static Blt_SwitchCustom regexpSwitch = { StringToPattern, FreePatterns, (ClientData)PATTERN_REGEXP, }; static Blt_SwitchCustom globSwitch = { StringToPattern, FreePatterns, (ClientData)PATTERN_GLOB, }; static Blt_SwitchCustom exactSwitch = { StringToPattern, FreePatterns, (ClientData)PATTERN_EXACT, }; static Blt_SwitchSpec findSwitches[] = { {BLT_SWITCH_STRING, "-addtag", Blt_Offset(FindData, addTag), 0}, {BLT_SWITCH_INT_NONNEGATIVE, "-count", Blt_Offset(FindData, maxMatches), 0}, {BLT_SWITCH_INT_NONNEGATIVE, "-depth", Blt_Offset(FindData, maxDepth), 0}, {BLT_SWITCH_CUSTOM, "-exact", Blt_Offset(FindData, patternList), 0, &exactSwitch}, {BLT_SWITCH_LIST, "-exec", Blt_Offset(FindData, command), 0}, {BLT_SWITCH_CUSTOM, "-glob", Blt_Offset(FindData, patternList), 0, &globSwitch}, {BLT_SWITCH_FLAG, "-invert", Blt_Offset(FindData, flags), 0, 0, MATCH_INVERT}, {BLT_SWITCH_CUSTOM, "-key", Blt_Offset(FindData, keyList), 0, &exactSwitch}, {BLT_SWITCH_CUSTOM, "-keyexact", Blt_Offset(FindData, keyList), 0, &exactSwitch}, {BLT_SWITCH_CUSTOM, "-keyglob", Blt_Offset(FindData, keyList), 0, &globSwitch}, {BLT_SWITCH_CUSTOM, "-keyregexp", Blt_Offset(FindData, keyList), 0, ®expSwitch}, {BLT_SWITCH_FLAG, "-leafonly", Blt_Offset(FindData, flags), 0, 0, MATCH_LEAFONLY}, {BLT_SWITCH_FLAG, "-nocase", Blt_Offset(FindData, flags), 0, 0, MATCH_NOCASE}, {BLT_SWITCH_CUSTOM, "-order", Blt_Offset(FindData, order), 0, &orderSwitch}, {BLT_SWITCH_FLAG, "-path", Blt_Offset(FindData, flags), 0, 0, MATCH_PATHNAME}, {BLT_SWITCH_CUSTOM, "-regexp", Blt_Offset(FindData, patternList), 0, ®expSwitch}, {BLT_SWITCH_STRING, "-tag", Blt_Offset(FindData, withTag), 0}, {BLT_SWITCH_END, NULL, 0, 0} }; static Blt_SwitchParseProc StringToNode; static Blt_SwitchCustom nodeSwitch = { StringToNode, (Blt_SwitchFreeProc *)NULL, (ClientData)0, }; typedef struct { TupleCmd *cmdPtr; /* Tuple to move nodes. */ Blt_TupleNode node; int movePos; } MoveData; static Blt_SwitchSpec moveSwitches[] = { {BLT_SWITCH_CUSTOM, "-after", Blt_Offset(MoveData, node), 0, &nodeSwitch}, {BLT_SWITCH_INT_NONNEGATIVE, "-at", Blt_Offset(MoveData, movePos), 0}, {BLT_SWITCH_CUSTOM, "-before", Blt_Offset(MoveData, node), 0, &nodeSwitch}, {BLT_SWITCH_END, NULL, 0, 0} }; typedef struct { Blt_TupleNode srcNode, destNode; Blt_Tuple srcTuple, destTuple; TupleCmd *srcPtr, *destPtr; unsigned int flags; char *label; } CopyData; #define COPY_RECURSE (1<<0) #define COPY_TAGS (1<<1) #define COPY_OVERWRITE (1<<2) static Blt_SwitchSpec copySwitches[] = { {BLT_SWITCH_STRING, "-label", Blt_Offset(CopyData, label), 0}, {BLT_SWITCH_FLAG, "-recurse", Blt_Offset(CopyData, flags), 0, 0, COPY_RECURSE}, {BLT_SWITCH_FLAG, "-tags", Blt_Offset(CopyData, flags), 0, 0, COPY_TAGS}, {BLT_SWITCH_FLAG, "-overwrite", Blt_Offset(CopyData, flags), 0, 0, COPY_OVERWRITE}, {BLT_SWITCH_END, NULL, 0, 0} }; typedef struct { TupleCmd *cmdPtr; /* Tuple to examine. */ Tcl_Obj **preObjv; /* Command converted into an array of * Tcl_Obj's. */ int preObjc; /* Number of Tcl_Objs in above array. */ Tcl_Obj **postObjv; /* Command converted into an array of * Tcl_Obj's. */ int postObjc; /* Number of Tcl_Objs in above array. */ unsigned int flags; /* See flags definitions above. */ int maxDepth; /* If > 0, don't descend more than this * many levels. */ /* String options. */ Blt_List patternList; /* List of label or value patterns. */ char **preCmd; /* Pre-command split into a Tcl list. */ char **postCmd; /* Post-command split into a Tcl list. */ Blt_List keyList; /* List of key-name patterns. */ char *withTag; } ApplyData; static Blt_SwitchSpec applySwitches[] = { {BLT_SWITCH_LIST, "-precommand", Blt_Offset(ApplyData, preCmd), 0}, {BLT_SWITCH_LIST, "-postcommand", Blt_Offset(ApplyData, postCmd), 0}, {BLT_SWITCH_INT_NONNEGATIVE, "-depth", Blt_Offset(ApplyData, maxDepth), 0}, {BLT_SWITCH_CUSTOM, "-exact", Blt_Offset(ApplyData, patternList), 0, &exactSwitch}, {BLT_SWITCH_CUSTOM, "-glob", Blt_Offset(ApplyData, patternList), 0, &globSwitch}, {BLT_SWITCH_FLAG, "-invert", Blt_Offset(ApplyData, flags), 0, 0, MATCH_INVERT}, {BLT_SWITCH_CUSTOM, "-key", Blt_Offset(ApplyData, keyList), 0, &exactSwitch}, {BLT_SWITCH_CUSTOM, "-keyexact", Blt_Offset(ApplyData, keyList), 0, &exactSwitch}, {BLT_SWITCH_CUSTOM, "-keyglob", Blt_Offset(ApplyData, keyList), 0, &globSwitch}, {BLT_SWITCH_CUSTOM, "-keyregexp", Blt_Offset(ApplyData, keyList), 0, ®expSwitch}, {BLT_SWITCH_FLAG, "-leafonly", Blt_Offset(ApplyData, flags), 0, 0, MATCH_LEAFONLY}, {BLT_SWITCH_FLAG, "-nocase", Blt_Offset(ApplyData, flags), 0, 0, MATCH_NOCASE}, {BLT_SWITCH_FLAG, "-path", Blt_Offset(ApplyData, flags), 0, 0, MATCH_PATHNAME}, {BLT_SWITCH_CUSTOM, "-regexp", Blt_Offset(ApplyData, patternList), 0, ®expSwitch}, {BLT_SWITCH_STRING, "-tag", Blt_Offset(ApplyData, withTag), 0}, {BLT_SWITCH_END, NULL, 0, 0} }; typedef struct { unsigned int flags; Blt_HashTable idTable; } RestoreData; #define RESTORE_NO_TAGS (1<<0) #define RESTORE_OVERWRITE (1<<1) static Blt_SwitchSpec restoreSwitches[] = { {BLT_SWITCH_FLAG, "-notags", Blt_Offset(RestoreData, flags), 0, 0, RESTORE_NO_TAGS}, {BLT_SWITCH_FLAG, "-overwrite", Blt_Offset(RestoreData, flags), 0, 0, RESTORE_OVERWRITE}, {BLT_SWITCH_END, NULL, 0, 0} }; static Blt_SwitchParseProc StringToFormat; static Blt_SwitchCustom formatSwitch = { StringToFormat, (Blt_SwitchFreeProc *)NULL, (ClientData)0, }; typedef struct { int sort; /* If non-zero, sort the tuples. */ int withParent; /* If non-zero, add the parent node id * to the output of the command.*/ int withId; /* If non-zero, echo the node id in the * output of the command. */ } PositionData; #define POSITION_SORTED (1<<0) static Blt_SwitchSpec positionSwitches[] = { {BLT_SWITCH_FLAG, "-sort", Blt_Offset(PositionData, sort), 0, 0, POSITION_SORTED}, {BLT_SWITCH_CUSTOM, "-format", 0, 0, &formatSwitch}, {BLT_SWITCH_END, NULL, 0, 0} }; static Blt_TupleApplyProc MatchTupleProc, SortTupleProc; static Blt_TupleApplyProc ApplyTupleProc; static Blt_TupleTraceProc TupleTraceProc; static Blt_TupleCompareTuplesProc CompareTuples; static Tcl_ObjCmdProc CompareDictionaryCmd; static Tcl_ObjCmdProc ExitCmd; #endif static Blt_TupleNotifyEventProc TupleEventProc; static Tcl_CmdDeleteProc TupleInstDeleteProc; static Tcl_InterpDeleteProc TupleInterpDeleteProc; static Tcl_ObjCmdProc TupleInstObjCmd; static Tcl_ObjCmdProc TupleObjCmd; static int GetTuple(TupleCmd *cmdPtr, Tcl_Obj *objPtr, Blt_Tuple *tuplePtr); /* *---------------------------------------------------------------------- * * NewTupleCmd -- * * This is a helper routine used by TupleCreateOp. It create a * new instance of a tuple command. Memory is allocated for the * command structure and a new Tcl command is created (same as * the instance name). All tuple commands have hash table * entries in a global (interpreter-specific) registry. * * Results: * Returns a pointer to the newly allocated tuple command structure. * * Side Effects: * Memory is allocated for the structure and a hash table entry is * added. * *---------------------------------------------------------------------- */ static TupleCmd * NewTupleCmd( Tcl_Interp *interp, TupleCmdInterpData *interpDataPtr, Blt_TupleTable table, CONST char *instName) { int isNew; TupleCmd *cmdPtr; cmdPtr = Blt_Calloc(1, sizeof(TupleCmd)); assert(cmdPtr); cmdPtr->table = table; cmdPtr->interp = interp; Blt_InitHashTable(&(cmdPtr->traceTable), BLT_STRING_KEYS); Blt_InitHashTable(&(cmdPtr->notifyTable), BLT_STRING_KEYS); cmdPtr->cmdToken = Tcl_CreateObjCommand(interp, (char *)instName, (Tcl_ObjCmdProc *)TupleInstObjCmd, cmdPtr, TupleInstDeleteProc); cmdPtr->instTablePtr = &interpDataPtr->instTable; cmdPtr->hashPtr = Blt_CreateHashEntry(cmdPtr->instTablePtr, (char *)cmdPtr, &isNew); cmdPtr->emptyObjPtr = Tcl_NewStringObj("NA", -1); Tcl_IncrRefCount(cmdPtr->emptyObjPtr); Blt_SetHashValue(cmdPtr->hashPtr, cmdPtr); return cmdPtr; } /* *---------------------------------------------------------------------- * * GetTupleCmdInterpData -- * *---------------------------------------------------------------------- */ static TupleCmdInterpData * GetTupleCmdInterpData(Tcl_Interp *interp) { TupleCmdInterpData *dataPtr; Tcl_InterpDeleteProc *proc; dataPtr = (TupleCmdInterpData *) Tcl_GetAssocData(interp, TUPLE_THREAD_KEY, &proc); if (dataPtr == NULL) { dataPtr = Blt_Malloc(sizeof(TupleCmdInterpData)); assert(dataPtr); dataPtr->interp = interp; Tcl_SetAssocData(interp, TUPLE_THREAD_KEY, TupleInterpDeleteProc, dataPtr); Blt_InitHashTable(&dataPtr->instTable, BLT_ONE_WORD_KEYS); } return dataPtr; } /* * ---------------------------------------------------------------------- * * GenerateName -- * * Generates an unique tuple command name. Tuple names are in * the form "tupleN", where N is a non-negative integer. Check * each name generated to see if it is already a tuple. We want * to recycle names if possible. * * Results: * Returns the unique name. The string itself is stored in the * dynamic string passed into the routine. * * ---------------------------------------------------------------------- */ static CONST char * GenerateName( Tcl_Interp *interp, CONST char *prefix, CONST char *suffix, Tcl_DString *resultPtr) { int n; Tcl_Namespace *nsPtr; char string[200]; Tcl_CmdInfo cmdInfo; Tcl_DString dString; CONST char *instName, *name; /* * Parse the command and put back so that it's in a consistent * format. * * t1 ::t1 * n1::t1 ::n1::t1 * ::t1 ::t1 * ::n1::t1 ::n1::t1 */ instName = NULL; /* Suppress compiler warning. */ for (n = 0; n < INT_MAX; n++) { Tcl_DStringInit(&dString); Tcl_DStringAppend(&dString, prefix, -1); sprintf(string, "tuple%d", n); Tcl_DStringAppend(&dString, string, -1); Tcl_DStringAppend(&dString, suffix, -1); instName = Tcl_DStringValue(&dString); if (Blt_ParseQualifiedName(interp, instName, &nsPtr, &name) != TCL_OK) { Tcl_AppendResult(interp, "can't find namespace in \"", instName, "\"", (char *)NULL); return NULL; } if (nsPtr == NULL) { nsPtr = Tcl_GetCurrentNamespace(interp); } instName = Blt_GetQualifiedName(nsPtr, name, resultPtr); /* * Check if the command already exists. */ if (Tcl_GetCommandInfo(interp, (char *)instName, &cmdInfo)) { continue; } if (!Blt_TupleTableExists(interp, instName)) { /* * We want the name of the tuple command and the underlying * tuple object to be the same. Check that the free command * name isn't an already a tuple object name. */ break; } } return instName; } /* *---------------------------------------------------------------------- * * GetTupleCmd -- * * Find the tuple command associated with the Tcl command "string". * * We have to perform multiple lookups to get this right. * * The first step is to generate a canonical command name. If an * unqualified command name (i.e. no namespace qualifier) is * given, we should search first the current namespace and then * the global one. Most Tcl commands (like Tcl_GetCmdInfo) look * only at the global namespace. * * Next check if the string is * a) a Tcl command and * b) really is a command for a tuple object. * Tcl_GetCommandInfo will get us the objClientData field that * should be a cmdPtr. We verify that by searching our hashtable * of cmdPtr addresses. * * Results: * A pointer to the tuple command. If no associated tuple command * can be found, NULL is returned. It's up to the calling routines * to generate an error message. * *---------------------------------------------------------------------- */ static TupleCmd * GetTupleCmd( TupleCmdInterpData *interpDataPtr, Tcl_Interp *interp, CONST char *string) { CONST char *name; Tcl_Namespace *nsPtr; Tcl_CmdInfo cmdInfo; Blt_HashEntry *hPtr; Tcl_DString dString; char *qualName; int result; /* Put apart the tuple name and put is back together in a standard * format. */ if (Blt_ParseQualifiedName(interp, string, &nsPtr, &name) != TCL_OK) { return NULL; /* No such parent namespace. */ } if (nsPtr == NULL) { nsPtr = Tcl_GetCurrentNamespace(interp); } /* Rebuild the fully qualified name. */ qualName = Blt_GetQualifiedName(nsPtr, name, &dString); result = Tcl_GetCommandInfo(interp, qualName, &cmdInfo); Tcl_DStringFree(&dString); if (!result) { return NULL; } hPtr = Blt_FindHashEntry(&interpDataPtr->instTable, (char *)(cmdInfo.objClientData)); if (hPtr == NULL) { return NULL; } return Blt_GetHashValue(hPtr); } /* *---------------------------------------------------------------------- * * GetTraceFlags -- * * Parses a string representation of the trace bit flags and * returns the mask. * * Results: * The trace mask is returned. * *---------------------------------------------------------------------- */ static int GetTraceFlags(char *string) { register char *p; unsigned int flags; flags = 0; for (p = string; *p != '\0'; p++) { switch (toupper(*p)) { case 'R': flags |= TUPLE_TRACE_READ; break; case 'W': flags |= TUPLE_TRACE_WRITE; break; case 'U': flags |= TUPLE_TRACE_UNSET; break; case 'C': flags |= TUPLE_TRACE_CREATE; break; default: return -1; } } return flags; } /* *---------------------------------------------------------------------- * * PrintTraceFlags -- * * Generates a string representation of the trace bit flags. * It's assumed that the provided string is at least 5 bytes. * * Results: * None. * * Side Effects: * The bitflag information is written to the provided string. * *---------------------------------------------------------------------- */ static void PrintTraceFlags(unsigned int flags, char *string) { register char *p; p = string; if (flags & TUPLE_TRACE_READ) { *p++ = 'r'; } if (flags & TUPLE_TRACE_WRITE) { *p++ = 'w'; } if (flags & TUPLE_TRACE_UNSET) { *p++ = 'u'; } if (flags & TUPLE_TRACE_CREATE) { *p++ = 'c'; } *p = '\0'; } /* *---------------------------------------------------------------------- * * PrintTuple -- * * Generates a string representation of a tuple in the provided * dynamic string (the dstring is assumed to be previously * initialized). * * Results: * None. * * Side Effects: * The tuple information is appended to the dynamic string. * *---------------------------------------------------------------------- */ static void PrintTuple( TupleCmd *cmdPtr, Blt_Tuple tuple, Tcl_DString *resultPtr) { /* Tuple index */ Tcl_DStringAppendElement(resultPtr, Blt_Itoa(Blt_TupleRowIndex(tuple))); /* Key-value pairs */ { int column, nColumns; CONST char *key; Tcl_Obj *valueObjPtr; Tcl_DStringStartSublist(resultPtr); nColumns = Blt_TupleTableWidth(cmdPtr->table); for (column = 0; column < nColumns; column++) { key = Blt_TupleGetColumnKey(cmdPtr->table, column); if (Blt_TupleGetValue((Tcl_Interp *)NULL, cmdPtr->table, tuple, key, &valueObjPtr) == TCL_OK) { Tcl_DStringAppendElement(resultPtr, key); if (valueObjPtr != NULL) { Tcl_DStringAppendElement(resultPtr, Tcl_GetString(valueObjPtr)); } else { Tcl_DStringAppendElement(resultPtr, "NA"); } } } Tcl_DStringEndSublist(resultPtr); } /* Tags */ { Blt_HashEntry *hPtr; Blt_HashSearch cursor; Blt_TupleTagEntry *tPtr; Tcl_DStringStartSublist(resultPtr); for (hPtr = Blt_TupleFirstTag(cmdPtr->table, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tPtr = Blt_GetHashValue(hPtr); Tcl_DStringAppendElement(resultPtr, tPtr->tagName); } Tcl_DStringEndSublist(resultPtr); } Tcl_DStringAppend(resultPtr, "\n", -1); } /* *---------------------------------------------------------------------- * * UnsetValues -- * * This is a helper routine used by UnsetOp. It unsets one or * more key value pairs for a given tuple. * * Results: * A standard Tcl result. If an error occurred when unsetting * the new value TCL_ERROR is returned and an error message is * left in the interpreter result. * *---------------------------------------------------------------------- */ static int UnsetValues( TupleCmd *cmdPtr, Blt_Tuple tuple, int objc, Tcl_Obj *CONST *objv) { register int i; for (i = 0; i < objc; i ++) { if (Blt_TupleUnsetValue(cmdPtr->interp, cmdPtr->table, tuple, Tcl_GetString(objv[i])) != TCL_OK) { return TCL_ERROR; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * DeleteNotifier -- * * This is a helper routine used to delete notifiers. It * releases the Tcl_Objs used in the notification callback * command and the actual tuple notifier. Memory for the * notifier is also freed. * * Results: * None. * * Side Effects: * Memory is deallocated and the notitifer is no longer * active. * *---------------------------------------------------------------------- */ static void DeleteNotifier(NotifyInfo *notifyPtr) { int i; for (i = 0; i < notifyPtr->objc; i++) { Tcl_DecrRefCount(notifyPtr->objv[i]); } Blt_TupleDeleteNotifier(notifyPtr->notifier); Blt_Free(notifyPtr->objv); Blt_Free(notifyPtr); } /* *---------------------------------------------------------------------- * * DeleteTrace -- * * This is a helper routine used to delete traces. It releases * the Tcl_Objs used in the trace callback command and the actual * tuple trace. Memory for the trace is also freed. * * Results: * None. * * Side Effects: * Memory is deallocated and the trace is no longer active. * *---------------------------------------------------------------------- */ static void DeleteTrace(TraceInfo *tracePtr) { int i; for(i = 0; i < tracePtr->objc; i++) { Tcl_DecrRefCount(tracePtr->objv[i]); } Blt_TupleDeleteTrace(tracePtr->trace); Blt_Free(tracePtr->objv); Blt_Free(tracePtr); } /* *---------------------------------------------------------------------- * * TupleTraceProc -- * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TupleTraceProc( ClientData clientData, Tcl_Interp *interp, unsigned int row, /* Tuple that has just been updated. */ unsigned int column, /* Field that's updated. */ unsigned int flags) { TraceInfo *tracePtr = clientData; char string[5]; CONST char *key; int result; int i; i = tracePtr->objc; /* Add extra command arguments * starting at this index. */ tracePtr->objv[i] = Tcl_NewIntObj(row); key = Blt_TupleGetColumnKey(tracePtr->cmdPtr->table, column); tracePtr->objv[i+1] = Tcl_NewStringObj(key, -1); PrintTraceFlags(flags, string); tracePtr->objv[i+2] = Tcl_NewStringObj(string, -1); Tcl_IncrRefCount(tracePtr->objv[i]); Tcl_IncrRefCount(tracePtr->objv[i+1]); Tcl_IncrRefCount(tracePtr->objv[i+2]); result = Tcl_EvalObjv(interp, tracePtr->objc + 3, tracePtr->objv, 0); Tcl_DecrRefCount(tracePtr->objv[i+2]); Tcl_DecrRefCount(tracePtr->objv[i+1]); Tcl_DecrRefCount(tracePtr->objv[i]); return result; } /* *---------------------------------------------------------------------- * * TupleEventProc -- * *---------------------------------------------------------------------- */ static int TupleEventProc(ClientData clientData, Blt_TupleNotifyEvent *eventPtr) { NotifyInfo *notifyPtr = clientData; int result; int i; char *string; switch (eventPtr->type) { case TUPLE_NOTIFY_CREATE_ROW: string = "-createrow"; break; case TUPLE_NOTIFY_CREATE_COLUMN: string = "-createcolumn"; break; case TUPLE_NOTIFY_DELETE_ROW: string = "-deleterow"; break; case TUPLE_NOTIFY_DELETE_COLUMN: string = "-deletecolumn"; break; case TUPLE_NOTIFY_MOVE: string = "-move"; break; case TUPLE_NOTIFY_SORT: string = "-sort"; break; case TUPLE_NOTIFY_RELABEL: string = "-relabel"; break; default: /* empty */ string = "???"; break; } i = notifyPtr->objc; notifyPtr->objv[i] = Tcl_NewStringObj(string, -1); notifyPtr->objv[i+1] = Tcl_NewIntObj(eventPtr->row); Tcl_IncrRefCount(notifyPtr->objv[i]); Tcl_IncrRefCount(notifyPtr->objv[i+1]); result = Tcl_EvalObjv(notifyPtr->cmdPtr->interp, notifyPtr->objc + 3, notifyPtr->objv, 0); Tcl_DecrRefCount(notifyPtr->objv[i+1]); Tcl_DecrRefCount(notifyPtr->objv[i]); if (result != TCL_OK) { Tcl_BackgroundError(notifyPtr->cmdPtr->interp); return TCL_ERROR; } Tcl_ResetResult(notifyPtr->cmdPtr->interp); return TCL_OK; } /* *---------------------------------------------------------------------- * * GetTuple -- * *---------------------------------------------------------------------- */ static int GetTuple(TupleCmd *cmdPtr, Tcl_Obj *objPtr, Blt_Tuple *tuplePtr) { char c; Blt_Tuple tuple; char *string; string = Tcl_GetString(objPtr); c = string[0]; if (isdigit(UCHAR(c))) { int row; if (Tcl_GetIntFromObj(cmdPtr->interp, objPtr, &row) != TCL_OK) { return TCL_ERROR; } tuple = Blt_TupleGetTupleByIndex(cmdPtr->table, row); if (tuple != NULL) { *tuplePtr = tuple; return TCL_OK; } } else if (cmdPtr != NULL) { if (strcmp(string, "all") == 0) { if (Blt_TupleTableLength(cmdPtr->table) > 1) { Tcl_AppendResult(cmdPtr->interp, "more than one node tagged as \"", string, "\"", (char *)NULL); return TCL_ERROR; } tuple = Blt_TupleGetTupleByIndex(cmdPtr->table, 0); } else { Blt_HashTable *tablePtr; Blt_HashSearch cursor; Blt_HashEntry *hPtr; int result; tuple = NULL; result = TCL_ERROR; tablePtr = Blt_TupleTagHashTable(cmdPtr->table, string); if (tablePtr == NULL) { Tcl_AppendResult(cmdPtr->interp, "can't find tag or index \"", string, "\" in ", Blt_TupleTableName(cmdPtr->table), (char *)NULL); } else if (tablePtr->numEntries > 1) { Tcl_AppendResult(cmdPtr->interp, "more than one node tagged as \"", string, "\"", (char *)NULL); } else if (tablePtr->numEntries > 0) { hPtr = Blt_FirstHashEntry(tablePtr, &cursor); tuple = Blt_GetHashValue(hPtr); result = TCL_OK; } if (result == TCL_ERROR) { return TCL_ERROR; } } if (tuple != NULL) { *tuplePtr = tuple; return TCL_OK; } } Tcl_AppendResult(cmdPtr->interp, "can't find tag or index \"", string, "\" in ", Blt_TupleTableName(cmdPtr->table), (char *)NULL); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * AttachOp -- * *---------------------------------------------------------------------- */ static int AttachOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { if (objc == 3) { CONST char *objName; CONST char *name; Blt_TupleTable table; Tcl_Namespace *nsPtr; Tcl_DString dString; int result; objName = Tcl_GetString(objv[2]); if (Blt_ParseQualifiedName(interp, objName, &nsPtr, &name) != TCL_OK) { Tcl_AppendResult(interp, "can't find namespace in \"", objName, "\"", (char *)NULL); return TCL_ERROR; } if (nsPtr == NULL) { nsPtr = Tcl_GetCurrentNamespace(interp); } objName = Blt_GetQualifiedName(nsPtr, name, &dString); result = Blt_TupleGetTable(interp, objName, &table); Tcl_DStringFree(&dString); if (result != TCL_OK) { return TCL_ERROR; } if (cmdPtr->table != NULL) { Blt_HashEntry *hPtr; Blt_HashSearch cursor; TraceInfo *tracePtr; NotifyInfo *notifyPtr; Blt_TupleReleaseTable(cmdPtr->table); /* Dump the current set of tags, traces, and notifiers. */ for (hPtr = Blt_FirstHashEntry(&cmdPtr->traceTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tracePtr = Blt_GetHashValue(hPtr); DeleteTrace(tracePtr); } Blt_DeleteHashTable(&cmdPtr->traceTable); Blt_InitHashTable(&cmdPtr->traceTable, TCL_STRING_KEYS); for (hPtr = Blt_FirstHashEntry(&cmdPtr->notifyTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { notifyPtr = Blt_GetHashValue(hPtr); DeleteNotifier(notifyPtr); } Blt_DeleteHashTable(&cmdPtr->notifyTable); Blt_InitHashTable(&cmdPtr->notifyTable, TCL_STRING_KEYS); } cmdPtr->table = table; } Tcl_SetResult(interp, (char *)Blt_TupleTableName(cmdPtr->table), TCL_VOLATILE); return TCL_OK; } /* *---------------------------------------------------------------------- * * ColumnOp -- * * Parses the given command line and calls one of several * column-specific operations. * * Results: * Returns a standard Tcl result. It is the result of * operation called. * *---------------------------------------------------------------------- */ static Blt_OpSpec columnOps[] = { #ifdef notdef {"create", 1, (Blt_Op)ColumnCreateOp, 4, 0, "name ?switches?",}, {"delete", 1, (Blt_Op)ColumnDeleteOp, 3, 0, "name...",}, {"get", 1, (Blt_Op)ColumnGetOp, 4, 0, "name...",}, {"info", 1, (Blt_Op)ColumnInfoOp, 4, 4, "name",}, {"names", 1, (Blt_Op)ColumnNamesOp, 3, 3, "",}, {"set", 1, (Blt_Op)ColumnSetOp, 4, 0, "name values ?name values?...",}, {"type", 1, (Blt_Op)ColumnTypeOp, 4, 0, "?newType?",}, {"unset", 1, (Blt_Op)ColumnUnsetOp, 4, 0, "name...",}, {"type", 1, (Blt_Op)ColumnTypeOp, 4, 0, "?newType?",}, #endif }; static int nColumnOps = sizeof(columnOps) / sizeof(Blt_OpSpec); static int ColumnOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_Op proc; int result; proc = Blt_GetOpFromObj(interp, nColumnOps, columnOps, BLT_OP_ARG2, objc, objv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (cmdPtr, interp, objc, objv); return result; } /* *---------------------------------------------------------------------- * * DeleteOp -- * * d0 delete tagOrIdx ?tagOrIdx...? * * Deletes one or more tuples from the table. Tuples may be * specified by their index or a tag. * *---------------------------------------------------------------------- */ static int DeleteOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_Tuple tuple; Blt_TupleTagSearch cursor; int i; Blt_TupleStartDeleteRows(cmdPtr->table); for (i = 2; i < objc; i++) { /* A tag may designate more than one row. */ tuple = Blt_TupleFirstTagged(interp, cmdPtr->table, objv[i], &cursor); if (tuple == NULL) { Blt_TupleEndDeleteRows(cmdPtr->table); return TCL_ERROR; } for (/* empty */; tuple != NULL; tuple = Blt_TupleNextTagged(&cursor)) { Blt_TupleDeleteTuple(cmdPtr->table, tuple); } } Blt_TupleEndDeleteRows(cmdPtr->table); return TCL_OK; } /* *---------------------------------------------------------------------- * * ExistsOp -- * *---------------------------------------------------------------------- */ static int ExistsOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_Tuple tuple; int bool; bool = TRUE; if (GetTuple(cmdPtr, objv[2], &tuple) != TCL_OK) { bool = FALSE; } else if (objc == 4) { Tcl_Obj *valueObjPtr; char *key; key = Tcl_GetString(objv[3]); if (Blt_TupleGetValue((Tcl_Interp *)NULL, cmdPtr->table, tuple, key, &valueObjPtr) != TCL_OK) { bool = FALSE; } bool = (valueObjPtr != NULL); } Tcl_SetObjResult(interp, Tcl_NewBooleanObj(bool)); return TCL_OK; } /* *---------------------------------------------------------------------- * * GetOp -- * * Retrieves the value from a given tuple for a designated * column. It's an error if the column key or row tuple is * invalid. If no key argument is provided then, all key-value * pairs in the tuple are returned. If a value is empty (the * Tcl_Obj value is NULL), then the tuple command's "empty" * string representation will be used. * * A third argument may be provided as the default return value. * If no value exists for the given key, then this value is * returned. * * Results: * A standard Tcl result. If the tag or index is invalid, * TCL_ERROR is returned and an error message is left in the * interpreter result. * * *---------------------------------------------------------------------- */ static int GetOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_Tuple tuple; if (GetTuple(cmdPtr, objv[2], &tuple) != TCL_OK) { return TCL_ERROR; } if (objc == 3) { int row, column; Tcl_Obj *valueObjPtr, *listObjPtr; /* Return all the key-value pairs in the tuple. Ignore columns * with empty values. */ listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); row = Blt_TupleRowIndex(tuple); for (column = 0; column < Blt_TupleTableWidth(cmdPtr->table); column++){ if (Blt_TupleGetValueByIndex((Tcl_Interp *)NULL, cmdPtr->table, row, column, &valueObjPtr) == TCL_OK) { if (valueObjPtr != NULL) { Tcl_Obj *objPtr; CONST char *key; key = Blt_TupleGetColumnKey(cmdPtr->table, column); objPtr = Tcl_NewStringObj(key, -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); Tcl_ListObjAppendElement(interp, listObjPtr, valueObjPtr); } } } Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; } else { Tcl_Obj *valueObjPtr; char *key; int row, column; row = Blt_TupleRowIndex(tuple); key = Tcl_GetString(objv[3]); if (Blt_TupleGetColumnIndex(interp, cmdPtr->table, key, &column) != TCL_OK) { return TCL_ERROR; } if (Blt_TupleGetValueByIndex((Tcl_Interp *)NULL, cmdPtr->table, row, column, &valueObjPtr) != TCL_OK) { return TCL_ERROR; } if (valueObjPtr == NULL) { if (objc == 4) { Tcl_AppendResult(interp, "tuple "\", Tcl_GetString(objv[2]), "\" in table \"", Tcl_GetString(objv[0]), "\" is empty.", (char *)NULL); return TCL_ERROR; } valueObjPtr = objv[4]; } Tcl_SetObjResult(interp, valueObjPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * NotifyCreateOp -- * * Creates a notifier for this instance. Notifiers represent * a bitmask of events and a command prefix to be invoked * when a matching event occurs. * * The command prefix is parsed and saved in an array of * Tcl_Objs. Extra slots are allocated for the * * Results: * A standard Tcl result. The name of the new notifier is * returned in the interpreter result. Otherwise, if it failed * to parse a switch, then TCL_ERROR is returned and an error * message is left in the interpreter result. * * Example: * tuple0 notify create ?flags? command arg * *---------------------------------------------------------------------- */ static int NotifyCreateOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { NotifyInfo *notifyPtr; NotifyData data; char *string; char idString[200]; int isNew, nArgs; Blt_HashEntry *hPtr; int count; register int i; count = 0; for (i = 3; i < objc; i++) { string = Tcl_GetString(objv[i]); if (string[0] != '-') { break; } count++; } data.mask = 0; /* Process switches */ if (Blt_ProcessObjSwitches(interp, notifySwitches, count, objv + 3, (char *)&data, 0) < 0) { return TCL_ERROR; } notifyPtr = Blt_Malloc(sizeof(NotifyInfo)); nArgs = objc - i; /* Stash away the command in structure and pass that to the notifier. */ notifyPtr->objv = Blt_Malloc((nArgs + 2) * sizeof(Tcl_Obj *)); for (count = 0; i < objc; i++, count++) { Tcl_IncrRefCount(objv[i]); notifyPtr->objv[count] = objv[i]; } notifyPtr->objc = nArgs + 2; notifyPtr->cmdPtr = cmdPtr; if (data.mask == 0) { data.mask = TUPLE_NOTIFY_ALL; } sprintf(idString, "notify%d", cmdPtr->notifyCounter++); hPtr = Blt_CreateHashEntry(&cmdPtr->notifyTable, idString, &isNew); Blt_SetHashValue(hPtr, notifyPtr); notifyPtr->notifier = Blt_TupleCreateNotifier(cmdPtr->table, data.mask, TupleEventProc, notifyPtr); Tcl_SetStringObj(Tcl_GetObjResult(interp), idString, -1); return TCL_OK; } /* *---------------------------------------------------------------------- * * NotifyDeleteOp -- * * Deletes one or more notifiers. * * Results: * A standard Tcl result. If a name given doesn't represent * a notifier, then TCL_ERROR is returned and an error message * is left in the interpreter result. * *---------------------------------------------------------------------- */ static int NotifyDeleteOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { NotifyInfo *notifyPtr; Blt_HashEntry *hPtr; register int i; char *string; for (i = 3; i < objc; i++) { string = Tcl_GetString(objv[i]); hPtr = Blt_FindHashEntry(&(cmdPtr->notifyTable), string); if (hPtr == NULL) { Tcl_AppendResult(interp, "unknown notify name \"", string, "\"", (char *)NULL); return TCL_ERROR; } notifyPtr = Blt_GetHashValue(hPtr); Blt_DeleteHashEntry(&cmdPtr->notifyTable, hPtr); DeleteNotifier(notifyPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * NotifyInfoOp -- * * Returns the details for a given notifier. The name * of the notifier is passed as an argument. The details * are both the event mask and command prefix. * * Results: * A standard Tcl result. If the name given doesn't represent * a notifier, then TCL_ERROR is returned and an error message * is left in the interpreter result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int NotifyInfoOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { NotifyInfo *notifyPtr; struct Blt_TupleNotifierStruct *nPtr; Blt_HashEntry *hPtr; Tcl_DString dString; char *string; int i; string = Tcl_GetString(objv[3]); hPtr = Blt_FindHashEntry(&(cmdPtr->notifyTable), string); if (hPtr == NULL) { Tcl_AppendResult(interp, "unknown notify name \"", string, "\"", (char *)NULL); return TCL_ERROR; } notifyPtr = Blt_GetHashValue(hPtr); Tcl_DStringInit(&dString); Tcl_DStringAppendElement(&dString, string); /* Copy notify Id */ Tcl_DStringStartSublist(&dString); nPtr = notifyPtr->notifier; if (nPtr->mask & TUPLE_NOTIFY_CREATE) { Tcl_DStringAppendElement(&dString, "-create"); } if (nPtr->mask & TUPLE_NOTIFY_DELETE) { Tcl_DStringAppendElement(&dString, "-delete"); } if (nPtr->mask & TUPLE_NOTIFY_MOVE) { Tcl_DStringAppendElement(&dString, "-move"); } if (nPtr->mask & TUPLE_NOTIFY_SORT) { Tcl_DStringAppendElement(&dString, "-sort"); } if (nPtr->mask & TUPLE_NOTIFY_RELABEL) { Tcl_DStringAppendElement(&dString, "-relabel"); } if (nPtr->mask & TUPLE_NOTIFY_WHENIDLE) { Tcl_DStringAppendElement(&dString, "-whenidle"); } Tcl_DStringEndSublist(&dString); Tcl_DStringStartSublist(&dString); for (i = 0; i < notifyPtr->objc; i++) { Tcl_DStringAppendElement(&dString, Tcl_GetString(notifyPtr->objv[i])); } Tcl_DStringEndSublist(&dString); Tcl_DStringResult(interp, &dString); return TCL_OK; } /* *---------------------------------------------------------------------- * * NotifyNamesOp -- * * Returns the names of all the notifiers in use by this * instance. Notifiers issues by other instances or object * clients are not reported. * * Results: * Always TCL_OK. A list of notifier names is left in the * interpreter result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int NotifyNamesOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { Blt_HashEntry *hPtr; Blt_HashSearch cursor; Tcl_Obj *objPtr, *listObjPtr; char *idString; listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); for (hPtr = Blt_FirstHashEntry(&(cmdPtr->notifyTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { idString = Blt_GetHashKey(&(cmdPtr->notifyTable), hPtr); objPtr = Tcl_NewStringObj(idString, -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * NotifyOp -- * * Parses the given command line and calls one of several * notifier-specific operations. * * Results: * Returns a standard Tcl result. It is the result of * operation called. * *---------------------------------------------------------------------- */ static Blt_OpSpec notifyOps[] = { {"create", 1, (Blt_Op)NotifyCreateOp, 4, 0, "?flags? command",}, {"delete", 1, (Blt_Op)NotifyDeleteOp, 3, 0, "notifyId...",}, {"info", 1, (Blt_Op)NotifyInfoOp, 4, 4, "notifyId",}, {"names", 1, (Blt_Op)NotifyNamesOp, 3, 3, "",}, }; static int nNotifyOps = sizeof(notifyOps) / sizeof(Blt_OpSpec); static int NotifyOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_Op proc; int result; proc = Blt_GetOpFromObj(interp, nNotifyOps, notifyOps, BLT_OP_ARG2, objc, objv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (cmdPtr, interp, objc, objv); return result; } /* *---------------------------------------------------------------------- * * ColumnOp -- * * Parses the given command line and calls one of several * column-specific operations. * * Results: * Returns a standard Tcl result. It is the result of * operation called. * *---------------------------------------------------------------------- */ static Blt_OpSpec columnOps[] = { #ifdef notdef {"create", 1, (Blt_Op)ColumnCreateOp, 4, 0, "name ?switches?",}, {"cut", 1, (Blt_Op)ColumnDeleteOp, 3, 0, "name...",}, {"dup", 1, (Blt_Op)ColumnGetOp, 4, 0, "name...",}, {"pack", 1, (Blt_Op)ColumnNamesOp, 3, 3, "",}, {"paste", 1, (Blt_Op)ColumnInfoOp, 4, 4, "name",}, {"range", 1, (Blt_Op)ColumnSetOp, 4, 0, "name values ?name values?..",}, {"type", 1, (Blt_Op)ColumnTypeOp, 4, 0, "?newType?",}, {"unset", 1, (Blt_Op)ColumnUnsetOp, 4, 0, "name...",}, {"type", 1, (Blt_Op)ColumnTypeOp, 4, 0, "?newType?",}, #endif }; static int nColumnOps = sizeof(columnOps) / sizeof(Blt_OpSpec); static int SelectOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_Op proc; int result; proc = Blt_GetOpFromObj(interp, nColumnOps, columnOps, BLT_OP_ARG2, objc, objv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (cmdPtr, interp, objc, objv); return result; } /* *---------------------------------------------------------------------- * * SetOp -- * * Sets one or more key-value pairs for tuples. One or more * tuples may be set. If any of the columns (keys) given don't * already exist, the columns will be automatically created. The * same holds true for rows. If a row index is beyond the end of * the table (tags are always in range), new rows are allocated. * * Results: * A standard Tcl result. If the tag or index is invalid, * TCL_ERROR is returned and an error message is left in the * interpreter result. * *---------------------------------------------------------------------- */ static int SetOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_Tuple tuple; register int i; int isNew; char *string; string = Tcl_GetString(objv[2]); if (isdigit(UCHAR(*string))) { int row, extra; CONST char *key; int column; if (Tcl_GetIntFromObj(interp, objv[2], &row) != TCL_OK) { return TCL_ERROR; } /* Extend the array of tuples if necessary */ extra = row - Blt_TupleTableLength(cmdPtr->table); if ((extra > 0) && (Blt_TupleExtendRows(cmdPtr->table, extra) != TCL_OK)) { return TCL_ERROR; } /* Add the values, creating new keys if necessary. */ for (i = 3; i < objc; i++) { key = Tcl_GetString(objv[i]); column = Blt_TupleAddColumn(cmdPtr->table, key, &isNew); i++; if (i == objc) { Tcl_AppendResult(cmdPtr->interp, "missing value for field \"", key, "\"", (char *)NULL); return TCL_ERROR; } if (Blt_TupleSetValue(interp, cmdPtr->table, tuple, key, objv[i]) != TCL_OK) { return TCL_ERROR; } } return TCL_OK; } else { Blt_TupleTagSearch cursor; KeyValue *values; CONST char *key; int n; tuple = Blt_TupleFirstTagged(interp, cmdPtr->table, objv[2], &cursor); if (tuple == NULL) { return TCL_ERROR; } values = Blt_Malloc(sizeof(KeyValue) * objc - 3); /* Create new keys if necessary. */ n = 0; for (i = 3; i < objc; i++) { key = Tcl_GetString(objv[i]); values[n].column = Blt_TupleAddColumn(cmdPtr->table, key, &isNew); i++; if (i == objc) { Tcl_AppendResult(cmdPtr->interp, "missing value for field \"", key, "\"", (char *)NULL); goto error; } values[n].objPtr = objv[i]; n++; } for (/* empty */; tuple != NULL; tuple = Blt_TupleNextTagged(&cursor)) { for (i = 0; i < n; i++) { if (Blt_TupleSetValueByIndex(cmdPtr->interp, cmdPtr->table, Blt_TupleRowIndex(tuple), values[i].column, values[i].objPtr) != TCL_OK) { goto error; } } } Blt_Free(values); return TCL_OK; error: Blt_Free(values); return TCL_ERROR; } } /* *---------------------------------------------------------------------- * * TagAddOp -- * * Adds a tag to one or more tuples. A tuple may already have the * tag. Tag names can not start with a digit. It's also an error * to try to add the reserved tag "all". * * Results: * A standard Tcl result. If a tag isn't valid then TCL_ERROR is * returned and an error message is left in the interpreter * result. * *---------------------------------------------------------------------- */ static int TagAddOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_Tuple tuple; register int i; char *tagName; Blt_TupleTagSearch cursor; tagName = Tcl_GetString(objv[3]); if (isdigit(UCHAR(tagName[0]))) { Tcl_AppendResult(interp, "bad tag \"", tagName, "\": can't start with a digit", (char *)NULL); return TCL_ERROR; } if (strcmp(tagName, "all") == 0) { Tcl_AppendResult(cmdPtr->interp, "can't add reserved tag \"", tagName, "\"", (char *)NULL); return TCL_ERROR; } for (i = 4; i < objc; i++) { tuple = Blt_TupleFirstTagged(interp, cmdPtr->table, objv[i], &cursor); if (tuple == NULL) { return TCL_ERROR; } for (/* empty */; tuple != NULL; tuple = Blt_TupleNextTagged(&cursor)) { Blt_TupleAddTag(cmdPtr->table, tuple, tagName); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * TagDeleteOp -- * * Deletes a tag from one or more tuples. It's an error to try to * remove the tag "all". It's not an error is the tuple doesn't * currently have the tag. * * Results: * A standard Tcl result. If a tag isn't valid then TCL_ERROR is * returned and an error message is left in the interpreter * result. * *---------------------------------------------------------------------- */ static int TagDeleteOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { char *tagName; Blt_Tuple tuple; int i; Blt_TupleTagSearch cursor; tagName = Tcl_GetString(objv[3]); if (strcmp(tagName, "all") == 0) { Tcl_AppendResult(interp, "can't delete reserved tag \"", tagName, "\"", (char *)NULL); return TCL_ERROR; } for (i = 4; i < objc; i++) { tuple = Blt_TupleFirstTagged(interp, cmdPtr->table, objv[i], &cursor); if (tuple == NULL) { return TCL_ERROR; } for (/* empty */; tuple != NULL; tuple = Blt_TupleNextTagged(&cursor)) { Blt_TupleRemoveTag(cmdPtr->table, tuple, tagName); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * TagDumpOp -- * * Reports information about the tuples tagged with the given * tags. * * Results: * A standard Tcl result. If a tag isn't valid then TCL_ERROR is * returned and an error message is left in the interpreter * result. * *---------------------------------------------------------------------- */ static int TagDumpOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Tcl_DString dString; Blt_TupleTagSearch cursor; Blt_Tuple tuple; register int i; Tcl_DStringInit(&dString); for (i = 3; i < objc; i++) { tuple = Blt_TupleFirstTagged(interp, cmdPtr->table, objv[i], &cursor); if (tuple == NULL) { Tcl_DStringFree(&dString); return TCL_ERROR; } for (/* empty */; tuple != NULL; tuple = Blt_TupleNextTagged(&cursor)) { PrintTuple(cmdPtr, tuple, &dString); } } Tcl_DStringResult(interp, &dString); Tcl_DStringFree(&dString); return TCL_OK; } /* *---------------------------------------------------------------------- * * TagForgetOp -- * * Deletes one or more tags. The tuples currently associated * with the tag remain otherwise intact. It's not an error if * the tag doesn't currently exist. * * Results: * Always TCL_OK. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TagForgetOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { register int i; for (i = 3; i < objc; i++) { Blt_TupleForgetTag(cmdPtr->table, Tcl_GetString(objv[i])); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TagNamesOp -- * * Returns a list of the unique tags for the given tuples. If no * tuples are given, then all tags are reported. * * Results: * A standard Tcl result. If a tag or index of a tuple isn't * valid then TCL_ERROR is returned and an error message is left * in the interpreter result. * *---------------------------------------------------------------------- */ static int TagNamesOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_HashSearch cursor; Blt_TupleTagEntry *tPtr; Tcl_Obj *listObjPtr, *objPtr; listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); objPtr = Tcl_NewStringObj("all", -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); if (objc == 3) { Blt_HashEntry *hPtr; for (hPtr = Blt_TupleFirstTag(cmdPtr->table, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tPtr = Blt_GetHashValue(hPtr); objPtr = Tcl_NewStringObj(tPtr->tagName, -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } } else { register int i; Blt_HashEntry *hPtr; Blt_HashTable uniqTable; int isNew; Blt_Tuple tuple; Blt_InitHashTable(&uniqTable, BLT_STRING_KEYS); for (i = 3; i < objc; i++) { if (GetTuple(cmdPtr, objv[i], &tuple) != TCL_OK) { goto error; } for (hPtr = Blt_TupleFirstTag(cmdPtr->table, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tPtr = Blt_GetHashValue(hPtr); if (Blt_TupleHasTag(cmdPtr->table, tuple, tPtr->tagName)) { Blt_CreateHashEntry(&uniqTable, tPtr->tagName, &isNew); } } } for (hPtr = Blt_FirstHashEntry(&uniqTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { objPtr = Tcl_NewStringObj(Blt_GetHashKey(&uniqTable, hPtr), -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } Blt_DeleteHashTable(&uniqTable); } Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; error: Tcl_DecrRefCount(listObjPtr); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TagRangeOp -- * * Adds a tag to a range of tuples. A tuple may already have the * tag. Tag names can not start with a digit. It's also an error * to try to add the reserved tag "all". * * Results: * A standard Tcl result. If a tag isn't valid then TCL_ERROR is * returned and an error message is left in the interpreter * result. * *---------------------------------------------------------------------- */ static int TagRangeOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { char *tagName; Blt_Tuple first, last; tagName = Tcl_GetString(objv[3]); if (isdigit(UCHAR(tagName[0]))) { Tcl_AppendResult(interp, "bad tag \"", tagName, "\": can't start with a digit", (char *)NULL); return TCL_ERROR; } if (strcmp(tagName, "all") == 0) { Tcl_AppendResult(cmdPtr->interp, "can't add reserved tag \"", tagName, "\"", (char *)NULL); return TCL_ERROR; } if ((GetTuple(cmdPtr, objv[4], &first) != TCL_OK) || (GetTuple(cmdPtr, objv[5], &last) != TCL_OK)) { return TCL_ERROR; } if (Blt_TupleRowIndex(first) <= Blt_TupleRowIndex(last)) { Blt_Tuple tuple; do { Blt_TupleAddTag(cmdPtr->table, tuple, tagName); tuple = Blt_TupleNextTuple(cmdPtr->table, tuple); } while(tuple != last); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TagTuplesOp -- * * Returns a list of unique tuple indices associated with the * tags given. * * Results: * A standard Tcl result. If a tag isn't valid then TCL_ERROR is * returned and an error message is left in the interpreter * result. * *---------------------------------------------------------------------- */ static int TagTuplesOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_HashEntry *hPtr; Blt_HashSearch cursor; Blt_HashTable uniqTable; Blt_Tuple tuple; Tcl_Obj *listObjPtr; Tcl_Obj *objPtr; char *tagName; int isNew; register int i; Blt_InitHashTable(&uniqTable, BLT_ONE_WORD_KEYS); for (i = 3; i < objc; i++) { tagName = Tcl_GetString(objv[i]); if (strcmp(tagName, "all") == 0) { break; } else { Blt_HashTable *tablePtr; tablePtr = Blt_TupleTagHashTable(cmdPtr->table, tagName); if (tablePtr != NULL) { for (hPtr = Blt_FirstHashEntry(tablePtr, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tuple = Blt_GetHashValue(hPtr); Blt_CreateHashEntry(&uniqTable, (char *)tuple, &isNew); } continue; } } Tcl_AppendResult(interp, "can't find a tag \"", tagName, "\"", (char *)NULL); goto error; } listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); for (hPtr = Blt_FirstHashEntry(&uniqTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tuple = (Blt_Tuple)Blt_GetHashKey(&uniqTable, hPtr); objPtr = Tcl_NewIntObj(Blt_TupleRowIndex(tuple)); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } Tcl_SetObjResult(interp, listObjPtr); Blt_DeleteHashTable(&uniqTable); return TCL_OK; error: Blt_DeleteHashTable(&uniqTable); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TagOp -- * * This procedure is invoked to process tag operations. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ static Blt_OpSpec tagOps[] = { {"add", 1, (Blt_Op)TagAddOp, 5, 0, "tag tagOrIdx...",}, {"delete", 2, (Blt_Op)TagDeleteOp, 5, 0, "tag tagOrIdx...",}, {"dump", 2, (Blt_Op)TagDumpOp, 4, 0, "tag...",}, {"forget", 1, (Blt_Op)TagForgetOp, 4, 0, "tag...",}, {"names", 1, (Blt_Op)TagNamesOp, 3, 0, "?tagOrIdx...?",}, {"range", 1, (Blt_Op)TagRangeOp, 6, 6, "tag first last",}, {"tuples", 1, (Blt_Op)TagTuplesOp, 4, 0, "tag ?tag...?",}, }; static int nTagOps = sizeof(tagOps) / sizeof(Blt_OpSpec); static int TagOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_Op proc; int result; proc = Blt_GetOpFromObj(interp, nTagOps, tagOps, BLT_OP_ARG2, objc, objv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (cmdPtr, interp, objc, objv); return result; } /* *---------------------------------------------------------------------- * * TraceCreateOp -- * * Creates a trace for this instance. Traces represent * list of keys, a bitmask of trace flags, and a command prefix * to be invoked when a matching trace event occurs. * * The command prefix is parsed and saved in an array of * Tcl_Objs. The qualified name of the instance is saved * also. * * Results: * A standard Tcl result. The name of the new trace is * returned in the interpreter result. Otherwise, if it failed * to parse a switch, then TCL_ERROR is returned and an error * message is left in the interpreter result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TraceCreateOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { Blt_Tuple tuple; TraceInfo *tracePtr; char *keyList, *tagName, *string; char idString[200]; int flags, isNew; struct Blt_TupleTraceStruct *tPtr; Tcl_Obj **args; int nArgs; int i; tagName = Tcl_GetString(objv[3]); if (isdigit(UCHAR(*tagName))) { if (GetTuple(cmdPtr, objv[3], &tuple) != TCL_OK) { return TCL_ERROR; } tagName = NULL; } else { tagName = Blt_Strdup(tagName); tuple = NULL; } keyList = Tcl_GetString(objv[4]); string = Tcl_GetString(objv[5]); flags = GetTraceFlags(string); if (flags < 0) { Tcl_AppendResult(interp, "unknown flag in \"", string, "\"", (char *)NULL); return TCL_ERROR; } if (Tcl_ListObjGetElements(interp, objv[6], &nArgs, &args) != TCL_OK) { return TCL_ERROR; } tPtr = Blt_TupleCreateTrace(cmdPtr->table, tuple, keyList, tagName, flags, TupleTraceProc, tracePtr); if (tPtr == NULL) { return TCL_ERROR; } /* Stash away the command in structure and pass that to the trace. */ tracePtr = Blt_Malloc(sizeof(TraceInfo)); tracePtr->cmdPtr = cmdPtr; tracePtr->trace = tPtr; sprintf(idString, "trace%d", cmdPtr->traceCounter++); tracePtr->hashPtr = Blt_CreateHashEntry(&cmdPtr->traceTable, idString, &isNew); Blt_SetHashValue(tracePtr->hashPtr, tracePtr); Tcl_SetStringObj(Tcl_GetObjResult(interp), idString, -1); tracePtr->objv = Blt_Calloc(nArgs + 1 + 3 + 1, sizeof(Tcl_Obj *)); for(i = 0; i < nArgs; i++) { tracePtr->objv[i] = args[i]; Tcl_IncrRefCount(tracePtr->objv[i]); } { Tcl_DString dString; char *qualName; Tcl_DStringInit(&dString); qualName = Blt_GetQualifiedName( Blt_GetCommandNamespace(interp, cmdPtr->cmdToken), Tcl_GetCommandName(interp, cmdPtr->cmdToken), &dString); tracePtr->objv[i] = Tcl_NewStringObj(qualName, -1); Tcl_IncrRefCount(tracePtr->objv[i]); Tcl_DStringFree(&dString); tracePtr->objc = nArgs + 1; } return TCL_OK; } /* *---------------------------------------------------------------------- * * TraceDeleteOp -- * * Deletes one or more traces. * * Results: * A standard Tcl result. If a name given doesn't represent * a trace, then TCL_ERROR is returned and an error message * is left in the interpreter result. * *---------------------------------------------------------------------- */ static int TraceDeleteOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { TraceInfo *tracePtr; Blt_HashEntry *hPtr; register int i; char *name; for (i = 3; i < objc; i++) { name = Tcl_GetString(objv[i]); hPtr = Blt_FindHashEntry(&cmdPtr->traceTable, name); if (hPtr == NULL) { Tcl_AppendResult(interp, "unknown trace \"", name, "\"", (char *)NULL); return TCL_ERROR; } tracePtr = Blt_GetHashValue(hPtr); Blt_DeleteHashEntry(&cmdPtr->traceTable, hPtr); DeleteTrace(tracePtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TraceInfoOp -- * * Returns the details for a given trace. The name of the trace * is passed as an argument. The details are returned as a list * of key-value pairs: trace name, tag, row index, keys, flags, * and the command prefix. * * Results: * A standard Tcl result. If the name given doesn't represent * a trace, then TCL_ERROR is returned and an error message * is left in the interpreter result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TraceInfoOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { TraceInfo *tracePtr; struct Blt_TupleTraceStruct *tPtr; Blt_HashEntry *hPtr; Tcl_DString dString; char string[5]; char *withTag; char *idString; int i; CONST char **p; idString = Tcl_GetString(objv[3]); hPtr = Blt_FindHashEntry(&cmdPtr->traceTable, idString); if (hPtr == NULL) { Tcl_AppendResult(interp, "unknown trace \"", idString, "\"", (char *)NULL); return TCL_ERROR; } Tcl_DStringInit(&dString); tPtr = tracePtr->trace; tracePtr = Blt_GetHashValue(hPtr); Tcl_DStringAppendElement(&dString, "id"); Tcl_DStringAppendElement(&dString, idString); Tcl_DStringAppendElement(&dString, "tag"); withTag = tPtr->withTag; if (withTag == NULL) { withTag = ""; } Tcl_DStringAppendElement(&dString, withTag); Tcl_DStringAppendElement(&dString, "row"); Tcl_DStringAppendElement(&dString, Blt_Itoa(Blt_TupleRowIndex(tPtr->tuple))); Tcl_DStringAppendElement(&dString, "keys"); Tcl_DStringStartSublist(&dString); for (p = tPtr->keys; *p != NULL; p++) { Tcl_DStringAppendElement(&dString, *p); } Tcl_DStringEndSublist(&dString); Tcl_DStringAppendElement(&dString, "flags"); PrintTraceFlags(tPtr->mask, string); Tcl_DStringAppendElement(&dString, string); Tcl_DStringAppendElement(&dString, "command"); Tcl_DStringStartSublist(&dString); for (i = 0; i < tracePtr->objc; i++) { Tcl_DStringAppendElement(&dString, Tcl_GetString(tracePtr->objv[i])); } Tcl_DStringEndSublist(&dString); Tcl_DStringResult(interp, &dString); return TCL_OK; } /* *---------------------------------------------------------------------- * * TraceNamesOp -- * * Returns the names of all the traces in use by this instance. * Traces created by other instances or object clients are not * reported. * * Results: * Always TCL_OK. A list of trace names is left in the * interpreter result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TraceNamesOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { Blt_HashEntry *hPtr; Blt_HashSearch cursor; for (hPtr = Blt_FirstHashEntry(&cmdPtr->traceTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { Tcl_AppendElement(interp, Blt_GetHashKey(&cmdPtr->traceTable, hPtr)); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TraceOp -- * * This procedure is invoked to process trace operations. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ static Blt_OpSpec traceOps[] = { {"create", 1, (Blt_Op)TraceCreateOp, 7, 7, "tagOrIdx keyList how command",}, {"delete", 1, (Blt_Op)TraceDeleteOp, 3, 0, "traceId...",}, {"info", 1, (Blt_Op)TraceInfoOp, 4, 4, "traceId",}, {"names", 1, (Blt_Op)TraceNamesOp, 3, 3, "",}, }; static int nTraceOps = sizeof(traceOps) / sizeof(Blt_OpSpec); static int TraceOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_Op proc; int result; proc = Blt_GetOpFromObj(interp, nTraceOps, traceOps, BLT_OP_ARG2, objc, objv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (cmdPtr, interp, objc, objv); return result; } /* *---------------------------------------------------------------------- * * UnsetOp -- * * Unsets one or more values. One or more tuples may be unset * (using tags). It's not an error if one of the key names * (columns) doesn't exist. The same holds true for rows. If a * row index is beyond the end of the table (tags are always in * range), it is also ignored. * * Results: * A standard Tcl result. If the tag or index is invalid, * TCL_ERROR is returned and an error message is left in the * interpreter result. * *---------------------------------------------------------------------- */ static int UnsetOp( TupleCmd *cmdPtr, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_Tuple tuple; char *string; string = Tcl_GetString(objv[2]); if (isdigit(UCHAR(*string))) { if (GetTuple(cmdPtr, objv[2], &tuple) != TCL_OK) { return TCL_ERROR; } if (UnsetValues(cmdPtr, tuple, objc - 3, objv + 3) != TCL_OK) { return TCL_ERROR; } } else { Blt_TupleTagSearch cursor; tuple = Blt_TupleFirstTagged(interp, cmdPtr->table, objv[2], &cursor); if (tuple == NULL) { return TCL_ERROR; } for (/* empty */; tuple != NULL; tuple = Blt_TupleNextTagged(&cursor)) { if (UnsetValues(cmdPtr, tuple, objc - 3, objv + 3) != TCL_OK) { return TCL_ERROR; } } } return TCL_OK; } /* * -------------------------------------------------------------- * * TupleInstObjCmd -- * * This procedure is invoked to process commands on behalf of * the instance of the tuple-object. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * * -------------------------------------------------------------- */ static Blt_OpSpec tupleOps[] = { {"attach", 2, (Blt_Op)AttachOp, 2, 3, "?tupleCmd?",}, {"delete", 2, (Blt_Op)DeleteOp, 3, 0, "tagOrIdx ?tagOrIdx...?",}, {"exists", 1, (Blt_Op)ExistsOp, 3, 4, "tagOrIdx ?key?",}, {"get", 1, (Blt_Op)GetOp, 3, 5, "tagOrIdx ?key? ?defaultValue?",}, {"notify", 2, (Blt_Op)NotifyOp, 2, 0, "args...",}, {"set", 3, (Blt_Op)SetOp, 3, 0, "tagOrIdx ?key value...?",}, {"tag", 2, (Blt_Op)TagOp, 3, 0, "args...",}, {"trace", 2, (Blt_Op)TraceOp, 2, 0, "args...",}, {"unset", 3, (Blt_Op)UnsetOp, 3, 0, "tagOrIdx ?key...?",}, #ifdef notdef {"-ancestor", 2, (Blt_Op)AncestorOp, 4, 4, "node1 node2",}, {"-apply", 1, (Blt_Op)ApplyOp, 3, 0, "first last ?switches?",}, {"column", 2, (Blt_Op)ColumnOp, 2, 0, "args...", }, {"copy", 2, (Blt_Op)CopyOp, 4, 0, "srcNode ?destTuple? destNode ?switches?",}, {"dump", 4, (Blt_Op)DumpOp, 3, 3, "first ?last?",}, {"dumpfile", 5, (Blt_Op)DumpfileOp, 4, 4, "first ?last? fileName",}, {"find", 4, (Blt_Op)FindOp, 3, 0, "node ?switches?",}, {"index", 3, (Blt_Op)IndexOp, 3, 3, "name",}, {"insert", 3, (Blt_Op)InsertOp, 3, 0, "parent ?switches?",}, {"-is", 2, (Blt_Op)IsOp, 2, 0, "oper args...",}, {"keys", 1, (Blt_Op)KeysOp, 3, 0, "node ?node...?",}, {"-label", 3, (Blt_Op)LabelOp, 3, 4, "node ?newLabel?",}, {"move", 1, (Blt_Op)MoveOp, 4, 0, "node newParent ?switches?",}, {"-next", 4, (Blt_Op)NextOp, 3, 3, "node",}, {"-position", 2, (Blt_Op)PositionOp, 3, 0, "?switches? node...",}, {"-previous", 5, (Blt_Op)PreviousOp, 3, 3, "node",}, {"range", 2, (Blt_Op)ChildrenOp, 4, 4, "first last",}, {"restore", 7, (Blt_Op)RestoreOp, 4, 4, "node dataString",}, {"restorefile", 8, (Blt_Op)RestorefileOp, 4, 4, "node fileName",}, {"width", 2, (Blt_Op)SizeOp, 3, 3, "?newWidth?",}, {"length", 2, (Blt_Op)SizeOp, 3, 3, "?newLength?",}, {"sort", 2, (Blt_Op)SortOp, 3, 0, "?flags...?",}, {"type", 2, (Blt_Op)TypeOp, 4, 4, "key",}, #endif }; static int nTupleOps = sizeof(tupleOps) / sizeof(Blt_OpSpec); static int TupleInstObjCmd( ClientData clientData, /* Pointer to the command structure. */ Tcl_Interp *interp, /* Interpreter to report errors back to. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST *objv) /* Vector of argument strings. */ { Blt_Op proc; TupleCmd *cmdPtr = clientData; int result; proc = Blt_GetOpFromObj(interp, nTupleOps, tupleOps, BLT_OP_ARG1, objc, objv, BLT_OP_LINEAR_SEARCH); if (proc == NULL) { return TCL_ERROR; } Tcl_Preserve(cmdPtr); result = (*proc) (cmdPtr, interp, objc, objv); Tcl_Release(cmdPtr); return result; } /* * ---------------------------------------------------------------------- * * TupleInstDeleteProc -- * * Deletes the command associated with the tuple. This is * called only when the command associated with the tuple is * destroyed. * * Results: * None. * * Side Effects: * The tuple object is released and bookkeeping data for traces * and notifiers are freed. * * ---------------------------------------------------------------------- */ static void TupleInstDeleteProc(ClientData clientData) { TupleCmd *cmdPtr = clientData; Blt_HashEntry *hPtr; Blt_HashSearch cursor; TraceInfo *tracePtr; NotifyInfo *notifyPtr; if (cmdPtr->hashPtr != NULL) { Blt_DeleteHashEntry(cmdPtr->instTablePtr, cmdPtr->hashPtr); } for (hPtr = Blt_FirstHashEntry(&cmdPtr->traceTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { tracePtr = Blt_GetHashValue(hPtr); DeleteTrace(tracePtr); } Blt_DeleteHashTable(&cmdPtr->traceTable); for (hPtr = Blt_FirstHashEntry(&cmdPtr->notifyTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { notifyPtr = Blt_GetHashValue(hPtr); DeleteNotifier(notifyPtr); } Tcl_DecrRefCount(cmdPtr->emptyObjPtr); Blt_DeleteHashTable(&cmdPtr->notifyTable); Blt_TupleReleaseTable(cmdPtr->table); Blt_Free(cmdPtr); } /* *---------------------------------------------------------------------- * * TupleCreateOp -- * * Creates a new instance of a tuple object. This routine * ensures that instance and object names are the same. For * example, you can't create an instance with the name of an * object that already exists. And because each instance has a * Tcl command associated with it that is used to access the * object, we also check more generally that is it also not the * name of an existing Tcl command. * * Instance names as namespace-qualified. If no namespace is * designated, it is assumed that instance is to be created in * the current namespace (not the global namespace). * * Results: * A standard Tcl result. If the instance is successfully created, * the namespace-qualified name of the instance is returned. If not, * then TCL_ERROR is returned and an error message is left in the * interpreter result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TupleCreateOp( ClientData clientData, /* Interpreter-specific data. */ Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { TupleCmdInterpData *interpDataPtr = clientData; CONST char *instName; Tcl_DString dString; Blt_TupleTable table; instName = NULL; if (objc == 3) { instName = Tcl_GetString(objv[2]); } Tcl_DStringInit(&dString); if (instName == NULL) { instName = GenerateName(interp, "", "", &dString); } else { char *p; p = strstr(instName, "#auto"); if (p != NULL) { *p = '\0'; instName = GenerateName(interp, instName, p + 5, &dString); *p = '#'; } else { CONST char *name; Tcl_CmdInfo cmdInfo; Tcl_Namespace *nsPtr; nsPtr = NULL; /* * Parse the command and put back so that it's in a consistent * format. * * t1 ::t1 * n1::t1 ::n1::t1 * ::t1 ::t1 * ::n1::t1 ::n1::t1 */ if (Blt_ParseQualifiedName(interp, instName, &nsPtr, &name) != TCL_OK) { Tcl_AppendResult(interp, "can't find namespace in \"", instName, "\"", (char *)NULL); return TCL_ERROR; } if (nsPtr == NULL) { nsPtr = Tcl_GetCurrentNamespace(interp); } instName = Blt_GetQualifiedName(nsPtr, name, &dString); /* * Check if the command already exists. */ if (Tcl_GetCommandInfo(interp, (char *)instName, &cmdInfo)) { Tcl_AppendResult(interp, "a command \"", instName, "\" already exists", (char *)NULL); goto error; } if (Blt_TupleTableExists(interp, instName)) { Tcl_AppendResult(interp, "a tuple \"", instName, "\" already exists", (char *)NULL); goto error; } } } if (instName == NULL) { goto error; } if (Blt_TupleCreateTable(interp, instName, &table) == TCL_OK) { TupleCmd *cmdPtr; cmdPtr = NewTupleCmd(interp, interpDataPtr, table, instName); Tcl_SetResult(interp, (char *)instName, TCL_VOLATILE); Tcl_DStringFree(&dString); return TCL_OK; } error: Tcl_DStringFree(&dString); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TupleDestroyOp -- * * Deletes one or more instances of tuple objects. The deletion * process is done by deleting the Tcl command associated with * the object. * * Results: * A standard Tcl result. If one of the names given doesn't * represent an instance, TCL_ERROR is returned and an error * message is left in the interpreter result. * *---------------------------------------------------------------------- */ static int TupleDestroyOp( ClientData clientData, /* Interpreter-specific data. */ Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { TupleCmdInterpData *interpDataPtr = clientData; TupleCmd *cmdPtr; char *string; register int i; for (i = 2; i < objc; i++) { string = Tcl_GetString(objv[i]); cmdPtr = GetTupleCmd(interpDataPtr, interp, string); if (cmdPtr == NULL) { Tcl_AppendResult(interp, "can't find a tuple named \"", string, "\"", (char *)NULL); return TCL_ERROR; } Tcl_DeleteCommandFromToken(interp, cmdPtr->cmdToken); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TupleNamesOp -- * * Returns the names of all the tuple-object instances matching a * given pattern. If no pattern argument is provided, then all * object names are returned. The names returned are namespace * qualified. * * Results: * Always returns TCL_OK. The names of the matching objects is * returned via the interpreter result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int TupleNamesOp( ClientData clientData, /* Interpreter-specific data. */ Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { TupleCmdInterpData *interpDataPtr = clientData; TupleCmd *cmdPtr; Blt_HashEntry *hPtr; Blt_HashSearch cursor; Tcl_Obj *objPtr, *listObjPtr; Tcl_DString dString; char *qualName; Tcl_DStringInit(&dString); listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); for (hPtr = Blt_FirstHashEntry(&interpDataPtr->instTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { cmdPtr = Blt_GetHashValue(hPtr); qualName = Blt_GetQualifiedName( Blt_GetCommandNamespace(interp, cmdPtr->cmdToken), Tcl_GetCommandName(interp, cmdPtr->cmdToken), &dString); if (objc == 3) { if (!Tcl_StringMatch(qualName, Tcl_GetString(objv[2]))) { continue; } } objPtr = Tcl_NewStringObj(qualName, -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } Tcl_SetObjResult(interp, listObjPtr); Tcl_DStringFree(&dString); return TCL_OK; } /* *---------------------------------------------------------------------- * * TupleObjCmd -- * *---------------------------------------------------------------------- */ static Blt_OpSpec tupleCmdOps[] = { {"create", 1, (Blt_Op)TupleCreateOp, 2, 3, "?name?",}, {"destroy", 1, (Blt_Op)TupleDestroyOp, 3, 0, "name...",}, {"names", 1, (Blt_Op)TupleNamesOp, 2, 3, "?pattern?...",}, }; static int nCmdOps = sizeof(tupleCmdOps) / sizeof(Blt_OpSpec); /*ARGSUSED*/ static int TupleObjCmd( ClientData clientData, /* Interpreter-specific data. */ Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_Op proc; proc = Blt_GetOpFromObj(interp, nCmdOps, tupleCmdOps, BLT_OP_ARG1, objc, objv, 0); if (proc == NULL) { return TCL_ERROR; } return (*proc) (clientData, interp, objc, objv); } /* * ----------------------------------------------------------------------- * * TupleInterpDeleteProc -- * * This is called when the interpreter hosting the "tuple" command * is deleted. * * Results: * None. * * Side effects: * Removes the hash table managing all tuple names. * * ------------------------------------------------------------------------ */ /* ARGSUSED */ static void TupleInterpDeleteProc( ClientData clientData, /* Interpreter-specific data. */ Tcl_Interp *interp) { TupleCmdInterpData *interpDataPtr = clientData; /* All tuple instances should already have been destroyed when * their respective Tcl commands were deleted. */ Blt_DeleteHashTable(&interpDataPtr->instTable); Tcl_DeleteAssocData(interp, TUPLE_THREAD_KEY); Blt_Free(interpDataPtr); } /* * ----------------------------------------------------------------------- * * Blt_TupleInit -- * * This procedure is invoked to initialize the "tuple" command. * * Results: * None. * * Side effects: * Creates the new command and adds a new entry into a global Tcl * associative array. * * ------------------------------------------------------------------------ */ int Blt_TupleInit(Tcl_Interp *interp) { TupleCmdInterpData *interpDataPtr; /* Interpreter-specific data. */ static Blt_ObjCmdSpec cmdSpec = { "tuple", TupleObjCmd, }; interpDataPtr = GetTupleCmdInterpData(interp); cmdSpec.clientData = interpDataPtr; if (Blt_InitObjCmd(interp, "blt", &cmdSpec) == NULL) { return TCL_ERROR; } return TCL_OK; } int Blt_TupleCmdGetToken( Tcl_Interp *interp, CONST char *string, Blt_TupleTable *tablePtr) { TupleCmdInterpData *interpDataPtr; TupleCmd *cmdPtr; interpDataPtr = GetTupleCmdInterpData(interp); cmdPtr = GetTupleCmd(interpDataPtr, interp, string); if (cmdPtr == NULL) { Tcl_AppendResult(interp, "can't find a tuple object associated with \"", string, "\"", (char *)NULL); return TCL_ERROR; } *tablePtr = cmdPtr->table; return TCL_OK; } /* Dump tuple to dbm */ /* Convert node data to datablock */ #endif /* NO_TUPLE */ blt-2.4z.orig/src/bltUnixDnd.c0100644000175000017500000045452107514140430014763 0ustar dokodoko /* * bltUnixDnd.c -- * * This module implements a drag-and-drop manager for the BLT * Toolkit. Allows widgets to be registered as drag&drop sources * and targets for handling "drag-and-drop" operations between * Tcl/Tk applications. * * Copyright 1993-1998 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. * * The "drag&drop" command was created by Michael J. McLennan. */ #include "bltInt.h" #ifndef NO_DRAGDROP #include #include #include #include #define DND_THREAD_KEY "BLT Dnd Data" #define DND_SELECTED (1<<0) #define DND_INITIATED (1<<1) #define DND_ACTIVE (DND_SELECTED | DND_INITIATED) #define DND_IN_PACKAGE (1<<2) /* Indicates if a token package command is * currently active. The user may invoke * "update" or "tkwait" commands from within * the package command script. This allows the * "drag" operation to preempt itself. */ #define DND_VOIDED (1<<3) #define DND_DELETED (1<<4) #define PACK(lo,hi) (((hi) << 16) | ((lo) & 0x0000FFFF)) #define UNPACK(x,lo,hi) ((lo) = (x & 0x0000FFFF), (hi) = (x >> 16)) #define WATCH_ENTER (1<<0) #define WATCH_LEAVE (1<<1) #define WATCH_MOTION (1<<2) #define WATCH_MASK (WATCH_ENTER | WATCH_LEAVE | WATCH_MOTION) /* Source-to-Target Message Types */ #define ST_DRAG_ENTER 0x1001 #define ST_DRAG_LEAVE 0x1002 #define ST_DRAG_MOTION 0x1003 #define ST_DROP 0x1004 /* Target-to-Source Message Types */ #define TS_DRAG_STATUS 0x1005 #define TS_START_DROP 0x1006 #define TS_DROP_RESULT 0x1007 /* Indices of information fields in ClientMessage array. */ #define MESG_TYPE 0 /* Message type. */ #define MESG_WINDOW 1 /* Window id of remote. */ #define MESG_TIMESTAMP 2 /* Transaction timestamp. */ #define MESG_POINT 3 /* Root X-Y coordinate. */ #define MESG_STATE 4 /* Button and key state. */ #define MESG_RESPONSE 3 /* Response to drag/drop message. */ #define MESG_FORMAT 3 /* Format atom. */ #define MESG_PROPERTY 4 /* Index of button #/key state. */ /* Drop Status Values (actions included) */ #define DROP_CONTINUE -2 #define DROP_FAIL -1 #define DROP_CANCEL 0 #define DROP_OK 1 #define DROP_COPY 1 #define DROP_LINK 2 #define DROP_MOVE 3 #define PROP_WATCH_FLAGS 0 #define PROP_DATA_FORMATS 1 #define PROP_MAX_SIZE 1000 /* Maximum size of property. */ #define PROTO_BLT 0 #define PROTO_XDND 1 #define TOKEN_OFFSET 0 #define TOKEN_REDRAW (1<<0) #define TOKEN_NORMAL 0 #define TOKEN_REJECT -1 #define TOKEN_ACTIVE 1 #define TOKEN_TIMEOUT 5000 /* 5 second timeout for drop requests. */ /* * Each widget representing a drag & drop target is tagged with * a "BltDndTarget" property in XA_STRING format. This property * identifies the window as a target. It's formated as a Tcl list * and contains the following information: * * "flags DATA_TYPE DATA_TYPE ..." * * "INTERP_NAME TARGET_NAME WINDOW_ID DATA_TYPE DATA_TYPE ..." * * INTERP_NAME Name of the target application's interpreter. * TARGET_NAME Path name of widget registered as the drop target. * WINDOW_ID Window Id of the target's communication window. * Used to forward Enter/Leave/Motion event information * to the target. * DATA_TYPE One or more "types" handled by the target. * * When the user invokes the "drag" operation, the window hierarchy * is progressively examined. Window information is cached during * the operation, to minimize X server traffic. Windows carrying a * "BltDndTarget" property are identified. When the token is dropped * over a valid site, the drop information is sent to the application * via the usual "send" command. If communication fails, the drag&drop * facility automatically posts a rejection symbol on the token window. */ /* * Drop Protocol: * * Source Target * ------ ------ * ButtonRelease-? event. * Invokes blt::dnd drop * + * Send "drop" message to target (via * ClientMessage). Contains X-Y, key/ --> Gets "drop" message. * button state, source window XID. Invokes LeaveCmd proc. * Gets property from source of * ordered matching formats. * + * Invokes DropCmd proc. Arguments * are X-Y coordinate, key/button * state, transaction timestamp, * list of matching formats. * + * Target selects format and invokes * blt::dnd pull to transfer the data * in the selected format. * + * Sends "drop start" message to * source. Contains selected format * Gets "drop start" message. <-- (as atom), ?action?, target window * Invokes data handler for the ID, transaction timestamp. * selected format. + * + Waits for property to change on * Places first packet of data in its window. Time out set for * property on target window. --> no response. * + + * Waits for response property After each packet, sets zero-length * change. Time out set for no resp. <-- property on source window. * If non-zero length packet, error + * occurred, packet is error message. Sends "drop finished" message. * Contains transaction timestamp, * Gets "drop finished" message. <-- status, ?action?. * Invokes FinishCmd proc. */ /* Configuration Parameters */ #define DEF_DND_BUTTON_BACKGROUND RGB_YELLOW #define DEF_DND_BUTTON_BG_MONO STD_NORMAL_BG_MONO #define DEF_DND_BUTTON_NUMBER "3" #define DEF_DND_ENTER_COMMAND (char *)NULL #define DEF_DND_LEAVE_COMMAND (char *)NULL #define DEF_DND_MOTION_COMMAND (char *)NULL #define DEF_DND_DROP_COMMAND (char *)NULL #define DEF_DND_RESULT_COMMAND (char *)NULL #define DEF_DND_PACKAGE_COMMAND (char *)NULL #define DEF_DND_SELF_TARGET "no" #define DEF_DND_SEND (char *)NULL #define DEF_DND_IS_TARGET "no" #define DEF_DND_IS_SOURCE "no" #define DEF_DND_SITE_COMMAND (char *)NULL #define DEF_DND_DRAG_THRESHOLD "0" #define DEF_TOKEN_ACTIVE_BACKGROUND STD_ACTIVE_BACKGROUND #define DEF_TOKEN_ACTIVE_BG_MONO STD_ACTIVE_BG_MONO #define DEF_TOKEN_ACTIVE_BORDERWIDTH "3" #define DEF_TOKEN_ACTIVE_RELIEF "sunken" #define DEF_TOKEN_ANCHOR "se" #define DEF_TOKEN_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_TOKEN_BG_MONO STD_NORMAL_BG_MONO #define DEF_TOKEN_BORDERWIDTH "3" #define DEF_TOKEN_CURSOR "top_left_arrow" #define DEF_TOKEN_REJECT_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_TOKEN_REJECT_BG_MONO RGB_WHITE #define DEF_TOKEN_REJECT_FOREGROUND RGB_RED #define DEF_TOKEN_REJECT_FG_MONO RGB_BLACK #define DEF_TOKEN_REJECT_STIPPLE_COLOR (char *)NULL #define DEF_TOKEN_REJECT_STIPPLE_MONO RGB_GREY50 #define DEF_TOKEN_RELIEF "raised" static int StringToCursors _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *string, char *widgRec, int offset)); static char *CursorsToString _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, char *widgRec, int offset, Tcl_FreeProc **freeProcPtr)); Tk_CustomOption cursorsOption = { StringToCursors, CursorsToString, (ClientData)0 }; typedef struct { Blt_HashTable dndTable; /* Hash table of dnd structures keyed by * the address of the reference Tk window */ Tk_Window mainWindow; Display *display; Atom mesgAtom; /* Atom signifying a drag-and-drop message. */ Atom formatsAtom; /* Source formats property atom. */ Atom targetAtom; /* Target property atom. */ Atom commAtom; /* Communication property atom. */ #ifdef HAVE_XDND Blt_HashTable handlerTable; /* Table of toplevel windows with XdndAware * properties attached to them. */ Atom XdndActionListAtom; Atom XdndAwareAtom; Atom XdndEnterAtom; Atom XdndFinishedAtom; Atom XdndLeaveAtom; Atom XdndPositionAtom; Atom XdndSelectionAtom; Atom XdndStatusAtom; Atom XdndTypeListAtom; Atom XdndActionCopyAtom; Atom XdndActionMoveAtom; Atom XdndActionLinkAtom; Atom XdndActionAskAtom; Atom XdndActionPrivateAtom; Atom XdndActionDescriptionAtom; #endif } DndInterpData; typedef struct { Tcl_DString dString; Window window; /* Source/Target window */ Display *display; Atom commAtom; /* Data communication property atom. */ int packetSize; Tcl_TimerToken timerToken; int status; /* Status of transaction: CONTINUE, OK, FAIL, * or TIMEOUT. */ int timestamp; /* Timestamp of the transaction. */ int offset; int protocol; /* Drag-and-drop protocol used by the source: * either PROTO_BLT or PROTO_XDND. */ } DropPending; /* * SubstDescriptors -- * * Structure to hold letter-value pairs for percent substitutions. */ typedef struct { char letter; /* character like 'x' in "%x" */ char *value; /* value to be substituted in place of "%x" */ } SubstDescriptors; /* * Drag&Drop Registration Data */ typedef struct { Tk_Window tkwin; /* Window that embodies the token. NULL * means that the window has been destroyed * but the data structures haven't yet been * cleaned up. */ Display *display; /* Display containing widget. Used, among * other things, so that resources can be * freed even after tkwin has gone away. */ Tcl_Interp *interp; /* Interpreter associated with widget. Used * to delete widget command. */ Tk_3DBorder border; /* Structure used to draw 3-D border and * background. NULL means no background * or border. */ int borderWidth; /* Width of 3-D border (if any). */ int relief; /* 3-d effect: TK_RELIEF_RAISED etc. */ int flags; /* Various flags; see below for * definitions. */ /* Token specific fields */ int x, y; /* Last position of token window */ int startX, startY; int status; /* Indicates the current status of the token: * 0 is normal, 1 is active. */ int lastStatus; /* Indicates the last status of the token. */ Tcl_TimerToken timerToken; /* Token for routine to hide tokenwin */ GC fillGC; /* GC used to draw rejection fg: (\) */ GC outlineGC; /* GC used to draw rejection bg: (\) */ int width, height; /* User-configurable fields */ Tk_Anchor anchor; /* Position of token win relative to mouse */ Tk_3DBorder normalBorder; /* Border/background for token window */ Tk_3DBorder activeBorder; /* Border/background for token window */ int activeRelief; int activeBorderWidth; /* Border width in pixels */ XColor *fillColor; /* Color used to draw rejection fg: (\) */ XColor *outlineColor; /* Color used to draw rejection bg: (\) */ Pixmap rejectStipple; /* Stipple used to draw rejection: (\) */ int reqWidth, reqHeight; int nSteps; } Token; /* * Winfo -- * * This structure represents a window hierarchy examined during a single * "drag" operation. It's used to cache information to reduce the round * trip calls to the server needed to query window geometry information * and grab the target property. */ typedef struct WinfoStruct { Window window; /* Window in hierarchy. */ int initialized; /* If zero, the rest of this structure's * information hasn't been set. */ int x1, y1, x2, y2; /* Extents of the window (upper-left and * lower-right corners). */ struct WinfoStruct *parentPtr; /* Parent node. NULL if root. Used to * compute offset for X11 windows. */ Blt_Chain *chainPtr; /* List of this window's children. If NULL, * there are no children. */ int isTarget; /* Indicates if this window is a drag&drop * target. */ int lookedForProperty; /* Indicates if this window */ int eventFlags; /* Retrieved from the target's drag&drop * property, indicates what kinds of pointer * events should be relayed to the target via * ClientMessages. Possible values are OR-ed * combinations of the following bits: * 001 Enter events. * 010 Motion events. * 100 Leave events. */ char *matches; } Winfo; /* * Dnd -- * * This structure represents the drag&drop manager. It is associated * with a widget as a drag&drop source, target, or both. It contains * both the source and target components, since a widget can be both * a drag source and a drop target. */ typedef struct { Tcl_Interp *interp; /* Interpreter associated with the drag&drop * manager. */ Tk_Window tkwin; /* Tk window representing the drag&drop * manager (can be source and/or target). */ Display *display; /* Display for drag&drop widget. Saved to free * resources after window has been destroyed. */ int isSource; /* Indicates if this drag&drop manager can act * as a drag source. */ int isTarget; /* Indicates if this drag&drop manager can act * as a drop target. */ int targetPropertyExists; /* Indicates is the drop target property has * been set. */ unsigned int flags; /* Various flags; see below for * definitions. */ int timestamp; /* Id of the current drag&drop transaction. */ int x, y; /* Last known location of the mouse pointer. */ Blt_HashEntry *hashPtr; DndInterpData *dataPtr; /* Source component. */ Blt_HashTable getDataTable; /* Table of data handlers (converters) * registered for this source. */ int reqButton; /* Button used to invoke drag operation. */ int button; /* Last button press detected. */ int keyState; /* Last key state. */ Tk_Cursor cursor; /* Cursor restored after dragging */ int selfTarget; /* Indicated if the source should drop onto * itself. */ char **reqFormats; /* List of requested data formats. The * list should be ordered with the more * desireable formats first. You can also * temporarily turn off a source by setting * the value to the empty string. */ Winfo *rootPtr; /* Cached window information: Gathered * and used during the "drag" operation * to see if the mouse pointer is over a * valid target. */ Winfo *windowPtr; /* Points to information about the last * target the pointer was over. If NULL, * the pointer was not over a valid target. */ char **packageCmd; /* Tcl command executed at start of the drag * operation to initialize token. */ char **resultCmd; /* Tcl command executed at the end of the * "drop" operation to indicate its status. */ char **siteCmd; /* Tcl command executed to update token * window. */ Token *tokenPtr; /* Token used to provide special cursor. */ Tcl_TimerToken timerToken; Tk_Cursor *cursors; /* Array of drag-and-drop cursors. */ int cursorPos; int dragStart; /* Minimum number of pixels movement * before B1-Motion is considered to * start dragging. */ /* Target component. */ Blt_HashTable setDataTable; /* Table of data handlers (converters) * registered for this target. */ char **enterCmd; /* Tcl proc called when the mouse enters the * target. */ char **leaveCmd; /* Tcl proc called when the mouse leaves the * target. */ char **motionCmd; /* Tcl proc called when the mouse is moved * over the target. */ char **dropCmd; /* Tcl proc called when the mouse button * is released over the target. */ char *matchingFormats; int lastId; /* The last transaction id used. This is used * to cache the above formats string. */ DropPending *pendingPtr; /* Points to structure containing information * about a current drop in progress. If NULL, * no drop is in progress. */ short int dropX, dropY; /* Location of the current drop. */ short int dragX, dragY; /* Starting position of token window */ } Dnd; typedef struct { Tk_Window tkwin; /* Toplevel window of the drop target. */ int refCount; /* # of targets referencing this structure. */ Dnd *dndPtr; /* Last drop target selected. Used the * implement Enter/Leave events for targets. * If NULL, indicates that no drop target was * previously selected. */ int lastRepsonse; /* Indicates what the last response was. */ Window window; /* Window id of the top-level window (ie. * the wrapper). */ char **formatArr; /* List of formats available from source. * Must be pruned down to matching list. */ DndInterpData *dataPtr; int x, y; } XDndHandler; extern Tk_CustomOption bltListOption; extern Tk_CustomOption bltDistanceOption; static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_CUSTOM, "-allowformats", "allowFormats", "AllowFormats", DEF_DND_SEND, Tk_Offset(Dnd, reqFormats), TK_CONFIG_NULL_OK, &bltListOption}, {TK_CONFIG_INT, "-button", "buttonNumber", "ButtonNumber", DEF_DND_BUTTON_NUMBER, Tk_Offset(Dnd, reqButton), 0}, {TK_CONFIG_CUSTOM, "-dragthreshold", "dragThreshold", "DragThreshold", DEF_DND_DRAG_THRESHOLD, Tk_Offset(Dnd, dragStart), 0, &bltDistanceOption}, {TK_CONFIG_CUSTOM, "-cursors", "cursors", "cursors", DEF_TOKEN_CURSOR, Tk_Offset(Dnd, cursors), TK_CONFIG_NULL_OK, &cursorsOption }, {TK_CONFIG_CUSTOM, "-onenter", "onEnter", "OnEnter", DEF_DND_ENTER_COMMAND, Tk_Offset(Dnd, enterCmd), TK_CONFIG_NULL_OK, &bltListOption}, {TK_CONFIG_CUSTOM, "-onmotion", "onMotion", "OnMotion", DEF_DND_MOTION_COMMAND, Tk_Offset(Dnd, motionCmd), TK_CONFIG_NULL_OK, &bltListOption}, {TK_CONFIG_CUSTOM, "-onleave", "onLeave", "OnLeave", DEF_DND_LEAVE_COMMAND, Tk_Offset(Dnd, leaveCmd), TK_CONFIG_NULL_OK, &bltListOption}, {TK_CONFIG_CUSTOM, "-ondrop", "onDrop", "OnDrop", DEF_DND_DROP_COMMAND, Tk_Offset(Dnd, dropCmd), TK_CONFIG_NULL_OK, &bltListOption}, {TK_CONFIG_CUSTOM, "-package", "packageCommand", "PackageCommand", DEF_DND_PACKAGE_COMMAND, Tk_Offset(Dnd, packageCmd), TK_CONFIG_NULL_OK, &bltListOption }, {TK_CONFIG_CUSTOM, "-result", "result", "Result", DEF_DND_RESULT_COMMAND, Tk_Offset(Dnd, resultCmd), TK_CONFIG_NULL_OK, &bltListOption}, {TK_CONFIG_BOOLEAN, "-selftarget", "selfTarget", "SelfTarget", DEF_DND_SELF_TARGET, Tk_Offset(Dnd, selfTarget), 0}, {TK_CONFIG_CUSTOM, "-site", "siteCommand", "Command", DEF_DND_SITE_COMMAND, Tk_Offset(Dnd, siteCmd), TK_CONFIG_NULL_OK, &bltListOption}, {TK_CONFIG_BOOLEAN, "-source", "source", "Source", DEF_DND_IS_SOURCE, Tk_Offset(Dnd, isSource), 0}, {TK_CONFIG_BOOLEAN, "-target", "target", "Target", DEF_DND_IS_TARGET, Tk_Offset(Dnd, isTarget), 0}, {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0}, }; static Tk_ConfigSpec tokenConfigSpecs[] = { {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "ActiveBackground", DEF_TOKEN_ACTIVE_BACKGROUND, Tk_Offset(Token, activeBorder), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "ActiveBackground", DEF_TOKEN_ACTIVE_BG_MONO, Tk_Offset(Token, activeBorder), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_RELIEF, "-activerelief", "activeRelief", "activeRelief", DEF_TOKEN_ACTIVE_RELIEF, Tk_Offset(Token, activeRelief), 0}, {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", DEF_TOKEN_ANCHOR, Tk_Offset(Token, anchor), 0}, {TK_CONFIG_PIXELS, "-activeborderwidth", "activeBorderWidth", "ActiveBorderWidth", DEF_TOKEN_ACTIVE_BORDERWIDTH, Tk_Offset(Token, activeBorderWidth), 0}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_TOKEN_BACKGROUND, Tk_Offset(Token, normalBorder), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_TOKEN_BG_MONO, Tk_Offset(Token, normalBorder), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", DEF_TOKEN_BORDERWIDTH, Tk_Offset(Token, borderWidth), 0}, {TK_CONFIG_COLOR, "-outline", "outline", "Outline", DEF_TOKEN_REJECT_BACKGROUND, Tk_Offset(Token, outlineColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-outline", "outline", "Outline", DEF_TOKEN_REJECT_BG_MONO, Tk_Offset(Token, outlineColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-fill", "fill", "Fill", DEF_TOKEN_REJECT_FOREGROUND, Tk_Offset(Token, fillColor), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-fill", "fill", "Fill", DEF_TOKEN_REJECT_BACKGROUND, Tk_Offset(Token, fillColor), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_BITMAP, "-rejectstipple", "rejectStipple", "Stipple", DEF_TOKEN_REJECT_STIPPLE_COLOR, Tk_Offset(Token, rejectStipple), TK_CONFIG_COLOR_ONLY | TK_CONFIG_NULL_OK}, {TK_CONFIG_BITMAP, "-rejectstipple", "rejectStipple", "Stipple", DEF_TOKEN_REJECT_STIPPLE_MONO, Tk_Offset(Token, rejectStipple), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_TOKEN_RELIEF, Tk_Offset(Token, relief), 0}, {TK_CONFIG_INT, "-width", "width", "Width", (char *)NULL, Tk_Offset(Token, reqWidth), 0}, {TK_CONFIG_INT, "-height", "height", "Height", (char *)NULL, Tk_Offset(Token, reqHeight), 0}, {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0}, }; /* * Forward Declarations */ static int DndCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, char **argv)); static void TokenEventProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); static void MoveToken _ANSI_ARGS_((Dnd *dndPtr)); static void DisplayToken _ANSI_ARGS_((ClientData clientData)); static void HideToken _ANSI_ARGS_((Dnd *dndPtr)); static void DrawRejectSymbol _ANSI_ARGS_((Dnd *dndPtr)); static int GetDnd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, char *name, Dnd **dndPtrPtr)); static Dnd *CreateDnd _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin)); static void DestroyDnd _ANSI_ARGS_((DestroyData data)); static int DndEventProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); static int ConfigureToken _ANSI_ARGS_((Tcl_Interp *interp, Dnd *dndPtr, int argc, char **argv, int flags)); static Winfo *OverTarget _ANSI_ARGS_((Dnd *dndPtr)); static void AddTargetProperty _ANSI_ARGS_((Dnd *dndPtr)); static Winfo *InitRoot _ANSI_ARGS_((Dnd *dndPtr)); static void FreeWinfo _ANSI_ARGS_((Winfo *wr)); static void GetWinfo _ANSI_ARGS_((Display *display, Winfo * windowPtr)); static void CancelDrag _ANSI_ARGS_((Dnd *dndPtr)); /* * ---------------------------------------------------------------------------- * * StringToCursors -- * * Converts the resize mode into its numeric representation. Valid * mode strings are "none", "expand", "shrink", or "both". * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ static int StringToCursors(clientData, interp, tkwin, string, widgRec, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter to send results back to */ Tk_Window tkwin; /* Not used. */ char *string; /* String representing cursors. */ char *widgRec; /* Structure record */ int offset; /* Offset of field in record. */ { Tk_Cursor **cursorPtrPtr = (Tk_Cursor **)(widgRec + offset); int result = TCL_OK; int nElems; char **elemArr; if (*cursorPtrPtr != NULL) { Blt_Free(*cursorPtrPtr); *cursorPtrPtr = NULL; } if (string == NULL) { return TCL_OK; } if (Tcl_SplitList(interp, string, &nElems, &elemArr) != TCL_OK) { return TCL_ERROR; } if (nElems > 0) { Tk_Cursor *cursorArr; register int i; cursorArr = Blt_Calloc(nElems + 1, sizeof(Tk_Cursor)); for (i = 0; i < nElems; i++) { cursorArr[i] = Tk_GetCursor(interp, tkwin, Tk_GetUid(elemArr[i])); if (cursorArr[i] == None) { *cursorPtrPtr = cursorArr; result = TCL_ERROR; break; } } Blt_Free(elemArr); *cursorPtrPtr = cursorArr; } return result; } /* * ---------------------------------------------------------------------------- * * CursorsToString -- * * Returns resize mode string based upon the resize flags. * * Results: * The resize mode string is returned. * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ static char * CursorsToString(clientData, tkwin, widgRec, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Not used. */ char *widgRec; /* Cursor record */ int offset; /* Offset of record. */ Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */ { Tk_Cursor *cursorArr = *(Tk_Cursor **)(widgRec + offset); Tk_Cursor *cursorPtr; Tcl_DString dString; char *result; if (cursorArr == NULL) { return ""; } Tcl_DStringInit(&dString); for (cursorPtr = cursorArr; *cursorPtr != NULL; cursorPtr++) { Tcl_DStringAppendElement(&dString, Tk_NameOfCursor(Tk_Display(tkwin), *cursorPtr)); } result = Blt_Strdup(Tcl_DStringValue(&dString)); Tcl_DStringFree(&dString); *freeProcPtr = (Tcl_FreeProc *)Blt_Free; return result; } static char * PrintList(list) char **list; { int count; char **p; count = 0; for(p = list; *p != NULL; p++) { count++; } return Tcl_Merge(count, list); } /* ARGSUSED */ static int XSendEventErrorProc(clientData, errEventPtr) ClientData clientData; XErrorEvent *errEventPtr; { int *errorPtr = clientData; *errorPtr = TCL_ERROR; return 0; } static void SendClientMsg(display, window, mesgAtom, data0, data1, data2, data3, data4) Display *display; Window window; Atom mesgAtom; int data0, data1, data2, data3, data4; { XEvent event; Tk_ErrorHandler handler; int result; int any = -1; event.xclient.type = ClientMessage; event.xclient.serial = 0; event.xclient.send_event = True; event.xclient.display = display; event.xclient.window = window; event.xclient.message_type = mesgAtom; event.xclient.format = 32; event.xclient.data.l[0] = data0; event.xclient.data.l[1] = data1; event.xclient.data.l[2] = data2; event.xclient.data.l[3] = data3; event.xclient.data.l[4] = data4; result = TCL_OK; handler = Tk_CreateErrorHandler(display, any, X_SendEvent, any, XSendEventErrorProc, &result); if (!XSendEvent(display, window, False, ClientMessage, &event)) { result = TCL_ERROR; } Tk_DeleteErrorHandler(handler); XSync(display, False); if (result != TCL_OK) { fprintf(stderr, "XSendEvent response to drop: Protocol failed\n"); } } /* * ------------------------------------------------------------------------ * * GetWindowZOrder -- * * Returns a chain of the child windows according to their stacking * order. The window ids are ordered from top to bottom. * * ------------------------------------------------------------------------ */ static Blt_Chain * GetWindowZOrder(display, window) Display *display; Window window; { Blt_Chain *chainPtr; Window *childArr; unsigned int nChildren; Window dummy; chainPtr = NULL; if ((XQueryTree(display, window, &dummy, &dummy, &childArr, &nChildren)) && (nChildren > 0)) { register int i; chainPtr = Blt_ChainCreate(); for (i = 0; i < nChildren; i++) { /* * XQuery returns windows in bottom to top order. We only care * about the top window. */ Blt_ChainPrepend(chainPtr, (ClientData)childArr[i]); } if (childArr != NULL) { XFree((char *)childArr); /* done with list of kids */ } } return chainPtr; } static int GetMaxPropertySize(display) Display *display; { int size; size = Blt_MaxRequestSize(display, sizeof(char)); size -= 32; return size; } /* * ------------------------------------------------------------------------ * * GetProperty -- * * Returns the data associated with the named property on the * given window. All data is assumed to be 8-bit string data. * * ------------------------------------------------------------------------ */ static char * GetProperty(display, window, atom) Display *display; Window window; Atom atom; { char *data; int result, format; Atom typeAtom; unsigned long nItems, bytesAfter; if (window == None) { return NULL; } data = NULL; result = XGetWindowProperty( display, /* Display of window. */ window, /* Window holding the property. */ atom, /* Name of property. */ 0, /* Offset of data (for multiple reads). */ GetMaxPropertySize(display), /* Maximum number of items to read. */ False, /* If true, delete the property. */ XA_STRING, /* Desired type of property. */ &typeAtom, /* (out) Actual type of the property. */ &format, /* (out) Actual format of the property. */ &nItems, /* (out) # of items in specified format. */ &bytesAfter, /* (out) # of bytes remaining to be read. */ (unsigned char **)&data); if ((result != Success) || (format != 8) || (typeAtom != XA_STRING)) { if (data != NULL) { XFree((char *)data); data = NULL; } } return data; } /* * ------------------------------------------------------------------------ * * SetProperty -- * * Associates the given data with the a property on a given window. * All data is assumed to be 8-bit string data. * * ------------------------------------------------------------------------ */ static void SetProperty(tkwin, atom, data) Tk_Window tkwin; Atom atom; char *data; { XChangeProperty(Tk_Display(tkwin), Tk_WindowId(tkwin), atom, XA_STRING, 8, PropModeReplace, (unsigned char *)data, strlen(data) + 1); } /* * ------------------------------------------------------------------------ * * GetWindowRegion -- * * Queries for the upper-left and lower-right corners of the * given window. * * Results: * Returns if the window is currently viewable. The coordinates * of the window are returned via parameters. * * ------------------------------------------------------------------------ */ static int GetWindowRegion(display, windowPtr) Display *display; Winfo *windowPtr; { XWindowAttributes winAttrs; if (XGetWindowAttributes(display, windowPtr->window, &winAttrs)) { windowPtr->x1 = winAttrs.x; windowPtr->y1 = winAttrs.y; windowPtr->x2 = winAttrs.x + winAttrs.width - 1; windowPtr->y2 = winAttrs.y + winAttrs.height - 1; } return (winAttrs.map_state == IsViewable); } /* * ------------------------------------------------------------------------ * * FindTopWindow -- * * Searches for the topmost window at a given pair of X-Y coordinates. * * Results: * Returns a pointer to the node representing the window containing * the point. If one can't be found, NULL is returned. * * ------------------------------------------------------------------------ */ static Winfo * FindTopWindow(dndPtr, x, y) Dnd *dndPtr; int x, y; { Winfo *rootPtr; register Blt_ChainLink *linkPtr; register Winfo *windowPtr; rootPtr = dndPtr->rootPtr; if (!rootPtr->initialized) { GetWinfo(dndPtr->display, rootPtr); } if ((x < rootPtr->x1) || (x > rootPtr->x2) || (y < rootPtr->y1) || (y > rootPtr->y2)) { return NULL; /* Point is not over window */ } windowPtr = rootPtr; /* * The window list is ordered top to bottom, so stop when we find the * first child that contains the X-Y coordinate. It will be the topmost * window in that hierarchy. If none exists, then we already have the * topmost window. */ descend: for (linkPtr = Blt_ChainFirstLink(rootPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { rootPtr = Blt_ChainGetValue(linkPtr); if (!rootPtr->initialized) { GetWinfo(dndPtr->display, rootPtr); } if (rootPtr->window == Blt_GetRealWindowId(dndPtr->tokenPtr->tkwin)) { continue; /* Don't examine the token window. */ } if ((x >= rootPtr->x1) && (x <= rootPtr->x2) && (y >= rootPtr->y1) && (y <= rootPtr->y2)) { /* * Remember the last window containing the pointer and descend * into its window hierarchy. We'll look for a child that also * contains the pointer. */ windowPtr = rootPtr; goto descend; } } return windowPtr; } /* * ------------------------------------------------------------------------ * * GetWidgetCursor -- * * Queries a widget for its current cursor. The given window * may or may not be a Tk widget that has a -cursor option. * * Results: * Returns the current cursor of the widget. * * ------------------------------------------------------------------------ */ static Tk_Cursor GetWidgetCursor(interp, tkwin) Tcl_Interp *interp; /* Interpreter to evaluate widget command. */ Tk_Window tkwin; /* Window of drag&drop source. */ { Tk_Cursor cursor; Tcl_DString dString, savedResult; cursor = None; Tcl_DStringInit(&dString); Blt_DStringAppendElements(&dString, Tk_PathName(tkwin), "cget", "-cursor", (char *)NULL); Tcl_DStringInit(&savedResult); Tcl_DStringGetResult(interp, &savedResult); if (Tcl_GlobalEval(interp, Tcl_DStringValue(&dString)) == TCL_OK) { char *name; name = Tcl_GetStringResult(interp); if ((name != NULL) && (name[0] != '\0')) { cursor = Tk_GetCursor(interp, tkwin, Tk_GetUid(name)); } } Tcl_DStringResult(interp, &savedResult); Tcl_DStringFree(&dString); return cursor; } /* * ------------------------------------------------------------------------ * * NameOfStatus -- * * Converts a numeric drop result into its string representation. * * Results: * Returns a static string representing the drop result. * * ------------------------------------------------------------------------ */ static char * NameOfStatus(status) int status; { switch (status) { case DROP_OK: return "active"; case DROP_CONTINUE: return "normal"; case DROP_FAIL: return "reject"; case DROP_CANCEL: return "cancel"; default: return "unknown status value"; } } /* * ------------------------------------------------------------------------ * * NameOfAction -- * * Converts a numeric drop result into its string representation. * * Results: * Returns a static string representing the drop result. * * ------------------------------------------------------------------------ */ static char * NameOfAction(action) int action; { switch (action) { case DROP_COPY: return "copy"; case DROP_CANCEL: return "cancel"; case DROP_MOVE: return "move"; break; case DROP_LINK: return "link"; case DROP_FAIL: return "fail"; default: return "unknown action"; } } /* * ------------------------------------------------------------------------ * * GetAction -- * * Converts a string to its numeric drop result value. * * Results: * Returns the drop result. * * ------------------------------------------------------------------------ */ static int GetAction(string) char *string; { char c; c = string[0]; if ((c == 'c') && (strcmp(string, "cancel") == 0)) { return DROP_CANCEL; } else if ((c == 'f') && (strcmp(string, "fail") == 0)) { return DROP_FAIL; } else if ((c == 'm') && (strcmp(string, "move") == 0)) { return DROP_MOVE; } else if ((c == 'l') && (strcmp(string, "link") == 0)) { return DROP_LINK; } else if ((c == 'c') && (strcmp(string, "copy") == 0)) { return DROP_COPY; } else { return DROP_COPY; } } /* * ------------------------------------------------------------------------ * * GetDragResult -- * * Converts a string to its numeric drag result value. * * Results: * Returns the drag result. * * ------------------------------------------------------------------------ */ static int GetDragResult(interp, string) Tcl_Interp *interp; char *string; { char c; int bool; c = string[0]; if ((c == 'c') && (strcmp(string, "cancel") == 0)) { return DROP_CANCEL; } else if (Tcl_GetBoolean(interp, string, &bool) != TCL_OK) { Tcl_BackgroundError(interp); return DROP_CANCEL; } return bool; } static void AnimateActiveCursor(clientData) ClientData clientData; { Dnd *dndPtr = clientData; Tk_Cursor cursor; dndPtr->cursorPos++; cursor = dndPtr->cursors[dndPtr->cursorPos]; if (cursor == None) { cursor = dndPtr->cursors[1]; dndPtr->cursorPos = 1; } Tk_DefineCursor(dndPtr->tkwin, cursor); dndPtr->timerToken = Tcl_CreateTimerHandler(100, AnimateActiveCursor, dndPtr); } static void StartActiveCursor(dndPtr) Dnd *dndPtr; { if (dndPtr->timerToken != NULL) { Tcl_DeleteTimerHandler(dndPtr->timerToken); } if (dndPtr->cursors != NULL) { Tk_Cursor cursor; dndPtr->cursorPos = 1; cursor = dndPtr->cursors[1]; if (cursor != None) { Tk_DefineCursor(dndPtr->tkwin, cursor); dndPtr->timerToken = Tcl_CreateTimerHandler(125, AnimateActiveCursor, dndPtr); } } } static void StopActiveCursor(dndPtr) Dnd *dndPtr; { if (dndPtr->cursorPos > 0) { dndPtr->cursorPos = 0; } if (dndPtr->cursors != NULL) { Tk_DefineCursor(dndPtr->tkwin, dndPtr->cursors[0]); } if (dndPtr->timerToken != NULL) { Tcl_DeleteTimerHandler(dndPtr->timerToken); dndPtr->timerToken = NULL; } } /* *---------------------------------------------------------------------- * * EventuallyRedrawToken -- * * Queues a request to redraw the widget at the next idle point. * * Results: * None. * * Side effects: * Information gets redisplayed. Right now we don't do selective * redisplays: the whole window will be redrawn. * *---------------------------------------------------------------------- */ static void EventuallyRedrawToken(dndPtr) Dnd *dndPtr; { Token *tokenPtr; if (dndPtr->tokenPtr == NULL) { return; } tokenPtr = dndPtr->tokenPtr; if ((tokenPtr->tkwin != NULL) && (tokenPtr->tkwin != NULL) && !(tokenPtr->flags & TOKEN_REDRAW)) { tokenPtr->flags |= TOKEN_REDRAW; Tcl_DoWhenIdle(DisplayToken, dndPtr); } } /* * ------------------------------------------------------------------------ * * RaiseToken -- * * ------------------------------------------------------------------------ */ static void RaiseToken(dndPtr) Dnd *dndPtr; { Token *tokenPtr = dndPtr->tokenPtr; if (dndPtr->flags & DND_INITIATED) { if ((Tk_Width(tokenPtr->tkwin) != Tk_ReqWidth(tokenPtr->tkwin)) || (Tk_Height(tokenPtr->tkwin) != Tk_ReqHeight(tokenPtr->tkwin))) { Blt_ResizeToplevel(tokenPtr->tkwin, Tk_ReqWidth(tokenPtr->tkwin), Tk_ReqHeight(tokenPtr->tkwin)); } Blt_MapToplevel(tokenPtr->tkwin); Blt_RaiseToplevel(tokenPtr->tkwin); } } /* * ------------------------------------------------------------------------ * * DisplayToken -- * * ------------------------------------------------------------------------ */ static void DisplayToken(clientData) ClientData clientData; { Dnd *dndPtr = clientData; Token *tokenPtr = dndPtr->tokenPtr; int relief; Tk_3DBorder border; int borderWidth; tokenPtr->flags &= ~TOKEN_REDRAW; if (tokenPtr->status == DROP_OK) { relief = tokenPtr->activeRelief; border = tokenPtr->activeBorder; borderWidth = tokenPtr->activeBorderWidth; if ((dndPtr->cursors != NULL) && (dndPtr->cursorPos == 0)) { StartActiveCursor(dndPtr); } } else { relief = tokenPtr->relief; border = tokenPtr->normalBorder; borderWidth = tokenPtr->borderWidth; StopActiveCursor(dndPtr); } Blt_Fill3DRectangle(tokenPtr->tkwin, Tk_WindowId(tokenPtr->tkwin), border, 0, 0, Tk_Width(tokenPtr->tkwin), Tk_Height(tokenPtr->tkwin), borderWidth, relief); tokenPtr->lastStatus = tokenPtr->status; if (tokenPtr->status == DROP_FAIL) { DrawRejectSymbol(dndPtr); } } /* * ------------------------------------------------------------------------ * * FadeToken -- * * Fades the token into the target. * * ------------------------------------------------------------------------ */ static void FadeToken(dndPtr) Dnd *dndPtr; /* Drag-and-drop manager (source). */ { Token *tokenPtr = dndPtr->tokenPtr; int w, h; int dx, dy; Window window; if (tokenPtr->status == DROP_FAIL) { tokenPtr->nSteps = 1; return; } if (tokenPtr->nSteps == 1) { HideToken(dndPtr); dndPtr->flags &= ~(DND_ACTIVE | DND_VOIDED); return; } if (tokenPtr->timerToken != NULL) { Tcl_DeleteTimerHandler(tokenPtr->timerToken); } tokenPtr->timerToken = Tcl_CreateTimerHandler(10, (Tcl_TimerProc *)FadeToken, dndPtr); tokenPtr->nSteps--; w = Tk_ReqWidth(tokenPtr->tkwin) * tokenPtr->nSteps / 10; h = Tk_ReqHeight(tokenPtr->tkwin) * tokenPtr->nSteps / 10; if (w < 1) { w = 1; } if (h < 1) { h = 1; } dx = (Tk_ReqWidth(tokenPtr->tkwin) - w) / 2; dy = (Tk_ReqHeight(tokenPtr->tkwin) - h) / 2; window = Blt_GetRealWindowId(tokenPtr->tkwin); XMoveResizeWindow(dndPtr->display, window, tokenPtr->x + dx, tokenPtr->y + dy, (unsigned int)w, (unsigned int)h); tokenPtr->width = w, tokenPtr->height = h; } /* * ------------------------------------------------------------------------ * * SnapToken -- * * Snaps the token back to the source. * * ------------------------------------------------------------------------ */ static void SnapToken(dndPtr) Dnd *dndPtr; /* drag&drop source window data */ { Token *tokenPtr = dndPtr->tokenPtr; if (tokenPtr->nSteps == 1) { HideToken(dndPtr); return; } if (tokenPtr->timerToken != NULL) { Tcl_DeleteTimerHandler(tokenPtr->timerToken); } tokenPtr->timerToken = Tcl_CreateTimerHandler(10, (Tcl_TimerProc *)SnapToken, dndPtr); tokenPtr->nSteps--; tokenPtr->x -= (tokenPtr->x - tokenPtr->startX) / tokenPtr->nSteps; tokenPtr->y -= (tokenPtr->y - tokenPtr->startY) / tokenPtr->nSteps; if ((tokenPtr->x != Tk_X(tokenPtr->tkwin)) || (tokenPtr->y != Tk_Y(tokenPtr->tkwin))) { Tk_MoveToplevelWindow(tokenPtr->tkwin, tokenPtr->x, tokenPtr->y); } RaiseToken(dndPtr); } /* * ------------------------------------------------------------------------ * * HideToken -- * * Unmaps the drag&drop token. Invoked directly at the end of a * successful communication, or after a delay if the communication * fails (allowing the user to see a graphical picture of failure). * * ------------------------------------------------------------------------ */ static void HideToken(dndPtr) Dnd *dndPtr; { Token *tokenPtr = dndPtr->tokenPtr; if (tokenPtr->timerToken != NULL) { Tcl_DeleteTimerHandler(tokenPtr->timerToken); tokenPtr->timerToken = NULL; } if (dndPtr->flags & DND_INITIATED) { /* Reset the cursor back to its normal state. */ StopActiveCursor(dndPtr); if (dndPtr->cursor == None) { Tk_UndefineCursor(dndPtr->tkwin); } else { Tk_DefineCursor(dndPtr->tkwin, dndPtr->cursor); } if (tokenPtr->tkwin != NULL) { Tk_UnmapWindow(tokenPtr->tkwin); Blt_ResizeToplevel(tokenPtr->tkwin, Tk_ReqWidth(tokenPtr->tkwin), Tk_ReqHeight(tokenPtr->tkwin)); } } if (dndPtr->rootPtr != NULL) { FreeWinfo(dndPtr->rootPtr); dndPtr->rootPtr = NULL; } dndPtr->flags &= ~(DND_ACTIVE | DND_VOIDED); tokenPtr->status = DROP_CONTINUE; } /* * ------------------------------------------------------------------------ * * MorphToken -- * * Fades the token into the target. * * ------------------------------------------------------------------------ */ static void MorphToken(dndPtr) Dnd *dndPtr; /* Drag-and-drop manager (source). */ { Token *tokenPtr = dndPtr->tokenPtr; if (tokenPtr->status == DROP_FAIL) { tokenPtr->nSteps = 1; return; } if (tokenPtr->nSteps == 1) { HideToken(dndPtr); dndPtr->flags &= ~(DND_ACTIVE | DND_VOIDED); return; } if (tokenPtr->timerToken != NULL) { Tcl_DeleteTimerHandler(tokenPtr->timerToken); } tokenPtr->timerToken = Tcl_CreateTimerHandler(10, (Tcl_TimerProc *)MorphToken, dndPtr); tokenPtr->nSteps--; if (dndPtr->flags & DROP_CANCEL) { tokenPtr->nSteps--; tokenPtr->x -= (tokenPtr->x - tokenPtr->startX) / tokenPtr->nSteps; tokenPtr->y -= (tokenPtr->y - tokenPtr->startY) / tokenPtr->nSteps; if ((tokenPtr->x != Tk_X(tokenPtr->tkwin)) || (tokenPtr->y != Tk_Y(tokenPtr->tkwin))) { Tk_MoveToplevelWindow(tokenPtr->tkwin, tokenPtr->x, tokenPtr->y); } } else { int w, h; int dx, dy; Window window; w = Tk_ReqWidth(tokenPtr->tkwin) * tokenPtr->nSteps / 10; h = Tk_ReqHeight(tokenPtr->tkwin) * tokenPtr->nSteps / 10; if (w < 1) { w = 1; } if (h < 1) { h = 1; } dx = (Tk_ReqWidth(tokenPtr->tkwin) - w) / 2; dy = (Tk_ReqHeight(tokenPtr->tkwin) - h) / 2; window = Blt_GetRealWindowId(tokenPtr->tkwin); XMoveResizeWindow(dndPtr->display, window, tokenPtr->x + dx, tokenPtr->y + dy, (unsigned int)w, (unsigned int)h); tokenPtr->width = w, tokenPtr->height = h; } RaiseToken(dndPtr); } static void GetTokenPosition(dndPtr, x, y) Dnd *dndPtr; int x, y; { Token *tokenPtr = dndPtr->tokenPtr; int maxX, maxY; int vx, vy, dummy; Screen *screenPtr; /* Adjust current location for virtual root windows. */ Tk_GetVRootGeometry(dndPtr->tkwin, &vx, &vy, &dummy, &dummy); x += vx - TOKEN_OFFSET; y += vy - TOKEN_OFFSET; screenPtr = Tk_Screen(tokenPtr->tkwin); maxX = WidthOfScreen(screenPtr) - Tk_Width(tokenPtr->tkwin); maxY = HeightOfScreen(screenPtr) - Tk_Height(tokenPtr->tkwin); Blt_TranslateAnchor(x, y, Tk_Width(tokenPtr->tkwin), Tk_Height(tokenPtr->tkwin), tokenPtr->anchor, &x, &y); if (x > maxX) { x = maxX; } else if (x < 0) { x = 0; } if (y > maxY) { y = maxY; } else if (y < 0) { y = 0; } tokenPtr->x = x, tokenPtr->y = y; } /* * ------------------------------------------------------------------------ * * MoveToken -- * * Invoked during "drag" operations to move a token window to its * current "drag" coordinate. * * ------------------------------------------------------------------------ */ static void MoveToken(dndPtr) Dnd *dndPtr; /* drag&drop source window data */ { Token *tokenPtr = dndPtr->tokenPtr; GetTokenPosition(dndPtr, dndPtr->x, dndPtr->y); if ((tokenPtr->x != Tk_X(tokenPtr->tkwin)) || (tokenPtr->y != Tk_Y(tokenPtr->tkwin))) { Tk_MoveToplevelWindow(tokenPtr->tkwin, tokenPtr->x, tokenPtr->y); } } /* * ------------------------------------------------------------------------ * * ChangeToken -- * * Invoked when the event loop is idle to determine whether or not * the current drag&drop token position is over another drag&drop * target. * * ------------------------------------------------------------------------ */ static void ChangeToken(dndPtr, status) Dnd *dndPtr; int status; { Token *tokenPtr = dndPtr->tokenPtr; tokenPtr->status = status; EventuallyRedrawToken(dndPtr); /* * If the source has a site command, then invoke it to * modify the appearance of the token window. Pass any * errors onto the drag&drop error handler. */ if (dndPtr->siteCmd) { Tcl_Interp *interp = dndPtr->interp; Tcl_DString dString, savedResult; char **p; Tcl_DStringInit(&dString); for (p = dndPtr->siteCmd; *p != NULL; p++) { Tcl_DStringAppendElement(&dString, *p); } Tcl_DStringAppendElement(&dString, Tk_PathName(dndPtr->tkwin)); Tcl_DStringAppendElement(&dString, "timestamp"); Tcl_DStringAppendElement(&dString, Blt_Utoa(dndPtr->timestamp)); Tcl_DStringAppendElement(&dString, "status"); Tcl_DStringAppendElement(&dString, NameOfStatus(status)); Tcl_DStringInit(&savedResult); Tcl_DStringGetResult(interp, &savedResult); if (Tcl_GlobalEval(interp, Tcl_DStringValue(&dString)) != TCL_OK) { Tcl_BackgroundError(interp); } Tcl_DStringFree(&dString); Tcl_DStringResult(interp, &savedResult); } } /* * ------------------------------------------------------------------------ * * DrawRejectSymbol -- * * Draws a rejection mark on the current drag&drop token, and arranges * for the token to be unmapped after a small delay. * * ------------------------------------------------------------------------ */ static void DrawRejectSymbol(dndPtr) Dnd *dndPtr; { Token *tokenPtr = dndPtr->tokenPtr; int divisor = 6; /* controls size of rejection symbol */ int w, h, lineWidth, x, y, margin; margin = 2 * tokenPtr->borderWidth; w = Tk_Width(tokenPtr->tkwin) - 2 * margin; h = Tk_Height(tokenPtr->tkwin) - 2 * margin; lineWidth = (w < h) ? w / divisor : h / divisor; lineWidth = (lineWidth < 1) ? 1 : lineWidth; w = h = lineWidth * (divisor - 1); x = (Tk_Width(tokenPtr->tkwin) - w) / 2; y = (Tk_Height(tokenPtr->tkwin) - h) / 2; /* * Draw the rejection symbol background (\) on the token window... */ XSetLineAttributes(Tk_Display(tokenPtr->tkwin), tokenPtr->outlineGC, lineWidth + 2, LineSolid, CapButt, JoinBevel); XDrawArc(Tk_Display(tokenPtr->tkwin), Tk_WindowId(tokenPtr->tkwin), tokenPtr->outlineGC, x, y, w, h, 0, 23040); XDrawLine(Tk_Display(tokenPtr->tkwin), Tk_WindowId(tokenPtr->tkwin), tokenPtr->outlineGC, x + lineWidth, y + lineWidth, x + w - lineWidth, y + h - lineWidth); /* * Draw the rejection symbol foreground (\) on the token window... */ XSetLineAttributes(Tk_Display(tokenPtr->tkwin), tokenPtr->fillGC, lineWidth, LineSolid, CapButt, JoinBevel); XDrawArc(Tk_Display(tokenPtr->tkwin), Tk_WindowId(tokenPtr->tkwin), tokenPtr->fillGC, x, y, w, h, 0, 23040); XDrawLine(Tk_Display(tokenPtr->tkwin), Tk_WindowId(tokenPtr->tkwin), tokenPtr->fillGC, x + lineWidth, y + lineWidth, x + w - lineWidth, y + h - lineWidth); tokenPtr->status = DROP_FAIL; /* * Arrange for token window to disappear eventually. */ if (tokenPtr->timerToken != NULL) { Tcl_DeleteTimerHandler(tokenPtr->timerToken); } tokenPtr->timerToken = Tcl_CreateTimerHandler(1000, (Tcl_TimerProc *)HideToken, dndPtr); RaiseToken(dndPtr); dndPtr->flags &= ~(DND_ACTIVE | DND_VOIDED); } /* * ------------------------------------------------------------------------ * * CreateToken -- * * Looks for a Source record in the hash table for drag&drop source * widgets. Creates a new record if the widget name is not already * registered. Returns a pointer to the desired record. * * ------------------------------------------------------------------------ */ static void DestroyToken(data) DestroyData data; { Dnd *dndPtr = (Dnd *)data; Token *tokenPtr = dndPtr->tokenPtr; dndPtr->tokenPtr = NULL; if (tokenPtr == NULL) { return; } if (tokenPtr->flags & TOKEN_REDRAW) { Tcl_CancelIdleCall(DisplayToken, dndPtr); } Tk_FreeOptions(tokenConfigSpecs, (char *)tokenPtr, dndPtr->display, 0); if (tokenPtr->timerToken) { Tcl_DeleteTimerHandler(tokenPtr->timerToken); } if (tokenPtr->fillGC != NULL) { Tk_FreeGC(dndPtr->display, tokenPtr->fillGC); } if (tokenPtr->outlineGC != NULL) { Tk_FreeGC(dndPtr->display, tokenPtr->outlineGC); } if (tokenPtr->tkwin != NULL) { Tk_DeleteEventHandler(tokenPtr->tkwin, ExposureMask | StructureNotifyMask, TokenEventProc, dndPtr); Tk_DestroyWindow(tokenPtr->tkwin); } Blt_Free(tokenPtr); } /* * ------------------------------------------------------------------------ * * TokenEventProc -- * * Invoked by the Tk dispatcher to handle widget events. * Manages redraws for the drag&drop token window. * * ------------------------------------------------------------------------ */ static void TokenEventProc(clientData, eventPtr) ClientData clientData; /* data associated with widget */ XEvent *eventPtr; /* information about event */ { Dnd *dndPtr = clientData; Token *tokenPtr = dndPtr->tokenPtr; if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) { if (tokenPtr->tkwin != NULL) { EventuallyRedrawToken(dndPtr); } } else if (eventPtr->type == DestroyNotify) { tokenPtr->tkwin = NULL; if (tokenPtr->flags & TOKEN_REDRAW) { tokenPtr->flags &= ~TOKEN_REDRAW; Tcl_CancelIdleCall(DisplayToken, dndPtr); } Tcl_EventuallyFree(dndPtr, DestroyToken); } } /* * ------------------------------------------------------------------------ * * CreateToken -- * * Looks for a Source record in the hash table for drag&drop source * widgets. Creates a new record if the widget name is not already * registered. Returns a pointer to the desired record. * * ------------------------------------------------------------------------ */ static int CreateToken(interp, dndPtr) Tcl_Interp *interp; Dnd *dndPtr; { XSetWindowAttributes attrs; Tk_Window tkwin; unsigned int mask; Token *tokenPtr; tokenPtr = Blt_Calloc(1, sizeof(Token)); assert(tokenPtr); tokenPtr->anchor = TK_ANCHOR_SE; tokenPtr->relief = TK_RELIEF_RAISED; tokenPtr->activeRelief = TK_RELIEF_SUNKEN; tokenPtr->borderWidth = tokenPtr->activeBorderWidth = 3; /* Create toplevel on parent's screen. */ tkwin = Tk_CreateWindow(interp, dndPtr->tkwin, "dndtoken", ""); if (tkwin == NULL) { Blt_Free(tokenPtr); return TCL_ERROR; } tokenPtr->tkwin = tkwin; Tk_SetClass(tkwin, "DndToken"); Tk_CreateEventHandler(tkwin, ExposureMask | StructureNotifyMask, TokenEventProc, dndPtr); attrs.override_redirect = True; attrs.backing_store = WhenMapped; attrs.save_under = True; mask = CWOverrideRedirect | CWSaveUnder | CWBackingStore; Tk_ChangeWindowAttributes(tkwin, mask, &attrs); Tk_SetInternalBorder(tkwin, tokenPtr->borderWidth + 2); Tk_MakeWindowExist(tkwin); dndPtr->tokenPtr = tokenPtr; return TCL_OK; } /* * ------------------------------------------------------------------------ * * ConfigureToken -- * * Called to process an (argc,argv) list to configure (or * reconfigure) a drag&drop source widget. * * ------------------------------------------------------------------------ */ static int ConfigureToken(interp, dndPtr, argc, argv, flags) Tcl_Interp *interp; /* current interpreter */ Dnd *dndPtr; /* Drag&drop source widget record */ int argc; /* number of arguments */ char **argv; /* argument strings */ int flags; /* flags controlling interpretation */ { GC newGC; Token *tokenPtr = dndPtr->tokenPtr; XGCValues gcValues; unsigned long gcMask; Tk_MakeWindowExist(tokenPtr->tkwin); if (Tk_ConfigureWidget(interp, tokenPtr->tkwin, tokenConfigSpecs, argc, argv, (char *)tokenPtr, flags) != TCL_OK) { return TCL_ERROR; } /* * Set up the rejection outline GC for the token window... */ gcValues.foreground = tokenPtr->outlineColor->pixel; gcValues.subwindow_mode = IncludeInferiors; gcValues.graphics_exposures = False; gcValues.line_style = LineSolid; gcValues.cap_style = CapButt; gcValues.join_style = JoinBevel; gcMask = GCForeground | GCSubwindowMode | GCLineStyle | GCCapStyle | GCJoinStyle | GCGraphicsExposures; newGC = Tk_GetGC(dndPtr->tkwin, gcMask, &gcValues); if (tokenPtr->outlineGC != NULL) { Tk_FreeGC(dndPtr->display, tokenPtr->outlineGC); } tokenPtr->outlineGC = newGC; /* * Set up the rejection fill GC for the token window... */ gcValues.foreground = tokenPtr->fillColor->pixel; if (tokenPtr->rejectStipple != None) { gcValues.stipple = tokenPtr->rejectStipple; gcValues.fill_style = FillStippled; gcMask |= GCStipple | GCFillStyle; } newGC = Tk_GetGC(dndPtr->tkwin, gcMask, &gcValues); if (tokenPtr->fillGC != NULL) { Tk_FreeGC(dndPtr->display, tokenPtr->fillGC); } tokenPtr->fillGC = newGC; if ((tokenPtr->reqWidth > 0) && (tokenPtr->reqHeight > 0)) { Tk_GeometryRequest(tokenPtr->tkwin, tokenPtr->reqWidth, tokenPtr->reqHeight); } /* * Reset the border width in case it has changed... */ Tk_SetInternalBorder(tokenPtr->tkwin, tokenPtr->borderWidth + 2); return TCL_OK; } static int GetFormattedData(dndPtr, format, timestamp, resultPtr) Dnd *dndPtr; char *format; int timestamp; Tcl_DString *resultPtr; { Tcl_Interp *interp = dndPtr->interp; Blt_HashEntry *hPtr; char **formatCmd; Tcl_DString savedResult; Tcl_DString dString; char **p; int x, y; /* Find the data converter for the prescribed format. */ hPtr = Blt_FindHashEntry(&(dndPtr->getDataTable), format); if (hPtr == NULL) { Tcl_AppendResult(interp, "can't find format \"", format, "\" in source \"", Tk_PathName(dndPtr->tkwin), "\"", (char *)NULL); return TCL_ERROR; } formatCmd = (char **)Blt_GetHashValue(hPtr); Tcl_DStringInit(&dString); for (p = formatCmd; *p != NULL; p++) { Tcl_DStringAppendElement(&dString, *p); } x = dndPtr->dragX - Blt_RootX(dndPtr->tkwin); y = dndPtr->dragY - Blt_RootY(dndPtr->tkwin); Tcl_DStringAppendElement(&dString, Tk_PathName(dndPtr->tkwin)); Tcl_DStringAppendElement(&dString, "x"); Tcl_DStringAppendElement(&dString, Blt_Itoa(x)); Tcl_DStringAppendElement(&dString, "y"); Tcl_DStringAppendElement(&dString, Blt_Itoa(y)); Tcl_DStringAppendElement(&dString, "timestamp"); Tcl_DStringAppendElement(&dString, Blt_Utoa(timestamp)); Tcl_DStringAppendElement(&dString, "format"); Tcl_DStringAppendElement(&dString, format); Tcl_DStringInit(&savedResult); Tcl_DStringGetResult(interp, &savedResult); if (Tcl_GlobalEval(interp, Tcl_DStringValue(&dString)) != TCL_OK) { Tcl_BackgroundError(interp); } Tcl_DStringFree(&dString); Tcl_DStringInit(resultPtr); Tcl_DStringGetResult(interp, resultPtr); /* Restore the interpreter result. */ Tcl_DStringResult(interp, &savedResult); return TCL_OK; } /* * ------------------------------------------------------------------------ * * DestroyDnd -- * * Free resources allocated for the drag&drop window. * * ------------------------------------------------------------------------ */ static void DestroyDnd(data) DestroyData data; { Dnd *dndPtr = (Dnd *)data; Blt_HashEntry *hPtr; Blt_HashSearch cursor; char **cmd; Tk_FreeOptions(configSpecs, (char *)dndPtr, dndPtr->display, 0); Tk_DeleteGenericHandler(DndEventProc, dndPtr); for (hPtr = Blt_FirstHashEntry(&(dndPtr->getDataTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { cmd = (char **)Blt_GetHashValue(hPtr); if (cmd != NULL) { Blt_Free(cmd); } } Blt_DeleteHashTable(&(dndPtr->getDataTable)); for (hPtr = Blt_FirstHashEntry(&(dndPtr->setDataTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { cmd = (char **)Blt_GetHashValue(hPtr); if (cmd != NULL) { Blt_Free(cmd); } } Blt_DeleteHashTable(&(dndPtr->setDataTable)); if (dndPtr->rootPtr != NULL) { FreeWinfo(dndPtr->rootPtr); } if (dndPtr->cursor != None) { Tk_FreeCursor(dndPtr->display, dndPtr->cursor); } if (dndPtr->reqFormats != NULL) { Blt_Free(dndPtr->reqFormats); } if (dndPtr->matchingFormats != NULL) { Blt_Free(dndPtr->matchingFormats); } /* Now that the various commands are custom list options, we need * to explicitly free them. */ if (dndPtr->motionCmd != NULL) { Blt_Free(dndPtr->motionCmd); } if (dndPtr->leaveCmd != NULL) { Blt_Free(dndPtr->leaveCmd); } if (dndPtr->enterCmd != NULL) { Blt_Free(dndPtr->enterCmd); } if (dndPtr->dropCmd != NULL) { Blt_Free(dndPtr->dropCmd); } if (dndPtr->resultCmd != NULL) { Blt_Free(dndPtr->resultCmd); } if (dndPtr->packageCmd != NULL) { Blt_Free(dndPtr->packageCmd); } if (dndPtr->siteCmd != NULL) { Blt_Free(dndPtr->siteCmd); } if (dndPtr->hashPtr != NULL) { Blt_DeleteHashEntry(&(dndPtr->dataPtr->dndTable), dndPtr->hashPtr); } if (dndPtr->tokenPtr != NULL) { DestroyToken((DestroyData)dndPtr); } if (dndPtr->tkwin != NULL) { XDeleteProperty(dndPtr->display, Tk_WindowId(dndPtr->tkwin), dndPtr->dataPtr->targetAtom); XDeleteProperty(dndPtr->display, Tk_WindowId(dndPtr->tkwin), dndPtr->dataPtr->commAtom); } Blt_Free(dndPtr); } /* * ------------------------------------------------------------------------ * * GetDnd -- * * Looks for a Source record in the hash table for drag&drop source * widgets. Returns a pointer to the desired record. * * ------------------------------------------------------------------------ */ static int GetDnd(clientData, interp, pathName, dndPtrPtr) ClientData clientData; Tcl_Interp *interp; char *pathName; /* widget pathname for desired record */ Dnd **dndPtrPtr; { DndInterpData *dataPtr = clientData; Blt_HashEntry *hPtr; Tk_Window tkwin; tkwin = Tk_NameToWindow(interp, pathName, dataPtr->mainWindow); if (tkwin == NULL) { return TCL_ERROR; } hPtr = Blt_FindHashEntry(&(dataPtr->dndTable), (char *)tkwin); if (hPtr == NULL) { Tcl_AppendResult(interp, "window \"", pathName, "\" is not a drag&drop source/target", (char *)NULL); return TCL_ERROR; } *dndPtrPtr = (Dnd *)Blt_GetHashValue(hPtr); return TCL_OK; } /* * ------------------------------------------------------------------------ * * CreateDnd -- * * Looks for a Source record in the hash table for drag&drop source * widgets. Creates a new record if the widget name is not already * registered. Returns a pointer to the desired record. * * ------------------------------------------------------------------------ */ static Dnd * CreateDnd(interp, tkwin) Tcl_Interp *interp; Tk_Window tkwin; /* widget for desired record */ { Dnd *dndPtr; dndPtr = Blt_Calloc(1, sizeof(Dnd)); assert(dndPtr); dndPtr->interp = interp; dndPtr->display = Tk_Display(tkwin); dndPtr->tkwin = tkwin; Tk_MakeWindowExist(tkwin); Blt_InitHashTable(&(dndPtr->setDataTable), BLT_STRING_KEYS); Blt_InitHashTable(&(dndPtr->getDataTable), BLT_STRING_KEYS); Tk_CreateGenericHandler(DndEventProc, dndPtr); return dndPtr; } static int ConfigureDnd(interp, dndPtr) Tcl_Interp *interp; Dnd *dndPtr; { Tcl_CmdInfo cmdInfo; Tcl_DString dString; int button, result; if (!Tcl_GetCommandInfo(interp, "blt::DndInit", &cmdInfo)) { static char cmd[] = "source [file join $blt_library dnd.tcl]"; /* * If the "DndInit" routine hasn't been sourced, do it now. */ if (Tcl_GlobalEval(interp, cmd) != TCL_OK) { Tcl_AddErrorInfo(interp, "\n (while loading bindings for blt::drag&drop)"); return TCL_ERROR; } } /* * Reset the target property if it's changed state or * added/subtracted one of its callback procedures. */ if (Blt_ConfigModified(configSpecs, "-target", "-onenter", "-onmotion", "-onleave", (char *)NULL)) { if (dndPtr->targetPropertyExists) { XDeleteProperty(dndPtr->display, Tk_WindowId(dndPtr->tkwin), dndPtr->dataPtr->targetAtom); dndPtr->targetPropertyExists = FALSE; } if (dndPtr->isTarget) { AddTargetProperty(dndPtr); dndPtr->targetPropertyExists = TRUE; } } if (dndPtr->isSource) { /* Check the button binding for valid range (0 or 1-5) */ if ((dndPtr->reqButton < 0) || (dndPtr->reqButton > 5)) { Tcl_AppendResult(interp, "button must be 1-5, or 0 for no bindings", (char *)NULL); return TCL_ERROR; } button = dndPtr->reqButton; } else { button = 0; } Tcl_DStringInit(&dString); Blt_DStringAppendElements(&dString, "blt::DndInit", Tk_PathName(dndPtr->tkwin), Blt_Itoa(button), (char *)NULL); result = Tcl_GlobalEval(interp, Tcl_DStringValue(&dString)); Tcl_DStringFree(&dString); if (result != TCL_OK) { return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * SendRestrictProc -- * * This procedure filters incoming events when a "send" command * is outstanding. It defers all events except those containing * send commands and results. * * Results: * False is returned except for property-change events on a * commWindow. * * Side effects: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static Tk_RestrictAction SendRestrictProc(clientData, eventPtr) ClientData clientData; /* Drag-and-drop manager. */ register XEvent *eventPtr; /* Event that just arrived. */ { Dnd *dndPtr = clientData; if (eventPtr->xproperty.window != Tk_WindowId(dndPtr->tkwin)) { return TK_PROCESS_EVENT; /* Event not in our window. */ } if ((eventPtr->type == PropertyNotify) && (eventPtr->xproperty.state == PropertyNewValue)) { return TK_PROCESS_EVENT; /* This is the one we want to process. */ } if (eventPtr->type == Expose) { return TK_PROCESS_EVENT; /* Let expose events also get * handled. */ } return TK_DEFER_EVENT; /* Defer everything else. */ } /* *---------------------------------------------------------------------- * * SendTimerProc -- * * Procedure called when the timer event elapses. Used to wait * between attempts checking for the designated window. * * Results: * None. * * Side Effects: * Sets a flag, indicating the timeout occurred. * *---------------------------------------------------------------------- */ static void SendTimerProc(clientData) ClientData clientData; { int *statusPtr = clientData; /* * An unusually long amount of time has elapsed since the drag * start message was sent. Assume that the other party has died * and abort the operation. */ *statusPtr = DROP_FAIL; } #define WAIT_INTERVAL 2000 /* Twenty seconds. */ /* * ------------------------------------------------------------------------ * * TargetPropertyEventProc -- * * Invoked by the Tk dispatcher to handle widget events. * Manages redraws for the drag&drop token window. * * ------------------------------------------------------------------------ */ static void TargetPropertyEventProc(clientData, eventPtr) ClientData clientData; /* Data associated with transaction. */ XEvent *eventPtr; /* information about event */ { DropPending *pendingPtr = clientData; char *data; int result, format; Atom typeAtom; unsigned long nItems, bytesAfter; #ifdef notdef fprintf(stderr, "TargetPropertyEventProc\n"); #endif if ((eventPtr->type != PropertyNotify) || (eventPtr->xproperty.atom != pendingPtr->commAtom) || (eventPtr->xproperty.state != PropertyNewValue)) { return; } Tcl_DeleteTimerHandler(pendingPtr->timerToken); data = NULL; result = XGetWindowProperty( eventPtr->xproperty.display, /* Display of window. */ eventPtr->xproperty.window, /* Window holding the property. */ eventPtr->xproperty.atom, /* Name of property. */ 0, /* Offset of data (for multiple reads). */ pendingPtr->packetSize, /* Maximum number of items to read. */ False, /* If true, delete the property. */ XA_STRING, /* Desired type of property. */ &typeAtom, /* (out) Actual type of the property. */ &format, /* (out) Actual format of the property. */ &nItems, /* (out) # of items in specified format. */ &bytesAfter, /* (out) # of bytes remaining to be read. */ (unsigned char **)&data); #ifdef notdef fprintf(stderr, "TargetPropertyEventProc: result=%d, typeAtom=%d, format=%d, nItems=%d\n", result, typeAtom, format, nItems); #endif pendingPtr->status = DROP_FAIL; if ((result == Success) && (typeAtom == XA_STRING) && (format == 8)) { pendingPtr->status = DROP_OK; #ifdef notdef fprintf(stderr, "data found is (%s)\n", data); #endif Tcl_DStringAppend(&(pendingPtr->dString), data, -1); XFree(data); if (nItems == pendingPtr->packetSize) { /* Normally, we'll receive the data in one chunk. But if * more are required, reset the timer and go back into the * wait loop again. */ pendingPtr->timerToken = Tcl_CreateTimerHandler(WAIT_INTERVAL, SendTimerProc, &pendingPtr->status); pendingPtr->status = DROP_CONTINUE; } } /* Set an empty, zero-length value on the source's property. This * acts as a handshake, indicating that the target received the * latest chunk. */ #ifdef notdef fprintf(stderr, "TargetPropertyEventProc: set response property\n"); #endif XChangeProperty(pendingPtr->display, pendingPtr->window, pendingPtr->commAtom, XA_STRING, 8, PropModeReplace, (unsigned char *)"", 0); } #ifdef HAVE_XDND static int XDndSelectionProc(clientData, interp, portion) ClientData clientData; Tcl_Interp *interp; char *portion; { DropPending *pendingPtr = clientData; Tcl_DStringAppend(&(pendingPtr->dString), portion, -1); #ifdef notdef fprintf(stderr, "-> XDndGetSelectionProc\n"); #endif return TCL_OK; } #endif /* HAVE_XDND */ static void CompleteDataTransaction(dndPtr, format, pendingPtr) Dnd *dndPtr; char *format; DropPending *pendingPtr; { DndInterpData *dataPtr = dndPtr->dataPtr; Tk_Window tkwin; Atom formatAtom; #ifdef notdef fprintf(stderr, "-> CompleteDataTransaction\n"); #endif /* Check if the source is local to the application. */ tkwin = Tk_IdToWindow(dndPtr->display, pendingPtr->window); if (tkwin != NULL) { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&(dndPtr->dataPtr->dndTable), (char *)tkwin); if (hPtr != NULL) { Dnd *srcPtr; srcPtr = (Dnd *)Blt_GetHashValue(hPtr); GetFormattedData(srcPtr, format, pendingPtr->timestamp, &(pendingPtr->dString)); } return; } formatAtom = XInternAtom(pendingPtr->display, format, False); if (pendingPtr->protocol == PROTO_XDND) { #ifdef HAVE_XDND if (Tk_GetSelection(dndPtr->interp, dndPtr->tkwin, dataPtr->XdndSelectionAtom, formatAtom, XDndSelectionProc, pendingPtr) != TCL_OK) { pendingPtr->status = DROP_FAIL; } #endif pendingPtr->status = DROP_OK; } else { Tk_RestrictProc *proc; ClientData arg; SendClientMsg(pendingPtr->display, pendingPtr->window, dataPtr->mesgAtom, TS_START_DROP, (int)Tk_WindowId(dndPtr->tkwin), pendingPtr->timestamp, (int)formatAtom, (int)pendingPtr->commAtom); pendingPtr->commAtom = dndPtr->dataPtr->commAtom; pendingPtr->status = DROP_CONTINUE; pendingPtr->display = dndPtr->display; proc = Tk_RestrictEvents(SendRestrictProc, dndPtr, &arg); Tk_CreateEventHandler(dndPtr->tkwin, PropertyChangeMask, TargetPropertyEventProc, pendingPtr); pendingPtr->timerToken = Tcl_CreateTimerHandler(WAIT_INTERVAL, SendTimerProc, &pendingPtr->status); /* * ---------------------------------------------------------- * * Enter a loop processing X events until the all the data is * received or the source is declared to be dead (i.e. we * timeout). While waiting for a result, restrict handling to * just property-related events so that the transfer is * synchronous with respect to other events in the widget. * * ---------------------------------------------------------- */ while (pendingPtr->status == DROP_CONTINUE) { /* Wait for property event. */ Tcl_DoOneEvent(TCL_ALL_EVENTS); } Tk_RestrictEvents(proc, arg, &arg); Tcl_DeleteTimerHandler(pendingPtr->timerToken); Tk_DeleteEventHandler(dndPtr->tkwin, PropertyChangeMask, TargetPropertyEventProc, pendingPtr); } #ifdef notdef fprintf(stderr, "<- CompleteDataTransaction\n"); #endif } /* * ------------------------------------------------------------------------ * * SourcePropertyEventProc -- * * Invoked by the Tk dispatcher when a PropertyNotify event occurs * on the source window. The event acts as a handshake between the * target and the source. The source acknowledges the target has * received the last packet of data and sends the next packet. * * Note a special case. If the data is divisible by the packetsize, * then an extra zero-length packet is sent to mark the end of the * data. A packetsize length packet indicates more is to follow. * * Normally the property is empty (zero-length). But if an * errored occurred on the target, it will contain the error * message. * * ------------------------------------------------------------------------ */ static void SourcePropertyEventProc(clientData, eventPtr) ClientData clientData; /* data associated with widget */ XEvent *eventPtr; /* information about event */ { DropPending *pendingPtr = clientData; char *data; int result, format; Atom typeAtom; unsigned long nItems, bytesAfter; int size, bytesLeft; unsigned char *p; #ifdef notdef fprintf(stderr, "-> SourcePropertyEventProc\n"); #endif if ((eventPtr->xproperty.atom != pendingPtr->commAtom) || (eventPtr->xproperty.state != PropertyNewValue)) { return; } Tcl_DeleteTimerHandler(pendingPtr->timerToken); data = NULL; result = XGetWindowProperty( eventPtr->xproperty.display, /* Display of window. */ eventPtr->xproperty.window, /* Window holding the property. */ eventPtr->xproperty.atom, /* Name of property. */ 0, /* Offset of data (for multiple reads). */ pendingPtr->packetSize, /* Maximum number of items to read. */ True, /* If true, delete the property. */ XA_STRING, /* Desired type of property. */ &typeAtom, /* (out) Actual type of the property. */ &format, /* (out) Actual format of the property. */ &nItems, /* (out) # of items in specified format. */ &bytesAfter, /* (out) # of bytes remaining to be read. */ (unsigned char **)&data); if ((result != Success) || (typeAtom != XA_STRING) || (format != 8)) { pendingPtr->status = DROP_FAIL; #ifdef notdef fprintf(stderr, "<- SourcePropertyEventProc: wrong format\n"); #endif return; /* Wrong data format. */ } if (nItems > 0) { pendingPtr->status = DROP_FAIL; Tcl_DStringFree(&(pendingPtr->dString)); Tcl_DStringAppend(&(pendingPtr->dString), data, -1); XFree(data); #ifdef notdef fprintf(stderr, "<- SourcePropertyEventProc: error\n"); #endif return; /* Error occurred on target. */ } bytesLeft = Tcl_DStringLength(&(pendingPtr->dString)) - pendingPtr->offset; if (bytesLeft <= 0) { #ifdef notdef fprintf(stderr, "<- SourcePropertyEventProc: done\n"); #endif pendingPtr->status = DROP_OK; size = 0; } else { size = MIN(bytesLeft, pendingPtr->packetSize); pendingPtr->status = DROP_CONTINUE; } p = (unsigned char *)Tcl_DStringValue(&(pendingPtr->dString)) + pendingPtr->offset; XChangeProperty(pendingPtr->display, pendingPtr->window, pendingPtr->commAtom, XA_STRING, 8, PropModeReplace, p, size); pendingPtr->offset += size; pendingPtr->timerToken = Tcl_CreateTimerHandler(WAIT_INTERVAL, SendTimerProc, &pendingPtr->status); #ifdef notdef fprintf(stderr, "<- SourcePropertyEventProc\n"); #endif } static void SendDataToTarget(dndPtr, pendingPtr) Dnd *dndPtr; DropPending *pendingPtr; { int size; Tk_RestrictProc *proc; ClientData arg; #ifdef notdef fprintf(stderr, "-> SendDataToTarget\n"); #endif Tk_CreateEventHandler(dndPtr->tkwin, PropertyChangeMask, SourcePropertyEventProc, pendingPtr); pendingPtr->timerToken = Tcl_CreateTimerHandler(WAIT_INTERVAL, SendTimerProc, &pendingPtr->status); size = MIN(Tcl_DStringLength(&pendingPtr->dString), pendingPtr->packetSize); proc = Tk_RestrictEvents(SendRestrictProc, dndPtr, &arg); /* * Setting the property starts the process. The target will * see the PropertyChange event and respond accordingly. */ XChangeProperty(dndPtr->display, pendingPtr->window, pendingPtr->commAtom, XA_STRING, 8, PropModeReplace, (unsigned char *)Tcl_DStringValue(&(pendingPtr->dString)), size); pendingPtr->offset += size; /* * Enter a loop processing X events until the result comes * in or the target is declared to be dead. While waiting * for a result, look only at property-related events so that * the handshake is synchronous with respect to other events in * the application. */ pendingPtr->status = DROP_CONTINUE; while (pendingPtr->status == DROP_CONTINUE) { /* Wait for the property change event. */ Tcl_DoOneEvent(TCL_ALL_EVENTS); } Tk_RestrictEvents(proc, arg, &arg); Tcl_DeleteTimerHandler(pendingPtr->timerToken); Tk_DeleteEventHandler(dndPtr->tkwin, PropertyChangeMask, SourcePropertyEventProc, pendingPtr); #ifdef notdef fprintf(stderr, "<- SendDataToTarget\n"); #endif } static void DoDrop(dndPtr, eventPtr) Dnd *dndPtr; XEvent *eventPtr; { DndInterpData *dataPtr = dndPtr->dataPtr; Token *tokenPtr = dndPtr->tokenPtr; Tcl_Interp *interp = dndPtr->interp; struct DropRequest { int mesg; /* TS_DROP_RESULT message. */ Window window; /* Target window. */ int timestamp; /* Transaction timestamp. */ Atom formatAtom; /* Format requested. */ } *dropPtr; char *format; DropPending pending; if (tokenPtr->timerToken != NULL) { Tcl_DeleteTimerHandler(tokenPtr->timerToken); } dropPtr = (struct DropRequest *)eventPtr->xclient.data.l; format = XGetAtomName(dndPtr->display, dropPtr->formatAtom); #ifdef notdef fprintf(stderr, "DoDrop %s 0x%x\n", Tk_PathName(dndPtr->tkwin), dropPtr->window); #endif if (GetFormattedData(dndPtr, format, dropPtr->timestamp, &(pending.dString)) != TCL_OK) { Tcl_BackgroundError(interp); /* Send empty string to break target's wait loop. */ XChangeProperty(dndPtr->display, dropPtr->window, dataPtr->commAtom, XA_STRING, 8, PropModeReplace, (unsigned char *)"", 0); return; } pending.window = dropPtr->window; pending.display = dndPtr->display; pending.commAtom = dataPtr->commAtom; pending.offset = 0; pending.packetSize = GetMaxPropertySize(dndPtr->display); SendDataToTarget(dndPtr, &pending); Tcl_DStringFree(&(pending.dString)); #ifdef notdef fprintf(stderr, "<- DoDrop\n"); #endif } static void DropFinished(dndPtr, eventPtr) Dnd *dndPtr; XEvent *eventPtr; { Tcl_Interp *interp = dndPtr->interp; Tcl_DString dString, savedResult; int result; char **p; struct DropResult { int mesg; /* TS_DROP_RESULT message. */ Window window; /* Target window. */ int timestamp; /* Transaction timestamp. */ int result; /* Result of transaction. */ } *dropPtr; #ifdef notdef fprintf(stderr, "DropFinished\n"); #endif dropPtr = (struct DropResult *)eventPtr->xclient.data.l; Tcl_DStringInit(&dString); for (p = dndPtr->resultCmd; *p != NULL; p++) { Tcl_DStringAppendElement(&dString, *p); } Tcl_DStringAppendElement(&dString, Tk_PathName(dndPtr->tkwin)); Tcl_DStringAppendElement(&dString, "action"); Tcl_DStringAppendElement(&dString, NameOfAction(dropPtr->result)); Tcl_DStringAppendElement(&dString, "timestamp"); Tcl_DStringAppendElement(&dString, Blt_Utoa(dropPtr->timestamp)); Tcl_DStringInit(&savedResult); Tcl_DStringGetResult(interp, &savedResult); result = Tcl_GlobalEval(interp, Tcl_DStringValue(&dString)); Tcl_DStringFree(&dString); if (result != TCL_OK) { Tcl_BackgroundError(interp); } Tcl_DStringResult(interp, &savedResult); } static void FreeFormats(dndPtr) Dnd *dndPtr; { if (dndPtr->matchingFormats != NULL) { Blt_Free(dndPtr->matchingFormats); dndPtr->matchingFormats = NULL; } dndPtr->lastId = None; } static char * GetSourceFormats(dndPtr, window, timestamp) Dnd *dndPtr; Window window; int timestamp; { if (dndPtr->lastId != timestamp) { char *data; FreeFormats(dndPtr); data = GetProperty(dndPtr->display, window, dndPtr->dataPtr->formatsAtom); if (data != NULL) { dndPtr->matchingFormats = Blt_Strdup(data); XFree(data); } dndPtr->lastId = timestamp; } if (dndPtr->matchingFormats == NULL) { return ""; } return dndPtr->matchingFormats; } static int InvokeCallback(dndPtr, cmd, x, y, formats, button, keyState, timestamp) Dnd *dndPtr; char **cmd; int x, y; char *formats; int button, keyState, timestamp; { Tcl_DString dString, savedResult; Tcl_Interp *interp = dndPtr->interp; int result; char **p; Tcl_DStringInit(&dString); for (p = cmd; *p != NULL; p++) { Tcl_DStringAppendElement(&dString, *p); } Tcl_DStringAppendElement(&dString, Tk_PathName(dndPtr->tkwin)); x -= Blt_RootX(dndPtr->tkwin); /* Send coordinates relative to target. */ y -= Blt_RootY(dndPtr->tkwin); Tcl_DStringAppendElement(&dString, "x"); Tcl_DStringAppendElement(&dString, Blt_Itoa(x)); Tcl_DStringAppendElement(&dString, "y"); Tcl_DStringAppendElement(&dString, Blt_Itoa(y)); Tcl_DStringAppendElement(&dString, "formats"); if (formats == NULL) { formats = ""; } Tcl_DStringAppendElement(&dString, formats); Tcl_DStringAppendElement(&dString, "button"); Tcl_DStringAppendElement(&dString, Blt_Itoa(button)); Tcl_DStringAppendElement(&dString, "state"); Tcl_DStringAppendElement(&dString, Blt_Itoa(keyState)); Tcl_DStringAppendElement(&dString, "timestamp"); Tcl_DStringAppendElement(&dString, Blt_Utoa(timestamp)); Tcl_Preserve(interp); Tcl_DStringInit(&savedResult); Tcl_DStringGetResult(interp, &savedResult); result = Tcl_GlobalEval(interp, Tcl_DStringValue(&dString)); Tcl_DStringFree(&dString); if (result == TCL_OK) { result = GetDragResult(interp, Tcl_GetStringResult(interp)); } else { result = DROP_CANCEL; Tcl_BackgroundError(interp); } Tcl_DStringResult(interp, &savedResult); Tcl_Release(interp); return result; } /* * ------------------------------------------------------------------------ * * AcceptDrop -- * * Invokes a Tcl procedure to handle the target's side of the * drop. A Tcl procedure is invoked, either one designated for * this target by the user (-ondrop) or a default Tcl procedure. * It is passed the following arguments: * * widget The path name of the target. * x X-coordinate of the mouse relative to the * widget. * y Y-coordinate of the mouse relative to the * widget. * formats A list of data formats acceptable to both * the source and target. * button Button pressed. * state Key state. * timestamp Timestamp of transaction. * action Requested action from source. * * If the Tcl procedure returns "cancel", this indicates that the drop was * not accepted by the target and the reject symbol should be displayed. * Otherwise one of the following strings may be recognized: * * "cancel" Drop was canceled. * "copy" Source data has been successfully copied. * "link" Target has made a link to the data. It's * Ok for the source to remove it's association * with the data, but not to delete the data * itself. * "move" Source data has been successfully copied, * it's Ok for the source to delete its * association with the data and the data itself. * * The result is relayed back to the source via another client message. * The source may or may not be waiting for the result. * * Results: * None. * * Side Effects: * A Tcl procedure is invoked in the target to handle the drop event. * The result of the drop is sent (via another ClientMessage) to the * source. * * ------------------------------------------------------------------------ */ static int AcceptDrop(dndPtr, x, y, formats, button, keyState, timestamp) Dnd *dndPtr; /* Target where the drop event occurred. */ int x, y; char *formats; int button, keyState, timestamp; { Tcl_Interp *interp = dndPtr->interp; char **cmd; Tcl_DString dString, savedResult; int result; if (dndPtr->motionCmd != NULL) { result = InvokeCallback(dndPtr, dndPtr->motionCmd, x, y, formats, button, keyState, timestamp); if (result != DROP_OK) { return result; } } if (dndPtr->leaveCmd != NULL) { InvokeCallback(dndPtr, dndPtr->leaveCmd, x, y, formats, button, keyState, timestamp); } Tcl_DStringInit(&dString); cmd = dndPtr->dropCmd; if (cmd != NULL) { char **p; for (p = cmd; *p != NULL; p++) { Tcl_DStringAppendElement(&dString, *p); } } else { Tcl_DStringAppendElement(&dString, "blt::DndStdDrop"); } Tcl_DStringAppendElement(&dString, Tk_PathName(dndPtr->tkwin)); dndPtr->dropX = x - Blt_RootX(dndPtr->tkwin); dndPtr->dropY = y - Blt_RootY(dndPtr->tkwin); Tcl_DStringAppendElement(&dString, "x"); Tcl_DStringAppendElement(&dString, Blt_Itoa(dndPtr->dropX)); Tcl_DStringAppendElement(&dString, "y"); Tcl_DStringAppendElement(&dString, Blt_Itoa(dndPtr->dropY)); Tcl_DStringAppendElement(&dString, "formats"); Tcl_DStringAppendElement(&dString, formats); Tcl_DStringAppendElement(&dString, "button"); Tcl_DStringAppendElement(&dString, Blt_Itoa(button)); Tcl_DStringAppendElement(&dString, "state"); Tcl_DStringAppendElement(&dString, Blt_Itoa(keyState)); Tcl_DStringAppendElement(&dString, "timestamp"); Tcl_DStringAppendElement(&dString, Blt_Utoa(timestamp)); Tcl_Preserve(interp); Tcl_DStringInit(&savedResult); Tcl_DStringGetResult(interp, &savedResult); result = Tcl_GlobalEval(interp, Tcl_DStringValue(&dString)); Tcl_DStringFree(&dString); if (result == TCL_OK) { result = GetAction(Tcl_GetStringResult(interp)); } else { result = DROP_CANCEL; Tcl_BackgroundError(interp); } Tcl_DStringResult(interp, &savedResult); Tcl_Release(interp); return result; } /* * ------------------------------------------------------------------------ * * HandleDropEvent -- * * Invokes a Tcl procedure to handle the target's side of the * drop. This routine is triggered via a client message from the * drag source indicating that the token was dropped over this * target. The fields of the incoming message are: * * data.l[0] Message type. * data.l[1] Window Id of the source. * data.l[2] Screen X-coordinate of the pointer. * data.l[3] Screen Y-coordinate of the pointer. * data.l[4] Id of the drag&drop transaction. * * A Tcl procedure is invoked, either one designated for this * target by the user (-ondrop) or a default Tcl procedure. It * is passed the following arguments: * * widget The path name of the target. * x X-coordinate of the mouse relative to the * widget. * y Y-coordinate of the mouse relative to the * widget. * formats A list of data formats acceptable to both * the source and target. * * If the Tcl procedure returns "cancel", this indicates that the drop was * not accepted by the target and the reject symbol should be displayed. * Otherwise one of the following strings may be recognized: * * "cancel" Drop was canceled. * "copy" Source data has been successfully copied. * "link" Target has made a link to the data. It's * Ok for the source to remove it's association * with the data, but not to delete the data * itself. * "move" Source data has been successfully copied, * it's Ok for the source to delete its * association with the data and the data itself. * * The result is relayed back to the source via another client message. * The source may or may not be waiting for the result. * * Results: * None. * * Side Effects: * A Tcl procedure is invoked in the target to handle the drop event. * The result of the drop is sent (via another ClientMessage) to the * source. * * ------------------------------------------------------------------------ */ static void HandleDropEvent(dndPtr, eventPtr) Dnd *dndPtr; /* Target where the drop event occurred. */ XEvent *eventPtr; /* Message sent from the drag source. */ { int button, keyState; int x, y; char *formats; int result; struct DropInfo { int mesg; /* TS_DROP message. */ Window window; /* Source window. */ int timestamp; /* Transaction timestamp. */ int point; /* Root X-Y coordinate of pointer. */ int flags; /* Button/keystate information. */ } *dropPtr; DropPending pending; dropPtr = (struct DropInfo *)eventPtr->xclient.data.l; UNPACK(dropPtr->point, x, y); UNPACK(dropPtr->flags, button, keyState); /* Set up temporary bookkeeping for the drop transaction */ memset (&pending, 0, sizeof(pending)); pending.window = dropPtr->window; pending.display = eventPtr->xclient.display; pending.timestamp = dropPtr->timestamp; pending.protocol = PROTO_BLT; pending.packetSize = GetMaxPropertySize(pending.display); Tcl_DStringInit(&(pending.dString)); formats = GetSourceFormats(dndPtr, dropPtr->window, dropPtr->timestamp); dndPtr->pendingPtr = &pending; result = AcceptDrop(dndPtr, x, y, formats, button, keyState, dropPtr->timestamp); dndPtr->pendingPtr = NULL; /* Target-to-Source: Drop result message. */ SendClientMsg(dndPtr->display, dropPtr->window, dndPtr->dataPtr->mesgAtom, TS_DROP_RESULT, (int)Tk_WindowId(dndPtr->tkwin), dropPtr->timestamp, result, 0); FreeFormats(dndPtr); } /* * ------------------------------------------------------------------------ * * HandleDragEvent -- * * Invokes one of 3 Tcl procedures to handle the target's side of * the drag operation. This routine is triggered via a ClientMessage * from the drag source indicating that the token as either entered, * moved, or left this target. The source sends messages only if * Tcl procedures on the target have been defined to watch the * events. The message_type field can be either * * ST_DRAG_ENTER The mouse has entered the target. * ST_DRAG_MOTION The mouse has moved within the target. * ST_DRAG_LEAVE The mouse has left the target. * * The data fields are as follows: * data.l[0] Message type. * data.l[1] Window Id of the source. * data.l[2] Timestamp of the drag&drop transaction. * data.l[3] Root X-Y coordinate of the pointer. * data.l[4] Button and key state information. * * For any of the 3 Tcl procedures, the following arguments * are passed: * * widget The path name of the target. * x X-coordinate of the mouse in the widget. * y Y-coordinate of the mouse in the widget. * formats A list of data formats acceptable to both * the source and target. * * If the Tcl procedure returns "cancel", this indicates that the drag * operation has been canceled and the reject symbol should be displayed. * Otherwise it should return a boolean: * * true Target will accept drop. * false Target will not accept the drop. * * The purpose of the Enter and Leave procedure is to allow the * target to provide visual feedback that the drop can occur or not. * The Motion procedure is for cases where the drop area is a smaller * area within the target, such as a canvas item on a canvas. The * procedure can determine (based upon the X-Y coordinates) whether * the pointer is over the canvas item and return a value accordingly. * * The result of the Tcl procedure is then relayed back to the * source by a ClientMessage. * * Results: * None. * * Side Effects: * A Tcl procedure is invoked in the target to handle the drag event. * The result of the drag is sent (via another ClientMessage) to the * source. * * ------------------------------------------------------------------------ */ static void HandleDragEvent(dndPtr, eventPtr) Dnd *dndPtr; /* Target where the drag event occurred. */ XEvent *eventPtr; /* Message sent from the drag source. */ { char **cmd; int resp; int x, y; int button, keyState; char *formats; struct DragInfo { int mesg; /* Drag-and-drop message type. */ Window window; /* Source window. */ int timestamp; /* Transaction timestamp. */ int point; /* Root X-Y coordinate of pointer. */ int flags; /* Button/keystate information. */ } *dragPtr; dragPtr = (struct DragInfo *)eventPtr->xclient.data.l; cmd = NULL; switch (dragPtr->mesg) { case ST_DRAG_ENTER: cmd = dndPtr->enterCmd; break; case ST_DRAG_MOTION: cmd = dndPtr->motionCmd; break; case ST_DRAG_LEAVE: cmd = dndPtr->leaveCmd; break; } if (cmd == NULL) { return; /* Nothing to do. */ } UNPACK(dragPtr->point, x, y); UNPACK(dragPtr->flags, button, keyState); formats = GetSourceFormats(dndPtr, dragPtr->window, dragPtr->timestamp); resp = InvokeCallback(dndPtr, cmd, x, y, formats, button, keyState, dragPtr->timestamp); /* Target-to-Source: Drag result message. */ SendClientMsg(dndPtr->display, dragPtr->window, dndPtr->dataPtr->mesgAtom, TS_DRAG_STATUS, (int)Tk_WindowId(dndPtr->tkwin), dragPtr->timestamp, resp, 0); } /* * ------------------------------------------------------------------------ * * DndEventProc -- * * Invoked by Tk_HandleEvent whenever a DestroyNotify event is received * on a registered drag&drop source widget. * * ------------------------------------------------------------------------ */ static int DndEventProc(clientData, eventPtr) ClientData clientData; /* Drag&drop record. */ XEvent *eventPtr; /* Event description. */ { Dnd *dndPtr = clientData; if (eventPtr->xany.window != Tk_WindowId(dndPtr->tkwin)) { return 0; } if (eventPtr->type == DestroyNotify) { dndPtr->tkwin = NULL; dndPtr->flags |= DND_DELETED; Tcl_EventuallyFree(dndPtr, DestroyDnd); return 0; /* Other handlers have to see this event too.*/ } else if (eventPtr->type == ButtonPress) { dndPtr->keyState = eventPtr->xbutton.state; dndPtr->button = eventPtr->xbutton.button; return 0; } else if (eventPtr->type == ButtonRelease) { dndPtr->keyState = eventPtr->xbutton.state; dndPtr->button = eventPtr->xbutton.button; return 0; } else if (eventPtr->type == MotionNotify) { dndPtr->keyState = eventPtr->xmotion.state; return 0; } else if ((eventPtr->type == ClientMessage) && (eventPtr->xclient.message_type == dndPtr->dataPtr->mesgAtom)) { int result; switch((unsigned int)eventPtr->xclient.data.l[0]) { case TS_START_DROP: DoDrop(dndPtr, eventPtr); return 1; case TS_DROP_RESULT: result = eventPtr->xclient.data.l[MESG_RESPONSE]; dndPtr->tokenPtr->status = result; if (result == DROP_CANCEL) { CancelDrag(dndPtr); } else if (result == DROP_FAIL) { EventuallyRedrawToken(dndPtr); } else { dndPtr->tokenPtr->nSteps = 10; FadeToken(dndPtr); } if (dndPtr->resultCmd != NULL) { DropFinished(dndPtr, eventPtr); } return 1; case TS_DRAG_STATUS: result = eventPtr->xclient.data.l[MESG_RESPONSE]; ChangeToken(dndPtr, result); return 1; case ST_DROP: HandleDropEvent(dndPtr, eventPtr); return 1; case ST_DRAG_ENTER: case ST_DRAG_MOTION: case ST_DRAG_LEAVE: HandleDragEvent(dndPtr, eventPtr); return 1; } } return 0; } static void SendPointerMessage(dndPtr, eventType, windowPtr, x, y) Dnd *dndPtr; /* Source drag&drop manager. */ int eventType; /* Type of event to relay. */ Winfo *windowPtr; /* Generic window information. */ int x, y; /* Root coordinates of mouse. */ { /* Source-to-Target: Pointer event messages. */ SendClientMsg( dndPtr->display, /* Display of recipient window. */ windowPtr->window, /* Recipient window. */ dndPtr->dataPtr->mesgAtom, /* Message type. */ eventType, /* Data 1 */ (int)Tk_WindowId(dndPtr->tkwin), /* Data 2 */ dndPtr->timestamp, /* Data 3 */ PACK(x, y), /* Data 4 */ PACK(dndPtr->button, dndPtr->keyState)); /* Data 5 */ /* Don't wait the response. */ } static void RelayEnterEvent(dndPtr, windowPtr, x, y) Dnd *dndPtr; Winfo *windowPtr; int x, y; { if ((windowPtr != NULL) && (windowPtr->eventFlags & WATCH_ENTER)) { SendPointerMessage(dndPtr, ST_DRAG_ENTER, windowPtr, x, y); } } static void RelayLeaveEvent(dndPtr, windowPtr, x, y) Dnd *dndPtr; Winfo *windowPtr; int x, y; { if ((windowPtr != NULL) && (windowPtr->eventFlags & WATCH_LEAVE)) { SendPointerMessage(dndPtr, ST_DRAG_LEAVE, windowPtr, x, y); } } static void RelayMotionEvent(dndPtr, windowPtr, x, y) Dnd *dndPtr; Winfo *windowPtr; int x, y; { if ((windowPtr != NULL) && (windowPtr->eventFlags & WATCH_MOTION)) { SendPointerMessage(dndPtr, ST_DRAG_MOTION, windowPtr, x, y); } } static void RelayDropEvent(dndPtr, windowPtr, x, y) Dnd *dndPtr; Winfo *windowPtr; int x, y; { SendPointerMessage(dndPtr, ST_DROP, windowPtr, x, y); } /* * ------------------------------------------------------------------------ * * FreeWinfo -- * * ------------------------------------------------------------------------ */ static void FreeWinfo(windowPtr) Winfo *windowPtr; /* window rep to be freed */ { Winfo *childPtr; Blt_ChainLink *linkPtr; for (linkPtr = Blt_ChainFirstLink(windowPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { childPtr = Blt_ChainGetValue(linkPtr); FreeWinfo(childPtr); /* Recursively free children. */ } if (windowPtr->matches != NULL) { Blt_Free(windowPtr->matches); } Blt_ChainDestroy(windowPtr->chainPtr); Blt_Free(windowPtr); } /* * ------------------------------------------------------------------------ * * GetWinfo -- * * Invoked during "drag" operations. Digs into the root window * hierarchy and caches the window-related information. * If the current point lies over an uninitialized window (i.e. * one that already has an allocated Winfo structure, but has * not been filled in yet), this routine is called to query * window coordinates. If the window has any children, more * uninitialized Winfo structures are allocated. Further queries * will cause these structures to be initialized in turn. * * ------------------------------------------------------------------------ */ static void GetWinfo(display, windowPtr) Display *display; Winfo *windowPtr; /* window rep to be initialized */ { int visible; if (windowPtr->initialized) { return; } /* Query for the window coordinates. */ visible = GetWindowRegion(display, windowPtr); if (visible) { Blt_ChainLink *linkPtr; Blt_Chain *chainPtr; Winfo *childPtr; /* Add offset from parent's origin to coordinates */ if (windowPtr->parentPtr != NULL) { windowPtr->x1 += windowPtr->parentPtr->x1; windowPtr->y1 += windowPtr->parentPtr->y1; windowPtr->x2 += windowPtr->parentPtr->x1; windowPtr->y2 += windowPtr->parentPtr->y1; } /* * Collect a list of child windows, sorted in z-order. The * topmost window will be first in the list. */ chainPtr = GetWindowZOrder(display, windowPtr->window); /* Add and initialize extra slots if needed. */ for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { childPtr = Blt_Calloc(1, sizeof(Winfo)); assert(childPtr); childPtr->initialized = FALSE; childPtr->window = (Window)Blt_ChainGetValue(linkPtr); childPtr->parentPtr = windowPtr; Blt_ChainSetValue(linkPtr, childPtr); } windowPtr->chainPtr = chainPtr; } else { /* If it's not viewable don't bother doing anything else. */ windowPtr->x1 = windowPtr->y1 = windowPtr->x2 = windowPtr->y2 = -1; windowPtr->chainPtr = NULL; } windowPtr->initialized = TRUE; } /* * ------------------------------------------------------------------------ * * InitRoot -- * * Invoked at the start of a "drag" operation to capture the * positions of all windows on the current root. Queries the * entire window hierarchy and determines the placement of each * window. Queries the "BltDndTarget" property info where * appropriate. This information is used during the drag * operation to determine when the drag&drop token is over a * valid drag&drop target. * * Results: * Returns the record for the root window, which contains records * for all other windows as children. * * ------------------------------------------------------------------------ */ static Winfo * InitRoot(dndPtr) Dnd *dndPtr; { Winfo *rootPtr; rootPtr = Blt_Calloc(1, sizeof(Winfo)); assert(rootPtr); rootPtr->window = DefaultRootWindow(dndPtr->display); dndPtr->windowPtr = NULL; GetWinfo(dndPtr->display, rootPtr); return rootPtr; } static int ParseProperty(interp, dndPtr, windowPtr, data) Tcl_Interp *interp; Dnd *dndPtr; Winfo *windowPtr; char *data; { int nElems; char **elemArr; int eventFlags; Tcl_DString dString; int count; register int i; if (Tcl_SplitList(interp, data, &nElems, &elemArr) != TCL_OK) { return TCL_ERROR; /* Malformed property list. */ } if (nElems < 1) { Tcl_AppendResult(interp, "Malformed property \"", data, "\"", (char *)NULL); goto error; } if (Tcl_GetInt(interp, elemArr[PROP_WATCH_FLAGS], &eventFlags) != TCL_OK) { goto error; } /* target flags, type1, type2, ... */ /* * The target property contains a list of possible formats. * Compare this with what formats the source is willing to * convert and compress the list down to just the matching * formats. It's up to the target to request the specific * type (or types) that it wants. */ count = 0; Tcl_DStringInit(&dString); if (dndPtr->reqFormats == NULL) { Blt_HashEntry *hPtr; Blt_HashSearch cursor; char *fmt; for (i = 1; i < nElems; i++) { for(hPtr = Blt_FirstHashEntry(&(dndPtr->getDataTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { fmt = Blt_GetHashKey(&(dndPtr->getDataTable), hPtr); if ((*fmt == elemArr[i][0]) && (strcmp(fmt, elemArr[i]) == 0)) { Tcl_DStringAppendElement(&dString, elemArr[i]); count++; break; } } } } else { register char **s; for (i = 1; i < nElems; i++) { for (s = dndPtr->reqFormats; *s != NULL; s++) { if ((**s == elemArr[i][0]) && (strcmp(*s, elemArr[i]) == 0)) { Tcl_DStringAppendElement(&dString, elemArr[i]); count++; } } } } if (count == 0) { #ifdef notdef fprintf(stderr, "source/target mismatch: No matching types\n"); #endif return TCL_BREAK; } if (eventFlags != 0) { SetProperty(dndPtr->tkwin, dndPtr->dataPtr->formatsAtom, Tcl_DStringValue(&dString)); windowPtr->matches = NULL; } else { windowPtr->matches = Blt_Strdup(Tcl_DStringValue(&dString)); } Tcl_DStringFree(&dString); windowPtr->eventFlags = eventFlags; return TCL_OK; error: Blt_Free(elemArr); return TCL_ERROR; } /* * ------------------------------------------------------------------------ * * OverTarget -- * * Checks to see if a compatible drag&drop target exists at the * given position. A target is "compatible" if it is a drag&drop * window, and if it has a handler that is compatible with the * current source window. * * Results: * Returns a pointer to a structure describing the target, or NULL * if no compatible target is found. * * ------------------------------------------------------------------------ */ static Winfo * OverTarget(dndPtr) Dnd *dndPtr; /* drag&drop source window */ { Tcl_Interp *interp = dndPtr->interp; int x, y; int vx, vy; int dummy; Winfo *windowPtr; /* * If no window info has been been gathered yet for this target, * then abort this call. This probably means that the token is * moved before it has been properly built. */ if (dndPtr->rootPtr == NULL) { fprintf(stderr, "rootPtr not initialized\n"); return NULL; } /* Adjust current location for virtual root windows. */ Tk_GetVRootGeometry(dndPtr->tkwin, &vx, &vy, &dummy, &dummy); x = dndPtr->x + vx; y = dndPtr->y + vy; windowPtr = FindTopWindow(dndPtr, x, y); if (windowPtr == NULL) { return NULL; /* Not over a window. */ } if ((!dndPtr->selfTarget) && (Tk_WindowId(dndPtr->tkwin) == windowPtr->window)) { return NULL; /* If the self-target flag isn't set, * don't allow the source window to * drop onto itself. */ } if (!windowPtr->lookedForProperty) { char *data; int result; windowPtr->lookedForProperty = TRUE; /* See if this window has a "BltDndTarget" property. */ data = GetProperty(dndPtr->display, windowPtr->window, dndPtr->dataPtr->targetAtom); if (data == NULL) { #ifdef notdef fprintf(stderr, "No property on 0x%x\n", windowPtr->window); #endif return NULL; /* No such property on window. */ } result = ParseProperty(interp, dndPtr, windowPtr, data); XFree(data); if (result == TCL_BREAK) { #ifdef notdef fprintf(stderr, "No matching formats\n"); #endif return NULL; } if (result != TCL_OK) { Tcl_BackgroundError(interp); return NULL; /* Malformed property list. */ } windowPtr->isTarget = TRUE; } if (!windowPtr->isTarget) { return NULL; } return windowPtr; } /* * ------------------------------------------------------------------------ * * AddTargetProperty -- * * Attaches a drag&drop property to the given target window. * This property allows us to recognize the window later as a * valid target. It also stores important information including * the interpreter managing the target and the pathname of the * target window. Usually this routine is called when the target * is first registered or first exposed (so that the X-window * really exists). * * ------------------------------------------------------------------------ */ static void AddTargetProperty(dndPtr) Dnd *dndPtr; /* drag&drop target window data */ { Tcl_DString dString; Blt_HashEntry *hPtr; unsigned int eventFlags; Blt_HashSearch cursor; char *fmt; char string[200]; Tcl_DStringInit(&dString); /* * Each target window's dnd property contains * * 1. Mouse event flags. * 2. List of all the data types that can be handled. If none * are listed, then all can be handled. */ eventFlags = 0; if (dndPtr->enterCmd != NULL) { eventFlags |= WATCH_ENTER; } if (dndPtr->leaveCmd != NULL) { eventFlags |= WATCH_LEAVE; } if (dndPtr->motionCmd != NULL) { eventFlags |= WATCH_MOTION; } sprintf(string, "0x%x", eventFlags); Tcl_DStringAppendElement(&dString, string); for (hPtr = Blt_FirstHashEntry(&(dndPtr->setDataTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { fmt = Blt_GetHashKey(&(dndPtr->setDataTable), hPtr); Tcl_DStringAppendElement(&dString, fmt); } SetProperty(dndPtr->tkwin, dndPtr->dataPtr->targetAtom, Tcl_DStringValue(&dString)); dndPtr->targetPropertyExists = TRUE; Tcl_DStringFree(&dString); } static void CancelDrag(dndPtr) Dnd *dndPtr; { if (dndPtr->flags & DND_INITIATED) { dndPtr->tokenPtr->nSteps = 10; SnapToken(dndPtr); StopActiveCursor(dndPtr); if (dndPtr->cursor == None) { Tk_UndefineCursor(dndPtr->tkwin); } else { Tk_DefineCursor(dndPtr->tkwin, dndPtr->cursor); } } if (dndPtr->rootPtr != NULL) { FreeWinfo(dndPtr->rootPtr); dndPtr->rootPtr = NULL; } } static int DragInit(dndPtr, x, y) Dnd *dndPtr; int x, y; { Token *tokenPtr = dndPtr->tokenPtr; int result; Winfo *newPtr; assert((dndPtr->flags & DND_ACTIVE) == DND_SELECTED); if (dndPtr->rootPtr != NULL) { FreeWinfo(dndPtr->rootPtr); } dndPtr->rootPtr = InitRoot(dndPtr); /* Reset information cache. */ dndPtr->flags &= ~DND_VOIDED; dndPtr->x = x; /* Save current location. */ dndPtr->y = y; result = TRUE; Tcl_Preserve(dndPtr); if (dndPtr->packageCmd != NULL) { Tcl_DString dString, savedResult; Tcl_Interp *interp = dndPtr->interp; int status; char **p; int rx, ry; Tcl_DStringInit(&dString); for (p = dndPtr->packageCmd; *p != NULL; p++) { Tcl_DStringAppendElement(&dString, *p); } Tcl_DStringAppendElement(&dString, Tk_PathName(dndPtr->tkwin)); rx = dndPtr->dragX - Blt_RootX(dndPtr->tkwin); ry = dndPtr->dragY - Blt_RootY(dndPtr->tkwin); Tcl_DStringAppendElement(&dString, "x"); Tcl_DStringAppendElement(&dString, Blt_Itoa(rx)); Tcl_DStringAppendElement(&dString, "y"); Tcl_DStringAppendElement(&dString, Blt_Itoa(ry)); Tcl_DStringAppendElement(&dString, "button"); Tcl_DStringAppendElement(&dString, Blt_Itoa(dndPtr->button)); Tcl_DStringAppendElement(&dString, "state"); Tcl_DStringAppendElement(&dString, Blt_Itoa(dndPtr->keyState)); Tcl_DStringAppendElement(&dString, "timestamp"); Tcl_DStringAppendElement(&dString, Blt_Utoa(dndPtr->timestamp)); Tcl_DStringAppendElement(&dString, "token"); Tcl_DStringAppendElement(&dString, Tk_PathName(tokenPtr->tkwin)); Tcl_DStringInit(&savedResult); Tcl_DStringGetResult(interp, &savedResult); dndPtr->flags |= DND_IN_PACKAGE; status = Tcl_GlobalEval(interp, Tcl_DStringValue(&dString)); dndPtr->flags &= ~DND_IN_PACKAGE; if (status == TCL_OK) { result = GetDragResult(interp, Tcl_GetStringResult(interp)); } else { Tcl_BackgroundError(interp); } Tcl_DStringFree(&dString); Tcl_DStringResult(interp, &savedResult); Tcl_DStringFree(&dString); if (status != TCL_OK) { HideToken(dndPtr); Tcl_Release(dndPtr); return TCL_ERROR; } } if (dndPtr->flags & DND_VOIDED) { HideToken(dndPtr); Tcl_Release(dndPtr); return TCL_RETURN; } if ((!result) || (dndPtr->flags & DND_DELETED)) { HideToken(dndPtr); Tcl_Release(dndPtr); return TCL_RETURN; } Tcl_Release(dndPtr); if (dndPtr->cursor != None) { Tk_Cursor cursor; /* Save the old cursor */ cursor = GetWidgetCursor(dndPtr->interp, dndPtr->tkwin); if (dndPtr->cursor != None) { Tk_FreeCursor(dndPtr->display, dndPtr->cursor); } dndPtr->cursor = cursor; if (dndPtr->cursors != NULL) { /* Temporarily install the drag-and-drop cursor. */ Tk_DefineCursor(dndPtr->tkwin, dndPtr->cursors[0]); } } if (Tk_WindowId(tokenPtr->tkwin) == None) { Tk_MakeWindowExist(tokenPtr->tkwin); } if (!Tk_IsMapped(tokenPtr->tkwin)) { Tk_MapWindow(tokenPtr->tkwin); } dndPtr->flags |= DND_INITIATED; newPtr = OverTarget(dndPtr); RelayEnterEvent(dndPtr, newPtr, x, y); dndPtr->windowPtr = newPtr; tokenPtr->status = (newPtr != NULL) ? DROP_OK : DROP_CONTINUE; if (tokenPtr->lastStatus != tokenPtr->status) { EventuallyRedrawToken(dndPtr); } MoveToken(dndPtr); /* Move token to current drag point. */ RaiseToken(dndPtr); return TCL_OK; } /* * ------------------------------------------------------------------------ * * CancelOp -- * * Cancels the current drag&drop operation for the source. Calling * this operation does not affect the transfer of data from the * source to the target, once the drop has been made. From the * source's point of view, the drag&drop operation is already over. * * Example: dnd cancel .widget * * Results: * A standard Tcl result. * * Side Effects: * Hides the token and sets a flag indicating that further "drag" * and "drop" operations should be ignored. * * ------------------------------------------------------------------------ */ /*ARGSUSED*/ static int CancelOp(clientData, interp, argc, argv) ClientData clientData; /* Thread-specific data. */ Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Dnd *dndPtr; if (GetDnd(clientData, interp, argv[2], &dndPtr) != TCL_OK) { return TCL_ERROR; } if (!dndPtr->isSource) { Tcl_AppendResult(interp, "widget \"", Tk_PathName(dndPtr->tkwin), "\" is not a registered drag&drop source.", (char *)NULL); return TCL_ERROR; } /* Send the target a Leave message so it can change back. */ RelayLeaveEvent(dndPtr, dndPtr->windowPtr, 0, 0); CancelDrag(dndPtr); return TCL_OK; } /* * ------------------------------------------------------------------------ * * CgetOp -- * * Called to process an (argc,argv) list to configure (or * reconfigure) a drag&drop widget. * * ------------------------------------------------------------------------ */ /* ARGSUSED*/ static int CgetOp(clientData, interp, argc, argv) ClientData clientData; /* Thread-specific data. */ Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Dnd *dndPtr; if (GetDnd(clientData, interp, argv[2], &dndPtr) != TCL_OK) { return TCL_ERROR; } return Tk_ConfigureValue(interp, dndPtr->tkwin, configSpecs, (char *)dndPtr, argv[3], 0); } /* * ------------------------------------------------------------------------ * * ConfigureOp -- * * Called to process an (argc,argv) list to configure (or * reconfigure) a drag&drop widget. * * ------------------------------------------------------------------------ */ static int ConfigureOp(clientData, interp, argc, argv) ClientData clientData; /* Thread-specific data. */ Tcl_Interp *interp; /* current interpreter */ int argc; /* number of arguments */ char **argv; /* argument strings */ { Dnd *dndPtr; int flags; if (GetDnd(clientData, interp, argv[2], &dndPtr) != TCL_OK) { return TCL_ERROR; } flags = TK_CONFIG_ARGV_ONLY; if (argc == 3) { return Tk_ConfigureInfo(interp, dndPtr->tkwin, configSpecs, (char *)dndPtr, (char *)NULL, flags); } else if (argc == 4) { return Tk_ConfigureInfo(interp, dndPtr->tkwin, configSpecs, (char *)dndPtr, argv[3], flags); } if (Tk_ConfigureWidget(interp, dndPtr->tkwin, configSpecs, argc - 3, argv + 3, (char *)dndPtr, flags) != TCL_OK) { return TCL_ERROR; } if (ConfigureDnd(interp, dndPtr) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } /* * ------------------------------------------------------------------------ * * DeleteOp -- * * Deletes the drag&drop manager from the widget. If a "-source" * or "-target" switch is present, only that component of the * drag&drop manager is shutdown. The manager is not deleted * unless both the target and source components are shutdown. * * Example: dnd delete .widget * * Results: * A standard Tcl result. * * Side Effects: * Deletes the drag&drop manager. Also the source and target window * properties are removed from the widget. * * ------------------------------------------------------------------------ */ static int DeleteOp(clientData, interp, argc, argv) ClientData clientData; /* Thread-specific data. */ Tcl_Interp *interp; int argc; char **argv; { Dnd *dndPtr; register int i; for(i = 3; i < argc; i++) { if (GetDnd(clientData, interp, argv[i], &dndPtr) != TCL_OK) { return TCL_ERROR; } dndPtr->flags |= DND_DELETED; Tcl_EventuallyFree(dndPtr, DestroyDnd); } return TCL_OK; } /* * ------------------------------------------------------------------------ * * SelectOp -- * * Initializes a drag&drop transaction. Typically this operation * is called from a ButtonPress event on a source widget. The * window information cache is initialized, and the token is * initialized and displayed. * * Example: dnd pickup .widget x y * * Results: * A standard Tcl result. * * Side Effects: * The token is initialized and displayed. This may require invoking * a user-defined package command. The window information cache is * also initialized. * * ------------------------------------------------------------------------ */ /*ARGSUSED*/ static int SelectOp(clientData, interp, argc, argv) ClientData clientData; /* Thread-specific data. */ Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Dnd *dndPtr; int x, y, timestamp; Token *tokenPtr; if (GetDnd(clientData, interp, argv[2], &dndPtr) != TCL_OK) { return TCL_ERROR; } if (!dndPtr->isSource) { Tcl_AppendResult(interp, "widget \"", Tk_PathName(dndPtr->tkwin), "\" is not a registered drag&drop source.", (char *)NULL); return TCL_ERROR; } tokenPtr = dndPtr->tokenPtr; if (tokenPtr == NULL) { Tcl_AppendResult(interp, "no drag&drop token created for \"", argv[2], "\"", (char *)NULL); return TCL_ERROR; } if ((Tcl_GetInt(interp, argv[3], &x) != TCL_OK) || (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)) { return TCL_ERROR; } if (Tcl_GetInt(interp, argv[5], ×tamp) != TCL_OK) { return TCL_ERROR; } if (dndPtr->flags & (DND_IN_PACKAGE | DND_ACTIVE | DND_VOIDED)) { return TCL_OK; } if (tokenPtr->timerToken != NULL) { HideToken(dndPtr); /* If the user selected again before the * token snap/melt has completed, first * disable the token timer callback. */ } /* At this point, simply save the starting pointer location. */ dndPtr->dragX = x, dndPtr->dragY = y; GetTokenPosition(dndPtr, x, y); tokenPtr->startX = tokenPtr->x; tokenPtr->startY = tokenPtr->y; dndPtr->timestamp = timestamp; dndPtr->flags |= DND_SELECTED; if (dndPtr->dragStart == 0) { if (DragInit(dndPtr, x, y) == TCL_ERROR) { return TCL_ERROR; } } return TCL_OK; } /* * ------------------------------------------------------------------------ * * DragOp -- * * Continues the drag&drop transaction. Typically this operation * is called from a button Motion event on a source widget. Pointer * event messages are possibly sent to the target, indicating Enter, * Leave, and Motion events. * * Example: dnd drag .widget x y * * Results: * A standard Tcl result. * * Side Effects: * Pointer events are relayed to the target (if the mouse is over * one). * * ------------------------------------------------------------------------ */ /*ARGSUSED*/ static int DragOp(clientData, interp, argc, argv) ClientData clientData; /* Thread-specific data. */ Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Winfo *newPtr, *oldPtr; Dnd *dndPtr; int x, y; if (GetDnd(clientData, interp, argv[2], &dndPtr) != TCL_OK) { return TCL_ERROR; } if (!dndPtr->isSource) { Tcl_AppendResult(interp, "widget \"", Tk_PathName(dndPtr->tkwin), "\" is not a registered drag&drop source.", (char *)NULL); return TCL_ERROR; } if (dndPtr->tokenPtr == NULL) { Tcl_AppendResult(interp, "no drag&drop token created for \"", argv[2], "\"", (char *)NULL); return TCL_ERROR; } if ((Tcl_GetInt(interp, argv[3], &x) != TCL_OK) || (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)) { return TCL_ERROR; } if ((dndPtr->flags & DND_SELECTED) == 0) { return TCL_OK; /* Re-entered this routine. */ } /* * The following code gets tricky because the package command may * call "update" or "tkwait". A motion event may then trigger * this routine, before the token has been initialized. Until the * package command finishes, no target messages are sent and drops * are silently ignored. Note that we do still track mouse * movements, so that when the package command completes, it will * have the latest pointer position. */ dndPtr->x = x; /* Save current location. */ dndPtr->y = y; if (dndPtr->flags & DND_IN_PACKAGE) { return TCL_OK; /* Re-entered this routine. */ } if ((dndPtr->flags & DND_INITIATED) == 0) { int dx, dy; int result; dx = dndPtr->dragX - x; dy = dndPtr->dragY - y; if ((ABS(dx) < dndPtr->dragStart) && (ABS(dy) < dndPtr->dragStart)) { return TCL_OK; } result = DragInit(dndPtr, x, y); if (result == TCL_ERROR) { return TCL_ERROR; } if (result == TCL_RETURN) { return TCL_OK; } } if (dndPtr->flags & DND_VOIDED) { return TCL_OK; } oldPtr = dndPtr->windowPtr; newPtr = OverTarget(dndPtr); if (newPtr == oldPtr) { RelayMotionEvent(dndPtr, oldPtr, x, y); dndPtr->windowPtr = oldPtr; } else { RelayLeaveEvent(dndPtr, oldPtr, x, y); RelayEnterEvent(dndPtr, newPtr, x, y); dndPtr->windowPtr = newPtr; } dndPtr->tokenPtr->status = (newPtr != NULL) ? DROP_OK : DROP_CONTINUE; if (dndPtr->tokenPtr->lastStatus != dndPtr->tokenPtr->status) { EventuallyRedrawToken(dndPtr); } MoveToken(dndPtr); /* Move token to current drag point. */ RaiseToken(dndPtr); return TCL_OK; } /* * ------------------------------------------------------------------------ * * DropOp -- * * Finishes the drag&drop transaction by dropping the data on the * selected target. Typically this operation is called from a * ButtonRelease event on a source widget. Note that a Leave message * is always sent to the target so that is can un-highlight itself. * The token is hidden and a drop message is sent to the target. * * Example: dnd drop .widget x y * * Results: * A standard Tcl result. * * Side Effects: * The token is hidden and a drop message is sent to the target. * * ------------------------------------------------------------------------ */ /*ARGSUSED*/ static int DropOp(clientData, interp, argc, argv) ClientData clientData; /* Thread-specific data. */ Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Winfo *windowPtr; Dnd *dndPtr; int x, y; if (GetDnd(clientData, interp, argv[2], &dndPtr) != TCL_OK) { return TCL_ERROR; } if (!dndPtr->isSource) { Tcl_AppendResult(interp, "widget \"", Tk_PathName(dndPtr->tkwin), "\" is not a registered drag&drop source.", (char *)NULL); return TCL_ERROR; } if ((Tcl_GetInt(interp, argv[3], &x) != TCL_OK) || (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)) { return TCL_ERROR; } dndPtr->x = x; /* Save drag&drop location */ dndPtr->y = y; if ((dndPtr->flags & DND_INITIATED) == 0) { return TCL_OK; /* Never initiated any drag operation. */ } if (dndPtr->flags & DND_VOIDED) { HideToken(dndPtr); return TCL_OK; } windowPtr = OverTarget(dndPtr); if (windowPtr != NULL) { if (windowPtr->matches != NULL) { SetProperty(dndPtr->tkwin, dndPtr->dataPtr->formatsAtom, windowPtr->matches); } MoveToken(dndPtr); /* Move token to current drag point. */ RaiseToken(dndPtr); RelayDropEvent(dndPtr, windowPtr, x, y); #ifdef notdef tokenPtr->nSteps = 10; FadeToken(dndPtr); #endif } else { CancelDrag(dndPtr); } return TCL_OK; } /* * ------------------------------------------------------------------------ * * GetdataOp -- * * Registers one or more data formats with a drag&drop source. * Each format has a Tcl command associated with it. This command * is automatically invoked whenever data is pulled from the source * to a target requesting the data in that particular format. The * purpose of the Tcl command is to get the data from in the * application. When the Tcl command is invoked, special percent * substitutions are made: * * %# Drag&drop transaction timestamp. * %W Source widget. * * If a converter (command) already exists for a format, it * overwrites the existing command. * * Example: dnd getdata .widget "color" { %W cget -bg } * * Results: * A standard Tcl result. * * ------------------------------------------------------------------------ */ static int GetdataOp(clientData, interp, argc, argv) ClientData clientData; /* Thread-specific data. */ Tcl_Interp *interp; int argc; char **argv; { Dnd *dndPtr; Blt_HashEntry *hPtr; Blt_HashSearch cursor; int isNew, nElem; char **cmd; register int i; if (GetDnd(clientData, interp, argv[2], &dndPtr) != TCL_OK) { return TCL_ERROR; } if (argc == 3) { /* Return list of source data formats */ for (hPtr = Blt_FirstHashEntry(&(dndPtr->getDataTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { Tcl_AppendElement(interp, Blt_GetHashKey(&(dndPtr->getDataTable), hPtr)); } return TCL_OK; } if (argc == 4) { hPtr = Blt_FindHashEntry(&(dndPtr->getDataTable), argv[3]); if (hPtr == NULL) { Tcl_AppendResult(interp, "can't find handler for format \"", argv[3], "\" for source \"", Tk_PathName(dndPtr->tkwin), "\"", (char *)NULL); return TCL_ERROR; } cmd = (char **)Blt_GetHashValue(hPtr); if (cmd == NULL) { Tcl_SetResult(interp, "", TCL_STATIC); } else { Tcl_SetResult(interp, PrintList(cmd), TCL_DYNAMIC); } return TCL_OK; } for (i = 3; i < argc; i += 2) { hPtr = Blt_CreateHashEntry(&(dndPtr->getDataTable), argv[i], &isNew); if (!isNew) { cmd = (char **)Blt_GetHashValue(hPtr); Blt_Free(cmd); } if (Tcl_SplitList(interp, argv[i + 1], &nElem, &cmd) != TCL_OK) { Blt_DeleteHashEntry(&(dndPtr->getDataTable), hPtr); return TCL_ERROR; } Blt_SetHashValue(hPtr, cmd); } return TCL_OK; } /* * ------------------------------------------------------------------------ * * NamesOp -- * * Returns the names of all the drag&drop managers. If either * a "-source" or "-target" switch is present, only the names of * managers acting as sources or targets respectively are returned. * A pattern argument may also be given. Only those managers * matching the pattern are returned. * * Examples: dnd names * dnd names -source * dnd names -target * dnd names .*label * Results: * A standard Tcl result. A Tcl list of drag&drop manager * names is returned. * * ------------------------------------------------------------------------ */ static int NamesOp(clientData, interp, argc, argv) ClientData clientData; /* Thread-specific data. */ Tcl_Interp *interp; int argc; char **argv; { DndInterpData *dataPtr = clientData; Blt_HashEntry *hPtr; Blt_HashSearch cursor; Dnd *dndPtr; int findSources, findTargets; findSources = findTargets = TRUE; if (argc > 2) { if ((argv[2][0] == '-') && (strcmp(argv[2], "-source") == 0)) { findTargets = FALSE; argc--, argv++; } else if ((argv[2][0] == '-') && (strcmp(argv[2], "-target") == 0)) { findSources = FALSE; argc--, argv++; } } for (hPtr = Blt_FirstHashEntry(&(dataPtr->dndTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { dndPtr = (Dnd *)Blt_GetHashValue(hPtr); if ((argc > 3) && (!Tcl_StringMatch(Tk_PathName(dndPtr->tkwin), argv[3]))) { continue; } if (((findSources) && (dndPtr->isSource)) || ((findTargets) && (dndPtr->isTarget))) { Tcl_AppendElement(interp, Tk_PathName(dndPtr->tkwin)); } } return TCL_OK; } /* * ------------------------------------------------------------------------ * * PullOp -- * * Pulls the current data from the source in the given format. * application. * * dnd pull .widget format data * * Results: * A standard Tcl result. * * Side Effects: * Invokes the target's data converter to store the data. * * ------------------------------------------------------------------------ */ /*ARGSUSED*/ static int PullOp(clientData, interp, argc, argv) ClientData clientData; /* Thread-specific data. */ Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Dnd *dndPtr; /* drag&drop source record */ int result; char **formatCmd; Blt_HashEntry *hPtr; if (GetDnd(clientData, interp, argv[2], &dndPtr) != TCL_OK) { return TCL_ERROR; } if (!dndPtr->isTarget) { Tcl_AppendResult(interp, "widget \"", Tk_PathName(dndPtr->tkwin), "\" is not a registered drag&drop target.", (char *)NULL); return TCL_ERROR; } hPtr = Blt_FindHashEntry(&(dndPtr->setDataTable), argv[3]); if (hPtr == NULL) { Tcl_AppendResult(interp, "can't find format \"", argv[3], "\" in target \"", Tk_PathName(dndPtr->tkwin), "\"", (char *)NULL); return TCL_ERROR; } formatCmd = (char **)Blt_GetHashValue(hPtr); if (dndPtr->pendingPtr == NULL) { Tcl_AppendResult(interp, "no drop in progress", (char *)NULL); return TCL_ERROR; } CompleteDataTransaction(dndPtr, argv[3], dndPtr->pendingPtr); result = TCL_OK; if (Tcl_DStringLength(&(dndPtr->pendingPtr->dString)) > 0) { Tcl_DString dString, savedResult; char **p; Tcl_DStringInit(&dString); for (p = formatCmd; *p != NULL; p++) { Tcl_DStringAppendElement(&dString, *p); } Tcl_DStringAppendElement(&dString, Tk_PathName(dndPtr->tkwin)); Tcl_DStringAppendElement(&dString, "x"); Tcl_DStringAppendElement(&dString, Blt_Itoa(dndPtr->dropX)); Tcl_DStringAppendElement(&dString, "y"); Tcl_DStringAppendElement(&dString, Blt_Itoa(dndPtr->dropY)); Tcl_DStringAppendElement(&dString, "timestamp"); Tcl_DStringAppendElement(&dString, Blt_Utoa(dndPtr->pendingPtr->timestamp)); Tcl_DStringAppendElement(&dString, "format"); Tcl_DStringAppendElement(&dString, argv[3]); Tcl_DStringAppendElement(&dString, "value"); Tcl_DStringAppendElement(&dString, Tcl_DStringValue(&(dndPtr->pendingPtr->dString))); Tcl_DStringInit(&savedResult); Tcl_DStringGetResult(interp, &savedResult); if (Tcl_GlobalEval(interp, Tcl_DStringValue(&dString)) != TCL_OK) { Tcl_BackgroundError(interp); } Tcl_DStringResult(interp, &savedResult); Tcl_DStringFree(&dString); } return result; } /* * ------------------------------------------------------------------------ * * SetdataOp -- * * Registers one or more data formats with a drag&drop target. * Each format has a Tcl command associated with it. This command * is automatically invoked whenever data arrives from a source * to be converted to that particular format. The purpose of the * command is to set the data somewhere in the application (either * using a Tcl command or variable). When the Tcl command is invoked, * special percent substitutions are made: * * %# Drag&drop transaction timestamp. * %W Target widget. * %v Data value transfered from the source to * be converted into the correct format. * * If a converter (command) already exists for a format, it * overwrites the existing command. * * Example: dnd setdata .widget color { . configure -bg %v } * * Results: * A standard Tcl result. * * ------------------------------------------------------------------------ */ static int SetdataOp(clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; int argc; char **argv; { Dnd *dndPtr; Blt_HashEntry *hPtr; Blt_HashSearch cursor; int isNew, nElem; char **cmd; int i; if (GetDnd(clientData, interp, argv[2], &dndPtr) != TCL_OK) { return TCL_ERROR; } if (argc == 3) { /* Show target handler data formats */ for (hPtr = Blt_FirstHashEntry(&(dndPtr->setDataTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { Tcl_AppendElement(interp, Blt_GetHashKey(&(dndPtr->setDataTable), hPtr)); } return TCL_OK; } if (argc == 4) { hPtr = Blt_FindHashEntry(&(dndPtr->setDataTable), argv[3]); if (hPtr == NULL) { Tcl_AppendResult(interp, "can't find handler for format \"", argv[3], "\" for target \"", Tk_PathName(dndPtr->tkwin), "\"", (char *)NULL); return TCL_ERROR; } cmd = (char **)Blt_GetHashValue(hPtr); if (cmd == NULL) { Tcl_SetResult(interp, "", TCL_STATIC); } else { Tcl_SetResult(interp, PrintList(cmd), TCL_DYNAMIC); } return TCL_OK; } for (i = 3; i < argc; i += 2) { hPtr = Blt_CreateHashEntry(&(dndPtr->setDataTable), argv[i], &isNew); if (!isNew) { cmd = (char **)Blt_GetHashValue(hPtr); Blt_Free(cmd); } if (Tcl_SplitList(interp, argv[i + 1], &nElem, &cmd) != TCL_OK) { Blt_DeleteHashEntry(&(dndPtr->setDataTable), hPtr); return TCL_ERROR; } Blt_SetHashValue(hPtr, cmd); } AddTargetProperty(dndPtr); return TCL_OK; } /* * ------------------------------------------------------------------------ * * RegisterOp -- * * dnd register .window * ------------------------------------------------------------------------ */ static int RegisterOp(clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; int argc; char **argv; { DndInterpData *dataPtr = clientData; Tk_Window tkwin; Blt_HashEntry *hPtr; Dnd *dndPtr; int isNew; tkwin = Tk_NameToWindow(interp, argv[2], dataPtr->mainWindow); if (tkwin == NULL) { return TCL_ERROR; } hPtr = Blt_CreateHashEntry(&(dataPtr->dndTable), (char *)tkwin, &isNew); if (!isNew) { Tcl_AppendResult(interp, "\"", Tk_PathName(tkwin), "\" is already registered as a drag&drop manager", (char *)NULL); return TCL_ERROR; } dndPtr = CreateDnd(interp, tkwin); dndPtr->hashPtr = hPtr; dndPtr->dataPtr = dataPtr; Blt_SetHashValue(hPtr, dndPtr); if (Tk_ConfigureWidget(interp, dndPtr->tkwin, configSpecs, argc - 3, argv + 3, (char *)dndPtr, 0) != TCL_OK) { return TCL_ERROR; } if (ConfigureDnd(interp, dndPtr) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } /* * ------------------------------------------------------------------------ * * TokenWindowOp -- * * ------------------------------------------------------------------------ */ static int TokenWindowOp(clientData, interp, argc, argv) ClientData clientData; /* Thread-specific data. */ Tcl_Interp *interp; int argc; char **argv; { Dnd *dndPtr; int flags; if (GetDnd(clientData, interp, argv[3], &dndPtr) != TCL_OK) { return TCL_ERROR; } flags = 0; if (dndPtr->tokenPtr == NULL) { if (CreateToken(interp, dndPtr) != TCL_OK) { return TCL_ERROR; } } else { flags = TK_CONFIG_ARGV_ONLY; } if (ConfigureToken(interp, dndPtr, argc - 4, argv + 4, flags) != TCL_OK) { return TCL_ERROR; } Tcl_SetResult(interp, Tk_PathName(dndPtr->tokenPtr->tkwin), TCL_VOLATILE); return TCL_OK; } /* * ------------------------------------------------------------------------ * * TokenCgetOp -- * * Called to process an (argc,argv) list to configure (or * reconfigure) a drag&drop widget. * * ------------------------------------------------------------------------ */ /* ARGSUSED*/ static int TokenCgetOp(clientData, interp, argc, argv) ClientData clientData; /* Thread-specific data. */ Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Dnd *dndPtr; if (GetDnd(clientData, interp, argv[3], &dndPtr) != TCL_OK) { return TCL_ERROR; } if (dndPtr->tokenPtr == NULL) { Tcl_AppendResult(interp, "no token created for \"", argv[3], "\"", (char *)NULL); return TCL_ERROR; } return Tk_ConfigureValue(interp, dndPtr->tokenPtr->tkwin, tokenConfigSpecs, (char *)dndPtr->tokenPtr, argv[4], TK_CONFIG_ARGV_ONLY); } /* * ------------------------------------------------------------------------ * * TokenConfigureOp -- * * ------------------------------------------------------------------------ */ static int TokenConfigureOp(clientData, interp, argc, argv) ClientData clientData; /* Thread-specific data. */ Tcl_Interp *interp; int argc; char **argv; { Token *tokenPtr; Dnd *dndPtr; int flags; if (GetDnd(clientData, interp, argv[3], &dndPtr) != TCL_OK) { return TCL_ERROR; } flags = TK_CONFIG_ARGV_ONLY; if (dndPtr->tokenPtr == NULL) { Tcl_AppendResult(interp, "no token created for \"", argv[3], "\"", (char *)NULL); return TCL_ERROR; } tokenPtr = dndPtr->tokenPtr; if (argc == 3) { return Tk_ConfigureInfo(interp, tokenPtr->tkwin, tokenConfigSpecs, (char *)tokenPtr, (char *)NULL, flags); } else if (argc == 4) { return Tk_ConfigureInfo(interp, tokenPtr->tkwin, tokenConfigSpecs, (char *)tokenPtr, argv[3], flags); } return ConfigureToken(interp, dndPtr, argc - 4, argv + 4, flags); } static Blt_OpSpec tokenOps[] = { {"cget", 2, (Blt_Op)TokenCgetOp, 5, 5, "widget option",}, {"configure", 2, (Blt_Op)TokenConfigureOp, 4, 0, "widget ?option value?...",}, {"window", 5, (Blt_Op)TokenWindowOp, 4, 0, "widget ?option value?...",}, }; static int nTokenOps = sizeof(tokenOps) / sizeof(Blt_OpSpec); /* * ------------------------------------------------------------------------ * * TokenOp -- * * ------------------------------------------------------------------------ */ static int TokenOp(clientData, interp, argc, argv) ClientData clientData; /* Thread-specific data. */ Tcl_Interp *interp; int argc; char **argv; { Blt_Op proc; int result; proc = Blt_GetOp(interp, nTokenOps, tokenOps, BLT_OP_ARG2, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (clientData, interp, argc, argv); return result; } static Blt_OpSpec dndOps[] = { {"cancel", 2, (Blt_Op)CancelOp, 3, 3, "widget",}, {"cget", 2, (Blt_Op)CgetOp, 4, 4, "widget option",}, {"configure", 4, (Blt_Op)ConfigureOp, 3, 0, "widget ?option value?...",}, #ifdef notdef {"convert", 4, (Blt_Op)ConvertOp, 5, 5, "widget data format",}, #endif {"delete", 2, (Blt_Op)DeleteOp, 3, 0,"?-source|-target? widget...",}, {"drag", 3, (Blt_Op)DragOp, 3, 0, "widget x y ?token?",}, {"drop", 3, (Blt_Op)DropOp, 3, 0, "widget x y ?token?",}, {"getdata", 1, (Blt_Op)GetdataOp, 3, 0, "widget ?format command?",}, {"names", 1, (Blt_Op)NamesOp, 2, 4, "?-source|-target? ?pattern?",}, {"pull", 1, (Blt_Op)PullOp, 4, 4, "widget format",}, {"register", 1, (Blt_Op)RegisterOp, 3, 0, "widget ?option value?...",}, {"select", 3, (Blt_Op)SelectOp, 6, 6, "widget x y timestamp",}, {"setdata", 3, (Blt_Op)SetdataOp, 3, 0, "widget ?format command?",}, {"token", 5, (Blt_Op)TokenOp, 3, 0, "args...",}, }; static int nDndOps = sizeof(dndOps) / sizeof(Blt_OpSpec); /* * ------------------------------------------------------------------------ * * DndCmd -- * * Invoked by TCL whenever the user issues a drag&drop command. * * ------------------------------------------------------------------------ */ static int DndCmd(clientData, interp, argc, argv) ClientData clientData; /* Thread-specific data. */ Tcl_Interp *interp; /* current interpreter */ int argc; /* number of arguments */ char **argv; /* argument strings */ { Blt_Op proc; int result; proc = Blt_GetOp(interp, nDndOps, dndOps, BLT_OP_ARG1, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (clientData, interp, argc, argv); return result; } /* * ----------------------------------------------------------------------- * * DndInterpDeleteProc -- * * This is called when the interpreter hosting the "dnd" command is * destroyed. * * Results: * None. * * Side effects: * Destroys the hash table containing the drag&drop managers. * * ------------------------------------------------------------------------ */ /* ARGSUSED */ static void DndInterpDeleteProc(clientData, interp) ClientData clientData; /* Thread-specific data. */ Tcl_Interp *interp; { DndInterpData *dataPtr = clientData; Dnd *dndPtr; Blt_HashEntry *hPtr; Blt_HashSearch cursor; for (hPtr = Blt_FirstHashEntry(&(dataPtr->dndTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { dndPtr = (Dnd *)Blt_GetHashValue(hPtr); dndPtr->hashPtr = NULL; DestroyDnd((DestroyData)dndPtr); } Blt_DeleteHashTable(&(dataPtr->dndTable)); Tcl_DeleteAssocData(interp, DND_THREAD_KEY); Blt_Free(dataPtr); } static DndInterpData * GetDndInterpData(interp) Tcl_Interp *interp; { DndInterpData *dataPtr; Tcl_InterpDeleteProc *proc; dataPtr = (DndInterpData *)Tcl_GetAssocData(interp, DND_THREAD_KEY, &proc); if (dataPtr == NULL) { Display *display; Tk_Window tkwin; dataPtr = Blt_Malloc(sizeof(DndInterpData)); assert(dataPtr); tkwin = Tk_MainWindow(interp); display = Tk_Display(tkwin); dataPtr->mainWindow = tkwin; dataPtr->display = display; Tcl_SetAssocData(interp, DND_THREAD_KEY, DndInterpDeleteProc, dataPtr); Blt_InitHashTable(&(dataPtr->dndTable), BLT_ONE_WORD_KEYS); dataPtr->mesgAtom = XInternAtom(display, "BLT Dnd Message", False); dataPtr->targetAtom = XInternAtom(display, "BLT Dnd Target", False); dataPtr->formatsAtom = XInternAtom(display, "BLT Dnd Formats",False); dataPtr->commAtom = XInternAtom(display, "BLT Dnd CommData", False); #ifdef HAVE_XDND dataPtr->XdndActionListAtom = XInternAtom(display, "XdndActionList", False); dataPtr->XdndAwareAtom = XInternAtom(display, "XdndAware", False); dataPtr->XdndEnterAtom = XInternAtom(display, "XdndEnter", False); dataPtr->XdndFinishedAtom = XInternAtom(display, "XdndFinished", False); dataPtr->XdndLeaveAtom = XInternAtom(display, "XdndLeave", False); dataPtr->XdndPositionAtom = XInternAtom(display, "XdndPosition", False); dataPtr->XdndSelectionAtom = XInternAtom(display, "XdndSelection", False); dataPtr->XdndStatusAtom = XInternAtom(display, "XdndStatus", False); dataPtr->XdndTypeListAtom = XInternAtom(display, "XdndTypeList", False); #endif /* HAVE_XDND */ } return dataPtr; } /* * ------------------------------------------------------------------------ * * Blt_DndInit -- * * Adds the drag&drop command to the given interpreter. Should * be invoked to properly install the command whenever a new * interpreter is created. * * ------------------------------------------------------------------------ */ int Blt_DndInit(interp) Tcl_Interp *interp; /* interpreter to be updated */ { static Blt_CmdSpec cmdSpec = { "dnd", DndCmd }; DndInterpData *dataPtr; dataPtr = GetDndInterpData(interp); cmdSpec.clientData = dataPtr; if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) { return TCL_ERROR; } return TCL_OK; } #ifdef notdef /* * Registers bitmap outline of dragged data, used to indicate * what is being dragged by source. Bitmap is XOR-ed as cursor/token * is moved around the screen. */ static void Blt_DndSetOutlineBitmap(tkwin, bitmap, x, y) Tk_Window tkwin; Pixmap bitmap; int x, y; { } #endif #ifdef HAVE_XDND static void XDndFreeFormats(handlerPtr) XDndHandler *handlerPtr; { if (handlerPtr->formatArr != NULL) { char **p; for (p = handlerPtr->formatArr; *p != NULL; p++) { XFree(*p); } Blt_Free(handlerPtr->formatArr); handlerPtr->formatArr = NULL; } } static char ** XDndGetFormats(handlerPtr, eventPtr) XDndHandler *handlerPtr; XEvent *eventPtr; { int flags; Window window; unsigned char *data; Atom typeAtom; Atom format; int nItems, bytesAfter; Atom *atomArr; char *nameArr[XDND_MAX_TYPES + 1]; Display *display; XDndFreeFormats(handlerPtr); display = eventPtr->xclient.display; window = eventPtr->xclient.data.l[0]; flags = eventPtr->xclient.data.l[1]; data = NULL; if (flags & 0x01) { result = XGetWindowProperty( display, /* Display of window. */ window, /* Window holding the property. */ handlerPtr->dataPtr->XdndTypeListAtom, /* Name of property. */ 0, /* Offset of data (for multiple reads). */ XDND_MAX_TYPES, /* Maximum number of items to read. */ False, /* If true, delete the property. */ XA_ATOM, /* Desired type of property. */ &typeAtom, /* (out) Actual type of the property. */ &format, /* (out) Actual format of the property. */ &nItems, /* (out) # of items in specified format. */ &bytesAfter, /* (out) # of bytes remaining to be read. */ (unsigned char **)&data); if ((result != Success) || (format != 32) || (typeAtom != XA_ATOM)) { if (data != NULL) { XFree((char *)data); return (char **)NULL; } } atomArr = (Atom *)data; nAtoms = nItems; } else { atomArr = &(eventPtr->xclient.data.l[2]); nAtoms = 3; } formatArr = Blt_Calloc(nAtoms + 1, sizeof(char *)); for (i = 0; (i < nAtoms) && (atomArr[i] != None); i++) { formatArr[i] = XGetAtomName(display, atomArr[i]); } if (data != NULL) { XFree((char *)data); } handlerPtr->formatArr = formatArr; } static char * GetMatchingFormats(dndPtr, formatArr) Dnd *dndPtr; char **formatArr; { int nMatches; nMatches = 0; Tcl_DStringInit(&dString); for (p = formatArr; *p != NULL; p++) { for(hPtr = Blt_FirstHashEntry(&(dndPtr->setDataTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { fmt = Blt_GetHashKey(&(dndPtr->setDataTable), hPtr); if ((*fmt == **p) && (strcmp(fmt, *p) == 0)) { Tcl_DStringAppendElement(&dString, *p); nMatches++; break; } } } if (nMatches > 0) { char *string; string = Blt_Strdup(Tcl_DStringValue(&dString)); Tcl_DStringFree(&dString); return string; } return NULL; } static void XDndPointerEvent(handlerPtr, eventPtr) XDndHandler *handlerPtr; XEvent *eventPtr; { Tk_Window tkwin; int flags; Atom action; Window window; flags = 0; action = None; window = eventPtr->xclient.data.l[MESG_XDND_WINDOW]; /* * If the XDND source has no formats specified, don't process any further. * Simply send a "no accept" action with the message. */ if (handlerPtr->formatArr != NULL) { Dnd *newPtr, *oldPtr; int point; int button, keyState; int x, y; char *formats; point = (int)eventPtr->xclient.data.l[MESG_XDND_POINT]; UNPACK(point, x, y); /* * See if the mouse pointer currently over a drop target. We first * determine what Tk window is under the mouse, and then check if * that window is registered as a drop target. */ newPtr = NULL; tkwin = Tk_CoordsToWindow(x, y, handlerPtr->tkwin); if (tkwin != NULL) { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&(handlerPtr->dataPtr->dndTable), (char *)tkwin); if (hPtr != NULL) { newPtr = (Dnd *)Blt_GetHashValue(hPtr); if (!newPtr->isTarget) { newPtr = NULL; /* Not a DND target. */ } formats = GetMatchingFormats(newPtr, handlerPtr->formatArr); if (formats == NULL) { newPtr = NULL; /* Source has no matching formats. */ } } } button = keyState = 0; oldPtr = handlerPtr->dndPtr; resp = DROP_CANCEL; if (newPtr == oldPtr) { if ((oldPtr != NULL) && (oldPtr->motionCmd != NULL)) { resp = InvokeCallback(oldPtr, oldPtr->motionCmd, x, y, formats, button, keyState, dndPtr->timestamp); } } else { if ((oldPtr != NULL) && (oldPtr->leaveCmd != NULL)) { InvokeCallback(oldPtr, oldPtr->leaveCmd, x, y, formats, button, keyState, dndPtr->timestamp); } if ((newPtr != NULL) && (newPtr->enterCmd != NULL)) { resp = InvokeCallback(newPtr, newPtr->enterCmd, x, y, formats, button, keyState, dndPtr->timestamp); } handlerPtr->dndPtr = newPtr; /* * Save the current mouse position, since we get them from the * drop message. */ newPtr->x = x; newPtr->y = y; } if (formats != NULL) { Blt_Free(formats); } flags = XDND_FLAGS_WANT_POSITION_MSGS; if (resp) { flags |= XDND_FLAGS_ACCEPT_DROP; action = handlerPtr->dataPtr->XdndActionCopyAtom; } } /* Target-to-Source: Drag result message. */ SendClientMsg(handlerPtr->display, window, handlerPtr->dataPtr->XdndStatusAtom, handlerPtr->window, flags, 0, 0, action); } static void XDndDropEvent(handlerPtr, eventPtr) XDndHandler *handlerPtr; XEvent *eventPtr; { Tk_Window tkwin; int flags; Atom action; Window window; int timestamp; flags = 0; action = None; window = eventPtr->xclient.data.l[MESG_XDND_WINDOW]; timestamp = eventPtr->xclient.data.l[MESG_XDND_TIMESTAMP]; /* * If no formats were specified for the XDND source or if the last * motion event did not place the mouse over a valid drop target, * don't process any further. Simply send a "no accept" action with * the message. */ if ((handlerPtr->formatArr != NULL) && (handlerPtr->dndPtr != NULL)) { int button, keyState; Dnd *dndPtr = handlerPtr->dndPtr; DropPending pending; int resp; button = keyState = 0; /* Protocol doesn't supply this information. */ /* Set up temporary bookkeeping for the drop transaction */ memset (&pending, 0, sizeof(pending)); pending.window = window; pending.display = eventPtr->xclient.display; pending.timestamp = timestamp; pending.protocol = PROTO_XDND; pending.packetSize = GetMaxPropertySize(pending.display); Tcl_DStringInit(&(pending.dString)); formats = GetMatchingFormats(handlerPtr->dndPtr, handlerPtr->formatArr); if (formats == NULL) { } dndPtr->pendingPtr = &pending; resp = AcceptDrop(dndPtr, dndPtr->x, dndPtr->y, formats, button, keyState, action, timestamp); dndPtr->pendingPtr = NULL; if (resp) { flags |= XDND_FLAGS_ACCEPT_DROP; action = handlerPtr->dataPtr->XdndActionCopyAtom; } } /* Target-to-Source: Drag result message. */ SendClientMsg(handlerPtr->display, window, handlerPtr->dataPtr->XdndStatusAtom, handlerPtr->window, flags, 0, 0, action); } /* * ------------------------------------------------------------------------ * * XDndProtoEventProc -- * * Invoked by Tk_HandleEvent whenever a DestroyNotify event is received * on a registered drag&drop source widget. * * ------------------------------------------------------------------------ */ static int XDndProtoEventProc(clientData, eventPtr) ClientData clientData; /* Drag&drop record. */ XEvent *eventPtr; /* Event description. */ { DndInterpData *dataPtr = clientData; Tk_Window tkwin; Blt_HashEntry *hPtr; XDndHandler *handlerPtr; int point; int x, y; Atom mesg; if (eventPtr->type != ClientMessage) { return 0; /* Not a ClientMessage event. */ } /* Was the recipient a registered toplevel window? */ hPtr = Blt_FindHashEntry(&(dataPtr->handlerTable), (char *)eventPtr->xclient.window); if (hPtr == NULL) { return 0; /* No handler registered with window. */ } handlerPtr = (XDndHandler *)Blt_GetHashValue(hPtr); mesg = eventPtr->xclient.message_type; if (mesg == dataPtr->XdndEnterAtom) { XDndGetFormats(handlerPtr, eventPtr); handlerPtr->dndPtr = NULL; } else if (mesg == dataPtr->XdndPositionAtom) { XDndPointerEvent(handlerPtr, eventPtr); } else if (mesg == dataPtr->XdndLeaveAtom) { XDndFreeFormats(handlerPtr); /* Free up any collected formats. */ if (handlerPtr->dndPtr != NULL) { InvokeCallback(handlerPtr->dndPtr, handlerPtr->dndPtr->leaveCmd, -1, -1, NULL, 0, 0); /* Send leave event to drop target. */ } } else if (mesg == dataPtr->XdndDropAtom) { XDndDropEvent(handlerPtr, eventPtr); } else { fprintf(stderr, "Unknown client message type = 0x%x\n", mesg); return 0; /* Unknown message type. */ } return 1; } static XDndHandler * XDndCreateHandler(dndPtr) Dnd *dndPtr; { Tk_Window tkwin; Window window; Blt_HashEntry *hPtr; int isNew; XDndHandler *handlerPtr; /* * Find the containing toplevel of this window. See if an XDND * handler is already registered for it. */ tkwin = Blt_GetToplevel(dndPtr->tkwin); window = Blt_GetRealWindowId(tkwin); /* Use the wrapper window as * the real toplevel window. */ hPtr = Blt_CreateHashEntry(&(dataPtr->XDndHandlerTable), (char *)window, &isNew); if (!isNew) { handlerPtr = (XDndHandler *)Blt_GetHashEntry(hPtr); handlerPtr->refCount++; } else { handlerPtr = Blt_Malloc(sizeof(XDndHandler)); handlerPtr->tkwin = tkwin; handlerPtr->dndPtr = NULL; handlerPtr->refCount = 1; handlerPtr->dataPtr = dataPtr; /* FIXME */ SetProperty(window, dataPtr->XdndAwareAtom, "3"); Blt_SetHashValue(hPtr, handlerPtr); } return handlerPtr; } static void XDndDeleteHandler(dndPtr) Dnd *dndPtr; { Tk_Window tkwin; Window window; Blt_HashEntry *hPtr; tkwin = Blt_GetToplevel(dndPtr->tkwin); window = Blt_GetRealWindowId(tkwin); /* Use the wrapper window as the real * toplevel window. */ hPtr = Blt_FindHashEntry(&(dataPtr->XDndHandlerTable), (char *)window); if (hPtr != NULL) { XDndHandler *handlerPtr; handlerPtr = (XDndHandler *)Blt_GetHashEntry(hPtr); handlerPtr->refCount--; if (handlerPtr->refCount == 0) { XDndFreeFormats(handlerPtr); XDeleteProperty(dndPtr->display, window, dndPtr->dataPtr->XdndAwareAtom); Blt_DeleteHashEntry(&(dataPtr->XDndHandlerTable), hPtr); Blt_Free(handlerPtr); } } } #endif /* HAVE_XDND */ #endif /* NO_DRAGDROP */ blt-2.4z.orig/src/bltUnixImage.c0100644000175000017500000011307007527076110015276 0ustar dokodoko /* * bltUnixImage.c -- * * This module implements image processing procedures for the BLT * toolkit. * * Copyright 1997-1998 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. */ #include "bltInt.h" #include "bltImage.h" #include "bltHash.h" #include #include #define CLAMP(c) ((((c) < 0.0) ? 0.0 : ((c) > 255.0) ? 255.0 : (c))) int redAdjust, greenAdjust, blueAdjust; int redMaskShift, greenMaskShift, blueMaskShift; /* *---------------------------------------------------------------------- * * ShiftCount -- * * Returns the position of the least significant (low) bit in * the given mask. * * For TrueColor and DirectColor visuals, a pixel value is * formed by OR-ing the red, green, and blue colormap indices * into a single 32-bit word. The visual's color masks tell * you where in the word the indices are supposed to be. The * masks contain bits only where the index is found. By counting * the leading zeros in the mask, we know how many bits to shift * to the individual red, green, and blue values to form a pixel. * * Results: * The number of the least significant bit. * *---------------------------------------------------------------------- */ static int ShiftCount(mask) register unsigned int mask; { register int count; for (count = 0; count < 32; count++) { if (mask & 0x01) { break; } mask >>= 1; } return count; } /* *---------------------------------------------------------------------- * * CountBits -- * * Returns the number of bits set in the given mask. * * Reference: Graphics Gems Volume 2. * * Results: * The number of bits to set in the mask. * * *---------------------------------------------------------------------- */ static int CountBits(mask) register unsigned long mask; /* 32 1-bit tallies */ { /* 16 2-bit tallies */ mask = (mask & 0x55555555) + ((mask >> 1) & (0x55555555)); /* 8 4-bit tallies */ mask = (mask & 0x33333333) + ((mask >> 2) & (0x33333333)); /* 4 8-bit tallies */ mask = (mask & 0x07070707) + ((mask >> 4) & (0x07070707)); /* 2 16-bit tallies */ mask = (mask & 0x000F000F) + ((mask >> 8) & (0x000F000F)); /* 1 32-bit tally */ mask = (mask & 0x0000001F) + ((mask >> 16) & (0x0000001F)); return mask; } static void ComputeMasks(visualPtr) Visual *visualPtr; { int count; redMaskShift = ShiftCount((unsigned int)visualPtr->red_mask); greenMaskShift = ShiftCount((unsigned int)visualPtr->green_mask); blueMaskShift = ShiftCount((unsigned int)visualPtr->blue_mask); redAdjust = greenAdjust = blueAdjust = 0; count = CountBits((unsigned long)visualPtr->red_mask); if (count < 8) { redAdjust = 8 - count; } count = CountBits((unsigned long)visualPtr->green_mask); if (count < 8) { greenAdjust = 8 - count; } count = CountBits((unsigned long)visualPtr->blue_mask); if (count < 8) { blueAdjust = 8 - count; } } /* *---------------------------------------------------------------------- * * TrueColorPixel -- * * Computes a pixel index from the 3 component RGB values. * * Results: * The pixel index is returned. * *---------------------------------------------------------------------- */ static INLINE unsigned int TrueColorPixel(visualPtr, pixelPtr) Visual *visualPtr; Pix32 *pixelPtr; { unsigned int red, green, blue; /* * The number of bits per color may be less than eight. For example, * 15/16 bit displays (hi-color) use only 5 bits, 8-bit displays * use 2 or 3 bits (don't ask me why you'd have an 8-bit TrueColor * display). So shift off the least significant bits. */ red = ((unsigned int)pixelPtr->Red >> redAdjust); green = ((unsigned int)pixelPtr->Green >> greenAdjust); blue = ((unsigned int)pixelPtr->Blue >> blueAdjust); /* Shift each color into the proper location of the pixel index. */ red = (red << redMaskShift) & visualPtr->red_mask; green = (green << greenMaskShift) & visualPtr->green_mask; blue = (blue << blueMaskShift) & visualPtr->blue_mask; return (red | green | blue); } /* *---------------------------------------------------------------------- * * DirectColorPixel -- * * Translates the 3 component RGB values into a pixel index. * This differs from TrueColor only in that it first translates * the RGB values through a color table. * * Results: * The pixel index is returned. * *---------------------------------------------------------------------- */ static INLINE unsigned int DirectColorPixel(colorTabPtr, pixelPtr) struct ColorTableStruct *colorTabPtr; Pix32 *pixelPtr; { unsigned int red, green, blue; red = colorTabPtr->red[pixelPtr->Red]; green = colorTabPtr->green[pixelPtr->Green]; blue = colorTabPtr->blue[pixelPtr->Blue]; return (red | green | blue); } /* *---------------------------------------------------------------------- * * PseudoColorPixel -- * * Translates the 3 component RGB values into a pixel index. * This differs from TrueColor only in that it first translates * the RGB values through a color table. * * Results: * The pixel index is returned. * *---------------------------------------------------------------------- */ static INLINE unsigned int PseudoColorPixel(pixelPtr, lut) Pix32 *pixelPtr; unsigned int *lut; { int red, green, blue; int pixel; red = (pixelPtr->Red >> 3) + 1; green = (pixelPtr->Green >> 3) + 1; blue = (pixelPtr->Blue >> 3) + 1; pixel = RGBIndex(red, green, blue); return lut[pixel]; } /* *---------------------------------------------------------------------- * * Blt_ColorImageToPixmap -- * * Converts a color image into a pixmap. * * Right now this only handles TrueColor visuals. * * Results: * The new pixmap is returned. * *---------------------------------------------------------------------- */ Pixmap Blt_ColorImageToPixmap(interp, tkwin, image, colorTablePtr) Tcl_Interp *interp; Tk_Window tkwin; Blt_ColorImage image; ColorTable *colorTablePtr; /* Points to array of colormap indices */ { Display *display; int width, height; Pixmap pixmap; GC pixmapGC; Visual *visualPtr; XImage *imagePtr; int nPixels; visualPtr = Tk_Visual(tkwin); width = Blt_ColorImageWidth(image); height = Blt_ColorImageHeight(image); display = Tk_Display(tkwin); ComputeMasks(visualPtr); *colorTablePtr = NULL; imagePtr = XCreateImage(Tk_Display(tkwin), visualPtr, Tk_Depth(tkwin), ZPixmap, 0, (char *)NULL, width, height, 32, 0); assert(imagePtr); nPixels = width * height; imagePtr->data = Blt_Malloc(sizeof(Pix32) * nPixels); assert(imagePtr->data); imagePtr->byte_order = MSBFirst; /* Force the byte order */ imagePtr->bitmap_bit_order = imagePtr->byte_order; imagePtr->bytes_per_line = width * sizeof(Pix32); switch (visualPtr->class) { case TrueColor: { register int x, y; register Pix32 *srcPtr; register char *destPtr; unsigned int pixel; int rowOffset; /* * Compute the colormap locations directly from pixel RGB values. */ srcPtr = Blt_ColorImageBits(image); rowOffset = 0; for (y = 0; y < height; y++) { destPtr = imagePtr->data + rowOffset; for (x = 0; x < width; x++, srcPtr++) { pixel = TrueColorPixel(visualPtr, srcPtr); switch (imagePtr->bits_per_pixel) { case 32: *destPtr++ = (pixel >> 24) & 0xFF; /*FALLTHRU*/ case 24: *destPtr++ = (pixel >> 16) & 0xFF; /*FALLTHRU*/ case 16: *destPtr++ = (pixel >> 8) & 0xFF; /*FALLTHRU*/ case 8: *destPtr++ = pixel & 0xFF; /*FALLTHRU*/ } } rowOffset += imagePtr->bytes_per_line; } } break; case DirectColor: { register int x, y; register Pix32 *srcPtr; register char *destPtr; unsigned int pixel; int rowOffset; struct ColorTableStruct *colorTabPtr; /* Build a color table first */ colorTabPtr = Blt_DirectColorTable(interp, tkwin, image); /* * Compute the colormap locations directly from pixel RGB values. */ srcPtr = Blt_ColorImageBits(image); rowOffset = 0; for (y = 0; y < height; y++) { destPtr = imagePtr->data + rowOffset; for (x = 0; x < width; x++, srcPtr++) { pixel = DirectColorPixel(colorTabPtr, srcPtr); switch (imagePtr->bits_per_pixel) { case 32: *destPtr++ = (pixel >> 24) & 0xFF; /*FALLTHRU*/ case 24: *destPtr++ = (pixel >> 16) & 0xFF; /*FALLTHRU*/ case 16: *destPtr++ = (pixel >> 8) & 0xFF; /*FALLTHRU*/ case 8: *destPtr++ = pixel & 0xFF; /*FALLTHRU*/ } } rowOffset += imagePtr->bytes_per_line; } *colorTablePtr = colorTabPtr; } break; case GrayScale: case StaticGray: case PseudoColor: case StaticColor: { register int x, y; register Pix32 *srcPtr; register char *destPtr; unsigned int pixel; int rowOffset; struct ColorTableStruct *colorTabPtr; colorTabPtr = Blt_PseudoColorTable(interp, tkwin, image); srcPtr = Blt_ColorImageBits(image); rowOffset = 0; for (y = 0; y < height; y++) { destPtr = imagePtr->data + rowOffset; for (x = 0; x < width; x++, srcPtr++) { pixel = PseudoColorPixel(srcPtr, colorTabPtr->lut); switch (imagePtr->bits_per_pixel) { case 32: *destPtr++ = (pixel >> 24) & 0xFF; /*FALLTHRU*/ case 24: *destPtr++ = (pixel >> 16) & 0xFF; /*FALLTHRU*/ case 16: *destPtr++ = (pixel >> 8) & 0xFF; /*FALLTHRU*/ case 8: *destPtr++ = pixel & 0xFF; /*FALLTHRU*/ } } rowOffset += imagePtr->bytes_per_line; } Blt_Free(colorTabPtr->lut); *colorTablePtr = colorTabPtr; } break; default: return None; /* Bad or unknown visual class. */ } pixmapGC = Tk_GetGC(tkwin, 0L, (XGCValues *)NULL); pixmap = Tk_GetPixmap(display, Tk_WindowId(tkwin), width, height, Tk_Depth(tkwin)); XPutImage(display, pixmap, pixmapGC, imagePtr, 0, 0, 0, 0, width, height); XDestroyImage(imagePtr); Tk_FreeGC(display, pixmapGC); return pixmap; } /* ARGSUSED */ static int XGetImageErrorProc(clientData, errEventPtr) ClientData clientData; XErrorEvent *errEventPtr; { int *errorPtr = clientData; *errorPtr = TCL_ERROR; return 0; } /* *---------------------------------------------------------------------- * * Blt_DrawableToColorImage -- * * Takes a snapshot of an X drawable (pixmap or window) and * converts it to a color image. * * The trick here is to efficiently convert the pixel values * (indices into the color table) into RGB color values. In the * days of 8-bit displays, it was simpler to get RGB values for * all 256 indices into the colormap. Instead we'll build a * hashtable of unique pixels and from that an array of pixels to * pass to XQueryColors. For TrueColor visuals, we'll simple * compute the colors from the pixel. * * [I don't know how much faster it would be to take advantage * of all the different visual types. This pretty much depends * on the size of the image and the number of colors it uses.] * * Results: * Returns a color image of the drawable. If an error occurred, * NULL is returned. * *---------------------------------------------------------------------- */ Blt_ColorImage Blt_DrawableToColorImage(tkwin, drawable, x, y, width, height, inputGamma) Tk_Window tkwin; Drawable drawable; register int x, y; /* Offset of image from the drawable's * origin. */ int width, height; /* Dimension of the image. Image must * be completely contained by the * drawable. */ double inputGamma; { XImage *imagePtr; Blt_ColorImage image; register Pix32 *destPtr; unsigned long pixel; int result = TCL_OK; Tk_ErrorHandler errHandler; Visual *visualPtr; unsigned char lut[256]; errHandler = Tk_CreateErrorHandler(Tk_Display(tkwin), BadMatch, X_GetImage, -1, XGetImageErrorProc, &result); imagePtr = XGetImage(Tk_Display(tkwin), drawable, x, y, width, height, AllPlanes, ZPixmap); Tk_DeleteErrorHandler(errHandler); XSync(Tk_Display(tkwin), False); if (result != TCL_OK) { return NULL; } { register int i; double value; for (i = 0; i < 256; i++) { value = pow(i / 255.0, inputGamma) * 255.0 + 0.5; lut[i] = (unsigned char)CLAMP(value); } } /* * First allocate a color image to hold the screen snapshot. */ image = Blt_CreateColorImage(width, height); visualPtr = Tk_Visual(tkwin); if (visualPtr->class == TrueColor) { unsigned int red, green, blue; /* * Directly compute the RGB color values from the pixel index * rather than of going through XQueryColors. */ ComputeMasks(visualPtr); destPtr = Blt_ColorImageBits(image); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { pixel = XGetPixel(imagePtr, x, y); red = ((pixel & visualPtr->red_mask) >> redMaskShift) << redAdjust; green = ((pixel & visualPtr->green_mask) >> greenMaskShift) << greenAdjust; blue = ((pixel & visualPtr->blue_mask) >> blueMaskShift) << blueAdjust; /* * The number of bits per color in the pixel may be * less than eight. For example, 15/16 bit displays * (hi-color) use only 5 bits, 8-bit displays use 2 or * 3 bits (don't ask me why you'd have an 8-bit * TrueColor display). So shift back the least * significant bits. */ destPtr->Red = lut[red]; destPtr->Green = lut[green]; destPtr->Blue = lut[blue]; destPtr->Alpha = (unsigned char)-1; destPtr++; } } XDestroyImage(imagePtr); } else { Blt_HashEntry *hPtr; Blt_HashSearch cursor; Blt_HashTable pixelTable; XColor *colorPtr, *colorArr; Pix32 *endPtr; int nPixels; int nColors; int isNew; /* * Fill the array with each pixel of the image. At the same time, build * up a hashtable of the pixels used. */ nPixels = width * height; Blt_InitHashTableWithPool(&pixelTable, BLT_ONE_WORD_KEYS); destPtr = Blt_ColorImageBits(image); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { pixel = XGetPixel(imagePtr, x, y); hPtr = Blt_CreateHashEntry(&pixelTable, (char *)pixel, &isNew); if (isNew) { Blt_SetHashValue(hPtr, (char *)pixel); } destPtr->value = pixel; destPtr++; } } XDestroyImage(imagePtr); /* * Convert the hashtable of pixels into an array of XColors so * that we can call XQueryColors with it. XQueryColors will * convert the pixels into their RGB values. */ nColors = pixelTable.numEntries; colorArr = Blt_Malloc(sizeof(XColor) * nColors); assert(colorArr); colorPtr = colorArr; for (hPtr = Blt_FirstHashEntry(&pixelTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { colorPtr->pixel = (unsigned long)Blt_GetHashValue(hPtr); Blt_SetHashValue(hPtr, (char *)colorPtr); colorPtr++; } XQueryColors(Tk_Display(tkwin), Tk_Colormap(tkwin), colorArr, nColors); /* * Go again through the array of pixels, replacing each pixel * of the image with its RGB value. */ destPtr = Blt_ColorImageBits(image); endPtr = destPtr + nPixels; for (/* empty */; destPtr < endPtr; destPtr++) { hPtr = Blt_FindHashEntry(&pixelTable, (char *)destPtr->value); colorPtr = (XColor *)Blt_GetHashValue(hPtr); destPtr->Red = lut[colorPtr->red >> 8]; destPtr->Green = lut[colorPtr->green >> 8]; destPtr->Blue = lut[colorPtr->blue >> 8]; destPtr->Alpha = (unsigned char)-1; } Blt_Free(colorArr); Blt_DeleteHashTable(&pixelTable); } return image; } Pixmap Blt_PhotoImageMask(tkwin, src) Tk_Window tkwin; Tk_PhotoImageBlock src; { Pixmap bitmap; int arraySize, bytes_per_line; int offset, count; int value, bitMask; register int x, y; unsigned char *bits; unsigned char *srcPtr; unsigned char *destPtr; unsigned long pixel; bytes_per_line = (src.width + 7) / 8; arraySize = src.height * bytes_per_line; bits = Blt_Malloc(sizeof(unsigned char) * arraySize); assert(bits); destPtr = bits; offset = count = 0; for (y = 0; y < src.height; y++) { value = 0, bitMask = 1; srcPtr = src.pixelPtr + offset; for (x = 0; x < src.width; /*empty*/ ) { pixel = (srcPtr[src.offset[3]] != 0x00); if (pixel) { value |= bitMask; } else { count++; /* Count the number of transparent pixels. */ } bitMask <<= 1; x++; if (!(x & 7)) { *destPtr++ = (unsigned char)value; value = 0, bitMask = 1; } srcPtr += src.pixelSize; } if (x & 7) { *destPtr++ = (unsigned char)value; } offset += src.pitch; } if (count > 0) { Tk_MakeWindowExist(tkwin); bitmap = XCreateBitmapFromData(Tk_Display(tkwin), Tk_WindowId(tkwin), (char *)bits, (unsigned int)src.width, (unsigned int)src.height); } else { bitmap = None; /* Image is opaque. */ } Blt_Free(bits); return bitmap; } Pixmap Blt_ColorImageMask(tkwin, image) Tk_Window tkwin; Blt_ColorImage image; { Pixmap bitmap; int arraySize, bytes_per_line; int count; int value, bitMask; register int x, y; unsigned char *bits; Pix32 *srcPtr; unsigned char *destPtr; unsigned long pixel; int width, height; width = Blt_ColorImageWidth(image); height = Blt_ColorImageHeight(image); bytes_per_line = (width + 7) / 8; arraySize = height * bytes_per_line; bits = Blt_Malloc(sizeof(unsigned char) * arraySize); assert(bits); destPtr = bits; count = 0; srcPtr = Blt_ColorImageBits(image); for (y = 0; y < height; y++) { value = 0, bitMask = 1; for (x = 0; x < width; /*empty*/ ) { pixel = (srcPtr->Alpha != 0x00); if (pixel) { value |= bitMask; } else { count++; /* Count the number of transparent pixels. */ } bitMask <<= 1; x++; if (!(x & 7)) { *destPtr++ = (unsigned char)value; value = 0, bitMask = 1; } srcPtr++; } if (x & 7) { *destPtr++ = (unsigned char)value; } } if (count > 0) { Tk_MakeWindowExist(tkwin); bitmap = XCreateBitmapFromData(Tk_Display(tkwin), Tk_WindowId(tkwin), (char *)bits, (unsigned int)width, (unsigned int)height); } else { bitmap = None; /* Image is opaque. */ } Blt_Free(bits); return bitmap; } /* * ----------------------------------------------------------------- * * Blt_RotateBitmap -- * * Creates a new bitmap containing the rotated image of the given * bitmap. We also need a special GC of depth 1, so that we do * not need to rotate more than one plane of the bitmap. * * Results: * Returns a new bitmap containing the rotated image. * * ----------------------------------------------------------------- */ Pixmap Blt_RotateBitmap(tkwin, srcBitmap, srcWidth, srcHeight, theta, destWidthPtr, destHeightPtr) Tk_Window tkwin; Pixmap srcBitmap; /* Source bitmap to be rotated */ int srcWidth, srcHeight; /* Width and height of the source bitmap */ double theta; /* Right angle rotation to perform */ int *destWidthPtr, *destHeightPtr; { Display *display; /* X display */ Window root; /* Root window drawable */ Pixmap destBitmap; int destWidth, destHeight; XImage *src, *dest; register int x, y; /* Destination bitmap coordinates */ register int sx, sy; /* Source bitmap coordinates */ unsigned long pixel; GC bitmapGC; double rotWidth, rotHeight; display = Tk_Display(tkwin); root = RootWindow(Tk_Display(tkwin), Tk_ScreenNumber(tkwin)); /* Create a bitmap and image big enough to contain the rotated text */ Blt_GetBoundingBox(srcWidth, srcHeight, theta, &rotWidth, &rotHeight, (Point2D *)NULL); destWidth = ROUND(rotWidth); destHeight = ROUND(rotHeight); destBitmap = Tk_GetPixmap(display, root, destWidth, destHeight, 1); bitmapGC = Blt_GetBitmapGC(tkwin); XSetForeground(display, bitmapGC, 0x0); XFillRectangle(display, destBitmap, bitmapGC, 0, 0, destWidth, destHeight); src = XGetImage(display, srcBitmap, 0, 0, srcWidth, srcHeight, 1, ZPixmap); dest = XGetImage(display, destBitmap, 0, 0, destWidth, destHeight, 1, ZPixmap); theta = FMOD(theta, 360.0); if (FMOD(theta, (double)90.0) == 0.0) { int quadrant; /* Handle right-angle rotations specifically */ quadrant = (int)(theta / 90.0); switch (quadrant) { case ROTATE_270: /* 270 degrees */ for (y = 0; y < destHeight; y++) { sx = y; for (x = 0; x < destWidth; x++) { sy = destWidth - x - 1; pixel = XGetPixel(src, sx, sy); if (pixel) { XPutPixel(dest, x, y, pixel); } } } break; case ROTATE_180: /* 180 degrees */ for (y = 0; y < destHeight; y++) { sy = destHeight - y - 1; for (x = 0; x < destWidth; x++) { sx = destWidth - x - 1, pixel = XGetPixel(src, sx, sy); if (pixel) { XPutPixel(dest, x, y, pixel); } } } break; case ROTATE_90: /* 90 degrees */ for (y = 0; y < destHeight; y++) { sx = destHeight - y - 1; for (x = 0; x < destWidth; x++) { sy = x; pixel = XGetPixel(src, sx, sy); if (pixel) { XPutPixel(dest, x, y, pixel); } } } break; case ROTATE_0: /* 0 degrees */ for (y = 0; y < destHeight; y++) { for (x = 0; x < destWidth; x++) { pixel = XGetPixel(src, x, y); if (pixel) { XPutPixel(dest, x, y, pixel); } } } break; default: /* The calling routine should never let this happen. */ break; } } else { double radians, sinTheta, cosTheta; double sox, soy; /* Offset from the center of * the source rectangle. */ double destCX, destCY; /* Offset to the center of the destination * rectangle. */ double tx, ty; /* Translated coordinates from center */ double rx, ry; /* Angle of rotation for x and y coordinates */ radians = (theta / 180.0) * M_PI; sinTheta = sin(radians), cosTheta = cos(radians); /* * Coordinates of the centers of the source and destination rectangles */ sox = srcWidth * 0.5; soy = srcHeight * 0.5; destCX = destWidth * 0.5; destCY = destHeight * 0.5; /* For each pixel of the destination image, transform back to the * associated pixel in the source image. */ for (y = 0; y < destHeight; y++) { ty = y - destCY; for (x = 0; x < destWidth; x++) { /* Translate origin to center of destination image. */ tx = x - destCX; /* Rotate the coordinates about the origin. */ rx = (tx * cosTheta) - (ty * sinTheta); ry = (tx * sinTheta) + (ty * cosTheta); /* Translate back to the center of the source image. */ rx += sox; ry += soy; sx = ROUND(rx); sy = ROUND(ry); /* * Verify the coordinates, since the destination image can be * bigger than the source. */ if ((sx >= srcWidth) || (sx < 0) || (sy >= srcHeight) || (sy < 0)) { continue; } pixel = XGetPixel(src, sx, sy); if (pixel) { XPutPixel(dest, x, y, pixel); } } } } /* Write the rotated image into the destination bitmap. */ XPutImage(display, destBitmap, bitmapGC, dest, 0, 0, 0, 0, destWidth, destHeight); /* Clean up the temporary resources used. */ XDestroyImage(src), XDestroyImage(dest); *destWidthPtr = destWidth; *destHeightPtr = destHeight; return destBitmap; } /* * ----------------------------------------------------------------------- * * Blt_ScaleBitmap -- * * Creates a new scaled bitmap from another bitmap. The new bitmap * is bounded by a specified region. Only this portion of the bitmap * is scaled from the original bitmap. * * By bounding scaling to a region we can generate a new bitmap * which is no bigger than the specified viewport. * * Results: * The new scaled bitmap is returned. * * Side Effects: * A new pixmap is allocated. The caller must release this. * * ----------------------------------------------------------------------- */ Pixmap Blt_ScaleBitmap(tkwin, srcBitmap, srcWidth, srcHeight, destWidth, destHeight) Tk_Window tkwin; Pixmap srcBitmap; int srcWidth, srcHeight, destWidth, destHeight; { Display *display; GC bitmapGC; Pixmap destBitmap; Window root; XImage *src, *dest; double xScale, yScale; register int sx, sy; /* Source bitmap coordinates */ register int x, y; /* Destination bitmap coordinates */ unsigned long pixel; /* Create a new bitmap the size of the region and clear it */ display = Tk_Display(tkwin); root = RootWindow(Tk_Display(tkwin), Tk_ScreenNumber(tkwin)); destBitmap = Tk_GetPixmap(display, root, destWidth, destHeight, 1); bitmapGC = Blt_GetBitmapGC(tkwin); XSetForeground(display, bitmapGC, 0x0); XFillRectangle(display, destBitmap, bitmapGC, 0, 0, destWidth, destHeight); src = XGetImage(display, srcBitmap, 0, 0, srcWidth, srcHeight, 1, ZPixmap); dest = XGetImage(display, destBitmap, 0, 0, destWidth, destHeight, 1, ZPixmap); /* * Scale each pixel of destination image from results of source * image. Verify the coordinates, since the destination image can * be bigger than the source */ xScale = (double)srcWidth / (double)destWidth; yScale = (double)srcHeight / (double)destHeight; /* Map each pixel in the destination image back to the source. */ for (y = 0; y < destHeight; y++) { sy = (int)(yScale * (double)y); for (x = 0; x < destWidth; x++) { sx = (int)(xScale * (double)x); pixel = XGetPixel(src, sx, sy); if (pixel) { XPutPixel(dest, x, y, pixel); } } } /* Write the scaled image into the destination bitmap */ XPutImage(display, destBitmap, bitmapGC, dest, 0, 0, 0, 0, destWidth, destHeight); XDestroyImage(src), XDestroyImage(dest); return destBitmap; } /* * ----------------------------------------------------------------------- * * Blt_RotateScaleBitmapRegion -- * * Creates a scaled and rotated bitmap from a given bitmap. The * caller also provides (offsets and dimensions) the region of * interest in the destination bitmap. This saves having to * process the entire destination bitmap is only part of it is * showing in the viewport. * * This uses a simple rotation/scaling of each pixel in the * destination image. For each pixel, the corresponding * pixel in the source bitmap is used. This means that * destination coordinates are first scaled to the size of * the rotated source bitmap. These coordinates are then * rotated back to their original orientation in the source. * * Results: * The new rotated and scaled bitmap is returned. * * Side Effects: * A new pixmap is allocated. The caller must release this. * * ----------------------------------------------------------------------- */ Pixmap Blt_ScaleRotateBitmapRegion( Tk_Window tkwin, Pixmap srcBitmap, /* Source bitmap. */ unsigned int srcWidth, unsigned int srcHeight, /* Size of source bitmap */ int regionX, int regionY, /* Offset of region in virtual * destination bitmap. */ unsigned int regionWidth, unsigned int regionHeight, /* Desire size of bitmap region. */ unsigned int destWidth, unsigned int destHeight, /* Virtual size of destination bitmap. */ double theta) /* Angle to rotate bitmap. */ { Display *display; /* X display */ Window root; /* Root window drawable */ Pixmap destBitmap; XImage *src, *dest; register int x, y; /* Destination bitmap coordinates */ register int sx, sy; /* Source bitmap coordinates */ unsigned long pixel; double xScale, yScale; double rotWidth, rotHeight; GC bitmapGC; display = Tk_Display(tkwin); root = RootWindow(Tk_Display(tkwin), Tk_ScreenNumber(tkwin)); /* Create a bitmap and image big enough to contain the rotated text */ bitmapGC = Blt_GetBitmapGC(tkwin); destBitmap = Tk_GetPixmap(display, root, regionWidth, regionHeight, 1); XSetForeground(display, bitmapGC, 0x0); XFillRectangle(display, destBitmap, bitmapGC, 0, 0, regionWidth, regionHeight); src = XGetImage(display, srcBitmap, 0, 0, srcWidth, srcHeight, 1, ZPixmap); dest = XGetImage(display, destBitmap, 0, 0, regionWidth, regionHeight, 1, ZPixmap); theta = FMOD(theta, 360.0); Blt_GetBoundingBox(srcWidth, srcHeight, theta, &rotWidth, &rotHeight, (Point2D *)NULL); xScale = rotWidth / (double)destWidth; yScale = rotHeight / (double)destHeight; if (FMOD(theta, (double)90.0) == 0.0) { int quadrant; /* Handle right-angle rotations specifically */ quadrant = (int)(theta / 90.0); switch (quadrant) { case ROTATE_270: /* 270 degrees */ for (y = 0; y < regionHeight; y++) { sx = (int)(yScale * (double)(y + regionY)); for (x = 0; x < regionWidth; x++) { sy = (int)(xScale *(double)(destWidth - (x + regionX) - 1)); pixel = XGetPixel(src, sx, sy); if (pixel) { XPutPixel(dest, x, y, pixel); } } } break; case ROTATE_180: /* 180 degrees */ for (y = 0; y < regionHeight; y++) { sy = (int)(yScale * (double)(destHeight - (y + regionY) - 1)); for (x = 0; x < regionWidth; x++) { sx = (int)(xScale *(double)(destWidth - (x + regionX) - 1)); pixel = XGetPixel(src, sx, sy); if (pixel) { XPutPixel(dest, x, y, pixel); } } } break; case ROTATE_90: /* 90 degrees */ for (y = 0; y < regionHeight; y++) { sx = (int)(yScale * (double)(destHeight - (y + regionY) - 1)); for (x = 0; x < regionWidth; x++) { sy = (int)(xScale * (double)(x + regionX)); pixel = XGetPixel(src, sx, sy); if (pixel) { XPutPixel(dest, x, y, pixel); } } } break; case ROTATE_0: /* 0 degrees */ for (y = 0; y < regionHeight; y++) { sy = (int)(yScale * (double)(y + regionY)); for (x = 0; x < regionWidth; x++) { sx = (int)(xScale * (double)(x + regionX)); pixel = XGetPixel(src, sx, sy); if (pixel) { XPutPixel(dest, x, y, pixel); } } } break; default: /* The calling routine should never let this happen. */ break; } } else { double radians, sinTheta, cosTheta; double sox, soy; /* Offset from the center of the * source rectangle. */ double rox, roy; /* Offset to the center of the * rotated rectangle. */ double tx, ty; /* Translated coordinates from center */ double rx, ry; /* Angle of rotation for x and y coordinates */ radians = (theta / 180.0) * M_PI; sinTheta = sin(radians), cosTheta = cos(radians); /* * Coordinates of the centers of the source and destination rectangles */ sox = srcWidth * 0.5; soy = srcHeight * 0.5; rox = rotWidth * 0.5; roy = rotHeight * 0.5; /* For each pixel of the destination image, transform back to the * associated pixel in the source image. */ for (y = 0; y < regionHeight; y++) { ty = (yScale * (double)(y + regionY)) - roy; for (x = 0; x < regionWidth; x++) { /* Translate origin to center of destination image. */ tx = (xScale * (double)(x + regionX)) - rox; /* Rotate the coordinates about the origin. */ rx = (tx * cosTheta) - (ty * sinTheta); ry = (tx * sinTheta) + (ty * cosTheta); /* Translate back to the center of the source image. */ rx += sox; ry += soy; sx = ROUND(rx); sy = ROUND(ry); /* * Verify the coordinates, since the destination image can be * bigger than the source. */ if ((sx >= srcWidth) || (sx < 0) || (sy >= srcHeight) || (sy < 0)) { continue; } pixel = XGetPixel(src, sx, sy); if (pixel) { XPutPixel(dest, x, y, pixel); } } } } /* Write the rotated image into the destination bitmap. */ XPutImage(display, destBitmap, bitmapGC, dest, 0, 0, 0, 0, regionWidth, regionHeight); /* Clean up the temporary resources used. */ XDestroyImage(src), XDestroyImage(dest); return destBitmap; } #if HAVE_JPEGLIB_H #undef HAVE_STDLIB_H #undef EXTERN #ifdef WIN32 #define XMD_H 1 #endif #include "jpeglib.h" #include typedef struct { struct jpeg_error_mgr pub; /* "public" fields */ jmp_buf jmpBuf; Tcl_DString dString; } ReaderHandler; static void ErrorProc _ANSI_ARGS_((j_common_ptr jpegInfo)); static void MessageProc _ANSI_ARGS_((j_common_ptr jpegInfo)); /* * Here's the routine that will replace the standard error_exit method: */ static void ErrorProc(jpgPtr) j_common_ptr jpgPtr; { ReaderHandler *handlerPtr = (ReaderHandler *)jpgPtr->err; (*handlerPtr->pub.output_message) (jpgPtr); longjmp(handlerPtr->jmpBuf, 1); } static void MessageProc(jpgPtr) j_common_ptr jpgPtr; { ReaderHandler *handlerPtr = (ReaderHandler *)jpgPtr->err; char buffer[JMSG_LENGTH_MAX]; /* Create the message and append it into the dynamic string. */ (*handlerPtr->pub.format_message) (jpgPtr, buffer); Tcl_DStringAppend(&(handlerPtr->dString), " ", -1); Tcl_DStringAppend(&(handlerPtr->dString), buffer, -1); } /* *---------------------------------------------------------------------- * * Blt_JPEGToColorImage -- * * Reads a JPEG file and converts it into a color image. * * Results: * The color image is returned. If an error occured, such * as the designated file could not be opened, NULL is returned. * *---------------------------------------------------------------------- */ Blt_ColorImage Blt_JPEGToColorImage(interp, fileName) Tcl_Interp *interp; char *fileName; { struct jpeg_decompress_struct jpg; Blt_ColorImage image; unsigned int imageWidth, imageHeight; register Pix32 *destPtr; ReaderHandler handler; FILE *f; JSAMPLE **readBuffer; int row_stride; register int i; register JSAMPLE *bufPtr; f = fopen(fileName, "rb"); if (f == NULL) { Tcl_AppendResult(interp, "can't open \"", fileName, "\":", Tcl_PosixError(interp), (char *)NULL); return NULL; } image = NULL; /* Step 1: allocate and initialize JPEG decompression object */ /* We set up the normal JPEG error routines, then override error_exit. */ jpg.dct_method = JDCT_IFAST; jpg.err = jpeg_std_error(&handler.pub); handler.pub.error_exit = ErrorProc; handler.pub.output_message = MessageProc; Tcl_DStringInit(&handler.dString); Tcl_DStringAppend(&handler.dString, "error reading \"", -1); Tcl_DStringAppend(&handler.dString, fileName, -1); Tcl_DStringAppend(&handler.dString, "\": ", -1); if (setjmp(handler.jmpBuf)) { jpeg_destroy_decompress(&jpg); fclose(f); Tcl_DStringResult(interp, &(handler.dString)); return NULL; } jpeg_create_decompress(&jpg); jpeg_stdio_src(&jpg, f); jpeg_read_header(&jpg, TRUE); /* Step 3: read file parameters */ jpeg_start_decompress(&jpg); /* Step 5: Start decompressor */ imageWidth = jpg.output_width; imageHeight = jpg.output_height; if ((imageWidth < 1) || (imageHeight < 1)) { Tcl_AppendResult(interp, "bad JPEG image size", (char *)NULL); fclose(f); return NULL; } /* JSAMPLEs per row in output buffer */ row_stride = imageWidth * jpg.output_components; /* Make a one-row-high sample array that will go away when done * with image */ readBuffer = (*jpg.mem->alloc_sarray) ((j_common_ptr)&jpg, JPOOL_IMAGE, row_stride, 1); image = Blt_CreateColorImage(imageWidth, imageHeight); destPtr = Blt_ColorImageBits(image); if (jpg.output_components == 1) { while (jpg.output_scanline < imageHeight) { jpeg_read_scanlines(&jpg, readBuffer, 1); bufPtr = readBuffer[0]; for (i = 0; i < (int)imageWidth; i++) { destPtr->Red = destPtr->Green = destPtr->Blue = *bufPtr++; destPtr->Alpha = (unsigned char)-1; destPtr++; } } } else { while (jpg.output_scanline < imageHeight) { jpeg_read_scanlines(&jpg, readBuffer, 1); bufPtr = readBuffer[0]; for (i = 0; i < (int)imageWidth; i++) { destPtr->Red = *bufPtr++; destPtr->Green = *bufPtr++; destPtr->Blue = *bufPtr++; destPtr->Alpha = (unsigned char)-1; destPtr++; } } } jpeg_finish_decompress(&jpg); /* We can ignore the return value * since suspension is not * possible with the stdio data * source. */ jpeg_destroy_decompress(&jpg); /* * After finish_decompress, we can close the input file. Here we * postpone it until after no more JPEG errors are possible, so as * to simplify the setjmp error logic above. (Actually, I don't * think that jpeg_destroy can do an error exit, but why assume * anything...) */ fclose(f); /* * At this point you may want to check to see whether any corrupt-data * warnings occurred (test whether jerr.pub.num_warnings is nonzero). */ if (handler.pub.num_warnings > 0) { Tcl_SetErrorCode(interp, "IMAGE", "JPEG", Tcl_DStringValue(&(handler.dString)), (char *)NULL); } else { Tcl_SetErrorCode(interp, "NONE", (char *)NULL); } /* * We're ready to call the Tk_Photo routines. They'll take the RGB * array we've processed to build the Tk image of the JPEG. */ Tcl_DStringFree(&(handler.dString)); return image; } #endif /* HAVE_JPEGLIB_H */ blt-2.4z.orig/src/bltUnixMain.c0100644000175000017500000001272407452443355015152 0ustar dokodoko/* * bltUnixMain.c -- * * Provides a default version of the Tcl_AppInit procedure for * use in wish and similar Tk-based applications. * * Copyright (c) 1993 The Regents of the University of California. * All rights reserved. * * Permission is hereby granted, without written agreement and without * license or royalty fees, to use, copy, modify, and distribute this * software and its documentation for any purpose, provided that the * above copyright notice and the following two paragraphs appear in * all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * 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. */ #include #ifndef TCL_ONLY #include #endif #if HAVE_ITCL_H #include "itcl.h" #endif #if HAVE_ITK_H #include "itk.h" #endif extern int Blt_Init _ANSI_ARGS_((Tcl_Interp *interp)); extern int Blt_SafeInit _ANSI_ARGS_((Tcl_Interp *interp)); /* * The following variable is a special hack that is needed in order for * Sun shared libraries to be used for Tcl. */ #ifdef NEED_MATHERR extern int matherr(); int *tclDummyMathPtr = (int *)matherr; #endif /* *---------------------------------------------------------------------- * * main -- * * This is the main program for the application. * * Results: * None: Tk_Main never returns here, so this procedure never * returns either. * * Side effects: * Whatever the application does. * *---------------------------------------------------------------------- */ int main(argc, argv) int argc; /* Number of command-line arguments. */ char **argv; /* Vector of command-line arguments. */ { #ifdef TCL_ONLY Tcl_Main(argc, argv, Tcl_AppInit); #else Tk_Main(argc, argv, Tcl_AppInit); #endif return 0; /* Needed only to prevent compiler warning. */ } /* *---------------------------------------------------------------------- * * Tcl_AppInit -- * * This procedure performs application-specific initialization. * Most applications, especially those that incorporate additional * packages, will have their own version of this procedure. * * Results: * Returns a standard Tcl completion code, and leaves an error * message in interp->result if an error occurs. * * Side effects: * Depends on the startup script. * *---------------------------------------------------------------------- */ int Tcl_AppInit(interp) Tcl_Interp *interp; /* Interpreter for application. */ { #ifdef TCLLIBPATH /* * It seems that some distributions of Tcl don't compile-in a * default location of the library. This causes Tcl_Init to fail * if bltwish and bltsh are moved to another directory. The * workaround is to set the magic variable "tclDefaultLibrary". */ Tcl_SetVar(interp, "tclDefaultLibrary", TCLLIBPATH, TCL_GLOBAL_ONLY); #endif if (Tcl_Init(interp) == TCL_ERROR) { return TCL_ERROR; } #ifndef TCL_ONLY if (Tk_Init(interp) == TCL_ERROR) { return TCL_ERROR; } #endif /* * Call the init procedures for included packages. Each call should * look like this: * * if (Mod_Init(interp) == TCL_ERROR) { * return TCL_ERROR; * } * * where "Mod" is the name of the module. */ if (Blt_Init(interp) == TCL_ERROR) { return TCL_ERROR; } Tcl_StaticPackage(interp, "BLT", Blt_Init, Blt_SafeInit); /* * Call Tcl_CreateCommand for application-specific commands, if * they weren't already created by the init procedures called above. */ /* * Specify a user-specific startup file to invoke if the application * is run interactively. Typically the startup file is "~/.apprc" * where "app" is the name of the application. If this line is deleted * then no user-specific startup file will be run under any conditions. */ Tcl_SetVar(interp, "tcl_rcFileName", "~/.wishrc", TCL_GLOBAL_ONLY); return TCL_OK; } blt-2.4z.orig/src/bltUnixPipe.c0100644000175000017500000006557707505147041015171 0ustar dokodoko/* * bltUnixPipe.c -- * * Originally taken from tclPipe.c and tclUnixPipe.c in the Tcl * distribution, implements the former Tcl_CreatePipeline API. * This file contains the generic portion of the command channel * driver as well as various utility routines used in managing * subprocesses. * * Copyright (c) 1997 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * */ #include "bltInt.h" #include #include #include "bltWait.h" #if (TCL_MAJOR_VERSION == 7) typedef pid_t Tcl_Pid; #define FILEHANDLER_USES_TCLFILES 1 static int Tcl_GetChannelHandle(channel, direction, clientDataPtr) Tcl_Channel channel; int direction; ClientData *clientDataPtr; { Tcl_File file; file = Tcl_GetChannelFile(channel, direction); if (file == NULL) { return TCL_ERROR; } *clientDataPtr = (ClientData)Tcl_GetFileInfo(file, NULL); return TCL_OK; } #else typedef int Tcl_File; #endif /* TCL_MAJOR_VERSION == 7 */ /* *---------------------------------------------------------------------- * * OpenFile -- * * Open a file for use in a pipeline. * * Results: * Returns a new TclFile handle or NULL on failure. * * Side effects: * May cause a file to be created on the file system. * *---------------------------------------------------------------------- */ static int OpenFile(fname, mode) char *fname; /* The name of the file to open. */ int mode; /* In what mode to open the file? */ { int fd; fd = open(fname, mode, 0666); if (fd != -1) { fcntl(fd, F_SETFD, FD_CLOEXEC); /* * If the file is being opened for writing, seek to the end * so we can append to any data already in the file. */ if (mode & O_WRONLY) { lseek(fd, 0, SEEK_END); } return fd; } return -1; } /* *---------------------------------------------------------------------- * * CreateTempFile -- * * This function creates a temporary file initialized with an * optional string, and returns a file handle with the file pointer * at the beginning of the file. * * Results: * A handle to a file. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int CreateTempFile(contents) char *contents; /* String to write into temp file, or NULL. */ { char fileName[L_tmpnam]; int fd; size_t length = (contents == NULL) ? 0 : strlen(contents); mkstemp(fileName); fd = OpenFile(fileName, O_RDWR | O_CREAT | O_TRUNC); unlink(fileName); if ((fd >= 0) && (length > 0)) { for (;;) { if (write(fd, contents, length) != -1) { break; } else if (errno != EINTR) { close(fd); return -1; } } lseek(fd, 0, SEEK_SET); } return fd; } /* *---------------------------------------------------------------------- * * CreatePipe -- * * Creates a pipe - simply calls the pipe() function. * * Results: * Returns 1 on success, 0 on failure. * * Side effects: * Creates a pipe. * *---------------------------------------------------------------------- */ static int CreatePipe(inFilePtr, outFilePtr) int *inFilePtr; /* (out) Descriptor for read side of pipe. */ int *outFilePtr; /* (out) Descriptor for write side of pipe. */ { int pipeIds[2]; if (pipe(pipeIds) != 0) { return 0; } fcntl(pipeIds[0], F_SETFD, FD_CLOEXEC); fcntl(pipeIds[1], F_SETFD, FD_CLOEXEC); *inFilePtr = pipeIds[0]; *outFilePtr = pipeIds[1]; return 1; } /* *---------------------------------------------------------------------- * * CloseFile -- * * Implements a mechanism to close a UNIX file. * * Results: * Returns 0 on success, or -1 on error, setting errno. * * Side effects: * The file is closed. * *---------------------------------------------------------------------- */ static int CloseFile(fd) int fd; /* File descriptor to be closed. */ { if ((fd == 0) || (fd == 1) || (fd == 2)) { return 0; /* Don't close stdin, stdout or stderr. */ } #if (TCL_MAJOR_VERSION > 7) Tcl_DeleteFileHandler(fd); #endif return close(fd); } /* *---------------------------------------------------------------------- * * RestoreSignals -- * * This procedure is invoked in a forked child process just before * exec-ing a new program to restore all signals to their default * settings. * * Results: * None. * * Side effects: * Signal settings get changed. * *---------------------------------------------------------------------- */ static void RestoreSignals() { #ifdef SIGABRT signal(SIGABRT, SIG_DFL); #endif #ifdef SIGALRM signal(SIGALRM, SIG_DFL); #endif #ifdef SIGFPE signal(SIGFPE, SIG_DFL); #endif #ifdef SIGHUP signal(SIGHUP, SIG_DFL); #endif #ifdef SIGILL signal(SIGILL, SIG_DFL); #endif #ifdef SIGINT signal(SIGINT, SIG_DFL); #endif #ifdef SIGPIPE signal(SIGPIPE, SIG_DFL); #endif #ifdef SIGQUIT signal(SIGQUIT, SIG_DFL); #endif #ifdef SIGSEGV signal(SIGSEGV, SIG_DFL); #endif #ifdef SIGTERM signal(SIGTERM, SIG_DFL); #endif #ifdef SIGUSR1 signal(SIGUSR1, SIG_DFL); #endif #ifdef SIGUSR2 signal(SIGUSR2, SIG_DFL); #endif #ifdef SIGCHLD signal(SIGCHLD, SIG_DFL); #endif #ifdef SIGCONT signal(SIGCONT, SIG_DFL); #endif #ifdef SIGTSTP signal(SIGTSTP, SIG_DFL); #endif #ifdef SIGTTIN signal(SIGTTIN, SIG_DFL); #endif #ifdef SIGTTOU signal(SIGTTOU, SIG_DFL); #endif } /* *---------------------------------------------------------------------- * * SetupStdFile -- * * Set up stdio file handles for the child process, using the * current standard channels if no other files are specified. * If no standard channel is defined, or if no file is associated * with the channel, then the corresponding standard fd is closed. * * Results: * Returns 1 on success, or 0 on failure. * * Side effects: * Replaces stdio fds. * *---------------------------------------------------------------------- */ static int SetupStdFile(fd, type) int fd; /* File descriptor to dup, or -1. */ int type; /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR */ { int targetFd = 0; /* Initializations here needed only to */ int direction = 0; /* prevent warnings about using uninitialized * variables. */ switch (type) { case TCL_STDIN: targetFd = 0; direction = TCL_READABLE; break; case TCL_STDOUT: targetFd = 1; direction = TCL_WRITABLE; break; case TCL_STDERR: targetFd = 2; direction = TCL_WRITABLE; break; } if (fd < 0) { Tcl_Channel channel; channel = Tcl_GetStdChannel(type); if (channel) { Tcl_GetChannelHandle(channel, direction, (ClientData *)&fd); } } if (fd >= 0) { if (fd != targetFd) { if (dup2(fd, targetFd) == -1) { return 0; } /* * Must clear the close-on-exec flag for the target FD, since * some systems (e.g. Ultrix) do not clear the CLOEXEC flag on * the target FD. */ fcntl(targetFd, F_SETFD, 0); } else { /* * Since we aren't dup'ing the file, we need to explicitly clear * the close-on-exec flag. */ fcntl(fd, F_SETFD, 0); } } else { close(targetFd); } return 1; } /* *---------------------------------------------------------------------- * * CreateProcess -- * * Create a child process that has the specified files as its * standard input, output, and error. The child process runs * asynchronously and runs with the same environment variables * as the creating process. * * The path is searched to find the specified executable. * * Results: * The return value is TCL_ERROR and an error message is left in * interp->result if there was a problem creating the child * process. Otherwise, the return value is TCL_OK and *pidPtr is * filled with the process id of the child process. * * Side effects: * A process is created. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int CreateProcess(interp, argc, argv, inputFile, outputFile, errorFile, pidPtr) Tcl_Interp *interp; /* Interpreter in which to leave errors that * occurred when creating the child process. * Error messages from the child process * itself are sent to errorFile. */ int argc; /* Number of arguments in following array. */ char **argv; /* Array of argument strings. argv[0] * contains the name of the executable * converted to native format (using the * Tcl_TranslateFileName call). Additional * arguments have not been converted. */ int inputFile; /* If non-NULL, gives the file to use as * input for the child process. If inputFile * file is not readable or is NULL, the child * will receive no standard input. */ int outputFile; /* If non-NULL, gives the file that * receives output from the child process. If * outputFile file is not writeable or is * NULL, output from the child will be * discarded. */ int errorFile; /* If non-NULL, gives the file that * receives errors from the child process. If * errorFile file is not writeable or is NULL, * errors from the child will be discarded. * errorFile may be the same as outputFile. */ int *pidPtr; /* If this procedure is successful, pidPtr * is filled with the process id of the child * process. */ { int errPipeIn, errPipeOut; int joinThisError, count, status, fd; char errSpace[200]; int pid; errPipeIn = errPipeOut = -1; pid = -1; /* * Create a pipe that the child can use to return error * information if anything goes wrong. */ if (CreatePipe(&errPipeIn, &errPipeOut) == 0) { Tcl_AppendResult(interp, "can't create pipe: ", Tcl_PosixError(interp), (char *)NULL); goto error; } joinThisError = (errorFile == outputFile); pid = fork(); if (pid == 0) { fd = errPipeOut; /* * Set up stdio file handles for the child process. */ if (!SetupStdFile(inputFile, TCL_STDIN) || !SetupStdFile(outputFile, TCL_STDOUT) || (!joinThisError && !SetupStdFile(errorFile, TCL_STDERR)) || (joinThisError && ((dup2(1, 2) == -1) || (fcntl(2, F_SETFD, 0) != 0)))) { sprintf(errSpace, "%dforked process can't set up input/output: ", errno); write(fd, errSpace, (size_t) strlen(errSpace)); _exit(1); } /* * Close the input side of the error pipe. */ RestoreSignals(); execvp(argv[0], &argv[0]); sprintf(errSpace, "%dcan't execute \"%.150s\": ", errno, argv[0]); write(fd, errSpace, (size_t) strlen(errSpace)); _exit(1); } if (pid == -1) { Tcl_AppendResult(interp, "can't fork child process: ", Tcl_PosixError(interp), (char *)NULL); goto error; } /* * Read back from the error pipe to see if the child started * up OK. The info in the pipe (if any) consists of a decimal * errno value followed by an error message. */ CloseFile(errPipeOut); errPipeOut = -1; fd = errPipeIn; count = read(fd, errSpace, (size_t) (sizeof(errSpace) - 1)); if (count > 0) { char *end; errSpace[count] = 0; errno = strtol(errSpace, &end, 10); Tcl_AppendResult(interp, end, Tcl_PosixError(interp), (char *)NULL); goto error; } CloseFile(errPipeIn); *pidPtr = pid; return TCL_OK; error: if (pid != -1) { /* * Reap the child process now if an error occurred during its * startup. */ Tcl_WaitPid((Tcl_Pid)pid, &status, WNOHANG); } if (errPipeIn >= 0) { CloseFile(errPipeIn); } if (errPipeOut >= 0) { CloseFile(errPipeOut); } return TCL_ERROR; } /* *---------------------------------------------------------------------- * * FileForRedirect -- * * This procedure does much of the work of parsing redirection * operators. It handles "@" if specified and allowed, and a file * name, and opens the file if necessary. * * Results: * The return value is the descriptor number for the file. If an * error occurs then NULL is returned and an error message is left * in interp->result. Several arguments are side-effected; see * the argument list below for details. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int FileForRedirect(interp, spec, atOK, arg, nextArg, flags, skipPtr, closePtr) Tcl_Interp *interp; /* Intepreter to use for error reporting. */ char *spec; /* Points to character just after * redirection character. */ char *arg; /* Pointer to entire argument containing * spec: used for error reporting. */ int atOK; /* Non-zero means that '@' notation can be * used to specify a channel, zero means that * it isn't. */ char *nextArg; /* Next argument in argc/argv array, if needed * for file name or channel name. May be * NULL. */ int flags; /* Flags to use for opening file or to * specify mode for channel. */ int *skipPtr; /* Filled with 1 if redirection target was * in spec, 2 if it was in nextArg. */ int *closePtr; /* Filled with one if the caller should * close the file when done with it, zero * otherwise. */ { int writing = (flags & O_WRONLY); Tcl_Channel chan; int fd; int direction; *skipPtr = 1; if ((atOK != 0) && (*spec == '@')) { spec++; if (*spec == '\0') { spec = nextArg; if (spec == NULL) { goto badLastArg; } *skipPtr = 2; } chan = Tcl_GetChannel(interp, spec, NULL); if (chan == NULL) { return -1; } direction = (writing) ? TCL_WRITABLE : TCL_READABLE; if (Tcl_GetChannelHandle(chan, direction, (ClientData *)&fd) != TCL_OK) { fd = -1; } if (fd < 0) { Tcl_AppendResult(interp, "channel \"", Tcl_GetChannelName(chan), "\" wasn't opened for ", ((writing) ? "writing" : "reading"), (char *)NULL); return -1; } if (writing) { /* * Be sure to flush output to the file, so that anything * written by the child appears after stuff we've already * written. */ Tcl_Flush(chan); } } else { char *name; Tcl_DString nameString; if (*spec == '\0') { spec = nextArg; if (spec == NULL) { goto badLastArg; } *skipPtr = 2; } name = Tcl_TranslateFileName(interp, spec, &nameString); if (name != NULL) { fd = OpenFile(name, flags); } else { fd = -1; } Tcl_DStringFree(&nameString); if (fd < 0) { Tcl_AppendResult(interp, "can't ", ((writing) ? "write" : "read"), " file \"", spec, "\": ", Tcl_PosixError(interp), (char *)NULL); return -1; } *closePtr = 1; } return fd; badLastArg: Tcl_AppendResult(interp, "can't specify \"", arg, "\" as last word in command", (char *)NULL); return -1; } /* *---------------------------------------------------------------------- * * Blt_CreatePipeline -- * * Given an argc/argv array, instantiate a pipeline of processes * as described by the argv. * * Results: * The return value is a count of the number of new processes * created, or -1 if an error occurred while creating the pipeline. * *pidArrayPtr is filled in with the address of a dynamically * allocated array giving the ids of all of the processes. It * is up to the caller to free this array when it isn't needed * anymore. If inPipePtr is non-NULL, *inPipePtr is filled in * with the file id for the input pipe for the pipeline (if any): * the caller must eventually close this file. If outPipePtr * isn't NULL, then *outPipePtr is filled in with the file id * for the output pipe from the pipeline: the caller must close * this file. If errPipePtr isn't NULL, then *errPipePtr is filled * with a file id that may be used to read error output after the * pipeline completes. * * Side effects: * Processes and pipes are created. * *---------------------------------------------------------------------- */ int Blt_CreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, outPipePtr, errPipePtr) Tcl_Interp *interp; /* Interpreter to use for error reporting. */ int argc; /* Number of entries in argv. */ char **argv; /* Array of strings describing commands in * pipeline plus I/O redirection with <, * <<, >, etc. Argv[argc] must be NULL. */ int **pidArrayPtr; /* Word at *pidArrayPtr gets filled in with * address of array of pids for processes * in pipeline (first pid is first process * in pipeline). */ int *inPipePtr; /* If non-NULL, input to the pipeline comes * from a pipe (unless overridden by * redirection in the command). The file * id with which to write to this pipe is * stored at *inPipePtr. NULL means command * specified its own input source. */ int *outPipePtr; /* If non-NULL, output to the pipeline goes * to a pipe, unless overriden by redirection * in the command. The file id with which to * read frome this pipe is stored at * *outPipePtr. NULL means command specified * its own output sink. */ int *errPipePtr; /* If non-NULL, all stderr output from the * pipeline will go to a temporary file * created here, and a descriptor to read * the file will be left at *errPipePtr. * The file will be removed already, so * closing this descriptor will be the end * of the file. If this is NULL, then * all stderr output goes to our stderr. * If the pipeline specifies redirection * then the file will still be created * but it will never get any data. */ { int *pidPtr = NULL; /* Points to malloc-ed array holding all * the pids of child processes. */ int nPids; /* Actual number of processes that exist * at *pidPtr right now. */ int cmdCount; /* Count of number of distinct commands * found in argc/argv. */ char *inputLiteral = NULL; /* If non-null, then this points to a * string containing input data (specified * via <<) to be piped to the first process * in the pipeline. */ int inputFd = -1; /* If != NULL, gives file to use as input for * first process in pipeline (specified via < * or <@). */ int inputClose = 0; /* If non-zero, then inputFd should be * closed when cleaning up. */ int outputFd = -1; /* Writable file for output from last command * in pipeline (could be file or pipe). NULL * means use stdout. */ int outputClose = 0; /* If non-zero, then outputFd should be * closed when cleaning up. */ int errorFd = -1; /* Writable file for error output from all * commands in pipeline. NULL means use * stderr. */ int errorClose = 0; /* If non-zero, then errorFd should be * closed when cleaning up. */ char *p; int skip, lastBar, lastArg, i, j, atOK, flags, errorToOutput; Tcl_DString execBuffer; int pipeIn; int curInFd, curOutFd, curErrFd; if (inPipePtr != NULL) { *inPipePtr = -1; } if (outPipePtr != NULL) { *outPipePtr = -1; } if (errPipePtr != NULL) { *errPipePtr = -1; } Tcl_DStringInit(&execBuffer); pipeIn = curInFd = curOutFd = -1; nPids = 0; /* * First, scan through all the arguments to figure out the structure * of the pipeline. Process all of the input and output redirection * arguments and remove them from the argument list in the pipeline. * Count the number of distinct processes (it's the number of "|" * arguments plus one) but don't remove the "|" arguments because * they'll be used in the second pass to seperate the individual * child processes. Cannot start the child processes in this pass * because the redirection symbols may appear anywhere in the * command line -- e.g., the '<' that specifies the input to the * entire pipe may appear at the very end of the argument list. */ lastBar = -1; cmdCount = 1; for (i = 0; i < argc; i++) { skip = 0; p = argv[i]; switch (*p++) { case '\\': continue; case '|': if (*p == '&') { p++; } if (*p == '\0') { if ((i == (lastBar + 1)) || (i == (argc - 1))) { Tcl_AppendResult(interp, "illegal use of | or |& in command", (char *)NULL); goto error; } } lastBar = i; cmdCount++; break; case '<': if (inputClose != 0) { inputClose = 0; CloseFile(inputFd); } if (*p == '<') { inputFd = -1; inputLiteral = p + 1; skip = 1; if (*inputLiteral == '\0') { inputLiteral = argv[i + 1]; if (inputLiteral == NULL) { Tcl_AppendResult(interp, "can't specify \"", argv[i], "\" as last word in command", (char *)NULL); goto error; } skip = 2; } } else { inputLiteral = NULL; inputFd = FileForRedirect(interp, p, 1, argv[i], argv[i + 1], O_RDONLY, &skip, &inputClose); if (inputFd < 0) { goto error; } } break; case '>': atOK = 1; flags = O_WRONLY | O_CREAT | O_TRUNC; errorToOutput = 0; if (*p == '>') { p++; atOK = 0; flags = O_WRONLY | O_CREAT; } if (*p == '&') { if (errorClose != 0) { errorClose = 0; CloseFile(errorFd); } errorToOutput = 1; p++; } if (outputClose != 0) { outputClose = 0; CloseFile(outputFd); } outputFd = FileForRedirect(interp, p, atOK, argv[i], argv[i + 1], flags, &skip, &outputClose); if (outputFd < 0) { goto error; } if (errorToOutput) { errorClose = 0; errorFd = outputFd; } break; case '2': if (*p != '>') { break; } p++; atOK = 1; flags = O_WRONLY | O_CREAT | O_TRUNC; if (*p == '>') { p++; atOK = 0; flags = O_WRONLY | O_CREAT; } if (errorClose != 0) { errorClose = 0; CloseFile(errorFd); } errorFd = FileForRedirect(interp, p, atOK, argv[i], argv[i + 1], flags, &skip, &errorClose); if (errorFd < 0) { goto error; } break; } if (skip != 0) { for (j = i + skip; j < argc; j++) { argv[j - skip] = argv[j]; } argc -= skip; i -= 1; } } if (inputFd == -1) { if (inputLiteral != NULL) { /* * The input for the first process is immediate data coming from * Tcl. Create a temporary file for it and put the data into the * file. */ inputFd = CreateTempFile(inputLiteral); if (inputFd < 0) { Tcl_AppendResult(interp, "can't create input file for command: ", Tcl_PosixError(interp), (char *)NULL); goto error; } inputClose = 1; } else if (inPipePtr != NULL) { /* * The input for the first process in the pipeline is to * come from a pipe that can be written from by the caller. */ if (CreatePipe(&inputFd, inPipePtr) == 0) { Tcl_AppendResult(interp, "can't create input pipe for command: ", Tcl_PosixError(interp), (char *)NULL); goto error; } inputClose = 1; } else { /* * The input for the first process comes from stdin. */ inputFd = 0; } } if (outputFd == -1) { if (outPipePtr != NULL) { /* * Output from the last process in the pipeline is to go to a * pipe that can be read by the caller. */ if (CreatePipe(outPipePtr, &outputFd) == 0) { Tcl_AppendResult(interp, "can't create output pipe for command: ", Tcl_PosixError(interp), (char *)NULL); goto error; } outputClose = 1; } else { /* * The output for the last process goes to stdout. */ outputFd = 1; } } if (errorFd == -1) { if (errPipePtr != NULL) { /* * Stderr from the last process in the pipeline is to go to a * pipe that can be read by the caller. */ if (CreatePipe(errPipePtr, &errorFd) == 0) { Tcl_AppendResult(interp, "can't create error pipe for command: ", Tcl_PosixError(interp), (char *)NULL); goto error; } errorClose = 1; } else { /* * Errors from the pipeline go to stderr. */ errorFd = 2; } } /* * Scan through the argc array, creating a process for each * group of arguments between the "|" characters. */ Tcl_ReapDetachedProcs(); pidPtr = Blt_Malloc((unsigned)(cmdCount * sizeof(int))); curInFd = inputFd; lastArg = 0; /* Suppress compiler warning */ for (i = 0; i < argc; i = lastArg + 1) { int joinThisError; int pid; /* * Convert the program name into native form. */ argv[i] = Tcl_TranslateFileName(interp, argv[i], &execBuffer); if (argv[i] == NULL) { goto error; } /* * Find the end of the current segment of the pipeline. */ joinThisError = 0; for (lastArg = i; lastArg < argc; lastArg++) { if (argv[lastArg][0] == '|') { if (argv[lastArg][1] == '\0') { break; } if ((argv[lastArg][1] == '&') && (argv[lastArg][2] == '\0')) { joinThisError = 1; break; } } } argv[lastArg] = NULL; /* * If this is the last segment, use the specified outputFile. * Otherwise create an intermediate pipe. pipeIn will become the * curInFile for the next segment of the pipe. */ if (lastArg == argc) { curOutFd = outputFd; } else { if (CreatePipe(&pipeIn, &curOutFd) == 0) { Tcl_AppendResult(interp, "can't create pipe: ", Tcl_PosixError(interp), (char *)NULL); goto error; } } if (joinThisError != 0) { curErrFd = curOutFd; } else { curErrFd = errorFd; } if (CreateProcess(interp, lastArg - i, argv + i, curInFd, curOutFd, curErrFd, &pid) != TCL_OK) { goto error; } Tcl_DStringFree(&execBuffer); pidPtr[nPids] = pid; nPids++; /* * Close off our copies of file descriptors that were set up for * this child, then set up the input for the next child. */ if ((curInFd >= 0) && (curInFd != inputFd)) { CloseFile(curInFd); } curInFd = pipeIn; pipeIn = -1; if ((curOutFd >= 0) && (curOutFd != outputFd)) { CloseFile(curOutFd); } curOutFd = -1; } *pidArrayPtr = pidPtr; /* * All done. Cleanup open files lying around and then return. */ cleanup: Tcl_DStringFree(&execBuffer); if (inputClose) { CloseFile(inputFd); } if (outputClose) { CloseFile(outputFd); } if (errorClose) { CloseFile(errorFd); } return nPids; /* * An error occurred. There could have been extra files open, such * as pipes between children. Clean them all up. Detach any child * processes that have been created. */ error: if (pipeIn >= 0) { CloseFile(pipeIn); } if ((curOutFd >= 0) && (curOutFd != outputFd)) { CloseFile(curOutFd); } if ((curInFd >= 0) && (curInFd != inputFd)) { CloseFile(curInFd); } if ((inPipePtr != NULL) && (*inPipePtr >= 0)) { CloseFile(*inPipePtr); *inPipePtr = -1; } if ((outPipePtr != NULL) && (*outPipePtr >= 0)) { CloseFile(*outPipePtr); *outPipePtr = -1; } if ((errPipePtr != NULL) && (*errPipePtr >= 0)) { CloseFile(*errPipePtr); *errPipePtr = -1; } if (pidPtr != NULL) { for (i = 0; i < nPids; i++) { if (pidPtr[i] != -1) { #if (TCL_MAJOR_VERSION == 7) Tcl_DetachPids(1, &pidPtr[i]); #else Tcl_DetachPids(1, (Tcl_Pid *)&pidPtr[i]); #endif } } Blt_Free(pidPtr); } nPids = -1; goto cleanup; } blt-2.4z.orig/src/bltUtil.c0100644000175000017500000011512007530772130014322 0ustar dokodoko/* * bltUtil.c -- * * This module implements utility procedures for the BLT * toolkit. * * Copyright 1991-1998 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. */ #include "bltInt.h" #if defined(__STDC__) #include #else #include #endif #include #ifndef HAVE_STRTOLOWER void strtolower(s) register char *s; { while (*s != '\0') { *s = tolower(UCHAR(*s)); s++; } } #endif /* !HAVE_STRTOLOWER */ #ifndef HAVE_STRCASECMP static unsigned char caseTable[] = { (unsigned char)'\000', (unsigned char)'\001', (unsigned char)'\002', (unsigned char)'\003', (unsigned char)'\004', (unsigned char)'\005', (unsigned char)'\006', (unsigned char)'\007', (unsigned char)'\010', (unsigned char)'\011', (unsigned char)'\012', (unsigned char)'\013', (unsigned char)'\014', (unsigned char)'\015', (unsigned char)'\016', (unsigned char)'\017', (unsigned char)'\020', (unsigned char)'\021', (unsigned char)'\022', (unsigned char)'\023', (unsigned char)'\024', (unsigned char)'\025', (unsigned char)'\026', (unsigned char)'\027', (unsigned char)'\030', (unsigned char)'\031', (unsigned char)'\032', (unsigned char)'\033', (unsigned char)'\034', (unsigned char)'\035', (unsigned char)'\036', (unsigned char)'\037', (unsigned char)'\040', (unsigned char)'\041', (unsigned char)'\042', (unsigned char)'\043', (unsigned char)'\044', (unsigned char)'\045', (unsigned char)'\046', (unsigned char)'\047', (unsigned char)'\050', (unsigned char)'\051', (unsigned char)'\052', (unsigned char)'\053', (unsigned char)'\054', (unsigned char)'\055', (unsigned char)'\056', (unsigned char)'\057', (unsigned char)'\060', (unsigned char)'\061', (unsigned char)'\062', (unsigned char)'\063', (unsigned char)'\064', (unsigned char)'\065', (unsigned char)'\066', (unsigned char)'\067', (unsigned char)'\070', (unsigned char)'\071', (unsigned char)'\072', (unsigned char)'\073', (unsigned char)'\074', (unsigned char)'\075', (unsigned char)'\076', (unsigned char)'\077', (unsigned char)'\100', (unsigned char)'\141', (unsigned char)'\142', (unsigned char)'\143', (unsigned char)'\144', (unsigned char)'\145', (unsigned char)'\146', (unsigned char)'\147', (unsigned char)'\150', (unsigned char)'\151', (unsigned char)'\152', (unsigned char)'\153', (unsigned char)'\154', (unsigned char)'\155', (unsigned char)'\156', (unsigned char)'\157', (unsigned char)'\160', (unsigned char)'\161', (unsigned char)'\162', (unsigned char)'\163', (unsigned char)'\164', (unsigned char)'\165', (unsigned char)'\166', (unsigned char)'\167', (unsigned char)'\170', (unsigned char)'\171', (unsigned char)'\172', (unsigned char)'\133', (unsigned char)'\134', (unsigned char)'\135', (unsigned char)'\136', (unsigned char)'\137', (unsigned char)'\140', (unsigned char)'\141', (unsigned char)'\142', (unsigned char)'\143', (unsigned char)'\144', (unsigned char)'\145', (unsigned char)'\146', (unsigned char)'\147', (unsigned char)'\150', (unsigned char)'\151', (unsigned char)'\152', (unsigned char)'\153', (unsigned char)'\154', (unsigned char)'\155', (unsigned char)'\156', (unsigned char)'\157', (unsigned char)'\160', (unsigned char)'\161', (unsigned char)'\162', (unsigned char)'\163', (unsigned char)'\164', (unsigned char)'\165', (unsigned char)'\166', (unsigned char)'\167', (unsigned char)'\170', (unsigned char)'\171', (unsigned char)'\172', (unsigned char)'\173', (unsigned char)'\174', (unsigned char)'\175', (unsigned char)'\176', (unsigned char)'\177', (unsigned char)'\200', (unsigned char)'\201', (unsigned char)'\202', (unsigned char)'\203', (unsigned char)'\204', (unsigned char)'\205', (unsigned char)'\206', (unsigned char)'\207', (unsigned char)'\210', (unsigned char)'\211', (unsigned char)'\212', (unsigned char)'\213', (unsigned char)'\214', (unsigned char)'\215', (unsigned char)'\216', (unsigned char)'\217', (unsigned char)'\220', (unsigned char)'\221', (unsigned char)'\222', (unsigned char)'\223', (unsigned char)'\224', (unsigned char)'\225', (unsigned char)'\226', (unsigned char)'\227', (unsigned char)'\230', (unsigned char)'\231', (unsigned char)'\232', (unsigned char)'\233', (unsigned char)'\234', (unsigned char)'\235', (unsigned char)'\236', (unsigned char)'\237', (unsigned char)'\240', (unsigned char)'\241', (unsigned char)'\242', (unsigned char)'\243', (unsigned char)'\244', (unsigned char)'\245', (unsigned char)'\246', (unsigned char)'\247', (unsigned char)'\250', (unsigned char)'\251', (unsigned char)'\252', (unsigned char)'\253', (unsigned char)'\254', (unsigned char)'\255', (unsigned char)'\256', (unsigned char)'\257', (unsigned char)'\260', (unsigned char)'\261', (unsigned char)'\262', (unsigned char)'\263', (unsigned char)'\264', (unsigned char)'\265', (unsigned char)'\266', (unsigned char)'\267', (unsigned char)'\270', (unsigned char)'\271', (unsigned char)'\272', (unsigned char)'\273', (unsigned char)'\274', (unsigned char)'\275', (unsigned char)'\276', (unsigned char)'\277', (unsigned char)'\300', (unsigned char)'\341', (unsigned char)'\342', (unsigned char)'\343', (unsigned char)'\344', (unsigned char)'\345', (unsigned char)'\346', (unsigned char)'\347', (unsigned char)'\350', (unsigned char)'\351', (unsigned char)'\352', (unsigned char)'\353', (unsigned char)'\354', (unsigned char)'\355', (unsigned char)'\356', (unsigned char)'\357', (unsigned char)'\360', (unsigned char)'\361', (unsigned char)'\362', (unsigned char)'\363', (unsigned char)'\364', (unsigned char)'\365', (unsigned char)'\366', (unsigned char)'\367', (unsigned char)'\370', (unsigned char)'\371', (unsigned char)'\372', (unsigned char)'\333', (unsigned char)'\334', (unsigned char)'\335', (unsigned char)'\336', (unsigned char)'\337', (unsigned char)'\340', (unsigned char)'\341', (unsigned char)'\342', (unsigned char)'\343', (unsigned char)'\344', (unsigned char)'\345', (unsigned char)'\346', (unsigned char)'\347', (unsigned char)'\350', (unsigned char)'\351', (unsigned char)'\352', (unsigned char)'\353', (unsigned char)'\354', (unsigned char)'\355', (unsigned char)'\356', (unsigned char)'\357', (unsigned char)'\360', (unsigned char)'\361', (unsigned char)'\362', (unsigned char)'\363', (unsigned char)'\364', (unsigned char)'\365', (unsigned char)'\366', (unsigned char)'\367', (unsigned char)'\370', (unsigned char)'\371', (unsigned char)'\372', (unsigned char)'\373', (unsigned char)'\374', (unsigned char)'\375', (unsigned char)'\376', (unsigned char)'\377', }; /* *---------------------------------------------------------------------- * * strcasecmp -- * * Compare two strings, disregarding case. * * Results: * Returns a signed integer representing the following: * * zero - two strings are equal * negative - first string is less than second * positive - first string is greater than second * *---------------------------------------------------------------------- */ int strcasecmp(s1, s2) CONST char *s1; CONST char *s2; { unsigned char *s = (unsigned char *)s1; unsigned char *t = (unsigned char *)s2; for ( /* empty */ ; (caseTable[*s] == caseTable[*t]); s++, t++) { if (*s == '\0') { return 0; } } return (caseTable[*s] - caseTable[*t]); } /* *---------------------------------------------------------------------- * * strncasecmp -- * * Compare two strings, disregarding case, up to a given length. * * Results: * Returns a signed integer representing the following: * * zero - two strings are equal * negative - first string is less than second * positive - first string is greater than second * *---------------------------------------------------------------------- */ int strncasecmp(s1, s2, length) CONST char *s1; CONST char *s2; size_t length; { register unsigned char *s = (unsigned char *)s1; register unsigned char *t = (unsigned char *)s2; for ( /* empty */ ; (length > 0); s++, t++, length--) { if (caseTable[*s] != caseTable[*t]) { return (caseTable[*s] - caseTable[*t]); } if (*s == '\0') { return 0; } } return 0; } #endif /* !HAVE_STRCASECMP */ #if (TCL_VERSION_NUMBER < _VERSION(8,1,0)) && (TCL_MAJOR_VERSION > 7) char * Tcl_GetString(Tcl_Obj *objPtr) { unsigned int dummy; return Tcl_GetStringFromObj(objPtr, &dummy); } int Tcl_EvalObjv(Tcl_Interp *interp, int objc, Tcl_Obj **objv, int flags) { Tcl_DString dString; register int i; int result; Tcl_DStringInit(&dString); for (i = 0; i < objc; i++) { Tcl_DStringAppendElement(&dString, Tcl_GetString(objv[i])); } result = Tcl_Eval(interp, Tcl_DStringValue(&dString)); Tcl_DStringFree(&dString); return result; } int Tcl_WriteObj(Tcl_Channel channel, Tcl_Obj *objPtr) { char *data; int nBytes; data = Tcl_GetStringFromObj(objPtr, &nBytes); return Tcl_Write(channel, data, nBytes); } char * Tcl_SetVar2Ex( Tcl_Interp *interp, char *part1, char *part2, Tcl_Obj *objPtr, int flags) { return Tcl_SetVar2(interp, part1, part2, Tcl_GetString(objPtr), flags); } Tcl_Obj * Tcl_GetVar2Ex( Tcl_Interp *interp, char *part1, char *part2, int flags) { char *result; result = Tcl_GetVar2(interp, part1, part2, flags); if (result == NULL) { return NULL; } return Tcl_NewStringObj(result, -1); } #endif /* *---------------------------------------------------------------------- * * CompareByDictionary * * This function compares two strings as if they were being used in * an index or card catalog. The case of alphabetic characters is * ignored, except to break ties. Thus "B" comes before "b" but * after "a". Also, integers embedded in the strings compare in * numerical order. In other words, "x10y" comes after "x9y", not * before it as it would when using strcmp(). * * Results: * A negative result means that the first element comes before the * second, and a positive result means that the second element * should come first. A result of zero means the two elements * are equal and it doesn't matter which comes first. * * Side effects: * None. * *---------------------------------------------------------------------- */ #if HAVE_UTF int Blt_DictionaryCompare(left, right) char *left, *right; { Tcl_UniChar uniLeft, uniRight, uniLeftLower, uniRightLower; int diff, zeros; int secondaryDiff = 0; for(;;) { if ((isdigit(UCHAR(*right))) && (isdigit(UCHAR(*left)))) { /* * There are decimal numbers embedded in the two * strings. Compare them as numbers, rather than * strings. If one number has more leading zeros than * the other, the number with more leading zeros sorts * later, but only as a secondary choice. */ zeros = 0; while ((*right == '0') && (isdigit(UCHAR(right[1])))) { right++; zeros--; } while ((*left == '0') && (isdigit(UCHAR(left[1])))) { left++; zeros++; } if (secondaryDiff == 0) { secondaryDiff = zeros; } /* * The code below compares the numbers in the two * strings without ever converting them to integers. It * does this by first comparing the lengths of the * numbers and then comparing the digit values. */ diff = 0; for (;;) { if (diff == 0) { diff = UCHAR(*left) - UCHAR(*right); } right++; left++; /* Ignore commas in numbers. */ if (*left == ',') { left++; } if (*right == ',') { right++; } if (!isdigit(UCHAR(*right))) { /* INTL: digit */ if (isdigit(UCHAR(*left))) { /* INTL: digit */ return 1; } else { /* * The two numbers have the same length. See * if their values are different. */ if (diff != 0) { return diff; } break; } } else if (!isdigit(UCHAR(*left))) { /* INTL: digit */ return -1; } } continue; } /* * Convert character to Unicode for comparison purposes. If either * string is at the terminating null, do a byte-wise comparison and * bail out immediately. */ if ((*left != '\0') && (*right != '\0')) { left += Tcl_UtfToUniChar(left, &uniLeft); right += Tcl_UtfToUniChar(right, &uniRight); /* * Convert both chars to lower for the comparison, because * dictionary sorts are case insensitve. Convert to lower, not * upper, so chars between Z and a will sort before A (where most * other interesting punctuations occur) */ uniLeftLower = Tcl_UniCharToLower(uniLeft); uniRightLower = Tcl_UniCharToLower(uniRight); } else { diff = UCHAR(*left) - UCHAR(*right); break; } diff = uniLeftLower - uniRightLower; if (diff) { return diff; } else if (secondaryDiff == 0) { if (Tcl_UniCharIsUpper(uniLeft) && Tcl_UniCharIsLower(uniRight)) { secondaryDiff = -1; } else if (Tcl_UniCharIsUpper(uniRight) && Tcl_UniCharIsLower(uniLeft)) { secondaryDiff = 1; } } } if (diff == 0) { diff = secondaryDiff; } return diff; } #else int Blt_DictionaryCompare(left, right) char *left, *right; /* The strings to compare */ { int diff, zeros; int secondaryDiff = 0; while (1) { if (isdigit(UCHAR(*right)) && isdigit(UCHAR(*left))) { /* * There are decimal numbers embedded in the two * strings. Compare them as numbers, rather than * strings. If one number has more leading zeros than * the other, the number with more leading zeros sorts * later, but only as a secondary choice. */ zeros = 0; while ((*right == '0') && (isdigit(UCHAR(right[1])))) { right++; zeros--; } while ((*left == '0') && (isdigit(UCHAR(left[1])))) { left++; zeros++; } if (secondaryDiff == 0) { secondaryDiff = zeros; } /* * The code below compares the numbers in the two * strings without ever converting them to integers. It * does this by first comparing the lengths of the * numbers and then comparing the digit values. */ diff = 0; while (1) { if (diff == 0) { diff = UCHAR(*left) - UCHAR(*right); } right++; left++; /* Ignore commas in numbers. */ if (*left == ',') { left++; } if (*right == ',') { right++; } if (!isdigit(UCHAR(*right))) { if (isdigit(UCHAR(*left))) { return 1; } else { /* * The two numbers have the same length. See * if their values are different. */ if (diff != 0) { return diff; } break; } } else if (!isdigit(UCHAR(*left))) { return -1; } } continue; } diff = UCHAR(*left) - UCHAR(*right); if (diff) { if (isupper(UCHAR(*left)) && islower(UCHAR(*right))) { diff = UCHAR(tolower(*left)) - UCHAR(*right); if (diff) { return diff; } else if (secondaryDiff == 0) { secondaryDiff = -1; } } else if (isupper(UCHAR(*right)) && islower(UCHAR(*left))) { diff = UCHAR(*left) - UCHAR(tolower(UCHAR(*right))); if (diff) { return diff; } else if (secondaryDiff == 0) { secondaryDiff = 1; } } else { return diff; } } if (*left == 0) { break; } left++; right++; } if (diff == 0) { diff = secondaryDiff; } return diff; } #endif #ifndef NDEBUG void Blt_Assert(testExpr, fileName, lineNumber) char *testExpr; char *fileName; int lineNumber; { #ifdef WINDEBUG PurifyPrintf("line %d of %s: Assert \"%s\" failed\n", lineNumber, fileName, testExpr); #endif fprintf(stderr, "line %d of %s: Assert \"%s\" failed\n", lineNumber, fileName, testExpr); fflush(stderr); abort(); } #endif /*ARGSUSED*/ void Blt_Panic TCL_VARARGS_DEF(char *, arg1) { va_list argList; char *format; format = TCL_VARARGS_START(char *, arg1, argList); vfprintf(stderr, format, argList); fprintf(stderr, "\n"); fflush(stderr); abort(); } void Blt_DStringAppendElements TCL_VARARGS_DEF(Tcl_DString *, arg1) { va_list argList; Tcl_DString *dsPtr; register char *elem; dsPtr = TCL_VARARGS_START(Tcl_DString *, arg1, argList); while ((elem = va_arg(argList, char *)) != NULL) { Tcl_DStringAppendElement(dsPtr, elem); } va_end(argList); } static char stringRep[200]; char * Blt_Itoa(value) int value; { sprintf(stringRep, "%d", value); return stringRep; } char * Blt_Utoa(value) unsigned int value; { sprintf(stringRep, "%u", value); return stringRep; } char * Blt_Dtoa(interp, value) Tcl_Interp *interp; double value; { Tcl_PrintDouble(interp, value, stringRep); return stringRep; } #if HAVE_UTF #undef fopen FILE * Blt_OpenUtfFile(fileName, mode) char *fileName, *mode; { Tcl_DString dString; FILE *f; fileName = Tcl_UtfToExternalDString(NULL, fileName, -1, &dString); f = fopen(fileName, mode); Tcl_DStringFree(&dString); return f; } #endif /* HAVE_UTF */ /* *-------------------------------------------------------------- * * Blt_InitHexTable -- * * Table index for the hex values. Initialized once, first time. * Used for translation value or delimiter significance lookup. * * We build the table at run time for several reasons: * * 1. portable to non-ASCII machines. * 2. still reentrant since we set the init flag after setting * table. * 3. easier to extend. * 4. less prone to bugs. * * Results: * None. * *-------------------------------------------------------------- */ void Blt_InitHexTable(hexTable) char hexTable[]; { hexTable['0'] = 0; hexTable['1'] = 1; hexTable['2'] = 2; hexTable['3'] = 3; hexTable['4'] = 4; hexTable['5'] = 5; hexTable['6'] = 6; hexTable['7'] = 7; hexTable['8'] = 8; hexTable['9'] = 9; hexTable['a'] = hexTable['A'] = 10; hexTable['b'] = hexTable['B'] = 11; hexTable['c'] = hexTable['C'] = 12; hexTable['d'] = hexTable['D'] = 13; hexTable['e'] = hexTable['E'] = 14; hexTable['f'] = hexTable['F'] = 15; } /* *-------------------------------------------------------------- * * Blt_GetPosition -- * * Convert a string representing a numeric position. * A position can be in one of the following forms. * * number - number of the item in the hierarchy, indexed * from zero. * "end" - last position in the hierarchy. * * Results: * A standard Tcl result. If "string" is a valid index, then * *indexPtr is filled with the corresponding numeric index. * If "end" was selected then *indexPtr is set to -1. * Otherwise an error message is left in interp->result. * * Side effects: * None. * *-------------------------------------------------------------- */ int Blt_GetPosition(interp, string, indexPtr) Tcl_Interp *interp; /* Interpreter to report results back * to. */ char *string; /* String representation of the index. * Can be an integer or "end" to refer * to the last index. */ int *indexPtr; /* Holds the converted index. */ { if ((string[0] == 'e') && (strcmp(string, "end") == 0)) { *indexPtr = -1; /* Indicates last position in hierarchy. */ } else { int position; if (Tcl_GetInt(interp, string, &position) != TCL_OK) { return TCL_ERROR; } if (position < 0) { Tcl_AppendResult(interp, "bad position \"", string, "\"", (char *)NULL); return TCL_ERROR; } *indexPtr = position; } return TCL_OK; } /* * The hash table below is used to keep track of all the Blt_Uids created * so far. */ static Blt_HashTable uidTable; static int uidInitialized = 0; /* *---------------------------------------------------------------------- * * Blt_GetUid -- * * Given a string, returns a unique identifier for the string. * A reference count is maintained, so that the identifier * can be freed when it is not needed any more. This can be used * in many places to replace Tcl_GetUid. * * Results: * This procedure returns a Blt_Uid corresponding to the "string" * argument. The Blt_Uid has a string value identical to string * (strcmp will return 0), but it's guaranteed that any other * calls to this procedure with a string equal to "string" will * return exactly the same result (i.e. can compare Blt_Uid * *values* directly, without having to call strcmp on what they * point to). * * Side effects: * New information may be entered into the identifier table. * *---------------------------------------------------------------------- */ Blt_Uid Blt_GetUid(string) char *string; /* String to convert. */ { int isNew; Blt_HashEntry *hPtr; int refCount; if (!uidInitialized) { Blt_InitHashTable(&uidTable, BLT_STRING_KEYS); uidInitialized = 1; } hPtr = Blt_CreateHashEntry(&uidTable, string, &isNew); if (isNew) { refCount = 0; } else { refCount = (int)Blt_GetHashValue(hPtr); } refCount++; Blt_SetHashValue(hPtr, (ClientData)refCount); return (Blt_Uid)Blt_GetHashKey(&uidTable, hPtr); } /* *---------------------------------------------------------------------- * * Blt_FreeUid -- * * Frees the Blt_Uid if there are no more clients using this * identifier. * * Results: * None. * * Side effects: * The identifier may be deleted from the identifier table. * *---------------------------------------------------------------------- */ void Blt_FreeUid(uid) Blt_Uid uid; /* Identifier to release. */ { Blt_HashEntry *hPtr; if (!uidInitialized) { Blt_InitHashTable(&uidTable, BLT_STRING_KEYS); uidInitialized = 1; } hPtr = Blt_FindHashEntry(&uidTable, uid); if (hPtr) { int refCount; refCount = (int)Blt_GetHashValue(hPtr); refCount--; if (refCount == 0) { Blt_DeleteHashEntry(&uidTable, hPtr); } else { Blt_SetHashValue(hPtr, (ClientData)refCount); } } else { fprintf(stderr, "tried to release unknown identifier \"%s\"\n", uid); } } /* *---------------------------------------------------------------------- * * Blt_FindUid -- * * Returns a Blt_Uid associated with a given string, if one exists. * * Results: * A Blt_Uid for the string if one exists. Otherwise NULL. * *---------------------------------------------------------------------- */ Blt_Uid Blt_FindUid(string) char *string; /* String to find. */ { Blt_HashEntry *hPtr; if (!uidInitialized) { Blt_InitHashTable(&uidTable, BLT_STRING_KEYS); uidInitialized = 1; } hPtr = Blt_FindHashEntry(&uidTable, string); if (hPtr == NULL) { return NULL; } return (Blt_Uid) Blt_GetHashKey(&uidTable, hPtr); } /* *---------------------------------------------------------------------- * * BinaryOpSearch -- * * Performs a binary search on the array of command operation * specifications to find a partial, anchored match for the * given operation string. * * Results: * If the string matches unambiguously the index of the specification * in the array is returned. If the string does not match, even * as an abbreviation, any operation, -1 is returned. If the string * matches, but ambiguously -2 is returned. * *---------------------------------------------------------------------- */ static int BinaryOpSearch(specArr, nSpecs, string) Blt_OpSpec specArr[]; int nSpecs; char *string; /* Name of minor operation to search for */ { Blt_OpSpec *specPtr; char c; register int high, low, median; register int compare, length; low = 0; high = nSpecs - 1; c = string[0]; length = strlen(string); while (low <= high) { median = (low + high) >> 1; specPtr = specArr + median; /* Test the first character */ compare = c - specPtr->name[0]; if (compare == 0) { /* Now test the entire string */ compare = strncmp(string, specPtr->name, length); if (compare == 0) { if (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 */ } /* *---------------------------------------------------------------------- * * LinearOpSearch -- * * Performs a binary search on the array of command operation * specifications to find a partial, anchored match for the * given operation string. * * Results: * If the string matches unambiguously the index of the specification * in the array is returned. If the string does not match, even * as an abbreviation, any operation, -1 is returned. If the string * matches, but ambiguously -2 is returned. * *---------------------------------------------------------------------- */ static int LinearOpSearch(specArr, nSpecs, string) Blt_OpSpec specArr[]; int nSpecs; char *string; /* Name of minor operation to search for */ { Blt_OpSpec *specPtr; char c; int length, nMatches, last; register int i; c = string[0]; length = strlen(string); nMatches = 0; last = -1; for (specPtr = specArr, i = 0; i < nSpecs; i++, specPtr++) { if ((c == specPtr->name[0]) && (strncmp(string, specPtr->name, length) == 0)) { last = i; nMatches++; if (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. */ } /* *---------------------------------------------------------------------- * * Blt_GetOp -- * * Find the command operation given a string name. This is useful * where a group of command operations have the same argument * signature. * * Results: * If found, a pointer to the procedure (function pointer) is * returned. Otherwise NULL is returned and an error message * containing a list of the possible commands is returned in * interp->result. * *---------------------------------------------------------------------- */ Blt_Op Blt_GetOp(interp, nSpecs, specArr, operPos, argc, argv, flags) Tcl_Interp *interp; /* Interpreter to report errors to */ int nSpecs; /* Number of specifications in array */ Blt_OpSpec specArr[]; /* Op specification array */ int operPos; /* Index of the operation name argument */ int argc; /* Number of arguments in the argument vector. * This includes any prefixed arguments */ char *argv[]; /* Argument vector */ int flags; /* */ { Blt_OpSpec *specPtr; char *string; register int i; register int n; if (argc <= 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 (i = 0; i < operPos; i++) { Tcl_AppendResult(interp, argv[i], " ", (char *)NULL); } specPtr = specArr + n; Tcl_AppendResult(interp, specPtr->name, " ", specPtr->usage, (char *)NULL); } return NULL; } string = argv[operPos]; if (flags & BLT_OP_LINEAR_SEARCH) { n = LinearOpSearch(specArr, nSpecs, string); } else { n = BinaryOpSearch(specArr, nSpecs, string); } if (n == -2) { char c; int length; Tcl_AppendResult(interp, "ambiguous", (char *)NULL); if (operPos > 2) { Tcl_AppendResult(interp, " ", argv[operPos - 1], (char *)NULL); } Tcl_AppendResult(interp, " operation \"", string, "\" matches:", (char *)NULL); c = string[0]; length = strlen(string); for (n = 0; n < nSpecs; n++) { specPtr = specArr + 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, " ", argv[operPos - 1], (char *)NULL); } Tcl_AppendResult(interp, " operation \"", string, "\": ", (char *)NULL); goto usage; } specPtr = specArr + n; if ((argc < specPtr->minArgs) || ((specPtr->maxArgs > 0) && (argc > specPtr->maxArgs))) { Tcl_AppendResult(interp, "wrong # args: should be \"", (char *)NULL); for (i = 0; i < operPos; i++) { Tcl_AppendResult(interp, argv[i], " ", (char *)NULL); } Tcl_AppendResult(interp, specPtr->name, " ", specPtr->usage, "\"", (char *)NULL); return NULL; } return specPtr->proc; } #if (TCL_VERSION_NUMBER >= _VERSION(8,0,0)) /* *---------------------------------------------------------------------- * * Blt_GetOpFromObj -- * * Find the command operation given a string name. This is useful * where a group of command operations have the same argument * signature. * * Results: * If found, a pointer to the procedure (function pointer) is * returned. Otherwise NULL is returned and an error message * containing a list of the possible commands is returned in * interp->result. * *---------------------------------------------------------------------- */ Blt_Op Blt_GetOpFromObj(interp, nSpecs, specArr, operPos, objc, objv, flags) Tcl_Interp *interp; /* Interpreter to report errors to */ int nSpecs; /* Number of specifications in array */ Blt_OpSpec specArr[]; /* Op specification array */ int operPos; /* Position of operation in argument list. */ int objc; /* Number of arguments in the argument vector. * This includes any prefixed arguments */ Tcl_Obj *CONST objv[]; /* Argument vector */ int flags; { Blt_OpSpec *specPtr; char *string; register int i; register 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 (i = 0; i < operPos; i++) { Tcl_AppendResult(interp, Tcl_GetString(objv[i]), " ", (char *)NULL); } specPtr = specArr + n; Tcl_AppendResult(interp, specPtr->name, " ", specPtr->usage, (char *)NULL); } return NULL; } string = Tcl_GetString(objv[operPos]); if (flags & BLT_OP_LINEAR_SEARCH) { n = LinearOpSearch(specArr, nSpecs, string); } else { n = BinaryOpSearch(specArr, nSpecs, string); } if (n == -2) { char c; int length; 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]; length = strlen(string); for (n = 0; n < nSpecs; n++) { specPtr = specArr + 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 = specArr + n; if ((objc < specPtr->minArgs) || ((specPtr->maxArgs > 0) && (objc > specPtr->maxArgs))) { 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; } #endif #include /* open a file * calculate the CRC32 of the entire contents * return the CRC * if there is an error rdet the global variable Crcerror */ /* ---------------------------------------------------------------- */ /* this is the CRC32 lookup table * thanks Gary S. Brown * 64 lines of 4 values for a 256 dword table (1024 bytes) */ static unsigned long crcTab[256] = { /* CRC polynomial 0xedb88320 */ 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, 0x2d02ef8dUL }; #define CRC32(c, b) (crcTab[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8)) #define DO1(buf) crc = CRC32(crc, *buf++) #define DO2(buf) DO1(buf); DO1(buf) #define DO4(buf) DO2(buf); DO2(buf) #define DO8(buf) DO4(buf); DO4(buf) static int Crc32Cmd( ClientData clientData, Tcl_Interp *interp, int argc, char **argv) { register unsigned int crc; char buf[200]; crc = 0L; crc = crc ^ 0xffffffffL; if (strcmp(argv[1], "-data") == 0) { register char *p; if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ?fileName? ?-data dataString?", (char *)NULL); return TCL_ERROR; } for (p = argv[2]; *p != '\0'; p++) { crc = CRC32(crc, *p); } } else { register int c; FILE *f; if (argc != 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ?fileName? ?-data dataString?", (char *)NULL); return TCL_ERROR; } f = fopen(argv[1], "rb"); if (f == NULL) { Tcl_AppendResult(interp, "can't open file \"", argv[1], "\": ", Tcl_PosixError(interp), (char *)NULL); return TCL_ERROR; } while((c = getc(f)) != EOF) { crc = CRC32(crc, c); } fclose(f); } crc = crc ^ 0xffffffffL; sprintf(buf, "%x", crc); Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_OK; } int Blt_Crc32Init(interp) Tcl_Interp *interp; { static Blt_CmdSpec cmdSpec = {"crc32", Crc32Cmd,}; if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) { return TCL_ERROR; } return TCL_OK; } blt-2.4z.orig/src/bltVecCmd.c0100644000175000017500000014276707510711437014570 0ustar dokodoko/* * bltVecCmd.c -- * * This module implements vector data objects. * * Copyright 1995-1998 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. */ /* * 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 "bltVecInt.h" #if (TCL_MAJOR_VERSION == 7) static void GetValues(vPtr, first, last, resultPtr) VectorObject *vPtr; int first, last; Tcl_DString *resultPtr; { register int i; char valueString[TCL_DOUBLE_SPACE + 1]; for (i = first; i <= last; i++) { Tcl_PrintDouble(vPtr->interp, vPtr->valueArr[i], valueString); Tcl_DStringAppendElement(resultPtr, valueString); } } static void ReplicateValue(vPtr, first, last, value) VectorObject *vPtr; int first, last; double value; { register int i; for (i = first; i <= last; i++) { vPtr->valueArr[i] = value; } vPtr->notifyFlags |= UPDATE_RANGE; } static int CopyList(vPtr, nElem, elemArr) VectorObject *vPtr; int nElem; char **elemArr; { register int i; double value; if (Blt_VectorChangeLength(vPtr, nElem) != TCL_OK) { return TCL_ERROR; } for (i = 0; i < nElem; i++) { if (Tcl_GetDouble(vPtr->interp, elemArr[i], &value)!= TCL_OK) { vPtr->length = i; return TCL_ERROR; } vPtr->valueArr[i] = value; } return TCL_OK; } static int AppendVector(destPtr, srcPtr) VectorObject *destPtr, *srcPtr; { int nBytes; int oldSize, newSize; oldSize = destPtr->length; newSize = oldSize + srcPtr->last - srcPtr->first + 1; if (Blt_VectorChangeLength(destPtr, newSize) != TCL_OK) { return TCL_ERROR; } 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(vPtr, nElem, elemArr) VectorObject *vPtr; int nElem; char **elemArr; { int count; register int i; double value; int oldSize; oldSize = vPtr->length; if (Blt_VectorChangeLength(vPtr, vPtr->length + nElem) != TCL_OK) { return TCL_ERROR; } count = oldSize; for (i = 0; i < nElem; i++) { if (Tcl_ExprDouble(vPtr->interp, elemArr[i], &value) != TCL_OK) { vPtr->length = count; return TCL_ERROR; } vPtr->valueArr[count++] = value; } vPtr->notifyFlags |= UPDATE_RANGE; return TCL_OK; } /* Vector instance option commands */ /* * ----------------------------------------------------------------------- * * AppendOp -- * * Appends one of more Tcl lists of values, or vector objects * onto the end of the current vector object. * * Results: * A standard Tcl result. If a current vector can't be created, * resized, any of the named vectors can't be found, or one of * lists of values is invalid, TCL_ERROR is returned. * * Side Effects: * Clients of current vector will be notified of the change. * * ----------------------------------------------------------------------- */ static int AppendOp(vPtr, interp, argc, argv) VectorObject *vPtr; Tcl_Interp *interp; int argc; char **argv; { register int i; int result; VectorObject *v2Ptr; for (i = 2; i < argc; i++) { v2Ptr = Blt_VectorParseElement((Tcl_Interp *)NULL, vPtr->dataPtr, argv[i], (char **)NULL, NS_SEARCH_BOTH); if (v2Ptr != NULL) { result = AppendVector(vPtr, v2Ptr); } else { int nElem; char **elemArr; if (Tcl_SplitList(interp, argv[i], &nElem, &elemArr) != TCL_OK) { return TCL_ERROR; } result = AppendList(vPtr, nElem, elemArr); Blt_Free(elemArr); } if (result != TCL_OK) { return TCL_ERROR; } } if (argc > 2) { if (vPtr->flush) { Blt_VectorFlushCache(vPtr); } Blt_VectorUpdateClients(vPtr); } return TCL_OK; } /* * ----------------------------------------------------------------------- * * ClearOp -- * * Deletes all the accumulated array indices for the Tcl array * associated will the vector. This routine can be used to * free excess memory from a large vector. * * Results: * Always returns TCL_OK. * * Side Effects: * Memory used for the entries of the Tcl array variable is freed. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int ClearOp(vPtr, interp, argc, argv) VectorObject *vPtr; Tcl_Interp *interp; int argc; char **argv; { Blt_VectorFlushCache(vPtr); return TCL_OK; } /* * ----------------------------------------------------------------------- * * DeleteOp -- * * Deletes the given indices from the vector. If no indices are * provided the entire vector is deleted. * * Results: * A standard Tcl result. If any of the given indices is invalid, * interp->result will an error message and TCL_ERROR is returned. * * Side Effects: * The clients of the vector will be notified of the vector * deletions. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int DeleteOp(vPtr, interp, argc, argv) VectorObject *vPtr; Tcl_Interp *interp; int argc; char **argv; { unsigned char *unsetArr; register int i, j; register int count; if (argc == 2) { Blt_VectorFree(vPtr); return TCL_OK; } /* * Allocate an "unset" bitmap the size of the vector. We should * try to use bit fields instead of a character array, since * memory may be an issue if the vector is large. */ unsetArr = Blt_Calloc(sizeof(unsigned char), vPtr->length); assert(unsetArr); for (i = 2; i < argc; i++) { if (Blt_VectorGetIndexRange(interp, vPtr, argv[i], (INDEX_COLON | INDEX_CHECK), (Blt_VectorIndexProc **) NULL) != TCL_OK) { Blt_Free(unsetArr); return TCL_ERROR; } for (j = vPtr->first; j <= vPtr->last; j++) { unsetArr[j] = TRUE; } } count = 0; for (i = 0; i < vPtr->length; i++) { if (unsetArr[i]) { continue; } if (count < i) { vPtr->valueArr[count] = vPtr->valueArr[i]; } count++; } Blt_Free(unsetArr); vPtr->length = count; if (vPtr->flush) { Blt_VectorFlushCache(vPtr); } Blt_VectorUpdateClients(vPtr); return TCL_OK; } /* * ----------------------------------------------------------------------- * * DupOp -- * * Creates one or more duplicates of the vector object. * * Results: * A standard Tcl result. If a new vector can't be created, * or and existing vector resized, TCL_ERROR is returned. * * Side Effects: * Clients of existing vectors will be notified of the change. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int DupOp(vPtr, interp, argc, argv) VectorObject *vPtr; Tcl_Interp *interp; /* Not used. */ int argc; char **argv; { VectorObject *v2Ptr; int isNew; register int i; for (i = 2; i < argc; i++) { v2Ptr = Blt_VectorCreate(vPtr->dataPtr, argv[i], argv[i], argv[i], &isNew); if (v2Ptr == NULL) { return TCL_ERROR; } if (v2Ptr == vPtr) { continue; } if (Blt_VectorDuplicate(v2Ptr, vPtr) != TCL_OK) { return TCL_ERROR; } if (!isNew) { if (v2Ptr->flush) { Blt_VectorFlushCache(v2Ptr); } Blt_VectorUpdateClients(v2Ptr); } } return TCL_OK; } /* * ----------------------------------------------------------------------- * * IndexOp -- * * Sets or reads the value of the index. This simulates what the * vector's variable does. * * Results: * A standard Tcl result. If the index is invalid, * interp->result will an error message and TCL_ERROR is returned. * Otherwise interp->result will contain the values. * * ----------------------------------------------------------------------- */ static int IndexOp(vPtr, interp, argc, argv) VectorObject *vPtr; Tcl_Interp *interp; int argc; char **argv; { int first, last; if (Blt_VectorGetIndexRange(interp, vPtr, argv[2], INDEX_ALL_FLAGS, (Blt_VectorIndexProc **) NULL) != TCL_OK) { return TCL_ERROR; } first = vPtr->first, last = vPtr->last; if (argc == 3) { Tcl_DString dString; if (first == vPtr->length) { Tcl_AppendResult(interp, "can't get index \"", argv[2], "\"", (char *)NULL); return TCL_ERROR; /* Can't read from index "++end" */ } Tcl_DStringInit(&dString); GetValues(vPtr, first, last, &dString); Tcl_DStringResult(interp, &dString); Tcl_DStringFree(&dString); } else { char string[TCL_DOUBLE_SPACE + 1]; double value; if (first == SPECIAL_INDEX) { Tcl_AppendResult(interp, "can't set index \"", argv[2], "\"", (char *)NULL); return TCL_ERROR; /* Tried to set "min" or "max" */ } if (Tcl_ExprDouble(interp, argv[3], &value) != TCL_OK) { return TCL_ERROR; } if (first == vPtr->length) { if (Blt_VectorChangeLength(vPtr, vPtr->length + 1) != TCL_OK) { return TCL_ERROR; } } ReplicateValue(vPtr, first, last, value); Tcl_PrintDouble(interp, value, string); Tcl_SetResult(interp, string, TCL_VOLATILE); if (vPtr->flush) { Blt_VectorFlushCache(vPtr); } Blt_VectorUpdateClients(vPtr); } return TCL_OK; } /* * ----------------------------------------------------------------------- * * LengthOp -- * * Returns the length of the vector. If a new size is given, the * vector is resized to the new vector. * * Results: * A standard Tcl result. If the new length is invalid, * interp->result will an error message and TCL_ERROR is returned. * Otherwise interp->result will contain the length of the vector. * * ----------------------------------------------------------------------- */ static int LengthOp(vPtr, interp, argc, argv) VectorObject *vPtr; Tcl_Interp *interp; int argc; char **argv; { if (argc == 3) { int size; if (Tcl_GetInt(interp, argv[2], &size) != TCL_OK) { return TCL_ERROR; } if (size < 0) { Tcl_AppendResult(interp, "bad vector size \"", argv[3], "\"", (char *)NULL); return TCL_ERROR; } if (Blt_VectorChangeLength(vPtr, size) != TCL_OK) { return TCL_ERROR; } if (vPtr->flush) { Blt_VectorFlushCache(vPtr); } Blt_VectorUpdateClients(vPtr); } Tcl_SetResult(interp, Blt_Itoa(vPtr->length), TCL_VOLATILE); return TCL_OK; } /* * ----------------------------------------------------------------------- * * MapOp -- * * Queries or sets the offset of the array index from the base * address of the data array of values. * * Results: * A standard Tcl result. If the source vector doesn't exist * or the source list is not a valid list of numbers, TCL_ERROR * returned. Otherwise TCL_OK is returned. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int MapOp(vPtr, interp, argc, argv) VectorObject *vPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { if (argc > 2) { if (Blt_VectorMapVariable(interp, vPtr, argv[2]) != TCL_OK) { return TCL_ERROR; } } if (vPtr->arrayName != NULL) { Tcl_SetResult(interp, vPtr->arrayName, TCL_VOLATILE); } return TCL_OK; } /* * ----------------------------------------------------------------------- * * MergeOp -- * * Merges the values from the given vectors to the current vector. * * Results: * A standard Tcl result. If any of the given vectors differ in size, * TCL_ERROR is returned. Otherwise TCL_OK is returned and the * vector data will contain merged values of the given vectors. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int MergeOp(vPtr, interp, argc, argv) VectorObject *vPtr; Tcl_Interp *interp; int argc; char **argv; { VectorObject *v2Ptr; VectorObject **vecArr; register VectorObject **vPtrPtr; int refSize, length, nElem; register int i; double *valuePtr, *valueArr; /* Allocate an array of vector pointers of each vector to be * merged in the current vector. */ vecArr = Blt_Malloc(sizeof(VectorObject *) * argc); assert(vecArr); vPtrPtr = vecArr; refSize = -1; nElem = 0; for (i = 2; i < argc; i++) { if (Blt_VectorLookupName(vPtr->dataPtr, argv[i], &v2Ptr) != TCL_OK) { Blt_Free(vecArr); return TCL_ERROR; } /* Check that all the vectors are the same length */ length = v2Ptr->last - v2Ptr->first + 1; if (refSize < 0) { refSize = length; } else if (length != refSize) { Tcl_AppendResult(vPtr->interp, "vector \"", v2Ptr->name, "\" has inconsistent length", (char *)NULL); Blt_Free(vecArr); return TCL_ERROR; } *vPtrPtr++ = v2Ptr; nElem += refSize; } *vPtrPtr = NULL; valueArr = Blt_Malloc(sizeof(double) * nElem); if (valueArr == NULL) { Tcl_AppendResult(vPtr->interp, "not enough memory to allocate ", Blt_Itoa(nElem), " vector elements", (char *)NULL); Blt_Free(vecArr); return TCL_ERROR; } /* Merge the values from each of the vectors into the current vector */ valuePtr = valueArr; for (i = 0; i < refSize; i++) { for (vPtrPtr = vecArr; *vPtrPtr != NULL; vPtrPtr++) { *valuePtr++ = (*vPtrPtr)->valueArr[i + (*vPtrPtr)->first]; } } Blt_Free(vecArr); Blt_VectorReset(vPtr, valueArr, nElem, nElem, TCL_DYNAMIC); return TCL_OK; } /* * ----------------------------------------------------------------------- * * NormalizeOp -- * * Normalizes the vector. * * Results: * A standard Tcl result. If the density is invalid, TCL_ERROR * is returned. Otherwise TCL_OK is returned. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int NormalizeOp(vPtr, interp, argc, argv) VectorObject *vPtr; Tcl_Interp *interp; int argc; char **argv; { register int i; double range; Blt_VectorUpdateRange(vPtr); range = vPtr->max - vPtr->min; if (argc > 2) { VectorObject *v2Ptr; int isNew; v2Ptr = Blt_VectorCreate(vPtr->dataPtr, argv[2], argv[2], argv[2], &isNew); if (v2Ptr == NULL) { return TCL_ERROR; } if (Blt_VectorChangeLength(v2Ptr, vPtr->length) != TCL_OK) { return TCL_ERROR; } for (i = 0; i < vPtr->length; i++) { v2Ptr->valueArr[i] = (vPtr->valueArr[i] - vPtr->min) / range; } Blt_VectorUpdateRange(v2Ptr); if (!isNew) { if (v2Ptr->flush) { Blt_VectorFlushCache(v2Ptr); } Blt_VectorUpdateClients(v2Ptr); } } else { double norm; for (i = 0; i < vPtr->length; i++) { norm = (vPtr->valueArr[i] - vPtr->min) / range; Tcl_AppendElement(interp, Blt_Dtoa(interp, norm)); } } return TCL_OK; } /* * ----------------------------------------------------------------------- * * NotifyOp -- * * Notify clients of vector. * * Results: * A standard Tcl result. If any of the given vectors differ in size, * TCL_ERROR is returned. Otherwise TCL_OK is returned and the * vector data will contain merged values of the given vectors. * * x vector notify now * x vector notify always * x vector notify whenidle * x vector notify update {} * x vector notify delete {} * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int NotifyOp(vPtr, interp, argc, argv) VectorObject *vPtr; Tcl_Interp *interp; int argc; char **argv; { char c; int length; c = argv[2][0]; length = strlen(argv[2]); if ((c == 'a') && (length > 1) && (strncmp(argv[2], "always", length) == 0)) { vPtr->notifyFlags &= ~NOTIFY_WHEN_MASK; vPtr->notifyFlags |= NOTIFY_ALWAYS; } else if ((c == 'n') && (length > 2) && (strncmp(argv[2], "never", length) == 0)) { vPtr->notifyFlags &= ~NOTIFY_WHEN_MASK; vPtr->notifyFlags |= NOTIFY_NEVER; } else if ((c == 'w') && (length > 1) && (strncmp(argv[2], "whenidle", length) == 0)) { vPtr->notifyFlags &= ~NOTIFY_WHEN_MASK; vPtr->notifyFlags |= NOTIFY_WHENIDLE; } else if ((c == 'n') && (length > 2) && (strncmp(argv[2], "now", length) == 0)) { /* How does this play when an update is pending? */ Blt_VectorNotifyClients(vPtr); } else if ((c == 'c') && (length > 1) && (strncmp(argv[2], "cancel", length) == 0)) { if (vPtr->notifyFlags & NOTIFY_PENDING) { vPtr->notifyFlags &= ~NOTIFY_PENDING; Tcl_CancelIdleCall(Blt_VectorNotifyClients, vPtr); } } else if ((c == 'p') && (length > 1) && (strncmp(argv[2], "pending", length) == 0)) { Blt_SetBooleanResult(interp, (vPtr->notifyFlags & NOTIFY_PENDING)); } else { Tcl_AppendResult(interp, "bad qualifier \"", argv[2], "\": should be \ \"always\", \"never\", \"whenidle\", \"now\", \"cancel\", or \"pending\"", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* * ----------------------------------------------------------------------- * * PopulateOp -- * * Creates or resizes a new vector based upon the density specified. * * Results: * A standard Tcl result. If the density is invalid, TCL_ERROR * is returned. Otherwise TCL_OK is returned. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int PopulateOp(vPtr, interp, argc, argv) VectorObject *vPtr; Tcl_Interp *interp; int argc; char **argv; { VectorObject *v2Ptr; int size, density; int isNew; register int i, j; double slice, range; register double *valuePtr; int count; v2Ptr = Blt_VectorCreate(vPtr->dataPtr, argv[2], argv[2], argv[2], &isNew); if (v2Ptr == NULL) { return TCL_ERROR; } if (vPtr->length == 0) { return TCL_OK; /* Source vector is empty. */ } if (Tcl_GetInt(interp, argv[3], &density) != TCL_OK) { return TCL_ERROR; } if (density < 1) { Tcl_AppendResult(interp, "bad density \"", argv[3], "\"", (char *)NULL); return TCL_ERROR; } size = (vPtr->length - 1) * (density + 1) + 1; if (Blt_VectorChangeLength(v2Ptr, size) != TCL_OK) { return TCL_ERROR; } count = 0; valuePtr = v2Ptr->valueArr; for (i = 0; i < (vPtr->length - 1); i++) { range = vPtr->valueArr[i + 1] - vPtr->valueArr[i]; slice = range / (double)(density + 1); for (j = 0; j <= density; j++) { *valuePtr = vPtr->valueArr[i] + (slice * (double)j); valuePtr++; count++; } } count++; *valuePtr = vPtr->valueArr[i]; assert(count == v2Ptr->length); if (!isNew) { if (v2Ptr->flush) { Blt_VectorFlushCache(v2Ptr); } Blt_VectorUpdateClients(v2Ptr); } return TCL_OK; } /* * ----------------------------------------------------------------------- * * RangeOp -- * * Returns a Tcl list of the range of vector values specified. * * Results: * A standard Tcl result. If the given range is invalid, TCL_ERROR * is returned. Otherwise TCL_OK is returned and interp->result * will contain the list of values. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int RangeOp(vPtr, interp, argc, argv) VectorObject *vPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { int first, last; register int i; if ((Blt_VectorGetIndex(interp, vPtr, argv[2], &first, INDEX_CHECK, (Blt_VectorIndexProc **) NULL) != TCL_OK) || (Blt_VectorGetIndex(interp, vPtr, argv[3], &last, INDEX_CHECK, (Blt_VectorIndexProc **) NULL) != TCL_OK)) { return TCL_ERROR; } if (first > last) { /* Return the list reversed */ for (i = last; i <= first; i++) { Tcl_AppendElement(interp, Blt_Dtoa(interp, vPtr->valueArr[i])); } } else { for (i = first; i <= last; i++) { Tcl_AppendElement(interp, Blt_Dtoa(interp, vPtr->valueArr[i])); } } return TCL_OK; } /* * ---------------------------------------------------------------------- * * InRange -- * * Determines if a value lies within a given range. * * The value is normalized and compared against the interval * [0..1], where 0.0 is the minimum and 1.0 is the maximum. * DBL_EPSILON is the smallest number that can be represented * on the host machine, such that (1.0 + epsilon) != 1.0. * * Please note, min can't be greater than max. * * Results: * If the value is within of the interval [min..max], 1 is * returned; 0 otherwise. * * ---------------------------------------------------------------------- */ INLINE static int InRange(value, min, max) register double value, min, max; { double range; range = max - min; if (range < DBL_EPSILON) { return (FABS(max - value) < DBL_EPSILON); } else { double norm; 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. Formats may be * as follows. * * signed i1, i2, i4, i8 * unsigned u1, u2, u4, u8 * real r4, r8, r16 * * But 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(interp, string, sizePtr) Tcl_Interp *interp; char *string; int *sizePtr; { char c; 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 TCL_ERROR; } 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(vPtr, byteArr, fmt, size, length, swap, indexPtr) VectorObject *vPtr; char *byteArr; enum NativeFormats fmt; int size; int length; int swap; int *indexPtr; { register int i, n; int newSize; if ((swap) && (size > 1)) { int nBytes = size * length; register unsigned char *p; register int left, right; for (i = 0; i < nBytes; i += size) { p = (unsigned char *)(byteArr + i); for (left = 0, right = size - 1; left < right; left++, right--) { p[left] ^= p[right]; p[right] ^= p[left]; p[left] ^= p[right]; } } } newSize = *indexPtr + length; if (newSize > vPtr->length) { if (Blt_VectorChangeLength(vPtr, newSize) != TCL_OK) { return TCL_ERROR; } } #define CopyArrayToVector(vPtr, arr) \ for (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 by Harald Kirsch (kir@iitb.fhg.de). * * 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. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int BinreadOp(vPtr, interp, argc, argv) VectorObject *vPtr; Tcl_Interp *interp; int argc; char **argv; { char *byteArr; enum NativeFormats fmt; int size, length, mode; Tcl_Channel channel; int arraySize, bytesRead; int count, total; int first; int swap; register int i; channel = Tcl_GetChannel(interp, argv[2], &mode); if (channel == NULL) { return TCL_ERROR; } if ((mode & TCL_READABLE) == 0) { Tcl_AppendResult(interp, "channel \"", argv[2], "\" wasn't opened for reading", (char *)NULL); return TCL_ERROR; } first = vPtr->length; fmt = FMT_DOUBLE; size = sizeof(double); swap = FALSE; count = 0; if ((argc > 3) && (argv[3][0] != '-')) { long int value; /* Get the number of values to read. */ if (Tcl_ExprLong(interp, argv[3], &value) != TCL_OK) { return TCL_ERROR; } if (value < 0) { Tcl_AppendResult(interp, "count can't be negative", (char *)NULL); return TCL_ERROR; } count = (int)value; argc--, argv++; } /* Process any option-value pairs that remain. */ for (i = 3; i < argc; i++) { if (strcmp(argv[i], "-swap") == 0) { swap = TRUE; } else if (strcmp(argv[i], "-format") == 0) { i += 1; if (i >= argc) { Tcl_AppendResult(interp, "missing arg after \"", argv[i - 1], "\"", (char *)NULL); return TCL_ERROR; } fmt = GetBinaryFormat(interp, argv[i], &size); if (fmt == FMT_UNKNOWN) { return TCL_ERROR; } } else if (strcmp(argv[i], "-at") == 0) { i += 1; if (i >= argc) { Tcl_AppendResult(interp, "missing arg after \"", argv[i - 1], "\"", (char *)NULL); return TCL_ERROR; } if (Blt_VectorGetIndex(interp, vPtr, argv[i], &first, 0, (Blt_VectorIndexProc **)NULL) != TCL_OK) { return TCL_ERROR; } if (first > vPtr->length) { Tcl_AppendResult(interp, "index \"", argv[i], "\" is out of range", (char *)NULL); return TCL_ERROR; } } } #define BUFFER_SIZE 1024 if (count == 0) { arraySize = BUFFER_SIZE * size; } else { arraySize = count * size; } byteArr = Blt_Malloc(arraySize); assert(byteArr); /* FIXME: restore old channel translation later? */ if (Tcl_SetChannelOption(interp, channel, "-translation", "binary") != TCL_OK) { return TCL_ERROR; } total = 0; while (!Tcl_Eof(channel)) { 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; } length = bytesRead / size; if (CopyValues(vPtr, byteArr, fmt, size, length, swap, &first) != TCL_OK) { return TCL_ERROR; } total += length; if (count > 0) { break; } } Blt_Free(byteArr); if (vPtr->flush) { Blt_VectorFlushCache(vPtr); } Blt_VectorUpdateClients(vPtr); /* Set the result as the number of values read. */ Tcl_SetResult(interp, Blt_Itoa(total), TCL_VOLATILE); return TCL_OK; } /* * ----------------------------------------------------------------------- * * SearchOp -- * * Searchs for a value in the vector. Returns the indices of all * vector elements matching a particular value. * * Results: * Always returns TCL_OK. interp->result will contain a list of * the indices of array elements matching value. If no elements * match, interp->result will contain the empty string. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int SearchOp(vPtr, interp, argc, argv) VectorObject *vPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { double min, max; register int i; int wantValue; wantValue = FALSE; if ((argv[2][0] == '-') && (strcmp(argv[2], "-value") == 0)) { wantValue = TRUE; argv++, argc--; } if (Tcl_ExprDouble(interp, argv[2], &min) != TCL_OK) { return TCL_ERROR; } max = min; if ((argc > 3) && (Tcl_ExprDouble(interp, argv[3], &max) != TCL_OK)) { return TCL_ERROR; } if ((min - max) >= DBL_EPSILON) { return TCL_OK; /* Bogus range. Don't bother looking. */ } if (wantValue) { for (i = 0; i < vPtr->length; i++) { if (InRange(vPtr->valueArr[i], min, max)) { Tcl_AppendElement(interp, Blt_Dtoa(interp, vPtr->valueArr[i])); } } } else { for (i = 0; i < vPtr->length; i++) { if (InRange(vPtr->valueArr[i], min, max)) { Tcl_AppendElement(interp, Blt_Itoa(i + vPtr->offset)); } } } return TCL_OK; } /* * ----------------------------------------------------------------------- * * OffsetOp -- * * Queries or sets the offset of the array index from the base * address of the data array of values. * * Results: * A standard Tcl result. If the source vector doesn't exist * or the source list is not a valid list of numbers, TCL_ERROR * returned. Otherwise TCL_OK is returned. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int OffsetOp(vPtr, interp, argc, argv) VectorObject *vPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { if (argc == 3) { int newOffset; if (Tcl_GetInt(interp, argv[2], &newOffset) != TCL_OK) { return TCL_ERROR; } vPtr->offset = newOffset; } Tcl_SetResult(interp, Blt_Itoa(vPtr->offset), TCL_VOLATILE); return TCL_OK; } /* * ----------------------------------------------------------------------- * * RandomOp -- * * Generates random values for the length of the vector. * * Results: * A standard Tcl result. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int RandomOp(vPtr, interp, argc, argv) VectorObject *vPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { #ifdef HAVE_DRAND48 register int i; for (i = 0; i < vPtr->length; i++) { vPtr->valueArr[i] = drand48(); } #endif /* HAVE_DRAND48 */ if (vPtr->flush) { Blt_VectorFlushCache(vPtr); } Blt_VectorUpdateClients(vPtr); return TCL_OK; } /* * ----------------------------------------------------------------------- * * SeqOp -- * * Generates a sequence of values in the vector. * * Results: * A standard Tcl result. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int SeqOp(vPtr, interp, argc, argv) VectorObject *vPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { register int i; double start, finish, step; int fillVector; int nSteps; if (Tcl_ExprDouble(interp, argv[2], &start) != TCL_OK) { return TCL_ERROR; } fillVector = FALSE; if ((argv[3][0] == 'e') && (strcmp(argv[3], "end") == 0)) { fillVector = TRUE; } else if (Tcl_ExprDouble(interp, argv[3], &finish) != TCL_OK) { return TCL_ERROR; } step = 1.0; if ((argc > 4) && (Tcl_ExprDouble(interp, argv[4], &step) != TCL_OK)) { return TCL_ERROR; } if (fillVector) { nSteps = vPtr->length; } else { nSteps = (int)((finish - start) / step) + 1; } if (nSteps > 0) { if (Blt_VectorChangeLength(vPtr, nSteps) != TCL_OK) { return TCL_ERROR; } for (i = 0; i < nSteps; i++) { vPtr->valueArr[i] = start + (step * (double)i); } if (vPtr->flush) { Blt_VectorFlushCache(vPtr); } Blt_VectorUpdateClients(vPtr); } return TCL_OK; } /* * ----------------------------------------------------------------------- * * SetOp -- * * Sets the data of the vector object from a list of values. * * Results: * A standard Tcl result. If the source vector doesn't exist * or the source list is not a valid list of numbers, TCL_ERROR * returned. Otherwise TCL_OK is returned. * * Side Effects: * The vector data is reset. Clients of the vector are notified. * Any cached array indices are flushed. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int SetOp(vPtr, interp, argc, argv) VectorObject *vPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { int result; VectorObject *v2Ptr; int nElem; char **elemArr; /* The source can be either a list of expressions of another * vector. */ if (Tcl_SplitList(interp, argv[2], &nElem, &elemArr) != TCL_OK) { return TCL_ERROR; } /* If there's only one element, see whether it's the name of a * vector. Otherwise, treat it as a single numeric expression. */ if ((nElem == 1) && ((v2Ptr = Blt_VectorParseElement((Tcl_Interp *)NULL, vPtr->dataPtr, argv[2], (char **)NULL, NS_SEARCH_BOTH)) != NULL)) { if (vPtr == v2Ptr) { VectorObject *tmpPtr; /* * Source and destination vectors are the same. Copy the * source first into a temporary vector to avoid memory * overlaps. */ tmpPtr = Blt_VectorNew(vPtr->dataPtr); result = Blt_VectorDuplicate(tmpPtr, v2Ptr); if (result == TCL_OK) { result = Blt_VectorDuplicate(vPtr, tmpPtr); } Blt_VectorFree(tmpPtr); } else { result = Blt_VectorDuplicate(vPtr, v2Ptr); } } else { result = CopyList(vPtr, nElem, elemArr); } Blt_Free(elemArr); 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) { Blt_VectorFlushCache(vPtr); } Blt_VectorUpdateClients(vPtr); } return result; } static VectorObject **sortVectorArr; /* Pointer to the array of values currently * being sorted. */ static int nSortVectors; static int reverse; /* Indicates the ordering of the sort. If * non-zero, the vectors are sorted in * decreasing order */ static int CompareVectors(a, b) void *a; void *b; { double delta; int i; int sign; register VectorObject *vPtr; sign = (reverse) ? -1 : 1; for (i = 0; i < nSortVectors; i++) { vPtr = sortVectorArr[i]; 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; } int * Blt_VectorSortIndex(vPtrPtr, nVectors) VectorObject **vPtrPtr; int nVectors; { int *indexArr; register int i; VectorObject *vPtr = *vPtrPtr; indexArr = Blt_Malloc(sizeof(int) * vPtr->length); assert(indexArr); for (i = 0; i < vPtr->length; i++) { indexArr[i] = i; } sortVectorArr = vPtrPtr; nSortVectors = nVectors; qsort((char *)indexArr, vPtr->length, sizeof(int), (QSortCompareProc *)CompareVectors); return indexArr; } static int * SortVectors(vPtr, interp, argc, argv) VectorObject *vPtr; Tcl_Interp *interp; int argc; char **argv; { VectorObject **vPtrArray, *v2Ptr; int *iArr; register int i; vPtrArray = Blt_Malloc(sizeof(VectorObject *) * (argc + 1)); assert(vPtrArray); vPtrArray[0] = vPtr; iArr = NULL; for (i = 0; i < argc; i++) { if (Blt_VectorLookupName(vPtr->dataPtr, argv[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; } vPtrArray[i + 1] = v2Ptr; } iArr = Blt_VectorSortIndex(vPtrArray, argc + 1); error: Blt_Free(vPtrArray); return iArr; } /* * ----------------------------------------------------------------------- * * SortOp -- * * Sorts the vector object and any other vectors according to * sorting order of the vector object. * * Results: * A standard Tcl result. If any of the auxiliary vectors are * a different size than the sorted vector object, TCL_ERROR is * returned. Otherwise TCL_OK is returned. * * Side Effects: * The vectors are sorted. * * ----------------------------------------------------------------------- */ static int SortOp(vPtr, interp, argc, argv) VectorObject *vPtr; Tcl_Interp *interp; int argc; char **argv; { int *iArr; double *mergeArr; VectorObject *v2Ptr; int refSize, nBytes; int result; register int i, n; reverse = FALSE; if ((argc > 2) && (argv[2][0] == '-')) { int length; length = strlen(argv[2]); if ((length > 1) && (strncmp(argv[2], "-reverse", length) == 0)) { reverse = TRUE; } else { Tcl_AppendResult(interp, "unknown flag \"", argv[2], "\": should be \"-reverse\"", (char *)NULL); return TCL_ERROR; } argc--, argv++; } if (argc > 2) { iArr = SortVectors(vPtr, interp, argc - 2, argv + 2); } else { iArr = Blt_VectorSortIndex(&vPtr, 1); } if (iArr == NULL) { return TCL_ERROR; } refSize = 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. */ nBytes = sizeof(double) * refSize; mergeArr = Blt_Malloc(nBytes); assert(mergeArr); memcpy((char *)mergeArr, (char *)vPtr->valueArr, nBytes); for (n = 0; n < refSize; n++) { vPtr->valueArr[n] = mergeArr[iArr[n]]; } if (vPtr->flush) { Blt_VectorFlushCache(vPtr); } Blt_VectorUpdateClients(vPtr); /* Now sort any other vectors in the same fashion. The vectors * must be the same size as the iArr though. */ result = TCL_ERROR; for (i = 2; i < argc; i++) { if (Blt_VectorLookupName(vPtr->dataPtr, argv[i], &v2Ptr) != TCL_OK) { goto error; } if (v2Ptr->length != refSize) { Tcl_AppendResult(interp, "vector \"", v2Ptr->name, "\" is not the same size as \"", vPtr->name, "\"", (char *)NULL); goto error; } memcpy((char *)mergeArr, (char *)v2Ptr->valueArr, nBytes); for (n = 0; n < refSize; n++) { v2Ptr->valueArr[n] = mergeArr[iArr[n]]; } Blt_VectorUpdateClients(v2Ptr); if (v2Ptr->flush) { Blt_VectorFlushCache(v2Ptr); } } result = TCL_OK; error: Blt_Free(mergeArr); Blt_Free(iArr); return result; } /* *---------------------------------------------------------------------- * * InstExprOp -- * * Computes the result of the expression which may be * either a scalar (single value) or vector (list of values). * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int InstExprOp(vPtr, interp, argc, argv) VectorObject *vPtr; Tcl_Interp *interp; int argc; char **argv; { if (Blt_ExprVector(interp, argv[2], (Blt_Vector *) vPtr) != TCL_OK) { return TCL_ERROR; } if (vPtr->flush) { Blt_VectorFlushCache(vPtr); } Blt_VectorUpdateClients(vPtr); return TCL_OK; } /* * ----------------------------------------------------------------------- * * ArithOp -- * * Results: * A standard Tcl result. If the source vector doesn't exist * or the source list is not a valid list of numbers, TCL_ERROR * returned. Otherwise TCL_OK is returned. * * Side Effects: * The vector data is reset. Clients of the vector are notified. * Any cached array indices are flushed. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int ArithOp(vPtr, interp, argc, argv) VectorObject *vPtr; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { register double value; register int i; VectorObject *v2Ptr; v2Ptr = Blt_VectorParseElement((Tcl_Interp *)NULL, vPtr->dataPtr, argv[2], (char **)NULL, NS_SEARCH_BOTH); if (v2Ptr != NULL) { register int j; int length; length = v2Ptr->last - v2Ptr->first + 1; if (length != vPtr->length) { Tcl_AppendResult(interp, "vectors \"", argv[0], "\" and \"", argv[2], "\" are not the same length", (char *)NULL); return TCL_ERROR; } switch (argv[1][0]) { case '*': for (i = 0, j = v2Ptr->first; i < vPtr->length; i++, j++) { value = vPtr->valueArr[i] * v2Ptr->valueArr[j]; Tcl_AppendElement(interp, Blt_Dtoa(interp, value)); } break; case '/': for (i = 0, j = v2Ptr->first; i < vPtr->length; i++, j++) { value = vPtr->valueArr[i] / v2Ptr->valueArr[j]; Tcl_AppendElement(interp, Blt_Dtoa(interp, value)); } break; case '-': for (i = 0, j = v2Ptr->first; i < vPtr->length; i++, j++) { value = vPtr->valueArr[i] - v2Ptr->valueArr[j]; Tcl_AppendElement(interp, Blt_Dtoa(interp, value)); } break; case '+': for (i = 0, j = v2Ptr->first; i < vPtr->length; i++, j++) { value = vPtr->valueArr[i] + v2Ptr->valueArr[j]; Tcl_AppendElement(interp, Blt_Dtoa(interp, value)); } break; } } else { double scalar; if (Tcl_ExprDouble(interp, argv[2], &scalar) != TCL_OK) { return TCL_ERROR; } switch (argv[1][0]) { case '*': for (i = 0; i < vPtr->length; i++) { value = vPtr->valueArr[i] * scalar; Tcl_AppendElement(interp, Blt_Dtoa(interp, value)); } break; case '/': for (i = 0; i < vPtr->length; i++) { value = vPtr->valueArr[i] / scalar; Tcl_AppendElement(interp, Blt_Dtoa(interp, value)); } break; case '-': for (i = 0; i < vPtr->length; i++) { value = vPtr->valueArr[i] - scalar; Tcl_AppendElement(interp, Blt_Dtoa(interp, value)); } break; case '+': for (i = 0; i < vPtr->length; i++) { value = vPtr->valueArr[i] + scalar; Tcl_AppendElement(interp, Blt_Dtoa(interp, value)); } break; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * VectorInstCmd -- * * Parses and invokes the appropriate vector instance command * option. * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ static Blt_OpSpec vectorInstOps[] = { {"*", 1, (Blt_Op)ArithOp, 3, 3, "item",}, /*Deprecated*/ {"+", 1, (Blt_Op)ArithOp, 3, 3, "item",}, /*Deprecated*/ {"-", 1, (Blt_Op)ArithOp, 3, 3, "item",}, /*Deprecated*/ {"/", 1, (Blt_Op)ArithOp, 3, 3, "item",}, /*Deprecated*/ {"append", 1, (Blt_Op)AppendOp, 3, 0, "item ?item...?",}, {"binread", 1, (Blt_Op)BinreadOp, 3, 0, "channel ?numValues? ?flags?",}, {"clear", 1, (Blt_Op)ClearOp, 2, 2, "",}, {"delete", 2, (Blt_Op)DeleteOp, 2, 0, "index ?index...?",}, {"dup", 2, (Blt_Op)DupOp, 3, 0, "vecName",}, {"expr", 1, (Blt_Op)InstExprOp, 3, 3, "expression",}, {"index", 1, (Blt_Op)IndexOp, 3, 4, "index ?value?",}, {"length", 1, (Blt_Op)LengthOp, 2, 3, "?newSize?",}, {"merge", 1, (Blt_Op)MergeOp, 3, 0, "vecName ?vecName...?",}, {"normalize", 3, (Blt_Op)NormalizeOp, 2, 3, "?vecName?",}, /*Deprecated*/ {"notify", 3, (Blt_Op)NotifyOp, 3, 3, "keyword",}, {"offset", 2, (Blt_Op)OffsetOp, 2, 3, "?offset?",}, {"populate", 1, (Blt_Op)PopulateOp, 4, 4, "vecName density",}, {"random", 4, (Blt_Op)RandomOp, 2, 2, "",}, /*Deprecated*/ {"range", 4, (Blt_Op)RangeOp, 4, 4, "first last",}, {"search", 3, (Blt_Op)SearchOp, 3, 4, "?-value? value ?value?",}, {"seq", 3, (Blt_Op)SeqOp, 4, 5, "start end ?step?",}, {"set", 3, (Blt_Op)SetOp, 3, 3, "list",}, {"sort", 2, (Blt_Op)SortOp, 2, 0, "?-reverse? ?vecName...?",}, {"variable", 1, (Blt_Op)MapOp, 2, 3, "?varName?",}, }; static int nInstOps = sizeof(vectorInstOps) / sizeof(Blt_OpSpec); int Blt_VectorInstCmd(clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; int argc; char **argv; { Blt_Op proc; VectorObject *vPtr = clientData; vPtr->first = 0; vPtr->last = vPtr->length - 1; proc = Blt_GetOp(interp, nInstOps, vectorInstOps, BLT_OP_ARG1, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } return (*proc) (vPtr, interp, argc, argv); } /* * ---------------------------------------------------------------------- * * Blt_VectorVarTrace -- * * Results: * Returns NULL on success. Only called from a variable trace. * * Side effects: * * ---------------------------------------------------------------------- */ char * Blt_VectorVarTrace(clientData, interp, part1, part2, flags) ClientData clientData; /* File output information. */ Tcl_Interp *interp; char *part1, *part2; int flags; { VectorObject *vPtr = clientData; char string[TCL_DOUBLE_SPACE + 1]; #define MAX_ERR_MSG 1023 static char message[MAX_ERR_MSG + 1]; Blt_VectorIndexProc *indexProc; int varFlags; int first, last; if (part2 == NULL) { if (flags & TCL_TRACE_UNSETS) { Blt_Free(vPtr->arrayName); vPtr->arrayName = NULL; vPtr->varNsPtr = NULL; if (vPtr->freeOnUnset) { Blt_VectorFree(vPtr); } } return NULL; } if (Blt_VectorGetIndexRange(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) { double value; char *newValue; if (first == SPECIAL_INDEX) { /* Tried to set "min" or "max" */ return "read-only index"; } newValue = Tcl_GetVar2(interp, part1, part2, varFlags); if (newValue == NULL) { goto error; } if (Tcl_ExprDouble(interp, newValue, &value) != TCL_OK) { if ((last == first) && (first >= 0)) { /* Single numeric index. Reset the array element to * its old value on errors */ Tcl_PrintDouble(interp, vPtr->valueArr[first], string); Tcl_SetVar2(interp, part1, part2, string, varFlags); } goto error; } if (first == vPtr->length) { if (Blt_VectorChangeLength(vPtr, vPtr->length + 1) != TCL_OK) { return "error resizing vector"; } } /* Set possibly an entire range of values */ ReplicateValue(vPtr, first, last, value); } else if (flags & TCL_TRACE_READS) { double value; if (vPtr->length == 0) { if (Tcl_SetVar2(interp, part1, part2, "", varFlags) == NULL) { goto error; } return NULL; } if (first == vPtr->length) { return "write-only index"; } if (first == last) { if (first >= 0) { value = vPtr->valueArr[first]; } else { vPtr->first = 0, vPtr->last = vPtr->length - 1; value = (*indexProc) ((Blt_Vector *) vPtr); } Tcl_PrintDouble(interp, value, string); if (Tcl_SetVar2(interp, part1, part2, string, varFlags) == NULL) { goto error; } } else { Tcl_DString dString; char *result; Tcl_DStringInit(&dString); GetValues(vPtr, first, last, &dString); result = Tcl_SetVar2(interp, part1, part2, Tcl_DStringValue(&dString), varFlags); Tcl_DStringFree(&dString); if (result == NULL) { goto error; } } } else if (flags & TCL_TRACE_UNSETS) { register int i, j; if ((first == vPtr->length) || (first == SPECIAL_INDEX)) { return "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 (i = first, j = last + 1; j < vPtr->length; i++, j++) { vPtr->valueArr[i] = vPtr->valueArr[j]; } vPtr->length -= ((last - first) + 1); if (vPtr->flush) { Blt_VectorFlushCache(vPtr); } } else { return "unknown variable trace flag"; } if (flags & (TCL_TRACE_UNSETS | TCL_TRACE_WRITES)) { Blt_VectorUpdateClients(vPtr); } Tcl_ResetResult(interp); return NULL; error: strncpy(message, Tcl_GetStringResult(interp), MAX_ERR_MSG); message[MAX_ERR_MSG] = '\0'; return message; } #endif /* TCL_MAJOR_VERSION == 7 */ blt-2.4z.orig/src/bltVecInt.h0100644000175000017500000002023007515370776014614 0ustar dokodoko/* * bltVecInt.h -- * * This module implements vector data objects. * * Copyright 1995-1998 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. */ #include "bltInt.h" #include #include #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 typedef struct { Blt_HashTable vectorTable; /* Table of vectors */ Blt_HashTable mathProcTable; /* Table of vector math functions */ Blt_HashTable indexProcTable; Tcl_Interp *interp; unsigned int nextId; } VectorInterpData; /* * VectorObject -- * * A vector is an array of double precision values. It can be * accessed through a Tcl command, a Tcl array variable, or C * API. The storage for the array points initially to a * statically allocated buffer, but to malloc-ed memory if more * is necessary. * * Vectors can be shared by several clients (for example, two * different graph widgets). The data is shared. When a client * wants to use a vector, it allocates a vector identifier, which * identifies the client. Clients use this ID to specify a * callback routine to be invoked whenever the vector is modified * or destroyed. Whenever the vector is updated or destroyed, * each client is notified of the change by their callback * routine. */ typedef struct { /* * If you change these fields, make sure you change the definition * of Blt_Vector in bltInt.h and 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 */ 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 */ Blt_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. */ 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 *varNsPtr; /* Namespace context of the Tcl variable * associated with the vector. This is * needed to reset the indices of the array * 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. */ Blt_Chain *chainPtr; /* 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 */ } VectorObject; #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]; \ } \ } \ } \ } extern void Blt_VectorInstallSpecialIndices _ANSI_ARGS_((Blt_HashTable *tablePtr)); extern void Blt_VectorInstallMathFunctions _ANSI_ARGS_((Blt_HashTable *tablePtr)); extern void Blt_VectorUninstallMathFunctions _ANSI_ARGS_((Blt_HashTable *tablePtr)); extern VectorInterpData *Blt_VectorGetInterpData _ANSI_ARGS_((Tcl_Interp *interp)); extern VectorObject *Blt_VectorNew _ANSI_ARGS_((VectorInterpData *dataPtr)); extern int Blt_VectorDuplicate _ANSI_ARGS_((VectorObject *destPtr, VectorObject *srcPtr)); extern int Blt_VectorChangeLength _ANSI_ARGS_((VectorObject *vPtr, int length)); extern VectorObject *Blt_VectorParseElement _ANSI_ARGS_((Tcl_Interp *interp, VectorInterpData *dataPtr, CONST char *start, char **endPtr, int flags)); extern void Blt_VectorFree _ANSI_ARGS_((VectorObject *vPtr)); extern int *Blt_VectorSortIndex _ANSI_ARGS_((VectorObject **vPtrPtr, int nVectors)); extern int Blt_VectorLookupName _ANSI_ARGS_((VectorInterpData *dataPtr, char *vecName, VectorObject **vPtrPtr)); extern VectorObject *Blt_VectorCreate _ANSI_ARGS_((VectorInterpData *dataPtr, CONST char *name, CONST char *cmdName, CONST char *varName, int *newPtr)); extern void Blt_VectorUpdateRange _ANSI_ARGS_((VectorObject *vPtr)); extern void Blt_VectorUpdateClients _ANSI_ARGS_((VectorObject *vPtr)); extern void Blt_VectorFlushCache _ANSI_ARGS_((VectorObject *vPtr)); extern int Blt_VectorReset _ANSI_ARGS_((VectorObject *vPtr, double *dataArr, int nValues, int arraySize, Tcl_FreeProc *freeProc)); extern int Blt_VectorGetIndex _ANSI_ARGS_((Tcl_Interp *interp, VectorObject *vPtr, CONST char *string, int *indexPtr, int flags, Blt_VectorIndexProc **procPtrPtr)); extern int Blt_VectorGetIndexRange _ANSI_ARGS_((Tcl_Interp *interp, VectorObject *vPtr, CONST char *string, int flags, Blt_VectorIndexProc **procPtrPtr)); extern int Blt_VectorMapVariable _ANSI_ARGS_((Tcl_Interp *interp, VectorObject *vPtr, CONST char *name)); #if (TCL_MAJOR_VERSION == 7) extern Tcl_CmdProc Blt_VectorInstCmd; #else extern Tcl_ObjCmdProc Blt_VectorInstCmd; #endif extern Tcl_VarTraceProc Blt_VectorVarTrace; extern Tcl_IdleProc Blt_VectorNotifyClients; blt-2.4z.orig/src/bltVecMath.c0100644000175000017500000014242107537277501014751 0ustar dokodoko /* * bltVecMath.c -- * * This module implements mathematical expressions with vector * data objects. * * Copyright 1995-1998 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. */ #include "bltVecInt.h" /* * 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) _ANSI_ARGS_((double value)); typedef int (VectorProc) _ANSI_ARGS_((VectorObject *vPtr)); typedef double (ScalarProc) _ANSI_ARGS_((VectorObject *vPtr)); /* * Built-in math functions: */ typedef int (GenericMathProc) _ANSI_ARGS_(ANYARGS); /* * 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 { 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. */ GenericMathProc *proc; /* Procedure that implements this math * function. */ ClientData clientData; /* Argument to pass when invoking the * function. */ } MathFunction; /* * Macros for testing floating-point values for certain special cases: * * IS_NAN Test for not-a-number by comparing a value against itself * IF_INF Test for infinity by comparing against the largest floating * point value. */ #define IS_NAN(v) ((v) != (v)) #ifdef DBL_MAX # define IS_INF(v) (((v) > DBL_MAX) || ((v) < -DBL_MAX)) #else # define IS_INF(v) 0 #endif /* 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 }; /* * ParseValue -- * * The following data structure is used by various parsing * procedures to hold information about where to store the * results of parsing (e.g. the substituted contents of a quoted * argument, or the result of a nested command). At any given * time, the space available for output is fixed, but a procedure * may be called to expand the space available if the current * space runs out. */ typedef struct ParseValueStruct ParseValue; struct ParseValueStruct { char *buffer; /* Address of first character in * output buffer. */ char *next; /* Place to store next character in * output buffer. */ char *end; /* Address of the last usable character * in the buffer. */ void (*expandProc) _ANSI_ARGS_((ParseValue * pvPtr, int needed)); /* Procedure to call when space runs out; * it will make more space. */ ClientData clientData; /* Arbitrary information for use of * expandProc. */ }; typedef struct { VectorObject *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 { char *expr; /* The entire right-hand side of the * expression, as originally passed to * Blt_ExprVector. */ 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 _ANSI_ARGS_((Tcl_Interp *interp, ParseInfo *parsePtr, int prec, Value * valuePtr)); #if (TCL_VERSION_NUMBER >= _VERSION(8,1,0)) #define TclParseBraces Blt_ParseBraces #define TclParseNestedCmd Blt_ParseNestedCmd #define TclParseQuotes Blt_ParseQuotes #define TclExpandParseValue Blt_ExpandParseValue #endif /* TCL_VERSION_NUMBER >= _VERSION(8,1,0) */ extern int TclParseBraces _ANSI_ARGS_((Tcl_Interp *interp, char *string, char **termPtr, ParseValue * pvPtr)); extern int TclParseNestedCmd _ANSI_ARGS_((Tcl_Interp *interp, char *string, int flags, char **termPtr, ParseValue * pvPtr)); extern int TclParseQuotes _ANSI_ARGS_((Tcl_Interp *interp, char *string, int termChar, int flags, char **termPtr, ParseValue * pvPtr)); extern void TclExpandParseValue _ANSI_ARGS_((ParseValue * pvPtr, int needed)); #if defined(HAVE_DRAND48) && defined(NO_DECL_DRAND48) extern double drand48 _ANSI_ARGS_((void)); #endif #include /* *-------------------------------------------------------------- * * First -- * * Gets the first index of the designated interval. The interval * is between vPtr->first and vPtr->last. But the range may * NaN or Inf values that should be ignored. * * Results: * Returns the index of the first finite value in the designated * interval. If no finite values exists in the range, then -1 is * returned. * *-------------------------------------------------------------- */ static int First(vPtr) VectorObject *vPtr; { register int i; for(i = vPtr->first; i <= vPtr->last; i++) { if (FINITE(vPtr->valueArr[i])) { return i; } } return -1; } /* *-------------------------------------------------------------- * * Next -- * * Gets the next index of the designated interval. The interval * is between vPtr->first and vPtr->last. Ignore NaN or Inf * values. * * Results: * Returns the index of the next finite value in the designated * interval. If no more finite values exists in the range, * then -1 is returned. * *-------------------------------------------------------------- */ static int Next(vPtr, current) VectorObject *vPtr; int current; { register int i; for(i = current + 1; i <= vPtr->last; i++) { if (FINITE(vPtr->valueArr[i])) { return i; } } return -1; } /* *-------------------------------------------------------------- * * Sort -- * * A vector math function. Sorts the values of the given * vector. * * Results: * Always TCL_OK. * * Side Effects: * The vector is sorted. * *-------------------------------------------------------------- */ static int Sort(vPtr) VectorObject *vPtr; { int *indexArr; double *tempArr; register int i; indexArr = Blt_VectorSortIndex(&vPtr, 1); tempArr = Blt_Malloc(sizeof(double) * vPtr->length); assert(tempArr); for(i = vPtr->first; i <= vPtr->last; i++) { tempArr[i] = vPtr->valueArr[indexArr[i]]; } Blt_Free(indexArr); for(i = vPtr->first; i <= vPtr->last; i++) { vPtr->valueArr[i] = tempArr[i]; } Blt_Free(tempArr); return TCL_OK; } static double Length(vecPtr) Blt_Vector *vecPtr; { VectorObject *vPtr = (VectorObject *)vecPtr; int count; register int i; count = 0; for(i = First(vPtr); i >= 0; i = Next(vPtr, i)) { count++; } return (double) count; } /* ARGSUSED */ double Blt_VecMin(vecPtr) Blt_Vector *vecPtr; { VectorObject *vPtr = (VectorObject *)vecPtr; if (!FINITE(vPtr->min)) { double min; register int i; min = bltNaN; for (i = 0; i < vPtr->length; i++) { if (FINITE(vPtr->valueArr[i])) { min = vPtr->valueArr[i]; break; } } for (/* empty */; i < vPtr->length; i++) { if (FINITE(vPtr->valueArr[i])) { if (min > vPtr->valueArr[i]) { min = vPtr->valueArr[i]; } } } vPtr->min = min; } return vPtr->min; } double Blt_VecMax(vecPtr) Blt_Vector *vecPtr; { VectorObject *vPtr = (VectorObject *)vecPtr; if (!FINITE(vPtr->max)) { double max; register int i; max = bltNaN; for (i = 0; i < vPtr->length; i++) { if (FINITE(vPtr->valueArr[i])) { max = vPtr->valueArr[i]; break; } } for (/* empty */; i < vPtr->length; i++) { if (FINITE(vPtr->valueArr[i])) { if (max < vPtr->valueArr[i]) { max = vPtr->valueArr[i]; } } } vPtr->max = max; } return vPtr->max; } static double Mean(vecPtr) Blt_Vector *vecPtr; { VectorObject *vPtr = (VectorObject *)vecPtr; register int i; int count; double sum; sum = 0.0; count = 0; for(i = First(vPtr); i >= 0; i = Next(vPtr, i)) { sum += vPtr->valueArr[i]; count++; } return sum / (double)count; } /* * var = 1/N Sum( (x[i] - mean)^2 ) */ static double Variance(vecPtr) Blt_Vector *vecPtr; { VectorObject *vPtr = (VectorObject *)vecPtr; register double dx, var, mean; register int i; int count; mean = Mean(vecPtr); var = 0.0; count = 0; for(i = First(vPtr); i >= 0; i = Next(vPtr, i)) { dx = vPtr->valueArr[i] - 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(vecPtr) Blt_Vector *vecPtr; { VectorObject *vPtr = (VectorObject *)vecPtr; register double diff, var, skew, mean, diffsq; register int i; int count; mean = Mean(vecPtr); var = skew = 0.0; count = 0; for(i = First(vPtr); i >= 0; i = Next(vPtr, i)) { diff = vPtr->valueArr[i] - mean; diff = FABS(diff); 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(vecPtr) Blt_Vector *vecPtr; { double var; var = Variance(vecPtr); if (var > 0.0) { return sqrt(var); } return 0.0; } static double AvgDeviation(vecPtr) Blt_Vector *vecPtr; { VectorObject *vPtr = (VectorObject *)vecPtr; register double diff, avg, mean; register int i; int count; mean = Mean(vecPtr); avg = 0.0; count = 0; for(i = First(vPtr); i >= 0; i = Next(vPtr, i)) { diff = vPtr->valueArr[i] - mean; avg += FABS(diff); count++; } if (count < 2) { return 0.0; } avg /= (double)count; return avg; } static double Kurtosis(vecPtr) Blt_Vector *vecPtr; { VectorObject *vPtr = (VectorObject *)vecPtr; register double diff, diffsq, kurt, var, mean; register int i; int count; mean = Mean(vecPtr); var = kurt = 0.0; count = 0; for(i = First(vPtr); i >= 0; i = Next(vPtr, i)) { diff = vPtr->valueArr[i] - mean; 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(vecPtr) Blt_Vector *vecPtr; { VectorObject *vPtr = (VectorObject *)vecPtr; int *iArr; double q2; int mid; if (vPtr->length == 0) { return -DBL_MAX; } iArr = Blt_VectorSortIndex(&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[iArr[mid]]; } else { /* Even */ q2 = (vPtr->valueArr[iArr[mid]] + vPtr->valueArr[iArr[mid + 1]]) * 0.5; } Blt_Free(iArr); return q2; } static double Q1(vecPtr) Blt_Vector *vecPtr; { VectorObject *vPtr = (VectorObject *)vecPtr; double q1; int *iArr; if (vPtr->length == 0) { return -DBL_MAX; } iArr = Blt_VectorSortIndex(&vPtr, 1); if (vPtr->length < 4) { q1 = vPtr->valueArr[iArr[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[iArr[q]]; } else { /* Even */ q1 = (vPtr->valueArr[iArr[q]] + vPtr->valueArr[iArr[q + 1]]) * 0.5; } } Blt_Free(iArr); return q1; } static double Q3(vecPtr) Blt_Vector *vecPtr; { VectorObject *vPtr = (VectorObject *)vecPtr; double q3; int *iArr; if (vPtr->length == 0) { return -DBL_MAX; } iArr = Blt_VectorSortIndex(&vPtr, 1); if (vPtr->length < 4) { q3 = vPtr->valueArr[iArr[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[iArr[q]]; } else { /* Even */ q3 = (vPtr->valueArr[iArr[q]] + vPtr->valueArr[iArr[q + 1]]) * 0.5; } } Blt_Free(iArr); return q3; } static int Norm(vecPtr) Blt_Vector *vecPtr; { VectorObject *vPtr = (VectorObject *)vecPtr; double norm, range, min, max; register int i; min = Blt_VecMin(vecPtr); max = Blt_VecMax(vecPtr); 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 Product(vecPtr) Blt_Vector *vecPtr; { VectorObject *vPtr = (VectorObject *)vecPtr; register int i; register double prod; prod = 1.0; for(i = First(vPtr); i >= 0; i = Next(vPtr, i)) { prod *= vPtr->valueArr[i]; } return prod; } static double Sum(vecPtr) Blt_Vector *vecPtr; { VectorObject *vPtr = (VectorObject *)vecPtr; register int i; double sum; sum = 0.0; for(i = First(vPtr); i >= 0; i = Next(vPtr, i)) { sum += vPtr->valueArr[i]; } return sum; } static double Nonzeros(vecPtr) Blt_Vector *vecPtr; { VectorObject *vPtr = (VectorObject *)vecPtr; register int i; int count; count = 0; for(i = First(vPtr); i >= 0; i = Next(vPtr, i)) { if (vPtr->valueArr[i] == 0.0) { count++; } } return (double) count; } static double Fabs(value) double value; { if (value < 0.0) { return -value; } return value; } static double Round(value) double value; { if (value < 0.0) { return ceil(value - 0.5); } else { return floor(value + 0.5); } } static double Fmod(x, y) double x, 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(interp, value) Tcl_Interp *interp; /* Where to store error message. */ double value; /* Value returned after error; used to * distinguish underflows from overflows. */ { if ((errno == EDOM) || (value != value)) { Tcl_AppendResult(interp, "domain error: argument not in valid range", (char *)NULL); Tcl_SetErrorCode(interp, "ARITH", "DOMAIN", interp->result, (char *)NULL); } else if ((errno == ERANGE) || IS_INF(value)) { if (value == 0.0) { Tcl_AppendResult(interp, "floating-point value too small to represent", (char *)NULL); Tcl_SetErrorCode(interp, "ARITH", "UNDERFLOW", interp->result, (char *)NULL); } else { Tcl_AppendResult(interp, "floating-point value too large to represent", (char *)NULL); Tcl_SetErrorCode(interp, "ARITH", "OVERFLOW", interp->result, (char *)NULL); } } else { char buf[20]; sprintf(buf, "%d", errno); Tcl_AppendResult(interp, "unknown floating-point error, ", "errno = ", buf, (char *)NULL); Tcl_SetErrorCode(interp, "ARITH", "UNKNOWN", interp->result, (char *)NULL); } } /* *-------------------------------------------------------------- * * ParseString -- * * Given a string (such as one coming from command or variable * substitution), make a Value based on the string. The value * will be a floating-point or integer, if possible, or else it * will just be a copy of the string. * * Results: * TCL_OK is returned under normal circumstances, and TCL_ERROR * is returned if a floating-point overflow or underflow occurred * while reading in a number. The value at *valuePtr is modified * to hold a number, if possible. * * Side effects: * None. * *-------------------------------------------------------------- */ static int ParseString(interp, string, valuePtr) Tcl_Interp *interp; /* Where to store error message. */ CONST char *string; /* String to turn into value. */ Value *valuePtr; /* Where to store value information. * Caller must have initialized pv field. */ { 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, &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 (Blt_VectorChangeLength(valuePtr->vPtr, 1) != TCL_OK) { return TCL_ERROR; } valuePtr->vPtr->valueArr[0] = value; return TCL_OK; } else { VectorObject *vPtr; while (isspace(UCHAR(*string))) { string++; /* Skip spaces leading the vector name. */ } vPtr = Blt_VectorParseElement(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. */ Blt_VectorDuplicate(valuePtr->vPtr, vPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * ParseMathFunction -- * * This procedure is invoked to parse a math function from an * expression string, carry out the function, and return the * value computed. * * Results: * TCL_OK is returned if all went well and the function's value * was computed successfully. If the name doesn't match any * known math function, returns TCL_RETURN. And if a format error * was found, TCL_ERROR is returned and an error message is left * in interp->result. * * After a successful return parsePtr will be updated to point to * the character just after the function call, the token is set * to VALUE, and the value is stored in valuePtr. * * Side effects: * Embedded commands could have arbitrary side-effects. * *---------------------------------------------------------------------- */ static int ParseMathFunction(interp, start, parsePtr, valuePtr) Tcl_Interp *interp; /* Interpreter to use for error reporting. */ char *start; /* Start of string to parse */ ParseInfo *parsePtr; /* Describes the state of the parse. * parsePtr->nextPtr must point to the * first character of the function's * name. */ Value *valuePtr; /* Where to store value, if that is * what's parsed from string. Caller * must have initialized pv field * correctly. */ { Blt_HashEntry *hPtr; MathFunction *mathPtr; /* Info about math function. */ register char *p; VectorInterpData *dataPtr; /* Interpreter-specific data. */ /* * Find the end of the math function's name and lookup the * record for the function. */ p = start; while (isspace(UCHAR(*p))) { p++; } parsePtr->nextPtr = p; while (isalnum(UCHAR(*p)) || (*p == '_')) { p++; } if (*p != '(') { return TCL_RETURN; /* Must start with open parenthesis */ } dataPtr = valuePtr->vPtr->dataPtr; *p = '\0'; hPtr = Blt_FindHashEntry(&(dataPtr->mathProcTable), parsePtr->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 */ parsePtr->token = OPEN_PAREN; parsePtr->nextPtr = p + 1; valuePtr->pv.next = valuePtr->pv.buffer; if (NextValue(interp, parsePtr, -1, valuePtr) != TCL_OK) { return TCL_ERROR; /* Parse error */ } if (parsePtr->token != CLOSE_PAREN) { Tcl_AppendResult(interp, "unmatched parentheses in expression \"", parsePtr->expr, "\"", (char *)NULL); return TCL_ERROR; /* Missing right parenthesis */ } mathPtr = (MathFunction *) Blt_GetHashValue(hPtr); if ((*mathPtr->proc) (mathPtr->clientData, interp, valuePtr->vPtr) != TCL_OK) { return TCL_ERROR; /* Function invocation error */ } parsePtr->token = VALUE; return TCL_OK; } /* *---------------------------------------------------------------------- * * NextToken -- * * Lexical analyzer for expression parser: parses a single value, * operator, or other syntactic element from an expression string. * * Results: * TCL_OK is returned unless an error occurred while doing lexical * analysis or executing an embedded command. In that case a * standard Tcl error is returned, using interp->result to hold * an error message. In the event of a successful return, the token * and field in parsePtr is updated to refer to the next symbol in * the expression string, and the expr field is advanced past that * token; if the token is a value, then the value is stored at * valuePtr. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int NextToken(interp, parsePtr, valuePtr) Tcl_Interp *interp; /* Interpreter to use for error reporting. */ ParseInfo *parsePtr; /* Describes the state of the parse. */ Value *valuePtr; /* Where to store value, if that is * what's parsed from string. Caller * must have initialized pv field * correctly. */ { register char *p; char *endPtr; CONST char *var; int result; p = parsePtr->nextPtr; while (isspace(UCHAR(*p))) { p++; } if (*p == '\0') { parsePtr->token = END; parsePtr->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, &endPtr); if (endPtr != p) { if (errno != 0) { MathError(interp, value); return TCL_ERROR; } parsePtr->token = VALUE; parsePtr->nextPtr = endPtr; /* * Save the single floating-point value as an 1-component vector. */ if (Blt_VectorChangeLength(valuePtr->vPtr, 1) != TCL_OK) { return TCL_ERROR; } valuePtr->vPtr->valueArr[0] = value; return TCL_OK; } } parsePtr->nextPtr = p + 1; switch (*p) { case '$': parsePtr->token = VALUE; var = Tcl_ParseVar(interp, p, &endPtr); if (var == NULL) { return TCL_ERROR; } parsePtr->nextPtr = endPtr; Tcl_ResetResult(interp); result = ParseString(interp, var, valuePtr); return result; case '[': parsePtr->token = VALUE; result = TclParseNestedCmd(interp, p + 1, 0, &endPtr, &(valuePtr->pv)); if (result != TCL_OK) { return result; } parsePtr->nextPtr = endPtr; Tcl_ResetResult(interp); result = ParseString(interp, valuePtr->pv.buffer, valuePtr); return result; case '"': parsePtr->token = VALUE; result = TclParseQuotes(interp, p + 1, '"', 0, &endPtr, &(valuePtr->pv)); if (result != TCL_OK) { return result; } parsePtr->nextPtr = endPtr; Tcl_ResetResult(interp); result = ParseString(interp, valuePtr->pv.buffer, valuePtr); return result; case '{': parsePtr->token = VALUE; result = TclParseBraces(interp, p + 1, &endPtr, &valuePtr->pv); if (result != TCL_OK) { return result; } parsePtr->nextPtr = endPtr; Tcl_ResetResult(interp); result = ParseString(interp, valuePtr->pv.buffer, valuePtr); return result; case '(': parsePtr->token = OPEN_PAREN; break; case ')': parsePtr->token = CLOSE_PAREN; break; case ',': parsePtr->token = COMMA; break; case '*': parsePtr->token = MULT; break; case '/': parsePtr->token = DIVIDE; break; case '%': parsePtr->token = MOD; break; case '+': parsePtr->token = PLUS; break; case '-': parsePtr->token = MINUS; break; case '^': parsePtr->token = EXPONENT; break; case '<': switch (*(p + 1)) { case '<': parsePtr->nextPtr = p + 2; parsePtr->token = LEFT_SHIFT; break; case '=': parsePtr->nextPtr = p + 2; parsePtr->token = LEQ; break; default: parsePtr->token = LESS; break; } break; case '>': switch (*(p + 1)) { case '>': parsePtr->nextPtr = p + 2; parsePtr->token = RIGHT_SHIFT; break; case '=': parsePtr->nextPtr = p + 2; parsePtr->token = GEQ; break; default: parsePtr->token = GREATER; break; } break; case '=': if (*(p + 1) == '=') { parsePtr->nextPtr = p + 2; parsePtr->token = EQUAL; } else { parsePtr->token = UNKNOWN; } break; case '&': if (*(p + 1) == '&') { parsePtr->nextPtr = p + 2; parsePtr->token = AND; } else { parsePtr->token = UNKNOWN; } break; case '|': if (*(p + 1) == '|') { parsePtr->nextPtr = p + 2; parsePtr->token = OR; } else { parsePtr->token = UNKNOWN; } break; case '!': if (*(p + 1) == '=') { parsePtr->nextPtr = p + 2; parsePtr->token = NEQ; } else { parsePtr->token = NOT; } break; default: parsePtr->token = VALUE; result = ParseMathFunction(interp, p, parsePtr, valuePtr); if ((result == TCL_OK) || (result == TCL_ERROR)) { return result; } else { VectorObject *vPtr; while (isspace(UCHAR(*p))) { p++; /* Skip spaces leading the vector name. */ } vPtr = Blt_VectorParseElement(interp, valuePtr->vPtr->dataPtr, p, &endPtr, NS_SEARCH_BOTH); if (vPtr == NULL) { return TCL_ERROR; } Blt_VectorDuplicate(valuePtr->vPtr, vPtr); parsePtr->nextPtr = endPtr; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * NextValue -- * * Parse a "value" from the remainder of the expression in parsePtr. * * Results: * Normally TCL_OK is returned. The value of the expression is * returned in *valuePtr. If an error occurred, then interp->result * contains an error message and TCL_ERROR is returned. * InfoPtr->token will be left pointing to the token AFTER the * expression, and parsePtr->nextPtr will point to the character just * after the terminating token. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int NextValue(interp, parsePtr, prec, valuePtr) Tcl_Interp *interp; /* Interpreter to use for error reporting. */ ParseInfo *parsePtr; /* Describes the state of the parse * just before the value (i.e. NextToken will * be called to get first token of value). */ int prec; /* Treat any un-parenthesized operator * with precedence <= this as the end * of the expression. */ Value *valuePtr; /* Where to store the value of the expression. * Caller must have initialized pv field. */ { Value value2; /* Second operand for current operator. */ int operator; /* 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; VectorObject *vPtr, *v2Ptr; register 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 = Blt_VectorNew(vPtr->dataPtr); gotOp = FALSE; value2.vPtr = v2Ptr; value2.pv.buffer = value2.pv.next = value2.staticSpace; value2.pv.end = value2.pv.buffer + STATIC_STRING_SPACE - 1; value2.pv.expandProc = TclExpandParseValue; value2.pv.clientData = NULL; result = NextToken(interp, parsePtr, valuePtr); if (result != TCL_OK) { goto done; } if (parsePtr->token == OPEN_PAREN) { /* Parenthesized sub-expression. */ result = NextValue(interp, parsePtr, -1, valuePtr); if (result != TCL_OK) { goto done; } if (parsePtr->token != CLOSE_PAREN) { Tcl_AppendResult(interp, "unmatched parentheses in expression \"", parsePtr->expr, "\"", (char *)NULL); result = TCL_ERROR; goto done; } } else { if (parsePtr->token == MINUS) { parsePtr->token = UNARY_MINUS; } if (parsePtr->token >= UNARY_MINUS) { operator = parsePtr->token; result = NextValue(interp, parsePtr, precTable[operator], valuePtr); if (result != TCL_OK) { goto done; } gotOp = TRUE; /* Process unary operators. */ switch (operator) { 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 (parsePtr->token != VALUE) { Tcl_AppendResult(interp, "missing operand", (char *)NULL); goto error; } } if (!gotOp) { result = NextToken(interp, parsePtr, &value2); if (result != TCL_OK) { goto done; } } /* * Got the first operand. Now fetch (operator, operand) pairs. */ for (;;) { operator = parsePtr->token; value2.pv.next = value2.pv.buffer; if ((operator < MULT) || (operator >= UNARY_MINUS)) { if ((operator == END) || (operator == CLOSE_PAREN) || (operator == COMMA)) { result = TCL_OK; goto done; } else { Tcl_AppendResult(interp, "bad operator", (char *)NULL); goto error; } } if (precTable[operator] <= prec) { result = TCL_OK; goto done; } result = NextValue(interp, parsePtr, precTable[operator], &value2); if (result != TCL_OK) { goto done; } if ((parsePtr->token < MULT) && (parsePtr->token != VALUE) && (parsePtr->token != END) && (parsePtr->token != CLOSE_PAREN) && (parsePtr->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) { register double *opnd; register double scalar; /* * 2nd operand is a scalar. */ scalar = v2Ptr->valueArr[0]; opnd = vPtr->valueArr; switch (operator) { 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; register int j; hold = Blt_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]; } Blt_Free(hold); } } break; case RIGHT_SHIFT: { int offset; offset = (int)scalar % vPtr->length; if (offset > 0) { double *hold; register int j; hold = Blt_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]; } Blt_Free(hold); } } break; default: Tcl_AppendResult(interp, "unknown operator in expression", (char *)NULL); goto error; } } else if (vPtr->length == 1) { register double *opnd; register double scalar; /* * 1st operand is a scalar. */ scalar = vPtr->valueArr[0]; Blt_VectorDuplicate(vPtr, v2Ptr); opnd = vPtr->valueArr; switch (operator) { 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 { register 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 (operator) { 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) { Blt_Free(value2.pv.buffer); } Blt_VectorFree(v2Ptr); return result; error: if (value2.pv.buffer != value2.staticSpace) { Blt_Free(value2.pv.buffer); } Blt_VectorFree(v2Ptr); return TCL_ERROR; } /* *-------------------------------------------------------------- * * EvaluateExpression -- * * This procedure provides top-level functionality shared by * procedures like Tcl_ExprInt, Tcl_ExprDouble, etc. * * Results: * The result is a standard Tcl return value. If an error * occurs then an error message is left in interp->result. * The value of the expression is returned in *valuePtr, in * whatever form it ends up in (could be string or integer * or double). Caller may need to convert result. Caller * is also responsible for freeing string memory in *valuePtr, * if any was allocated. * * Side effects: * None. * *-------------------------------------------------------------- */ static int EvaluateExpression(interp, string, valuePtr) Tcl_Interp *interp; /* Context in which to evaluate the * expression. */ char *string; /* Expression to evaluate. */ Value *valuePtr; /* Where to store result. Should * not be initialized by caller. */ { ParseInfo info; int result; VectorObject *vPtr; register int i; 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 = TclExpandParseValue; 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 (i = 0; i < vPtr->length; i++) { if (!FINITE(vPtr->valueArr[i])) { /* * IEEE floating-point error. */ MathError(interp, vPtr->valueArr[i]); return TCL_ERROR; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * Math Functions -- * * This page contains the procedures that implement all of the * built-in math functions for expressions. * * Results: * Each procedure returns TCL_OK if it succeeds and places result * information at *resultPtr. If it fails it returns TCL_ERROR * and leaves an error message in interp->result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int ComponentFunc(clientData, interp, vPtr) ClientData clientData; /* Contains address of procedure that * takes one double argument and * returns a double result. */ Tcl_Interp *interp; VectorObject *vPtr; { ComponentProc *procPtr = (ComponentProc *) clientData; register int i; errno = 0; for(i = First(vPtr); i >= 0; i = Next(vPtr, i)) { vPtr->valueArr[i] = (*procPtr) (vPtr->valueArr[i]); if (errno != 0) { MathError(interp, vPtr->valueArr[i]); return TCL_ERROR; } if (!FINITE(vPtr->valueArr[i])) { /* * IEEE floating-point error. */ MathError(interp, vPtr->valueArr[i]); return TCL_ERROR; } } return TCL_OK; } static int ScalarFunc(clientData, interp, vPtr) ClientData clientData; Tcl_Interp *interp; VectorObject *vPtr; { double value; ScalarProc *procPtr = (ScalarProc *) clientData; errno = 0; value = (*procPtr) (vPtr); if (errno != 0) { MathError(interp, value); return TCL_ERROR; } if (Blt_VectorChangeLength(vPtr, 1) != TCL_OK) { return TCL_ERROR; } vPtr->valueArr[0] = value; return TCL_OK; } /*ARGSUSED*/ static int VectorFunc(clientData, interp, vPtr) ClientData clientData; Tcl_Interp *interp; /* Not used. */ VectorObject *vPtr; { VectorProc *procPtr = (VectorProc *) clientData; return (*procPtr) (vPtr); } static MathFunction mathFunctions[] = { {"abs", (GenericMathProc *) ComponentFunc, (ClientData)Fabs}, {"acos", (GenericMathProc *) ComponentFunc, (ClientData)acos}, {"asin", (GenericMathProc *) ComponentFunc, (ClientData)asin}, {"atan", (GenericMathProc *) ComponentFunc, (ClientData)atan}, {"adev", (GenericMathProc *) ScalarFunc, (ClientData)AvgDeviation}, {"ceil", (GenericMathProc *) ComponentFunc, (ClientData)ceil}, {"cos", (GenericMathProc *) ComponentFunc, (ClientData)cos}, {"cosh", (GenericMathProc *) ComponentFunc, (ClientData)cosh}, {"exp", (GenericMathProc *) ComponentFunc, (ClientData)exp}, {"floor", (GenericMathProc *) ComponentFunc, (ClientData)floor}, {"kurtosis", (GenericMathProc *) ScalarFunc, (ClientData)Kurtosis}, {"length", (GenericMathProc *) ScalarFunc, (ClientData)Length}, {"log", (GenericMathProc *) ComponentFunc, (ClientData)log}, {"log10", (GenericMathProc *) ComponentFunc, (ClientData)log10}, {"max", (GenericMathProc *) ScalarFunc, (ClientData)Blt_VecMax}, {"mean", (GenericMathProc *) ScalarFunc, (ClientData)Mean}, {"median", (GenericMathProc *) ScalarFunc, (ClientData)Median}, {"min", (GenericMathProc *) ScalarFunc, (ClientData)Blt_VecMin}, {"norm", (GenericMathProc *) VectorFunc, (ClientData)Norm}, {"nz", (GenericMathProc *) ScalarFunc, (ClientData)Nonzeros}, {"q1", (GenericMathProc *) ScalarFunc, (ClientData)Q1}, {"q3", (GenericMathProc *) ScalarFunc, (ClientData)Q3}, {"prod", (GenericMathProc *) ScalarFunc, (ClientData)Product}, #ifdef HAVE_DRAND48 {"random", (GenericMathProc *) ComponentFunc, (ClientData)drand48}, #endif {"round", (GenericMathProc *) ComponentFunc, (ClientData)Round}, {"sdev", (GenericMathProc *) ScalarFunc, (ClientData)StdDeviation}, {"sin", (GenericMathProc *) ComponentFunc, (ClientData)sin}, {"sinh", (GenericMathProc *) ComponentFunc, (ClientData)sinh}, {"skew", (GenericMathProc *) ScalarFunc, (ClientData)Skew}, {"sort", (GenericMathProc *) VectorFunc, (ClientData)Sort}, {"sqrt", (GenericMathProc *) ComponentFunc, (ClientData)sqrt}, {"sum", (GenericMathProc *) ScalarFunc, (ClientData)Sum}, {"tan", (GenericMathProc *) ComponentFunc, (ClientData)tan}, {"tanh", (GenericMathProc *) ComponentFunc, (ClientData)tanh}, {"var", (GenericMathProc *) ScalarFunc, (ClientData)Variance}, {(char *)NULL,}, }; void Blt_VectorInstallMathFunctions(tablePtr) Blt_HashTable *tablePtr; { Blt_HashEntry *hPtr; register MathFunction *mathPtr; int isNew; for (mathPtr = mathFunctions; mathPtr->name != NULL; mathPtr++) { hPtr = Blt_CreateHashEntry(tablePtr, mathPtr->name, &isNew); Blt_SetHashValue(hPtr, (ClientData)mathPtr); } } void Blt_VectorUninstallMathFunctions(tablePtr) Blt_HashTable *tablePtr; { MathFunction *mathPtr; Blt_HashEntry *hPtr; Blt_HashSearch cursor; for (hPtr = Blt_FirstHashEntry(tablePtr, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { mathPtr = (MathFunction *) Blt_GetHashValue(hPtr); if (mathPtr->name == NULL) { Blt_Free(mathPtr); } } } static void InstallIndexProc(tablePtr, string, procPtr) Blt_HashTable *tablePtr; char *string; Blt_VectorIndexProc *procPtr; /* Pointer to function to be called * when the vector finds the named index. * If NULL, this indicates to remove * the index from the table. */ { Blt_HashEntry *hPtr; int dummy; hPtr = Blt_CreateHashEntry(tablePtr, string, &dummy); if (procPtr == NULL) { Blt_DeleteHashEntry(tablePtr, hPtr); } else { Blt_SetHashValue(hPtr, (ClientData)procPtr); } } void Blt_VectorInstallSpecialIndices(tablePtr) Blt_HashTable *tablePtr; { InstallIndexProc(tablePtr, "min", Blt_VecMin); InstallIndexProc(tablePtr, "max", Blt_VecMax); InstallIndexProc(tablePtr, "mean", Mean); InstallIndexProc(tablePtr, "sum", Sum); InstallIndexProc(tablePtr, "prod", Product); } /* *-------------------------------------------------------------- * * Blt_ExprVector -- * * Evaluates an vector expression and returns its value(s). * * Results: * Each of the procedures below returns a standard Tcl result. * If an error occurs then an error message is left in * interp->result. Otherwise the value of the expression, * in the appropriate form, is stored at *resultPtr. If * the expression had a result that was incompatible with the * desired form then an error is returned. * * Side effects: * None. * *-------------------------------------------------------------- */ int Blt_ExprVector(interp, string, vecPtr) Tcl_Interp *interp; /* Context in which to evaluate the * expression. */ char *string; /* Expression to evaluate. */ Blt_Vector *vecPtr; /* Where to store result. */ { VectorInterpData *dataPtr; /* Interpreter-specific data. */ VectorObject *vPtr = (VectorObject *)vecPtr; Value value; dataPtr = (vecPtr != NULL) ? vPtr->dataPtr : Blt_VectorGetInterpData(interp); value.vPtr = Blt_VectorNew(dataPtr); if (EvaluateExpression(interp, string, &value) != TCL_OK) { Blt_VectorFree(value.vPtr); return TCL_ERROR; } if (vPtr != NULL) { Blt_VectorDuplicate(vPtr, value.vPtr); } else { register int i; /* No result vector. Put values in interp->result. */ for (i = 0; i < value.vPtr->length; i++) { string = Blt_Dtoa(interp, value.vPtr->valueArr[i]); Tcl_AppendElement(interp, string); } } Blt_VectorFree(value.vPtr); return TCL_OK; } blt-2.4z.orig/src/bltVecObjCmd.c0100644000175000017500000015203707540713417015215 0ustar dokodoko /* * bltVecCmd.c -- * * This module implements vector data objects. * * Copyright 1995-1998 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. */ /* * 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 "bltVecInt.h" #if (TCL_MAJOR_VERSION > 7) static int GetDouble(interp, objPtr, valuePtr) Tcl_Interp *interp; Tcl_Obj *objPtr; double *valuePtr; { /* First try to extract the value as a double precision number. */ if (Tcl_GetDoubleFromObj(interp, objPtr, valuePtr) == TCL_OK) { return TCL_OK; } Tcl_ResetResult(interp); /* Then try to parse it as an expression. */ if (Tcl_ExprDouble(interp, Tcl_GetString(objPtr), valuePtr) == TCL_OK) { return TCL_OK; } return TCL_ERROR; } static Tcl_Obj * GetValues(VectorObject *vPtr, int first, int last) { register int i; Tcl_Obj *listObjPtr; listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); for (i = first; i <= last; i++) { Tcl_ListObjAppendElement(vPtr->interp, listObjPtr, Tcl_NewDoubleObj(vPtr->valueArr[i])); } return listObjPtr; } static void ReplicateValue(vPtr, first, last, value) VectorObject *vPtr; int first, last; double value; { register int i; for (i = first; i <= last; i++) { vPtr->valueArr[i] = value; } vPtr->notifyFlags |= UPDATE_RANGE; } static int CopyList(vPtr, objc, objv) VectorObject *vPtr; int objc; Tcl_Obj *CONST *objv; { register int i; double value; if (Blt_VectorChangeLength(vPtr, objc) != TCL_OK) { return TCL_ERROR; } for (i = 0; i < objc; i++) { if (GetDouble(vPtr->interp, objv[i], &value) != TCL_OK) { Blt_VectorChangeLength(vPtr, i); return TCL_ERROR; } vPtr->valueArr[i] = value; } return TCL_OK; } static int AppendVector(destPtr, srcPtr) VectorObject *destPtr, *srcPtr; { int nBytes; int oldSize, newSize; oldSize = destPtr->length; newSize = oldSize + srcPtr->last - srcPtr->first + 1; if (Blt_VectorChangeLength(destPtr, newSize) != TCL_OK) { return TCL_ERROR; } 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(vPtr, objc, objv) VectorObject *vPtr; int objc; Tcl_Obj *CONST *objv; { int count; register int i; double value; int oldSize; oldSize = vPtr->length; if (Blt_VectorChangeLength(vPtr, vPtr->length + objc) != TCL_OK) { return TCL_ERROR; } count = oldSize; for (i = 0; i < objc; i++) { if (GetDouble(vPtr->interp, objv[i], &value) != TCL_OK) { Blt_VectorChangeLength(vPtr, count); return TCL_ERROR; } vPtr->valueArr[count++] = value; } vPtr->notifyFlags |= UPDATE_RANGE; return TCL_OK; } /* Vector instance option commands */ /* * ----------------------------------------------------------------------- * * AppendOp -- * * Appends one of more Tcl lists of values, or vector objects * onto the end of the current vector object. * * Results: * A standard Tcl result. If a current vector can't be created, * resized, any of the named vectors can't be found, or one of * lists of values is invalid, TCL_ERROR is returned. * * Side Effects: * Clients of current vector will be notified of the change. * * ----------------------------------------------------------------------- */ static int AppendOp(vPtr, interp, objc, objv) VectorObject *vPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { register int i; int result; VectorObject *v2Ptr; for (i = 2; i < objc; i++) { v2Ptr = Blt_VectorParseElement((Tcl_Interp *)NULL, vPtr->dataPtr, Tcl_GetString(objv[i]), (char **)NULL, NS_SEARCH_BOTH); 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) { Blt_VectorFlushCache(vPtr); } Blt_VectorUpdateClients(vPtr); } return TCL_OK; } /* * ----------------------------------------------------------------------- * * ClearOp -- * * Deletes all the accumulated array indices for the Tcl array * associated will the vector. This routine can be used to * free excess memory from a large vector. * * Results: * Always returns TCL_OK. * * Side Effects: * Memory used for the entries of the Tcl array variable is freed. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int ClearOp(vPtr, interp, objc, objv) VectorObject *vPtr; Tcl_Interp *interp; /* Not used. */ int objc; /* Not used. */ Tcl_Obj *CONST *objv; /* Not used. */ { Blt_VectorFlushCache(vPtr); return TCL_OK; } /* * ----------------------------------------------------------------------- * * DeleteOp -- * * Deletes the given indices from the vector. If no indices are * provided the entire vector is deleted. * * Results: * A standard Tcl result. If any of the given indices is invalid, * interp->result will an error message and TCL_ERROR is returned. * * Side Effects: * The clients of the vector will be notified of the vector * deletions. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int DeleteOp(vPtr, interp, objc, objv) VectorObject *vPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { unsigned char *unsetArr; register int i, j; register int count; char *string; /* FIXME: Don't delete vector with no indices. */ if (objc == 2) { Blt_VectorFree(vPtr); return TCL_OK; } /* * Allocate an "unset" bitmap the size of the vector. */ unsetArr = Blt_Calloc(sizeof(unsigned char), (vPtr->length + 7) / 8); assert(unsetArr); #define SetBit(i) \ unsetArr[(i) >> 3] |= (1 << ((i) & 0x07)) #define GetBit(i) \ (unsetArr[(i) >> 3] & (1 << ((i) & 0x07))) for (i = 2; i < objc; i++) { string = Tcl_GetString(objv[i]); if (Blt_VectorGetIndexRange(interp, vPtr, string, (INDEX_COLON | INDEX_CHECK), (Blt_VectorIndexProc **) NULL) != TCL_OK) { Blt_Free(unsetArr); return TCL_ERROR; } for (j = vPtr->first; j <= vPtr->last; j++) { SetBit(j); /* Mark the range of elements for deletion. */ } } count = 0; for (i = 0; i < vPtr->length; i++) { if (GetBit(i)) { continue; /* Skip elements marked for deletion. */ } if (count < i) { vPtr->valueArr[count] = vPtr->valueArr[i]; } count++; } Blt_Free(unsetArr); vPtr->length = count; if (vPtr->flush) { Blt_VectorFlushCache(vPtr); } Blt_VectorUpdateClients(vPtr); return TCL_OK; } /* * ----------------------------------------------------------------------- * * DupOp -- * * Creates one or more duplicates of the vector object. * * Results: * A standard Tcl result. If a new vector can't be created, * or and existing vector resized, TCL_ERROR is returned. * * Side Effects: * Clients of existing vectors will be notified of the change. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int DupOp(vPtr, interp, objc, objv) VectorObject *vPtr; Tcl_Interp *interp; /* Not used. */ int objc; Tcl_Obj *CONST *objv; { VectorObject *v2Ptr; int isNew; register int i; char *string; for (i = 2; i < objc; i++) { string = Tcl_GetString(objv[i]); v2Ptr = Blt_VectorCreate(vPtr->dataPtr, string, string, string,&isNew); if (v2Ptr == NULL) { return TCL_ERROR; } if (v2Ptr == vPtr) { continue; } if (Blt_VectorDuplicate(v2Ptr, vPtr) != TCL_OK) { return TCL_ERROR; } if (!isNew) { if (v2Ptr->flush) { Blt_VectorFlushCache(v2Ptr); } Blt_VectorUpdateClients(v2Ptr); } } return TCL_OK; } /* * ----------------------------------------------------------------------- * * IndexOp -- * * Sets or reads the value of the index. This simulates what the * vector's variable does. * * Results: * A standard Tcl result. If the index is invalid, * interp->result will an error message and TCL_ERROR is returned. * Otherwise interp->result will contain the values. * * ----------------------------------------------------------------------- */ static int IndexOp(vPtr, interp, objc, objv) VectorObject *vPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { int first, last; char *string; string = Tcl_GetString(objv[2]); if (Blt_VectorGetIndexRange(interp, vPtr, string, INDEX_ALL_FLAGS, (Blt_VectorIndexProc **) NULL) != TCL_OK) { return TCL_ERROR; } first = vPtr->first, 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 { double value; /* FIXME: huh? Why set values here?. */ if (first == SPECIAL_INDEX) { Tcl_AppendResult(interp, "can't set index \"", string, "\"", (char *)NULL); return TCL_ERROR; /* Tried to set "min" or "max" */ } if (GetDouble(vPtr->interp, objv[3], &value) != TCL_OK) { return TCL_ERROR; } if (first == vPtr->length) { if (Blt_VectorChangeLength(vPtr, vPtr->length + 1) != TCL_OK) { return TCL_ERROR; } } ReplicateValue(vPtr, first, last, value); Tcl_SetObjResult(interp, objv[3]); if (vPtr->flush) { Blt_VectorFlushCache(vPtr); } Blt_VectorUpdateClients(vPtr); } return TCL_OK; } /* * ----------------------------------------------------------------------- * * LengthOp -- * * Returns the length of the vector. If a new size is given, the * vector is resized to the new vector. * * Results: * A standard Tcl result. If the new length is invalid, * interp->result will an error message and TCL_ERROR is returned. * Otherwise interp->result will contain the length of the vector. * * ----------------------------------------------------------------------- */ static int LengthOp(vPtr, interp, objc, objv) VectorObject *vPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { if (objc == 3) { int size; if (Tcl_GetIntFromObj(interp, objv[2], &size) != TCL_OK) { return TCL_ERROR; } if (size < 0) { Tcl_AppendResult(interp, "bad vector size \"", Tcl_GetString(objv[2]), "\"", (char *)NULL); return TCL_ERROR; } if (Blt_VectorChangeLength(vPtr, size) != TCL_OK) { return TCL_ERROR; } if (vPtr->flush) { Blt_VectorFlushCache(vPtr); } Blt_VectorUpdateClients(vPtr); } Tcl_SetObjResult(interp, Tcl_NewIntObj(vPtr->length)); return TCL_OK; } /* * ----------------------------------------------------------------------- * * MapOp -- * * Queries or sets the offset of the array index from the base * address of the data array of values. * * Results: * A standard Tcl result. If the source vector doesn't exist * or the source list is not a valid list of numbers, TCL_ERROR * returned. Otherwise TCL_OK is returned. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int MapOp(vPtr, interp, objc, objv) VectorObject *vPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { if (objc > 2) { if (Blt_VectorMapVariable(interp, vPtr, Tcl_GetString(objv[2])) != TCL_OK) { return TCL_ERROR; } } if (vPtr->arrayName != NULL) { Tcl_SetResult(interp, vPtr->arrayName, TCL_VOLATILE); } return TCL_OK; } /* * ----------------------------------------------------------------------- * * MergeOp -- * * Merges the values from the given vectors to the current vector. * * Results: * A standard Tcl result. If any of the given vectors differ in size, * TCL_ERROR is returned. Otherwise TCL_OK is returned and the * vector data will contain merged values of the given vectors. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int MergeOp(vPtr, interp, objc, objv) VectorObject *vPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { VectorObject *v2Ptr; VectorObject **vecArr; register VectorObject **vPtrPtr; int refSize, length, nElem; register int i; double *valuePtr, *valueArr; /* Allocate an array of vector pointers of each vector to be * merged in the current vector. */ vecArr = Blt_Malloc(sizeof(VectorObject *) * objc); assert(vecArr); vPtrPtr = vecArr; refSize = -1; nElem = 0; for (i = 2; i < objc; i++) { if (Blt_VectorLookupName(vPtr->dataPtr, Tcl_GetString(objv[i]), &v2Ptr) != TCL_OK) { Blt_Free(vecArr); return TCL_ERROR; } /* Check that all the vectors are the same length */ 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); Blt_Free(vecArr); return TCL_ERROR; } *vPtrPtr++ = v2Ptr; nElem += refSize; } *vPtrPtr = NULL; valueArr = Blt_Malloc(sizeof(double) * nElem); if (valueArr == NULL) { Tcl_AppendResult(vPtr->interp, "not enough memory to allocate ", Blt_Itoa(nElem), " vector elements", (char *)NULL); return TCL_ERROR; } /* Merge the values from each of the vectors into the current vector */ valuePtr = valueArr; for (i = 0; i < refSize; i++) { for (vPtrPtr = vecArr; *vPtrPtr != NULL; vPtrPtr++) { *valuePtr++ = (*vPtrPtr)->valueArr[i + (*vPtrPtr)->first]; } } Blt_Free(vecArr); Blt_VectorReset(vPtr, valueArr, nElem, nElem, TCL_DYNAMIC); return TCL_OK; } /* * ----------------------------------------------------------------------- * * NormalizeOp -- * * Normalizes the vector. * * Results: * A standard Tcl result. If the density is invalid, TCL_ERROR * is returned. Otherwise TCL_OK is returned. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int NormalizeOp(vPtr, interp, objc, objv) VectorObject *vPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { register int i; double range; Blt_VectorUpdateRange(vPtr); range = vPtr->max - vPtr->min; if (objc > 2) { VectorObject *v2Ptr; int isNew; char *string; string = Tcl_GetString(objv[2]); v2Ptr = Blt_VectorCreate(vPtr->dataPtr, string, string, string, &isNew); if (v2Ptr == NULL) { return TCL_ERROR; } if (Blt_VectorChangeLength(v2Ptr, vPtr->length) != TCL_OK) { return TCL_ERROR; } for (i = 0; i < vPtr->length; i++) { v2Ptr->valueArr[i] = (vPtr->valueArr[i] - vPtr->min) / range; } Blt_VectorUpdateRange(v2Ptr); if (!isNew) { if (v2Ptr->flush) { Blt_VectorFlushCache(v2Ptr); } Blt_VectorUpdateClients(v2Ptr); } } else { double norm; Tcl_Obj *listObjPtr; listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); for (i = 0; i < vPtr->length; i++) { norm = (vPtr->valueArr[i] - vPtr->min) / range; Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(norm)); } Tcl_SetObjResult(interp, listObjPtr); } return TCL_OK; } /* * ----------------------------------------------------------------------- * * NotifyOp -- * * Notify clients of vector. * * Results: * A standard Tcl result. If any of the given vectors differ in size, * TCL_ERROR is returned. Otherwise TCL_OK is returned and the * vector data will contain merged values of the given vectors. * * x vector notify now * x vector notify always * x vector notify whenidle * x vector notify update {} * x vector notify delete {} * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int NotifyOp(vPtr, interp, objc, objv) VectorObject *vPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { int option; int bool; enum optionIndices { OPTION_ALWAYS, OPTION_NEVER, OPTION_WHENIDLE, OPTION_NOW, OPTION_CANCEL, OPTION_PENDING }; static char *optionArr[] = { "always", "never", "whenidle", "now", "cancel", "pending", NULL }; 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_VectorNotifyClients(vPtr); break; case OPTION_CANCEL: if (vPtr->notifyFlags & NOTIFY_PENDING) { vPtr->notifyFlags &= ~NOTIFY_PENDING; Tcl_CancelIdleCall(Blt_VectorNotifyClients, (ClientData)vPtr); } break; case OPTION_PENDING: bool = (vPtr->notifyFlags & NOTIFY_PENDING); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(bool)); break; } return TCL_OK; } /* * ----------------------------------------------------------------------- * * PopulateOp -- * * Creates or resizes a new vector based upon the density specified. * * Results: * A standard Tcl result. If the density is invalid, TCL_ERROR * is returned. Otherwise TCL_OK is returned. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int PopulateOp(vPtr, interp, objc, objv) VectorObject *vPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { VectorObject *v2Ptr; int size, density; int isNew; register int i, j; double slice, range; register double *valuePtr; int count; char *string; string = Tcl_GetString(objv[2]); v2Ptr = Blt_VectorCreate(vPtr->dataPtr, string, string, string, &isNew); if (v2Ptr == NULL) { return TCL_ERROR; } if (vPtr->length == 0) { return TCL_OK; /* Source vector is empty. */ } 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; } size = (vPtr->length - 1) * (density + 1) + 1; if (Blt_VectorChangeLength(v2Ptr, size) != TCL_OK) { return TCL_ERROR; } count = 0; valuePtr = v2Ptr->valueArr; for (i = 0; i < (vPtr->length - 1); i++) { range = vPtr->valueArr[i + 1] - vPtr->valueArr[i]; slice = range / (double)(density + 1); for (j = 0; j <= density; j++) { *valuePtr = vPtr->valueArr[i] + (slice * (double)j); valuePtr++; count++; } } count++; *valuePtr = vPtr->valueArr[i]; assert(count == v2Ptr->length); if (!isNew) { if (v2Ptr->flush) { Blt_VectorFlushCache(v2Ptr); } Blt_VectorUpdateClients(v2Ptr); } return TCL_OK; } /* * ----------------------------------------------------------------------- * * RangeOp -- * * Returns a Tcl list of the range of vector values specified. * * Results: * A standard Tcl result. If the given range is invalid, TCL_ERROR * is returned. Otherwise TCL_OK is returned and interp->result * will contain the list of values. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int RangeOp(vPtr, interp, objc, objv) VectorObject *vPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { Tcl_Obj *listObjPtr; int first, last; register int i; if ((Blt_VectorGetIndex(interp, vPtr, Tcl_GetString(objv[2]), &first, INDEX_CHECK, (Blt_VectorIndexProc **) NULL) != TCL_OK) || (Blt_VectorGetIndex(interp, vPtr, Tcl_GetString(objv[3]), &last, INDEX_CHECK, (Blt_VectorIndexProc **) NULL) != TCL_OK)) { return TCL_ERROR; } listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); if (first > last) { /* Return the list reversed */ for (i = last; i <= first; i++) { Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(vPtr->valueArr[i])); } } else { for (i = first; i <= last; i++) { Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(vPtr->valueArr[i])); } } Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; } /* * ---------------------------------------------------------------------- * * InRange -- * * Determines if a value lies within a given range. * * The value is normalized and compared against the interval * [0..1], where 0.0 is the minimum and 1.0 is the maximum. * DBL_EPSILON is the smallest number that can be represented * on the host machine, such that (1.0 + epsilon) != 1.0. * * Please note, min cannot be greater than max. * * Results: * If the value is within of the interval [min..max], 1 is * returned; 0 otherwise. * * ---------------------------------------------------------------------- */ INLINE static int InRange(value, min, max) double value, min, max; { double range; range = max - min; if (range < DBL_EPSILON) { return (FABS(max - value) < DBL_EPSILON); } else { double norm; 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. Formats may be * as follows. * * signed i1, i2, i4, i8 * unsigned u1, u2, u4, u8 * real r4, r8, r16 * * But 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(interp, string, sizePtr) Tcl_Interp *interp; char *string; int *sizePtr; { char c; 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(vPtr, byteArr, fmt, size, length, swap, indexPtr) VectorObject *vPtr; char *byteArr; enum NativeFormats fmt; int size; int length; int swap; int *indexPtr; { register int i, n; int newSize; if ((swap) && (size > 1)) { int nBytes = size * length; register unsigned char *p; register int left, right; for (i = 0; i < nBytes; i += size) { p = (unsigned char *)(byteArr + i); for (left = 0, right = size - 1; left < right; left++, right--) { p[left] ^= p[right]; p[right] ^= p[left]; p[left] ^= p[right]; } } } newSize = *indexPtr + length; if (newSize > vPtr->length) { if (Blt_VectorChangeLength(vPtr, newSize) != TCL_OK) { return TCL_ERROR; } } #define CopyArrayToVector(vPtr, arr) \ for (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 by Harald Kirsch (kir@iitb.fhg.de). * Anything that's wrong is due to my munging of his 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. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int BinreadOp(vPtr, interp, objc, objv) VectorObject *vPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { Tcl_Channel channel; char *byteArr; char *string; enum NativeFormats fmt; int arraySize, bytesRead; int count, total; int first; int size, length, mode; int swap; register int i; string = Tcl_GetString(objv[2]); 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; } first = vPtr->length; fmt = FMT_DOUBLE; size = sizeof(double); swap = FALSE; 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 = (int)value; objc--, objv++; } } /* Process any option-value pairs that remain. */ for (i = 3; i < objc; i++) { string = Tcl_GetString(objv[i]); if (strcmp(string, "-swap") == 0) { swap = TRUE; } 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 (Blt_VectorGetIndex(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 if (count == 0) { arraySize = BUFFER_SIZE * size; } else { arraySize = count * size; } byteArr = Blt_Malloc(arraySize); assert(byteArr); /* FIXME: restore old channel translation later? */ if (Tcl_SetChannelOption(interp, channel, "-translation", "binary") != TCL_OK) { return TCL_ERROR; } total = 0; while (!Tcl_Eof(channel)) { 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; } length = bytesRead / size; if (CopyValues(vPtr, byteArr, fmt, size, length, swap, &first) != TCL_OK) { return TCL_ERROR; } total += length; if (count > 0) { break; } } Blt_Free(byteArr); if (vPtr->flush) { Blt_VectorFlushCache(vPtr); } Blt_VectorUpdateClients(vPtr); /* Set the result as the number of values read. */ Tcl_SetObjResult(interp, Tcl_NewIntObj(total)); return TCL_OK; } /* * ----------------------------------------------------------------------- * * SearchOp -- * * Searchs for a value in the vector. Returns the indices of all * vector elements matching a particular value. * * Results: * Always returns TCL_OK. interp->result will contain a list of * the indices of array elements matching value. If no elements * match, interp->result will contain the empty string. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int SearchOp(vPtr, interp, objc, objv) VectorObject *vPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { double min, max; register int i; int wantValue; char *string; Tcl_Obj *listObjPtr; wantValue = FALSE; string = Tcl_GetString(objv[2]); if ((string[0] == '-') && (strcmp(string, "-value") == 0)) { wantValue = TRUE; objv++, objc--; } if (GetDouble(interp, objv[2], &min) != TCL_OK) { return TCL_ERROR; } max = min; if ((objc > 3) && (GetDouble(interp, objv[3], &max) != TCL_OK)) { return TCL_ERROR; } if ((min - max) >= DBL_EPSILON) { return TCL_OK; /* Bogus range. Don't bother looking. */ } listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); if (wantValue) { for (i = 0; i < vPtr->length; i++) { if (InRange(vPtr->valueArr[i], min, max)) { Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(vPtr->valueArr[i])); } } } else { for (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; } /* * ----------------------------------------------------------------------- * * OffsetOp -- * * Queries or sets the offset of the array index from the base * address of the data array of values. * * Results: * A standard Tcl result. If the source vector doesn't exist * or the source list is not a valid list of numbers, TCL_ERROR * returned. Otherwise TCL_OK is returned. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int OffsetOp(vPtr, interp, objc, objv) VectorObject *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_SetObjResult(interp, Tcl_NewIntObj(vPtr->offset)); return TCL_OK; } /* * ----------------------------------------------------------------------- * * RandomOp -- * * Generates random values for the length of the vector. * * Results: * A standard Tcl result. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int RandomOp(vPtr, interp, objc, objv) VectorObject *vPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; /* Not used. */ { #ifdef HAVE_DRAND48 register int i; for (i = 0; i < vPtr->length; i++) { vPtr->valueArr[i] = drand48(); } #endif /* HAVE_DRAND48 */ if (vPtr->flush) { Blt_VectorFlushCache(vPtr); } Blt_VectorUpdateClients(vPtr); return TCL_OK; } /* * ----------------------------------------------------------------------- * * SeqOp -- * * Generates a sequence of values in the vector. * * Results: * A standard Tcl result. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int SeqOp(vPtr, interp, objc, objv) VectorObject *vPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { register int i; double start, finish, step; int fillVector; int nSteps; char *string; if (GetDouble(interp, objv[2], &start) != TCL_OK) { return TCL_ERROR; } fillVector = FALSE; string = Tcl_GetString(objv[3]); if ((string[0] == 'e') && (strcmp(string, "end") == 0)) { fillVector = TRUE; } else if (GetDouble(interp, objv[3], &finish) != TCL_OK) { return TCL_ERROR; } step = 1.0; if ((objc > 4) && (GetDouble(interp, objv[4], &step) != TCL_OK)) { return TCL_ERROR; } if (fillVector) { nSteps = vPtr->length; } else { nSteps = (int)((finish - start) / step) + 1; } if (nSteps > 0) { if (Blt_VectorChangeLength(vPtr, nSteps) != TCL_OK) { return TCL_ERROR; } for (i = 0; i < nSteps; i++) { vPtr->valueArr[i] = start + (step * (double)i); } if (vPtr->flush) { Blt_VectorFlushCache(vPtr); } Blt_VectorUpdateClients(vPtr); } return TCL_OK; } /* * ----------------------------------------------------------------------- * * SetOp -- * * Sets the data of the vector object from a list of values. * * Results: * A standard Tcl result. If the source vector doesn't exist * or the source list is not a valid list of numbers, TCL_ERROR * returned. Otherwise TCL_OK is returned. * * Side Effects: * The vector data is reset. Clients of the vector are notified. * Any cached array indices are flushed. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int SetOp(vPtr, interp, objc, objv) VectorObject *vPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { int result; VectorObject *v2Ptr; int nElem; Tcl_Obj **elemObjArr; /* The source can be either a list of numbers or another vector. */ v2Ptr = Blt_VectorParseElement((Tcl_Interp *)NULL, vPtr->dataPtr, Tcl_GetString(objv[2]), (char **)NULL, NS_SEARCH_BOTH); if (v2Ptr != NULL) { if (vPtr == v2Ptr) { VectorObject *tmpPtr; /* * Source and destination vectors are the same. Copy the * source first into a temporary vector to avoid memory * overlaps. */ tmpPtr = Blt_VectorNew(vPtr->dataPtr); result = Blt_VectorDuplicate(tmpPtr, v2Ptr); if (result == TCL_OK) { result = Blt_VectorDuplicate(vPtr, tmpPtr); } Blt_VectorFree(tmpPtr); } else { result = Blt_VectorDuplicate(vPtr, v2Ptr); } } else if (Tcl_ListObjGetElements(interp, objv[2], &nElem, &elemObjArr) == TCL_OK) { result = CopyList(vPtr, 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) { Blt_VectorFlushCache(vPtr); } Blt_VectorUpdateClients(vPtr); } return result; } /* * ----------------------------------------------------------------------- * * SplitOp -- * * Copies the values from the vector evens into one of more * vectors. * * Results: * A standard Tcl result. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int SplitOp(vPtr, interp, objc, objv) VectorObject *vPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { int nVectors; nVectors = objc - 2; if ((vPtr->length % nVectors) != 0) { Tcl_AppendResult(interp, "can't split vector \"", vPtr->name, "\" into ", Blt_Itoa(nVectors), " even parts.", (char *)NULL); return TCL_ERROR; } if (nVectors > 0) { VectorObject *v2Ptr; char *string; /* Name of vector. */ int i, j, k; int oldSize, newSize, extra, isNew; extra = vPtr->length / nVectors; for (i = 0; i < nVectors; i++) { string = Tcl_GetString(objv[i+2]); v2Ptr = Blt_VectorCreate(vPtr->dataPtr, string, string, string, &isNew); oldSize = v2Ptr->length; newSize = oldSize + extra; if (Blt_VectorChangeLength(v2Ptr, newSize) != TCL_OK) { return TCL_ERROR; } for (j = i, k = oldSize; j < vPtr->length; j += nVectors, k++) { v2Ptr->valueArr[k] = vPtr->valueArr[j]; } Blt_VectorUpdateClients(v2Ptr); if (v2Ptr->flush) { Blt_VectorFlushCache(v2Ptr); } } } return TCL_OK; } static VectorObject **sortVectorArr; /* Pointer to the array of values * currently being sorted. */ static int nSortVectors; static int reverse; /* Indicates the ordering of the sort. If * non-zero, the vectors are sorted in * decreasing order */ static int CompareVectors(a, b) void *a; void *b; { double delta; int i; int sign; register VectorObject *vPtr; sign = (reverse) ? -1 : 1; for (i = 0; i < nSortVectors; i++) { vPtr = sortVectorArr[i]; 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; } int * Blt_VectorSortIndex(vPtrPtr, nVectors) VectorObject **vPtrPtr; int nVectors; { int *indexArr; register int i; VectorObject *vPtr = *vPtrPtr; int length; length = vPtr->last - vPtr->first + 1; indexArr = Blt_Malloc(sizeof(int) * length); assert(indexArr); for (i = vPtr->first; i <= vPtr->last; i++) { indexArr[i] = i; } sortVectorArr = vPtrPtr; nSortVectors = nVectors; qsort((char *)indexArr, length, sizeof(int), (QSortCompareProc *)CompareVectors); return indexArr; } static int * SortVectors(vPtr, interp, objc, objv) VectorObject *vPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { VectorObject **vPtrArray, *v2Ptr; int *iArr; register int i; vPtrArray = Blt_Malloc(sizeof(VectorObject *) * (objc + 1)); assert(vPtrArray); vPtrArray[0] = vPtr; iArr = NULL; for (i = 0; i < objc; i++) { if (Blt_VectorLookupName(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; } vPtrArray[i + 1] = v2Ptr; } iArr = Blt_VectorSortIndex(vPtrArray, objc + 1); error: Blt_Free(vPtrArray); return iArr; } /* * ----------------------------------------------------------------------- * * SortOp -- * * Sorts the vector object and any other vectors according to * sorting order of the vector object. * * Results: * A standard Tcl result. If any of the auxiliary vectors are * a different size than the sorted vector object, TCL_ERROR is * returned. Otherwise TCL_OK is returned. * * Side Effects: * The vectors are sorted. * * ----------------------------------------------------------------------- */ static int SortOp(vPtr, interp, objc, objv) VectorObject *vPtr; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { VectorObject *v2Ptr; char *string; double *mergeArr; int *iArr; int refSize, nBytes; int result; register int i, n; reverse = FALSE; if (objc > 2) { int length; string = Tcl_GetStringFromObj(objv[2], &length); if (string[0] == '-') { if ((length > 1) && (strncmp(string, "-reverse", length) == 0)) { reverse = TRUE; } else { Tcl_AppendResult(interp, "unknown flag \"", string, "\": should be \"-reverse\"", (char *)NULL); return TCL_ERROR; } objc--, objv++; } } if (objc > 2) { iArr = SortVectors(vPtr, interp, objc - 2, objv + 2); } else { iArr = Blt_VectorSortIndex(&vPtr, 1); } if (iArr == NULL) { return TCL_ERROR; } refSize = 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. */ nBytes = sizeof(double) * refSize; mergeArr = Blt_Malloc(nBytes); assert(mergeArr); memcpy((char *)mergeArr, (char *)vPtr->valueArr, nBytes); for (n = 0; n < refSize; n++) { vPtr->valueArr[n] = mergeArr[iArr[n]]; } if (vPtr->flush) { Blt_VectorFlushCache(vPtr); } Blt_VectorUpdateClients(vPtr); /* Now sort any other vectors in the same fashion. The vectors * must be the same size as the iArr though. */ result = TCL_ERROR; for (i = 2; i < objc; i++) { if (Blt_VectorLookupName(vPtr->dataPtr, Tcl_GetString(objv[i]), &v2Ptr) != TCL_OK) { goto error; } if (v2Ptr->length != refSize) { Tcl_AppendResult(interp, "vector \"", v2Ptr->name, "\" is not the same size as \"", vPtr->name, "\"", (char *)NULL); goto error; } memcpy((char *)mergeArr, (char *)v2Ptr->valueArr, nBytes); for (n = 0; n < refSize; n++) { v2Ptr->valueArr[n] = mergeArr[iArr[n]]; } Blt_VectorUpdateClients(v2Ptr); if (v2Ptr->flush) { Blt_VectorFlushCache(v2Ptr); } } result = TCL_OK; error: Blt_Free(mergeArr); Blt_Free(iArr); return result; } /* *---------------------------------------------------------------------- * * InstExprOp -- * * Computes the result of the expression which may be * either a scalar (single value) or vector (list of values). * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int InstExprOp(vPtr, interp, objc, objv) VectorObject *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) { Blt_VectorFlushCache(vPtr); } Blt_VectorUpdateClients(vPtr); return TCL_OK; } /* * ----------------------------------------------------------------------- * * ArithOp -- * * Results: * A standard Tcl result. If the source vector doesn't exist * or the source list is not a valid list of numbers, TCL_ERROR * returned. Otherwise TCL_OK is returned. * * Side Effects: * The vector data is reset. Clients of the vector are notified. * Any cached array indices are flushed. * * ----------------------------------------------------------------------- */ /*ARGSUSED*/ static int ArithOp(vPtr, interp, objc, objv) VectorObject *vPtr; Tcl_Interp *interp; int objc; /* Not used. */ Tcl_Obj *CONST *objv; { register double value; register int i; VectorObject *v2Ptr; double scalar; Tcl_Obj *listObjPtr; char *string; v2Ptr = Blt_VectorParseElement((Tcl_Interp *)NULL, vPtr->dataPtr, Tcl_GetString(objv[2]), (char **)NULL, NS_SEARCH_BOTH); if (v2Ptr != NULL) { register int j; int length; 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; } string = Tcl_GetString(objv[1]); listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); switch (string[0]) { case '*': for (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 (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 (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 (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 (GetDouble(interp, objv[2], &scalar) == TCL_OK) { listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); string = Tcl_GetString(objv[1]); switch (string[0]) { case '*': for (i = 0; i < vPtr->length; i++) { value = vPtr->valueArr[i] * scalar; Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(value)); } break; case '/': for (i = 0; i < vPtr->length; i++) { value = vPtr->valueArr[i] / scalar; Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(value)); } break; case '-': for (i = 0; i < vPtr->length; i++) { value = vPtr->valueArr[i] - scalar; Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(value)); } break; case '+': for (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; } /* *---------------------------------------------------------------------- * * VectorInstCmd -- * * Parses and invokes the appropriate vector instance command * option. * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ static Blt_OpSpec vectorInstOps[] = { {"*", 1, (Blt_Op)ArithOp, 3, 3, "item",}, /*Deprecated*/ {"+", 1, (Blt_Op)ArithOp, 3, 3, "item",}, /*Deprecated*/ {"-", 1, (Blt_Op)ArithOp, 3, 3, "item",}, /*Deprecated*/ {"/", 1, (Blt_Op)ArithOp, 3, 3, "item",}, /*Deprecated*/ {"append", 1, (Blt_Op)AppendOp, 3, 0, "item ?item...?",}, {"binread", 1, (Blt_Op)BinreadOp, 3, 0, "channel ?numValues? ?flags?",}, {"clear", 1, (Blt_Op)ClearOp, 2, 2, "",}, {"delete", 2, (Blt_Op)DeleteOp, 2, 0, "index ?index...?",}, {"dup", 2, (Blt_Op)DupOp, 3, 0, "vecName",}, {"expr", 1, (Blt_Op)InstExprOp, 3, 3, "expression",}, {"index", 1, (Blt_Op)IndexOp, 3, 4, "index ?value?",}, {"length", 1, (Blt_Op)LengthOp, 2, 3, "?newSize?",}, {"merge", 1, (Blt_Op)MergeOp, 3, 0, "vecName ?vecName...?",}, {"normalize", 3, (Blt_Op)NormalizeOp, 2, 3, "?vecName?",}, /*Deprecated*/ {"notify", 3, (Blt_Op)NotifyOp, 3, 3, "keyword",}, {"offset", 2, (Blt_Op)OffsetOp, 2, 3, "?offset?",}, {"populate", 1, (Blt_Op)PopulateOp, 4, 4, "vecName density",}, {"random", 4, (Blt_Op)RandomOp, 2, 2, "",}, /*Deprecated*/ {"range", 4, (Blt_Op)RangeOp, 4, 4, "first last",}, {"search", 3, (Blt_Op)SearchOp, 3, 4, "?-value? value ?value?",}, {"seq", 3, (Blt_Op)SeqOp, 4, 5, "start end ?step?",}, {"set", 3, (Blt_Op)SetOp, 3, 3, "list",}, {"sort", 2, (Blt_Op)SortOp, 2, 0, "?-reverse? ?vecName...?",}, {"split", 2, (Blt_Op)SplitOp, 2, 0, "?vecName...?",}, {"variable", 1, (Blt_Op)MapOp, 2, 3, "?varName?",}, }; static int nInstOps = sizeof(vectorInstOps) / sizeof(Blt_OpSpec); int Blt_VectorInstCmd(clientData, interp, objc, objv) ClientData clientData; Tcl_Interp *interp; int objc; Tcl_Obj *CONST *objv; { Blt_Op proc; VectorObject *vPtr = clientData; vPtr->first = 0; vPtr->last = vPtr->length - 1; proc = Blt_GetOpFromObj(interp, nInstOps, vectorInstOps, BLT_OP_ARG1, objc, objv, 0); if (proc == NULL) { return TCL_ERROR; } return (*proc) (vPtr, interp, objc, objv); } /* * ---------------------------------------------------------------------- * * Blt_VectorVarTrace -- * * Results: * Returns NULL on success. Only called from a variable trace. * * Side effects: * * ---------------------------------------------------------------------- */ char * Blt_VectorVarTrace(clientData, interp, part1, part2, flags) ClientData clientData; /* Vector object. */ Tcl_Interp *interp; char *part1, *part2; int flags; { Blt_VectorIndexProc *indexProc; VectorObject *vPtr = clientData; int first, last; int varFlags; #define MAX_ERR_MSG 1023 static char message[MAX_ERR_MSG + 1]; if (part2 == NULL) { if (flags & TCL_TRACE_UNSETS) { Blt_Free(vPtr->arrayName); vPtr->arrayName = NULL; vPtr->varNsPtr = NULL; if (vPtr->freeOnUnset) { Blt_VectorFree(vPtr); } } return NULL; } if (Blt_VectorGetIndexRange(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) { double value; Tcl_Obj *objPtr; if (first == SPECIAL_INDEX) { /* Tried to set "min" or "max" */ return "read-only index"; } objPtr = Tcl_GetVar2Ex(interp, part1, part2, varFlags); if (objPtr == NULL) { goto error; } if (GetDouble(interp, objPtr, &value) != TCL_OK) { if ((last == first) && (first >= 0)) { /* Single numeric index. Reset the array element to * its old value on errors */ Tcl_SetVar2Ex(interp, part1, part2, objPtr, varFlags); } goto error; } if (first == vPtr->length) { if (Blt_VectorChangeLength(vPtr, vPtr->length + 1) != TCL_OK) { return "error resizing vector"; } } /* Set possibly an entire range of values */ ReplicateValue(vPtr, first, last, value); } else if (flags & TCL_TRACE_READS) { double value; Tcl_Obj *objPtr; if (vPtr->length == 0) { if (Tcl_SetVar2(interp, part1, part2, "", varFlags) == NULL) { goto error; } return NULL; } if (first == vPtr->length) { return "write-only index"; } if (first == last) { 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) { register int i, j; if ((first == vPtr->length) || (first == SPECIAL_INDEX)) { return "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 (i = first, j = last + 1; j < vPtr->length; i++, j++) { vPtr->valueArr[i] = vPtr->valueArr[j]; } vPtr->length -= ((last - first) + 1); if (vPtr->flush) { Blt_VectorFlushCache(vPtr); } } else { return "unknown variable trace flag"; } if (flags & (TCL_TRACE_UNSETS | TCL_TRACE_WRITES)) { Blt_VectorUpdateClients(vPtr); } Tcl_ResetResult(interp); return NULL; error: strncpy(message, Tcl_GetStringResult(interp), MAX_ERR_MSG); message[MAX_ERR_MSG] = '\0'; return message; } #endif /* TCL_MAJOR_VERSION > 7 */ blt-2.4z.orig/src/bltVector.c0100644000175000017500000017677707520126772014704 0ustar dokodoko/* * bltVector.c -- * * This module implements vector data objects. * * Copyright 1995-1998 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. */ /* * 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 "bltVecInt.h" #include #ifdef TIME_WITH_SYS_TIME #include #include #else #ifdef HAVE_SYS_TIME_H #include #else #include #endif /* HAVE_SYS_TIME_H */ #endif /* TIME_WITH_SYS_TIME */ #ifndef TCL_NAMESPACE_ONLY #define TCL_NAMESPACE_ONLY TCL_GLOBAL_ONLY #endif #define DEF_ARRAY_SIZE 64 #define VECFLAGS(v) \ (((v)->varNsPtr != NULL) ? (TCL_NAMESPACE_ONLY | TCL_GLOBAL_ONLY) : 0; #define TRACE_ALL (TCL_TRACE_WRITES | TCL_TRACE_READS | TCL_TRACE_UNSETS) #define VECTOR_CHAR(c) ((isalnum(UCHAR(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 */ VectorObject *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. */ Blt_ChainLink *linkPtr; /* Used to quickly remove this entry from * its server's client chain. */ } VectorClient; static Tcl_CmdDeleteProc VectorInstDeleteProc; static Tcl_CmdProc VectorCmd; static Tcl_InterpDeleteProc VectorInterpDeleteProc; #if defined(HAVE_SRAND48) && defined(NO_DECL_SRAND48) extern void srand48 _ANSI_ARGS_((long int seed)); #endif static VectorObject * FindVectorInNamespace(dataPtr, nsPtr, vecName) VectorInterpData *dataPtr; /* Interpreter-specific data. */ Tcl_Namespace *nsPtr; CONST char *vecName; { Tcl_DString dString; CONST char *name; Blt_HashEntry *hPtr; name = Blt_GetQualifiedName(nsPtr, vecName, &dString); hPtr = Blt_FindHashEntry(&(dataPtr->vectorTable), name); Tcl_DStringFree(&dString); if (hPtr != NULL) { return (VectorObject *)Blt_GetHashValue(hPtr); } return NULL; } /* * ---------------------------------------------------------------------- * * GetVectorObject -- * * Searches for the vector associated with the name given. * Allow for a range specification. * * Results: * Returns a pointer to the vector if found, otherwise NULL. * * ---------------------------------------------------------------------- */ static VectorObject * GetVectorObject(dataPtr, name, flags) VectorInterpData *dataPtr; /* Interpreter-specific data. */ CONST char *name; int flags; { CONST char *vecName; Tcl_Namespace *nsPtr; VectorObject *vPtr; nsPtr = NULL; vecName = name; if (Blt_ParseQualifiedName(dataPtr->interp, name, &nsPtr, &vecName) != TCL_OK) { return NULL; /* Can't find namespace. */ } vPtr = NULL; if (nsPtr != NULL) { vPtr = FindVectorInNamespace(dataPtr, nsPtr, vecName); } else { if (flags & NS_SEARCH_CURRENT) { nsPtr = Tcl_GetCurrentNamespace(dataPtr->interp); vPtr = FindVectorInNamespace(dataPtr, nsPtr, vecName); } if ((vPtr == NULL) && (flags & NS_SEARCH_GLOBAL)) { nsPtr = Tcl_GetGlobalNamespace(dataPtr->interp); vPtr = FindVectorInNamespace(dataPtr, nsPtr, vecName); } } return vPtr; } void Blt_VectorUpdateRange(vPtr) VectorObject *vPtr; { double min, max; register int i; min = DBL_MAX, max = -DBL_MAX; for (i = 0; i < vPtr->length; i++) { if (FINITE(vPtr->valueArr[i])) { min = max = vPtr->valueArr[i]; break; } } for (/* empty */; i < vPtr->length; i++) { if (FINITE(vPtr->valueArr[i])) { if (min > vPtr->valueArr[i]) { min = vPtr->valueArr[i]; } else if (max < vPtr->valueArr[i]) { max = vPtr->valueArr[i]; } } } vPtr->min = min; vPtr->max = max; vPtr->notifyFlags &= ~UPDATE_RANGE; } /* * ---------------------------------------------------------------------- * * Blt_VectorGetIndex -- * * Converts the string representing an index in the vector, to * its numeric value. A valid index may be an numeric string of * the string "end" (indicating the last element in the string). * * Results: * A standard Tcl result. If the string is a valid index, TCL_OK * is returned. Otherwise TCL_ERROR is returned and interp->result * will contain an error message. * * ---------------------------------------------------------------------- */ int Blt_VectorGetIndex(interp, vPtr, string, indexPtr, flags, procPtrPtr) Tcl_Interp *interp; VectorObject *vPtr; CONST char *string; int *indexPtr; int flags; Blt_VectorIndexProc **procPtrPtr; { char c; int value; 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) { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&(vPtr->dataPtr->indexProcTable), string); if (hPtr != NULL) { *indexPtr = SPECIAL_INDEX; *procPtrPtr = (Blt_VectorIndexProc *) Blt_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 = 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; } /* * ---------------------------------------------------------------------- * * Blt_VectorGetIndexRange -- * * Converts the string representing an index in the vector, to * its numeric value. A valid index may be an numeric string of * the string "end" (indicating the last element in the string). * * Results: * A standard Tcl result. If the string is a valid index, TCL_OK * is returned. Otherwise TCL_ERROR is returned and interp->result * will contain an error message. * * ---------------------------------------------------------------------- */ int Blt_VectorGetIndexRange(interp, vPtr, string, flags, procPtrPtr) Tcl_Interp *interp; VectorObject *vPtr; CONST char *string; int flags; Blt_VectorIndexProc **procPtrPtr; { int ielem; char *colon; colon = NULL; if (flags & INDEX_COLON) { colon = strchr(string, ':'); } if (colon != NULL) { if (string == colon) { vPtr->first = 0; /* Default to the first index */ } else { int result; *colon = '\0'; result = Blt_VectorGetIndex(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 (Blt_VectorGetIndex(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 (Blt_VectorGetIndex(interp, vPtr, string, &ielem, flags, procPtrPtr) != TCL_OK) { return TCL_ERROR; } vPtr->last = vPtr->first = ielem; } return TCL_OK; } VectorObject * Blt_VectorParseElement(interp, dataPtr, start, endPtr, flags) Tcl_Interp *interp; VectorInterpData *dataPtr; /* Interpreter-specific data. */ CONST char *start; char **endPtr; int flags; { register char *p; char saved; VectorObject *vPtr; p = (char *)start; /* Find the end of the vector name */ while (VECTOR_CHAR(*p)) { p++; } saved = *p; *p = '\0'; 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 = Blt_VectorGetIndexRange(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; } /* * ---------------------------------------------------------------------- * * Blt_VectorNotifyClients -- * * Notifies each client of the vector that the vector has changed * (updated or destroyed) by calling the provided function back. * The function pointer may be NULL, in that case the client is * not notified. * * Results: * None. * * Side effects: * The results depend upon what actions the client callbacks * take. * * ---------------------------------------------------------------------- */ void Blt_VectorNotifyClients(clientData) ClientData clientData; { VectorObject *vPtr = clientData; Blt_ChainLink *linkPtr; VectorClient *clientPtr; 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 (linkPtr = Blt_ChainFirstLink(vPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { clientPtr = Blt_ChainGetValue(linkPtr); if (clientPtr->proc != 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 (linkPtr = Blt_ChainFirstLink(vPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { clientPtr = Blt_ChainGetValue(linkPtr); clientPtr->serverPtr = NULL; } } } /* * ---------------------------------------------------------------------- * * Blt_VectorUpdateClients -- * * Notifies each client of the vector that the vector has changed * (updated or destroyed) by calling the provided function back. * * Results: * None. * * Side effects: * The individual client callbacks are eventually invoked. * * ---------------------------------------------------------------------- */ void Blt_VectorUpdateClients(vPtr) VectorObject *vPtr; { vPtr->dirty++; vPtr->max = vPtr->min = bltNaN; if (vPtr->notifyFlags & NOTIFY_NEVER) { return; } vPtr->notifyFlags |= NOTIFY_UPDATED; if (vPtr->notifyFlags & NOTIFY_ALWAYS) { Blt_VectorNotifyClients(vPtr); return; } if (!(vPtr->notifyFlags & NOTIFY_PENDING)) { vPtr->notifyFlags |= NOTIFY_PENDING; Tcl_DoWhenIdle(Blt_VectorNotifyClients, vPtr); } } /* * ---------------------------------------------------------------------- * * Blt_VectorFlushCache -- * * Unsets all the elements of the Tcl array variable associated * with the vector, freeing memory associated with the variable. * This includes both the hash table and the hash keys. The down * side is that this effectively flushes the caching of vector * elements in the array. This means that the subsequent reads * of the array will require a decimal to string conversion. * * This is needed when the vector changes its values, making * the array variable out-of-sync. * * Results: * None. * * Side effects: * All elements of array variable (except one) are unset, freeing * the memory associated with the variable. * * ---------------------------------------------------------------------- */ void Blt_VectorFlushCache(vPtr) VectorObject *vPtr; { Tcl_CallFrame *framePtr; Tcl_Interp *interp = vPtr->interp; if (vPtr->arrayName == NULL) { return; /* Doesn't use the variable API */ } framePtr = NULL; if (vPtr->varNsPtr != NULL) { framePtr = Blt_EnterNamespace(interp, vPtr->varNsPtr); } /* 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, Blt_VectorVarTrace, 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, Blt_VectorVarTrace, vPtr); if ((vPtr->varNsPtr != NULL) && (framePtr != NULL)) { Blt_LeaveNamespace(interp, framePtr); /* Go back to current */ } } /* * ---------------------------------------------------------------------- * * Blt_VectorLookupName -- * * Searches for the vector associated with the name given. Allow * for a range specification. * * Results: * Returns a pointer to the vector if found, otherwise NULL. * If the name is not associated with a vector and the * TCL_LEAVE_ERR_MSG flag is set, and interp->result will contain * an error message. * * ---------------------------------------------------------------------- */ int Blt_VectorLookupName(dataPtr, vecName, vPtrPtr) VectorInterpData *dataPtr; /* Interpreter-specific data. */ char *vecName; VectorObject **vPtrPtr; { VectorObject *vPtr; char *endPtr; vPtr = Blt_VectorParseElement(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; } /* * ---------------------------------------------------------------------- * * DeleteCommand -- * * Deletes the Tcl command associated with the vector, without * triggering a callback to "VectorInstDeleteProc". * * Results: * None. * * ---------------------------------------------------------------------- */ static void DeleteCommand(vPtr) VectorObject *vPtr; /* Vector associated with the Tcl command. */ { Tcl_Interp *interp = vPtr->interp; char *qualName; /* Name of Tcl command. */ Tcl_CmdInfo cmdInfo; Tcl_DString dString; Tcl_DStringInit(&dString); qualName = Blt_GetQualifiedName( Blt_GetCommandNamespace(interp, vPtr->cmdToken), Tcl_GetCommandName(interp, vPtr->cmdToken), &dString); if (Tcl_GetCommandInfo(interp, qualName, &cmdInfo)) { cmdInfo.deleteProc = NULL; /* Disable the callback before * deleting the Tcl command.*/ Tcl_SetCommandInfo(interp, qualName, &cmdInfo); Tcl_DeleteCommandFromToken(interp, vPtr->cmdToken); } Tcl_DStringFree(&dString); vPtr->cmdToken = 0; } /* * ---------------------------------------------------------------------- * * UnmapVariable -- * * Destroys the trace on the current Tcl variable designated * to access the vector. * * Results: * None. * * ---------------------------------------------------------------------- */ static void UnmapVariable(vPtr) VectorObject *vPtr; { Tcl_Interp *interp = vPtr->interp; Tcl_CallFrame *framePtr; framePtr = NULL; if (vPtr->varNsPtr != NULL) { /* Activate namespace */ framePtr = Blt_EnterNamespace(interp, vPtr->varNsPtr); } /* Unset the entire array */ Tcl_UntraceVar2(interp, vPtr->arrayName, (char *)NULL, (TRACE_ALL | vPtr->varFlags), Blt_VectorVarTrace, vPtr); Tcl_UnsetVar2(interp, vPtr->arrayName, (char *)NULL, vPtr->varFlags); if ((vPtr->varNsPtr != NULL) && (framePtr != NULL)) { /* Go back to current namespace */ Blt_LeaveNamespace(interp, framePtr); } if (vPtr->arrayName != NULL) { Blt_Free(vPtr->arrayName); vPtr->arrayName = NULL; } vPtr->varNsPtr = NULL; } /* * ---------------------------------------------------------------------- * * Blt_VectorMapVariable -- * * Sets up traces on a Tcl variable to access the vector. * * If another variable is already mapped, it's first untraced and * removed. Don't do anything else for variables named "" (even * though Tcl allows this pathology). Saves the name of the new * array variable. * * Results: * A standard Tcl result. If an error occurs setting the variable * TCL_ERROR is returned and an error message is left in the * interpreter. * * Side effects: * Traces are set for the new variable. The new variable name is * saved in a malloc'ed string in vPtr->arrayName. If this * variable is non-NULL, it indicates that a Tcl variable has * been mapped to this vector. * * ---------------------------------------------------------------------- */ int Blt_VectorMapVariable(interp, vPtr, name) Tcl_Interp *interp; VectorObject *vPtr; CONST char *name; { Tcl_Namespace *nsPtr; Tcl_CallFrame *framePtr; CONST char *varName; CONST char *result; if (vPtr->arrayName != NULL) { UnmapVariable(vPtr); } if ((name == NULL) || (name[0] == '\0')) { return TCL_OK; /* If the variable name is the empty * string, simply return after * removing any existing variable. */ } framePtr = NULL; /* Get the variable name (without the namespace qualifier). */ if (Blt_ParseQualifiedName(interp, name, &nsPtr, &varName) != TCL_OK) { Tcl_AppendResult(interp, "can't find namespace in \"", name, "\"", (char *)NULL); return TCL_ERROR; } if (nsPtr != NULL) { /* [incr Tcl] 2.x doesn't like qualifiers with variable names, * so we need to enter the namespace if one was designated. */ framePtr = Blt_EnterNamespace(interp, nsPtr); } /* * To play it safe, delete the variable first. This has * side-effect of unmapping the variable from any vector that may * be currently using it. */ Tcl_UnsetVar2(interp, (char *)varName, (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, (char *)varName, "end", "", TCL_LEAVE_ERR_MSG); /* Determine if the variable is global or not. If there wasn't a * namespace qualifier, it still may be global. We need to look * inside the Var structure to see what it's namespace field says. * NULL indicates that it's local. */ vPtr->varNsPtr = Blt_GetVariableNamespace(interp, varName); vPtr->varFlags = (vPtr->varNsPtr != NULL) ? (TCL_NAMESPACE_ONLY | TCL_GLOBAL_ONLY) : 0; if (result != NULL) { /* Trace the array on reads, writes, and unsets */ Tcl_TraceVar2(interp, (char *)varName, (char *)NULL, (TRACE_ALL | vPtr->varFlags), Blt_VectorVarTrace, vPtr); } if ((nsPtr != NULL) && (framePtr != NULL)) { Blt_LeaveNamespace(interp, framePtr); /* Go back to current */ } vPtr->arrayName = Blt_Strdup(varName); return (result == NULL) ? TCL_ERROR : TCL_OK; } /* * ---------------------------------------------------------------------- * * Blt_VectorChangeLength -- * * Resizes the vector to the new size. * * The new size of the vector is computed by doubling the * size of the vector until it fits the number of slots needed * (designated by *length*). * * If the new size is the same as the old, simply adjust the * length of the vector. Otherwise we're copying the data from * one memory location to another. The trailing elements of the * vector need to be reset to zero. * * If the storage changed memory locations, free up the old * location if it was dynamically allocated. * * Results: * A standard Tcl result. If the reallocation is successful, * TCL_OK is returned, otherwise TCL_ERROR. * * Side effects: * Memory for the array is reallocated. * * ---------------------------------------------------------------------- */ int Blt_VectorChangeLength(vPtr, length) VectorObject *vPtr; int length; { int newSize; /* Size of array in elements */ double *newArr; Tcl_FreeProc *freeProc; newArr = NULL; newSize = 0; freeProc = TCL_STATIC; if (length > 0) { int wanted, used; wanted = length; used = vPtr->length; /* Compute the new size by doubling old size until it's big enough */ newSize = DEF_ARRAY_SIZE; if (wanted > DEF_ARRAY_SIZE) { while (newSize < wanted) { newSize += newSize; } } freeProc = vPtr->freeProc; if (newSize == vPtr->size) { newArr = vPtr->valueArr; /* Same size, use current array. */ } else { /* Dynamically allocate memory for the new array. */ newArr = Blt_Malloc(newSize * sizeof(double)); if (newArr == NULL) { Tcl_AppendResult(vPtr->interp, "can't allocate ", Blt_Itoa(newSize), " elements for vector \"", vPtr->name, "\"", (char *)NULL); return TCL_ERROR; } if (used > wanted) { used = wanted; } /* Copy any previous data */ if (used > 0) { memcpy(newArr, vPtr->valueArr, used * sizeof(double)); } freeProc = TCL_DYNAMIC; } /* Clear any new slots that we're now using in the array */ if (wanted > used) { memset(newArr + used, 0, (wanted - used) * sizeof(double)); } } if ((newArr != vPtr->valueArr) && (vPtr->valueArr != NULL)) { /* * We're not using the old storage anymore, so free it if it's * not 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) { Blt_Free(vPtr->valueArr); } else { (*vPtr->freeProc) ((char *)vPtr->valueArr); } } } vPtr->valueArr = newArr; vPtr->size = newSize; vPtr->length = length; vPtr->first = 0; vPtr->last = length - 1; vPtr->freeProc = freeProc; /* Set the type of the new storage */ return TCL_OK; } /* * ----------------------------------------------------------------------- * * Blt_ResetVector -- * * Resets the vector data. This is called by a client to * indicate that the vector data has changed. The vector does * not need to point to different memory. Any clients of the * vector will be notified of the change. * * Results: * A standard Tcl result. If the new array size is invalid, * TCL_ERROR is returned. Otherwise TCL_OK is returned and the * new vector data is recorded. * * Side Effects: * Any client designated callbacks will be posted. Memory may * be changed for the vector array. * * ----------------------------------------------------------------------- */ int Blt_VectorReset(vPtr, valueArr, length, size, freeProc) VectorObject *vPtr; double *valueArr; /* Array containing the elements of the * vector. If NULL, indicates to reset the * vector.*/ int length; /* The number of elements that the vector * currently holds. */ int size; /* The maximum number of elements that the * array can hold. */ Tcl_FreeProc *freeProc; /* Address of memory deallocation routine * for the array of values. Can also be * TCL_STATIC, TCL_DYNAMIC, or TCL_VOLATILE. */ { 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 */ freeProc = TCL_STATIC; valueArr = NULL; size = length = 0; } else if (freeProc == TCL_VOLATILE) { double *newArr; /* Data is volatile. Make a copy of the value array. */ newArr = Blt_Malloc(size * sizeof(double)); if (newArr == NULL) { Tcl_AppendResult(vPtr->interp, "can't allocate ", Blt_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) { Blt_Free(vPtr->valueArr); } else { (*freeProc) ((char *)vPtr->valueArr); } } vPtr->freeProc = freeProc; vPtr->valueArr = valueArr; vPtr->size = size; } vPtr->length = length; if (vPtr->flush) { Blt_VectorFlushCache(vPtr); } Blt_VectorUpdateClients(vPtr); return TCL_OK; } VectorObject * Blt_VectorNew(dataPtr) VectorInterpData *dataPtr; /* Interpreter-specific data. */ { VectorObject *vPtr; vPtr = Blt_Calloc(1, sizeof(VectorObject)); assert(vPtr); vPtr->notifyFlags = NOTIFY_WHENIDLE; vPtr->freeProc = TCL_STATIC; vPtr->dataPtr = dataPtr; vPtr->valueArr = NULL; vPtr->length = vPtr->size = 0; vPtr->interp = dataPtr->interp; vPtr->hashPtr = NULL; vPtr->chainPtr = Blt_ChainCreate(); vPtr->flush = FALSE; vPtr->min = vPtr->max = bltNaN; return vPtr; } /* * ---------------------------------------------------------------------- * * Blt_VectorFree -- * * Removes the memory and frees resources associated with the * vector. * * o Removes the trace and the Tcl array variable and unsets * the variable. * o Notifies clients of the vector that the vector is being * destroyed. * o Removes any clients that are left after notification. * o Frees the memory (if necessary) allocated for the array. * o Removes the entry from the hash table of vectors. * o Frees the memory allocated for the name. * * Results: * None. * * Side effects: * * ---------------------------------------------------------------------- */ void Blt_VectorFree(vPtr) VectorObject *vPtr; { Blt_ChainLink *linkPtr; VectorClient *clientPtr; 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_VectorNotifyClients, vPtr); } vPtr->notifyFlags |= NOTIFY_DESTROYED; Blt_VectorNotifyClients(vPtr); for (linkPtr = Blt_ChainFirstLink(vPtr->chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { clientPtr = Blt_ChainGetValue(linkPtr); Blt_Free(clientPtr); } Blt_ChainDestroy(vPtr->chainPtr); if ((vPtr->valueArr != NULL) && (vPtr->freeProc != TCL_STATIC)) { if (vPtr->freeProc == TCL_DYNAMIC) { Blt_Free(vPtr->valueArr); } else { (*vPtr->freeProc) ((char *)vPtr->valueArr); } } if (vPtr->hashPtr != NULL) { Blt_DeleteHashEntry(&(vPtr->dataPtr->vectorTable), vPtr->hashPtr); } #ifdef NAMESPACE_DELETE_NOTIFY if (vPtr->nsPtr != NULL) { Blt_DestroyNsDeleteNotify(vPtr->interp, vPtr->nsPtr, vPtr); } #endif /* NAMESPACE_DELETE_NOTIFY */ Blt_Free(vPtr); } /* * ---------------------------------------------------------------------- * * VectorInstDeleteProc -- * * Deletes the command associated with the vector. This is * called only when the command associated with the vector is * destroyed. * * Results: * None. * * ---------------------------------------------------------------------- */ static void VectorInstDeleteProc(clientData) ClientData clientData; { VectorObject *vPtr = clientData; vPtr->cmdToken = 0; Blt_VectorFree(vPtr); } /* * ---------------------------------------------------------------------- * * Blt_VectorCreate -- * * Creates a vector structure and the following items: * * o Tcl command * o Tcl array variable and establishes traces on the variable * o Adds a new entry in the vector hash table * * Results: * A pointer to the new vector structure. If an error occurred * NULL is returned and an error message is left in * interp->result. * * Side effects: * A new Tcl command and array variable is added to the * interpreter. * * ---------------------------------------------------------------------- */ VectorObject * Blt_VectorCreate(dataPtr, vecName, cmdName, varName, newPtr) VectorInterpData *dataPtr; /* Interpreter-specific data. */ CONST char *vecName; /* Namespace-qualified name of the vector */ CONST char *cmdName; /* Name of the Tcl command mapped to * the vector */ CONST char *varName; /* Name of the Tcl array mapped to the * vector */ int *newPtr; { Tcl_DString dString; VectorObject *vPtr; int isNew; CONST char *name; char *qualName; Tcl_Namespace *nsPtr; Blt_HashEntry *hPtr; Tcl_Interp *interp = dataPtr->interp; isNew = 0; nsPtr = NULL; vPtr = NULL; if (Blt_ParseQualifiedName(interp, vecName, &nsPtr, &name) != TCL_OK) { Tcl_AppendResult(interp, "can't find namespace in \"", vecName, "\"", (char *)NULL); return NULL; } if (nsPtr == NULL) { nsPtr = Tcl_GetCurrentNamespace(interp); } Tcl_DStringInit(&dString); if ((name[0] == '#') && (strcmp(name, "#auto") == 0)) { char string[200]; do { /* Generate a unique vector name. */ sprintf(string, "vector%d", dataPtr->nextId++); qualName = Blt_GetQualifiedName(nsPtr, string, &dString); hPtr = Blt_FindHashEntry(&(dataPtr->vectorTable), qualName); } while (hPtr != NULL); } else { register CONST char *p; for (p = name; *p != '\0'; p++) { if (!VECTOR_CHAR(*p)) { Tcl_AppendResult(interp, "bad vector name \"", name, "\": must contain digits, letters, underscore, or period", (char *)NULL); goto error; } } qualName = Blt_GetQualifiedName(nsPtr, name, &dString); vPtr = Blt_VectorParseElement((Tcl_Interp *)NULL, dataPtr, qualName, (char **)NULL, NS_SEARCH_CURRENT); } if (vPtr == NULL) { hPtr = Blt_CreateHashEntry(&(dataPtr->vectorTable), qualName, &isNew); vPtr = Blt_VectorNew(dataPtr); vPtr->hashPtr = hPtr; vPtr->nsPtr = nsPtr; vPtr->name = Blt_GetHashKey(&(dataPtr->vectorTable), hPtr); #ifdef NAMESPACE_DELETE_NOTIFY Blt_CreateNsDeleteNotify(interp, nsPtr, vPtr, VectorInstDeleteProc); #endif /* NAMESPACE_DELETE_NOTIFY */ Blt_SetHashValue(hPtr, vPtr); } if (cmdName != NULL) { Tcl_CmdInfo cmdInfo; if ((cmdName == vecName) || ((name[0] == '#') && (strcmp(name, "#auto") == 0))) { cmdName = qualName; } if (Tcl_GetCommandInfo(interp, (char *)cmdName, &cmdInfo)) { #if TCL_MAJOR_VERSION > 7 if (vPtr != cmdInfo.objClientData) { #else if (vPtr != cmdInfo.clientData) { #endif 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) { #if (TCL_MAJOR_VERSION == 7) vPtr->cmdToken = Blt_CreateCommand(interp, cmdName, Blt_VectorInstCmd, vPtr, VectorInstDeleteProc); #else Tcl_DString dString2; Tcl_DStringInit(&dString2); if (cmdName != qualName) { if (Blt_ParseQualifiedName(interp, cmdName, &nsPtr, &name) != TCL_OK) { Tcl_AppendResult(interp, "can't find namespace in \"", cmdName, "\"", (char *)NULL); goto error; } if (nsPtr == NULL) { nsPtr = Tcl_GetCurrentNamespace(interp); } cmdName = Blt_GetQualifiedName(nsPtr, name, &dString2); } vPtr->cmdToken = Tcl_CreateObjCommand(interp, (char *)cmdName, Blt_VectorInstCmd, vPtr, VectorInstDeleteProc); Tcl_DStringFree(&dString2); #endif } checkVariable: if (varName != NULL) { if ((varName[0] == '#') && (strcmp(varName, "#auto") == 0)) { varName = qualName; } if (Blt_VectorMapVariable(interp, vPtr, varName) != TCL_OK) { goto error; } } Tcl_DStringFree(&dString); *newPtr = isNew; return vPtr; error: Tcl_DStringFree(&dString); if (vPtr != NULL) { Blt_VectorFree(vPtr); } return NULL; } int Blt_VectorDuplicate(destPtr, srcPtr) VectorObject *destPtr, *srcPtr; { int nBytes; int length; if (destPtr == srcPtr) { /* Copying the same vector. */ } length = srcPtr->last - srcPtr->first + 1; if (Blt_VectorChangeLength(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; } /* *---------------------------------------------------------------------- * * VectorNamesOp -- * * Reports the names of all the current vectors in the interpreter. * * Results: * A standard Tcl result. interp->result will contain a list of * all the names of the vector instances. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int VectorNamesOp(clientData, interp, argc, argv) ClientData clientData; /* Interpreter-specific data. */ Tcl_Interp *interp; int argc; char **argv; { VectorInterpData *dataPtr = clientData; Blt_HashEntry *hPtr; char *name; Blt_HashSearch cursor; for (hPtr = Blt_FirstHashEntry(&(dataPtr->vectorTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { name = Blt_GetHashKey(&(dataPtr->vectorTable), hPtr); if ((argc == 2) || (Tcl_StringMatch(name, argv[2]))) { Tcl_AppendElement(interp, name); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * VectorCreateOp -- * * Creates a Tcl command, and array variable representing an * instance of a vector. * * vector a * vector b(20) * vector c(-5:14) * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int VectorCreate2(clientData, interp, argStart, argc, argv) ClientData clientData; /* Interpreter-specific data. */ Tcl_Interp *interp; int argStart; int argc; char **argv; { VectorInterpData *dataPtr = clientData; VectorObject *vPtr; char *leftParen, *rightParen; int isNew, size, first, last; char *cmdName, *varName; int length; int inspectFlags, freeOnUnset, flush; char **nameArr; int count; register int i; /* * Handle switches to the vector command and collect the vector * name arguments into an array. */ varName = cmdName = NULL; freeOnUnset = 0; nameArr = Blt_Malloc(sizeof(char *) * argc); assert(nameArr); inspectFlags = TRUE; flush = FALSE; count = 0; vPtr = NULL; for (i = argStart; i < argc; i++) { if ((inspectFlags) && (argv[i][0] == '-')) { length = strlen(argv[i]); if ((length > 1) && (strncmp(argv[i], "-variable", length) == 0)) { if ((i + 1) == argc) { Tcl_AppendResult(interp, "no variable name supplied with \"", argv[i], "\" switch", (char *)NULL); goto error; } i++; varName = argv[i]; } else if ((length > 1) && (strncmp(argv[i], "-command", length) == 0)) { if ((i + 1) == argc) { Tcl_AppendResult(interp, "no command name supplied with \"", argv[i], "\" switch", (char *)NULL); goto error; } i++; cmdName = argv[i]; } else if ((length > 1) && (strncmp(argv[i], "-watchunset", length) == 0)) { int bool; if ((i + 1) == argc) { Tcl_AppendResult(interp, "no value name supplied with \"", argv[i], "\" switch", (char *)NULL); goto error; } i++; if (Tcl_GetBoolean(interp, argv[i], &bool) != TCL_OK) { goto error; } freeOnUnset = bool; } else if ((length > 1) && (strncmp(argv[i], "-flush", length) == 0)) { int bool; if ((i + 1) == argc) { Tcl_AppendResult(interp, "no value name supplied with \"", argv[i], "\" switch", (char *)NULL); goto error; } i++; if (Tcl_GetBoolean(interp, argv[i], &bool) != TCL_OK) { goto error; } flush = bool; } else if ((length > 1) && (argv[i][1] == '-') && (argv[i][2] == '\0')) { inspectFlags = FALSE; /* Allow vector names to start with - */ } else { Tcl_AppendResult(interp, "bad vector switch \"", argv[i], "\"", (char *)NULL); goto error; } } else { nameArr[count++] = argv[i]; } } if (count == 0) { Tcl_AppendResult(interp, "no vector names supplied", (char *)NULL); goto error; } if (count > 1) { if ((cmdName != NULL) && (cmdName[0] != '\0')) { Tcl_AppendResult(interp, "can't specify more than one vector with \"-command\" switch", (char *)NULL); goto error; } if ((varName != NULL) && (varName[0] != '\0')) { Tcl_AppendResult(interp, "can't specify more than one vector with \"-variable\" switch", (char *)NULL); goto error; } } for (i = 0; i < count; i++) { size = first = last = 0; leftParen = strchr(nameArr[i], '('); rightParen = strchr(nameArr[i], ')'); if (((leftParen != NULL) && (rightParen == NULL)) || ((leftParen == NULL) && (rightParen != NULL)) || (leftParen > rightParen)) { Tcl_AppendResult(interp, "bad vector specification \"", nameArr[i], "\"", (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 \"", nameArr[i], "\"", (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 \"", nameArr[i], "\"", (char *)NULL); goto error; } } if (leftParen != NULL) { *leftParen = '\0'; } /* * By default, we create a Tcl command by the name of the vector. */ vPtr = Blt_VectorCreate(dataPtr, nameArr[i], (cmdName == NULL) ? nameArr[i] : cmdName, (varName == NULL) ? nameArr[i] : varName, &isNew); if (leftParen != NULL) { *leftParen = '('; } if (vPtr == NULL) { goto error; } vPtr->freeOnUnset = freeOnUnset; vPtr->flush = flush; vPtr->offset = first; if (size > 0) { if (Blt_VectorChangeLength(vPtr, size) != TCL_OK) { goto error; } } if (!isNew) { if (vPtr->flush) { Blt_VectorFlushCache(vPtr); } Blt_VectorUpdateClients(vPtr); } } Blt_Free(nameArr); if (vPtr != NULL) { /* Return the name of the last vector created */ Tcl_SetResult(interp, vPtr->name, TCL_VOLATILE); } return TCL_OK; error: Blt_Free(nameArr); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * VectorCreateOp -- * * Creates a Tcl command, and array variable representing an * instance of a vector. * * vector a * vector b(20) * vector c(-5:14) * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int VectorCreateOp(clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; int argc; char **argv; { return VectorCreate2(clientData, interp, 2, argc, argv); } /* *---------------------------------------------------------------------- * * VectorDestroyOp -- * * Destroys the vector and its related Tcl command and array * variable (if they exist). * * Results: * A standard Tcl result. * * Side effects: * Deletes the vector. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int VectorDestroyOp(clientData, interp, argc, argv) ClientData clientData; /* Interpreter-specific data. */ Tcl_Interp *interp; int argc; char **argv; { VectorInterpData *dataPtr = clientData; VectorObject *vPtr; register int i; for (i = 2; i < argc; i++) { if (Blt_VectorLookupName(dataPtr, argv[i], &vPtr) != TCL_OK) { return TCL_ERROR; } Blt_VectorFree(vPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * VectorExprOp -- * * Computes the result of the expression which may be * either a scalar (single value) or vector (list of values). * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int VectorExprOp(clientData, interp, argc, argv) ClientData clientData; /* Not Used. */ Tcl_Interp *interp; int argc; char **argv; { return Blt_ExprVector(interp, argv[2], (Blt_Vector *) NULL); } static Blt_OpSpec vectorCmdOps[] = { {"create", 1, (Blt_Op)VectorCreateOp, 3, 0, "vecName ?vecName...? ?switches...?",}, {"destroy", 1, (Blt_Op)VectorDestroyOp, 3, 0, "vecName ?vecName...?",}, {"expr", 1, (Blt_Op)VectorExprOp, 3, 3, "expression",}, {"names", 1, (Blt_Op)VectorNamesOp, 2, 3, "?pattern?...",}, }; static int nCmdOps = sizeof(vectorCmdOps) / sizeof(Blt_OpSpec); /*ARGSUSED*/ static int VectorCmd(clientData, interp, argc, argv) ClientData clientData; /* Interpreter-specific data. */ Tcl_Interp *interp; int argc; char **argv; { Blt_Op proc; /* * Try to replicate the old vector command's behavior: */ if (argc > 1) { char c; register int i; register Blt_OpSpec *specPtr; c = argv[1][0]; for (specPtr = vectorCmdOps, i = 0; i < nCmdOps; i++, specPtr++) { if ((c == specPtr->name[0]) && (strcmp(argv[1], 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, argc, argv); } doOp: /* Do the usual vector operation lookup now. */ proc = Blt_GetOp(interp, nCmdOps, vectorCmdOps, BLT_OP_ARG1, argc, argv,0); if (proc == NULL) { return TCL_ERROR; } return (*proc) (clientData, interp, argc, argv); } /* * ----------------------------------------------------------------------- * * VectorInterpDeleteProc -- * * This is called when the interpreter hosting the "vector" command * is deleted. * * Results: * None. * * Side effects: * Destroys the math and index hash tables. In addition removes * the hash table managing all vector names. * * ------------------------------------------------------------------------ */ /* ARGSUSED */ static void VectorInterpDeleteProc(clientData, interp) ClientData clientData; /* Interpreter-specific data. */ Tcl_Interp *interp; { VectorInterpData *dataPtr = clientData; Blt_HashEntry *hPtr; Blt_HashSearch cursor; VectorObject *vPtr; for (hPtr = Blt_FirstHashEntry(&(dataPtr->vectorTable), &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { vPtr = (VectorObject *)Blt_GetHashValue(hPtr); vPtr->hashPtr = NULL; Blt_VectorFree(vPtr); } Blt_DeleteHashTable(&(dataPtr->vectorTable)); /* If any user-defined math functions were installed, remove them. */ Blt_VectorUninstallMathFunctions(&(dataPtr->mathProcTable)); Blt_DeleteHashTable(&(dataPtr->mathProcTable)); Blt_DeleteHashTable(&(dataPtr->indexProcTable)); Tcl_DeleteAssocData(interp, VECTOR_THREAD_KEY); Blt_Free(dataPtr); } VectorInterpData * Blt_VectorGetInterpData(interp) Tcl_Interp *interp; { VectorInterpData *dataPtr; Tcl_InterpDeleteProc *proc; dataPtr = (VectorInterpData *) Tcl_GetAssocData(interp, VECTOR_THREAD_KEY, &proc); if (dataPtr == NULL) { dataPtr = Blt_Malloc(sizeof(VectorInterpData)); assert(dataPtr); dataPtr->interp = interp; dataPtr->nextId = 0; Tcl_SetAssocData(interp, VECTOR_THREAD_KEY, VectorInterpDeleteProc, dataPtr); Blt_InitHashTable(&(dataPtr->vectorTable), BLT_STRING_KEYS); Blt_InitHashTable(&(dataPtr->mathProcTable), BLT_STRING_KEYS); Blt_InitHashTable(&(dataPtr->indexProcTable), BLT_STRING_KEYS); Blt_VectorInstallMathFunctions(&(dataPtr->mathProcTable)); Blt_VectorInstallSpecialIndices(&(dataPtr->indexProcTable)); #ifdef HAVE_SRAND48 srand48(time((time_t *) NULL)); #endif } return dataPtr; } /* * ----------------------------------------------------------------------- * * Blt_VectorInit -- * * This procedure is invoked to initialize the "vector" command. * * Results: * None. * * Side effects: * Creates the new command and adds a new entry into a global Tcl * associative array. * * ------------------------------------------------------------------------ */ int Blt_VectorInit(interp) Tcl_Interp *interp; { VectorInterpData *dataPtr; /* Interpreter-specific data. */ static Blt_CmdSpec cmdSpec = {"vector", VectorCmd, }; dataPtr = Blt_VectorGetInterpData(interp); /* * This routine may be run several times in the same interpreter. * For example, if someone tries to initial the BLT commands from * another namespace. Keep a reference count, so we know when it's * safe to clean up. */ cmdSpec.clientData = dataPtr; if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) { return TCL_ERROR; } return TCL_OK; } /* C Application interface to vectors */ /* * ----------------------------------------------------------------------- * * Blt_CreateVector -- * * Creates a new vector by the name and size. * * Results: * A standard Tcl result. If the new array size is invalid or a * vector already exists by that name, TCL_ERROR is returned. * Otherwise TCL_OK is returned and the new vector is created. * * Side Effects: * Memory will be allocated for the new vector. A new Tcl command * and Tcl array variable will be created. * * ----------------------------------------------------------------------- */ /*LINTLIBRARY*/ int Blt_CreateVector2(interp, vecName, cmdName, varName, initialSize, vecPtrPtr) Tcl_Interp *interp; char *vecName; char *cmdName, *varName; int initialSize; Blt_Vector **vecPtrPtr; { VectorInterpData *dataPtr; /* Interpreter-specific data. */ VectorObject *vPtr; int isNew; char *nameCopy; if (initialSize < 0) { Tcl_AppendResult(interp, "bad vector size \"", Blt_Itoa(initialSize), "\"", (char *)NULL); return TCL_ERROR; } dataPtr = Blt_VectorGetInterpData(interp); nameCopy = Blt_Strdup(vecName); vPtr = Blt_VectorCreate(dataPtr, nameCopy, cmdName, varName, &isNew); Blt_Free(nameCopy); if (vPtr == NULL) { return TCL_ERROR; } if (initialSize > 0) { if (Blt_VectorChangeLength(vPtr, initialSize) != TCL_OK) { return TCL_ERROR; } } if (vecPtrPtr != NULL) { *vecPtrPtr = (Blt_Vector *) vPtr; } return TCL_OK; } int Blt_CreateVector(interp, name, size, vecPtrPtr) Tcl_Interp *interp; char *name; int size; Blt_Vector **vecPtrPtr; { return Blt_CreateVector2(interp, name, name, name, size, vecPtrPtr); } /* * ----------------------------------------------------------------------- * * Blt_DeleteVector -- * * Deletes the vector of the given name. All clients with * designated callback routines will be notified. * * Results: * A standard Tcl result. If no vector exists by that name, * TCL_ERROR is returned. Otherwise TCL_OK is returned and * vector is deleted. * * Side Effects: * Memory will be released for the new vector. Both the Tcl * command and array variable will be deleted. All clients which * set call back procedures will be notified. * * ----------------------------------------------------------------------- */ /*LINTLIBRARY*/ int Blt_DeleteVector(vecPtr) Blt_Vector *vecPtr; { VectorObject *vPtr = (VectorObject *)vecPtr; Blt_VectorFree(vPtr); return TCL_OK; } /* * ----------------------------------------------------------------------- * * Blt_DeleteVectorByName -- * * Deletes the vector of the given name. All clients with * designated callback routines will be notified. * * Results: * A standard Tcl result. If no vector exists by that name, * TCL_ERROR is returned. Otherwise TCL_OK is returned and * vector is deleted. * * Side Effects: * Memory will be released for the new vector. Both the Tcl * command and array variable will be deleted. All clients which * set call back procedures will be notified. * * ----------------------------------------------------------------------- */ /*LINTLIBRARY*/ int Blt_DeleteVectorByName(interp, name) Tcl_Interp *interp; char *name; { VectorInterpData *dataPtr; /* Interpreter-specific data. */ VectorObject *vPtr; char *nameCopy; int result; /* * If the vector name was passed via a read-only string (e.g. "x"), * the Blt_VectorParseElement 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); dataPtr = Blt_VectorGetInterpData(interp); result = Blt_VectorLookupName(dataPtr, nameCopy, &vPtr); Blt_Free(nameCopy); if (result != TCL_OK) { return TCL_ERROR; } Blt_VectorFree(vPtr); return TCL_OK; } /* * ---------------------------------------------------------------------- * * Blt_VectorExists2 -- * * Returns whether the vector associated with the client token * still exists. * * Results: * Returns 1 is the vector still exists, 0 otherwise. * * ---------------------------------------------------------------------- */ int Blt_VectorExists2(interp, vecName) Tcl_Interp *interp; char *vecName; { VectorInterpData *dataPtr; /* Interpreter-specific data. */ dataPtr = Blt_VectorGetInterpData(interp); if (GetVectorObject(dataPtr, vecName, NS_SEARCH_BOTH) != NULL) { return TRUE; } return FALSE; } /* * ---------------------------------------------------------------------- * * Blt_VectorExists -- * * Returns whether the vector associated with the client token * still exists. * * Results: * Returns 1 is the vector still exists, 0 otherwise. * * ---------------------------------------------------------------------- */ int Blt_VectorExists(interp, vecName) Tcl_Interp *interp; 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); Blt_Free(nameCopy); return result; } /* * ----------------------------------------------------------------------- * * Blt_GetVector -- * * Returns a pointer to the vector associated with the given name. * * Results: * A standard Tcl result. If there is no vector "name", TCL_ERROR * is returned. Otherwise TCL_OK is returned and vecPtrPtr will * point to the vector. * * ----------------------------------------------------------------------- */ int Blt_GetVector(interp, name, vecPtrPtr) Tcl_Interp *interp; char *name; Blt_Vector **vecPtrPtr; { VectorInterpData *dataPtr; /* Interpreter-specific data. */ VectorObject *vPtr; char *nameCopy; int result; dataPtr = Blt_VectorGetInterpData(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 = Blt_VectorLookupName(dataPtr, nameCopy, &vPtr); Blt_Free(nameCopy); if (result != TCL_OK) { return TCL_ERROR; } Blt_VectorUpdateRange(vPtr); *vecPtrPtr = (Blt_Vector *) vPtr; return TCL_OK; } /* * ----------------------------------------------------------------------- * * Blt_ResetVector -- * * Resets the vector data. This is called by a client to * indicate that the vector data has changed. The vector does * not need to point to different memory. Any clients of the * vector will be notified of the change. * * Results: * A standard Tcl result. If the new array size is invalid, * TCL_ERROR is returned. Otherwise TCL_OK is returned and the * new vector data is recorded. * * Side Effects: * Any client designated callbacks will be posted. Memory may * be changed for the vector array. * * ----------------------------------------------------------------------- */ int Blt_ResetVector(vecPtr, valueArr, length, size, freeProc) Blt_Vector *vecPtr; double *valueArr; /* Array containing the elements of the * vector. If NULL, indicates to reset the * vector.*/ int length; /* The number of elements that the vector * currently holds. */ int size; /* The maximum number of elements that the * array can hold. */ Tcl_FreeProc *freeProc; /* Address of memory deallocation routine * for the array of values. Can also be * TCL_STATIC, TCL_DYNAMIC, or TCL_VOLATILE. */ { VectorObject *vPtr = (VectorObject *)vecPtr; if (size < 0) { Tcl_AppendResult(vPtr->interp, "bad array size", (char *)NULL); return TCL_ERROR; } return Blt_VectorReset(vPtr, valueArr, length, size, freeProc); } /* * ----------------------------------------------------------------------- * * Blt_ResizeVector -- * * Changes the size of the vector. All clients with designated * callback routines will be notified of the size change. * * Results: * A standard Tcl result. If no vector exists by that name, * TCL_ERROR is returned. Otherwise TCL_OK is returned and * vector is resized. * * Side Effects: * Memory may be reallocated for the new vector size. All clients * which set call back procedures will be notified. * * ----------------------------------------------------------------------- */ int Blt_ResizeVector(vecPtr, length) Blt_Vector *vecPtr; int length; { VectorObject *vPtr = (VectorObject *)vecPtr; if (Blt_VectorChangeLength(vPtr, length) != TCL_OK) { Tcl_AppendResult(vPtr->interp, "can't resize vector \"", vPtr->name, "\"", (char *)NULL); return TCL_ERROR; } if (vPtr->flush) { Blt_VectorFlushCache(vPtr); } Blt_VectorUpdateClients(vPtr); return TCL_OK; } /* *-------------------------------------------------------------- * * Blt_AllocVectorId -- * * Creates an identifier token for an existing vector. The * identifier is used by the client routines to get call backs * when (and if) the vector changes. * * Results: * A standard Tcl result. If "vecName" is not associated with * a vector, TCL_ERROR is returned and interp->result is filled * with an error message. * *-------------------------------------------------------------- */ Blt_VectorId Blt_AllocVectorId(interp, name) Tcl_Interp *interp; char *name; { VectorInterpData *dataPtr; /* Interpreter-specific data. */ VectorObject *vPtr; VectorClient *clientPtr; Blt_VectorId clientId; int result; char *nameCopy; dataPtr = Blt_VectorGetInterpData(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 = Blt_VectorLookupName(dataPtr, nameCopy, &vPtr); Blt_Free(nameCopy); if (result != TCL_OK) { return (Blt_VectorId) 0; } /* Allocate a new client structure */ clientPtr = Blt_Calloc(1, sizeof(VectorClient)); assert(clientPtr); clientPtr->magic = VECTOR_MAGIC; /* Add the new client to the server's list of clients */ clientPtr->linkPtr = Blt_ChainAppend(vPtr->chainPtr, clientPtr); clientPtr->serverPtr = vPtr; clientId = (Blt_VectorId) clientPtr; return clientId; } /* * ----------------------------------------------------------------------- * * Blt_SetVectorChangedProc -- * * Sets the routine to be called back when the vector is changed * or deleted. *clientData* will be provided as an argument. If * *proc* is NULL, no callback will be made. * * Results: * None. * * Side Effects: * The designated routine will be called when the vector is changed * or deleted. * * ----------------------------------------------------------------------- */ void Blt_SetVectorChangedProc(clientId, proc, clientData) Blt_VectorId clientId; /* Client token identifying the vector */ Blt_VectorChangedProc *proc;/* Address of routine to call when the contents * of the vector change. If NULL, no routine * will be called */ ClientData clientData; /* One word of information to pass along when * the above routine is called */ { VectorClient *clientPtr = (VectorClient *)clientId; if (clientPtr->magic != VECTOR_MAGIC) { return; /* Not a valid token */ } clientPtr->clientData = clientData; clientPtr->proc = proc; } /* *-------------------------------------------------------------- * * Blt_FreeVectorId -- * * Releases the token for an existing vector. This indicates * that the client is no longer interested the vector. Any * previously specified callback routine will no longer be * invoked when (and if) the vector changes. * * Results: * None. * * Side Effects: * Any previously specified callback routine will no longer be * invoked when (and if) the vector changes. * *-------------------------------------------------------------- */ void Blt_FreeVectorId(clientId) Blt_VectorId clientId; /* Client token identifying the vector */ { VectorClient *clientPtr = (VectorClient *)clientId; if (clientPtr->magic != VECTOR_MAGIC) { return; /* Not a valid token */ } if (clientPtr->serverPtr != NULL) { /* Remove the client from the server's list */ Blt_ChainDeleteLink(clientPtr->serverPtr->chainPtr, clientPtr->linkPtr); } Blt_Free(clientPtr); } /* *-------------------------------------------------------------- * * Blt_NameOfVectorId -- * * Returns the name of the vector (and array variable). * * Results: * The name of the array variable is returned. * *-------------------------------------------------------------- */ char * Blt_NameOfVectorId(clientId) Blt_VectorId clientId; /* Client token identifying the vector */ { VectorClient *clientPtr = (VectorClient *)clientId; if ((clientPtr->magic != VECTOR_MAGIC) || (clientPtr->serverPtr == NULL)) { return NULL; } return clientPtr->serverPtr->name; } char * Blt_NameOfVector(vecPtr) Blt_Vector *vecPtr; /* Vector to query. */ { VectorObject *vPtr = (VectorObject *)vecPtr; return vPtr->name; } /* *-------------------------------------------------------------- * * Blt_VectorNotifyPending -- * * Returns the name of the vector (and array variable). * * Results: * The name of the array variable is returned. * *-------------------------------------------------------------- */ int Blt_VectorNotifyPending(clientId) Blt_VectorId clientId; /* Client token identifying the vector */ { VectorClient *clientPtr = (VectorClient *)clientId; if ((clientPtr == NULL) || (clientPtr->magic != VECTOR_MAGIC) || (clientPtr->serverPtr == NULL)) { return 0; } return (clientPtr->serverPtr->notifyFlags & NOTIFY_PENDING); } /* * ----------------------------------------------------------------------- * * Blt_GetVectorById -- * * Returns a pointer to the vector associated with the client * token. * * Results: * A standard Tcl result. If the client token is not associated * with a vector any longer, TCL_ERROR is returned. Otherwise, * TCL_OK is returned and vecPtrPtr will point to vector. * * ----------------------------------------------------------------------- */ int Blt_GetVectorById(interp, clientId, vecPtrPtr) Tcl_Interp *interp; Blt_VectorId clientId; /* Client token identifying the vector */ 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; } Blt_VectorUpdateRange(clientPtr->serverPtr); *vecPtrPtr = (Blt_Vector *) clientPtr->serverPtr; return TCL_OK; } /*LINTLIBRARY*/ void Blt_InstallIndexProc(interp, string, procPtr) Tcl_Interp *interp; char *string; Blt_VectorIndexProc *procPtr; /* Pointer to function to be called * when the vector finds the named index. * If NULL, this indicates to remove * the index from the table. */ { VectorInterpData *dataPtr; /* Interpreter-specific data. */ Blt_HashEntry *hPtr; int isNew; dataPtr = Blt_VectorGetInterpData(interp); hPtr = Blt_CreateHashEntry(&(dataPtr->indexProcTable), string, &isNew); if (procPtr == NULL) { Blt_DeleteHashEntry(&(dataPtr->indexProcTable), hPtr); } else { Blt_SetHashValue(hPtr, procPtr); } } blt-2.4z.orig/src/bltVector.h0100644000175000017500000001132607403601147014655 0ustar dokodoko /* * bltVector.h -- * * Copyright 1993-2000 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. */ #ifndef _BLT_VECTOR_H #define _BLT_VECTOR_H 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_VectorIdStruct *Blt_VectorId; typedef void (Blt_VectorChangedProc) _ANSI_ARGS_((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) _ANSI_ARGS_((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) EXTERN double Blt_VecMin _ANSI_ARGS_((Blt_Vector *vPtr)); EXTERN double Blt_VecMax _ANSI_ARGS_((Blt_Vector *vPtr)); EXTERN Blt_VectorId Blt_AllocVectorId _ANSI_ARGS_((Tcl_Interp *interp, char *vecName)); EXTERN void Blt_SetVectorChangedProc _ANSI_ARGS_((Blt_VectorId clientId, Blt_VectorChangedProc * proc, ClientData clientData)); EXTERN void Blt_FreeVectorId _ANSI_ARGS_((Blt_VectorId clientId)); EXTERN int Blt_GetVectorById _ANSI_ARGS_((Tcl_Interp *interp, Blt_VectorId clientId, Blt_Vector **vecPtrPtr)); EXTERN char *Blt_NameOfVectorId _ANSI_ARGS_((Blt_VectorId clientId)); EXTERN char *Blt_NameOfVector _ANSI_ARGS_((Blt_Vector *vecPtr)); EXTERN int Blt_VectorNotifyPending _ANSI_ARGS_((Blt_VectorId clientId)); EXTERN int Blt_CreateVector _ANSI_ARGS_((Tcl_Interp *interp, char *vecName, int size, Blt_Vector ** vecPtrPtr)); EXTERN int Blt_GetVector _ANSI_ARGS_((Tcl_Interp *interp, char *vecName, Blt_Vector **vecPtrPtr)); EXTERN int Blt_VectorExists _ANSI_ARGS_((Tcl_Interp *interp, char *vecName)); EXTERN int Blt_ResetVector _ANSI_ARGS_((Blt_Vector *vecPtr, double *dataArr, int nValues, int arraySize, Tcl_FreeProc *freeProc)); EXTERN int Blt_ResizeVector _ANSI_ARGS_((Blt_Vector *vecPtr, int nValues)); EXTERN int Blt_DeleteVectorByName _ANSI_ARGS_((Tcl_Interp *interp, char *vecName)); EXTERN int Blt_DeleteVector _ANSI_ARGS_((Blt_Vector *vecPtr)); EXTERN int Blt_ExprVector _ANSI_ARGS_((Tcl_Interp *interp, char *expression, Blt_Vector *vecPtr)); EXTERN void Blt_InstallIndexProc _ANSI_ARGS_((Tcl_Interp *interp, char *indexName, Blt_VectorIndexProc * procPtr)); #endif /* _BLT_VECTOR_H */ blt-2.4z.orig/src/bltWait.h0100644000175000017500000001403307356175576014340 0ustar dokodoko/* * bltWait.h -- * * Copyright 1993-1998 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. */ #ifndef _BLT_WAIT_H #define _BLT_WAIT_H #ifdef HAVE_WAITFLAGS_H # include #endif #ifdef HAVE_SYS_WAIT_H # include #endif #ifdef HAVE_ERRNO_H # include #endif /* * Define EINPROGRESS in terms of WSAEINPROGRESS. */ #ifndef EINPROGRESS #define EINPROGRESS WSAEINPROGRESS #endif /* * If ENOTSUP is not defined, define it to a value that will never occur. */ #ifndef ENOTSUP #define ENOTSUP -1030507 #endif /* * The following defines redefine the Windows Socket errors as * BSD errors so Tcl_PosixError can do the right thing. */ #ifndef EWOULDBLOCK #define EWOULDBLOCK EAGAIN #endif #ifndef EALREADY #define EALREADY 149 /* operation already in progress */ #endif #ifndef ENOTSOCK #define ENOTSOCK 95 /* Socket operation on non-socket */ #endif #ifndef EDESTADDRREQ #define EDESTADDRREQ 96 /* Destination address required */ #endif #ifndef EMSGSIZE #define EMSGSIZE 97 /* Message too long */ #endif #ifndef EPROTOTYPE #define EPROTOTYPE 98 /* Protocol wrong type for socket */ #endif #ifndef ENOPROTOOPT #define ENOPROTOOPT 99 /* Protocol not available */ #endif #ifndef EPROTONOSUPPORT #define EPROTONOSUPPORT 120 /* Protocol not supported */ #endif #ifndef ESOCKTNOSUPPORT #define ESOCKTNOSUPPORT 121 /* Socket type not supported */ #endif #ifndef EOPNOTSUPP #define EOPNOTSUPP 122 /* Operation not supported on socket */ #endif #ifndef EPFNOSUPPORT #define EPFNOSUPPORT 123 /* Protocol family not supported */ #endif #ifndef EAFNOSUPPORT #define EAFNOSUPPORT 124 /* Address family not supported */ #endif #ifndef EADDRINUSE #define EADDRINUSE 125 /* Address already in use */ #endif #ifndef EADDRNOTAVAIL #define EADDRNOTAVAIL 126 /* Can't assign requested address */ #endif #ifndef ENETDOWN #define ENETDOWN 127 /* Network is down */ #endif #ifndef ENETUNREACH #define ENETUNREACH 128 /* Network is unreachable */ #endif #ifndef ENETRESET #define ENETRESET 129 /* Network dropped connection on reset */ #endif #ifndef ECONNABORTED #define ECONNABORTED 130 /* Software caused connection abort */ #endif #ifndef ECONNRESET #define ECONNRESET 131 /* Connection reset by peer */ #endif #ifndef ENOBUFS #define ENOBUFS 132 /* No buffer space available */ #endif #ifndef EISCONN #define EISCONN 133 /* Socket is already connected */ #endif #ifndef ENOTCONN #define ENOTCONN 134 /* Socket is not connected */ #endif #ifndef ESHUTDOWN #define ESHUTDOWN 143 /* Can't send after socket shutdown */ #endif #ifndef ETOOMANYREFS #define ETOOMANYREFS 144 /* Too many references: can't splice */ #endif #ifndef ETIMEDOUT #define ETIMEDOUT 145 /* Connection timed out */ #endif #ifndef ECONNREFUSED #define ECONNREFUSED 146 /* Connection refused */ #endif #ifndef ELOOP #define ELOOP 90 /* Symbolic link loop */ #endif #ifndef EHOSTDOWN #define EHOSTDOWN 147 /* Host is down */ #endif #ifndef EHOSTUNREACH #define EHOSTUNREACH 148 /* No route to host */ #endif #ifndef ENOTEMPTY #define ENOTEMPTY 93 /* directory not empty */ #endif #ifndef EUSERS #define EUSERS 94 /* Too many users (for UFS) */ #endif #ifndef EDQUOT #define EDQUOT 49 /* Disc quota exceeded */ #endif #ifndef ESTALE #define ESTALE 151 /* Stale NFS file handle */ #endif #ifndef EREMOTE #define EREMOTE 66 /* The object is remote */ #endif #ifndef WIFEXITED # define WIFEXITED(stat) (((*((int *) &(stat))) & 0xff) == 0) #endif #ifndef WEXITSTATUS # define WEXITSTATUS(stat) (((*((int *) &(stat))) >> 8) & 0xff) #endif #ifndef WIFSIGNALED # define WIFSIGNALED(stat) (((*((int *) &(stat)))) && ((*((int *) &(stat))) == ((*((int *) &(stat))) & 0x00ff))) #endif #ifndef WTERMSIG # define WTERMSIG(stat) ((*((int *) &(stat))) & 0x7f) #endif #ifndef WIFSTOPPED # define WIFSTOPPED(stat) (((*((int *) &(stat))) & 0xff) == 0177) #endif #ifndef WSTOPSIG # define WSTOPSIG(stat) (((*((int *) &(stat))) >> 8) & 0xff) #endif /* * Define constants for waitpid() system call if they aren't defined * by a system header file. */ #ifndef WNOHANG # define WNOHANG 1 #endif #ifndef WUNTRACED # define WUNTRACED 2 #endif /* * The type of the status returned by wait varies from UNIX system * to UNIX system. The macro below defines it: */ #ifdef AIX # define WAIT_STATUS_TYPE pid_t #else #ifdef HAVE_UNION_WAIT # define WAIT_STATUS_TYPE union wait #else # define WAIT_STATUS_TYPE int #endif #endif /* * Supply definitions for macros to query wait status, if not already * defined in header files above. */ #ifndef WIFEXITED # define WIFEXITED(stat) (((*((int *) &(stat))) & 0xff) == 0) #endif #ifndef WEXITSTATUS # define WEXITSTATUS(stat) (((*((int *) &(stat))) >> 8) & 0xff) #endif #ifndef WIFSIGNALED # define WIFSIGNALED(stat) (((*((int *) &(stat)))) && ((*((int *) &(stat))) == ((*((int *) &(stat))) & 0x00ff))) #endif #ifndef WTERMSIG # define WTERMSIG(stat) ((*((int *) &(stat))) & 0x7f) #endif #ifndef WIFSTOPPED # define WIFSTOPPED(stat) (((*((int *) &(stat))) & 0xff) == 0177) #endif #ifndef WSTOPSIG # define WSTOPSIG(stat) (((*((int *) &(stat))) >> 8) & 0xff) #endif #endif /* _BLT_WAIT_H */ blt-2.4z.orig/src/bltWatch.c0100644000175000017500000005477607542177233014504 0ustar dokodoko/* * bltWatch.c -- * * This module implements watch procedure callbacks for Tcl * commands and procedures. * * Copyright 1994-1998 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. * * The "watch" command was created by George Howlett. */ #include "bltInt.h" #include #include "bltSwitch.h" #define UNKNOWN_RETURN_CODE 5 static char *codeNames[] = { "OK", "ERROR", "RETURN", "BREAK", "CONTINUE" }; #define WATCH_MAX_LEVEL 10000 /* Maximum depth of Tcl traces. */ enum WatchStates { WATCH_STATE_DONT_CARE = -1, /* Select watch regardless of state */ WATCH_STATE_IDLE = 0, /* */ WATCH_STATE_ACTIVE = 1 }; typedef struct { Tcl_Interp *interp; /* Interpreter associated with the watch */ Blt_Uid nameId; /* Watch identifier */ /* User-configurable fields */ enum WatchStates state; /* Current state of watch: either * WATCH_STATE_IDLE or WATCH_STATE_ACTIVE */ int maxLevel; /* Maximum depth of tracing allowed */ char **preCmd; /* Procedure to be invoked before the * command is executed (but after * substitutions have occurred). */ char **postCmd; /* Procedure to be invoked after the command * is executed. */ Tcl_Trace trace; /* Trace handler which activates "pre" * command procedures */ Tcl_AsyncHandler asyncHandle; /* Async handler which triggers the * "post" command procedure (if one * exists) */ int active; /* Indicates if a trace is currently * active. This prevents recursive * tracing of the "pre" and "post" * procedures. */ int level; /* Current level of traced command. */ char *cmdPtr; /* Command string before substitutions. * Points to a original command buffer. */ char *args; /* Tcl list of the command after * substitutions. List is malloc-ed by * Tcl_Merge. Must be freed in handler * procs */ } Watch; typedef struct { Blt_Uid nameId; /* Name identifier of the watch */ Tcl_Interp *interp; /* Interpreter associated with the * watch */ } WatchKey; static Blt_HashTable watchTable; static int refCount = 0; static Blt_SwitchSpec switchSpecs[] = { {BLT_SWITCH_LIST, "-precmd", Blt_Offset(Watch, preCmd), 0}, {BLT_SWITCH_LIST, "-postcmd", Blt_Offset(Watch, postCmd), 0}, {BLT_SWITCH_BOOLEAN, "-active", Blt_Offset(Watch, state), 0}, {BLT_SWITCH_INT_NONNEGATIVE, "-maxlevel", Blt_Offset(Watch, maxLevel), 0}, {BLT_SWITCH_END, NULL, 0, 0} }; static Tcl_CmdTraceProc PreCmdProc; static Tcl_AsyncProc PostCmdProc; static Tcl_CmdProc WatchCmd; static Tcl_CmdDeleteProc WatchDeleteCmd; /* *---------------------------------------------------------------------- * * PreCmdProc -- * * Procedure callback for Tcl_Trace. Gets called before the * command is executed, but after substitutions have occurred. * If a watch procedure is active, it evals a Tcl command. * Activates the "precmd" callback, if one exists. * * Stashes some information for the "pre" callback: command * string, substituted argument list, and current level. * * Format of "pre" proc: * * proc beforeCmd { level cmdStr argList } { * * } * * * Results: * None. * * Side Effects: * A Tcl_AsyncHandler may be triggered, if a "post" procedure is * defined. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static void PreCmdProc(clientData, interp, level, command, cmdProc, cmdClientData, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Not used. */ int level; /* Current level */ char *command; /* Command before substitution */ Tcl_CmdProc *cmdProc; /* Not used. */ ClientData cmdClientData; /* Not used. */ int argc; char **argv; /* Command after parsing, but before * evaluation */ { Watch *watchPtr = clientData; if (watchPtr->active) { return; /* Don't re-enter from Tcl_Eval below */ } watchPtr->cmdPtr = command; watchPtr->level = level; /* * There's no guarantee that the calls to PreCmdProc will match * up with PostCmdProc. So free up argument lists that are still * hanging around before allocating a new one. */ if (watchPtr->args != NULL) { Blt_Free(watchPtr->args); } watchPtr->args = Tcl_Merge(argc, argv); if (watchPtr->preCmd != NULL) { Tcl_DString buffer; char string[200]; int status; register char **p; /* Create the "pre" command procedure call */ Tcl_DStringInit(&buffer); for (p = watchPtr->preCmd; *p != NULL; p++) { Tcl_DStringAppendElement(&buffer, *p); } sprintf(string, "%d", watchPtr->level); Tcl_DStringAppendElement(&buffer, string); Tcl_DStringAppendElement(&buffer, watchPtr->cmdPtr); Tcl_DStringAppendElement(&buffer, watchPtr->args); watchPtr->active = 1; status = Tcl_Eval(interp, Tcl_DStringValue(&buffer)); watchPtr->active = 0; Tcl_DStringFree(&buffer); if (status != TCL_OK) { fprintf(stderr, "%s failed: %s\n", watchPtr->preCmd[0], Tcl_GetStringResult(interp)); } } /* Set the trigger for the "post" command procedure */ if (watchPtr->postCmd != NULL) { Tcl_AsyncMark(watchPtr->asyncHandle); } } /* *---------------------------------------------------------------------- * * PostCmdProc -- * * Procedure callback for Tcl_AsyncHandler. Gets called after * the command has executed. It tests for a "post" command, but * you really can't get here, if one doesn't exist. * * Save the current contents of interp->result before calling * the "post" command, and restore it afterwards. * * Format of "post" proc: * * proc afterCmd { level cmdStr argList retCode results } { * * } * * Results: * None. * * Side Effects: * Memory for argument list is released. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int PostCmdProc(clientData, interp, code) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Not used. */ int code; /* Completion code of command */ { Watch *watchPtr = clientData; if (watchPtr->active) { return code; } if (watchPtr->postCmd != NULL) { int status; Tcl_DString buffer; char string[200]; char *results; register char **p; char *retCode; char *errorCode, *errorInfo; errorInfo = errorCode = NULL; results = "NO INTERPRETER AVAILABLE"; /* * ---------------------------------------------------- * * Save the state of the interpreter. * * ---------------------------------------------------- */ if (interp != NULL) { errorInfo = (char *)Tcl_GetVar2(interp, "errorInfo", (char *)NULL, TCL_GLOBAL_ONLY); if (errorInfo != NULL) { errorInfo = Blt_Strdup(errorInfo); } errorCode = (char *)Tcl_GetVar2(interp, "errorCode", (char *)NULL, TCL_GLOBAL_ONLY); if (errorCode != NULL) { errorCode = Blt_Strdup(errorCode); } results = Blt_Strdup(Tcl_GetStringResult(interp)); } /* Create the "post" command procedure call */ Tcl_DStringInit(&buffer); for (p = watchPtr->postCmd; *p != NULL; p++) { Tcl_DStringAppendElement(&buffer, *p); } sprintf(string, "%d", watchPtr->level); Tcl_DStringAppendElement(&buffer, string); Tcl_DStringAppendElement(&buffer, watchPtr->cmdPtr); Tcl_DStringAppendElement(&buffer, watchPtr->args); if (code < UNKNOWN_RETURN_CODE) { retCode = codeNames[code]; } else { sprintf(string, "%d", code); retCode = string; } Tcl_DStringAppendElement(&buffer, retCode); Tcl_DStringAppendElement(&buffer, results); watchPtr->active = 1; status = Tcl_Eval(watchPtr->interp, Tcl_DStringValue(&buffer)); watchPtr->active = 0; Tcl_DStringFree(&buffer); Blt_Free(watchPtr->args); watchPtr->args = NULL; if (status != TCL_OK) { fprintf(stderr, "%s failed: %s\n", watchPtr->postCmd[0], Tcl_GetStringResult(watchPtr->interp)); } /* * ---------------------------------------------------- * * Restore the state of the interpreter. * * ---------------------------------------------------- */ if (interp != NULL) { if (errorInfo != NULL) { Tcl_SetVar2(interp, "errorInfo", (char *)NULL, errorInfo, TCL_GLOBAL_ONLY); Blt_Free(errorInfo); } if (errorCode != NULL) { Tcl_SetVar2(interp, "errorCode", (char *)NULL, errorCode, TCL_GLOBAL_ONLY); Blt_Free(errorCode); } Tcl_SetResult(interp, results, TCL_DYNAMIC); } } return code; } /* *---------------------------------------------------------------------- * * NewWatch -- * * Creates a new watch. Uses the nameId and interpreter * address to create a unique hash key. The new watch is * registered into the "watchTable" hash table. Also creates a * Tcl_AsyncHandler for triggering "post" events. * * Results: * If memory for the watch could be allocated, a pointer to * the new watch is returned. Otherwise NULL, and interp->result * points to an error message. * * Side Effects: * A new Tcl_AsyncHandler is created. A new hash table entry * is created. Memory the watch structure is allocated. * *---------------------------------------------------------------------- */ static Watch * NewWatch(interp, name) Tcl_Interp *interp; char *name; { Watch *watchPtr; WatchKey key; Blt_HashEntry *hPtr; int dummy; watchPtr = Blt_Calloc(1, sizeof(Watch)); if (watchPtr == NULL) { Tcl_AppendResult(interp, "can't allocate watch structure", (char *)NULL); return NULL; } watchPtr->state = WATCH_STATE_ACTIVE; watchPtr->maxLevel = WATCH_MAX_LEVEL; watchPtr->nameId = Blt_GetUid(name); watchPtr->interp = interp; watchPtr->asyncHandle = Tcl_AsyncCreate(PostCmdProc, watchPtr); key.interp = interp; key.nameId = watchPtr->nameId; hPtr = Blt_CreateHashEntry(&watchTable, (char *)&key, &dummy); Blt_SetHashValue(hPtr, watchPtr); return watchPtr; } /* *---------------------------------------------------------------------- * * DestroyWatch -- * * Removes the watch. The resources used by the watch * are released. * 1) If the watch is active, its trace is deleted. * 2) Memory for command strings is free-ed. * 3) Entry is removed from watch registry. * 4) Async handler is deleted. * 5) Memory for watch itself is released. * * Results: * None. * * Side Effects: * Everything associated with the watch is freed. * *---------------------------------------------------------------------- */ static void DestroyWatch(watchPtr) Watch *watchPtr; { WatchKey key; Blt_HashEntry *hPtr; Tcl_AsyncDelete(watchPtr->asyncHandle); if (watchPtr->state == WATCH_STATE_ACTIVE) { Tcl_DeleteTrace(watchPtr->interp, watchPtr->trace); } if (watchPtr->preCmd != NULL) { Blt_Free(watchPtr->preCmd); } if (watchPtr->postCmd != NULL) { Blt_Free(watchPtr->postCmd); } if (watchPtr->args != NULL) { Blt_Free(watchPtr->args); } key.interp = watchPtr->interp; key.nameId = watchPtr->nameId; hPtr = Blt_FindHashEntry(&watchTable, (char *)&key); Blt_DeleteHashEntry(&watchTable, hPtr); Blt_FreeUid(key.nameId); Blt_Free(watchPtr); } /* *---------------------------------------------------------------------- * * NameToWatch -- * * Searches for the watch represented by the watch name and its * associated interpreter in its directory. * * Results: * If found, the pointer to the watch structure is returned, * otherwise NULL. If requested, interp-result will be filled * with an error message. * *---------------------------------------------------------------------- */ static Watch * NameToWatch(interp, name, flags) Tcl_Interp *interp; char *name; int flags; { WatchKey key; Blt_HashEntry *hPtr; key.interp = interp; key.nameId = Blt_FindUid(name); if (key.nameId != NULL) { hPtr = Blt_FindHashEntry(&watchTable, (char *)&key); if (hPtr != NULL) { return (Watch *) Blt_GetHashValue(hPtr); } } if (flags & TCL_LEAVE_ERR_MSG) { Tcl_AppendResult(interp, "can't find any watch named \"", name, "\"", (char *)NULL); } return NULL; } /* *---------------------------------------------------------------------- * * ListWatches -- * * Creates a list of all watches in the interpreter. The * list search may be restricted to selected states by * setting "state" to something other than WATCH_STATE_DONT_CARE. * * Results: * A standard Tcl result. Interp->result will contain a list * of all watches matches the state criteria. * *---------------------------------------------------------------------- */ static int ListWatches(interp, state) Tcl_Interp *interp; enum WatchStates state; /* Active flag */ { Blt_HashEntry *hPtr; Blt_HashSearch cursor; register Watch *watchPtr; for (hPtr = Blt_FirstHashEntry(&watchTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { watchPtr = (Watch *)Blt_GetHashValue(hPtr); if (watchPtr->interp == interp) { if ((state == WATCH_STATE_DONT_CARE) || (state == watchPtr->state)) { Tcl_AppendElement(interp, (char *)watchPtr->nameId); } } } return TCL_OK; } /* *---------------------------------------------------------------------- * * ConfigWatch -- * * Processes argument list of switches and values, setting * Watch fields. * * Results: * If found, the pointer to the watch structure is returned, * otherwise NULL. If requested, interp-result will be filled * with an error message. * *---------------------------------------------------------------------- */ static int ConfigWatch(watchPtr, interp, argc, argv) Watch *watchPtr; Tcl_Interp *interp; int argc; char *argv[]; { if (Blt_ProcessSwitches(interp, switchSpecs, argc, argv, (char *)watchPtr, 0) < 0) { return TCL_ERROR; } /* * If the watch's max depth changed or its state, reset the traces. */ if (watchPtr->trace != (Tcl_Trace) 0) { Tcl_DeleteTrace(interp, watchPtr->trace); watchPtr->trace = (Tcl_Trace) 0; } if (watchPtr->state == WATCH_STATE_ACTIVE) { watchPtr->trace = Tcl_CreateTrace(interp, watchPtr->maxLevel, PreCmdProc, watchPtr); } return TCL_OK; } /* Tcl interface routines */ /* *---------------------------------------------------------------------- * * CreateOp -- * * Creates a new watch and processes any extra switches. * * Results: * A standard Tcl result. * * Side Effects: * A new watch is created. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int CreateOp(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; int argc; char **argv; { register Watch *watchPtr; watchPtr = NameToWatch(interp, argv[2], 0); if (watchPtr != NULL) { Tcl_AppendResult(interp, "a watch \"", argv[2], "\" already exists", (char *)NULL); return TCL_ERROR; } watchPtr = NewWatch(interp, argv[2]); if (watchPtr == NULL) { return TCL_ERROR; /* Can't create new watch */ } return ConfigWatch(watchPtr, interp, argc - 3, argv + 3); } /* *---------------------------------------------------------------------- * * DeleteOp -- * * Deletes the watch. * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int DeleteOp(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; int argc; char **argv; { register Watch *watchPtr; watchPtr = NameToWatch(interp, argv[2], TCL_LEAVE_ERR_MSG); if (watchPtr == NULL) { return TCL_ERROR; } DestroyWatch(watchPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * ActivateOp -- * * Activate/deactivates the named watch. * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ActivateOp(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; int argc; char **argv; { register Watch *watchPtr; enum WatchStates state; state = (argv[1][0] == 'a') ? WATCH_STATE_ACTIVE : WATCH_STATE_IDLE; watchPtr = NameToWatch(interp, argv[2], TCL_LEAVE_ERR_MSG); if (watchPtr == NULL) { return TCL_ERROR; } if (state != watchPtr->state) { if (watchPtr->trace == (Tcl_Trace) 0) { watchPtr->trace = Tcl_CreateTrace(interp, watchPtr->maxLevel, PreCmdProc, watchPtr); } else { Tcl_DeleteTrace(interp, watchPtr->trace); watchPtr->trace = (Tcl_Trace) 0; } watchPtr->state = state; } return TCL_OK; } /* *---------------------------------------------------------------------- * * NamesOp -- * * Returns the names of all watches in the interpreter. * * Results: * A standard Tcl result. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int NamesOp(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; int argc; char **argv; { enum WatchStates state; state = WATCH_STATE_DONT_CARE; if (argc == 3) { char c; c = argv[2][0]; if ((c == 'a') && (strcmp(argv[2], "active") == 0)) { state = WATCH_STATE_ACTIVE; } else if ((c == 'i') && (strcmp(argv[2], "idle") == 0)) { state = WATCH_STATE_IDLE; } else if ((c == 'i') && (strcmp(argv[2], "ignore") == 0)) { state = WATCH_STATE_DONT_CARE; } else { Tcl_AppendResult(interp, "bad state \"", argv[2], "\" should be \ \"active\", \"idle\", or \"ignore\"", (char *)NULL); return TCL_ERROR; } } return ListWatches(interp, state); } /* *---------------------------------------------------------------------- * * ConfigureOp -- * * Convert the range of the pixel values allowed into a list. * * Results: * The string representation of the limits is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int ConfigureOp(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; int argc; char **argv; { register Watch *watchPtr; watchPtr = NameToWatch(interp, argv[2], TCL_LEAVE_ERR_MSG); if (watchPtr == NULL) { return TCL_ERROR; } return ConfigWatch(watchPtr, interp, argc - 3, argv + 3); } /* *---------------------------------------------------------------------- * * InfoOp -- * * Convert the limits of the pixel values allowed into a list. * * Results: * The string representation of the limits is returned. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static int InfoOp(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; int argc; char **argv; { register Watch *watchPtr; char string[200]; register char **p; watchPtr = NameToWatch(interp, argv[2], TCL_LEAVE_ERR_MSG); if (watchPtr == NULL) { return TCL_ERROR; } if (watchPtr->preCmd != NULL) { Tcl_AppendResult(interp, "-precmd", (char *)NULL); for (p = watchPtr->preCmd; *p != NULL; p++) { Tcl_AppendResult(interp, " ", *p, (char *)NULL); } } if (watchPtr->postCmd != NULL) { Tcl_AppendResult(interp, "-postcmd", (char *)NULL); for (p = watchPtr->postCmd; *p != NULL; p++) { Tcl_AppendResult(interp, " ", *p, (char *)NULL); } } sprintf(string, "%d", watchPtr->maxLevel); Tcl_AppendResult(interp, "-maxlevel ", string, " ", (char *)NULL); Tcl_AppendResult(interp, "-active ", (watchPtr->state == WATCH_STATE_ACTIVE) ? "true" : "false", " ", (char *)NULL); return TCL_OK; } /* *-------------------------------------------------------------- * * WatchCmd -- * * This procedure is invoked to process the Tcl "blt_watch" * command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ static Blt_OpSpec watchOps[] = { {"activate", 1, (Blt_Op)ActivateOp, 3, 3, "watchName",}, {"configure", 2, (Blt_Op)ConfigureOp, 3, 0, "watchName ?options...?"}, {"create", 2, (Blt_Op)CreateOp, 3, 0, "watchName ?switches?",}, {"deactivate", 3, (Blt_Op)ActivateOp, 3, 3, "watchName",}, {"delete", 3, (Blt_Op)DeleteOp, 3, 3, "watchName",}, {"info", 1, (Blt_Op)InfoOp, 3, 3, "watchName",}, {"names", 1, (Blt_Op)NamesOp, 2, 3, "?state?",}, }; static int nWatchOps = sizeof(watchOps) / sizeof(Blt_OpSpec); /*ARGSUSED*/ static int WatchCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; int argc; char **argv; { Blt_Op proc; int result; proc = Blt_GetOp(interp, nWatchOps, watchOps, BLT_OP_ARG1, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (clientData, interp, argc, argv); return result; } /* ARGSUSED */ static void WatchDeleteCmd(clientData) ClientData clientData; /* Not Used. */ { refCount--; if (refCount == 0) { Blt_DeleteHashTable(&watchTable); } } /* Public initialization routine */ /* *-------------------------------------------------------------- * * Blt_WatchInit -- * * This procedure is invoked to initialize the Tcl command * "blt_watch". * * Results: * None. * * Side effects: * Creates the new command and adds a new entry into a * global Tcl associative array. * *-------------------------------------------------------------- */ int Blt_WatchInit(interp) Tcl_Interp *interp; { static Blt_CmdSpec cmdSpec = {"watch", WatchCmd, WatchDeleteCmd}; if (refCount == 0) { Blt_InitHashTable(&watchTable, sizeof(WatchKey) / sizeof(int)); } refCount++; if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) { return TCL_ERROR; } return TCL_OK; } blt-2.4z.orig/src/bltWin.h0100644000175000017500000002151507536456632014167 0ustar dokodoko /* * bltWin.h -- * * Copyright 1993-1998 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. */ #ifndef _BLT_WIN_H #define _BLT_WIN_H #define STRICT #define WIN32_LEAN_AND_MEAN #include #undef STRICT #undef WIN32_LEAN_AND_MEAN #include #undef STD_NORMAL_BACKGROUND #undef STD_NORMAL_FOREGROUND #undef STD_SELECT_BACKGROUND #undef STD_SELECT_FOREGROUND #undef STD_TEXT_FOREGROUND #undef STD_FONT #undef STD_FONT_LARGE #undef STD_FONT_SMALL #define STD_NORMAL_BACKGROUND "SystemButtonFace" #define STD_NORMAL_FOREGROUND "SystemButtonText" #define STD_SELECT_BACKGROUND "SystemHighlight" #define STD_SELECT_FOREGROUND "SystemHighlightText" #define STD_TEXT_FOREGROUND "SystemWindowText" #define STD_FONT "Arial 8" #define STD_FONT_LARGE "Arial 12" #define STD_FONT_SMALL "Arial 6" #ifdef CHECK_UNICODE_CALLS #define _UNICODE #define UNICODE #define __TCHAR_DEFINED typedef float *_TCHAR; #define _TCHAR_DEFINED typedef float *TCHAR; #endif /* CHECK_UNICODE_CALLS */ /* DOS Encapsulated PostScript File Header */ #pragma pack(2) typedef struct { BYTE magic[4]; /* Magic number for a DOS EPS file * C5,D0,D3,C6 */ DWORD psStart; /* Offset of PostScript section. */ DWORD psLength; /* Length of the PostScript section. */ DWORD wmfStart; /* Offset of Windows Meta File section. */ DWORD wmfLength; /* Length of Meta file section. */ DWORD tiffStart; /* Offset of TIFF section. */ DWORD tiffLength; /* Length of TIFF section. */ WORD checksum; /* Checksum of header. If FFFF, ignore. */ } DOSEPSHEADER; #pragma pack() /* Aldus Portable Metafile Header */ #pragma pack(2) typedef struct { DWORD key; /* Type of metafile */ WORD hmf; /* Unused. Must be NULL. */ SMALL_RECT bbox; /* Bounding rectangle */ WORD inch; /* Units per inch. */ DWORD reserved; /* Unused. */ WORD checksum; /* XOR of previous fields (10 32-bit words). */ } APMHEADER; #pragma pack() extern double hypot(double x, double y); extern int Blt_AsyncRead(int fd, char *buffer, unsigned int size); extern int Blt_AsyncWrite(int fd, char *buffer, unsigned int size); extern void Blt_CreateFileHandler(int fd, int flags, Tcl_FileProc * proc, ClientData clientData); extern void Blt_DeleteFileHandler(int fd); extern int Blt_GetPlatformId(void); extern char *Blt_LastError(void); extern int Blt_GetOpenPrinter(Tcl_Interp *interp, const char *id, Drawable *drawablePtr); extern int Blt_PrintDialog(Tcl_Interp *interp, Drawable *drawablePtr); extern int Blt_OpenPrinterDoc(Tcl_Interp *interp, const char *id); extern int Blt_ClosePrinterDoc(Tcl_Interp *interp, const char *id); extern void Blt_GetPrinterScale(HDC dc, double *xRatio, double *yRatio); extern int Blt_StartPrintJob(Tcl_Interp *interp, Drawable drawable); extern int Blt_EndPrintJob(Tcl_Interp *interp, Drawable drawable); #undef EXPORT #define EXPORT __declspec(dllexport) #ifdef _MSC_VER #define strncasecmp(s1,s2,n) _strnicmp(s1,s2,n) #define strcasecmp(s1,s2) _stricmp(s1,s2) #define isnan(x) _isnan(x) #endif /* _MSC_VER */ #ifdef __BORLANDC__ #define isnan(x) _isnan(x) #endif #if defined(__BORLANDC__) || defined(_MSC_VER) #ifdef FINITE #undef FINITE #define FINITE(x) _finite(x) #endif #endif /* __BORLANDC__ || _MSC_VER */ #ifdef __GNUC__ #include #include #undef Status #include #define Status int /* * Add definitions missing from windgi.h, windowsx.h, and winspool.h */ #include #endif /* __GNUC__ */ #define XCopyArea Blt_EmulateXCopyArea #define XCopyPlane Blt_EmulateXCopyPlane #define XDrawArcs Blt_EmulateXDrawArcs #define XDrawLine Blt_EmulateXDrawLine #define XDrawLines Blt_EmulateXDrawLines #define XDrawPoints Blt_EmulateXDrawPoints #define XDrawRectangle Blt_EmulateXDrawRectangle #define XDrawRectangles Blt_EmulateXDrawRectangles #define XDrawSegments Blt_EmulateXDrawSegments #define XDrawString Blt_EmulateXDrawString #define XFillArcs Blt_EmulateXFillArcs #define XFillPolygon Blt_EmulateXFillPolygon #define XFillRectangle Blt_EmulateXFillRectangle #define XFillRectangles Blt_EmulateXFillRectangles #define XFree Blt_EmulateXFree #define XGetWindowAttributes Blt_EmulateXGetWindowAttributes #define XLowerWindow Blt_EmulateXLowerWindow #define XMaxRequestSize Blt_EmulateXMaxRequestSize #define XRaiseWindow Blt_EmulateXRaiseWindow #define XReparentWindow Blt_EmulateXReparentWindow #define XSetDashes Blt_EmulateXSetDashes #define XUnmapWindow Blt_EmulateXUnmapWindow #define XWarpPointer Blt_EmulateXWarpPointer EXTERN GC Blt_EmulateXCreateGC(Display *display, Drawable drawable, unsigned long mask, XGCValues *valuesPtr); EXTERN void Blt_EmulateXCopyArea(Display *display, Drawable src, Drawable dest, GC gc, int src_x, int src_y, unsigned int width, unsigned int height, int dest_x, int dest_y); EXTERN void Blt_EmulateXCopyPlane(Display *display, Drawable src, Drawable dest, GC gc, int src_x, int src_y, unsigned int width, unsigned int height, int dest_x, int dest_y, unsigned long plane); EXTERN void Blt_EmulateXDrawArcs(Display *display, Drawable drawable, GC gc, XArc *arcArr, int nArcs); EXTERN void Blt_EmulateXDrawLine(Display *display, Drawable drawable, GC gc, int x1, int y1, int x2, int y2); EXTERN void Blt_EmulateXDrawLines(Display *display, Drawable drawable, GC gc, XPoint *pointArr, int nPoints, int mode); EXTERN void Blt_EmulateXDrawPoints(Display *display, Drawable drawable, GC gc, XPoint *pointArr, int nPoints, int mode); EXTERN void Blt_EmulateXDrawRectangle(Display *display, Drawable drawable, GC gc, int x, int y, unsigned int width, unsigned int height); EXTERN void Blt_EmulateXDrawRectangles(Display *display, Drawable drawable, GC gc, XRectangle *rectArr, int nRects); EXTERN void Blt_EmulateXDrawSegments(Display *display, Drawable drawable, GC gc, XSegment *segArr, int nSegments); EXTERN void Blt_EmulateXDrawSegments(Display *display, Drawable drawable, GC gc, XSegment *segArr, int nSegments); EXTERN void Blt_EmulateXDrawString(Display *display, Drawable drawable, GC gc, int x, int y, _Xconst char *string, int length); EXTERN void Blt_EmulateXFillArcs(Display *display, Drawable drawable, GC gc, XArc *arcArr, int nArcs); EXTERN void Blt_EmulateXFillPolygon(Display *display, Drawable drawable, GC gc, XPoint *points, int nPoints, int shape, int mode); EXTERN void Blt_EmulateXFillRectangle(Display *display, Drawable drawable, GC gc, int x, int y, unsigned int width, unsigned int height); EXTERN void Blt_EmulateXFillRectangles(Display *display, Drawable drawable, GC gc, XRectangle *rectArr, int nRects); EXTERN void Blt_EmulateXFree(void *ptr); EXTERN int Blt_EmulateXGetWindowAttributes(Display *display, Window window, XWindowAttributes * attrsPtr); EXTERN void Blt_EmulateXLowerWindow(Display *display, Window window); EXTERN void Blt_EmulateXMapWindow(Display *display, Window window); EXTERN long Blt_EmulateXMaxRequestSize(Display *display); EXTERN void Blt_EmulateXRaiseWindow(Display *display, Window window); EXTERN void Blt_EmulateXReparentWindow(Display *display, Window window, Window parent, int x, int y); EXTERN void Blt_EmulateXSetDashes(Display *display, GC gc, int dashOffset, _Xconst char *dashList, int n); EXTERN void Blt_EmulateXUnmapWindow(Display *display, Window window); EXTERN void Blt_EmulateXWarpPointer(Display *display, Window srcWindow, Window destWindow, int srcX, int srcY, unsigned int srcWidth, unsigned int srcHeight, int destX, int destY); EXTERN void Blt_DrawLine2D(Display *display, Drawable drawable, GC gc, POINT *screenPts, int nScreenPts); extern unsigned char *Blt_GetBitmapData _ANSI_ARGS_((Display *display, Pixmap bitmap, int width, int height, int *pitchPtr)); extern HFONT Blt_CreateRotatedFont _ANSI_ARGS_((Tk_Window tkwin, unsigned long font, double theta)); extern HPALETTE Blt_GetSystemPalette _ANSI_ARGS_((void)); extern HPEN Blt_GCToPen _ANSI_ARGS_((HDC dc, GC gc)); #endif /*_BLT_WIN_H*/ blt-2.4z.orig/src/bltWinConfig.h0100644000175000017500000000723407515237461015311 0ustar dokodoko/* src/bltConfig.h. Generated automatically by configure. */ /* src/bltConfig.h.in. Generated automatically from configure.in by autoheader. */ /* Define if you have that is POSIX.1 compatible. */ #undef HAVE_SYS_WAIT_H /* Define to `int' if doesn't define. */ #if defined(_MSC_VER) || defined(__BORLANDC__) #define pid_t int #endif /* _MSC_VER || __BORLANDC__ */ /* Define to `unsigned' if doesn't define. */ #undef size_t /* Define if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define if you can safely include both and . */ #undef TIME_WITH_SYS_TIME /* Define if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel and VAX). */ #undef WORDS_BIGENDIAN /* Define if DBL_EPSILON is not defined in float.h */ #undef BLT_DBL_EPSILON /* Define if drand48 isn't declared in math.h. */ #define NEED_DECL_DRAND48 1 /* Define if srand48 isn't declared in math.h. */ #define NEED_DECL_SRAND48 1 /* Define if strdup isn't declared in a standard header file. */ #undef NEED_DECL_STRDUP /* Define if j1 isn't declared in a standard header file. */ #define NEED_DECL_J1 1 /* Define if union wait type is defined incorrectly. */ #undef HAVE_UNION_WAIT /* Define if isfinite is found in libm. */ #undef HAVE_ISFINITE /* The number of bytes in a long. */ #define SIZEOF_LONG 4 /* The number of bytes in a long long. */ #define SIZEOF_LONG_LONG 8 /* The number of bytes in a void *. */ #define SIZEOF_VOID_P 4 /* Define if you have the XExtendedMaxRequestSize function. */ #undef HAVE_XEXTENDEDMAXREQUESTSIZE /* Define if you have the drand48 function. */ #define HAVE_DRAND48 1 /* Define if you have the finite function. */ #undef HAVE_FINITE /* Define if you have the srand48 function. */ #define HAVE_SRAND48 1 /* Define if you have the strdup function. */ #define HAVE_STRDUP 1 #ifndef __BORLANDC__ /* Define if you have the strcasecmp function. */ #define HAVE_STRCASECMP 1 /* Define if you have the strncasecmp function. */ #define HAVE_STRNCASECMP 1 #endif /* Define if you have the header file. */ #define HAVE_CTYPE_H 1 /* Define if you have the header file. */ #define HAVE_ERRNO_H 1 /* Define if you have the header file. */ #define HAVE_FLOAT_H 1 /* Define if you have the header file. */ #undef HAVE_IEEEFP_H /* Define if you have the header file. */ /* Defined in Makefile */ /* #undef HAVE_JPEGLIB_H */ /* Define if you have the header file. */ #define HAVE_LIMITS_H 1 /* Define if you have the header file. */ #define HAVE_MALLOC_H 1 /* Define if you have the header file. */ #define HAVE_MATH_H 1 /* Define if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define if you have the header file. */ #define HAVE_SETJMP_H 1 /* Define if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define if you have the header file. */ #define HAVE_STRING_H 1 /* Define if you have the header file. */ #undef HAVE_SYS_PARAM_H /* Define if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define if you have the header file. */ #undef HAVE_SYS_WAIT_H /* Define if you have the header file. */ #undef HAVE_UNISTD_H /* Define if you have the header file. */ #undef HAVE_WAITFLAGS_H /* Define if you have the m library (-lm). */ #define HAVE_LIBM 1 /* Define if you have the nsl library (-lnsl). */ #undef HAVE_LIBNSL /* Define if you have the socket library (-lsocket). */ #undef HAVE_LIBSOCKET blt-2.4z.orig/src/bltWinDde.c0100644000175000017500000010270507535436724014577 0ustar dokodoko /* * bltWinDde.c -- * * This file provides procedures that implement the "send" * command, allowing commands to be passed from interpreter * to interpreter. * * Copyright (c) 1997 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * RCS: @(#) $Id: bltWinDde.c,v 1.7 2002/09/04 17:07:32 ghowlett Exp $ */ #include "bltInt.h" #ifndef NO_DDE #include /* * The following structure is used to keep track of the interpreters * registered by this process. */ typedef struct RegisteredInterp { struct RegisteredInterp *nextPtr; /* The next interp this application knows * about. */ Tcl_Interp *interp; /* The interpreter attached to this name. */ char name[1]; /* Interpreter's name. Malloc-ed as * part of the structure. */ } RegisteredInterp; /* * Used to keep track of conversations. */ typedef struct Conversation { struct Conversation *nextPtr; /* The next conversation in the list. */ RegisteredInterp *riPtr; /* The info we know about the conversation. */ HCONV hConv; /* The DDE handle for this conversation. */ Tcl_Obj *returnPackagePtr; /* The result package for this conversation. */ } Conversation; static Conversation *conversations; /* A list of conversations currently * being processed. */ static RegisteredInterp *interps; /* List of all interpreters registered * in the current process. */ static HSZ globalService; static DWORD instance; /* The application instance handle given * to us by DdeInitialize. */ static int isServer; #define TCL_DDE_VERSION "1.2" #define TCL_DDE_PACKAGE_NAME "dde" #define TCL_DDE_SERVICE_NAME "TclEval" /* * Forward declarations for procedures defined later in this file. */ static Tcl_Obj *ExecuteRemoteObject _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); static int MakeConnection _ANSI_ARGS_((Tcl_Interp *interp, char *name, HCONV *convPtr)); static HDDEDATA CALLBACK ServerProc _ANSI_ARGS_((UINT uType, UINT uFmt, HCONV hConv, HSZ topic, HSZ item, HDDEDATA hData, DWORD dwData1, DWORD dwData2)); static Tcl_ExitProc ExitProc; static Tcl_CmdDeleteProc DeleteProc; static void SetError _ANSI_ARGS_((Tcl_Interp *interp)); static Tcl_ObjCmdProc DdeObjCmd; /* *---------------------------------------------------------------------- * * Initialize -- * * Initialize the global DDE instance. * * Results: * None. * * Side effects: * Registers the DDE server proc. * *---------------------------------------------------------------------- */ static void Initialize(void) { int nameFound = 0; /* * See if the application is already registered; if so, remove its * current name from the registry. The deletion of the command * will take care of disposing of this entry. */ if (interps != NULL) { nameFound = 1; } /* * Make sure that the DDE server is there. This is done only once, * add an exit handler tear it down. */ if (instance == 0) { if (instance == 0) { unsigned int flags; flags = (CBF_SKIP_REGISTRATIONS | CBF_SKIP_UNREGISTRATIONS | CBF_FAIL_POKES); if (DdeInitialize(&instance, ServerProc, flags, 0) != DMLERR_NO_ERROR) { instance = 0; } } } if ((globalService == 0) && (nameFound != 0)) { if ((globalService == 0) && (nameFound != 0)) { isServer = TRUE; Tcl_CreateExitHandler(ExitProc, NULL); globalService = DdeCreateStringHandle(instance, TCL_DDE_SERVICE_NAME, 0); DdeNameService(instance, globalService, 0L, DNS_REGISTER); } else { isServer = FALSE; } } } /* *-------------------------------------------------------------- * * SetServerName -- * * This procedure is called to associate an ASCII name with a Dde * server. If the interpreter has already been named, the * name replaces the old one. * * Results: * The return value is the name actually given to the interp. * This will normally be the same as name, but if name was already * in use for a Dde Server then a name of the form "name #2" will * be chosen, with a high enough number to make the name unique. * * Side effects: * Registration info is saved, thereby allowing the "send" command * to be used later to invoke commands in the application. In * addition, the "send" command is created in the application's * interpreter. The registration will be removed automatically * if the interpreter is deleted or the "send" command is removed. * *-------------------------------------------------------------- */ static char * SetServerName( Tcl_Interp *interp, char *name /* The name that will be used to * refer to the interpreter in later * "send" commands. Must be globally * unique. */ ) { int suffix, offset; RegisteredInterp *riPtr, *prevPtr; Tcl_DString dString; /* * See if the application is already registered; if so, remove its * current name from the registry. The deletion of the command * will take care of disposing of this entry. */ for (riPtr = interps, prevPtr = NULL; riPtr != NULL; prevPtr = riPtr, riPtr = riPtr->nextPtr) { if (riPtr->interp == interp) { if (name != NULL) { if (prevPtr == NULL) { interps = interps->nextPtr; } else { prevPtr->nextPtr = riPtr->nextPtr; } break; } else { /* * the name was NULL, so the caller is asking for * the name of the current interp. */ return riPtr->name; } } } if (name == NULL) { /* * the name was NULL, so the caller is asking for * the name of the current interp, but it doesn't * have a name. */ return ""; } /* * Pick a name to use for the application. Use "name" if it's not * already in use. Otherwise add a suffix such as " #2", trying * larger and larger numbers until we eventually find one that is * unique. */ suffix = 1; offset = 0; Tcl_DStringInit(&dString); /* * We have found a unique name. Now add it to the registry. */ riPtr = Blt_Malloc(sizeof(RegisteredInterp) + strlen(name)); riPtr->interp = interp; riPtr->nextPtr = interps; interps = riPtr; strcpy(riPtr->name, name); Tcl_CreateObjCommand(interp, "dde", DdeObjCmd, riPtr, DeleteProc); if (Tcl_IsSafe(interp)) { Tcl_HideCommand(interp, "dde", "dde"); } Tcl_DStringFree(&dString); /* * re-initialize with the new name */ Initialize(); return riPtr->name; } /* *-------------------------------------------------------------- * * DeleteProc * * This procedure is called when the command "dde" is destroyed. * * Results: * none * * Side effects: * The interpreter given by riPtr is unregistered. * *-------------------------------------------------------------- */ static void DeleteProc(clientData) ClientData clientData; /* The interp we are deleting passed * as ClientData. */ { RegisteredInterp *riPtr = clientData; RegisteredInterp *searchPtr, *prevPtr; for (searchPtr = interps, prevPtr = NULL; (searchPtr != NULL) && (searchPtr != riPtr); prevPtr = searchPtr, searchPtr = searchPtr->nextPtr) { /* * Empty loop body. */ } if (searchPtr != NULL) { if (prevPtr == NULL) { interps = interps->nextPtr; } else { prevPtr->nextPtr = searchPtr->nextPtr; } } Tcl_EventuallyFree(clientData, TCL_DYNAMIC); } /* *-------------------------------------------------------------- * * ExecuteRemoteObject -- * * Takes the package delivered by DDE and executes it in * the server's interpreter. * * Results: * A list Tcl_Obj * that describes what happened. The first * element is the numerical return code (TCL_ERROR, etc.). * The second element is the result of the script. If the * return result was TCL_ERROR, then the third element * will be the value of the global "errorCode", and the * fourth will be the value of the global "errorInfo". * The return result will have a refCount of 0. * * Side effects: * A Tcl script is run, which can cause all kinds of other * things to happen. * *-------------------------------------------------------------- */ static Tcl_Obj * ExecuteRemoteObject( Tcl_Interp *interp, /* Remote interpreter. */ Tcl_Obj *objPtr) /* The object to execute. */ { Tcl_Obj *listObjPtr; int result; result = Tcl_GlobalEval(interp, Tcl_GetString(objPtr)); listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); Tcl_ListObjAppendElement(NULL, listObjPtr, Tcl_NewIntObj(result)); Tcl_ListObjAppendElement(NULL, listObjPtr, Tcl_GetObjResult(interp)); if (result == TCL_ERROR) { char *value; Tcl_Obj *objPtr; value = Tcl_GetVar2(interp, "errorCode", NULL, TCL_GLOBAL_ONLY); objPtr = Tcl_NewStringObj(value, -1); Tcl_ListObjAppendElement(NULL, listObjPtr, objPtr); value = Tcl_GetVar2(interp, "errorInfo", NULL, TCL_GLOBAL_ONLY); objPtr = Tcl_NewStringObj(value, -1); Tcl_ListObjAppendElement(NULL, listObjPtr, objPtr); } return listObjPtr; } /* *-------------------------------------------------------------- * * ServerProc -- * * Handles all transactions for this server. Can handle * execute, request, and connect protocols. Dde will * call this routine when a client attempts to run a dde * command using this server. * * Results: * A DDE Handle with the result of the dde command. * * Side effects: * Depending on which command is executed, arbitrary * Tcl scripts can be run. * *-------------------------------------------------------------- */ static HDDEDATA CALLBACK ServerProc ( UINT uType, /* The type of DDE transaction we * are performing. */ UINT uFmt, /* The format that data is sent or * received. */ HCONV hConv, /* The conversation associated with the * current transaction. */ HSZ topic, /* A string handle. Transaction-type * dependent. */ HSZ item, /* A string handle. Transaction-type * dependent. */ HDDEDATA hData, /* DDE data. Transaction-type dependent. */ DWORD dwData1, /* Transaction-dependent data. */ DWORD dwData2) /* Transaction-dependent data. */ { Tcl_DString dString; char *utilString; Tcl_Obj *objPtr; HDDEDATA code = NULL; RegisteredInterp *riPtr; Conversation *convPtr, *prevConvPtr; switch(uType) { case XTYP_CONNECT: { int length; /* * Dde is trying to initialize a conversation with us. Check * and make sure we have a valid topic. */ length = DdeQueryString(instance, topic, NULL, 0, 0); Tcl_DStringInit(&dString); Tcl_DStringSetLength(&dString, length); utilString = Tcl_DStringValue(&dString); DdeQueryString(instance, topic, utilString, length + 1, CP_WINANSI); for (riPtr = interps; riPtr != NULL; riPtr = riPtr->nextPtr) { if (strcasecmp(utilString, riPtr->name) == 0) { Tcl_DStringFree(&dString); return (HDDEDATA) TRUE; } } Tcl_DStringFree(&dString); return (HDDEDATA) FALSE; } case XTYP_CONNECT_CONFIRM: { DWORD length; /* * Dde has decided that we can connect, so it gives us a * conversation handle. We need to keep track of it * so we know which execution result to return in an * XTYP_REQUEST. */ length = DdeQueryString(instance, topic, NULL, 0, 0); Tcl_DStringInit(&dString); Tcl_DStringSetLength(&dString, length); utilString = Tcl_DStringValue(&dString); DdeQueryString(instance, topic, utilString, length + 1, CP_WINANSI); for (riPtr = interps; riPtr != NULL; riPtr = riPtr->nextPtr) { if (strcasecmp(riPtr->name, utilString) == 0) { convPtr = Blt_Malloc(sizeof(Conversation)); convPtr->nextPtr = conversations; convPtr->returnPackagePtr = NULL; convPtr->hConv = hConv; convPtr->riPtr = riPtr; conversations = convPtr; break; } } Tcl_DStringFree(&dString); return (HDDEDATA) TRUE; } case XTYP_DISCONNECT: { /* * The client has disconnected from our server. Forget this * conversation. */ for (convPtr = conversations, prevConvPtr = NULL; convPtr != NULL; prevConvPtr = convPtr, convPtr = convPtr->nextPtr) { if (hConv == convPtr->hConv) { if (prevConvPtr == NULL) { conversations = convPtr->nextPtr; } else { prevConvPtr->nextPtr = convPtr->nextPtr; } if (convPtr->returnPackagePtr != NULL) { Tcl_DecrRefCount(convPtr->returnPackagePtr); } Blt_Free(convPtr); break; } } return (HDDEDATA) TRUE; } case XTYP_REQUEST: { int length; /* * This could be either a request for a value of a Tcl variable, * or it could be the send command requesting the results of the * last execute. */ if (uFmt != CF_TEXT) { return (HDDEDATA) FALSE; } code = (HDDEDATA) FALSE; for (convPtr = conversations; (convPtr != NULL) && (convPtr->hConv != hConv); convPtr = convPtr->nextPtr) { /* * Empty loop body. */ } if (convPtr != NULL) { length = DdeQueryString(instance, item, NULL, 0, CP_WINANSI); Tcl_DStringInit(&dString); Tcl_DStringSetLength(&dString, length); utilString = Tcl_DStringValue(&dString); DdeQueryString(instance, item, utilString, length + 1, CP_WINANSI); if (strcasecmp(utilString, "$TCLEVAL$EXECUTE$RESULT") == 0) { char *value; value = Tcl_GetStringFromObj(convPtr->returnPackagePtr, &length); code = DdeCreateDataHandle(instance, value, length+1, 0, item, CF_TEXT, 0); } else { char *value; value = Tcl_GetVar2(convPtr->riPtr->interp, utilString, NULL, TCL_GLOBAL_ONLY); if (value != NULL) { length = strlen(value); code = DdeCreateDataHandle(instance, value, length+1, 0, item, CF_TEXT, 0); } else { code = NULL; } } Tcl_DStringFree(&dString); } return code; } case XTYP_EXECUTE: { DWORD length; /* * Execute this script. The results will be saved into * a list object which will be retreived later. See * ExecuteRemoteObject. */ Tcl_Obj *returnPackagePtr; for (convPtr = conversations; (convPtr != NULL) && (convPtr->hConv != hConv); convPtr = convPtr->nextPtr) { /* * Empty loop body. */ } if (convPtr == NULL) { return (HDDEDATA) DDE_FNOTPROCESSED; } utilString = (char *) DdeAccessData(hData, &length); objPtr = Tcl_NewStringObj(utilString, -1); Tcl_IncrRefCount(objPtr); DdeUnaccessData(hData); if (convPtr->returnPackagePtr != NULL) { Tcl_DecrRefCount(convPtr->returnPackagePtr); } convPtr->returnPackagePtr = NULL; returnPackagePtr = ExecuteRemoteObject(convPtr->riPtr->interp, objPtr); for (convPtr = conversations; (convPtr != NULL) && (convPtr->hConv != hConv); convPtr = convPtr->nextPtr) { /* * Empty loop body. */ } if (convPtr != NULL) { Tcl_IncrRefCount(returnPackagePtr); convPtr->returnPackagePtr = returnPackagePtr; } Tcl_DecrRefCount(objPtr); if (returnPackagePtr == NULL) { return (HDDEDATA) DDE_FNOTPROCESSED; } else { return (HDDEDATA) DDE_FACK; } } case XTYP_WILDCONNECT: { DWORD length; /* * Dde wants a list of services and topics that we support. */ HSZPAIR *returnPtr; int i; int numItems; for (i = 0, riPtr = interps; riPtr != NULL; i++, riPtr = riPtr->nextPtr) { /* * Empty loop body. */ } numItems = i; code = DdeCreateDataHandle(instance, NULL, (numItems + 1) * sizeof(HSZPAIR), 0, 0, 0, 0); returnPtr = (HSZPAIR *) DdeAccessData(code, &length); for (i = 0, riPtr = interps; i < numItems; i++, riPtr = riPtr->nextPtr) { returnPtr[i].hszSvc = DdeCreateStringHandle( instance, "TclEval", CP_WINANSI); returnPtr[i].hszTopic = DdeCreateStringHandle( instance, riPtr->name, CP_WINANSI); } returnPtr[i].hszSvc = NULL; returnPtr[i].hszTopic = NULL; DdeUnaccessData(code); return code; } } return NULL; } /* *-------------------------------------------------------------- * * ExitProc -- * * Gets rid of our DDE server when we go away. * * Results: * None. * * Side effects: * The DDE server is deleted. * *-------------------------------------------------------------- */ static void ExitProc( ClientData clientData) /* Not used in this handler. */ { DdeNameService(instance, NULL, 0, DNS_UNREGISTER); DdeUninitialize(instance); instance = 0; } /* *-------------------------------------------------------------- * * MakeConnection -- * * This procedure is a utility used to connect to a DDE * server when given a server name and a topic name. * * Results: * A standard Tcl result. * * * Side effects: * Passes back a conversation through ddeConvPtr * *-------------------------------------------------------------- */ static int MakeConnection( Tcl_Interp *interp, /* Used to report errors. */ char *name, /* The connection to use. */ HCONV *convPtr) { HSZ topic, service; HCONV conv; service = DdeCreateStringHandle(instance, "TclEval", 0); topic = DdeCreateStringHandle(instance, name, 0); conv = DdeConnect(instance, service, topic, NULL); DdeFreeStringHandle(instance, service); DdeFreeStringHandle(instance, topic); if (conv == NULL) { if (interp != NULL) { Tcl_AppendResult(interp, "no registered server named \"", name, "\"", (char *) NULL); } return TCL_ERROR; } *convPtr = conv; return TCL_OK; } /* *-------------------------------------------------------------- * * SetError -- * * Sets the interp result to a cogent error message * describing the last DDE error. * * Results: * None. * * * Side effects: * The interp's result object is changed. * *-------------------------------------------------------------- */ static void SetError( Tcl_Interp *interp) /* The interp to put the message in.*/ { int err; char *mesg; err = DdeGetLastError(instance); switch (err) { case DMLERR_DATAACKTIMEOUT: case DMLERR_EXECACKTIMEOUT: case DMLERR_POKEACKTIMEOUT: mesg = "remote interpreter did not respond"; break; case DMLERR_BUSY: mesg = "remote server is busy"; break; case DMLERR_NOTPROCESSED: mesg = "remote server cannot handle this command"; break; default: mesg = "dde command failed"; break; } Tcl_SetResult(interp, mesg, TCL_VOLATILE); } /* *-------------------------------------------------------------- * * DdeObjCmd -- * * This procedure is invoked to process the "dde" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ static int DdeObjCmd( ClientData clientData, /* Used only for deletion */ Tcl_Interp *interp, /* The interp we are sending from */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[]) /* The arguments */ { enum { DDE_SERVERNAME, DDE_EXECUTE, DDE_POKE, DDE_REQUEST, DDE_SERVICES, DDE_EVAL }; static char *commands[] = { "servername", "execute", "poke", "request", "services", "eval", (char *) NULL }; static char *options[] = { "-async", (char *) NULL }; int index, argIndex; int async = 0, binary = 0; int result = TCL_OK; HSZ service = NULL; HSZ topic = NULL; HSZ item = NULL; HDDEDATA data = NULL; HDDEDATA itemData = NULL; HCONV hConv = NULL; HSZ cookie = 0; char *serviceName, *topicName, *itemString, *dataString; char *string; int firstArg, length, dataLength; HDDEDATA code; RegisteredInterp *riPtr; Tcl_Interp *sendInterp; Tcl_Obj *objPtr; /* * Initialize DDE server/client */ if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "?-async? serviceName topicName value"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], commands, "command", 0, &index) != TCL_OK) { return TCL_ERROR; } serviceName = NULL; /* Suppress compiler warning. */ firstArg = 1; switch (index) { case DDE_SERVERNAME: if ((objc != 3) && (objc != 2)) { Tcl_WrongNumArgs(interp, 1, objv, "servername ?serverName?"); return TCL_ERROR; } firstArg = (objc - 1); break; case DDE_EXECUTE: if ((objc < 5) || (objc > 6)) { Tcl_WrongNumArgs(interp, 1, objv, "execute ?-async? serviceName topicName value"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(NULL, objv[2], options, "option", 0, &argIndex) != TCL_OK) { if (objc != 5) { Tcl_WrongNumArgs(interp, 1, objv, "execute ?-async? serviceName topicName value"); return TCL_ERROR; } async = 0; firstArg = 2; } else { if (objc != 6) { Tcl_WrongNumArgs(interp, 1, objv, "execute ?-async? serviceName topicName value"); return TCL_ERROR; } async = 1; firstArg = 3; } break; case DDE_POKE: if (objc != 6) { Tcl_WrongNumArgs(interp, 1, objv, "poke serviceName topicName item value"); return TCL_ERROR; } firstArg = 2; break; case DDE_REQUEST: if (objc != 5) { Tcl_WrongNumArgs(interp, 1, objv, "request serviceName topicName value"); return TCL_ERROR; } binary = 0; firstArg = 2; break; case DDE_SERVICES: if (objc != 4) { Tcl_WrongNumArgs(interp, 1, objv, "services serviceName topicName"); return TCL_ERROR; } firstArg = 2; break; case DDE_EVAL: if (objc < 4) { Tcl_WrongNumArgs(interp, 1, objv, "eval ?-async? serviceName args"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(NULL, objv[2], options, "option", 0, &argIndex) != TCL_OK) { if (objc < 4) { Tcl_WrongNumArgs(interp, 1, objv, "eval ?-async? serviceName args"); return TCL_ERROR; } async = 0; firstArg = 2; } else { if (objc < 5) { Tcl_WrongNumArgs(interp, 1, objv, "eval ?-async? serviceName args"); return TCL_ERROR; } async = 1; firstArg = 3; } break; } Initialize(); if (firstArg != 1) { serviceName = Tcl_GetStringFromObj(objv[firstArg], &length); } else { length = 0; } if (length == 0) { serviceName = NULL; } else if ((index != DDE_SERVERNAME) && (index != DDE_EVAL)) { service = DdeCreateStringHandle(instance, serviceName, CP_WINANSI); } if ((index != DDE_SERVERNAME) &&(index != DDE_EVAL)) { topicName = Tcl_GetStringFromObj(objv[firstArg + 1], &length); if (length == 0) { topicName = NULL; } else { topic = DdeCreateStringHandle(instance, topicName, CP_WINANSI); } } switch (index) { case DDE_SERVERNAME: serviceName = SetServerName(interp, serviceName); if (serviceName != NULL) { Tcl_SetStringObj(Tcl_GetObjResult(interp), serviceName, -1); } else { Tcl_ResetResult(interp); } break; case DDE_EXECUTE: { dataString = Tcl_GetStringFromObj(objv[firstArg + 2], &dataLength); if (dataLength == 0) { Tcl_SetStringObj(Tcl_GetObjResult(interp), "cannot execute null data", -1); result = TCL_ERROR; break; } hConv = DdeConnect(instance, service, topic, NULL); DdeFreeStringHandle(instance, service); DdeFreeStringHandle(instance, topic); if (hConv == NULL) { SetError(interp); result = TCL_ERROR; break; } data = DdeCreateDataHandle(instance, dataString, dataLength + 1, 0, 0, CF_TEXT, 0); if (data != NULL) { if (async) { DWORD status; DdeClientTransaction((LPBYTE) data, 0xFFFFFFFF, hConv, 0, CF_TEXT, XTYP_EXECUTE, TIMEOUT_ASYNC, &status); DdeAbandonTransaction(instance, hConv, status); } else { code = DdeClientTransaction((LPBYTE) data, 0xFFFFFFFF, hConv, 0, CF_TEXT, XTYP_EXECUTE, 30000, NULL); if (code == 0) { SetError(interp); result = TCL_ERROR; } } DdeFreeDataHandle(data); } else { SetError(interp); result = TCL_ERROR; } break; } case DDE_REQUEST: { itemString = Tcl_GetStringFromObj(objv[firstArg + 2], &length); if (length == 0) { Tcl_SetStringObj(Tcl_GetObjResult(interp), "cannot request value of null data", -1); return TCL_ERROR; } hConv = DdeConnect(instance, service, topic, NULL); DdeFreeStringHandle(instance, service); DdeFreeStringHandle(instance, topic); if (hConv == NULL) { SetError(interp); result = TCL_ERROR; } else { item = DdeCreateStringHandle(instance, itemString, CP_WINANSI); if (item != NULL) { data = DdeClientTransaction(NULL, 0, hConv, item, CF_TEXT, XTYP_REQUEST, 5000, NULL); if (data == NULL) { SetError(interp); result = TCL_ERROR; } else { Tcl_Obj *objPtr; DWORD dataLength; dataString = DdeAccessData(data, &dataLength); objPtr = Tcl_NewStringObj(dataString, -1); DdeUnaccessData(data); DdeFreeDataHandle(data); Tcl_SetObjResult(interp, objPtr); } } else { SetError(interp); result = TCL_ERROR; } } break; } case DDE_POKE: { itemString = Tcl_GetStringFromObj(objv[firstArg + 2], &length); if (length == 0) { Tcl_SetStringObj(Tcl_GetObjResult(interp), "cannot have a null item", -1); return TCL_ERROR; } dataString = Tcl_GetStringFromObj(objv[firstArg + 3], &length); hConv = DdeConnect(instance, service, topic, NULL); DdeFreeStringHandle(instance, service); DdeFreeStringHandle(instance, topic); if (hConv == NULL) { SetError(interp); result = TCL_ERROR; } else { item = DdeCreateStringHandle(instance, itemString, CP_WINANSI); if (item != NULL) { data = DdeClientTransaction(dataString,length+1, hConv, item, CF_TEXT, XTYP_POKE, 5000, NULL); if (data == NULL) { SetError(interp); result = TCL_ERROR; } } else { SetError(interp); result = TCL_ERROR; } } break; } case DDE_SERVICES: { HCONVLIST hConvList; CONVINFO convInfo; Tcl_Obj *convListObjPtr, *elementObjPtr; Tcl_DString dString; char *name; convInfo.cb = sizeof(CONVINFO); hConvList = DdeConnectList(instance, service, topic, 0, NULL); DdeFreeStringHandle(instance, service); DdeFreeStringHandle(instance, topic); hConv = 0; convListObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); Tcl_DStringInit(&dString); while (hConv = DdeQueryNextServer(hConvList, hConv), hConv != 0) { elementObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); DdeQueryConvInfo(hConv, QID_SYNC, &convInfo); length = DdeQueryString(instance, convInfo.hszSvcPartner, NULL, 0, CP_WINANSI); Tcl_DStringSetLength(&dString, length); name = Tcl_DStringValue(&dString); DdeQueryString(instance, convInfo.hszSvcPartner, name, length + 1, CP_WINANSI); Tcl_ListObjAppendElement(interp, elementObjPtr, Tcl_NewStringObj(name, length)); length = DdeQueryString(instance, convInfo.hszTopic, NULL, 0, CP_WINANSI); Tcl_DStringSetLength(&dString, length); name = Tcl_DStringValue(&dString); DdeQueryString(instance, convInfo.hszTopic, name, length + 1, CP_WINANSI); Tcl_ListObjAppendElement(interp, elementObjPtr, Tcl_NewStringObj(name, length)); Tcl_ListObjAppendElement(interp, convListObjPtr, elementObjPtr); } DdeDisconnectList(hConvList); Tcl_SetObjResult(interp, convListObjPtr); Tcl_DStringFree(&dString); break; } case DDE_EVAL: { objc -= (async + 3); ((Tcl_Obj **) objv) += (async + 3); /* * See if the target interpreter is local. If so, execute * the command directly without going through the DDE * server. Don't exchange objects between interps. The * target interp could compile an object, producing a * bytecode structure that refers to other objects owned * by the target interp. If the target interp is then * deleted, the bytecode structure would be referring to * deallocated objects. */ for (riPtr = interps; riPtr != NULL; riPtr = riPtr->nextPtr) { if (strcasecmp(serviceName, riPtr->name) == 0) { break; } } if (riPtr != NULL) { /* * This command is to a local interp. No need to go through * the server. */ Tcl_Preserve(riPtr); sendInterp = riPtr->interp; Tcl_Preserve(sendInterp); /* * Don't exchange objects between interps. The target interp * would compile an object, producing a bytecode structure that * refers to other objects owned by the target interp. If the * target interp is then deleted, the bytecode structure would * be referring to deallocated objects. */ if (objc == 1) { result = Tcl_GlobalEval(sendInterp,Tcl_GetString(objv[0])); } else { objPtr = Tcl_ConcatObj(objc, objv); Tcl_IncrRefCount(objPtr); result = Tcl_GlobalEval(sendInterp, Tcl_GetString(objPtr)); Tcl_DecrRefCount(objPtr); } if (interp != sendInterp) { if (result == TCL_ERROR) { char *value; /* * An error occurred, so transfer error information * from the destination interpreter back to our * interpreter. */ Tcl_ResetResult(interp); value = Tcl_GetVar2(sendInterp, "errorInfo", NULL, TCL_GLOBAL_ONLY); Tcl_AddObjErrorInfo(interp, value, length); value = Tcl_GetVar2(sendInterp, "errorCode", NULL, TCL_GLOBAL_ONLY); Tcl_SetErrorCode(interp, value, (char *)NULL); } Tcl_SetObjResult(interp, Tcl_GetObjResult(sendInterp)); } Tcl_Release(riPtr); Tcl_Release(sendInterp); } else { /* * This is a non-local request. Send the script to the server * and poll it for a result. */ if (MakeConnection(interp, serviceName, &hConv) != TCL_OK) { goto error; } objPtr = Tcl_ConcatObj(objc, objv); string = Tcl_GetStringFromObj(objPtr, &length); itemData = DdeCreateDataHandle(instance, string, length+1, 0, 0, CF_TEXT, 0); if (async) { DWORD status; data = DdeClientTransaction((LPBYTE) itemData, 0xFFFFFFFF, hConv, 0, CF_TEXT, XTYP_EXECUTE, TIMEOUT_ASYNC, &status); DdeAbandonTransaction(instance, hConv, status); } else { data = DdeClientTransaction((LPBYTE) itemData, 0xFFFFFFFF, hConv, 0, CF_TEXT, XTYP_EXECUTE, 30000, NULL); if (data != 0) { cookie = DdeCreateStringHandle(instance, "$TCLEVAL$EXECUTE$RESULT", CP_WINANSI); data = DdeClientTransaction(NULL, 0, hConv, cookie, CF_TEXT, XTYP_REQUEST, 30000, NULL); } } Tcl_DecrRefCount(objPtr); if (data == 0) { SetError(interp); goto errorNoResult; } if (async == 0) { Tcl_Obj *resultPtr; /* * The return handle has a two or four element list in * it. The first element is the return code (TCL_OK, * TCL_ERROR, etc.). The second is the result of the * script. If the return code is TCL_ERROR, then the third * element is the value of the variable "errorCode", and * the fourth is the value of the variable "errorInfo". */ resultPtr = Tcl_NewObj(); length = DdeGetData(data, NULL, 0, 0); Tcl_SetObjLength(resultPtr, length); string = Tcl_GetString(resultPtr); DdeGetData(data, string, length, 0); Tcl_SetObjLength(resultPtr, strlen(string)); if (Tcl_ListObjIndex(NULL, resultPtr, 0, &objPtr) != TCL_OK) { Tcl_DecrRefCount(resultPtr); goto error; } if (Tcl_GetIntFromObj(NULL, objPtr, &result) != TCL_OK) { Tcl_DecrRefCount(resultPtr); goto error; } if (result == TCL_ERROR) { Tcl_ResetResult(interp); if (Tcl_ListObjIndex(NULL, resultPtr, 3, &objPtr) != TCL_OK) { Tcl_DecrRefCount(resultPtr); goto error; } length = -1; string = Tcl_GetStringFromObj(objPtr, &length); Tcl_AddObjErrorInfo(interp, string, length); Tcl_ListObjIndex(NULL, resultPtr, 2, &objPtr); Tcl_SetObjErrorCode(interp, objPtr); } if (Tcl_ListObjIndex(NULL, resultPtr, 1, &objPtr) != TCL_OK) { Tcl_DecrRefCount(resultPtr); goto error; } Tcl_SetObjResult(interp, objPtr); Tcl_DecrRefCount(resultPtr); } } } } if (cookie != NULL) { DdeFreeStringHandle(instance, cookie); } if (item != NULL) { DdeFreeStringHandle(instance, item); } if (itemData != NULL) { DdeFreeDataHandle(itemData); } if (data != NULL) { DdeFreeDataHandle(data); } if (hConv != NULL) { DdeDisconnect(hConv); } return result; error: Tcl_SetStringObj(Tcl_GetObjResult(interp), "invalid data returned from server", -1); errorNoResult: if (cookie != NULL) { DdeFreeStringHandle(instance, cookie); } if (item != NULL) { DdeFreeStringHandle(instance, item); } if (itemData != NULL) { DdeFreeDataHandle(itemData); } if (data != NULL) { DdeFreeDataHandle(data); } if (hConv != NULL) { DdeDisconnect(hConv); } return TCL_ERROR; } /* *---------------------------------------------------------------------- * * Blt_DdeInit -- * * This procedure initializes the dde command. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Blt_DdeInit(interp) Tcl_Interp *interp; { Tcl_CreateObjCommand(interp, "dde", DdeObjCmd, NULL, NULL); conversations = NULL; interps = NULL; Tcl_CreateExitHandler(ExitProc, NULL); return Tcl_PkgProvide(interp, TCL_DDE_PACKAGE_NAME, TCL_DDE_VERSION); } #endif /* NO_DDE */ blt-2.4z.orig/src/bltWinDraw.c0100644000175000017500000021364107536461660015000 0ustar dokodoko/* * bltWinDraw.c -- * * This module contains WIN32 routines not included in the Tcl/Tk * libraries. * * Copyright 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. */ #include #include #include #define WINDEBUG 0 /* * Data structure for setting graphics context. */ typedef struct { int function; /* logical operation */ unsigned long plane_mask; /* plane mask */ unsigned long foreground; /* foreground pixel */ unsigned long background; /* background pixel */ int line_width; /* line width */ int line_style; /* LineSolid, LineOnOffDash, LineDoubleDash */ int cap_style; /* CapNotLast, CapButt, CapRound, CapProjecting */ int join_style; /* JoinMiter, JoinRound, JoinBevel */ int fill_style; /* FillSolid, FillTiled, FillStippled, FillOpaeueStippled */ int fill_rule; /* EvenOddRule, WindingRule */ int arc_mode; /* ArcChord, ArcPieSlice */ Pixmap tile; /* tile pixmap for tiling operations */ Pixmap stipple; /* stipple 1 plane pixmap for stipping */ int ts_x_origin; /* offset for tile or stipple operations */ int ts_y_origin; Font font; /* default text font for text operations */ int subwindow_mode; /* ClipByChildren, IncludeInferiors */ Bool graphics_exposures; /* boolean, should exposures be generated */ int clip_x_origin; /* origin for clipping */ int clip_y_origin; Pixmap clip_mask; /* bitmap clipping; other calls for rects */ int dash_offset; /* patterned/dashed line information */ char dashes; /* If -1, indicates that the extended * information below is available. */ int nDashValues; char dashValues[12]; } XGCValuesEx; static int tkpWinRopModes[] = { R2_BLACK, /* GXclear */ R2_MASKPEN, /* GXand */ R2_MASKPENNOT, /* GXandReverse */ R2_COPYPEN, /* GXcopy */ R2_MASKNOTPEN, /* GXandInverted */ R2_NOT, /* GXnoop */ R2_XORPEN, /* GXxor */ R2_MERGEPEN, /* GXor */ R2_NOTMERGEPEN, /* GXnor */ R2_NOTXORPEN, /* GXequiv */ R2_NOT, /* GXinvert */ R2_MERGEPENNOT, /* GXorReverse */ R2_NOTCOPYPEN, /* GXcopyInverted */ R2_MERGENOTPEN, /* GXorInverted */ R2_NOTMASKPEN, /* GXnand */ R2_WHITE /* GXset */ }; #define MASKPAT 0x00E20746 /* dest = (src & pat) | (!src & dst) */ #define COPYFG 0x00CA0749 /* dest = (pat & src) | (!pat & dst) */ #define COPYBG 0x00AC0744 /* dest = (!pat & src) | (pat & dst) */ /* * Translation table between X gc functions and Win32 BitBlt op modes. Some * of the operations defined in X don't have names, so we have to construct * new opcodes for those functions. This is arcane and probably not all that * useful, but at least it's accurate. */ #define NOTSRCAND (DWORD)0x00220326 /* dest = (NOT src) AND dest */ #define NOTSRCINVERT (DWORD)0x00990066 /* dest = (NOT src) XOR dest */ #define SRCORREVERSE (DWORD)0x00DD0228 /* dest = src OR (NOT dest) */ #define SRCNAND (DWORD)0x007700E6 /* dest = NOT (src AND dest) */ static int bltModes[] = { BLACKNESS, /* GXclear */ SRCAND, /* GXand */ SRCERASE, /* GXandReverse */ SRCCOPY, /* GXcopy */ NOTSRCAND, /* GXandInverted */ PATCOPY, /* GXnoop */ SRCINVERT, /* GXxor */ SRCPAINT, /* GXor */ NOTSRCERASE, /* GXnor */ NOTSRCINVERT, /* GXequiv */ DSTINVERT, /* GXinvert */ SRCORREVERSE, /* GXorReverse */ NOTSRCCOPY, /* GXcopyInverted */ MERGEPAINT, /* GXorInverted */ SRCNAND, /* GXnand */ WHITENESS /* GXset */ }; #if (TCL_VERSION_NUMBER < _VERSION(8,1,0)) typedef void *Tcl_Encoding; /* Make up dummy type for encoding. */ #else static Tcl_Encoding systemEncoding = NULL; #endif HPALETTE Blt_GetSystemPalette(void) { HDC hDC; HPALETTE hPalette; DWORD flags; hPalette = NULL; hDC = GetDC(NULL); /* Get the desktop device context */ flags = GetDeviceCaps(hDC, RASTERCAPS); if (flags & RC_PALETTE) { LOGPALETTE *palettePtr; palettePtr = (LOGPALETTE *) GlobalAlloc(GPTR, sizeof(LOGPALETTE) + 256 * sizeof(PALETTEENTRY)); palettePtr->palVersion = 0x300; palettePtr->palNumEntries = 256; GetSystemPaletteEntries(hDC, 0, 256, palettePtr->palPalEntry); hPalette = CreatePalette(palettePtr); GlobalFree(palettePtr); } ReleaseDC(NULL, hDC); return hPalette; } /* *---------------------------------------------------------------------- * * CreateRotatedFont -- * * Creates a rotated copy of the given font. This only works * for TrueType fonts. * * Results: * Returns the newly create font or NULL if the font could not * be created. * *---------------------------------------------------------------------- */ HFONT CreateRotatedFont( unsigned long fontId, /* Font identifier (actually a Tk_Font) */ double theta) { /* Number of degrees to rotate font */ TkFontAttributes *faPtr; /* Set of attributes to match. */ TkFont *fontPtr; HFONT hFont; LOGFONTW lf; fontPtr = (TkFont *) fontId; faPtr = &fontPtr->fa; ZeroMemory(&lf, sizeof(LOGFONT)); lf.lfHeight = -faPtr->pointsize; if (lf.lfHeight < 0) { HDC dc; dc = GetDC(NULL); lf.lfHeight = -MulDiv(faPtr->pointsize, GetDeviceCaps(dc, LOGPIXELSY), 72); ReleaseDC(NULL, dc); } lf.lfWidth = 0; lf.lfEscapement = lf.lfOrientation = ROUND(theta * 10.0); #define TK_FW_NORMAL 0 lf.lfWeight = (faPtr->weight == TK_FW_NORMAL) ? FW_NORMAL : FW_BOLD; lf.lfItalic = faPtr->slant; lf.lfUnderline = faPtr->underline; lf.lfStrikeOut = faPtr->overstrike; lf.lfCharSet = DEFAULT_CHARSET; lf.lfOutPrecision = OUT_TT_ONLY_PRECIS; lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; lf.lfQuality = DEFAULT_QUALITY; lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; hFont = NULL; if (faPtr->family == NULL) { lf.lfFaceName[0] = '\0'; } else { #if (TCL_VERSION_NUMBER >= _VERSION(8,1,0)) Tcl_DString dString; Tcl_UtfToExternalDString(systemEncoding, faPtr->family, -1, &dString); if (Blt_GetPlatformId() == VER_PLATFORM_WIN32_NT) { Tcl_UniChar *src, *dst; /* * We can only store up to LF_FACESIZE wide characters */ if (Tcl_DStringLength(&dString) >= (LF_FACESIZE * sizeof(WCHAR))) { Tcl_DStringSetLength(&dString, LF_FACESIZE); } src = (Tcl_UniChar *)Tcl_DStringValue(&dString); dst = (Tcl_UniChar *)lf.lfFaceName; while (*src != '\0') { *dst++ = *src++; } *dst = '\0'; hFont = CreateFontIndirectW((LOGFONTW *)&lf); } else { /* * We can only store up to LF_FACESIZE characters */ if (Tcl_DStringLength(&dString) >= LF_FACESIZE) { Tcl_DStringSetLength(&dString, LF_FACESIZE); } strcpy((char *)lf.lfFaceName, Tcl_DStringValue(&dString)); hFont = CreateFontIndirectA((LOGFONTA *)&lf); } Tcl_DStringFree(&dString); #else strncpy((char *)lf.lfFaceName, faPtr->family, LF_FACESIZE - 1); lf.lfFaceName[LF_FACESIZE] = '\0'; #endif /* TCL_VERSION_NUMBER >= 8.1.0 */ } if (hFont == NULL) { #if WINDEBUG PurifyPrintf("can't create font: %s\n", Blt_LastError()); #endif } else { HFONT oldFont; TEXTMETRIC tm; HDC hRefDC; int result; /* Check if the rotated font is really a TrueType font. */ hRefDC = GetDC(NULL); /* Get the desktop device context */ oldFont = SelectFont(hRefDC, hFont); result = ((GetTextMetrics(hRefDC, &tm)) && (tm.tmPitchAndFamily & TMPF_TRUETYPE)); SelectFont(hRefDC, oldFont); ReleaseDC(NULL, hRefDC); if (!result) { #if WINDEBUG PurifyPrintf("not a true type font\n"); #endif DeleteFont(hFont); return NULL; } } return hFont; } /* *---------------------------------------------------------------------- * * Blt_GetBitmapData -- * * Returns the DIB bits from a bitmap. * * Results: * Returns a byte array of bitmap data or NULL if an error * occurred. The parameter pitchPtr returns the number * of bytes per row. * *---------------------------------------------------------------------- */ unsigned char * Blt_GetBitmapData( Display *display, /* Display of bitmap */ Pixmap bitmap, /* Bitmap to query */ int width, /* Width of bitmap */ int height, /* Height of bitmap */ int *pitchPtr) /* (out) Number of bytes per row */ { TkWinDCState state; HDC dc; int result; unsigned char *bits; unsigned int size; HBITMAP hBitmap; BITMAPINFOHEADER *bmiPtr; HANDLE hMem, hMem2; int bytesPerRow, imageSize; size = sizeof(BITMAPINFOHEADER) + 2 * sizeof(RGBQUAD); hMem = GlobalAlloc(GHND, size); bmiPtr = (BITMAPINFOHEADER *)GlobalLock(hMem); bmiPtr->biSize = sizeof(BITMAPINFOHEADER); bmiPtr->biPlanes = 1; bmiPtr->biBitCount = 1; bmiPtr->biCompression = BI_RGB; bmiPtr->biWidth = width; bmiPtr->biHeight = height; hBitmap = ((TkWinDrawable *)bitmap)->bitmap.handle; dc = TkWinGetDrawableDC(display, bitmap, &state); result = GetDIBits(dc, hBitmap, 0, height, (LPVOID)NULL, (BITMAPINFO *)bmiPtr, DIB_RGB_COLORS); TkWinReleaseDrawableDC(bitmap, dc, &state); if (!result) { GlobalUnlock(hMem); GlobalFree(hMem); return NULL; } imageSize = bmiPtr->biSizeImage; GlobalUnlock(hMem); bytesPerRow = ((width + 31) & ~31) / 8; if (imageSize == 0) { imageSize = bytesPerRow * height; } hMem2 = GlobalReAlloc(hMem, size + imageSize, 0); if (hMem2 == NULL) { GlobalFree(hMem); return NULL; } hMem = hMem2; bmiPtr = (LPBITMAPINFOHEADER)GlobalLock(hMem); dc = TkWinGetDrawableDC(display, bitmap, &state); result = GetDIBits(dc, hBitmap, 0, height, (unsigned char *)bmiPtr + size, (BITMAPINFO *)bmiPtr, DIB_RGB_COLORS); TkWinReleaseDrawableDC(bitmap, dc, &state); bits = NULL; if (!result) { OutputDebugString("GetDIBits failed\n"); } else { bits = Blt_Malloc(imageSize); if (bits != NULL) { memcpy (bits, (unsigned char *)bmiPtr + size, imageSize); } } *pitchPtr = bytesPerRow; GlobalUnlock(hMem); GlobalFree(hMem); return bits; } /* *---------------------------------------------------------------------- * * XFree -- * *---------------------------------------------------------------------- */ void Blt_EmulateXFree(void *ptr) { Blt_Free(ptr); } /* *---------------------------------------------------------------------- * * XMaxRequestSize -- * *---------------------------------------------------------------------- */ long Blt_EmulateXMaxRequestSize(Display *display) { return (SHRT_MAX / 4); } /* *---------------------------------------------------------------------- * * XLowerWindow -- * *---------------------------------------------------------------------- */ void Blt_EmulateXLowerWindow( Display *display, Window window) { HWND hWnd; hWnd = Tk_GetHWND(window); display->request++; SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); } /* *---------------------------------------------------------------------- * * XRaiseWindow -- * *---------------------------------------------------------------------- */ void Blt_EmulateXRaiseWindow( Display *display, Window window) { HWND hWnd; hWnd = Tk_GetHWND(window); display->request++; SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); } /* *---------------------------------------------------------------------- * * XUnmapWindow -- * *---------------------------------------------------------------------- */ void Blt_EmulateXUnmapWindow( Display *display, Window window) { HWND hWnd; hWnd = Tk_GetHWND(window); display->request++; ShowWindow(hWnd, SW_HIDE); /* SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); */ } /* *---------------------------------------------------------------------- * * XWarpPointer -- * * If destWindow is None, moves the pointer by the offsets (destX, * destY) relative to the current position of the pointer. * If destWindow is a window, moves the pointer to the offsets * (destX, destY) relative to the origin of destWindow. However, * if srcWindow is a window, the move only takes place if the window * srcWindow contains the pointer and if the specified rectangle of * srcWindow contains the pointer. * * The srcX and srcY coordinates are relative to the origin of * srcWindow. If srcHeight is zero, it is replaced with the current * height of srcWindow minus srcY. If srcWidth is zero, it is * replaced with the current width of srcWindow minus srcX. * *---------------------------------------------------------------------- */ void Blt_EmulateXWarpPointer( Display *display, Window srcWindow, Window destWindow, int srcX, int srcY, unsigned int srcWidth, unsigned int srcHeight, int destX, int destY) { HWND hWnd; POINT point; hWnd = Tk_GetHWND(destWindow); point.x = destX, point.y = destY; if (ClientToScreen(hWnd, &point)) { SetCursorPos(point.x, point.y); } } #ifdef notdef static Blt_HashTable gcTable; static int gcInitialized = FALSE; #endif typedef struct { HDC dc; int count; COLORREF color; int offset, nBits; } DashInfo; void Blt_SetDashes(Display *display, GC gc, Blt_Dashes *dashesPtr) { XGCValuesEx *gcPtr = (XGCValuesEx *)gc; /* This must be used only with a privately created GC */ assert((int)gcPtr->dashes == -1); gcPtr->nDashValues = strlen(dashesPtr->values); gcPtr->dash_offset = dashesPtr->offset; strcpy(gcPtr->dashValues, dashesPtr->values); } static int GetDashInfo( HDC dc, GC gc, DashInfo *infoPtr) { int dashOffset, dashValue; dashValue = 0; dashOffset = gc->dash_offset; if ((int)gc->dashes == -1) { XGCValuesEx *gcPtr = (XGCValuesEx *)gc; if (gcPtr->nDashValues == 1) { dashValue = gcPtr->dashValues[0]; } } else if (gc->dashes > 0) { dashValue = (int)gc->dashes; } if (dashValue == 0) { return FALSE; } infoPtr->dc = dc; infoPtr->nBits = dashValue; infoPtr->offset = dashOffset; infoPtr->count = 0; infoPtr->color = gc->foreground; return TRUE; } void Blt_SetROP2(HDC dc, int function) { SetROP2(dc, tkpWinRopModes[function]); } static XGCValuesEx * CreateGC() { XGCValuesEx *gcPtr; gcPtr = Blt_Malloc(sizeof(XGCValuesEx)); if (gcPtr == NULL) { return NULL; } gcPtr->arc_mode = ArcPieSlice; gcPtr->background = 0xffffff; gcPtr->cap_style = CapNotLast; gcPtr->clip_mask = None; gcPtr->clip_x_origin = gcPtr->clip_y_origin = 0; gcPtr->dash_offset = 0; gcPtr->fill_rule = WindingRule; gcPtr->fill_style = FillSolid; gcPtr->font = None; gcPtr->foreground = 0; gcPtr->function = GXcopy; gcPtr->graphics_exposures = True; gcPtr->join_style = JoinMiter; gcPtr->line_style = LineSolid; gcPtr->line_width = 0; gcPtr->plane_mask = ~0; gcPtr->stipple = None; gcPtr->subwindow_mode = ClipByChildren; gcPtr->tile = None; gcPtr->ts_x_origin = gcPtr->ts_y_origin = 0; gcPtr->dashes = -1; /* Mark that this an extended GC */ gcPtr->nDashValues = 0; return gcPtr; } /* *---------------------------------------------------------------------- * * Blt_EmulateXCreateGC -- * * Allocate a new extended GC, and initialize the specified fields. * * Results: * Returns a newly allocated GC. * * Side effects: * None. * *---------------------------------------------------------------------- */ GC Blt_EmulateXCreateGC( Display *display, Drawable drawable, unsigned long mask, XGCValues *srcPtr) { XGCValuesEx *destPtr; destPtr = CreateGC(); if (destPtr == NULL) { return None; } if (mask & GCFunction) { destPtr->function = srcPtr->function; } if (mask & GCPlaneMask) { destPtr->plane_mask = srcPtr->plane_mask; } if (mask & GCForeground) { destPtr->foreground = srcPtr->foreground; } if (mask & GCBackground) { destPtr->background = srcPtr->background; } if (mask & GCLineWidth) { destPtr->line_width = srcPtr->line_width; } if (mask & GCLineStyle) { destPtr->line_style = srcPtr->line_style; } if (mask & GCCapStyle) { destPtr->cap_style = srcPtr->cap_style; } if (mask & GCJoinStyle) { destPtr->join_style = srcPtr->join_style; } if (mask & GCFillStyle) { destPtr->fill_style = srcPtr->fill_style; } if (mask & GCFillRule) { destPtr->fill_rule = srcPtr->fill_rule; } if (mask & GCArcMode) { destPtr->arc_mode = srcPtr->arc_mode; } if (mask & GCTile) { destPtr->tile = srcPtr->tile; } if (mask & GCStipple) { destPtr->stipple = srcPtr->stipple; } if (mask & GCTileStipXOrigin) { destPtr->ts_x_origin = srcPtr->ts_x_origin; } if (mask & GCTileStipXOrigin) { destPtr->ts_y_origin = srcPtr->ts_y_origin; } if (mask & GCFont) { destPtr->font = srcPtr->font; } if (mask & GCSubwindowMode) { destPtr->subwindow_mode = srcPtr->subwindow_mode; } if (mask & GCGraphicsExposures) { destPtr->graphics_exposures = srcPtr->graphics_exposures; } if (mask & GCClipXOrigin) { destPtr->clip_x_origin = srcPtr->clip_x_origin; } if (mask & GCClipYOrigin) { destPtr->clip_y_origin = srcPtr->clip_y_origin; } if (mask & GCDashOffset) { destPtr->dash_offset = srcPtr->dash_offset; } if (mask & GCDashList) { destPtr->dashes = srcPtr->dashes; } if (mask & GCClipMask) { struct ClipMask { int type; /* TKP_CLIP_PIXMAP or TKP_CLIP_REGION */ Pixmap pixmap; } *clipPtr; clipPtr = Blt_Malloc(sizeof(struct ClipMask)); #define TKP_CLIP_PIXMAP 0 clipPtr->type = TKP_CLIP_PIXMAP; clipPtr->pixmap = srcPtr->clip_mask; destPtr->clip_mask = (Pixmap) clipPtr; } return (GC)destPtr; } /* *---------------------------------------------------------------------- * * Blt_GCToPen -- * * Set up the graphics port from the given GC. * * Geometric and cosmetic pens available under both 95 and NT. * Geometric pens differ from cosmetic pens in that they can * 1. Draw in world units (can have thick lines: line width > 1). * 2. Under NT, allow arbitrary line style. * 3. Can have caps and join (needed for thick lines). * 4. Draw very, very slowly. * * Cosmetic pens are single line width only. * * 95 98 NT * PS_SOLID c,g c,g c,g * PS_DASH c,g c,g c,g * PS_DOT c c c,g * PS_DASHDOT c - c,g * PS_DASHDOTDOT c - c,g * PS_USERSTYLE - - c,g * PS_ALTERNATE - - c * * Geometric only for 95/98 * * PS_ENDCAP_ROUND * PS_ENDCAP_SQUARE * PS_ENDCAP_FLAT * PS_JOIN_BEVEL * PS_JOIN_ROUND * PS_JOIN_MITER * * Results: * None. * * Side effects: * The current port is adjusted. * *---------------------------------------------------------------------- */ HPEN Blt_GCToPen(HDC dc, GC gc) { DWORD lineAttrs, lineStyle; DWORD dashArr[12]; DWORD *dashPtr; int nValues, lineWidth; LOGBRUSH lBrush; HPEN pen; nValues = 0; lineWidth = (gc->line_width < 1) ? 1 : gc->line_width; if ((gc->line_style == LineOnOffDash) || (gc->line_style == LineDoubleDash)) { XGCValuesEx *gcPtr = (XGCValuesEx *)gc; if ((int)gc->dashes == -1) { register int i; nValues = strlen(gcPtr->dashValues); for (i = 0; i < nValues; i++) { dashArr[i] = (DWORD)gcPtr->dashValues[i]; } if (nValues == 1) { dashArr[1] = dashArr[0]; nValues = 2; } } else { dashArr[1] = dashArr[0] = (DWORD) gc->dashes; nValues = 2; gc->dashes = -1; } } switch (nValues) { case 0: lineStyle = PS_SOLID; break; case 3: lineStyle = PS_DASHDOT; break; case 4: lineStyle = PS_DASHDOTDOT; break; case 2: default: /* PS_DASH style dash length is too long. */ lineStyle = PS_DOT; break; } lBrush.lbStyle = BS_SOLID; lBrush.lbColor = gc->foreground; lBrush.lbHatch = 0; /* Value is ignored when style is BS_SOLID. */ lineAttrs = 0; switch (gc->cap_style) { case CapNotLast: case CapButt: lineAttrs |= PS_ENDCAP_FLAT; break; case CapRound: lineAttrs |= PS_ENDCAP_ROUND; break; default: lineAttrs |= PS_ENDCAP_SQUARE; break; } switch (gc->join_style) { case JoinMiter: lineAttrs |= PS_JOIN_MITER; break; case JoinBevel: lineAttrs |= PS_JOIN_BEVEL; break; case JoinRound: default: lineAttrs |= PS_JOIN_ROUND; break; } SetBkMode(dc, TRANSPARENT); if (Blt_GetPlatformId() == VER_PLATFORM_WIN32_NT) { /* Windows NT/2000/XP. */ if (nValues > 0) { lineStyle = PS_USERSTYLE; dashPtr = dashArr; } else { dashPtr = NULL; } if (lineWidth > 1) { /* Limit the use of geometric pens to thick lines. */ pen = ExtCreatePen(PS_GEOMETRIC | lineAttrs | lineStyle, lineWidth, &lBrush, nValues, dashPtr); } else { /* Cosmetic pens are much faster. */ pen = ExtCreatePen(PS_COSMETIC | lineAttrs | lineStyle, 1, &lBrush, nValues, dashPtr); } } else { /* Windows 95/98. */ if ((lineStyle == PS_SOLID) && (lineWidth > 1)) { /* Use geometric pens with solid, thick lines only. */ pen = ExtCreatePen(PS_GEOMETRIC | lineAttrs | lineStyle, lineWidth, &lBrush, 0, NULL); } else { /* Otherwise sacrifice thick lines for dashes. */ pen = ExtCreatePen(PS_COSMETIC | lineStyle, 1, &lBrush, 0, NULL); } } assert(pen != NULL); return pen; } /* *---------------------------------------------------------------------- * * XDrawRectangles -- * * Draws the outlines of the specified rectangles as if a * five-point PolyLine protocol request were specified for each * rectangle: * * [x,y] [x+width,y] [x+width,y+height] [x,y+height] * [x,y] * * For the specified rectangles, these functions do not draw a * pixel more than once. XDrawRectangles draws the rectangles in * the order listed in the array. If rectangles intersect, the * intersecting pixels are drawn multiple times. Draws a * rectangle. * * Results: * None. * * Side effects: * Draws rectangles on the specified drawable. * *---------------------------------------------------------------------- */ void Blt_EmulateXDrawRectangles( Display *display, Drawable drawable, GC gc, XRectangle *rectArr, int nRects) { HPEN pen, oldPen; TkWinDCState state; HBRUSH brush, oldBrush; HDC dc; register XRectangle *rectPtr; register int i; if (drawable == None) { return; } dc = TkWinGetDrawableDC(display, drawable, &state); pen = Blt_GCToPen(dc, gc); brush = GetStockObject(NULL_BRUSH); oldPen = SelectPen(dc, pen); oldBrush = SelectBrush(dc, brush); SetROP2(dc, tkpWinRopModes[gc->function]); rectPtr = rectArr; for (i = 0; i < nRects; i++, rectPtr++) { Rectangle(dc, (int)rectPtr->x, (int)rectPtr->y, (int)(rectPtr->x + rectPtr->width + 1), (int)(rectPtr->y + rectPtr->height + 1)); } DeletePen(SelectPen(dc, oldPen)); DeleteBrush(SelectBrush(dc, oldBrush)); TkWinReleaseDrawableDC(drawable, dc, &state); } #ifdef notdef /* * Implements the "pixeling" of small arcs, because GDI-performance * for this is awful * was made especially for BLT, graph4 demo now runs 4x faster * */ /* O-outer , I-inner, B-both */ #define NEITHER_ 0 #define OUTLINE 1 #define FILL 2 #define BOTH (OUTLINE|FILL) #define MINIARCS 5 static int arcus0[1] = { BOTH }; static int arcus1[4] = { BOTH, BOTH, BOTH, BOTH }; static int arcus2[9] = { NEITHER, OUTLINE, NEITHER, OUTLINE, FILL, OUTLINE, NEITHER, OUTLINE, NEITHER }; static int arcus3[16] = { NEITHER, OUTLINE, OUTLINE, NEITHER, OUTLINE, FILL, FILL, OUTLINE, OUTLINE, FILL, FILL, OUTLINE, NEITHER, OUTLINE, OUTLINE, NEITHER }; static int arcus4[25] = { NEITHER, OUTLINE, OUTLINE, OUTLINE, NEITHER, OUTLINE, FILL, FILL, FILL, OUTLINE, OUTLINE, FILL, FILL, FILL, OUTLINE, OUTLINE, FILL, FILL, FILL, OUTLINE, NEITHER, OUTLINE, OUTLINE, OUTLINE, NEITHER }; static int *arcis[MINIARCS] = { arcus0, arcus1, arcus2, arcus3, arcus4 }; static void DrawMiniArc( HDC dc, int width, int x, int y, int mask, COLORREF inner, COLORREF outer) { int *arc; int i, j; if (width > MINIARCS) { return; } arc = arcis[width]; for (i = 0; i <= width; i++) { for (j = 0; j <= width; j++) { bit = (mask & *arc); if (bit & OUTLINE) { SetPixelV(dc, x + i, y + j, outer); } else if (bit & FILL) { SetPixelV(dc, x + i, y + j, inner); } arc++; } } } #endif /* *---------------------------------------------------------------------- * * DrawArc -- * * This procedure handles the rendering of drawn or filled * arcs and chords. * * Results: * None. * * Side effects: * Renders the requested arcs. * *---------------------------------------------------------------------- */ static void DrawArc( HDC dc, int arcMode, /* Mode: either ArcChord or ArcPieSlice */ XArc *arcPtr, HPEN pen, HBRUSH brush) { int start, extent, clockwise; int xstart, ystart, xend, yend; double radian_start, radian_end, xr, yr; double dx, dy; if ((arcPtr->angle1 == 0) && (arcPtr->angle2 == 23040)) { /* Handle special case of circle or ellipse */ Ellipse(dc, arcPtr->x, arcPtr->y, arcPtr->x + arcPtr->width + 1, arcPtr->y + arcPtr->height + 1); return; } start = arcPtr->angle1, extent = arcPtr->angle2; clockwise = (extent < 0); /* Non-zero if clockwise */ /* * Compute the absolute starting and ending angles in normalized radians. * Swap the start and end if drawing clockwise. */ start = start % (64 * 360); if (start < 0) { start += (64 * 360); } extent = (start + extent) % (64 * 360); if (extent < 0) { extent += (64 * 360); } if (clockwise) { int tmp = start; start = extent; extent = tmp; } #define XAngleToRadians(a) ((double)(a) / 64 * M_PI / 180); radian_start = XAngleToRadians(start); radian_end = XAngleToRadians(extent); /* * Now compute points on the radial lines that define the starting and * ending angles. Be sure to take into account that the y-coordinate * system is inverted. */ dx = arcPtr->width * 0.5; dy = arcPtr->height * 0.5; xr = arcPtr->x + dx; yr = arcPtr->y + dy; xstart = (int)((xr + cos(radian_start) * dx) + 0.5); ystart = (int)((yr + sin(-radian_start) * dy) + 0.5); xend = (int)((xr + cos(radian_end) * dx) + 0.5); yend = (int)((yr + sin(-radian_end) * dy) + 0.5); /* * Now draw a filled or open figure. Note that we have to * increase the size of the bounding box by one to account for the * difference in pixel definitions between X and Windows. */ if (brush == 0) { /* * Note that this call will leave a gap of one pixel at the * end of the arc for thin arcs. We can't use ArcTo because * it's only supported under Windows NT. */ Arc(dc, arcPtr->x, arcPtr->y, arcPtr->x + arcPtr->width + 1, arcPtr->y + arcPtr->height + 1, xstart, ystart, xend, yend); /* FIXME: */ } else { if (arcMode == ArcChord) { Chord(dc, arcPtr->x, arcPtr->y, arcPtr->x + arcPtr->width + 1, arcPtr->y + arcPtr->height + 1, xstart, ystart, xend, yend); } else if (arcMode == ArcPieSlice) { Pie(dc, arcPtr->x, arcPtr->y, arcPtr->x + arcPtr->width + 1, arcPtr->y + arcPtr->height + 1, xstart, ystart, xend, yend); } } } /* *---------------------------------------------------------------------- * * XDrawArcs -- * * Draws multiple circular or elliptical arcs. Each arc is * specified by a rectangle and two angles. The center of the * circle or ellipse is the center of the rect- angle, and the * major and minor axes are specified by the width and height. * Positive angles indicate counterclock- wise motion, and * negative angles indicate clockwise motion. If the magnitude * of angle2 is greater than 360 degrees, XDrawArcs truncates it * to 360 degrees. * * Results: * None. * * Side effects: * Draws an arc for each array element on the specified drawable. * *---------------------------------------------------------------------- */ void Blt_EmulateXDrawArcs( Display *display, Drawable drawable, GC gc, XArc *arcArr, int nArcs) { HPEN pen, oldPen; HBRUSH brush, oldBrush; HDC dc; TkWinDCState state; register XArc *arcPtr, *endPtr; display->request++; if (drawable == None) { return; } dc = TkWinGetDrawableDC(display, drawable, &state); SetROP2(dc, tkpWinRopModes[gc->function]); pen = Blt_GCToPen(dc, gc); oldPen = SelectPen(dc, pen); brush = GetStockBrush(NULL_BRUSH); oldBrush = SelectBrush(dc, brush); endPtr = arcArr + nArcs; for (arcPtr = arcArr; arcPtr < endPtr; arcPtr++) { DrawArc(dc, gc->arc_mode, arcPtr, pen, 0); } DeleteBrush(SelectBrush(dc, oldBrush)); DeletePen(SelectPen(dc, oldPen)); TkWinReleaseDrawableDC(drawable, dc, &state); } /* *---------------------------------------------------------------------- * * XFillArcs -- * * Draw a filled arc. * * Results: * None. * * Side effects: * Draws a filled arc for each array element on the specified drawable. * *---------------------------------------------------------------------- */ void Blt_EmulateXFillArcs( Display *display, Drawable drawable, GC gc, XArc *arcArr, int nArcs) { HBRUSH brush, oldBrush; HPEN pen, oldPen; HDC dc; register XArc *arcPtr, *endPtr; TkWinDCState state; display->request++; if (drawable == None) { return; } dc = TkWinGetDrawableDC(display, drawable, &state); SetROP2(dc, tkpWinRopModes[gc->function]); pen = Blt_GCToPen(dc, gc); oldPen = SelectPen(dc, pen); brush = CreateSolidBrush(gc->foreground); oldBrush = SelectBrush(dc, brush); endPtr = arcArr + nArcs; for (arcPtr = arcArr; arcPtr < endPtr; arcPtr++) { DrawArc(dc, gc->arc_mode, arcPtr, pen, brush); } DeleteBrush(SelectBrush(dc, oldBrush)); DeletePen(SelectPen(dc, oldPen)); TkWinReleaseDrawableDC(drawable, dc, &state); } /* *---------------------------------------------------------------------- * * XDrawLines -- * * Draw connected lines. * * Results: * None. * * Side effects: * Renders a series of connected lines. * *---------------------------------------------------------------------- */ static void CALLBACK DrawDot( int x, int y, /* Coordinates of point */ LPARAM clientData) { /* Line information */ DashInfo *infoPtr = (DashInfo *) clientData; int count; infoPtr->count++; count = (infoPtr->count + infoPtr->offset) / infoPtr->nBits; if (count & 0x1) { SetPixelV(infoPtr->dc, x, y, infoPtr->color); } } void Blt_EmulateXDrawLine( Display *display, Drawable drawable, GC gc, int x1, int y1, int x2, int y2) { TkWinDCState state; HDC dc; if (drawable == None) { return; } dc = TkWinGetDrawableDC(display, drawable, &state); SetROP2(dc, tkpWinRopModes[gc->function]); if (gc->line_style != LineSolid) { /* Handle dotted lines specially */ DashInfo info; if (!GetDashInfo(dc, gc, &info)) { goto solidLine; } LineDDA(x1, y1, x2, y2, DrawDot, (LPARAM)&info); } else { HPEN pen, oldPen; HBRUSH brush, oldBrush; solidLine: pen = Blt_GCToPen(dc, gc); oldPen = SelectPen(dc, pen); brush = CreateSolidBrush(gc->foreground); oldBrush = SelectBrush(dc, brush); MoveToEx(dc, x1, y1, (LPPOINT)NULL); LineTo(dc, x2, y2); DeletePen(SelectPen(dc, oldPen)); DeleteBrush(SelectBrush(dc, oldBrush)); } TkWinReleaseDrawableDC(drawable, dc, &state); } static void DrawLine( Display *display, Drawable drawable, GC gc, POINT *points, int nPoints) { TkWinDCState state; HDC dc; register int i, n; int start, extra, size; HPEN pen, oldPen; HBRUSH brush, oldBrush; if (drawable == None) { return; } dc = TkWinGetDrawableDC(display, drawable, &state); pen = Blt_GCToPen(dc, gc); oldPen = SelectPen(dc, pen); brush = CreateSolidBrush(gc->foreground); oldBrush = SelectBrush(dc, brush); SetROP2(dc, tkpWinRopModes[gc->function]); start = extra = 0; /* * Depending if the line is wide (> 1 pixel), arbitrarily break * the line in sections of 100 points. This bit of weirdness has * to do with wide geometric pens. The longer the polyline, the * slower it draws. The trade off is that we lose dash and * cap uniformity for unbearably slow polyline draws. */ if (gc->line_width > 1) { size = 100; } else { size = nPoints; } for (i = nPoints; i > 0; i -= size) { n = MIN(i, size); Polyline(dc, points + start, n + extra); start += (n - 1); extra = 1; } DeletePen(SelectPen(dc, oldPen)); DeleteBrush(SelectBrush(dc, oldBrush)); TkWinReleaseDrawableDC(drawable, dc, &state); } void Blt_EmulateXDrawLines( Display *display, Drawable drawable, GC gc, XPoint *pointArr, int nPoints, int mode) { if (drawable == None) { return; } if (gc->line_style != LineSolid) { /* Handle dotted lines specially */ DashInfo info; TkWinDCState state; HDC dc; int result; dc = TkWinGetDrawableDC(display, drawable, &state); SetROP2(dc, tkpWinRopModes[gc->function]); result = GetDashInfo(dc, gc, &info); if (result) { register XPoint *p1, *p2; register int i; p1 = pointArr; p2 = p1 + 1; for (i = 1; i < nPoints; i++, p1++, p2++) { LineDDA(p1->x, p1->y, p2->x, p2->y, DrawDot, (LPARAM)&info); } result = TCL_OK; } TkWinReleaseDrawableDC(drawable, dc, &state); if (result) { return; } } else { POINT *points, *destPtr; XPoint *srcPtr, *endPtr; points = Blt_Malloc(sizeof(POINT) * nPoints); if (points == NULL) { return; } endPtr = pointArr + nPoints; if (mode == CoordModeOrigin) { destPtr = points; for (srcPtr = pointArr; srcPtr < endPtr; srcPtr++) { destPtr->x = (int)srcPtr->x; destPtr->y = (int)srcPtr->y; destPtr++; } } else { POINT *lastPtr; srcPtr = pointArr; destPtr = points; destPtr->x = (int)srcPtr->x; destPtr->y = (int)srcPtr->y; lastPtr = destPtr; srcPtr++, destPtr++; for (/*empty*/; srcPtr < endPtr; srcPtr++) { destPtr->x = lastPtr->x + (int)srcPtr->x; destPtr->y = lastPtr->y + (int)srcPtr->y; lastPtr = destPtr; destPtr++; } } DrawLine(display, drawable, gc, points, nPoints); Blt_Free(points); } } /* *---------------------------------------------------------------------- * * Blt_EmultateXDrawSegments -- * * Draws multiple, unconnected lines. For each segment, draws a * line between (x1, y1) and (x2, y2). It draws the lines in the * order listed in the array of XSegment structures and does not * perform joining at coincident endpoints. For any given line, * does not draw a pixel more than once. If lines intersect, the * intersecting pixels are drawn multiple times. * * Results: * None. * * Side effects: * Draws unconnected line segments on the specified drawable. * *---------------------------------------------------------------------- */ void Blt_EmulateXDrawSegments( Display *display, Drawable drawable, GC gc, XSegment *segArr, int nSegments) { HDC dc; register XSegment *segPtr, *endPtr; TkWinDCState state; display->request++; if (drawable == None) { return; } dc = TkWinGetDrawableDC(display, drawable, &state); SetROP2(dc, tkpWinRopModes[gc->function]); if (gc->line_style != LineSolid) { /* Handle dotted lines specially */ DashInfo info; if (!GetDashInfo(dc, gc, &info)) { goto solidLine; } endPtr = segArr + nSegments; for (segPtr = segArr; segPtr < endPtr; segPtr++) { info.count = 0; /* Reset dash counter after every segment. */ LineDDA(segPtr->x1, segPtr->y1, segPtr->x2, segPtr->y2, DrawDot, (LPARAM)&info); } } else { HPEN pen, oldPen; solidLine: pen = Blt_GCToPen(dc, gc); oldPen = SelectPen(dc, pen); endPtr = segArr + nSegments; for (segPtr = segArr; segPtr < endPtr; segPtr++) { MoveToEx(dc, segPtr->x1, segPtr->y1, (LPPOINT)NULL); LineTo(dc, segPtr->x2, segPtr->y2); } DeletePen(SelectPen(dc, oldPen)); } TkWinReleaseDrawableDC(drawable, dc, &state); } /* *---------------------------------------------------------------------- * * Blt_EmultateXDrawRectangle -- * * Draws the outlines of the specified rectangle as if a * five-point PolyLine protocol request were specified for each * rectangle: * * [x,y] [x+width,y] [x+width,y+height] [x,y+height] * [x,y] * * Results: * None. * * Side effects: * Draws a rectangle on the specified drawable. * *---------------------------------------------------------------------- */ void Blt_EmulateXDrawRectangle( Display *display, Drawable drawable, GC gc, int x, int y, unsigned int width, unsigned int height) { TkWinDCState state; HPEN pen, oldPen; HBRUSH brush, oldBrush; HDC dc; if (drawable == None) { return; } dc = TkWinGetDrawableDC(display, drawable, &state); pen = Blt_GCToPen(dc, gc); brush = GetStockObject(NULL_BRUSH); oldPen = SelectPen(dc, pen); oldBrush = SelectBrush(dc, brush); SetROP2(dc, tkpWinRopModes[gc->function]); if (gc->line_style != LineSolid) { /* Handle dotted lines specially */ register int x2, y2; DashInfo info; if (!GetDashInfo(dc, gc, &info)) { goto solidLine; } x2 = x + width; y2 = y + height; LineDDA(x, y, x2, y, DrawDot, (LPARAM)&info); LineDDA(x2, y, x2, y2, DrawDot, (LPARAM)&info); LineDDA(x2, y2, x, y2, DrawDot, (LPARAM)&info); LineDDA(x, y2, x, y, DrawDot, (LPARAM)&info); } else { solidLine: Rectangle(dc, x, y, x + width + 1, y + height + 1); } DeletePen(SelectPen(dc, oldPen)); DeleteBrush(SelectBrush(dc, oldBrush)); TkWinReleaseDrawableDC(drawable, dc, &state); } /* *---------------------------------------------------------------------- * * Blt_EmulateXDrawPoints -- * * Uses the foreground pixel and function components of the GC to * draw a multiple points into the specified drawable. * CoordModeOrigin treats all coordinates as relative to the * origin, and CoordModePrevious treats all coordinates after * the first as relative to the previous point. * * Results: * None. * * Side effects: * Draws points on the specified drawable. * *---------------------------------------------------------------------- */ void Blt_EmulateXDrawPoints( Display *display, Drawable drawable, GC gc, XPoint *pointArr, int nPoints, int mode) { /* Ignored. CoordModeOrigin is assumed. */ HDC dc; register XPoint *pointPtr, *endPtr; TkWinDCState state; display->request++; if (drawable == None) { return; } dc = TkWinGetDrawableDC(display, drawable, &state); SetROP2(dc, tkpWinRopModes[gc->function]); endPtr = pointArr + nPoints; for (pointPtr = pointArr; pointPtr < endPtr; pointPtr++) { SetPixelV(dc, pointPtr->x, pointPtr->y, gc->foreground); } TkWinReleaseDrawableDC(drawable, dc, &state); } /* *---------------------------------------------------------------------- * * Blt_EmultateXReparentWindow -- * * If the specified window is mapped, automatically performs an * UnmapWindow request on it, removes it from its current * position in the hierarchy, and inserts it as the child of the * specified parent. The window is placed in the stacking order * on top with respect to sibling windows. * * Note: In WIN32 you can't reparent to/from another application. * * Results: * None. * * Side effects: * Reparents the specified window. * *---------------------------------------------------------------------- */ void Blt_EmulateXReparentWindow( Display *display, Window window, Window parent, int x, int y) { HWND child, newParent; child = Tk_GetHWND(window); newParent = Tk_GetHWND(parent); SetParent(child, newParent); SetWindowLong(child, GWL_STYLE, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); XMoveWindow(display, window, x, y); XRaiseWindow(display, window); XMapWindow(display, window); } void Blt_EmulateXSetDashes( Display *display, GC gc, int dashOffset, _Xconst char *dashList, int n) { gc->dashes = (unsigned char)strlen(dashList); gc->dash_offset = (int)dashList; } /* *---------------------------------------------------------------------- * * Blt_EmultateXDrawString -- * * Draw a single string in the current font. * * Results: * None. * * Side effects: * Renders the specified string in the drawable. * *---------------------------------------------------------------------- */ void Blt_EmulateXDrawString( Display *display, Drawable drawable, GC gc, int x, int y, _Xconst char *string, int length) { if (drawable == None) { return; } Tk_DrawChars(display, drawable, gc, (Tk_Font)gc->font, string, length, x, y); } static void TileArea(destDC, srcDC, tileOriginX, tileOriginY, tileWidth, tileHeight, x, y, width, height) HDC destDC, srcDC; int tileOriginX, tileOriginY, tileWidth, tileHeight; int x, y, width, height; { int destX, destY; int destWidth, destHeight; int srcX, srcY; int xOrigin, yOrigin; int delta; int left, top, right, bottom; xOrigin = x, yOrigin = y; if (x < tileOriginX) { delta = (tileOriginX - x) % tileWidth; if (delta > 0) { xOrigin -= (tileWidth - delta); } } else if (x > tileOriginX) { delta = (x - tileOriginX) % tileWidth; if (delta > 0) { xOrigin -= delta; } } if (y < tileOriginY) { delta = (tileOriginY - y) % tileHeight; if (delta > 0) { yOrigin -= (tileHeight - delta); } } else if (y >= tileOriginY) { delta = (y - tileOriginY) % tileHeight; if (delta > 0) { yOrigin -= delta; } } #ifdef notdef PurifyPrintf("tile is (%d,%d,%d,%d)\n", tileOriginX, tileOriginY, tileWidth, tileHeight); PurifyPrintf("region is (%d,%d,%d,%d)\n", x, y, width, height); PurifyPrintf("starting at %d,%d\n", xOrigin, yOrigin); #endif left = x; right = x + width; top = y; bottom = y + height; for (y = yOrigin; y < bottom; y += tileHeight) { srcY = 0; destY = y; destHeight = tileHeight; if (y < top) { srcY = (top - y); destHeight = tileHeight - srcY; destY = top; } if ((destY + destHeight) > bottom) { destHeight = (bottom - destY); } for (x = xOrigin; x < right; x += tileWidth) { srcX = 0; destX = x; destWidth = tileWidth; if (x < left) { srcX = (left - x); destWidth = tileWidth - srcX; destX = left; } if ((destX + destWidth) > right) { destWidth = (right - destX); } #ifdef notdef PurifyPrintf("drawing pattern (%d,%d,%d,%d) at %d,%d\n", srcX , srcY, destWidth, destHeight, destX, destY); #endif BitBlt(destDC, destX, destY, destWidth, destHeight, srcDC, srcX, srcY, SRCCOPY); } } } /* *---------------------------------------------------------------------- * * Blt_EmultateXFillRectangles -- * * Fill multiple rectangular areas in the given drawable. * Handles tiling. * * Results: * None. * * Side effects: * Draws onto the specified drawable. * *---------------------------------------------------------------------- */ void Blt_EmulateXFillRectangles( Display *display, Drawable drawable, GC gc, XRectangle *rectArr, int nRectangles) { BITMAP bm; HBITMAP oldBitmap, hBitmap; HBRUSH oldBrush, hFgBrush, hBgBrush, hBrush; HDC hDC; HDC memDC; RECT rect; TkWinDCState state; TkWinDrawable *twdPtr; register XRectangle *rectPtr, *endPtr; if (drawable == None) { return; } hDC = TkWinGetDrawableDC(display, drawable, &state); SetROP2(hDC, tkpWinRopModes[gc->function]); switch(gc->fill_style) { case FillTiled: if (gc->tile == None) { goto fillSolid; } #ifdef notdef if ((GetDeviceCaps(hDC, RASTERCAPS) & RC_BITBLT) == 0) { goto fillSolid; } #endif twdPtr = (TkWinDrawable *)gc->tile; GetObject(twdPtr->bitmap.handle, sizeof(BITMAP), &bm); memDC = CreateCompatibleDC(hDC); oldBitmap = SelectBitmap(memDC, twdPtr->bitmap.handle); endPtr = rectArr + nRectangles; for (rectPtr = rectArr; rectPtr < endPtr; rectPtr++) { TileArea(hDC, memDC, gc->ts_x_origin, gc->ts_y_origin, bm.bmWidth, bm.bmHeight, (int)rectPtr->x, (int)rectPtr->y, (int)rectPtr->width, (int)rectPtr->height); } SelectBitmap(memDC, oldBitmap); DeleteDC(memDC); break; case FillOpaqueStippled: case FillStippled: if (gc->stipple == None) { goto fillSolid; } twdPtr = (TkWinDrawable *)gc->stipple; if (twdPtr->type != TWD_BITMAP) { panic("unexpected drawable type in stipple"); } hBrush = CreatePatternBrush(twdPtr->bitmap.handle); SetBrushOrgEx(hDC, gc->ts_x_origin, gc->ts_y_origin, NULL); oldBrush = SelectBrush(hDC, hBrush); memDC = CreateCompatibleDC(hDC); /* * For each rectangle, create a drawing surface which is the size of * the rectangle and fill it with the background color. Then merge the * result with the stipple pattern. */ hFgBrush = CreateSolidBrush(gc->foreground); hBgBrush = CreateSolidBrush(gc->background); endPtr = rectArr + nRectangles; for (rectPtr = rectArr; rectPtr < endPtr; rectPtr++) { hBitmap = CreateCompatibleBitmap(hDC, rectPtr->width, rectPtr->height); oldBitmap = SelectObject(memDC, hBitmap); rect.left = rect.top = 0; rect.right = rectPtr->width; rect.bottom = rectPtr->height; FillRect(memDC, &rect, hFgBrush); BitBlt(hDC, rectPtr->x, rectPtr->y, rectPtr->width, rectPtr->height, memDC, 0, 0, COPYBG); if (gc->fill_style == FillOpaqueStippled) { FillRect(memDC, &rect, hBgBrush); BitBlt(hDC, rectPtr->x, rectPtr->y, rectPtr->width, rectPtr->height, memDC, 0, 0, COPYFG); } SelectObject(memDC, oldBitmap); DeleteObject(hBitmap); } DeleteBrush(hFgBrush); DeleteBrush(hBgBrush); DeleteDC(memDC); SelectBrush(hDC, oldBrush); DeleteBrush(hBrush); break; case FillSolid: fillSolid: memDC = CreateCompatibleDC(hDC); hFgBrush = CreateSolidBrush(gc->foreground); endPtr = rectArr + nRectangles; for (rectPtr = rectArr; rectPtr < endPtr; rectPtr++) { hBitmap = CreateCompatibleBitmap(hDC, rectPtr->width, rectPtr->height); oldBitmap = SelectObject(memDC, hBitmap); rect.left = rect.top = 0; rect.right = rectPtr->width; rect.bottom = rectPtr->height; FillRect(memDC, &rect, hFgBrush); BitBlt(hDC, rectPtr->x, rectPtr->y, rectPtr->width, rectPtr->height, memDC, 0, 0, SRCCOPY); SelectObject(memDC, oldBitmap); DeleteObject(hBitmap); } DeleteBrush(hFgBrush); DeleteDC(memDC); break; } TkWinReleaseDrawableDC(drawable, hDC, &state); } void Blt_EmulateXFillRectangle( Display *display, Drawable drawable, GC gc, int x, int y, unsigned int width, unsigned int height) { HDC hDC; RECT rect; TkWinDCState state; if (drawable == None) { return; } hDC = TkWinGetDrawableDC(display, drawable, &state); SetROP2(hDC, tkpWinRopModes[gc->function]); rect.left = rect.top = 0; rect.right = width; rect.bottom = height; switch(gc->fill_style) { case FillTiled: { TkWinDrawable *twdPtr; HBITMAP oldBitmap; HDC memDC; BITMAP bm; if (gc->tile == None) { goto fillSolid; } #ifdef notdef if ((GetDeviceCaps(hDC, RASTERCAPS) & RC_BITBLT) == 0) { goto fillSolid; } #endif twdPtr = (TkWinDrawable *)gc->tile; /* The tiling routine needs to know the size of the bitmap */ GetObject(twdPtr->bitmap.handle, sizeof(BITMAP), &bm); memDC = CreateCompatibleDC(hDC); oldBitmap = SelectBitmap(memDC, twdPtr->bitmap.handle); TileArea(hDC, memDC, gc->ts_x_origin, gc->ts_y_origin, bm.bmWidth, bm.bmHeight, x, y, width, height); SelectBitmap(memDC, oldBitmap); DeleteDC(memDC); } break; case FillOpaqueStippled: case FillStippled: { TkWinDrawable *twdPtr; HBRUSH oldBrush, hBrush; HBRUSH hBrushFg, hBrushBg; HBITMAP oldBitmap, hBitmap; HDC memDC; if (gc->stipple == None) { goto fillSolid; } twdPtr = (TkWinDrawable *)gc->stipple; if (twdPtr->type != TWD_BITMAP) { panic("unexpected drawable type in stipple"); } hBrush = CreatePatternBrush(twdPtr->bitmap.handle); SetBrushOrgEx(hDC, gc->ts_x_origin, gc->ts_y_origin, NULL); oldBrush = SelectBrush(hDC, hBrush); memDC = CreateCompatibleDC(hDC); hBrushFg = CreateSolidBrush(gc->foreground); hBrushBg = CreateSolidBrush(gc->background); hBitmap = CreateCompatibleBitmap(hDC, width, height); oldBitmap = SelectObject(memDC, hBitmap); FillRect(memDC, &rect, hBrushFg); SetBkMode(hDC, TRANSPARENT); BitBlt(hDC, x, y, width, height, memDC, 0, 0, COPYFG); if (gc->fill_style == FillOpaqueStippled) { FillRect(memDC, &rect, hBrushBg); BitBlt(hDC, x, y, width, height, memDC, 0, 0, COPYBG); } SelectBrush(hDC, oldBrush); SelectBitmap(memDC, oldBitmap); DeleteBrush(hBrushFg); DeleteBrush(hBrushBg); DeleteBrush(hBrush); DeleteBitmap(hBitmap); DeleteDC(memDC); } break; case FillSolid: { HBRUSH hBrush; HBITMAP oldBitmap, hBitmap; HDC memDC; fillSolid: /* TkWinFillRect(hDC, x, y, width, height, gc->foreground); */ memDC = CreateCompatibleDC(hDC); hBrush = CreateSolidBrush(gc->foreground); hBitmap = CreateCompatibleBitmap(hDC, width, height); oldBitmap = SelectBitmap(memDC, hBitmap); rect.left = rect.top = 0; rect.right = width; rect.bottom = height; FillRect(memDC, &rect, hBrush); BitBlt(hDC, x, y, width, height, memDC, 0, 0, SRCCOPY); SelectObject(memDC, oldBitmap); DeleteBitmap(hBitmap); DeleteBrush(hBrush); DeleteDC(memDC); } break; } TkWinReleaseDrawableDC(drawable, hDC, &state); } static BOOL DrawChars(HDC dc, int x, int y, char *string, int length) { BOOL result; #if (TCL_VERSION_NUMBER >= _VERSION(8,1,0)) if (systemEncoding == NULL) { result = TextOutA(dc, x, y, string, length); } else { const unsigned short *wstring; Tcl_DString dString; Tcl_DStringInit(&dString); Tcl_UtfToExternalDString(systemEncoding, string, length, &dString); length = Tcl_NumUtfChars(string, -1); wstring = (const unsigned short *)Tcl_DStringValue(&dString); result = TextOutW(dc, x, y, wstring, length); Tcl_DStringFree(&dString); } #else result = TextOutA(dc, x, y, string, length); #endif /* TCL_VERSION_NUMBER >= 8.1.0 */ return result; } int Blt_DrawRotatedText( Display *display, Drawable drawable, int x, int y, double theta, TextStyle *tsPtr, TextLayout *textPtr) { HFONT hFont, oldFont; TkWinDCState state; HDC hDC; int isActive; int bbWidth, bbHeight; double rotWidth, rotHeight; double sinTheta, cosTheta; Point2D p, q, center; register TextFragment *fragPtr, *endPtr; #if (TCL_VERSION_NUMBER >= _VERSION(8,1,0)) static int initialized = 0; if (!initialized) { if (Blt_GetPlatformId() == VER_PLATFORM_WIN32_NT) { /* * If running NT, then we will be calling some Unicode functions * explictly. So, even if the Tcl system encoding isn't Unicode, * make sure we convert to/from the Unicode char set. */ systemEncoding = Tcl_GetEncoding(NULL, "unicode"); } initialized = 1; } #endif hFont = CreateRotatedFont(tsPtr->gc->font, theta); if (hFont == NULL) { return FALSE; } isActive = (tsPtr->state & STATE_ACTIVE); hDC = TkWinGetDrawableDC(display, drawable, &state); SetROP2(hDC, tsPtr->gc->function); oldFont = SelectFont(hDC, hFont); Blt_GetBoundingBox(textPtr->width, textPtr->height, theta, &rotWidth, &rotHeight, (Point2D *)NULL); bbWidth = ROUND(rotWidth); bbHeight = ROUND(rotHeight); Blt_TranslateAnchor(x, y, bbWidth, bbHeight, tsPtr->anchor, &x, &y); center.x = (double)textPtr->width * -0.5; center.y = (double)textPtr->height * -0.5; theta = (-theta / 180.0) * M_PI; sinTheta = sin(theta), cosTheta = cos(theta); endPtr = textPtr->fragArr + textPtr->nFrags; for (fragPtr = textPtr->fragArr; fragPtr < endPtr; fragPtr++) { p.x = center.x + (double)fragPtr->x; p.y = center.y + (double)fragPtr->y; q.x = x + (p.x * cosTheta) - (p.y * sinTheta) + (bbWidth * 0.5); q.y = y + (p.x * sinTheta) + (p.y * cosTheta) + (bbHeight * 0.5); fragPtr->sx = ROUND(q.x); fragPtr->sy = ROUND(q.y); } SetBkMode(hDC, TRANSPARENT); SetTextAlign(hDC, TA_LEFT | TA_BASELINE); if (tsPtr->state & (STATE_DISABLED | STATE_EMPHASIS)) { TkBorder *borderPtr = (TkBorder *) tsPtr->border; XColor *color1, *color2; color1 = borderPtr->lightColor, color2 = borderPtr->darkColor; if (tsPtr->state & STATE_EMPHASIS) { XColor *hold; hold = color1, color1 = color2, color2 = hold; } if (color1 != NULL) { SetTextColor(hDC, color1->pixel); for (fragPtr = textPtr->fragArr; fragPtr < endPtr; fragPtr++) { DrawChars(hDC, fragPtr->sx, fragPtr->sy, fragPtr->text, fragPtr->count); } } if (color2 != NULL) { SetTextColor(hDC, color2->pixel); for (fragPtr = textPtr->fragArr; fragPtr < endPtr; fragPtr++) { DrawChars(hDC, fragPtr->sx + 1, fragPtr->sy + 1, fragPtr->text, fragPtr->count); } } goto done; /* Done */ } SetBkMode(hDC, TRANSPARENT); if ((tsPtr->shadow.offset > 0) && (tsPtr->shadow.color != NULL)) { SetTextColor(hDC, tsPtr->shadow.color->pixel); for (fragPtr = textPtr->fragArr; fragPtr < endPtr; fragPtr++) { DrawChars(hDC, fragPtr->sx + tsPtr->shadow.offset, fragPtr->sy + tsPtr->shadow.offset, fragPtr->text, fragPtr->count); } } if (isActive) { SetTextColor(hDC, tsPtr->activeColor->pixel); } else { SetTextColor(hDC, tsPtr->color->pixel); } for (fragPtr = textPtr->fragArr; fragPtr < endPtr; fragPtr++) { DrawChars(hDC, fragPtr->sx, fragPtr->sy, fragPtr->text, fragPtr->count); } if (isActive) { SetTextColor(hDC, tsPtr->color->pixel); } done: SelectFont(hDC, oldFont); DeleteFont(hFont); TkWinReleaseDrawableDC(drawable, hDC, &state); return TRUE; } static void DrawPixel( HDC hDC, int x, int y, COLORREF color) { HDC memDC; HBRUSH hBrushFg; HBITMAP oldBitmap, hBitmap; RECT rect; int size; size = 1; memDC = CreateCompatibleDC(hDC); hBrushFg = CreateSolidBrush(color); hBitmap = CreateCompatibleBitmap(hDC, size, size); oldBitmap = SelectObject(memDC, hBitmap); rect.left = rect.top = 0; rect.right = rect.bottom = size; FillRect(memDC, &rect, hBrushFg); BitBlt(hDC, x, y, size, size, memDC, 0, 0, SRCCOPY); SelectObject(memDC, oldBitmap); DeleteObject(hBitmap); DeleteBrush(hBrushFg); DeleteDC(memDC); } /* *---------------------------------------------------------------------- * * PixelateBitmap -- * * Draws a masked bitmap in given device (should be printer) * context. Bit operations on print devices usually fail because * there's no way to read back from the device surface to get the * previous pixel values, rendering BitBlt useless. The bandaid * solution here is to draw 1x1 pixel rectangles at each * coordinate as directed by the the mask and source bitmaps. * * Results: * None. * * Side effects: * Draws onto the specified drawable. * *---------------------------------------------------------------------- */ static void PixelateBitmap( Display *display, Drawable drawable, Pixmap srcBitmap, Pixmap maskBitmap, int width, int height, GC gc, int destX, int destY) { register int x, y; register int dx, dy; int pixel; unsigned char *srcBits; register unsigned char *srcPtr; int bitPos, bytesPerRow; HDC hDC; TkWinDCState state; srcBits = Blt_GetBitmapData(display, srcBitmap, width, height, &bytesPerRow); if (srcBits == NULL) { return; } hDC = TkWinGetDrawableDC(display, drawable, &state); if (maskBitmap != None) { register unsigned char *maskPtr; unsigned char *maskBits; maskBits = Blt_GetBitmapData(display, maskBitmap, width, height, &bytesPerRow); bytesPerRow = ((width + 31) & ~31) / 8; for (dy = destY, y = height - 1; y >= 0; y--, dy++) { maskPtr = maskBits + (bytesPerRow * y); srcPtr = srcBits + (bytesPerRow * y); for (dx = destX, x = 0; x < width; x++, dx++) { bitPos = x % 8; pixel = (*maskPtr & (0x80 >> bitPos)); if (pixel) { pixel = (*srcPtr & (0x80 >> bitPos)); DrawPixel(hDC, dx, dy, (pixel) ? gc->foreground : gc->background); } if (bitPos == 7) { srcPtr++, maskPtr++; } } /* x */ } Blt_Free(maskBits); } else { bytesPerRow = ((width + 31) & ~31) / 8; for (dy = destY, y = height - 1; y >= 0; y--, dy++) { srcPtr = srcBits + (bytesPerRow * y); for (dx = destX, x = 0; x < width; x++, dx++) { bitPos = x % 8; pixel = (*srcPtr & (0x80 >> bitPos)); DrawPixel(hDC, dx, dy, (pixel) ? gc->foreground : gc->background); if (bitPos == 7) { srcPtr++; } } } } TkWinReleaseDrawableDC(drawable, hDC, &state); Blt_Free(srcBits); } /* *---------------------------------------------------------------------- * * Blt_EmulateXCopyPlane -- * * Simplified version of XCopyPlane. Right now it ignores * function, * clip_x_origin, * clip_y_origin * * The plane argument must always be 1. * * This routine differs from the Tk version in how it handles * transparency. It uses a different method of drawing transparent * bitmaps that doesn't copy the background or use brushes. The * second change is to call a special routine when the destDC is * a printer. Stippling is done by a very slow brute-force * method of drawing 1x1 rectangles for each pixel (bleech). * * Results: * None. * * Side effects: * Changes the destination drawable. * *---------------------------------------------------------------------- */ void Blt_EmulateXCopyPlane( Display *display, Drawable src, Drawable dest, GC gc, int srcX, int srcY, unsigned int width, unsigned int height, int destX, int destY, unsigned long plane) { HDC srcDC, destDC; TkWinDCState srcState, destState; TkpClipMask *clipPtr = (TkpClipMask *) gc->clip_mask; display->request++; if (plane != 1) { panic("Unexpected plane specified for XCopyPlane"); } srcDC = TkWinGetDrawableDC(display, src, &srcState); if (src != dest) { destDC = TkWinGetDrawableDC(display, dest, &destState); } else { destDC = srcDC; } if ((clipPtr == NULL) || (clipPtr->type == TKP_CLIP_REGION)) { /* * Case 1: opaque bitmaps. Windows handles the conversion * from one bit to multiple bits by setting 0 to the * foreground color, and 1 to the background color (seems * backwards, but there you are). */ if ((clipPtr != NULL) && (clipPtr->type == TKP_CLIP_REGION)) { SelectClipRgn(destDC, (HRGN) clipPtr->value.region); OffsetClipRgn(destDC, gc->clip_x_origin, gc->clip_y_origin); } SetBkMode(destDC, OPAQUE); SetBkColor(destDC, gc->foreground); SetTextColor(destDC, gc->background); BitBlt(destDC, destX, destY, width, height, srcDC, srcX, srcY, SRCCOPY); SelectClipRgn(destDC, NULL); } else if (clipPtr->type == TKP_CLIP_PIXMAP) { Drawable mask; /* * Case 2: transparent bitmaps are handled by setting the * destination to the foreground color whenever the source * pixel is set. */ /* * Case 3: two arbitrary bitmaps. Copy the source rectangle * into a color pixmap. Use the result as a brush when * copying the clip mask into the destination. */ mask = clipPtr->value.pixmap; #if WINDEBUG PurifyPrintf("mask %s src\n", (mask == src) ? "==" : "!="); PurifyPrintf("GetDeviceCaps=%x\n", GetDeviceCaps(destDC, TECHNOLOGY) & DT_RASDISPLAY); #endif { HDC maskDC; TkWinDCState maskState; if (mask != src) { maskDC = TkWinGetDrawableDC(display, mask, &maskState); } else { maskDC = srcDC; } SetBkMode(destDC, OPAQUE); SetTextColor(destDC, gc->background); SetBkColor(destDC, gc->foreground); BitBlt(destDC, destX, destY, width, height, srcDC, srcX, srcY, SRCINVERT); /* * Make sure we treat the mask as a monochrome bitmap. * We can get alpha-blending with non-black/white fg/bg * color selections. */ SetTextColor(destDC, RGB(255,255,255)); SetBkColor(destDC, RGB(0,0,0)); /* FIXME: Handle gc->clip_?_origin's */ BitBlt(destDC, destX, destY, width, height, maskDC, 0, 0, SRCAND); SetTextColor(destDC, gc->background); SetBkColor(destDC, gc->foreground); BitBlt(destDC, destX, destY, width, height, srcDC, srcX, srcY, SRCINVERT); if (mask != src) { TkWinReleaseDrawableDC(mask, maskDC, &maskState); } } } if (src != dest) { TkWinReleaseDrawableDC(dest, destDC, &destState); } TkWinReleaseDrawableDC(src, srcDC, &srcState); } /* *---------------------------------------------------------------------- * * Blt_EmulateXCopyArea -- * * Copies data from one drawable to another using block transfer * routines. The small enhancement over the version in Tk is * that it doesn't assume that the source and destination devices * have the same resolution. This isn't true when the destination * device is a printer. * * FIXME: not true anymore. delete this routine. * * Results: * None. * * Side effects: * Data is moved from a window or bitmap to a second window, * bitmap, or printer. * *---------------------------------------------------------------------- */ void Blt_EmulateXCopyArea( Display *display, Drawable src, Drawable dest, GC gc, int srcX, /* Source X-coordinate */ int srcY, /* Source Y-coordinate. */ unsigned int width, /* Width of area. */ unsigned int height, /* Height of area. */ int destX, /* Destination X-coordinate (in screen * coordinates). */ int destY) /* Destination Y-coordinate (in screen * coordinates). */ { HDC srcDC, destDC; TkWinDCState srcState, destState; TkpClipMask *clipPtr; srcDC = TkWinGetDrawableDC(display, src, &srcState); if (src != dest) { destDC = TkWinGetDrawableDC(display, dest, &destState); } else { destDC = srcDC; } clipPtr = (TkpClipMask *)gc->clip_mask; if ((clipPtr != NULL) && (clipPtr->type == TKP_CLIP_REGION)) { SelectClipRgn(destDC, (HRGN)clipPtr->value.region); OffsetClipRgn(destDC, gc->clip_x_origin, gc->clip_y_origin); } BitBlt(destDC, destX, destY, width, height, srcDC, srcX, srcY, bltModes[gc->function]); SelectClipRgn(destDC, NULL); if (src != dest) { TkWinReleaseDrawableDC(dest, destDC, &destState); } TkWinReleaseDrawableDC(src, srcDC, &srcState); } static void StippleRegion( Display *display, HDC hDC, /* Device context: For polygons, clip * region will be installed. */ GC gc, int x, int y, int width, int height) { BITMAP bm; HBITMAP oldBitmap; HDC maskDC, memDC; Pixmap mask; TkWinDCState maskState; TkWinDrawable *twdPtr; int destX, destY, destWidth, destHeight; int dx, dy; int left, top, right, bottom; int srcX, srcY; int startX, startY; /* Starting upper left corner of region. */ twdPtr = (TkWinDrawable *)gc->stipple; GetObject(twdPtr->bitmap.handle, sizeof(BITMAP), &bm); startX = x; if (x < gc->ts_x_origin) { dx = (gc->ts_x_origin - x) % bm.bmWidth; if (dx > 0) { startX -= (bm.bmWidth - dx); } } else if (x > gc->ts_x_origin) { dx = (x - gc->ts_x_origin) % bm.bmWidth; if (dx > 0) { startX -= dx; } } startY = y; if (y < gc->ts_y_origin) { dy = (gc->ts_y_origin - y) % bm.bmHeight; if (dy > 0) { startY -= (bm.bmHeight - dy); } } else if (y >= gc->ts_y_origin) { dy = (y - gc->ts_y_origin) % bm.bmHeight; if (dy > 0) { startY -= dy; } } #ifdef notdef PurifyPrintf("tile is (%d,%d,%d,%d)\n", gc->ts_x_origin, gc->ts_y_origin, bm.bmWidth, bm.bmHeight); PurifyPrintf("region is (%d,%d,%d,%d)\n", x, y, width, height); PurifyPrintf("starting at %d,%d\n", startX, startY); #endif left = x; right = x + width; top = y; bottom = y + height; maskDC = memDC = CreateCompatibleDC(hDC); oldBitmap = SelectBitmap(memDC, twdPtr->bitmap.handle); mask = gc->stipple; if (gc->fill_style == FillStippled) { /* With transparency. */ if (gc->clip_mask != None) { TkpClipMask *clipPtr; mask = gc->stipple; clipPtr = (TkpClipMask *)gc->clip_mask; if (clipPtr->type == TKP_CLIP_PIXMAP) { mask = clipPtr->value.pixmap; } } if (mask != gc->stipple) { maskDC = TkWinGetDrawableDC(display, mask, &maskState); } } for (y = startY; y < bottom; y += bm.bmHeight) { srcY = 0; destY = y; destHeight = bm.bmHeight; if (y < top) { srcY = (top - y); destHeight = bm.bmHeight - srcY; destY = top; } if ((destY + destHeight) > bottom) { destHeight = (bottom - destY); } for (x = startX; x < right; x += bm.bmWidth) { srcX = 0; destX = x; destWidth = bm.bmWidth; if (x < left) { srcX = (left - x); destWidth = bm.bmWidth - srcX; destX = left; } if ((destX + destWidth) > right) { destWidth = (right - destX); } #ifdef notdef PurifyPrintf("drawing pattern (%d,%d,%d,%d) at %d,%d\n", srcX , srcY, destWidth, destHeight, destX, destY); #endif if (gc->fill_style == FillStippled) { /* With transparency. */ SetBkMode(hDC, OPAQUE); SetTextColor(hDC, gc->background); SetBkColor(hDC, gc->foreground); BitBlt(hDC, destX, destY, destWidth, destHeight, memDC, srcX, srcY, SRCINVERT); SetTextColor(hDC, RGB(255,255,255)); SetBkColor(hDC, RGB(0,0,0)); BitBlt(hDC, destX, destY, destWidth, destHeight, maskDC, srcX, srcY, SRCAND); SetTextColor(hDC, gc->background); SetBkColor(hDC, gc->foreground); BitBlt(hDC, destX, destY, destWidth, destHeight, memDC, srcX, srcY, SRCINVERT); } else if (gc->fill_style == FillOpaqueStippled) { /* Opaque. */ SetBkColor(hDC, gc->foreground); SetTextColor(hDC, gc->background); BitBlt(hDC, destX, destY, destWidth, destHeight, memDC, srcX, srcY, SRCCOPY); } } } SelectBitmap(memDC, oldBitmap); if (maskDC != memDC) { TkWinReleaseDrawableDC(mask, maskDC, &maskState); } DeleteDC(memDC); } /* *---------------------------------------------------------------------- * * Blt_EmulateXFillPolygon -- * * This differs from Tk's XFillPolygon in that it works around * deficencies in Windows 95/98: * 1. Stippling bitmap is limited to 8x8. * 2. No tiling (with or without mask). * Results: * None. * *---------------------------------------------------------------------- */ void Blt_EmulateXFillPolygon( Display *display, Drawable drawable, GC gc, XPoint *pointPtr, int nPoints, int shape, int mode) { HDC hDC; HRGN hRgn; POINT *p, *winPts, *endPtr; Region2D bbox; TkWinDCState state; int fillMode; if (drawable == None) { return; } /* Determine the bounding box of the polygon. */ bbox.left = bbox.right = pointPtr->x; bbox.top = bbox.bottom = pointPtr->y; hDC = TkWinGetDrawableDC(display, drawable, &state); /* Allocate array of POINTS to create the polygon's path. */ winPts = Blt_Malloc(sizeof(POINT) * nPoints); endPtr = winPts + nPoints; for (p = winPts; p < endPtr; p++) { if (pointPtr->x < bbox.left) { bbox.left = pointPtr->x; } if (pointPtr->x > bbox.right) { bbox.right = pointPtr->x; } if (pointPtr->y < bbox.top) { bbox.top = pointPtr->y; } if (pointPtr->y > bbox.bottom) { bbox.bottom = pointPtr->y; } p->x = pointPtr->x; p->y = pointPtr->y; pointPtr++; } SetROP2(hDC, tkpWinRopModes[gc->function]); fillMode = (gc->fill_rule == EvenOddRule) ? ALTERNATE : WINDING; if ((gc->fill_style == FillStippled) || (gc->fill_style == FillOpaqueStippled)) { int width, height; /* Points are offsets within the bounding box. */ for (p = winPts; p < endPtr; p++) { p->x -= bbox.left; p->y -= bbox.top; } /* Use the polygon as a clip path. */ LPtoDP(hDC, winPts, nPoints); hRgn = CreatePolygonRgn(winPts, nPoints, fillMode); SelectClipRgn(hDC, hRgn); OffsetClipRgn(hDC, bbox.left, bbox.top); /* Tile the bounding box. */ width = bbox.right - bbox.left + 1; height = bbox.bottom - bbox.top + 1; StippleRegion(display, hDC, gc, bbox.left, bbox.top, width, height); SelectClipRgn(hDC, NULL); DeleteRgn(hRgn); } else { HPEN oldPen; HBRUSH oldBrush; /* * FIXME: Right now, we're assuming that it's solid or * stippled and ignoring tiling. I'll merge the bits from * Blt_TilePolygon later. */ oldPen = SelectPen(hDC, GetStockObject(NULL_PEN)); oldBrush = SelectBrush(hDC, CreateSolidBrush(gc->foreground)); SetPolyFillMode(hDC, fillMode); Polygon(hDC, winPts, nPoints); SelectPen(hDC, oldPen); DeleteBrush(SelectBrush(hDC, oldBrush)); } Blt_Free(winPts); TkWinReleaseDrawableDC(drawable, hDC, &state); } blt-2.4z.orig/src/bltWinImage.c0100644000175000017500000010662207535436724015127 0ustar dokodoko /* * bltWinImage.c -- * * This module implements image processing procedures for the BLT * toolkit. * * Copyright 1997-1998 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. */ #include "bltInt.h" #include "bltImage.h" #include #define CLAMP(c) ((((c) < 0.0) ? 0.0 : ((c) > 255.0) ? 255.0 : (c))) #define GetBit(x, y) \ srcBits[(srcBytesPerRow * (srcHeight - y - 1)) + (x>>3)] & (0x80 >> (x&7)) #define SetBit(x, y) \ destBits[(destBytesPerRow * (destHeight - y - 1)) + (x>>3)] |= (0x80 >>(x&7)) /* *---------------------------------------------------------------------- * * Blt_ColorImageToPixmap -- * * Converts a color image into a pixmap. * * Right now this only handles TrueColor visuals. * * Results: * The new pixmap is returned. * *---------------------------------------------------------------------- */ Pixmap Blt_ColorImageToPixmap( Tcl_Interp *interp, Tk_Window tkwin, Blt_ColorImage image, ColorTable *colorTablePtr) /* Points to array of colormap indices */ { HDC pixmapDC; TkWinDCState state; Display *display; int width, height, depth; Pixmap pixmap; register int x, y; register Pix32 *srcPtr; COLORREF rgb; *colorTablePtr = NULL; width = Blt_ColorImageWidth(image); height = Blt_ColorImageHeight(image); display = Tk_Display(tkwin); depth = Tk_Depth(tkwin); pixmap = Tk_GetPixmap(display, Tk_WindowId(tkwin), width, height, depth); pixmapDC = TkWinGetDrawableDC(display, pixmap, &state); srcPtr = Blt_ColorImageBits(image); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { rgb = PALETTERGB(srcPtr->Red, srcPtr->Green, srcPtr->Blue); SetPixelV(pixmapDC, x, y, rgb); srcPtr++; } } TkWinReleaseDrawableDC(pixmap, pixmapDC, &state); return pixmap; } /* *---------------------------------------------------------------------- * * Blt_ColorImageToPixmap2 -- * * Converts a color image into a pixmap. * * Right now this only handles TrueColor visuals. * * Results: * The new pixmap is returned. * *---------------------------------------------------------------------- */ Pixmap Blt_ColorImageToPixmap2( Display *display, int depth, Blt_ColorImage image, ColorTable *colorTablePtr) /* Points to array of colormap indices */ { BITMAP bm; HBITMAP hBitmap; TkWinBitmap *twdPtr; int width, height; register Pix32 *srcPtr; register int x, y; register unsigned char *destPtr; unsigned char *bits; *colorTablePtr = NULL; width = Blt_ColorImageWidth(image); height = Blt_ColorImageHeight(image); /* * Copy the color image RGB data into the DIB. The DIB scanlines * are stored bottom-to-top and the order of the RGB color * components is BGR. Who says Win32 GDI programming isn't * backwards? */ bits = Blt_Malloc(width * height * sizeof(unsigned char)); assert(bits); srcPtr = Blt_ColorImageBits(image); for (y = height - 1; y >= 0; y--) { destPtr = bits + (y * width); for (x = 0; x < width; x++) { *destPtr++ = srcPtr->Blue; *destPtr++ = srcPtr->Green; *destPtr++ = srcPtr->Red; *destPtr++ = (unsigned char)-1; srcPtr++; } } bm.bmType = 0; bm.bmWidth = width; bm.bmHeight = height; bm.bmWidthBytes = width; bm.bmPlanes = 1; bm.bmBitsPixel = 32; bm.bmBits = bits; hBitmap = CreateBitmapIndirect(&bm); /* Create a windows version of a drawable. */ twdPtr = Blt_Malloc(sizeof(TkWinBitmap)); assert(twdPtr); twdPtr->type = TWD_BITMAP; twdPtr->handle = hBitmap; twdPtr->depth = depth; twdPtr->colormap = DefaultColormap(display, DefaultScreen(display)); return (Pixmap)twdPtr; } /* *---------------------------------------------------------------------- * * Blt_DrawableToColorImage -- * * Takes a snapshot of an X drawable (pixmap or window) and * converts it to a color image. * * Results: * Returns a color image of the drawable. If an error occurred, * NULL is returned. * *---------------------------------------------------------------------- */ Blt_ColorImage Blt_DrawableToColorImage( Tk_Window tkwin, Drawable drawable, int x, int y, int width, int height, /* Dimension of the drawable. */ double inputGamma) { void *data; BITMAPINFO info; DIBSECTION ds; HBITMAP hBitmap, oldBitmap; HPALETTE hPalette; HDC memDC; unsigned char *srcArr; register unsigned char *srcPtr; HDC hDC; TkWinDCState state; register Pix32 *destPtr; Blt_ColorImage image; unsigned char lut[256]; hDC = TkWinGetDrawableDC(Tk_Display(tkwin), drawable, &state); /* Create the intermediate drawing surface at window resolution. */ ZeroMemory(&info, sizeof(info)); info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); info.bmiHeader.biWidth = width; info.bmiHeader.biHeight = height; info.bmiHeader.biPlanes = 1; info.bmiHeader.biBitCount = 32; info.bmiHeader.biCompression = BI_RGB; hBitmap = CreateDIBSection(hDC, &info, DIB_RGB_COLORS, &data, NULL, 0); memDC = CreateCompatibleDC(hDC); oldBitmap = SelectBitmap(memDC, hBitmap); hPalette = Blt_GetSystemPalette(); if (hPalette != NULL) { SelectPalette(hDC, hPalette, FALSE); RealizePalette(hDC); SelectPalette(memDC, hPalette, FALSE); RealizePalette(memDC); } image = NULL; /* Copy the window contents to the memory surface. */ if (!BitBlt(memDC, 0, 0, width, height, hDC, x, y, SRCCOPY)) { #ifdef notdef PurifyPrintf("can't blit: %s\n", Blt_LastError()); #endif goto done; } if (GetObject(hBitmap, sizeof(DIBSECTION), &ds) == 0) { #ifdef notdef PurifyPrintf("can't get object: %s\n", Blt_LastError()); #endif goto done; } srcArr = (unsigned char *)ds.dsBm.bmBits; image = Blt_CreateColorImage(width, height); destPtr = Blt_ColorImageBits(image); { register int i; double value; for (i = 0; i < 256; i++) { value = pow(i / 255.0, inputGamma) * 255.0 + 0.5; lut[i] = (unsigned char)CLAMP(value); } } /* * Copy the DIB RGB data into the color image. The DIB scanlines * are stored bottom-to-top and the order of the RGB color * components is BGR. Who says Win32 GDI programming isn't * backwards? */ for (y = height - 1; y >= 0; y--) { srcPtr = srcArr + (y * ds.dsBm.bmWidthBytes); for (x = 0; x < width; x++) { destPtr->Blue = lut[*srcPtr++]; destPtr->Green = lut[*srcPtr++]; destPtr->Red = lut[*srcPtr++]; destPtr->Alpha = (unsigned char)-1; destPtr++; srcPtr++; } } done: DeleteBitmap(SelectBitmap(memDC, oldBitmap)); DeleteDC(memDC); TkWinReleaseDrawableDC(drawable, hDC, &state); if (hPalette != NULL) { DeletePalette(hPalette); } return image; } Pixmap Blt_PhotoImageMask( Tk_Window tkwin, Tk_PhotoImageBlock src) { TkWinBitmap *twdPtr; int offset, count; register int x, y; unsigned char *srcPtr; int destBytesPerRow; int destHeight; unsigned char *destBits; destBytesPerRow = ((src.width + 31) & ~31) / 8; destBits = Blt_Calloc(src.height, destBytesPerRow); destHeight = src.height; offset = count = 0; /* FIXME: figure out why this is so! */ for (y = src.height - 1; y >= 0; y--) { srcPtr = src.pixelPtr + offset; for (x = 0; x < src.width; x++) { if (srcPtr[src.offset[3]] == 0x00) { SetBit(x, y); count++; } srcPtr += src.pixelSize; } offset += src.pitch; } if (count > 0) { HBITMAP hBitmap; BITMAP bm; bm.bmType = 0; bm.bmWidth = src.width; bm.bmHeight = src.height; bm.bmWidthBytes = destBytesPerRow; bm.bmPlanes = 1; bm.bmBitsPixel = 1; bm.bmBits = destBits; hBitmap = CreateBitmapIndirect(&bm); twdPtr = Blt_Malloc(sizeof(TkWinBitmap)); assert(twdPtr); twdPtr->type = TWD_BITMAP; twdPtr->handle = hBitmap; twdPtr->depth = 1; if (Tk_WindowId(tkwin) == None) { twdPtr->colormap = DefaultColormap(Tk_Display(tkwin), DefaultScreen(Tk_Display(tkwin))); } else { twdPtr->colormap = Tk_Colormap(tkwin); } } else { twdPtr = NULL; } if (destBits != NULL) { Blt_Free(destBits); } return (Pixmap)twdPtr; } Pixmap Blt_ColorImageMask( Tk_Window tkwin, Blt_ColorImage image) { TkWinBitmap *twdPtr; int count; register int x, y; Pix32 *srcPtr; int destBytesPerRow; int destWidth, destHeight; unsigned char *destBits; destWidth = Blt_ColorImageWidth(image); destHeight = Blt_ColorImageHeight(image); destBytesPerRow = ((destWidth + 31) & ~31) / 8; destBits = Blt_Calloc(destHeight, destBytesPerRow); count = 0; srcPtr = Blt_ColorImageBits(image); for (y = 0; y < destHeight; y++) { for (x = 0; x < destWidth; x++) { if (srcPtr->Alpha == 0x00) { SetBit(x, y); count++; } srcPtr++; } } if (count > 0) { HBITMAP hBitmap; BITMAP bm; bm.bmType = 0; bm.bmWidth = Blt_ColorImageWidth(image); bm.bmHeight = Blt_ColorImageHeight(image); bm.bmWidthBytes = destBytesPerRow; bm.bmPlanes = 1; bm.bmBitsPixel = 1; bm.bmBits = destBits; hBitmap = CreateBitmapIndirect(&bm); twdPtr = Blt_Malloc(sizeof(TkWinBitmap)); assert(twdPtr); twdPtr->type = TWD_BITMAP; twdPtr->handle = hBitmap; twdPtr->depth = 1; if (Tk_WindowId(tkwin) == None) { twdPtr->colormap = DefaultColormap(Tk_Display(tkwin), DefaultScreen(Tk_Display(tkwin))); } else { twdPtr->colormap = Tk_Colormap(tkwin); } } else { twdPtr = NULL; } if (destBits != NULL) { Blt_Free(destBits); } return (Pixmap)twdPtr; } /* * ----------------------------------------------------------------- * * Blt_RotateBitmap -- * * Creates a new bitmap containing the rotated image of the given * bitmap. We also need a special GC of depth 1, so that we do * not need to rotate more than one plane of the bitmap. * * Note that under Windows, monochrome bitmaps are stored * bottom-to-top. This is why the right angle rotations 0/180 * and 90/270 look reversed. * * Results: * Returns a new bitmap containing the rotated image. * * ----------------------------------------------------------------- */ Pixmap Blt_RotateBitmap( Tk_Window tkwin, Pixmap srcBitmap, /* Source bitmap to be rotated */ int srcWidth, int srcHeight, /* Width and height of the source bitmap */ double theta, /* Right angle rotation to perform */ int *destWidthPtr, int *destHeightPtr) { Display *display; /* X display */ Window root; /* Root window drawable */ Pixmap destBitmap; double rotWidth, rotHeight; HDC hDC; TkWinDCState state; register int x, y; /* Destination bitmap coordinates */ register int sx, sy; /* Source bitmap coordinates */ unsigned long pixel; HBITMAP hBitmap; int result; struct MonoBitmap { BITMAPINFOHEADER bi; RGBQUAD colors[2]; } mb; int srcBytesPerRow, destBytesPerRow; int destWidth, destHeight; unsigned char *srcBits, *destBits; display = Tk_Display(tkwin); root = RootWindow(Tk_Display(tkwin), Tk_ScreenNumber(tkwin)); Blt_GetBoundingBox(srcWidth, srcHeight, theta, &rotWidth, &rotHeight, (Point2D *)NULL); destWidth = (int)ceil(rotWidth); destHeight = (int)ceil(rotHeight); destBitmap = Tk_GetPixmap(display, root, destWidth, destHeight, 1); if (destBitmap == None) { return None; /* Can't allocate pixmap. */ } srcBits = Blt_GetBitmapData(display, srcBitmap, srcWidth, srcHeight, &srcBytesPerRow); if (srcBits == NULL) { OutputDebugString("Blt_GetBitmapData failed"); return None; } destBytesPerRow = ((destWidth + 31) & ~31) / 8; destBits = Blt_Calloc(destHeight, destBytesPerRow); theta = FMOD(theta, 360.0); if (FMOD(theta, (double)90.0) == 0.0) { int quadrant; /* Handle right-angle rotations specially. */ quadrant = (int)(theta / 90.0); switch (quadrant) { case ROTATE_270: /* 270 degrees */ for (y = 0; y < destHeight; y++) { sx = y; for (x = 0; x < destWidth; x++) { sy = destWidth - x - 1; pixel = GetBit(sx, sy); if (pixel) { SetBit(x, y); } } } break; case ROTATE_180: /* 180 degrees */ for (y = 0; y < destHeight; y++) { sy = destHeight - y - 1; for (x = 0; x < destWidth; x++) { sx = destWidth - x - 1; pixel = GetBit(sx, sy); if (pixel) { SetBit(x, y); } } } break; case ROTATE_90: /* 90 degrees */ for (y = 0; y < destHeight; y++) { sx = destHeight - y - 1; for (x = 0; x < destWidth; x++) { sy = x; pixel = GetBit(sx, sy); if (pixel) { SetBit(x, y); } } } break; case ROTATE_0: /* 0 degrees */ for (y = 0; y < destHeight; y++) { for (x = 0; x < destWidth; x++) { pixel = GetBit(x, y); if (pixel) { SetBit(x, y); } } } break; default: /* The calling routine should never let this happen. */ break; } } else { double radians, sinTheta, cosTheta; double srcCX, srcCY; /* Center of source rectangle */ double destCX, destCY; /* Center of destination rectangle */ double tx, ty; double rx, ry; /* Angle of rotation for x and y coordinates */ radians = (theta / 180.0) * M_PI; sinTheta = sin(radians), cosTheta = cos(radians); /* * Coordinates of the centers of the source and destination rectangles */ srcCX = srcWidth * 0.5; srcCY = srcHeight * 0.5; destCX = destWidth * 0.5; destCY = destHeight * 0.5; /* Rotate each pixel of dest image, placing results in source image */ for (y = 0; y < destHeight; y++) { ty = y - destCY; for (x = 0; x < destWidth; x++) { /* Translate origin to center of destination image */ tx = x - destCX; /* Rotate the coordinates about the origin */ rx = (tx * cosTheta) - (ty * sinTheta); ry = (tx * sinTheta) + (ty * cosTheta); /* Translate back to the center of the source image */ rx += srcCX; ry += srcCY; sx = ROUND(rx); sy = ROUND(ry); /* * Verify the coordinates, since the destination image can be * bigger than the source */ if ((sx >= srcWidth) || (sx < 0) || (sy >= srcHeight) || (sy < 0)) { continue; } pixel = GetBit(sx, sy); if (pixel) { SetBit(x, y); } } } } hBitmap = ((TkWinDrawable *)destBitmap)->bitmap.handle; ZeroMemory(&mb, sizeof(mb)); mb.bi.biSize = sizeof(BITMAPINFOHEADER); mb.bi.biPlanes = 1; mb.bi.biBitCount = 1; mb.bi.biCompression = BI_RGB; mb.bi.biWidth = destWidth; mb.bi.biHeight = destHeight; mb.bi.biSizeImage = destBytesPerRow * destHeight; mb.colors[0].rgbBlue = mb.colors[0].rgbRed = mb.colors[0].rgbGreen = 0x0; mb.colors[1].rgbBlue = mb.colors[1].rgbRed = mb.colors[1].rgbGreen = 0xFF; hDC = TkWinGetDrawableDC(display, destBitmap, &state); result = SetDIBits(hDC, hBitmap, 0, destHeight, (LPVOID)destBits, (BITMAPINFO *)&mb, DIB_RGB_COLORS); TkWinReleaseDrawableDC(destBitmap, hDC, &state); if (!result) { #if WINDEBUG PurifyPrintf("can't setDIBits: %s\n", Blt_LastError()); #endif destBitmap = None; } if (destBits != NULL) { Blt_Free(destBits); } if (srcBits != NULL) { Blt_Free(srcBits); } *destWidthPtr = destWidth; *destHeightPtr = destHeight; return destBitmap; } /* * ----------------------------------------------------------------------- * * Blt_ScaleBitmap -- * * Creates a new scaled bitmap from another bitmap. * * Results: * The new scaled bitmap is returned. * * Side Effects: * A new pixmap is allocated. The caller must release this. * * ----------------------------------------------------------------------- */ Pixmap Blt_ScaleBitmap( Tk_Window tkwin, Pixmap srcBitmap, int srcWidth, int srcHeight, int destWidth, int destHeight) { TkWinDCState srcState, destState; HDC src, dest; Pixmap destBitmap; Window root; Display *display; /* Create a new bitmap the size of the region and clear it */ display = Tk_Display(tkwin); root = RootWindow(Tk_Display(tkwin), Tk_ScreenNumber(tkwin)); destBitmap = Tk_GetPixmap(display, root, destWidth, destHeight, 1); if (destBitmap == None) { return None; } src = TkWinGetDrawableDC(display, srcBitmap, &srcState); dest = TkWinGetDrawableDC(display, destBitmap, &destState); StretchBlt(dest, 0, 0, destWidth, destHeight, src, 0, 0, srcWidth, srcHeight, SRCCOPY); TkWinReleaseDrawableDC(srcBitmap, src, &srcState); TkWinReleaseDrawableDC(destBitmap, dest, &destState); return destBitmap; } /* * ----------------------------------------------------------------------- * * Blt_ScaleRotateBitmapRegion -- * * Creates a scaled and rotated bitmap from a given bitmap. The * caller also provides (offsets and dimensions) the region of * interest in the destination bitmap. This saves having to * process the entire destination bitmap is only part of it is * showing in the viewport. * * This uses a simple rotation/scaling of each pixel in the * destination image. For each pixel, the corresponding * pixel in the source bitmap is used. This means that * destination coordinates are first scaled to the size of * the rotated source bitmap. These coordinates are then * rotated back to their original orientation in the source. * * Results: * The new rotated and scaled bitmap is returned. * * Side Effects: * A new pixmap is allocated. The caller must release this. * * ----------------------------------------------------------------------- */ Pixmap Blt_ScaleRotateBitmapRegion( Tk_Window tkwin, Pixmap srcBitmap, /* Source bitmap. */ unsigned int srcWidth, unsigned int srcHeight, /* Size of source bitmap */ int regionX, int regionY, /* Offset of region in virtual * destination bitmap. */ unsigned int regionWidth, unsigned int regionHeight, /* Desire size of bitmap region. */ unsigned int virtWidth, unsigned int virtHeight, /* Virtual size of destination bitmap. */ double theta) /* Angle to rotate bitmap. */ { Display *display; /* X display */ HBITMAP hBitmap; HDC hDC; Pixmap destBitmap; TkWinDCState state; Window root; /* Root window drawable */ double rotWidth, rotHeight; double xScale, yScale; int srcBytesPerRow, destBytesPerRow; int destHeight; int result; register int sx, sy; /* Source bitmap coordinates */ register int x, y; /* Destination bitmap coordinates */ unsigned char *srcBits, *destBits; unsigned long pixel; struct MonoBitmap { BITMAPINFOHEADER bi; RGBQUAD colors[2]; } mb; display = Tk_Display(tkwin); root = RootWindow(Tk_Display(tkwin), Tk_ScreenNumber(tkwin)); /* Create a bitmap and image big enough to contain the rotated text */ destBitmap = Tk_GetPixmap(display, root, regionWidth, regionHeight, 1); if (destBitmap == None) { return None; /* Can't allocate pixmap. */ } srcBits = Blt_GetBitmapData(display, srcBitmap, srcWidth, srcHeight, &srcBytesPerRow); if (srcBits == NULL) { OutputDebugString("Blt_GetBitmapData failed"); return None; } destBytesPerRow = ((regionWidth + 31) & ~31) / 8; destBits = Blt_Calloc(regionHeight, destBytesPerRow); destHeight = regionHeight; theta = FMOD(theta, 360.0); Blt_GetBoundingBox(srcWidth, srcHeight, theta, &rotWidth, &rotHeight, (Point2D *)NULL); xScale = rotWidth / (double)virtWidth; yScale = rotHeight / (double)virtHeight; if (FMOD(theta, (double)90.0) == 0.0) { int quadrant; /* Handle right-angle rotations specifically */ quadrant = (int)(theta / 90.0); switch (quadrant) { case ROTATE_270: /* 270 degrees */ for (y = 0; y < (int)regionHeight; y++) { sx = (int)(yScale * (double)(y+regionY)); for (x = 0; x < (int)regionWidth; x++) { sy = (int)(xScale *(double)(virtWidth - (x+regionX) - 1)); pixel = GetBit(sx, sy); if (pixel) { SetBit(x, y); } } } break; case ROTATE_180: /* 180 degrees */ for (y = 0; y < (int)regionHeight; y++) { sy = (int)(yScale * (double)(virtHeight - (y + regionY) - 1)); for (x = 0; x < (int)regionWidth; x++) { sx = (int)(xScale *(double)(virtWidth - (x+regionX) - 1)); pixel = GetBit(sx, sy); if (pixel) { SetBit(x, y); } } } break; case ROTATE_90: /* 90 degrees */ for (y = 0; y < (int)regionHeight; y++) { sx = (int)(yScale * (double)(virtHeight - (y + regionY) - 1)); for (x = 0; x < (int)regionWidth; x++) { sy = (int)(xScale * (double)(x + regionX)); pixel = GetBit(sx, sy); if (pixel) { SetBit(x, y); } } } break; case ROTATE_0: /* 0 degrees */ for (y = 0; y < (int)regionHeight; y++) { sy = (int)(yScale * (double)(y + regionY)); for (x = 0; x < (int)regionWidth; x++) { sx = (int)(xScale * (double)(x + regionX)); pixel = GetBit(sx, sy); if (pixel) { SetBit(x, y); } } } break; default: /* The calling routine should never let this happen. */ break; } } else { double radians, sinTheta, cosTheta; double scx, scy; /* Offset from the center of the * source rectangle. */ double rcx, rcy; /* Offset to the center of the * rotated rectangle. */ double tx, ty; /* Translated coordinates from center */ double rx, ry; /* Angle of rotation for x and y coordinates */ radians = (theta / 180.0) * M_PI; sinTheta = sin(radians), cosTheta = cos(radians); /* * Coordinates of the centers of the source and destination rectangles */ scx = srcWidth * 0.5; scy = srcHeight * 0.5; rcx = rotWidth * 0.5; rcy = rotHeight * 0.5; /* For each pixel of the destination image, transform back to the * associated pixel in the source image. */ for (y = 0; y < (int)regionHeight; y++) { ty = (yScale * (double)(y + regionY)) - rcy; for (x = 0; x < (int)regionWidth; x++) { /* Translate origin to center of destination image. */ tx = (xScale * (double)(x + regionX)) - rcx; /* Rotate the coordinates about the origin. */ rx = (tx * cosTheta) - (ty * sinTheta); ry = (tx * sinTheta) + (ty * cosTheta); /* Translate back to the center of the source image. */ rx += scx; ry += scy; sx = ROUND(rx); sy = ROUND(ry); /* * Verify the coordinates, since the destination image can be * bigger than the source. */ if ((sx >= (int)srcWidth) || (sx < 0) || (sy >= (int)srcHeight) || (sy < 0)) { continue; } pixel = GetBit(sx, sy); if (pixel) { SetBit(x, y); } } } } /* Write the rotated image into the destination bitmap. */ hBitmap = ((TkWinDrawable *)destBitmap)->bitmap.handle; ZeroMemory(&mb, sizeof(mb)); mb.bi.biSize = sizeof(BITMAPINFOHEADER); mb.bi.biPlanes = 1; mb.bi.biBitCount = 1; mb.bi.biCompression = BI_RGB; mb.bi.biWidth = regionWidth; mb.bi.biHeight = regionHeight; mb.bi.biSizeImage = destBytesPerRow * regionHeight; mb.colors[0].rgbBlue = mb.colors[0].rgbRed = mb.colors[0].rgbGreen = 0x0; mb.colors[1].rgbBlue = mb.colors[1].rgbRed = mb.colors[1].rgbGreen = 0xFF; hDC = TkWinGetDrawableDC(display, destBitmap, &state); result = SetDIBits(hDC, hBitmap, 0, regionHeight, (LPVOID)destBits, (BITMAPINFO *)&mb, DIB_RGB_COLORS); TkWinReleaseDrawableDC(destBitmap, hDC, &state); if (!result) { #if WINDEBUG PurifyPrintf("can't setDIBits: %s\n", Blt_LastError()); #endif destBitmap = None; } if (destBits != NULL) { Blt_Free(destBits); } if (srcBits != NULL) { Blt_Free(srcBits); } return destBitmap; } #ifdef notdef /* *---------------------------------------------------------------------- * * Blt_BlendColorImage -- * * Takes a snapshot of an X drawable (pixmap or window) and * converts it to a color image. * * Results: * Returns a color image of the drawable. If an error occurred, * NULL is returned. * *---------------------------------------------------------------------- */ void Blt_BlendColorImage( Tk_Window tkwin, Drawable drawable, int width, int height, /* Dimension of the drawable. */ Region2D *regionPtr) /* Region to be snapped. */ { void *data; BITMAPINFO info; DIBSECTION ds; HBITMAP hBitmap, oldBitmap; HPALETTE hPalette; HDC memDC; unsigned char *srcArr; register unsigned char *srcPtr; HDC hDC; TkWinDCState state; register Pix32 *destPtr; Blt_ColorImage image; register int x, y; if (regionPtr == NULL) { regionPtr = Blt_SetRegion(0, 0, ColorImageWidth(image), ColorImageHeight(image), ®ion); } if (regionPtr->left < 0) { regionPtr->left = 0; } if (regionPtr->right >= destWidth) { regionPtr->right = destWidth - 1; } if (regionPtr->top < 0) { regionPtr->top = 0; } if (regionPtr->bottom >= destHeight) { regionPtr->bottom = destHeight - 1; } width = RegionWidth(regionPtr); height = RegionHeight(regionPtr); hDC = TkWinGetDrawableDC(display, drawable, &state); /* Create the intermediate drawing surface at window resolution. */ ZeroMemory(&info, sizeof(info)); info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); info.bmiHeader.biWidth = width; info.bmiHeader.biHeight = height; info.bmiHeader.biPlanes = 1; info.bmiHeader.biBitCount = 32; info.bmiHeader.biCompression = BI_RGB; hBitmap = CreateDIBSection(hDC, &info, DIB_RGB_COLORS, &data, NULL, 0); memDC = CreateCompatibleDC(hDC); oldBitmap = SelectBitmap(memDC, hBitmap); hPalette = Blt_GetSystemPalette(); if (hPalette != NULL) { SelectPalette(hDC, hPalette, FALSE); RealizePalette(hDC); SelectPalette(memDC, hPalette, FALSE); RealizePalette(memDC); } image = NULL; /* Copy the window contents to the memory surface. */ if (!BitBlt(memDC, 0, 0, width, height, hDC, regionPtr->left, regionPtr->top, SRCCOPY)) { #ifdef notdef PurifyPrintf("can't blit: %s\n", Blt_LastError()); #endif goto done; } if (GetObject(hBitmap, sizeof(DIBSECTION), &ds) == 0) { #ifdef notdef PurifyPrintf("can't get object: %s\n", Blt_LastError()); #endif goto done; } srcArr = (unsigned char *)ds.dsBm.bmBits; image = Blt_CreateColorImage(width, height); destPtr = Blt_ColorImageBits(image); /* * Copy the DIB RGB data into the color image. The DIB scanlines * are stored bottom-to-top and the order of the RGBA color * components is BGRA. Who says Win32 GDI programming isn't * backwards? */ for (y = height - 1; y >= 0; y--) { srcPtr = srcArr + (y * ds.dsBm.bmWidthBytes); for (x = 0; x < width; x++) { if (destPtr->Alpha > 0) { /* Blend colorimage with background. */ destPtr->Blue = *srcPtr++; destPtr->Green = *srcPtr++; destPtr->Red = *srcPtr++; destPtr->Alpha = (unsigned char)-1; srcPtr++; } destPtr++; } } done: DeleteBitmap(SelectBitmap(memDC, oldBitmap)); DeleteDC(memDC); TkWinReleaseDrawableDC(drawable, hDC, &state); if (hPalette != NULL) { DeletePalette(hPalette); } return image; } #endif #ifdef HAVE_IJL_H #include Blt_ColorImage Blt_JPEGToColorImage(interp, fileName) Tcl_Interp *interp; char *fileName; { JPEG_CORE_PROPERTIES jpgProps; Blt_ColorImage image; ZeroMemory(&jpgProps, sizeof(JPEG_CORE_PROPERTIES)); if(ijlInit(&jpgProps) != IJL_OK) { Tcl_AppendResult(interp, "can't initialize Intel JPEG library", (char *)NULL); return NULL; } jpgProps.JPGFile = fileName; if (ijlRead(&jpgProps, IJL_JFILE_READPARAMS) != IJL_OK) { Tcl_AppendResult(interp, "can't read JPEG file header from \"", fileName, "\" file.", (char *)NULL); goto error; } // !dudnik: to fix bug case 584680, [OT:287A305B] // Set the JPG color space ... this will always be // somewhat of an educated guess at best because JPEG // is "color blind" (i.e., nothing in the bit stream // tells you what color space the data was encoded from). // However, in this example we assume that we are // reading JFIF files which means that 3 channel images // are in the YCbCr color space and 1 channel images are // in the Y color space. switch(jpgProps.JPGChannels) { case 1: jpgProps.JPGColor = IJL_G; jpgProps.DIBChannels = 4; jpgProps.DIBColor = IJL_RGBA_FPX; break; case 3: jpgProps.JPGColor = IJL_YCBCR; jpgProps.DIBChannels = 4; jpgProps.DIBColor = IJL_RGBA_FPX; break; case 4: jpgProps.JPGColor = IJL_YCBCRA_FPX; jpgProps.DIBChannels = 4; jpgProps.DIBColor = IJL_RGBA_FPX; break; default: /* This catches everything else, but no color twist will be performed by the IJL. */ jpgProps.DIBColor = (IJL_COLOR)IJL_OTHER; jpgProps.JPGColor = (IJL_COLOR)IJL_OTHER; jpgProps.DIBChannels = jpgProps.JPGChannels; break; } jpgProps.DIBWidth = jpgProps.JPGWidth; jpgProps.DIBHeight = jpgProps.JPGHeight; jpgProps.DIBPadBytes = IJL_DIB_PAD_BYTES(jpgProps.DIBWidth, jpgProps.DIBChannels); image = Blt_CreateColorImage(jpgProps.JPGWidth, jpgProps.JPGHeight); jpgProps.DIBBytes = (BYTE *)Blt_ColorImageBits(image); if (ijlRead(&jpgProps, IJL_JFILE_READWHOLEIMAGE) != IJL_OK) { Tcl_AppendResult(interp, "can't read image data from \"", fileName, "\"", (char *)NULL); goto error; } if (ijlFree(&jpgProps) != IJL_OK) { fprintf(stderr, "can't free Intel(R) JPEG library\n"); } return image; error: ijlFree(&jpgProps); if (image != NULL) { Blt_FreeColorImage(image); } ijlFree(&jpgProps); return NULL; } #else #ifdef HAVE_JPEGLIB_H #undef HAVE_STDLIB_H #undef EXTERN #ifdef WIN32 #define XMD_H 1 #endif #include "jpeglib.h" #include typedef struct { struct jpeg_error_mgr pub; /* "public" fields */ jmp_buf jmpBuf; Tcl_DString dString; } ReaderHandler; static void ErrorProc _ANSI_ARGS_((j_common_ptr jpegInfo)); static void MessageProc _ANSI_ARGS_((j_common_ptr jpegInfo)); /* * Here's the routine that will replace the standard error_exit method: */ static void ErrorProc(jpgPtr) j_common_ptr jpgPtr; { ReaderHandler *handlerPtr = (ReaderHandler *)jpgPtr->err; (*handlerPtr->pub.output_message) (jpgPtr); longjmp(handlerPtr->jmpBuf, 1); } static void MessageProc(jpgPtr) j_common_ptr jpgPtr; { ReaderHandler *handlerPtr = (ReaderHandler *)jpgPtr->err; char buffer[JMSG_LENGTH_MAX]; /* Create the message and append it into the dynamic string. */ (*handlerPtr->pub.format_message) (jpgPtr, buffer); Tcl_DStringAppend(&(handlerPtr->dString), " ", -1); Tcl_DStringAppend(&(handlerPtr->dString), buffer, -1); } /* *---------------------------------------------------------------------- * * Blt_JPEGToColorImage -- * * Reads a JPEG file and converts it into a color image. * * Results: * The color image is returned. If an error occured, such * as the designated file could not be opened, NULL is returned. * *---------------------------------------------------------------------- */ Blt_ColorImage Blt_JPEGToColorImage(interp, fileName) Tcl_Interp *interp; char *fileName; { struct jpeg_decompress_struct jpg; Blt_ColorImage image; unsigned int imageWidth, imageHeight; register Pix32 *destPtr; ReaderHandler handler; FILE *f; JSAMPLE **readBuffer; int row_stride; register int i; register JSAMPLE *bufPtr; f = fopen(fileName, "rb"); if (f == NULL) { Tcl_AppendResult(interp, "can't open \"", fileName, "\":", Tcl_PosixError(interp), (char *)NULL); return NULL; } image = NULL; /* Step 1: allocate and initialize JPEG decompression object */ /* We set up the normal JPEG error routines, then override error_exit. */ jpg.dct_method = JDCT_IFAST; jpg.err = jpeg_std_error(&handler.pub); handler.pub.error_exit = ErrorProc; handler.pub.output_message = MessageProc; Tcl_DStringInit(&handler.dString); Tcl_DStringAppend(&handler.dString, "error reading \"", -1); Tcl_DStringAppend(&handler.dString, fileName, -1); Tcl_DStringAppend(&handler.dString, "\": ", -1); if (setjmp(handler.jmpBuf)) { jpeg_destroy_decompress(&jpg); fclose(f); Tcl_DStringResult(interp, &(handler.dString)); return NULL; } jpeg_create_decompress(&jpg); jpeg_stdio_src(&jpg, f); jpeg_read_header(&jpg, TRUE); /* Step 3: read file parameters */ jpeg_start_decompress(&jpg); /* Step 5: Start decompressor */ imageWidth = jpg.output_width; imageHeight = jpg.output_height; if ((imageWidth < 1) || (imageHeight < 1)) { Tcl_AppendResult(interp, "bad JPEG image size", (char *)NULL); fclose(f); return NULL; } /* JSAMPLEs per row in output buffer */ row_stride = imageWidth * jpg.output_components; /* Make a one-row-high sample array that will go away when done * with image */ readBuffer = (*jpg.mem->alloc_sarray) ((j_common_ptr)&jpg, JPOOL_IMAGE, row_stride, 1); image = Blt_CreateColorImage(imageWidth, imageHeight); destPtr = Blt_ColorImageBits(image); if (jpg.output_components == 1) { while (jpg.output_scanline < imageHeight) { jpeg_read_scanlines(&jpg, readBuffer, 1); bufPtr = readBuffer[0]; for (i = 0; i < (int)imageWidth; i++) { destPtr->Red = destPtr->Green = destPtr->Blue = *bufPtr++; destPtr->Alpha = (unsigned char)-1; destPtr++; } } } else { while (jpg.output_scanline < imageHeight) { jpeg_read_scanlines(&jpg, readBuffer, 1); bufPtr = readBuffer[0]; for (i = 0; i < (int)imageWidth; i++) { destPtr->Red = *bufPtr++; destPtr->Green = *bufPtr++; destPtr->Blue = *bufPtr++; destPtr->Alpha = (unsigned char)-1; destPtr++; } } } jpeg_finish_decompress(&jpg); /* We can ignore the return value * since suspension is not * possible with the stdio data * source. */ jpeg_destroy_decompress(&jpg); /* * After finish_decompress, we can close the input file. Here we * postpone it until after no more JPEG errors are possible, so as * to simplify the setjmp error logic above. (Actually, I don't * think that jpeg_destroy can do an error exit, but why assume * anything...) */ fclose(f); /* * At this point you may want to check to see whether any corrupt-data * warnings occurred (test whether jerr.pub.num_warnings is nonzero). */ if (handler.pub.num_warnings > 0) { Tcl_SetErrorCode(interp, "IMAGE", "JPEG", Tcl_DStringValue(&(handler.dString)), (char *)NULL); } else { Tcl_SetErrorCode(interp, "NONE", (char *)NULL); } /* * We're ready to call the Tk_Photo routines. They'll take the RGB * array we've processed to build the Tk image of the JPEG. */ Tcl_DStringFree(&(handler.dString)); return image; } #endif /* HAVE_JPEGLIB_H */ #endif /* HAVE_IJL_H */ blt-2.4z.orig/src/bltWinMain.c0100644000175000017500000002327207514116170014753 0ustar dokodoko /* * bltWinMain.c -- * * Main entry point for wish and other Tk-based applications. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * SCCS: @(#) winMain.c 1.37 98/01/20 22:47:06 */ #include "bltInt.h" #include /* * Forward declarations for procedures defined later in this file: */ static void setargv _ANSI_ARGS_((int *argcPtr, char ***argvPtr)); #if (TCL_VERSION_NUMBER >= _VERSION(8,2,0)) static BOOL consoleRequired = TRUE; #endif extern EXPORT int Blt_Init(Tcl_Interp *interp); extern EXPORT int Blt_SafeInit(Tcl_Interp *interp); static Tcl_AppInitProc AppInit; /* *------------------------------------------------------------------------- * * setargv -- * * Parse the Windows command line string into argc/argv. Done here * because we don't trust the builtin argument parser in crt0. * Windows applications are responsible for breaking their command * line into arguments. * * 2N backslashes + quote -> N backslashes + begin quoted string * 2N + 1 backslashes + quote -> literal * N backslashes + non-quote -> literal * quote + quote in a quoted string -> single quote * quote + quote not in quoted string -> empty string * quote -> begin quoted string * * Results: * Fills argcPtr with the number of arguments and argvPtr with the * array of arguments. * * Side effects: * Memory allocated. * *-------------------------------------------------------------------------- */ static void setargv( int *argcPtr, /* Filled with number of argument strings. */ char ***argvPtr) { /* Filled with argument strings (malloc'd). */ char *cmdLine, *p, *arg, *argSpace; char **argv; int argc, size, inquote, copy, slashes; cmdLine = GetCommandLine(); /* INTL: BUG */ /* * Precompute an overly pessimistic guess at the number of arguments * in the command line by counting non-space spans. */ size = 2; for (p = cmdLine; *p != '\0'; p++) { if ((*p == ' ') || (*p == '\t')) { /* INTL: ISO space. */ size++; while ((*p == ' ') || (*p == '\t')) { /* INTL: ISO space. */ p++; } if (*p == '\0') { break; } } } argSpace = (char *)Tcl_Alloc( (unsigned)(size * sizeof(char *) + strlen(cmdLine) + 1)); argv = (char **)argSpace; argSpace += size * sizeof(char *); size--; p = cmdLine; for (argc = 0; argc < size; argc++) { argv[argc] = arg = argSpace; while ((*p == ' ') || (*p == '\t')) { /* INTL: ISO space. */ p++; } if (*p == '\0') { break; } inquote = 0; slashes = 0; while (1) { copy = 1; while (*p == '\\') { slashes++; p++; } if (*p == '"') { if ((slashes & 1) == 0) { copy = 0; if ((inquote) && (p[1] == '"')) { p++; copy = 1; } else { inquote = !inquote; } } slashes >>= 1; } while (slashes) { *arg = '\\'; arg++; slashes--; } if ((*p == '\0') || (!inquote && ((*p == ' ') || (*p == '\t')))) { /* INTL: ISO space. */ break; } if (copy != 0) { *arg = *p; arg++; } p++; } *arg = '\0'; argSpace = arg + 1; } argv[argc] = NULL; *argcPtr = argc; *argvPtr = argv; } #ifdef TCL_ONLY /* *---------------------------------------------------------------------- * * main -- * * This is the main program for the application. * * Results: * None: Tcl_Main never returns here, so this procedure never * returns either. * * Side effects: * Whatever the application does. * *---------------------------------------------------------------------- */ int main(argc, argv) int argc; /* Number of command-line arguments. */ char **argv; /* Values of command-line arguments. */ { char buffer[MAX_PATH +1]; char *p; /* * Set up the default locale to be standard "C" locale so parsing * is performed correctly. */ setlocale(LC_ALL, "C"); setargv(&argc, &argv); /* * Replace argv[0] with full pathname of executable, and forward * slashes substituted for backslashes. */ GetModuleFileName(NULL, buffer, sizeof(buffer)); argv[0] = buffer; for (p = buffer; *p != '\0'; p++) { if (*p == '\\') { *p = '/'; } } Tcl_Main(argc, argv, AppInit); return 0; /* Needed only to prevent compiler warning. */ } #else /* TCL_ONLY */ #if (TK_VERSION_NUMBER < _VERSION(8,2,0)) /* * The following declarations refer to internal Tk routines. These * interfaces are available for use, but are not supported. */ extern void TkConsoleCreate(void); extern int TkConsoleInit(Tcl_Interp *interp); #endif /* TK_VERSION_NUMBER < 8.2.0 */ /* *---------------------------------------------------------------------- * * WishPanic -- * * Display a message and exit. * * Results: * None. * * Side effects: * Exits the program. * *---------------------------------------------------------------------- */ void WishPanic TCL_VARARGS_DEF(char *, arg1) { va_list argList; char buf[1024]; CONST char *format; format = TCL_VARARGS_START(char *, arg1, argList); vsprintf(buf, format, argList); MessageBeep(MB_ICONEXCLAMATION); MessageBox(NULL, buf, "Fatal Error in Wish", MB_ICONSTOP | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND); #if defined(_MSC_VER) || defined(__BORLANDC__) DebugBreak(); #ifdef notdef /* Panics shouldn't cause exceptions. * Simply let the program exit. */ _asm { int 3 } #endif #endif /* _MSC_VER || __BORLANDC__ */ ExitProcess(1); } /* *---------------------------------------------------------------------- * * WinMain -- * * Main entry point from Windows. * * Results: * Returns false if initialization fails, otherwise it never * returns. * * Side effects: * Just about anything, since from here we call arbitrary Tcl code. * *---------------------------------------------------------------------- */ int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { char **argv; int argc; Tcl_SetPanicProc(WishPanic); /* * Set up the default locale to be standard "C" locale so parsing * is performed correctly. */ setlocale(LC_ALL, "C"); setargv(&argc, &argv); /* * Increase the application queue size from default value of 8. * At the default value, cross application SendMessage of WM_KILLFOCUS * will fail because the handler will not be able to do a PostMessage! * This is only needed for Windows 3.x, since NT dynamically expands * the queue. */ SetMessageQueue(64); /* * Create the console channels and install them as the standard * channels. All I/O will be discarded until TkConsoleInit is * called to attach the console to a text widget. */ #if (TCL_VERSION_NUMBER >= _VERSION(8,2,0)) consoleRequired = TRUE; #else TkConsoleCreate(); #endif Tk_Main(argc, argv, AppInit); return 1; } #endif /* TCL_ONLY */ /* *---------------------------------------------------------------------- * * AppInit -- * * This procedure performs application-specific initialization. * Most applications, especially those that incorporate additional * packages, will have their own version of this procedure. * * Results: * Returns a standard Tcl completion code, and leaves an error * message in the interp's result if an error occurs. * * Side effects: * Depends on the startup script. * *---------------------------------------------------------------------- */ #ifdef TCL_ONLY static int AppInit(Tcl_Interp *interp) { /* Interpreter for application. */ #ifdef TCLLIBPATH /* * It seems that some distributions of Tcl don't compile-in a * default location of the library. This causes Tcl_Init to fail * if bltwish and bltsh are moved to another directory. The * workaround is to set the magic variable "tclDefaultLibrary". */ Tcl_SetVar(interp, "tclDefaultLibrary", TCLLIBPATH, TCL_GLOBAL_ONLY); #endif if (Tcl_Init(interp) == TCL_ERROR) { return TCL_ERROR; } if (Blt_Init(interp) == TCL_ERROR) { return TCL_ERROR; } Tcl_StaticPackage(interp, "Blt", Blt_Init, Blt_SafeInit); Tcl_SetVar(interp, "tcl_rcFileName", "~/tclshrc.tcl", TCL_GLOBAL_ONLY); return TCL_OK; } #else static int AppInit(Tcl_Interp *interp) { /* Interpreter for application. */ #ifdef TCLLIBPATH /* * It seems that some distributions of Tcl don't compile-in a * default location of the library. This causes Tcl_Init to fail * if bltwish and bltsh are moved to another directory. The * workaround is to set the magic variable "tclDefaultLibrary". */ Tcl_SetVar(interp, "tclDefaultLibrary", TCLLIBPATH, TCL_GLOBAL_ONLY); #endif if (Tcl_Init(interp) == TCL_ERROR) { goto error; } if (Tk_Init(interp) == TCL_ERROR) { goto error; } Tcl_StaticPackage(interp, "Tk", Tk_Init, Tk_SafeInit); if (Blt_Init(interp) == TCL_ERROR) { goto error; } Tcl_StaticPackage(interp, "Blt", Blt_Init, Blt_SafeInit); /* * Initialize the console only if we are running as an interactive * application. */ #if (TCL_VERSION_NUMBER >= _VERSION(8,2,0)) if (consoleRequired) { if (Tk_CreateConsoleWindow(interp) == TCL_ERROR) { goto error; } } #else /* * Initialize the console only if we are running as an interactive * application. */ if (TkConsoleInit(interp) == TCL_ERROR) { goto error; } #endif /* TCL_VERSION_NUMBER >= 8.2.0 */ Tcl_SetVar(interp, "tcl_rcFileName", "~/wishrc.tcl", TCL_GLOBAL_ONLY); return TCL_OK; error: /* WishPanic(Tcl_GetStringResult(interp)); */ return TCL_ERROR; } #endif /* TCL_ONLY */ blt-2.4z.orig/src/bltWinPipe.c0100644000175000017500000020562707526260721014777 0ustar dokodoko /* * bltWinPipe.c -- * * Lifted from tclPipe.c and tclWinPipe.c in the Tcl * distribution, this is the first step toward freedom from the * tyranny of the former Tcl_CreatePipeline API. * * This file contains the generic portion of the command channel * driver as well as various utility routines used in managing * subprocesses. * * [It's not clear why we needed a whole new API for I/O. Channels * are one of the few losing propositions in Tcl. While it's easy * to see that one needs to handle the different platform I/O * semantics in a coherent fashion, it's usually better to pick * an API from one of platforms (hopefully a mature, well-known model) * and crowbar the other platforms to follow that. At least then * you're working from a known set of sematics. With Tcl Channels, * no one's an expert and the interface is incomplete.] * * Copyright (c) 1997 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * */ /* * Todo: * Test on win95 * Does terminating bltwish kill child processes? * Handle EOL translation more cleanly. */ #include "bltInt.h" #include "bltChain.h" #include #define PEEK_DEBUG 0 #define QUEUE_DEBUG 0 #define READER_DEBUG 0 #define ASYNC_DEBUG 0 #define KILL_DEBUG 0 typedef struct { DWORD pid; HANDLE hProcess; } Process; /* * The following type identifies the various types of applications that * run under windows. There is special case code for the various types. */ typedef enum ApplicationTypes { APPL_NONE, APPL_DOS, APPL_WIN3X, APPL_WIN32, APPL_INTERP } ApplicationType; #ifndef IMAGE_OS2_SIGNATURE # define IMAGE_OS2_SIGNATURE (0x454E) #endif #ifndef IMAGE_VXD_SIGNATURE # define IMAGE_VXD_SIGNATURE (0x454C) #endif #define PIPE_BUFSIZ (BUFSIZ*2) /* Size of pipe read buffer. */ #define PIPE_PENDING (1<<13) /* Message is pending in the queue. */ #define PIPE_EOF (1<<14) /* Pipe has reached EOF. */ #define PIPE_DELETED (1<<15) /* Indicates if the pipe has been deleted * but its memory hasn't been freed yet. */ typedef struct { int flags; /* State flags, see above for a list. */ HANDLE hPipe; /* Pipe handle */ HANDLE thread; /* Thread watching I/O on this pipe. */ HANDLE parent; /* Handle of main thread. */ DWORD parentId; /* Main thread ID. */ HWND hWindow; /* Notifier window in main thread. Used to * goose the Tcl notifier system indicating * that an event has occurred that it * needs to process. */ HANDLE idleEvent; /* Signals that the pipe is idle (no one * is reading/writing from it). */ HANDLE readyEvent; /* Signals that the pipe is ready for * the next I/O operation. */ DWORD lastError; /* Error. */ char *buffer; /* Current background output buffer. */ size_t start, end; /* Pointers into the output buffer */ size_t size; /* Size of buffer. */ Tcl_FileProc *proc; ClientData clientData; } PipeHandler; typedef struct { Tcl_Event header; /* Information that is standard for * all events. */ PipeHandler *pipePtr; /* Pointer to pipe handler structure. * Note that we still have to verify * that the pipe exists before * dereferencing this pointer. */ } PipeEvent; static int initialized = 0; static Blt_Chain pipeChain; static CRITICAL_SECTION pipeCriticalSection; static DWORD WINAPI PipeWriterThread(void *clientData); static DWORD WINAPI PipeReaderThread(void *clientData); static Tcl_FreeProc DestroyPipe; extern void Blt_MapPid(HANDLE hProcess, DWORD pid); extern HINSTANCE TclWinGetTclInstance(void); extern void TclWinConvertError(DWORD lastError); /* *---------------------------------------------------------------------- * * NotifierWindowProc -- * * This procedure is called to "goose" the Tcl notifier layer to * service pending events. The notifier layer is built upon the * Windows message system. It may need to be awakened if it's * blocked waiting on messages, since synthetic events (i.e. * data available on a pipe) won't do that. There may be events * pending in the Tcl queue, but the Windows message system knows * nothing about Tcl events and won't unblock until the next * message arrives (whenever that may be). * * This callback is triggered by messages posted to the notifier * window (we set up earlier) from the reader/writer pipe * threads. It's purpose is to 1) unblock Windows (posting the * message does that) and 2) call Tcl_ServiceAll from the main * thread. It has to be called from the main thread, not * directly from the pipe threads. * * Results: * A standard Windows result. * * Side effects: * Services any pending Tcl events. * *---------------------------------------------------------------------- */ static LRESULT CALLBACK NotifierWindowProc( HWND hWindow, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_USER: case WM_TIMER: break; default: return DefWindowProc(hWindow, message, wParam, lParam); } Tcl_ServiceAll(); /* Process all run-able events. */ return 0; } static void WakeupNotifier(HWND hWindow) { PostMessage(hWindow, WM_USER, 0, 0); } /* *---------------------------------------------------------------------- * * GetNotifierWindow -- * * Initializes the platform specific notifier state. * * Results: * Returns a handle to the notifier state for this thread.. * * Side effects: * None. * *---------------------------------------------------------------------- */ static HWND GetNotifierWindow(void) { static HWND hWindow = NULL; /* * Register Notifier window class if this is the first thread to * use this module. */ if (hWindow == NULL) { WNDCLASS class; HINSTANCE hInstance; memset(&class, 0, sizeof(WNDCLASS)); hInstance = TclWinGetTclInstance(); class.hInstance = hInstance; class.lpszClassName = "PipeNotifier"; class.lpfnWndProc = NotifierWindowProc; if (!RegisterClassA(&class)) { panic("Unable to register PipeNotifier window class"); } /* * Create a window for communication with the notifier. */ hWindow = CreateWindowA("PipeNotifier", "PipeNotifier", WS_TILED, 0, 0, 0, 0, NULL, NULL, hInstance, NULL); } return hWindow; } /* *---------------------------------------------------------------------- * * PeekOnPipe -- * * See if some data is available, the pipe is at EOF, or the * reader thread is currently blocked waiting for data. * * Results: * Return TRUE if data is available, FALSE if otherwise. Note * that errors and EOF always return TRUE. We always make the * condition available until the caller handles it by deleting * the pipe event handler. * * On TRUE, the number of bytes returned indicates the following: * 0 EOF. * -1 An error has occured or the thread is currently * blocked reading. In that last case, errno is set * to EAGAIN. * >0 Number of bytes of data in the buffer. * *---------------------------------------------------------------------- */ static int PeekOnPipe( PipeHandler *pipePtr, /* Pipe state. */ int *nAvailPtr) { int state; *nAvailPtr = -1; #if PEEK_DEBUG PurifyPrintf("PEEK(%d): waiting for reader\n", pipePtr->hPipe); #endif state = WaitForSingleObject(pipePtr->readyEvent, 0); #if PEEK_DEBUG PurifyPrintf("PEEK(%d): state is %d\n", pipePtr->hPipe, state); #endif if (state == WAIT_TIMEOUT) { #if PEEK_DEBUG PurifyPrintf("PEEK(%d): try again, %d\n", pipePtr->hPipe, state); #endif errno = EAGAIN; return FALSE; /* Reader thread is currently blocked. */ } /* * At this point the two threads are synchronized. So it's safe * to access shared information. */ if (state == WAIT_OBJECT_0) { int nAvail; nAvail = pipePtr->end - pipePtr->start; #if PEEK_DEBUG PurifyPrintf("PEEK(%d): Found %d bytes available\n", pipePtr->hPipe, nAvail); #endif if ((nAvail <= 0) && !(pipePtr->flags & PIPE_EOF)) { TclWinConvertError(pipePtr->lastError); #if PEEK_DEBUG PurifyPrintf("PEEK(%d): Error = %d\n", pipePtr->hPipe, pipePtr->lastError); #endif nAvail = -1; } *nAvailPtr = nAvail; } #if PEEK_DEBUG PurifyPrintf("PEEK(%d): Reseting events\n", pipePtr->hPipe); #endif return TRUE; } /* *---------------------------------------------------------------------- * * PipeEventProc -- * * This function is invoked by Tcl_ServiceEvent when a file event * reaches the front of the event queue. This procedure calls back * the handler procedure designated for this pipe. * * Results: * Returns 1 if the event was handled, meaning it should be removed * from the queue. Returns 0 if the event was not handled, meaning * it should stay on the queue. The only time the event isn't * handled is if the TCL_FILE_EVENTS flag bit isn't set. * * Side effects: * Whatever the pipe handler callback does. * *---------------------------------------------------------------------- */ static int PipeEventProc(Tcl_Event * eventPtr, int flags) { PipeHandler *pipePtr; if (!(flags & TCL_FILE_EVENTS)) { return 0; } pipePtr = ((PipeEvent *) eventPtr)->pipePtr; if ((pipePtr != NULL) && !(pipePtr->flags & PIPE_DELETED)) { Tcl_Preserve(pipePtr); if (pipePtr->proc != NULL) { (*pipePtr->proc) (pipePtr->clientData, flags); } /* Allow more events again. */ pipePtr->flags &= ~PIPE_PENDING; Tcl_Release(pipePtr); } return 1; } /* *---------------------------------------------------------------------- * * SetupHandlers -- * * This procedure is invoked before Tcl_DoOneEvent blocks waiting * for an event. * * Results: * None. * * Side effects: * Adjusts the block time if needed. * *---------------------------------------------------------------------- */ void SetupHandlers(ClientData clientData, int flags) { Blt_Chain *chainPtr = (Blt_Chain *) clientData; register PipeHandler *pipePtr; Blt_ChainLink *linkPtr; int dontBlock, nBytes; Tcl_Time blockTime; if (!(flags & TCL_FILE_EVENTS)) { return; } /* * Loop through the list of pipe handlers. Check if any I/O * events are currently pending. */ dontBlock = FALSE; blockTime.sec = blockTime.usec = 0L; #if QUEUE_DEBUG PurifyPrintf("SetupHandlers: before loop\n"); #endif for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { pipePtr = Blt_ChainGetValue(linkPtr); if (pipePtr->flags & PIPE_DELETED) { continue; /* Ignore pipes pending to be freed. */ } if (pipePtr->flags & TCL_READABLE) { if (PeekOnPipe(pipePtr, &nBytes)) { dontBlock = TRUE; } } if (pipePtr->flags & TCL_WRITABLE) { if (WaitForSingleObject(pipePtr->readyEvent, 0) != WAIT_TIMEOUT) { dontBlock = TRUE; } } } #if QUEUE_DEBUG PurifyPrintf("SetupHandlers: after loop\n"); #endif if (dontBlock) { Tcl_SetMaxBlockTime(&blockTime); } } /* *---------------------------------------------------------------------- * * CheckHandlers -- * * This procedure is called by Tcl_DoOneEvent to check the pipe * event source for events. * * Results: * None. * * Side effects: * May queue an event. * *---------------------------------------------------------------------- */ static void CheckHandlers(ClientData clientData, int flags) { Blt_Chain *chainPtr = (Blt_Chain *) clientData; PipeHandler *pipePtr; Blt_ChainLink *linkPtr; int queueEvent, nBytes; if ((flags & TCL_FILE_EVENTS) == 0) { return; } /* Queue events for any ready pipes that aren't already queued. */ for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { pipePtr = Blt_ChainGetValue(linkPtr); if (pipePtr->flags & (PIPE_PENDING | PIPE_DELETED)) { continue; /* If this pipe already is scheduled to * service an event, wait for it to handle * it. */ } /* Queue an event if the pipe is signaled for reading or writing. */ queueEvent = FALSE; if (pipePtr->flags & TCL_READABLE) { if (PeekOnPipe(pipePtr, &nBytes)) { queueEvent = TRUE; } } if (pipePtr->flags & TCL_WRITABLE) { if (WaitForSingleObject(pipePtr->readyEvent, 0) != WAIT_TIMEOUT) { queueEvent = TRUE; } } #if QUEUE_DEBUG PurifyPrintf("Queue event is %d \n", queueEvent); #endif if (queueEvent) { PipeEvent *eventPtr; pipePtr->flags |= PIPE_PENDING; eventPtr = Blt_Malloc(sizeof(PipeEvent)); assert(eventPtr); eventPtr->header.proc = PipeEventProc; eventPtr->pipePtr = pipePtr; Tcl_QueueEvent((Tcl_Event *) eventPtr, TCL_QUEUE_TAIL); } } } static PipeHandler * CreatePipeHandler(HANDLE hFile, int flags) { DWORD id; PipeHandler *pipePtr; LPTHREAD_START_ROUTINE threadProc; pipePtr = Blt_Calloc(1, sizeof(PipeHandler)); assert(pipePtr); pipePtr->hPipe = hFile; pipePtr->flags = flags; pipePtr->parentId = GetCurrentThreadId(); pipePtr->parent = GetCurrentThread(); pipePtr->hWindow = GetNotifierWindow(); pipePtr->readyEvent = CreateEvent( NULL, /* Security attributes. */ TRUE, /* Manual reset event */ FALSE, /* Initially not signaled. */ NULL); /* Event object's name. */ pipePtr->idleEvent = CreateEvent( NULL, /* Security attributes. */ FALSE, /* Auto reset event. */ TRUE, /* Initially signaled. */ NULL); /* Event object's name. */ if (flags & TCL_READABLE) { threadProc = (LPTHREAD_START_ROUTINE) PipeReaderThread; pipePtr->buffer = Blt_Calloc(1, PIPE_BUFSIZ); pipePtr->size = PIPE_BUFSIZ; } else { threadProc = (LPTHREAD_START_ROUTINE) PipeWriterThread; } pipePtr->thread = CreateThread( NULL, /* Security attributes */ 8000, /* Initial stack size. */ threadProc, /* Starting address of thread routine */ (DWORD *) pipePtr, /* One-word of data passed to routine. */ 0, /* Creation flags */ &id); /* (out) Will contain Id of new thread. */ return pipePtr; } static void DestroyPipe(DestroyData data) { PipeHandler *pipePtr = (PipeHandler *)data; if (pipePtr->buffer != NULL) { Blt_Free(pipePtr->buffer); } Blt_Free(pipePtr); } static void DeletePipeHandler(PipeHandler * pipePtr) { #if KILL_DEBUG PurifyPrintf("DestroyPipeHandler(%d)\n", pipePtr->hPipe); #endif if ((pipePtr->flags & TCL_WRITABLE) && (pipePtr->hPipe != INVALID_HANDLE_VALUE)) { /* Wait for the writer thread to finish with the current buffer */ WaitForSingleObject(pipePtr->idleEvent, INFINITE); } if (pipePtr->hPipe != INVALID_HANDLE_VALUE) { CloseHandle(pipePtr->hPipe); } CloseHandle(pipePtr->readyEvent); CloseHandle(pipePtr->idleEvent); CloseHandle(pipePtr->thread); pipePtr->idleEvent = pipePtr->readyEvent = INVALID_HANDLE_VALUE; pipePtr->thread = pipePtr->hPipe = INVALID_HANDLE_VALUE; pipePtr->flags |= PIPE_DELETED; /* Mark the pipe has deleted. */ Tcl_EventuallyFree(pipePtr, DestroyPipe); } /* *---------------------------------------------------------------------- * * PipeInit -- * * This function initializes the static variables for this file. * * Results: * None. * * Side effects: * Creates a new event source. * *---------------------------------------------------------------------- */ static void PipeInit(void) { initialized = TRUE; InitializeCriticalSection(&pipeCriticalSection); Blt_ChainInit(&pipeChain); Tcl_CreateEventSource(SetupHandlers, CheckHandlers, &pipeChain); } static PipeHandler * GetPipeHandler(HANDLE hPipe) { PipeHandler *pipePtr; Blt_ChainLink *linkPtr; for (linkPtr = Blt_ChainFirstLink(&pipeChain); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { pipePtr = Blt_ChainGetValue(linkPtr); if ((pipePtr->hPipe == hPipe) && !(pipePtr->flags & PIPE_DELETED)){ return pipePtr; } } return NULL; } /* *---------------------------------------------------------------------- * * Blt_PipeTeardown -- * * This function releases any storage allocated for this file. * * Results: * None. * * Side effects: * Creates a new event source. * *---------------------------------------------------------------------- */ void Blt_PipeTeardown(void) { Blt_ChainLink *linkPtr; PipeHandler *pipePtr; if (!initialized) { return; /* Was never initialized. */ } initialized = FALSE; EnterCriticalSection(&pipeCriticalSection); for (linkPtr = Blt_ChainFirstLink(&pipeChain); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { pipePtr = Blt_ChainGetValue(linkPtr); if ((pipePtr != NULL) && !(pipePtr->flags & PIPE_DELETED)) { DeletePipeHandler(pipePtr); } } DestroyWindow(GetNotifierWindow()); UnregisterClassA("PipeNotifier", TclWinGetTclInstance()); Blt_ChainReset(&pipeChain); LeaveCriticalSection(&pipeCriticalSection); Tcl_DeleteEventSource(SetupHandlers, CheckHandlers, &pipeChain); DeleteCriticalSection(&pipeCriticalSection); } /* *---------------------------------------------------------------------- * * PipeReaderThread -- * * This function runs in a separate thread and waits for input * to become available on a pipe. * * Results: * None. * * Side effects: * Signals the main thread when input become available. May * cause the main thread to wake up by posting a message. * *---------------------------------------------------------------------- */ static DWORD WINAPI PipeReaderThread(void *clientData) { PipeHandler *pipePtr = (PipeHandler *) clientData; DWORD count; BOOL result; for (;;) { if (pipePtr->flags & PIPE_DELETED) { break; } /* Synchronize with the main thread so that we don't try to * read from the pipe while it's copying to the buffer. */ #if READER_DEBUG PurifyPrintf("READER(%d): waiting\n", pipePtr->hPipe); #endif WaitForSingleObject(pipePtr->idleEvent, INFINITE); #if READER_DEBUG PurifyPrintf("READER(%d): ok\n", pipePtr->hPipe); #endif /* Read from the pipe. The thread will block here until some * data is read into its buffer. */ #if READER_DEBUG PurifyPrintf("READER(%d): before read\n", pipePtr->hPipe); #endif assert(pipePtr->start == pipePtr->end); result = ReadFile( pipePtr->hPipe, /* Handle to anonymous pipe. */ pipePtr->buffer, /* Data buffer. */ pipePtr->size, /* Requested number of bytes (the size * of the buffer) */ &count, /* (out) Number of bytes actually read. */ NULL); /* Overlapping I/O */ if (result) { #if READER_DEBUG PurifyPrintf("READER(%d): after read. status=%d, count=%d\n", pipePtr->hPipe, result, count); #endif } /* * Reset counters to indicate that the buffer has been refreshed. */ pipePtr->start = 0; pipePtr->end = count; if (count == 0) { /* We've hit EOF or an error. */ pipePtr->lastError = GetLastError(); if ((pipePtr->lastError == ERROR_BROKEN_PIPE) || (pipePtr->lastError == ERROR_HANDLE_EOF)) { pipePtr->flags |= PIPE_EOF; } #if READER_DEBUG PurifyPrintf("READER(%d): error is %s\n", pipePtr->hPipe, Blt_LastError()); #endif } WakeupNotifier(pipePtr->hWindow); SetEvent(pipePtr->readyEvent); if (count == 0) { #if READER_DEBUG PurifyPrintf("READER(%d): exiting\n", pipePtr->hPipe); #endif ExitThread(0); } } /* NOTREACHED */ return 0; } /* *---------------------------------------------------------------------- * * PipeWriterThread -- * * This function runs in a separate thread and writes data * to the process' standard input pipe. * * Results: * Always returns 0. * * Side effects: * Signals the main thread when an output operation is completed. * May cause the main thread to wake up by posting a message. * *---------------------------------------------------------------------- */ static DWORD WINAPI PipeWriterThread(void *clientData) { PipeHandler *pipePtr = (PipeHandler *) clientData; DWORD count, bytesLeft; register char *ptr; for (;;) { if (pipePtr->flags & PIPE_DELETED) { break; } /* * Synchronize with the main thread so that we don't test the * pipe until its done writing. */ WaitForSingleObject(pipePtr->idleEvent, INFINITE); ptr = pipePtr->buffer; bytesLeft = pipePtr->end; /* Loop until all of the bytes are written or an error occurs. */ while (bytesLeft > 0) { if (!WriteFile(pipePtr->hPipe, ptr, bytesLeft, &count, NULL)) { pipePtr->lastError = GetLastError(); break; } bytesLeft -= count; ptr += count; } /* Tell the main thread that data can be written to the pipe. * Remember to wake up the notifier thread. */ SetEvent(pipePtr->readyEvent); WakeupNotifier(pipePtr->hWindow); } /* NOTREACHED */ return 0; } /* *---------------------------------------------------------------------- * * TempFileName -- * * Gets a temporary file name and deals with the fact that the * temporary file path provided by Windows may not actually exist * if the TMP or TEMP environment variables refer to a * non-existent directory. * * Results: * 0 if error, non-zero otherwise. If non-zero is returned, the * name buffer will be filled with a name that can be used to * construct a temporary file. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TempFileName(char *name) /* (out) Buffer to hold name of * temporary file. */ { if ((GetTempPath(MAX_PATH, name) > 0) && (GetTempFileName(name, "TCL", 0, name))) { return 1; } /* Bail out and use the current working directory. */ return GetTempFileName(".", "TCL", 0, name); } /* *---------------------------------------------------------------------- * * OpenRedirectFile -- * * Open a file for use in a pipeline. * * Results: * Returns a new handle or NULL on failure. * * Side effects: * May cause a file to be created on the file system. * *---------------------------------------------------------------------- */ static HANDLE OpenRedirectFile( const char *path, DWORD accessFlags, DWORD createFlags) { HANDLE hFile; DWORD attribFlags; int useExisting; attribFlags = 0; useExisting = (createFlags & (TRUNCATE_EXISTING | OPEN_EXISTING)); if (useExisting) { attribFlags = GetFileAttributes(path); if (attribFlags == 0xFFFFFFFF) { attribFlags = 0; } } hFile = CreateFile(path, accessFlags, /* Access mode flags */ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, /* No security */ createFlags, /* Creation attributes */ attribFlags, /* File attribute flags */ NULL); /* Template file */ if (hFile == INVALID_HANDLE_VALUE) { DWORD lastError; lastError = GetLastError(); if ((lastError & 0xffffL) == ERROR_OPEN_FAILED) { lastError = (useExisting) ? ERROR_FILE_NOT_FOUND : ERROR_FILE_EXISTS; } TclWinConvertError(lastError); return INVALID_HANDLE_VALUE; } /* * Seek to the end of file if we are writing. */ if (createFlags & GENERIC_WRITE) { SetFilePointer(hFile, 0, NULL, FILE_END); } return hFile; } /* *---------------------------------------------------------------------- * * CreateTempFile -- * * This function creates a temporary file initialized with an * optional string, and returns a file handle with the file pointer * at the beginning of the file. * * Results: * A handle to a file. * * Side effects: * None. * *---------------------------------------------------------------------- */ static HANDLE CreateTempFile(const char *data) /* String to write into temp file, or * NULL. */ { char fileName[MAX_PATH + 1]; HANDLE hFile; DWORD lastError; if (!TempFileName(fileName)) { return INVALID_HANDLE_VALUE; } hFile = CreateFile( fileName, /* File path */ GENERIC_READ | GENERIC_WRITE, /* Access mode */ 0, /* No sharing. */ NULL, /* Security attributes */ CREATE_ALWAYS, /* Overwrite any existing file */ FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL); /* No template file */ if (hFile == INVALID_HANDLE_VALUE) { goto error; } if (data != NULL) { DWORD result, length; const char *p; const char *string; string = data; for (p = string; *p != '\0'; p++) { if (*p == '\n') { length = p - string; if (length > 0) { if (!WriteFile(hFile, string, length, &result, NULL)) { goto error; } } if (!WriteFile(hFile, "\r\n", 2, &result, NULL)) { goto error; } string = p + 1; } } length = p - string; if (length > 0) { if (!WriteFile(hFile, string, length, &result, NULL)) { goto error; } } if (SetFilePointer(hFile, 0, NULL, FILE_BEGIN) == (DWORD) - 1) { goto error; } } return hFile; error: lastError = GetLastError(); CloseHandle(hFile); DeleteFile(fileName); /* Do I need this? Delete on close? */ TclWinConvertError(lastError); return INVALID_HANDLE_VALUE; } /* *---------------------------------------------------------------------- * * HasConsole -- * * Determines whether the current application is attached to a * console. * * Results: * Returns TRUE if this application has a console, else FALSE. * * Side effects: * None. * *---------------------------------------------------------------------- */ static BOOL HasConsole(void) { HANDLE hFile; hFile = CreateFileA("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { return FALSE; } CloseHandle(hFile); return TRUE; } static ApplicationType GetApplicationType(const char *file, char *cmdPrefix) { char *dot; HANDLE hFile; IMAGE_DOS_HEADER imageDosHeader; ULONG signature; BOOL result; DWORD offset; DWORD nBytes; ApplicationType type; dot = strrchr(file, '.'); if ((dot != NULL) && (strcasecmp(dot, ".bat") == 0)) { return APPL_DOS; } /* Work a little harder. Open the binary and read the header */ hFile = CreateFileA(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { return APPL_NONE; } type = APPL_NONE; result = ReadFile(hFile, &imageDosHeader, sizeof(IMAGE_DOS_HEADER), &nBytes, NULL); if ((!result) || (nBytes != sizeof(IMAGE_DOS_HEADER))) { goto done; } #if KILL_DEBUG PurifyPrintf("magic number is %x\n", imageDosHeader.e_magic); #endif if (imageDosHeader.e_magic == 0x2123) { /* #! */ register char *p; register unsigned int i; offset = SetFilePointer(hFile, 2, NULL, FILE_BEGIN); if (offset == (DWORD) - 1) { goto done; } result = ReadFile(hFile, cmdPrefix, MAX_PATH + 1, &nBytes, NULL); if ((!result) || (nBytes < 1)) { goto done; } for (p = cmdPrefix, i = 0; i < nBytes; i++, p++) { if ((*p == '\n') || (*p == '\r')) { break; } } *p = '\0'; type = APPL_INTERP; goto done; } /* * Doesn't have the magic number for relocatable executables. If * filename ends with .com, assume it's a DOS application anyhow. * Note that we didn't make this assumption at first, because some * supposed .com files are really 32-bit executables with all the * magic numbers and everything. */ if ((dot != NULL) && (strcmp(dot, ".com") == 0)) { #if KILL_DEBUG PurifyPrintf(".com\n"); #endif type = APPL_DOS; goto done; } if (imageDosHeader.e_magic != IMAGE_DOS_SIGNATURE) { #if KILL_DEBUG PurifyPrintf("Application doesn't have correct sig?\n"); #endif } if (imageDosHeader.e_lfarlc != sizeof(IMAGE_DOS_HEADER)) { /* This assumes that all 3.x and Win32 programs have their * file relocation table immediately following this header. */ /* * All Windows 3.X and Win32 and some DOS programs have this value * set here. If it doesn't, assume that since it already had the * other magic number it was a DOS application. */ #if KILL_DEBUG PurifyPrintf("wrong reloc table address\n"); #endif type = APPL_DOS; goto done; } offset = SetFilePointer(hFile, imageDosHeader.e_lfanew, NULL, FILE_BEGIN); if (offset == (DWORD) - 1) { goto done; } result = ReadFile(hFile, &signature, sizeof(ULONG), &nBytes, NULL); if ((!result) || (nBytes != sizeof(ULONG))) { goto done; } #if KILL_DEBUG PurifyPrintf("signature is %x\n", signature); #endif switch (signature) { case IMAGE_NT_SIGNATURE: type = APPL_WIN32; break; case IMAGE_OS2_SIGNATURE: type = APPL_WIN3X; break; case IMAGE_VXD_SIGNATURE: type = APPL_WIN32; break; default: type = APPL_DOS; break; } done: CloseHandle(hFile); return type; } /* *---------------------------------------------------------------------- * * GetFullPath -- * * Look for the program as an external program. First try the * name as it is, then try adding .com, .exe, and .bat, in that * order, to the name, looking for an executable. * * Using the raw SearchPath() procedure doesn't do quite what is * necessary. If the name of the executable already contains a * '.' character, it will not try appending the specified * extension when searching (in other words, SearchPath will * not find the program "a.b.exe" if the arguments specified * "a.b" and ".exe"). So, first look for the file as it is * named. Then manually append extensions, looking for a * match. * * Results: * Always returns TCL_OK. * * Side Effects: * *---------------------------------------------------------------------- */ static int GetFullPath( Tcl_Interp *interp, /* Interpreter to report errors to */ const char *program, /* Name of program. */ char *fullPath, /* (out) Returned full path. */ char *cmdPrefix, /* (out) If program is a script, this contains * the name of the interpreter. */ ApplicationType * typePtr) { /* (out) Type of program */ TCHAR *rest; DWORD attr; int length; char cmd[MAX_PATH + 5]; register char **p; static char *dosExts[] = { "", ".com", ".exe", ".bat", NULL }; *typePtr = APPL_NONE; length = strlen(program); strcpy(cmd, program); cmdPrefix[0] = '\0'; for (p = dosExts; *p != NULL; p++) { cmd[length] = '\0'; /* Reset to original program name. */ strcat(cmd, *p); /* Append the DOS extension to the * program name. */ if (!SearchPath( NULL, /* Use standard Windows search paths */ cmd, /* Program name */ NULL, /* Extension provided by program name. */ MAX_PATH, /* Buffer size */ fullPath, /* Buffer for absolute path of program */ &rest)) { continue; /* Can't find program with that extension */ } /* * Ignore matches on directories or data files. * Return when we identify a known program type. */ attr = GetFileAttributesA(fullPath); if ((attr == (DWORD)-1) || (attr & FILE_ATTRIBUTE_DIRECTORY)) { continue; } *typePtr = GetApplicationType(fullPath, cmdPrefix); if (*typePtr != APPL_NONE) { break; } } if (*typePtr == APPL_NONE) { /* * Can't find the program. Check if it's an internal shell command * like "copy" or "dir" and let cmd.exe deal with it. */ static char *shellCmds[] = { "copy", "del", "dir", "echo", "edit", "erase", "label", "md", "rd", "ren", "start", "time", "type", "ver", "vol", NULL }; for (p = shellCmds; *p != NULL; p++) { if (((*p)[0] == program[0]) && (strcmp(*p, program) == 0)) { break; } } if (*p == NULL) { Tcl_AppendResult(interp, "can't execute \"", program, "\": no such file or directory", (char *)NULL); return TCL_ERROR; } *typePtr = APPL_DOS; strcpy(fullPath, program); } if ((*typePtr == APPL_DOS) || (*typePtr == APPL_WIN3X)) { /* For 16-bit applications, convert the long executable path * name to a short one. Otherwise the application may not be * able to correctly parse its own command line. */ GetShortPathName(fullPath, fullPath, MAX_PATH); } return TCL_OK; } /* *---------------------------------------------------------------------- * * ConcatCmdArgs -- * * Concatonates command line arguments parsed from Tcl into a * single string. If an argument contain spaces, it is grouped * with surrounding double quotes. Must also escape any quotes we * find. * * Results: * Returns a malloc-ed string containing the concatonated command * line. * *---------------------------------------------------------------------- */ static char * ConcatCmdArgs( int argc, char **argv, Tcl_DString *resultPtr) { BOOL needQuote; register const char *s; register char *cp; char *string; /* Will contain the new command line */ register int count; register int i; /* * Pass 1. Compute how much space we need for an array to hold the entire * command line. Then allocate the string. */ count = 0; for (i = 0; i < argc; i++) { needQuote = FALSE; if (*argv[i] == '\0') { needQuote = TRUE; /* Zero length args also need quotes. */ } for (s = argv[i]; *s != '\0'; s++) { if (*s == '"') { register const char *bp; count++; /* +1 Backslash needed to escape quote */ for (bp = s - 1; (*bp == '\\') && (bp >= argv[i]); bp--) { count++; /* +? one for each preceding backslash */ } } else if (isspace(*s)) { needQuote = TRUE; } count++; /* +1 Normal character */ } if (needQuote) { count += 2; /* +2 Pair of quotes */ } count++; /* +1 Space separating arguments */ } string = Blt_Malloc(count + 1); assert(string); /* * Pass 2. Copy the arguments, quoting arguments with embedded spaces and * escaping all other quotes in the string. */ cp = string; for (i = 0; i < argc; i++) { needQuote = FALSE; if (*argv[i] == '\0') { needQuote = TRUE; } for (s = argv[i]; *s != '\0'; s++) { if (isspace(*s)) { needQuote = TRUE; } } if (needQuote) { *cp++ = '"'; } for (s = argv[i]; *s; s++) { if (*s == '"') { register const char *bp; for (bp = s - 1; (*bp == '\\') && (bp >= argv[i]); bp--) { *cp++ = '\\'; } *cp++ = '\\'; } *cp++ = *s; } if (needQuote) { *cp++ = '"'; } *cp++ = ' '; } *cp = '\0'; assert((cp - string) == count); Tcl_DStringAppend(resultPtr, string, count); Blt_Free(string); return Tcl_DStringValue(resultPtr); } /* *---------------------------------------------------------------------- * * StartProcess -- * * Create a child process that has the specified files as its * standard input, output, and error. * * The complete Windows search path is searched to find the specified * executable. If an executable by the given name is not found, * automatically tries appending ".com", ".exe", and ".bat" to the * executable name. * * Results: * The return value is TCL_ERROR and an error message is left in * the interp's result if there was a problem creating the child * process. Otherwise, the return value is TCL_OK and *pidPtr is * filled with the process id of the child process. * * Side effects: * A process is created. * *---------------------------------------------------------------------- */ static int StartProcess( Tcl_Interp *interp, /* Interpreter to report errors that * occurred when creating the child process. * Error messages from the child process * itself are sent to errorFile. */ int argc, /* Number of arguments. */ char **argv, /* Command line arguments. */ HANDLE hStdin, /* File handle to use as input (stdin) for the * child process. If handle is -1, no * standard input. */ HANDLE hStdout, /* File handle to receive output (stdout) * from the child process. If -1, output * is discarded. */ HANDLE hStderr, /* File handle to receive errors (stderr) * from the child process. If -1, stderr * will be discarded. Can be the same handle * as hStdOut */ HANDLE *hProcessPtr, /* (out) Handle of child process. */ DWORD *pidPtr) /* (out) Id of child process. */ { int result, createFlags; ApplicationType applType; Tcl_DString dString; /* Complete command line */ char *command; BOOL hasConsole; #ifdef notdef DWORD idleResult; #endif STARTUPINFOA si; PROCESS_INFORMATION pi; SECURITY_ATTRIBUTES securityAttrs; HANDLE hProcess, hPipe; char progPath[MAX_PATH]; char cmdPrefix[MAX_PATH]; *hProcessPtr = INVALID_HANDLE_VALUE; GetFullPath(interp, argv[0], progPath, cmdPrefix, &applType); #if KILL_DEBUG PurifyPrintf("Application type is %d\n", (int)applType); #endif if (applType == APPL_NONE) { return TCL_ERROR; } result = TCL_ERROR; hProcess = GetCurrentProcess(); ZeroMemory(&si, sizeof(STARTUPINFOA)); si.cb = sizeof(STARTUPINFOA); /* * The flag STARTF_USESTDHANDLES must be set to pass handles to * the child process. Using SetStdHandle and/or dup2 works only * when a console mode parent process is spawning an attached * console mode child process. */ si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = si.hStdOutput = si.hStdError = INVALID_HANDLE_VALUE; securityAttrs.nLength = sizeof(SECURITY_ATTRIBUTES); securityAttrs.lpSecurityDescriptor = NULL; securityAttrs.bInheritHandle = TRUE; /* * Duplicate all the handles to be passed off as stdin, stdout and * stderr of the child process. The duplicate handles are set to * be inheritable, so the child process can use them. */ if (hStdin == INVALID_HANDLE_VALUE) { /* * If handle was not set, stdin should return immediate EOF. * Under Windows95, some applications (both 16 and 32 bit!) * can't read from the NUL device; they read from console * instead. When running tk, this is fatal because the child * process would hang forever waiting for EOF from the unmapped * console window used by the helper application. * * Fortunately, the helper application detects a closed pipe * as an immediate EOF and can pass that information to the * child process. */ if (CreatePipe(&si.hStdInput, &hPipe, &securityAttrs, 0)) { CloseHandle(hPipe); } } else { DuplicateHandle(hProcess, hStdin, hProcess, &si.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS); } if (si.hStdInput == INVALID_HANDLE_VALUE) { Tcl_AppendResult(interp, "can't duplicate input handle: ", Blt_LastError(), (char *)NULL); goto closeHandles; } if (hStdout == INVALID_HANDLE_VALUE) { /* * If handle was not set, output should be sent to an infinitely * deep sink. Under Windows 95, some 16 bit applications cannot * have stdout redirected to NUL; they send their output to * the console instead. Some applications, like "more" or "dir /p", * when outputting multiple pages to the console, also then try and * read from the console to go the next page. When running tk, this * is fatal because the child process would hang forever waiting * for input from the unmapped console window used by the helper * application. * * Fortunately, the helper application will detect a closed pipe * as a sink. */ if ((Blt_GetPlatformId() == VER_PLATFORM_WIN32_WINDOWS) && (applType == APPL_DOS)) { if (CreatePipe(&hPipe, &si.hStdOutput, &securityAttrs, 0)) { CloseHandle(hPipe); } } else { si.hStdOutput = CreateFileA("NUL:", GENERIC_WRITE, 0, &securityAttrs, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); } } else { DuplicateHandle(hProcess, hStdout, hProcess, &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS); } if (si.hStdOutput == INVALID_HANDLE_VALUE) { Tcl_AppendResult(interp, "can't duplicate output handle: ", Blt_LastError(), (char *)NULL); goto closeHandles; } if (hStderr == INVALID_HANDLE_VALUE) { /* * If handle was not set, errors should be sent to an infinitely * deep sink. */ si.hStdError = CreateFileA("NUL:", GENERIC_WRITE, 0, &securityAttrs, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); } else { DuplicateHandle(hProcess, hStderr, hProcess, &si.hStdError, 0, TRUE, DUPLICATE_SAME_ACCESS); } if (si.hStdError == INVALID_HANDLE_VALUE) { Tcl_AppendResult(interp, "can't duplicate error handle: ", Blt_LastError(), (char *)NULL); goto closeHandles; } Tcl_DStringInit(&dString); createFlags = 0; hasConsole = HasConsole(); if (!hasConsole) { createFlags |= DETACHED_PROCESS; } /* * If we do not have a console window, then we must run DOS and * WIN32 console mode applications as detached processes. This tells * the loader that the child application should not inherit the * console, and that it should not create a new console window for * the child application. The child application should get its stdio * from the redirection handles provided by this application, and run * in the background. * * If we are starting a GUI process, they don't automatically get a * console, so it doesn't matter if they are started as foreground or * detached processes. The GUI window will still pop up to the * foreground. */ if (applType == APPL_DOS) { if (Blt_GetPlatformId() == VER_PLATFORM_WIN32_NT) { /* * Under NT, 16-bit DOS applications will not run unless they * can be attached to a console. If we are running without a * console, run the 16-bit program as an normal process inside * of a hidden console application, and then run that hidden * console as a detached process. */ si.wShowWindow = SW_HIDE; si.dwFlags |= STARTF_USESHOWWINDOW; createFlags = CREATE_NEW_CONSOLE; Tcl_DStringAppend(&dString, "cmd.exe /c ", -1); } else { /* * Under Windows 95, 16-bit DOS applications do not work well * with pipes: * * 1. EOF on a pipe between a detached 16-bit DOS application * and another application is not seen at the other * end of the pipe, so the listening process blocks forever on * reads. This inablity to detect EOF happens when either a * 16-bit app or the 32-bit app is the listener. * * 2. If a 16-bit DOS application (detached or not) blocks when * writing to a pipe, it will never wake up again, and it * eventually brings the whole system down around it. * * The 16-bit application is run as a normal process * inside of a hidden helper console app, and this helper * may be run as a detached process. If a stdio handle is * a pipe, the helper application accumulates information * into temp files and forwards it to or from the DOS * application as appropriate. This means that DOS apps * must receive EOF from a stdin pipe before they will * actually begin, and must finish generating stdout or * stderr before the data will be sent to the next stage * of the pipe. * * The helper app should be located in the same directory * as the tcl dll. */ if (!hasConsole) { si.wShowWindow = SW_HIDE; si.dwFlags |= STARTF_USESHOWWINDOW; createFlags = CREATE_NEW_CONSOLE; } Tcl_DStringAppend(&dString, "tclpip" STRINGIFY(TCL_MAJOR_VERSION) STRINGIFY(TCL_MINOR_VERSION) ".dll ", -1); } } else if (applType == APPL_INTERP) { Tcl_DStringAppend(&dString, cmdPrefix, -1); Tcl_DStringAppend(&dString, " ", -1); } argv[0] = progPath; command = ConcatCmdArgs(argc, argv, &dString); #if KILL_DEBUG PurifyPrintf("command is %s\n", command); #endif result = CreateProcess( NULL, /* Module name. */ (TCHAR *)command, /* Command line */ NULL, /* Process security */ NULL, /* Thread security */ TRUE, /* Inherit handles */ createFlags, /* Creation flags */ NULL, /* Environment */ NULL, /* Current working directory */ &si, /* Initialization for process: includes * standard handles, appearance and location * of window */ &pi); /* (out) Information about newly created process */ Tcl_DStringFree(&dString); if (!result) { Tcl_AppendResult(interp, "can't execute \"", argv[0], "\": ", Blt_LastError(), (char *)NULL); goto closeHandles; } #if KILL_DEBUG PurifyPrintf("Starting process with handle of %d\n", pi.hProcess); PurifyPrintf("Starting process with id of %d\n", pi.dwProcessId); #endif if (applType == APPL_DOS) { /* Force the OS to give some time to the DOS process. */ WaitForSingleObject(hProcess, 50); } #ifdef notdef /* FIXME: I don't think this actually * ever worked. WaitForInputIdle * usually fails with "Access is * denied" (maybe the process handle * isn't valid yet?). When you add a * delay, WaitForInputIdle will time * out instead. */ /* * PSS ID Number: Q124121 * * "When an application spawns a process repeatedly, a new * thread instance will be created for each process but the * previous instances may not be cleaned up. This results in * a significant virtual memory loss each time the process is * spawned. If there is a WaitForInputIdle() call between * CreateProcess() and CloseHandle(), the problem does not * occur." */ idleResult = WaitForInputIdle(pi.hProcess, 1000); if (idleResult == (DWORD) - 1) { #if KILL_DEBUG PurifyPrintf("wait failed on %d: %s\n", pi.hProcess, Blt_LastError()); #endif } #endif CloseHandle(pi.hThread); *hProcessPtr = pi.hProcess; /* * Add the entry to mapping table. Its purpose is to translate * process handles to process ids. Most things we do with the * Win32 API take handles, but we still want to present process * ids to the user. */ *pidPtr = pi.dwProcessId; result = TCL_OK; closeHandles: if (si.hStdInput != INVALID_HANDLE_VALUE) { CloseHandle(si.hStdInput); } if (si.hStdOutput != INVALID_HANDLE_VALUE) { CloseHandle(si.hStdOutput); } if (si.hStdError != INVALID_HANDLE_VALUE) { CloseHandle(si.hStdError); } return result; } /* *---------------------------------------------------------------------- * * FileForRedirect -- * * This procedure does much of the work of parsing redirection * operators. It handles "@" if specified and allowed, and a file * name, and opens the file if necessary. * * Results: * The return value is the descriptor number for the file. If an * error occurs then NULL is returned and an error message is left * in interp->result. Several arguments are side-effected; see * the argument list below for details. * * Side effects: * None. * *---------------------------------------------------------------------- */ static HANDLE FileForRedirect( Tcl_Interp *interp, /* Intepreter to use for error reporting. */ char *spec, /* Points to character just after * redirection character. */ BOOL atOK, /* Non-zero means that '@' notation can be * used to specify a channel, zero means that * it isn't. */ char *arg, /* Pointer to entire argument containing * spec: used for error reporting. */ char *nextArg, /* Next argument in argc/argv array, if needed * for file name or channel name. May be * NULL. */ DWORD accessFlags, /* Flags to use for opening file or to * specify mode for channel. */ DWORD createFlags, /* Flags to use for opening file or to * specify mode for channel. */ int *skipPtr, /* Filled with 1 if redirection target was * in spec, 2 if it was in nextArg. */ int *closePtr) /* Filled with one if the caller should * close the file when done with it, zero * otherwise. */ { int writing = (accessFlags & GENERIC_WRITE); Tcl_Channel chan; HANDLE hFile; *skipPtr = 1; *closePtr = FALSE; if ((atOK) && (*spec == '@')) { spec++; if (*spec == '\0') { spec = nextArg; if (spec == NULL) { goto badLastArg; } *skipPtr = 2; } chan = Tcl_GetChannel(interp, spec, NULL); if (chan == NULL) { return INVALID_HANDLE_VALUE; } if (Tcl_GetChannelHandle(chan, (writing) ? TCL_WRITABLE : TCL_READABLE, (ClientData *)&hFile) != TCL_OK) { hFile = INVALID_HANDLE_VALUE; } if (hFile == INVALID_HANDLE_VALUE) { Tcl_AppendResult(interp, "channel \"", Tcl_GetChannelName(chan), "\" wasn't opened for ", ((writing) ? "writing" : "reading"), (char *)NULL); return INVALID_HANDLE_VALUE; } if (writing) { /* * Be sure to flush output to the file, so that anything * written by the child appears after stuff we've already * written. */ Tcl_Flush(chan); } } else { char *name; Tcl_DString dString; if (*spec == '\0') { spec = nextArg; if (spec == NULL) { goto badLastArg; } *skipPtr = 2; } name = Tcl_TranslateFileName(interp, spec, &dString); if (name != NULL) { hFile = OpenRedirectFile(name, accessFlags, createFlags); } else { hFile = INVALID_HANDLE_VALUE; } Tcl_DStringFree(&dString); if (hFile == INVALID_HANDLE_VALUE) { Tcl_AppendResult(interp, "can't ", (writing) ? "write" : "read", " file \"", spec, "\": ", Tcl_PosixError(interp), (char *)NULL); return INVALID_HANDLE_VALUE; } *closePtr = TRUE; } return hFile; badLastArg: Tcl_AppendResult(interp, "can't specify \"", arg, "\" as last word in command", (char *)NULL); return INVALID_HANDLE_VALUE; } /* *---------------------------------------------------------------------- * * Blt_CreatePipeline -- * * Given an argc/argv array, instantiate a pipeline of processes * as described by the argv. * * Results: * The return value is a count of the number of new processes * created, or -1 if an error occurred while creating the pipeline. * *pidArrayPtr is filled in with the address of a dynamically * allocated array giving the ids of all of the processes. It * is up to the caller to free this array when it isn't needed * anymore. If inPipePtr is non-NULL, *inPipePtr is filled in * with the file id for the input pipe for the pipeline (if any): * the caller must eventually close this file. If outPipePtr * isn't NULL, then *outPipePtr is filled in with the file id * for the output pipe from the pipeline: the caller must close * this file. If errPipePtr isn't NULL, then *errPipePtr is filled * with a file id that may be used to read error output after the * pipeline completes. * * Side effects: * Processes and pipes are created. * *---------------------------------------------------------------------- */ int Blt_CreatePipeline( Tcl_Interp *interp, /* Interpreter to use for error reporting. */ int argc, /* Number of entries in argv. */ char **argv, /* Array of strings describing commands in * pipeline plus I/O redirection with <, * <<, >, etc. Argv[argc] must be NULL. */ Process **procArrPtr, /* *procArrPtr gets filled in with * address of array of pids for processes * in pipeline (first pid is first process * in pipeline). */ int *inPipePtr, /* If non-NULL, input to the pipeline comes * from a pipe (unless overridden by * redirection in the command). The file * id with which to write to this pipe is * stored at *inPipePtr. NULL means command * specified its own input source. */ int *outPipePtr, /* If non-NULL, output to the pipeline goes * to a pipe, unless overriden by redirection * in the command. The file id with which to * read frome this pipe is stored at * *outPipePtr. NULL means command specified * its own output sink. */ int *errPipePtr) /* If non-NULL, all stderr output from the * pipeline will go to a temporary file * created here, and a descriptor to read * the file will be left at *errPipePtr. * The file will be removed already, so * closing this descriptor will be the end * of the file. If this is NULL, then * all stderr output goes to our stderr. * If the pipeline specifies redirection * then the file will still be created * but it will never get any data. */ { Process *procArr = NULL; /* Points to malloc-ed array holding all * the handles of child processes. */ int nPids; /* Actual number of processes that exist * at *procArr right now. */ int cmdCount; /* Count of number of distinct commands * found in argc/argv. */ char *inputLiteral = NULL; /* If non-null, then this points to a * string containing input data (specified * via <<) to be piped to the first process * in the pipeline. */ HANDLE hStdin; /* If != -1, gives file to use as input for * first process in pipeline (specified via < * or <@). */ BOOL closeStdin; /* If non-zero, then hStdin should be * closed when cleaning up. */ HANDLE hStdout; /* Writable file for output from last command * in pipeline (could be file or pipe). NULL * means use stdout. */ BOOL closeStdout; /* If non-zero, then hStdout should be * closed when cleaning up. */ HANDLE hStderr; /* Writable file for error output from all * commands in pipeline. NULL means use * stderr. */ BOOL closeStderr; /* If non-zero, then hStderr should be * closed when cleaning up. */ HANDLE hInPipe, hOutPipe, hErrPipe; char *p; int skip, lastBar, lastArg, i, j, flags; int pid; BOOL atOK, errorToOutput; Tcl_DString dString; HANDLE hPipe; HANDLE thisInput, thisOutput, thisError; if (inPipePtr != NULL) { *inPipePtr = -1; } if (outPipePtr != NULL) { *outPipePtr = -1; } if (errPipePtr != NULL) { *errPipePtr = -1; } Tcl_DStringInit(&dString); hStdin = hStdout = hStderr = INVALID_HANDLE_VALUE; hPipe = thisInput = thisOutput = INVALID_HANDLE_VALUE; hInPipe = hOutPipe = hErrPipe = INVALID_HANDLE_VALUE; closeStdin = closeStdout = closeStderr = FALSE; nPids = 0; /* * First, scan through all the arguments to figure out the structure * of the pipeline. Process all of the input and output redirection * arguments and remove them from the argument list in the pipeline. * Count the number of distinct processes (it's the number of "|" * arguments plus one) but don't remove the "|" arguments because * they'll be used in the second pass to seperate the individual * child processes. Cannot start the child processes in this pass * because the redirection symbols may appear anywhere in the * command line -- e.g., the '<' that specifies the input to the * entire pipe may appear at the very end of the argument list. */ lastBar = -1; cmdCount = 1; for (i = 0; i < argc; i++) { skip = 0; p = argv[i]; switch (*p++) { case '|': if (*p == '&') { p++; } if (*p == '\0') { if ((i == (lastBar + 1)) || (i == (argc - 1))) { Tcl_AppendResult(interp, "illegal use of | or |& in command", (char *)NULL); goto error; } } lastBar = i; cmdCount++; break; case '<': if (closeStdin) { closeStdin = FALSE; CloseHandle(hStdin); } if (*p == '<') { hStdin = INVALID_HANDLE_VALUE; inputLiteral = p + 1; skip = 1; if (*inputLiteral == '\0') { inputLiteral = argv[i + 1]; if (inputLiteral == NULL) { Tcl_AppendResult(interp, "can't specify \"", argv[i], "\" as last word in command", (char *)NULL); goto error; } skip = 2; } } else { inputLiteral = NULL; hStdin = FileForRedirect(interp, p, TRUE, argv[i], argv[i + 1], GENERIC_READ, OPEN_EXISTING, &skip, &closeStdin); if (hStdin == INVALID_HANDLE_VALUE) { goto error; } } break; case '>': atOK = 1; flags = CREATE_ALWAYS; errorToOutput = FALSE; if (*p == '>') { p++; atOK = 0; flags = OPEN_ALWAYS; } if (*p == '&') { if (closeStderr) { closeStderr = FALSE; CloseHandle(hStderr); } errorToOutput = TRUE; p++; } if (closeStdout) { closeStdout = FALSE; CloseHandle(hStdout); } hStdout = FileForRedirect(interp, p, atOK, argv[i], argv[i + 1], GENERIC_WRITE, flags, &skip, &closeStdout); if (hStdout == INVALID_HANDLE_VALUE) { goto error; } if (errorToOutput) { closeStderr = FALSE; hStderr = hStdout; } break; case '2': if (*p != '>') { break; } p++; atOK = TRUE; flags = CREATE_ALWAYS; if (*p == '>') { p++; atOK = FALSE; flags = OPEN_ALWAYS; } if (closeStderr) { closeStderr = FALSE; CloseHandle(hStderr); } hStderr = FileForRedirect(interp, p, atOK, argv[i], argv[i + 1], GENERIC_WRITE, flags, &skip, &closeStderr); if (hStderr == INVALID_HANDLE_VALUE) { goto error; } break; } if (skip != 0) { for (j = i + skip; j < argc; j++) { argv[j - skip] = argv[j]; } argc -= skip; i -= 1; } } if (hStdin == INVALID_HANDLE_VALUE) { if (inputLiteral != NULL) { /* * The input for the first process is immediate data coming from * Tcl. Create a temporary file for it and put the data into the * file. */ hStdin = CreateTempFile(inputLiteral); if (hStdin == INVALID_HANDLE_VALUE) { Tcl_AppendResult(interp, "can't create input file for command: ", Tcl_PosixError(interp), (char *)NULL); goto error; } closeStdin = TRUE; } else if (inPipePtr != NULL) { /* * The input for the first process in the pipeline is to * come from a pipe that can be written from by the caller. */ if (!CreatePipe(&hStdin, &hInPipe, NULL, 0)) { Tcl_AppendResult(interp, "can't create input pipe for command: ", Tcl_PosixError(interp), (char *)NULL); goto error; } closeStdin = TRUE; } else { /* * The input for the first process comes from stdin. */ } } if (hStdout == INVALID_HANDLE_VALUE) { if (outPipePtr != NULL) { /* * Output from the last process in the pipeline is to go to a * pipe that can be read by the caller. */ if (!CreatePipe(&hOutPipe, &hStdout, NULL, 0)) { Tcl_AppendResult(interp, "can't create output pipe for command: ", Tcl_PosixError(interp), (char *)NULL); goto error; } closeStdout = TRUE; } else { /* * The output for the last process goes to stdout. */ } } if (hStderr == INVALID_HANDLE_VALUE) { if (errPipePtr != NULL) { /* * Stderr from the last process in the pipeline is to go to a * pipe that can be read by the caller. */ if (CreatePipe(&hErrPipe, &hStderr, NULL, 0) == 0) { Tcl_AppendResult(interp, "can't create error pipe for command: ", Tcl_PosixError(interp), (char *)NULL); goto error; } closeStderr = TRUE; } else { /* * Errors from the pipeline go to stderr. */ } } /* * Scan through the argc array, creating a process for each * group of arguments between the "|" characters. */ Tcl_ReapDetachedProcs(); procArr = Blt_Malloc((unsigned)((cmdCount + 1) * sizeof(Process))); assert(procArr); thisInput = hStdin; if (argc == 0) { Tcl_AppendResult(interp, "invalid null command", (char *)NULL); goto error; } #ifdef notdef lastArg = 0; /* Suppress compiler warning */ #endif for (i = 0; i < argc; i = lastArg + 1) { BOOL joinThisError; HANDLE hProcess; /* Convert the program name into native form. */ argv[i] = Tcl_TranslateFileName(interp, argv[i], &dString); if (argv[i] == NULL) { goto error; } /* Find the end of the current segment of the pipeline. */ joinThisError = FALSE; for (lastArg = i; lastArg < argc; lastArg++) { if (argv[lastArg][0] == '|') { if (argv[lastArg][1] == '\0') { break; } if ((argv[lastArg][1] == '&') && (argv[lastArg][2] == '\0')) { joinThisError = TRUE; break; } } } argv[lastArg] = NULL; if ((lastArg - i) == 0) { Tcl_AppendResult(interp, "invalid null command", (char *)NULL); goto error; } /* * If this is the last segment, use the specified output handle. * Otherwise create an intermediate pipe. hPipe will become the * input for the next segment of the pipe. */ if (lastArg == argc) { thisOutput = hStdout; } else { if (CreatePipe(&hPipe, &thisOutput, NULL, 0) == 0) { Tcl_AppendResult(interp, "can't create pipe: ", Tcl_PosixError(interp), (char *)NULL); goto error; } } if (joinThisError) { thisError = thisOutput; } else { thisError = hStderr; } if (StartProcess(interp, lastArg - i, argv + i, thisInput, thisOutput, thisError, &hProcess, (DWORD *)&pid) != TCL_OK) { goto error; } Tcl_DStringFree(&dString); procArr[nPids].hProcess = hProcess; procArr[nPids].pid = pid; nPids++; /* * Close off our copies of file descriptors that were set up for * this child, then set up the input for the next child. */ if ((thisInput != INVALID_HANDLE_VALUE) && (thisInput != hStdin)) { CloseHandle(thisInput); } thisInput = hPipe; hPipe = INVALID_HANDLE_VALUE; if ((thisOutput != INVALID_HANDLE_VALUE) && (thisOutput != hStdout)) { CloseHandle(thisOutput); } thisOutput = INVALID_HANDLE_VALUE; } *procArrPtr = (Process *)procArr; if (inPipePtr != NULL) { *inPipePtr = (int)hInPipe; } if (outPipePtr != NULL) { *outPipePtr = (int)hOutPipe; } if (errPipePtr != NULL) { *errPipePtr = (int)hErrPipe; } /* * All done. Cleanup open files lying around and then return. */ cleanup: Tcl_DStringFree(&dString); if (closeStdin) { CloseHandle(hStdin); } if (closeStdout) { CloseHandle(hStdout); } if (closeStderr) { CloseHandle(hStderr); } return nPids; /* * An error occurred. There could have been extra files open, such * as pipes between children. Clean them all up. Detach any child * processes that have been created. */ error: if (hPipe != INVALID_HANDLE_VALUE) { CloseHandle(hPipe); } if ((thisOutput != INVALID_HANDLE_VALUE) && (thisOutput != hStdout)) { CloseHandle(thisOutput); } if ((thisInput != INVALID_HANDLE_VALUE) && (thisInput != hStdin)) { CloseHandle(thisInput); } if (hInPipe != INVALID_HANDLE_VALUE) { CloseHandle(hInPipe); } if (hOutPipe != INVALID_HANDLE_VALUE) { CloseHandle(hOutPipe); } if (hErrPipe != INVALID_HANDLE_VALUE) { CloseHandle(hErrPipe); } if (procArr != NULL) { for (i = 0; i < nPids; i++) { if (procArr[i].hProcess != INVALID_HANDLE_VALUE) { /* It's Ok to use Tcl_DetachPids, since for WIN32 it's really * using process handles, not process ids. */ Tcl_DetachPids(1, (Tcl_Pid *)&(procArr[i].pid)); } } Blt_Free(procArr); } nPids = -1; goto cleanup; } /* *---------------------------------------------------------------------- * * Blt_CreateFileHandler -- * * Limited emulation Tcl_CreateFileHandler for Win32. Works * with pipes. Don't know if anything else will (such as sockets). * * Results: * None. * * Side Effects: * Registers procedure and data to call back when data * is available on the pipe. * *---------------------------------------------------------------------- */ void Blt_CreateFileHandler( int fd, /* Descriptor or handle of file */ int flags, /* TCL_READABLE or TCL_WRITABLE */ Tcl_FileProc *proc, ClientData clientData) { PipeHandler *pipePtr; if (!initialized) { PipeInit(); } if ((flags != TCL_READABLE) && (flags != TCL_WRITABLE)) { return; /* Only one of the flags can be set. */ } pipePtr = CreatePipeHandler((HANDLE) fd, flags); pipePtr->proc = proc; pipePtr->clientData = clientData; /* Add the handler to the list of managed pipes. */ EnterCriticalSection(&pipeCriticalSection); Blt_ChainAppend(&pipeChain, pipePtr); LeaveCriticalSection(&pipeCriticalSection); } /* *---------------------------------------------------------------------- * * Blt_DeleteFileHandler -- * * Win32 emulation Tcl_DeleteFileHandler. Cleans up resources * used. * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_DeleteFileHandler(int fd) /* Descriptor or handle of file */ { PipeHandler *pipePtr; Blt_ChainLink *linkPtr; HANDLE hPipe; if (!initialized) { PipeInit(); } #if KILL_DEBUG PurifyPrintf("Blt_DeleteFileHandler(%d)\n", fd); #endif hPipe = (HANDLE) fd; EnterCriticalSection(&pipeCriticalSection); for (linkPtr = Blt_ChainFirstLink(&pipeChain); linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) { pipePtr = Blt_ChainGetValue(linkPtr); if ((pipePtr->hPipe == hPipe) && !(pipePtr->flags & PIPE_DELETED)) { Blt_ChainDeleteLink(&pipeChain, linkPtr); DeletePipeHandler(pipePtr); break; } } LeaveCriticalSection(&pipeCriticalSection); #if KILL_DEBUG PurifyPrintf("Blt_DeleteFileHandler: done\n"); #endif } /* *---------------------------------------------------------------------- * * Blt_AsyncRead -- * * Reads input from the pipe into the given buffer. * * Results: * Returns the number of bytes read. * *---------------------------------------------------------------------- */ int Blt_AsyncRead( int f, char *buffer, unsigned int size) { register PipeHandler *pipePtr; unsigned int count; int nBytes; #if ASYNC_DEBUG PurifyPrintf("Blt_AsyncRead(f=%d)\n", f); #endif pipePtr = GetPipeHandler((HANDLE) f); if ((pipePtr == NULL) || (pipePtr->flags & PIPE_DELETED)) { errno = EBADF; #if ASYNC_DEBUG PurifyPrintf("Blt_AsyncRead: bad file\n"); #endif return -1; } if (!PeekOnPipe(pipePtr, &nBytes)) { #if ASYNC_DEBUG PurifyPrintf("Blt_AsyncRead: pipe is drained (nBytes=%d).\n", nBytes); #endif return -1; /* No data available. */ } /* * nBytes is 0 EOF found. * -1 Error occured. * 1+ Number of bytes available. */ if (nBytes == -1) { #if ASYNC_DEBUG PurifyPrintf("Blt_AsyncRead: Error\n"); #endif return -1; } if (nBytes == 0) { #if ASYNC_DEBUG PurifyPrintf("Blt_AsyncRead: EOF\n"); #endif return 0; } count = pipePtr->end - pipePtr->start; #if ASYNC_DEBUG PurifyPrintf("Blt_AsyncRead: nBytes is %d, %d\n", nBytes, count); #endif assert(count == (unsigned int)nBytes); if (size > count) { size = count; /* Reset request to what's available. */ } memcpy(buffer, pipePtr->buffer + pipePtr->start, size); pipePtr->start += size; if (pipePtr->start == pipePtr->end) { #if ASYNC_DEBUG PurifyPrintf("Blt_AsyncRead: signaling idle\n"); #endif ResetEvent(pipePtr->readyEvent); SetEvent(pipePtr->idleEvent); } return size; } /* *---------------------------------------------------------------------- * * Blt_AsyncWrite -- * * Writes output to the pipe from the given buffer. * * Results: * Returns the number of bytes written. * *---------------------------------------------------------------------- */ int Blt_AsyncWrite( int f, char *buffer, unsigned int size) { register PipeHandler *pipePtr; pipePtr = GetPipeHandler((HANDLE) f); if ((pipePtr == NULL) || (pipePtr->flags & PIPE_DELETED)) { errno = EBADF; return -1; } if (WaitForSingleObject(pipePtr->readyEvent, 0) == WAIT_TIMEOUT) { /* * Writer thread is currently blocked waiting for a write to * complete. */ errno = EAGAIN; return -1; } /* Check for a background error on the last write. */ if (pipePtr->lastError) { TclWinConvertError(pipePtr->lastError); pipePtr->lastError = 0; return -1; } /* Reallocate the buffer to be large enough to hold the data. */ if (size > pipePtr->size) { char *ptr; ptr = Blt_Malloc(size); assert(ptr); Blt_Free(pipePtr->buffer); pipePtr->buffer = ptr; } memcpy(pipePtr->buffer, buffer, size); pipePtr->end = pipePtr->size = size; ResetEvent(pipePtr->readyEvent); SetEvent(pipePtr->idleEvent); return size; } blt-2.4z.orig/src/bltWinPrnt.c0100644000175000017500000013014507540713417015016 0ustar dokodoko /* * bltWinPrnt.c -- * * This module implements Win32 printer access. * * Copyright 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. * */ #include #include #ifndef NO_PRINTER #include #undef Status #if defined(_MSC_VER) || defined(__BORLANDC__) #include #endif /* _MSC_VER || __BORLANDC__ */ /* set pid [printer open name] printer close $pid printer write $pid $data printer snap $pid .window printer names printer enum things printer getattr $pid printer setattr $pid set pid [open ] blt::printer open {\\alprint\2a211} p1 p1 getattr varName p1 setattr varName p1 write $data .graph print p1 p1 snap .window p1 close blt::printer names blt::printer emum things */ #define PRINTER_THREAD_KEY "BLT Printer Data" typedef struct { Blt_HashTable printerTable; /* Hash table of printer structures keyed by * the name of the printer. */ int nextId; } PrinterInterpData; typedef struct { int type; HDC hDC; } PrintDrawable; typedef struct { Tcl_Interp *interp; Tcl_Command cmdToken; /* Token for vector's Tcl command. */ char *name; char *fileName; PrintDrawable drawable; HANDLE hPrinter; Blt_HashEntry *hashPtr; Blt_HashTable *tablePtr; char *driverName; char *deviceName; char *printerName; char *docName; char *portName; DEVMODE *dmPtr; int dmSize; } PrintQueue; typedef struct { DWORD token; char *string; } TokenString; static TokenString sizeTable[] = { /* Letter 8 1/2 x 11 in */ { DMPAPER_LETTER, "Letter" }, /* Letter Small 8 1/2 x 11 in */ { DMPAPER_LETTERSMALL, "Letter Small" }, /* Tabloid 11 x 17 in */ { DMPAPER_TABLOID, "Tabloid" }, /* Ledger 17 x 11 in */ { DMPAPER_LEDGER, "Ledger" }, /* Legal 8 1/2 x 14 in */ { DMPAPER_LEGAL, "Legal" }, /* Statement 5 1/2 x 8 1/2 in */ { DMPAPER_STATEMENT, "Statement" }, /* Executive 7 1/4 x 10 1/2 in */ { DMPAPER_EXECUTIVE, "Executive" }, /* A3 297 x 420 mm */ { DMPAPER_A3, "A3" }, /* A4 210 x 297 mm */ { DMPAPER_A4, "A4" }, /* A4 Small 210 x 297 mm */ { DMPAPER_A4SMALL, "A4 Small" }, /* A5 148 x 210 mm */ { DMPAPER_A5, "A5" }, /* B4 (JIS) 250 x 354 */ { DMPAPER_B4, "B4 (JIS)" }, /* B5 (JIS) 182 x 257 mm */ { DMPAPER_B5, "B5 (JIS)" }, /* Folio 8 1/2 x 13 in */ { DMPAPER_FOLIO, "Folio" }, /* Quarto 215 x 275 mm */ { DMPAPER_QUARTO, "Quarto" }, /* 10x14 in */ { DMPAPER_10X14, "10x14" }, /* 11x17 in */ { DMPAPER_11X17, "11x17" }, /* Note 8 1/2 x 11 in */ { DMPAPER_NOTE, "Note" }, /* Envelope #9 3 7/8 x 8 7/8 */ { DMPAPER_ENV_9, "Envelope #9" }, /* Envelope #10 4 1/8 x 9 1/2 */ { DMPAPER_ENV_10, "Envelope #10" }, /* Envelope #11 4 1/2 x 10 3/8 */ { DMPAPER_ENV_11, "Envelope #11" }, /* Envelope #12 4 \276 x 11 */ { DMPAPER_ENV_12, "Envelope #12" }, /* Envelope #14 5 x 11 1/2 */ { DMPAPER_ENV_14, "Envelope #14" }, /* C size sheet */ { DMPAPER_CSHEET, "C size sheet" }, /* D size sheet */ { DMPAPER_DSHEET, "D size sheet" }, /* E size sheet */ { DMPAPER_ESHEET, "E size sheet" }, /* Envelope DL 110 x 220mm */ { DMPAPER_ENV_DL, "Envelope DL" }, /* Envelope C5 162 x 229 mm */ { DMPAPER_ENV_C5, "Envelope C5" }, /* Envelope C3 324 x 458 mm */ { DMPAPER_ENV_C3, "Envelope C3" }, /* Envelope C4 229 x 324 mm */ { DMPAPER_ENV_C4, "Envelope C4" }, /* Envelope C6 114 x 162 mm */ { DMPAPER_ENV_C6, "Envelope C6" }, /* Envelope C65 114 x 229 mm */ { DMPAPER_ENV_C65, "Envelope C65" }, /* Envelope B4 250 x 353 mm */ { DMPAPER_ENV_B4, "Envelope B4" }, /* Envelope B5 176 x 250 mm */ { DMPAPER_ENV_B5, "Envelope B5" }, /* Envelope B6 176 x 125 mm */ { DMPAPER_ENV_B6, "Envelope B6" }, /* Envelope 110 x 230 mm */ { DMPAPER_ENV_ITALY, "Envelope Italy" }, /* Env Monarch 3 7/8 x 7 1/2 in */ { DMPAPER_ENV_MONARCH, "Envelope Monarch" }, /* 6 3/4 Envelope 3 5/8 x 6 1/2 in */ { DMPAPER_ENV_PERSONAL, "6 3/4 Envelope" }, /* US Std Fanfold 14 7/8 x 11 in */ { DMPAPER_FANFOLD_US, "US Std Fanfold" }, /* German Std Fanfold 8 1/2 x 12 in */ { DMPAPER_FANFOLD_STD_GERMAN, "German Std Fanfold" }, /* German Legal Fanfold 8 1/2 x 13 in */ { DMPAPER_FANFOLD_LGL_GERMAN, "German Legal Fanfold" }, /* B4 (ISO) 250 x 353 mm */ { DMPAPER_ISO_B4, "ISOB4" }, /* Japanese Postcard 100 x 148 mm */ { DMPAPER_JAPANESE_POSTCARD, "Postcard (JIS)" }, /* 9 x 11 in */ { DMPAPER_9X11, "9x11" }, /* 10 x 11 in */ { DMPAPER_10X11, "10x11" }, /* 15 x 11 in */ { DMPAPER_15X11, "15x11" }, /* Envelope Invite 220 x 220 mm */ { DMPAPER_ENV_INVITE, "Envelope Invite" }, /* Letter Extra 9 \275 x 12 in */ { DMPAPER_LETTER_EXTRA, "Letter Extra" }, /* Legal Extra 9 \275 x 15 in */ { DMPAPER_LEGAL_EXTRA, "Legal Extra" }, /* Tabloid Extra 11.69 x 18 in */ { DMPAPER_TABLOID_EXTRA, "Tabloid Extra" }, /* A4 Extra 9.27 x 12.69 in */ { DMPAPER_A4_EXTRA, "A4 Extra" }, /* Letter Transverse 8 \275 x 11 in */ { DMPAPER_LETTER_TRANSVERSE, "Letter Transverse" }, /* A4 Transverse 210 x 297 mm */ { DMPAPER_A4_TRANSVERSE, "A4 Transverse" }, /* Letter Extra Transverse 9\275 x 12 in */ { DMPAPER_LETTER_EXTRA_TRANSVERSE, "Letter Extra Transverse" }, /* SuperA/SuperA/A4 227 x 356 mm */ { DMPAPER_A_PLUS, "Super A Plus" }, /* SuperB/SuperB/A3 305 x 487 mm */ { DMPAPER_B_PLUS, "Super B Plus" }, /* Letter Plus 8.5 x 12.69 in */ { DMPAPER_LETTER_PLUS, "Letter Plus" }, /* A4 Plus 210 x 330 mm */ { DMPAPER_A4_PLUS, "A4 Plus" }, /* A5 Transverse 148 x 210 mm */ { DMPAPER_A5_TRANSVERSE, "A5 Transverse" }, /* B5 (JIS) Transverse 182 x 257 mm */ { DMPAPER_B5_TRANSVERSE, "B5 Transverse" }, /* A3 Extra 322 x 445 mm */ { DMPAPER_A3_EXTRA, "A3 Extra" }, /* A5 Extra 174 x 235 mm */ { DMPAPER_A5_EXTRA, "A5 Extra" }, /* B5 (ISO) Extra 201 x 276 mm */ { DMPAPER_B5_EXTRA, "B5 Extra" }, /* A2 420 x 594 mm */ { DMPAPER_A2, "A2" }, /* A3 Transverse 297 x 420 mm */ { DMPAPER_A3_TRANSVERSE, "A3 Transverse" }, /* A3 Extra Transverse 322 x 445 mm */ { DMPAPER_A3_EXTRA_TRANSVERSE, "A3 Extra Transverse" }, { 0, NULL } }; static TokenString statusTable[] = { { PRINTER_STATUS_BUSY, "Busy" }, { PRINTER_STATUS_DOOR_OPEN, "Door Open" }, { PRINTER_STATUS_ERROR, "Error" }, { PRINTER_STATUS_INITIALIZING, "Initializing" }, { PRINTER_STATUS_IO_ACTIVE, "IO Active" }, { PRINTER_STATUS_MANUAL_FEED, "Manual Feed" }, { PRINTER_STATUS_NOT_AVAILABLE, "Not Available" }, { PRINTER_STATUS_NO_TONER, "No Toner" }, { PRINTER_STATUS_OFFLINE, "Offline" }, { PRINTER_STATUS_OUTPUT_BIN_FULL, "Bin Full" }, { PRINTER_STATUS_OUT_OF_MEMORY, "Out Of Memory" }, { PRINTER_STATUS_PAGE_PUNT, "Page Punt" }, { PRINTER_STATUS_PAPER_JAM, "Paper Jam" }, { PRINTER_STATUS_PAPER_OUT, "Paper Out" }, { PRINTER_STATUS_PAPER_PROBLEM, "Paper Problem" }, { PRINTER_STATUS_PAUSED, "Paused" }, { PRINTER_STATUS_PENDING_DELETION, "Pending Deletion" }, { PRINTER_STATUS_POWER_SAVE, "Power Save" }, { PRINTER_STATUS_PRINTING, "Printing" }, { PRINTER_STATUS_PROCESSING, "Processing" }, { PRINTER_STATUS_SERVER_UNKNOWN, "Server Unknown" }, { PRINTER_STATUS_TONER_LOW, "Toner Low" }, { PRINTER_STATUS_USER_INTERVENTION, "User Intervention" }, { PRINTER_STATUS_WAITING, "Waiting" }, { PRINTER_STATUS_WARMING_UP, "Warming Up" }, { 0, NULL } }; static TokenString attributeTable[] = { { PRINTER_ATTRIBUTE_DEFAULT, "Default" }, { PRINTER_ATTRIBUTE_DIRECT, "Direct" }, { PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST, "Do Complete First" }, { PRINTER_ATTRIBUTE_ENABLE_BIDI, "Enable BIDI" }, { PRINTER_ATTRIBUTE_ENABLE_DEVQ, "Enable Devq" }, { PRINTER_ATTRIBUTE_HIDDEN, "Hidden" }, { PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS, "Keep Printed Jobs" }, { PRINTER_ATTRIBUTE_LOCAL, "Local" }, { PRINTER_ATTRIBUTE_NETWORK, "Network" }, { PRINTER_ATTRIBUTE_QUEUED, "Queued" }, { PRINTER_ATTRIBUTE_RAW_ONLY, "Raw Only" }, { PRINTER_ATTRIBUTE_SHARED, "Shared" }, { PRINTER_ATTRIBUTE_WORK_OFFLINE, "Offline" }, { 0, NULL } }; static TokenString binTable[] = { { DMBIN_UPPER, "Upper" }, { DMBIN_LOWER, "Lower" }, { DMBIN_MIDDLE, "Middle" }, { DMBIN_MANUAL, "Manual" }, { DMBIN_ENVELOPE, "Envelope" }, { DMBIN_ENVMANUAL, "Envelope Manual" }, { DMBIN_AUTO, "Automatic" }, { DMBIN_TRACTOR, "Tractor" }, { DMBIN_SMALLFMT, "Small Format" }, { DMBIN_LARGEFMT, "Large Format" }, { DMBIN_LARGECAPACITY, "Large Capacity" }, { DMBIN_CASSETTE, "Cassette" }, { DMBIN_FORMSOURCE, "Form Source" }, { 0, NULL } }; static TokenString orientationTable[] = { { DMORIENT_PORTRAIT, "Portrait" }, { DMORIENT_LANDSCAPE, "Landscape" }, { 0, NULL } }; static TokenString qualityTable[] = { { DMRES_HIGH, "High" }, { DMRES_MEDIUM, "Medium" }, { DMRES_LOW, "Low" }, { DMRES_DRAFT, "Draft" }, { 0, NULL } }; static TokenString colorTable[] = { { DMCOLOR_COLOR, "Color" }, { DMCOLOR_MONOCHROME, "Monochrome" }, { 0, NULL } }; static TokenString duplexTable[] = { { DMDUP_SIMPLEX, "Simplex" }, { DMDUP_HORIZONTAL, "Horizontal" }, { DMDUP_VERTICAL, "Vertical" }, { 0, NULL } }; static TokenString ttOptionTable[] = { { DMTT_BITMAP, "Bitmap" }, { DMTT_DOWNLOAD, "Download" }, { DMTT_SUBDEV, "Substitute Device" }, { DMTT_DOWNLOAD_OUTLINE, "Download Outline" }, { 0, NULL } }; static Tcl_ObjCmdProc PrinterCmd; static Tcl_InterpDeleteProc PrinterInterpDeleteProc; void Blt_GetPrinterScale(HDC printerDC, double *xRatioPtr, double *yRatioPtr) { double xScreen, yScreen; double xPrinter, yPrinter; HDC screenDC; xPrinter = (double)GetDeviceCaps(printerDC, LOGPIXELSX); yPrinter = (double)GetDeviceCaps(printerDC, LOGPIXELSY); screenDC = GetDC(NULL); xScreen = (double)GetDeviceCaps(screenDC, LOGPIXELSX); yScreen = (double)GetDeviceCaps(screenDC, LOGPIXELSY); ReleaseDC(NULL, screenDC); *xRatioPtr = (xPrinter / xScreen); *yRatioPtr = (yPrinter / yScreen); } static PrinterInterpData * GetPrinterInterpData(Tcl_Interp *interp) { PrinterInterpData *dataPtr; Tcl_InterpDeleteProc *proc; dataPtr = (PrinterInterpData *) Tcl_GetAssocData(interp, PRINTER_THREAD_KEY, &proc); if (dataPtr == NULL) { dataPtr = Blt_Malloc(sizeof(PrinterInterpData)); dataPtr->nextId = 0; assert(dataPtr); Tcl_SetAssocData(interp, PRINTER_THREAD_KEY, PrinterInterpDeleteProc, dataPtr); Blt_InitHashTable(&dataPtr->printerTable, BLT_STRING_KEYS); } return dataPtr; } static int GetQueue( Tcl_Interp *interp, const char *name, PrintQueue **queuePtrPtr) { Blt_HashEntry *hPtr; PrinterInterpData *dataPtr; dataPtr = GetPrinterInterpData(interp); hPtr = Blt_FindHashEntry(&dataPtr->printerTable, name); if (hPtr == NULL) { Tcl_AppendResult(interp, "can't find printer \"", name, "\"", (char *)NULL); return TCL_ERROR; } *queuePtrPtr = (PrintQueue *)Blt_GetHashValue(hPtr); return TCL_OK; } static int GetQueueFromObj( Tcl_Interp *interp, Tcl_Obj *objPtr, PrintQueue **queuePtrPtr) { return GetQueue(interp, Tcl_GetString(objPtr), queuePtrPtr); } static void CloseQueue( PrintQueue *queuePtr) { ClosePrinter(queuePtr->hPrinter); queuePtr->hPrinter = NULL; } static int OpenQueue( Tcl_Interp *interp, PrintQueue *queuePtr) { PRINTER_DEFAULTS pd; HANDLE hPrinter; ZeroMemory(&pd, sizeof(pd)); pd.DesiredAccess = PRINTER_ALL_ACCESS; if (!OpenPrinter(queuePtr->printerName, &hPrinter, &pd)) { Tcl_AppendResult(interp, "can't open printer \"", queuePtr->printerName, "\": ", Blt_LastError(), (char *)NULL); queuePtr->hPrinter = NULL; return TCL_ERROR; } queuePtr->hPrinter = hPrinter; return TCL_OK; } static HGLOBAL GetQueueProperties( PrintQueue *queuePtr, DEVMODE **dmPtrPtr) { HWND hWnd; unsigned int dmSize; HGLOBAL hMem; DEVMODE *dmPtr; hWnd = GetDesktopWindow(); dmSize = DocumentProperties(hWnd, queuePtr->hPrinter, queuePtr->printerName, NULL, NULL, 0); if (dmSize == 0) { Tcl_AppendResult(queuePtr->interp, "can't get document properties for \"", queuePtr->printerName, "\": ", Blt_LastError(), (char *)NULL); return NULL; } hMem = GlobalAlloc(GHND, dmSize); dmPtr = (DEVMODE *)GlobalLock(hMem); if (!DocumentProperties(hWnd, queuePtr->hPrinter, queuePtr->printerName, dmPtr, NULL, DM_OUT_BUFFER)) { Tcl_AppendResult(queuePtr->interp, "can't allocate document properties for \"", queuePtr->printerName, "\": ", Blt_LastError(), (char *)NULL); GlobalUnlock(hMem); GlobalFree(hMem); return NULL; } *dmPtrPtr = dmPtr; queuePtr->dmSize = dmSize; return hMem; } static int SetQueueProperties( Tcl_Interp *interp, PrintQueue *queuePtr, DEVMODE *dmPtr) { HWND hWnd; int result; hWnd = GetDesktopWindow(); result = DocumentProperties(hWnd, queuePtr->hPrinter, queuePtr->printerName, dmPtr, dmPtr, DM_IN_BUFFER | DM_OUT_BUFFER); if (result == 0) { Tcl_AppendResult(interp, "can't set document properties for \"", queuePtr->printerName, "\": ", Blt_LastError(), (char *)NULL); return TCL_ERROR; } if (queuePtr->dmPtr != NULL) { Blt_Free(queuePtr->dmPtr); } queuePtr->dmPtr = Blt_Malloc(queuePtr->dmSize); *queuePtr->dmPtr = *dmPtr; return TCL_OK; } static void DestroyQueue(PrintQueue *queuePtr) { if (queuePtr->drawable.hDC != NULL) { DeleteDC(queuePtr->drawable.hDC); } if (queuePtr->printerName != NULL) { Blt_Free(queuePtr->printerName); } if (queuePtr->deviceName != NULL) { Blt_Free(queuePtr->deviceName); } if (queuePtr->portName != NULL) { Blt_Free(queuePtr->portName); } if (queuePtr->driverName != NULL) { Blt_Free(queuePtr->driverName); } if (queuePtr->hashPtr != NULL) { Blt_DeleteHashEntry(queuePtr->tablePtr, queuePtr->hashPtr); } if (queuePtr->dmPtr != NULL) { Blt_Free(queuePtr->dmPtr); } Blt_Free(queuePtr); } static char * AttributesToString(DWORD attributes, Tcl_DString * resultPtr) { register TokenString *p; Tcl_DStringInit(resultPtr); for (p = attributeTable; p->string != NULL; p++) { if (attributes & p->token) { Tcl_DStringAppendElement(resultPtr, p->string); } } return Tcl_DStringValue(resultPtr); } static char * StatusToString(DWORD status, Tcl_DString * resultPtr) { register TokenString *p; Tcl_DStringInit(resultPtr); for (p = statusTable; p->string != NULL; p++) { if (status & p->token) { Tcl_DStringAppendElement(resultPtr, p->string); } } return Tcl_DStringValue(resultPtr); } static char * TokenToString(TokenString *table, DWORD token) { register TokenString *p; for (p = table; p->string != NULL; p++) { if (token == p->token) { return p->string; } } return "???"; } static DWORD StringToToken(TokenString * table, char *string) { register TokenString *p; char c; c = toupper(string[0]); for (p = table; p->string != NULL; p++) { if ((c == toupper(p->string[0])) && (strcasecmp(string, p->string) == 0)) { return p->token; } } return 0; } static void GetFormInfo( Tcl_Interp *interp, FORM_INFO_1 * infoArr, int nForms, char *varName) { Tcl_DString dString; register int i; Tcl_DStringInit(&dString); for (i = 0; i < nForms; i++) { Tcl_DStringAppendElement(&dString, infoArr[i].pName); } Tcl_SetVar2(interp, varName, "EnumForms", Tcl_DStringValue(&dString), TCL_LEAVE_ERR_MSG); Tcl_DStringFree(&dString); } static int GetPrinterAttributes( Tcl_Interp *interp, /* Interpreter context. */ PrintQueue *queuePtr, Tcl_Obj *objPtr) /* Name of array variable to contain * printer device information. */ { char *string; Tcl_DString dString; DEVMODE *dmPtr; DWORD bytesNeeded; HGLOBAL hMem1, hMem2; PRINTER_INFO_2* pi2Ptr; LPVOID buffer; int result = TCL_ERROR; char *varName; if (OpenQueue(interp, queuePtr) != TCL_OK) { return TCL_ERROR; } Tcl_DStringInit(&dString); hMem2 = NULL; GetPrinter(queuePtr->hPrinter, 2, NULL, 0, &bytesNeeded); /* Windows 95/98 seems to only want locked memory. Allocating * unlocked memory will sometimes crash the printer driver and * therefore Windows itself. */ hMem1 = GlobalAlloc(GHND, bytesNeeded); if (hMem1 == NULL) { Tcl_AppendResult(interp, "can't allocate memory for printer \"", queuePtr->name, "\": ", Blt_LastError(), (char *)NULL); goto error; } buffer = (LPVOID)GlobalLock(hMem1); if (!GetPrinter(queuePtr->hPrinter, 2, buffer, bytesNeeded, &bytesNeeded)) { Tcl_AppendResult(interp, "can't get printer \"", queuePtr->name, "\": ", Blt_LastError(), (char *)NULL); goto error; } hMem2 = GetQueueProperties(queuePtr, &dmPtr); if (hMem2 == NULL) { Tcl_AppendResult(interp, "can't allocate memory for printer \"", queuePtr->name, "\" properties: ", Blt_LastError(), (char *)NULL); goto error; } pi2Ptr = (PRINTER_INFO_2 *)buffer; varName = Tcl_GetString(objPtr); Tcl_SetVar2(interp, varName, "ServerName", pi2Ptr->pServerName, 0); Tcl_SetVar2(interp, varName, "PrinterName", pi2Ptr->pPrinterName, 0); Tcl_SetVar2(interp, varName, "PortName", pi2Ptr->pPortName, 0); Tcl_SetVar2(interp, varName, "DriverName", pi2Ptr->pDriverName, 0); Tcl_SetVar2(interp, varName, "Comment", pi2Ptr->pComment, 0); Tcl_SetVar2(interp, varName, "Location", pi2Ptr->pLocation, 0); Tcl_SetVar2(interp, varName, "SepFile", pi2Ptr->pSepFile, 0); Tcl_SetVar2(interp, varName, "PrintProcessor", pi2Ptr->pPrintProcessor, 0); Tcl_SetVar2(interp, varName, "Datatype", pi2Ptr->pDatatype, 0); Tcl_SetVar2(interp, varName, "Parameters", pi2Ptr->pParameters, 0); Tcl_SetVar2(interp, varName, "Attributes", AttributesToString(pi2Ptr->Attributes, &dString), 0); Tcl_SetVar2(interp, varName, "Priority", Blt_Itoa(pi2Ptr->Priority), 0); Tcl_SetVar2(interp, varName, "DefaultPriority", Blt_Itoa(pi2Ptr->DefaultPriority), 0); Tcl_SetVar2(interp, varName, "StartTime", Blt_Itoa(pi2Ptr->StartTime), 0); Tcl_SetVar2(interp, varName, "UntilTime", Blt_Itoa(pi2Ptr->UntilTime), 0); Tcl_SetVar2(interp, varName, "Status", StatusToString(pi2Ptr->Status, &dString), 0); Tcl_SetVar2(interp, varName, "Jobs", Blt_Itoa(pi2Ptr->cJobs), 0); Tcl_SetVar2(interp, varName, "AveragePPM", Blt_Itoa(pi2Ptr->AveragePPM), 0); if (dmPtr->dmFields & DM_ORIENTATION) { Tcl_SetVar2(interp, varName, "Orientation", TokenToString(orientationTable, dmPtr->dmOrientation), 0); } if (dmPtr->dmFields & DM_PAPERSIZE) { Tcl_SetVar2(interp, varName, "PaperSize", TokenToString(sizeTable, dmPtr->dmPaperSize), 0); } if (dmPtr->dmFields & DM_PAPERWIDTH) { Tcl_SetVar2(interp, varName, "PaperWidth", Blt_Itoa(dmPtr->dmPaperWidth), 0); } if (dmPtr->dmFields & DM_PAPERLENGTH) { Tcl_SetVar2(interp, varName, "PaperLength", Blt_Itoa(dmPtr->dmPaperLength), 0); } if (dmPtr->dmFields & DM_SCALE) { Tcl_SetVar2(interp, varName, "Scale", Blt_Itoa(dmPtr->dmScale), 0); } if (dmPtr->dmFields & DM_COPIES) { Tcl_SetVar2(interp, varName, "Copies", Blt_Itoa(dmPtr->dmCopies), 0); } if (dmPtr->dmFields & DM_DEFAULTSOURCE) { Tcl_SetVar2(interp, varName, "DefaultSource", TokenToString(binTable, dmPtr->dmDefaultSource), 0); } if (dmPtr->dmFields & DM_PRINTQUALITY) { if (dmPtr->dmPrintQuality < 0) { string = TokenToString(qualityTable, dmPtr->dmPrintQuality); } else { string = Blt_Itoa(dmPtr->dmPrintQuality); } Tcl_SetVar2(interp, varName, "PrintQuality", string, 0); } if (dmPtr->dmFields & DM_COLOR) { Tcl_SetVar2(interp, varName, "Color", TokenToString(colorTable, dmPtr->dmColor), 0); } if (dmPtr->dmFields & DM_DUPLEX) { Tcl_SetVar2(interp, varName, "Duplex", TokenToString(duplexTable, dmPtr->dmDuplex), 0); } if (dmPtr->dmFields & DM_YRESOLUTION) { Tcl_SetVar2(interp, varName, "YResolution", Blt_Itoa(dmPtr->dmYResolution), 0); } if (dmPtr->dmFields & DM_TTOPTION) { Tcl_SetVar2(interp, varName, "TTOption", TokenToString(ttOptionTable, dmPtr->dmTTOption), 0); } if (dmPtr->dmFields & DM_COLLATE) { if (dmPtr->dmCollate == DMCOLLATE_TRUE) { string = "true"; } else if (dmPtr->dmCollate == DMCOLLATE_FALSE) { string = "false"; } else { string = "???"; } Tcl_SetVar2(interp, varName, "Collate", string, 0); } if (dmPtr->dmFields & DM_FORMNAME) { Tcl_SetVar2(interp, varName, "FormName", dmPtr->dmFormName, 0); } Tcl_SetVar2(interp, varName, "OutputFile", dmPtr->dmDeviceName, 0); result = TCL_OK; error: Tcl_DStringFree(&dString); CloseQueue(queuePtr); if (hMem1 != NULL) { GlobalUnlock(hMem1); GlobalFree(hMem1); } if (hMem2 != NULL) { GlobalUnlock(hMem2); GlobalFree(hMem2); } return result; } static int SetQueueAttributes( Tcl_Interp *interp, PrintQueue *queuePtr, Tcl_Obj *objPtr) { char *string; DEVMODE *dmPtr; int value; HGLOBAL hMem; int result; char *varName; if (OpenQueue(interp, queuePtr) != TCL_OK) { return TCL_ERROR; } hMem = GetQueueProperties(queuePtr, &dmPtr); CloseQueue(queuePtr); if (hMem == NULL) { return TCL_ERROR; } dmPtr->dmFields = 0; varName = Tcl_GetString(objPtr); string = (char *)Tcl_GetVar2(interp, varName, "Orientation", 0); if (string != NULL) { value = StringToToken(orientationTable, string); if (value > 0) { dmPtr->dmFields |= DM_ORIENTATION; dmPtr->dmOrientation = value; } } string = (char *)Tcl_GetVar2(interp, varName, "PaperSize", 0); if (string != NULL) { value = StringToToken(sizeTable, string); if (value > 0) { dmPtr->dmFields |= DM_PAPERSIZE; dmPtr->dmPaperSize = value; } } string = (char *)Tcl_GetVar2(interp, varName, "PaperWidth", 0); if (string != NULL) { if (Tcl_GetInt(interp, string, &value) == TCL_OK) { dmPtr->dmFields |= DM_PAPERWIDTH; dmPtr->dmPaperWidth = value; } } string = (char *)Tcl_GetVar2(interp, varName, "PaperLength", 0); if (string != NULL) { if (Tcl_GetInt(interp, string, &value) == TCL_OK) { dmPtr->dmFields |= DM_PAPERLENGTH; dmPtr->dmPaperLength = value; } } string = (char *)Tcl_GetVar2(interp, varName, "Scale", 0); if (string != NULL) { if (Tcl_GetInt(interp, string, &value) == TCL_OK) { dmPtr->dmFields |= DM_SCALE; dmPtr->dmScale = value; } } string = (char *)Tcl_GetVar2(interp, varName, "Copies", 0); if (string != NULL) { if (Tcl_GetInt(interp, string, &value) == TCL_OK) { dmPtr->dmFields |= DM_COPIES; dmPtr->dmCopies = value; } } string = (char *)Tcl_GetVar2(interp, varName, "DefaultSource", 0); if (string != NULL) { value = StringToToken(binTable, string); if (value > 0) { dmPtr->dmFields |= DM_DEFAULTSOURCE; dmPtr->dmDefaultSource = value; } } string = (char *)Tcl_GetVar2(interp, varName, "PrintQuality", 0); if (string != NULL) { value = StringToToken(qualityTable, string); if (value > 0) { dmPtr->dmFields |= DM_PRINTQUALITY; dmPtr->dmPrintQuality = value; } } string = (char *)Tcl_GetVar2(interp, varName, "Color", 0); if (string != NULL) { value = StringToToken(colorTable, string); if (value > 0) { dmPtr->dmFields |= DM_COLOR; dmPtr->dmColor = value; } } string = (char *)Tcl_GetVar2(interp, varName, "Duplex", 0); if (string != NULL) { value = StringToToken(duplexTable, string); if (value > 0) { dmPtr->dmFields |= DM_DUPLEX; dmPtr->dmDuplex = value; } } string = (char *)Tcl_GetVar2(interp, varName, "YResolution", 0); if (string != NULL) { if (Tcl_GetInt(interp, string, &value) == TCL_OK) { dmPtr->dmFields |= DM_YRESOLUTION; dmPtr->dmYResolution = value; } } string = (char *)Tcl_GetVar2(interp, varName, "TTOption", 0); if (string != NULL) { value = StringToToken(ttOptionTable, string); if (value > 0) { dmPtr->dmFields |= DM_TTOPTION; dmPtr->dmTTOption = value; } } string = (char *)Tcl_GetVar2(interp, varName, "Collate", 0); if (string != NULL) { if (Tcl_GetBoolean(interp, string, &value) == TCL_OK) { dmPtr->dmFields |= DM_COLLATE; dmPtr->dmCollate = value; } } string = (char *)Tcl_GetVar2(interp, varName, "OutputFile", 0); if (string != NULL) { if (queuePtr->fileName != NULL) { Blt_Free(queuePtr->fileName); } queuePtr->fileName = Blt_Strdup(string); } if (queuePtr->dmPtr != NULL) { Blt_Free(queuePtr->dmPtr); } string = (char *)Tcl_GetVar2(interp, varName, "DocumentName", 0); if (string != NULL) { if (queuePtr->docName != NULL) { Blt_Free(queuePtr->docName); } queuePtr->docName = Blt_Strdup(string); } result = SetQueueProperties(interp, queuePtr, dmPtr); GlobalUnlock(hMem); GlobalFree(hMem); CloseQueue(queuePtr); return result; } /*ARGSUSED*/ static int EnumOp( ClientData clientData, /* Not used. */ Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { TokenString *p; char c; unsigned int length; char *attr; attr = Tcl_GetStringFromObj(objv[2], &length); c = attr[0]; if ((c == 'p') && (strncmp(attr, "paper", length) == 0)) { p = sizeTable; } else if ((c == 'q') && (strncmp(attr, "quality", length) == 0)) { p = qualityTable; } else if ((c == 'b') && (strncmp(attr, "bin", length) == 0)) { p = binTable; } else if ((c == 'o') && (strncmp(attr, "orientation", length) == 0)) { p = orientationTable; } else if ((c == 'c') && (strncmp(attr, "color", length) == 0)) { p = colorTable; } else if ((c == 'd') && (strncmp(attr, "duplex", length) == 0)) { p = duplexTable; } else if ((c == 't') && (strncmp(attr, "ttoption", length) == 0)) { p = ttOptionTable; } else { Tcl_AppendResult(interp, "bad enumeration field \"", attr, "\": should be \"paper\", \"quality\", \"bin\", \"orientation\", \"color\", \"duplex\", or \"ttoption\"", (char *)NULL); return TCL_ERROR; } for ( /*empty*/ ; p->string != NULL; p++) { Tcl_AppendElement(interp, p->string); } return TCL_OK; } /*ARGSUSED*/ static int OpenOp( ClientData clientData, /* Interpreter-specific data. */ Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { PrinterInterpData *dataPtr = clientData; PrintQueue *queuePtr; LPVOID buffer; PRINTER_INFO_2* pi2Ptr; DWORD bytesNeeded; int isNew; Blt_HashEntry *hPtr; HANDLE hMem; char *name; name = Tcl_GetString(objv[2]); hPtr = Blt_CreateHashEntry(&dataPtr->printerTable, name, &isNew); if (isNew) { queuePtr = Blt_Calloc(1, sizeof(PrintQueue)); queuePtr->name = Blt_GetHashKey(&dataPtr->printerTable, hPtr); queuePtr->interp = interp; Tcl_SetResult(interp, name, TCL_VOLATILE); Blt_SetHashValue(hPtr, queuePtr); queuePtr->hashPtr = hPtr; queuePtr->tablePtr = &dataPtr->printerTable; queuePtr->printerName = Blt_Strdup(name); } else { Tcl_AppendResult(interp, "printer \"", name, "\" is already open", (char *)NULL); return TCL_ERROR; } if (OpenQueue(interp, queuePtr) != TCL_OK) { DestroyQueue(queuePtr); return TCL_ERROR; } /* Call the first time to determine the amount of memory needed. */ GetPrinter(queuePtr->hPrinter, 2, NULL, 0, &bytesNeeded); if ((bytesNeeded == 0) || (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) { Tcl_AppendResult(interp, "can't get size of attribute buffer for \"", name, "\": ", Blt_LastError(), (char *)NULL); return TCL_ERROR; } /* Allocate a buffer to contain all printer information. */ hMem = GlobalAlloc(GHND, bytesNeeded); if (hMem == NULL) { return TCL_ERROR; } buffer = (LPVOID)GlobalLock(hMem); /* And call the again to actually get the printer. */ if (!GetPrinter(queuePtr->hPrinter, 2, buffer, bytesNeeded, &bytesNeeded)) { Tcl_AppendResult(interp, "can't get printer attributes for \"", name, "\": ", Blt_LastError(), (char *)NULL); GlobalUnlock(hMem); GlobalFree(hMem); return TCL_ERROR; } pi2Ptr = (PRINTER_INFO_2 *)buffer; if (pi2Ptr->pDevMode != NULL) { queuePtr->deviceName = Blt_Strdup(pi2Ptr->pDevMode->dmDeviceName); } queuePtr->driverName = Blt_Strdup(pi2Ptr->pDriverName); /* queuePtr->printerName = Blt_Strdup(pi2Ptr->pPrinterName); */ queuePtr->portName = Blt_Strdup(pi2Ptr->pPortName); GlobalUnlock(hMem); GlobalFree(hMem); return TCL_OK; } /*ARGSUSED*/ static int NamesOp( ClientData clientData, /* Interpreter-specific data. */ Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) /* Not used. */ { DWORD nPrinters, bytesNeeded; int elemSize, level; unsigned char *buffer; int result, flags; HANDLE hMem; if (Blt_GetPlatformId() == VER_PLATFORM_WIN32_NT) { level = 4; elemSize = sizeof(PRINTER_INFO_4); flags = PRINTER_ENUM_NAME; } else { level = 5; elemSize = sizeof(PRINTER_INFO_5); flags = PRINTER_ENUM_LOCAL; } result = EnumPrinters( flags, /* Flags */ NULL, /* Printer name */ level, /* Information level: 1, 2, 4, or 5 */ NULL, /* Array of returned information */ 0, /* Size of array */ &bytesNeeded, /* Size needed for array */ &nPrinters); /* Number of structures returned */ if ((!result) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) { Tcl_AppendResult(interp, "can't enumerate printers (memory alloc): ", Blt_LastError(), (char *)NULL); return TCL_ERROR; } hMem = GlobalAlloc(GHND, bytesNeeded); buffer = (unsigned char *)GlobalLock(hMem); result = EnumPrinters( flags, /* Flags */ NULL, /* Printer name */ level, /* Information level: 1, 2, 4, or 5 */ buffer, /* Array of returned information */ bytesNeeded, /* Size of array */ &bytesNeeded, /* Size needed for array */ &nPrinters); /* Number of structures returned */ if (!result) { Tcl_AppendResult(interp, "can't enumerate printers: ", Blt_LastError(), (char *)NULL); return TCL_ERROR; } if (objc > 2) { register unsigned int i; char *pattern; char *p; p = buffer; pattern = Tcl_GetString(objv[2]); for (i = 0; i < nPrinters; i++) { if (Tcl_StringMatch(p, pattern)) { Tcl_AppendElement(interp, *(char **)p); } p += elemSize; } } else { register unsigned int i; char *p; p = buffer; for (i = 0; i < nPrinters; i++) { Tcl_AppendElement(interp, *(char **)p); p += elemSize; } } GlobalUnlock(hMem); GlobalFree(hMem); return TCL_OK; } /*ARGSUSED*/ static int CloseOp( ClientData clientData, /* Interpreter-specific data. */ Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { PrintQueue *queuePtr; if (GetQueueFromObj(interp, objv[2], &queuePtr) != TCL_OK) { return TCL_ERROR; } DestroyQueue(queuePtr); return TCL_OK; } /*ARGSUSED*/ static int GetAttrOp( ClientData clientData, /* Interpreter-specific data. */ Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { PrintQueue *queuePtr; if (GetQueueFromObj(interp, objv[2], &queuePtr) != TCL_OK) { return TCL_ERROR; } return GetPrinterAttributes(interp, queuePtr, objv[3]); } /*ARGSUSED*/ static int SetAttrOp( ClientData clientData, /* Interpreter-specific data. */ Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { PrintQueue *queuePtr; if (GetQueueFromObj(interp, objv[2], &queuePtr) != TCL_OK) { return TCL_ERROR; } return SetQueueAttributes(interp, queuePtr, objv[3]); } /* * -------------------------------------------------------------------------- * * SnapOp -- * * Prints a snapshot of a Tk_Window to the designated printer. * * Results: * Returns a standard Tcl result. If an error occurred * TCL_ERROR is returned and interp->result will contain an * error message. * * ------------------------------------------------------------------------- */ static int SnapOp( ClientData clientData, /* Interpreter-specific data. */ Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { BITMAPINFO bi; DIBSECTION ds; HBITMAP hBitmap; HPALETTE hPalette; HDC hDC, printDC, memDC; void *data; Tk_Window tkwin; TkWinDCState state; int result; PrintQueue *queuePtr; DOCINFO di; double pageWidth, pageHeight; int jobId; char *driverName; DEVMODE *dmPtr; HGLOBAL hMem; Tcl_DString dString; char *path; Tcl_DStringInit(&dString); if (GetQueueFromObj(interp, objv[2], &queuePtr) != TCL_OK) { return TCL_ERROR; } path = Tcl_GetString(objv[3]); tkwin = Tk_NameToWindow(interp, path, Tk_MainWindow(interp)); if (tkwin == NULL) { return TCL_ERROR; } if (Tk_WindowId(tkwin) == None) { Tk_MakeWindowExist(tkwin); } result = TCL_ERROR; hDC = TkWinGetDrawableDC(Tk_Display(tkwin), Tk_WindowId(tkwin), &state); ZeroMemory(&bi, sizeof(bi)); bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bi.bmiHeader.biWidth = Tk_Width(tkwin); bi.bmiHeader.biHeight = Tk_Height(tkwin); bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biBitCount = 32; bi.bmiHeader.biCompression = BI_RGB; hBitmap = CreateDIBSection(hDC, &bi, DIB_RGB_COLORS, &data, NULL, 0); memDC = CreateCompatibleDC(hDC); SelectBitmap(memDC, hBitmap); hPalette = Blt_GetSystemPalette(); if (hPalette != NULL) { SelectPalette(hDC, hPalette, FALSE); RealizePalette(hDC); SelectPalette(memDC, hPalette, FALSE); RealizePalette(memDC); } /* Copy the window contents to the memory surface. */ if (!BitBlt(memDC, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), hDC, 0, 0, SRCCOPY)) { Tcl_AppendResult(interp, "can't blit \"", Tk_PathName(tkwin), "\": ", Blt_LastError(), (char *)NULL); goto done; } /* Now that the DIB contains the image of the window, get the * databits and write them to the printer device, stretching the * image to the fit the printer's resolution. */ if (GetObject(hBitmap, sizeof(DIBSECTION), &ds) == 0) { Tcl_AppendResult(interp, "can't get DIB object: ", Blt_LastError(), (char *)NULL); goto done; } driverName = NULL; if (Blt_GetPlatformId() == VER_PLATFORM_WIN32_NT) { driverName = queuePtr->driverName; } if (OpenQueue(interp, queuePtr) != TCL_OK) { goto done; } hMem = GetQueueProperties(queuePtr, &dmPtr); if (hMem == NULL) { goto done; } printDC = CreateDC(driverName, queuePtr->deviceName, NULL, dmPtr); GlobalUnlock(hMem); GlobalFree(hMem); if (printDC == NULL) { Tcl_AppendResult(interp, "can't allocate printer DC for \"", queuePtr->name, "\": ", Blt_LastError(), (char *)NULL); goto done; } { double scale, sx, sy; /* Get the resolution of the printer device. */ sx = (double)GetDeviceCaps(printDC, HORZRES)/(double)Tk_Width(tkwin); sy = (double)GetDeviceCaps(printDC, VERTRES)/(double)Tk_Height(tkwin); scale = MIN(sx, sy); pageWidth = scale * Tk_Width(tkwin); pageHeight = scale * Tk_Height(tkwin); } ZeroMemory(&di, sizeof(di)); di.cbSize = sizeof(di); Tcl_DStringAppend(&dString, "Snapshot of \"", -1); Tcl_DStringAppend(&dString, Tk_PathName(tkwin), -1); Tcl_DStringAppend(&dString, "\"", -1); di.lpszDocName = Tcl_DStringValue(&dString); jobId = StartDoc(printDC, &di); if (jobId <= 0) { Tcl_AppendResult(interp, "can't start document: ", Blt_LastError(), (char *)NULL); goto done; } if (StartPage(printDC) <= 0) { Tcl_AppendResult(interp, "error starting page: ", Blt_LastError(), (char *)NULL); goto done; } StretchDIBits(printDC, 0, 0, ROUND(pageWidth), ROUND(pageHeight), 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), ds.dsBm.bmBits, (LPBITMAPINFO)&ds.dsBmih, DIB_RGB_COLORS, SRCCOPY); EndPage(printDC); EndDoc(printDC); DeleteDC(printDC); Tcl_SetResult(interp, Blt_Itoa(jobId), TCL_VOLATILE); result = TCL_OK; done: Tcl_DStringFree(&dString); if (queuePtr->hPrinter != NULL) { CloseQueue(queuePtr); } DeleteBitmap(hBitmap); DeleteDC(memDC); TkWinReleaseDrawableDC(Tk_WindowId(tkwin), hDC, &state); if (hPalette != NULL) { DeletePalette(hPalette); } return result; } /*ARGSUSED*/ static int WriteOp( ClientData clientData, /* Interpreter-specific data. */ Tcl_Interp *interp, int objc, /* Not used. */ Tcl_Obj *CONST *objv) { DWORD bytesLeft, nBytes; DOC_INFO_1 di1; DWORD jobId; char *title; register char *data; static int nextJob = 0; char string[200]; PrintQueue *queuePtr; int result; if (GetQueueFromObj(interp, objv[2], &queuePtr) != TCL_OK) { return TCL_ERROR; } if (OpenQueue(interp, queuePtr) != TCL_OK) { return TCL_ERROR; } if (objc == 5) { title = Tcl_GetString(objv[3]); data = Tcl_GetStringFromObj(objv[4], &bytesLeft); } else { sprintf(string, "Print Job #%d", nextJob++); title = string; data = Tcl_GetStringFromObj(objv[3], &bytesLeft); } ZeroMemory(&di1, sizeof(DOC_INFO_1)); di1.pDocName = title; if (queuePtr->fileName != NULL) { di1.pOutputFile = queuePtr->fileName; } else { di1.pOutputFile = NULL; } di1.pDatatype = "RAW"; result = TCL_ERROR; /* Start new document */ jobId = StartDocPrinter(queuePtr->hPrinter, 1, (unsigned char *)&di1); if (jobId == 0) { Tcl_AppendResult(interp, "error starting document on \"", queuePtr->printerName, "\": ", Blt_LastError(), (char *)NULL); goto error; } /* Start new page */ if (!StartPagePrinter(queuePtr->hPrinter)) { Tcl_AppendResult(interp, "error starting page on \"", queuePtr->printerName, "\": ", Blt_LastError(), (char *)NULL); goto error; } do { if (!WritePrinter(queuePtr->hPrinter, data, bytesLeft, &nBytes)) { Tcl_AppendResult(interp, "can't write data to \"", queuePtr->printerName, "\": ", Blt_LastError(), (char *)NULL); EndDocPrinter(queuePtr->hPrinter); goto error; } data += nBytes; bytesLeft -= nBytes; } while (bytesLeft > 0); /* End last page */ if (!EndPagePrinter(queuePtr->hPrinter)) { Tcl_AppendResult(interp, "error ending page on \"", queuePtr->printerName, "\": ", Blt_LastError(), (char *)NULL); goto error; } /* End document */ if (!EndDocPrinter(queuePtr->hPrinter)) { Tcl_AppendResult(interp, "error ending document on \"", queuePtr->printerName, "\": ", Blt_LastError(), (char *)NULL); goto error; } result = TCL_OK; error: CloseQueue(queuePtr); return result; } static Blt_OpSpec printerOps[] = { {"close", 1, (Blt_Op)CloseOp, 3, 3, "pid",}, {"enum", 1, (Blt_Op)EnumOp, 3, 3, "attribute",}, {"getattrs", 1, (Blt_Op)GetAttrOp, 4, 4, "pid varName",}, {"names", 1, (Blt_Op)NamesOp, 2, 3, "?pattern?",}, {"open", 1, (Blt_Op)OpenOp, 3, 3, "printerName",}, {"setattrs", 1, (Blt_Op)SetAttrOp, 4, 4, "pid varName",}, {"snap", 1, (Blt_Op)SnapOp, 4, 4, "pid window",}, {"write", 1, (Blt_Op)WriteOp, 4, 5, "pid ?title? string",}, }; static int nPrinterOps = sizeof(printerOps) / sizeof(Blt_OpSpec); /* ARGSUSED */ static int PrinterCmd( ClientData clientData, /* Not used. */ Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv) { Blt_Op proc; int result; proc = Blt_GetOpFromObj(interp, nPrinterOps, printerOps, BLT_OP_ARG1, objc, objv, 0); if (proc == NULL) { return TCL_ERROR; } result = (*proc) (clientData, interp, objc, objv); return result; } /* * ----------------------------------------------------------------------- * * PrinterInterpDeleteProc -- * * This is called when the interpreter hosting one or more printer * commands is destroyed. * * Results: * None. * * Side effects: * Closes and removes all open printers. * * ------------------------------------------------------------------------ */ /* ARGSUSED */ static void PrinterInterpDeleteProc(clientData, interp) ClientData clientData; /* Interpreter-specific data. */ Tcl_Interp *interp; { PrinterInterpData *dataPtr = clientData; Blt_HashEntry *hPtr; Blt_HashSearch cursor; PrintQueue *queuePtr; for (hPtr = Blt_FirstHashEntry(&dataPtr->printerTable, &cursor); hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) { queuePtr = (PrintQueue *)Blt_GetHashValue(hPtr); queuePtr->hashPtr = NULL; DestroyQueue(queuePtr); } Blt_DeleteHashTable(&dataPtr->printerTable); Tcl_DeleteAssocData(interp, PRINTER_THREAD_KEY); Blt_Free(dataPtr); } int Blt_PrinterInit(Tcl_Interp *interp) { static Blt_ObjCmdSpec cmdSpec = { "printer", PrinterCmd }; PrinterInterpData *dataPtr; dataPtr = GetPrinterInterpData(interp); cmdSpec.clientData = dataPtr; if (Blt_InitObjCmd(interp, "blt", &cmdSpec) == NULL) { return TCL_ERROR; } return TCL_OK; } /* Public routines */ int Blt_GetOpenPrinter( Tcl_Interp *interp, const char *name, Drawable *drawablePtr) { PrintQueue *queuePtr; if (GetQueue(interp, name, &queuePtr) != TCL_OK) { return TCL_ERROR; } if (queuePtr->drawable.hDC == NULL) { char *driverName; HGLOBAL hMem; DEVMODE *dmPtr; HDC hDC; driverName = NULL; if (Blt_GetPlatformId() == VER_PLATFORM_WIN32_NT) { driverName = queuePtr->driverName; } if (OpenQueue(interp, queuePtr) != TCL_OK) { return TCL_ERROR; } hMem = GetQueueProperties(queuePtr, &dmPtr); if (hMem == NULL) { CloseQueue(queuePtr); return TCL_ERROR; } if (queuePtr->dmPtr != NULL) { *dmPtr = *queuePtr->dmPtr; } hDC = CreateDC(driverName, queuePtr->deviceName, NULL, dmPtr); GlobalUnlock(hMem); GlobalFree(hMem); CloseQueue(queuePtr); if (hDC == NULL) { Tcl_AppendResult(interp, "can't allocate printer DC for \"", queuePtr->name, "\": ", Blt_LastError(), (char *)NULL); return TCL_ERROR; } queuePtr->drawable.hDC = hDC; queuePtr->drawable.type = TWD_WINDC; } *drawablePtr = (Drawable)(&queuePtr->drawable); return TCL_OK; } #include int Blt_PrintDialog( Tcl_Interp *interp, Drawable *drawablePtr) { PRINTDLG dlg; static PrintDrawable drawable; int mode, result; ZeroMemory(&dlg, sizeof(PRINTDLG)); dlg.lStructSize = sizeof(PRINTDLG); dlg.Flags = PD_RETURNDC | PD_NOPAGENUMS | PD_NOSELECTION; mode = Tcl_SetServiceMode(TCL_SERVICE_NONE); result = PrintDlg(&dlg); Tcl_SetServiceMode(mode); if (!result) { if (!CommDlgExtendedError()) { return TCL_RETURN; /* User canceled. */ } Tcl_AppendResult(interp, "can't access printer:", Blt_LastError(), (char *)NULL); return TCL_ERROR; } *drawablePtr = (Drawable)&drawable; drawable.type = TWD_WINDC; drawable.hDC = dlg.hDC; return TCL_OK; } int Blt_StartPrintJob( Tcl_Interp *interp, Drawable drawable) { DOCINFO di; PrintDrawable *drawPtr = (PrintDrawable *)drawable; int jobId; ZeroMemory((char *)&di, sizeof(DOCINFO)); di.cbSize = sizeof(DOCINFO); di.lpszDocName = "Unknown"; jobId = StartDoc(drawPtr->hDC, &di); if (jobId == 0) { Tcl_AppendResult(interp, "error starting document: ", Blt_LastError(), (char *)NULL); return TCL_ERROR; } return TCL_OK; } int Blt_EndPrintJob( Tcl_Interp *interp, Drawable drawable) { PrintDrawable *drawPtr = (PrintDrawable *)drawable; EndPage(drawPtr->hDC); EndDoc(drawPtr->hDC); return TCL_OK; } #endif /*NO_PRINTER*/ blt-2.4z.orig/src/bltWinUtil.c0100644000175000017500000000366007320470723015005 0ustar dokodoko/* * bltWinUtil.c -- * * This module contains WIN32 routines not included in the Tcl/Tk * libraries. * * Copyright 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. * */ #include double drand48(void) { return (double) rand() / (double)RAND_MAX; } void srand48(long int seed) { srand(seed); } int Blt_GetPlatformId(void) { static int platformId = 0; if (platformId == 0) { OSVERSIONINFO opsysInfo; opsysInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (GetVersionEx(&opsysInfo)) { platformId = opsysInfo.dwPlatformId; } } return platformId; } char * Blt_LastError(void) { static char buffer[1024]; int length; FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */ buffer, 1024, NULL); length = strlen(buffer); if (buffer[length - 2] == '\r') { buffer[length - 2] = '\0'; } return buffer; } blt-2.4z.orig/src/bltWindow.c0100644000175000017500000014410607542237061014664 0ustar dokodoko/* * bltWindow.c -- * * This module implements additional window functionality for * the BLT toolkit, such as transparent Tk windows, * and reparenting Tk windows. * * Copyright 1991-1998 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. */ #include "bltInt.h" #include #ifndef WIN32 #include #endif typedef struct TkIdStackStruct TkIdStack; typedef struct TkErrorHandlerStruct TkErrorHandler; typedef struct TkSelectionInfoStruct TkSelectionInfo; typedef struct TkClipboardTargetStruct TkClipboardTarget; #ifndef WIN32 typedef struct TkWindowStruct TkWindow; #endif typedef struct TkWindowEventStruct TkWindowEvent; typedef struct TkMainInfoStruct TkMainInfo; typedef struct TkEventHandlerStruct TkEventHandler; typedef struct TkSelHandlerStruct TkSelHandler; typedef struct TkWinInfoStruct TkWinInfo; typedef struct TkClassProcsStruct TkClassProcs; typedef struct TkWindowPrivateStruct TkWindowPrivate; typedef struct TkGrabEventStruct TkGrabEvent; typedef struct TkColormapStruct TkColormap; typedef struct TkStressedCmapStruct TkStressedCmap; typedef struct TkWmInfoStruct TkWmInfo; #ifdef XNQueryInputStyle #define TK_USE_INPUT_METHODS #endif /* * This defines whether we should try to use XIM over-the-spot style * input. Allow users to override it. It is a much more elegant use * of XIM, but uses a bit more memory. */ #ifndef TK_XIM_SPOT # define TK_XIM_SPOT 1 #endif #ifndef TK_REPARENTED #define TK_REPARENTED 0 #endif #if (TK_VERSION_NUMBER >= _VERSION(8,1,0)) typedef struct TkCaret { struct TkWindow *winPtr; /* the window on which we requested caret * placement */ int x; /* relative x coord of the caret */ int y; /* relative y coord of the caret */ int height; /* specified height of the window */ } TkCaret; /* * One of the following structures is maintained for each display * containing a window managed by Tk. In part, the structure is * used to store thread-specific data, since each thread will have * its own TkDisplay structure. */ typedef struct TkDisplayStruct { Display *display; /* Xlib's info about display. */ struct TkDisplayStruct *nextPtr; /* Next in list of all displays. */ char *name; /* Name of display (with any screen * identifier removed). Malloc-ed. */ Time lastEventTime; /* Time of last event received for this * display. */ /* * Information used primarily by tk3d.c: */ int borderInit; /* 0 means borderTable needs initializing. */ Tcl_HashTable borderTable; /* Maps from color name to TkBorder * structure. */ /* * Information used by tkAtom.c only: */ int atomInit; /* 0 means stuff below hasn't been * initialized yet. */ Tcl_HashTable nameTable; /* Maps from names to Atom's. */ Tcl_HashTable atomTable; /* Maps from Atom's back to names. */ /* * Information used primarily by tkBind.c: */ int bindInfoStale; /* Non-zero means the variables in this * part of the structure are potentially * incorrect and should be recomputed. */ unsigned int modeModMask; /* Has one bit set to indicate the modifier * corresponding to "mode shift". If no * such modifier, than this is zero. */ unsigned int metaModMask; /* Has one bit set to indicate the modifier * corresponding to the "Meta" key. If no * such modifier, then this is zero. */ unsigned int altModMask; /* Has one bit set to indicate the modifier * corresponding to the "Meta" key. If no * such modifier, then this is zero. */ enum { LU_IGNORE, LU_CAPS, LU_SHIFT } lockUsage; /* Indicates how to interpret lock modifier. */ int numModKeyCodes; /* Number of entries in modKeyCodes array * below. */ KeyCode *modKeyCodes; /* Pointer to an array giving keycodes for * all of the keys that have modifiers * associated with them. Malloc'ed, but * may be NULL. */ /* * Information used by tkBitmap.c only: */ int bitmapInit; /* 0 means tables above need initializing. */ int bitmapAutoNumber; /* Used to number bitmaps. */ Tcl_HashTable bitmapNameTable; /* Maps from name of bitmap to the first * TkBitmap record for that name. */ Tcl_HashTable bitmapIdTable;/* Maps from bitmap id to the TkBitmap * structure for the bitmap. */ Tcl_HashTable bitmapDataTable; /* Used by Tk_GetBitmapFromData to map from * a collection of in-core data about a * bitmap to a reference giving an auto- * matically-generated name for the bitmap. */ /* * Information used by tkCanvas.c only: */ int numIdSearches; int numSlowSearches; /* * Used by tkColor.c only: */ int colorInit; /* 0 means color module needs initializing. */ TkStressedCmap *stressPtr; /* First in list of colormaps that have * filled up, so we have to pick an * approximate color. */ Tcl_HashTable colorNameTable; /* Maps from color name to TkColor structure * for that color. */ Tcl_HashTable colorValueTable; /* Maps from integer RGB values to TkColor * structures. */ /* * Used by tkCursor.c only: */ int cursorInit; /* 0 means cursor module need initializing. */ Tcl_HashTable cursorNameTable; /* Maps from a string name to a cursor to the * TkCursor record for the cursor. */ Tcl_HashTable cursorDataTable; /* Maps from a collection of in-core data * about a cursor to a TkCursor structure. */ Tcl_HashTable cursorIdTable; /* Maps from a cursor id to the TkCursor * structure for the cursor. */ char cursorString[20]; /* Used to store a cursor id string. */ Font cursorFont; /* Font to use for standard cursors. * None means font not loaded yet. */ /* * Information used by tkError.c only: */ struct TkErrorHandler *errorPtr; /* First in list of error handlers * for this display. NULL means * no handlers exist at present. */ int deleteCount; /* Counts # of handlers deleted since * last time inactive handlers were * garbage-collected. When this number * gets big, handlers get cleaned up. */ /* * Used by tkEvent.c only: */ struct TkWindowEvent *delayedMotionPtr; /* Points to a malloc-ed motion event * whose processing has been delayed in * the hopes that another motion event * will come along right away and we can * merge the two of them together. NULL * means that there is no delayed motion * event. */ /* * Information used by tkFocus.c only: */ int focusDebug; /* 1 means collect focus debugging * statistics. */ struct TkWindow *implicitWinPtr; /* If the focus arrived at a toplevel window * implicitly via an Enter event (rather * than via a FocusIn event), this points * to the toplevel window. Otherwise it is * NULL. */ struct TkWindow *focusPtr; /* Points to the window on this display that * should be receiving keyboard events. When * multiple applications on the display have * the focus, this will refer to the * innermost window in the innermost * application. This information isn't used * under Unix or Windows, but it's needed on * the Macintosh. */ /* * Information used by tkGC.c only: */ Tcl_HashTable gcValueTable; /* Maps from a GC's values to a TkGC structure * describing a GC with those values. */ Tcl_HashTable gcIdTable; /* Maps from a GC to a TkGC. */ int gcInit; /* 0 means the tables below need * initializing. */ /* * Information used by tkGeometry.c only: */ Tcl_HashTable maintainHashTable; /* Hash table that maps from a master's * Tk_Window token to a list of slaves * managed by that master. */ int geomInit; /* * Information used by tkGet.c only: */ Tcl_HashTable uidTable; /* Stores all Tk_Uids used in a thread. */ int uidInit; /* 0 means uidTable needs initializing. */ /* * Information used by tkGrab.c only: */ struct TkWindow *grabWinPtr; /* Window in which the pointer is currently * grabbed, or NULL if none. */ struct TkWindow *eventualGrabWinPtr; /* Value that grabWinPtr will have once the * grab event queue (below) has been * completely emptied. */ struct TkWindow *buttonWinPtr; /* Window in which first mouse button was * pressed while grab was in effect, or NULL * if no such press in effect. */ struct TkWindow *serverWinPtr; /* If no application contains the pointer then * this is NULL. Otherwise it contains the * last window for which we've gotten an * Enter or Leave event from the server (i.e. * the last window known to have contained * the pointer). Doesn't reflect events * that were synthesized in tkGrab.c. */ TkGrabEvent *firstGrabEventPtr; /* First in list of enter/leave events * synthesized by grab code. These events * must be processed in order before any other * events are processed. NULL means no such * events. */ TkGrabEvent *lastGrabEventPtr; /* Last in list of synthesized events, or NULL * if list is empty. */ int grabFlags; /* Miscellaneous flag values. See definitions * in tkGrab.c. */ /* * Information used by tkGrid.c only: */ int gridInit; /* 0 means table below needs initializing. */ Tcl_HashTable gridHashTable;/* Maps from Tk_Window tokens to * corresponding Grid structures. */ /* * Information used by tkImage.c only: */ int imageId; /* Value used to number image ids. */ /* * Information used by tkMacWinMenu.c only: */ int postCommandGeneration; /* * Information used by tkOption.c only. */ /* * Information used by tkPack.c only. */ int packInit; /* 0 means table below needs initializing. */ Tcl_HashTable packerHashTable; /* Maps from Tk_Window tokens to * corresponding Packer structures. */ /* * Information used by tkPlace.c only. */ int placeInit; /* 0 means tables below need initializing. */ Tcl_HashTable masterTable; /* Maps from Tk_Window toke to the Master * structure for the window, if it exists. */ Tcl_HashTable slaveTable; /* Maps from Tk_Window toke to the Slave * structure for the window, if it exists. */ /* * Information used by tkSelect.c and tkClipboard.c only: */ struct TkSelectionInfo *selectionInfoPtr; /* First in list of selection information * records. Each entry contains information * about the current owner of a particular * selection on this display. */ Atom multipleAtom; /* Atom for MULTIPLE. None means * selection stuff isn't initialized. */ Atom incrAtom; /* Atom for INCR. */ Atom targetsAtom; /* Atom for TARGETS. */ Atom timestampAtom; /* Atom for TIMESTAMP. */ Atom textAtom; /* Atom for TEXT. */ Atom compoundTextAtom; /* Atom for COMPOUND_TEXT. */ Atom applicationAtom; /* Atom for TK_APPLICATION. */ Atom windowAtom; /* Atom for TK_WINDOW. */ Atom clipboardAtom; /* Atom for CLIPBOARD. */ #if (TK_VERSION_NUMBER >= _VERSION(8,4,0)) Atom utf8Atom; #endif Tk_Window clipWindow; /* Window used for clipboard ownership and to * retrieve selections between processes. NULL * means clipboard info hasn't been * initialized. */ int clipboardActive; /* 1 means we currently own the clipboard * selection, 0 means we don't. */ struct TkMainInfo *clipboardAppPtr; /* Last application that owned clipboard. */ struct TkClipboardTarget *clipTargetPtr; /* First in list of clipboard type information * records. Each entry contains information * about the buffers for a given selection * target. */ /* * Information used by tkSend.c only: */ Tk_Window commTkwin; /* Window used for communication * between interpreters during "send" * commands. NULL means send info hasn't * been initialized yet. */ Atom commProperty; /* X's name for comm property. */ Atom registryProperty; /* X's name for property containing * registry of interpreter names. */ Atom appNameProperty; /* X's name for property used to hold the * application name on each comm window. */ /* * Information used by tkXId.c only: */ struct TkIdStack *idStackPtr; /* First in list of chunks of free resource * identifiers, or NULL if there are no free * resources. */ XID(*defaultAllocProc) _ANSI_ARGS_((Display *display)); /* Default resource allocator for display. */ struct TkIdStack *windowStackPtr; /* First in list of chunks of window * identifers that can't be reused right * now. */ #if (TK_VERSION_NUMBER < _VERSION(8,4,0)) int idCleanupScheduled; /* 1 means a call to WindowIdCleanup has * already been scheduled, 0 means it * hasn't. */ #else Tcl_TimerToken idCleanupScheduled; /* If set, it means a call to WindowIdCleanup * has already been scheduled, 0 means it * hasn't. */ #endif /* * Information used by tkUnixWm.c and tkWinWm.c only: */ #if (TK_VERSION_NUMBER < _VERSION(8,4,0)) int wmTracing; /* Used to enable or disable tracing in * this module. If tracing is enabled, * then information is printed on * standard output about interesting * interactions with the window manager. */ #endif struct TkWmInfo *firstWmPtr; /* Points to first top-level window. */ struct TkWmInfo *foregroundWmPtr; /* Points to the foreground window. */ /* * Information maintained by tkWindow.c for use later on by tkXId.c: */ int destroyCount; /* Number of Tk_DestroyWindow operations * in progress. */ unsigned long lastDestroyRequest; /* Id of most recent XDestroyWindow request; * can re-use ids in windowStackPtr when * server has seen this request and event * queue is empty. */ /* * Information used by tkVisual.c only: */ TkColormap *cmapPtr; /* First in list of all non-default colormaps * allocated for this display. */ /* * Miscellaneous information: */ #ifdef TK_USE_INPUT_METHODS XIM inputMethod; /* Input method for this display */ #if (TK_VERSION_NUMBER >= _VERSION(8,4,0)) #if TK_XIM_SPOT XFontSet inputXfs; /* XFontSet cached for over-the-spot XIM. */ #endif /* TK_XIM_SPOT */ #endif /* TK_VERSION_NUMBER >= 8.4 */ #endif /* TK_USE_INPUT_METHODS */ Tcl_HashTable winTable; /* Maps from X window ids to TkWindow ptrs. */ int refCount; /* Reference count of how many Tk applications * are using this display. Used to clean up * the display when we no longer have any * Tk applications using it. */ /* * The following field were all added for Tk8.3 */ int mouseButtonState; /* current mouse button state for this * display */ #if (TK_VERSION_NUMBER < _VERSION(8,4,0)) int warpInProgress; #endif Window warpWindow; int warpX; int warpY; #if (TK_VERSION_NUMBER < _VERSION(8,4,0)) int useInputMethods; /* Whether to use input methods */ #else /* * The following field(s) were all added for Tk8.4 */ long deletionEpoch; /* Incremented by window deletions */ unsigned int flags; /* Various flag values: these are all * defined in below. */ TkCaret caret; /* information about the caret for this * display. This is not a pointer. */ #endif } TkDisplay; #else /* * One of the following structures is maintained for each display * containing a window managed by Tk: */ typedef struct TkDisplayStruct { Display *display; /* Xlib's info about display. */ struct TkDisplayStruct *nextPtr; /* Next in list of all displays. */ char *name; /* Name of display (with any screen * identifier removed). Malloc-ed. */ Time lastEventTime; /* Time of last event received for this * display. */ /* * Information used primarily by tkBind.c: */ int bindInfoStale; /* Non-zero means the variables in this * part of the structure are potentially * incorrect and should be recomputed. */ unsigned int modeModMask; /* Has one bit set to indicate the modifier * corresponding to "mode shift". If no * such modifier, than this is zero. */ unsigned int metaModMask; /* Has one bit set to indicate the modifier * corresponding to the "Meta" key. If no * such modifier, then this is zero. */ unsigned int altModMask; /* Has one bit set to indicate the modifier * corresponding to the "Meta" key. If no * such modifier, then this is zero. */ enum { LU_IGNORE, LU_CAPS, LU_SHIFT } lockUsage; /* Indicates how to interpret lock modifier. */ int numModKeyCodes; /* Number of entries in modKeyCodes array * below. */ KeyCode *modKeyCodes; /* Pointer to an array giving keycodes for * all of the keys that have modifiers * associated with them. Malloc'ed, but * may be NULL. */ /* * Information used by tkError.c only: */ TkErrorHandler *errorPtr; /* First in list of error handlers * for this display. NULL means * no handlers exist at present. */ int deleteCount; /* Counts # of handlers deleted since * last time inactive handlers were * garbage-collected. When this number * gets big, handlers get cleaned up. */ /* * Information used by tkSend.c only: */ Tk_Window commTkwin; /* Window used for communication * between interpreters during "send" * commands. NULL means send info hasn't * been initialized yet. */ Atom commProperty; /* X's name for comm property. */ Atom registryProperty; /* X's name for property containing * registry of interpreter names. */ Atom appNameProperty; /* X's name for property used to hold the * application name on each comm window. */ /* * Information used by tkSelect.c and tkClipboard.c only: */ TkSelectionInfo *selectionInfoPtr; /* First in list of selection information * records. Each entry contains information * about the current owner of a particular * selection on this display. */ Atom multipleAtom; /* Atom for MULTIPLE. None means * selection stuff isn't initialized. */ Atom incrAtom; /* Atom for INCR. */ Atom targetsAtom; /* Atom for TARGETS. */ Atom timestampAtom; /* Atom for TIMESTAMP. */ Atom textAtom; /* Atom for TEXT. */ Atom compoundTextAtom; /* Atom for COMPOUND_TEXT. */ Atom applicationAtom; /* Atom for TK_APPLICATION. */ Atom windowAtom; /* Atom for TK_WINDOW. */ Atom clipboardAtom; /* Atom for CLIPBOARD. */ Tk_Window clipWindow; /* Window used for clipboard ownership and to * retrieve selections between processes. NULL * means clipboard info hasn't been * initialized. */ int clipboardActive; /* 1 means we currently own the clipboard * selection, 0 means we don't. */ TkMainInfo *clipboardAppPtr; /* Last application that owned clipboard. */ TkClipboardTarget *clipTargetPtr; /* First in list of clipboard type information * records. Each entry contains information * about the buffers for a given selection * target. */ /* * Information used by tkAtom.c only: */ int atomInit; /* 0 means stuff below hasn't been * initialized yet. */ Tcl_HashTable nameTable; /* Maps from names to Atom's. */ Tcl_HashTable atomTable; /* Maps from Atom's back to names. */ /* * Information used by tkCursor.c only: */ Font cursorFont; /* Font to use for standard cursors. * None means font not loaded yet. */ /* * Information used by tkGrab.c only: */ TkWindow *grabWinPtr; /* Window in which the pointer is currently * grabbed, or NULL if none. */ TkWindow *eventualGrabWinPtr; /* Value that grabWinPtr will have once the * grab event queue (below) has been * completely emptied. */ TkWindow *buttonWinPtr; /* Window in which first mouse button was * pressed while grab was in effect, or NULL * if no such press in effect. */ TkWindow *serverWinPtr; /* If no application contains the pointer then * this is NULL. Otherwise it contains the * last window for which we've gotten an * Enter or Leave event from the server (i.e. * the last window known to have contained * the pointer). Doesn't reflect events * that were synthesized in tkGrab.c. */ TkGrabEvent *firstGrabEventPtr; /* First in list of enter/leave events * synthesized by grab code. These events * must be processed in order before any other * events are processed. NULL means no such * events. */ TkGrabEvent *lastGrabEventPtr; /* Last in list of synthesized events, or NULL * if list is empty. */ int grabFlags; /* Miscellaneous flag values. See definitions * in tkGrab.c. */ /* * Information used by tkXId.c only: */ TkIdStack *idStackPtr; /* First in list of chunks of free resource * identifiers, or NULL if there are no free * resources. */ XID(*defaultAllocProc) _ANSI_ARGS_((Display *display)); /* Default resource allocator for display. */ TkIdStack *windowStackPtr; /* First in list of chunks of window * identifers that can't be reused right * now. */ int idCleanupScheduled; /* 1 means a call to WindowIdCleanup has * already been scheduled, 0 means it * hasn't. */ /* * Information maintained by tkWindow.c for use later on by tkXId.c: */ int destroyCount; /* Number of Tk_DestroyWindow operations * in progress. */ unsigned long lastDestroyRequest; /* Id of most recent XDestroyWindow request; * can re-use ids in windowStackPtr when * server has seen this request and event * queue is empty. */ /* * Information used by tkVisual.c only: */ TkColormap *cmapPtr; /* First in list of all non-default colormaps * allocated for this display. */ /* * Information used by tkFocus.c only: */ #if (TK_MAJOR_VERSION == 4) TkWindow *focusWinPtr; /* Window that currently has the focus for * this display, or NULL if none. */ TkWindow *implicitWinPtr; /* If the focus arrived at a toplevel window * implicitly via an Enter event (rather * than via a FocusIn event), this points * to the toplevel window. Otherwise it is * NULL. */ TkWindow *focusOnMapPtr; /* This points to a toplevel window that is * supposed to receive the X input focus as * soon as it is mapped (needed to handle the * fact that X won't allow the focus on an * unmapped window). NULL means no delayed * focus op in progress. */ int forceFocus; /* Associated with focusOnMapPtr: non-zero * means claim the focus even if some other * application currently has it. */ #else TkWindow *implicitWinPtr; /* If the focus arrived at a toplevel window * implicitly via an Enter event (rather * than via a FocusIn event), this points * to the toplevel window. Otherwise it is * NULL. */ TkWindow *focusPtr; /* Points to the window on this display that * should be receiving keyboard events. When * multiple applications on the display have * the focus, this will refer to the * innermost window in the innermost * application. This information isn't used * under Unix or Windows, but it's needed on * the Macintosh. */ #endif /* TK_MAJOR_VERSION == 4 */ /* * Used by tkColor.c only: */ TkStressedCmap *stressPtr; /* First in list of colormaps that have * filled up, so we have to pick an * approximate color. */ /* * Used by tkEvent.c only: */ TkWindowEvent *delayedMotionPtr; /* Points to a malloc-ed motion event * whose processing has been delayed in * the hopes that another motion event * will come along right away and we can * merge the two of them together. NULL * means that there is no delayed motion * event. */ /* * Miscellaneous information: */ #ifdef TK_USE_INPUT_METHODS XIM inputMethod; /* Input method for this display */ #endif /* TK_USE_INPUT_METHODS */ Tcl_HashTable winTable; /* Maps from X window ids to TkWindow ptrs. */ #if (TK_MAJOR_VERSION > 4) int refCount; /* Reference count of how many Tk applications * are using this display. Used to clean up * the display when we no longer have any * Tk applications using it. */ #endif /* TK_MAJOR_VERSION > 4 */ } TkDisplay; #endif /* TK_VERSION_NUMBER >= _VERSION(8,1,0) */ struct TkWindowStruct { Display *display; TkDisplay *dispPtr; int screenNum; Visual *visual; int depth; Window window; TkWindow *childList; TkWindow *lastChildPtr; TkWindow *parentPtr; TkWindow *nextPtr; TkMainInfo *infoPtr; char *pathName; Tk_Uid nameUid; Tk_Uid classUid; XWindowChanges changes; unsigned int dirtyChanges; XSetWindowAttributes atts; unsigned long dirtyAtts; unsigned int flags; TkEventHandler *handlerList; #ifdef TK_USE_INPUT_METHODS XIC inputContext; #endif /* TK_USE_INPUT_METHODS */ ClientData *tagPtr; int nTags; int optionLevel; TkSelHandler *selHandlerList; Tk_GeomMgr *geomMgrPtr; ClientData geomData; int reqWidth, reqHeight; int internalBorderWidth; TkWinInfo *wmInfoPtr; #if (TK_MAJOR_VERSION > 4) TkClassProcs *classProcsPtr; ClientData instanceData; #endif TkWindowPrivate *privatePtr; }; #ifdef WIN32 /* *---------------------------------------------------------------------- * * GetWindowHandle -- * * Returns the XID for the Tk_Window given. Starting in Tk 8.0, * the toplevel widgets are wrapped by another window. * Currently there's no way to get at that window, other than * what is done here: query the X window hierarchy and grab the * parent. * * Results: * Returns the X Window ID of the widget. If it's a toplevel, then * the XID of the wrapper is returned. * *---------------------------------------------------------------------- */ static HWND GetWindowHandle(Tk_Window tkwin) { HWND hWnd; Window window; window = Tk_WindowId(tkwin); if (window == None) { Tk_MakeWindowExist(tkwin); } hWnd = Tk_GetHWND(Tk_WindowId(tkwin)); #if (TK_MAJOR_VERSION > 4) if (Tk_IsTopLevel(tkwin)) { hWnd = GetParent(hWnd); } #endif /* TK_MAJOR_VERSION > 4 */ return hWnd; } #else Window Blt_GetParent(display, window) Display *display; Window window; { Window root, parent; Window *dummy; unsigned int count; if (XQueryTree(display, window, &root, &parent, &dummy, &count) > 0) { XFree(dummy); return parent; } return None; } static Window GetWindowId(tkwin) Tk_Window tkwin; { Window window; Tk_MakeWindowExist(tkwin); window = Tk_WindowId(tkwin); #if (TK_MAJOR_VERSION > 4) if (Tk_IsTopLevel(tkwin)) { Window parent; parent = Blt_GetParent(Tk_Display(tkwin), window); if (parent != None) { window = parent; } window = parent; } #endif /* TK_MAJOR_VERSION > 4 */ return window; } #endif /* WIN32 */ /* *---------------------------------------------------------------------- * * DoConfigureNotify -- * * Generate a ConfigureNotify event describing the current * configuration of a window. * * Results: * None. * * Side effects: * An event is generated and processed by Tk_HandleEvent. * *---------------------------------------------------------------------- */ static void DoConfigureNotify(winPtr) Tk_FakeWin *winPtr; /* Window whose configuration was just * changed. */ { XEvent event; event.type = ConfigureNotify; event.xconfigure.serial = LastKnownRequestProcessed(winPtr->display); event.xconfigure.send_event = False; event.xconfigure.display = winPtr->display; event.xconfigure.event = winPtr->window; event.xconfigure.window = winPtr->window; event.xconfigure.x = winPtr->changes.x; event.xconfigure.y = winPtr->changes.y; event.xconfigure.width = winPtr->changes.width; event.xconfigure.height = winPtr->changes.height; event.xconfigure.border_width = winPtr->changes.border_width; if (winPtr->changes.stack_mode == Above) { event.xconfigure.above = winPtr->changes.sibling; } else { event.xconfigure.above = None; } event.xconfigure.override_redirect = winPtr->atts.override_redirect; Tk_HandleEvent(&event); } /* *-------------------------------------------------------------- * * Blt_MakeTransparentWindowExist -- * * Similar to Tk_MakeWindowExist but instead creates a * transparent window to block for user events from sibling * windows. * * Differences from Tk_MakeWindowExist. * * 1. This is always a "busy" window. There's never a * platform-specific class procedure to execute instead. * 2. The window is transparent and never will contain children, * so colormap information is irrelevant. * * Results: * None. * * Side effects: * When the procedure returns, the internal window associated * with tkwin is guaranteed to exist. This may require the * window's ancestors to be created too. * *-------------------------------------------------------------- */ void Blt_MakeTransparentWindowExist(tkwin, parent, isBusy) Tk_Window tkwin; /* Token for window. */ Window parent; /* Parent window. */ int isBusy; /* */ { TkWindow *winPtr = (TkWindow *) tkwin; TkWindow *winPtr2; Tcl_HashEntry *hPtr; int notUsed; TkDisplay *dispPtr; #ifdef WIN32 HWND hParent; int style; DWORD exStyle; HWND hWnd; #else long int mask; #endif /* WIN32 */ if (winPtr->window != None) { return; /* Window already exists. */ } #ifdef notdef if ((winPtr->parentPtr == NULL) || (winPtr->flags & TK_TOP_LEVEL)) { parent = XRootWindow(winPtr->display, winPtr->screenNum); /* TODO: Make the entire screen busy */ } else { if (Tk_WindowId(winPtr->parentPtr) == None) { Tk_MakeWindowExist((Tk_Window)winPtr->parentPtr); } } #endif /* Create a transparent window and put it on top. */ #ifdef WIN32 hParent = (HWND) parent; style = (WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); exStyle = (WS_EX_TRANSPARENT | WS_EX_TOPMOST); #define TK_WIN_CHILD_CLASS_NAME "TkChild" hWnd = CreateWindowEx(exStyle, TK_WIN_CHILD_CLASS_NAME, NULL, style, Tk_X(tkwin), Tk_Y(tkwin), Tk_Width(tkwin), Tk_Height(tkwin), hParent, NULL, (HINSTANCE) Tk_GetHINSTANCE(), NULL); winPtr->window = Tk_AttachHWND(tkwin, hWnd); #else mask = (!isBusy) ? 0 : (CWDontPropagate | CWEventMask); /* Ignore the important events while the window is mapped. */ #define USER_EVENTS (EnterWindowMask | LeaveWindowMask | KeyPressMask | \ KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask) #define PROP_EVENTS (KeyPressMask | KeyReleaseMask | ButtonPressMask | \ ButtonReleaseMask | PointerMotionMask) winPtr->atts.do_not_propagate_mask = PROP_EVENTS; winPtr->atts.event_mask = USER_EVENTS; winPtr->changes.border_width = 0; winPtr->depth = 0; winPtr->window = XCreateWindow(winPtr->display, parent, winPtr->changes.x, winPtr->changes.y, (unsigned)winPtr->changes.width, /* width */ (unsigned)winPtr->changes.height, /* height */ (unsigned)winPtr->changes.border_width, /* border_width */ winPtr->depth, /* depth */ InputOnly, /* class */ winPtr->visual, /* visual */ mask, /* valuemask */ &(winPtr->atts) /* attributes */ ); #endif /* WIN32 */ dispPtr = winPtr->dispPtr; hPtr = Tcl_CreateHashEntry(&(dispPtr->winTable), (char *)winPtr->window, ¬Used); Tcl_SetHashValue(hPtr, winPtr); winPtr->dirtyAtts = 0; winPtr->dirtyChanges = 0; #ifdef TK_USE_INPUT_METHODS winPtr->inputContext = NULL; #endif /* TK_USE_INPUT_METHODS */ if (!(winPtr->flags & TK_TOP_LEVEL)) { /* * If any siblings higher up in the stacking order have already * been created then move this window to its rightful position * in the stacking order. * * NOTE: this code ignores any changes anyone might have made * to the sibling and stack_mode field of the window's attributes, * so it really isn't safe for these to be manipulated except * by calling Tk_RestackWindow. */ for (winPtr2 = winPtr->nextPtr; winPtr2 != NULL; winPtr2 = winPtr2->nextPtr) { if ((winPtr2->window != None) && !(winPtr2->flags & TK_TOP_LEVEL)) { XWindowChanges changes; changes.sibling = winPtr2->window; changes.stack_mode = Below; XConfigureWindow(winPtr->display, winPtr->window, CWSibling | CWStackMode, &changes); break; } } } /* * Issue a ConfigureNotify event if there were deferred configuration * changes (but skip it if the window is being deleted; the * ConfigureNotify event could cause problems if we're being called * from Tk_DestroyWindow under some conditions). */ if ((winPtr->flags & TK_NEED_CONFIG_NOTIFY) && !(winPtr->flags & TK_ALREADY_DEAD)) { winPtr->flags &= ~TK_NEED_CONFIG_NOTIFY; DoConfigureNotify((Tk_FakeWin *) tkwin); } } /* *---------------------------------------------------------------------- * * Blt_FindChild -- * * Performs a linear search for the named child window in a given * parent window. * * This can be done via Tcl, but not through Tk's C API. It's * simple enough, if you peek into the Tk_Window structure. * * Results: * The child Tk_Window. If the named child can't be found, NULL * is returned. * *---------------------------------------------------------------------- */ /*LINTLIBRARY*/ Tk_Window Blt_FindChild(parent, name) Tk_Window parent; char *name; { register TkWindow *winPtr; TkWindow *parentPtr = (TkWindow *)parent; for (winPtr = parentPtr->childList; winPtr != NULL; winPtr = winPtr->nextPtr) { if (strcmp(name, winPtr->nameUid) == 0) { return (Tk_Window)winPtr; } } return NULL; } /* *---------------------------------------------------------------------- * * Blt_FirstChildWindow -- * * Performs a linear search for the named child window in a given * parent window. * * This can be done via Tcl, but not through Tk's C API. It's * simple enough, if you peek into the Tk_Window structure. * * Results: * The child Tk_Window. If the named child can't be found, NULL * is returned. * *---------------------------------------------------------------------- */ /*LINTLIBRARY*/ Tk_Window Blt_FirstChild(parent) Tk_Window parent; { TkWindow *parentPtr = (TkWindow *)parent; return (Tk_Window)parentPtr->childList; } /* *---------------------------------------------------------------------- * * Blt_FindChild -- * * Performs a linear search for the named child window in a given * parent window. * * This can be done via Tcl, but not through Tk's C API. It's * simple enough, if you peek into the Tk_Window structure. * * Results: * The child Tk_Window. If the named child can't be found, NULL * is returned. * *---------------------------------------------------------------------- */ /*LINTLIBRARY*/ Tk_Window Blt_NextChild(tkwin) Tk_Window tkwin; { TkWindow *winPtr = (TkWindow *)tkwin; if (winPtr == NULL) { return NULL; } return (Tk_Window)winPtr->nextPtr; } /* *---------------------------------------------------------------------- * * UnlinkWindow -- * * This procedure removes a window from the childList of its * parent. * * Results: * None. * * Side effects: * The window is unlinked from its childList. * *---------------------------------------------------------------------- */ static void UnlinkWindow(winPtr) TkWindow *winPtr; /* Child window to be unlinked. */ { TkWindow *prevPtr; prevPtr = winPtr->parentPtr->childList; if (prevPtr == winPtr) { winPtr->parentPtr->childList = winPtr->nextPtr; if (winPtr->nextPtr == NULL) { winPtr->parentPtr->lastChildPtr = NULL; } } else { while (prevPtr->nextPtr != winPtr) { prevPtr = prevPtr->nextPtr; if (prevPtr == NULL) { panic("UnlinkWindow couldn't find child in parent"); } } prevPtr->nextPtr = winPtr->nextPtr; if (winPtr->nextPtr == NULL) { winPtr->parentPtr->lastChildPtr = prevPtr; } } } /* *---------------------------------------------------------------------- * * Blt_RelinkWindow -- * * Relinks a window into a new parent. The window is unlinked * from its original parent's child list and added onto the end * of the new parent's list. * * FIXME: If the window has focus, the focus should be moved * to an ancestor. Otherwise, Tk becomes confused * about which Toplevel turns on focus for the window. * Right now this is done at the Tcl layer. For example, * see blt::CreateTearoff in tabset.tcl. * * Results: * None. * * Side effects: * The window is unlinked from its childList. * *---------------------------------------------------------------------- */ void Blt_RelinkWindow(tkwin, newParent, x, y) Tk_Window tkwin; /* Child window to be linked. */ Tk_Window newParent; int x, y; { TkWindow *winPtr, *parentWinPtr; if (Blt_ReparentWindow(Tk_Display(tkwin), Tk_WindowId(tkwin), Tk_WindowId(newParent), x, y) != TCL_OK) { return; } winPtr = (TkWindow *)tkwin; parentWinPtr = (TkWindow *)newParent; winPtr->flags &= ~TK_REPARENTED; UnlinkWindow(winPtr); /* Remove the window from its parent's list */ /* Append the window onto the end of the parent's list of children */ winPtr->parentPtr = parentWinPtr; winPtr->nextPtr = NULL; if (parentWinPtr->childList == NULL) { parentWinPtr->childList = winPtr; } else { parentWinPtr->lastChildPtr->nextPtr = winPtr; } parentWinPtr->lastChildPtr = winPtr; } /* *---------------------------------------------------------------------- * * Blt_RelinkWindow -- * * Relinks a window into a new parent. The window is unlinked * from its original parent's child list and added onto the end * of the new parent's list. * * FIXME: If the window has focus, the focus should be moved * to an ancestor. Otherwise, Tk becomes confused * about which Toplevel turns on focus for the window. * Right now this is done at the Tcl layer. For example, * see blt::CreateTearoff in tabset.tcl. * * Results: * None. * * Side effects: * The window is unlinked from its childList. * *---------------------------------------------------------------------- */ void Blt_RelinkWindow2(tkwin, window, newParent, x, y) Tk_Window tkwin; /* Child window to be linked. */ Window window; Tk_Window newParent; int x, y; { #ifdef notdef TkWindow *winPtr, *parentWinPtr; #endif if (Blt_ReparentWindow(Tk_Display(tkwin), window, Tk_WindowId(newParent), x, y) != TCL_OK) { return; } #ifdef notdef winPtr = (TkWindow *)tkwin; parentWinPtr = (TkWindow *)newParent; winPtr->flags &= ~TK_REPARENTED; UnlinkWindow(winPtr); /* Remove the window from its parent's list */ /* Append the window onto the end of the parent's list of children */ winPtr->parentPtr = parentWinPtr; winPtr->nextPtr = NULL; if (parentWinPtr->childList == NULL) { parentWinPtr->childList = winPtr; } else { parentWinPtr->lastChildPtr->nextPtr = winPtr; } parentWinPtr->lastChildPtr = winPtr; #endif } void Blt_UnlinkWindow(tkwin) Tk_Window tkwin; /* Child window to be linked. */ { TkWindow *winPtr; Window root; root = XRootWindow(Tk_Display(tkwin), Tk_ScreenNumber(tkwin)); if (Blt_ReparentWindow(Tk_Display(tkwin), Tk_WindowId(tkwin), root, 0, 0) != TCL_OK) { return; } winPtr = (TkWindow *)tkwin; winPtr->flags &= ~TK_REPARENTED; #ifdef notdef UnlinkWindow(winPtr); /* Remove the window from its parent's list */ #endif } /* *---------------------------------------------------------------------- * * Blt_Toplevel -- * * Climbs up the widget hierarchy to find the top level window of * the window given. * * Results: * Returns the Tk_Window of the toplevel widget. * *---------------------------------------------------------------------- */ Tk_Window Blt_Toplevel(tkwin) register Tk_Window tkwin; { while (!Tk_IsTopLevel(tkwin)) { tkwin = Tk_Parent(tkwin); } return tkwin; } void Blt_RootCoordinates(tkwin, x, y, rootXPtr, rootYPtr) Tk_Window tkwin; int x, y; int *rootXPtr, *rootYPtr; { int vx, vy, vw, vh; int rootX, rootY; Tk_GetRootCoords(tkwin, &rootX, &rootY); x += rootX; y += rootY; Tk_GetVRootGeometry(tkwin, &vx, &vy, &vw, &vh); x += vx; y += vy; *rootXPtr = x; *rootYPtr = y; } /* Find the toplevel then */ int Blt_RootX(tkwin) Tk_Window tkwin; { int x; for (x = 0; tkwin != NULL; tkwin = Tk_Parent(tkwin)) { x += Tk_X(tkwin) + Tk_Changes(tkwin)->border_width; if (Tk_IsTopLevel(tkwin)) { break; } } return x; } int Blt_RootY(tkwin) Tk_Window tkwin; { int y; for (y = 0; tkwin != NULL; tkwin = Tk_Parent(tkwin)) { y += Tk_Y(tkwin) + Tk_Changes(tkwin)->border_width; if (Tk_IsTopLevel(tkwin)) { break; } } return y; } #ifdef WIN32 /* *---------------------------------------------------------------------- * * Blt_GetRealWindowId -- * * Returns the XID for the Tk_Window given. Starting in Tk 8.0, * the toplevel widgets are wrapped by another window. * Currently there's no way to get at that window, other than * what is done here: query the X window hierarchy and grab the * parent. * * Results: * Returns the X Window ID of the widget. If it's a toplevel, then * the XID of the wrapper is returned. * *---------------------------------------------------------------------- */ Window Blt_GetRealWindowId(Tk_Window tkwin) { return (Window) GetWindowHandle(tkwin); } /* *---------------------------------------------------------------------- * * Blt_GetToplevel -- * * Retrieves the toplevel window which is the nearest ancestor of * of the specified window. * * Results: * Returns the toplevel window or NULL if the window has no * ancestor which is a toplevel. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tk_Window Blt_GetToplevel(Tk_Window tkwin) /* Window for which the toplevel * should be deterined. */ { while (!Tk_IsTopLevel(tkwin)) { tkwin = Tk_Parent(tkwin); if (tkwin == NULL) { return NULL; } } return tkwin; } /* *---------------------------------------------------------------------- * * Blt_RaiseToLevelWindow -- * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_RaiseToplevel(Tk_Window tkwin) { SetWindowPos(GetWindowHandle(tkwin), HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); } /* *---------------------------------------------------------------------- * * Blt_MapToplevel -- * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_MapToplevel(Tk_Window tkwin) { ShowWindow(GetWindowHandle(tkwin), SW_SHOWNORMAL); } /* *---------------------------------------------------------------------- * * Blt_UnmapToplevel -- * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_UnmapToplevel(Tk_Window tkwin) { ShowWindow(GetWindowHandle(tkwin), SW_HIDE); } /* *---------------------------------------------------------------------- * * Blt_MoveResizeToplevel -- * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_MoveResizeToplevel(tkwin, x, y, width, height) Tk_Window tkwin; int x, y, width, height; { SetWindowPos(GetWindowHandle(tkwin), HWND_TOP, x, y, width, height, 0); } int Blt_ReparentWindow( Display *display, Window window, Window newParent, int x, int y) { XReparentWindow(display, window, newParent, x, y); return TCL_OK; } #else /* WIN32 */ /* *---------------------------------------------------------------------- * * Blt_GetRealWindowId -- * * Returns the XID for the Tk_Window given. Starting in Tk 8.0, * the toplevel widgets are wrapped by another window. * Currently there's no way to get at that window, other than * what is done here: query the X window hierarchy and grab the * parent. * * Results: * Returns the X Window ID of the widget. If it's a toplevel, then * the XID of the wrapper is returned. * *---------------------------------------------------------------------- */ Window Blt_GetRealWindowId(tkwin) Tk_Window tkwin; { return GetWindowId(tkwin); } /* *---------------------------------------------------------------------- * * Blt_RaiseToplevel -- * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_RaiseToplevel(tkwin) Tk_Window tkwin; { XRaiseWindow(Tk_Display(tkwin), GetWindowId(tkwin)); } /* *---------------------------------------------------------------------- * * Blt_LowerToplevel -- * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_LowerToplevel(tkwin) Tk_Window tkwin; { XLowerWindow(Tk_Display(tkwin), GetWindowId(tkwin)); } /* *---------------------------------------------------------------------- * * Blt_ResizeToplevel -- * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_ResizeToplevel(tkwin, width, height) Tk_Window tkwin; int width, height; { XResizeWindow(Tk_Display(tkwin), GetWindowId(tkwin), width, height); } /* *---------------------------------------------------------------------- * * Blt_MoveResizeToplevel -- * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_MoveResizeToplevel(tkwin, x, y, width, height) Tk_Window tkwin; int x, y, width, height; { XMoveResizeWindow(Tk_Display(tkwin), GetWindowId(tkwin), x, y, width, height); } /* *---------------------------------------------------------------------- * * Blt_ResizeToplevel -- * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_MoveToplevel(tkwin, x, y) Tk_Window tkwin; int x, y; { XMoveWindow(Tk_Display(tkwin), GetWindowId(tkwin), x, y); } /* *---------------------------------------------------------------------- * * Blt_MapToplevel -- * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_MapToplevel(tkwin) Tk_Window tkwin; { XMapWindow(Tk_Display(tkwin), GetWindowId(tkwin)); } /* *---------------------------------------------------------------------- * * Blt_UnmapToplevel -- * * Results: * None. * *---------------------------------------------------------------------- */ void Blt_UnmapToplevel(tkwin) Tk_Window tkwin; { XUnmapWindow(Tk_Display(tkwin), GetWindowId(tkwin)); } /* ARGSUSED */ static int XReparentWindowErrorProc(clientData, errEventPtr) ClientData clientData; XErrorEvent *errEventPtr; { int *errorPtr = clientData; *errorPtr = TCL_ERROR; return 0; } int Blt_ReparentWindow(display, window, newParent, x, y) Display *display; Window window, newParent; int x, y; { Tk_ErrorHandler handler; int result; int any = -1; result = TCL_OK; handler = Tk_CreateErrorHandler(display, any, X_ReparentWindow, any, XReparentWindowErrorProc, &result); XReparentWindow(display, window, newParent, x, y); Tk_DeleteErrorHandler(handler); XSync(display, False); return result; } #endif /* WIN32 */ #if (TK_MAJOR_VERSION == 4) #include static int initialized = FALSE; static Blt_HashTable windowTable; void Blt_SetWindowInstanceData(tkwin, instanceData) Tk_Window tkwin; ClientData instanceData; { Blt_HashEntry *hPtr; int isNew; if (!initialized) { Blt_InitHashTable(&windowTable, BLT_ONE_WORD_KEYS); initialized = TRUE; } hPtr = Blt_CreateHashEntry(&windowTable, (char *)tkwin, &isNew); assert(isNew); Blt_SetHashValue(hPtr, instanceData); } ClientData Blt_GetWindowInstanceData(tkwin) Tk_Window tkwin; { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&windowTable, (char *)tkwin); if (hPtr == NULL) { return NULL; } return Blt_GetHashValue(hPtr); } void Blt_DeleteWindowInstanceData(tkwin) Tk_Window tkwin; { Blt_HashEntry *hPtr; hPtr = Blt_FindHashEntry(&windowTable, (char *)tkwin); assert(hPtr); Blt_DeleteHashEntry(&windowTable, hPtr); } #else void Blt_SetWindowInstanceData(tkwin, instanceData) Tk_Window tkwin; ClientData instanceData; { TkWindow *winPtr = (TkWindow *)tkwin; winPtr->instanceData = instanceData; } ClientData Blt_GetWindowInstanceData(tkwin) Tk_Window tkwin; { TkWindow *winPtr = (TkWindow *)tkwin; return winPtr->instanceData; } void Blt_DeleteWindowInstanceData(tkwin) Tk_Window tkwin; { } #endif blt-2.4z.orig/src/bltWinop.c0100644000175000017500000007413707525066175014526 0ustar dokodoko/* * bltWinop.c -- * * This module implements simple window commands for the BLT toolkit. * * Copyright 1991-1998 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. */ #include "bltInt.h" #ifndef NO_WINOP #include "bltImage.h" #include #ifndef WIN32 #include #endif static Tcl_CmdProc WinopCmd; static int GetRealizedWindow(interp, string, tkwinPtr) Tcl_Interp *interp; char *string; Tk_Window *tkwinPtr; { Tk_Window tkwin; tkwin = Tk_NameToWindow(interp, string, Tk_MainWindow(interp)); if (tkwin == NULL) { return TCL_ERROR; } if (Tk_WindowId(tkwin) == None) { Tk_MakeWindowExist(tkwin); } *tkwinPtr = tkwin; return TCL_OK; } static Window StringToWindow(interp, string) Tcl_Interp *interp; char *string; { int xid; if (string[0] == '.') { Tk_Window tkwin; if (GetRealizedWindow(interp, string, &tkwin) != TCL_OK) { return None; } if (Tk_IsTopLevel(tkwin)) { return Blt_GetRealWindowId(tkwin); } else { return Tk_WindowId(tkwin); } } else if (Tcl_GetInt(interp, string, &xid) == TCL_OK) { #ifdef WIN32 static TkWinWindow tkWinWindow; tkWinWindow.handle = (HWND)xid; tkWinWindow.winPtr = NULL; tkWinWindow.type = TWD_WINDOW; return (Window)&tkWinWindow; #else return (Window)xid; #endif } return None; } #ifdef WIN32 static int GetWindowSize( Tcl_Interp *interp, Window window, int *widthPtr, int *heightPtr) { int result; RECT region; TkWinWindow *winPtr = (TkWinWindow *)window; result = GetWindowRect(winPtr->handle, ®ion); if (result) { *widthPtr = region.right - region.left; *heightPtr = region.bottom - region.top; return TCL_OK; } return TCL_ERROR; } #else /* *---------------------------------------------------------------------- * * XGeometryErrorProc -- * * Flags errors generated from XGetGeometry calls to the X server. * * Results: * Always returns 0. * * Side Effects: * Sets a flag, indicating an error occurred. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int XGeometryErrorProc(clientData, errEventPtr) ClientData clientData; XErrorEvent *errEventPtr; { int *errorPtr = clientData; *errorPtr = TCL_ERROR; return 0; } static int GetWindowSize(interp, window, widthPtr, heightPtr) Tcl_Interp *interp; Window window; int *widthPtr, *heightPtr; { int result; int any = -1; int x, y, borderWidth, depth; Window root; Tk_ErrorHandler handler; Tk_Window tkwin; tkwin = Tk_MainWindow(interp); handler = Tk_CreateErrorHandler(Tk_Display(tkwin), any, X_GetGeometry, any, XGeometryErrorProc, &result); result = XGetGeometry(Tk_Display(tkwin), window, &root, &x, &y, (unsigned int *)widthPtr, (unsigned int *)heightPtr, (unsigned int *)&borderWidth, (unsigned int *)&depth); Tk_DeleteErrorHandler(handler); XSync(Tk_Display(tkwin), False); if (result) { return TCL_OK; } return TCL_ERROR; } #endif /*WIN32*/ #ifndef WIN32 /*ARGSUSED*/ static int ColormapOp(clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { register int i; Tk_Window tkwin; #define MAXCOLORS 256 register XColor *colorPtr; XColor colorArr[MAXCOLORS]; unsigned long int pixelValues[MAXCOLORS]; int inUse[MAXCOLORS]; char string[20]; unsigned long int *indexPtr; int nFree; if (GetRealizedWindow(interp, argv[2], &tkwin) != TCL_OK) { return TCL_ERROR; } /* Initially, we assume all color cells are allocated. */ memset((char *)inUse, 0, sizeof(int) * MAXCOLORS); /* * Start allocating color cells. This will tell us which color cells * haven't already been allocated in the colormap. We'll release the * cells as soon as we find out how many there are. */ nFree = 0; for (indexPtr = pixelValues, i = 0; i < MAXCOLORS; i++, indexPtr++) { if (!XAllocColorCells(Tk_Display(tkwin), Tk_Colormap(tkwin), False, NULL, 0, indexPtr, 1)) { break; } inUse[*indexPtr] = TRUE;/* Indicate the cell is unallocated */ nFree++; } XFreeColors(Tk_Display(tkwin), Tk_Colormap(tkwin), pixelValues, nFree, 0); for (colorPtr = colorArr, i = 0; i < MAXCOLORS; i++, colorPtr++) { colorPtr->pixel = i; } XQueryColors(Tk_Display(tkwin), Tk_Colormap(tkwin), colorArr, MAXCOLORS); for (colorPtr = colorArr, i = 0; i < MAXCOLORS; i++, colorPtr++) { if (!inUse[colorPtr->pixel]) { sprintf(string, "#%02x%02x%02x", (colorPtr->red >> 8), (colorPtr->green >> 8), (colorPtr->blue >> 8)); Tcl_AppendElement(interp, string); sprintf(string, "%ld", colorPtr->pixel); Tcl_AppendElement(interp, string); } } return TCL_OK; } #endif /*ARGSUSED*/ static int LowerOp(clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { register int i; Window window; Display *display; display = Tk_Display(Tk_MainWindow(interp)); for (i = 2; i < argc; i++) { window = StringToWindow(interp, argv[i]); if (window == None) { return TCL_ERROR; } XLowerWindow(display, window); } return TCL_OK; } /*ARGSUSED*/ static int RaiseOp(clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { register int i; Window window; Display *display; display = Tk_Display(Tk_MainWindow(interp)); for (i = 2; i < argc; i++) { window = StringToWindow(interp, argv[i]); if (window == None) { return TCL_ERROR; } XRaiseWindow(display, window); } return TCL_OK; } /*ARGSUSED*/ static int MapOp(clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { register int i; Window window; Display *display; display = Tk_Display(Tk_MainWindow(interp)); for (i = 2; i < argc; i++) { if (argv[i][0] == '.') { Tk_Window tkwin; Tk_FakeWin *fakePtr; if (GetRealizedWindow(interp, argv[i], &tkwin) != TCL_OK) { return TCL_ERROR; } fakePtr = (Tk_FakeWin *) tkwin; fakePtr->flags |= TK_MAPPED; window = Tk_WindowId(tkwin); } else { int xid; if (Tcl_GetInt(interp, argv[i], &xid) != TCL_OK) { return TCL_ERROR; } window = (Window)xid; } XMapWindow(display, window); } return TCL_OK; } /*ARGSUSED*/ static int MoveOp(clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; int argc; /* Not Used. */ char **argv; { int x, y; Tk_Window tkwin; Window window; Display *display; tkwin = Tk_MainWindow(interp); display = Tk_Display(tkwin); window = StringToWindow(interp, argv[2]); if (window == None) { return TCL_ERROR; } if (Tk_GetPixels(interp, tkwin, argv[3], &x) != TCL_OK) { Tcl_AppendResult(interp, ": bad window x-coordinate", (char *)NULL); return TCL_ERROR; } if (Tk_GetPixels(interp, tkwin, argv[4], &y) != TCL_OK) { Tcl_AppendResult(interp, ": bad window y-coordinate", (char *)NULL); return TCL_ERROR; } XMoveWindow(display, window, x, y); return TCL_OK; } /*ARGSUSED*/ static int UnmapOp(clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { register int i; Window window; Display *display; display = Tk_Display(Tk_MainWindow(interp)); for (i = 2; i < argc; i++) { if (argv[i][0] == '.') { Tk_Window tkwin; Tk_FakeWin *fakePtr; if (GetRealizedWindow(interp, argv[i], &tkwin) != TCL_OK) { return TCL_ERROR; } fakePtr = (Tk_FakeWin *) tkwin; fakePtr->flags &= ~TK_MAPPED; window = Tk_WindowId(tkwin); } else { int xid; if (Tcl_GetInt(interp, argv[i], &xid) != TCL_OK) { return TCL_ERROR; } window = (Window)xid; } XMapWindow(display, window); } return TCL_OK; } /* ARGSUSED */ static int ChangesOp(clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; /* Not used. */ { Tk_Window tkwin; if (GetRealizedWindow(interp, argv[2], &tkwin) != TCL_OK) { return TCL_ERROR; } if (Tk_IsTopLevel(tkwin)) { XSetWindowAttributes attrs; Window window; unsigned int mask; window = Blt_GetRealWindowId(tkwin); attrs.backing_store = WhenMapped; attrs.save_under = True; mask = CWBackingStore | CWSaveUnder; XChangeWindowAttributes(Tk_Display(tkwin), window, mask, &attrs); } return TCL_OK; } /* ARGSUSED */ static int QueryOp(clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; /* Not used. */ { int rootX, rootY, childX, childY; Window root, child; unsigned int mask; Tk_Window tkwin = (Tk_Window)clientData; /* GetCursorPos */ if (XQueryPointer(Tk_Display(tkwin), Tk_WindowId(tkwin), &root, &child, &rootX, &rootY, &childX, &childY, &mask)) { char string[200]; sprintf(string, "@%d,%d", rootX, rootY); Tcl_SetResult(interp, string, TCL_VOLATILE); } return TCL_OK; } /*ARGSUSED*/ static int WarpToOp(clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tk_Window tkwin, mainWindow; mainWindow = (Tk_Window)clientData; if (argc > 2) { if (argv[2][0] == '@') { int x, y; Window root; if (Blt_GetXY(interp, mainWindow, argv[2], &x, &y) != TCL_OK) { return TCL_ERROR; } root = RootWindow(Tk_Display(mainWindow), Tk_ScreenNumber(mainWindow)); XWarpPointer(Tk_Display(mainWindow), None, root, 0, 0, 0, 0, x, y); } else { if (GetRealizedWindow(interp, argv[2], &tkwin) != TCL_OK) { return TCL_ERROR; } if (!Tk_IsMapped(tkwin)) { Tcl_AppendResult(interp, "can't warp to unmapped window \"", Tk_PathName(tkwin), "\"", (char *)NULL); return TCL_ERROR; } XWarpPointer(Tk_Display(tkwin), None, Tk_WindowId(tkwin), 0, 0, 0, 0, Tk_Width(tkwin) / 2, Tk_Height(tkwin) / 2); } } return QueryOp(clientData, interp, 0, (char **)NULL); } #ifdef notdef static int ReparentOp(clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; int argc; char **argv; { Tk_Window tkwin; if (GetRealizedWindow(interp, argv[2], &tkwin) != TCL_OK) { return TCL_ERROR; } if (argc == 4) { Tk_Window newParent; if (GetRealizedWindow(interp, argv[3], &newParent) != TCL_OK) { return TCL_ERROR; } Blt_RelinkWindow2(tkwin, Blt_GetRealWindowId(tkwin), newParent, 0, 0); } else { Blt_UnlinkWindow(tkwin); } return TCL_OK; } #endif /* * This is a temporary home for these image routines. They will be * moved when a new image type is created for them. */ /*ARGSUSED*/ static int ConvolveOp(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tk_PhotoHandle srcPhoto, destPhoto; Blt_ColorImage srcImage, destImage; Filter2D filter; int nValues; char **valueArr; double *kernel; double value, sum; register int i; int dim; int result = TCL_ERROR; srcPhoto = Blt_FindPhoto(interp, argv[2]); if (srcPhoto == NULL) { Tcl_AppendResult(interp, "source image \"", argv[2], "\" doesn't", " exist or is not a photo image", (char *)NULL); return TCL_ERROR; } destPhoto = Blt_FindPhoto(interp, argv[3]); if (destPhoto == NULL) { Tcl_AppendResult(interp, "destination image \"", argv[3], "\" doesn't", " exist or is not a photo image", (char *)NULL); return TCL_ERROR; } if (Tcl_SplitList(interp, argv[4], &nValues, &valueArr) != TCL_OK) { return TCL_ERROR; } kernel = NULL; if (nValues == 0) { Tcl_AppendResult(interp, "empty kernel", (char *)NULL); goto error; } dim = (int)sqrt((double)nValues); if ((dim * dim) != nValues) { Tcl_AppendResult(interp, "kernel must be square", (char *)NULL); goto error; } kernel = Blt_Malloc(sizeof(double) * nValues); sum = 0.0; for (i = 0; i < nValues; i++) { if (Tcl_GetDouble(interp, valueArr[i], &value) != TCL_OK) { goto error; } kernel[i] = value; sum += value; } filter.kernel = kernel; filter.support = dim * 0.5; filter.sum = (sum == 0.0) ? 1.0 : sum; filter.scale = 1.0 / nValues; srcImage = Blt_PhotoToColorImage(srcPhoto); destImage = Blt_ConvolveColorImage(srcImage, &filter); Blt_FreeColorImage(srcImage); Blt_ColorImageToPhoto(destImage, destPhoto); Blt_FreeColorImage(destImage); result = TCL_OK; error: if (valueArr != NULL) { Blt_Free(valueArr); } if (kernel != NULL) { Blt_Free(kernel); } return result; } /*ARGSUSED*/ static int QuantizeOp(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tk_PhotoHandle srcPhoto, destPhoto; Tk_PhotoImageBlock src, dest; Blt_ColorImage srcImage, destImage; int nColors; int result; srcPhoto = Blt_FindPhoto(interp, argv[2]); if (srcPhoto == NULL) { Tcl_AppendResult(interp, "source image \"", argv[2], "\" doesn't", " exist or is not a photo image", (char *)NULL); return TCL_ERROR; } Tk_PhotoGetImage(srcPhoto, &src); if ((src.width <= 1) || (src.height <= 1)) { Tcl_AppendResult(interp, "source image \"", argv[2], "\" is empty", (char *)NULL); return TCL_ERROR; } destPhoto = Blt_FindPhoto(interp, argv[3]); if (destPhoto == NULL) { Tcl_AppendResult(interp, "destination image \"", argv[3], "\" doesn't", " exist or is not a photo image", (char *)NULL); return TCL_ERROR; } Tk_PhotoGetImage(destPhoto, &dest); if ((dest.width != src.width) || (dest.height != src.height)) { Tk_PhotoSetSize(destPhoto, src.width, src.height); } if (Tcl_GetInt(interp, argv[4], &nColors) != TCL_OK) { return TCL_ERROR; } srcImage = Blt_PhotoToColorImage(srcPhoto); destImage = Blt_PhotoToColorImage(destPhoto); result = Blt_QuantizeColorImage(srcImage, destImage, nColors); if (result == TCL_OK) { Blt_ColorImageToPhoto(destImage, destPhoto); } Blt_FreeColorImage(srcImage); Blt_FreeColorImage(destImage); return result; } /*ARGSUSED*/ static int ReadJPEGOp(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { #if HAVE_JPEGLIB_H Tk_PhotoHandle photo; /* The photo image to write into. */ photo = Blt_FindPhoto(interp, argv[3]); if (photo == NULL) { Tcl_AppendResult(interp, "image \"", argv[3], "\" doesn't", " exist or is not a photo image", (char *)NULL); return TCL_ERROR; } return Blt_JPEGToPhoto(interp, argv[2], photo); #else Tcl_AppendResult(interp, "JPEG support not compiled", (char *)NULL); return TCL_ERROR; #endif } /*ARGSUSED*/ static int GradientOp(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tk_PhotoHandle photo; Tk_PhotoImageBlock src; XColor *leftPtr, *rightPtr; Tk_Window tkwin; double range[3]; double left[3]; Pix32 *destPtr; Blt_ColorImage destImage; tkwin = Tk_MainWindow(interp); photo = Blt_FindPhoto(interp, argv[2]); if (photo == NULL) { Tcl_AppendResult(interp, "source image \"", argv[2], "\" doesn't", " exist or is not a photo image", (char *)NULL); return TCL_ERROR; } Tk_PhotoGetImage(photo, &src); leftPtr = Tk_GetColor(interp, tkwin, Tk_GetUid(argv[3])); if (leftPtr == NULL) { return TCL_ERROR; } rightPtr = Tk_GetColor(interp, tkwin, Tk_GetUid(argv[4])); if (leftPtr == NULL) { return TCL_ERROR; } left[0] = (double)(leftPtr->red >> 8); left[1] = (double)(leftPtr->green >> 8); left[2] = (double)(leftPtr->blue >> 8); range[0] = (double)((rightPtr->red - leftPtr->red) / 257.0); range[1] = (double)((rightPtr->green - leftPtr->green) / 257.0); range[2] = (double)((rightPtr->blue - leftPtr->blue) / 257.0); destImage = Blt_CreateColorImage(src.width, src.height); destPtr = Blt_ColorImageBits(destImage); #define CLAMP(c) ((((c) < 0.0) ? 0.0 : ((c) > 1.0) ? 1.0 : (c))) if (strcmp(argv[5], "linear") == 0) { register int x, y; double t; for (y = 0; y < src.height; y++) { for (x = 0; x < src.width; x++) { t = (double)x * (drand48() * 0.10 - 0.05); t = CLAMP(t); destPtr->Red = (unsigned char)(left[0] + t * range[0]); destPtr->Green = (unsigned char)(left[1] + t * range[1]); destPtr->Blue = (unsigned char)(left[2] + t * range[2]); destPtr->Alpha = (unsigned char)-1; destPtr++; } } } else if (strcmp(argv[5], "radial") == 0) { register int x, y; register double dx, dy; double dy2; double t; double midX, midY; midX = midY = 0.5; for (y = 0; y < src.height; y++) { dy = (y / (double)src.height) - midY; dy2 = dy * dy; for (x = 0; x < src.width; x++) { dx = (x / (double)src.width) - midX; t = 1.0 - (double)sqrt(dx * dx + dy2); t += t * (drand48() * 0.10 - 0.05); t = CLAMP(t); destPtr->Red = (unsigned char)(left[0] + t * range[0]); destPtr->Green = (unsigned char)(left[1] + t * range[1]); destPtr->Blue = (unsigned char)(left[2] + t * range[2]); destPtr->Alpha = (unsigned char)-1; destPtr++; } } } else if (strcmp(argv[5], "rectangular") == 0) { register int x, y; register double dx, dy; double t, px, py; double midX, midY; double cosTheta, sinTheta; double angle; angle = M_PI_2 * -0.3; cosTheta = cos(angle); sinTheta = sin(angle); midX = 0.5, midY = 0.5; for (y = 0; y < src.height; y++) { dy = (y / (double)src.height) - midY; for (x = 0; x < src.width; x++) { dx = (x / (double)src.width) - midX; px = dx * cosTheta - dy * sinTheta; py = dx * sinTheta + dy * cosTheta; t = FABS(px) + FABS(py); t += t * (drand48() * 0.10 - 0.05); t = CLAMP(t); destPtr->Red = (unsigned char)(left[0] + t * range[0]); destPtr->Green = (unsigned char)(left[1] + t * range[1]); destPtr->Blue = (unsigned char)(left[2] + t * range[2]); destPtr->Alpha = (unsigned char)-1; destPtr++; } } } else if (strcmp(argv[5], "blank") == 0) { register int x, y; for (y = 0; y < src.height; y++) { for (x = 0; x < src.width; x++) { destPtr->Red = (unsigned char)0xFF; destPtr->Green = (unsigned char)0xFF; destPtr->Blue = (unsigned char)0xFF; destPtr->Alpha = (unsigned char)-1; destPtr++; } } } Blt_ColorImageToPhoto(destImage, photo); return TCL_OK; } /*ARGSUSED*/ static int ResampleOp(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tk_PhotoHandle srcPhoto, destPhoto; Tk_PhotoImageBlock src, dest; ResampleFilter *filterPtr, *vertFilterPtr, *horzFilterPtr; char *filterName; srcPhoto = Blt_FindPhoto(interp, argv[2]); if (srcPhoto == NULL) { Tcl_AppendResult(interp, "source image \"", argv[2], "\" doesn't", " exist or is not a photo image", (char *)NULL); return TCL_ERROR; } destPhoto = Blt_FindPhoto(interp, argv[3]); if (destPhoto == NULL) { Tcl_AppendResult(interp, "destination image \"", argv[3], "\" doesn't", " exist or is not a photo image", (char *)NULL); return TCL_ERROR; } filterName = (argc > 4) ? argv[4] : "none"; if (Blt_GetResampleFilter(interp, filterName, &filterPtr) != TCL_OK) { return TCL_ERROR; } vertFilterPtr = horzFilterPtr = filterPtr; if ((filterPtr != NULL) && (argc > 5)) { if (Blt_GetResampleFilter(interp, argv[5], &filterPtr) != TCL_OK) { return TCL_ERROR; } vertFilterPtr = filterPtr; } Tk_PhotoGetImage(srcPhoto, &src); if ((src.width <= 1) || (src.height <= 1)) { Tcl_AppendResult(interp, "source image \"", argv[2], "\" is empty", (char *)NULL); return TCL_ERROR; } Tk_PhotoGetImage(destPhoto, &dest); if ((dest.width <= 1) || (dest.height <= 1)) { Tk_PhotoSetSize(destPhoto, src.width, src.height); goto copyImage; } if ((src.width == dest.width) && (src.height == dest.height)) { copyImage: /* Source and destination image sizes are the same. Don't * resample. Simply make copy of image */ dest.width = src.width; dest.height = src.height; dest.pixelPtr = src.pixelPtr; dest.pixelSize = src.pixelSize; dest.pitch = src.pitch; dest.offset[0] = src.offset[0]; dest.offset[1] = src.offset[1]; dest.offset[2] = src.offset[2]; Tk_PhotoPutBlock(destPhoto, &dest, 0, 0, dest.width, dest.height); return TCL_OK; } if (filterPtr == NULL) { Blt_ResizePhoto(srcPhoto, 0, 0, src.width, src.height, destPhoto); } else { Blt_ResamplePhoto(srcPhoto, 0, 0, src.width, src.height, destPhoto, horzFilterPtr, vertFilterPtr); } return TCL_OK; } /*ARGSUSED*/ static int RotateOp(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tk_PhotoHandle srcPhoto, destPhoto; Blt_ColorImage srcImage, destImage; double theta; srcPhoto = Blt_FindPhoto(interp, argv[2]); if (srcPhoto == NULL) { Tcl_AppendResult(interp, "image \"", argv[2], "\" doesn't", " exist or is not a photo image", (char *)NULL); return TCL_ERROR; } destPhoto = Blt_FindPhoto(interp, argv[3]); if (destPhoto == NULL) { Tcl_AppendResult(interp, "destination image \"", argv[3], "\" doesn't", " exist or is not a photo image", (char *)NULL); return TCL_ERROR; } if (Tcl_ExprDouble(interp, argv[4], &theta) != TCL_OK) { return TCL_ERROR; } srcImage = Blt_PhotoToColorImage(srcPhoto); destImage = Blt_RotateColorImage(srcImage, theta); Blt_ColorImageToPhoto(destImage, destPhoto); Blt_FreeColorImage(srcImage); Blt_FreeColorImage(destImage); return TCL_OK; } /* * -------------------------------------------------------------------------- * * SnapOp -- * * Snaps a picture of a window and stores it in a designated * photo image. The window must be completely visible or * the snap will fail. * * Results: * Returns a standard Tcl result. interp->result contains * the list of the graph coordinates. If an error occurred * while parsing the window positions, TCL_ERROR is returned, * then interp->result will contain an error message. * * ------------------------------------------------------------------------- */ /*ARGSUSED*/ static int SnapOp(clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tk_Window tkwin; int width, height, destWidth, destHeight; Window window; tkwin = Tk_MainWindow(interp); window = StringToWindow(interp, argv[2]); if (window == None) { return TCL_ERROR; } if (GetWindowSize(interp, window, &width, &height) != TCL_OK) { Tcl_AppendResult(interp, "can't get window geometry of \"", argv[2], "\"", (char *)NULL); return TCL_ERROR; } destWidth = width, destHeight = height; if ((argc > 4) && (Blt_GetPixels(interp, tkwin, argv[4], PIXELS_POSITIVE, &destWidth) != TCL_OK)) { return TCL_ERROR; } if ((argc > 5) && (Blt_GetPixels(interp, tkwin, argv[5], PIXELS_POSITIVE, &destHeight) != TCL_OK)) { return TCL_ERROR; } return Blt_SnapPhoto(interp, tkwin, window, 0, 0, width, height, destWidth, destHeight, argv[3], GAMMA); } /*ARGSUSED*/ static int SubsampleOp(clientData, interp, argc, argv) ClientData clientData; /* Main window of the interpreter. */ Tcl_Interp *interp; int argc; /* Not used. */ char **argv; { Tk_Window tkwin; Tk_PhotoHandle srcPhoto, destPhoto; Tk_PhotoImageBlock src, dest; ResampleFilter *filterPtr, *vertFilterPtr, *horzFilterPtr; char *filterName; int flag; int x, y; int width, height; srcPhoto = Blt_FindPhoto(interp, argv[2]); if (srcPhoto == NULL) { Tcl_AppendResult(interp, "source image \"", argv[2], "\" doesn't", " exist or is not a photo image", (char *)NULL); return TCL_ERROR; } destPhoto = Blt_FindPhoto(interp, argv[3]); if (destPhoto == NULL) { Tcl_AppendResult(interp, "destination image \"", argv[3], "\" doesn't", " exist or is not a photo image", (char *)NULL); return TCL_ERROR; } tkwin = (Tk_Window)clientData; flag = PIXELS_NONNEGATIVE; if (Blt_GetPixels(interp, tkwin, argv[4], flag, &x) != TCL_OK) { return TCL_ERROR; } if (Blt_GetPixels(interp, tkwin, argv[5], flag, &y) != TCL_OK) { return TCL_ERROR; } flag = PIXELS_POSITIVE; if (Blt_GetPixels(interp, tkwin, argv[6], flag, &width) != TCL_OK) { return TCL_ERROR; } if (Blt_GetPixels(interp, tkwin, argv[7], flag, &height) != TCL_OK) { return TCL_ERROR; } filterName = (argc > 8) ? argv[8] : "box"; if (Blt_GetResampleFilter(interp, filterName, &filterPtr) != TCL_OK) { return TCL_ERROR; } vertFilterPtr = horzFilterPtr = filterPtr; if ((filterPtr != NULL) && (argc > 9)) { if (Blt_GetResampleFilter(interp, argv[9], &filterPtr) != TCL_OK) { return TCL_ERROR; } vertFilterPtr = filterPtr; } Tk_PhotoGetImage(srcPhoto, &src); Tk_PhotoGetImage(destPhoto, &dest); if ((src.width <= 1) || (src.height <= 1)) { Tcl_AppendResult(interp, "source image \"", argv[2], "\" is empty", (char *)NULL); return TCL_ERROR; } if (((x + width) > src.width) || ((y + height) > src.height)) { Tcl_AppendResult(interp, "nonsensical dimensions for subregion: x=", argv[4], " y=", argv[5], " width=", argv[6], " height=", argv[7], (char *)NULL); return TCL_ERROR; } if ((dest.width <= 1) || (dest.height <= 1)) { Tk_PhotoSetSize(destPhoto, width, height); } if (filterPtr == NULL) { Blt_ResizePhoto(srcPhoto, x, y, width, height, destPhoto); } else { Blt_ResamplePhoto(srcPhoto, x, y, width, height, destPhoto, horzFilterPtr, vertFilterPtr); } return TCL_OK; } static Blt_OpSpec imageOps[] = { {"convolve", 1, (Blt_Op)ConvolveOp, 6, 6, "srcPhoto destPhoto filter",}, {"gradient", 1, (Blt_Op)GradientOp, 7, 7, "photo left right type",}, {"readjpeg", 3, (Blt_Op)ReadJPEGOp, 5, 5, "fileName photoName",}, {"resample", 3, (Blt_Op)ResampleOp, 5, 7, "srcPhoto destPhoto ?horzFilter vertFilter?",}, {"rotate", 2, (Blt_Op)RotateOp, 6, 6, "srcPhoto destPhoto angle",}, {"snap", 2, (Blt_Op)SnapOp, 5, 7, "window photoName ?width height?",}, {"subsample", 2, (Blt_Op)SubsampleOp, 9, 11, "srcPhoto destPhoto x y width height ?horzFilter? ?vertFilter?",}, }; static int nImageOps = sizeof(imageOps) / sizeof(Blt_OpSpec); /* ARGSUSED */ static int ImageOp(clientData, interp, argc, argv) ClientData clientData; /* Main window of interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { Blt_Op proc; int result; proc = Blt_GetOp(interp, nImageOps, imageOps, BLT_OP_ARG2, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } clientData = (ClientData)Tk_MainWindow(interp); result = (*proc) (clientData, interp, argc - 1, argv + 1); return result; } static Blt_OpSpec winOps[] = { {"changes", 3, (Blt_Op)ChangesOp, 3, 3, "window",}, #ifndef WIN32 {"colormap", 3, (Blt_Op)ColormapOp, 3, 3, "window",}, #endif {"convolve", 3, (Blt_Op)ConvolveOp, 5, 5, "srcPhoto destPhoto filter",}, {"image", 1, (Blt_Op)ImageOp, 2, 0, "args",}, {"lower", 1, (Blt_Op)LowerOp, 2, 0, "window ?window?...",}, {"map", 2, (Blt_Op)MapOp, 2, 0, "window ?window?...",}, {"move", 2, (Blt_Op)MoveOp, 5, 5, "window x y",}, {"quantize", 3, (Blt_Op)QuantizeOp, 4, 5, "srcPhoto destPhoto ?nColors?",}, {"query", 3, (Blt_Op)QueryOp, 2, 2, "",}, {"raise", 2, (Blt_Op)RaiseOp, 2, 0, "window ?window?...",}, {"readjpeg", 3, (Blt_Op)ReadJPEGOp, 4, 4, "fileName photoName",}, #ifdef notdef {"reparent", 3, (Blt_Op)ReparentOp, 3, 4, "window ?parent?",}, #endif {"resample", 3, (Blt_Op)ResampleOp, 4, 6, "srcPhoto destPhoto ?horzFilter vertFilter?",}, {"snap", 2, (Blt_Op)SnapOp, 4, 6, "window photoName ?width height?",}, {"subsample", 2, (Blt_Op)SubsampleOp, 8, 10, "srcPhoto destPhoto x y width height ?horzFilter? ?vertFilter?",}, {"unmap", 1, (Blt_Op)UnmapOp, 2, 0, "window ?window?...",}, {"warpto", 1, (Blt_Op)WarpToOp, 2, 5, "?window?",}, }; static int nWinOps = sizeof(winOps) / sizeof(Blt_OpSpec); /* ARGSUSED */ static int WinopCmd(clientData, interp, argc, argv) ClientData clientData; /* Main window of interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { Blt_Op proc; int result; proc = Blt_GetOp(interp, nWinOps, winOps, BLT_OP_ARG1, argc, argv, 0); if (proc == NULL) { return TCL_ERROR; } clientData = (ClientData)Tk_MainWindow(interp); result = (*proc) (clientData, interp, argc, argv); return result; } int Blt_WinopInit(interp) Tcl_Interp *interp; { static Blt_CmdSpec cmdSpec = {"winop", WinopCmd,}; if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) { return TCL_ERROR; } return TCL_OK; } #endif /* NO_WINOP */ blt-2.4z.orig/src/missing.h0100644000175000017500000001066607433613270014373 0ustar dokodoko#ifndef _MISSING_H #define _MISSING_H #include #ifndef DeleteBitmap #define DeleteBitmap(hbm) DeleteObject((HGDIOBJ)(HBITMAP)(hbm)) #endif #ifndef DeleteBrush #define DeleteBrush(hbr) DeleteObject((HGDIOBJ)(HBRUSH)(hbr)) #endif #ifndef DeleteFont #define DeleteFont(hfont) DeleteObject((HGDIOBJ)(HFONT)(hfont)) #endif #ifndef DeletePalette #define DeletePalette(hpal) DeleteObject((HGDIOBJ)(HPALETTE)(hpal)) #endif #ifndef DeletePen #define DeletePen(hpen) DeleteObject((HGDIOBJ)(HPEN)(hpen)) #endif #ifndef SelectBitmap #define SelectBitmap(hdc, hbm) ((HBITMAP)SelectObject((hdc), (HGDIOBJ)(HBITMAP)(hbm))) #endif #ifndef SelectBrush #define SelectBrush(hdc, hbr) ((HBRUSH)SelectObject((hdc), (HGDIOBJ)(HBRUSH)(hbr))) #endif #ifndef SelectFont #define SelectFont(hdc, hfont) ((HFONT)SelectObject((hdc), (HGDIOBJ)(HFONT)(hfont))) #endif #ifndef SelectPen #define SelectPen(hdc, hpen) ((HPEN)SelectObject((hdc), (HGDIOBJ)(HPEN)(hpen))) #endif #ifndef GetNextWindow #define GetNextWindow(hWnd,wCmd) GetWindow((hWnd),(wCmd)) #endif #ifndef GetStockBrush #define GetStockBrush(i) ((HBRUSH)GetStockObject(i)) #endif #ifndef GetStockPen #define GetStockPen(i) ((HPEN)GetStockObject(i)) #endif #define DM_SPECVERSION 0x0401 #define DMPAPER_ISO_B4 42 /* B4 (ISO) 250 x 353 mm */ #define DMPAPER_JAPANESE_POSTCARD 43 /* Japanese Postcard 100 x 148 mm */ #define DMPAPER_9X11 44 /* 9 x 11 in */ #define DMPAPER_10X11 45 /* 10 x 11 in */ #define DMPAPER_15X11 46 /* 15 x 11 in */ #define DMPAPER_ENV_INVITE 47 /* Envelope Invite 220 x 220 mm */ #define DMPAPER_RESERVED_48 48 /* RESERVED--DO NOT USE */ #define DMPAPER_RESERVED_49 49 /* RESERVED--DO NOT USE */ #define DMPAPER_LETTER_EXTRA 50 /* Letter Extra 9 \275 x 12 in */ #define DMPAPER_LEGAL_EXTRA 51 /* Legal Extra 9 \275 x 15 in */ #define DMPAPER_TABLOID_EXTRA 52 /* Tabloid Extra 11.69 x 18 in */ #define DMPAPER_A4_EXTRA 53 /* A4 Extra 9.27 x 12.69 in */ #define DMPAPER_LETTER_TRANSVERSE 54 /* Letter Transverse 8 \275 x 11 in */ #define DMPAPER_A4_TRANSVERSE 55 /* A4 Transverse 210 x 297 mm */ #define DMPAPER_LETTER_EXTRA_TRANSVERSE 56 /* Letter Extra Transverse 9\275 x 12 in */ #define DMPAPER_A_PLUS 57 /* SuperA/SuperA/A4 227 x 356 mm */ #define DMPAPER_B_PLUS 58 /* SuperB/SuperB/A3 305 x 487 mm */ #define DMPAPER_LETTER_PLUS 59 /* Letter Plus 8.5 x 12.69 in */ #define DMPAPER_A4_PLUS 60 /* A4 Plus 210 x 330 mm */ #define DMPAPER_A5_TRANSVERSE 61 /* A5 Transverse 148 x 210 mm */ #define DMPAPER_B5_TRANSVERSE 62 /* B5 (JIS) Transverse 182 x 257 mm */ #define DMPAPER_A3_EXTRA 63 /* A3 Extra 322 x 445 mm */ #define DMPAPER_A5_EXTRA 64 /* A5 Extra 174 x 235 mm */ #define DMPAPER_B5_EXTRA 65 /* B5 (ISO) Extra 201 x 276 mm */ #define DMPAPER_A2 66 /* A2 420 x 594 mm */ #define DMPAPER_A3_TRANSVERSE 67 /* A3 Transverse 297 x 420 mm */ #define DMPAPER_A3_EXTRA_TRANSVERSE 68 /* A3 Extra Transverse 322 x 445 mm */ #ifndef DMPAPER_LAST #define DMPAPER_LAST DMPAPER_A3_EXTRA_TRANSVERSE #endif /*DMPAPER_LAST */ #define DMPAPER_USER 256 /* bin selections */ #ifndef DMPAPER_FIRST #define DMBIN_FIRST DMBIN_UPPER #endif /*DMPAPER_FIRST*/ #define DMBIN_UPPER 1 #define DMBIN_ONLYONE 1 #define DMBIN_LOWER 2 #define DMBIN_MIDDLE 3 #define DMBIN_MANUAL 4 #define DMBIN_ENVELOPE 5 #define DMBIN_ENVMANUAL 6 #define DMBIN_AUTO 7 #define DMBIN_TRACTOR 8 #define DMBIN_SMALLFMT 9 #define DMBIN_LARGEFMT 10 #define DMBIN_LARGECAPACITY 11 #define DMBIN_CASSETTE 14 #define DMBIN_FORMSOURCE 15 #ifndef DMBIN_LAST #define DMBIN_LAST DMBIN_FORMSOURCE #endif /*DMBIN_LAST*/ #define DMBIN_USER 256 /* device specific bins start here */ /* print qualities */ #define DMRES_DRAFT (-1) #define DMRES_LOW (-2) #define DMRES_MEDIUM (-3) #define DMRES_HIGH (-4) #define DMTT_DOWNLOAD_OUTLINE 4 /* download TT fonts as outline soft fonts */ #endif /* _MISSING_H */ blt-2.4z.orig/src/pure_api.c0100644000175000017500000001542707240160120014504 0ustar dokodoko/* * Header file of Pure API function declarations. * * Explicitly no copyright. * You may recompile and redistribute these definitions as required. * * NOTE1: In some situations when compiling with MFC, you should * enable the setting 'Not using precompiled headers' in Visual C++ * to avoid a compiler diagnostic. * * NOTE2: This file works through the use of deep magic. Calls to functions * in this file are replaced with calls into the OCI runtime system * when an instrumented version of this program is run. * * NOTE3: The static vars avoidGy_n (where n is a unique number) are used * to prevent optimizing the functions away when compiler option * /Gy is set. This is needed so that NOTE2 works properly. */ static int avoidGy_1; static int avoidGy_2; static int avoidGy_3; static int avoidGy_4; static int avoidGy_5; static int avoidGy_6; static int avoidGy_7; static int avoidGy_8; static int avoidGy_9; static int avoidGy_10; static int avoidGy_11; static int avoidGy_12; static int avoidGy_13; static int avoidGy_14; static int avoidGy_15; static int avoidGy_16; static int avoidGy_17; static int avoidGy_18; static int avoidGy_19; static int avoidGy_20; static int avoidGy_21; static int avoidGy_22; static int avoidGy_23; static int avoidGy_24; static int avoidGy_25; static int avoidGy_26; static int avoidGy_27; static int avoidGy_28; static int avoidGy_29; static int avoidGy_30; static int avoidGy_31; static int avoidGy_32; static int avoidGy_33; static int avoidGy_34; static int avoidGy_35; static int avoidGy_36; static int avoidGy_37; static int avoidGy_38; static int avoidGy_39; static int avoidGy_40; static int avoidGy_41; static int avoidGy_42; static int avoidGy_43; static int avoidGy_44; static int avoidGy_45; static int avoidGy_46; static int avoidGy_47; static int avoidGy_48; static int avoidGy_49; static int avoidGy_50; static int avoidGy_51; static int avoidGy_52; static int avoidGy_53; static int avoidGy_54; static int avoidGy_55; static int avoidGy_56; static int avoidGy_57; static int avoidGy_58; static int avoidGy_59; static int avoidGy_60; static int avoidGy_PL_01; __declspec(dllexport) int __cdecl PurePrintf(const char *fmt, ...) { avoidGy_1++; fmt; return 0; } __declspec(dllexport) int __cdecl PurifyIsRunning(void) { avoidGy_2++; return 0; } __declspec(dllexport) int __cdecl PurifyPrintf(const char *fmt, ...) { avoidGy_3++; fmt; return 0; } __declspec(dllexport) int __cdecl PurifyNewInuse(void) { avoidGy_4++; return 0; } __declspec(dllexport) int __cdecl PurifyAllInuse(void) { avoidGy_5++; return 0; } __declspec(dllexport) int __cdecl PurifyClearInuse(void) { avoidGy_6++; return 0; } __declspec(dllexport) int __cdecl PurifyNewLeaks(void) { avoidGy_7++; return 0; } __declspec(dllexport) int __cdecl PurifyAllLeaks(void) { avoidGy_8++; return 0; } __declspec(dllexport) int __cdecl PurifyClearLeaks(void) { avoidGy_9++; return 0; } __declspec(dllexport) int __cdecl PurifyAllHandlesInuse(void) { avoidGy_10++; return 0; } __declspec(dllexport) int __cdecl PurifyNewHandlesInuse(void) { avoidGy_11++; return 0; } __declspec(dllexport) int __cdecl PurifyDescribe(void *addr) { avoidGy_12++; addr; return 0; } __declspec(dllexport) int __cdecl PurifyWhatColors(void *addr, int size) { avoidGy_13++; addr; size; return 0; } __declspec(dllexport) int __cdecl PurifyAssertIsReadable(const void *addr, int size) { avoidGy_14++; addr; size; return 1; } __declspec(dllexport) int __cdecl PurifyAssertIsWritable(const void *addr, int size) { avoidGy_15++; addr; size; return 1; } __declspec(dllexport) int __cdecl PurifyIsReadable(const void *addr, int size) { avoidGy_16++; addr; size; return 1; } __declspec(dllexport) int __cdecl PurifyIsWritable(const void *addr, int size) { avoidGy_17++; addr; size; return 1; } __declspec(dllexport) int __cdecl PurifyIsInitialized(const void *addr, int size) { avoidGy_18++; addr; size; return 1; } __declspec(dllexport) int __cdecl PurifyRed(void *addr, int size) { avoidGy_19++; addr; size; return 0; } __declspec(dllexport) int __cdecl PurifyGreen(void *addr, int size) { avoidGy_20++; addr; size; return 0; } __declspec(dllexport) int __cdecl PurifyYellow(void *addr, int size) { avoidGy_21++; addr; size; return 0; } __declspec(dllexport) int __cdecl PurifyBlue(void *addr, int size) { avoidGy_22++; addr; size; return 0; } __declspec(dllexport) int __cdecl PurifyMarkAsInitialized(void *addr, int size) { avoidGy_23++; addr; size; return 0; } __declspec(dllexport) int __cdecl PurifyMarkAsUninitialized(void *addr, int size) { avoidGy_24++; addr; size; return 0; } __declspec(dllexport) int __cdecl PurifyMarkForTrap(void *addr, int size) { avoidGy_25++; addr; size; return 0; } __declspec(dllexport) int __cdecl PurifyMarkForNoTrap(void *addr, int size) { avoidGy_26++; addr; size; return 0; } __declspec(dllexport) int __cdecl PurifyHeapValidate(unsigned int hHeap, unsigned int dwFlags, const void *addr) { avoidGy_27++; hHeap; dwFlags; addr; return 1; } __declspec(dllexport) int __cdecl PurifySetLateDetectScanCounter(int counter) { avoidGy_28++; counter; return 0; }; __declspec(dllexport) int __cdecl PurifySetLateDetectScanInterval(int seconds) { avoidGy_29++; seconds; return 0; }; __declspec(dllexport) int __cdecl CoverageIsRunning(void) { avoidGy_30++; return 0; } __declspec(dllexport) int __cdecl CoverageDisableRecordingData(void) { avoidGy_31++; return 0; } __declspec(dllexport) int __cdecl CoverageStartRecordingData(void) { avoidGy_32++; return 0; } __declspec(dllexport) int __cdecl CoverageStopRecordingData(void) { avoidGy_33++; return 0; } __declspec(dllexport) int __cdecl CoverageClearData(void) { avoidGy_34++; return 0; } __declspec(dllexport) int __cdecl CoverageIsRecordingData(void) { avoidGy_35++; return 0; } __declspec(dllexport) int __cdecl CoverageAddAnnotation(char *str) { avoidGy_36++; str; return 0; } __declspec(dllexport) int __cdecl CoverageSaveData(void) { avoidGy_37++; return 0; } __declspec(dllexport) int __cdecl QuantifyIsRunning(void) { avoidGy_42++; return 0; } __declspec(dllexport) int __cdecl QuantifyDisableRecordingData(void) { avoidGy_43++; return 0; } __declspec(dllexport) int __cdecl QuantifyStartRecordingData(void) { avoidGy_44++; return 0; } __declspec(dllexport) int __cdecl QuantifyStopRecordingData(void) { avoidGy_45++; return 0; } __declspec(dllexport) int __cdecl QuantifyClearData(void) { avoidGy_46++; return 0; } __declspec(dllexport) int __cdecl QuantifyIsRecordingData(void) { avoidGy_47++; return 0; } __declspec(dllexport) int __cdecl QuantifyAddAnnotation(char *str) { avoidGy_48++; str; return 0; } __declspec(dllexport) int __cdecl QuantifySaveData(void) { avoidGy_49++; return 0; } __declspec(dllexport) int __cdecl PurelockIsRunning(void) { avoidGy_PL_01++; return 0; } blt-2.4z.orig/src/tkButton.c0100644000175000017500000021104507543540145014523 0ustar dokodoko/* * tkButton.c -- * * This module implements a collection of button-like * widgets for the Tk toolkit. The widgets implemented * include labels, buttons, check buttons, and radio * buttons. * * Copyright (c) 1990-1994 The Regents of the University of California. * Copyright (c) 1994-1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * SCCS: @(#) tkButton.c 1.128 96/03/01 17:34:49 */ #include "bltInt.h" #ifndef NO_TILEBUTTON #include "bltTile.h" extern Tk_CustomOption bltTileOption; /* * The definitions below provide symbolic names for the default colors. * NORMAL_BG - Normal background color. * ACTIVE_BG - Background color when widget is active. * SELECT_BG - Background color for selected text. * TROUGH - Background color for troughs in scales and scrollbars. * INDICATOR - Color for indicator when button is selected. * DISABLED - Foreground color when widget is disabled. */ #define NORMAL_BG "#d9d9d9" #define ACTIVE_BG "#ececec" #define SELECT_BG "#c3c3c3" #define TROUGH "#c3c3c3" #define INDICATOR "#b03060" #define DISABLED "#a3a3a3" static Tk_Uid tkNormalUid, tkActiveUid, tkDisabledUid; #define DEF_BUTTON_ANCHOR "center" #define DEF_BUTTON_ACTIVE_BACKGROUND STD_ACTIVE_BACKGROUND #define DEF_BUTTON_ACTIVE_BG_MONO RGB_BLACK #define DEF_BUTTON_ACTIVE_FOREGROUND RGB_BLACK #define DEF_BUTTON_ACTIVE_FG_MONO RGB_WHITE #define DEF_BUTTON_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_BUTTON_BG_MONO RGB_WHITE #define DEF_BUTTON_BITMAP "" #define DEF_BUTTON_BORDERWIDTH "2" #define DEF_BUTTON_CURSOR "" #define DEF_BUTTON_COMMAND "" #define DEF_BUTTON_COMPOUND "none" #define DEF_BUTTON_DEFAULT "disabled" #define DEF_BUTTON_DISABLED_FOREGROUND STD_DISABLE_FOREGROUND #define DEF_BUTTON_DISABLED_FG_MONO "" #define DEF_BUTTON_FG RGB_BLACK #define DEF_BUTTON_FONT "-Adobe-Helvetica-Bold-R-Normal--*-120-*-*-*-*-*-*" #define DEF_BUTTON_HEIGHT "0" #define DEF_BUTTON_HIGHLIGHT_BG STD_NORMAL_BACKGROUND #define DEF_BUTTON_HIGHLIGHT RGB_BLACK #define DEF_LABEL_HIGHLIGHT_WIDTH "0" #define DEF_BUTTON_HIGHLIGHT_WIDTH "2" #define DEF_BUTTON_IMAGE (char *) NULL #define DEF_BUTTON_INDICATOR "1" #define DEF_BUTTON_JUSTIFY "center" #define DEF_BUTTON_OFF_VALUE "0" #define DEF_BUTTON_ON_VALUE "1" #define DEF_BUTTON_OVER_RELIEF "raised" #define DEF_BUTTON_PADX "3m" #define DEF_LABCHKRAD_PADX "1" #define DEF_BUTTON_PADY "1m" #define DEF_LABCHKRAD_PADY "1" #define DEF_BUTTON_RELIEF "raised" #define DEF_BUTTON_REPEAT_DELAY "0" #define DEF_LABCHKRAD_RELIEF "flat" #define DEF_BUTTON_SELECT_COLOR STD_INDICATOR_COLOR #define DEF_BUTTON_SELECT_MONO RGB_BLACK #define DEF_BUTTON_SELECT_IMAGE (char *) NULL #define DEF_BUTTON_STATE "normal" #define DEF_LABEL_TAKE_FOCUS "0" #define DEF_BUTTON_TAKE_FOCUS (char *) NULL #define DEF_BUTTON_TEXT "" #define DEF_BUTTON_TEXT_VARIABLE "" #define DEF_BUTTON_UNDERLINE "-1" #define DEF_BUTTON_VALUE "" #define DEF_BUTTON_WIDTH "0" #define DEF_BUTTON_WRAP_LENGTH "0" #define DEF_RADIOBUTTON_VARIABLE "selectedButton" #define DEF_CHECKBUTTON_VARIABLE "" /* * A data structure of the following type is kept for each * widget managed by this file: */ typedef struct { Tk_Window tkwin; /* Window that embodies the button. NULL * means that the window has been destroyed. */ Display *display; /* Display containing widget. Needed to * free up resources after tkwin is gone. */ Tcl_Interp *interp; /* Interpreter associated with button. */ Tcl_Command widgetCmd; /* Token for button's widget command. */ int type; /* Type of widget: restricts operations * that may be performed on widget. See * below for possible values. */ /* * Information about what's in the button. */ char *text; /* Text to display in button (malloc'ed) * or NULL. */ int numChars; /* # of characters in text. */ int underline; /* Index of character to underline. < 0 means * don't underline anything. */ char *textVarName; /* Name of variable (malloc'ed) or NULL. * If non-NULL, button displays the contents * of this variable. */ Pixmap bitmap; /* Bitmap to display or None. If not None * then text and textVar are ignored. */ char *imageString; /* Name of image to display (malloc'ed), or * NULL. If non-NULL, bitmap, text, and * textVarName are ignored. */ Tk_Image image; /* Image to display in window, or NULL if * none. */ char *selectImageString; /* Name of image to display when selected * (malloc'ed), or NULL. */ Tk_Image selectImage; /* Image to display in window when selected, * or NULL if none. Ignored if image is * NULL. */ /* * Information used when displaying widget: */ Tk_Uid state; /* State of button for display purposes: * normal, active, or disabled. */ Tk_3DBorder normalBorder; /* Structure used to draw 3-D * border and background when window * isn't active. NULL means no such * border exists. */ Tk_3DBorder activeBorder; /* Structure used to draw 3-D * border and background when window * is active. NULL means no such * border exists. */ int borderWidth; /* Width of border. */ int relief; /* 3-d effect: TK_RELIEF_RAISED, etc. */ int overRelief; /* Value of -overrelief option: specifies a 3-d * effect for the border, such as * TK_RELIEF_RAISED, to be used when the mouse * is over the button. */ int highlightWidth; /* Width in pixels of highlight to draw * around widget when it has the focus. * <= 0 means don't draw a highlight. */ XColor *highlightBgColorPtr; /* Color for drawing traversal highlight * area when highlight is off. */ XColor *highlightColorPtr; /* Color for drawing traversal highlight. */ int inset; /* Total width of all borders, including * traversal highlight and 3-D border. * Indicates how much interior stuff must * be offset from outside edges to leave * room for borders. */ Tk_Font font; /* Information about text font, or NULL. */ XColor *normalFg; /* Foreground color in normal mode. */ XColor *activeFg; /* Foreground color in active mode. NULL * means use normalFg instead. */ XColor *disabledFg; /* Foreground color when disabled. NULL * means use normalFg with a 50% stipple * instead. */ GC normalTextGC; /* GC for drawing text in normal mode. Also * used to copy from off-screen pixmap onto * screen. */ GC activeTextGC; /* GC for drawing text in active mode (NULL * means use normalTextGC). */ Pixmap gray; /* Pixmap for displaying disabled text if * disabledFg is NULL. */ GC disabledGC; /* Used to produce disabled effect. If * disabledFg isn't NULL, this GC is used to * draw button text or icon. Otherwise * text or icon is drawn with normalGC and * this GC is used to stipple background * across it. For labels this is None. */ GC copyGC; /* Used for copying information from an * off-screen pixmap to the screen. */ char *widthString; /* Value of -width option. Malloc'ed. */ char *heightString; /* Value of -height option. Malloc'ed. */ int width, height; /* If > 0, these specify dimensions to request * for window, in characters for text and in * pixels for bitmaps. In this case the actual * size of the text string or bitmap is * ignored in computing desired window size. */ int wrapLength; /* Line length (in pixels) at which to wrap * onto next line. <= 0 means don't wrap * except at newlines. */ int padX, padY; /* Extra space around text (pixels to leave * on each side). Ignored for bitmaps and * images. */ Tk_Anchor anchor; /* Where text/bitmap should be displayed * inside button region. */ Tk_Justify justify; /* Justification to use for multi-line text. */ int indicatorOn; /* True means draw indicator, false means * don't draw it. */ Tk_3DBorder selectBorder; /* For drawing indicator background, or perhaps * widget background, when selected. */ int textWidth; /* Width needed to display text as requested, * in pixels. */ int textHeight; /* Height needed to display text as requested, * in pixels. */ #if (TK_MAJOR_VERSION > 4) Tk_TextLayout textLayout; /* Saved text layout information. */ #endif int indicatorSpace; /* Horizontal space (in pixels) allocated for * display of indicator. */ int indicatorDiameter; /* Diameter of indicator, in pixels. */ Tk_Uid defaultState; /* Used in 8.0 (not here) */ /* * For check and radio buttons, the fields below are used * to manage the variable indicating the button's state. */ char *selVarName; /* Name of variable used to control selected * state of button. Malloc'ed (if * not NULL). */ char *onValue; /* Value to store in variable when * this button is selected. Malloc'ed (if * not NULL). */ char *offValue; /* Value to store in variable when this * button isn't selected. Malloc'ed * (if not NULL). Valid only for check * buttons. */ /* * Miscellaneous information: */ Tk_Cursor cursor; /* Current cursor for window, or None. */ char *takeFocus; /* Value of -takefocus option; not used in * the C code, but used by keyboard traversal * scripts. Malloc'ed, but may be NULL. */ char *command; /* Command to execute when button is * invoked; valid for buttons only. * If not NULL, it's malloc-ed. */ char *compound; /* Value of -compound option; specifies whether * the button should show both an image and * text, and, if so, how. */ int repeatDelay; /* Value of -repeatdelay option; specifies * the number of ms after which the button will * start to auto-repeat its command. */ int repeatInterval; /* Value of -repeatinterval option; specifies * the number of ms between auto-repeat * invocataions of the button command. */ int flags; /* Various flags; see below for * definitions. */ Blt_Tile tile, activeTile; } Button; /* * Possible "type" values for buttons. These are the kinds of * widgets supported by this file. The ordering of the type * numbers is significant: greater means more features and is * used in the code. */ #define TYPE_LABEL 0 #define TYPE_BUTTON 1 #define TYPE_CHECK_BUTTON 2 #define TYPE_RADIO_BUTTON 3 /* * Class names for buttons, indexed by one of the type values above. */ static char *classNames[] = {"Label", "Button", "Checkbutton", "Radiobutton"}; /* * Flag bits for buttons: * * REDRAW_PENDING: Non-zero means a DoWhenIdle handler * has already been queued to redraw * this window. * SELECTED: Non-zero means this button is selected, * so special highlight should be drawn. * GOT_FOCUS: Non-zero means this button currently * has the input focus. */ #define REDRAW_PENDING 1 #define SELECTED 2 #define GOT_FOCUS 4 /* * Mask values used to selectively enable entries in the * configuration specs: */ #define LABEL_MASK TK_CONFIG_USER_BIT #define BUTTON_MASK TK_CONFIG_USER_BIT << 1 #define CHECK_BUTTON_MASK TK_CONFIG_USER_BIT << 2 #define RADIO_BUTTON_MASK TK_CONFIG_USER_BIT << 3 #define ALL_MASK (LABEL_MASK | BUTTON_MASK \ | CHECK_BUTTON_MASK | RADIO_BUTTON_MASK) static int configFlags[] = {LABEL_MASK, BUTTON_MASK, CHECK_BUTTON_MASK, RADIO_BUTTON_MASK}; /* * Information used for parsing configuration specs: */ static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", DEF_BUTTON_ACTIVE_BACKGROUND, Tk_Offset(Button, activeBorder), BUTTON_MASK | CHECK_BUTTON_MASK | RADIO_BUTTON_MASK | TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", DEF_BUTTON_ACTIVE_BG_MONO, Tk_Offset(Button, activeBorder), BUTTON_MASK | CHECK_BUTTON_MASK | RADIO_BUTTON_MASK | TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background", DEF_BUTTON_ACTIVE_FOREGROUND, Tk_Offset(Button, activeFg), BUTTON_MASK | CHECK_BUTTON_MASK | RADIO_BUTTON_MASK | TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background", DEF_BUTTON_ACTIVE_FG_MONO, Tk_Offset(Button, activeFg), BUTTON_MASK | CHECK_BUTTON_MASK | RADIO_BUTTON_MASK | TK_CONFIG_MONO_ONLY}, {TK_CONFIG_CUSTOM, "-activetile", "activeTile", "Tile", (char *)NULL, Tk_Offset(Button, activeTile), ALL_MASK | TK_CONFIG_NULL_OK, &bltTileOption}, {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", DEF_BUTTON_ANCHOR, Tk_Offset(Button, anchor), ALL_MASK}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_BUTTON_BACKGROUND, Tk_Offset(Button, normalBorder), ALL_MASK | TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_BUTTON_BG_MONO, Tk_Offset(Button, normalBorder), ALL_MASK | TK_CONFIG_MONO_ONLY}, {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, ALL_MASK}, {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, ALL_MASK}, {TK_CONFIG_BITMAP, "-bitmap", "bitmap", "Bitmap", DEF_BUTTON_BITMAP, Tk_Offset(Button, bitmap), ALL_MASK | TK_CONFIG_NULL_OK}, {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", DEF_BUTTON_BORDERWIDTH, Tk_Offset(Button, borderWidth), ALL_MASK}, {TK_CONFIG_STRING, "-command", "command", "Command", DEF_BUTTON_COMMAND, Tk_Offset(Button, command), BUTTON_MASK | CHECK_BUTTON_MASK | RADIO_BUTTON_MASK | TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-compound", "compound", "Compound", DEF_BUTTON_COMPOUND, Tk_Offset(Button, compound), ALL_MASK | TK_CONFIG_NULL_OK}, {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", DEF_BUTTON_CURSOR, Tk_Offset(Button, cursor), ALL_MASK | TK_CONFIG_NULL_OK}, {TK_CONFIG_UID, "-default", "default", "Default", DEF_BUTTON_DEFAULT, Tk_Offset(Button, defaultState), BUTTON_MASK}, {TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground", "DisabledForeground", DEF_BUTTON_DISABLED_FOREGROUND, Tk_Offset(Button, disabledFg), BUTTON_MASK | CHECK_BUTTON_MASK | RADIO_BUTTON_MASK | TK_CONFIG_COLOR_ONLY | TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground", "DisabledForeground", DEF_BUTTON_DISABLED_FG_MONO, Tk_Offset(Button, disabledFg), BUTTON_MASK | CHECK_BUTTON_MASK | RADIO_BUTTON_MASK | TK_CONFIG_MONO_ONLY | TK_CONFIG_NULL_OK}, {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *)NULL, (char *)NULL, 0, ALL_MASK}, {TK_CONFIG_FONT, "-font", "font", "Font", DEF_BUTTON_FONT, Tk_Offset(Button, font), ALL_MASK}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_BUTTON_FG, Tk_Offset(Button, normalFg), ALL_MASK}, {TK_CONFIG_STRING, "-height", "height", "Height", DEF_BUTTON_HEIGHT, Tk_Offset(Button, heightString), ALL_MASK}, {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", "HighlightBackground", DEF_BUTTON_HIGHLIGHT_BG, Tk_Offset(Button, highlightBgColorPtr), ALL_MASK}, {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", DEF_BUTTON_HIGHLIGHT, Tk_Offset(Button, highlightColorPtr), ALL_MASK}, {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", "HighlightThickness", DEF_LABEL_HIGHLIGHT_WIDTH, Tk_Offset(Button, highlightWidth), LABEL_MASK}, {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", "HighlightThickness", DEF_BUTTON_HIGHLIGHT_WIDTH, Tk_Offset(Button, highlightWidth), BUTTON_MASK | CHECK_BUTTON_MASK | RADIO_BUTTON_MASK}, {TK_CONFIG_STRING, "-image", "image", "Image", DEF_BUTTON_IMAGE, Tk_Offset(Button, imageString), ALL_MASK | TK_CONFIG_NULL_OK}, {TK_CONFIG_BOOLEAN, "-indicatoron", "indicatorOn", "IndicatorOn", DEF_BUTTON_INDICATOR, Tk_Offset(Button, indicatorOn), CHECK_BUTTON_MASK | RADIO_BUTTON_MASK}, {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify", DEF_BUTTON_JUSTIFY, Tk_Offset(Button, justify), ALL_MASK}, {TK_CONFIG_STRING, "-offvalue", "offValue", "Value", DEF_BUTTON_OFF_VALUE, Tk_Offset(Button, offValue), CHECK_BUTTON_MASK}, {TK_CONFIG_STRING, "-onvalue", "onValue", "Value", DEF_BUTTON_ON_VALUE, Tk_Offset(Button, onValue), CHECK_BUTTON_MASK}, {TK_CONFIG_RELIEF, "-overrelief", "overRelief", "OverRelief", DEF_BUTTON_OVER_RELIEF, Tk_Offset(Button, overRelief), BUTTON_MASK | CHECK_BUTTON_MASK | RADIO_BUTTON_MASK | TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_PIXELS, "-padx", "padX", "Pad", DEF_BUTTON_PADX, Tk_Offset(Button, padX), BUTTON_MASK}, {TK_CONFIG_PIXELS, "-padx", "padX", "Pad", DEF_LABCHKRAD_PADX, Tk_Offset(Button, padX), LABEL_MASK | CHECK_BUTTON_MASK | RADIO_BUTTON_MASK}, {TK_CONFIG_PIXELS, "-pady", "padY", "Pad", DEF_BUTTON_PADY, Tk_Offset(Button, padY), BUTTON_MASK}, {TK_CONFIG_PIXELS, "-pady", "padY", "Pad", DEF_LABCHKRAD_PADY, Tk_Offset(Button, padY), LABEL_MASK | CHECK_BUTTON_MASK | RADIO_BUTTON_MASK}, {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_BUTTON_RELIEF, Tk_Offset(Button, relief), BUTTON_MASK}, {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_LABCHKRAD_RELIEF, Tk_Offset(Button, relief), LABEL_MASK | CHECK_BUTTON_MASK | RADIO_BUTTON_MASK}, {TK_CONFIG_INT, "-repeatdelay", "repeatDelay", "RepeatDelay", DEF_BUTTON_REPEAT_DELAY, Tk_Offset(Button, repeatDelay), BUTTON_MASK | CHECK_BUTTON_MASK | RADIO_BUTTON_MASK}, {TK_CONFIG_BORDER, "-selectcolor", "selectColor", "Background", DEF_BUTTON_SELECT_COLOR, Tk_Offset(Button, selectBorder), CHECK_BUTTON_MASK | RADIO_BUTTON_MASK | TK_CONFIG_COLOR_ONLY | TK_CONFIG_NULL_OK}, {TK_CONFIG_BORDER, "-selectcolor", "selectColor", "Background", DEF_BUTTON_SELECT_MONO, Tk_Offset(Button, selectBorder), CHECK_BUTTON_MASK | RADIO_BUTTON_MASK | TK_CONFIG_MONO_ONLY | TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-selectimage", "selectImage", "SelectImage", DEF_BUTTON_SELECT_IMAGE, Tk_Offset(Button, selectImageString), CHECK_BUTTON_MASK | RADIO_BUTTON_MASK | TK_CONFIG_NULL_OK}, {TK_CONFIG_UID, "-state", "state", "State", DEF_BUTTON_STATE, Tk_Offset(Button, state), BUTTON_MASK | CHECK_BUTTON_MASK | RADIO_BUTTON_MASK}, {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", DEF_LABEL_TAKE_FOCUS, Tk_Offset(Button, takeFocus), LABEL_MASK | TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", DEF_BUTTON_TAKE_FOCUS, Tk_Offset(Button, takeFocus), BUTTON_MASK | CHECK_BUTTON_MASK | RADIO_BUTTON_MASK | TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-text", "text", "Text", DEF_BUTTON_TEXT, Tk_Offset(Button, text), ALL_MASK}, {TK_CONFIG_STRING, "-textvariable", "textVariable", "Variable", DEF_BUTTON_TEXT_VARIABLE, Tk_Offset(Button, textVarName), ALL_MASK | TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-tile", "tile", "Tile", (char *)NULL, Tk_Offset(Button, tile), ALL_MASK | TK_CONFIG_NULL_OK, &bltTileOption}, {TK_CONFIG_INT, "-underline", "underline", "Underline", DEF_BUTTON_UNDERLINE, Tk_Offset(Button, underline), ALL_MASK}, {TK_CONFIG_STRING, "-value", "value", "Value", DEF_BUTTON_VALUE, Tk_Offset(Button, onValue), RADIO_BUTTON_MASK}, {TK_CONFIG_STRING, "-variable", "variable", "Variable", DEF_RADIOBUTTON_VARIABLE, Tk_Offset(Button, selVarName), RADIO_BUTTON_MASK}, {TK_CONFIG_STRING, "-variable", "variable", "Variable", DEF_CHECKBUTTON_VARIABLE, Tk_Offset(Button, selVarName), CHECK_BUTTON_MASK | TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-width", "width", "Width", DEF_BUTTON_WIDTH, Tk_Offset(Button, widthString), ALL_MASK}, {TK_CONFIG_PIXELS, "-wraplength", "wrapLength", "WrapLength", DEF_BUTTON_WRAP_LENGTH, Tk_Offset(Button, wrapLength), ALL_MASK}, {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; /* * String to print out in error messages, identifying options for * widget commands for different types of labels or buttons: */ static char *optionStrings[] = { "cget or configure", "cget, configure, flash, or invoke", "cget, configure, deselect, flash, invoke, select, or toggle", "cget, configure, deselect, flash, invoke, or select" }; /* * Forward declarations for procedures defined later in this file: */ static void ButtonCmdDeletedProc _ANSI_ARGS_(( ClientData clientData)); static int ButtonCreate _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, char **argv, int type)); static void ButtonEventProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); static void ButtonImageProc _ANSI_ARGS_((ClientData clientData, int x, int y, int width, int height, int imgWidth, int imgHeight)); static void ButtonSelectImageProc _ANSI_ARGS_(( ClientData clientData, int x, int y, int width, int height, int imgWidth, int imgHeight)); static char *ButtonTextVarProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)); static char *ButtonVarProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)); static int ButtonWidgetCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, char **argv)); static void ComputeButtonGeometry _ANSI_ARGS_((Button *butPtr)); static int ConfigureButton _ANSI_ARGS_((Tcl_Interp *interp, Button *butPtr, int argc, char **argv, int flags)); static void DestroyButton _ANSI_ARGS_((Button *butPtr)); static void DisplayButton _ANSI_ARGS_((ClientData clientData)); static int InvokeButton _ANSI_ARGS_((Button *butPtr)); static Blt_TileChangedProc TileChangedProc; static Tcl_CmdProc ButtonCmd, LabelCmd, CheckbuttonCmd, RadiobuttonCmd; EXTERN int TkCopyAndGlobalEval _ANSI_ARGS_((Tcl_Interp *interp, char *script)); #if (TK_MAJOR_VERSION > 4) EXTERN void TkComputeAnchor _ANSI_ARGS_((Tk_Anchor anchor, Tk_Window tkwin, int padX, int padY, int innerWidth, int innerHeight, int *xPtr, int *yPtr)); #endif #if (TK_MAJOR_VERSION == 4) /* *--------------------------------------------------------------------------- * * TkComputeAnchor -- * * Determine where to place a rectangle so that it will be properly * anchored with respect to the given window. Used by widgets * to align a box of text inside a window. When anchoring with * respect to one of the sides, the rectangle be placed inside of * the internal border of the window. * * Results: * *xPtr and *yPtr set to the upper-left corner of the rectangle * anchored in the window. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static void TkComputeAnchor(anchor, tkwin, padX, padY, innerWidth, innerHeight, xPtr, yPtr) Tk_Anchor anchor; /* Desired anchor. */ Tk_Window tkwin; /* Anchored with respect to this window. */ int padX, padY; /* Use this extra padding inside window, in * addition to the internal border. */ int innerWidth, innerHeight;/* Size of rectangle to anchor in window. */ int *xPtr, *yPtr; /* Returns upper-left corner of anchored * rectangle. */ { switch (anchor) { case TK_ANCHOR_NW: case TK_ANCHOR_W: case TK_ANCHOR_SW: *xPtr = Tk_InternalBorderWidth(tkwin) + padX; break; case TK_ANCHOR_N: case TK_ANCHOR_CENTER: case TK_ANCHOR_S: *xPtr = (Tk_Width(tkwin) - innerWidth) / 2; break; default: *xPtr = Tk_Width(tkwin) - (Tk_InternalBorderWidth(tkwin) + padX) - innerWidth; break; } switch (anchor) { case TK_ANCHOR_NW: case TK_ANCHOR_N: case TK_ANCHOR_NE: *yPtr = Tk_InternalBorderWidth(tkwin) + padY; break; case TK_ANCHOR_W: case TK_ANCHOR_CENTER: case TK_ANCHOR_E: *yPtr = (Tk_Height(tkwin) - innerHeight) / 2; break; default: *yPtr = Tk_Height(tkwin) - Tk_InternalBorderWidth(tkwin) - padY - innerHeight; break; } } #endif /* *-------------------------------------------------------------- * * Tk_ButtonCmd, Tk_CheckbuttonCmd, Tk_LabelCmd, Tk_RadiobuttonCmd -- * * These procedures are invoked to process the "button", "label", * "radiobutton", and "checkbutton" Tcl commands. See the * user documentation for details on what they do. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. These procedures are just wrappers; * they call ButtonCreate to do all of the real work. * *-------------------------------------------------------------- */ static int ButtonCmd(clientData, interp, argc, argv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { return ButtonCreate(clientData, interp, argc, argv, TYPE_BUTTON); } static int CheckbuttonCmd(clientData, interp, argc, argv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { return ButtonCreate(clientData, interp, argc, argv, TYPE_CHECK_BUTTON); } static int LabelCmd(clientData, interp, argc, argv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { return ButtonCreate(clientData, interp, argc, argv, TYPE_LABEL); } static int RadiobuttonCmd(clientData, interp, argc, argv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { return ButtonCreate(clientData, interp, argc, argv, TYPE_RADIO_BUTTON); } /* *-------------------------------------------------------------- * * ButtonCreate -- * * This procedure does all the real work of implementing the * "button", "label", "radiobutton", and "checkbutton" Tcl * commands. See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ /*ARGSUSED*/ static int ButtonCreate(clientData, interp, argc, argv, type) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ int type; /* Type of button to create: TYPE_LABEL, * TYPE_BUTTON, TYPE_CHECK_BUTTON, or * TYPE_RADIO_BUTTON. */ { register Button *butPtr; Tk_Window tkwin; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " pathName ?options?\"", (char *)NULL); return TCL_ERROR; } /* * Create the new window. */ tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp), argv[1], (char *)NULL); if (tkwin == NULL) { return TCL_ERROR; } /* * Initialize the data structure for the button. */ butPtr = Blt_Malloc(sizeof(Button)); butPtr->tkwin = tkwin; butPtr->display = Tk_Display(tkwin); butPtr->widgetCmd = Tcl_CreateCommand(interp, Tk_PathName(butPtr->tkwin), ButtonWidgetCmd, butPtr, ButtonCmdDeletedProc); #ifdef ITCL_NAMESPACES Itk_SetWidgetCommand(butPtr->tkwin, butPtr->widgetCmd); #endif /* ITCL_NAMESPACES */ butPtr->interp = interp; butPtr->type = type; butPtr->text = NULL; butPtr->numChars = 0; butPtr->underline = -1; butPtr->textVarName = NULL; butPtr->bitmap = None; butPtr->imageString = NULL; butPtr->image = NULL; butPtr->selectImageString = NULL; butPtr->selectImage = NULL; butPtr->state = tkNormalUid; butPtr->normalBorder = NULL; butPtr->activeBorder = NULL; butPtr->borderWidth = 0; butPtr->relief = TK_RELIEF_FLAT; butPtr->highlightWidth = 0; butPtr->highlightBgColorPtr = NULL; butPtr->highlightColorPtr = NULL; butPtr->inset = 0; butPtr->font = NULL; butPtr->normalFg = NULL; butPtr->activeFg = NULL; butPtr->disabledFg = NULL; butPtr->normalTextGC = None; butPtr->activeTextGC = None; butPtr->gray = None; butPtr->disabledGC = None; butPtr->copyGC = None; butPtr->widthString = NULL; butPtr->heightString = NULL; butPtr->width = 0; butPtr->height = 0; butPtr->wrapLength = 0; butPtr->padX = 0; butPtr->padY = 0; butPtr->anchor = TK_ANCHOR_CENTER; butPtr->justify = TK_JUSTIFY_CENTER; #if (TK_MAJOR_VERSION > 4) butPtr->textLayout = NULL; #endif butPtr->indicatorOn = 0; butPtr->selectBorder = NULL; butPtr->indicatorSpace = 0; butPtr->indicatorDiameter = 0; butPtr->selVarName = NULL; butPtr->onValue = NULL; butPtr->offValue = NULL; butPtr->cursor = None; butPtr->command = NULL; butPtr->takeFocus = NULL; butPtr->flags = 0; butPtr->tile = butPtr->activeTile = NULL; butPtr->defaultState = tkDisabledUid; butPtr->compound = NULL; butPtr->repeatDelay = 0; butPtr->overRelief = TK_RELIEF_RAISED; Tk_SetClass(tkwin, classNames[type]); Tk_CreateEventHandler(butPtr->tkwin, ExposureMask | StructureNotifyMask | FocusChangeMask, ButtonEventProc, butPtr); if (ConfigureButton(interp, butPtr, argc - 2, argv + 2, configFlags[type]) != TCL_OK) { Tk_DestroyWindow(butPtr->tkwin); return TCL_ERROR; } Tcl_SetResult(interp, Tk_PathName(butPtr->tkwin), TCL_VOLATILE); return TCL_OK; } /* *-------------------------------------------------------------- * * ButtonWidgetCmd -- * * This procedure is invoked to process the Tcl command * that corresponds to a widget managed by this module. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ static int ButtonWidgetCmd(clientData, interp, argc, argv) ClientData clientData; /* Information about button widget. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { register Button *butPtr = clientData; int result = TCL_OK; size_t length; int c; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " option ?arg arg ...?\"", (char *)NULL); return TCL_ERROR; } Tcl_Preserve(butPtr); c = argv[1][0]; length = strlen(argv[1]); if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) && (length >= 2)) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " cget option\"", (char *)NULL); goto error; } result = Tk_ConfigureValue(interp, butPtr->tkwin, configSpecs, (char *)butPtr, argv[2], configFlags[butPtr->type]); } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) && (length >= 2)) { if (argc == 2) { result = Tk_ConfigureInfo(interp, butPtr->tkwin, configSpecs, (char *)butPtr, (char *)NULL, configFlags[butPtr->type]); } else if (argc == 3) { result = Tk_ConfigureInfo(interp, butPtr->tkwin, configSpecs, (char *)butPtr, argv[2], configFlags[butPtr->type]); } else { result = ConfigureButton(interp, butPtr, argc - 2, argv + 2, configFlags[butPtr->type] | TK_CONFIG_ARGV_ONLY); } } else if ((c == 'd') && (strncmp(argv[1], "deselect", length) == 0) && (butPtr->type >= TYPE_CHECK_BUTTON)) { if (argc > 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " deselect\"", (char *)NULL); goto error; } if (butPtr->type == TYPE_CHECK_BUTTON) { if (Tcl_SetVar(interp, butPtr->selVarName, butPtr->offValue, TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL) { result = TCL_ERROR; } } else if (butPtr->flags & SELECTED) { if (Tcl_SetVar(interp, butPtr->selVarName, "", TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL) { result = TCL_ERROR; }; } } else if ((c == 'f') && (strncmp(argv[1], "flash", length) == 0) && (butPtr->type != TYPE_LABEL)) { int i; if (argc > 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " flash\"", (char *)NULL); goto error; } if (butPtr->state != tkDisabledUid) { for (i = 0; i < 4; i++) { butPtr->state = (butPtr->state == tkNormalUid) ? tkActiveUid : tkNormalUid; Tk_SetBackgroundFromBorder(butPtr->tkwin, (butPtr->state == tkActiveUid) ? butPtr->activeBorder : butPtr->normalBorder); DisplayButton(butPtr); /* * Special note: must cancel any existing idle handler * for DisplayButton; it's no longer needed, and DisplayButton * cleared the REDRAW_PENDING flag. */ Tcl_CancelIdleCall(DisplayButton, butPtr); #ifndef WIN32 XFlush(butPtr->display); #endif Tcl_Sleep(50); } } } else if ((c == 'i') && (strncmp(argv[1], "invoke", length) == 0) && (butPtr->type > TYPE_LABEL)) { if (argc > 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", " invoke\"", (char *)NULL); goto error; } if (butPtr->state != tkDisabledUid) { result = InvokeButton(butPtr); } } else if ((c == 's') && (strncmp(argv[1], "select", length) == 0) && (butPtr->type >= TYPE_CHECK_BUTTON)) { if (argc > 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " select\"", (char *)NULL); goto error; } if (Tcl_SetVar(interp, butPtr->selVarName, butPtr->onValue, TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL) { result = TCL_ERROR; } } else if ((c == 't') && (strncmp(argv[1], "toggle", length) == 0) && (length >= 2) && (butPtr->type == TYPE_CHECK_BUTTON)) { if (argc > 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " toggle\"", (char *)NULL); goto error; } if (butPtr->flags & SELECTED) { if (Tcl_SetVar(interp, butPtr->selVarName, butPtr->offValue, TCL_GLOBAL_ONLY) == NULL) { result = TCL_ERROR; } } else { if (Tcl_SetVar(interp, butPtr->selVarName, butPtr->onValue, TCL_GLOBAL_ONLY) == NULL) { result = TCL_ERROR; } } } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": must be ", optionStrings[butPtr->type], (char *)NULL); goto error; } Tcl_Release(butPtr); return result; error: Tcl_Release(butPtr); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * DestroyButton -- * * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release * to clean up the internal structure of a button at a safe time * (when no-one is using it anymore). * * Results: * None. * * Side effects: * Everything associated with the widget is freed up. * *---------------------------------------------------------------------- */ static void DestroyButton(butPtr) Button *butPtr; /* Info about button widget. */ { /* * Free up all the stuff that requires special handling, then * let Tk_FreeOptions handle all the standard option-related * stuff. */ if (butPtr->textVarName != NULL) { Tcl_UntraceVar(butPtr->interp, butPtr->textVarName, TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, ButtonTextVarProc, butPtr); } if (butPtr->image != NULL) { Tk_FreeImage(butPtr->image); } if (butPtr->selectImage != NULL) { Tk_FreeImage(butPtr->selectImage); } if (butPtr->normalTextGC != None) { Tk_FreeGC(butPtr->display, butPtr->normalTextGC); } if (butPtr->activeTextGC != None) { Tk_FreeGC(butPtr->display, butPtr->activeTextGC); } if (butPtr->gray != None) { Tk_FreeBitmap(butPtr->display, butPtr->gray); } if (butPtr->disabledGC != None) { Tk_FreeGC(butPtr->display, butPtr->disabledGC); } if (butPtr->copyGC != None) { Tk_FreeGC(butPtr->display, butPtr->copyGC); } if (butPtr->selVarName != NULL) { Tcl_UntraceVar(butPtr->interp, butPtr->selVarName, TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, ButtonVarProc, (ClientData)butPtr); } if (butPtr->activeTile != NULL) { Blt_FreeTile(butPtr->activeTile); } if (butPtr->tile != NULL) { Blt_FreeTile(butPtr->tile); } #if (TK_MAJOR_VERSION > 4) Tk_FreeTextLayout(butPtr->textLayout); #endif Tk_FreeOptions(configSpecs, (char *)butPtr, butPtr->display, configFlags[butPtr->type]); Tcl_EventuallyFree((ClientData)butPtr, TCL_DYNAMIC); } /*ARGSUSED*/ static void TileChangedProc(clientData, tile) ClientData clientData; Blt_Tile tile; /* Not used. */ { Button *butPtr = clientData; if (butPtr->tkwin != NULL) { /* * Arrange for the button to be redisplayed. */ if (Tk_IsMapped(butPtr->tkwin) && !(butPtr->flags & REDRAW_PENDING)) { Tcl_DoWhenIdle(DisplayButton, (ClientData)butPtr); butPtr->flags |= REDRAW_PENDING; } } } /* *---------------------------------------------------------------------- * * ConfigureButton -- * * This procedure is called to process an argv/argc list, plus * the Tk option database, in order to configure (or * reconfigure) a button widget. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then interp->result contains an error message. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for butPtr; old resources get freed, if there * were any. The button is redisplayed. * *---------------------------------------------------------------------- */ static int ConfigureButton(interp, butPtr, argc, argv, flags) Tcl_Interp *interp; /* Used for error reporting. */ register Button *butPtr; /* Information about widget; may or may * not already have values for some fields. */ int argc; /* Number of valid entries in argv. */ char **argv; /* Arguments. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { XGCValues gcValues; GC newGC; unsigned long mask; Tk_Image image; /* * Eliminate any existing trace on variables monitored by the button. */ if (butPtr->textVarName != NULL) { Tcl_UntraceVar(interp, butPtr->textVarName, TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, ButtonTextVarProc, (ClientData)butPtr); } if (butPtr->selVarName != NULL) { Tcl_UntraceVar(interp, butPtr->selVarName, TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, ButtonVarProc, (ClientData)butPtr); } if (Tk_ConfigureWidget(interp, butPtr->tkwin, configSpecs, argc, argv, (char *)butPtr, flags) != TCL_OK) { return TCL_ERROR; } /* * A few options need special processing, such as setting the * background from a 3-D border, or filling in complicated * defaults that couldn't be specified to Tk_ConfigureWidget. */ if ((butPtr->state == tkActiveUid) && !Tk_StrictMotif(butPtr->tkwin)) { Tk_SetBackgroundFromBorder(butPtr->tkwin, butPtr->activeBorder); } else { Tk_SetBackgroundFromBorder(butPtr->tkwin, butPtr->normalBorder); if ((butPtr->state != tkNormalUid) && (butPtr->state != tkActiveUid) && (butPtr->state != tkDisabledUid)) { Tcl_AppendResult(interp, "bad state value \"", butPtr->state, "\": must be normal, active, or disabled", (char *)NULL); butPtr->state = tkNormalUid; return TCL_ERROR; } } if ((butPtr->defaultState != tkActiveUid) && (butPtr->defaultState != tkDisabledUid) && (butPtr->defaultState != tkNormalUid)) { Tcl_AppendResult(interp, "bad -default value \"", butPtr->defaultState, "\": must be normal, active, or disabled", (char *)NULL); butPtr->defaultState = tkDisabledUid; return TCL_ERROR; } if (butPtr->highlightWidth < 0) { butPtr->highlightWidth = 0; } gcValues.font = Tk_FontId(butPtr->font); gcValues.foreground = butPtr->normalFg->pixel; gcValues.background = Tk_3DBorderColor(butPtr->normalBorder)->pixel; if (butPtr->tile != NULL) { Blt_SetTileChangedProc(butPtr->tile, TileChangedProc, (ClientData)butPtr); } if (butPtr->activeTile != NULL) { Blt_SetTileChangedProc(butPtr->activeTile, TileChangedProc, (ClientData)butPtr); } /* * Note: GraphicsExpose events are disabled in normalTextGC because it's * used to copy stuff from an off-screen pixmap onto the screen (we know * that there's no problem with obscured areas). */ gcValues.graphics_exposures = False; newGC = Tk_GetGC(butPtr->tkwin, GCForeground | GCBackground | GCFont | GCGraphicsExposures, &gcValues); if (butPtr->normalTextGC != None) { Tk_FreeGC(butPtr->display, butPtr->normalTextGC); } butPtr->normalTextGC = newGC; if (butPtr->activeFg != NULL) { gcValues.font = Tk_FontId(butPtr->font); gcValues.foreground = butPtr->activeFg->pixel; gcValues.background = Tk_3DBorderColor(butPtr->activeBorder)->pixel; newGC = Tk_GetGC(butPtr->tkwin, GCForeground | GCBackground | GCFont, &gcValues); if (butPtr->activeTextGC != None) { Tk_FreeGC(butPtr->display, butPtr->activeTextGC); } butPtr->activeTextGC = newGC; } if (butPtr->type != TYPE_LABEL) { gcValues.font = Tk_FontId(butPtr->font); gcValues.background = Tk_3DBorderColor(butPtr->normalBorder)->pixel; if ((butPtr->disabledFg != NULL) && (butPtr->imageString == NULL)) { gcValues.foreground = butPtr->disabledFg->pixel; mask = GCForeground | GCBackground | GCFont; } else { gcValues.foreground = gcValues.background; if (butPtr->gray == None) { butPtr->gray = Tk_GetBitmap(interp, butPtr->tkwin, Tk_GetUid("gray50")); if (butPtr->gray == None) { return TCL_ERROR; } } gcValues.fill_style = FillStippled; gcValues.stipple = butPtr->gray; mask = GCForeground | GCFillStyle | GCStipple; } newGC = Tk_GetGC(butPtr->tkwin, mask, &gcValues); if (butPtr->disabledGC != None) { Tk_FreeGC(butPtr->display, butPtr->disabledGC); } butPtr->disabledGC = newGC; } if (butPtr->copyGC == None) { butPtr->copyGC = Tk_GetGC(butPtr->tkwin, 0, &gcValues); } if (butPtr->padX < 0) { butPtr->padX = 0; } if (butPtr->padY < 0) { butPtr->padY = 0; } if (butPtr->type >= TYPE_CHECK_BUTTON) { CONST char *value; if (butPtr->selVarName == NULL) { butPtr->selVarName = Blt_Malloc(strlen(Tk_Name(butPtr->tkwin)) + 1); strcpy(butPtr->selVarName, Tk_Name(butPtr->tkwin)); } /* * Select the button if the associated variable has the * appropriate value, initialize the variable if it doesn't * exist, then set a trace on the variable to monitor future * changes to its value. */ value = Tcl_GetVar(interp, butPtr->selVarName, TCL_GLOBAL_ONLY); butPtr->flags &= ~SELECTED; if (value != NULL) { if (strcmp(value, butPtr->onValue) == 0) { butPtr->flags |= SELECTED; } } else { if (Tcl_SetVar(interp, butPtr->selVarName, (butPtr->type == TYPE_CHECK_BUTTON) ? butPtr->offValue : "", TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } } Tcl_TraceVar(interp, butPtr->selVarName, TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, ButtonVarProc, (ClientData)butPtr); } /* * Get the images for the widget, if there are any. Allocate the * new images before freeing the old ones, so that the reference * counts don't go to zero and cause image data to be discarded. */ if (butPtr->imageString != NULL) { image = Tk_GetImage(butPtr->interp, butPtr->tkwin, butPtr->imageString, ButtonImageProc, (ClientData)butPtr); if (image == NULL) { return TCL_ERROR; } } else { image = NULL; } if (butPtr->image != NULL) { Tk_FreeImage(butPtr->image); } butPtr->image = image; if (butPtr->selectImageString != NULL) { image = Tk_GetImage(butPtr->interp, butPtr->tkwin, butPtr->selectImageString, ButtonSelectImageProc, (ClientData)butPtr); if (image == NULL) { return TCL_ERROR; } } else { image = NULL; } if (butPtr->selectImage != NULL) { Tk_FreeImage(butPtr->selectImage); } butPtr->selectImage = image; if ((butPtr->image == NULL) && (butPtr->bitmap == None) && (butPtr->textVarName != NULL)) { /* * The button must display the value of a variable: set up a trace * on the variable's value, create the variable if it doesn't * exist, and fetch its current value. */ CONST char *value; value = Tcl_GetVar(interp, butPtr->textVarName, TCL_GLOBAL_ONLY); if (value == NULL) { if (Tcl_SetVar(interp, butPtr->textVarName, butPtr->text, TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } } else { if (butPtr->text != NULL) { Blt_Free(butPtr->text); } butPtr->text = Blt_Malloc(strlen(value) + 1); strcpy(butPtr->text, value); } Tcl_TraceVar(interp, butPtr->textVarName, TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, ButtonTextVarProc, (ClientData)butPtr); } if ((butPtr->bitmap != None) || (butPtr->image != NULL)) { if (Tk_GetPixels(interp, butPtr->tkwin, butPtr->widthString, &butPtr->width) != TCL_OK) { widthError: Tcl_AddErrorInfo(interp, "\n (processing -width option)"); return TCL_ERROR; } if (Tk_GetPixels(interp, butPtr->tkwin, butPtr->heightString, &butPtr->height) != TCL_OK) { heightError: Tcl_AddErrorInfo(interp, "\n (processing -height option)"); return TCL_ERROR; } } else { if (Tcl_GetInt(interp, butPtr->widthString, &butPtr->width) != TCL_OK) { goto widthError; } if (Tcl_GetInt(interp, butPtr->heightString, &butPtr->height) != TCL_OK) { goto heightError; } } ComputeButtonGeometry(butPtr); /* * Lastly, arrange for the button to be redisplayed. */ if (Tk_IsMapped(butPtr->tkwin) && !(butPtr->flags & REDRAW_PENDING)) { Tcl_DoWhenIdle(DisplayButton, (ClientData)butPtr); butPtr->flags |= REDRAW_PENDING; } return TCL_OK; } /* *---------------------------------------------------------------------- * * DisplayButton -- * * This procedure is invoked to display a button widget. It is * normally invoked as an idle handler. * * Results: * None. * * Side effects: * Commands are output to X to display the button in its * current mode. The REDRAW_PENDING flag is cleared. * *---------------------------------------------------------------------- */ static void DisplayButton(clientData) ClientData clientData; /* Information about widget. */ { register Button *butPtr = clientData; GC gc; Tk_3DBorder border; Pixmap pixmap; int x = 0; /* Initialization only needed to stop * compiler warning. */ int y, relief; register Tk_Window tkwin = butPtr->tkwin; int width, height; int offset; /* 0 means this is a label widget. 1 means * it is a flavor of button, so we offset * the text to make the button appear to * move up and down as the relief changes. */ Blt_Tile tile; butPtr->flags &= ~REDRAW_PENDING; if ((butPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { return; } tile = butPtr->tile; border = butPtr->normalBorder; if ((butPtr->state == tkDisabledUid) && (butPtr->disabledFg != NULL)) { gc = butPtr->disabledGC; } else if ((butPtr->state == tkActiveUid) && !Tk_StrictMotif(butPtr->tkwin)) { gc = butPtr->activeTextGC; border = butPtr->activeBorder; tile = butPtr->activeTile; } else { gc = butPtr->normalTextGC; } if ((butPtr->flags & SELECTED) && (butPtr->state != tkActiveUid) && (butPtr->selectBorder != NULL) && !butPtr->indicatorOn) { border = butPtr->selectBorder; } /* * Override the relief specified for the button if this is a * checkbutton or radiobutton and there's no indicator. */ relief = butPtr->relief; if ((butPtr->type >= TYPE_CHECK_BUTTON) && !butPtr->indicatorOn) { relief = (butPtr->flags & SELECTED) ? TK_RELIEF_SUNKEN : TK_RELIEF_RAISED; } offset = (butPtr->type == TYPE_BUTTON) && !Tk_StrictMotif(butPtr->tkwin); /* * In order to avoid screen flashes, this procedure redraws * the button in a pixmap, then copies the pixmap to the * screen in a single operation. This means that there's no * point in time where the on-sreen image has been cleared. */ pixmap = Tk_GetPixmap(butPtr->display, Tk_WindowId(tkwin), Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin)); if (tile != NULL) { Blt_SetTileOrigin(tkwin, tile, 0, 0); Blt_TileRectangle(tkwin, pixmap, tile, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin)); } else { Blt_Fill3DRectangle(tkwin, pixmap, border, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); } /* * Display image or bitmap or text for button. */ if (butPtr->image != None) { Tk_SizeOfImage(butPtr->image, &width, &height); imageOrBitmap: TkComputeAnchor(butPtr->anchor, tkwin, 0, 0, butPtr->indicatorSpace + width, height, &x, &y); x += butPtr->indicatorSpace; x += offset; y += offset; if (relief == TK_RELIEF_RAISED) { x -= offset; y -= offset; } else if (relief == TK_RELIEF_SUNKEN) { x += offset; y += offset; } if (butPtr->image != NULL) { if ((butPtr->selectImage != NULL) && (butPtr->flags & SELECTED)) { Tk_RedrawImage(butPtr->selectImage, 0, 0, width, height, pixmap, x, y); } else { Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap, x, y); } } else { XSetClipOrigin(butPtr->display, gc, x, y); if (tile != NULL) { XSetClipMask(butPtr->display, gc, butPtr->bitmap); } XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, gc, 0, 0, (unsigned int)width, (unsigned int)height, x, y, 1); if (tile != NULL) { XSetClipMask(butPtr->display, gc, None); } XSetClipOrigin(butPtr->display, gc, 0, 0); } y += height / 2; } else if (butPtr->bitmap != None) { Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height); goto imageOrBitmap; } else { TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY, butPtr->indicatorSpace + butPtr->textWidth, butPtr->textHeight, &x, &y); x += butPtr->indicatorSpace; x += offset; y += offset; if (relief == TK_RELIEF_RAISED) { x -= offset; y -= offset; } else if (relief == TK_RELIEF_SUNKEN) { x += offset; y += offset; } #if (TK_MAJOR_VERSION > 4) Tk_DrawTextLayout(butPtr->display, pixmap, gc, butPtr->textLayout, x, y, 0, -1); Tk_UnderlineTextLayout(butPtr->display, pixmap, gc, butPtr->textLayout, x, y, butPtr->underline); #else TkDisplayText(butPtr->display, pixmap, butPtr->font, butPtr->text, butPtr->numChars, x, y, butPtr->textWidth, butPtr->justify, butPtr->underline, gc); #endif y += butPtr->textHeight / 2; } /* * Draw the indicator for check buttons and radio buttons. At this * point x and y refer to the top-left corner of the text or image * or bitmap. */ if ((butPtr->type == TYPE_CHECK_BUTTON) && butPtr->indicatorOn) { int dim; dim = butPtr->indicatorDiameter; x -= butPtr->indicatorSpace; y -= dim / 2; if (dim > 2 * butPtr->borderWidth) { Blt_Draw3DRectangle(tkwin, pixmap, border, x, y, dim, dim, butPtr->borderWidth, (butPtr->flags & SELECTED) ? TK_RELIEF_SUNKEN : TK_RELIEF_RAISED); x += butPtr->borderWidth; y += butPtr->borderWidth; dim -= 2 * butPtr->borderWidth; if (butPtr->flags & SELECTED) { GC borderGC; borderGC = Tk_3DBorderGC(tkwin, (butPtr->selectBorder != NULL) ? butPtr->selectBorder : butPtr->normalBorder, TK_3D_FLAT_GC); XFillRectangle(butPtr->display, pixmap, borderGC, x, y, (unsigned int)dim, (unsigned int)dim); } else { Blt_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, x, y, dim, dim, butPtr->borderWidth, TK_RELIEF_FLAT); } } } else if ((butPtr->type == TYPE_RADIO_BUTTON) && butPtr->indicatorOn) { XPoint points[4]; int radius; radius = butPtr->indicatorDiameter / 2; points[0].x = x - butPtr->indicatorSpace; points[0].y = y; points[1].x = points[0].x + radius; points[1].y = points[0].y + radius; points[2].x = points[1].x + radius; points[2].y = points[0].y; points[3].x = points[1].x; points[3].y = points[0].y - radius; if (butPtr->flags & SELECTED) { GC borderGC; borderGC = Tk_3DBorderGC(tkwin, (butPtr->selectBorder != NULL) ? butPtr->selectBorder : butPtr->normalBorder, TK_3D_FLAT_GC); XFillPolygon(butPtr->display, pixmap, borderGC, points, 4, Convex, CoordModeOrigin); } else { Tk_Fill3DPolygon(tkwin, pixmap, butPtr->normalBorder, points, 4, butPtr->borderWidth, TK_RELIEF_FLAT); } Tk_Draw3DPolygon(tkwin, pixmap, border, points, 4, butPtr->borderWidth, (butPtr->flags & SELECTED) ? TK_RELIEF_SUNKEN : TK_RELIEF_RAISED); } /* * If the button is disabled with a stipple rather than a special * foreground color, generate the stippled effect. If the widget * is selected and we use a different background color when selected, * must temporarily modify the GC. */ if ((butPtr->state == tkDisabledUid) && ((butPtr->disabledFg == NULL) || (butPtr->image != NULL))) { if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn && (butPtr->selectBorder != NULL)) { XSetForeground(butPtr->display, butPtr->disabledGC, Tk_3DBorderColor(butPtr->selectBorder)->pixel); } XFillRectangle(butPtr->display, pixmap, butPtr->disabledGC, butPtr->inset, butPtr->inset, (unsigned)(Tk_Width(tkwin) - 2 * butPtr->inset), (unsigned)(Tk_Height(tkwin) - 2 * butPtr->inset)); if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn && (butPtr->selectBorder != NULL)) { XSetForeground(butPtr->display, butPtr->disabledGC, Tk_3DBorderColor(butPtr->normalBorder)->pixel); } } /* * Draw the border and traversal highlight last. This way, if the * button's contents overflow they'll be covered up by the border. */ if (relief != TK_RELIEF_FLAT) { int inset = butPtr->highlightWidth; if (butPtr->defaultState == tkActiveUid) { inset += 2; Blt_Draw3DRectangle(tkwin, pixmap, border, inset, inset, Tk_Width(tkwin) - 2 * inset, Tk_Height(tkwin) - 2 * inset, 1, TK_RELIEF_SUNKEN); inset += 3; } Blt_Draw3DRectangle(tkwin, pixmap, border, inset, inset, Tk_Width(tkwin) - 2 * inset, Tk_Height(tkwin) - 2 * inset, butPtr->borderWidth, relief); } if (butPtr->highlightWidth != 0) { GC highlightGC; if (butPtr->flags & GOT_FOCUS) { highlightGC = Tk_GCForColor(butPtr->highlightColorPtr, pixmap); } else { highlightGC = Tk_GCForColor(butPtr->highlightBgColorPtr, pixmap); } Tk_DrawFocusHighlight(tkwin, highlightGC, butPtr->highlightWidth, pixmap); } /* * Copy the information from the off-screen pixmap onto the screen, * then delete the pixmap. */ XCopyArea(butPtr->display, pixmap, Tk_WindowId(tkwin), butPtr->copyGC, 0, 0, (unsigned)Tk_Width(tkwin), (unsigned)Tk_Height(tkwin), 0, 0); Tk_FreePixmap(butPtr->display, pixmap); } /* *---------------------------------------------------------------------- * * ComputeButtonGeometry -- * * After changes in a button's text or bitmap, this procedure * recomputes the button's geometry and passes this information * along to the geometry manager for the window. * * Results: * None. * * Side effects: * The button's window may change size. * *---------------------------------------------------------------------- */ static void ComputeButtonGeometry(butPtr) register Button *butPtr; /* Button whose geometry may have changed. */ { int width, height; if (butPtr->highlightWidth < 0) { butPtr->highlightWidth = 0; } butPtr->inset = butPtr->highlightWidth + butPtr->borderWidth; /* * Leave room for the default ring if needed. */ if (butPtr->defaultState == tkActiveUid) { butPtr->inset += 5; } butPtr->indicatorSpace = 0; if (butPtr->image != NULL) { Tk_SizeOfImage(butPtr->image, &width, &height); imageOrBitmap: if (butPtr->width > 0) { width = butPtr->width; } if (butPtr->height > 0) { height = butPtr->height; } if ((butPtr->type >= TYPE_CHECK_BUTTON) && butPtr->indicatorOn) { butPtr->indicatorSpace = height; if (butPtr->type == TYPE_CHECK_BUTTON) { butPtr->indicatorDiameter = (65 * height) / 100; } else { butPtr->indicatorDiameter = (75 * height) / 100; } } } else if (butPtr->bitmap != None) { Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height); goto imageOrBitmap; } else { int avgWidth; Tk_FontMetrics fm; #if (TK_MAJOR_VERSION > 4) Tk_FreeTextLayout(butPtr->textLayout); butPtr->textLayout = Tk_ComputeTextLayout(butPtr->font, butPtr->text, -1, butPtr->wrapLength, butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight); #else butPtr->numChars = strlen(butPtr->text); TkComputeTextGeometry(butPtr->font, butPtr->text, butPtr->numChars, butPtr->wrapLength, &butPtr->textWidth, &butPtr->textHeight); #endif width = butPtr->textWidth; height = butPtr->textHeight; avgWidth = Tk_TextWidth(butPtr->font, "0", 1); Tk_GetFontMetrics(butPtr->font, &fm); if (butPtr->width > 0) { width = butPtr->width * avgWidth; } if (butPtr->height > 0) { height = butPtr->height * fm.linespace; } if ((butPtr->type >= TYPE_CHECK_BUTTON) && butPtr->indicatorOn) { butPtr->indicatorDiameter = fm.linespace; if (butPtr->type == TYPE_CHECK_BUTTON) { butPtr->indicatorDiameter = (80 * butPtr->indicatorDiameter) / 100; } butPtr->indicatorSpace = butPtr->indicatorDiameter + avgWidth; } } /* * When issuing the geometry request, add extra space for the indicator, * if any, and for the border and padding, plus two extra pixels so the * display can be offset by 1 pixel in either direction for the raised * or lowered effect. */ if ((butPtr->image == NULL) && (butPtr->bitmap == None)) { width += 2 * butPtr->padX; height += 2 * butPtr->padY; } if ((butPtr->type == TYPE_BUTTON) && !Tk_StrictMotif(butPtr->tkwin)) { width += 2; height += 2; } Tk_GeometryRequest(butPtr->tkwin, (int)(width + butPtr->indicatorSpace + 2 * butPtr->inset), (int)(height + 2 * butPtr->inset)); Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset); } /* *-------------------------------------------------------------- * * ButtonEventProc -- * * This procedure is invoked by the Tk dispatcher for various * events on buttons. * * Results: * None. * * Side effects: * When the window gets deleted, internal structures get * cleaned up. When it gets exposed, it is redisplayed. * *-------------------------------------------------------------- */ static void ButtonEventProc(clientData, eventPtr) ClientData clientData; /* Information about window. */ XEvent *eventPtr; /* Information about event. */ { Button *butPtr = clientData; if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) { goto redraw; } else if (eventPtr->type == ConfigureNotify) { /* * Must redraw after size changes, since layout could have changed * and borders will need to be redrawn. */ goto redraw; } else if (eventPtr->type == DestroyNotify) { if (butPtr->tkwin != NULL) { butPtr->tkwin = NULL; Tcl_DeleteCommandFromToken(butPtr->interp, butPtr->widgetCmd); } if (butPtr->flags & REDRAW_PENDING) { Tcl_CancelIdleCall(DisplayButton, (ClientData)butPtr); } /* This is a hack to workaround a bug in 8.3.3. */ DestroyButton((ClientData)butPtr); /* Tcl_EventuallyFree((ClientData)butPtr, (Tcl_FreeProc *)Blt_Free); */ } else if (eventPtr->type == FocusIn) { if (eventPtr->xfocus.detail != NotifyInferior) { butPtr->flags |= GOT_FOCUS; if (butPtr->highlightWidth > 0) { goto redraw; } } } else if (eventPtr->type == FocusOut) { if (eventPtr->xfocus.detail != NotifyInferior) { butPtr->flags &= ~GOT_FOCUS; if (butPtr->highlightWidth > 0) { goto redraw; } } } return; redraw: if ((butPtr->tkwin != NULL) && !(butPtr->flags & REDRAW_PENDING)) { Tcl_DoWhenIdle(DisplayButton, (ClientData)butPtr); butPtr->flags |= REDRAW_PENDING; } } /* *---------------------------------------------------------------------- * * ButtonCmdDeletedProc -- * * This procedure is invoked when a widget command is deleted. If * the widget isn't already in the process of being destroyed, * this command destroys it. * * Results: * None. * * Side effects: * The widget is destroyed. * *---------------------------------------------------------------------- */ static void ButtonCmdDeletedProc(clientData) ClientData clientData; /* Pointer to widget record for widget. */ { Button *butPtr = clientData; Tk_Window tkwin = butPtr->tkwin; /* * This procedure could be invoked either because the window was * destroyed and the command was then deleted (in which case tkwin * is NULL) or because the command was deleted, and then this procedure * destroys the widget. */ if (tkwin != NULL) { butPtr->tkwin = NULL; #ifdef ITCL_NAMESPACES Itk_SetWidgetCommand(tkwin, (Tcl_Command) NULL); #endif Tk_DestroyWindow(tkwin); } } /* *---------------------------------------------------------------------- * * InvokeButton -- * * This procedure is called to carry out the actions associated * with a button, such as invoking a Tcl command or setting a * variable. This procedure is invoked, for example, when the * button is invoked via the mouse. * * Results: * A standard Tcl return value. Information is also left in * interp->result. * * Side effects: * Depends on the button and its associated command. * *---------------------------------------------------------------------- */ static int InvokeButton(butPtr) register Button *butPtr; /* Information about button. */ { if (butPtr->type == TYPE_CHECK_BUTTON) { if (butPtr->flags & SELECTED) { if (Tcl_SetVar(butPtr->interp, butPtr->selVarName, butPtr->offValue, TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } } else { if (Tcl_SetVar(butPtr->interp, butPtr->selVarName, butPtr->onValue, TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } } } else if (butPtr->type == TYPE_RADIO_BUTTON) { if (Tcl_SetVar(butPtr->interp, butPtr->selVarName, butPtr->onValue, TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } } if ((butPtr->type != TYPE_LABEL) && (butPtr->command != NULL)) { return TkCopyAndGlobalEval(butPtr->interp, butPtr->command); } return TCL_OK; } /* *-------------------------------------------------------------- * * ButtonVarProc -- * * This procedure is invoked when someone changes the * state variable associated with a radio button. Depending * on the new value of the button's variable, the button * may be selected or deselected. * * Results: * NULL is always returned. * * Side effects: * The button may become selected or deselected. * *-------------------------------------------------------------- */ /* ARGSUSED */ static char * ButtonVarProc(clientData, interp, name1, name2, flags) ClientData clientData; /* Information about button. */ Tcl_Interp *interp; /* Interpreter containing variable. */ char *name1; /* Name of variable. */ char *name2; /* Second part of variable name. */ int flags; /* Information about what happened. */ { register Button *butPtr = clientData; CONST char *value; /* * If the variable is being unset, then just re-establish the * trace unless the whole interpreter is going away. */ if (flags & TCL_TRACE_UNSETS) { butPtr->flags &= ~SELECTED; if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) { Tcl_TraceVar(interp, butPtr->selVarName, TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, ButtonVarProc, clientData); } goto redisplay; } /* * Use the value of the variable to update the selected status of * the button. */ value = Tcl_GetVar(interp, butPtr->selVarName, TCL_GLOBAL_ONLY); if (value == NULL) { value = ""; } if (strcmp(value, butPtr->onValue) == 0) { if (butPtr->flags & SELECTED) { return (char *) NULL; } butPtr->flags |= SELECTED; } else if (butPtr->flags & SELECTED) { butPtr->flags &= ~SELECTED; } else { return (char *) NULL; } redisplay: if ((butPtr->tkwin != NULL) && Tk_IsMapped(butPtr->tkwin) && !(butPtr->flags & REDRAW_PENDING)) { Tcl_DoWhenIdle(DisplayButton, (ClientData)butPtr); butPtr->flags |= REDRAW_PENDING; } return (char *) NULL; } /* *-------------------------------------------------------------- * * ButtonTextVarProc -- * * This procedure is invoked when someone changes the variable * whose contents are to be displayed in a button. * * Results: * NULL is always returned. * * Side effects: * The text displayed in the button will change to match the * variable. * *-------------------------------------------------------------- */ /* ARGSUSED */ static char * ButtonTextVarProc(clientData, interp, name1, name2, flags) ClientData clientData; /* Information about button. */ Tcl_Interp *interp; /* Interpreter containing variable. */ char *name1; /* Not used. */ char *name2; /* Not used. */ int flags; /* Information about what happened. */ { register Button *butPtr = clientData; CONST char *value; /* * If the variable is unset, then immediately recreate it unless * the whole interpreter is going away. */ if (flags & TCL_TRACE_UNSETS) { if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) { Tcl_SetVar(interp, butPtr->textVarName, butPtr->text, TCL_GLOBAL_ONLY); Tcl_TraceVar(interp, butPtr->textVarName, TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, ButtonTextVarProc, clientData); } return (char *) NULL; } value = Tcl_GetVar(interp, butPtr->textVarName, TCL_GLOBAL_ONLY); if (value == NULL) { value = ""; } if (butPtr->text != NULL) { Blt_Free(butPtr->text); } butPtr->text = Blt_Malloc(strlen(value) + 1); strcpy(butPtr->text, value); ComputeButtonGeometry(butPtr); if ((butPtr->tkwin != NULL) && Tk_IsMapped(butPtr->tkwin) && !(butPtr->flags & REDRAW_PENDING)) { Tcl_DoWhenIdle(DisplayButton, (ClientData)butPtr); butPtr->flags |= REDRAW_PENDING; } return (char *) NULL; } /* *---------------------------------------------------------------------- * * ButtonImageProc -- * * This procedure is invoked by the image code whenever the manager * for an image does something that affects the size of contents * of an image displayed in a button. * * Results: * None. * * Side effects: * Arranges for the button to get redisplayed. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static void ButtonImageProc(clientData, x, y, width, height, imgWidth, imgHeight) ClientData clientData; /* Pointer to widget record. */ int x, y; /* Upper left pixel (within image) * that must be redisplayed. */ int width, height; /* Dimensions of area to redisplay * (may be <= 0). */ int imgWidth, imgHeight; /* New dimensions of image. */ { register Button *butPtr = clientData; if (butPtr->tkwin != NULL) { ComputeButtonGeometry(butPtr); if (Tk_IsMapped(butPtr->tkwin) && !(butPtr->flags & REDRAW_PENDING)) { Tcl_DoWhenIdle(DisplayButton, (ClientData)butPtr); butPtr->flags |= REDRAW_PENDING; } } } /* *---------------------------------------------------------------------- * * ButtonSelectImageProc -- * * This procedure is invoked by the image code whenever the manager * for an image does something that affects the size of contents * of the image displayed in a button when it is selected. * * Results: * None. * * Side effects: * May arrange for the button to get redisplayed. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static void ButtonSelectImageProc(clientData, x, y, width, height, imgWidth, imgHeight) ClientData clientData; /* Pointer to widget record. */ int x, y; /* Upper left pixel (within image) * that must be redisplayed. */ int width, height; /* Dimensions of area to redisplay * (may be <= 0). */ int imgWidth, imgHeight; /* New dimensions of image. */ { register Button *butPtr = clientData; /* * Don't recompute geometry: it's controlled by the primary image. */ if ((butPtr->flags & SELECTED) && (butPtr->tkwin != NULL) && Tk_IsMapped(butPtr->tkwin) && !(butPtr->flags & REDRAW_PENDING)) { Tcl_DoWhenIdle(DisplayButton, (ClientData)butPtr); butPtr->flags |= REDRAW_PENDING; } } int Blt_ButtonInit(interp) Tcl_Interp *interp; { static Blt_CmdSpec cmdSpecs[4] = { #if HAVE_NAMESPACES {"button", ButtonCmd,}, {"checkbutton", CheckbuttonCmd,}, {"radiobutton", RadiobuttonCmd,}, {"label", LabelCmd,}, #else {"tilebutton", ButtonCmd,}, {"tilecheckbutton", CheckbuttonCmd,}, {"tileradiobutton", RadiobuttonCmd,}, {"tilelabel", LabelCmd,}, #endif /* HAVE_NAMESPACES */ }; tkNormalUid = Tk_GetUid("normal"); tkDisabledUid = Tk_GetUid("disabled"); tkActiveUid = Tk_GetUid("active"); return Blt_InitCmds(interp, "blt::tile", cmdSpecs, 4); } #endif /* NO_TILEBUTTON */ blt-2.4z.orig/src/tkConsole.c0100644000175000017500000004231707514116170014651 0ustar dokodoko /* * tkConsole.c -- * * This file implements a Tcl console for systems that may not * otherwise have access to a console. It uses the Text widget * and provides special access via a console command. * * Copyright (c) 1995-1996 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * SCCS: @(#) tkConsole.c 1.55 98/01/02 17:40:37 */ #include "bltInt.h" /* * A data structure of the following type holds information for each console * which a handler (i.e. a Tcl command) has been defined for a particular * top-level window. */ typedef struct { Tcl_Interp *consoleInterp; /* Interpreter for the console. */ Tcl_Interp *interp; /* Interpreter to send console commands. */ } ConsoleInfo; static Tcl_Interp *gStdoutInterp = NULL; #if ((TCL_VERSION_NUMBER >= _VERSION(8,0,0)) && \ (TCL_VERSION_NUMBER < _VERSION(8,1,0))) #define HAVE_BROKEN_LIB_PATH 1 #undef HAVE_UTF #endif #if (TCL_VERSION_NUMBER >= _VERSION(8,1,1)) #define HAVE_UTF 1 extern void TclInitSubsystems _ANSI_ARGS_((CONST char *argv0)); #else #endif /* * Forward declarations for procedures defined later in this file: * * The first three will be used in the tk app shells... */ void TkConsoleCreate _ANSI_ARGS_((void)); int TkConsoleInit _ANSI_ARGS_((Tcl_Interp *interp)); void TkConsolePrint _ANSI_ARGS_((Tcl_Interp *interp, int devId, CONST char *buffer, long size)); static int ConsoleCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, char **argv)); static void ConsoleDeleteProc _ANSI_ARGS_((ClientData clientData)); static void ConsoleEventProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); static int InterpreterCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, char **argv)); static int ConsoleInput _ANSI_ARGS_((ClientData instanceData, char *buf, int toRead, int *errorCode)); static int ConsoleOutput _ANSI_ARGS_((ClientData instanceData, char *buf, int toWrite, int *errorCode)); static int ConsoleClose _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp)); static void ConsoleWatch _ANSI_ARGS_((ClientData instanceData, int mask)); static int ConsoleHandle _ANSI_ARGS_((ClientData instanceData, int direction, ClientData *handlePtr)); /* * This structure describes the channel type structure for file based IO: */ static Tcl_ChannelType consoleChannelType = { "console", /* Type name. */ NULL, /* Always non-blocking.*/ ConsoleClose, /* Close proc. */ ConsoleInput, /* Input proc. */ ConsoleOutput, /* Output proc. */ NULL, /* Seek proc. */ NULL, /* Set option proc. */ NULL, /* Get option proc. */ ConsoleWatch, /* Watch for events on console. */ ConsoleHandle, /* Get a handle from the device. */ }; /* *---------------------------------------------------------------------- * * TkConsoleCreate -- * * Create the console channels and install them as the standard * channels. All I/O will be discarded until TkConsoleInit is * called to attach the console to a text widget. * * Results: * None. * * Side effects: * Creates the console channel and installs it as the standard * channels. * *---------------------------------------------------------------------- */ void TkConsoleCreate() { Tcl_Channel consoleChannel; #ifdef HAVE_UTF TclInitSubsystems(NULL); #endif consoleChannel = Tcl_CreateChannel(&consoleChannelType, "console0", (ClientData)TCL_STDIN, TCL_READABLE); if (consoleChannel != NULL) { Tcl_SetChannelOption(NULL, consoleChannel, "-translation", "lf"); Tcl_SetChannelOption(NULL, consoleChannel, "-buffering", "none"); #ifdef HAVE_UTF Tcl_SetChannelOption(NULL, consoleChannel, "-encoding", "utf-8"); #endif } Tcl_SetStdChannel(consoleChannel, TCL_STDIN); consoleChannel = Tcl_CreateChannel(&consoleChannelType, "console1", (ClientData)TCL_STDOUT, TCL_WRITABLE); if (consoleChannel != NULL) { Tcl_SetChannelOption(NULL, consoleChannel, "-translation", "lf"); Tcl_SetChannelOption(NULL, consoleChannel, "-buffering", "none"); #ifdef HAVE_UTF Tcl_SetChannelOption(NULL, consoleChannel, "-encoding", "utf-8"); #endif } Tcl_SetStdChannel(consoleChannel, TCL_STDOUT); consoleChannel = Tcl_CreateChannel(&consoleChannelType, "console2", (ClientData)TCL_STDERR, TCL_WRITABLE); if (consoleChannel != NULL) { Tcl_SetChannelOption(NULL, consoleChannel, "-translation", "lf"); Tcl_SetChannelOption(NULL, consoleChannel, "-buffering", "none"); #ifdef HAVE_UTF Tcl_SetChannelOption(NULL, consoleChannel, "-encoding", "utf-8"); #endif } Tcl_SetStdChannel(consoleChannel, TCL_STDERR); } /* *---------------------------------------------------------------------- * * TkConsoleInit -- * * Initialize the console. This code actually creates a new * application and associated interpreter. This effectivly hides * the implementation from the main application. * * Results: * None. * * Side effects: * A new console it created. * *---------------------------------------------------------------------- */ int TkConsoleInit(interp) Tcl_Interp *interp; /* Interpreter to use for prompting. */ { Tcl_Interp *consoleInterp; ConsoleInfo *info; Tk_Window mainWindow = Tk_MainWindow(interp); #ifdef MAC_TCL static char initCmd[] = "source -rsrc {Console}"; #else static char initCmd[] = "source $tk_library/console.tcl"; #endif consoleInterp = Tcl_CreateInterp(); if (consoleInterp == NULL) { goto error; } #if defined(HAVE_BROKEN_LIB_PATH) && defined(TCLLIBPATH) Tcl_SetVar(consoleInterp, "tclDefaultLibrary", TCLLIBPATH, TCL_GLOBAL_ONLY); #endif /* * Initialized Tcl and Tk. */ if (Tcl_Init(consoleInterp) != TCL_OK) { goto error; } if (Tk_Init(consoleInterp) != TCL_OK) { goto error; } gStdoutInterp = interp; /* * Add console commands to the interp */ info = (ConsoleInfo *) Tcl_Alloc(sizeof(ConsoleInfo)); info->interp = interp; info->consoleInterp = consoleInterp; Tcl_CreateCommand(interp, "console", ConsoleCmd, (ClientData)info, (Tcl_CmdDeleteProc *)ConsoleDeleteProc); Tcl_CreateCommand(consoleInterp, "consoleinterp", InterpreterCmd, (ClientData)info, (Tcl_CmdDeleteProc *)NULL); Tk_CreateEventHandler(mainWindow, StructureNotifyMask, ConsoleEventProc, (ClientData)info); Tcl_Preserve((ClientData)consoleInterp); if (Tcl_Eval(consoleInterp, initCmd) == TCL_ERROR) { /* goto error; -- no problem for now... */ printf("Eval error: %s", consoleInterp->result); } Tcl_Release((ClientData)consoleInterp); return TCL_OK; error: if (consoleInterp != NULL) { Tcl_DeleteInterp(consoleInterp); } return TCL_ERROR; } /* *---------------------------------------------------------------------- * * ConsoleOutput-- * * Writes the given output on the IO channel. Returns count of how * many characters were actually written, and an error indication. * * Results: * A count of how many characters were written is returned and an * error indication is returned in an output argument. * * Side effects: * Writes output on the actual channel. * *---------------------------------------------------------------------- */ static int ConsoleOutput(instanceData, buf, toWrite, errorCode) ClientData instanceData; /* Indicates which device to use. */ char *buf; /* The data buffer. */ int toWrite; /* How many bytes to write? */ int *errorCode; /* Where to store error code. */ { *errorCode = 0; Tcl_SetErrno(0); if (gStdoutInterp != NULL) { TkConsolePrint(gStdoutInterp, (int)instanceData, buf, toWrite); } return toWrite; } /* *---------------------------------------------------------------------- * * ConsoleInput -- * * Read input from the console. Not currently implemented. * * Results: * Always returns EOF. * * Side effects: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int ConsoleInput(instanceData, buf, bufSize, errorCode) ClientData instanceData; /* Not Used.. */ char *buf; /* Where to store data read. */ int bufSize; /* How much space is available * in the buffer? */ int *errorCode; /* Where to store error code. */ { return 0; /* Always return EOF. */ } /* *---------------------------------------------------------------------- * * ConsoleClose -- * * Closes the IO channel. * * Results: * Always returns 0 (success). * * Side effects: * Frees the dummy file associated with the channel. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int ConsoleClose(instanceData, interp) ClientData instanceData; /* Not Used.. */ Tcl_Interp *interp; /* Not Used.. */ { return 0; } /* *---------------------------------------------------------------------- * * ConsoleWatch -- * * Called by the notifier to set up the console device so that * events will be noticed. Since there are no events on the * console, this routine just returns without doing anything. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static void ConsoleWatch(instanceData, mask) ClientData instanceData; /* Device ID for the channel. */ int mask; /* OR-ed combination of * TCL_READABLE, TCL_WRITABLE and * TCL_EXCEPTION, for the events * we are interested in. */ { } /* *---------------------------------------------------------------------- * * ConsoleHandle -- * * Invoked by the generic IO layer to get a handle from a channel. * Because console channels are not devices, this function always * fails. * * Results: * Always returns TCL_ERROR. * * Side effects: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int ConsoleHandle(instanceData, direction, handlePtr) ClientData instanceData; /* Device ID for the channel. */ int direction; /* TCL_READABLE or TCL_WRITABLE to indicate * which direction of the channel is being * requested. */ ClientData *handlePtr; /* Where to store handle */ { return TCL_ERROR; } /* *---------------------------------------------------------------------- * * ConsoleCmd -- * * The console command implements a Tcl interface to the various console * options. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int ConsoleCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { ConsoleInfo *info = (ConsoleInfo *) clientData; char c; int length; int result; Tcl_Interp *consoleInterp; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " option ?arg arg ...?\"", (char *)NULL); return TCL_ERROR; } c = argv[1][0]; length = strlen(argv[1]); result = TCL_OK; consoleInterp = info->consoleInterp; Tcl_Preserve((ClientData)consoleInterp); if ((c == 't') && (strncmp(argv[1], "title", length)) == 0) { Tcl_DString dString; Tcl_DStringInit(&dString); Tcl_DStringAppend(&dString, "wm title . ", -1); if (argc == 3) { Tcl_DStringAppendElement(&dString, argv[2]); } Tcl_Eval(consoleInterp, Tcl_DStringValue(&dString)); Tcl_DStringFree(&dString); } else if ((c == 'h') && (strncmp(argv[1], "hide", length)) == 0) { Tcl_Eval(info->consoleInterp, "wm withdraw ."); } else if ((c == 's') && (strncmp(argv[1], "show", length)) == 0) { Tcl_Eval(info->consoleInterp, "wm deiconify ."); } else if ((c == 'e') && (strncmp(argv[1], "eval", length)) == 0) { if (argc == 3) { Tcl_Eval(info->consoleInterp, argv[2]); } else { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " eval command\"", (char *)NULL); return TCL_ERROR; } } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": should be hide, show, or title", (char *)NULL); result = TCL_ERROR; } Tcl_Release((ClientData)consoleInterp); return result; } /* *---------------------------------------------------------------------- * * InterpreterCmd -- * * This command allows the console interp to communicate with the * main interpreter. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int InterpreterCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { ConsoleInfo *info = (ConsoleInfo *) clientData; char c; int length; int result; Tcl_Interp *otherInterp; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " option ?arg arg ...?\"", (char *)NULL); return TCL_ERROR; } c = argv[1][0]; length = strlen(argv[1]); otherInterp = info->interp; Tcl_Preserve((ClientData)otherInterp); if ((c == 'e') && (strncmp(argv[1], "eval", length)) == 0) { result = Tcl_GlobalEval(otherInterp, argv[2]); Tcl_AppendResult(interp, otherInterp->result, (char *)NULL); } else if ((c == 'r') && (strncmp(argv[1], "record", length)) == 0) { Tcl_RecordAndEval(otherInterp, argv[2], TCL_EVAL_GLOBAL); result = TCL_OK; Tcl_AppendResult(interp, otherInterp->result, (char *)NULL); } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": should be eval or record", (char *)NULL); result = TCL_ERROR; } Tcl_Release((ClientData)otherInterp); return result; } /* *---------------------------------------------------------------------- * * ConsoleDeleteProc -- * * If the console command is deleted we destroy the console window * and all associated data structures. * * Results: * None. * * Side effects: * A new console it created. * *---------------------------------------------------------------------- */ void ConsoleDeleteProc(clientData) ClientData clientData; { ConsoleInfo *info = (ConsoleInfo *) clientData; Tcl_DeleteInterp(info->consoleInterp); info->consoleInterp = NULL; } /* *---------------------------------------------------------------------- * * ConsoleEventProc -- * * This event procedure is registered on the main window of the * slave interpreter. If the user or a running script causes the * main window to be destroyed, then we need to inform the console * interpreter by invoking "tkConsoleExit". * * Results: * None. * * Side effects: * Invokes the "tkConsoleExit" procedure in the console interp. * *---------------------------------------------------------------------- */ static void ConsoleEventProc(clientData, eventPtr) ClientData clientData; XEvent *eventPtr; { ConsoleInfo *info = (ConsoleInfo *) clientData; Tcl_Interp *consoleInterp; if (eventPtr->type == DestroyNotify) { consoleInterp = info->consoleInterp; /* * It is possible that the console interpreter itself has * already been deleted. In that case the consoleInterp * field will be set to NULL. If the interpreter is already * gone, we do not have to do any work here. */ if (consoleInterp == (Tcl_Interp *)NULL) { return; } Tcl_Preserve((ClientData)consoleInterp); Tcl_Eval(consoleInterp, "tkConsoleExit"); Tcl_Release((ClientData)consoleInterp); } } /* *---------------------------------------------------------------------- * * TkConsolePrint -- * * Prints to the give text to the console. Given the main interp * this functions find the appropiate console interp and forwards * the text to be added to that console. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TkConsolePrint(interp, devId, buffer, size) Tcl_Interp *interp; /* Main interpreter. */ int devId; /* TCL_STDOUT for stdout, TCL_STDERR for * stderr. */ CONST char *buffer; /* Text buffer. */ long size; /* Size of text buffer. */ { Tcl_DString command, output; Tcl_CmdInfo cmdInfo; char *cmd; ConsoleInfo *info; Tcl_Interp *consoleInterp; int result; if (interp == NULL) { return; } if (devId == TCL_STDERR) { cmd = "tkConsoleOutput stderr "; } else { cmd = "tkConsoleOutput stdout "; } result = Tcl_GetCommandInfo(interp, "console", &cmdInfo); if (result == 0) { return; } info = (ConsoleInfo *) cmdInfo.clientData; Tcl_DStringInit(&output); Tcl_DStringAppend(&output, buffer, size); Tcl_DStringInit(&command); Tcl_DStringAppend(&command, cmd, strlen(cmd)); Tcl_DStringAppendElement(&command, output.string); consoleInterp = info->consoleInterp; Tcl_Preserve((ClientData)consoleInterp); Tcl_Eval(consoleInterp, command.string); Tcl_Release((ClientData)consoleInterp); Tcl_DStringFree(&command); Tcl_DStringFree(&output); } blt-2.4z.orig/src/tkFrame.c0100644000175000017500000010277407553175101014307 0ustar dokodoko/* * tkFrame.c -- * * This module implements "frame" and "toplevel" widgets for * the Tk toolkit. Frames are windows with a background color * and possibly a 3-D effect, but not much else in the way of * attributes. * * Copyright (c) 1990-1994 The Regents of the University of California. * Copyright (c) 1994-1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * SCCS: @(#) tkFrame.c 1.68 96/02/15 18:53:30 */ #include "bltInt.h" #ifndef NO_TILEFRAME #include "bltTile.h" /* * Defaults for frames: */ #define DEF_FRAME_BACKGROUND STD_NORMAL_BACKGROUND #define DEF_FRAME_BG_MONO STD_NORMAL_BG_MONO #define DEF_FRAME_BORDERWIDTH "0" #define DEF_FRAME_CLASS "Frame" #define DEF_FRAME_COLORMAP "" #define DEF_FRAME_CONTAINER "0" #define DEF_FRAME_CURSOR "" #define DEF_FRAME_HEIGHT "0" #define DEF_FRAME_HIGHLIGHT_BG STD_NORMAL_BACKGROUND #define DEF_FRAME_HIGHLIGHT RGB_BLACK #define DEF_FRAME_HIGHLIGHT_WIDTH "0" #define DEF_FRAME_RELIEF "flat" #define DEF_FRAME_TAKE_FOCUS "0" #define DEF_FRAME_USE "" #define DEF_FRAME_VISUAL "" #define DEF_FRAME_WIDTH "0" /* * Defaults for toplevels (most of the defaults for frames also apply * to toplevels): */ #define DEF_TOPLEVEL_CLASS "Toplevel" #define DEF_TOPLEVEL_SCREEN "" #define DEF_TOPLEVEL_MENU "" extern Tk_CustomOption bltTileOption; /* * A data structure of the following type is kept for each * frame that currently exists for this process: */ typedef struct { Tk_Window tkwin; /* Window that embodies the frame. NULL * means that the window has been destroyed * but the data structures haven't yet been * cleaned up. */ Display *display; /* Display containing widget. Used, among * other things, so that resources can be * freed even after tkwin has gone away. */ Tcl_Interp *interp; /* Interpreter associated with widget. Used * to delete widget command. */ Tcl_Command widgetCmd; /* Token for frame's widget command. */ char *className; /* Class name for widget (from configuration * option). Malloc-ed. */ int mask; /* Either FRAME or TOPLEVEL; used to select * which configuration options are valid for * widget. */ char *screenName; /* Screen on which widget is created. Non-null * only for top-levels. Malloc-ed, may be * NULL. */ char *visualName; /* Textual description of visual for window, * from -visual option. Malloc-ed, may be * NULL. */ char *colormapName; /* Textual description of colormap for window, * from -colormap option. Malloc-ed, may be * NULL. */ char *menuName; /* Textual description of menu to use for * menubar. Malloc-ed, may be NULL. */ Colormap colormap; /* If not None, identifies a colormap * allocated for this window, which must be * freed when the window is deleted. */ Tk_3DBorder border; /* Structure used to draw 3-D border and * background. NULL means no background * or border. */ int borderWidth; /* Width of 3-D border (if any). */ int relief; /* 3-d effect: TK_RELIEF_RAISED etc. */ int highlightWidth; /* Width in pixels of highlight to draw * around widget when it has the focus. * 0 means don't draw a highlight. */ XColor *highlightBgColorPtr; /* Color for drawing traversal highlight * area when highlight is off. */ XColor *highlightColorPtr; /* Color for drawing traversal highlight. */ int width; /* Width to request for window. <= 0 means * don't request any size. */ int height; /* Height to request for window. <= 0 means * don't request any size. */ Tk_Cursor cursor; /* Current cursor for window, or None. */ char *takeFocus; /* Value of -takefocus option; not used in * the C code, but used by keyboard traversal * scripts. Malloc'ed, but may be NULL. */ int isContainer; /* 1 means this window is a container, 0 means * that it isn't. */ char *useThis; /* If the window is embedded, this points to * the name of the window in which it is * embedded (malloc'ed). For non-embedded * windows this is NULL. */ int flags; /* Various flags; see below for * definitions. */ Blt_Tile tile; } Frame; /* * Flag bits for frames: * * REDRAW_PENDING: Non-zero means a DoWhenIdle handler * has already been queued to redraw * this window. * GOT_FOCUS: Non-zero means this widget currently * has the input focus. */ #define REDRAW_PENDING 1 #define GOT_FOCUS 4 /* * The following flag bits are used so that there can be separate * defaults for some configuration options for frames and toplevels. */ #define FRAME TK_CONFIG_USER_BIT #define TOPLEVEL (TK_CONFIG_USER_BIT << 1) #define BOTH (FRAME | TOPLEVEL) static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_FRAME_BACKGROUND, Tk_Offset(Frame, border), BOTH | TK_CONFIG_COLOR_ONLY | TK_CONFIG_NULL_OK}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_FRAME_BG_MONO, Tk_Offset(Frame, border), BOTH | TK_CONFIG_MONO_ONLY | TK_CONFIG_NULL_OK}, {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, BOTH}, {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, BOTH}, {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", DEF_FRAME_BORDERWIDTH, Tk_Offset(Frame, borderWidth), BOTH}, {TK_CONFIG_STRING, "-class", "class", "Class", DEF_FRAME_CLASS, Tk_Offset(Frame, className), FRAME}, {TK_CONFIG_STRING, "-class", "class", "Class", DEF_TOPLEVEL_CLASS, Tk_Offset(Frame, className), TOPLEVEL}, {TK_CONFIG_STRING, "-colormap", "colormap", "Colormap", DEF_FRAME_COLORMAP, Tk_Offset(Frame, colormapName), BOTH | TK_CONFIG_NULL_OK}, #if (TK_MAJOR_VERSION > 4) {TK_CONFIG_BOOLEAN, "-container", "container", "Container", DEF_FRAME_CONTAINER, Tk_Offset(Frame, isContainer), BOTH}, #endif /* TK_MAJOR_VERSION > 4 */ {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", DEF_FRAME_CURSOR, Tk_Offset(Frame, cursor), BOTH | TK_CONFIG_NULL_OK}, {TK_CONFIG_PIXELS, "-height", "height", "Height", DEF_FRAME_HEIGHT, Tk_Offset(Frame, height), BOTH}, {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", "HighlightBackground", DEF_FRAME_HIGHLIGHT_BG, Tk_Offset(Frame, highlightBgColorPtr), BOTH}, {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", DEF_FRAME_HIGHLIGHT, Tk_Offset(Frame, highlightColorPtr), BOTH}, {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", "HighlightThickness", DEF_FRAME_HIGHLIGHT_WIDTH, Tk_Offset(Frame, highlightWidth), BOTH}, #if (TK_MAJOR_VERSION > 4) {TK_CONFIG_STRING, "-menu", "menu", "Menu", DEF_TOPLEVEL_MENU, Tk_Offset(Frame, menuName), TOPLEVEL | TK_CONFIG_NULL_OK}, #endif /* TK_MAJOR_VERSION > 4 */ {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_FRAME_RELIEF, Tk_Offset(Frame, relief), BOTH}, {TK_CONFIG_STRING, "-screen", "screen", "Screen", DEF_TOPLEVEL_SCREEN, Tk_Offset(Frame, screenName), TOPLEVEL | TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", DEF_FRAME_TAKE_FOCUS, Tk_Offset(Frame, takeFocus), BOTH | TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-tile", "tile", "Tile", (char *)NULL, Tk_Offset(Frame, tile), BOTH | TK_CONFIG_NULL_OK, &bltTileOption}, #if (TK_MAJOR_VERSION > 4) {TK_CONFIG_STRING, "-use", "use", "Use", DEF_FRAME_USE, Tk_Offset(Frame, useThis), TOPLEVEL|TK_CONFIG_NULL_OK}, #endif {TK_CONFIG_STRING, "-visual", "visual", "Visual", DEF_FRAME_VISUAL, Tk_Offset(Frame, visualName), BOTH | TK_CONFIG_NULL_OK}, {TK_CONFIG_PIXELS, "-width", "width", "Width", DEF_FRAME_WIDTH, Tk_Offset(Frame, width), BOTH}, {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; /* * Forward declarations for procedures defined later in this file: */ static int ConfigureFrame _ANSI_ARGS_((Tcl_Interp *interp, Frame * framePtr, int argc, char **argv, int flags)); static void DestroyFrame _ANSI_ARGS_((DestroyData *memPtr)); static void DisplayFrame _ANSI_ARGS_((ClientData clientData)); static void FrameCmdDeletedProc _ANSI_ARGS_(( ClientData clientData)); static void FrameEventProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); static int FrameWidgetCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, char **argv)); static void MapFrame _ANSI_ARGS_((ClientData clientData)); static Blt_TileChangedProc TileChangedProc; static Tcl_CmdProc FrameCmd, ToplevelCmd; #ifdef TILE_MAINWINDOW EXTERN #else static #endif int TkCreateFrame _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, char **argv, int toplevel, char *appName)); EXTERN void TkSetWindowMenuBar _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, char *oldMenuName, char *menuName)); EXTERN Tk_Window TkCreateMainWindow _ANSI_ARGS_((Tcl_Interp * interp, char * screenName, char * baseName)); #if (TK_MAJOR_VERSION == 8) && (TK_MINOR_VERSION > 3) #define TkSetClassProcs Tk_SetClassProcs #else EXTERN void TkSetClassProcs _ANSI_ARGS_((Tk_Window tkwin, void *procs, ClientData instanceData)); #endif /* TK_MAJOR_VERSION == 8 && TK_MINOR_VERSION > 3 */ EXTERN void TkpSetMainMenubar _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, char * menuName)); EXTERN int TkpUseWindow _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, char * string)); EXTERN void TkpMakeContainer _ANSI_ARGS_((Tk_Window tkwin)); /* *-------------------------------------------------------------- * * FrameCmd, ToplevelCmd -- * * These procedures are invoked to process the "frame" and * "toplevel" Tcl commands. See the user documentation for * details on what they do. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. These procedures are just wrappers; * they call ButtonCreate to do all of the real work. * *-------------------------------------------------------------- */ static int FrameCmd(clientData, interp, argc, argv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { return TkCreateFrame(clientData, interp, argc, argv, 0, (char *)NULL); } static int ToplevelCmd(clientData, interp, argc, argv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { return TkCreateFrame(clientData, interp, argc, argv, 1, (char *)NULL); } /* *-------------------------------------------------------------- * * TkFrameCreate -- * * This procedure is invoked to process the "frame" and "toplevel" * Tcl commands; it is also invoked directly by Tk_Init to create * a new main window. See the user documentation for the "frame" * and "toplevel" commands for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ /*ARGSUSED*/ #ifndef TILE_MAINWINDOW static #endif /* TILE_MAINWINDOW */ int TkCreateFrame(clientData, interp, argc, argv, toplevel, appName) ClientData clientData; /* Main window associated with interpreter. * If we're called by Tk_Init to create a * new application, then this is NULL. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ int toplevel; /* Non-zero means create a toplevel window, * zero means create a frame. */ char *appName; /* Should only be non-NULL if clientData is * NULL: gives the base name to use for the * new application. */ { Frame *framePtr; Tk_Window new; char *className, *screenName, *visualName, *colormapName, *arg, *useOption; int i, c, length, depth; unsigned int mask; Colormap colormap; Visual *visual; Tk_Window tkwin; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " pathName ?options?\"", (char *)NULL); return TCL_ERROR; } /* * Pre-process the argument list. Scan through it to find any * "-class", "-screen", "-visual", and "-colormap" options. These * arguments need to be processed specially, before the window * is configured using the usual Tk mechanisms. */ className = colormapName = screenName = visualName = useOption = NULL; colormap = None; for (i = 2; i < argc; i += 2) { arg = argv[i]; length = strlen(arg); if (length < 2) { continue; } c = arg[1]; if ((c == 'c') && (strncmp(arg, "-class", strlen(arg)) == 0) && (length >= 3)) { className = argv[i + 1]; } else if ((c == 'c') && (strncmp(arg, "-colormap", strlen(arg)) == 0)) { colormapName = argv[i + 1]; } else if ((c == 's') && toplevel && (strncmp(arg, "-screen", strlen(arg)) == 0)) { screenName = argv[i + 1]; } else if ((c == 'u') && toplevel && (strncmp(arg, "-use", strlen(arg)) == 0)) { useOption = argv[i + 1]; } else if ((c == 'v') && (strncmp(arg, "-visual", strlen(arg)) == 0)) { visualName = argv[i + 1]; } } /* * Create the window, and deal with the special options -use, * -classname, -colormap, -screenname, and -visual. These options * must be handle before calling ConfigureFrame below, and they must * also be processed in a particular order, for the following * reasons: * 1. Must set the window's class before calling ConfigureFrame, * so that unspecified options are looked up in the option * database using the correct class. * 2. Must set visual information before calling ConfigureFrame * so that colors are allocated in a proper colormap. * 3. Must call TkpUseWindow before setting non-default visual * information, since TkpUseWindow changes the defaults. */ if (screenName == NULL) { screenName = (toplevel) ? "" : NULL; } tkwin = Tk_MainWindow(interp); if (tkwin != NULL) { new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], screenName); } else { /* * We were called from Tk_Init; create a new application. */ if (appName == NULL) { panic("TkCreateFrame didn't get application name"); } new = (Tk_Window)TkCreateMainWindow(interp, screenName, appName); } if (new == NULL) { goto error; } if (className == NULL) { className = (char *)Tk_GetOption(new, "class", "Class"); if (className == NULL) { className = (toplevel) ? "Toplevel" : "Frame"; } } Tk_SetClass(new, className); #if (TK_MAJOR_VERSION > 4) if (useOption == NULL) { useOption = (char *)Tk_GetOption(new, "use", "Use"); } if (useOption != NULL) { if (TkpUseWindow(interp, new, useOption) != TCL_OK) { goto error; } } #endif if (visualName == NULL) { visualName = (char *)Tk_GetOption(new, "visual", "Visual"); } if (colormapName == NULL) { colormapName = (char *)Tk_GetOption(new, "colormap", "Colormap"); } if (visualName != NULL) { visual = Tk_GetVisual(interp, new, visualName, &depth, (colormapName == NULL) ? &colormap : (Colormap *) NULL); if (visual == NULL) { goto error; } Tk_SetWindowVisual(new, visual, depth, colormap); } if (colormapName != NULL) { colormap = Tk_GetColormap(interp, new, colormapName); if (colormap == None) { goto error; } Tk_SetWindowColormap(new, colormap); } /* * For top-level windows, provide an initial geometry request of * 200x200, just so the window looks nicer on the screen if it * doesn't request a size for itself. */ if (toplevel) { Tk_GeometryRequest(new, 200, 200); } /* * Create the widget record, process configuration options, and * create event handlers. Then fill in a few additional fields * in the widget record from the special options. */ framePtr = Blt_Malloc(sizeof(Frame)); framePtr->tkwin = new; framePtr->display = Tk_Display(new); framePtr->interp = interp; framePtr->widgetCmd = Tcl_CreateCommand(interp, Tk_PathName(new), FrameWidgetCmd, (ClientData)framePtr, FrameCmdDeletedProc); framePtr->className = NULL; framePtr->mask = (toplevel) ? TOPLEVEL : FRAME; framePtr->screenName = NULL; framePtr->visualName = NULL; framePtr->colormapName = NULL; framePtr->colormap = colormap; framePtr->border = NULL; framePtr->borderWidth = 0; framePtr->relief = TK_RELIEF_FLAT; framePtr->highlightWidth = 0; framePtr->highlightBgColorPtr = NULL; framePtr->highlightColorPtr = NULL; framePtr->width = 0; framePtr->height = 0; framePtr->cursor = None; framePtr->takeFocus = NULL; framePtr->isContainer = 0; framePtr->useThis = NULL; framePtr->flags = 0; framePtr->tile = NULL; framePtr->menuName = NULL; #if (TK_MAJOR_VERSION > 4) /* * Store backreference to frame widget in window structure. */ TkSetClassProcs(new, NULL, (ClientData)framePtr); #endif mask = ExposureMask | StructureNotifyMask | FocusChangeMask; if (toplevel) { mask |= ActivateMask; } Tk_CreateEventHandler(new, mask, FrameEventProc, (ClientData)framePtr); if (ConfigureFrame(interp, framePtr, argc - 2, argv + 2, 0) != TCL_OK) { goto error; } #if (TK_MAJOR_VERSION > 4) if ((framePtr->isContainer)) { if (framePtr->useThis == NULL) { TkpMakeContainer(framePtr->tkwin); } else { Tcl_AppendResult(interp, "A window cannot have both the -use ", "and the -container option set.", (char *)NULL); return TCL_ERROR; } } #endif if (toplevel) { Tcl_DoWhenIdle(MapFrame, (ClientData)framePtr); } Tcl_SetResult(interp, Tk_PathName(new), TCL_VOLATILE); return TCL_OK; error: if (new != NULL) { Tk_DestroyWindow(new); } return TCL_ERROR; } /* *-------------------------------------------------------------- * * FrameWidgetCmd -- * * This procedure is invoked to process the Tcl command * that corresponds to a frame widget. See the user * documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ static int FrameWidgetCmd(clientData, interp, argc, argv) ClientData clientData; /* Information about frame widget. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { register Frame *framePtr = (Frame *) clientData; int result; size_t length; int c, i; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " option ?arg arg ...?\"", (char *)NULL); return TCL_ERROR; } Tcl_Preserve((ClientData)framePtr); c = argv[1][0]; length = strlen(argv[1]); if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) && (length >= 2)) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " cget option\"", (char *)NULL); result = TCL_ERROR; goto done; } result = Tk_ConfigureValue(interp, framePtr->tkwin, configSpecs, (char *)framePtr, argv[2], framePtr->mask); } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) && (length >= 2)) { if (argc == 2) { result = Tk_ConfigureInfo(interp, framePtr->tkwin, configSpecs, (char *)framePtr, (char *)NULL, framePtr->mask); } else if (argc == 3) { result = Tk_ConfigureInfo(interp, framePtr->tkwin, configSpecs, (char *)framePtr, argv[2], framePtr->mask); } else { /* * Don't allow the options -class, -colormap, -container, * -newcmap, -screen, -use, or -visual to be changed. */ for (i = 2; i < argc; i++) { length = strlen(argv[i]); if (length < 2) { continue; } c = argv[i][1]; if (((c == 'c') && (strncmp(argv[i], "-class", length) == 0) && (length >= 2)) || ((c == 'c') && (framePtr->mask == TOPLEVEL) && (strncmp(argv[i], "-colormap", length) == 0) && (length >= 3)) || ((c == 'c') && (strncmp(argv[i], "-container", length) == 0) && (length >= 3)) || ((c == 's') && (framePtr->mask == TOPLEVEL) && (strncmp(argv[i], "-screen", length) == 0)) || ((c == 'u') && (framePtr->mask == TOPLEVEL) && (strncmp(argv[i], "-use", length) == 0)) || ((c == 'v') && (framePtr->mask == TOPLEVEL) && (strncmp(argv[i], "-visual", length) == 0))) { Tcl_AppendResult(interp, "can't modify ", argv[i], " option after widget is created", (char *)NULL); result = TCL_ERROR; goto done; } } result = ConfigureFrame(interp, framePtr, argc - 2, argv + 2, TK_CONFIG_ARGV_ONLY); } } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": must be cget or configure", (char *)NULL); result = TCL_ERROR; } done: Tcl_Release((ClientData)framePtr); return result; } /* *---------------------------------------------------------------------- * * DestroyFrame -- * * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release * to clean up the internal structure of a frame at a safe time * (when no-one is using it anymore). * * Results: * None. * * Side effects: * Everything associated with the frame is freed up. * *---------------------------------------------------------------------- */ static void DestroyFrame(memPtr) DestroyData *memPtr; /* Info about frame widget. */ { register Frame *framePtr = (Frame *) memPtr; Tk_FreeOptions(configSpecs, (char *)framePtr, framePtr->display, framePtr->mask); if (framePtr->tile != NULL) { Blt_FreeTile(framePtr->tile); } if (framePtr->colormap != None) { Tk_FreeColormap(framePtr->display, framePtr->colormap); } Blt_Free(framePtr); } /* *---------------------------------------------------------------------- * * TileChangedProc * * Results: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static void TileChangedProc(clientData, tile) ClientData clientData; Blt_Tile tile; { Frame *framePtr = (Frame *) clientData; if (framePtr->tkwin != NULL) { if (!(framePtr->flags & REDRAW_PENDING)) { Tcl_DoWhenIdle(DisplayFrame, (ClientData)framePtr); framePtr->flags |= REDRAW_PENDING; } } } /* *---------------------------------------------------------------------- * * ConfigureFrame -- * * This procedure is called to process an argv/argc list, plus * the Tk option database, in order to configure (or * reconfigure) a frame widget. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then interp->result contains an error message. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for framePtr; old resources get freed, if there * were any. * *---------------------------------------------------------------------- */ static int ConfigureFrame(interp, framePtr, argc, argv, flags) Tcl_Interp *interp; /* Used for error reporting. */ register Frame *framePtr; /* Information about widget; may or may * not already have values for some fields. */ int argc; /* Number of valid entries in argv. */ char **argv; /* Arguments. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { #if (TK_MAJOR_VERSION > 4) char *oldMenuName; /* * Need the old menubar name for the menu code to delete it. */ if (framePtr->menuName == NULL) { oldMenuName = NULL; } else { oldMenuName = Blt_Malloc(strlen(framePtr->menuName) + 1); strcpy(oldMenuName, framePtr->menuName); } #endif /* TK_MAJOR_VERSION > 4 */ if (Tk_ConfigureWidget(interp, framePtr->tkwin, configSpecs, argc, argv, (char *)framePtr, flags | framePtr->mask) != TCL_OK) { return TCL_ERROR; } if (framePtr->tile != NULL) { Blt_SetTileChangedProc(framePtr->tile, TileChangedProc, (ClientData)framePtr); } #if (TK_MAJOR_VERSION > 4) if (((oldMenuName == NULL) && (framePtr->menuName != NULL)) || ((oldMenuName != NULL) && (framePtr->menuName == NULL)) || ((oldMenuName != NULL) && (framePtr->menuName != NULL) && strcmp(oldMenuName, framePtr->menuName) != 0)) { TkSetWindowMenuBar(interp, framePtr->tkwin, oldMenuName, framePtr->menuName); } #endif /* TK_MAJOR_VERSION > 4 */ if (framePtr->border != NULL) { Tk_SetBackgroundFromBorder(framePtr->tkwin, framePtr->border); } else { Tk_SetWindowBackgroundPixmap(framePtr->tkwin, None); } if (framePtr->highlightWidth < 0) { framePtr->highlightWidth = 0; } Tk_SetInternalBorder(framePtr->tkwin, framePtr->borderWidth + framePtr->highlightWidth); if ((framePtr->width > 0) || (framePtr->height > 0)) { Tk_GeometryRequest(framePtr->tkwin, framePtr->width, framePtr->height); } #if (TK_MAJOR_VERSION > 4) if (oldMenuName != NULL) { Blt_Free(oldMenuName); } #endif /* TK_MAJOR_VERSION > 4 */ if (Tk_IsMapped(framePtr->tkwin)) { if (!(framePtr->flags & REDRAW_PENDING)) { Tcl_DoWhenIdle(DisplayFrame, (ClientData)framePtr); } framePtr->flags |= REDRAW_PENDING; } return TCL_OK; } /* *---------------------------------------------------------------------- * * DisplayFrame -- * * This procedure is invoked to display a frame widget. * * Results: * None. * * Side effects: * Commands are output to X to display the frame in its * current mode. * *---------------------------------------------------------------------- */ static void DisplayFrame(clientData) ClientData clientData; /* Information about widget. */ { register Frame *framePtr = (Frame *) clientData; register Tk_Window tkwin = framePtr->tkwin; GC gc; framePtr->flags &= ~REDRAW_PENDING; if ((framePtr->tkwin == NULL) || !Tk_IsMapped(tkwin) || framePtr->isContainer) { return; } if (framePtr->tile == NULL) { Blt_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), framePtr->border, framePtr->highlightWidth, framePtr->highlightWidth, Tk_Width(tkwin) - 2 * framePtr->highlightWidth, Tk_Height(tkwin) - 2 * framePtr->highlightWidth, framePtr->borderWidth, framePtr->relief); } else { Blt_SetTileOrigin(tkwin, framePtr->tile, 0, 0); Blt_TileRectangle(tkwin, Tk_WindowId(tkwin), framePtr->tile, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin)); if ((framePtr->border != NULL) && (framePtr->relief != TK_RELIEF_FLAT)) { Blt_Draw3DRectangle(tkwin, Tk_WindowId(tkwin), framePtr->border, framePtr->highlightWidth, framePtr->highlightWidth, Tk_Width(tkwin) - 2 * framePtr->highlightWidth, Tk_Height(tkwin) - 2 * framePtr->highlightWidth, framePtr->borderWidth, framePtr->relief); } } if (framePtr->highlightWidth != 0) { if (framePtr->flags & GOT_FOCUS) { gc = Tk_GCForColor(framePtr->highlightColorPtr, Tk_WindowId(tkwin)); } else { gc = Tk_GCForColor(framePtr->highlightBgColorPtr, Tk_WindowId(tkwin)); } Tk_DrawFocusHighlight(tkwin, gc, framePtr->highlightWidth, Tk_WindowId(tkwin)); } } /* *-------------------------------------------------------------- * * FrameEventProc -- * * This procedure is invoked by the Tk dispatcher on * structure changes to a frame. For frames with 3D * borders, this procedure is also invoked for exposures. * * Results: * None. * * Side effects: * When the window gets deleted, internal structures get * cleaned up. When it gets exposed, it is redisplayed. * *-------------------------------------------------------------- */ static void FrameEventProc(clientData, eventPtr) ClientData clientData; /* Information about window. */ register XEvent *eventPtr; /* Information about event. */ { register Frame *framePtr = (Frame *) clientData; if (((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) || (eventPtr->type == ConfigureNotify)) { goto redraw; } else if (eventPtr->type == DestroyNotify) { #if (TK_MAJOR_VERSION > 4) if (framePtr->menuName != NULL) { TkSetWindowMenuBar(framePtr->interp, framePtr->tkwin, framePtr->menuName, NULL); Blt_Free(framePtr->menuName); framePtr->menuName = NULL; } #endif /* TK_MAJOR_VERSION > 4 */ if (framePtr->tkwin != NULL) { /* * If this window is a container, then this event could be * coming from the embedded application, in which case * Tk_DestroyWindow hasn't been called yet. When Tk_DestroyWindow * is called later, then another destroy event will be generated. * We need to be sure we ignore the second event, since the frame * could be gone by then. To do so, delete the event handler * explicitly (normally it's done implicitly by Tk_DestroyWindow). */ Tk_DeleteEventHandler(framePtr->tkwin, ExposureMask | StructureNotifyMask | FocusChangeMask, FrameEventProc, (ClientData)framePtr); framePtr->tkwin = NULL; Tcl_DeleteCommandFromToken(framePtr->interp, framePtr->widgetCmd); } if (framePtr->flags & REDRAW_PENDING) { Tcl_CancelIdleCall(DisplayFrame, (ClientData)framePtr); } Tcl_CancelIdleCall(MapFrame, (ClientData)framePtr); Tcl_EventuallyFree((ClientData)framePtr, (Tcl_FreeProc *)DestroyFrame); } else if (eventPtr->type == FocusIn) { if (eventPtr->xfocus.detail != NotifyInferior) { framePtr->flags |= GOT_FOCUS; if (framePtr->highlightWidth > 0) { goto redraw; } } } else if (eventPtr->type == FocusOut) { if (eventPtr->xfocus.detail != NotifyInferior) { framePtr->flags &= ~GOT_FOCUS; if (framePtr->highlightWidth > 0) { goto redraw; } } #if (TK_MAJOR_VERSION > 4) } else if (eventPtr->type == ActivateNotify) { TkpSetMainMenubar(framePtr->interp, framePtr->tkwin, framePtr->menuName); #endif /* TK_MAJOR_VERSION > 4 */ } return; redraw: if ((framePtr->tkwin != NULL) && !(framePtr->flags & REDRAW_PENDING)) { Tcl_DoWhenIdle(DisplayFrame, (ClientData)framePtr); framePtr->flags |= REDRAW_PENDING; } } /* *---------------------------------------------------------------------- * * FrameCmdDeletedProc -- * * This procedure is invoked when a widget command is deleted. If * the widget isn't already in the process of being destroyed, * this command destroys it. * * Results: * None. * * Side effects: * The widget is destroyed. * *---------------------------------------------------------------------- */ static void FrameCmdDeletedProc(clientData) ClientData clientData; /* Pointer to widget record for widget. */ { Frame *framePtr = (Frame *) clientData; Tk_Window tkwin = framePtr->tkwin; #if (TK_MAJOR_VERSION > 4) if (framePtr->menuName != NULL) { TkSetWindowMenuBar(framePtr->interp, framePtr->tkwin, framePtr->menuName, NULL); Blt_Free(framePtr->menuName); framePtr->menuName = NULL; } #endif /* TK_MAJOR_VERSION > 4 */ /* * This procedure could be invoked either because the window was * destroyed and the command was then deleted (in which case tkwin * is NULL) or because the command was deleted, and then this procedure * destroys the widget. */ if (tkwin != NULL) { framePtr->tkwin = NULL; Tk_DestroyWindow(tkwin); } } /* *---------------------------------------------------------------------- * * MapFrame -- * * This procedure is invoked as a when-idle handler to map a * newly-created top-level frame. * * Results: * None. * * Side effects: * The frame given by the clientData argument is mapped. * *---------------------------------------------------------------------- */ static void MapFrame(clientData) ClientData clientData; /* Pointer to frame structure. */ { Frame *framePtr = (Frame *) clientData; /* * Wait for all other background events to be processed before * mapping window. This ensures that the window's correct geometry * will have been determined before it is first mapped, so that the * window manager doesn't get a false idea of its desired geometry. */ Tcl_Preserve((ClientData)framePtr); for(;;) { if (Tcl_DoOneEvent(TCL_IDLE_EVENTS) == 0) { break; } /* * After each event, make sure that the window still exists * and quit if the window has been destroyed. */ if (framePtr->tkwin == NULL) { Tcl_Release((ClientData)framePtr); return; } } Tk_MapWindow(framePtr->tkwin); Tcl_Release((ClientData)framePtr); } /* *-------------------------------------------------------------- * * TkInstallFrameMenu -- * * This function is needed when a Windows HWND is created * and a menubar has been set to the window with a system * menu. It notifies the menu package so that the system * menu can be rebuilt. * * Results: * None. * * Side effects: * The system menu (if any) is created for the menubar * associated with this frame. * *-------------------------------------------------------------- */ #ifdef notdef void TkInstallFrameMenu(tkwin) Tk_Window tkwin; /* The window that was just created. */ { #if (TK_MAJOR_VERSION > 4) #define Tk_InstanceData(tkwin) (((Tk_FakeWin *)(tkwin))->dummy18) #define Tk_MainPtr(tkwin) (((Tk_FakeWin *)(tkwin))->dummy5) if (Tk_MainPtr(tkwin) != NULL) { Frame *framePtr; framePtr = (Frame *) Tk_InstanceData(tkwin); TkpMenuNotifyToplevelCreate(framePtr->interp, framePtr->menuName); } #endif /* TK_MAJOR_VERSION > 4 */ } #endif int Blt_FrameInit(interp) Tcl_Interp *interp; { static Blt_CmdSpec cmdSpecs[2] = { #if HAVE_NAMESPACES {"frame", FrameCmd,}, {"toplevel", ToplevelCmd,}, #else {"tileframe", FrameCmd,}, {"tiletoplevel", ToplevelCmd,}, #endif /* HAVE_NAMESPACES */ }; return Blt_InitCmds(interp, "blt::tile", cmdSpecs, 2); } #endif /* NO_TILEFRAME */ blt-2.4z.orig/src/tkMenubutton.c0100644000175000017500000011556207471015210015405 0ustar dokodoko/* * tkMenubutton.c -- * * This module implements button-like widgets that are used * to invoke pull-down menus. * * Copyright (c) 1990-1994 The Regents of the University of California. * Copyright (c) 1994-1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * SCCS: @(#) tkMenubutton.c 1.77 96/02/15 18:52:22 */ #include "tkPort.h" #include "default.h" #include "tkInt.h" /* * A data structure of the following type is kept for each * widget managed by this file: */ typedef struct { Tk_Window tkwin; /* Window that embodies the widget. NULL * means that the window has been destroyed * but the data structures haven't yet been * cleaned up.*/ Display *display; /* Display containing widget. Needed, among * other things, so that resources can bee * freed up even after tkwin has gone away. */ Tcl_Interp *interp; /* Interpreter associated with menubutton. */ Tcl_Command widgetCmd; /* Token for menubutton's widget command. */ char *menuName; /* Name of menu associated with widget. * Malloc-ed. */ /* * Information about what's displayed in the menu button: */ char *text; /* Text to display in button (malloc'ed) * or NULL. */ int numChars; /* # of characters in text. */ int underline; /* Index of character to underline. */ char *textVarName; /* Name of variable (malloc'ed) or NULL. * If non-NULL, button displays the contents * of this variable. */ Pixmap bitmap; /* Bitmap to display or None. If not None * then text and textVar and underline * are ignored. */ char *imageString; /* Name of image to display (malloc'ed), or * NULL. If non-NULL, bitmap, text, and * textVarName are ignored. */ Tk_Image image; /* Image to display in window, or NULL if * none. */ /* * Information used when displaying widget: */ Tk_Uid state; /* State of button for display purposes: * normal, active, or disabled. */ Tk_3DBorder normalBorder; /* Structure used to draw 3-D * border and background when window * isn't active. NULL means no such * border exists. */ Tk_3DBorder activeBorder; /* Structure used to draw 3-D * border and background when window * is active. NULL means no such * border exists. */ int borderWidth; /* Width of border. */ int relief; /* 3-d effect: TK_RELIEF_RAISED, etc. */ int highlightWidth; /* Width in pixels of highlight to draw * around widget when it has the focus. * <= 0 means don't draw a highlight. */ XColor *highlightBgColorPtr; /* Color for drawing traversal highlight * area when highlight is off. */ XColor *highlightColorPtr; /* Color for drawing traversal highlight. */ int inset; /* Total width of all borders, including * traversal highlight and 3-D border. * Indicates how much interior stuff must * be offset from outside edges to leave * room for borders. */ XFontStruct *fontPtr; /* Information about text font, or NULL. */ XColor *normalFg; /* Foreground color in normal mode. */ XColor *activeFg; /* Foreground color in active mode. NULL * means use normalFg instead. */ XColor *disabledFg; /* Foreground color when disabled. NULL * means use normalFg with a 50% stipple * instead. */ GC normalTextGC; /* GC for drawing text in normal mode. */ GC activeTextGC; /* GC for drawing text in active mode (NULL * means use normalTextGC). */ Pixmap gray; /* Pixmap for displaying disabled text/icon if * disabledFg is NULL. */ GC disabledGC; /* Used to produce disabled effect. If * disabledFg isn't NULL, this GC is used to * draw button text or icon. Otherwise * text or icon is drawn with normalGC and * this GC is used to stipple background * across it. */ int leftBearing; /* Distance from text origin to leftmost drawn * pixel (positive means to right). */ int rightBearing; /* Amount text sticks right from its origin. */ char *widthString; /* Value of -width option. Malloc'ed. */ char *heightString; /* Value of -height option. Malloc'ed. */ int width, height; /* If > 0, these specify dimensions to request * for window, in characters for text and in * pixels for bitmaps. In this case the actual * size of the text string or bitmap is * ignored in computing desired window size. */ int wrapLength; /* Line length (in pixels) at which to wrap * onto next line. <= 0 means don't wrap * except at newlines. */ int padX, padY; /* Extra space around text or bitmap (pixels * on each side). */ Tk_Anchor anchor; /* Where text/bitmap should be displayed * inside window region. */ Tk_Justify justify; /* Justification to use for multi-line text. */ int textWidth; /* Width needed to display text as requested, * in pixels. */ int textHeight; /* Height needed to display text as requested, * in pixels. */ int indicatorOn; /* Non-zero means display indicator; 0 means * don't display. */ int indicatorHeight; /* Height of indicator in pixels. This same * amount of extra space is also left on each * side of the indicator. 0 if no indicator. */ int indicatorWidth; /* Width of indicator in pixels, including * indicatorHeight in padding on each side. * 0 if no indicator. */ /* * Miscellaneous information: */ Tk_Cursor cursor; /* Current cursor for window, or None. */ char *takeFocus; /* Value of -takefocus option; not used in * the C code, but used by keyboard traversal * scripts. Malloc'ed, but may be NULL. */ int flags; /* Various flags; see below for * definitions. */ } MenuButton; /* * Flag bits for buttons: * * REDRAW_PENDING: Non-zero means a DoWhenIdle handler * has already been queued to redraw * this window. * POSTED: Non-zero means that the menu associated * with this button has been posted (typically * because of an active button press). * GOT_FOCUS: Non-zero means this button currently * has the input focus. */ #define REDRAW_PENDING 1 #define POSTED 2 #define GOT_FOCUS 4 /* * The following constants define the dimensions of the cascade indicator, * which is displayed if the "-indicatoron" option is true. The units for * these options are 1/10 millimeters. */ #define INDICATOR_WIDTH 40 #define INDICATOR_HEIGHT 17 /* * Information used for parsing configuration specs: */ static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", DEF_MENUBUTTON_ACTIVE_BACKGROUND, Tk_Offset(MenuButton, activeBorder), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", DEF_MENUBUTTON_ACTIVE_BG_MONO, Tk_Offset(MenuButton, activeBorder), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background", DEF_MENUBUTTON_ACTIVE_FOREGROUND, Tk_Offset(MenuButton, activeFg), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background", DEF_MENUBUTTON_ACTIVE_FG_MONO, Tk_Offset(MenuButton, activeFg), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", DEF_MENUBUTTON_ANCHOR, Tk_Offset(MenuButton, anchor), 0}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_MENUBUTTON_BACKGROUND, Tk_Offset(MenuButton, normalBorder), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_MENUBUTTON_BG_MONO, Tk_Offset(MenuButton, normalBorder), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_BITMAP, "-bitmap", "bitmap", "Bitmap", DEF_MENUBUTTON_BITMAP, Tk_Offset(MenuButton, bitmap), TK_CONFIG_NULL_OK}, {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", DEF_MENUBUTTON_BORDERWIDTH, Tk_Offset(MenuButton, borderWidth), 0}, {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", DEF_MENUBUTTON_CURSOR, Tk_Offset(MenuButton, cursor), TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground", "DisabledForeground", DEF_MENUBUTTON_DISABLED_FOREGROUND, Tk_Offset(MenuButton, disabledFg), TK_CONFIG_COLOR_ONLY | TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground", "DisabledForeground", DEF_MENUBUTTON_DISABLED_FG_MONO, Tk_Offset(MenuButton, disabledFg), TK_CONFIG_MONO_ONLY | TK_CONFIG_NULL_OK}, {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_FONT, "-font", "font", "Font", DEF_MENUBUTTON_FONT, Tk_Offset(MenuButton, fontPtr), 0}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_MENUBUTTON_FG, Tk_Offset(MenuButton, normalFg), 0}, {TK_CONFIG_STRING, "-height", "height", "Height", DEF_MENUBUTTON_HEIGHT, Tk_Offset(MenuButton, heightString), 0}, {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", "HighlightBackground", DEF_MENUBUTTON_HIGHLIGHT_BG, Tk_Offset(MenuButton, highlightBgColorPtr), 0}, {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", DEF_MENUBUTTON_HIGHLIGHT, Tk_Offset(MenuButton, highlightColorPtr), 0}, {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", "HighlightThickness", DEF_MENUBUTTON_HIGHLIGHT_WIDTH, Tk_Offset(MenuButton, highlightWidth), 0}, {TK_CONFIG_STRING, "-image", "image", "Image", DEF_MENUBUTTON_IMAGE, Tk_Offset(MenuButton, imageString), TK_CONFIG_NULL_OK}, {TK_CONFIG_BOOLEAN, "-indicatoron", "indicatorOn", "IndicatorOn", DEF_MENUBUTTON_INDICATOR, Tk_Offset(MenuButton, indicatorOn), 0}, {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify", DEF_MENUBUTTON_JUSTIFY, Tk_Offset(MenuButton, justify), 0}, {TK_CONFIG_STRING, "-menu", "menu", "Menu", DEF_MENUBUTTON_MENU, Tk_Offset(MenuButton, menuName), TK_CONFIG_NULL_OK}, {TK_CONFIG_PIXELS, "-padx", "padX", "Pad", DEF_MENUBUTTON_PADX, Tk_Offset(MenuButton, padX), 0}, {TK_CONFIG_PIXELS, "-pady", "padY", "Pad", DEF_MENUBUTTON_PADY, Tk_Offset(MenuButton, padY), 0}, {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_MENUBUTTON_RELIEF, Tk_Offset(MenuButton, relief), 0}, {TK_CONFIG_UID, "-state", "state", "State", DEF_MENUBUTTON_STATE, Tk_Offset(MenuButton, state), 0}, {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", DEF_MENUBUTTON_TAKE_FOCUS, Tk_Offset(MenuButton, takeFocus), TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-text", "text", "Text", DEF_MENUBUTTON_TEXT, Tk_Offset(MenuButton, text), 0}, {TK_CONFIG_STRING, "-textvariable", "textVariable", "Variable", DEF_MENUBUTTON_TEXT_VARIABLE, Tk_Offset(MenuButton, textVarName), TK_CONFIG_NULL_OK}, {TK_CONFIG_INT, "-underline", "underline", "Underline", DEF_MENUBUTTON_UNDERLINE, Tk_Offset(MenuButton, underline), 0}, {TK_CONFIG_STRING, "-width", "width", "Width", DEF_MENUBUTTON_WIDTH, Tk_Offset(MenuButton, widthString), 0}, {TK_CONFIG_PIXELS, "-wraplength", "wrapLength", "WrapLength", DEF_MENUBUTTON_WRAP_LENGTH, Tk_Offset(MenuButton, wrapLength), 0}, {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; /* * Forward declarations for procedures defined later in this file: */ static void ComputeMenuButtonGeometry _ANSI_ARGS_(( MenuButton *mbPtr)); static void MenuButtonCmdDeletedProc _ANSI_ARGS_(( ClientData clientData)); static void MenuButtonEventProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); static void MenuButtonImageProc _ANSI_ARGS_((ClientData clientData, int x, int y, int width, int height, int imgWidth, int imgHeight)); static char *MenuButtonTextVarProc _ANSI_ARGS_(( ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)); static int MenuButtonWidgetCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, char **argv)); static int ConfigureMenuButton _ANSI_ARGS_((Tcl_Interp *interp, MenuButton *mbPtr, int argc, char **argv, int flags)); static void DestroyMenuButton _ANSI_ARGS_((char *memPtr)); static void DisplayMenuButton _ANSI_ARGS_((ClientData clientData)); /* *-------------------------------------------------------------- * * Tk_MenubuttonCmd -- * * This procedure is invoked to process the "button", "label", * "radiobutton", and "checkbutton" Tcl commands. See the * user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ int Tk_MenubuttonCmd(clientData, interp, argc, argv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { register MenuButton *mbPtr; Tk_Window tkwin; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " pathName ?options?\"", (char *)NULL); return TCL_ERROR; } /* * Create the new window. */ tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp), argv[1], (char *)NULL); if (tkwin == NULL) { return TCL_ERROR; } /* * Initialize the data structure for the button. */ mbPtr = Blt_Malloc(sizeof(MenuButton)); mbPtr->tkwin = tkwin; mbPtr->display = Tk_Display(tkwin); mbPtr->interp = interp; mbPtr->widgetCmd = Tcl_CreateCommand(interp, Tk_PathName(mbPtr->tkwin), MenuButtonWidgetCmd, (ClientData)mbPtr, MenuButtonCmdDeletedProc); mbPtr->menuName = NULL; mbPtr->text = NULL; mbPtr->numChars = 0; mbPtr->underline = -1; mbPtr->textVarName = NULL; mbPtr->bitmap = None; mbPtr->imageString = NULL; mbPtr->image = NULL; mbPtr->state = tkNormalUid; mbPtr->normalBorder = NULL; mbPtr->activeBorder = NULL; mbPtr->borderWidth = 0; mbPtr->relief = TK_RELIEF_FLAT; mbPtr->highlightWidth = 0; mbPtr->highlightBgColorPtr = NULL; mbPtr->highlightColorPtr = NULL; mbPtr->inset = 0; mbPtr->fontPtr = NULL; mbPtr->normalFg = NULL; mbPtr->activeFg = NULL; mbPtr->disabledFg = NULL; mbPtr->normalTextGC = None; mbPtr->activeTextGC = None; mbPtr->gray = None; mbPtr->disabledGC = None; mbPtr->leftBearing = 0; mbPtr->rightBearing = 0; mbPtr->widthString = NULL; mbPtr->heightString = NULL; mbPtr->width = 0; mbPtr->width = 0; mbPtr->wrapLength = 0; mbPtr->padX = 0; mbPtr->padY = 0; mbPtr->anchor = TK_ANCHOR_CENTER; mbPtr->justify = TK_JUSTIFY_CENTER; mbPtr->indicatorOn = 0; mbPtr->indicatorWidth = 0; mbPtr->indicatorHeight = 0; mbPtr->cursor = None; mbPtr->takeFocus = NULL; mbPtr->flags = 0; Tk_SetClass(mbPtr->tkwin, "Menubutton"); Tk_CreateEventHandler(mbPtr->tkwin, ExposureMask | StructureNotifyMask | FocusChangeMask, MenuButtonEventProc, (ClientData)mbPtr); if (ConfigureMenuButton(interp, mbPtr, argc - 2, argv + 2, 0) != TCL_OK) { Tk_DestroyWindow(mbPtr->tkwin); return TCL_ERROR; } Tcl_SetResult(interp, Tk_PathName(mbPtr->tkwin), TCL_VOLATILE); return TCL_OK; } /* *-------------------------------------------------------------- * * MenuButtonWidgetCmd -- * * This procedure is invoked to process the Tcl command * that corresponds to a widget managed by this module. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ static int MenuButtonWidgetCmd(clientData, interp, argc, argv) ClientData clientData; /* Information about button widget. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { register MenuButton *mbPtr = clientData; int result = TCL_OK; size_t length; int c; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " option ?arg arg ...?\"", (char *)NULL); return TCL_ERROR; } Tcl_Preserve((ClientData)mbPtr); c = argv[1][0]; length = strlen(argv[1]); if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) && (length >= 2)) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " cget option\"", (char *)NULL); goto error; } result = Tk_ConfigureValue(interp, mbPtr->tkwin, configSpecs, (char *)mbPtr, argv[2], 0); } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) && (length >= 2)) { if (argc == 2) { result = Tk_ConfigureInfo(interp, mbPtr->tkwin, configSpecs, (char *)mbPtr, (char *)NULL, 0); } else if (argc == 3) { result = Tk_ConfigureInfo(interp, mbPtr->tkwin, configSpecs, (char *)mbPtr, argv[2], 0); } else { result = ConfigureMenuButton(interp, mbPtr, argc - 2, argv + 2, TK_CONFIG_ARGV_ONLY); } } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": must be cget or configure", (char *)NULL); goto error; } Tcl_Release((ClientData)mbPtr); return result; error: Tcl_Release((ClientData)mbPtr); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * DestroyMenuButton -- * * This procedure is invoked to recycle all of the resources * associated with a button widget. It is invoked as a * when-idle handler in order to make sure that there is no * other use of the button pending at the time of the deletion. * * Results: * None. * * Side effects: * Everything associated with the widget is freed up. * *---------------------------------------------------------------------- */ static void DestroyMenuButton(memPtr) char *memPtr; /* Info about button widget. */ { register MenuButton *mbPtr = (MenuButton *)memPtr; /* * Free up all the stuff that requires special handling, then * let Tk_FreeOptions handle all the standard option-related * stuff. */ if (mbPtr->textVarName != NULL) { Tcl_UntraceVar(mbPtr->interp, mbPtr->textVarName, TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, MenuButtonTextVarProc, (ClientData)mbPtr); } if (mbPtr->image != NULL) { Tk_FreeImage(mbPtr->image); } if (mbPtr->normalTextGC != None) { Tk_FreeGC(mbPtr->display, mbPtr->normalTextGC); } if (mbPtr->activeTextGC != None) { Tk_FreeGC(mbPtr->display, mbPtr->activeTextGC); } if (mbPtr->gray != None) { Tk_FreeBitmap(mbPtr->display, mbPtr->gray); } if (mbPtr->disabledGC != None) { Tk_FreeGC(mbPtr->display, mbPtr->disabledGC); } Tk_FreeOptions(configSpecs, (char *)mbPtr, mbPtr->display, 0); ckBlt_Free(mbPtr); } /* *---------------------------------------------------------------------- * * ConfigureMenuButton -- * * This procedure is called to process an argv/argc list, plus * the Tk option database, in order to configure (or * reconfigure) a menubutton widget. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then interp->result contains an error message. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for mbPtr; old resources get freed, if there * were any. The menubutton is redisplayed. * *---------------------------------------------------------------------- */ static int ConfigureMenuButton(interp, mbPtr, argc, argv, flags) Tcl_Interp *interp; /* Used for error reporting. */ register MenuButton *mbPtr; /* Information about widget; may or may * not already have values for some fields. */ int argc; /* Number of valid entries in argv. */ char **argv; /* Arguments. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { XGCValues gcValues; GC newGC; unsigned long mask; int result; Tk_Image image; /* * Eliminate any existing trace on variables monitored by the menubutton. */ if (mbPtr->textVarName != NULL) { Tcl_UntraceVar(interp, mbPtr->textVarName, TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, MenuButtonTextVarProc, (ClientData)mbPtr); } result = Tk_ConfigureWidget(interp, mbPtr->tkwin, configSpecs, argc, argv, (char *)mbPtr, flags); if (result != TCL_OK) { return TCL_ERROR; } /* * A few options need special processing, such as setting the * background from a 3-D border, or filling in complicated * defaults that couldn't be specified to Tk_ConfigureWidget. */ if ((mbPtr->state == tkActiveUid) && !Tk_StrictMotif(mbPtr->tkwin)) { Tk_SetBackgroundFromBorder(mbPtr->tkwin, mbPtr->activeBorder); } else { Tk_SetBackgroundFromBorder(mbPtr->tkwin, mbPtr->normalBorder); if ((mbPtr->state != tkNormalUid) && (mbPtr->state != tkActiveUid) && (mbPtr->state != tkDisabledUid)) { Tcl_AppendResult(interp, "bad state value \"", mbPtr->state, "\": must be normal, active, or disabled", (char *)NULL); mbPtr->state = tkNormalUid; return TCL_ERROR; } } if (mbPtr->highlightWidth < 0) { mbPtr->highlightWidth = 0; } gcValues.font = mbPtr->fontPtr->fid; gcValues.foreground = mbPtr->normalFg->pixel; gcValues.background = Tk_3DBorderColor(mbPtr->normalBorder)->pixel; /* * Note: GraphicsExpose events are disabled in GC's because they're * used to copy stuff from an off-screen pixmap onto the screen (we know * that there's no problem with obscured areas). */ gcValues.graphics_exposures = False; newGC = Tk_GetGC(mbPtr->tkwin, GCForeground | GCBackground | GCFont | GCGraphicsExposures, &gcValues); if (mbPtr->normalTextGC != None) { Tk_FreeGC(mbPtr->display, mbPtr->normalTextGC); } mbPtr->normalTextGC = newGC; gcValues.font = mbPtr->fontPtr->fid; gcValues.foreground = mbPtr->activeFg->pixel; gcValues.background = Tk_3DBorderColor(mbPtr->activeBorder)->pixel; newGC = Tk_GetGC(mbPtr->tkwin, GCForeground | GCBackground | GCFont, &gcValues); if (mbPtr->activeTextGC != None) { Tk_FreeGC(mbPtr->display, mbPtr->activeTextGC); } mbPtr->activeTextGC = newGC; gcValues.font = mbPtr->fontPtr->fid; gcValues.background = Tk_3DBorderColor(mbPtr->normalBorder)->pixel; if ((mbPtr->disabledFg != NULL) && (mbPtr->imageString == NULL)) { gcValues.foreground = mbPtr->disabledFg->pixel; mask = GCForeground | GCBackground | GCFont; } else { gcValues.foreground = gcValues.background; if (mbPtr->gray == None) { mbPtr->gray = Tk_GetBitmap(interp, mbPtr->tkwin, Tk_GetUid("gray50")); if (mbPtr->gray == None) { return TCL_ERROR; } } gcValues.fill_style = FillStippled; gcValues.stipple = mbPtr->gray; mask = GCForeground | GCFillStyle | GCStipple; } newGC = Tk_GetGC(mbPtr->tkwin, mask, &gcValues); if (mbPtr->disabledGC != None) { Tk_FreeGC(mbPtr->display, mbPtr->disabledGC); } mbPtr->disabledGC = newGC; if (mbPtr->padX < 0) { mbPtr->padX = 0; } if (mbPtr->padY < 0) { mbPtr->padY = 0; } /* * Get the image for the widget, if there is one. Allocate the * new image before freeing the old one, so that the reference * count doesn't go to zero and cause image data to be discarded. */ if (mbPtr->imageString != NULL) { image = Tk_GetImage(mbPtr->interp, mbPtr->tkwin, mbPtr->imageString, MenuButtonImageProc, (ClientData)mbPtr); if (image == NULL) { return TCL_ERROR; } } else { image = NULL; } if (mbPtr->image != NULL) { Tk_FreeImage(mbPtr->image); } mbPtr->image = image; if ((mbPtr->image == NULL) && (mbPtr->bitmap == None) && (mbPtr->textVarName != NULL)) { /* * The menubutton displays a variable. Set up a trace to watch * for any changes in it. */ char *value; value = Tcl_GetVar(interp, mbPtr->textVarName, TCL_GLOBAL_ONLY); if (value == NULL) { Tcl_SetVar(interp, mbPtr->textVarName, mbPtr->text, TCL_GLOBAL_ONLY); } else { if (mbPtr->text != NULL) { ckBlt_Free(mbPtr->text); } mbPtr->text = Blt_Malloc(strlen(value) + 1); strcpy(mbPtr->text, value); } Tcl_TraceVar(interp, mbPtr->textVarName, TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, MenuButtonTextVarProc, (ClientData)mbPtr); } /* * Recompute the geometry for the button. */ if ((mbPtr->bitmap != None) || (mbPtr->image != NULL)) { if (Tk_GetPixels(interp, mbPtr->tkwin, mbPtr->widthString, &mbPtr->width) != TCL_OK) { widthError: Tcl_AddErrorInfo(interp, "\n (processing -width option)"); return TCL_ERROR; } if (Tk_GetPixels(interp, mbPtr->tkwin, mbPtr->heightString, &mbPtr->height) != TCL_OK) { heightError: Tcl_AddErrorInfo(interp, "\n (processing -height option)"); return TCL_ERROR; } } else { if (Tcl_GetInt(interp, mbPtr->widthString, &mbPtr->width) != TCL_OK) { goto widthError; } if (Tcl_GetInt(interp, mbPtr->heightString, &mbPtr->height) != TCL_OK) { goto heightError; } } ComputeMenuButtonGeometry(mbPtr); /* * Lastly, arrange for the button to be redisplayed. */ if (Tk_IsMapped(mbPtr->tkwin) && !(mbPtr->flags & REDRAW_PENDING)) { Tcl_DoWhenIdle(DisplayMenuButton, (ClientData)mbPtr); mbPtr->flags |= REDRAW_PENDING; } return TCL_OK; } /* *---------------------------------------------------------------------- * * DisplayMenuButton -- * * This procedure is invoked to display a menubutton widget. * * Results: * None. * * Side effects: * Commands are output to X to display the menubutton in its * current mode. * *---------------------------------------------------------------------- */ static void DisplayMenuButton(clientData) ClientData clientData; /* Information about widget. */ { register MenuButton *mbPtr = clientData; GC gc; Tk_3DBorder border; Pixmap pixmap; int x = 0; /* Initialization needed only to stop * compiler warning. */ int y; register Tk_Window tkwin = mbPtr->tkwin; int width, height; mbPtr->flags &= ~REDRAW_PENDING; if ((mbPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { return; } if ((mbPtr->state == tkDisabledUid) && (mbPtr->disabledFg != NULL)) { gc = mbPtr->disabledGC; border = mbPtr->normalBorder; } else if ((mbPtr->state == tkActiveUid) && !Tk_StrictMotif(mbPtr->tkwin)) { gc = mbPtr->activeTextGC; border = mbPtr->activeBorder; } else { gc = mbPtr->normalTextGC; border = mbPtr->normalBorder; } /* * In order to avoid screen flashes, this procedure redraws * the menu button in a pixmap, then copies the pixmap to the * screen in a single operation. This means that there's no * point in time where the on-sreen image has been cleared. */ pixmap = Tk_GetPixmap(mbPtr->display, Tk_WindowId(tkwin), Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin)); Blt_Fill3DRectangle(tkwin, pixmap, border, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); /* * Display image or bitmap or text for button. */ if (mbPtr->image != None) { Tk_SizeOfImage(mbPtr->image, &width, &height); imageOrBitmap: switch (mbPtr->anchor) { case TK_ANCHOR_NW: case TK_ANCHOR_W: case TK_ANCHOR_SW: x += mbPtr->inset; break; case TK_ANCHOR_N: case TK_ANCHOR_CENTER: case TK_ANCHOR_S: x += ((int)(Tk_Width(tkwin) - width - mbPtr->indicatorWidth)) / 2; break; default: x += Tk_Width(tkwin) - mbPtr->inset - width - mbPtr->indicatorWidth; break; } switch (mbPtr->anchor) { case TK_ANCHOR_NW: case TK_ANCHOR_N: case TK_ANCHOR_NE: y = mbPtr->inset; break; case TK_ANCHOR_W: case TK_ANCHOR_CENTER: case TK_ANCHOR_E: y = ((int)(Tk_Height(tkwin) - height)) / 2; break; default: y = Tk_Height(tkwin) - mbPtr->inset - height; break; } if (mbPtr->image != NULL) { Tk_RedrawImage(mbPtr->image, 0, 0, width, height, pixmap, x, y); } else { XCopyPlane(mbPtr->display, mbPtr->bitmap, pixmap, gc, 0, 0, (unsigned)width, (unsigned)height, x, y, 1); } } else if (mbPtr->bitmap != None) { Tk_SizeOfBitmap(mbPtr->display, mbPtr->bitmap, &width, &height); goto imageOrBitmap; } else { width = mbPtr->textWidth; height = mbPtr->textHeight; switch (mbPtr->anchor) { case TK_ANCHOR_NW: case TK_ANCHOR_W: case TK_ANCHOR_SW: x = mbPtr->inset + mbPtr->padX; break; case TK_ANCHOR_N: case TK_ANCHOR_CENTER: case TK_ANCHOR_S: x = ((int)(Tk_Width(tkwin) - width - mbPtr->indicatorWidth)) / 2; break; default: x = Tk_Width(tkwin) - width - mbPtr->padX - mbPtr->inset - mbPtr->indicatorWidth; break; } switch (mbPtr->anchor) { case TK_ANCHOR_NW: case TK_ANCHOR_N: case TK_ANCHOR_NE: y = mbPtr->inset + mbPtr->padY; break; case TK_ANCHOR_W: case TK_ANCHOR_CENTER: case TK_ANCHOR_E: y = ((int)(Tk_Height(tkwin) - height)) / 2; break; default: y = Tk_Height(tkwin) - mbPtr->inset - mbPtr->padY - height; break; } TkDisplayText(mbPtr->display, pixmap, mbPtr->fontPtr, mbPtr->text, mbPtr->numChars, x, y, mbPtr->textWidth, mbPtr->justify, mbPtr->underline, gc); } /* * If the menu button is disabled with a stipple rather than a special * foreground color, generate the stippled effect. */ if ((mbPtr->state == tkDisabledUid) && ((mbPtr->disabledFg == NULL) || (mbPtr->image != NULL))) { XFillRectangle(mbPtr->display, pixmap, mbPtr->disabledGC, mbPtr->inset, mbPtr->inset, (unsigned)(Tk_Width(tkwin) - 2 * mbPtr->inset), (unsigned)(Tk_Height(tkwin) - 2 * mbPtr->inset)); } /* * Draw the cascade indicator for the menu button on the * right side of the window, if desired. */ if (mbPtr->indicatorOn) { int borderWidth; borderWidth = (mbPtr->indicatorHeight + 1) / 3; if (borderWidth < 1) { borderWidth = 1; } Blt_Fill3DRectangle(tkwin, pixmap, border, Tk_Width(tkwin) - mbPtr->inset - mbPtr->indicatorWidth + mbPtr->indicatorHeight, y + ((int)(height - mbPtr->indicatorHeight)) / 2, mbPtr->indicatorWidth - 2 * mbPtr->indicatorHeight, mbPtr->indicatorHeight, borderWidth, TK_RELIEF_RAISED); } /* * Draw the border and traversal highlight last. This way, if the * menu button's contents overflow onto the border they'll be covered * up by the border. */ if (mbPtr->relief != TK_RELIEF_FLAT) { Blt_Draw3DRectangle(tkwin, pixmap, border, mbPtr->highlightWidth, mbPtr->highlightWidth, Tk_Width(tkwin) - 2 * mbPtr->highlightWidth, Tk_Height(tkwin) - 2 * mbPtr->highlightWidth, mbPtr->borderWidth, mbPtr->relief); } if (mbPtr->highlightWidth != 0) { GC gc; if (mbPtr->flags & GOT_FOCUS) { gc = Tk_GCForColor(mbPtr->highlightColorPtr, pixmap); } else { gc = Tk_GCForColor(mbPtr->highlightBgColorPtr, pixmap); } Tk_DrawFocusHighlight(tkwin, gc, mbPtr->highlightWidth, pixmap); } /* * Copy the information from the off-screen pixmap onto the screen, * then delete the pixmap. */ XCopyArea(mbPtr->display, pixmap, Tk_WindowId(tkwin), mbPtr->normalTextGC, 0, 0, (unsigned)Tk_Width(tkwin), (unsigned)Tk_Height(tkwin), 0, 0); Tk_FreePixmap(mbPtr->display, pixmap); } /* *-------------------------------------------------------------- * * MenuButtonEventProc -- * * This procedure is invoked by the Tk dispatcher for various * events on buttons. * * Results: * None. * * Side effects: * When the window gets deleted, internal structures get * cleaned up. When it gets exposed, it is redisplayed. * *-------------------------------------------------------------- */ static void MenuButtonEventProc(clientData, eventPtr) ClientData clientData; /* Information about window. */ XEvent *eventPtr; /* Information about event. */ { MenuButton *mbPtr = clientData; if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) { goto redraw; } else if (eventPtr->type == ConfigureNotify) { /* * Must redraw after size changes, since layout could have changed * and borders will need to be redrawn. */ goto redraw; } else if (eventPtr->type == DestroyNotify) { if (mbPtr->tkwin != NULL) { mbPtr->tkwin = NULL; Tcl_DeleteCommandFromToken(mbPtr->interp, mbPtr->widgetCmd); } if (mbPtr->flags & REDRAW_PENDING) { Tcl_CancelIdleCall(DisplayMenuButton, (ClientData)mbPtr); } Tcl_EventuallyFree((ClientData)mbPtr, DestroyMenuButton); } else if (eventPtr->type == FocusIn) { if (eventPtr->xfocus.detail != NotifyInferior) { mbPtr->flags |= GOT_FOCUS; if (mbPtr->highlightWidth > 0) { goto redraw; } } } else if (eventPtr->type == FocusOut) { if (eventPtr->xfocus.detail != NotifyInferior) { mbPtr->flags &= ~GOT_FOCUS; if (mbPtr->highlightWidth > 0) { goto redraw; } } } return; redraw: if ((mbPtr->tkwin != NULL) && !(mbPtr->flags & REDRAW_PENDING)) { Tcl_DoWhenIdle(DisplayMenuButton, (ClientData)mbPtr); mbPtr->flags |= REDRAW_PENDING; } } /* *---------------------------------------------------------------------- * * MenuButtonCmdDeletedProc -- * * This procedure is invoked when a widget command is deleted. If * the widget isn't already in the process of being destroyed, * this command destroys it. * * Results: * None. * * Side effects: * The widget is destroyed. * *---------------------------------------------------------------------- */ static void MenuButtonCmdDeletedProc(clientData) ClientData clientData; /* Pointer to widget record for widget. */ { MenuButton *mbPtr = clientData; Tk_Window tkwin = mbPtr->tkwin; /* * This procedure could be invoked either because the window was * destroyed and the command was then deleted (in which case tkwin * is NULL) or because the command was deleted, and then this procedure * destroys the widget. */ if (tkwin != NULL) { mbPtr->tkwin = NULL; Tk_DestroyWindow(tkwin); } } /* *---------------------------------------------------------------------- * * ComputeMenuButtonGeometry -- * * After changes in a menu button's text or bitmap, this procedure * recomputes the menu button's geometry and passes this information * along to the geometry manager for the window. * * Results: * None. * * Side effects: * The menu button's window may change size. * *---------------------------------------------------------------------- */ static void ComputeMenuButtonGeometry(mbPtr) register MenuButton *mbPtr; /* Widget record for menu button. */ { int width, height, mm, pixels; mbPtr->inset = mbPtr->highlightWidth + mbPtr->borderWidth; if (mbPtr->image != None) { Tk_SizeOfImage(mbPtr->image, &width, &height); if (mbPtr->width > 0) { width = mbPtr->width; } if (mbPtr->height > 0) { height = mbPtr->height; } } else if (mbPtr->bitmap != None) { Tk_SizeOfBitmap(mbPtr->display, mbPtr->bitmap, &width, &height); if (mbPtr->width > 0) { width = mbPtr->width; } if (mbPtr->height > 0) { height = mbPtr->height; } } else { mbPtr->numChars = strlen(mbPtr->text); TkComputeTextGeometry(mbPtr->fontPtr, mbPtr->text, mbPtr->numChars, mbPtr->wrapLength, &mbPtr->textWidth, &mbPtr->textHeight); width = mbPtr->textWidth; height = mbPtr->textHeight; if (mbPtr->width > 0) { width = mbPtr->width * XTextWidth(mbPtr->fontPtr, "0", 1); } if (mbPtr->height > 0) { height = mbPtr->height * (mbPtr->fontPtr->ascent + mbPtr->fontPtr->descent); } width += 2 * mbPtr->padX; height += 2 * mbPtr->padY; } if (mbPtr->indicatorOn) { mm = WidthMMOfScreen(Tk_Screen(mbPtr->tkwin)); pixels = WidthOfScreen(Tk_Screen(mbPtr->tkwin)); mbPtr->indicatorHeight = (INDICATOR_HEIGHT * pixels) / (10 * mm); mbPtr->indicatorWidth = (INDICATOR_WIDTH * pixels) / (10 * mm) + 2 * mbPtr->indicatorHeight; width += mbPtr->indicatorWidth; } else { mbPtr->indicatorHeight = 0; mbPtr->indicatorWidth = 0; } Tk_GeometryRequest(mbPtr->tkwin, (int)(width + 2 * mbPtr->inset), (int)(height + 2 * mbPtr->inset)); Tk_SetInternalBorder(mbPtr->tkwin, mbPtr->inset); } /* *-------------------------------------------------------------- * * MenuButtonTextVarProc -- * * This procedure is invoked when someone changes the variable * whose contents are to be displayed in a menu button. * * Results: * NULL is always returned. * * Side effects: * The text displayed in the menu button will change to match the * variable. * *-------------------------------------------------------------- */ /* ARGSUSED */ static char * MenuButtonTextVarProc(clientData, interp, name1, name2, flags) ClientData clientData; /* Information about button. */ Tcl_Interp *interp; /* Interpreter containing variable. */ char *name1; /* Name of variable. */ char *name2; /* Second part of variable name. */ int flags; /* Information about what happened. */ { register MenuButton *mbPtr = clientData; char *value; /* * If the variable is unset, then immediately recreate it unless * the whole interpreter is going away. */ if (flags & TCL_TRACE_UNSETS) { if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) { Tcl_SetVar(interp, mbPtr->textVarName, mbPtr->text, TCL_GLOBAL_ONLY); Tcl_TraceVar(interp, mbPtr->textVarName, TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, MenuButtonTextVarProc, clientData); } return (char *) NULL; } value = Tcl_GetVar(interp, mbPtr->textVarName, TCL_GLOBAL_ONLY); if (value == NULL) { value = ""; } if (mbPtr->text != NULL) { ckBlt_Free(mbPtr->text); } mbPtr->text = Blt_Malloc(strlen(value) + 1); strcpy(mbPtr->text, value); ComputeMenuButtonGeometry(mbPtr); if ((mbPtr->tkwin != NULL) && Tk_IsMapped(mbPtr->tkwin) && !(mbPtr->flags & REDRAW_PENDING)) { Tcl_DoWhenIdle(DisplayMenuButton, (ClientData)mbPtr); mbPtr->flags |= REDRAW_PENDING; } return (char *) NULL; } /* *---------------------------------------------------------------------- * * MenuButtonImageProc -- * * This procedure is invoked by the image code whenever the manager * for an image does something that affects the size of contents * of an image displayed in a button. * * Results: * None. * * Side effects: * Arranges for the button to get redisplayed. * *---------------------------------------------------------------------- */ static void MenuButtonImageProc(clientData, x, y, width, height, imgWidth, imgHeight) ClientData clientData; /* Pointer to widget record. */ int x, y; /* Upper left pixel (within image) * that must be redisplayed. */ int width, height; /* Dimensions of area to redisplay * (may be <= 0). */ int imgWidth, imgHeight; /* New dimensions of image. */ { register MenuButton *mbPtr = clientData; if (mbPtr->tkwin != NULL) { ComputeMenuButtonGeometry(mbPtr); if (Tk_IsMapped(mbPtr->tkwin) && !(mbPtr->flags & REDRAW_PENDING)) { Tcl_DoWhenIdle(DisplayMenuButton, (ClientData)mbPtr); mbPtr->flags |= REDRAW_PENDING; } } } blt-2.4z.orig/src/tkScrollbar.c0100644000175000017500000012716607471015211015174 0ustar dokodoko /* * tkScrollbar.c -- * * This module implements a scrollbar widgets for the Tk * toolkit. A scrollbar displays a slider and two arrows; * mouse clicks on features within the scrollbar cause * scrolling commands to be invoked. * * Copyright (c) 1990-1994 The Regents of the University of California. * Copyright (c) 1994-1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * SCCS: @(#) tkScrollbar.c 1.79 96/02/15 18:52:40 */ #include "bltInt.h" #ifndef NO_TILESCROLLBAR #include "bltTile.h" extern Tk_CustomOption bltTileOption; #define NORMAL_BG "#d9d9d9" #define ACTIVE_BG "#ececec" #define SELECT_BG "#c3c3c3" #define TROUGH "#c3c3c3" #define INDICATOR "#b03060" #define DISABLED "#a3a3a3" /* * Defaults for scrollbars: */ #define DEF_SCROLLBAR_ACTIVE_BACKGROUND ACTIVE_BG #define DEF_SCROLLBAR_ACTIVE_BG_MONO RGB_BLACK #define DEF_SCROLLBAR_ACTIVE_RELIEF "raised" #define DEF_SCROLLBAR_BACKGROUND NORMAL_BG #define DEF_SCROLLBAR_BG_MONO RGB_WHITE #define DEF_SCROLLBAR_BORDERWIDTH "2" #define DEF_SCROLLBAR_COMMAND "" #define DEF_SCROLLBAR_CURSOR "" #define DEF_SCROLLBAR_EL_BORDERWIDTH "-1" #define DEF_SCROLLBAR_HIGHLIGHT_BG NORMAL_BG #define DEF_SCROLLBAR_HIGHLIGHT RGB_BLACK #define DEF_SCROLLBAR_HIGHLIGHT_WIDTH "2" #define DEF_SCROLLBAR_JUMP "0" #define DEF_SCROLLBAR_ORIENT "vertical" #define DEF_SCROLLBAR_RELIEF "sunken" #define DEF_SCROLLBAR_REPEAT_DELAY "300" #define DEF_SCROLLBAR_REPEAT_INTERVAL "100" #define DEF_SCROLLBAR_TAKE_FOCUS (char *) NULL #define DEF_SCROLLBAR_TROUGH_COLOR TROUGH #define DEF_SCROLLBAR_TROUGH_MONO RGB_WHITE #define DEF_SCROLLBAR_WIDTH "15" /* * A data structure of the following type is kept for each scrollbar * widget managed by this file: */ typedef struct { Tk_Window tkwin; /* Window that embodies the scrollbar. NULL * means that the window has been destroyed * but the data structures haven't yet been * cleaned up.*/ Display *display; /* Display containing widget. Used, among * other things, so that resources can be * freed even after tkwin has gone away. */ Tcl_Interp *interp; /* Interpreter associated with scrollbar. */ Tcl_Command widgetCmd; /* Token for scrollbar's widget command. */ Tk_Uid orientUid; /* Orientation for window ("vertical" or * "horizontal"). */ int vertical; /* Non-zero means vertical orientation * requested, zero means horizontal. */ int width; /* Desired narrow dimension of scrollbar, * in pixels. */ char *command; /* Command prefix to use when invoking * scrolling commands. NULL means don't * invoke commands. Malloc'ed. */ int commandSize; /* Number of non-NULL bytes in command. */ int repeatDelay; /* How long to wait before auto-repeating * on scrolling actions (in ms). */ int repeatInterval; /* Interval between autorepeats (in ms). */ int jump; /* Value of -jump option. */ /* * Information used when displaying widget: */ int borderWidth; /* Width of 3-D borders. */ Tk_3DBorder bgBorder; /* Used for drawing background (all flat * surfaces except for trough). */ Tk_3DBorder activeBorder; /* For drawing backgrounds when active (i.e. * when mouse is positioned over element). */ XColor *troughColorPtr; /* Color for drawing trough. */ GC troughGC; /* For drawing trough. */ GC copyGC; /* Used for copying from pixmap onto screen. */ int relief; /* Indicates whether window as a whole is * raised, sunken, or flat. */ int highlightWidth; /* Width in pixels of highlight to draw * around widget when it has the focus. * <= 0 means don't draw a highlight. */ XColor *highlightBgColorPtr; /* Color for drawing traversal highlight * area when highlight is off. */ XColor *highlightColorPtr; /* Color for drawing traversal highlight. */ int inset; /* Total width of all borders, including * traversal highlight and 3-D border. * Indicates how much interior stuff must * be offset from outside edges to leave * room for borders. */ int elementBorderWidth; /* Width of border to draw around elements * inside scrollbar (arrows and slider). * -1 means use borderWidth. */ int arrowLength; /* Length of arrows along long dimension of * scrollbar, including space for a small gap * between the arrow and the slider. * Recomputed on window size changes. */ int sliderFirst; /* Pixel coordinate of top or left edge * of slider area, including border. */ int sliderLast; /* Coordinate of pixel just after bottom * or right edge of slider area, including * border. */ int activeField; /* Names field to be displayed in active * colors, such as TOP_ARROW, or 0 for * no field. */ int activeRelief; /* Value of -activeRelief option: relief * to use for active element. */ /* * Information describing the application related to the scrollbar. * This information is provided by the application by invoking the * "set" widget command. This information can now be provided in * two ways: the "old" form (totalUnits, windowUnits, firstUnit, * and lastUnit), or the "new" form (firstFraction and lastFraction). * FirstFraction and lastFraction will always be valid, but * the old-style information is only valid if the NEW_STYLE_COMMANDS * flag is 0. */ int totalUnits; /* Total dimension of application, in * units. Valid only if the NEW_STYLE_COMMANDS * flag isn't set. */ int windowUnits; /* Maximum number of units that can be * displayed in the window at once. Valid * only if the NEW_STYLE_COMMANDS flag isn't * set. */ int firstUnit; /* Number of last unit visible in * application's window. Valid only if the * NEW_STYLE_COMMANDS flag isn't set. */ int lastUnit; /* Index of last unit visible in window. * Valid only if the NEW_STYLE_COMMANDS * flag isn't set. */ double firstFraction; /* Position of first visible thing in window, * specified as a fraction between 0 and * 1.0. */ double lastFraction; /* Position of last visible thing in window, * specified as a fraction between 0 and * 1.0. */ /* * Miscellaneous information: */ Tk_Cursor cursor; /* Current cursor for window, or None. */ char *takeFocus; /* Value of -takefocus option; not used in * the C code, but used by keyboard traversal * scripts. Malloc'ed, but may be NULL. */ int flags; /* Various flags; see below for * definitions. */ Blt_Tile tile, activeTile; } Scrollbar; /* * Legal values for "activeField" field of Scrollbar structures. These * are also the return values from the ScrollbarPosition procedure. */ #define OUTSIDE 0 #define TOP_ARROW 1 #define TOP_GAP 2 #define SLIDER 3 #define BOTTOM_GAP 4 #define BOTTOM_ARROW 5 /* * Flag bits for scrollbars: * * REDRAW_PENDING: Non-zero means a DoWhenIdle handler * has already been queued to redraw * this window. * NEW_STYLE_COMMANDS: Non-zero means the new style of commands * should be used to communicate with the * widget: ".t yview scroll 2 lines", instead * of ".t yview 40", for example. * GOT_FOCUS: Non-zero means this window has the input * focus. */ #define REDRAW_PENDING 1 #define NEW_STYLE_COMMANDS 2 #define GOT_FOCUS 4 /* * Minimum slider length, in pixels (designed to make sure that the slider * is always easy to grab with the mouse). */ #define MIN_SLIDER_LENGTH 8 /* * Information used for argv parsing. */ static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", DEF_SCROLLBAR_ACTIVE_BACKGROUND, Tk_Offset(Scrollbar, activeBorder), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", DEF_SCROLLBAR_ACTIVE_BG_MONO, Tk_Offset(Scrollbar, activeBorder), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_RELIEF, "-activerelief", "activeRelief", "Relief", DEF_SCROLLBAR_ACTIVE_RELIEF, Tk_Offset(Scrollbar, activeRelief), 0}, {TK_CONFIG_CUSTOM, "-activetile", "activeTile", "Tile", (char *)NULL, Tk_Offset(Scrollbar, activeTile), TK_CONFIG_NULL_OK, &bltTileOption}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_SCROLLBAR_BACKGROUND, Tk_Offset(Scrollbar, bgBorder), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_SCROLLBAR_BG_MONO, Tk_Offset(Scrollbar, bgBorder), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", DEF_SCROLLBAR_BORDERWIDTH, Tk_Offset(Scrollbar, borderWidth), 0}, {TK_CONFIG_STRING, "-command", "command", "Command", DEF_SCROLLBAR_COMMAND, Tk_Offset(Scrollbar, command), TK_CONFIG_NULL_OK}, {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", DEF_SCROLLBAR_CURSOR, Tk_Offset(Scrollbar, cursor), TK_CONFIG_NULL_OK}, {TK_CONFIG_PIXELS, "-elementborderwidth", "elementBorderWidth", "BorderWidth", DEF_SCROLLBAR_EL_BORDERWIDTH, Tk_Offset(Scrollbar, elementBorderWidth), 0}, {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", "HighlightBackground", DEF_SCROLLBAR_HIGHLIGHT_BG, Tk_Offset(Scrollbar, highlightBgColorPtr), 0}, {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", DEF_SCROLLBAR_HIGHLIGHT, Tk_Offset(Scrollbar, highlightColorPtr), 0}, {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", "HighlightThickness", DEF_SCROLLBAR_HIGHLIGHT_WIDTH, Tk_Offset(Scrollbar, highlightWidth), 0}, {TK_CONFIG_BOOLEAN, "-jump", "jump", "Jump", DEF_SCROLLBAR_JUMP, Tk_Offset(Scrollbar, jump), 0}, {TK_CONFIG_UID, "-orient", "orient", "Orient", DEF_SCROLLBAR_ORIENT, Tk_Offset(Scrollbar, orientUid), 0}, {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_SCROLLBAR_RELIEF, Tk_Offset(Scrollbar, relief), 0}, {TK_CONFIG_INT, "-repeatdelay", "repeatDelay", "RepeatDelay", DEF_SCROLLBAR_REPEAT_DELAY, Tk_Offset(Scrollbar, repeatDelay), 0}, {TK_CONFIG_INT, "-repeatinterval", "repeatInterval", "RepeatInterval", DEF_SCROLLBAR_REPEAT_INTERVAL, Tk_Offset(Scrollbar, repeatInterval), 0}, {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", DEF_SCROLLBAR_TAKE_FOCUS, Tk_Offset(Scrollbar, takeFocus), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-tile", "tile", "Tile", (char *)NULL, Tk_Offset(Scrollbar, tile), TK_CONFIG_NULL_OK, &bltTileOption}, {TK_CONFIG_COLOR, "-troughcolor", "troughColor", "Background", DEF_SCROLLBAR_TROUGH_COLOR, Tk_Offset(Scrollbar, troughColorPtr), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-troughcolor", "troughColor", "Background", DEF_SCROLLBAR_TROUGH_MONO, Tk_Offset(Scrollbar, troughColorPtr), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_PIXELS, "-width", "width", "Width", DEF_SCROLLBAR_WIDTH, Tk_Offset(Scrollbar, width), 0}, {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0} }; /* * Forward declarations for procedures defined later in this file: */ static void ComputeScrollbarGeometry _ANSI_ARGS_(( Scrollbar *scrollPtr)); static int ConfigureScrollbar _ANSI_ARGS_((Tcl_Interp *interp, Scrollbar *scrollPtr, int argc, char **argv, int flags)); static void DestroyScrollbar _ANSI_ARGS_((DestroyData *memPtr)); static void DisplayScrollbar _ANSI_ARGS_((ClientData clientData)); static void EventuallyRedraw _ANSI_ARGS_((Scrollbar *scrollPtr)); static void ScrollbarCmdDeletedProc _ANSI_ARGS_(( ClientData clientData)); static void ScrollbarEventProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); static int ScrollbarPosition _ANSI_ARGS_((Scrollbar *scrollPtr, int x, int y)); static int ScrollbarWidgetCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *, int argc, char **argv)); /* *-------------------------------------------------------------- * * ScrollbarCmd -- * * This procedure is invoked to process the "scrollbar" Tcl * command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ static int ScrollbarCmd(clientData, interp, argc, argv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { register Scrollbar *scrollPtr; Tk_Window tkwin; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " pathName ?options?\"", (char *)NULL); return TCL_ERROR; } tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp), argv[1], (char *)NULL); if (tkwin == NULL) { return TCL_ERROR; } /* * Initialize fields that won't be initialized by ConfigureScrollbar, * or which ConfigureScrollbar expects to have reasonable values * (e.g. resource pointers). */ scrollPtr = Blt_Malloc(sizeof(Scrollbar)); scrollPtr->tkwin = tkwin; scrollPtr->display = Tk_Display(tkwin); scrollPtr->interp = interp; scrollPtr->widgetCmd = Tcl_CreateCommand(interp, Tk_PathName(scrollPtr->tkwin), ScrollbarWidgetCmd, (ClientData)scrollPtr, ScrollbarCmdDeletedProc); #ifdef ITCL_NAMESPACES Itk_SetWidgetCommand(scrollPtr->tkwin, scrollPtr->widgetCmd); #endif /* ITCL_NAMESPACES */ scrollPtr->orientUid = NULL; scrollPtr->vertical = 0; scrollPtr->width = 0; scrollPtr->command = NULL; scrollPtr->commandSize = 0; scrollPtr->repeatDelay = 0; scrollPtr->repeatInterval = 0; scrollPtr->borderWidth = 0; scrollPtr->bgBorder = NULL; scrollPtr->activeBorder = NULL; scrollPtr->troughColorPtr = NULL; scrollPtr->troughGC = None; scrollPtr->copyGC = None; scrollPtr->relief = TK_RELIEF_FLAT; scrollPtr->highlightWidth = 0; scrollPtr->highlightBgColorPtr = NULL; scrollPtr->highlightColorPtr = NULL; scrollPtr->inset = 0; scrollPtr->elementBorderWidth = -1; scrollPtr->arrowLength = 0; scrollPtr->sliderFirst = 0; scrollPtr->sliderLast = 0; scrollPtr->activeField = 0; scrollPtr->activeRelief = TK_RELIEF_RAISED; scrollPtr->totalUnits = 0; scrollPtr->windowUnits = 0; scrollPtr->firstUnit = 0; scrollPtr->lastUnit = 0; scrollPtr->firstFraction = 0.0; scrollPtr->lastFraction = 0.0; scrollPtr->cursor = None; scrollPtr->takeFocus = NULL; scrollPtr->flags = 0; scrollPtr->tile = scrollPtr->activeTile = NULL; Tk_SetClass(scrollPtr->tkwin, "Scrollbar"); Tk_CreateEventHandler(scrollPtr->tkwin, ExposureMask | StructureNotifyMask | FocusChangeMask, ScrollbarEventProc, (ClientData)scrollPtr); if (ConfigureScrollbar(interp, scrollPtr, argc - 2, argv + 2, 0) != TCL_OK) { goto error; } Tcl_SetResult(interp, Tk_PathName(scrollPtr->tkwin), TCL_VOLATILE); return TCL_OK; error: Tk_DestroyWindow(scrollPtr->tkwin); return TCL_ERROR; } /* *-------------------------------------------------------------- * * ScrollbarWidgetCmd -- * * This procedure is invoked to process the Tcl command * that corresponds to a widget managed by this module. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ static int ScrollbarWidgetCmd(clientData, interp, argc, argv) ClientData clientData; /* Information about scrollbar * widget. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { register Scrollbar *scrollPtr = clientData; char string[200]; int result = TCL_OK; size_t length; int c; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " option ?arg arg ...?\"", (char *)NULL); return TCL_ERROR; } Tcl_Preserve((ClientData)scrollPtr); c = argv[1][0]; length = strlen(argv[1]); if ((c == 'a') && (strncmp(argv[1], "activate", length) == 0)) { if (argc == 2) { switch (scrollPtr->activeField) { case TOP_ARROW: Tcl_SetResult(interp, "arrow1", TCL_STATIC); break; case SLIDER: Tcl_SetResult(interp, "slider", TCL_STATIC); break; case BOTTOM_ARROW: Tcl_SetResult(interp, "arrow2", TCL_STATIC); break; } goto done; } if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " activate element\"", (char *)NULL); goto error; } c = argv[2][0]; length = strlen(argv[2]); if ((c == 'a') && (strcmp(argv[2], "arrow1") == 0)) { scrollPtr->activeField = TOP_ARROW; } else if ((c == 'a') && (strcmp(argv[2], "arrow2") == 0)) { scrollPtr->activeField = BOTTOM_ARROW; } else if ((c == 's') && (strncmp(argv[2], "slider", length) == 0)) { scrollPtr->activeField = SLIDER; } else { scrollPtr->activeField = OUTSIDE; } EventuallyRedraw(scrollPtr); } else if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) && (length >= 2)) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " cget option\"", (char *)NULL); goto error; } result = Tk_ConfigureValue(interp, scrollPtr->tkwin, configSpecs, (char *)scrollPtr, argv[2], 0); } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) && (length >= 2)) { if (argc == 2) { result = Tk_ConfigureInfo(interp, scrollPtr->tkwin, configSpecs, (char *)scrollPtr, (char *)NULL, 0); } else if (argc == 3) { result = Tk_ConfigureInfo(interp, scrollPtr->tkwin, configSpecs, (char *)scrollPtr, argv[2], 0); } else { result = ConfigureScrollbar(interp, scrollPtr, argc - 2, argv + 2, TK_CONFIG_ARGV_ONLY); } } else if ((c == 'd') && (strncmp(argv[1], "delta", length) == 0)) { int xDelta, yDelta, pixels, barWidth; double fraction; if (argc != 4) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " delta xDelta yDelta\"", (char *)NULL); goto error; } if ((Tcl_GetInt(interp, argv[2], &xDelta) != TCL_OK) || (Tcl_GetInt(interp, argv[3], &yDelta) != TCL_OK)) { goto error; } if (scrollPtr->vertical) { pixels = yDelta; barWidth = Tk_Height(scrollPtr->tkwin) - 1 - 2 * (scrollPtr->arrowLength + scrollPtr->inset); } else { pixels = xDelta; barWidth = Tk_Width(scrollPtr->tkwin) - 1 - 2 * (scrollPtr->arrowLength + scrollPtr->inset); } if (barWidth == 0) { fraction = 0.0; } else { fraction = ((double)pixels / (double)barWidth); } sprintf(interp->result, "%g", fraction); } else if ((c == 'f') && (strncmp(argv[1], "fraction", length) == 0)) { int x, y, pos, barWidth; double fraction; if (argc != 4) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " fraction x y\"", (char *)NULL); goto error; } if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { goto error; } if (scrollPtr->vertical) { pos = y - (scrollPtr->arrowLength + scrollPtr->inset); barWidth = Tk_Height(scrollPtr->tkwin) - 1 - 2 * (scrollPtr->arrowLength + scrollPtr->inset); } else { pos = x - (scrollPtr->arrowLength + scrollPtr->inset); barWidth = Tk_Width(scrollPtr->tkwin) - 1 - 2 * (scrollPtr->arrowLength + scrollPtr->inset); } if (barWidth == 0) { fraction = 0.0; } else { fraction = ((double)pos / (double)barWidth); } if (fraction < 0) { fraction = 0; } else if (fraction > 1.0) { fraction = 1.0; } sprintf(string, "%g", fraction); Tcl_SetResult(interp, string, TCL_VOLATILE); } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) { if (argc != 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " get\"", (char *)NULL); goto error; } if (scrollPtr->flags & NEW_STYLE_COMMANDS) { char first[TCL_DOUBLE_SPACE], last[TCL_DOUBLE_SPACE]; Tcl_PrintDouble(interp, scrollPtr->firstFraction, first); Tcl_PrintDouble(interp, scrollPtr->lastFraction, last); Tcl_AppendResult(interp, first, " ", last, (char *)NULL); } else { sprintf(string, "%d %d %d %d", scrollPtr->totalUnits, scrollPtr->windowUnits, scrollPtr->firstUnit, scrollPtr->lastUnit); Tcl_SetResult(interp, string, TCL_VOLATILE); } } else if ((c == 'i') && (strncmp(argv[1], "identify", length) == 0)) { int x, y, thing; if (argc != 4) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " identify x y\"", (char *)NULL); goto error; } if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { goto error; } thing = ScrollbarPosition(scrollPtr, x, y); switch (thing) { case TOP_ARROW: Tcl_SetResult(interp, "arrow1", TCL_STATIC); break; case TOP_GAP: Tcl_SetResult(interp, "trough1", TCL_STATIC); break; case SLIDER: Tcl_SetResult(interp, "slider", TCL_STATIC); break; case BOTTOM_GAP: Tcl_SetResult(interp, "trough2", TCL_STATIC); break; case BOTTOM_ARROW: Tcl_SetResult(interp, "arrow2", TCL_STATIC); break; } } else if ((c == 's') && (strncmp(argv[1], "set", length) == 0)) { int totalUnits, windowUnits, firstUnit, lastUnit; if (argc == 4) { double first, last; if (Tcl_GetDouble(interp, argv[2], &first) != TCL_OK) { goto error; } if (Tcl_GetDouble(interp, argv[3], &last) != TCL_OK) { goto error; } if (first < 0) { scrollPtr->firstFraction = 0; } else if (first > 1.0) { scrollPtr->firstFraction = 1.0; } else { scrollPtr->firstFraction = first; } if (last < scrollPtr->firstFraction) { scrollPtr->lastFraction = scrollPtr->firstFraction; } else if (last > 1.0) { scrollPtr->lastFraction = 1.0; } else { scrollPtr->lastFraction = last; } scrollPtr->flags |= NEW_STYLE_COMMANDS; } else if (argc == 6) { if (Tcl_GetInt(interp, argv[2], &totalUnits) != TCL_OK) { goto error; } if (totalUnits < 0) { totalUnits = 0; } if (Tcl_GetInt(interp, argv[3], &windowUnits) != TCL_OK) { goto error; } if (windowUnits < 0) { windowUnits = 0; } if (Tcl_GetInt(interp, argv[4], &firstUnit) != TCL_OK) { goto error; } if (Tcl_GetInt(interp, argv[5], &lastUnit) != TCL_OK) { goto error; } if (totalUnits > 0) { if (lastUnit < firstUnit) { lastUnit = firstUnit; } } else { firstUnit = lastUnit = 0; } scrollPtr->totalUnits = totalUnits; scrollPtr->windowUnits = windowUnits; scrollPtr->firstUnit = firstUnit; scrollPtr->lastUnit = lastUnit; if (scrollPtr->totalUnits == 0) { scrollPtr->firstFraction = 0.0; scrollPtr->lastFraction = 1.0; } else { scrollPtr->firstFraction = ((double)firstUnit) / totalUnits; scrollPtr->lastFraction = ((double)(lastUnit + 1)) / totalUnits; } scrollPtr->flags &= ~NEW_STYLE_COMMANDS; } else { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " set firstFraction lastFraction\" or \"", argv[0], " set totalUnits windowUnits firstUnit lastUnit\"", (char *)NULL); goto error; } ComputeScrollbarGeometry(scrollPtr); EventuallyRedraw(scrollPtr); } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": must be activate, cget, configure, delta, fraction, ", "get, identify, or set", (char *)NULL); goto error; } done: Tcl_Release((ClientData)scrollPtr); return result; error: Tcl_Release((ClientData)scrollPtr); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * DestroyScrollbar -- * * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release * to clean up the internal structure of a scrollbar at a safe time * (when no-one is using it anymore). * * Results: * None. * * Side effects: * Everything associated with the scrollbar is freed up. * *---------------------------------------------------------------------- */ static void DestroyScrollbar(memPtr) DestroyData *memPtr; /* Info about scrollbar widget. */ { register Scrollbar *scrollPtr = (Scrollbar *)memPtr; /* * Free up all the stuff that requires special handling, then * let Tk_FreeOptions handle all the standard option-related * stuff. */ if (scrollPtr->troughGC != None) { Tk_FreeGC(scrollPtr->display, scrollPtr->troughGC); } if (scrollPtr->copyGC != None) { Tk_FreeGC(scrollPtr->display, scrollPtr->copyGC); } if (scrollPtr->activeTile != NULL) { Blt_FreeTile(scrollPtr->activeTile); } if (scrollPtr->tile != NULL) { Blt_FreeTile(scrollPtr->tile); } Tk_FreeOptions(configSpecs, (char *)scrollPtr, scrollPtr->display, 0); Blt_Free(scrollPtr); } /* *---------------------------------------------------------------------- * * TileChangedProc * * Routine for tile change notifications. * * Results: * None. * *---------------------------------------------------------------------- */ /*ARGSUSED*/ static void TileChangedProc(clientData, tile) ClientData clientData; Blt_Tile tile; /* Not used. */ { Scrollbar *scrollPtr = clientData; if (scrollPtr->tkwin != NULL) { EventuallyRedraw(scrollPtr); } } /* *---------------------------------------------------------------------- * * ConfigureScrollbar -- * * This procedure is called to process an argv/argc list, plus * the Tk option database, in order to configure (or * reconfigure) a scrollbar widget. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then interp->result contains an error message. * * Side effects: * Configuration information, such as colors, border width, * etc. get set for scrollPtr; old resources get freed, * if there were any. * *---------------------------------------------------------------------- */ static int ConfigureScrollbar(interp, scrollPtr, argc, argv, flags) Tcl_Interp *interp; /* Used for error reporting. */ register Scrollbar *scrollPtr; /* Information about widget; may or * may not already have values for * some fields. */ int argc; /* Number of valid entries in argv. */ char **argv; /* Arguments. */ int flags; /* Flags to pass to * Tk_ConfigureWidget. */ { size_t length; XGCValues gcValues; GC new; if (Tk_ConfigureWidget(interp, scrollPtr->tkwin, configSpecs, argc, argv, (char *)scrollPtr, flags) != TCL_OK) { return TCL_ERROR; } /* * A few options need special processing, such as parsing the * orientation or setting the background from a 3-D border. */ length = strlen(scrollPtr->orientUid); if (strncmp(scrollPtr->orientUid, "vertical", length) == 0) { scrollPtr->vertical = 1; } else if (strncmp(scrollPtr->orientUid, "horizontal", length) == 0) { scrollPtr->vertical = 0; } else { Tcl_AppendResult(interp, "bad orientation \"", scrollPtr->orientUid, "\": must be vertical or horizontal", (char *)NULL); return TCL_ERROR; } if (scrollPtr->command != NULL) { scrollPtr->commandSize = strlen(scrollPtr->command); } else { scrollPtr->commandSize = 0; } if (scrollPtr->activeTile != NULL) { Blt_SetTileChangedProc(scrollPtr->activeTile, TileChangedProc, (ClientData)scrollPtr); } if (scrollPtr->tile != NULL) { Blt_SetTileChangedProc(scrollPtr->tile, TileChangedProc, (ClientData)scrollPtr); } Tk_SetBackgroundFromBorder(scrollPtr->tkwin, scrollPtr->bgBorder); gcValues.foreground = scrollPtr->troughColorPtr->pixel; new = Tk_GetGC(scrollPtr->tkwin, GCForeground, &gcValues); if (scrollPtr->troughGC != None) { Tk_FreeGC(scrollPtr->display, scrollPtr->troughGC); } scrollPtr->troughGC = new; if (scrollPtr->copyGC == None) { gcValues.graphics_exposures = False; scrollPtr->copyGC = Tk_GetGC(scrollPtr->tkwin, GCGraphicsExposures, &gcValues); } /* * Register the desired geometry for the window (leave enough space * for the two arrows plus a minimum-size slider, plus border around * the whole window, if any). Then arrange for the window to be * redisplayed. */ ComputeScrollbarGeometry(scrollPtr); EventuallyRedraw(scrollPtr); return TCL_OK; } /* *-------------------------------------------------------------- * * DisplayScrollbar -- * * This procedure redraws the contents of a scrollbar window. * It is invoked as a do-when-idle handler, so it only runs * when there's nothing else for the application to do. * * Results: * None. * * Side effects: * Information appears on the screen. * *-------------------------------------------------------------- */ static void DisplayScrollbar(clientData) ClientData clientData; /* Information about window. */ { register Scrollbar *scrollPtr = clientData; register Tk_Window tkwin = scrollPtr->tkwin; XPoint points[7]; Tk_3DBorder border; int relief, width, elementBorderWidth; Pixmap pixmap; Blt_Tile tile; if ((scrollPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { goto done; } if (scrollPtr->vertical) { width = Tk_Width(tkwin) - 2 * scrollPtr->inset; } else { width = Tk_Height(tkwin) - 2 * scrollPtr->inset; } elementBorderWidth = scrollPtr->elementBorderWidth; if (elementBorderWidth < 0) { elementBorderWidth = scrollPtr->borderWidth; } /* * In order to avoid screen flashes, this procedure redraws * the scrollbar in a pixmap, then copies the pixmap to the * screen in a single operation. This means that there's no * point in time where the on-sreen image has been cleared. */ pixmap = Tk_GetPixmap(scrollPtr->display, Tk_WindowId(tkwin), Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin)); if (scrollPtr->highlightWidth != 0) { GC gc; if (scrollPtr->flags & GOT_FOCUS) { gc = Tk_GCForColor(scrollPtr->highlightColorPtr, pixmap); } else { gc = Tk_GCForColor(scrollPtr->highlightBgColorPtr, pixmap); } Tk_DrawFocusHighlight(tkwin, gc, scrollPtr->highlightWidth, pixmap); } Blt_Draw3DRectangle(tkwin, pixmap, scrollPtr->bgBorder, scrollPtr->highlightWidth, scrollPtr->highlightWidth, Tk_Width(tkwin) - 2 * scrollPtr->highlightWidth, Tk_Height(tkwin) - 2 * scrollPtr->highlightWidth, scrollPtr->borderWidth, scrollPtr->relief); if (scrollPtr->tile != NULL) { Blt_SetTileOrigin(tkwin, scrollPtr->tile, 0, 0); Blt_TileRectangle(tkwin, pixmap, scrollPtr->tile, scrollPtr->inset, scrollPtr->inset, (unsigned)(Tk_Width(tkwin) - 2 * scrollPtr->inset), (unsigned)(Tk_Height(tkwin) - 2 * scrollPtr->inset)); } else { XFillRectangle(scrollPtr->display, pixmap, scrollPtr->troughGC, scrollPtr->inset, scrollPtr->inset, (unsigned)(Tk_Width(tkwin) - 2 * scrollPtr->inset), (unsigned)(Tk_Height(tkwin) - 2 * scrollPtr->inset)); } /* * Draw the top or left arrow. The coordinates of the polygon * points probably seem odd, but they were carefully chosen with * respect to X's rules for filling polygons. These point choices * cause the arrows to just fill the narrow dimension of the * scrollbar and be properly centered. */ tile = NULL; if (scrollPtr->activeField == TOP_ARROW) { border = scrollPtr->activeBorder; relief = scrollPtr->activeField == TOP_ARROW ? scrollPtr->activeRelief : TK_RELIEF_RAISED; if (scrollPtr->activeTile != NULL) { Blt_SetTileOrigin(tkwin, scrollPtr->activeTile, 0, 0); tile = scrollPtr->activeTile; } } else { border = scrollPtr->bgBorder; relief = TK_RELIEF_RAISED; if (scrollPtr->tile != NULL) { tile = scrollPtr->tile; } } if (scrollPtr->vertical) { points[0].x = scrollPtr->inset - 1; points[0].y = scrollPtr->arrowLength + scrollPtr->inset - 1; points[1].x = width + scrollPtr->inset; points[1].y = points[0].y; points[2].x = width / 2 + scrollPtr->inset; points[2].y = scrollPtr->inset - 1; } else { points[0].x = scrollPtr->arrowLength + scrollPtr->inset - 1; points[0].y = scrollPtr->inset - 1; points[1].x = scrollPtr->inset; points[1].y = width / 2 + scrollPtr->inset; points[2].x = points[0].x; points[2].y = width + scrollPtr->inset; } if (tile != NULL) { Blt_TilePolygon(tkwin, pixmap, tile, points, 3); Tk_Draw3DPolygon(tkwin, pixmap, border, points, 3, scrollPtr->borderWidth, relief); } else { Tk_Fill3DPolygon(tkwin, pixmap, border, points, 3, scrollPtr->borderWidth, relief); } /* * Display the bottom or right arrow. */ tile = NULL; if (scrollPtr->activeField == BOTTOM_ARROW) { border = scrollPtr->activeBorder; relief = scrollPtr->activeField == BOTTOM_ARROW ? scrollPtr->activeRelief : TK_RELIEF_RAISED; if (scrollPtr->activeTile != NULL) { Blt_SetTileOrigin(tkwin, scrollPtr->activeTile, 0, 0); tile = scrollPtr->activeTile; } } else { border = scrollPtr->bgBorder; relief = TK_RELIEF_RAISED; if (scrollPtr->tile != NULL) { tile = scrollPtr->tile; } } if (scrollPtr->vertical) { points[0].x = scrollPtr->inset; points[0].y = Tk_Height(tkwin) - scrollPtr->arrowLength - scrollPtr->inset + 1; points[1].x = width / 2 + scrollPtr->inset; points[1].y = Tk_Height(tkwin) - scrollPtr->inset; points[2].x = width + scrollPtr->inset; points[2].y = points[0].y; } else { points[0].x = Tk_Width(tkwin) - scrollPtr->arrowLength - scrollPtr->inset + 1; points[0].y = scrollPtr->inset - 1; points[1].x = points[0].x; points[1].y = width + scrollPtr->inset; points[2].x = Tk_Width(tkwin) - scrollPtr->inset; points[2].y = width / 2 + scrollPtr->inset; } if (tile != NULL) { Blt_TilePolygon(tkwin, pixmap, tile, points, 3); Tk_Draw3DPolygon(tkwin, pixmap, border, points, 3, scrollPtr->borderWidth, relief); } else { Tk_Fill3DPolygon(tkwin, pixmap, border, points, 3, scrollPtr->borderWidth, relief); } /* * Display the slider. */ tile = NULL; if (scrollPtr->activeField == SLIDER) { border = scrollPtr->activeBorder; relief = scrollPtr->activeField == SLIDER ? scrollPtr->activeRelief : TK_RELIEF_RAISED; if (scrollPtr->activeTile != NULL) { Blt_SetTileOrigin(tkwin, scrollPtr->activeTile, 0, 0); tile = scrollPtr->activeTile; } } else { border = scrollPtr->bgBorder; relief = TK_RELIEF_RAISED; if (scrollPtr->tile != NULL) { tile = scrollPtr->tile; } } if (scrollPtr->vertical) { if (tile != NULL) { Blt_TileRectangle(tkwin, pixmap, tile, scrollPtr->inset, scrollPtr->sliderFirst, width - 1, scrollPtr->sliderLast - scrollPtr->sliderFirst - 1); Blt_Draw3DRectangle(tkwin, pixmap, border, scrollPtr->inset, scrollPtr->sliderFirst, width, scrollPtr->sliderLast - scrollPtr->sliderFirst, scrollPtr->borderWidth, relief); } else { Blt_Fill3DRectangle(tkwin, pixmap, border, scrollPtr->inset, scrollPtr->sliderFirst, width, scrollPtr->sliderLast - scrollPtr->sliderFirst, elementBorderWidth, relief); } } else { if (tile != NULL) { Blt_TileRectangle(tkwin, pixmap, tile, scrollPtr->sliderFirst, scrollPtr->inset, scrollPtr->sliderLast - scrollPtr->sliderFirst - 1, width - 1); Blt_Draw3DRectangle(tkwin, pixmap, border, scrollPtr->sliderFirst, scrollPtr->inset, scrollPtr->sliderLast - scrollPtr->sliderFirst, width, scrollPtr->borderWidth, relief); } else { Blt_Fill3DRectangle(tkwin, pixmap, border, scrollPtr->sliderFirst, scrollPtr->inset, scrollPtr->sliderLast - scrollPtr->sliderFirst, width, scrollPtr->borderWidth, relief); } } /* * Copy the information from the off-screen pixmap onto the screen, * then delete the pixmap. */ XCopyArea(scrollPtr->display, pixmap, Tk_WindowId(tkwin), scrollPtr->copyGC, 0, 0, (unsigned)Tk_Width(tkwin), (unsigned)Tk_Height(tkwin), 0, 0); Tk_FreePixmap(scrollPtr->display, pixmap); done: scrollPtr->flags &= ~REDRAW_PENDING; } /* *-------------------------------------------------------------- * * ScrollbarEventProc -- * * This procedure is invoked by the Tk dispatcher for various * events on scrollbars. * * Results: * None. * * Side effects: * When the window gets deleted, internal structures get * cleaned up. When it gets exposed, it is redisplayed. * *-------------------------------------------------------------- */ static void ScrollbarEventProc(clientData, eventPtr) ClientData clientData; /* Information about window. */ XEvent *eventPtr; /* Information about event. */ { Scrollbar *scrollPtr = clientData; if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) { EventuallyRedraw(scrollPtr); } else if (eventPtr->type == DestroyNotify) { if (scrollPtr->tkwin != NULL) { scrollPtr->tkwin = NULL; Tcl_DeleteCommandFromToken(scrollPtr->interp,scrollPtr->widgetCmd); } if (scrollPtr->flags & REDRAW_PENDING) { Tcl_CancelIdleCall(DisplayScrollbar, (ClientData)scrollPtr); } Tcl_EventuallyFree((ClientData)scrollPtr, (Tcl_FreeProc *)DestroyScrollbar); } else if (eventPtr->type == ConfigureNotify) { ComputeScrollbarGeometry(scrollPtr); EventuallyRedraw(scrollPtr); } else if (eventPtr->type == FocusIn) { if (eventPtr->xfocus.detail != NotifyInferior) { scrollPtr->flags |= GOT_FOCUS; if (scrollPtr->highlightWidth > 0) { EventuallyRedraw(scrollPtr); } } } else if (eventPtr->type == FocusOut) { if (eventPtr->xfocus.detail != NotifyInferior) { scrollPtr->flags &= ~GOT_FOCUS; if (scrollPtr->highlightWidth > 0) { EventuallyRedraw(scrollPtr); } } } } /* *---------------------------------------------------------------------- * * ScrollbarCmdDeletedProc -- * * This procedure is invoked when a widget command is deleted. If * the widget isn't already in the process of being destroyed, * this command destroys it. * * Results: * None. * * Side effects: * The widget is destroyed. * *---------------------------------------------------------------------- */ static void ScrollbarCmdDeletedProc(clientData) ClientData clientData; /* Pointer to widget record for widget. */ { Scrollbar *scrollPtr = clientData; Tk_Window tkwin = scrollPtr->tkwin; /* * This procedure could be invoked either because the window was * destroyed and the command was then deleted (in which case tkwin * is NULL) or because the command was deleted, and then this procedure * destroys the widget. */ if (tkwin != NULL) { #ifdef ITCL_NAMESPACES Itk_SetWidgetCommand(scrollPtr->tkwin, (Tcl_Command) NULL); #endif scrollPtr->tkwin = NULL; Tk_DestroyWindow(tkwin); } } /* *---------------------------------------------------------------------- * * ComputeScrollbarGeometry -- * * After changes in a scrollbar's size or configuration, this * procedure recomputes various geometry information used in * displaying the scrollbar. * * Results: * None. * * Side effects: * The scrollbar will be displayed differently. * *---------------------------------------------------------------------- */ static void ComputeScrollbarGeometry(scrollPtr) register Scrollbar *scrollPtr; /* Scrollbar whose geometry may * have changed. */ { int width, fieldLength; if (scrollPtr->highlightWidth < 0) { scrollPtr->highlightWidth = 0; } scrollPtr->inset = scrollPtr->highlightWidth + scrollPtr->borderWidth; width = (scrollPtr->vertical) ? Tk_Width(scrollPtr->tkwin) : Tk_Height(scrollPtr->tkwin); scrollPtr->arrowLength = width - 2 * scrollPtr->inset + 1; fieldLength = (scrollPtr->vertical ? Tk_Height(scrollPtr->tkwin) : Tk_Width(scrollPtr->tkwin)) - 2 * (scrollPtr->arrowLength + scrollPtr->inset); if (fieldLength < 0) { fieldLength = 0; } scrollPtr->sliderFirst = fieldLength * scrollPtr->firstFraction; scrollPtr->sliderLast = fieldLength * scrollPtr->lastFraction; /* * Adjust the slider so that some piece of it is always * displayed in the scrollbar and so that it has at least * a minimal width (so it can be grabbed with the mouse). */ if (scrollPtr->sliderFirst > (fieldLength - 2 * scrollPtr->borderWidth)) { scrollPtr->sliderFirst = fieldLength - 2 * scrollPtr->borderWidth; } if (scrollPtr->sliderFirst < 0) { scrollPtr->sliderFirst = 0; } if (scrollPtr->sliderLast < (scrollPtr->sliderFirst + MIN_SLIDER_LENGTH)) { scrollPtr->sliderLast = scrollPtr->sliderFirst + MIN_SLIDER_LENGTH; } if (scrollPtr->sliderLast > fieldLength) { scrollPtr->sliderLast = fieldLength; } scrollPtr->sliderFirst += scrollPtr->arrowLength + scrollPtr->inset; scrollPtr->sliderLast += scrollPtr->arrowLength + scrollPtr->inset; /* * Register the desired geometry for the window (leave enough space * for the two arrows plus a minimum-size slider, plus border around * the whole window, if any). Then arrange for the window to be * redisplayed. */ if (scrollPtr->vertical) { Tk_GeometryRequest(scrollPtr->tkwin, scrollPtr->width + 2 * scrollPtr->inset, 2 * (scrollPtr->arrowLength + scrollPtr->borderWidth + scrollPtr->inset)); } else { Tk_GeometryRequest(scrollPtr->tkwin, 2 * (scrollPtr->arrowLength + scrollPtr->borderWidth + scrollPtr->inset), scrollPtr->width + 2 * scrollPtr->inset); } Tk_SetInternalBorder(scrollPtr->tkwin, scrollPtr->inset); } /* *-------------------------------------------------------------- * * ScrollbarPosition -- * * Determine the scrollbar element corresponding to a * given position. * * Results: * One of TOP_ARROW, TOP_GAP, etc., indicating which element * of the scrollbar covers the position given by (x, y). If * (x,y) is outside the scrollbar entirely, then OUTSIDE is * returned. * * Side effects: * None. * *-------------------------------------------------------------- */ static int ScrollbarPosition(scrollPtr, x, y) register Scrollbar *scrollPtr; /* Scrollbar widget record. */ int x, y; /* Coordinates within scrollPtr's * window. */ { int length, width, tmp; if (scrollPtr->vertical) { length = Tk_Height(scrollPtr->tkwin); width = Tk_Width(scrollPtr->tkwin); } else { tmp = x; x = y; y = tmp; length = Tk_Width(scrollPtr->tkwin); width = Tk_Height(scrollPtr->tkwin); } if ((x < scrollPtr->inset) || (x >= (width - scrollPtr->inset)) || (y < scrollPtr->inset) || (y >= (length - scrollPtr->inset))) { return OUTSIDE; } /* * All of the calculations in this procedure mirror those in * DisplayScrollbar. Be sure to keep the two consistent. */ if (y < (scrollPtr->inset + scrollPtr->arrowLength)) { return TOP_ARROW; } if (y < scrollPtr->sliderFirst) { return TOP_GAP; } if (y < scrollPtr->sliderLast) { return SLIDER; } if (y >= (length - (scrollPtr->arrowLength + scrollPtr->inset))) { return BOTTOM_ARROW; } return BOTTOM_GAP; } /* *-------------------------------------------------------------- * * EventuallyRedraw -- * * Arrange for one or more of the fields of a scrollbar * to be redrawn. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static void EventuallyRedraw(scrollPtr) register Scrollbar *scrollPtr; /* Information about widget. */ { if ((scrollPtr->tkwin == NULL) || (!Tk_IsMapped(scrollPtr->tkwin))) { return; } if ((scrollPtr->flags & REDRAW_PENDING) == 0) { Tcl_DoWhenIdle(DisplayScrollbar, (ClientData)scrollPtr); scrollPtr->flags |= REDRAW_PENDING; } } int Blt_ScrollbarInit(interp) Tcl_Interp *interp; { static Blt_CmdSpec cmdSpec = { #if HAVE_NAMESPACES "scrollbar", ScrollbarCmd, #else "tilescrollbar", ScrollbarCmd, #endif /* HAVE_NAMESPACES */ }; if (Blt_InitCmd(interp, "blt::tile", &cmdSpec) == NULL) { return TCL_ERROR; } return TCL_OK; } #endif /* NO_TILESCROLLBAR */ blt-2.4z.orig/win/0042755000175000017500000000000007553201250012545 5ustar dokodokoblt-2.4z.orig/win/install.tcl0100644000175000017500000005315007240160121014710 0ustar dokodoko# # Script for installation of BLT under Windows # namespace eval Installer { variable commandList {} variable cmdLog {} variable component array set component { binaries 1 headers 1 html 1 scripts 1 demos 1 } variable totalBytes 0 variable totalFiles 0 variable panel 0 variable panelList { Welcome Directory Components Ready Finish } } proc Installer::DoInstall { package version } { global prefix srcdir regsub {\.} $version {} v2 variable scriptdir set scriptdir $prefix/lib/blt${version} variable component global tcl_platform if { $component(binaries) } { if { $tcl_platform(platform) == "unix" } { Add ${srcdir}/src -perm 0755 \ -file bltwish \ -file bltsh \ -rename "bltwish bltwish${v2}" \ -rename "bltsh bltsh${v2}" \ $prefix/bin set ext [info sharedlibextension] Add ${srcdir}/src -perm 0755 \ -file libBLT${v2}.a \ -file libBLTlite${v2}.a \ -file shared/libBLT${v2}${ext} \ -file shared/libBLTlite${v2}${ext} \ $prefix/lib } else { Add ${srcdir}/src -perm 0755 \ -file bltwish.exe \ -file bltsh.exe \ -file BLT${v2}.dll \ -file BLTlite${v2}.dll \ -rename "bltwish.exe bltwish${v2}.exe" \ -rename "bltsh.exe bltsh${v2}.exe" \ $prefix/bin Add ${srcdir}/src -perm 0755 \ -file BLT${v2}.lib \ -file BLTlite${v2}.lib \ $prefix/lib } } if { $component(headers) } { Add ${srcdir}/src \ -file blt.h \ -file bltChain.h \ -file bltVector.h \ -file bltTree.h \ $prefix/include } if { $component(html) } { Add ${srcdir}/html -pattern *.html $scriptdir/html } if { $component(scripts) } { Add ${srcdir} -file README -file PROBLEMS $scriptdir Add ${srcdir}/library \ -pattern *.cur \ -pattern *.tcl \ -pattern *.pro \ -file tclIndex \ $scriptdir Add ${srcdir}/library/dd_protocols \ -pattern *.tcl \ -file tclIndex \ $scriptdir/dd_protocols } if { $component(demos) } { Add ${srcdir}/demos \ -pattern *.tcl \ -file htext.txt \ $scriptdir/demos Add ${srcdir}/demos/bitmaps -pattern *.xbm $scriptdir/bitmaps Add ${srcdir}/demos/bitmaps/hand -pattern *.xbm $scriptdir/bitmaps/hand Add ${srcdir}/demos/bitmaps/fish -pattern *.xbm $scriptdir/bitmaps/fish Add ${srcdir}/demos/images \ -pattern *.gif \ -file out.ps \ $scriptdir/images Add ${srcdir}/demos/scripts -pattern *.tcl $scriptdir/scripts } Install $package $version } proc Installer::InstallDirectory { dest } { variable commandList lappend commandList [list CheckPath $dest] } proc Installer::Update { src dest size perm } { variable currentBytes variable totalBytes .install.text insert end "file copy -force $src $dest\n" if { [catch {file copy -force $src $dest} results] != 0 } { .install.text insert end "Error: $results\n" fail } else { incr currentBytes $size } global tcl_platform if { $tcl_platform(platform) == "unix" } { .install.text insert end "file attributes $dest -permissions $perm\n" if { [catch {file attributes $dest -permissions $perm} results] != 0 } { .install.text insert end "Error: $results\n" fail } } set percent [expr round(double($currentBytes)/$totalBytes * 100.0)] .install.current configure -text "$percent% complete" update } proc Installer::InstallFile { src dest perm } { variable commandList variable totalBytes variable totalFiles if { [catch { file size $src } size ] != 0 } { set size 0 } lappend commandList [list Update $src $dest $size $perm] incr totalBytes $size incr totalFiles } proc Installer::Add { dir args } { variable commandList variable totalBytes if { ![file exists $dir] } { error "can't find directory \"$dir\"" } set argc [llength $args] set destDir [lindex $args end] incr argc -2 set perm 0644 InstallDirectory $destDir foreach { option value } [lrange $args 0 $argc] { switch -- $option { "-pattern" { foreach f [lsort [glob $dir/$value]] { InstallFile $f $destDir/[file tail $f] $perm } } "-rename" { set src [lindex $value 0] set dest [lindex $value 1] InstallFile $dir/$src $destDir/$dest $perm } "-perm" { set perm $value } "-file" { InstallFile $dir/$value $destDir/$value $perm } default { error "Unknown option \"$option\"" } } } } proc Installer::CheckPath { dest } { set save [pwd] if { [file pathtype $dest] == "absolute" } { if { [string match {[a-zA-Z]:*} $dest] } { cd [string range $dest 0 2] set dest [string range $dest 3 end] } else { cd / set dest [string range $dest 1 end] } } set dirs [file split $dest] foreach d $dirs { if { ![file exists $d] } { .install.text insert end "file mkdir $d\n" if { [catch { file mkdir $d } result] != 0 } { .install.text insert end "Error: $result\n" fail break } } if { ![file isdirectory $d] } { .install.text insert end "Error: Not a directory: \"$d\"" fail break } update cd $d } cd $save } proc Installer::MakePackageIndex { package version file } { global prefix set suffix [info sharedlibextension] regsub {\.} $version {} version_no_dots set libName "${package}${version_no_dots}${suffix}" set libPath [file join ${prefix}/bin $libName] set cmd [list load $libPath $package] if { [file exists $file] } { file delete $file } set cmd { set fid [open $file "w"] puts $fid "# Package Index for $package" puts $fid "# generated on [clock format [clock seconds]]" puts $fid "" puts $fid [list package ifneeded $package $version $cmd] close $fid } if { [catch $cmd result] != 0 } { .install.text insert end "Error: $result\n" fail } } proc Installer::SetRegistryKey { package version valueName } { variable scriptdir global tcl_version package require registry set key HKEY_LOCAL_MACHINE\\Software\\$package\\$version\\$tcl_version registry set $key $valueName $scriptdir } proc Installer::Install { package version } { variable commandList variable totalBytes variable currentBytes 0 variable totalFiles variable scriptdir .install.totals configure -text "Files: $totalFiles Size: $totalBytes" foreach cmd $commandList { if { ![winfo exists .install] } { return } if { [catch $cmd result] != 0 } { .install.text insert end "Error: $result\n" fail } update } global tcl_version tcl_platform prefix set name [string tolower $package] MakePackageIndex $package $version $scriptdir/pkgIndex.tcl MakePackageIndex $package $version \ $prefix/lib/tcl${tcl_version}/${name}${version}/pkgIndex.tcl if { $tcl_platform(platform) == "windows" } { SetRegistryKey $package $version ${package}_LIBRARY } .install.cancel configure -text "Done" } proc Installer::Next {} { variable panel variable continue variable panelList incr panel set max [llength $panelList] if { $panel >= $max } { exit 0 } if { ($panel + 1) == $max } { .next configure -text "Finish" .cancel configure -state disabled } else { .next configure -text "Next" } if { $panel > 0 } { .back configure -state normal } set continue 1 } proc Installer::Back {} { variable panel variable continue incr panel -1 if { $panel <= 0 } { .back configure -state disabled set panel 0 } else { .back configure -state normal } .next configure -text "Next" .cancel configure -state normal set continue 0 } proc Installer::Cancel {} { exit 0 } if { $tcl_platform(platform) == "unix" } { font create textFont -family Helvetica -weight normal -size 11 font create titleFont -family Helvetica -weight normal -size 14 } else { font create titleFont -family Arial -weight bold -size 12 font create textFont -family Arial -weight normal -size 9 } font create hugeFont -family {Times New Roman} -size 18 -slant italic \ -weight bold proc Installer::MakeLink { widget tag command } { $widget tag configure $tag -foreground blue -underline yes $widget tag bind $tag \ "$command; $widget tag configure $tag -foreground blue" $widget tag bind $tag \ [list $widget tag configure $tag -foreground red] } proc Installer::Welcome { package version } { global tcl_version if { [winfo exists .panel] } { destroy .panel } text .panel -wrap word -width 10 -height 18 \ -relief flat -padx 4 -pady 4 -cursor arrow \ -background [. cget -bg] .panel tag configure welcome -font titleFont -justify center \ -foreground navyblue .panel tag configure package -font hugeFont -foreground red \ -justify center MakeLink .panel next "Installer::Next" MakeLink .panel cancel "Installer::Cancel" .panel insert end "Welcome!\n" welcome .panel insert end "\n" .panel insert end \ "This installs the compiled \n" "" \ "${package} ${version}\n" package \ "binaries and components from the source directories to " "" \ "where Tcl/Tk is currently installed.\n\nThe compiled binaries " "" \ "require Tcl/Tk $tcl_version.\n\n" .panel insert end \ "Press the " "" \ "Next" next \ " button to continue. Press the " "" \ "Cancel" cancel \ " button if you do not wish to install $package at this time." .panel configure -state disabled blt::table . \ 0,1 .panel -columnspan 3 -pady 10 -padx { 0 10 } -fill x -anchor n tkwait variable Installer::continue } option add *Hierbox.openCommand {Installer::OpenDir %W "%P" %n} proc Installer::OpenDir { widget path atnode } { puts path=$path set save [pwd] global tcl_platform if { $tcl_platform(platform) == "windows" } { if { $path == "/" } { foreach v [file volumes] { if { ![string match {[A-B]:/} $v] } { .browser.h insert end $v -button yes } } return } set path [string trimleft $path /] } cd $path/ foreach dir [lsort [glob -nocomplain */ ]] { set node [$widget insert -at $atnode end $dir] # Does the directory have subdirectories? set subdirs [glob -nocomplain $dir/*/ ] if { $subdirs != "" } { $widget entry configure $node -button yes } else { $widget entry configure $node -button no } } cd $save } proc Installer::CenterPanel { panel } { update idletasks set x [expr ([winfo width .] - [winfo reqwidth $panel]) / 2] set y [expr ([winfo height .] - [winfo reqheight $panel]) / 2] incr x [winfo rootx .] incr y [winfo rooty .] wm geometry $panel +$x+$y wm deiconify $panel } proc Installer::Browse { } { if { [winfo exists .browser] } { raise .browser wm deiconify .browser return } toplevel .browser entry .browser.entry -bg white -borderwidth 2 -relief sunken \ -textvariable Installer::selection bind .browser.entry { .browser.ok flash .browser.ok invoke } blt::hierbox .browser.h -hideroot yes -separator / -height 1i -width 3i \ -borderwidth 2 -relief sunken -autocreate yes -trim / \ -yscrollcommand { .browser.sbar set } \ -selectcommand { set index [.browser.h curselection] set path [lindex [.browser.h get -full $index] 0] if { $tcl_platform(platform) == "windows" } { set path [string trimleft $path /] } puts $path set Installer::selection $path } scrollbar .browser.sbar -command { .browser.h yview } wm protocol .browser WM_DELETE_WINDOW { .browser.cancel invoke } wm transient .browser . frame .browser.sep -height 2 -borderwidth 1 -relief sunken button .browser.ok -text "Continue" -command { set prefix $Installer::selection grab release .browser destroy .browser } button .browser.cancel -text "Cancel" -command { grab release .browser destroy .browser } global tcl_platform global prefix if { $tcl_platform(platform) == "windows" } { set root "C:/" .browser.h open "C:/" .browser.h open "C:/Program Files" if { [file exists $prefix] } { .browser.h see $prefix/ } } else { set root /usr/local #.browser.h open $root } set Installer::selection $prefix wm title .browser "Installer: Select Install Directory" blt::table .browser \ 0,0 .browser.entry -fill x -columnspan 2 -padx 4 -pady 4 \ 1,0 .browser.h -fill both -columnspan 2 -padx 4 -pady { 0 4 } \ 1,2 .browser.sbar -fill y \ 2,0 .browser.sep -fill x -padx 10 -cspan 3 -pady { 4 0 } \ 3,0 .browser.ok -width .75i -padx 4 -pady 4 \ 3,1 .browser.cancel -width .75i -padx 4 -pady 4 blt::table configure .browser c2 r0 r2 r3 -resize none wm withdraw .browser after idle { Installer::CenterPanel .browser grab set .browser } } proc Installer::Directory { package version } { global tcl_version if { [winfo exists .panel] } { destroy .panel } frame .panel text .panel.text -wrap word -width 10 \ -height 10 -borderwidth 0 -padx 4 -pady 4 -cursor arrow \ -background [.panel cget -background] .panel.text tag configure title -font titleFont -justify center \ -foreground navyblue .panel.text insert end "Select Destination Directory\n" title .panel.text insert end "\n\n" .panel.text insert end "Please select the directory where Tcl/Tk \ $tcl_version is installed. This is also where $package $version will be \ installed.\n" .panel.text configure -state disabled frame .panel.frame -relief groove -borderwidth 2 label .panel.frame.label -textvariable ::prefix button .panel.frame.button -text "Browse..." -command Installer::Browse blt::table .panel.frame \ 0,0 .panel.frame.label -padx 4 -pady 4 -anchor w \ 0,1 .panel.frame.button -padx 4 -pady 4 -anchor e blt::table .panel \ 0,0 .panel.text -padx 4 -pady 4 -fill both \ 1,0 .panel.frame -padx 4 -fill x blt::table . \ 0,1 .panel -columnspan 3 -pady 10 -padx { 0 10 } -fill both tkwait variable Installer::continue } proc Installer::Components { package version } { global tcl_version if { [winfo exists .panel] } { destroy .panel } regsub {\.} $version {} v2 frame .panel text .panel.text -wrap word -width 10 \ -height 8 -borderwidth 0 -padx 4 -pady 4 -cursor arrow \ -background [.panel cget -background] .panel.text tag configure title -font titleFont -justify center \ -foreground navyblue .panel.text insert end "Select Components\n" title .panel.text insert end "\n\n" .panel.text insert end "Please select the components you wish to install. \ You should install all components.\n" .panel.text configure -state disabled frame .panel.frame -relief groove -borderwidth 2 variable component global tcl_platform if { $tcl_platform(platform) == "unix" } { set ext [info sharedlibextension] set sharedlib lib${package}${v2}${ext} set lib lib${package}${v2}.a set exe "" } else { set sharedlib ${package}${v2}.dll set lib ${package}${v2}.lib set exe ".exe" } checkbutton .panel.frame.binaries \ -text "bltwish${exe} and Shared Library" \ -variable Installer::component(binaries) checkbutton .panel.frame.scripts \ -text "Script Library" \ -variable Installer::component(scripts) checkbutton .panel.frame.headers \ -text "Include Files and Static Library" \ -variable Installer::component(headers) checkbutton .panel.frame.html -text "HTML Manual Pages" \ -variable Installer::component(html) checkbutton .panel.frame.demos -text "Demos" \ -variable Installer::component(demos) blt::table .panel.frame \ 0,0 .panel.frame.binaries -padx 4 -pady 4 -anchor w \ 1,0 .panel.frame.scripts -padx 4 -pady 4 -anchor w \ 2,0 .panel.frame.headers -padx 4 -pady 4 -anchor w \ 3,0 .panel.frame.html -padx 4 -pady 4 -anchor w \ 4,0 .panel.frame.demos -padx 4 -pady 4 -anchor w blt::table .panel \ 0,0 .panel.text -padx 4 -pady 4 -fill both \ 1,0 .panel.frame -padx 4 -fill both blt::table . \ 0,1 .panel -columnspan 3 -pady 10 -padx { 0 10 } -fill both tkwait variable Installer::continue } proc Installer::Ready { package version } { global tcl_version if { [winfo exists .panel] } { destroy .panel } text .panel -wrap word -width 10 -height 18 \ -relief flat -padx 4 -pady 4 -cursor arrow \ -background [. cget -bg] .panel tag configure welcome -font titleFont -justify center \ -foreground navyblue .panel tag configure package -font hugeFont -foreground red \ -justify center MakeLink .panel next "Installer::Next" MakeLink .panel cancel "Installer::Cancel" MakeLink .panel back "Installer::Back" .panel insert end "Ready To Install!\n" welcome .panel insert end "\n" .panel insert end "We're now ready to install ${package} ${version} \ and its components.\n\n" .panel insert end \ "Press the " "" \ "Next" next \ " button to install all selected components.\n\n" "" .panel insert end \ "To reselect components, click on the " "" \ "Back" back \ " button.\n\n" .panel insert end \ "Press the " "" \ "Cancel" cancel \ " button if you do not wish to install $package at this time." .panel configure -state disabled blt::table . \ 0,1 .panel -columnspan 3 -pady 10 -padx { 0 10 } -fill x -anchor n tkwait variable Installer::continue if { $Installer::continue } { Results update DoInstall $package $version } } proc Installer::Results { } { if { [winfo exists .install] } { destroy .install } toplevel .install text .install.text -height 10 -width 50 -wrap none -bg white \ -yscrollcommand { .install.ybar set } \ -xscrollcommand { .install.xbar set } .install.text tag configure fail -foreground red label .install.totals -text "Files: 0 Bytes: 0" -width 50 label .install.current -text "Installing:\n" -height 2 -width 50 scrollbar .install.ybar -command { .install.text yview } scrollbar .install.xbar -command { .install.text xview } -orient horizontal wm protocol .install WM_DELETE_WINDOW { .install.cancel invoke } wm transient .install . button .install.cancel -text "Cancel" -command { grab release .install destroy .install } blt::table .install \ 0,0 .install.totals -anchor w -columnspan 2 \ 1,0 .install.current -anchor w -cspan 2 \ 2,0 .install.text -fill both \ 2,1 .install.ybar -fill y \ 3,0 .install.xbar -fill x \ 4,0 .install.cancel -width .75i -padx 4 -pady 4 -cspan 2 blt::table configure .install c1 r0 r1 r3 -resize none wm withdraw .install after idle { Installer::CenterPanel .install grab set .install } } proc Installer::Finish { package version } { global tcl_version if { [winfo exists .panel] } { destroy .panel } text .panel -wrap word -width 10 -height 18 \ -relief flat -padx 4 -pady 4 -cursor arrow \ -background [. cget -bg] .panel tag configure welcome -font titleFont -justify center \ -foreground navyblue .panel tag configure package -font hugeFont -foreground red \ -justify center .panel insert end "Installation Completed\n" welcome .panel insert end "\n" .panel insert end "${package} ${version} is now installed.\n\n" MakeLink .panel finish "Installer::Next" .panel insert end \ "Press the " "" \ "Finish" finish \ " button to exit this installation" .panel configure -state disabled blt::table . \ 0,1 .panel -columnspan 3 -pady 10 -padx { 0 10 } -fill x -anchor n tkwait variable Installer::continue } set prefix [lindex $argv 2] set srcdir [lindex $argv 1] set version [lindex $argv 0] set version 2.4 set package BLT regsub {\.} $version {} v2 set ext [info sharedlibextension] if { $tcl_platform(platform) == "unix" } { set ext [info sharedlibextension] set sharedlib shared/lib${package}${v2}${ext} set prefix "/usr/local/blt" } else { set sharedlib ${package}${v2}.dll set prefix "C:/Program Files/Tcl" } if { [file exists ./src/$sharedlib] } { load ./src/$sharedlib $package } else { error "Can't find library \"$sharedlib\" to load" } set blt_library $srcdir/library image create photo openFolder -format gif -data { R0lGODlhEAANAPIAAAAAAH9/f7+/v///////AAAAAAAAAAAAACH+JEZpbGUgd3JpdHRlbiBi eSBBZG9iZSBQaG90b3Nob3CoIDUuMAAsAAAAABAADQAAAzk4Gsz6cIQ44xqCZCGbk4MmclAA gNs4ml7rEaxVAkKc3gTAnBO+sbyQT6M7gVQpk9HlAhgHzqhUmgAAOw== } image create photo closeFolder -format gif -data { R0lGODlhEAANAPIAAAAAAH9/f7+/v///AP///wAAAAAAAAAAACH+JEZpbGUgd3JpdHRlbiBi eSBBZG9iZSBQaG90b3Nob3CoIDUuMAAsAAAAABAADQAAAzNIGsz6kAQxqAjxzcpvc1KWBUDY nRQZWmilYi37EmztlrAt43R8mzrO60P8lAiApHK5TAAAOw== } image create photo blt -file ${srcdir}/demos/images/blt98.gif option add *Text.font textFont option add *HighlightThickness 0 option add *Hierbox.icons "closeFolder openFolder" option add *Hierbox.button yes set color \#accaff option add *Frame.background $color option add *Toplevel.background $color #option add *Button.background $color option add *Checkbutton.background $color option add *Label.background $color option add *Text.background $color . configure -bg $color wm title . "$package $version Installer" label .image -image blt -borderwidth 2 -relief groove button .back -text "Back" -state disabled -command Installer::Back -underline 0 button .next -text "Next" -command Installer::Next -underline 0 button .cancel -text "Cancel" -command Installer::Cancel -underline 0 frame .sep -height 2 -borderwidth 1 -relief sunken blt::table . \ 0,0 .image -fill both -padx 10 -pady 10 \ 1,0 .sep -fill x -padx 4 -pady 4 -columnspan 4 -padx 5 \ 2,1 .back -anchor e -padx 4 -pady 4 \ 2,2 .next -anchor w -padx 4 -pady 4 \ 2,3 .cancel -padx 20 -pady 4 blt::table configure . .back .next .cancel -width .75i blt::table configure . r1 r2 -resize none blt::table configure . r3 -height 0.125i while { 1 } { namespace eval Installer { variable panel set cmd [lindex $panelList $panel] eval [list $cmd $package $version] } update } blt-2.4z.orig/win/README0100644000175000017500000002243007527120102013416 0ustar dokodoko This file describes how to build BLT under Windows 95/98/NT/2000/XP. It's not necessary to compile BLT for Windows 95/98/NT/2000/XP. Binary versions are available on ftp.tcltk.com/pub/blt. http://www.sourceforge.net/projects/blt/files/blt2.4z-for-8.0.exe -or- http://www.sourceforge.net/projects/blt/files/blt2.4z-for-8.1.exe -or- http://www.sourceforge.net/projects/blt/files/blt2.4z-for-8.2.exe -or- http://www.sourceforge.net/projects/blt/files/blt2.4z-for-8.3.exe They will dynamically load into wish80.exe, wish81.exe, wish82.exe, or wish83.exe by invoking package require BLT from within your script. If you really need to build BLT yourself, then hold onto your hat. It's a lot more difficult to build BLT under Windows than under Unix. Most Windows software is designed to be delivered as a self-installing binary executable, therefore it's rare to find the installation tools necessary to build and install BLT from the source code. 1. What versions of Tcl/Tk can I use? Any stable release. I've built and tested BLT with Tcl/Tk versions 8.0.5, 8.1.1, and 8.2.3, and 8.3.4. Avoid the alpha and beta versions. 2. What compiler can I use? You can use one of the following compilers: 1. Microsoft Visual C++ 5.0/6.0 2. Cygwin's GNU CC 2.95.2 (with or without -mno-cygwin) 3. Borland Free compiler 5.5.1 I normally build with VC++ 6.0. This is also what the binary Tcl/Tk distribution use. Note: Unless it's your only option, I don't recommend using the Borland free compiler right now. 3. What "make" program do I need? I highly recommend installing the Cygwin tool suite. You can pick this up from http://sourceware.cygnus.com/cygwin/setup.exe I normally use GNU make instead of Microsoft's nmake. But you can also nmake. If you have a choice, use the Cygnus tools. For compiling with Borland's C compiler, you can use Borland's make.exe. 4. Do I need to compile the Tcl/Tk libraries? More than likely. Unless you're compiling with Cygwin GCC and the cygwin-version of the Tcl/Tk libraries, you'll need to obtain the Tcl/Tk sources and compile them. 5. Is there anything else I need? By default, JPEG support is enabled. It uses the jpeg-6b libraries from ftp.uu.net. You can pick up the sources from ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz You can also use the Intel JPEG Libraries. JPEG support is optional. You can disable it. 6. Can I mix-and-match DLLs? You can't really mix the Borland and VC++ compiled DLLs. BLT isn't stubbed and the symbol names are incompatible between versions. The various workarounds are difficult. I haven't tested this, but I believe you can load a GNU CC (-mno-cygwin) BLT24.dll into a VC++ compiled wish. In general the best advice is to use the same compiler that that you compiled Tcl/Tk to compile BLT. 7. What compiler should I use? Right now, probably Microsoft VC++. This is what all Tcl/Tk releases 8.0 to present have been built with. So you shouldn't have to work too hard to compile the Tcl and Tk libraries. Having said that, Cygwin's GNU CC works just fine. You can obtain versions from Mumit Khan to build Tcl and Tk. I recommend compiling the Tcl/Tk libraries yourself with the -mno-cygwin option. And if compiling Tcl and Tk is too much of a hassle, you can always built BLT with the cygwin Tcl/Tk libraries (cygtcl80.dll and cygtk80.dll). The downside is that the cygwin libraries are 1) pretty old (version 8.0) and 2) there may be some incompatibilities between the native Win32 calls in BLT and the cygwin emulation layer. I have built BLT with the Borland free compiler. It's not 100% yet. The problems are 1) If you automatically load BLT from a script file, you will generate exception in the DLL. Oddly enough, you can source the script manually. 2) Resampled images are blank (see the graph3.tcl and eps.tcl demos). The same code works with both GCC and VC++. 3) I can't even get wish83.exe to open a console window. Weirdly, bltwish.exe does this properly. 4) The turbo debugger is a pain. Building BLT with Microsoft VC++, Cygwin Make, and VC++ compiled Tcl/Tk libraries. =================================================================== 1. Install the Tcl/Tk sources. They should reside in the same directory tree as the BLT sources. ______________|______________ | | | | blt2.4 tcl8.3.4 tk8.3.4 jpeg-6b 2. Build and install the Tcl and Tk libraries. cd tcl8.3.4/win nmake -f Makefile.vc nmake -f Makefile.vc install cd ../../tk8.3.4/win nmake -f Makefile.vc nmake -f Makefile.vc install 3. In the BLT directory, edit ./win/makedefs. Set the following macros. v1 = 8.3 Tcl/Tk version. v2 = 83 Version number without dots. v3 = 8.3.4 Suffix of Tcl/Tk directories prefix = C:/Program\ Files/Tcl Location of installed Tcl/Tk files. TOOLS32 = C:/Program\ Files/Microsoft\ Visual\ Studio/VC90 Location of MS C compiler and tools. HAVE_JPEG = 0 4. Compile and install. make -f Makefile.vc make -f Makefile.vc install 5. Add the location of BLT24.dll to your PATH variable and test BLT cd demos export PATH=/cygdrive/c/Program\ Files/Tcl/bin:$PATH bltwish.exe graph1.tcl Building BLT with Microsoft VC++, nmake, and VC++ compiled Tcl/Tk libraries. ==================================================================== 1. Install the Tcl/Tk sources. They should reside in the same directory tree as the BLT sources. ______________|______________ | | | | blt2.4 tcl8.3.4 tk8.3.4 jpeg-6b 2. Build and install the Tcl and Tk libraries. cd tcl8.3.4\win nmake -f Makefile.vc nmake -f Makefile.vc install cd ..\..\tk8.3.4\win nmake -f Makefile.vc nmake -f Makefile.vc install 3. In the BLT directory, edit .\win\makedefs. Set the following macros. v1 = 8.3 Tcl/Tk version. v2 = 83 Version number without dots. v3 = 8.3.4 Suffix of Tcl/Tk directories prefix = C:/Program\ Files/Tcl Location of installed Tcl/Tk files. TOOLS32 = C:/Program\ Files/Microsoft\ Visual\ Studio/VC90 Location of MS C compiler and tools. HAVE_JPEG = 0 4. Compile BLT. make -f blt.mak 5. Install BLT Since Windows doesn't provide tools to install software, we'll use Tcl/Tk to do it. There's an install script in ./win/install.tcl. Add the location of wish83.exe to your PATH and run wish83.exe. wish83.exe ./win/install.tcl 6. Test BLT cd demos bltwish.exe graph1.tcl Building BLT with Cygwin GCC and mingw (-mno-cygwin) Tcl/Tk libraries. ====================================================================== 1. Install the Tcl/Tk sources. They should reside in the same directory tree as the BLT sources. ______________|______________ | | | | blt2.4 tcl8.3.4 tk8.3.4 jpeg-6b 2. Install the cygwin tool suite. 3. Build and install the Tcl and Tk libraries. cd tcl8.3.4/win ./configure --prefix=/usr/local/tcl8.3.4 make make install cd ../../tk8.3.4/win ./configure --prefix=/usr/local/tcl8.3.4 make make install 3. Compile and install BLT. ./configure --disable-cygwin --prefix=/usr/local/tcl8.3.4 make make install 4. Test BLT Add the location of wish83.exe to your PATH and run bltwish.exe. cd demos bltwish.exe graph1.tcl Building BLT with Cygwin GCC and the cygwin distribution Tcl/Tk libraries. ============================================================= 1. Install the cygwin tool suite. 2. Compile and install BLT. ./configure --disable-cygwin --with-scriptdir=/usr/share --prefix=/usr make make install 3. Test BLT Add the location of wish83.exe to your PATH and run bltwish.exe. cd demos bltwish.exe graph1.tcl Building BLT with Borland bcc55 and Borland compiled Tcl/Tk libraries. ====================================================================== 1. Install the Tcl/Tk sources. They should reside in the same directory tree as the BLT sources. ______________|______________ | | | | blt2.4 tcl8.3.4 tk8.3.4 jpeg-6b 2. Build and install the Tcl and Tk libraries. cd tcl8.3.4\win make -f Makefile.bc make -f Makefile.bc install cd ..\..\tk8.3.4\win make -f Makefile.bc make -f Makefile.bc install 3. In the BLT directory, edit .\win\makedefs. Set the following macros. v1 = 8.3 Tcl/Tk version. v2 = 83 Version number without dots. v3 = 8.3.4 Suffix of Tcl/Tk directories 4. Edit .\src\Makefile.bc prefix = C:\Program Files\Tcl Location of installed Tcl/Tk files. TOOLS32 = C:\Borland\BCC55\ Location of Borland C compiler and tools. HAVE_JPEG = 0 4. Compile BLT. cd src make -f Makefile.bc 5. Install BLT Since Windows doesn't provide tools to install software, we'll use Tcl/Tk to do it. There's an install script in ./win/install.tcl. Add the location of wish83.exe to your PATH and run wish83.exe. wish83.exe ./win/install.tcl 6. Test BLT cd demos bltwish.exe graph1.tcl blt-2.4z.orig/win/X11/0042755000175000017500000000000007553201250013116 5ustar dokodokoblt-2.4z.orig/win/X11/Xatom.h0100644000175000017500000000472607514116170014366 0ustar dokodoko#ifndef XATOM_H #define XATOM_H 1 /* THIS IS A GENERATED FILE * * Do not change! Changing this file implies a protocol change! */ #define XA_PRIMARY ((Atom) 1) #define XA_SECONDARY ((Atom) 2) #define XA_ARC ((Atom) 3) #define XA_ATOM ((Atom) 4) #define XA_BITMAP ((Atom) 5) #define XA_CARDINAL ((Atom) 6) #define XA_COLORMAP ((Atom) 7) #define XA_CURSOR ((Atom) 8) #define XA_CUT_BUFFER0 ((Atom) 9) #define XA_CUT_BUFFER1 ((Atom) 10) #define XA_CUT_BUFFER2 ((Atom) 11) #define XA_CUT_BUFFER3 ((Atom) 12) #define XA_CUT_BUFFER4 ((Atom) 13) #define XA_CUT_BUFFER5 ((Atom) 14) #define XA_CUT_BUFFER6 ((Atom) 15) #define XA_CUT_BUFFER7 ((Atom) 16) #define XA_DRAWABLE ((Atom) 17) #define XA_FONT ((Atom) 18) #define XA_INTEGER ((Atom) 19) #define XA_PIXMAP ((Atom) 20) #define XA_POINT ((Atom) 21) #define XA_RECTANGLE ((Atom) 22) #define XA_RESOURCE_MANAGER ((Atom) 23) #define XA_RGB_COLOR_MAP ((Atom) 24) #define XA_RGB_BEST_MAP ((Atom) 25) #define XA_RGB_BLUE_MAP ((Atom) 26) #define XA_RGB_DEFAULT_MAP ((Atom) 27) #define XA_RGB_GRAY_MAP ((Atom) 28) #define XA_RGB_GREEN_MAP ((Atom) 29) #define XA_RGB_RED_MAP ((Atom) 30) #define XA_STRING ((Atom) 31) #define XA_VISUALID ((Atom) 32) #define XA_WINDOW ((Atom) 33) #define XA_WM_COMMAND ((Atom) 34) #define XA_WM_HINTS ((Atom) 35) #define XA_WM_CLIENT_MACHINE ((Atom) 36) #define XA_WM_ICON_NAME ((Atom) 37) #define XA_WM_ICON_SIZE ((Atom) 38) #define XA_WM_NAME ((Atom) 39) #define XA_WM_NORMAL_HINTS ((Atom) 40) #define XA_WM_SIZE_HINTS ((Atom) 41) #define XA_WM_ZOOM_HINTS ((Atom) 42) #define XA_MIN_SPACE ((Atom) 43) #define XA_NORM_SPACE ((Atom) 44) #define XA_MAX_SPACE ((Atom) 45) #define XA_END_SPACE ((Atom) 46) #define XA_SUPERSCRIPT_X ((Atom) 47) #define XA_SUPERSCRIPT_Y ((Atom) 48) #define XA_SUBSCRIPT_X ((Atom) 49) #define XA_SUBSCRIPT_Y ((Atom) 50) #define XA_UNDERLINE_POSITION ((Atom) 51) #define XA_UNDERLINE_THICKNESS ((Atom) 52) #define XA_STRIKEOUT_ASCENT ((Atom) 53) #define XA_STRIKEOUT_DESCENT ((Atom) 54) #define XA_ITALIC_ANGLE ((Atom) 55) #define XA_X_HEIGHT ((Atom) 56) #define XA_QUAD_WIDTH ((Atom) 57) #define XA_WEIGHT ((Atom) 58) #define XA_POINT_SIZE ((Atom) 59) #define XA_RESOLUTION ((Atom) 60) #define XA_COPYRIGHT ((Atom) 61) #define XA_NOTICE ((Atom) 62) #define XA_FONT_NAME ((Atom) 63) #define XA_FAMILY_NAME ((Atom) 64) #define XA_FULL_NAME ((Atom) 65) #define XA_CAP_HEIGHT ((Atom) 66) #define XA_WM_CLASS ((Atom) 67) #define XA_WM_TRANSIENT_FOR ((Atom) 68) #define XA_LAST_PREDEFINED ((Atom) 68) #endif /* XATOM_H */ blt-2.4z.orig/win/X11/X.h0100644000175000017500000004423707514116170013506 0ustar dokodoko/* * $XConsortium: X.h,v 1.66 88/09/06 15:55:56 jim Exp $ */ /* Definitions for the X window system likely to be used by applications */ #ifndef X_H #define X_H /*********************************************************** Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, and the Massachusetts Institute of Technology, Cambridge, Massachusetts. All Rights Reserved 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 copyright notice and this permission notice appear in supporting documentation, and that the names of Digital or MIT not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DIGITAL 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 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************/ #define X_PROTOCOL 11 /* current protocol version */ #define X_PROTOCOL_REVISION 0 /* current minor version */ #ifdef MAC_TCL # define Cursor XCursor # define Region XRegion #endif /* Resources */ typedef unsigned long XID; typedef XID Window; typedef XID Drawable; typedef XID Font; typedef XID Pixmap; typedef XID Cursor; typedef XID Colormap; typedef XID GContext; typedef XID KeySym; typedef unsigned long Mask; typedef unsigned long Atom; typedef unsigned long VisualID; typedef unsigned long Time; typedef unsigned long KeyCode; /* In order to use IME, the Macintosh needs * to pack 3 bytes into the keyCode field in * the XEvent. In the real X.h, a KeyCode is * defined as a short, which wouldn't be big * enough. */ /***************************************************************** * RESERVED RESOURCE AND CONSTANT DEFINITIONS *****************************************************************/ #define None 0L /* universal null resource or null atom */ #define ParentRelative 1L /* background pixmap in CreateWindow and ChangeWindowAttributes */ #define CopyFromParent 0L /* border pixmap in CreateWindow and ChangeWindowAttributes special VisualID and special window class passed to CreateWindow */ #define PointerWindow 0L /* destination window in SendEvent */ #define InputFocus 1L /* destination window in SendEvent */ #define PointerRoot 1L /* focus window in SetInputFocus */ #define AnyPropertyType 0L /* special Atom, passed to GetProperty */ #define AnyKey 0L /* special Key Code, passed to GrabKey */ #define AnyButton 0L /* special Button Code, passed to GrabButton */ #define AllTemporary 0L /* special Resource ID passed to KillClient */ #define CurrentTime 0L /* special Time */ #define NoSymbol 0L /* special KeySym */ /***************************************************************** * EVENT DEFINITIONS *****************************************************************/ /* Input Event Masks. Used as event-mask window attribute and as arguments to Grab requests. Not to be confused with event names. */ #define NoEventMask 0L #define KeyPressMask (1L<<0) #define KeyReleaseMask (1L<<1) #define ButtonPressMask (1L<<2) #define ButtonReleaseMask (1L<<3) #define EnterWindowMask (1L<<4) #define LeaveWindowMask (1L<<5) #define PointerMotionMask (1L<<6) #define PointerMotionHintMask (1L<<7) #define Button1MotionMask (1L<<8) #define Button2MotionMask (1L<<9) #define Button3MotionMask (1L<<10) #define Button4MotionMask (1L<<11) #define Button5MotionMask (1L<<12) #define ButtonMotionMask (1L<<13) #define KeymapStateMask (1L<<14) #define ExposureMask (1L<<15) #define VisibilityChangeMask (1L<<16) #define StructureNotifyMask (1L<<17) #define ResizeRedirectMask (1L<<18) #define SubstructureNotifyMask (1L<<19) #define SubstructureRedirectMask (1L<<20) #define FocusChangeMask (1L<<21) #define PropertyChangeMask (1L<<22) #define ColormapChangeMask (1L<<23) #define OwnerGrabButtonMask (1L<<24) /* Event names. Used in "type" field in XEvent structures. Not to be confused with event masks above. They start from 2 because 0 and 1 are reserved in the protocol for errors and replies. */ #define KeyPress 2 #define KeyRelease 3 #define ButtonPress 4 #define ButtonRelease 5 #define MotionNotify 6 #define EnterNotify 7 #define LeaveNotify 8 #define FocusIn 9 #define FocusOut 10 #define KeymapNotify 11 #define Expose 12 #define GraphicsExpose 13 #define NoExpose 14 #define VisibilityNotify 15 #define CreateNotify 16 #define DestroyNotify 17 #define UnmapNotify 18 #define MapNotify 19 #define MapRequest 20 #define ReparentNotify 21 #define ConfigureNotify 22 #define ConfigureRequest 23 #define GravityNotify 24 #define ResizeRequest 25 #define CirculateNotify 26 #define CirculateRequest 27 #define PropertyNotify 28 #define SelectionClear 29 #define SelectionRequest 30 #define SelectionNotify 31 #define ColormapNotify 32 #define ClientMessage 33 #define MappingNotify 34 #define LASTEvent 35 /* must be bigger than any event # */ /* Key masks. Used as modifiers to GrabButton and GrabKey, results of QueryPointer, state in various key-, mouse-, and button-related events. */ #define ShiftMask (1<<0) #define LockMask (1<<1) #define ControlMask (1<<2) #define Mod1Mask (1<<3) #define Mod2Mask (1<<4) #define Mod3Mask (1<<5) #define Mod4Mask (1<<6) #define Mod5Mask (1<<7) /* modifier names. Used to build a SetModifierMapping request or to read a GetModifierMapping request. These correspond to the masks defined above. */ #define ShiftMapIndex 0 #define LockMapIndex 1 #define ControlMapIndex 2 #define Mod1MapIndex 3 #define Mod2MapIndex 4 #define Mod3MapIndex 5 #define Mod4MapIndex 6 #define Mod5MapIndex 7 /* button masks. Used in same manner as Key masks above. Not to be confused with button names below. */ #define Button1Mask (1<<8) #define Button2Mask (1<<9) #define Button3Mask (1<<10) #define Button4Mask (1<<11) #define Button5Mask (1<<12) #define AnyModifier (1<<15) /* used in GrabButton, GrabKey */ /* button names. Used as arguments to GrabButton and as detail in ButtonPress and ButtonRelease events. Not to be confused with button masks above. Note that 0 is already defined above as "AnyButton". */ #define Button1 1 #define Button2 2 #define Button3 3 #define Button4 4 #define Button5 5 /* Notify modes */ #define NotifyNormal 0 #define NotifyGrab 1 #define NotifyUngrab 2 #define NotifyWhileGrabbed 3 #define NotifyHint 1 /* for MotionNotify events */ /* Notify detail */ #define NotifyAncestor 0 #define NotifyVirtual 1 #define NotifyInferior 2 #define NotifyNonlinear 3 #define NotifyNonlinearVirtual 4 #define NotifyPointer 5 #define NotifyPointerRoot 6 #define NotifyDetailNone 7 /* Visibility notify */ #define VisibilityUnobscured 0 #define VisibilityPartiallyObscured 1 #define VisibilityFullyObscured 2 /* Circulation request */ #define PlaceOnTop 0 #define PlaceOnBottom 1 /* protocol families */ #define FamilyInternet 0 #define FamilyDECnet 1 #define FamilyChaos 2 /* Property notification */ #define PropertyNewValue 0 #define PropertyDelete 1 /* Color Map notification */ #define ColormapUninstalled 0 #define ColormapInstalled 1 /* GrabPointer, GrabButton, GrabKeyboard, GrabKey Modes */ #define GrabModeSync 0 #define GrabModeAsync 1 /* GrabPointer, GrabKeyboard reply status */ #define GrabSuccess 0 #define AlreadyGrabbed 1 #define GrabInvalidTime 2 #define GrabNotViewable 3 #define GrabFrozen 4 /* AllowEvents modes */ #define AsyncPointer 0 #define SyncPointer 1 #define ReplayPointer 2 #define AsyncKeyboard 3 #define SyncKeyboard 4 #define ReplayKeyboard 5 #define AsyncBoth 6 #define SyncBoth 7 /* Used in SetInputFocus, GetInputFocus */ #define RevertToNone (int)None #define RevertToPointerRoot (int)PointerRoot #define RevertToParent 2 /***************************************************************** * ERROR CODES *****************************************************************/ #define Success 0 /* everything's okay */ #define BadRequest 1 /* bad request code */ #define BadValue 2 /* int parameter out of range */ #define BadWindow 3 /* parameter not a Window */ #define BadPixmap 4 /* parameter not a Pixmap */ #define BadAtom 5 /* parameter not an Atom */ #define BadCursor 6 /* parameter not a Cursor */ #define BadFont 7 /* parameter not a Font */ #define BadMatch 8 /* parameter mismatch */ #define BadDrawable 9 /* parameter not a Pixmap or Window */ #define BadAccess 10 /* depending on context: - key/button already grabbed - attempt to free an illegal cmap entry - attempt to store into a read-only color map entry. - attempt to modify the access control list from other than the local host. */ #define BadAlloc 11 /* insufficient resources */ #define BadColor 12 /* no such colormap */ #define BadGC 13 /* parameter not a GC */ #define BadIDChoice 14 /* choice not in range or already used */ #define BadName 15 /* font or color name doesn't exist */ #define BadLength 16 /* Request length incorrect */ #define BadImplementation 17 /* server is defective */ #define FirstExtensionError 128 #define LastExtensionError 255 /***************************************************************** * WINDOW DEFINITIONS *****************************************************************/ /* Window classes used by CreateWindow */ /* Note that CopyFromParent is already defined as 0 above */ #define InputOutput 1 #define InputOnly 2 /* Window attributes for CreateWindow and ChangeWindowAttributes */ #define CWBackPixmap (1L<<0) #define CWBackPixel (1L<<1) #define CWBorderPixmap (1L<<2) #define CWBorderPixel (1L<<3) #define CWBitGravity (1L<<4) #define CWWinGravity (1L<<5) #define CWBackingStore (1L<<6) #define CWBackingPlanes (1L<<7) #define CWBackingPixel (1L<<8) #define CWOverrideRedirect (1L<<9) #define CWSaveUnder (1L<<10) #define CWEventMask (1L<<11) #define CWDontPropagate (1L<<12) #define CWColormap (1L<<13) #define CWCursor (1L<<14) /* ConfigureWindow structure */ #define CWX (1<<0) #define CWY (1<<1) #define CWWidth (1<<2) #define CWHeight (1<<3) #define CWBorderWidth (1<<4) #define CWSibling (1<<5) #define CWStackMode (1<<6) /* Bit Gravity */ #define ForgetGravity 0 #define NorthWestGravity 1 #define NorthGravity 2 #define NorthEastGravity 3 #define WestGravity 4 #define CenterGravity 5 #define EastGravity 6 #define SouthWestGravity 7 #define SouthGravity 8 #define SouthEastGravity 9 #define StaticGravity 10 /* Window gravity + bit gravity above */ #define UnmapGravity 0 /* Used in CreateWindow for backing-store hint */ #define NotUseful 0 #define WhenMapped 1 #define Always 2 /* Used in GetWindowAttributes reply */ #define IsUnmapped 0 #define IsUnviewable 1 #define IsViewable 2 /* Used in ChangeSaveSet */ #define SetModeInsert 0 #define SetModeDelete 1 /* Used in ChangeCloseDownMode */ #define DestroyAll 0 #define RetainPermanent 1 #define RetainTemporary 2 /* Window stacking method (in configureWindow) */ #define Above 0 #define Below 1 #define TopIf 2 #define BottomIf 3 #define Opposite 4 /* Circulation direction */ #define RaiseLowest 0 #define LowerHighest 1 /* Property modes */ #define PropModeReplace 0 #define PropModePrepend 1 #define PropModeAppend 2 /***************************************************************** * GRAPHICS DEFINITIONS *****************************************************************/ /* graphics functions, as in GC.alu */ #define GXclear 0x0 /* 0 */ #define GXand 0x1 /* src AND dst */ #define GXandReverse 0x2 /* src AND NOT dst */ #define GXcopy 0x3 /* src */ #define GXandInverted 0x4 /* NOT src AND dst */ #define GXnoop 0x5 /* dst */ #define GXxor 0x6 /* src XOR dst */ #define GXor 0x7 /* src OR dst */ #define GXnor 0x8 /* NOT src AND NOT dst */ #define GXequiv 0x9 /* NOT src XOR dst */ #define GXinvert 0xa /* NOT dst */ #define GXorReverse 0xb /* src OR NOT dst */ #define GXcopyInverted 0xc /* NOT src */ #define GXorInverted 0xd /* NOT src OR dst */ #define GXnand 0xe /* NOT src OR NOT dst */ #define GXset 0xf /* 1 */ /* LineStyle */ #define LineSolid 0 #define LineOnOffDash 1 #define LineDoubleDash 2 /* capStyle */ #define CapNotLast 0 #define CapButt 1 #define CapRound 2 #define CapProjecting 3 /* joinStyle */ #define JoinMiter 0 #define JoinRound 1 #define JoinBevel 2 /* fillStyle */ #define FillSolid 0 #define FillTiled 1 #define FillStippled 2 #define FillOpaqueStippled 3 /* fillRule */ #define EvenOddRule 0 #define WindingRule 1 /* subwindow mode */ #define ClipByChildren 0 #define IncludeInferiors 1 /* SetClipRectangles ordering */ #define Unsorted 0 #define YSorted 1 #define YXSorted 2 #define YXBanded 3 /* CoordinateMode for drawing routines */ #define CoordModeOrigin 0 /* relative to the origin */ #define CoordModePrevious 1 /* relative to previous point */ /* Polygon shapes */ #define Complex 0 /* paths may intersect */ #define Nonconvex 1 /* no paths intersect, but not convex */ #define Convex 2 /* wholly convex */ /* Arc modes for PolyFillArc */ #define ArcChord 0 /* join endpoints of arc */ #define ArcPieSlice 1 /* join endpoints to center of arc */ /* GC components: masks used in CreateGC, CopyGC, ChangeGC, OR'ed into GC.stateChanges */ #define GCFunction (1L<<0) #define GCPlaneMask (1L<<1) #define GCForeground (1L<<2) #define GCBackground (1L<<3) #define GCLineWidth (1L<<4) #define GCLineStyle (1L<<5) #define GCCapStyle (1L<<6) #define GCJoinStyle (1L<<7) #define GCFillStyle (1L<<8) #define GCFillRule (1L<<9) #define GCTile (1L<<10) #define GCStipple (1L<<11) #define GCTileStipXOrigin (1L<<12) #define GCTileStipYOrigin (1L<<13) #define GCFont (1L<<14) #define GCSubwindowMode (1L<<15) #define GCGraphicsExposures (1L<<16) #define GCClipXOrigin (1L<<17) #define GCClipYOrigin (1L<<18) #define GCClipMask (1L<<19) #define GCDashOffset (1L<<20) #define GCDashList (1L<<21) #define GCArcMode (1L<<22) #define GCLastBit 22 /***************************************************************** * FONTS *****************************************************************/ /* used in QueryFont -- draw direction */ #define FontLeftToRight 0 #define FontRightToLeft 1 #define FontChange 255 /***************************************************************** * IMAGING *****************************************************************/ /* ImageFormat -- PutImage, GetImage */ #define XYBitmap 0 /* depth 1, XYFormat */ #define XYPixmap 1 /* depth == drawable depth */ #define ZPixmap 2 /* depth == drawable depth */ /***************************************************************** * COLOR MAP STUFF *****************************************************************/ /* For CreateColormap */ #define AllocNone 0 /* create map with no entries */ #define AllocAll 1 /* allocate entire map writeable */ /* Flags used in StoreNamedColor, StoreColors */ #define DoRed (1<<0) #define DoGreen (1<<1) #define DoBlue (1<<2) /***************************************************************** * CURSOR STUFF *****************************************************************/ /* QueryBestSize Class */ #define CursorShape 0 /* largest size that can be displayed */ #define TileShape 1 /* size tiled fastest */ #define StippleShape 2 /* size stippled fastest */ /***************************************************************** * KEYBOARD/POINTER STUFF *****************************************************************/ #define AutoRepeatModeOff 0 #define AutoRepeatModeOn 1 #define AutoRepeatModeDefault 2 #define LedModeOff 0 #define LedModeOn 1 /* masks for ChangeKeyboardControl */ #define KBKeyClickPercent (1L<<0) #define KBBellPercent (1L<<1) #define KBBellPitch (1L<<2) #define KBBellDuration (1L<<3) #define KBLed (1L<<4) #define KBLedMode (1L<<5) #define KBKey (1L<<6) #define KBAutoRepeatMode (1L<<7) #define MappingSuccess 0 #define MappingBusy 1 #define MappingFailed 2 #define MappingModifier 0 #define MappingKeyboard 1 #define MappingPointer 2 /***************************************************************** * SCREEN SAVER STUFF *****************************************************************/ #define DontPreferBlanking 0 #define PreferBlanking 1 #define DefaultBlanking 2 #define DisableScreenSaver 0 #define DisableScreenInterval 0 #define DontAllowExposures 0 #define AllowExposures 1 #define DefaultExposures 2 /* for ForceScreenSaver */ #define ScreenSaverReset 0 #define ScreenSaverActive 1 /***************************************************************** * HOSTS AND CONNECTIONS *****************************************************************/ /* for ChangeHosts */ #define HostInsert 0 #define HostDelete 1 /* for ChangeAccessControl */ #define EnableAccess 1 #define DisableAccess 0 /* Display classes used in opening the connection * Note that the statically allocated ones are even numbered and the * dynamically changeable ones are odd numbered */ #define StaticGray 0 #define GrayScale 1 #define StaticColor 2 #define PseudoColor 3 #define TrueColor 4 #define DirectColor 5 /* Byte order used in imageByteOrder and bitmapBitOrder */ #define LSBFirst 0 #define MSBFirst 1 #ifdef MAC_TCL # undef Cursor # undef Region #endif #endif /* X_H */ blt-2.4z.orig/win/X11/Xfuncproto.h0100644000175000017500000000327007514116170015436 0ustar dokodoko/* $XConsortium: Xfuncproto.h,v 1.7 91/05/13 20:49:21 rws Exp $ */ /* * Copyright 1989, 1991 by the Massachusetts Institute of Technology * * 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 * copyright notice and this permission notice appear in supporting * documentation, and that the name of M.I.T. not be used in advertising * or publicity pertaining to distribution of the software without specific, * written prior permission. M.I.T. makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * */ /* Definitions to make function prototypes manageable */ #ifndef _XFUNCPROTO_H_ #define _XFUNCPROTO_H_ #ifndef NeedFunctionPrototypes #define NeedFunctionPrototypes 1 #endif /* NeedFunctionPrototypes */ #ifndef NeedVarargsPrototypes #define NeedVarargsPrototypes 0 #endif /* NeedVarargsPrototypes */ #if NeedFunctionPrototypes #ifndef NeedNestedPrototypes #define NeedNestedPrototypes 1 #endif /* NeedNestedPrototypes */ #ifndef _Xconst #define _Xconst const #endif /* _Xconst */ #ifndef NeedWidePrototypes #ifdef NARROWPROTO #define NeedWidePrototypes 0 #else #define NeedWidePrototypes 1 /* default to make interropt. easier */ #endif #endif /* NeedWidePrototypes */ #endif /* NeedFunctionPrototypes */ #ifdef __cplusplus #define _XFUNCPROTOBEGIN extern "C" { #define _XFUNCPROTOEND } #endif #ifndef _XFUNCPROTOBEGIN #define _XFUNCPROTOBEGIN #define _XFUNCPROTOEND #endif /* _XFUNCPROTOBEGIN */ #endif /* _XFUNCPROTO_H_ */ blt-2.4z.orig/win/X11/Xlib.h0100644000175000017500000014042707514116170014173 0ustar dokodoko/* $XConsortium: Xlib.h,v 11.221 93/07/02 14:13:28 gildea Exp $ */ /* * Copyright 1985, 1986, 1987, 1991 by the Massachusetts Institute of Technology * * 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 * copyright notice and this permission notice appear in supporting * documentation, and that the name of M.I.T. not be used in advertising * or publicity pertaining to distribution of the software without specific, * written prior permission. M.I.T. makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * X Window System is a Trademark of MIT. * */ /* * Xlib.h - Header definition and support file for the C subroutine * interface library (Xlib) to the X Window System Protocol (V11). * Structures and symbols starting with "_" are private to the library. */ #ifndef _XLIB_H_ #define _XLIB_H_ #define XlibSpecificationRelease 5 #ifdef MAC_TCL # include # define Cursor XCursor # define Region XRegion #else # include #endif /* applications should not depend on these two headers being included! */ #ifdef MAC_TCL #include #else #include #endif #ifndef X_WCHAR #ifdef X_NOT_STDC_ENV #define X_WCHAR #endif #endif #ifndef X_WCHAR #include #else /* replace this with #include or typedef appropriate for your system */ typedef unsigned long wchar_t; #endif typedef char *XPointer; #define Bool int #ifdef MAC_TCL #define Status int #else typedef int Status; #endif #define True 1 #define False 0 #define QueuedAlready 0 #define QueuedAfterReading 1 #define QueuedAfterFlush 2 #define ConnectionNumber(dpy) ((dpy)->fd) #define RootWindow(dpy, scr) (((dpy)->screens[(scr)]).root) #define DefaultScreen(dpy) ((dpy)->default_screen) #define DefaultRootWindow(dpy) (((dpy)->screens[(dpy)->default_screen]).root) #define DefaultVisual(dpy, scr) (((dpy)->screens[(scr)]).root_visual) #define DefaultGC(dpy, scr) (((dpy)->screens[(scr)]).default_gc) #define BlackPixel(dpy, scr) (((dpy)->screens[(scr)]).black_pixel) #define WhitePixel(dpy, scr) (((dpy)->screens[(scr)]).white_pixel) #define AllPlanes ((unsigned long)~0L) #define QLength(dpy) ((dpy)->qlen) #define DisplayWidth(dpy, scr) (((dpy)->screens[(scr)]).width) #define DisplayHeight(dpy, scr) (((dpy)->screens[(scr)]).height) #define DisplayWidthMM(dpy, scr)(((dpy)->screens[(scr)]).mwidth) #define DisplayHeightMM(dpy, scr)(((dpy)->screens[(scr)]).mheight) #define DisplayPlanes(dpy, scr) (((dpy)->screens[(scr)]).root_depth) #define DisplayCells(dpy, scr) (DefaultVisual((dpy), (scr))->map_entries) #define ScreenCount(dpy) ((dpy)->nscreens) #define ServerVendor(dpy) ((dpy)->vendor) #define ProtocolVersion(dpy) ((dpy)->proto_major_version) #define ProtocolRevision(dpy) ((dpy)->proto_minor_version) #define VendorRelease(dpy) ((dpy)->release) #define DisplayString(dpy) ((dpy)->display_name) #define DefaultDepth(dpy, scr) (((dpy)->screens[(scr)]).root_depth) #define DefaultColormap(dpy, scr)(((dpy)->screens[(scr)]).cmap) #define BitmapUnit(dpy) ((dpy)->bitmap_unit) #define BitmapBitOrder(dpy) ((dpy)->bitmap_bit_order) #define BitmapPad(dpy) ((dpy)->bitmap_pad) #define ImageByteOrder(dpy) ((dpy)->byte_order) #define NextRequest(dpy) ((dpy)->request + 1) #define LastKnownRequestProcessed(dpy) ((dpy)->request) /* macros for screen oriented applications (toolkit) */ #define ScreenOfDisplay(dpy, scr)(&((dpy)->screens[(scr)])) #define DefaultScreenOfDisplay(dpy) (&((dpy)->screens[(dpy)->default_screen])) #define DisplayOfScreen(s) ((s)->display) #define RootWindowOfScreen(s) ((s)->root) #define BlackPixelOfScreen(s) ((s)->black_pixel) #define WhitePixelOfScreen(s) ((s)->white_pixel) #define DefaultColormapOfScreen(s)((s)->cmap) #define DefaultDepthOfScreen(s) ((s)->root_depth) #define DefaultGCOfScreen(s) ((s)->default_gc) #define DefaultVisualOfScreen(s)((s)->root_visual) #define WidthOfScreen(s) ((s)->width) #define HeightOfScreen(s) ((s)->height) #define WidthMMOfScreen(s) ((s)->mwidth) #define HeightMMOfScreen(s) ((s)->mheight) #define PlanesOfScreen(s) ((s)->root_depth) #define CellsOfScreen(s) (DefaultVisualOfScreen((s))->map_entries) #define MinCmapsOfScreen(s) ((s)->min_maps) #define MaxCmapsOfScreen(s) ((s)->max_maps) #define DoesSaveUnders(s) ((s)->save_unders) #define DoesBackingStore(s) ((s)->backing_store) #define EventMaskOfScreen(s) ((s)->root_input_mask) /* * Extensions need a way to hang private data on some structures. */ typedef struct _XExtData { int number; /* number returned by XRegisterExtension */ struct _XExtData *next; /* next item on list of data for structure */ int (*free_private)(); /* called to free private storage */ XPointer private_data; /* data private to this extension. */ } XExtData; /* * This file contains structures used by the extension mechanism. */ typedef struct { /* public to extension, cannot be changed */ int extension; /* extension number */ int major_opcode; /* major op-code assigned by server */ int first_event; /* first event number for the extension */ int first_error; /* first error number for the extension */ } XExtCodes; /* * Data structure for retrieving info about pixmap formats. */ typedef struct { int depth; int bits_per_pixel; int scanline_pad; } XPixmapFormatValues; /* * Data structure for setting graphics context. */ typedef struct { int function; /* logical operation */ unsigned long plane_mask;/* plane mask */ unsigned long foreground;/* foreground pixel */ unsigned long background;/* background pixel */ int line_width; /* line width */ int line_style; /* LineSolid, LineOnOffDash, LineDoubleDash */ int cap_style; /* CapNotLast, CapButt, CapRound, CapProjecting */ int join_style; /* JoinMiter, JoinRound, JoinBevel */ int fill_style; /* FillSolid, FillTiled, FillStippled, FillOpaeueStippled */ int fill_rule; /* EvenOddRule, WindingRule */ int arc_mode; /* ArcChord, ArcPieSlice */ Pixmap tile; /* tile pixmap for tiling operations */ Pixmap stipple; /* stipple 1 plane pixmap for stipping */ int ts_x_origin; /* offset for tile or stipple operations */ int ts_y_origin; Font font; /* default text font for text operations */ int subwindow_mode; /* ClipByChildren, IncludeInferiors */ Bool graphics_exposures;/* boolean, should exposures be generated */ int clip_x_origin; /* origin for clipping */ int clip_y_origin; Pixmap clip_mask; /* bitmap clipping; other calls for rects */ int dash_offset; /* patterned/dashed line information */ char dashes; } XGCValues; /* * Graphics context. The contents of this structure are implementation * dependent. A GC should be treated as opaque by application code. */ typedef XGCValues *GC; /* * Visual structure; contains information about colormapping possible. */ typedef struct { XExtData *ext_data; /* hook for extension to hang data */ VisualID visualid; /* visual id of this visual */ #if defined(__cplusplus) || defined(c_plusplus) int c_class; /* C++ class of screen (monochrome, etc.) */ #else int class; /* class of screen (monochrome, etc.) */ #endif unsigned long red_mask, green_mask, blue_mask; /* mask values */ int bits_per_rgb; /* log base 2 of distinct color values */ int map_entries; /* color map entries */ } Visual; /* * Depth structure; contains information for each possible depth. */ typedef struct { int depth; /* this depth (Z) of the depth */ int nvisuals; /* number of Visual types at this depth */ Visual *visuals; /* list of visuals possible at this depth */ } Depth; /* * Information about the screen. The contents of this structure are * implementation dependent. A Screen should be treated as opaque * by application code. */ typedef struct { XExtData *ext_data; /* hook for extension to hang data */ struct _XDisplay *display;/* back pointer to display structure */ Window root; /* Root window id. */ int width, height; /* width and height of screen */ int mwidth, mheight; /* width and height of in millimeters */ int ndepths; /* number of depths possible */ Depth *depths; /* list of allowable depths on the screen */ int root_depth; /* bits per pixel */ Visual *root_visual; /* root visual */ GC default_gc; /* GC for the root root visual */ Colormap cmap; /* default color map */ unsigned long white_pixel; unsigned long black_pixel; /* White and Black pixel values */ int max_maps, min_maps; /* max and min color maps */ int backing_store; /* Never, WhenMapped, Always */ Bool save_unders; long root_input_mask; /* initial root input mask */ } Screen; /* * Format structure; describes ZFormat data the screen will understand. */ typedef struct { XExtData *ext_data; /* hook for extension to hang data */ int depth; /* depth of this image format */ int bits_per_pixel; /* bits/pixel at this depth */ int scanline_pad; /* scanline must padded to this multiple */ } ScreenFormat; /* * Data structure for setting window attributes. */ typedef struct { Pixmap background_pixmap; /* background or None or ParentRelative */ unsigned long background_pixel; /* background pixel */ Pixmap border_pixmap; /* border of the window */ unsigned long border_pixel; /* border pixel value */ int bit_gravity; /* one of bit gravity values */ int win_gravity; /* one of the window gravity values */ int backing_store; /* NotUseful, WhenMapped, Always */ unsigned long backing_planes;/* planes to be preseved if possible */ unsigned long backing_pixel;/* value to use in restoring planes */ Bool save_under; /* should bits under be saved? (popups) */ long event_mask; /* set of events that should be saved */ long do_not_propagate_mask; /* set of events that should not propagate */ Bool override_redirect; /* boolean value for override-redirect */ Colormap colormap; /* color map to be associated with window */ Cursor cursor; /* cursor to be displayed (or None) */ } XSetWindowAttributes; typedef struct { int x, y; /* location of window */ int width, height; /* width and height of window */ int border_width; /* border width of window */ int depth; /* depth of window */ Visual *visual; /* the associated visual structure */ Window root; /* root of screen containing window */ #if defined(__cplusplus) || defined(c_plusplus) int c_class; /* C++ InputOutput, InputOnly*/ #else int class; /* InputOutput, InputOnly*/ #endif int bit_gravity; /* one of bit gravity values */ int win_gravity; /* one of the window gravity values */ int backing_store; /* NotUseful, WhenMapped, Always */ unsigned long backing_planes;/* planes to be preserved if possible */ unsigned long backing_pixel;/* value to be used when restoring planes */ Bool save_under; /* boolean, should bits under be saved? */ Colormap colormap; /* color map to be associated with window */ Bool map_installed; /* boolean, is color map currently installed*/ int map_state; /* IsUnmapped, IsUnviewable, IsViewable */ long all_event_masks; /* set of events all people have interest in*/ long your_event_mask; /* my event mask */ long do_not_propagate_mask; /* set of events that should not propagate */ Bool override_redirect; /* boolean value for override-redirect */ Screen *screen; /* back pointer to correct screen */ } XWindowAttributes; /* * Data structure for host setting; getting routines. * */ typedef struct { int family; /* for example FamilyInternet */ int length; /* length of address, in bytes */ char *address; /* pointer to where to find the bytes */ } XHostAddress; /* * Data structure for "image" data, used by image manipulation routines. */ typedef struct _XImage { int width, height; /* size of image */ int xoffset; /* number of pixels offset in X direction */ int format; /* XYBitmap, XYPixmap, ZPixmap */ char *data; /* pointer to image data */ int byte_order; /* data byte order, LSBFirst, MSBFirst */ int bitmap_unit; /* quant. of scanline 8, 16, 32 */ int bitmap_bit_order; /* LSBFirst, MSBFirst */ int bitmap_pad; /* 8, 16, 32 either XY or ZPixmap */ int depth; /* depth of image */ int bytes_per_line; /* accelarator to next line */ int bits_per_pixel; /* bits per pixel (ZPixmap) */ unsigned long red_mask; /* bits in z arrangment */ unsigned long green_mask; unsigned long blue_mask; XPointer obdata; /* hook for the object routines to hang on */ struct funcs { /* image manipulation routines */ struct _XImage *(*create_image)(); #if NeedFunctionPrototypes int (*destroy_image) (struct _XImage *); unsigned long (*get_pixel) (struct _XImage *, int, int); int (*put_pixel) (struct _XImage *, int, int, unsigned long); struct _XImage *(*sub_image)(struct _XImage *, int, int, unsigned int, unsigned int); int (*add_pixel) (struct _XImage *, long); #else int (*destroy_image)(); unsigned long (*get_pixel)(); int (*put_pixel)(); struct _XImage *(*sub_image)(); int (*add_pixel)(); #endif } f; } XImage; /* * Data structure for XReconfigureWindow */ typedef struct { int x, y; int width, height; int border_width; Window sibling; int stack_mode; } XWindowChanges; /* * Data structure used by color operations */ typedef struct { unsigned long pixel; unsigned short red, green, blue; char flags; /* do_red, do_green, do_blue */ char pad; } XColor; /* * Data structures for graphics operations. On most machines, these are * congruent with the wire protocol structures, so reformatting the data * can be avoided on these architectures. */ typedef struct { short x1, y1, x2, y2; } XSegment; typedef struct { short x, y; } XPoint; typedef struct { short x, y; unsigned short width, height; } XRectangle; typedef struct { short x, y; unsigned short width, height; short angle1, angle2; } XArc; /* Data structure for XChangeKeyboardControl */ typedef struct { int key_click_percent; int bell_percent; int bell_pitch; int bell_duration; int led; int led_mode; int key; int auto_repeat_mode; /* On, Off, Default */ } XKeyboardControl; /* Data structure for XGetKeyboardControl */ typedef struct { int key_click_percent; int bell_percent; unsigned int bell_pitch, bell_duration; unsigned long led_mask; int global_auto_repeat; char auto_repeats[32]; } XKeyboardState; /* Data structure for XGetMotionEvents. */ typedef struct { Time time; short x, y; } XTimeCoord; /* Data structure for X{Set,Get}ModifierMapping */ typedef struct { int max_keypermod; /* The server's max # of keys per modifier */ KeyCode *modifiermap; /* An 8 by max_keypermod array of modifiers */ } XModifierKeymap; /* * Display datatype maintaining display specific data. * The contents of this structure are implementation dependent. * A Display should be treated as opaque by application code. */ typedef struct _XDisplay { XExtData *ext_data; /* hook for extension to hang data */ struct _XFreeFuncs *free_funcs; /* internal free functions */ int fd; /* Network socket. */ int conn_checker; /* ugly thing used by _XEventsQueued */ int proto_major_version;/* maj. version of server's X protocol */ int proto_minor_version;/* minor version of servers X protocol */ char *vendor; /* vendor of the server hardware */ XID resource_base; /* resource ID base */ XID resource_mask; /* resource ID mask bits */ XID resource_id; /* allocator current ID */ int resource_shift; /* allocator shift to correct bits */ XID (*resource_alloc)(); /* allocator function */ int byte_order; /* screen byte order, LSBFirst, MSBFirst */ int bitmap_unit; /* padding and data requirements */ int bitmap_pad; /* padding requirements on bitmaps */ int bitmap_bit_order; /* LeastSignificant or MostSignificant */ int nformats; /* number of pixmap formats in list */ ScreenFormat *pixmap_format; /* pixmap format list */ int vnumber; /* Xlib's X protocol version number. */ int release; /* release of the server */ struct _XSQEvent *head, *tail; /* Input event queue. */ int qlen; /* Length of input event queue */ unsigned long request; /* sequence number of last request. */ char *last_req; /* beginning of last request, or dummy */ char *buffer; /* Output buffer starting address. */ char *bufptr; /* Output buffer index pointer. */ char *bufmax; /* Output buffer maximum+1 address. */ unsigned max_request_size; /* maximum number 32 bit words in request*/ struct _XrmHashBucketRec *db; int (*synchandler)(); /* Synchronization handler */ char *display_name; /* "host:display" string used on this connect*/ int default_screen; /* default screen for operations */ int nscreens; /* number of screens on this server*/ Screen *screens; /* pointer to list of screens */ unsigned long motion_buffer; /* size of motion buffer */ unsigned long flags; /* internal connection flags */ int min_keycode; /* minimum defined keycode */ int max_keycode; /* maximum defined keycode */ KeySym *keysyms; /* This server's keysyms */ XModifierKeymap *modifiermap; /* This server's modifier keymap */ int keysyms_per_keycode;/* number of rows */ char *xdefaults; /* contents of defaults from server */ char *scratch_buffer; /* place to hang scratch buffer */ unsigned long scratch_length; /* length of scratch buffer */ int ext_number; /* extension number on this display */ struct _XExten *ext_procs; /* extensions initialized on this display */ /* * the following can be fixed size, as the protocol defines how * much address space is available. * While this could be done using the extension vector, there * may be MANY events processed, so a search through the extension * list to find the right procedure for each event might be * expensive if many extensions are being used. */ Bool (*event_vec[128])(); /* vector for wire to event */ Status (*wire_vec[128])(); /* vector for event to wire */ KeySym lock_meaning; /* for XLookupString */ struct _XLockInfo *lock; /* multi-thread state, display lock */ struct _XInternalAsync *async_handlers; /* for internal async */ unsigned long bigreq_size; /* max size of big requests */ struct _XLockPtrs *lock_fns; /* pointers to threads functions */ /* things above this line should not move, for binary compatibility */ struct _XKeytrans *key_bindings; /* for XLookupString */ Font cursor_font; /* for XCreateFontCursor */ struct _XDisplayAtoms *atoms; /* for XInternAtom */ unsigned int mode_switch; /* keyboard group modifiers */ struct _XContextDB *context_db; /* context database */ Bool (**error_vec)(); /* vector for wire to error */ /* * Xcms information */ struct { XPointer defaultCCCs; /* pointer to an array of default XcmsCCC */ XPointer clientCmaps; /* pointer to linked list of XcmsCmapRec */ XPointer perVisualIntensityMaps; /* linked list of XcmsIntensityMap */ } cms; struct _XIMFilter *im_filters; struct _XSQEvent *qfree; /* unallocated event queue elements */ unsigned long next_event_serial_num; /* inserted into next queue elt */ int (*savedsynchandler)(); /* user synchandler when Xlib usurps */ } Display; #if NeedFunctionPrototypes /* prototypes require event type definitions */ #undef _XEVENT_ #endif #ifndef _XEVENT_ #define XMaxTransChars 4 /* * Definitions of specific events. */ typedef struct { int type; /* of event */ unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window window; /* "event" window it is reported relative to */ Window root; /* root window that the event occured on */ Window subwindow; /* child window */ Time time; /* milliseconds */ int x, y; /* pointer x, y coordinates in event window */ int x_root, y_root; /* coordinates relative to root */ unsigned int state; /* key or button mask */ unsigned int keycode; /* detail */ Bool same_screen; /* same screen flag */ char trans_chars[XMaxTransChars]; /* translated characters */ int nbytes; } XKeyEvent; typedef XKeyEvent XKeyPressedEvent; typedef XKeyEvent XKeyReleasedEvent; typedef struct { int type; /* of event */ unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window window; /* "event" window it is reported relative to */ Window root; /* root window that the event occured on */ Window subwindow; /* child window */ Time time; /* milliseconds */ int x, y; /* pointer x, y coordinates in event window */ int x_root, y_root; /* coordinates relative to root */ unsigned int state; /* key or button mask */ unsigned int button; /* detail */ Bool same_screen; /* same screen flag */ } XButtonEvent; typedef XButtonEvent XButtonPressedEvent; typedef XButtonEvent XButtonReleasedEvent; typedef struct { int type; /* of event */ unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window window; /* "event" window reported relative to */ Window root; /* root window that the event occured on */ Window subwindow; /* child window */ Time time; /* milliseconds */ int x, y; /* pointer x, y coordinates in event window */ int x_root, y_root; /* coordinates relative to root */ unsigned int state; /* key or button mask */ char is_hint; /* detail */ Bool same_screen; /* same screen flag */ } XMotionEvent; typedef XMotionEvent XPointerMovedEvent; typedef struct { int type; /* of event */ unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window window; /* "event" window reported relative to */ Window root; /* root window that the event occured on */ Window subwindow; /* child window */ Time time; /* milliseconds */ int x, y; /* pointer x, y coordinates in event window */ int x_root, y_root; /* coordinates relative to root */ int mode; /* NotifyNormal, NotifyGrab, NotifyUngrab */ int detail; /* * NotifyAncestor, NotifyVirtual, NotifyInferior, * NotifyNonlinear,NotifyNonlinearVirtual */ Bool same_screen; /* same screen flag */ Bool focus; /* boolean focus */ unsigned int state; /* key or button mask */ } XCrossingEvent; typedef XCrossingEvent XEnterWindowEvent; typedef XCrossingEvent XLeaveWindowEvent; typedef struct { int type; /* FocusIn or FocusOut */ unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window window; /* window of event */ int mode; /* NotifyNormal, NotifyGrab, NotifyUngrab */ int detail; /* * NotifyAncestor, NotifyVirtual, NotifyInferior, * NotifyNonlinear,NotifyNonlinearVirtual, NotifyPointer, * NotifyPointerRoot, NotifyDetailNone */ } XFocusChangeEvent; typedef XFocusChangeEvent XFocusInEvent; typedef XFocusChangeEvent XFocusOutEvent; /* generated on EnterWindow and FocusIn when KeyMapState selected */ typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window window; char key_vector[32]; } XKeymapEvent; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window window; int x, y; int width, height; int count; /* if non-zero, at least this many more */ } XExposeEvent; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Drawable drawable; int x, y; int width, height; int count; /* if non-zero, at least this many more */ int major_code; /* core is CopyArea or CopyPlane */ int minor_code; /* not defined in the core */ } XGraphicsExposeEvent; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Drawable drawable; int major_code; /* core is CopyArea or CopyPlane */ int minor_code; /* not defined in the core */ } XNoExposeEvent; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window window; int state; /* Visibility state */ } XVisibilityEvent; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window parent; /* parent of the window */ Window window; /* window id of window created */ int x, y; /* window location */ int width, height; /* size of window */ int border_width; /* border width */ Bool override_redirect; /* creation should be overridden */ } XCreateWindowEvent; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window event; Window window; } XDestroyWindowEvent; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window event; Window window; Bool from_configure; } XUnmapEvent; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window event; Window window; Bool override_redirect; /* boolean, is override set... */ } XMapEvent; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window parent; Window window; } XMapRequestEvent; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window event; Window window; Window parent; int x, y; Bool override_redirect; } XReparentEvent; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window event; Window window; int x, y; int width, height; int border_width; Window above; Bool override_redirect; } XConfigureEvent; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window event; Window window; int x, y; } XGravityEvent; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window window; int width, height; } XResizeRequestEvent; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window parent; Window window; int x, y; int width, height; int border_width; Window above; int detail; /* Above, Below, TopIf, BottomIf, Opposite */ unsigned long value_mask; } XConfigureRequestEvent; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window event; Window window; int place; /* PlaceOnTop, PlaceOnBottom */ } XCirculateEvent; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window parent; Window window; int place; /* PlaceOnTop, PlaceOnBottom */ } XCirculateRequestEvent; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window window; Atom atom; Time time; int state; /* NewValue, Deleted */ } XPropertyEvent; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window window; Atom selection; Time time; } XSelectionClearEvent; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window owner; Window requestor; Atom selection; Atom target; Atom property; Time time; } XSelectionRequestEvent; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window requestor; Atom selection; Atom target; Atom property; /* ATOM or None */ Time time; } XSelectionEvent; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window window; Colormap colormap; /* COLORMAP or None */ #if defined(__cplusplus) || defined(c_plusplus) Bool c_new; /* C++ */ #else Bool new; #endif int state; /* ColormapInstalled, ColormapUninstalled */ } XColormapEvent; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window window; Atom message_type; int format; union { char b[20]; short s[10]; long l[5]; } data; } XClientMessageEvent; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window window; /* unused */ int request; /* one of MappingModifier, MappingKeyboard, MappingPointer */ int first_keycode; /* first keycode */ int count; /* defines range of change w. first_keycode*/ } XMappingEvent; typedef struct { int type; Display *display; /* Display the event was read from */ XID resourceid; /* resource id */ unsigned long serial; /* serial number of failed request */ unsigned char error_code; /* error code of failed request */ unsigned char request_code; /* Major op-code of failed request */ unsigned char minor_code; /* Minor op-code of failed request */ } XErrorEvent; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display;/* Display the event was read from */ Window window; /* window on which event was requested in event mask */ } XAnyEvent; /* * this union is defined so Xlib can always use the same sized * event structure internally, to avoid memory fragmentation. */ typedef union _XEvent { int type; /* must not be changed; first element */ XAnyEvent xany; XKeyEvent xkey; XButtonEvent xbutton; XMotionEvent xmotion; XCrossingEvent xcrossing; XFocusChangeEvent xfocus; XExposeEvent xexpose; XGraphicsExposeEvent xgraphicsexpose; XNoExposeEvent xnoexpose; XVisibilityEvent xvisibility; XCreateWindowEvent xcreatewindow; XDestroyWindowEvent xdestroywindow; XUnmapEvent xunmap; XMapEvent xmap; XMapRequestEvent xmaprequest; XReparentEvent xreparent; XConfigureEvent xconfigure; XGravityEvent xgravity; XResizeRequestEvent xresizerequest; XConfigureRequestEvent xconfigurerequest; XCirculateEvent xcirculate; XCirculateRequestEvent xcirculaterequest; XPropertyEvent xproperty; XSelectionClearEvent xselectionclear; XSelectionRequestEvent xselectionrequest; XSelectionEvent xselection; XColormapEvent xcolormap; XClientMessageEvent xclient; XMappingEvent xmapping; XErrorEvent xerror; XKeymapEvent xkeymap; long pad[24]; } XEvent; #endif #define XAllocID(dpy) ((*(dpy)->resource_alloc)((dpy))) /* * per character font metric information. */ typedef struct { short lbearing; /* origin to left edge of raster */ short rbearing; /* origin to right edge of raster */ short width; /* advance to next char's origin */ short ascent; /* baseline to top edge of raster */ short descent; /* baseline to bottom edge of raster */ unsigned short attributes; /* per char flags (not predefined) */ } XCharStruct; /* * To allow arbitrary information with fonts, there are additional properties * returned. */ typedef struct { Atom name; unsigned long card32; } XFontProp; typedef struct { XExtData *ext_data; /* hook for extension to hang data */ Font fid; /* Font id for this font */ unsigned direction; /* hint about direction the font is painted */ unsigned min_char_or_byte2;/* first character */ unsigned max_char_or_byte2;/* last character */ unsigned min_byte1; /* first row that exists */ unsigned max_byte1; /* last row that exists */ Bool all_chars_exist;/* flag if all characters have non-zero size*/ unsigned default_char; /* char to print for undefined character */ int n_properties; /* how many properties there are */ XFontProp *properties; /* pointer to array of additional properties*/ XCharStruct min_bounds; /* minimum bounds over all existing char*/ XCharStruct max_bounds; /* maximum bounds over all existing char*/ XCharStruct *per_char; /* first_char to last_char information */ int ascent; /* log. extent above baseline for spacing */ int descent; /* log. descent below baseline for spacing */ } XFontStruct; /* * PolyText routines take these as arguments. */ typedef struct { char *chars; /* pointer to string */ int nchars; /* number of characters */ int delta; /* delta between strings */ Font font; /* font to print it in, None don't change */ } XTextItem; typedef struct { /* normal 16 bit characters are two bytes */ unsigned char byte1; unsigned char byte2; } XChar2b; typedef struct { XChar2b *chars; /* two byte characters */ int nchars; /* number of characters */ int delta; /* delta between strings */ Font font; /* font to print it in, None don't change */ } XTextItem16; typedef union { Display *display; GC gc; Visual *visual; Screen *screen; ScreenFormat *pixmap_format; XFontStruct *font; } XEDataObject; typedef struct { XRectangle max_ink_extent; XRectangle max_logical_extent; } XFontSetExtents; typedef struct _XFontSet *XFontSet; typedef struct { char *chars; int nchars; int delta; XFontSet font_set; } XmbTextItem; typedef struct { wchar_t *chars; int nchars; int delta; XFontSet font_set; } XwcTextItem; typedef void (*XIMProc)(); typedef struct _XIM *XIM; typedef struct _XIC *XIC; typedef unsigned long XIMStyle; typedef struct { unsigned short count_styles; XIMStyle *supported_styles; } XIMStyles; #define XIMPreeditArea 0x0001L #define XIMPreeditCallbacks 0x0002L #define XIMPreeditPosition 0x0004L #define XIMPreeditNothing 0x0008L #define XIMPreeditNone 0x0010L #define XIMStatusArea 0x0100L #define XIMStatusCallbacks 0x0200L #define XIMStatusNothing 0x0400L #define XIMStatusNone 0x0800L #define XNVaNestedList "XNVaNestedList" #define XNClientWindow "clientWindow" #define XNInputStyle "inputStyle" #define XNFocusWindow "focusWindow" #define XNResourceName "resourceName" #define XNResourceClass "resourceClass" #define XNGeometryCallback "geometryCallback" #define XNFilterEvents "filterEvents" #define XNPreeditStartCallback "preeditStartCallback" #define XNPreeditDoneCallback "preeditDoneCallback" #define XNPreeditDrawCallback "preeditDrawCallback" #define XNPreeditCaretCallback "preeditCaretCallback" #define XNPreeditAttributes "preeditAttributes" #define XNStatusStartCallback "statusStartCallback" #define XNStatusDoneCallback "statusDoneCallback" #define XNStatusDrawCallback "statusDrawCallback" #define XNStatusAttributes "statusAttributes" #define XNArea "area" #define XNAreaNeeded "areaNeeded" #define XNSpotLocation "spotLocation" #define XNColormap "colorMap" #define XNStdColormap "stdColorMap" #define XNForeground "foreground" #define XNBackground "background" #define XNBackgroundPixmap "backgroundPixmap" #define XNFontSet "fontSet" #define XNLineSpace "lineSpace" #define XNCursor "cursor" #define XBufferOverflow -1 #define XLookupNone 1 #define XLookupChars 2 #define XLookupKeySym 3 #define XLookupBoth 4 #if NeedFunctionPrototypes typedef void *XVaNestedList; #else typedef XPointer XVaNestedList; #endif typedef struct { XPointer client_data; XIMProc callback; } XIMCallback; typedef unsigned long XIMFeedback; #define XIMReverse 1 #define XIMUnderline (1<<1) #define XIMHighlight (1<<2) #define XIMPrimary (1<<5) #define XIMSecondary (1<<6) #define XIMTertiary (1<<7) typedef struct _XIMText { unsigned short length; XIMFeedback *feedback; Bool encoding_is_wchar; union { char *multi_byte; wchar_t *wide_char; } string; } XIMText; typedef struct _XIMPreeditDrawCallbackStruct { int caret; /* Cursor offset within pre-edit string */ int chg_first; /* Starting change position */ int chg_length; /* Length of the change in character count */ XIMText *text; } XIMPreeditDrawCallbackStruct; typedef enum { XIMForwardChar, XIMBackwardChar, XIMForwardWord, XIMBackwardWord, XIMCaretUp, XIMCaretDown, XIMNextLine, XIMPreviousLine, XIMLineStart, XIMLineEnd, XIMAbsolutePosition, XIMDontChange } XIMCaretDirection; typedef enum { XIMIsInvisible, /* Disable caret feedback */ XIMIsPrimary, /* UI defined caret feedback */ XIMIsSecondary /* UI defined caret feedback */ } XIMCaretStyle; typedef struct _XIMPreeditCaretCallbackStruct { int position; /* Caret offset within pre-edit string */ XIMCaretDirection direction; /* Caret moves direction */ XIMCaretStyle style; /* Feedback of the caret */ } XIMPreeditCaretCallbackStruct; typedef enum { XIMTextType, XIMBitmapType } XIMStatusDataType; typedef struct _XIMStatusDrawCallbackStruct { XIMStatusDataType type; union { XIMText *text; Pixmap bitmap; } data; } XIMStatusDrawCallbackStruct; typedef int (*XErrorHandler) ( /* WARNING, this type not in Xlib spec */ #if NeedFunctionPrototypes Display* /* display */, XErrorEvent* /* error_event */ #endif ); _XFUNCPROTOBEGIN #include "X11/Xutil.h" extern void XSetDashes(Display * display, GC gc, int dash_offset, _Xconst char* dash_list, int n); extern XModifierKeymap *XGetModifierMapping(Display *display); extern XImage *XCreateImage(Display *display, Visual *visual, unsigned int ui1, int i1, int i2, char* cp, unsigned int ui2, unsigned int ui3, int i3, int i4); extern XImage *XGetImage(Display* display,Drawable dr, int i1, int i2, unsigned int ui1, unsigned int ui2, unsigned long ul, int i3); extern char *XGetAtomName(Display *d, Atom a); extern char *XKeysymToString(KeySym k); extern Colormap XCreateColormap(Display *d, Window w, Visual* v, int i); extern Cursor XCreatePixmapCursor(Display *d, Pixmap p1, Pixmap p2, XColor* x1, XColor* x2, unsigned int ui1, unsigned int ui2); extern Cursor XCreateGlyphCursor(Display *d, Font f1, Font f2, unsigned int ui1, unsigned int ui2, XColor* x1, XColor* x2); extern GContext XGContextFromGC(GC g); extern XHostAddress *XListHosts(Display *d, int* i, Bool* b); extern KeySym XKeycodeToKeysym(Display *d, unsigned int k, int i); extern KeySym XStringToKeysym(_Xconst char* c); extern Window XRootWindow(Display *d, int i); extern XErrorHandler XSetErrorHandler(XErrorHandler x); extern Status XIconifyWindow(Display *d, Window w, int i); extern Status XWithdrawWindow(Display *d, Window w, int i); extern Status XGetWMColormapWindows(Display *d, Window w, Window** wpp, int* ip); extern Status XAllocColor(Display *d, Colormap c, XColor* xp); extern void XBell(Display *d, int i); extern void XChangeProperty(Display *d, Window w, Atom a1, Atom a2, int i1, int i2, _Xconst unsigned char* c, int i3); extern void XChangeWindowAttributes(Display *d, Window w, unsigned long ul, XSetWindowAttributes* x); extern void XClearWindow(Display *d, Window w); extern void XConfigureWindow(Display *d, Window w, unsigned int i, XWindowChanges* x); extern void XCopyArea(Display *d, Drawable dr1, Drawable dr2, GC g, int i1, int i2, unsigned int ui1, unsigned int ui2, int i3, int i4); extern void XCopyPlane(Display *d, Drawable dr1, Drawable dr2, GC g, int i1, int i2, unsigned int ui1, unsigned int ui2, int i3, int i4, unsigned long ul); extern Pixmap XCreateBitmapFromData(Display *display, Drawable d, _Xconst char* data, unsigned int width, unsigned int height); extern void XDefineCursor(Display *d, Window w, Cursor c); extern void XDeleteProperty(Display *d, Window w, Atom a); extern void XDestroyWindow(Display *d, Window w); extern void XDrawArc(Display *d, Drawable dr, GC g, int i1, int i2, unsigned int ui1, unsigned int ui2, int i3, int i4); extern void XDrawLines(Display *d, Drawable dr, GC g, XPoint* x, int i1, int i2); extern void XDrawRectangle(Display *d, Drawable dr, GC g, int i1, int i2, unsigned int ui1, unsigned int ui2); extern void XFillArc(Display *d, Drawable dr, GC g, int i1, int i2, unsigned int ui1, unsigned int ui2, int i3, int i4); extern void XFillPolygon(Display *d, Drawable dr, GC g, XPoint* x, int i1, int i2, int i3); extern void XFillRectangles(Display *d, Drawable dr, GC g, XRectangle* x, int i); extern void XForceScreenSaver(Display *d, int i); extern void XFreeColormap(Display *d, Colormap c); extern void XFreeColors(Display *d, Colormap c, unsigned long* ulp, int i, unsigned long ul); extern void XFreeCursor(Display *d, Cursor c); extern void XFreeModifiermap(XModifierKeymap* x); extern Status XGetGeometry(Display *d, Drawable dr, Window* w, int* i1, int* i2, unsigned int* ui1, unsigned int* ui2, unsigned int* ui3, unsigned int* ui4); extern void XGetInputFocus(Display *d, Window* w, int* i); extern int XGetWindowProperty(Display *d, Window w, Atom a1, long l1, long l2, Bool b, Atom a2, Atom* ap, int* ip, unsigned long* ulp1, unsigned long* ulp2, unsigned char** cpp); extern Status XGetWindowAttributes(Display *d, Window w, XWindowAttributes* x); extern int XGrabKeyboard(Display *d, Window w, Bool b, int i1, int i2, Time t); extern int XGrabPointer(Display *d, Window w1, Bool b, unsigned int ui, int i1, int i2, Window w2, Cursor c, Time t); extern KeyCode XKeysymToKeycode(Display *d, KeySym k); extern Status XLookupColor(Display *d, Colormap c1, _Xconst char* c2, XColor* x1, XColor* x2); extern void XMapWindow(Display *d, Window w); extern void XMoveResizeWindow(Display *d, Window w, int i1, int i2, unsigned int ui1, unsigned int ui2); extern void XMoveWindow(Display *d, Window w, int i1, int i2); extern void XNextEvent(Display *d, XEvent* x); extern void XPutBackEvent(Display *d, XEvent* x); extern void XQueryColors(Display *d, Colormap c, XColor* x, int i); extern Bool XQueryPointer(Display *d, Window w1, Window* w2, Window* w3, int* i1, int* i2, int* i3, int* i4, unsigned int* ui); extern Status XQueryTree(Display *d, Window w1, Window* w2, Window* w3, Window** w4, unsigned int* ui); extern void XRaiseWindow(Display *d, Window w); extern void XRefreshKeyboardMapping(XMappingEvent* x); extern void XResizeWindow(Display *d, Window w, unsigned int ui1, unsigned int ui2); extern void XSelectInput(Display *d, Window w, long l); extern Status XSendEvent(Display *d, Window w, Bool b, long l, XEvent* x); extern void XSetCommand(Display *d, Window w, char** c, int i); extern void XSetIconName(Display *d, Window w, _Xconst char* c); extern void XSetInputFocus(Display *d, Window w, int i, Time t); extern void XSetSelectionOwner(Display *d, Atom a, Window w, Time t); extern void XSetWindowBackground(Display *d, Window w, unsigned long ul); extern void XSetWindowBackgroundPixmap(Display *d, Window w, Pixmap p); extern void XSetWindowBorder(Display *d, Window w, unsigned long ul); extern void XSetWindowBorderPixmap(Display *d, Window w, Pixmap p); extern void XSetWindowBorderWidth(Display *d, Window w, unsigned int ui); extern void XSetWindowColormap(Display *d, Window w, Colormap c); extern Bool XTranslateCoordinates(Display *d, Window w1, Window w2, int i1, int i2, int* i3, int* i4, Window* w3); extern void XUngrabKeyboard(Display *d, Time t); extern void XUngrabPointer(Display *d, Time t); extern void XUnmapWindow(Display *d, Window w); extern void XWindowEvent(Display *d, Window w, long l, XEvent* x); extern void XDestroyIC(XIC x); extern Bool XFilterEvent(XEvent* x, Window w); extern int XmbLookupString(XIC xi, XKeyPressedEvent* xk, char* c, int i, KeySym* k, Status* s); extern void TkPutImage(unsigned long * colors, int ncolors, Display *display, Drawable d, GC gc, XImage* image, int src_x, int src_y, int dest_x, int dest_y, unsigned int width, unsigned int height); extern Status XParseColor(Display * display, Colormap map, _Xconst char* spec, XColor * colorPtr); extern GC XCreateGC(Display *display, Drawable d, unsigned long valuemask, XGCValues* values); extern void XFreeGC(Display *display, GC gc); extern Atom XInternAtom(Display *display, _Xconst char* atom_name, Bool only_if_exists); extern void XSetBackground(Display *display, GC gc, unsigned long foreground); extern void XSetForeground(Display *display, GC gc, unsigned long foreground); extern void XSetClipMask(Display *display, GC gc, Pixmap pixmap); extern void XSetClipOrigin(Display *display, GC gc, int clip_x_origin, int clip_y_origin); extern void XSetTSOrigin(Display *display, GC gc, int ts_x_origin, int ts_y_origin); extern void XChangeGC(Display *display, GC gc, unsigned long mask, XGCValues * values); extern void XSetFont(Display *display, GC gc, Font font); extern void XSetArcMode(Display *display, GC gc, int arc_mode); extern void XSetStipple(Display * display, GC gc, Pixmap stipple); extern void XSetFillRule(Display *display, GC gc, int fill_rule); extern void XSetFillStyle(Display *display, GC gc, int fill_style); extern void XSetFunction(Display *display, GC gc, int function); extern void XSetLineAttributes(Display *display, GC gc, unsigned int line_width, int line_style, int cap_style, int join_style); extern int _XInitImageFuncPtrs(XImage * image); extern XIC XCreateIC(void); extern XVisualInfo *XGetVisualInfo(Display *display, long vinfo_mask, XVisualInfo* vinfo_template, int* nitems_return); extern void XSetWMClientMachine(Display *display, Window w, XTextProperty* text_prop); extern Status XStringListToTextProperty(char** list, int count, XTextProperty* text_prop_return); extern void XDrawLine(Display *d, Drawable dr, GC g, int x1, int y1, int x2, int y2); extern void XWarpPointer(Display *d, Window s, Window dw, int sx, int sy, unsigned int sw, unsigned int sh, int dx, int dy); extern void XFillRectangle(Display *display, Drawable d, GC gc, int x, int y, unsigned int width, unsigned int height); _XFUNCPROTOEND #ifdef MAC_TCL # undef Cursor # undef Region #endif #endif /* _XLIB_H_ */ blt-2.4z.orig/win/X11/Xutil.h0100644000175000017500000004736707514116170014413 0ustar dokodoko/* $XConsortium: Xutil.h,v 11.73 91/07/30 16:21:37 rws Exp $ */ /*********************************************************** Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, and the Massachusetts Institute of Technology, Cambridge, Massachusetts. All Rights Reserved 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 copyright notice and this permission notice appear in supporting documentation, and that the names of Digital or MIT not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DIGITAL 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 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************/ #ifndef _XUTIL_H_ #define _XUTIL_H_ /* You must include before including this file */ #ifdef MAC_TCL # define Region XRegion #endif /* * Bitmask returned by XParseGeometry(). Each bit tells if the corresponding * value (x, y, width, height) was found in the parsed string. */ #define NoValue 0x0000 #define XValue 0x0001 #define YValue 0x0002 #define WidthValue 0x0004 #define HeightValue 0x0008 #define AllValues 0x000F #define XNegative 0x0010 #define YNegative 0x0020 /* * new version containing base_width, base_height, and win_gravity fields; * used with WM_NORMAL_HINTS. */ typedef struct { long flags; /* marks which fields in this structure are defined */ int x, y; /* obsolete for new window mgrs, but clients */ int width, height; /* should set so old wm's don't mess up */ int min_width, min_height; int max_width, max_height; int width_inc, height_inc; struct { int x; /* numerator */ int y; /* denominator */ } min_aspect, max_aspect; int base_width, base_height; /* added by ICCCM version 1 */ int win_gravity; /* added by ICCCM version 1 */ } XSizeHints; /* * The next block of definitions are for window manager properties that * clients and applications use for communication. */ /* flags argument in size hints */ #define USPosition (1L << 0) /* user specified x, y */ #define USSize (1L << 1) /* user specified width, height */ #define PPosition (1L << 2) /* program specified position */ #define PSize (1L << 3) /* program specified size */ #define PMinSize (1L << 4) /* program specified minimum size */ #define PMaxSize (1L << 5) /* program specified maximum size */ #define PResizeInc (1L << 6) /* program specified resize increments */ #define PAspect (1L << 7) /* program specified min and max aspect ratios */ #define PBaseSize (1L << 8) /* program specified base for incrementing */ #define PWinGravity (1L << 9) /* program specified window gravity */ /* obsolete */ #define PAllHints (PPosition|PSize|PMinSize|PMaxSize|PResizeInc|PAspect) typedef struct { long flags; /* marks which fields in this structure are defined */ Bool input; /* does this application rely on the window manager to get keyboard input? */ int initial_state; /* see below */ Pixmap icon_pixmap; /* pixmap to be used as icon */ Window icon_window; /* window to be used as icon */ int icon_x, icon_y; /* initial position of icon */ Pixmap icon_mask; /* icon mask bitmap */ XID window_group; /* id of related window group */ /* this structure may be extended in the future */ } XWMHints; /* definition for flags of XWMHints */ #define InputHint (1L << 0) #define StateHint (1L << 1) #define IconPixmapHint (1L << 2) #define IconWindowHint (1L << 3) #define IconPositionHint (1L << 4) #define IconMaskHint (1L << 5) #define WindowGroupHint (1L << 6) #define AllHints (InputHint|StateHint|IconPixmapHint|IconWindowHint| \ IconPositionHint|IconMaskHint|WindowGroupHint) /* definitions for initial window state */ #define WithdrawnState 0 /* for windows that are not mapped */ #define NormalState 1 /* most applications want to start this way */ #define IconicState 3 /* application wants to start as an icon */ /* * Obsolete states no longer defined by ICCCM */ #define DontCareState 0 /* don't know or care */ #define ZoomState 2 /* application wants to start zoomed */ #define InactiveState 4 /* application believes it is seldom used; */ /* some wm's may put it on inactive menu */ /* * new structure for manipulating TEXT properties; used with WM_NAME, * WM_ICON_NAME, WM_CLIENT_MACHINE, and WM_COMMAND. */ typedef struct { unsigned char *value; /* same as Property routines */ Atom encoding; /* prop type */ int format; /* prop data format: 8, 16, or 32 */ unsigned long nitems; /* number of data items in value */ } XTextProperty; #define XNoMemory -1 #define XLocaleNotSupported -2 #define XConverterNotFound -3 typedef enum { XStringStyle, /* STRING */ XCompoundTextStyle, /* COMPOUND_TEXT */ XTextStyle, /* text in owner's encoding (current locale)*/ XStdICCTextStyle /* STRING, else COMPOUND_TEXT */ } XICCEncodingStyle; typedef struct { int min_width, min_height; int max_width, max_height; int width_inc, height_inc; } XIconSize; typedef struct { char *res_name; char *res_class; } XClassHint; /* * These macros are used to give some sugar to the image routines so that * naive people are more comfortable with them. */ #define XDestroyImage(ximage) \ ((*((ximage)->f.destroy_image))((ximage))) #define XGetPixel(ximage, x, y) \ ((*((ximage)->f.get_pixel))((ximage), (x), (y))) #define XPutPixel(ximage, x, y, pixel) \ ((*((ximage)->f.put_pixel))((ximage), (x), (y), (pixel))) #define XSubImage(ximage, x, y, width, height) \ ((*((ximage)->f.sub_image))((ximage), (x), (y), (width), (height))) #define XAddPixel(ximage, value) \ ((*((ximage)->f.add_pixel))((ximage), (value))) /* * Compose sequence status structure, used in calling XLookupString. */ typedef struct _XComposeStatus { XPointer compose_ptr; /* state table pointer */ int chars_matched; /* match state */ } XComposeStatus; /* * Keysym macros, used on Keysyms to test for classes of symbols */ #define IsKeypadKey(keysym) \ (((unsigned)(keysym) >= XK_KP_Space) && ((unsigned)(keysym) <= XK_KP_Equal)) #define IsCursorKey(keysym) \ (((unsigned)(keysym) >= XK_Home) && ((unsigned)(keysym) < XK_Select)) #define IsPFKey(keysym) \ (((unsigned)(keysym) >= XK_KP_F1) && ((unsigned)(keysym) <= XK_KP_F4)) #define IsFunctionKey(keysym) \ (((unsigned)(keysym) >= XK_F1) && ((unsigned)(keysym) <= XK_F35)) #define IsMiscFunctionKey(keysym) \ (((unsigned)(keysym) >= XK_Select) && ((unsigned)(keysym) <= XK_Break)) #define IsModifierKey(keysym) \ ((((unsigned)(keysym) >= XK_Shift_L) && ((unsigned)(keysym) <= XK_Hyper_R)) \ || ((unsigned)(keysym) == XK_Mode_switch) \ || ((unsigned)(keysym) == XK_Num_Lock)) /* * opaque reference to Region data type */ typedef struct _XRegion *Region; /* Return values from XRectInRegion() */ #define RectangleOut 0 #define RectangleIn 1 #define RectanglePart 2 /* * Information used by the visual utility routines to find desired visual * type from the many visuals a display may support. */ typedef struct { Visual *visual; VisualID visualid; int screen; int depth; #if defined(__cplusplus) || defined(c_plusplus) int c_class; /* C++ */ #else int class; #endif unsigned long red_mask; unsigned long green_mask; unsigned long blue_mask; int colormap_size; int bits_per_rgb; } XVisualInfo; #define VisualNoMask 0x0 #define VisualIDMask 0x1 #define VisualScreenMask 0x2 #define VisualDepthMask 0x4 #define VisualClassMask 0x8 #define VisualRedMaskMask 0x10 #define VisualGreenMaskMask 0x20 #define VisualBlueMaskMask 0x40 #define VisualColormapSizeMask 0x80 #define VisualBitsPerRGBMask 0x100 #define VisualAllMask 0x1FF /* * This defines a window manager property that clients may use to * share standard color maps of type RGB_COLOR_MAP: */ typedef struct { Colormap colormap; unsigned long red_max; unsigned long red_mult; unsigned long green_max; unsigned long green_mult; unsigned long blue_max; unsigned long blue_mult; unsigned long base_pixel; VisualID visualid; /* added by ICCCM version 1 */ XID killid; /* added by ICCCM version 1 */ } XStandardColormap; #define ReleaseByFreeingColormap ((XID) 1L) /* for killid field above */ /* * return codes for XReadBitmapFile and XWriteBitmapFile */ #define BitmapSuccess 0 #define BitmapOpenFailed 1 #define BitmapFileInvalid 2 #define BitmapNoMemory 3 /**************************************************************** * * Context Management * ****************************************************************/ /* Associative lookup table return codes */ #define XCSUCCESS 0 /* No error. */ #define XCNOMEM 1 /* Out of memory */ #define XCNOENT 2 /* No entry in table */ typedef int XContext; #define XUniqueContext() ((XContext) XrmUniqueQuark()) #define XStringToContext(string) ((XContext) XrmStringToQuark(string)) _XFUNCPROTOBEGIN /* The following declarations are alphabetized. */ extern XClassHint *XAllocClassHint ( #if NeedFunctionPrototypes void #endif ); extern XIconSize *XAllocIconSize ( #if NeedFunctionPrototypes void #endif ); extern XSizeHints *XAllocSizeHints ( #if NeedFunctionPrototypes void #endif ); extern XStandardColormap *XAllocStandardColormap ( #if NeedFunctionPrototypes void #endif ); extern XWMHints *XAllocWMHints ( #if NeedFunctionPrototypes void #endif ); extern void XClipBox( #if NeedFunctionPrototypes Region /* r */, XRectangle* /* rect_return */ #endif ); extern Region XCreateRegion( #if NeedFunctionPrototypes void #endif ); extern char *XDefaultString( #if NeedFunctionPrototypes void #endif ); extern int XDeleteContext( #if NeedFunctionPrototypes Display* /* display */, XID /* rid */, XContext /* context */ #endif ); extern void XDestroyRegion( #if NeedFunctionPrototypes Region /* r */ #endif ); extern void XEmptyRegion( #if NeedFunctionPrototypes Region /* r */ #endif ); extern void XEqualRegion( #if NeedFunctionPrototypes Region /* r1 */, Region /* r2 */ #endif ); extern int XFindContext( #if NeedFunctionPrototypes Display* /* display */, XID /* rid */, XContext /* context */, XPointer* /* data_return */ #endif ); extern Status XGetClassHint( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XClassHint* /* class_hints_return */ #endif ); extern Status XGetIconSizes( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XIconSize** /* size_list_return */, int* /* count_return */ #endif ); extern Status XGetNormalHints( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XSizeHints* /* hints_return */ #endif ); extern Status XGetRGBColormaps( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XStandardColormap** /* stdcmap_return */, int* /* count_return */, Atom /* property */ #endif ); extern Status XGetSizeHints( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XSizeHints* /* hints_return */, Atom /* property */ #endif ); extern Status XGetStandardColormap( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XStandardColormap* /* colormap_return */, Atom /* property */ #endif ); extern Status XGetTextProperty( #if NeedFunctionPrototypes Display* /* display */, Window /* window */, XTextProperty* /* text_prop_return */, Atom /* property */ #endif ); extern Status XGetWMClientMachine( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XTextProperty* /* text_prop_return */ #endif ); extern XWMHints *XGetWMHints( #if NeedFunctionPrototypes Display* /* display */, Window /* w */ #endif ); extern Status XGetWMIconName( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XTextProperty* /* text_prop_return */ #endif ); extern Status XGetWMName( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XTextProperty* /* text_prop_return */ #endif ); extern Status XGetWMNormalHints( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XSizeHints* /* hints_return */, long* /* supplied_return */ #endif ); extern Status XGetWMSizeHints( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XSizeHints* /* hints_return */, long* /* supplied_return */, Atom /* property */ #endif ); extern Status XGetZoomHints( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XSizeHints* /* zhints_return */ #endif ); extern void XIntersectRegion( #if NeedFunctionPrototypes Region /* sra */, Region /* srb */, Region /* dr_return */ #endif ); extern int XLookupString( #if NeedFunctionPrototypes XKeyEvent* /* event_struct */, char* /* buffer_return */, int /* bytes_buffer */, KeySym* /* keysym_return */, XComposeStatus* /* status_in_out */ #endif ); extern Status XMatchVisualInfo( #if NeedFunctionPrototypes Display* /* display */, int /* screen */, int /* depth */, int /* class */, XVisualInfo* /* vinfo_return */ #endif ); extern void XOffsetRegion( #if NeedFunctionPrototypes Region /* r */, int /* dx */, int /* dy */ #endif ); extern Bool XPointInRegion( #if NeedFunctionPrototypes Region /* r */, int /* x */, int /* y */ #endif ); extern Region XPolygonRegion( #if NeedFunctionPrototypes XPoint* /* points */, int /* n */, int /* fill_rule */ #endif ); extern int XRectInRegion( #if NeedFunctionPrototypes Region /* r */, int /* x */, int /* y */, unsigned int /* width */, unsigned int /* height */ #endif ); extern int XSaveContext( #if NeedFunctionPrototypes Display* /* display */, XID /* rid */, XContext /* context */, _Xconst char* /* data */ #endif ); extern void XSetClassHint( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XClassHint* /* class_hints */ #endif ); extern void XSetIconSizes( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XIconSize* /* size_list */, int /* count */ #endif ); extern void XSetNormalHints( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XSizeHints* /* hints */ #endif ); extern void XSetRGBColormaps( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XStandardColormap* /* stdcmaps */, int /* count */, Atom /* property */ #endif ); extern void XSetSizeHints( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XSizeHints* /* hints */, Atom /* property */ #endif ); extern void XSetStandardProperties( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, _Xconst char* /* window_name */, _Xconst char* /* icon_name */, Pixmap /* icon_pixmap */, char** /* argv */, int /* argc */, XSizeHints* /* hints */ #endif ); extern void XSetTextProperty( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XTextProperty* /* text_prop */, Atom /* property */ #endif ); extern void XSetWMHints( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XWMHints* /* wm_hints */ #endif ); extern void XSetWMIconName( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XTextProperty* /* text_prop */ #endif ); extern void XSetWMName( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XTextProperty* /* text_prop */ #endif ); extern void XSetWMNormalHints( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XSizeHints* /* hints */ #endif ); extern void XSetWMProperties( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XTextProperty* /* window_name */, XTextProperty* /* icon_name */, char** /* argv */, int /* argc */, XSizeHints* /* normal_hints */, XWMHints* /* wm_hints */, XClassHint* /* class_hints */ #endif ); extern void XmbSetWMProperties( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, _Xconst char* /* window_name */, _Xconst char* /* icon_name */, char** /* argv */, int /* argc */, XSizeHints* /* normal_hints */, XWMHints* /* wm_hints */, XClassHint* /* class_hints */ #endif ); extern void XSetWMSizeHints( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XSizeHints* /* hints */, Atom /* property */ #endif ); extern void XSetRegion( #if NeedFunctionPrototypes Display* /* display */, GC /* gc */, Region /* r */ #endif ); extern void XSetStandardColormap( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XStandardColormap* /* colormap */, Atom /* property */ #endif ); extern void XSetZoomHints( #if NeedFunctionPrototypes Display* /* display */, Window /* w */, XSizeHints* /* zhints */ #endif ); extern void XShrinkRegion( #if NeedFunctionPrototypes Region /* r */, int /* dx */, int /* dy */ #endif ); extern void XSubtractRegion( #if NeedFunctionPrototypes Region /* sra */, Region /* srb */, Region /* dr_return */ #endif ); extern int XmbTextListToTextProperty( #if NeedFunctionPrototypes Display* /* display */, char** /* list */, int /* count */, XICCEncodingStyle /* style */, XTextProperty* /* text_prop_return */ #endif ); extern int XwcTextListToTextProperty( #if NeedFunctionPrototypes Display* /* display */, wchar_t** /* list */, int /* count */, XICCEncodingStyle /* style */, XTextProperty* /* text_prop_return */ #endif ); extern void XwcFreeStringList( #if NeedFunctionPrototypes wchar_t** /* list */ #endif ); extern Status XTextPropertyToStringList( #if NeedFunctionPrototypes XTextProperty* /* text_prop */, char*** /* list_return */, int* /* count_return */ #endif ); extern int XmbTextPropertyToTextList( #if NeedFunctionPrototypes Display* /* display */, XTextProperty* /* text_prop */, char*** /* list_return */, int* /* count_return */ #endif ); extern int XwcTextPropertyToTextList( #if NeedFunctionPrototypes Display* /* display */, XTextProperty* /* text_prop */, wchar_t*** /* list_return */, int* /* count_return */ #endif ); extern void XUnionRectWithRegion( #if NeedFunctionPrototypes XRectangle* /* rectangle */, Region /* src_region */, Region /* dest_region_return */ #endif ); extern void XUnionRegion( #if NeedFunctionPrototypes Region /* sra */, Region /* srb */, Region /* dr_return */ #endif ); extern int XWMGeometry( #if NeedFunctionPrototypes Display* /* display */, int /* screen_number */, _Xconst char* /* user_geometry */, _Xconst char* /* default_geometry */, unsigned int /* border_width */, XSizeHints* /* hints */, int* /* x_return */, int* /* y_return */, int* /* width_return */, int* /* height_return */, int* /* gravity_return */ #endif ); extern void XXorRegion( #if NeedFunctionPrototypes Region /* sra */, Region /* srb */, Region /* dr_return */ #endif ); _XFUNCPROTOEND #ifdef MAC_TCL # undef Region #endif #endif /* _XUTIL_H_ */ blt-2.4z.orig/win/X11/cursorfont.h0100644000175000017500000000364107514116170015475 0ustar dokodoko/* $XConsortium: cursorfont.h,v 1.2 88/09/06 16:44:27 jim Exp $ */ #define XC_num_glyphs 154 #define XC_X_cursor 0 #define XC_arrow 2 #define XC_based_arrow_down 4 #define XC_based_arrow_up 6 #define XC_boat 8 #define XC_bogosity 10 #define XC_bottom_left_corner 12 #define XC_bottom_right_corner 14 #define XC_bottom_side 16 #define XC_bottom_tee 18 #define XC_box_spiral 20 #define XC_center_ptr 22 #define XC_circle 24 #define XC_clock 26 #define XC_coffee_mug 28 #define XC_cross 30 #define XC_cross_reverse 32 #define XC_crosshair 34 #define XC_diamond_cross 36 #define XC_dot 38 #define XC_dotbox 40 #define XC_double_arrow 42 #define XC_draft_large 44 #define XC_draft_small 46 #define XC_draped_box 48 #define XC_exchange 50 #define XC_fleur 52 #define XC_gobbler 54 #define XC_gumby 56 #define XC_hand1 58 #define XC_hand2 60 #define XC_heart 62 #define XC_icon 64 #define XC_iron_cross 66 #define XC_left_ptr 68 #define XC_left_side 70 #define XC_left_tee 72 #define XC_leftbutton 74 #define XC_ll_angle 76 #define XC_lr_angle 78 #define XC_man 80 #define XC_middlebutton 82 #define XC_mouse 84 #define XC_pencil 86 #define XC_pirate 88 #define XC_plus 90 #define XC_question_arrow 92 #define XC_right_ptr 94 #define XC_right_side 96 #define XC_right_tee 98 #define XC_rightbutton 100 #define XC_rtl_logo 102 #define XC_sailboat 104 #define XC_sb_down_arrow 106 #define XC_sb_h_double_arrow 108 #define XC_sb_left_arrow 110 #define XC_sb_right_arrow 112 #define XC_sb_up_arrow 114 #define XC_sb_v_double_arrow 116 #define XC_shuttle 118 #define XC_sizing 120 #define XC_spider 122 #define XC_spraycan 124 #define XC_star 126 #define XC_target 128 #define XC_tcross 130 #define XC_top_left_arrow 132 #define XC_top_left_corner 134 #define XC_top_right_corner 136 #define XC_top_side 138 #define XC_top_tee 140 #define XC_trek 142 #define XC_ul_angle 144 #define XC_umbrella 146 #define XC_ur_angle 148 #define XC_watch 150 #define XC_xterm 152 blt-2.4z.orig/win/X11/keysym.h0100644000175000017500000000273507514116170014615 0ustar dokodoko/* $XConsortium: keysym.h,v 1.13 91/03/13 20:09:49 rws Exp $ */ /*********************************************************** Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, and the Massachusetts Institute of Technology, Cambridge, Massachusetts. All Rights Reserved 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 copyright notice and this permission notice appear in supporting documentation, and that the names of Digital or MIT not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DIGITAL 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 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************/ /* default keysyms */ #define XK_MISCELLANY #define XK_LATIN1 #define XK_LATIN2 #define XK_LATIN3 #define XK_LATIN4 #define XK_GREEK #ifdef MAC_TCL #include #else #include #endif blt-2.4z.orig/win/X11/keysymdef.h0100644000175000017500000014631507514116170015277 0ustar dokodoko/* $XConsortium: keysymdef.h,v 1.15 93/04/02 10:57:36 rws Exp $ */ /*********************************************************** Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, and the Massachusetts Institute of Technology, Cambridge, Massachusetts. All Rights Reserved 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 copyright notice and this permission notice appear in supporting documentation, and that the names of Digital or MIT not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DIGITAL 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 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************/ #define XK_VoidSymbol 0xFFFFFF /* void symbol */ #ifdef XK_MISCELLANY /* * TTY Functions, cleverly chosen to map to ascii, for convenience of * programming, but could have been arbitrary (at the cost of lookup * tables in client code. */ #define XK_BackSpace 0xFF08 /* back space, back char */ #define XK_Tab 0xFF09 #define XK_Linefeed 0xFF0A /* Linefeed, LF */ #define XK_Clear 0xFF0B #define XK_Return 0xFF0D /* Return, enter */ #define XK_Pause 0xFF13 /* Pause, hold */ #define XK_Scroll_Lock 0xFF14 #define XK_Sys_Req 0xFF15 #define XK_Escape 0xFF1B #define XK_Delete 0xFFFF /* Delete, rubout */ /* International & multi-key character composition */ #define XK_Multi_key 0xFF20 /* Multi-key character compose */ /* Japanese keyboard support */ #define XK_Kanji 0xFF21 /* Kanji, Kanji convert */ #define XK_Muhenkan 0xFF22 /* Cancel Conversion */ #define XK_Henkan_Mode 0xFF23 /* Start/Stop Conversion */ #define XK_Henkan 0xFF23 /* Alias for Henkan_Mode */ #define XK_Romaji 0xFF24 /* to Romaji */ #define XK_Hiragana 0xFF25 /* to Hiragana */ #define XK_Katakana 0xFF26 /* to Katakana */ #define XK_Hiragana_Katakana 0xFF27 /* Hiragana/Katakana toggle */ #define XK_Zenkaku 0xFF28 /* to Zenkaku */ #define XK_Hankaku 0xFF29 /* to Hankaku */ #define XK_Zenkaku_Hankaku 0xFF2A /* Zenkaku/Hankaku toggle */ #define XK_Touroku 0xFF2B /* Add to Dictionary */ #define XK_Massyo 0xFF2C /* Delete from Dictionary */ #define XK_Kana_Lock 0xFF2D /* Kana Lock */ #define XK_Kana_Shift 0xFF2E /* Kana Shift */ #define XK_Eisu_Shift 0xFF2F /* Alphanumeric Shift */ #define XK_Eisu_toggle 0xFF30 /* Alphanumeric toggle */ /* Cursor control & motion */ #define XK_Home 0xFF50 #define XK_Left 0xFF51 /* Move left, left arrow */ #define XK_Up 0xFF52 /* Move up, up arrow */ #define XK_Right 0xFF53 /* Move right, right arrow */ #define XK_Down 0xFF54 /* Move down, down arrow */ #define XK_Prior 0xFF55 /* Prior, previous */ #define XK_Page_Up 0xFF55 #define XK_Next 0xFF56 /* Next */ #define XK_Page_Down 0xFF56 #define XK_End 0xFF57 /* EOL */ #define XK_Begin 0xFF58 /* BOL */ /* Special Windows keyboard keys */ #define XK_Win_L 0xFF5B /* Left-hand Windows */ #define XK_Win_R 0xFF5C /* Right-hand Windows */ #define XK_App 0xFF5D /* Menu key */ /* Misc Functions */ #define XK_Select 0xFF60 /* Select, mark */ #define XK_Print 0xFF61 #define XK_Execute 0xFF62 /* Execute, run, do */ #define XK_Insert 0xFF63 /* Insert, insert here */ #define XK_Undo 0xFF65 /* Undo, oops */ #define XK_Redo 0xFF66 /* redo, again */ #define XK_Menu 0xFF67 #define XK_Find 0xFF68 /* Find, search */ #define XK_Cancel 0xFF69 /* Cancel, stop, abort, exit */ #define XK_Help 0xFF6A /* Help, ? */ #define XK_Break 0xFF6B #define XK_Mode_switch 0xFF7E /* Character set switch */ #define XK_script_switch 0xFF7E /* Alias for mode_switch */ #define XK_Num_Lock 0xFF7F /* Keypad Functions, keypad numbers cleverly chosen to map to ascii */ #define XK_KP_Space 0xFF80 /* space */ #define XK_KP_Tab 0xFF89 #define XK_KP_Enter 0xFF8D /* enter */ #define XK_KP_F1 0xFF91 /* PF1, KP_A, ... */ #define XK_KP_F2 0xFF92 #define XK_KP_F3 0xFF93 #define XK_KP_F4 0xFF94 #define XK_KP_Home 0xFF95 #define XK_KP_Left 0xFF96 #define XK_KP_Up 0xFF97 #define XK_KP_Right 0xFF98 #define XK_KP_Down 0xFF99 #define XK_KP_Prior 0xFF9A #define XK_KP_Page_Up 0xFF9A #define XK_KP_Next 0xFF9B #define XK_KP_Page_Down 0xFF9B #define XK_KP_End 0xFF9C #define XK_KP_Begin 0xFF9D #define XK_KP_Insert 0xFF9E #define XK_KP_Delete 0xFF9F #define XK_KP_Equal 0xFFBD /* equals */ #define XK_KP_Multiply 0xFFAA #define XK_KP_Add 0xFFAB #define XK_KP_Separator 0xFFAC /* separator, often comma */ #define XK_KP_Subtract 0xFFAD #define XK_KP_Decimal 0xFFAE #define XK_KP_Divide 0xFFAF #define XK_KP_0 0xFFB0 #define XK_KP_1 0xFFB1 #define XK_KP_2 0xFFB2 #define XK_KP_3 0xFFB3 #define XK_KP_4 0xFFB4 #define XK_KP_5 0xFFB5 #define XK_KP_6 0xFFB6 #define XK_KP_7 0xFFB7 #define XK_KP_8 0xFFB8 #define XK_KP_9 0xFFB9 /* * Auxilliary Functions; note the duplicate definitions for left and right * function keys; Sun keyboards and a few other manufactures have such * function key groups on the left and/or right sides of the keyboard. * We've not found a keyboard with more than 35 function keys total. */ #define XK_F1 0xFFBE #define XK_F2 0xFFBF #define XK_F3 0xFFC0 #define XK_F4 0xFFC1 #define XK_F5 0xFFC2 #define XK_F6 0xFFC3 #define XK_F7 0xFFC4 #define XK_F8 0xFFC5 #define XK_F9 0xFFC6 #define XK_F10 0xFFC7 #define XK_F11 0xFFC8 #define XK_L1 0xFFC8 #define XK_F12 0xFFC9 #define XK_L2 0xFFC9 #define XK_F13 0xFFCA #define XK_L3 0xFFCA #define XK_F14 0xFFCB #define XK_L4 0xFFCB #define XK_F15 0xFFCC #define XK_L5 0xFFCC #define XK_F16 0xFFCD #define XK_L6 0xFFCD #define XK_F17 0xFFCE #define XK_L7 0xFFCE #define XK_F18 0xFFCF #define XK_L8 0xFFCF #define XK_F19 0xFFD0 #define XK_L9 0xFFD0 #define XK_F20 0xFFD1 #define XK_L10 0xFFD1 #define XK_F21 0xFFD2 #define XK_R1 0xFFD2 #define XK_F22 0xFFD3 #define XK_R2 0xFFD3 #define XK_F23 0xFFD4 #define XK_R3 0xFFD4 #define XK_F24 0xFFD5 #define XK_R4 0xFFD5 #define XK_F25 0xFFD6 #define XK_R5 0xFFD6 #define XK_F26 0xFFD7 #define XK_R6 0xFFD7 #define XK_F27 0xFFD8 #define XK_R7 0xFFD8 #define XK_F28 0xFFD9 #define XK_R8 0xFFD9 #define XK_F29 0xFFDA #define XK_R9 0xFFDA #define XK_F30 0xFFDB #define XK_R10 0xFFDB #define XK_F31 0xFFDC #define XK_R11 0xFFDC #define XK_F32 0xFFDD #define XK_R12 0xFFDD #define XK_F33 0xFFDE #define XK_R13 0xFFDE #define XK_F34 0xFFDF #define XK_R14 0xFFDF #define XK_F35 0xFFE0 #define XK_R15 0xFFE0 /* Modifiers */ #define XK_Shift_L 0xFFE1 /* Left shift */ #define XK_Shift_R 0xFFE2 /* Right shift */ #define XK_Control_L 0xFFE3 /* Left control */ #define XK_Control_R 0xFFE4 /* Right control */ #define XK_Caps_Lock 0xFFE5 /* Caps lock */ #define XK_Shift_Lock 0xFFE6 /* Shift lock */ #define XK_Meta_L 0xFFE7 /* Left meta */ #define XK_Meta_R 0xFFE8 /* Right meta */ #define XK_Alt_L 0xFFE9 /* Left alt */ #define XK_Alt_R 0xFFEA /* Right alt */ #define XK_Super_L 0xFFEB /* Left super */ #define XK_Super_R 0xFFEC /* Right super */ #define XK_Hyper_L 0xFFED /* Left hyper */ #define XK_Hyper_R 0xFFEE /* Right hyper */ #endif /* XK_MISCELLANY */ /* * Latin 1 * Byte 3 = 0 */ #ifdef XK_LATIN1 #define XK_space 0x020 #define XK_exclam 0x021 #define XK_quotedbl 0x022 #define XK_numbersign 0x023 #define XK_dollar 0x024 #define XK_percent 0x025 #define XK_ampersand 0x026 #define XK_apostrophe 0x027 #define XK_quoteright 0x027 /* deprecated */ #define XK_parenleft 0x028 #define XK_parenright 0x029 #define XK_asterisk 0x02a #define XK_plus 0x02b #define XK_comma 0x02c #define XK_minus 0x02d #define XK_period 0x02e #define XK_slash 0x02f #define XK_0 0x030 #define XK_1 0x031 #define XK_2 0x032 #define XK_3 0x033 #define XK_4 0x034 #define XK_5 0x035 #define XK_6 0x036 #define XK_7 0x037 #define XK_8 0x038 #define XK_9 0x039 #define XK_colon 0x03a #define XK_semicolon 0x03b #define XK_less 0x03c #define XK_equal 0x03d #define XK_greater 0x03e #define XK_question 0x03f #define XK_at 0x040 #define XK_A 0x041 #define XK_B 0x042 #define XK_C 0x043 #define XK_D 0x044 #define XK_E 0x045 #define XK_F 0x046 #define XK_G 0x047 #define XK_H 0x048 #define XK_I 0x049 #define XK_J 0x04a #define XK_K 0x04b #define XK_L 0x04c #define XK_M 0x04d #define XK_N 0x04e #define XK_O 0x04f #define XK_P 0x050 #define XK_Q 0x051 #define XK_R 0x052 #define XK_S 0x053 #define XK_T 0x054 #define XK_U 0x055 #define XK_V 0x056 #define XK_W 0x057 #define XK_X 0x058 #define XK_Y 0x059 #define XK_Z 0x05a #define XK_bracketleft 0x05b #define XK_backslash 0x05c #define XK_bracketright 0x05d #define XK_asciicircum 0x05e #define XK_underscore 0x05f #define XK_grave 0x060 #define XK_quoteleft 0x060 /* deprecated */ #define XK_a 0x061 #define XK_b 0x062 #define XK_c 0x063 #define XK_d 0x064 #define XK_e 0x065 #define XK_f 0x066 #define XK_g 0x067 #define XK_h 0x068 #define XK_i 0x069 #define XK_j 0x06a #define XK_k 0x06b #define XK_l 0x06c #define XK_m 0x06d #define XK_n 0x06e #define XK_o 0x06f #define XK_p 0x070 #define XK_q 0x071 #define XK_r 0x072 #define XK_s 0x073 #define XK_t 0x074 #define XK_u 0x075 #define XK_v 0x076 #define XK_w 0x077 #define XK_x 0x078 #define XK_y 0x079 #define XK_z 0x07a #define XK_braceleft 0x07b #define XK_bar 0x07c #define XK_braceright 0x07d #define XK_asciitilde 0x07e #define XK_nobreakspace 0x0a0 #define XK_exclamdown 0x0a1 #define XK_cent 0x0a2 #define XK_sterling 0x0a3 #define XK_currency 0x0a4 #define XK_yen 0x0a5 #define XK_brokenbar 0x0a6 #define XK_section 0x0a7 #define XK_diaeresis 0x0a8 #define XK_copyright 0x0a9 #define XK_ordfeminine 0x0aa #define XK_guillemotleft 0x0ab /* left angle quotation mark */ #define XK_notsign 0x0ac #define XK_hyphen 0x0ad #define XK_registered 0x0ae #define XK_macron 0x0af #define XK_degree 0x0b0 #define XK_plusminus 0x0b1 #define XK_twosuperior 0x0b2 #define XK_threesuperior 0x0b3 #define XK_acute 0x0b4 #define XK_mu 0x0b5 #define XK_paragraph 0x0b6 #define XK_periodcentered 0x0b7 #define XK_cedilla 0x0b8 #define XK_onesuperior 0x0b9 #define XK_masculine 0x0ba #define XK_guillemotright 0x0bb /* right angle quotation mark */ #define XK_onequarter 0x0bc #define XK_onehalf 0x0bd #define XK_threequarters 0x0be #define XK_questiondown 0x0bf #define XK_Agrave 0x0c0 #define XK_Aacute 0x0c1 #define XK_Acircumflex 0x0c2 #define XK_Atilde 0x0c3 #define XK_Adiaeresis 0x0c4 #define XK_Aring 0x0c5 #define XK_AE 0x0c6 #define XK_Ccedilla 0x0c7 #define XK_Egrave 0x0c8 #define XK_Eacute 0x0c9 #define XK_Ecircumflex 0x0ca #define XK_Ediaeresis 0x0cb #define XK_Igrave 0x0cc #define XK_Iacute 0x0cd #define XK_Icircumflex 0x0ce #define XK_Idiaeresis 0x0cf #define XK_ETH 0x0d0 #define XK_Eth 0x0d0 /* deprecated */ #define XK_Ntilde 0x0d1 #define XK_Ograve 0x0d2 #define XK_Oacute 0x0d3 #define XK_Ocircumflex 0x0d4 #define XK_Otilde 0x0d5 #define XK_Odiaeresis 0x0d6 #define XK_multiply 0x0d7 #define XK_Ooblique 0x0d8 #define XK_Ugrave 0x0d9 #define XK_Uacute 0x0da #define XK_Ucircumflex 0x0db #define XK_Udiaeresis 0x0dc #define XK_Yacute 0x0dd #define XK_THORN 0x0de #define XK_Thorn 0x0de /* deprecated */ #define XK_ssharp 0x0df #define XK_agrave 0x0e0 #define XK_aacute 0x0e1 #define XK_acircumflex 0x0e2 #define XK_atilde 0x0e3 #define XK_adiaeresis 0x0e4 #define XK_aring 0x0e5 #define XK_ae 0x0e6 #define XK_ccedilla 0x0e7 #define XK_egrave 0x0e8 #define XK_eacute 0x0e9 #define XK_ecircumflex 0x0ea #define XK_ediaeresis 0x0eb #define XK_igrave 0x0ec #define XK_iacute 0x0ed #define XK_icircumflex 0x0ee #define XK_idiaeresis 0x0ef #define XK_eth 0x0f0 #define XK_ntilde 0x0f1 #define XK_ograve 0x0f2 #define XK_oacute 0x0f3 #define XK_ocircumflex 0x0f4 #define XK_otilde 0x0f5 #define XK_odiaeresis 0x0f6 #define XK_division 0x0f7 #define XK_oslash 0x0f8 #define XK_ugrave 0x0f9 #define XK_uacute 0x0fa #define XK_ucircumflex 0x0fb #define XK_udiaeresis 0x0fc #define XK_yacute 0x0fd #define XK_thorn 0x0fe #define XK_ydiaeresis 0x0ff #endif /* XK_LATIN1 */ /* * Latin 2 * Byte 3 = 1 */ #ifdef XK_LATIN2 #define XK_Aogonek 0x1a1 #define XK_breve 0x1a2 #define XK_Lstroke 0x1a3 #define XK_Lcaron 0x1a5 #define XK_Sacute 0x1a6 #define XK_Scaron 0x1a9 #define XK_Scedilla 0x1aa #define XK_Tcaron 0x1ab #define XK_Zacute 0x1ac #define XK_Zcaron 0x1ae #define XK_Zabovedot 0x1af #define XK_aogonek 0x1b1 #define XK_ogonek 0x1b2 #define XK_lstroke 0x1b3 #define XK_lcaron 0x1b5 #define XK_sacute 0x1b6 #define XK_caron 0x1b7 #define XK_scaron 0x1b9 #define XK_scedilla 0x1ba #define XK_tcaron 0x1bb #define XK_zacute 0x1bc #define XK_doubleacute 0x1bd #define XK_zcaron 0x1be #define XK_zabovedot 0x1bf #define XK_Racute 0x1c0 #define XK_Abreve 0x1c3 #define XK_Lacute 0x1c5 #define XK_Cacute 0x1c6 #define XK_Ccaron 0x1c8 #define XK_Eogonek 0x1ca #define XK_Ecaron 0x1cc #define XK_Dcaron 0x1cf #define XK_Dstroke 0x1d0 #define XK_Nacute 0x1d1 #define XK_Ncaron 0x1d2 #define XK_Odoubleacute 0x1d5 #define XK_Rcaron 0x1d8 #define XK_Uring 0x1d9 #define XK_Udoubleacute 0x1db #define XK_Tcedilla 0x1de #define XK_racute 0x1e0 #define XK_abreve 0x1e3 #define XK_lacute 0x1e5 #define XK_cacute 0x1e6 #define XK_ccaron 0x1e8 #define XK_eogonek 0x1ea #define XK_ecaron 0x1ec #define XK_dcaron 0x1ef #define XK_dstroke 0x1f0 #define XK_nacute 0x1f1 #define XK_ncaron 0x1f2 #define XK_odoubleacute 0x1f5 #define XK_udoubleacute 0x1fb #define XK_rcaron 0x1f8 #define XK_uring 0x1f9 #define XK_tcedilla 0x1fe #define XK_abovedot 0x1ff #endif /* XK_LATIN2 */ /* * Latin 3 * Byte 3 = 2 */ #ifdef XK_LATIN3 #define XK_Hstroke 0x2a1 #define XK_Hcircumflex 0x2a6 #define XK_Iabovedot 0x2a9 #define XK_Gbreve 0x2ab #define XK_Jcircumflex 0x2ac #define XK_hstroke 0x2b1 #define XK_hcircumflex 0x2b6 #define XK_idotless 0x2b9 #define XK_gbreve 0x2bb #define XK_jcircumflex 0x2bc #define XK_Cabovedot 0x2c5 #define XK_Ccircumflex 0x2c6 #define XK_Gabovedot 0x2d5 #define XK_Gcircumflex 0x2d8 #define XK_Ubreve 0x2dd #define XK_Scircumflex 0x2de #define XK_cabovedot 0x2e5 #define XK_ccircumflex 0x2e6 #define XK_gabovedot 0x2f5 #define XK_gcircumflex 0x2f8 #define XK_ubreve 0x2fd #define XK_scircumflex 0x2fe #endif /* XK_LATIN3 */ /* * Latin 4 * Byte 3 = 3 */ #ifdef XK_LATIN4 #define XK_kra 0x3a2 #define XK_kappa 0x3a2 /* deprecated */ #define XK_Rcedilla 0x3a3 #define XK_Itilde 0x3a5 #define XK_Lcedilla 0x3a6 #define XK_Emacron 0x3aa #define XK_Gcedilla 0x3ab #define XK_Tslash 0x3ac #define XK_rcedilla 0x3b3 #define XK_itilde 0x3b5 #define XK_lcedilla 0x3b6 #define XK_emacron 0x3ba #define XK_gcedilla 0x3bb #define XK_tslash 0x3bc #define XK_ENG 0x3bd #define XK_eng 0x3bf #define XK_Amacron 0x3c0 #define XK_Iogonek 0x3c7 #define XK_Eabovedot 0x3cc #define XK_Imacron 0x3cf #define XK_Ncedilla 0x3d1 #define XK_Omacron 0x3d2 #define XK_Kcedilla 0x3d3 #define XK_Uogonek 0x3d9 #define XK_Utilde 0x3dd #define XK_Umacron 0x3de #define XK_amacron 0x3e0 #define XK_iogonek 0x3e7 #define XK_eabovedot 0x3ec #define XK_imacron 0x3ef #define XK_ncedilla 0x3f1 #define XK_omacron 0x3f2 #define XK_kcedilla 0x3f3 #define XK_uogonek 0x3f9 #define XK_utilde 0x3fd #define XK_umacron 0x3fe #endif /* XK_LATIN4 */ /* * Katakana * Byte 3 = 4 */ #ifdef XK_KATAKANA #define XK_overline 0x47e #define XK_kana_fullstop 0x4a1 #define XK_kana_openingbracket 0x4a2 #define XK_kana_closingbracket 0x4a3 #define XK_kana_comma 0x4a4 #define XK_kana_conjunctive 0x4a5 #define XK_kana_middledot 0x4a5 /* deprecated */ #define XK_kana_WO 0x4a6 #define XK_kana_a 0x4a7 #define XK_kana_i 0x4a8 #define XK_kana_u 0x4a9 #define XK_kana_e 0x4aa #define XK_kana_o 0x4ab #define XK_kana_ya 0x4ac #define XK_kana_yu 0x4ad #define XK_kana_yo 0x4ae #define XK_kana_tsu 0x4af #define XK_kana_tu 0x4af /* deprecated */ #define XK_prolongedsound 0x4b0 #define XK_kana_A 0x4b1 #define XK_kana_I 0x4b2 #define XK_kana_U 0x4b3 #define XK_kana_E 0x4b4 #define XK_kana_O 0x4b5 #define XK_kana_KA 0x4b6 #define XK_kana_KI 0x4b7 #define XK_kana_KU 0x4b8 #define XK_kana_KE 0x4b9 #define XK_kana_KO 0x4ba #define XK_kana_SA 0x4bb #define XK_kana_SHI 0x4bc #define XK_kana_SU 0x4bd #define XK_kana_SE 0x4be #define XK_kana_SO 0x4bf #define XK_kana_TA 0x4c0 #define XK_kana_CHI 0x4c1 #define XK_kana_TI 0x4c1 /* deprecated */ #define XK_kana_TSU 0x4c2 #define XK_kana_TU 0x4c2 /* deprecated */ #define XK_kana_TE 0x4c3 #define XK_kana_TO 0x4c4 #define XK_kana_NA 0x4c5 #define XK_kana_NI 0x4c6 #define XK_kana_NU 0x4c7 #define XK_kana_NE 0x4c8 #define XK_kana_NO 0x4c9 #define XK_kana_HA 0x4ca #define XK_kana_HI 0x4cb #define XK_kana_FU 0x4cc #define XK_kana_HU 0x4cc /* deprecated */ #define XK_kana_HE 0x4cd #define XK_kana_HO 0x4ce #define XK_kana_MA 0x4cf #define XK_kana_MI 0x4d0 #define XK_kana_MU 0x4d1 #define XK_kana_ME 0x4d2 #define XK_kana_MO 0x4d3 #define XK_kana_YA 0x4d4 #define XK_kana_YU 0x4d5 #define XK_kana_YO 0x4d6 #define XK_kana_RA 0x4d7 #define XK_kana_RI 0x4d8 #define XK_kana_RU 0x4d9 #define XK_kana_RE 0x4da #define XK_kana_RO 0x4db #define XK_kana_WA 0x4dc #define XK_kana_N 0x4dd #define XK_voicedsound 0x4de #define XK_semivoicedsound 0x4df #define XK_kana_switch 0xFF7E /* Alias for mode_switch */ #endif /* XK_KATAKANA */ /* * Arabic * Byte 3 = 5 */ #ifdef XK_ARABIC #define XK_Arabic_comma 0x5ac #define XK_Arabic_semicolon 0x5bb #define XK_Arabic_question_mark 0x5bf #define XK_Arabic_hamza 0x5c1 #define XK_Arabic_maddaonalef 0x5c2 #define XK_Arabic_hamzaonalef 0x5c3 #define XK_Arabic_hamzaonwaw 0x5c4 #define XK_Arabic_hamzaunderalef 0x5c5 #define XK_Arabic_hamzaonyeh 0x5c6 #define XK_Arabic_alef 0x5c7 #define XK_Arabic_beh 0x5c8 #define XK_Arabic_tehmarbuta 0x5c9 #define XK_Arabic_teh 0x5ca #define XK_Arabic_theh 0x5cb #define XK_Arabic_jeem 0x5cc #define XK_Arabic_hah 0x5cd #define XK_Arabic_khah 0x5ce #define XK_Arabic_dal 0x5cf #define XK_Arabic_thal 0x5d0 #define XK_Arabic_ra 0x5d1 #define XK_Arabic_zain 0x5d2 #define XK_Arabic_seen 0x5d3 #define XK_Arabic_sheen 0x5d4 #define XK_Arabic_sad 0x5d5 #define XK_Arabic_dad 0x5d6 #define XK_Arabic_tah 0x5d7 #define XK_Arabic_zah 0x5d8 #define XK_Arabic_ain 0x5d9 #define XK_Arabic_ghain 0x5da #define XK_Arabic_tatweel 0x5e0 #define XK_Arabic_feh 0x5e1 #define XK_Arabic_qaf 0x5e2 #define XK_Arabic_kaf 0x5e3 #define XK_Arabic_lam 0x5e4 #define XK_Arabic_meem 0x5e5 #define XK_Arabic_noon 0x5e6 #define XK_Arabic_ha 0x5e7 #define XK_Arabic_heh 0x5e7 /* deprecated */ #define XK_Arabic_waw 0x5e8 #define XK_Arabic_alefmaksura 0x5e9 #define XK_Arabic_yeh 0x5ea #define XK_Arabic_fathatan 0x5eb #define XK_Arabic_dammatan 0x5ec #define XK_Arabic_kasratan 0x5ed #define XK_Arabic_fatha 0x5ee #define XK_Arabic_damma 0x5ef #define XK_Arabic_kasra 0x5f0 #define XK_Arabic_shadda 0x5f1 #define XK_Arabic_sukun 0x5f2 #define XK_Arabic_switch 0xFF7E /* Alias for mode_switch */ #endif /* XK_ARABIC */ /* * Cyrillic * Byte 3 = 6 */ #ifdef XK_CYRILLIC #define XK_Serbian_dje 0x6a1 #define XK_Macedonia_gje 0x6a2 #define XK_Cyrillic_io 0x6a3 #define XK_Ukrainian_ie 0x6a4 #define XK_Ukranian_je 0x6a4 /* deprecated */ #define XK_Macedonia_dse 0x6a5 #define XK_Ukrainian_i 0x6a6 #define XK_Ukranian_i 0x6a6 /* deprecated */ #define XK_Ukrainian_yi 0x6a7 #define XK_Ukranian_yi 0x6a7 /* deprecated */ #define XK_Cyrillic_je 0x6a8 #define XK_Serbian_je 0x6a8 /* deprecated */ #define XK_Cyrillic_lje 0x6a9 #define XK_Serbian_lje 0x6a9 /* deprecated */ #define XK_Cyrillic_nje 0x6aa #define XK_Serbian_nje 0x6aa /* deprecated */ #define XK_Serbian_tshe 0x6ab #define XK_Macedonia_kje 0x6ac #define XK_Byelorussian_shortu 0x6ae #define XK_Cyrillic_dzhe 0x6af #define XK_Serbian_dze 0x6af /* deprecated */ #define XK_numerosign 0x6b0 #define XK_Serbian_DJE 0x6b1 #define XK_Macedonia_GJE 0x6b2 #define XK_Cyrillic_IO 0x6b3 #define XK_Ukrainian_IE 0x6b4 #define XK_Ukranian_JE 0x6b4 /* deprecated */ #define XK_Macedonia_DSE 0x6b5 #define XK_Ukrainian_I 0x6b6 #define XK_Ukranian_I 0x6b6 /* deprecated */ #define XK_Ukrainian_YI 0x6b7 #define XK_Ukranian_YI 0x6b7 /* deprecated */ #define XK_Cyrillic_JE 0x6b8 #define XK_Serbian_JE 0x6b8 /* deprecated */ #define XK_Cyrillic_LJE 0x6b9 #define XK_Serbian_LJE 0x6b9 /* deprecated */ #define XK_Cyrillic_NJE 0x6ba #define XK_Serbian_NJE 0x6ba /* deprecated */ #define XK_Serbian_TSHE 0x6bb #define XK_Macedonia_KJE 0x6bc #define XK_Byelorussian_SHORTU 0x6be #define XK_Cyrillic_DZHE 0x6bf #define XK_Serbian_DZE 0x6bf /* deprecated */ #define XK_Cyrillic_yu 0x6c0 #define XK_Cyrillic_a 0x6c1 #define XK_Cyrillic_be 0x6c2 #define XK_Cyrillic_tse 0x6c3 #define XK_Cyrillic_de 0x6c4 #define XK_Cyrillic_ie 0x6c5 #define XK_Cyrillic_ef 0x6c6 #define XK_Cyrillic_ghe 0x6c7 #define XK_Cyrillic_ha 0x6c8 #define XK_Cyrillic_i 0x6c9 #define XK_Cyrillic_shorti 0x6ca #define XK_Cyrillic_ka 0x6cb #define XK_Cyrillic_el 0x6cc #define XK_Cyrillic_em 0x6cd #define XK_Cyrillic_en 0x6ce #define XK_Cyrillic_o 0x6cf #define XK_Cyrillic_pe 0x6d0 #define XK_Cyrillic_ya 0x6d1 #define XK_Cyrillic_er 0x6d2 #define XK_Cyrillic_es 0x6d3 #define XK_Cyrillic_te 0x6d4 #define XK_Cyrillic_u 0x6d5 #define XK_Cyrillic_zhe 0x6d6 #define XK_Cyrillic_ve 0x6d7 #define XK_Cyrillic_softsign 0x6d8 #define XK_Cyrillic_yeru 0x6d9 #define XK_Cyrillic_ze 0x6da #define XK_Cyrillic_sha 0x6db #define XK_Cyrillic_e 0x6dc #define XK_Cyrillic_shcha 0x6dd #define XK_Cyrillic_che 0x6de #define XK_Cyrillic_hardsign 0x6df #define XK_Cyrillic_YU 0x6e0 #define XK_Cyrillic_A 0x6e1 #define XK_Cyrillic_BE 0x6e2 #define XK_Cyrillic_TSE 0x6e3 #define XK_Cyrillic_DE 0x6e4 #define XK_Cyrillic_IE 0x6e5 #define XK_Cyrillic_EF 0x6e6 #define XK_Cyrillic_GHE 0x6e7 #define XK_Cyrillic_HA 0x6e8 #define XK_Cyrillic_I 0x6e9 #define XK_Cyrillic_SHORTI 0x6ea #define XK_Cyrillic_KA 0x6eb #define XK_Cyrillic_EL 0x6ec #define XK_Cyrillic_EM 0x6ed #define XK_Cyrillic_EN 0x6ee #define XK_Cyrillic_O 0x6ef #define XK_Cyrillic_PE 0x6f0 #define XK_Cyrillic_YA 0x6f1 #define XK_Cyrillic_ER 0x6f2 #define XK_Cyrillic_ES 0x6f3 #define XK_Cyrillic_TE 0x6f4 #define XK_Cyrillic_U 0x6f5 #define XK_Cyrillic_ZHE 0x6f6 #define XK_Cyrillic_VE 0x6f7 #define XK_Cyrillic_SOFTSIGN 0x6f8 #define XK_Cyrillic_YERU 0x6f9 #define XK_Cyrillic_ZE 0x6fa #define XK_Cyrillic_SHA 0x6fb #define XK_Cyrillic_E 0x6fc #define XK_Cyrillic_SHCHA 0x6fd #define XK_Cyrillic_CHE 0x6fe #define XK_Cyrillic_HARDSIGN 0x6ff #endif /* XK_CYRILLIC */ /* * Greek * Byte 3 = 7 */ #ifdef XK_GREEK #define XK_Greek_ALPHAaccent 0x7a1 #define XK_Greek_EPSILONaccent 0x7a2 #define XK_Greek_ETAaccent 0x7a3 #define XK_Greek_IOTAaccent 0x7a4 #define XK_Greek_IOTAdiaeresis 0x7a5 #define XK_Greek_OMICRONaccent 0x7a7 #define XK_Greek_UPSILONaccent 0x7a8 #define XK_Greek_UPSILONdieresis 0x7a9 #define XK_Greek_OMEGAaccent 0x7ab #define XK_Greek_accentdieresis 0x7ae #define XK_Greek_horizbar 0x7af #define XK_Greek_alphaaccent 0x7b1 #define XK_Greek_epsilonaccent 0x7b2 #define XK_Greek_etaaccent 0x7b3 #define XK_Greek_iotaaccent 0x7b4 #define XK_Greek_iotadieresis 0x7b5 #define XK_Greek_iotaaccentdieresis 0x7b6 #define XK_Greek_omicronaccent 0x7b7 #define XK_Greek_upsilonaccent 0x7b8 #define XK_Greek_upsilondieresis 0x7b9 #define XK_Greek_upsilonaccentdieresis 0x7ba #define XK_Greek_omegaaccent 0x7bb #define XK_Greek_ALPHA 0x7c1 #define XK_Greek_BETA 0x7c2 #define XK_Greek_GAMMA 0x7c3 #define XK_Greek_DELTA 0x7c4 #define XK_Greek_EPSILON 0x7c5 #define XK_Greek_ZETA 0x7c6 #define XK_Greek_ETA 0x7c7 #define XK_Greek_THETA 0x7c8 #define XK_Greek_IOTA 0x7c9 #define XK_Greek_KAPPA 0x7ca #define XK_Greek_LAMDA 0x7cb #define XK_Greek_LAMBDA 0x7cb #define XK_Greek_MU 0x7cc #define XK_Greek_NU 0x7cd #define XK_Greek_XI 0x7ce #define XK_Greek_OMICRON 0x7cf #define XK_Greek_PI 0x7d0 #define XK_Greek_RHO 0x7d1 #define XK_Greek_SIGMA 0x7d2 #define XK_Greek_TAU 0x7d4 #define XK_Greek_UPSILON 0x7d5 #define XK_Greek_PHI 0x7d6 #define XK_Greek_CHI 0x7d7 #define XK_Greek_PSI 0x7d8 #define XK_Greek_OMEGA 0x7d9 #define XK_Greek_alpha 0x7e1 #define XK_Greek_beta 0x7e2 #define XK_Greek_gamma 0x7e3 #define XK_Greek_delta 0x7e4 #define XK_Greek_epsilon 0x7e5 #define XK_Greek_zeta 0x7e6 #define XK_Greek_eta 0x7e7 #define XK_Greek_theta 0x7e8 #define XK_Greek_iota 0x7e9 #define XK_Greek_kappa 0x7ea #define XK_Greek_lamda 0x7eb #define XK_Greek_lambda 0x7eb #define XK_Greek_mu 0x7ec #define XK_Greek_nu 0x7ed #define XK_Greek_xi 0x7ee #define XK_Greek_omicron 0x7ef #define XK_Greek_pi 0x7f0 #define XK_Greek_rho 0x7f1 #define XK_Greek_sigma 0x7f2 #define XK_Greek_finalsmallsigma 0x7f3 #define XK_Greek_tau 0x7f4 #define XK_Greek_upsilon 0x7f5 #define XK_Greek_phi 0x7f6 #define XK_Greek_chi 0x7f7 #define XK_Greek_psi 0x7f8 #define XK_Greek_omega 0x7f9 #define XK_Greek_switch 0xFF7E /* Alias for mode_switch */ #endif /* XK_GREEK */ /* * Technical * Byte 3 = 8 */ #ifdef XK_TECHNICAL #define XK_leftradical 0x8a1 #define XK_topleftradical 0x8a2 #define XK_horizconnector 0x8a3 #define XK_topintegral 0x8a4 #define XK_botintegral 0x8a5 #define XK_vertconnector 0x8a6 #define XK_topleftsqbracket 0x8a7 #define XK_botleftsqbracket 0x8a8 #define XK_toprightsqbracket 0x8a9 #define XK_botrightsqbracket 0x8aa #define XK_topleftparens 0x8ab #define XK_botleftparens 0x8ac #define XK_toprightparens 0x8ad #define XK_botrightparens 0x8ae #define XK_leftmiddlecurlybrace 0x8af #define XK_rightmiddlecurlybrace 0x8b0 #define XK_topleftsummation 0x8b1 #define XK_botleftsummation 0x8b2 #define XK_topvertsummationconnector 0x8b3 #define XK_botvertsummationconnector 0x8b4 #define XK_toprightsummation 0x8b5 #define XK_botrightsummation 0x8b6 #define XK_rightmiddlesummation 0x8b7 #define XK_lessthanequal 0x8bc #define XK_notequal 0x8bd #define XK_greaterthanequal 0x8be #define XK_integral 0x8bf #define XK_therefore 0x8c0 #define XK_variation 0x8c1 #define XK_infinity 0x8c2 #define XK_nabla 0x8c5 #define XK_approximate 0x8c8 #define XK_similarequal 0x8c9 #define XK_ifonlyif 0x8cd #define XK_implies 0x8ce #define XK_identical 0x8cf #define XK_radical 0x8d6 #define XK_includedin 0x8da #define XK_includes 0x8db #define XK_intersection 0x8dc #define XK_union 0x8dd #define XK_logicaland 0x8de #define XK_logicalor 0x8df #define XK_partialderivative 0x8ef #define XK_function 0x8f6 #define XK_leftarrow 0x8fb #define XK_uparrow 0x8fc #define XK_rightarrow 0x8fd #define XK_downarrow 0x8fe #endif /* XK_TECHNICAL */ /* * Special * Byte 3 = 9 */ #ifdef XK_SPECIAL #define XK_blank 0x9df #define XK_soliddiamond 0x9e0 #define XK_checkerboard 0x9e1 #define XK_ht 0x9e2 #define XK_ff 0x9e3 #define XK_cr 0x9e4 #define XK_lf 0x9e5 #define XK_nl 0x9e8 #define XK_vt 0x9e9 #define XK_lowrightcorner 0x9ea #define XK_uprightcorner 0x9eb #define XK_upleftcorner 0x9ec #define XK_lowleftcorner 0x9ed #define XK_crossinglines 0x9ee #define XK_horizlinescan1 0x9ef #define XK_horizlinescan3 0x9f0 #define XK_horizlinescan5 0x9f1 #define XK_horizlinescan7 0x9f2 #define XK_horizlinescan9 0x9f3 #define XK_leftt 0x9f4 #define XK_rightt 0x9f5 #define XK_bott 0x9f6 #define XK_topt 0x9f7 #define XK_vertbar 0x9f8 #endif /* XK_SPECIAL */ /* * Publishing * Byte 3 = a */ #ifdef XK_PUBLISHING #define XK_emspace 0xaa1 #define XK_enspace 0xaa2 #define XK_em3space 0xaa3 #define XK_em4space 0xaa4 #define XK_digitspace 0xaa5 #define XK_punctspace 0xaa6 #define XK_thinspace 0xaa7 #define XK_hairspace 0xaa8 #define XK_emdash 0xaa9 #define XK_endash 0xaaa #define XK_signifblank 0xaac #define XK_ellipsis 0xaae #define XK_doubbaselinedot 0xaaf #define XK_onethird 0xab0 #define XK_twothirds 0xab1 #define XK_onefifth 0xab2 #define XK_twofifths 0xab3 #define XK_threefifths 0xab4 #define XK_fourfifths 0xab5 #define XK_onesixth 0xab6 #define XK_fivesixths 0xab7 #define XK_careof 0xab8 #define XK_figdash 0xabb #define XK_leftanglebracket 0xabc #define XK_decimalpoint 0xabd #define XK_rightanglebracket 0xabe #define XK_marker 0xabf #define XK_oneeighth 0xac3 #define XK_threeeighths 0xac4 #define XK_fiveeighths 0xac5 #define XK_seveneighths 0xac6 #define XK_trademark 0xac9 #define XK_signaturemark 0xaca #define XK_trademarkincircle 0xacb #define XK_leftopentriangle 0xacc #define XK_rightopentriangle 0xacd #define XK_emopencircle 0xace #define XK_emopenrectangle 0xacf #define XK_leftsinglequotemark 0xad0 #define XK_rightsinglequotemark 0xad1 #define XK_leftdoublequotemark 0xad2 #define XK_rightdoublequotemark 0xad3 #define XK_prescription 0xad4 #define XK_minutes 0xad6 #define XK_seconds 0xad7 #define XK_latincross 0xad9 #define XK_hexagram 0xada #define XK_filledrectbullet 0xadb #define XK_filledlefttribullet 0xadc #define XK_filledrighttribullet 0xadd #define XK_emfilledcircle 0xade #define XK_emfilledrect 0xadf #define XK_enopencircbullet 0xae0 #define XK_enopensquarebullet 0xae1 #define XK_openrectbullet 0xae2 #define XK_opentribulletup 0xae3 #define XK_opentribulletdown 0xae4 #define XK_openstar 0xae5 #define XK_enfilledcircbullet 0xae6 #define XK_enfilledsqbullet 0xae7 #define XK_filledtribulletup 0xae8 #define XK_filledtribulletdown 0xae9 #define XK_leftpointer 0xaea #define XK_rightpointer 0xaeb #define XK_club 0xaec #define XK_diamond 0xaed #define XK_heart 0xaee #define XK_maltesecross 0xaf0 #define XK_dagger 0xaf1 #define XK_doubledagger 0xaf2 #define XK_checkmark 0xaf3 #define XK_ballotcross 0xaf4 #define XK_musicalsharp 0xaf5 #define XK_musicalflat 0xaf6 #define XK_malesymbol 0xaf7 #define XK_femalesymbol 0xaf8 #define XK_telephone 0xaf9 #define XK_telephonerecorder 0xafa #define XK_phonographcopyright 0xafb #define XK_caret 0xafc #define XK_singlelowquotemark 0xafd #define XK_doublelowquotemark 0xafe #define XK_cursor 0xaff #endif /* XK_PUBLISHING */ /* * APL * Byte 3 = b */ #ifdef XK_APL #define XK_leftcaret 0xba3 #define XK_rightcaret 0xba6 #define XK_downcaret 0xba8 #define XK_upcaret 0xba9 #define XK_overbar 0xbc0 #define XK_downtack 0xbc2 #define XK_upshoe 0xbc3 #define XK_downstile 0xbc4 #define XK_underbar 0xbc6 #define XK_jot 0xbca #define XK_quad 0xbcc #define XK_uptack 0xbce #define XK_circle 0xbcf #define XK_upstile 0xbd3 #define XK_downshoe 0xbd6 #define XK_rightshoe 0xbd8 #define XK_leftshoe 0xbda #define XK_lefttack 0xbdc #define XK_righttack 0xbfc #endif /* XK_APL */ /* * Hebrew * Byte 3 = c */ #ifdef XK_HEBREW #define XK_hebrew_doublelowline 0xcdf #define XK_hebrew_aleph 0xce0 #define XK_hebrew_bet 0xce1 #define XK_hebrew_beth 0xce1 /* deprecated */ #define XK_hebrew_gimel 0xce2 #define XK_hebrew_gimmel 0xce2 /* deprecated */ #define XK_hebrew_dalet 0xce3 #define XK_hebrew_daleth 0xce3 /* deprecated */ #define XK_hebrew_he 0xce4 #define XK_hebrew_waw 0xce5 #define XK_hebrew_zain 0xce6 #define XK_hebrew_zayin 0xce6 /* deprecated */ #define XK_hebrew_chet 0xce7 #define XK_hebrew_het 0xce7 /* deprecated */ #define XK_hebrew_tet 0xce8 #define XK_hebrew_teth 0xce8 /* deprecated */ #define XK_hebrew_yod 0xce9 #define XK_hebrew_finalkaph 0xcea #define XK_hebrew_kaph 0xceb #define XK_hebrew_lamed 0xcec #define XK_hebrew_finalmem 0xced #define XK_hebrew_mem 0xcee #define XK_hebrew_finalnun 0xcef #define XK_hebrew_nun 0xcf0 #define XK_hebrew_samech 0xcf1 #define XK_hebrew_samekh 0xcf1 /* deprecated */ #define XK_hebrew_ayin 0xcf2 #define XK_hebrew_finalpe 0xcf3 #define XK_hebrew_pe 0xcf4 #define XK_hebrew_finalzade 0xcf5 #define XK_hebrew_finalzadi 0xcf5 /* deprecated */ #define XK_hebrew_zade 0xcf6 #define XK_hebrew_zadi 0xcf6 /* deprecated */ #define XK_hebrew_qoph 0xcf7 #define XK_hebrew_kuf 0xcf7 /* deprecated */ #define XK_hebrew_resh 0xcf8 #define XK_hebrew_shin 0xcf9 #define XK_hebrew_taw 0xcfa #define XK_hebrew_taf 0xcfa /* deprecated */ #define XK_Hebrew_switch 0xFF7E /* Alias for mode_switch */ #endif /* XK_HEBREW */ blt-2.4z.orig/win/makedefs0100644000175000017500000000174207553175101014253 0ustar dokodokoDEBUG=0 SHARED=1 v1 = 8.4 v2 = 84 v3 = 8.4.0 #v1 = 8.3 #v2 = 83 #v3 = 8.3.4 #v1 = 8.3 #v2 = 83 #v3 = 8.3.2 #v1 = 8.2 #v2 = 82 #v3 = 8.2.3 #v1 = 8.1 #v2 = 81 #v3 = 8.1.1 #v1 = 8.0 #v2 = 80 #v3 = 8.0.5 #Use Independent JPEG Group (IJG) library or Intel JPEG Library (IJL) # 0 = None. # 1 = IJG # 2 = IJL WITH_JPEG=2 # ------------------------------------------------------------------------ # You shouldn't need to edit anything beyond this point # ------------------------------------------------------------------------ BLT_MAJOR_VERSION = 2 BLT_MINOR_VERSION = 4 BLT_VERSION = 2.4 prefix = C:/Program\ Files/Tcl exec_prefix = $(prefix) includedir = $(prefix)/include bindir = $(prefix)/bin libdir = $(prefix)/lib scriptdir = $(libdir)/blt$(BLT_VERSION) BLT_LIBRARY = $(libdir)/blt$(BLT_VERSION) TCLLIBPATH = $(libdir)/tcl$(v1) AUX_LIBS = SHLIB_SUFFIX = .dll INSTALL = install -m 0755 INSTALL_DATA = install -m 0444 RANLIB = : SHELL = bash.exe RM = rm -f